Skip to content

Commit 3bca6cd

Browse files
committed
test: add compact block filter (BIP158) helper routines
By now, we add one helper for calculating ranged hashes and another one for finding relevant scriptPubKeys given a block.
1 parent 25ee74d commit 3bca6cd

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2022 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Helper routines relevant for compact block filters (BIP158).
6+
"""
7+
from .siphash import siphash
8+
9+
10+
def bip158_basic_element_hash(script_pub_key, N, block_hash):
11+
""" Calculates the ranged hash of a filter element as defined in BIP158:
12+
13+
'The first step in the filter construction is hashing the variable-sized
14+
raw items in the set to the range [0, F), where F = N * M.'
15+
16+
'The items are first passed through the pseudorandom function SipHash, which takes a
17+
128-bit key k and a variable-sized byte vector and produces a uniformly random 64-bit
18+
output. Implementations of this BIP MUST use the SipHash parameters c = 2 and d = 4.'
19+
20+
'The parameter k MUST be set to the first 16 bytes of the hash (in standard
21+
little-endian representation) of the block for which the filter is constructed. This
22+
ensures the key is deterministic while still varying from block to block.'
23+
"""
24+
M = 784931
25+
block_hash_bytes = bytes.fromhex(block_hash)[::-1]
26+
k0 = int.from_bytes(block_hash_bytes[0:8], 'little')
27+
k1 = int.from_bytes(block_hash_bytes[8:16], 'little')
28+
return (siphash(k0, k1, script_pub_key) * (N * M)) >> 64
29+
30+
31+
def bip158_relevant_scriptpubkeys(node, block_hash):
32+
""" Determines the basic filter relvant scriptPubKeys as defined in BIP158:
33+
34+
'A basic filter MUST contain exactly the following items for each transaction in a block:
35+
- The previous output script (the script being spent) for each input, except for
36+
the coinbase transaction.
37+
- The scriptPubKey of each output, aside from all OP_RETURN output scripts.'
38+
"""
39+
spks = set()
40+
for tx in node.getblock(blockhash=block_hash, verbosity=3)['tx']:
41+
# gather prevout scripts
42+
for i in tx['vin']:
43+
if 'prevout' in i:
44+
spks.add(bytes.fromhex(i['prevout']['scriptPubKey']['hex']))
45+
# gather output scripts
46+
for o in tx['vout']:
47+
if o['scriptPubKey']['type'] != 'nulldata':
48+
spks.add(bytes.fromhex(o['scriptPubKey']['hex']))
49+
return spks

0 commit comments

Comments
 (0)