def test_split(self): a = Address('127.0.0.1:80') host, port = a.split(':') self.assertEqual(host, '127.0.0.1') self.assertEqual(port, '80') host, port = a.rsplit(':', maxsplit=1) self.assertEqual(host, '127.0.0.1') self.assertEqual(port, '80')
def test_list_lookup(self): a = Address('127.0.0.1:80') b = Address('127.0.0.2:80') c = Address('127.0.0.1:80') d = Address('127.0.0.1:99') z = [a, b] self.assertTrue(a in z) self.assertTrue(b in z) # duplicate check, equals to 'a' self.assertTrue(c in z) self.assertFalse(d in z)
def _check_for_consecutive_disconnects(self, error_name): now = datetime.datetime.utcnow().timestamp() FIVE_MINUTES = 5 * 60 if self.address.last_connection != 0 and now - self.address.last_connection < FIVE_MINUTES: self.leader.AddDeadAddress(self.address, reason=f"{self.prefix} second {error_name} within 5 minutes") else: self.address.last_connection = Address.Now()
def buildProtocol(self, addr): print(f"building new protocol for addr: {addr}") self.leader.AddKnownAddress( Address(f"{addr.host}:{addr.port}")) p = NeoNode(incoming_client=True) p.factory = self return p
def RemoteNodePeerReceived(self, host, port, via_node_addr): addr = Address("%s:%s" % (host, port)) if addr not in self.KNOWN_ADDRS and addr not in self.DEAD_ADDRS: logger.debug( f"Adding new address {addr:>21} to known addresses list, received from {via_node_addr}" ) # we always want to save new addresses in case we lose all active connections before we can request a new list self.KNOWN_ADDRS.append(addr)
def test_repr_and_str(self): host = '127.0.0.1:80' a = Address(host, last_connection_to=0) self.assertEqual(host, str(a)) x = repr(a) self.assertIn("Address", x) self.assertIn(host, x)
def conn_setup(node: NeoNode): with self.assertLogHandler('network', 10) as log: # setup last_connection, to indicate we've lost connection before node.address.last_connection = Address.Now( ) # returns a timestamp of utcnow() # setup the heartbeat data to have last happened 25 seconds ago # if we disconnect now we should get a premature disconnect node.start_outstanding_data_request[ HEARTBEAT_BLOCKS] = Address.Now() - 25 # now lose the connection node.connectionLost(failure.Failure(error.ConnectionLost())) self.assertIn("Premature disconnect", log.output[-2]) self.assertIn(str(error.ConnectionLost()), log.output[-1]) self.assertIn(self.addr, self.leader.DEAD_ADDRS) self.assertNotIn(self.addr, self.leader.KNOWN_ADDRS) self.assertNotIn(self.addr, self.leader.Peers) self.assertFalse(node.has_tasks_running())
def connectionLost(self, reason=None): """Callback handler from twisted when a connection was lost.""" try: self.connected = False self.stop_block_loop() self.stop_peerinfo_loop() self.stop_header_loop() self.ReleaseBlockRequests() self.leader.RemoveConnectedPeer(self) time_expired = self.time_expired(HEARTBEAT_BLOCKS) # some NEO-cli versions have a 30s timeout to receive block/consensus or tx messages. By default neo-python doesn't respond to these requests if time_expired > 20: self.address.last_connection = Address.Now() self.leader.AddDeadAddress( self.address, reason=f"{self.prefix} Premature disconnect") if reason and reason.check(twisted_error.ConnectionDone): # this might happen if they close our connection because they've reached max peers or something similar logger.debug( f"{self.prefix} disconnected normally with reason:{reason.value}" ) self._check_for_consecutive_disconnects("connection done") elif reason and reason.check(twisted_error.ConnectionLost): # Can be due to a timeout. Only if this happened again within 5 minutes do we label the node as bad # because then it clearly doesn't want to talk to us or we have a bad connection to them. # Otherwise allow for the node to be queued again by NodeLeader. logger.debug( f"{self.prefix} disconnected with connectionlost reason: {reason.value}" ) self._check_for_consecutive_disconnects("connection lost") else: logger.debug( f"{self.prefix} disconnected with reason: {reason.value}") except Exception as e: logger.error("Error with connection lost: %s " % e) def try_me(err): err.check(error.ConnectionAborted) if self.disconnect_deferred: d, self.disconnect_deferred = self.disconnect_deferred, None # type: defer.Deferred d.addErrback(try_me) if len(d.callbacks) > 0: d.callback(reason) else: print("connLost, disconnect_deferred cancelling!") d.cancel()
def test_show_nodes(self): # query nodes with no NodeLeader.Instance() with patch('neo.Network.NodeLeader.NodeLeader.Instance'): args = ['nodes'] res = CommandShow().execute(args) self.assertFalse(res) # query nodes with connected peers # first make sure we have a predictable state NodeLeader.Instance().Reset() leader = NodeLeader.Instance() addr1 = Address("127.0.0.1:20333") addr2 = Address("127.0.0.1:20334") leader.ADDRS = [addr1, addr2] leader.DEAD_ADDRS = [Address("127.0.0.1:20335")] test_node = NeoNode() test_node.host = "127.0.0.1" test_node.port = 20333 test_node.address = Address("127.0.0.1:20333") leader.Peers = [test_node] # now show nodes with patch('neo.Network.NeoNode.NeoNode.Name', return_value="test name"): args = ['nodes'] res = CommandShow().execute(args) self.assertTrue(res) self.assertIn('Total Connected: 1', res) self.assertIn('Peer 0', res) # now use "node" args = ['node'] res = CommandShow().execute(args) self.assertTrue(res) self.assertIn('Total Connected: 1', res) self.assertIn('Peer 0', res)
def setUp(self): self.node = None self.leader = NodeLeader.Instance() host, port = '127.0.0.1', 8080 self.addr = Address(f"{host}:{port}") # we use a helper class such that we do not have to setup a real TCP connection peerAddress = IPv4Address('TCP', host, port) self.endpoint = TestTransportEndpoint( self.leader.reactor, str(self.addr), proto_helpers.StringTransportWithDisconnection( peerAddress=peerAddress)) # store our deferred so we can add callbacks self.d = self.leader.SetupConnection(self.addr, self.endpoint) # make sure we create a fully running client self.d.addCallback(self.do_handshake)
def conn_setup(node: NeoNode): # at this point we should have a fully connected node, so lets try to simulate a connection lost by the other side with self.assertLogHandler('network', 10) as log: # setup last_connection, to indicate we've lost connection before node.address.last_connection = Address.Now( ) # returns a timestamp of utcnow() # now lose the connection node.connectionLost(failure.Failure(error.ConnectionLost())) self.assertIn("second connection lost within 5 minutes", log.output[-1]) self.assertIn(str(error.ConnectionLost()), log.output[-2]) self.assertIn(self.addr, self.leader.DEAD_ADDRS) self.assertNotIn(self.addr, self.leader.KNOWN_ADDRS) self.assertNotIn(self.addr, self.leader.Peers) self.assertFalse(node.has_tasks_running())
def connectionMade(self): """Callback handler from twisted when establishing a new connection.""" self.endpoint = self.transport.getPeer() # get the reference to the Address object in NodeLeader so we can manipulate it properly. tmp_addr = Address(f"{self.endpoint.host}:{self.endpoint.port}") try: known_idx = self.leader.KNOWN_ADDRS.index(tmp_addr) self.address = self.leader.KNOWN_ADDRS[known_idx] except ValueError: # Not found. self.leader.AddKnownAddress(tmp_addr) self.address = tmp_addr self.address.address = "%s:%s" % (self.endpoint.host, self.endpoint.port) self.host = self.endpoint.host self.port = int(self.endpoint.port) self.leader.AddConnectedPeer(self) self.leader.RemoveFromQueue(self.address) self.leader.peers_connecting -= 1 logger.debug(f"{self.address} connection established") if self.incoming_client: # start protocol self.SendVersion()
def test_equality(self): """ Only the host:port matters in equality """ a = Address('127.0.0.1:80', last_connection_to=0) b = Address('127.0.0.1:80', last_connection_to=0) c = Address('127.0.0.1:99', last_connection_to=0) self.assertEqual(a, b) self.assertNotEqual(a, c) # last connected does not influence equality b.last_connection = 123 self.assertEqual(a, b) # different port does change equality b.address = "127.0.0.1:99" self.assertNotEqual(a, b) # test diff types self.assertNotEqual(int(1), a) self.assertNotEqual("127.0.0.1:80", a)
def Start(self, seed_list: List[str] = None, skip_seeds: bool = False) -> None: """ Start connecting to the seed list. Args: seed_list: a list of host:port strings if not supplied use list from `protocol.xxx.json` skip_seeds: skip connecting to seed list """ if not seed_list: seed_list = settings.SEED_LIST logger.debug("Starting up nodeleader") if not skip_seeds: logger.debug("Attempting to connect to seed list...") for bootstrap in seed_list: if not is_ip_address(bootstrap): host, port = bootstrap.split(':') bootstrap = f"{hostname_to_ip(host)}:{port}" addr = Address(bootstrap) self.KNOWN_ADDRS.append(addr) self.SetupConnection(addr) logger.debug( "Starting up nodeleader: starting peer, mempool, and blockheight check loops" ) # check in on peers every 10 seconds self.start_peer_check_loop() self.start_memcheck_loop() self.start_blockheight_loop() if settings.ACCEPT_INCOMING_PEERS and not self.incoming_server_running: class OneShotFactory(Factory): def __init__(self, leader): self.leader = leader def buildProtocol(self, addr): print(f"building new protocol for addr: {addr}") self.leader.AddKnownAddress( Address(f"{addr.host}:{addr.port}")) p = NeoNode(incoming_client=True) p.factory = self return p def listen_err(err): print(f"Failed start listening server for reason: {err.value}") def listen_ok(value): self.incoming_server_running = True logger.debug( f"Starting up nodeleader: setting up listen server on port: {settings.NODE_PORT}" ) server_endpoint = TCP4ServerEndpoint(self.reactor, settings.NODE_PORT) listenport_deferred = server_endpoint.listen( OneShotFactory(leader=self)) listenport_deferred.addCallback(listen_ok) listenport_deferred.addErrback(listen_err)
def test_str_formatting(self): a = Address('127.0.0.1:80') expected = " 127.0.0.1:80" out = f"{a:>15}" self.assertEqual(expected, out)
def test_config_maxpeers(self): # test no input and verify output confirming current maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers'] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn( f"Maintaining maxpeers at {settings.CONNECTED_PEER_MAX}", mock_print.getvalue()) # test changing the number of maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "6"] res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(int(res), settings.CONNECTED_PEER_MAX) self.assertIn(f"Maxpeers set to {settings.CONNECTED_PEER_MAX}", mock_print.getvalue()) # test bad input with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "blah"] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn("Please supply a positive integer for maxpeers", mock_print.getvalue()) # test negative number with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "-1"] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn("Please supply a positive integer for maxpeers", mock_print.getvalue()) # test if the new maxpeers < settings.CONNECTED_PEER_MAX # first make sure we have a predictable state NodeLeader.Instance().Reset() leader = NodeLeader.Instance() addr1 = Address("127.0.0.1:20333") addr2 = Address("127.0.0.1:20334") leader.ADDRS = [addr1, addr2] leader.DEAD_ADDRS = [Address("127.0.0.1:20335")] test_node = NeoNode() test_node.host = "127.0.0.1" test_node.port = 20333 test_node.address = Address("127.0.0.1:20333") test_node2 = NeoNode() test_node2.host = "127.0.0.1" test_node2.port = 20333 test_node2.address = Address("127.0.0.1:20334") leader.Peers = [test_node, test_node2] with patch( "neo.Network.NeoNode.NeoNode.Disconnect") as mock_disconnect: # first test if the number of connected peers !< new maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "4"] res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(len(leader.Peers), 2) self.assertFalse(mock_disconnect.called) self.assertIn(f"Maxpeers set to {settings.CONNECTED_PEER_MAX}", mock_print.getvalue()) # now test if the number of connected peers < new maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "1"] res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(len(leader.Peers), 1) self.assertEqual(leader.Peers[0].address, test_node.address) self.assertTrue(mock_disconnect.called) self.assertIn(f"Maxpeers set to {settings.CONNECTED_PEER_MAX}", mock_print.getvalue())
def test_now_helper(self): n = Address.Now() delta = datetime.now().utcnow().timestamp() - n self.assertTrue(delta < 2)