def run_test(self): filter_peer = self.nodes[0].add_p2p_connection(P2PBloomFilter()) self.log.info('Test filter size limits') self.test_size_limits(filter_peer) self.log.info('Test BIP 37 for a node with fRelay = True (default)') self.test_filter(filter_peer) self.nodes[0].disconnect_p2ps() self.log.info('Test BIP 37 for a node with fRelay = False') # Add peer but do not send version yet filter_peer_without_nrelay = self.nodes[0].add_p2p_connection( P2PBloomFilter(), send_version=False, wait_for_verack=False) # Send version with fRelay=False filter_peer_without_nrelay.wait_until( lambda: filter_peer_without_nrelay.is_connected, timeout=10) version_without_fRelay = msg_version() version_without_fRelay.nRelay = 0 filter_peer_without_nrelay.send_message(version_without_fRelay) filter_peer_without_nrelay.wait_for_verack() assert not self.nodes[0].getpeerinfo()[0]['relaytxes'] self.test_frelay_false(filter_peer_without_nrelay) self.test_filter(filter_peer_without_nrelay) self.test_msg_mempool()
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): filter_peer = self.nodes[0].add_p2p_connection(P2PBloomFilter()) self.log.info('Test filter size limits') self.test_size_limits(filter_peer) self.log.info('Test BIP 37 for a node with fRelay = True (default)') self.test_filter(filter_peer) self.nodes[0].disconnect_p2ps() self.log.info('Test BIP 37 for a node with fRelay = False') # Add peer but do not send version yet filter_peer_without_nrelay = self.nodes[0].add_p2p_connection( P2PBloomFilter(), send_version=False, wait_for_verack=False) # Send version with relay=False version_without_fRelay = msg_version() version_without_fRelay.nVersion = P2P_VERSION version_without_fRelay.strSubVer = P2P_SUBVERSION version_without_fRelay.nServices = P2P_SERVICES version_without_fRelay.relay = 0 filter_peer_without_nrelay.send_message(version_without_fRelay) filter_peer_without_nrelay.wait_for_verack() assert not self.nodes[0].getpeerinfo()[0]['relaytxes'] self.test_frelay_false(filter_peer_without_nrelay) self.test_filter(filter_peer_without_nrelay) self.test_msg_mempool()
def test_duplicate_version_msg(self): self.log.info("Test duplicate version message is ignored") conn = self.nodes[0].add_p2p_connection(P2PDataStore()) with self.nodes[0].assert_debug_log( ['redundant version message from peer']): conn.send_and_ping(msg_version()) self.nodes[0].disconnect_p2ps()
def run_test(self): # Peer that never sends a version. We will send a bunch of messages # from this peer anyway and verify eventual disconnection. no_version_disconnect_peer = self.nodes[0].add_p2p_connection( LazyPeer(), send_version=False, wait_for_verack=False) # Another 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) # Peer that sends a version but not a verack. no_verack_idle_peer = self.nodes[0].add_p2p_connection(NoVerackIdlePeer(), wait_for_verack=False) # Send enough ping messages (any non-version message will do) prior to sending # version to reach the peer discouragement threshold. This should get us disconnected. for _ in range(DISCOURAGEMENT_THRESHOLD): no_version_disconnect_peer.send_message(msg_ping()) # Wait until we got the verack in response to the version. Though, don't wait for the node to receive the # verack, since we never sent one no_verack_idle_peer.wait_for_verack() no_version_disconnect_peer.wait_until(lambda: no_version_disconnect_peer.ever_connected, check_connected=False) 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) # Mine a block and make sure that it's not sent to the connected peers self.nodes[0].generate(nblocks=1) #Give the node enough time to possibly leak out a message time.sleep(5) # Expect this peer to be disconnected for misbehavior assert not no_version_disconnect_peer.is_connected self.nodes[0].disconnect_p2ps() # Make sure no unexpected messages came in assert no_version_disconnect_peer.unexpected_msg == False assert no_version_idle_peer.unexpected_msg == False assert no_verack_idle_peer.unexpected_msg == False 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()) ver = p2p_version_store.version_received # Check that received time is within one hour of now assert_greater_than_or_equal(ver.nTime, time.time() - 3600) assert_greater_than_or_equal(time.time() + 3600, ver.nTime) assert_equal(ver.addrFrom.port, 0) assert_equal(ver.addrFrom.ip, '0.0.0.0') assert_equal(ver.nStartingHeight, 201) assert_equal(ver.nRelay, 1) 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) old_version_msg = msg_version() old_version_msg.nVersion = 31799 with self.nodes[0].assert_debug_log(['peer=4 using obsolete version 31799; disconnecting']): p2p_old_peer.send_message(old_version_msg) p2p_old_peer.wait_for_disconnect()
def peer_connect_send_version(self, services): # Send a version msg vt = msg_version() vt.nServices = services vt.addrTo.ip = self.dstaddr vt.addrTo.port = self.dstport vt.addrFrom.ip = "0.0.0.0" vt.addrFrom.port = 0 self.on_connection_send_msg = vt # Will be sent in connection_made callback
def run_test(self): # Another 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) # Peer that sends a version but not a verack. 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 # verack, since we never sent one no_verack_idle_peer.wait_for_verack() 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) # Mine a block and make sure that it's not sent to the connected peers self.nodes[0].generate(nblocks=1) #Give the node enough time to possibly leak out a message time.sleep(5) self.nodes[0].disconnect_p2ps() # Make sure no unexpected messages came in assert no_version_idle_peer.unexpected_msg == False assert no_verack_idle_peer.unexpected_msg == False 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()) ver = p2p_version_store.version_received # Check that received time is within one hour of now assert_greater_than_or_equal(ver.nTime, time.time() - 3600) assert_greater_than_or_equal(time.time() + 3600, ver.nTime) assert_equal(ver.addrFrom.port, 0) assert_equal(ver.addrFrom.ip, '0.0.0.0') assert_equal(ver.nStartingHeight, 201) assert_equal(ver.relay, 1) 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) old_version_msg = msg_version() old_version_msg.nVersion = 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()
def send_version(self): # Send version message with invalid checksum vt = msg_version() vt.nServices = self.services vt.addrTo.ip = self.dstaddr vt.addrTo.port = self.dstport vt.addrFrom.ip = "0.0.0.0" vt.addrFrom.port = 0 invalid_vt = msg_bad_checksum(self, vt) self.send_raw_message(invalid_vt)
def run_test(self): no_version_bannode = self.nodes[0].add_p2p_connection( CNodeNoVersionBan(), send_version=False, wait_for_verack=False) no_version_idlenode = self.nodes[0].add_p2p_connection( CNodeNoVersionIdle(), send_version=False, wait_for_verack=False) no_verack_idlenode = self.nodes[0].add_p2p_connection( CNodeNoVerackIdle(), wait_for_verack=False) # Wait until we got the verack in response to the version. Though, don't wait for the other node to receive the # verack, since we never sent one no_verack_idlenode.wait_for_verack() wait_until(lambda: no_version_bannode.ever_connected, timeout=10, lock=p2p_lock) wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=p2p_lock) wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=p2p_lock) # Mine a block and make sure that it's not sent to the connected nodes self.generatetoaddress( self.nodes[0], 1, self.nodes[0].get_deterministic_priv_key().address) # Give the node enough time to possibly leak out a message time.sleep(5) # This node should have been banned assert not no_version_bannode.is_connected self.nodes[0].disconnect_p2ps() # Wait until all connections are closed wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0) # Make sure no unexpected messages came in assert not no_version_bannode.unexpected_msg assert not no_version_idlenode.unexpected_msg assert not no_verack_idlenode.unexpected_msg self.log.info('Check that old nodes are disconnected') p2p_old_node = self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False) old_version_msg = msg_version() old_version_msg.nVersion = 31799 wait_until(lambda: p2p_old_node.is_connected) with self.nodes[0].assert_debug_log( ['peer=3 using obsolete version 31799; disconnecting']): p2p_old_node.send_message(old_version_msg) p2p_old_node.wait_for_disconnect()
def peer_connect_send_version(self, services): # Send a version msg vt = msg_version() vt.nVersion = P2P_VERSION vt.strSubVer = P2P_SUBVERSION vt.relay = P2P_VERSION_RELAY vt.nServices = services vt.addrTo.ip = self.dstaddr vt.addrTo.port = self.dstport vt.addrFrom.ip = "0.0.0.0" vt.addrFrom.port = 0 self.on_connection_send_msg = vt # Will be sent in connection_made callback
def peer_connect(self, *args, services=NODE_NETWORK, send_version=True, **kwargs): super().peer_connect(*args, **kwargs) if send_version: # Send a version msg vt = msg_version() vt.nServices = services vt.addrTo.ip = self.dstaddr vt.addrTo.port = self.dstport vt.addrFrom.ip = "0.0.0.0" vt.addrFrom.port = 0 self.send_message(vt, True)
def run_test(self): no_version_bannode = self.nodes[0].add_p2p_connection(CNodeNoVersionBan(), send_version=False, wait_for_verack=False) no_version_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVersionIdle(), send_version=False, wait_for_verack=False) no_verack_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVerackIdle(), wait_for_verack=False) # Wait until we got the verack in response to the version. Though, don't wait for the other node to receive the # verack, since we never sent one no_verack_idlenode.wait_for_verack() wait_until(lambda: no_version_bannode.ever_connected, timeout=10, lock=mininode_lock) wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=mininode_lock) wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock) # Mine a block and make sure that it's not sent to the connected nodes self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address) #Give the node enough time to possibly leak out a message time.sleep(5) #This node should have been banned assert not no_version_bannode.is_connected self.nodes[0].disconnect_p2ps() # Wait until all connections are closed wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0) # Make sure no unexpected messages came in assert no_version_bannode.unexpected_msg == False assert no_version_idlenode.unexpected_msg == False assert no_verack_idlenode.unexpected_msg == False self.log.info('Check that the version message does not leak the local address of the node') time_begin = int(time.time()) p2p_version_store = self.nodes[0].add_p2p_connection(P2PVersionStore()) time_end = time.time() ver = p2p_version_store.version_received assert_greater_than_or_equal(ver.nTime, time_begin) assert_greater_than_or_equal(time_end, ver.nTime) assert_equal(ver.addrFrom.port, 0) assert_equal(ver.addrFrom.ip, '0.0.0.0') assert_equal(ver.nStartingHeight, 201) assert_equal(ver.nRelay, 1) self.log.info('Check that old nodes are disconnected') p2p_old_node = self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False) old_version_msg = msg_version() old_version_msg.nVersion = 31799 wait_until(lambda: p2p_old_node.is_connected) with self.nodes[0].assert_debug_log(['peer=4 using obsolete version 31799; disconnecting']): p2p_old_node.send_message(old_version_msg) p2p_old_node.wait_for_disconnect()
def peer_connect(self, *args, services=NODE_NETWORK|NODE_WITNESS, send_version=True, **kwargs): create_conn = super().peer_connect(*args, **kwargs) if send_version: # Send a version msg vt = msg_version() vt.nServices = services vt.addrTo.ip = self.dstaddr vt.addrTo.port = self.dstport vt.addrFrom.ip = "0.0.0.0" vt.addrFrom.port = 0 self.on_connection_send_msg = vt # Will be sent soon after connection_made return create_conn
def peer_connect(self, *args, services=NODE_NETWORK, send_version=False, **kwargs): super().peer_connect(*args, send_version=send_version, **kwargs) # Send version message with invalid checksum vt = msg_version() vt.nServices = services vt.addrTo.ip = self.dstaddr vt.addrTo.port = self.dstport vt.addrFrom.ip = "0.0.0.0" vt.addrFrom.port = 0 invalid_vt = msg_bad_checksum(self, vt) self.send_raw_message(invalid_vt, True)
def peer_connect(self, *args, services=NODE_NETWORK, send_version=False, **kwargs): create_conn = super().peer_connect(*args, send_version=send_version, **kwargs) # Send version message with invalid timestamp vt = msg_version() vt.nTime = self.versionTimestamp vt.nServices = services vt.addrTo.ip = self.dstaddr vt.addrTo.port = self.dstport vt.addrFrom.ip = "0.0.0.0" vt.addrFrom.port = 0 # Will be sent right after connection_made self.on_connection_send_msg = vt return create_conn
def peer_connect(self, *args, services=NODE_NETWORK, send_version=False, **kwargs): create_conn = super().peer_connect(*args, send_version=send_version, **kwargs) # Send version message with invalid checksum vt = msg_version() vt.nServices = services vt.addrTo.ip = self.dstaddr vt.addrTo.port = self.dstport vt.addrFrom.ip = "0.0.0.0" vt.addrFrom.port = 0 invalid_vt = msg_bad_checksum(self, vt) # Will be sent right after connection_made self.on_connection_send_msg = invalid_vt self.on_connection_send_msg_is_raw = True return create_conn
def check_p2p_message(event, inbound): nonlocal checked_inbound_version_msg, checked_outbound_version_msg if event.msg_type.decode("utf-8") == "version": self.log.info( f"check_p2p_message(): {'inbound' if inbound else 'outbound'} {event}" ) peer = self.nodes[0].getpeerinfo()[0] msg = msg_version() msg.deserialize(BytesIO(bytes(event.msg[:event.msg_size]))) assert_equal(peer["id"], event.peer_id, peer["id"]) assert_equal(peer["addr"], event.peer_addr.decode("utf-8")) assert_equal(peer["connection_type"], event.peer_conn_type.decode("utf-8")) if inbound: checked_inbound_version_msg += 1 else: checked_outbound_version_msg += 1
def run_test(self): no_version_disconnect_node = self.nodes[0].add_p2p_connection( CNodeNoVersionMisbehavior(), send_version=False, wait_for_verack=False) no_version_idlenode = self.nodes[0].add_p2p_connection( CNodeNoVersionIdle(), send_version=False, wait_for_verack=False) no_verack_idlenode = self.nodes[0].add_p2p_connection( CNodeNoVerackIdle(), wait_for_verack=False) # Send enough veracks without a message to reach the peer discouragement # threshold. This should get us disconnected. for _ in range(DISCOURAGEMENT_THRESHOLD): no_version_disconnect_node.send_message(msg_verack()) # Wait until we got the verack in response to the version. Though, don't wait for the other node to receive the # verack, since we never sent one no_verack_idlenode.wait_for_verack() wait_until(lambda: no_version_disconnect_node.ever_connected, timeout=10, lock=mininode_lock) wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=mininode_lock) wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock) # Mine a block and make sure that it's not sent to the connected nodes self.nodes[0].generatetoaddress( 1, self.nodes[0].get_deterministic_priv_key().address) #Give the node enough time to possibly leak out a message time.sleep(5) # Expect this node to be disconnected for misbehavior assert not no_version_disconnect_node.is_connected self.nodes[0].disconnect_p2ps() # Make sure no unexpected messages came in assert no_version_disconnect_node.unexpected_msg == False assert no_version_idlenode.unexpected_msg == False assert no_verack_idlenode.unexpected_msg == False 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()) ver = p2p_version_store.version_received # Check that received time is within one hour of now assert_greater_than_or_equal(ver.nTime, time.time() - 3600) assert_greater_than_or_equal(time.time() + 3600, ver.nTime) assert_equal(ver.addrFrom.port, 0) assert_equal(ver.addrFrom.ip, '0.0.0.0') assert_equal(ver.nStartingHeight, 201) assert_equal(ver.nRelay, 1) self.log.info('Check that old nodes are disconnected') p2p_old_node = self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False) old_version_msg = msg_version() old_version_msg.nVersion = 31799 with self.nodes[0].assert_debug_log( ['peer=4 using obsolete version 31799; disconnecting']): p2p_old_node.send_message(old_version_msg) p2p_old_node.wait_for_disconnect()
def run_test(self): self.miner = self.nodes[self.minerPos] # initialize and start masternodes self.setup_test() assert_equal(len(self.mns), 6) ############################################################## # 1) Disconnect peers from DMN and add a direct DMN connection ############################################################## self.log.info("1) Testing single DMN connection, disconnecting nodes..") mn1 = self.mns[0] mn1_node = self.nodes[mn1.idx] self.disconnect_peers(mn1_node) self.log.info("disconnected, connecting to a single DMN and auth him..") # Now try to connect to the second DMN only mn2 = self.mns[1] assert mn1_node.mnconnect("single_conn", [mn2.proTx]) self.wait_for_auth_connections(mn1_node, [mn2.proTx]) # Check connected peer info: same DMN and mnauth succeeded self.wait_for_peers_info(mn1_node, [mn2], is_iqr_conn=False) # Same for the the other side mn2_node = self.nodes[mn2.idx] self.wait_for_peers_info(mn2_node, [mn1], is_iqr_conn=False, inbound=True) self.log.info("Completed DMN-to-DMN authenticated connection!") ################################################################ # 2) Disconnect peers from DMN and add quorum members connection ################################################################ self.log.info("2) Testing quorum connections, disconnecting nodes..") mn3 = self.mns[2] mn4 = self.mns[3] mn5 = self.mns[4] mn6 = self.mns[5] quorum_nodes = [mn3, mn4, mn5, mn6] self.disconnect_peers(mn2_node) self.wait_for_peers_count([mn2_node], 0) self.log.info("disconnected, connecting to quorum members..") quorum_members = [mn2.proTx, mn3.proTx, mn4.proTx, mn5.proTx, mn6.proTx] assert mn2_node.mnconnect("quorum_members_conn", quorum_members, 1, mn2_node.getbestblockhash()) # Check connected peer info: same quorum members and mnauth succeeded self.wait_for_peers_count([mn2_node], 4) self.wait_for_peers_info(mn2_node, quorum_nodes, is_iqr_conn=False) # Same for the other side (MNs receiving the new connection) for mn_node in [self.nodes[mn3.idx], self.nodes[mn4.idx], self.nodes[mn5.idx], self.nodes[mn6.idx]]: self.wait_for_peers_info(mn_node, [mn2], is_iqr_conn=False, inbound=True) self.log.info("Completed DMN-to-quorum connections!") ################################################################################## # 3) Update already connected quorum members in (2) to be intra-quorum connections ################################################################################## self.log.info("3) Testing connections update to be intra-quorum relay connections") assert mn2_node.mnconnect("iqr_members_conn", quorum_members, 1, mn2_node.getbestblockhash()) time.sleep(2) self.wait_for_peers_info(mn2_node, quorum_nodes, is_iqr_conn=True) # Same for the other side (MNs receiving the new connection) for mn_node in [self.nodes[mn3.idx], self.nodes[mn4.idx], self.nodes[mn5.idx], self.nodes[mn6.idx]]: assert mn_node.mnconnect("iqr_members_conn", quorum_members, 1, mn2_node.getbestblockhash()) self.wait_for_peers_info(mn_node, [mn2], is_iqr_conn=True, inbound=True) self.log.info("Completed update to quorum relay members!") ########################################### # 4) Now test the connections probe process ########################################### self.log.info("4) Testing MN probe connection process..") # Take mn6, disconnect all the nodes and try to probe connection to one of them mn6_node = self.nodes[mn6.idx] self.disconnect_peers(mn6_node) self.log.info("disconnected, probing MN connection..") with mn6_node.assert_debug_log(["Masternode probe successful for " + mn5.proTx]): assert mn_node.mnconnect("probe_conn", [mn5.proTx]) time.sleep(10) # wait a bit until the connection gets established self.log.info("Completed MN connection probe!") ############################################################################### # 5) Now test regular node disconnecting after receiving an auth DMN connection ############################################################################### self.log.info("5) Testing regular node disconnection after receiving an auth DMN connection..") self.disconnect_peers(self.miner) no_version_node = self.miner.add_p2p_connection(TestP2PConn(), send_version=False, wait_for_verack=False) self.wait_for_peers_count([self.miner], 1) # send the version as it would be a MN mn_challenge = getrandbits(256) with self.miner.assert_debug_log(["but we're not a masternode, disconnecting"]): no_version_node.send_message(msg_version(mn_challenge)) time.sleep(2) # as the miner is not a DMN, the miner should had dropped the connection. assert_equal(len(self.miner.getpeerinfo()), 0) self.log.info("Regular node disconnected auth connection successfully") ############################################################################## # 6) Now test regular connection refresh after selecting peer as quorum member ############################################################################## self.log.info("6) Now test regular connection refresh after selecting peer as quorum member..") # Cleaning internal data first mn5_node = self.nodes[mn5.idx] self.clean_conns_and_disconnect(mn5_node) self.clean_conns_and_disconnect(mn6_node) # Create the regular connection connect_nodes(mn5_node, mn6.idx) self.wait_for_peers_count([mn5_node], 1) assert self.has_single_regular_connection(mn5_node) assert self.has_single_regular_connection(mn6_node) # Now refresh it to be a quorum member connection quorum_hash = mn5_node.getbestblockhash() assert mn5_node.mnconnect("quorum_members_conn", [mn6.proTx], 1, quorum_hash) assert mn5_node.mnconnect("iqr_members_conn", [mn6.proTx], 1, quorum_hash) assert mn6_node.mnconnect("iqr_members_conn", [mn5.proTx], 1, quorum_hash) self.wait_for_auth_connections(mn5_node, [mn6.proTx]) self.log.info("Connection refreshed!")