diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index aff246b37..dfa1bf678 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -1,205 +1,206 @@
 # Copyright (c) 2013-2016 The Bitcoin Core developers
 # Distributed under the MIT software license, see the accompanying
 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 TESTS += test/test_bitcoin
 LOG_DRIVER = $(srcdir)/test/test-bitcoin-driver
 EXTRA_DIST += test/test-bitcoin-driver
 bin_PROGRAMS += test/test_bitcoin
 noinst_PROGRAMS += test/test_bitcoin_fuzzy
 TEST_SRCDIR = test
 TEST_BINARY=test/test_bitcoin$(EXEEXT)
 
 JSON_TEST_FILES = \
   test/data/script_tests.json \
   test/data/base58_keys_valid.json \
   test/data/base58_encode_decode.json \
   test/data/base58_keys_invalid.json \
+  test/data/blockfilters.json \
   test/data/tx_invalid.json \
   test/data/tx_valid.json \
   test/data/sighash.json
 
 RAW_TEST_FILES =
 
 GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
 
 # test_bitcoin binary #
 BITCOIN_TESTS =\
   test/scriptnum10.h \
   test/activation_tests.cpp \
   test/addrman_tests.cpp \
   test/allocator_tests.cpp \
   test/amount_tests.cpp \
   test/arith_uint256_tests.cpp \
   test/avalanche_tests.cpp \
   test/base32_tests.cpp \
   test/base58_tests.cpp \
   test/base64_tests.cpp \
   test/bip32_tests.cpp \
   test/blockcheck_tests.cpp \
   test/blockencodings_tests.cpp \
   test/blockfilter_tests.cpp \
   test/blockindex_tests.cpp \
   test/blockstatus_tests.cpp \
   test/bloom_tests.cpp \
   test/bswap_tests.cpp \
   test/cashaddr_tests.cpp \
   test/cashaddrenc_tests.cpp \
   test/checkdatasig_tests.cpp \
   test/checkpoints_tests.cpp \
   test/checkqueue_tests.cpp \
   test/coins_tests.cpp \
   test/compress_tests.cpp \
   test/config_tests.cpp \
   test/core_io_tests.cpp \
   test/crypto_tests.cpp \
   test/cuckoocache_tests.cpp \
   test/dbwrapper_tests.cpp \
   test/DoS_tests.cpp \
   test/dstencode_tests.cpp \
   test/excessiveblock_tests.cpp \
   test/feerate_tests.cpp \
   test/finalization_tests.cpp \
   test/getarg_tests.cpp \
   test/hash_tests.cpp \
   test/inv_tests.cpp \
   test/jsonutil.cpp \
   test/jsonutil.h \
   test/key_tests.cpp \
   test/lcg_tests.cpp \
   test/lcg.h \
   test/limitedmap_tests.cpp \
   test/main_tests.cpp \
   test/mempool_tests.cpp \
   test/merkle_tests.cpp \
   test/miner_tests.cpp \
   test/monolith_opcodes_tests.cpp \
   test/multisig_tests.cpp \
   test/net_tests.cpp \
   test/netbase_tests.cpp \
   test/pmt_tests.cpp \
   test/policyestimator_tests.cpp \
   test/pow_tests.cpp \
   test/prevector_tests.cpp \
   test/radix_tests.cpp \
   test/raii_event_tests.cpp \
   test/random_tests.cpp \
   test/rcu_tests.cpp \
   test/reverselock_tests.cpp \
   test/rpc_tests.cpp \
   test/rpc_server_tests.cpp \
   test/rwcollection_tests.cpp \
   test/sanity_tests.cpp \
   test/scheduler_tests.cpp \
   test/schnorr_tests.cpp \
   test/script_commitment_tests.cpp \
   test/script_P2SH_tests.cpp \
   test/script_tests.cpp \
   test/scriptflags.cpp \
   test/scriptflags.h \
   test/scriptnum_tests.cpp \
   test/serialize_tests.cpp \
   test/sigcache_tests.cpp \
   test/sigencoding_tests.cpp \
   test/sighash_tests.cpp \
   test/sighashtype_tests.cpp \
   test/sigopcount_tests.cpp \
   test/sigutil.cpp \
   test/sigutil.h \
   test/skiplist_tests.cpp \
   test/streams_tests.cpp \
   test/sync_tests.cpp \
   test/test_bitcoin.cpp \
   test/test_bitcoin.h \
   test/test_bitcoin_main.cpp \
   test/timedata_tests.cpp \
   test/transaction_tests.cpp \
   test/txvalidationcache_tests.cpp \
   test/uint256_tests.cpp \
   test/undo_tests.cpp \
   test/univalue_tests.cpp \
   test/util_tests.cpp \
   test/validation_tests.cpp \
   test/work_comparator_tests.cpp \
   rpc/test/server_tests.cpp
 
 if ENABLE_WALLET
 BITCOIN_TESTS += \
   wallet/test/wallet_test_fixture.cpp \
   wallet/test/wallet_test_fixture.h \
   wallet/test/accounting_tests.cpp \
   wallet/test/wallet_tests.cpp \
   wallet/test/walletdb_tests.cpp \
   wallet/test/wallet_crypto_tests.cpp
 endif
 
 test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
 test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
 test_test_bitcoin_LDADD =
 if ENABLE_WALLET
 test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
 endif
 
 test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \
   $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
 test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
 
 test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
 test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
 
 if ENABLE_ZMQ
 test_test_bitcoin_LDADD += $(ZMQ_LIBS)
 endif
 #
 
 # test_bitcoin_fuzzy binary #
 test_test_bitcoin_fuzzy_SOURCES = test/test_bitcoin_fuzzy.cpp
 test_test_bitcoin_fuzzy_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
 test_test_bitcoin_fuzzy_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
 test_test_bitcoin_fuzzy_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
 
 test_test_bitcoin_fuzzy_LDADD = \
   $(LIBUNIVALUE) \
   $(LIBBITCOIN_SERVER) \
   $(LIBBITCOIN_COMMON) \
   $(LIBBITCOIN_UTIL) \
   $(LIBBITCOIN_CONSENSUS) \
   $(LIBBITCOIN_CRYPTO) \
   $(LIBSECP256K1)
 
 test_test_bitcoin_fuzzy_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
 #
 
 nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
 
 $(BITCOIN_TESTS): $(GENERATED_TEST_FILES)
 
 CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES)
 
 CLEANFILES += $(CLEAN_BITCOIN_TEST)
 
 bitcoin_test: $(TEST_BINARY)
 
 bitcoin_test_check: $(TEST_BINARY) FORCE
 	$(MAKE) check-TESTS TESTS=$^
 
 bitcoin_test_clean : FORCE
 	rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY)
 
 check-local:
 	@echo "Running test/util/bitcoin-util-test.py..."
 	$(top_builddir)/test/util/bitcoin-util-test.py
 	$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check
 if EMBEDDED_UNIVALUE
 	$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check
 endif
 
 %.json.h: %.json
 	@$(MKDIR_P) $(@D)
 	@{ \
 	 echo "namespace json_tests{" && \
 	 echo "static unsigned const char $(*F)[] = {" && \
 	 $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x  ,//g' && \
 	 echo "};};"; \
 	} > "$@.new" && mv -f "$@.new" "$@"
 	@echo "Generated $@"
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
index 98a16fcbf..d2227dc42 100644
--- a/src/blockfilter.cpp
+++ b/src/blockfilter.cpp
@@ -1,198 +1,263 @@
 // Copyright (c) 2018 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <blockfilter.h>
 #include <crypto/siphash.h>
+#include <hash.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
 #include <streams.h>
 
 /// SerType used to serialize parameters in GCS filter encoding.
 static constexpr int GCS_SER_TYPE = SER_NETWORK;
 
 /// Protocol version used to serialize parameters in GCS filter encoding.
 static constexpr int GCS_SER_VERSION = 0;
 
 template <typename OStream>
 static void GolombRiceEncode(BitStreamWriter<OStream> &bitwriter, uint8_t P,
                              uint64_t x) {
     // Write quotient as unary-encoded: q 1's followed by one 0.
     uint64_t q = x >> P;
     while (q > 0) {
         int nbits = q <= 64 ? static_cast<int>(q) : 64;
         bitwriter.Write(~0ULL, nbits);
         q -= nbits;
     }
     bitwriter.Write(0, 1);
 
     // Write the remainder in P bits. Since the remainder is just the bottom
     // P bits of x, there is no need to mask first.
     bitwriter.Write(x, P);
 }
 
 template <typename IStream>
 static uint64_t GolombRiceDecode(BitStreamReader<IStream> &bitreader,
                                  uint8_t P) {
     // Read unary-encoded quotient: q 1's followed by one 0.
     uint64_t q = 0;
     while (bitreader.Read(1) == 1) {
         ++q;
     }
 
     uint64_t r = bitreader.Read(P);
 
     return (q << P) + r;
 }
 
 // Map a value x that is uniformly distributed in the range [0, 2^64) to a
 // value uniformly distributed in [0, n) by returning the upper 64 bits of
 // x * n.
 //
 // See:
 // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
 static uint64_t MapIntoRange(uint64_t x, uint64_t n) {
 #ifdef __SIZEOF_INT128__
     return (static_cast<unsigned __int128>(x) *
             static_cast<unsigned __int128>(n)) >>
            64;
 #else
     // To perform the calculation on 64-bit numbers without losing the
     // result to overflow, split the numbers into the most significant and
     // least significant 32 bits and perform multiplication piece-wise.
     //
     // See: https://stackoverflow.com/a/26855440
     uint64_t x_hi = x >> 32;
     uint64_t x_lo = x & 0xFFFFFFFF;
     uint64_t n_hi = n >> 32;
     uint64_t n_lo = n & 0xFFFFFFFF;
 
     uint64_t ac = x_hi * n_hi;
     uint64_t ad = x_hi * n_lo;
     uint64_t bc = x_lo * n_hi;
     uint64_t bd = x_lo * n_lo;
 
     uint64_t mid34 = (bd >> 32) + (bc & 0xFFFFFFFF) + (ad & 0xFFFFFFFF);
     uint64_t upper64 = ac + (bc >> 32) + (ad >> 32) + (mid34 >> 32);
     return upper64;
 #endif
 }
 
 uint64_t GCSFilter::HashToRange(const Element &element) const {
     uint64_t hash = CSipHasher(m_siphash_k0, m_siphash_k1)
                         .Write(element.data(), element.size())
                         .Finalize();
     return MapIntoRange(hash, m_F);
 }
 
 std::vector<uint64_t>
 GCSFilter::BuildHashedSet(const ElementSet &elements) const {
     std::vector<uint64_t> hashed_elements;
     hashed_elements.reserve(elements.size());
     for (const Element &element : elements) {
         hashed_elements.push_back(HashToRange(element));
     }
     std::sort(hashed_elements.begin(), hashed_elements.end());
     return hashed_elements;
 }
 
 GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P,
                      uint32_t M)
     : m_siphash_k0(siphash_k0), m_siphash_k1(siphash_k1), m_P(P), m_M(M),
       m_N(0), m_F(0) {}
 
 GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P,
                      uint32_t M, std::vector<uint8_t> encoded_filter)
     : GCSFilter(siphash_k0, siphash_k1, P, M) {
     m_encoded = std::move(encoded_filter);
 
     VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
 
     uint64_t N = ReadCompactSize(stream);
     m_N = static_cast<uint32_t>(N);
     if (m_N != N) {
         throw std::ios_base::failure("N must be <2^32");
     }
     m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_M);
 
     // Verify that the encoded filter contains exactly N elements. If it has too
     // much or too little data, a std::ios_base::failure exception will be
     // raised.
     BitStreamReader<VectorReader> bitreader(stream);
     for (uint64_t i = 0; i < m_N; ++i) {
         GolombRiceDecode(bitreader, m_P);
     }
     if (!stream.empty()) {
         throw std::ios_base::failure("encoded_filter contains excess data");
     }
 }
 
 GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P,
                      uint32_t M, const ElementSet &elements)
     : GCSFilter(siphash_k0, siphash_k1, P, M) {
     size_t N = elements.size();
     m_N = static_cast<uint32_t>(N);
     if (m_N != N) {
         throw std::invalid_argument("N must be <2^32");
     }
     m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_M);
 
     CVectorWriter stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
 
     WriteCompactSize(stream, m_N);
 
     if (elements.empty()) {
         return;
     }
 
     BitStreamWriter<CVectorWriter> bitwriter(stream);
 
     uint64_t last_value = 0;
     for (uint64_t value : BuildHashedSet(elements)) {
         uint64_t delta = value - last_value;
         GolombRiceEncode(bitwriter, m_P, delta);
         last_value = value;
     }
 
     bitwriter.Flush();
 }
 
 bool GCSFilter::MatchInternal(const uint64_t *element_hashes,
                               size_t size) const {
     VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
 
     // Seek forward by size of N
     uint64_t N = ReadCompactSize(stream);
     assert(N == m_N);
 
     BitStreamReader<VectorReader> bitreader(stream);
 
     uint64_t value = 0;
     size_t hashes_index = 0;
     for (uint32_t i = 0; i < m_N; ++i) {
         uint64_t delta = GolombRiceDecode(bitreader, m_P);
         value += delta;
 
         while (true) {
             if (hashes_index == size) {
                 return false;
             } else if (element_hashes[hashes_index] == value) {
                 return true;
             } else if (element_hashes[hashes_index] > value) {
                 break;
             }
 
             hashes_index++;
         }
     }
 
     return false;
 }
 
 bool GCSFilter::Match(const Element &element) const {
     uint64_t query = HashToRange(element);
     return MatchInternal(&query, 1);
 }
 
 bool GCSFilter::MatchAny(const ElementSet &elements) const {
     const std::vector<uint64_t> queries = BuildHashedSet(elements);
     return MatchInternal(queries.data(), queries.size());
 }
+
+static GCSFilter::ElementSet BasicFilterElements(const CBlock &block,
+                                                 const CBlockUndo &block_undo) {
+    GCSFilter::ElementSet elements;
+
+    for (const CTransactionRef &tx : block.vtx) {
+        for (const CTxOut &txout : tx->vout) {
+            const CScript &script = txout.scriptPubKey;
+            if (script.empty() || script[0] == OP_RETURN) {
+                continue;
+            }
+            elements.emplace(script.begin(), script.end());
+        }
+    }
+
+    for (const CTxUndo &tx_undo : block_undo.vtxundo) {
+        for (const Coin &prevout : tx_undo.vprevout) {
+            const CScript &script = prevout.GetTxOut().scriptPubKey;
+            if (script.empty()) {
+                continue;
+            }
+            elements.emplace(script.begin(), script.end());
+        }
+    }
+
+    return elements;
+}
+
+BlockFilter::BlockFilter(BlockFilterType filter_type, const CBlock &block,
+                         const CBlockUndo &block_undo)
+    : m_filter_type(filter_type), m_block_hash(block.GetHash()) {
+    switch (m_filter_type) {
+        case BlockFilterType::BASIC:
+            m_filter =
+                GCSFilter(m_block_hash.GetUint64(0), m_block_hash.GetUint64(1),
+                          BASIC_FILTER_P, BASIC_FILTER_M,
+                          BasicFilterElements(block, block_undo));
+            break;
+
+        default:
+            throw std::invalid_argument("unknown filter_type");
+    }
+}
+
+uint256 BlockFilter::GetHash() const {
+    const std::vector<uint8_t> &data = GetEncodedFilter();
+
+    uint256 result;
+    CHash256().Write(data.data(), data.size()).Finalize(result.begin());
+    return result;
+}
+
+uint256 BlockFilter::ComputeHeader(const uint256 &prev_header) const {
+    const uint256 &filter_hash = GetHash();
+
+    uint256 result;
+    CHash256()
+        .Write(filter_hash.begin(), filter_hash.size())
+        .Write(prev_header.begin(), prev_header.size())
+        .Finalize(result.begin());
+    return result;
+}
diff --git a/src/blockfilter.h b/src/blockfilter.h
index 373b60ebe..71b0b2d1f 100644
--- a/src/blockfilter.h
+++ b/src/blockfilter.h
@@ -1,74 +1,138 @@
 // Copyright (c) 2018 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #ifndef BITCOIN_BLOCKFILTER_H
 #define BITCOIN_BLOCKFILTER_H
 
+#include <primitives/block.h>
 #include <serialize.h>
 #include <uint256.h>
+#include <undo.h>
 
 #include <cstdint>
 #include <set>
 #include <vector>
 
 /**
  * This implements a Golomb-coded set as defined in BIP 158. It is a
  * compact, probabilistic data structure for testing set membership.
  */
 class GCSFilter {
 public:
     typedef std::vector<uint8_t> Element;
     typedef std::set<Element> ElementSet;
 
 private:
     uint64_t m_siphash_k0;
     uint64_t m_siphash_k1;
     uint8_t m_P;  //!< Golomb-Rice coding parameter
     uint32_t m_M; //!< Inverse false positive rate
     uint32_t m_N; //!< Number of elements in the filter
     uint64_t m_F; //!< Range of element hashes, F = N * M
     std::vector<uint8_t> m_encoded;
 
     /** Hash a data element to an integer in the range [0, N * M). */
     uint64_t HashToRange(const Element &element) const;
 
     std::vector<uint64_t> BuildHashedSet(const ElementSet &elements) const;
 
     /** Helper method used to implement Match and MatchAny */
     bool MatchInternal(const uint64_t *sorted_element_hashes,
                        size_t size) const;
 
 public:
     /** Constructs an empty filter. */
     GCSFilter(uint64_t siphash_k0 = 0, uint64_t siphash_k1 = 0, uint8_t P = 0,
               uint32_t M = 0);
 
     /** Reconstructs an already-created filter from an encoding. */
     GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
               std::vector<uint8_t> encoded_filter);
 
     /** Builds a new filter from the params and set of elements. */
     GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
               const ElementSet &elements);
 
     uint8_t GetP() const { return m_P; }
     uint32_t GetN() const { return m_N; }
     uint32_t GetM() const { return m_M; }
     const std::vector<uint8_t> &GetEncoded() const { return m_encoded; }
 
     /**
      * Checks if the element may be in the set. False positives are possible
      * with probability 1/M.
      */
     bool Match(const Element &element) const;
 
     /**
      * Checks if any of the given elements may be in the set. False positives
      * are possible with probability 1/M per element checked. This is more
      * efficient that checking Match on multiple elements separately.
      */
     bool MatchAny(const ElementSet &elements) const;
 };
 
+constexpr uint8_t BASIC_FILTER_P = 19;
+constexpr uint32_t BASIC_FILTER_M = 784931;
+
+enum BlockFilterType : uint8_t {
+    BASIC = 0,
+};
+
+/**
+ * Complete block filter struct as defined in BIP 157. Serialization matches
+ * payload of "cfilter" messages.
+ */
+class BlockFilter {
+private:
+    BlockFilterType m_filter_type;
+    uint256 m_block_hash;
+    GCSFilter m_filter;
+
+public:
+    // Construct a new BlockFilter of the specified type from a block.
+    BlockFilter(BlockFilterType filter_type, const CBlock &block,
+                const CBlockUndo &block_undo);
+
+    BlockFilterType GetFilterType() const { return m_filter_type; }
+
+    const GCSFilter &GetFilter() const { return m_filter; }
+
+    const std::vector<uint8_t> &GetEncodedFilter() const {
+        return m_filter.GetEncoded();
+    }
+
+    // Compute the filter hash.
+    uint256 GetHash() const;
+
+    // Compute the filter header given the previous one.
+    uint256 ComputeHeader(const uint256 &prev_header) const;
+
+    template <typename Stream> void Serialize(Stream &s) const {
+        s << m_block_hash << static_cast<uint8_t>(m_filter_type)
+          << m_filter.GetEncoded();
+    }
+
+    template <typename Stream> void Unserialize(Stream &s) {
+        std::vector<uint8_t> encoded_filter;
+        uint8_t filter_type;
+
+        s >> m_block_hash >> filter_type >> encoded_filter;
+
+        m_filter_type = static_cast<BlockFilterType>(filter_type);
+
+        switch (m_filter_type) {
+            case BlockFilterType::BASIC:
+                m_filter = GCSFilter(m_block_hash.GetUint64(0),
+                                     m_block_hash.GetUint64(1), BASIC_FILTER_P,
+                                     BASIC_FILTER_M, std::move(encoded_filter));
+                break;
+
+            default:
+                throw std::ios_base::failure("unknown filter_type");
+        }
+    }
+};
+
 #endif // BITCOIN_BLOCKFILTER_H
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
index 7767e3b24..a2118d8fb 100644
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -1,176 +1,177 @@
 # Copyright (c) 2018 The Bitcoin developers
 
 project(bitcoin-test)
 
 # Process json files.
 file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/data")
 
 find_program(PYTHON python)
 function(gen_json_header NAME)
 	set(HEADERS "")
 	foreach(f ${ARGN})
 		set(h "${CMAKE_CURRENT_BINARY_DIR}/${f}.h")
 
 		# Get the proper name for the test variable.
 		get_filename_component(TEST_NAME ${f} NAME_WE)
 		add_custom_command(OUTPUT ${h}
 			COMMAND ${PYTHON}
 			ARGS
 				"${CMAKE_CURRENT_SOURCE_DIR}/data/generate_header.py"
 				"${TEST_NAME}"
 				"${CMAKE_CURRENT_SOURCE_DIR}/${f}" > ${h}
 			MAIN_DEPENDENCY ${f}
 			DEPENDS
 				"data/generate_header.py"
 			VERBATIM
 		)
 		list(APPEND HEADERS ${h})
 	endforeach(f)
 	set(${NAME} "${HEADERS}" PARENT_SCOPE)
 endfunction()
 
 gen_json_header(JSON_HEADERS
 	data/script_tests.json
 	data/base58_keys_valid.json
 	data/base58_encode_decode.json
 	data/base58_keys_invalid.json
+	data/blockfilters.json
 	data/tx_invalid.json
 	data/tx_valid.json
 	data/sighash.json
 )
 
 include(TestSuite)
 create_test_suite(bitcoin)
 add_dependencies(check check-bitcoin)
 
 add_test_to_suite(bitcoin test_bitcoin
 	activation_tests.cpp
 	addrman_tests.cpp
 	allocator_tests.cpp
 	amount_tests.cpp
 	arith_uint256_tests.cpp
 	avalanche_tests.cpp
 	base32_tests.cpp
 	base58_tests.cpp
 	base64_tests.cpp
 	bip32_tests.cpp
 	blockcheck_tests.cpp
 	blockencodings_tests.cpp
 	blockfilter_tests.cpp
 	blockindex_tests.cpp
 	blockstatus_tests.cpp
 	bloom_tests.cpp
 	bswap_tests.cpp
 	cashaddr_tests.cpp
 	cashaddrenc_tests.cpp
 	checkdatasig_tests.cpp
 	checkpoints_tests.cpp
 	checkqueue_tests.cpp
 	coins_tests.cpp
 	compress_tests.cpp
 	config_tests.cpp
 	core_io_tests.cpp
 	crypto_tests.cpp
 	cuckoocache_tests.cpp
 	dbwrapper_tests.cpp
 	DoS_tests.cpp
 	dstencode_tests.cpp
 	excessiveblock_tests.cpp
 	feerate_tests.cpp
 	finalization_tests.cpp
 	getarg_tests.cpp
 	hash_tests.cpp
 	inv_tests.cpp
 	jsonutil.cpp
 	key_tests.cpp
 	lcg_tests.cpp
 	limitedmap_tests.cpp
 	main_tests.cpp
 	mempool_tests.cpp
 	merkle_tests.cpp
 	miner_tests.cpp
 	monolith_opcodes_tests.cpp
 	multisig_tests.cpp
 	net_tests.cpp
 	netbase_tests.cpp
 	pmt_tests.cpp
 	policyestimator_tests.cpp
 	pow_tests.cpp
 	prevector_tests.cpp
 	radix_tests.cpp
 	raii_event_tests.cpp
 	random_tests.cpp
 	rcu_tests.cpp
 	reverselock_tests.cpp
 	rpc_tests.cpp
 	rpc_server_tests.cpp
 	rwcollection_tests.cpp
 	sanity_tests.cpp
 	scheduler_tests.cpp
 	schnorr_tests.cpp
 	script_commitment_tests.cpp
 	script_P2SH_tests.cpp
 	script_tests.cpp
 	scriptflags.cpp
 	scriptnum_tests.cpp
 	serialize_tests.cpp
 	sigcache_tests.cpp
 	sigencoding_tests.cpp
 	sighash_tests.cpp
 	sighashtype_tests.cpp
 	sigopcount_tests.cpp
 	sigutil.cpp
 	skiplist_tests.cpp
 	streams_tests.cpp
 	sync_tests.cpp
 	test_bitcoin.cpp
 	test_bitcoin_main.cpp
 	timedata_tests.cpp
 	transaction_tests.cpp
 	txvalidationcache_tests.cpp
 	uint256_tests.cpp
 	undo_tests.cpp
 	univalue_tests.cpp
 	util_tests.cpp
 	validation_tests.cpp
 	work_comparator_tests.cpp
 
 	# RPC Tests
 	../rpc/test/server_tests.cpp
 
 	# Tests generated from JSON
 	${JSON_HEADERS}
 )
 
 target_include_directories(test_bitcoin
 	PUBLIC
 		# To access the generated json headers.
 		${CMAKE_CURRENT_BINARY_DIR}
 )
 
 find_package(Boost 1.58 REQUIRED unit_test_framework)
 
 target_link_libraries(test_bitcoin Boost::unit_test_framework rpcclient server)
 
 # We need to detect if the BOOST_TEST_DYN_LINK flag is required.
 set(CMAKE_REQUIRED_LIBRARIES Boost::unit_test_framework)
 check_cxx_source_compiles("
 	#define BOOST_TEST_DYN_LINK
 	#define BOOST_TEST_MAIN
 	#include <boost/test/unit_test.hpp>
 " BOOST_TEST_DYN_LINK)
 
 if(BOOST_TEST_DYN_LINK)
 	target_compile_definitions(test_bitcoin PRIVATE BOOST_TEST_DYN_LINK)
 endif(BOOST_TEST_DYN_LINK)
 
 if(BUILD_BITCOIN_WALLET)
 	target_sources(test_bitcoin
 		PRIVATE
 			../wallet/test/wallet_test_fixture.cpp
 			../wallet/test/accounting_tests.cpp
 			../wallet/test/wallet_tests.cpp
 			../wallet/test/walletdb_tests.cpp
 			../wallet/test/wallet_crypto_tests.cpp
 	)
 endif()
diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp
index b97deed3c..28553b89b 100644
--- a/src/test/blockfilter_tests.cpp
+++ b/src/test/blockfilter_tests.cpp
@@ -1,33 +1,160 @@
 // Copyright (c) 2018 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <blockfilter.h>
 
+#include <core_io.h>
+#include <serialize.h>
+#include <streams.h>
+#include <utilstrencodings.h>
+
+#include <test/data/blockfilters.json.h>
+#include <test/test_bitcoin.h>
+
 #include <boost/test/unit_test.hpp>
 
+#include <univalue.h>
+
 BOOST_AUTO_TEST_SUITE(blockfilter_tests)
 
 BOOST_AUTO_TEST_CASE(gcsfilter_test) {
     GCSFilter::ElementSet included_elements, excluded_elements;
     for (int i = 0; i < 100; ++i) {
         GCSFilter::Element element1(32);
         element1[0] = i;
         included_elements.insert(std::move(element1));
 
         GCSFilter::Element element2(32);
         element2[1] = i;
         excluded_elements.insert(std::move(element2));
     }
 
     GCSFilter filter(0, 0, 10, 1 << 10, included_elements);
     for (const auto &element : included_elements) {
         BOOST_CHECK(filter.Match(element));
 
         auto insertion = excluded_elements.insert(element);
         BOOST_CHECK(filter.MatchAny(excluded_elements));
         excluded_elements.erase(insertion.first);
     }
 }
 
+BOOST_AUTO_TEST_CASE(blockfilter_basic_test) {
+    CScript included_scripts[5], excluded_scripts[3];
+
+    // First two are outputs on a single transaction.
+    included_scripts[0] << std::vector<uint8_t>(0, 65) << OP_CHECKSIG;
+    included_scripts[1] << OP_DUP << OP_HASH160 << std::vector<uint8_t>(1, 20)
+                        << OP_EQUALVERIFY << OP_CHECKSIG;
+
+    // Third is an output on in a second transaction.
+    included_scripts[2] << OP_1 << std::vector<uint8_t>(2, 33) << OP_1
+                        << OP_CHECKMULTISIG;
+
+    // Last two are spent by a single transaction.
+    included_scripts[3] << OP_0 << std::vector<uint8_t>(3, 32);
+    included_scripts[4] << OP_4 << OP_ADD << OP_8 << OP_EQUAL;
+
+    // OP_RETURN output is an output on the second transaction.
+    excluded_scripts[0] << OP_RETURN << std::vector<uint8_t>(4, 40);
+
+    // This script is not related to the block at all.
+    excluded_scripts[1] << std::vector<uint8_t>(5, 33) << OP_CHECKSIG;
+
+    CMutableTransaction tx_1;
+    tx_1.vout.emplace_back(100 * SATOSHI, included_scripts[0]);
+    tx_1.vout.emplace_back(200 * SATOSHI, included_scripts[1]);
+
+    CMutableTransaction tx_2;
+    tx_2.vout.emplace_back(300 * SATOSHI, included_scripts[2]);
+    tx_2.vout.emplace_back(0 * SATOSHI, excluded_scripts[0]);
+    // Script is empty
+    tx_2.vout.emplace_back(400 * SATOSHI, excluded_scripts[2]);
+
+    CBlock block;
+    block.vtx.push_back(MakeTransactionRef(tx_1));
+    block.vtx.push_back(MakeTransactionRef(tx_2));
+
+    CBlockUndo block_undo;
+    block_undo.vtxundo.emplace_back();
+    block_undo.vtxundo.back().vprevout.emplace_back(
+        CTxOut(500 * SATOSHI, included_scripts[3]), 1000, true);
+    block_undo.vtxundo.back().vprevout.emplace_back(
+        CTxOut(600 * SATOSHI, included_scripts[4]), 10000, false);
+    block_undo.vtxundo.back().vprevout.emplace_back(
+        CTxOut(700 * SATOSHI, excluded_scripts[2]), 100000, false);
+
+    BlockFilter block_filter(BlockFilterType::BASIC, block, block_undo);
+    const GCSFilter &filter = block_filter.GetFilter();
+
+    for (const CScript &script : included_scripts) {
+        BOOST_CHECK(
+            filter.Match(GCSFilter::Element(script.begin(), script.end())));
+    }
+    for (const CScript &script : excluded_scripts) {
+        BOOST_CHECK(
+            !filter.Match(GCSFilter::Element(script.begin(), script.end())));
+    }
+}
+
+BOOST_AUTO_TEST_CASE(blockfilters_json_test) {
+    UniValue json;
+    std::string json_data(json_tests::blockfilters,
+                          json_tests::blockfilters +
+                              sizeof(json_tests::blockfilters));
+    if (!json.read(json_data) || !json.isArray()) {
+        BOOST_ERROR("Parse error.");
+        return;
+    }
+
+    const UniValue &tests = json.get_array();
+    for (size_t i = 0; i < tests.size(); i++) {
+        UniValue test = tests[i];
+        std::string strTest = test.write();
+
+        if (test.size() == 1) {
+            continue;
+        } else if (test.size() < 7) {
+            BOOST_ERROR("Bad test: " << strTest);
+            continue;
+        }
+
+        size_t pos = 0;
+        /*int block_height =*/test[pos++].get_int();
+        /*uint256 block_hash =*/ParseHashStr(test[pos++].get_str(),
+                                             "block_hash");
+
+        CBlock block;
+        BOOST_REQUIRE(DecodeHexBlk(block, test[pos++].get_str()));
+
+        CBlockUndo block_undo;
+        block_undo.vtxundo.emplace_back();
+        CTxUndo &tx_undo = block_undo.vtxundo.back();
+        const UniValue &prev_scripts = test[pos++].get_array();
+        for (size_t ii = 0; ii < prev_scripts.size(); ii++) {
+            std::vector<uint8_t> raw_script =
+                ParseHex(prev_scripts[ii].get_str());
+            CTxOut txout(0 * SATOSHI,
+                         CScript(raw_script.begin(), raw_script.end()));
+            tx_undo.vprevout.emplace_back(txout, 0, false);
+        }
+
+        uint256 prev_filter_header_basic =
+            ParseHashStr(test[pos++].get_str(), "prev_filter_header_basic");
+        std::vector<uint8_t> filter_basic = ParseHex(test[pos++].get_str());
+        uint256 filter_header_basic =
+            ParseHashStr(test[pos++].get_str(), "filter_header_basic");
+
+        BlockFilter computed_filter_basic(BlockFilterType::BASIC, block,
+                                          block_undo);
+        BOOST_CHECK(computed_filter_basic.GetFilter().GetEncoded() ==
+                    filter_basic);
+
+        uint256 computed_header_basic =
+            computed_filter_basic.ComputeHeader(prev_filter_header_basic);
+        BOOST_CHECK(computed_header_basic == filter_header_basic);
+    }
+}
+
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/data/blockfilters.json b/src/test/data/blockfilters.json
new file mode 100644
index 000000000..598d2767f
--- /dev/null
+++ b/src/test/data/blockfilters.json
@@ -0,0 +1,9 @@
+[
+["Block Height,Block Hash,Block,[Prev Output Scripts for Block],Previous Basic Header,Basic Filter,Basic Header,Notes"],
+[0,"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943","0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000",[],"0000000000000000000000000000000000000000000000000000000000000000","019dfca8","21584579b7eb08997773e5aeff3a7f932700042d0ed2a6129012b7d7ae81b750","Genesis block"],
+[2,"000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820","0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d235340101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0432e7494d010e062f503253482fffffffff0100f2052a010000002321038a7f6ef1c8ca0c588aa53fa860128077c9e6c11e6830f4d7ee4e763a56b7718fac00000000",[],"d7bdac13a59d745b1add0d2ce852f1a0442e8945fc1bf3848d3cbffd88c24fe1","0174a170","186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0",""],
+[3,"000000008b896e272758da5297bcd98fdc6d97c9b765ecec401e286dc1fdbe10","0100000020782a005255b657696ea057d5b98f34defcf75196f64f6eeac8026c0000000041ba5afc532aae03151b8aa87b65e1594f97504a768e010c98c0add79216247186e7494dffff001d058dc2b60101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0486e7494d0151062f503253482fffffffff0100f2052a01000000232103f6d9ff4c12959445ca5549c811683bf9c88e637b222dd2e0311154c4c85cf423ac00000000",[],"186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0","016cf7a0","8d63aadf5ab7257cb6d2316a57b16f517bff1c6388f124ec4c04af1212729d2a",""],
+[49291,"0000000018b07dca1b28b4b5a119f6d6e71698ce1ed96f143f54179ce177a19c","02000000abfaf47274223ca2fea22797e44498240e482cb4c2f2baea088962f800000000604b5b52c32305b15d7542071d8b04e750a547500005d4010727694b6e72a776e55d0d51ffff001d211806480201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0d038bc0000102062f503253482fffffffff01a078072a01000000232102971dd6034ed0cf52450b608d196c07d6345184fcb14deb277a6b82d526a6163dac0000000001000000081cefd96060ecb1c4fbe675ad8a4f8bdc61d634c52b3a1c4116dee23749fe80ff000000009300493046022100866859c21f306538152e83f115bcfbf59ab4bb34887a88c03483a5dff9895f96022100a6dfd83caa609bf0516debc2bf65c3df91813a4842650a1858b3f61cfa8af249014730440220296d4b818bb037d0f83f9f7111665f49532dfdcbec1e6b784526e9ac4046eaa602204acf3a5cb2695e8404d80bf49ab04828bcbe6fc31d25a2844ced7a8d24afbdff01ffffffff1cefd96060ecb1c4fbe675ad8a4f8bdc61d634c52b3a1c4116dee23749fe80ff020000009400483045022100e87899175991aa008176cb553c6f2badbb5b741f328c9845fcab89f8b18cae2302200acce689896dc82933015e7230e5230d5cff8a1ffe82d334d60162ac2c5b0c9601493046022100994ad29d1e7b03e41731a4316e5f4992f0d9b6e2efc40a1ccd2c949b461175c502210099b69fdc2db00fbba214f16e286f6a49e2d8a0d5ffc6409d87796add475478d601ffffffff1e4a6d2d280ea06680d6cf8788ac90344a9c67cca9b06005bbd6d3f6945c8272010000009500493046022100a27400ba52fd842ce07398a1de102f710a10c5599545e6c95798934352c2e4df022100f6383b0b14c9f64b6718139f55b6b9494374755b86bae7d63f5d3e583b57255a01493046022100fdf543292f34e1eeb1703b264965339ec4a450ec47585009c606b3edbc5b617b022100a5fbb1c8de8aaaa582988cdb23622838e38de90bebcaab3928d949aa502a65d401ffffffff1e4a6d2d280ea06680d6cf8788ac90344a9c67cca9b06005bbd6d3f6945c8272020000009400493046022100ac626ac3051f875145b4fe4cfe089ea895aac73f65ab837b1ac30f5d875874fa022100bc03e79fa4b7eb707fb735b95ff6613ca33adeaf3a0607cdcead4cfd3b51729801483045022100b720b04a5c5e2f61b7df0fcf334ab6fea167b7aaede5695d3f7c6973496adbf1022043328c4cc1cdc3e5db7bb895ccc37133e960b2fd3ece98350f774596badb387201ffffffff23a8733e349c97d6cd90f520fdd084ba15ce0a395aad03cd51370602bb9e5db3010000004a00483045022100e8556b72c5e9c0da7371913a45861a61c5df434dfd962de7b23848e1a28c86ca02205d41ceda00136267281be0974be132ac4cda1459fe2090ce455619d8b91045e901ffffffff6856d609b881e875a5ee141c235e2a82f6b039f2b9babe82333677a5570285a6000000006a473044022040a1c631554b8b210fbdf2a73f191b2851afb51d5171fb53502a3a040a38d2c0022040d11cf6e7b41fe1b66c3d08f6ada1aee07a047cb77f242b8ecc63812c832c9a012102bcfad931b502761e452962a5976c79158a0f6d307ad31b739611dac6a297c256ffffffff6856d609b881e875a5ee141c235e2a82f6b039f2b9babe82333677a5570285a601000000930048304502205b109df098f7e932fbf71a45869c3f80323974a826ee2770789eae178a21bfc8022100c0e75615e53ee4b6e32b9bb5faa36ac539e9c05fa2ae6b6de5d09c08455c8b9601483045022009fb7d27375c47bea23b24818634df6a54ecf72d52e0c1268fb2a2c84f1885de022100e0ed4f15d62e7f537da0d0f1863498f9c7c0c0a4e00e4679588c8d1a9eb20bb801ffffffffa563c3722b7b39481836d5edfc1461f97335d5d1e9a23ade13680d0e2c1c371f030000006c493046022100ecc38ae2b1565643dc3c0dad5e961a5f0ea09cab28d024f92fa05c922924157e022100ebc166edf6fbe4004c72bfe8cf40130263f98ddff728c8e67b113dbd621906a601210211a4ed241174708c07206601b44a4c1c29e5ad8b1f731c50ca7e1d4b2a06dc1fffffffff02d0223a00000000001976a91445db0b779c0b9fa207f12a8218c94fc77aff504588ac80f0fa02000000000000000000",["5221033423007d8f263819a2e42becaaf5b06f34cb09919e06304349d950668209eaed21021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae","52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae","522102a7ae1e0971fc1689bd66d2a7296da3a1662fd21a53c9e38979e0f090a375c12d21022adb62335f41eb4e27056ac37d462cda5ad783fa8e0e526ed79c752475db285d52ae","52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821022adb62335f41eb4e27056ac37d462cda5ad783fa8e0e526ed79c752475db285d52ae","512103b9d1d0e2b4355ec3cdef7c11a5c0beff9e8b8d8372ab4b4e0aaf30e80173001951ae","76a9149144761ebaccd5b4bbdc2a35453585b5637b2f8588ac","522103f1848b40621c5d48471d9784c8174ca060555891ace6d2b03c58eece946b1a9121020ee5d32b54d429c152fdc7b1db84f2074b0564d35400d89d11870f9273ec140c52ae","76a914f4fa1cc7de742d135ea82c17adf0bb9cf5f4fb8388ac"],"ed47705334f4643892ca46396eb3f4196a5e30880589e4009ef38eae895d4a13","0afbc2920af1b027f31f87b592276eb4c32094bb4d3697021b4c6380","b6d98692cec5145f67585f3434ec3c2b3030182e1cb3ec58b855c5c164dfaaa3","Tx pays to empty output script"],
+[180480,"00000000fd3ceb2404ff07a785c7fdcc76619edc8ed61bd25134eaa22084366a","020000006058aa080a655aa991a444bd7d1f2defd9a3bbe68aabb69030cf3b4e00000000d2e826bfd7ef0beaa891a7eedbc92cd6a544a6cb61c7bdaa436762eb2123ef9790f5f552ffff001d0002c90f0501000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0300c102024608062f503253482fffffffff01c0c6072a01000000232102e769e60137a4df6b0df8ebd387cca44c4c57ae74cc0114a8e8317c8f3bfd85e9ac00000000010000000381a0802911a01ffb025c4dea0bc77963e8c1bb46313b71164c53f72f37fe5248010000000151ffffffffc904b267833d215e2128bd9575242232ac2bc311550c7fc1f0ef6f264b40d14c010000000151ffffffffdf0915666649dba81886519c531649b7b02180b4af67d6885e871299e9d5f775000000000151ffffffff0180817dcb00000000232103bb52138972c48a132fc1f637858c5189607dd0f7fe40c4f20f6ad65f2d389ba4ac0000000001000000018da38b434fba82d66052af74fc5e4e94301b114d9bc03f819dc876398404c8b4010000006c493046022100fe738b7580dc5fb5168e51fc61b5aed211125eb71068031009a22d9bbad752c5022100be5086baa384d40bcab0fa586e4f728397388d86e18b66cc417dc4f7fa4f9878012103f233299455134caa2687bdf15cb0becdfb03bd0ff2ff38e65ec6b7834295c34fffffffff022ebc1400000000001976a9147779b7fba1c1e06b717069b80ca170e8b04458a488ac9879c40f000000001976a9142a0307cd925dbb66b534c4db33003dd18c57015788ac0000000001000000026139a62e3422a602de36c873a225c1d3ca5aeee598539ceecb9f0dc8d1ad0f83010000006b483045022100ad9f32b4a0a2ddc19b5a74eba78123e57616f1b3cfd72ce68c03ea35a3dda1f002200dbd22aa6da17213df5e70dfc3b2611d40f70c98ed9626aa5e2cde9d97461f0a012103ddb295d2f1e8319187738fb4b230fdd9aa29d0e01647f69f6d770b9ab24eea90ffffffff983c82c87cf020040d671956525014d5c2b28c6d948c85e1a522362c0059eeae010000006b4830450221009ca544274c786d30a5d5d25e17759201ea16d3aedddf0b9e9721246f7ef6b32e02202cfa5564b6e87dfd9fd98957820e4d4e6238baeb0f65fe305d91506bb13f5f4f012103c99113deac0d5d044e3ac0346abc02501542af8c8d3759f1382c72ff84e704f7ffffffff02c0c62d00000000001976a914ae19d27efe12f5a886dc79af37ad6805db6f922d88ac70ce2000000000001976a9143b8d051d37a07ea1042067e93efe63dbf73920b988ac000000000100000002be566e8cd9933f0c75c4a82c027f7d0c544d5c101d0607ef6ae5d07b98e7f1dc000000006b483045022036a8cdfd5ea7ebc06c2bfb6e4f942bbf9a1caeded41680d11a3a9f5d8284abad022100cacb92a5be3f39e8bc14db1710910ef7b395fa1e18f45d41c28d914fcdde33be012102bf59abf110b5131fae0a3ce1ec379329b4c896a6ae5d443edb68529cc2bc7816ffffffff96cf67645b76ceb23fe922874847456a15feee1655082ff32d25a6bf2c0dfc90000000006a47304402203471ca2001784a5ac0abab583581f2613523da47ec5f53df833c117b5abd81500220618a2847723d57324f2984678db556dbca1a72230fc7e39df04c2239942ba942012102925c9794fd7bb9f8b29e207d5fc491b1150135a21f505041858889fa4edf436fffffffff026c840f00000000001976a914797fb8777d7991d8284d88bfd421ce520f0f843188ac00ca9a3b000000001976a9146d10f3f592699265d10b106eda37c3ce793f7a8588ac00000000",["","","","76a9142903b138c24be9e070b3e73ec495d77a204615e788ac","76a91433a1941fd9a37b9821d376f5a51bd4b52fa50e2888ac","76a914e4374e8155d0865742ca12b8d4d14d41b57d682f88ac","76a914001fa7459a6cfc64bdc178ba7e7a21603bb2568f88ac","76a914f6039952bc2b307aeec5371bfb96b66078ec17f688ac"],"b109139671dbedc2b6fcd499a5480a7461ae458af8ff9411d819aa64ba6995d1","0db414c859a07e8205876354a210a75042d0463404913d61a8e068e58a3ae2aa080026","a0af77e0a7ed20ea78d2def3200cc24f08217dcd51755c7c7feb0e2ba8316c2d","Tx spends from empty output script"],
+[987876,"0000000000000c00901f2049055e2a437c819d79a3d54fd63e6af796cd7b8a79","000000202694f74969fdb542090e95a56bc8aa2d646e27033850e32f1c5f000000000000f7e53676b3f12d5beb524ed617f2d25f5a93b5f4f52c1ba2678260d72712f8dd0a6dfe5740257e1a4b1768960101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1603e4120ff9c30a1c216900002f424d4920546573742fffffff0001205fa012000000001e76a914c486de584a735ec2f22da7cd9681614681f92173d83d0aa68688ac00000000",[],"e9d729b72d533c29abe5276d5cf6c152f3723f10efe000b1e0c9ca5265a8beb6","010c0b40","e6137ae5a8424c40da1e5023c16975cc97b09300b4c050e6b1c713add3836c40","Coinbase tx has unparseable output script"]
+]