Changeset View
Changeset View
Standalone View
Standalone View
test/functional/node_network_limited.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2017 The Bitcoin Core developers | # Copyright (c) 2017 The Bitcoin Core developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
"""Tests NODE_NETWORK_LIMITED. | |||||
Tests that a node configured with -prune=550 signals NODE_NETWORK_LIMITED correctly | |||||
and that it responds to getdata requests for blocks correctly: | |||||
- send a block within 288 + 2 of the tip | |||||
- disconnect peers who request blocks older than that.""" | |||||
from test_framework.messages import CInv, msg_getdata | from test_framework.messages import CInv, msg_getdata | ||||
from test_framework.mininode import NODE_BLOOM, NODE_NETWORK_LIMITED, NODE_BITCOIN_CASH, NetworkThread, P2PInterface | from test_framework.mininode import NODE_BLOOM, NODE_NETWORK_LIMITED, NODE_BITCOIN_CASH, NetworkThread, P2PInterface | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.util import assert_equal | from test_framework.util import assert_equal | ||||
class P2PIgnoreInv(P2PInterface): | class P2PIgnoreInv(P2PInterface): | ||||
def on_inv(self, message): | def on_inv(self, message): | ||||
# The node will send us invs for other blocks. Ignore them. | # The node will send us invs for other blocks. Ignore them. | ||||
pass | pass | ||||
def send_getdata_for_block(self, blockhash): | |||||
getdata_request = msg_getdata() | |||||
getdata_request.inv.append(CInv(2, int(blockhash, 16))) | |||||
self.send_message(getdata_request) | |||||
class NodeNetworkLimitedTest(BitcoinTestFramework): | class NodeNetworkLimitedTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.setup_clean_chain = True | self.setup_clean_chain = True | ||||
self.num_nodes = 1 | self.num_nodes = 1 | ||||
self.extra_args = [['-prune=550']] | self.extra_args = [['-prune=550']] | ||||
def get_signalled_service_flags(self): | def run_test(self): | ||||
node = self.nodes[0].add_p2p_connection(P2PIgnoreInv()) | |||||
NetworkThread().start() | |||||
node.wait_for_verack() | |||||
services = node.nServices | |||||
self.nodes[0].disconnect_p2ps() | |||||
node.wait_for_disconnect() | |||||
return services | |||||
def try_get_block_via_getdata(self, blockhash, must_disconnect): | |||||
node = self.nodes[0].add_p2p_connection(P2PIgnoreInv()) | node = self.nodes[0].add_p2p_connection(P2PIgnoreInv()) | ||||
NetworkThread().start() | NetworkThread().start() | ||||
node.wait_for_verack() | node.wait_for_verack() | ||||
getdata_request = msg_getdata() | |||||
getdata_request.inv.append(CInv(2, int(blockhash, 16))) | |||||
node.send_message(getdata_request) | |||||
if (must_disconnect): | expected_services = NODE_BLOOM | NODE_BITCOIN_CASH | NODE_NETWORK_LIMITED | ||||
# Ensure we get disconnected | |||||
node.wait_for_disconnect(5) | |||||
else: | |||||
# check if the peer sends us the requested block | |||||
node.wait_for_block(int(blockhash, 16), 3) | |||||
self.nodes[0].disconnect_p2ps() | |||||
node.wait_for_disconnect() | |||||
def run_test(self): | self.log.info("Check that node has signalled expected services.") | ||||
# NODE_BLOOM & NODE_BITCOIN_CASH & NODE_NETWORK_LIMITED must now be signaled | assert_equal(node.nServices, expected_services) | ||||
assert_equal(self.get_signalled_service_flags(), | |||||
NODE_BLOOM | NODE_BITCOIN_CASH | NODE_NETWORK_LIMITED) | |||||
# Test the RPC service flags | self.log.info("Check that the localservices is as expected.") | ||||
assert_equal(int(self.nodes[0].getnetworkinfo()[ | assert_equal(int(self.nodes[0].getnetworkinfo()[ | ||||
'localservices'], 16), NODE_BLOOM | NODE_BITCOIN_CASH | NODE_NETWORK_LIMITED) | 'localservices'], 16), expected_services) | ||||
# Now mine some blocks over the NODE_NETWORK_LIMITED + 2(racy buffer ext.) target | self.log.info( | ||||
"Mine enough blocks to reach the NODE_NETWORK_LIMITED range.") | |||||
blocks = self.nodes[0].generate(292) | blocks = self.nodes[0].generate(292) | ||||
# Make sure we can max retrive block at tip-288 | self.log.info("Make sure we can max retrive block at tip-288.") | ||||
# requesting block at height 2 (tip-289) must fail (ignored) | |||||
# last block in valid range | # last block in valid range | ||||
self.try_get_block_via_getdata(blocks[1], False) | node.send_getdata_for_block(blocks[1]) | ||||
node.wait_for_block(int(blocks[1], 16), timeout=3) | |||||
self.log.info( | |||||
"Requesting block at height 2 (tip-289) must fail (ignored).") | |||||
# first block outside of the 288+2 limit | # first block outside of the 288+2 limit | ||||
self.try_get_block_via_getdata(blocks[0], True) | node.send_getdata_for_block(blocks[0]) | ||||
node.wait_for_disconnect(5) | |||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
NodeNetworkLimitedTest().main() | NodeNetworkLimitedTest().main() |