async def get_directly_linked_peers(chaindb1=None, received_msg_callback1=None, chaindb2=None, received_msg_callback2=None): """Create two LESPeers with their readers/writers connected directly. The first peer's reader will write directly to the second's writer, and vice-versa. """ if chaindb1 is None: chaindb1 = BaseChainDB(MemoryDB()) chaindb1.persist_header_to_db(MAINNET_GENESIS_HEADER) if chaindb2 is None: chaindb2 = BaseChainDB(MemoryDB()) chaindb2.persist_header_to_db(MAINNET_GENESIS_HEADER) peer1_private_key = ecies.generate_privkey() peer2_private_key = ecies.generate_privkey() peer1_remote = kademlia.Node( peer2_private_key.public_key, kademlia.Address('0.0.0.0', 0, 0)) peer2_remote = kademlia.Node( peer1_private_key.public_key, kademlia.Address('0.0.0.0', 0, 0)) initiator = auth.HandshakeInitiator(peer1_remote, peer1_private_key) peer2_reader = asyncio.StreamReader() peer1_reader = asyncio.StreamReader() # Link the peer1's writer to the peer2's reader, and the peer2's writer to the # peer1's reader. peer2_writer = type( "mock-streamwriter", (object,), {"write": peer1_reader.feed_data, "close": lambda: None} ) peer1_writer = type( "mock-streamwriter", (object,), {"write": peer2_reader.feed_data, "close": lambda: None} ) peer1, peer2 = None, None handshake_finished = asyncio.Event() async def do_handshake(): nonlocal peer1, peer2 aes_secret, mac_secret, egress_mac, ingress_mac = await auth._handshake( initiator, peer1_reader, peer1_writer) # Need to copy those before we pass them on to the Peer constructor because they're # mutable. Also, the 2nd peer's ingress/egress MACs are reversed from the first peer's. peer2_ingress = egress_mac.copy() peer2_egress = ingress_mac.copy() peer1 = LESPeerServing( remote=peer1_remote, privkey=peer1_private_key, reader=peer1_reader, writer=peer1_writer, aes_secret=aes_secret, mac_secret=mac_secret, egress_mac=egress_mac, ingress_mac=ingress_mac, chaindb=chaindb1, network_id=1, received_msg_callback=received_msg_callback1) peer2 = LESPeerServing( remote=peer2_remote, privkey=peer2_private_key, reader=peer2_reader, writer=peer2_writer, aes_secret=aes_secret, mac_secret=mac_secret, egress_mac=peer2_egress, ingress_mac=peer2_ingress, chaindb=chaindb2, network_id=1, received_msg_callback=received_msg_callback2) handshake_finished.set() asyncio.ensure_future(do_handshake()) responder = auth.HandshakeResponder(peer2_remote, peer2_private_key) auth_msg = await peer2_reader.read(constants.ENCRYPTED_AUTH_MSG_LEN) peer1_ephemeral_pubkey, peer1_nonce = responder.decode_authentication(auth_msg) peer2_nonce = keccak(os.urandom(constants.HASH_LEN)) auth_ack_msg = responder.create_auth_ack_message(peer2_nonce) auth_ack_ciphertext = responder.encrypt_auth_ack_message(auth_ack_msg) peer2_writer.write(auth_ack_ciphertext) await handshake_finished.wait() # Perform the base protocol (P2P) handshake. peer1.base_protocol.send_handshake() peer2.base_protocol.send_handshake() msg1 = await peer1.read_msg() peer1.process_msg(msg1) msg2 = await peer2.read_msg() peer2.process_msg(msg2) # Now send the handshake msg for each enabled sub-protocol. for proto in peer1.enabled_sub_protocols: proto.send_handshake(peer1._local_chain_info) for proto in peer2.enabled_sub_protocols: proto.send_handshake(peer2._local_chain_info) return peer1, peer2
async def _get_directly_linked_peers_without_handshake(peer1_class=LESPeer, peer1_chaindb=None, peer2_class=LESPeer, peer2_chaindb=None): """See get_directly_linked_peers(). Neither the P2P handshake nor the sub-protocol handshake will be performed here. """ if peer1_chaindb is None: peer1_chaindb = get_fresh_mainnet_chaindb() if peer2_chaindb is None: peer2_chaindb = get_fresh_mainnet_chaindb() peer1_private_key = ecies.generate_privkey() peer2_private_key = ecies.generate_privkey() peer1_remote = kademlia.Node(peer2_private_key.public_key, kademlia.Address('0.0.0.0', 0, 0)) peer2_remote = kademlia.Node(peer1_private_key.public_key, kademlia.Address('0.0.0.0', 0, 0)) initiator = auth.HandshakeInitiator(peer1_remote, peer1_private_key) peer2_reader = asyncio.StreamReader() peer1_reader = asyncio.StreamReader() # Link the peer1's writer to the peer2's reader, and the peer2's writer to the # peer1's reader. peer2_writer = type("mock-streamwriter", (object, ), { "write": peer1_reader.feed_data, "close": lambda: None }) peer1_writer = type("mock-streamwriter", (object, ), { "write": peer2_reader.feed_data, "close": lambda: None }) peer1, peer2 = None, None handshake_finished = asyncio.Event() async def do_handshake(): nonlocal peer1, peer2 aes_secret, mac_secret, egress_mac, ingress_mac = await auth._handshake( initiator, peer1_reader, peer1_writer) # Need to copy those before we pass them on to the Peer constructor because they're # mutable. Also, the 2nd peer's ingress/egress MACs are reversed from the first peer's. peer2_ingress = egress_mac.copy() peer2_egress = ingress_mac.copy() peer1 = peer1_class(remote=peer1_remote, privkey=peer1_private_key, reader=peer1_reader, writer=peer1_writer, aes_secret=aes_secret, mac_secret=mac_secret, egress_mac=egress_mac, ingress_mac=ingress_mac, chaindb=peer1_chaindb, network_id=1) peer2 = peer2_class(remote=peer2_remote, privkey=peer2_private_key, reader=peer2_reader, writer=peer2_writer, aes_secret=aes_secret, mac_secret=mac_secret, egress_mac=peer2_egress, ingress_mac=peer2_ingress, chaindb=peer2_chaindb, network_id=1) handshake_finished.set() asyncio.ensure_future(do_handshake()) responder = auth.HandshakeResponder(peer2_remote, peer2_private_key) auth_msg = await peer2_reader.read(constants.ENCRYPTED_AUTH_MSG_LEN) # Can't assert return values, but checking that the decoder doesn't raise # any exceptions at least. _, _ = responder.decode_authentication(auth_msg) peer2_nonce = keccak(os.urandom(constants.HASH_LEN)) auth_ack_msg = responder.create_auth_ack_message(peer2_nonce) auth_ack_ciphertext = responder.encrypt_auth_ack_message(auth_ack_msg) peer2_writer.write(auth_ack_ciphertext) await handshake_finished.wait() return peer1, peer2