@ -4,8 +4,8 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
""" Test message sending before handshake completion.
""" Test message sending before handshake completion.
A node should never send anything other than VERSION / VERACK until it ' s
Before receiving a VERACK , a node should not send anything but VERSION / VERACK
received a VERACK .
and feature negotiation messages ( WTXIDRELAY , SENDADDRV2 ) .
This test connects to a node and sends it a few messages , trying to entice it
This test connects to a node and sends it a few messages , trying to entice it
into sending us something it shouldn ' t. " " "
into sending us something it shouldn ' t. " " "
@ -35,10 +35,12 @@ class LazyPeer(P2PInterface):
super ( ) . __init__ ( )
super ( ) . __init__ ( )
self . unexpected_msg = False
self . unexpected_msg = False
self . ever_connected = False
self . ever_connected = False
self . got_wtxidrelay = False
self . got_sendaddrv2 = False
def bad_message ( self , message ) :
def bad_message ( self , message ) :
self . unexpected_msg = True
self . unexpected_msg = True
self . log . info ( " should not have received message: %s " % message . msgtype )
print ( " should not have received message: %s " % message . msgtype )
def on_open ( self ) :
def on_open ( self ) :
self . ever_connected = True
self . ever_connected = True
@ -64,6 +66,8 @@ class LazyPeer(P2PInterface):
def on_cmpctblock ( self , message ) : self . bad_message ( message )
def on_cmpctblock ( self , message ) : self . bad_message ( message )
def on_getblocktxn ( self , message ) : self . bad_message ( message )
def on_getblocktxn ( self , message ) : self . bad_message ( message )
def on_blocktxn ( self , message ) : self . bad_message ( message )
def on_blocktxn ( self , message ) : self . bad_message ( message )
def on_wtxidrelay ( self , message ) : self . got_wtxidrelay = True
def on_sendaddrv2 ( self , message ) : self . got_sendaddrv2 = True
# Peer that sends a version but not a verack.
# Peer that sends a version but not a verack.
@ -94,32 +98,61 @@ class P2PVersionStore(P2PInterface):
class P2PLeakTest ( BitcoinTestFramework ) :
class P2PLeakTest ( BitcoinTestFramework ) :
def set_test_params ( self ) :
def set_test_params ( self ) :
self . num_nodes = 1
self . num_nodes = 1
self . extra_args = [ [ ' -peertimeout=4 ' ] ]
def create_old_version ( self , nversion ) :
old_version_msg = msg_version ( )
old_version_msg . nVersion = nversion
old_version_msg . strSubVer = P2P_SUBVERSION
old_version_msg . nServices = P2P_SERVICES
old_version_msg . relay = P2P_VERSION_RELAY
return old_version_msg
def run_test ( self ) :
def run_test ( self ) :
# Another peer that never sends a version, nor any other messages. It shouldn't receive anything from the node.
self . log . info ( ' Check that the node doesn \' t send unexpected messages before handshake completion ' )
# Peer that never sends a version, nor any other messages. It shouldn't receive anything from the node.
no_version_idle_peer = self . nodes [ 0 ] . add_p2p_connection ( LazyPeer ( ) , send_version = False , wait_for_verack = False )
no_version_idle_peer = self . nodes [ 0 ] . add_p2p_connection ( LazyPeer ( ) , send_version = False , wait_for_verack = False )
# Peer that sends a version but not a verack.
# Peer that sends a version but not a verack.
no_verack_idle_peer = self . nodes [ 0 ] . add_p2p_connection ( NoVerackIdlePeer ( ) , wait_for_verack = False )
no_verack_idle_peer = self . nodes [ 0 ] . add_p2p_connection ( NoVerackIdlePeer ( ) , wait_for_verack = False )
# Wait until we got the verack in response to the version. Though, don't wait for the node to receive the
# Pre-wtxidRelay peer that sends a version but not a verack and does not support feature negotiation
# verack, since we never sent one
# messages which start at nVersion == 70016
pre_wtxidrelay_peer = self . nodes [ 0 ] . add_p2p_connection ( NoVerackIdlePeer ( ) , send_version = False , wait_for_verack = False )
pre_wtxidrelay_peer . send_message ( self . create_old_version ( 70015 ) )
# Wait until the peer gets the verack in response to the version. Though, don't wait for the node to receive the
# verack, since the peer never sent one
no_verack_idle_peer . wait_for_verack ( )
no_verack_idle_peer . wait_for_verack ( )
pre_wtxidrelay_peer . wait_for_verack ( )
no_version_idle_peer . wait_until ( lambda : no_version_idle_peer . ever_connected )
no_version_idle_peer . wait_until ( lambda : no_version_idle_peer . ever_connected )
no_verack_idle_peer . wait_until ( lambda : no_verack_idle_peer . version_received )
no_verack_idle_peer . wait_until ( lambda : no_verack_idle_peer . version_received )
pre_wtxidrelay_peer . wait_until ( lambda : pre_wtxidrelay_peer . version_received )
# Mine a block and make sure that it's not sent to the connected peers
# Mine a block and make sure that it's not sent to the connected peers
self . nodes [ 0 ] . generate ( nblocks = 1 )
self . nodes [ 0 ] . generate ( nblocks = 1 )
# Give the node enough time to possibly leak out a message
# Give the node enough time to possibly leak out a message
time . sleep ( 5 )
time . sleep ( 5 )
self . nodes [ 0 ] . disconnect_p2ps ( )
# Make sure only expected messages came in
assert not no_version_idle_peer . unexpected_msg
assert not no_version_idle_peer . got_wtxidrelay
assert not no_version_idle_peer . got_sendaddrv2
# Make sure no unexpected messages came in
assert not no_verack_idle_peer . unexpected_msg
assert no_version_idle_peer . unexpected_msg == False
assert no_verack_idle_peer . got_wtxidrelay
assert no_verack_idle_peer . unexpected_msg == False
assert no_verack_idle_peer . got_sendaddrv2
assert not pre_wtxidrelay_peer . unexpected_msg
assert not pre_wtxidrelay_peer . got_wtxidrelay
assert not pre_wtxidrelay_peer . got_sendaddrv2
# Expect peers to be disconnected due to timeout
assert not no_version_idle_peer . is_connected
assert not no_verack_idle_peer . is_connected
assert not pre_wtxidrelay_peer . is_connected
self . log . info ( ' Check that the version message does not leak the local address of the node ' )
self . log . info ( ' Check that the version message does not leak the local address of the node ' )
p2p_version_store = self . nodes [ 0 ] . add_p2p_connection ( P2PVersionStore ( ) )
p2p_version_store = self . nodes [ 0 ] . add_p2p_connection ( P2PVersionStore ( ) )
@ -134,13 +167,8 @@ class P2PLeakTest(BitcoinTestFramework):
self . log . info ( ' Check that old peers are disconnected ' )
self . log . info ( ' Check that old peers are disconnected ' )
p2p_old_peer = self . nodes [ 0 ] . add_p2p_connection ( P2PInterface ( ) , send_version = False , wait_for_verack = False )
p2p_old_peer = self . nodes [ 0 ] . add_p2p_connection ( P2PInterface ( ) , send_version = False , wait_for_verack = False )
old_version_msg = msg_version ( )
with self . nodes [ 0 ] . assert_debug_log ( [ ' peer=4 using obsolete version 31799; disconnecting ' ] ) :
old_version_msg . nVersion = 31799
p2p_old_peer . send_message ( self . create_old_version ( 31799 ) )
old_version_msg . strSubVer = P2P_SUBVERSION
old_version_msg . nServices = P2P_SERVICES
old_version_msg . relay = P2P_VERSION_RELAY
with self . nodes [ 0 ] . assert_debug_log ( [ ' peer=3 using obsolete version 31799; disconnecting ' ] ) :
p2p_old_peer . send_message ( old_version_msg )
p2p_old_peer . wait_for_disconnect ( )
p2p_old_peer . wait_for_disconnect ( )