2017-12-09 08:34:31 +01:00
#!/usr/bin/env python3
2020-12-31 18:50:11 +01:00
# Copyright (c) 2017-2020 The Bitcoin Core developers
2017-12-09 08:34:31 +01:00
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-12-19 21:16:26 +01:00
""" 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 . """
2023-10-11 07:20:31 +02:00
from test_framework . messages import CInv , MSG_BLOCK , msg_getdata , NODE_BLOOM , NODE_NETWORK_LIMITED , NODE_HEADERS_COMPRESSED
2020-08-27 08:21:53 +02:00
from test_framework . p2p import P2PInterface
2017-12-09 08:34:31 +01:00
from test_framework . test_framework import BitcoinTestFramework
2020-08-27 08:21:53 +02:00
from test_framework . util import assert_equal
2017-12-09 08:34:31 +01:00
2020-04-07 01:15:22 +02:00
class P2PIgnoreInv ( P2PInterface ) :
2020-04-19 15:21:47 +02:00
firstAddrnServices = 0
2017-12-19 21:16:26 +01:00
def on_inv ( self , message ) :
# The node will send us invs for other blocks. Ignore them.
pass
2020-04-19 15:21:47 +02:00
def on_addr ( self , message ) :
self . firstAddrnServices = message . addrs [ 0 ] . nServices
def wait_for_addr ( self , timeout = 5 ) :
test_function = lambda : self . last_message . get ( " addr " )
2020-08-27 08:21:53 +02:00
self . wait_until ( test_function , timeout = timeout )
2017-12-19 21:16:26 +01:00
def send_getdata_for_block ( self , blockhash ) :
getdata_request = msg_getdata ( )
2022-09-20 09:52:32 +02:00
getdata_request . inv . append ( CInv ( MSG_BLOCK , int ( blockhash , 16 ) ) )
2017-12-19 21:16:26 +01:00
self . send_message ( getdata_request )
2017-12-09 08:34:31 +01:00
class NodeNetworkLimitedTest ( BitcoinTestFramework ) :
def set_test_params ( self ) :
self . setup_clean_chain = True
2020-04-19 15:21:47 +02:00
self . num_nodes = 3
2023-10-11 07:20:31 +02:00
self . extra_args = [ [ ' -prune=550 ' ] , [ ] , [ ] ]
2020-04-19 15:21:47 +02:00
def disconnect_all ( self ) :
2022-09-24 14:36:35 +02:00
self . disconnect_nodes ( 0 , 1 )
self . disconnect_nodes ( 0 , 2 )
self . disconnect_nodes ( 1 , 2 )
2020-04-19 15:21:47 +02:00
def setup_network ( self ) :
2018-11-02 16:41:29 +01:00
self . add_nodes ( self . num_nodes , self . extra_args )
self . start_nodes ( )
2017-12-09 08:34:31 +01:00
2017-12-19 21:16:26 +01:00
def run_test ( self ) :
node = self . nodes [ 0 ] . add_p2p_connection ( P2PIgnoreInv ( ) )
2017-12-09 08:34:31 +01:00
2022-03-11 20:39:12 +01:00
expected_services = NODE_BLOOM | NODE_NETWORK_LIMITED | NODE_HEADERS_COMPRESSED
2017-12-09 08:34:31 +01:00
2017-12-19 21:16:26 +01:00
self . log . info ( " Check that node has signalled expected services. " )
assert_equal ( node . nServices , expected_services )
2017-12-09 08:34:31 +01:00
2017-12-19 21:16:26 +01:00
self . log . info ( " Check that the localservices is as expected. " )
assert_equal ( int ( self . nodes [ 0 ] . getnetworkinfo ( ) [ ' localservices ' ] , 16 ) , expected_services )
2017-12-09 08:34:31 +01:00
2017-12-19 21:16:26 +01:00
self . log . info ( " Mine enough blocks to reach the NODE_NETWORK_LIMITED range. " )
2022-09-24 14:36:35 +02:00
self . connect_nodes ( 0 , 1 )
2018-09-17 20:00:41 +02:00
blocks = self . nodes [ 1 ] . generatetoaddress ( 292 , self . nodes [ 1 ] . get_deterministic_priv_key ( ) . address )
2020-06-21 15:17:31 +02:00
self . sync_blocks ( [ self . nodes [ 0 ] , self . nodes [ 1 ] ] )
2017-12-09 08:34:31 +01:00
2018-03-21 16:16:28 +01:00
self . log . info ( " Make sure we can max retrieve block at tip-288. " )
2017-12-19 21:16:26 +01:00
node . send_getdata_for_block ( blocks [ 1 ] ) # last block in valid range
node . wait_for_block ( int ( blocks [ 1 ] , 16 ) , timeout = 3 )
2017-12-09 08:34:31 +01:00
2017-12-19 21:16:26 +01:00
self . log . info ( " Requesting block at height 2 (tip-289) must fail (ignored). " )
node . send_getdata_for_block ( blocks [ 0 ] ) # first block outside of the 288+2 limit
node . wait_for_disconnect ( 5 )
2020-04-19 15:21:47 +02:00
self . nodes [ 0 ] . disconnect_p2ps ( )
# connect unsynced node 2 with pruned NODE_NETWORK_LIMITED peer
# because node 2 is in IBD and node 0 is a NODE_NETWORK_LIMITED peer, sync must not be possible
2022-09-24 14:36:35 +02:00
self . connect_nodes ( 0 , 2 )
2020-04-19 15:21:47 +02:00
try :
2020-06-21 15:17:31 +02:00
self . sync_blocks ( [ self . nodes [ 0 ] , self . nodes [ 2 ] ] , timeout = 5 )
2020-04-19 15:21:47 +02:00
except :
pass
2018-09-06 00:12:39 +02:00
# node2 must remain at height 0
2020-04-19 15:21:47 +02:00
assert_equal ( self . nodes [ 2 ] . getblockheader ( self . nodes [ 2 ] . getbestblockhash ( ) ) [ ' height ' ] , 0 )
# now connect also to node 1 (non pruned)
2022-09-24 14:36:35 +02:00
self . connect_nodes ( 1 , 2 )
2020-04-19 15:21:47 +02:00
# sync must be possible
2020-06-21 15:17:31 +02:00
self . sync_blocks ( )
2020-04-19 15:21:47 +02:00
# disconnect all peers
self . disconnect_all ( )
# mine 10 blocks on node 0 (pruned node)
2018-09-17 20:00:41 +02:00
self . nodes [ 0 ] . generatetoaddress ( 10 , self . nodes [ 0 ] . get_deterministic_priv_key ( ) . address )
2020-04-19 15:21:47 +02:00
# connect node1 (non pruned) with node0 (pruned) and check if the can sync
2022-09-24 14:36:35 +02:00
self . connect_nodes ( 0 , 1 )
2020-04-19 15:21:47 +02:00
# sync must be possible, node 1 is no longer in IBD and should therefore connect to node 0 (NODE_NETWORK_LIMITED)
2020-06-21 15:17:31 +02:00
self . sync_blocks ( [ self . nodes [ 0 ] , self . nodes [ 1 ] ] )
2021-06-17 20:26:27 +02:00
self . stop_node ( 0 , expected_stderr = ' Warning: You are starting with governance validation disabled. This is expected because you are running a pruned node. ' )
2020-04-19 15:21:47 +02:00
2017-12-09 08:34:31 +01:00
if __name__ == ' __main__ ' :
NodeNetworkLimitedTest ( ) . main ( )