blockfilter_tests.cpp raw

   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()
 192