Skip to content

Commit c1855f6

Browse files
Jim Posenjimpo
Jim Posen
authored andcommitted
blockfilter: Construction of basic block filters.
1 parent 53e7874 commit c1855f6

File tree

4 files changed

+129
-0
lines changed

4 files changed

+129
-0
lines changed

src/blockfilter.cpp

+40
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include <blockfilter.h>
66
#include <hash.h>
7+
#include <primitives/transaction.h>
8+
#include <script/script.h>
79
#include <streams.h>
810

911
/// SerType used to serialize parameters in GCS filter encoding.
@@ -193,3 +195,41 @@ bool GCSFilter::MatchAny(const ElementSet& elements) const
193195
const std::vector<uint64_t> queries = BuildHashedSet(elements);
194196
return MatchInternal(queries.data(), queries.size());
195197
}
198+
199+
static GCSFilter::ElementSet BasicFilterElements(const CBlock& block,
200+
const CBlockUndo& block_undo)
201+
{
202+
GCSFilter::ElementSet elements;
203+
204+
for (const CTransactionRef& tx : block.vtx) {
205+
for (const CTxOut& txout : tx->vout) {
206+
const CScript& script = txout.scriptPubKey;
207+
if (script[0] == OP_RETURN) continue;
208+
elements.emplace(script.begin(), script.end());
209+
}
210+
}
211+
212+
for (const CTxUndo& tx_undo : block_undo.vtxundo) {
213+
for (const Coin& prevout : tx_undo.vprevout) {
214+
const CScript& script = prevout.out.scriptPubKey;
215+
elements.emplace(script.begin(), script.end());
216+
}
217+
}
218+
219+
return elements;
220+
}
221+
222+
BlockFilter::BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo)
223+
: m_filter_type(filter_type), m_block_hash(block.GetHash())
224+
{
225+
switch (m_filter_type) {
226+
case BlockFilterType::BASIC:
227+
m_filter = GCSFilter(m_block_hash.GetUint64(0), m_block_hash.GetUint64(1),
228+
BASIC_FILTER_P, BASIC_FILTER_M,
229+
BasicFilterElements(block, block_undo));
230+
break;
231+
232+
default:
233+
throw std::invalid_argument("unknown filter_type");
234+
}
235+
}

src/blockfilter.h

+35
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
#include <stdint.h>
1010
#include <vector>
1111

12+
#include <primitives/block.h>
1213
#include <serialize.h>
1314
#include <uint256.h>
15+
#include <undo.h>
1416

1517
/**
1618
* This implements a Golomb-coded set as defined in BIP 158. It is a
@@ -71,4 +73,37 @@ class GCSFilter
7173
bool MatchAny(const ElementSet& elements) const;
7274
};
7375

76+
constexpr uint8_t BASIC_FILTER_P = 19;
77+
constexpr uint32_t BASIC_FILTER_M = 784931;
78+
79+
enum BlockFilterType : uint8_t
80+
{
81+
BASIC = 0,
82+
};
83+
84+
/**
85+
* Complete block filter struct as defined in BIP 157.
86+
*/
87+
class BlockFilter
88+
{
89+
private:
90+
BlockFilterType m_filter_type;
91+
uint256 m_block_hash;
92+
GCSFilter m_filter;
93+
94+
public:
95+
96+
// Construct a new BlockFilter of the specified type from a block.
97+
BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo);
98+
99+
BlockFilterType GetFilterType() const { return m_filter_type; }
100+
101+
const GCSFilter& GetFilter() const { return m_filter; }
102+
103+
const std::vector<unsigned char>& GetEncodedFilter() const
104+
{
105+
return m_filter.GetEncoded();
106+
}
107+
};
108+
74109
#endif // BITCOIN_BLOCKFILTER_H

src/test/blockfilter_tests.cpp

+53
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
// Distributed under the MIT software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

5+
#include <test/test_bitcoin.h>
6+
57
#include <blockfilter.h>
8+
#include <serialize.h>
9+
#include <streams.h>
610

711
#include <boost/test/unit_test.hpp>
812

@@ -31,4 +35,53 @@ BOOST_AUTO_TEST_CASE(gcsfilter_test)
3135
}
3236
}
3337

38+
BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
39+
{
40+
CScript included_scripts[5], excluded_scripts[2];
41+
42+
// First two are outputs on a single transaction.
43+
included_scripts[0] << std::vector<unsigned char>(0, 65) << OP_CHECKSIG;
44+
included_scripts[1] << OP_DUP << OP_HASH160 << std::vector<unsigned char>(1, 20) << OP_EQUALVERIFY << OP_CHECKSIG;
45+
46+
// Third is an output on in a second transaction.
47+
included_scripts[2] << OP_1 << std::vector<unsigned char>(2, 33) << OP_1 << OP_CHECKMULTISIG;
48+
49+
// Last two are spent by a single transaction.
50+
included_scripts[3] << OP_0 << std::vector<unsigned char>(3, 32);
51+
included_scripts[4] << OP_4 << OP_ADD << OP_8 << OP_EQUAL;
52+
53+
// OP_RETURN output is an output on the second transaction.
54+
excluded_scripts[0] << OP_RETURN << std::vector<unsigned char>(4, 40);
55+
56+
// This script is not related to the block at all.
57+
excluded_scripts[1] << std::vector<unsigned char>(5, 33) << OP_CHECKSIG;
58+
59+
CMutableTransaction tx_1;
60+
tx_1.vout.emplace_back(100, included_scripts[0]);
61+
tx_1.vout.emplace_back(200, included_scripts[1]);
62+
63+
CMutableTransaction tx_2;
64+
tx_2.vout.emplace_back(300, included_scripts[2]);
65+
tx_2.vout.emplace_back(0, excluded_scripts[0]);
66+
67+
CBlock block;
68+
block.vtx.push_back(MakeTransactionRef(tx_1));
69+
block.vtx.push_back(MakeTransactionRef(tx_2));
70+
71+
CBlockUndo block_undo;
72+
block_undo.vtxundo.emplace_back();
73+
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(400, included_scripts[3]), 1000, true);
74+
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(500, included_scripts[4]), 10000, false);
75+
76+
BlockFilter block_filter(BlockFilterType::BASIC, block, block_undo);
77+
const GCSFilter& filter = block_filter.GetFilter();
78+
79+
for (const CScript& script : included_scripts) {
80+
BOOST_CHECK(filter.Match(GCSFilter::Element(script.begin(), script.end())));
81+
}
82+
for (const CScript& script : excluded_scripts) {
83+
BOOST_CHECK(!filter.Match(GCSFilter::Element(script.begin(), script.end())));
84+
}
85+
}
86+
3487
BOOST_AUTO_TEST_SUITE_END()

src/undo.h

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#ifndef BITCOIN_UNDO_H
77
#define BITCOIN_UNDO_H
88

9+
#include <coins.h>
910
#include <compressor.h>
1011
#include <consensus/consensus.h>
1112
#include <primitives/transaction.h>

0 commit comments

Comments
 (0)