From 0aa5c6e5619ed045bdff9328e1d4318a83661a9d Mon Sep 17 00:00:00 2001 From: Wojciech Dubiel Date: Tue, 25 Jul 2017 13:55:57 +0200 Subject: [PATCH 1/3] Fix offset-based cmd_id translation Make the loops in Peer.protocol_cmd_id_from_packet and Peer.send_packet sum the max_ids correctly --- devp2p/peer.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/devp2p/peer.py b/devp2p/peer.py index d3713aa..331eac7 100644 --- a/devp2p/peer.py +++ b/devp2p/peer.py @@ -178,11 +178,10 @@ def send_packet(self, packet): # rewrite cmd_id (backwards compatibility) if self.offset_based_dispatch: for i, protocol in enumerate(self.protocols.values()): - if packet.protocol_id > i: - packet.cmd_id += (0 if protocol.max_cmd_id == 0 else protocol.max_cmd_id + 1) if packet.protocol_id == protocol.protocol_id: break - packet.protocol_id = 0 + packet.cmd_id += (0 if protocol.max_cmd_id == 0 else protocol.max_cmd_id + 1) + packet.protocol_id = 0 self.mux.add_packet(packet) # receiving p2p messages @@ -193,8 +192,8 @@ def protocol_cmd_id_from_packet(self, packet): max_id = 0 for protocol in self.protocols.values(): if packet.cmd_id < max_id + protocol.max_cmd_id + 1: - return protocol, packet.cmd_id - (0 if max_id == 0 else max_id + 1) - max_id += protocol.max_cmd_id + return protocol, packet.cmd_id - max_id + max_id += protocol.max_cmd_id + 1 raise UnknownCommandError('no protocol for id %s' % packet.cmd_id) # new-style dispatch based on protocol_id for i, protocol in enumerate(self.protocols.values()): From 3d60418757646c400aca129a306b13e0a3225e9a Mon Sep 17 00:00:00 2001 From: Wojciech Dubiel Date: Tue, 25 Jul 2017 13:59:33 +0200 Subject: [PATCH 2/3] Add a regression test for offset-based cmd_id translation --- devp2p/tests/test_peer.py | 80 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/devp2p/tests/test_peer.py b/devp2p/tests/test_peer.py index 015a580..4030903 100644 --- a/devp2p/tests/test_peer.py +++ b/devp2p/tests/test_peer.py @@ -113,6 +113,86 @@ def mock_receive_hello(self, proto, version, client_version_string, b_app.stop() gevent.sleep(0.1) +def test_offset_dispatch(): + """ test offset-based cmd_id translation """ + + def make_mock_service(n, size): + class MockProtocol(devp2p.protocol.BaseProtocol): + protocol_id = n + max_cmd_id = size + name = b'mock%d' % n + version = 1 + def __init__(self, *args, **kwargs): + super(MockProtocol, self).__init__(*args, **kwargs) + self.cmd_by_id = ['mock_cmd%d' % i for i in range(size + 1)] + + class MockService(devp2p.service.WiredService): + name = 'mock%d' % n + default_config = {} + wire_protocol = MockProtocol + def __init__(self): + pass + return MockService() + + services = [ + make_mock_service(2, 7), + make_mock_service(19, 1), + ] + + class MockPeerManager(peermanager.PeerManager): + privkey = crypto.sha3(b'a') + pubkey = crypto.privtopub(privkey) + wired_services = services + config = { + 'client_version_string': 'mock', + 'p2p': {'listen_port': 3006}, + 'node': { + 'privkey_hex': encode_hex(privkey), + 'id': encode_hex(pubkey), + }} + def __init__(self): + pass + + class MockConnection(object): + def getpeername(*_): + return "mock" + + packets = [] + + def mock_add_packet(x): + packets.append(x) + + class MockPacket(object): + def __init__(self, proto, cmd, cookie): + self.protocol_id = proto + self.cmd_id = cmd + self.__cookie = cookie + + mpm = MockPeerManager() + p = peer.Peer(mpm, MockConnection()) + mpm.peers = [p] + p.offset_based_dispatch = True + p.mux.add_packet = mock_add_packet + p.connect_service(services[0]) + p.connect_service(services[1]) + for i in range(8): + p.send_packet(MockPacket(2, i, 'protoA%d' % i)) + for i in range(2): + p.send_packet(MockPacket(19, i, 'protoB%d' % i)) + for i in range(8): + pkt = packets.pop(0) + proto, cmd_id = p.protocol_cmd_id_from_packet(pkt) + assert proto.protocol_id == 2 + assert proto.name == b'mock2' + assert cmd_id == i + for i in range(2): + pkt = packets.pop(0) + proto, cmd_id = p.protocol_cmd_id_from_packet(pkt) + assert proto.protocol_id == 19 + assert proto.name == b'mock19' + assert cmd_id == i + + p.stop() def connect_go(): a_config = dict(p2p=dict(listen_host='127.0.0.1', listen_port=3010), From 662961fd3ec07dbd95b21e3acf8f1bd839e44340 Mon Sep 17 00:00:00 2001 From: Wojciech Dubiel Date: Fri, 28 Jul 2017 10:18:01 +0200 Subject: [PATCH 3/3] Make test_offset_dispatch compatible with python 3.4 --- devp2p/tests/test_peer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devp2p/tests/test_peer.py b/devp2p/tests/test_peer.py index 4030903..922adcb 100644 --- a/devp2p/tests/test_peer.py +++ b/devp2p/tests/test_peer.py @@ -11,7 +11,7 @@ import time import gevent import copy -from rlp.utils import encode_hex, decode_hex +from rlp.utils import encode_hex, decode_hex, str_to_bytes def get_connected_apps(): @@ -120,7 +120,7 @@ def make_mock_service(n, size): class MockProtocol(devp2p.protocol.BaseProtocol): protocol_id = n max_cmd_id = size - name = b'mock%d' % n + name = str_to_bytes('mock%d' % n) version = 1 def __init__(self, *args, **kwargs): super(MockProtocol, self).__init__(*args, **kwargs)