blockfilter_tests.cpp raw

   1  // Copyright (c) 2018-2022 The Limenka 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/setup_common.h>
   7  
   8  #include <addresstype.h>
   9  #include <blockfilter.h>
  10  #include <core_io.h>
  11  #include <primitives/block.h>
  12  #include <serialize.h>
  13  #include <streams.h>
  14  #include <undo.h>
  15  #include <univalue.h>
  16  #include <util/strencodings.h>
  17  
  18  #include <boost/test/unit_test.hpp>
  19  
  20  BOOST_AUTO_TEST_SUITE(blockfilter_tests)
  21  
  22  BOOST_AUTO_TEST_CASE(gcsfilter_test)
  23  {
  24      GCSFilter::ElementSet included_elements, excluded_elements;
  25      for (int i = 0; i < 100; ++i) {
  26          GCSFilter::Element element1(32);
  27          element1[0] = i;
  28          included_elements.insert(std::move(element1));
  29  
  30          GCSFilter::Element element2(32);
  31          element2[1] = i;
  32          excluded_elements.insert(std::move(element2));
  33      }
  34  
  35      GCSFilter filter({0, 0, 10, 1 << 10}, included_elements);
  36      for (const auto& element : included_elements) {
  37          BOOST_CHECK(filter.Match(element));
  38  
  39          auto insertion = excluded_elements.insert(element);
  40          BOOST_CHECK(filter.MatchAny(excluded_elements));
  41          excluded_elements.erase(insertion.first);
  42      }
  43  }
  44  
  45  BOOST_AUTO_TEST_CASE(gcsfilter_default_constructor)
  46  {
  47      GCSFilter filter;
  48      BOOST_CHECK_EQUAL(filter.GetN(), 0U);
  49      BOOST_CHECK_EQUAL(filter.GetEncoded().size(), 1U);
  50  
  51      const GCSFilter::Params& params = filter.GetParams();
  52      BOOST_CHECK_EQUAL(params.m_siphash_k0, 0U);
  53      BOOST_CHECK_EQUAL(params.m_siphash_k1, 0U);
  54      BOOST_CHECK_EQUAL(params.m_P, 0);
  55      BOOST_CHECK_EQUAL(params.m_M, 1U);
  56  }
  57  
  58  BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
  59  {
  60      CScript included_scripts[5], excluded_scripts[4];
  61  
  62      // First two are outputs on a single transaction.
  63      included_scripts[0] << std::vector<unsigned char>(0, 65) << OP_CHECKSIG;
  64      included_scripts[1] << OP_DUP << OP_HASH160 << std::vector<unsigned char>(1, 20) << OP_EQUALVERIFY << OP_CHECKSIG;
  65  
  66      // Third is an output on in a second transaction.
  67      included_scripts[2] << OP_1 << std::vector<unsigned char>(2, 33) << OP_1 << OP_CHECKMULTISIG;
  68  
  69      // Last two are spent by a single transaction.
  70      included_scripts[3] << OP_0 << std::vector<unsigned char>(3, 32);
  71      included_scripts[4] << OP_4 << OP_ADD << OP_8 << OP_EQUAL;
  72  
  73      // OP_RETURN output is an output on the second transaction.
  74      excluded_scripts[0] << OP_RETURN << std::vector<unsigned char>(4, 40);
  75  
  76      // This script is not related to the block at all.
  77      excluded_scripts[1] << std::vector<unsigned char>(5, 33) << OP_CHECKSIG;
  78  
  79      // OP_RETURN is non-standard since it's not followed by a data push, but is still excluded from
  80      // filter.
  81      excluded_scripts[2] << OP_RETURN << OP_4 << OP_ADD << OP_8 << OP_EQUAL;
  82  
  83      CMutableTransaction tx_1;
  84      tx_1.vout.emplace_back(100, included_scripts[0]);
  85      tx_1.vout.emplace_back(200, included_scripts[1]);
  86      tx_1.vout.emplace_back(0, excluded_scripts[0]);
  87  
  88      CMutableTransaction tx_2;
  89      tx_2.vout.emplace_back(300, included_scripts[2]);
  90      tx_2.vout.emplace_back(0, excluded_scripts[2]);
  91      tx_2.vout.emplace_back(400, excluded_scripts[3]); // Script is empty
  92  
  93      CBlock block;
  94      block.vtx.push_back(MakeTransactionRef(tx_1));
  95      block.vtx.push_back(MakeTransactionRef(tx_2));
  96  
  97      CBlockUndo block_undo;
  98      block_undo.vtxundo.emplace_back();
  99      block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(500, included_scripts[3]), 1000, true);
 100      block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(600, included_scripts[4]), 10000, false);
 101      block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(700, excluded_scripts[3]), 100000, false);
 102  
 103      BlockFilter block_filter(BlockFilterType::BASIC, block, block_undo);
 104      const GCSFilter& filter = block_filter.GetFilter();
 105  
 106      for (const CScript& script : included_scripts) {
 107          BOOST_CHECK(filter.Match(GCSFilter::Element(script.begin(), script.end())));
 108      }
 109      for (const CScript& script : excluded_scripts) {
 110          BOOST_CHECK(!filter.Match(GCSFilter::Element(script.begin(), script.end())));
 111      }
 112  
 113      // Test serialization/unserialization.
 114      BlockFilter block_filter2;
 115  
 116      DataStream stream{};
 117      stream << block_filter;
 118      stream >> block_filter2;
 119  
 120      BOOST_CHECK_EQUAL(block_filter.GetFilterType(), block_filter2.GetFilterType());
 121      BOOST_CHECK_EQUAL(block_filter.GetBlockHash(), block_filter2.GetBlockHash());
 122      BOOST_CHECK(block_filter.GetEncodedFilter() == block_filter2.GetEncodedFilter());
 123  
 124      BlockFilter default_ctor_block_filter_1;
 125      BlockFilter default_ctor_block_filter_2;
 126      BOOST_CHECK_EQUAL(default_ctor_block_filter_1.GetFilterType(), default_ctor_block_filter_2.GetFilterType());
 127      BOOST_CHECK_EQUAL(default_ctor_block_filter_1.GetBlockHash(), default_ctor_block_filter_2.GetBlockHash());
 128      BOOST_CHECK(default_ctor_block_filter_1.GetEncodedFilter() == default_ctor_block_filter_2.GetEncodedFilter());
 129  }
 130  
 131  BOOST_AUTO_TEST_CASE(blockfilter_v0_test)
 132  {
 133      CScript included_scripts[4], excluded_scripts[8];
 134  
 135      included_scripts[0] = GetScriptForDestination(WitnessV0KeyHash());  // p2wpkh
 136      included_scripts[1] = GetScriptForDestination(WitnessV0KeyHash()); // p2wpkh
 137      included_scripts[2] = GetScriptForDestination(WitnessV0ScriptHash()); // p2wsh
 138      included_scripts[3] = GetScriptForDestination(WitnessV0ScriptHash()); // p2wsh
 139  
 140      excluded_scripts[0] << std::vector<unsigned char>(0, 65) << OP_CHECKSIG; // p2pk
 141      excluded_scripts[1] << OP_0 << OP_HASH160 << std::vector<unsigned char>(1, 20) << OP_EQUALVERIFY << OP_CHECKSIG; // p2pkh
 142      excluded_scripts[2] << OP_1 << std::vector<unsigned char>(2, 33) << OP_1 << OP_CHECKMULTISIG; // multisig
 143      excluded_scripts[3] << OP_0 << std::vector<unsigned char>(3, 32); // push data
 144      excluded_scripts[4] << OP_4 << OP_ADD << OP_8 << OP_EQUAL; // random script
 145      excluded_scripts[5] << OP_RETURN << std::vector<unsigned char>(4, 40); // opreturn
 146      excluded_scripts[6] << OP_RETURN << OP_4 << OP_ADD << OP_8 << OP_EQUAL; // none standard opreturn
 147  
 148      CMutableTransaction tx_1;
 149      tx_1.vout.emplace_back(100, included_scripts[0]);
 150      tx_1.vout.emplace_back(100, included_scripts[2]);
 151      tx_1.vout.emplace_back(200, excluded_scripts[0]);
 152      tx_1.vout.emplace_back(300, excluded_scripts[1]);
 153      tx_1.vout.emplace_back(400, excluded_scripts[2]);
 154  
 155      CMutableTransaction tx_2;
 156      tx_2.vout.emplace_back(100, included_scripts[3]);
 157      tx_2.vout.emplace_back(100, excluded_scripts[3]);
 158      tx_2.vout.emplace_back(0, excluded_scripts[4]);
 159      tx_2.vout.emplace_back(400, excluded_scripts[7]); // Script is empty
 160  
 161      CBlock block;
 162      block.vtx.push_back(MakeTransactionRef(tx_1));
 163      block.vtx.push_back(MakeTransactionRef(tx_2));
 164  
 165      CBlockUndo block_undo;
 166      block_undo.vtxundo.emplace_back();
 167      block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(500, included_scripts[1]), 1000, true);
 168      block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(600, excluded_scripts[5]), 10000, false);
 169      block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(700, excluded_scripts[6]), 100000, false);
 170  
 171      BlockFilter block_filter(BlockFilterType::V0, block, block_undo);
 172      const GCSFilter& filter = block_filter.GetFilter();
 173  
 174      for (const CScript& script : included_scripts) {
 175          BOOST_CHECK(filter.Match(GCSFilter::Element(script.begin(), script.end())));
 176      }
 177      for (const CScript& script : excluded_scripts) {
 178          BOOST_CHECK(!filter.Match(GCSFilter::Element(script.begin(), script.end())));
 179      }
 180  
 181      // Test serialization/unserialization.
 182      BlockFilter block_filter2;
 183  
 184      DataStream stream;
 185      stream << block_filter;
 186      stream >> block_filter2;
 187  
 188      BOOST_CHECK_EQUAL(block_filter.GetFilterType(), block_filter2.GetFilterType());
 189      BOOST_CHECK_EQUAL(block_filter.GetBlockHash(), block_filter2.GetBlockHash());
 190      BOOST_CHECK(block_filter.GetEncodedFilter() == block_filter2.GetEncodedFilter());
 191  
 192      BlockFilter default_ctor_block_filter_1;
 193      BlockFilter default_ctor_block_filter_2;
 194      BOOST_CHECK_EQUAL(default_ctor_block_filter_1.GetFilterType(), default_ctor_block_filter_2.GetFilterType());
 195      BOOST_CHECK_EQUAL(default_ctor_block_filter_1.GetBlockHash(), default_ctor_block_filter_2.GetBlockHash());
 196      BOOST_CHECK(default_ctor_block_filter_1.GetEncodedFilter() == default_ctor_block_filter_2.GetEncodedFilter());
 197  }
 198  
 199  BOOST_AUTO_TEST_CASE(blockfilters_json_test)
 200  {
 201      UniValue json;
 202      if (!json.read(json_tests::blockfilters) || !json.isArray()) {
 203          BOOST_ERROR("Parse error.");
 204          return;
 205      }
 206  
 207      const UniValue& tests = json.get_array();
 208      for (unsigned int i = 0; i < tests.size(); i++) {
 209          const UniValue& test = tests[i];
 210          std::string strTest = test.write();
 211  
 212          if (test.size() == 1) {
 213              continue;
 214          } else if (test.size() < 7) {
 215              BOOST_ERROR("Bad test: " << strTest);
 216              continue;
 217          }
 218  
 219          unsigned int pos = 0;
 220          /*int block_height =*/ test[pos++].getInt<int>();
 221          BOOST_CHECK(uint256::FromHex(test[pos++].get_str()));
 222  
 223          CBlock block;
 224          BOOST_REQUIRE(DecodeHexBlk(block, test[pos++].get_str()));
 225  
 226          CBlockUndo block_undo;
 227          block_undo.vtxundo.emplace_back();
 228          CTxUndo& tx_undo = block_undo.vtxundo.back();
 229          const UniValue& prev_scripts = test[pos++].get_array();
 230          for (unsigned int ii = 0; ii < prev_scripts.size(); ii++) {
 231              std::vector<unsigned char> raw_script = ParseHex(prev_scripts[ii].get_str());
 232              CTxOut txout(0, CScript(raw_script.begin(), raw_script.end()));
 233              tx_undo.vprevout.emplace_back(txout, 0, false);
 234          }
 235  
 236          uint256 prev_filter_header_basic{*Assert(uint256::FromHex(test[pos++].get_str()))};
 237          std::vector<unsigned char> filter_basic = ParseHex(test[pos++].get_str());
 238          uint256 filter_header_basic{*Assert(uint256::FromHex(test[pos++].get_str()))};
 239  
 240          BlockFilter computed_filter_basic(BlockFilterType::BASIC, block, block_undo);
 241          BOOST_CHECK(computed_filter_basic.GetFilter().GetEncoded() == filter_basic);
 242  
 243          uint256 computed_header_basic = computed_filter_basic.ComputeHeader(prev_filter_header_basic);
 244          BOOST_CHECK(computed_header_basic == filter_header_basic);
 245      }
 246  }
 247  
 248  BOOST_AUTO_TEST_CASE(blockfilter_type_names)
 249  {
 250      BOOST_CHECK_EQUAL(BlockFilterTypeName(BlockFilterType::BASIC), "basic");
 251      BOOST_CHECK_EQUAL(BlockFilterTypeName(BlockFilterType::V0), "v0");
 252      BOOST_CHECK_EQUAL(BlockFilterTypeName(static_cast<BlockFilterType>(255)), "");
 253  
 254      BlockFilterType filter_type;
 255      BOOST_CHECK(BlockFilterTypeByName("basic", filter_type));
 256      BOOST_CHECK_EQUAL(filter_type, BlockFilterType::BASIC);
 257  
 258      BlockFilterType filter_type_v0;
 259      BOOST_CHECK(BlockFilterTypeByName("v0", filter_type_v0));
 260      BOOST_CHECK_EQUAL(filter_type_v0, BlockFilterType::V0);
 261  
 262      BOOST_CHECK(!BlockFilterTypeByName("unknown", filter_type));
 263  }
 264  
 265  BOOST_AUTO_TEST_SUITE_END()
 266