Changeset View
Changeset View
Standalone View
Standalone View
test/functional/p2p_blockfilters.py
Show First 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
self.generate(self.nodes[0], 999, sync_fun=self.no_op) | self.generate(self.nodes[0], 999, sync_fun=self.no_op) | ||||
# Sync the blocks. Since they are numerous, bump the timeout so it | # Sync the blocks. Since they are numerous, bump the timeout so it | ||||
# doesn't fail on slow machines. | # doesn't fail on slow machines. | ||||
self.sync_blocks(timeout=360) | self.sync_blocks(timeout=360) | ||||
# Stale blocks by disconnecting nodes 0 & 1, mining, then reconnecting | # Stale blocks by disconnecting nodes 0 & 1, mining, then reconnecting | ||||
self.disconnect_nodes(0, 1) | self.disconnect_nodes(0, 1) | ||||
stale_block_hash = self.generate( | stale_block_hash = self.generate(self.nodes[0], 1, sync_fun=self.no_op)[0] | ||||
self.nodes[0], 1, sync_fun=self.no_op)[0] | |||||
self.nodes[0].syncwithvalidationinterfacequeue() | self.nodes[0].syncwithvalidationinterfacequeue() | ||||
assert_equal(self.nodes[0].getblockcount(), 1000) | assert_equal(self.nodes[0].getblockcount(), 1000) | ||||
self.generate(self.nodes[1], 1001, sync_fun=self.no_op) | self.generate(self.nodes[1], 1001, sync_fun=self.no_op) | ||||
assert_equal(self.nodes[1].getblockcount(), 2000) | assert_equal(self.nodes[1].getblockcount(), 2000) | ||||
# Check that nodes have signalled NODE_COMPACT_FILTERS correctly. | # Check that nodes have signalled NODE_COMPACT_FILTERS correctly. | ||||
assert peer_0.nServices & NODE_COMPACT_FILTERS != 0 | assert peer_0.nServices & NODE_COMPACT_FILTERS != 0 | ||||
assert peer_1.nServices & NODE_COMPACT_FILTERS == 0 | assert peer_1.nServices & NODE_COMPACT_FILTERS == 0 | ||||
# Check that the localservices is as expected. | # Check that the localservices is as expected. | ||||
assert int( | assert ( | ||||
self.nodes[0].getnetworkinfo()['localservices'], | int(self.nodes[0].getnetworkinfo()["localservices"], 16) | ||||
16) & NODE_COMPACT_FILTERS != 0 | & NODE_COMPACT_FILTERS | ||||
assert int( | != 0 | ||||
self.nodes[1].getnetworkinfo()['localservices'], | ) | ||||
16) & NODE_COMPACT_FILTERS == 0 | assert ( | ||||
int(self.nodes[1].getnetworkinfo()["localservices"], 16) | |||||
& NODE_COMPACT_FILTERS | |||||
== 0 | |||||
) | |||||
self.log.info("get cfcheckpt on chain to be re-orged out.") | self.log.info("get cfcheckpt on chain to be re-orged out.") | ||||
request = msg_getcfcheckpt( | request = msg_getcfcheckpt( | ||||
filter_type=FILTER_TYPE_BASIC, | filter_type=FILTER_TYPE_BASIC, | ||||
stop_hash=int(stale_block_hash, 16), | stop_hash=int(stale_block_hash, 16), | ||||
) | ) | ||||
peer_0.send_and_ping(message=request) | peer_0.send_and_ping(message=request) | ||||
response = peer_0.last_message['cfcheckpt'] | response = peer_0.last_message["cfcheckpt"] | ||||
assert_equal(response.filter_type, request.filter_type) | assert_equal(response.filter_type, request.filter_type) | ||||
assert_equal(response.stop_hash, request.stop_hash) | assert_equal(response.stop_hash, request.stop_hash) | ||||
assert_equal(len(response.headers), 1) | assert_equal(len(response.headers), 1) | ||||
self.log.info("Reorg node 0 to a new chain.") | self.log.info("Reorg node 0 to a new chain.") | ||||
self.connect_nodes(0, 1) | self.connect_nodes(0, 1) | ||||
self.sync_blocks(timeout=600) | self.sync_blocks(timeout=600) | ||||
self.nodes[0].syncwithvalidationinterfacequeue() | self.nodes[0].syncwithvalidationinterfacequeue() | ||||
main_block_hash = self.nodes[0].getblockhash(1000) | main_block_hash = self.nodes[0].getblockhash(1000) | ||||
assert main_block_hash != stale_block_hash, "node 0 chain did not reorganize" | assert main_block_hash != stale_block_hash, "node 0 chain did not reorganize" | ||||
self.log.info("Check that peers can fetch cfcheckpt on active chain.") | self.log.info("Check that peers can fetch cfcheckpt on active chain.") | ||||
tip_hash = self.nodes[0].getbestblockhash() | tip_hash = self.nodes[0].getbestblockhash() | ||||
request = msg_getcfcheckpt( | request = msg_getcfcheckpt( | ||||
filter_type=FILTER_TYPE_BASIC, | filter_type=FILTER_TYPE_BASIC, | ||||
stop_hash=int(tip_hash, 16), | stop_hash=int(tip_hash, 16), | ||||
) | ) | ||||
peer_0.send_and_ping(request) | peer_0.send_and_ping(request) | ||||
response = peer_0.last_message['cfcheckpt'] | response = peer_0.last_message["cfcheckpt"] | ||||
assert_equal(response.filter_type, request.filter_type) | assert_equal(response.filter_type, request.filter_type) | ||||
assert_equal(response.stop_hash, request.stop_hash) | assert_equal(response.stop_hash, request.stop_hash) | ||||
main_cfcheckpt = self.nodes[0].getblockfilter( | main_cfcheckpt = self.nodes[0].getblockfilter(main_block_hash, "basic")[ | ||||
main_block_hash, 'basic')['header'] | "header" | ||||
tip_cfcheckpt = self.nodes[0].getblockfilter(tip_hash, 'basic')[ | ] | ||||
'header'] | tip_cfcheckpt = self.nodes[0].getblockfilter(tip_hash, "basic")["header"] | ||||
assert_equal( | assert_equal( | ||||
response.headers, | response.headers, | ||||
[int(header, 16) for header in (main_cfcheckpt, tip_cfcheckpt)], | [int(header, 16) for header in (main_cfcheckpt, tip_cfcheckpt)], | ||||
) | ) | ||||
self.log.info("Check that peers can fetch cfcheckpt on stale chain.") | self.log.info("Check that peers can fetch cfcheckpt on stale chain.") | ||||
request = msg_getcfcheckpt( | request = msg_getcfcheckpt( | ||||
filter_type=FILTER_TYPE_BASIC, | filter_type=FILTER_TYPE_BASIC, | ||||
stop_hash=int(stale_block_hash, 16), | stop_hash=int(stale_block_hash, 16), | ||||
) | ) | ||||
peer_0.send_and_ping(request) | peer_0.send_and_ping(request) | ||||
response = peer_0.last_message['cfcheckpt'] | response = peer_0.last_message["cfcheckpt"] | ||||
stale_cfcheckpt = self.nodes[0].getblockfilter( | stale_cfcheckpt = self.nodes[0].getblockfilter(stale_block_hash, "basic")[ | ||||
stale_block_hash, 'basic')['header'] | "header" | ||||
] | |||||
assert_equal( | assert_equal( | ||||
response.headers, | response.headers, | ||||
[int(header, 16) for header in (stale_cfcheckpt, )], | [int(header, 16) for header in (stale_cfcheckpt,)], | ||||
) | ) | ||||
self.log.info("Check that peers can fetch cfheaders on active chain.") | self.log.info("Check that peers can fetch cfheaders on active chain.") | ||||
request = msg_getcfheaders( | request = msg_getcfheaders( | ||||
filter_type=FILTER_TYPE_BASIC, | filter_type=FILTER_TYPE_BASIC, | ||||
start_height=1, | start_height=1, | ||||
stop_hash=int(main_block_hash, 16), | stop_hash=int(main_block_hash, 16), | ||||
) | ) | ||||
peer_0.send_and_ping(request) | peer_0.send_and_ping(request) | ||||
response = peer_0.last_message['cfheaders'] | response = peer_0.last_message["cfheaders"] | ||||
main_cfhashes = response.hashes | main_cfhashes = response.hashes | ||||
assert_equal(len(main_cfhashes), 1000) | assert_equal(len(main_cfhashes), 1000) | ||||
assert_equal( | assert_equal( | ||||
compute_last_header(response.prev_header, response.hashes), | compute_last_header(response.prev_header, response.hashes), | ||||
int(main_cfcheckpt, 16), | int(main_cfcheckpt, 16), | ||||
) | ) | ||||
self.log.info("Check that peers can fetch cfheaders on stale chain.") | self.log.info("Check that peers can fetch cfheaders on stale chain.") | ||||
request = msg_getcfheaders( | request = msg_getcfheaders( | ||||
filter_type=FILTER_TYPE_BASIC, | filter_type=FILTER_TYPE_BASIC, | ||||
start_height=1, | start_height=1, | ||||
stop_hash=int(stale_block_hash, 16), | stop_hash=int(stale_block_hash, 16), | ||||
) | ) | ||||
peer_0.send_and_ping(request) | peer_0.send_and_ping(request) | ||||
response = peer_0.last_message['cfheaders'] | response = peer_0.last_message["cfheaders"] | ||||
stale_cfhashes = response.hashes | stale_cfhashes = response.hashes | ||||
assert_equal(len(stale_cfhashes), 1000) | assert_equal(len(stale_cfhashes), 1000) | ||||
assert_equal( | assert_equal( | ||||
compute_last_header(response.prev_header, response.hashes), | compute_last_header(response.prev_header, response.hashes), | ||||
int(stale_cfcheckpt, 16), | int(stale_cfcheckpt, 16), | ||||
) | ) | ||||
self.log.info("Check that peers can fetch cfilters.") | self.log.info("Check that peers can fetch cfilters.") | ||||
stop_hash = self.nodes[0].getblockhash(10) | stop_hash = self.nodes[0].getblockhash(10) | ||||
request = msg_getcfilters( | request = msg_getcfilters( | ||||
filter_type=FILTER_TYPE_BASIC, | filter_type=FILTER_TYPE_BASIC, | ||||
start_height=1, | start_height=1, | ||||
stop_hash=int(stop_hash, 16), | stop_hash=int(stop_hash, 16), | ||||
) | ) | ||||
peer_0.send_and_ping(request) | peer_0.send_and_ping(request) | ||||
response = peer_0.pop_cfilters() | response = peer_0.pop_cfilters() | ||||
assert_equal(len(response), 10) | assert_equal(len(response), 10) | ||||
self.log.info("Check that cfilter responses are correct.") | self.log.info("Check that cfilter responses are correct.") | ||||
for cfilter, cfhash, height in zip( | for cfilter, cfhash, height in zip(response, main_cfhashes, range(1, 11)): | ||||
response, main_cfhashes, range(1, 11)): | |||||
block_hash = self.nodes[0].getblockhash(height) | block_hash = self.nodes[0].getblockhash(height) | ||||
assert_equal(cfilter.filter_type, FILTER_TYPE_BASIC) | assert_equal(cfilter.filter_type, FILTER_TYPE_BASIC) | ||||
assert_equal(cfilter.block_hash, int(block_hash, 16)) | assert_equal(cfilter.block_hash, int(block_hash, 16)) | ||||
computed_cfhash = uint256_from_str(hash256(cfilter.filter_data)) | computed_cfhash = uint256_from_str(hash256(cfilter.filter_data)) | ||||
assert_equal(computed_cfhash, cfhash) | assert_equal(computed_cfhash, cfhash) | ||||
self.log.info("Check that peers can fetch cfilters for stale blocks.") | self.log.info("Check that peers can fetch cfilters for stale blocks.") | ||||
request = msg_getcfilters( | request = msg_getcfilters( | ||||
filter_type=FILTER_TYPE_BASIC, | filter_type=FILTER_TYPE_BASIC, | ||||
start_height=1000, | start_height=1000, | ||||
stop_hash=int(stale_block_hash, 16), | stop_hash=int(stale_block_hash, 16), | ||||
) | ) | ||||
peer_0.send_and_ping(request) | peer_0.send_and_ping(request) | ||||
response = peer_0.pop_cfilters() | response = peer_0.pop_cfilters() | ||||
assert_equal(len(response), 1) | assert_equal(len(response), 1) | ||||
cfilter = response[0] | cfilter = response[0] | ||||
assert_equal(cfilter.filter_type, FILTER_TYPE_BASIC) | assert_equal(cfilter.filter_type, FILTER_TYPE_BASIC) | ||||
assert_equal(cfilter.block_hash, int(stale_block_hash, 16)) | assert_equal(cfilter.block_hash, int(stale_block_hash, 16)) | ||||
computed_cfhash = uint256_from_str(hash256(cfilter.filter_data)) | computed_cfhash = uint256_from_str(hash256(cfilter.filter_data)) | ||||
assert_equal(computed_cfhash, stale_cfhashes[999]) | assert_equal(computed_cfhash, stale_cfhashes[999]) | ||||
self.log.info( | self.log.info( | ||||
"Requests to node 1 without NODE_COMPACT_FILTERS results in disconnection.") | "Requests to node 1 without NODE_COMPACT_FILTERS results in disconnection." | ||||
) | |||||
requests = [ | requests = [ | ||||
msg_getcfcheckpt( | msg_getcfcheckpt( | ||||
filter_type=FILTER_TYPE_BASIC, | filter_type=FILTER_TYPE_BASIC, | ||||
stop_hash=int(main_block_hash, 16), | stop_hash=int(main_block_hash, 16), | ||||
), | ), | ||||
msg_getcfheaders( | msg_getcfheaders( | ||||
filter_type=FILTER_TYPE_BASIC, | filter_type=FILTER_TYPE_BASIC, | ||||
start_height=1000, | start_height=1000, | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
def compute_last_header(prev_header, hashes): | def compute_last_header(prev_header, hashes): | ||||
"""Compute the last filter header from a starting header and a sequence of filter hashes.""" | """Compute the last filter header from a starting header and a sequence of filter hashes.""" | ||||
header = ser_uint256(prev_header) | header = ser_uint256(prev_header) | ||||
for filter_hash in hashes: | for filter_hash in hashes: | ||||
header = hash256(ser_uint256(filter_hash) + header) | header = hash256(ser_uint256(filter_hash) + header) | ||||
return uint256_from_str(header) | return uint256_from_str(header) | ||||
if __name__ == '__main__': | if __name__ == "__main__": | ||||
CompactFiltersTest().main() | CompactFiltersTest().main() |