def run_test(self): # Create all the connections we will need to node0 at the start because they all need to be # setup before we call NetworkThread().start() # Create a P2P connection just so that the test framework is happy we're connected dummyCB = NodeConnCB() dummyConn = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], dummyCB, nullAssocID=True) dummyCB.add_connection(dummyConn) # By setting the assocID on this second NodeConn we prevent it sending a version message badConnCB = TestNode() badConn = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], badConnCB, assocID=0x01) badConnCB.add_connection(badConn) # Start up network handling in another thread. This needs to be called # after the P2P connections have been created. NetworkThread().start() # Check initial state dummyCB.wait_for_protoconf() with mininode_lock: assert_equal(len(badConnCB.message_count), 0) # Send a badly formatted version message badConn.send_message(msg_version_bad()) # Connection will be closed with a reject wait_until(lambda: badConnCB.last_reject is not None, lock=mininode_lock, timeout=5) wait_until(lambda: badConn.state == "closed", lock=mininode_lock, timeout=5) # Check clear log message was generated assert check_for_log_msg( self, "Failed to process version: (Badly formatted association ID", "/node0")
def run_test(self): # Create all the connections we will need to node0 at the start because they all need to be # setup before we call NetworkThread().start() # Create a P2P connection with no association ID (old style) oldStyleConnCB = TestNode() oldStyleConn = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], oldStyleConnCB, nullAssocID=True) oldStyleConnCB.add_connection(oldStyleConn) # Create a P2P connection with a new association ID newStyleConnCB = TestNode() newStyleConn = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], newStyleConnCB) newStyleConnCB.add_connection(newStyleConn) # Create a P2P connection with a new association ID and another connection that uses the same ID newStyleFirstConnCB = TestNode() newStyleFirstConn = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], newStyleFirstConnCB) newStyleFirstConnCB.add_connection(newStyleFirstConn) # By setting the assocID on this second NodeConn we prevent it sending a version message newStyleSecondConnCB = TestNode() newStyleSecondConn = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], newStyleSecondConnCB, assocID=newStyleFirstConn.assocID) newStyleSecondConnCB.add_connection(newStyleSecondConn) # Some connections we will use to test setup of DATA2, DATA3, DATA4 streams newStyleSecondConnCB_Data2 = TestNode() newStyleSecondConn_Data2 = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], newStyleSecondConnCB_Data2, assocID=newStyleFirstConn.assocID) newStyleSecondConnCB_Data2.add_connection(newStyleSecondConn_Data2) newStyleSecondConnCB_Data3 = TestNode() newStyleSecondConn_Data3 = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], newStyleSecondConnCB_Data3, assocID=newStyleFirstConn.assocID) newStyleSecondConnCB_Data3.add_connection(newStyleSecondConn_Data3) newStyleSecondConnCB_Data4 = TestNode() newStyleSecondConn_Data4 = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], newStyleSecondConnCB_Data4, assocID=newStyleFirstConn.assocID) newStyleSecondConnCB_Data4.add_connection(newStyleSecondConn_Data4) # Some connections we will use to test error scenarios newStyleThirdConnCB = TestNode() badStreamConn1 = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], newStyleThirdConnCB, assocID=create_association_id()) newStyleThirdConnCB.add_connection(badStreamConn1) newStyleFourthConnCB = TestNode() badStreamConn2 = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], newStyleFourthConnCB, assocID=newStyleFirstConn.assocID) newStyleFourthConnCB.add_connection(badStreamConn2) newStyleFifthConnCB = TestNode() badStreamConn3 = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], newStyleFifthConnCB, assocID=newStyleFirstConn.assocID) newStyleFifthConnCB.add_connection(badStreamConn3) newStyleSixthConnCB = TestNode() badStreamConn4 = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], newStyleSixthConnCB, assocID=newStyleFirstConn.assocID) newStyleSixthConnCB.add_connection(badStreamConn4) newStyleSeventhConnCB = TestNode() badStreamConn5 = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], newStyleSeventhConnCB, assocID=newStyleFirstConn.assocID) newStyleSeventhConnCB.add_connection(badStreamConn5) # Start up network handling in another thread. This needs to be called # after the P2P connections have been created. NetworkThread().start() # Wait for all connections to come up to the required initial state oldStyleConnCB.wait_for_protoconf() newStyleConnCB.wait_for_protoconf() newStyleFirstConnCB.wait_for_protoconf() # Check initial state with mininode_lock: assert_equal(oldStyleConnCB.recvAssocID, None) with mininode_lock: assert_equal(oldStyleConnCB.recvStreamPolicies, b'BlockPriority,Default') with mininode_lock: assert_equal(newStyleConnCB.recvAssocID, newStyleConn.assocID) with mininode_lock: assert_equal(newStyleConnCB.recvStreamPolicies, b'BlockPriority,Default') with mininode_lock: assert_equal(newStyleFirstConnCB.recvAssocID, newStyleFirstConn.assocID) with mininode_lock: assert_equal(newStyleFirstConnCB.recvStreamPolicies, b'BlockPriority,Default') with mininode_lock: assert_equal(len(newStyleSecondConnCB.message_count), 0) with mininode_lock: assert_equal(len(newStyleSecondConnCB_Data2.message_count), 0) with mininode_lock: assert_equal(len(newStyleSecondConnCB_Data3.message_count), 0) with mininode_lock: assert_equal(len(newStyleSecondConnCB_Data4.message_count), 0) expected = [ { 'id': 0, # oldStyleConn 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 1, # newStyleConn 'associd': str(newStyleConn.assocID), 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 2, # newStyleFirstConn 'associd': str(newStyleFirstConn.assocID), 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 3, # newStyleSecondConn 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 4, # newStyleSecondConn_Data2 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 5, # newStyleSecondConn_Data3 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 6, # newStyleSecondConn_Data4 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 7, # badStreamConn1 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 8, # badStreamConn2 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 9, # badStreamConn3 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 10, # badStreamConn4 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 11, # badStreamConn5 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, ] wait_until(lambda: self.check_peer_info(self.nodes[0], expected), timeout=5) # Check a new block is recieved by all connections self.nodes[0].generate(1) tip = self.nodes[0].getbestblockhash() wait_until(lambda: oldStyleConnCB.seen_block(tip), lock=mininode_lock, timeout=5) wait_until(lambda: newStyleConnCB.seen_block(tip), lock=mininode_lock, timeout=5) wait_until(lambda: newStyleFirstConnCB.seen_block(tip), lock=mininode_lock, timeout=5) with mininode_lock: assert (not newStyleSecondConnCB.seen_block(tip)) with mininode_lock: assert (not newStyleSecondConnCB_Data2.seen_block(tip)) with mininode_lock: assert (not newStyleSecondConnCB_Data3.seen_block(tip)) with mininode_lock: assert (not newStyleSecondConnCB_Data4.seen_block(tip)) # Send create new stream message newStyleSecondConn.send_message( msg_createstream(stream_type=StreamType.DATA1.value, stream_policy=b"BlockPriority", assocID=newStyleFirstConn.assocID)) expected = [ { 'id': 0, # oldStyleConn 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 1, 'associd': str(newStyleConn.assocID), # newStyleConn 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 2, 'associd': str(newStyleFirstConn.assocID ), # newStyleFirstConn & newStyleSecondConn 'streampolicy': 'BlockPriority', 'streams': ['GENERAL', 'DATA1'] }, { 'id': 4, # newStyleSecondConn_Data2 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 5, # newStyleSecondConn_Data3 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 6, # newStyleSecondConn_Data4 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 7, # badStreamConn1 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 8, # badStreamConn2 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 9, # badStreamConn3 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 10, # badStreamConn4 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 11, # badStreamConn5 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, ] wait_until(lambda: self.check_peer_info(self.nodes[0], expected), timeout=5) with mininode_lock: assert (newStyleSecondConnCB.last_streamack is not None) # Send create stream with wrong association ID badStreamConn1.send_message( msg_createstream(stream_type=StreamType.DATA2.value, assocID=badStreamConn1.assocID)) # Should receive reject, no streamack wait_until(lambda: newStyleThirdConnCB.last_reject is not None, lock=mininode_lock, timeout=5) with mininode_lock: assert (newStyleThirdConnCB.last_streamack is None) assert ("No node found with association ID" in str(newStyleThirdConnCB.last_reject.reason)) # Connection will be closed wait_until(lambda: badStreamConn1.state == "closed", lock=mininode_lock, timeout=5) # Send create stream with missing association ID badStreamConn5.send_message( msg_createstream(stream_type=StreamType.DATA2.value, assocID="")) # Should receive reject, no streamack wait_until(lambda: newStyleSeventhConnCB.last_reject is not None, lock=mininode_lock, timeout=5) with mininode_lock: assert (newStyleSeventhConnCB.last_streamack is None) assert ("Badly formatted message" in str(newStyleSeventhConnCB.last_reject.reason)) # Connection will be closed wait_until(lambda: badStreamConn5.state == "closed", lock=mininode_lock, timeout=5) # Send create stream for unknown stream type badStreamConn2.send_message( msg_createstream(stream_type=9, assocID=badStreamConn2.assocID)) # Should receive reject, no streamack wait_until(lambda: newStyleFourthConnCB.last_reject is not None, lock=mininode_lock, timeout=5) with mininode_lock: assert (newStyleFourthConnCB.last_streamack is None) assert ("StreamType out of range" in str(newStyleFourthConnCB.last_reject.reason)) # Connection will be closed wait_until(lambda: badStreamConn2.state == "closed", lock=mininode_lock, timeout=5) # Send create stream for existing stream type badStreamConn3.send_message( msg_createstream(stream_type=StreamType.GENERAL.value, assocID=badStreamConn3.assocID)) # Should receive reject, no streamack wait_until(lambda: newStyleFifthConnCB.last_reject is not None, lock=mininode_lock, timeout=5) with mininode_lock: assert (newStyleFifthConnCB.last_streamack is None) assert ("Attempt to overwrite existing stream" in str(newStyleFifthConnCB.last_reject.reason)) # Connection will be closed wait_until(lambda: badStreamConn3.state == "closed", lock=mininode_lock, timeout=5) # Send create stream with unknown stream policy specified badStreamConn4.send_message( msg_createstream(stream_type=StreamType.GENERAL.value, stream_policy=b"UnknownPolicy", assocID=badStreamConn3.assocID)) # Should receive reject, no streamack wait_until(lambda: newStyleSixthConnCB.last_reject is not None, lock=mininode_lock, timeout=5) with mininode_lock: assert (newStyleSixthConnCB.last_streamack is None) assert ("Unknown stream policy name" in str(newStyleSixthConnCB.last_reject.reason)) # Connection will be closed wait_until(lambda: badStreamConn4.state == "closed", lock=mininode_lock, timeout=5) # Check streams are in the expected state after all those errors expected = [ { 'id': 0, # oldStyleConn 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 1, # newStyleConn 'associd': str(newStyleConn.assocID), 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 2, # newStyleFirstConn & newStyleSecondConn 'associd': str(newStyleFirstConn.assocID), 'streampolicy': 'BlockPriority', 'streams': ['GENERAL', 'DATA1'] }, { 'id': 4, # newStyleSecondConn_Data2 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 5, # newStyleSecondConn_Data3 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 6, # newStyleSecondConn_Data4 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, ] wait_until(lambda: self.check_peer_info(self.nodes[0], expected), timeout=5) # See if we can establish all the possible stream types newStyleSecondConn_Data2.send_message( msg_createstream(stream_type=StreamType.DATA2.value, assocID=newStyleFirstConn.assocID)) newStyleSecondConn_Data3.send_message( msg_createstream(stream_type=StreamType.DATA3.value, assocID=newStyleFirstConn.assocID)) newStyleSecondConn_Data4.send_message( msg_createstream(stream_type=StreamType.DATA4.value, assocID=newStyleFirstConn.assocID)) expected = [ { 'id': 0, # oldStyleConn 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 1, 'associd': str(newStyleConn.assocID), # newStyleConn 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 2, # newStyleFirstConn, newStyleSecondConn, newStyleSecondConn_Data2, 'associd': str(newStyleFirstConn.assocID ), # newStyleSecondConn_Data3, newStyleSecondConn_Data4 'streampolicy': 'BlockPriority', 'streams': ['GENERAL', 'DATA1', 'DATA2', 'DATA3', 'DATA4'] }, ] wait_until(lambda: self.check_peer_info(self.nodes[0], expected), timeout=5) # Connect 2 nodes and check they establish the expected streams connect_nodes(self.nodes[0], 1) expected0 = [ { 'id': 0, # oldStyleConn 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 1, # newStyleConn 'associd': str(newStyleConn.assocID), 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 2, # newStyleFirstConn, newStyleSecondConn, newStyleSecondConn_Data2, 'associd': str(newStyleFirstConn.assocID ), # newStyleSecondConn_Data3, newStyleSecondConn_Data4 'streampolicy': 'BlockPriority', 'streams': ['GENERAL', 'DATA1', 'DATA2', 'DATA3', 'DATA4'] }, { 'id': 12, # A new association established to node1 'associd': '<UNKNOWN>', 'streampolicy': 'BlockPriority', 'streams': ['GENERAL', 'DATA1'] }, ] wait_until(lambda: self.check_peer_info(self.nodes[0], expected0), timeout=5) expected1 = [ { 'id': 0, # An association to node0 'associd': '<UNKNOWN>', 'streampolicy': 'BlockPriority', 'streams': ['GENERAL', 'DATA1'] }, ] wait_until(lambda: self.check_peer_info(self.nodes[1], expected1), timeout=5) # Connect 2 nodes, one of which has streams disabled, and check they establish the expected streams connect_nodes(self.nodes[0], 2) expected0 = [ { 'id': 0, # oldStyleConn 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 1, # newStyleConn 'associd': str(newStyleConn.assocID), 'streampolicy': 'Default', 'streams': ['GENERAL'] }, { 'id': 2, # newStyleFirstConn, newStyleSecondConn, newStyleSecondConn_Data2, 'associd': str(newStyleFirstConn.assocID ), # newStyleSecondConn_Data3, newStyleSecondConn_Data4 'streampolicy': 'BlockPriority', 'streams': ['GENERAL', 'DATA1', 'DATA2', 'DATA3', 'DATA4'] }, { 'id': 12, # Association to node 1 'associd': '<UNKNOWN>', 'streampolicy': 'BlockPriority', 'streams': ['GENERAL', 'DATA1'] }, { 'id': 14, # Old style association to node 2 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, ] wait_until(lambda: self.check_peer_info(self.nodes[0], expected0), timeout=5) expected2 = [ { 'id': 0, # An association to node0 'associd': 'Not-Set', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, ] wait_until(lambda: self.check_peer_info(self.nodes[2], expected2), timeout=5) # Make sure everyone sees all blocks over whatever stream self.nodes[0].generate(1) tip = self.nodes[0].getbestblockhash() wait_until(lambda: self.nodes[1].getbestblockhash() == tip, timeout=5) wait_until(lambda: self.nodes[2].getbestblockhash() == tip, timeout=5) self.nodes[1].generate(1) tip = self.nodes[1].getbestblockhash() wait_until(lambda: self.nodes[0].getbestblockhash() == tip, timeout=5) wait_until(lambda: self.nodes[2].getbestblockhash() == tip, timeout=5) self.nodes[2].generate(1) tip = self.nodes[2].getbestblockhash() wait_until(lambda: self.nodes[0].getbestblockhash() == tip, timeout=5) wait_until(lambda: self.nodes[1].getbestblockhash() == tip, timeout=5) # Add another node, configured to only support the Default stream policy self.add_node(3, extra_args=[ '-whitelist=127.0.0.1', '-multistreampolicies=Default' ], init_data_dir=True) self.start_node(3) # Check streampolicies field from getnetworkinfo assert_equal(self.nodes[0].getnetworkinfo()["streampolicies"], "BlockPriority,Default") assert_equal(self.nodes[1].getnetworkinfo()["streampolicies"], "BlockPriority,Default") assert_equal(self.nodes[2].getnetworkinfo()["streampolicies"], "BlockPriority,Default") assert_equal(self.nodes[3].getnetworkinfo()["streampolicies"], "Default") # Connect the new node to one of the existing nodes and check that they establish a Default association connect_nodes(self.nodes[1], 3) expected1 = [ { 'id': 0, # An association to node0 'associd': '<UNKNOWN>', 'streampolicy': 'BlockPriority', 'streams': ['GENERAL', 'DATA1'] }, { 'id': 2, # An association to node3 'associd': '<UNKNOWN>', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, ] wait_until(lambda: self.check_peer_info(self.nodes[1], expected1), timeout=5) expected3 = [ { 'id': 0, # An association to node1 'associd': '<UNKNOWN>', 'streampolicy': 'Default', 'streams': ['GENERAL'] }, ] wait_until(lambda: self.check_peer_info(self.nodes[3], expected3), timeout=5)