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