16
16
msg_filterclear ,
17
17
msg_filterload ,
18
18
msg_getdata ,
19
+ msg_mempool ,
20
+ msg_version ,
19
21
)
20
- from test_framework .mininode import P2PInterface
22
+ from test_framework .mininode import P2PInterface , mininode_lock
21
23
from test_framework .script import MAX_SCRIPT_ELEMENT_SIZE
22
24
from test_framework .test_framework import BitcoinTestFramework
23
25
24
26
25
- class FilterNode (P2PInterface ):
27
+ class P2PBloomFilter (P2PInterface ):
26
28
# This is a P2SH watch-only wallet
27
29
watch_script_pubkey = 'a914ffffffffffffffffffffffffffffffffffffffff87'
28
30
# The initial filter (n=10, fp=0.000001) with just the above scriptPubKey added
@@ -34,6 +36,11 @@ class FilterNode(P2PInterface):
34
36
nFlags = 1 ,
35
37
)
36
38
39
+ def __init__ (self ):
40
+ super ().__init__ ()
41
+ self ._tx_received = False
42
+ self ._merkleblock_received = False
43
+
37
44
def on_inv (self , message ):
38
45
want = msg_getdata ()
39
46
for i in message .inv :
@@ -46,10 +53,30 @@ def on_inv(self, message):
46
53
self .send_message (want )
47
54
48
55
def on_merkleblock (self , message ):
49
- self .merkleblock_received = True
56
+ self ._merkleblock_received = True
50
57
51
58
def on_tx (self , message ):
52
- self .tx_received = True
59
+ self ._tx_received = True
60
+
61
+ @property
62
+ def tx_received (self ):
63
+ with mininode_lock :
64
+ return self ._tx_received
65
+
66
+ @tx_received .setter
67
+ def tx_received (self , value ):
68
+ with mininode_lock :
69
+ self ._tx_received = value
70
+
71
+ @property
72
+ def merkleblock_received (self ):
73
+ with mininode_lock :
74
+ return self ._merkleblock_received
75
+
76
+ @merkleblock_received .setter
77
+ def merkleblock_received (self , value ):
78
+ with mininode_lock :
79
+ self ._merkleblock_received = value
53
80
54
81
55
82
class FilterTest (BitcoinTestFramework ):
@@ -64,95 +91,144 @@ def set_test_params(self):
64
91
def skip_test_if_missing_module (self ):
65
92
self .skip_if_no_wallet ()
66
93
67
- def test_size_limits (self , filter_node ):
94
+ def test_size_limits (self , filter_peer ):
68
95
self .log .info ('Check that too large filter is rejected' )
69
96
with self .nodes [0 ].assert_debug_log (['Misbehaving' ]):
70
- filter_node .send_and_ping (msg_filterload (data = b'\xbb ' * (MAX_BLOOM_FILTER_SIZE + 1 )))
97
+ filter_peer .send_and_ping (msg_filterload (data = b'\xbb ' * (MAX_BLOOM_FILTER_SIZE + 1 )))
71
98
72
99
self .log .info ('Check that max size filter is accepted' )
73
100
with self .nodes [0 ].assert_debug_log ([], unexpected_msgs = ['Misbehaving' ]):
74
- filter_node .send_and_ping (msg_filterload (data = b'\xbb ' * (MAX_BLOOM_FILTER_SIZE )))
75
- filter_node .send_and_ping (msg_filterclear ())
101
+ filter_peer .send_and_ping (msg_filterload (data = b'\xbb ' * (MAX_BLOOM_FILTER_SIZE )))
102
+ filter_peer .send_and_ping (msg_filterclear ())
76
103
77
104
self .log .info ('Check that filter with too many hash functions is rejected' )
78
105
with self .nodes [0 ].assert_debug_log (['Misbehaving' ]):
79
- filter_node .send_and_ping (msg_filterload (data = b'\xaa ' , nHashFuncs = MAX_BLOOM_HASH_FUNCS + 1 ))
106
+ filter_peer .send_and_ping (msg_filterload (data = b'\xaa ' , nHashFuncs = MAX_BLOOM_HASH_FUNCS + 1 ))
80
107
81
108
self .log .info ('Check that filter with max hash functions is accepted' )
82
109
with self .nodes [0 ].assert_debug_log ([], unexpected_msgs = ['Misbehaving' ]):
83
- filter_node .send_and_ping (msg_filterload (data = b'\xaa ' , nHashFuncs = MAX_BLOOM_HASH_FUNCS ))
110
+ filter_peer .send_and_ping (msg_filterload (data = b'\xaa ' , nHashFuncs = MAX_BLOOM_HASH_FUNCS ))
84
111
# Don't send filterclear until next two filteradd checks are done
85
112
86
113
self .log .info ('Check that max size data element to add to the filter is accepted' )
87
114
with self .nodes [0 ].assert_debug_log ([], unexpected_msgs = ['Misbehaving' ]):
88
- filter_node .send_and_ping (msg_filteradd (data = b'\xcc ' * (MAX_SCRIPT_ELEMENT_SIZE )))
115
+ filter_peer .send_and_ping (msg_filteradd (data = b'\xcc ' * (MAX_SCRIPT_ELEMENT_SIZE )))
89
116
90
117
self .log .info ('Check that too large data element to add to the filter is rejected' )
91
118
with self .nodes [0 ].assert_debug_log (['Misbehaving' ]):
92
- filter_node .send_and_ping (msg_filteradd (data = b'\xcc ' * (MAX_SCRIPT_ELEMENT_SIZE + 1 )))
119
+ filter_peer .send_and_ping (msg_filteradd (data = b'\xcc ' * (MAX_SCRIPT_ELEMENT_SIZE + 1 )))
93
120
94
- filter_node .send_and_ping (msg_filterclear ())
121
+ filter_peer .send_and_ping (msg_filterclear ())
95
122
96
- def run_test (self ):
97
- filter_node = self .nodes [0 ].add_p2p_connection (FilterNode ())
123
+ def test_msg_mempool (self ):
124
+ self .log .info ("Check that a node with bloom filters enabled services p2p mempool messages" )
125
+ filter_peer = P2PBloomFilter ()
98
126
99
- self .test_size_limits (filter_node )
127
+ self .log .info ("Create a tx relevant to the peer before connecting" )
128
+ filter_address = self .nodes [0 ].decodescript (filter_peer .watch_script_pubkey )['addresses' ][0 ]
129
+ txid = self .nodes [0 ].sendtoaddress (filter_address , 90 )
100
130
101
- self .log .info ('Add filtered P2P connection to the node' )
102
- filter_node .send_and_ping (filter_node .watch_filter_init )
103
- filter_address = self .nodes [0 ].decodescript (filter_node .watch_script_pubkey )['addresses' ][0 ]
131
+ self .log .info ("Send a mempool msg after connecting and check that the tx is received" )
132
+ self .nodes [0 ].add_p2p_connection (filter_peer )
133
+ filter_peer .send_and_ping (filter_peer .watch_filter_init )
134
+ self .nodes [0 ].p2p .send_message (msg_mempool ())
135
+ filter_peer .wait_for_tx (txid )
136
+
137
+ def test_frelay_false (self , filter_peer ):
138
+ self .log .info ("Check that a node with fRelay set to false does not receive invs until the filter is set" )
139
+ filter_peer .tx_received = False
140
+ filter_address = self .nodes [0 ].decodescript (filter_peer .watch_script_pubkey )['addresses' ][0 ]
141
+ self .nodes [0 ].sendtoaddress (filter_address , 90 )
142
+ # Sync to make sure the reason filter_peer doesn't receive the tx is not p2p delays
143
+ filter_peer .sync_with_ping ()
144
+ assert not filter_peer .tx_received
145
+
146
+ # Clear the mempool so that this transaction does not impact subsequent tests
147
+ self .nodes [0 ].generate (1 )
148
+
149
+ def test_filter (self , filter_peer ):
150
+ # Set the bloomfilter using filterload
151
+ filter_peer .send_and_ping (filter_peer .watch_filter_init )
152
+ # If fRelay is not already True, sending filterload sets it to True
153
+ assert self .nodes [0 ].getpeerinfo ()[0 ]['relaytxes' ]
154
+ filter_address = self .nodes [0 ].decodescript (filter_peer .watch_script_pubkey )['addresses' ][0 ]
104
155
105
156
self .log .info ('Check that we receive merkleblock and tx if the filter matches a tx in a block' )
106
157
block_hash = self .nodes [0 ].generatetoaddress (1 , filter_address )[0 ]
107
158
txid = self .nodes [0 ].getblock (block_hash )['tx' ][0 ]
108
- filter_node .wait_for_merkleblock (block_hash )
109
- filter_node .wait_for_tx (txid )
159
+ filter_peer .wait_for_merkleblock (block_hash )
160
+ filter_peer .wait_for_tx (txid )
110
161
111
162
self .log .info ('Check that we only receive a merkleblock if the filter does not match a tx in a block' )
112
- filter_node .tx_received = False
163
+ filter_peer .tx_received = False
113
164
block_hash = self .nodes [0 ].generatetoaddress (1 , self .nodes [0 ].getnewaddress ())[0 ]
114
- filter_node .wait_for_merkleblock (block_hash )
115
- assert not filter_node .tx_received
165
+ filter_peer .wait_for_merkleblock (block_hash )
166
+ assert not filter_peer .tx_received
116
167
117
168
self .log .info ('Check that we not receive a tx if the filter does not match a mempool tx' )
118
- filter_node .merkleblock_received = False
119
- filter_node .tx_received = False
169
+ filter_peer .merkleblock_received = False
170
+ filter_peer .tx_received = False
120
171
self .nodes [0 ].sendtoaddress (self .nodes [0 ].getnewaddress (), 90 )
121
- filter_node .sync_with_ping ()
122
- filter_node .sync_with_ping ()
123
- assert not filter_node .merkleblock_received
124
- assert not filter_node .tx_received
172
+ filter_peer .sync_with_ping ()
173
+ filter_peer .sync_with_ping ()
174
+ assert not filter_peer .merkleblock_received
175
+ assert not filter_peer .tx_received
125
176
126
- self .log .info ('Check that we receive a tx in reply to a mempool msg if the filter matches a mempool tx' )
127
- filter_node .merkleblock_received = False
177
+ self .log .info ('Check that we receive a tx if the filter matches a mempool tx' )
178
+ filter_peer .merkleblock_received = False
128
179
txid = self .nodes [0 ].sendtoaddress (filter_address , 90 )
129
- filter_node .wait_for_tx (txid )
130
- assert not filter_node .merkleblock_received
180
+ filter_peer .wait_for_tx (txid )
181
+ assert not filter_peer .merkleblock_received
131
182
132
183
self .log .info ('Check that after deleting filter all txs get relayed again' )
133
- filter_node .send_and_ping (msg_filterclear ())
184
+ filter_peer .send_and_ping (msg_filterclear ())
134
185
for _ in range (5 ):
135
186
txid = self .nodes [0 ].sendtoaddress (self .nodes [0 ].getnewaddress (), 7 )
136
- filter_node .wait_for_tx (txid )
187
+ filter_peer .wait_for_tx (txid )
137
188
138
189
self .log .info ('Check that request for filtered blocks is ignored if no filter is set' )
139
- filter_node .merkleblock_received = False
140
- filter_node .tx_received = False
190
+ filter_peer .merkleblock_received = False
191
+ filter_peer .tx_received = False
141
192
with self .nodes [0 ].assert_debug_log (expected_msgs = ['received getdata' ]):
142
193
block_hash = self .nodes [0 ].generatetoaddress (1 , self .nodes [0 ].getnewaddress ())[0 ]
143
- filter_node .wait_for_inv ([CInv (MSG_BLOCK , int (block_hash , 16 ))])
144
- filter_node .sync_with_ping ()
145
- assert not filter_node .merkleblock_received
146
- assert not filter_node .tx_received
194
+ filter_peer .wait_for_inv ([CInv (MSG_BLOCK , int (block_hash , 16 ))])
195
+ filter_peer .sync_with_ping ()
196
+ assert not filter_peer .merkleblock_received
197
+ assert not filter_peer .tx_received
147
198
148
199
self .log .info ('Check that sending "filteradd" if no filter is set is treated as misbehavior' )
149
200
with self .nodes [0 ].assert_debug_log (['Misbehaving' ]):
150
- filter_node .send_and_ping (msg_filteradd (data = b'letsmisbehave' ))
201
+ filter_peer .send_and_ping (msg_filteradd (data = b'letsmisbehave' ))
151
202
152
203
self .log .info ("Check that division-by-zero remote crash bug [CVE-2013-5700] is fixed" )
153
- filter_node .send_and_ping (msg_filterload (data = b'' , nHashFuncs = 1 ))
154
- filter_node .send_and_ping (msg_filteradd (data = b'letstrytocrashthisnode' ))
204
+ filter_peer .send_and_ping (msg_filterload (data = b'' , nHashFuncs = 1 ))
205
+ filter_peer .send_and_ping (msg_filteradd (data = b'letstrytocrashthisnode' ))
206
+ self .nodes [0 ].disconnect_p2ps ()
155
207
208
+ def run_test (self ):
209
+ filter_peer = self .nodes [0 ].add_p2p_connection (P2PBloomFilter ())
210
+ self .log .info ('Test filter size limits' )
211
+ self .test_size_limits (filter_peer )
212
+
213
+ self .log .info ('Test BIP 37 for a node with fRelay = True (default)' )
214
+ self .test_filter (filter_peer )
215
+ self .nodes [0 ].disconnect_p2ps ()
216
+
217
+ self .log .info ('Test BIP 37 for a node with fRelay = False' )
218
+ # Add peer but do not send version yet
219
+ filter_peer_without_nrelay = self .nodes [0 ].add_p2p_connection (P2PBloomFilter (), send_version = False , wait_for_verack = False )
220
+ # Send version with fRelay=False
221
+ filter_peer_without_nrelay .wait_until (lambda : filter_peer_without_nrelay .is_connected , timeout = 10 )
222
+ version_without_fRelay = msg_version ()
223
+ version_without_fRelay .nRelay = 0
224
+ filter_peer_without_nrelay .send_message (version_without_fRelay )
225
+ filter_peer_without_nrelay .wait_for_verack ()
226
+ assert not self .nodes [0 ].getpeerinfo ()[0 ]['relaytxes' ]
227
+ self .test_frelay_false (filter_peer_without_nrelay )
228
+ self .test_filter (filter_peer_without_nrelay )
229
+
230
+ self .log .info ('Test msg_mempool' )
231
+ self .test_msg_mempool ()
156
232
157
233
if __name__ == '__main__' :
158
234
FilterTest ().main ()
0 commit comments