blockfilter_tests.cpp
1 // Copyright (c) 2018-present The Bitcoin Core developers 2 // Distributed under the MIT software license, see the accompanying 3 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 5 #include <test/data/blockfilters.json.h> 6 #include <test/util/common.h> 7 8 #include <blockfilter.h> 9 #include <core_io.h> 10 #include <primitives/block.h> 11 #include <serialize.h> 12 #include <streams.h> 13 #include <undo.h> 14 #include <univalue.h> 15 #include <util/strencodings.h> 16 17 #include <boost/test/unit_test.hpp> 18 19 BOOST_AUTO_TEST_SUITE(blockfilter_tests) 20 21 BOOST_AUTO_TEST_CASE(gcsfilter_test) 22 { 23 GCSFilter::ElementSet included_elements, excluded_elements; 24 for (int i = 0; i < 100; ++i) { 25 GCSFilter::Element element1(32); 26 element1[0] = i; 27 included_elements.insert(std::move(element1)); 28 29 GCSFilter::Element element2(32); 30 element2[1] = i; 31 excluded_elements.insert(std::move(element2)); 32 } 33 34 GCSFilter filter({0, 0, 10, 1 << 10}, included_elements); 35 for (const auto& element : included_elements) { 36 BOOST_CHECK(filter.Match(element)); 37 38 auto insertion = excluded_elements.insert(element); 39 BOOST_CHECK(filter.MatchAny(excluded_elements)); 40 excluded_elements.erase(insertion.first); 41 } 42 } 43 44 BOOST_AUTO_TEST_CASE(gcsfilter_default_constructor) 45 { 46 GCSFilter filter; 47 BOOST_CHECK_EQUAL(filter.GetN(), 0U); 48 BOOST_CHECK_EQUAL(filter.GetEncoded().size(), 1U); 49 50 const GCSFilter::Params& params = filter.GetParams(); 51 BOOST_CHECK_EQUAL(params.m_siphash_k0, 0U); 52 BOOST_CHECK_EQUAL(params.m_siphash_k1, 0U); 53 BOOST_CHECK_EQUAL(params.m_P, 0); 54 BOOST_CHECK_EQUAL(params.m_M, 1U); 55 } 56 57 BOOST_AUTO_TEST_CASE(blockfilter_basic_test) 58 { 59 CScript included_scripts[5], excluded_scripts[4]; 60 61 // First two are outputs on a single transaction. 62 included_scripts[0] << std::vector<unsigned char>(65, 0) << OP_CHECKSIG; 63 included_scripts[1] << OP_DUP << OP_HASH160 << std::vector<unsigned char>(20, 1) << OP_EQUALVERIFY << OP_CHECKSIG; 64 65 // Third is an output on in a second transaction. 66 included_scripts[2] << OP_1 << std::vector<unsigned char>(33, 2) << OP_1 << OP_CHECKMULTISIG; 67 68 // Last two are spent by a single transaction. 69 included_scripts[3] << OP_0 << std::vector<unsigned char>(32, 3); 70 included_scripts[4] << OP_4 << OP_ADD << OP_8 << OP_EQUAL; 71 72 // OP_RETURN output is an output on the second transaction. 73 excluded_scripts[0] << OP_RETURN << std::vector<unsigned char>(40, 4); 74 75 // This script is not related to the block at all. 76 excluded_scripts[1] << std::vector<unsigned char>(33, 5) << OP_CHECKSIG; 77 78 // OP_RETURN is non-standard since it's not followed by a data push, but is still excluded from 79 // filter. 80 excluded_scripts[2] << OP_RETURN << OP_4 << OP_ADD << OP_8 << OP_EQUAL; 81 82 CMutableTransaction tx_1; 83 tx_1.vout.emplace_back(100, included_scripts[0]); 84 tx_1.vout.emplace_back(200, included_scripts[1]); 85 tx_1.vout.emplace_back(0, excluded_scripts[0]); 86 87 CMutableTransaction tx_2; 88 tx_2.vout.emplace_back(300, included_scripts[2]); 89 tx_2.vout.emplace_back(0, excluded_scripts[2]); 90 tx_2.vout.emplace_back(400, excluded_scripts[3]); // Script is empty 91 92 CBlock block; 93 block.vtx.push_back(MakeTransactionRef(tx_1)); 94 block.vtx.push_back(MakeTransactionRef(tx_2)); 95 96 CBlockUndo block_undo; 97 block_undo.vtxundo.emplace_back(); 98 block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(500, included_scripts[3]), 1000, true); 99 block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(600, included_scripts[4]), 10000, false); 100 block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(700, excluded_scripts[3]), 100000, false); 101 102 BlockFilter block_filter(BlockFilterType::BASIC, block, block_undo); 103 const GCSFilter& filter = block_filter.GetFilter(); 104 105 for (const CScript& script : included_scripts) { 106 BOOST_CHECK(filter.Match(GCSFilter::Element(script.begin(), script.end()))); 107 } 108 for (const CScript& script : excluded_scripts) { 109 BOOST_CHECK(!filter.Match(GCSFilter::Element(script.begin(), script.end()))); 110 } 111 112 // Test serialization/unserialization. 113 BlockFilter block_filter2; 114 115 DataStream stream{}; 116 stream << block_filter; 117 stream >> block_filter2; 118 119 BOOST_CHECK_EQUAL(block_filter.GetFilterType(), block_filter2.GetFilterType()); 120 BOOST_CHECK_EQUAL(block_filter.GetBlockHash(), block_filter2.GetBlockHash()); 121 BOOST_CHECK(block_filter.GetEncodedFilter() == block_filter2.GetEncodedFilter()); 122 123 BlockFilter default_ctor_block_filter_1; 124 BlockFilter default_ctor_block_filter_2; 125 BOOST_CHECK_EQUAL(default_ctor_block_filter_1.GetFilterType(), default_ctor_block_filter_2.GetFilterType()); 126 BOOST_CHECK_EQUAL(default_ctor_block_filter_1.GetBlockHash(), default_ctor_block_filter_2.GetBlockHash()); 127 BOOST_CHECK(default_ctor_block_filter_1.GetEncodedFilter() == default_ctor_block_filter_2.GetEncodedFilter()); 128 } 129 130 BOOST_AUTO_TEST_CASE(blockfilters_json_test) 131 { 132 UniValue json; 133 if (!json.read(json_tests::blockfilters) || !json.isArray()) { 134 BOOST_ERROR("Parse error."); 135 return; 136 } 137 138 const UniValue& tests = json.get_array(); 139 for (unsigned int i = 0; i < tests.size(); i++) { 140 const UniValue& test = tests[i]; 141 std::string strTest = test.write(); 142 143 if (test.size() == 1) { 144 continue; 145 } else if (test.size() < 7) { 146 BOOST_ERROR("Bad test: " << strTest); 147 continue; 148 } 149 150 unsigned int pos = 0; 151 /*int block_height =*/ test[pos++].getInt<int>(); 152 BOOST_CHECK(uint256::FromHex(test[pos++].get_str())); 153 154 CBlock block; 155 BOOST_REQUIRE(DecodeHexBlk(block, test[pos++].get_str())); 156 157 CBlockUndo block_undo; 158 block_undo.vtxundo.emplace_back(); 159 CTxUndo& tx_undo = block_undo.vtxundo.back(); 160 const UniValue& prev_scripts = test[pos++].get_array(); 161 for (unsigned int ii = 0; ii < prev_scripts.size(); ii++) { 162 std::vector<unsigned char> raw_script = ParseHex(prev_scripts[ii].get_str()); 163 CTxOut txout(0, CScript(raw_script.begin(), raw_script.end())); 164 tx_undo.vprevout.emplace_back(txout, 0, false); 165 } 166 167 uint256 prev_filter_header_basic{*Assert(uint256::FromHex(test[pos++].get_str()))}; 168 std::vector<unsigned char> filter_basic = ParseHex(test[pos++].get_str()); 169 uint256 filter_header_basic{*Assert(uint256::FromHex(test[pos++].get_str()))}; 170 171 BlockFilter computed_filter_basic(BlockFilterType::BASIC, block, block_undo); 172 BOOST_CHECK(computed_filter_basic.GetFilter().GetEncoded() == filter_basic); 173 174 uint256 computed_header_basic = computed_filter_basic.ComputeHeader(prev_filter_header_basic); 175 BOOST_CHECK(computed_header_basic == filter_header_basic); 176 } 177 } 178 179 BOOST_AUTO_TEST_CASE(blockfilter_type_names) 180 { 181 BOOST_CHECK_EQUAL(BlockFilterTypeName(BlockFilterType::BASIC), "basic"); 182 BOOST_CHECK_EQUAL(BlockFilterTypeName(static_cast<BlockFilterType>(255)), ""); 183 184 BlockFilterType filter_type; 185 BOOST_CHECK(BlockFilterTypeByName("basic", filter_type)); 186 BOOST_CHECK_EQUAL(filter_type, BlockFilterType::BASIC); 187 188 BOOST_CHECK(!BlockFilterTypeByName("unknown", filter_type)); 189 } 190 191 BOOST_AUTO_TEST_SUITE_END()