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