def setUp(self): self.public_ip = '123.45.67.89' self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ('132.54.76.98', 54321) self.addr2 = ('231.76.45.89', 15243) self.addr3 = ("193.193.111.00", 99999) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection(self.proto_mock, self.handler_mock, self.own_addr, self.addr1) valid_key = "63d901c4d57cde34fc1f1e28b9af5d56ed342cae5c2fb470046d0130a4226b0c" self.signing_key = nacl.signing.SigningKey( valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key h = nacl.hash.sha512(verify_key.encode()) self.storage = ForgetfulStorage() self.node = Node(unhexlify(h[:40]), self.public_ip, self.port, verify_key.encode(), None, FULL_CONE, True) self.db = Database(filepath="test.db") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db, self.signing_key) self.wire_protocol = OpenBazaarProtocol(self.db, self.own_addr, FULL_CONE) self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler( [self.protocol], self.wire_protocol, None, self.wire_protocol.ban_score) transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address('UDP', self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), 'getHost') self.wire_protocol.makeConnection(transport) self.node1 = Node(digest("id1"), self.addr1[0], self.addr1[1], digest("key1"), None, FULL_CONE, True) self.node2 = Node(digest("id2"), self.addr2[0], self.addr2[1], digest("key2"), None, FULL_CONE, True) self.node3 = Node(digest("id3"), self.addr3[0], self.addr3[1], digest("key3"), None, FULL_CONE, True)
def setUp(self): self.public_ip = '123.45.67.89' self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ('132.54.76.98', 54321) self.addr2 = ('231.76.45.89', 15243) self.addr3 = ("193.193.111.00", 99999) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection(self.proto_mock, self.handler_mock, self.own_addr, self.addr1) valid_key = "1a5c8e67edb8d279d1ae32fa2da97e236b95e95c837dc8c3c7c2ff7a7cc29855" self.signing_key = nacl.signing.SigningKey( valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key signed_pubkey = self.signing_key.sign(str(verify_key)) h = nacl.hash.sha512(signed_pubkey) self.storage = ForgetfulStorage() self.node = Node(unhexlify(h[:40]), self.public_ip, self.port, signed_pubkey, None, FULL_CONE, True) self.db = Database(filepath=":memory:") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db) self.wire_protocol = OpenBazaarProtocol(self.own_addr, FULL_CONE) self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler([self.protocol], self.wire_protocol, None) transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address('UDP', self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), 'getHost') self.wire_protocol.makeConnection(transport) self.node1 = Node(digest("id1"), self.addr1[0], self.addr1[1], digest("key1"), None, FULL_CONE, True) self.node2 = Node(digest("id2"), self.addr2[0], self.addr2[1], digest("key2"), None, FULL_CONE, True) self.node3 = Node(digest("id3"), self.addr3[0], self.addr3[1], digest("key3"), None, FULL_CONE, True)
def setUp(self): self.public_ip = '123.45.67.89' self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ('132.54.76.98', 54321) self.addr2 = ('231.76.45.89', 15243) self.addr3 = ("193.193.111.00", 99999) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection( self.proto_mock, self.handler_mock, self.own_addr, self.addr1 ) valid_key = "63d901c4d57cde34fc1f1e28b9af5d56ed342cae5c2fb470046d0130a4226b0c" self.signing_key = nacl.signing.SigningKey(valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key h = nacl.hash.sha512(verify_key.encode()) self.storage = ForgetfulStorage() self.node = Node(unhexlify(h[:40]), self.public_ip, self.port, verify_key.encode(), None, FULL_CONE, True) self.db = Database(filepath="test.db") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db, self.signing_key) self.wire_protocol = OpenBazaarProtocol(self.db, self.own_addr, FULL_CONE) self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler([self.protocol], self.wire_protocol, None, self.wire_protocol.ban_score) transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address('UDP', self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), 'getHost') self.wire_protocol.makeConnection(transport) self.node1 = Node(digest("id1"), self.addr1[0], self.addr1[1], digest("key1"), None, FULL_CONE, True) self.node2 = Node(digest("id2"), self.addr2[0], self.addr2[1], digest("key2"), None, FULL_CONE, True) self.node3 = Node(digest("id3"), self.addr3[0], self.addr3[1], digest("key3"), None, FULL_CONE, True)
def setUp(self): self.public_ip = '123.45.67.89' self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ('132.54.76.98', 54321) self.addr2 = ('231.76.45.89', 15243) self.addr3 = ("193.193.111.00", 99999) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection( self.proto_mock, self.handler_mock, self.own_addr, self.addr1 ) valid_key = "1a5c8e67edb8d279d1ae32fa2da97e236b95e95c837dc8c3c7c2ff7a7cc29855" self.signing_key = nacl.signing.SigningKey(valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key signed_pubkey = self.signing_key.sign(str(verify_key)) h = nacl.hash.sha512(signed_pubkey) self.storage = ForgetfulStorage() self.node = Node(unhexlify(h[:40]), self.public_ip, self.port, signed_pubkey, None, FULL_CONE, True) self.db = Database(filepath=":memory:") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db) self.wire_protocol = OpenBazaarProtocol(self.own_addr, FULL_CONE) self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler([self.protocol], self.wire_protocol, None) transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address('UDP', self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), 'getHost') self.wire_protocol.makeConnection(transport) self.node1 = Node(digest("id1"), self.addr1[0], self.addr1[1], digest("key1"), None, FULL_CONE, True) self.node2 = Node(digest("id2"), self.addr2[0], self.addr2[1], digest("key2"), None, FULL_CONE, True) self.node3 = Node(digest("id3"), self.addr3[0], self.addr3[1], digest("key3"), None, FULL_CONE, True)
def setUp(self): self.version = PROTOCOL_VERSION self.public_ip = "123.45.67.89" self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ("132.54.76.98", 54321) self.addr2 = ("231.76.45.89", 15243) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection(self.proto_mock, self.handler_mock, self.own_addr, self.addr1) valid_key = "63d901c4d57cde34fc1f1e28b9af5d56ed342cae5c2fb470046d0130a4226b0c" self.signing_key = nacl.signing.SigningKey(valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key h = nacl.hash.sha512(verify_key.encode()) self.storage = ForgetfulStorage() self.node = Node( unhexlify(h[:40]), self.public_ip, self.port, verify_key.encode(), None, objects.FULL_CONE, True ) self.db = datastore.Database(filepath="test.db") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db, self.signing_key) self.wire_protocol = OpenBazaarProtocol(self.own_addr, objects.FULL_CONE) self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler([self.protocol], self.wire_protocol, None) self.handler.connection = self.con transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address("UDP", self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), "getHost") self.wire_protocol.makeConnection(transport)
def setUp(self): self.version = PROTOCOL_VERSION self.public_ip = "123.45.67.89" self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ("132.54.76.98", 54321) self.addr2 = ("231.76.45.89", 15243) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection(self.proto_mock, self.handler_mock, self.own_addr, self.addr1) valid_key = "1a5c8e67edb8d279d1ae32fa2da97e236b95e95c837dc8c3c7c2ff7a7cc29855" self.signing_key = nacl.signing.SigningKey(valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key signed_pubkey = self.signing_key.sign(str(verify_key)) h = nacl.hash.sha512(signed_pubkey) self.storage = ForgetfulStorage() self.node = Node(unhexlify(h[:40]), self.public_ip, self.port, signed_pubkey, True) self.db = datastore.Database(filepath="test.db") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db) self.wire_protocol = OpenBazaarProtocol(self.own_addr, "Full Cone") self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler([self.protocol], self.wire_protocol) self.handler.connection = self.con transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address("UDP", self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), "getHost") self.wire_protocol.makeConnection(transport)
def run(*args): TESTNET = args[0] SSL = args[5] # database db = Database(TESTNET) # key generation keys = KeyChain(db) # logging logFile = logfile.LogFile.fromFullPath(DATA_FOLDER + "debug.log", rotateLength=15000000, maxRotatedFiles=1) log.addObserver(FileLogObserver(logFile, level=args[1]).emit) log.addObserver(FileLogObserver(level=args[1]).emit) logger = Logger(system="OpenBazaard") # NAT traversal port = args[2] PortMapper().add_port_mapping(port, port, 'UDP') logger.info("Finding NAT Type...") while True: try: response = stun.get_ip_info(source_port=port) break except Exception: pass logger.info("%s on %s:%s" % (response[0], response[1], response[2])) ip_address = response[1] port = response[2] # TODO: use TURN if symmetric NAT def on_bootstrap_complete(resp): logger.info("bootstrap complete, downloading outstanding messages...") mserver.get_messages(mlistener) # TODO: ping seed node to establish connection if not full cone NAT # TODO: after bootstrap run through any pending contracts and see if the bitcoin address # has been funded, if not listen on the address and start the 10 minute delete timer. protocol = OpenBazaarProtocol((ip_address, port), response[0], testnet=TESTNET) # kademlia node = Node(keys.guid, ip_address, port, signed_pubkey=keys.guid_signed_pubkey, vendor=Profile(db).get().vendor) storage = ForgetfulStorage() if TESTNET else PersistentStorage(db.DATABASE) try: kserver = Server.loadState(DATA_FOLDER + 'cache.pickle', ip_address, port, protocol, db, on_bootstrap_complete, storage=storage) except Exception: kserver = Server(node, db, KSIZE, ALPHA, storage=storage) kserver.protocol.connect_multiplexer(protocol) kserver.bootstrap(kserver.querySeed(SEED)).addCallback(on_bootstrap_complete) kserver.saveStateRegularly(DATA_FOLDER + 'cache.pickle', 10) protocol.register_processor(kserver.protocol) # market mserver = network.Server(kserver, keys.signing_key, db) mserver.protocol.connect_multiplexer(protocol) protocol.register_processor(mserver.protocol) reactor.listenUDP(port, protocol) class OnlyIP(Site): def __init__(self, resource, ip, timeout=60 * 60 * 1): self.ip = ip Site.__init__(self, resource, timeout=timeout) def buildProtocol(self, addr): if addr.host == self.ip: return Site.buildProtocol(self, addr) return None # websockets api if SSL: ws_factory = WSFactory("wss://127.0.0.1:18466", mserver, kserver) contextFactory = ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT) ws_factory.protocol = WSProtocol ws_factory.setProtocolOptions(allowHixie76=True) listenWS(ws_factory, contextFactory) else: ws_factory = WSFactory("ws://127.0.0.1:18466", mserver, kserver) ws_factory.protocol = WSProtocol ws_factory.setProtocolOptions(allowHixie76=True) listenWS(ws_factory) webdir = File(".") if args[4] != "127.0.0.1" and args[4] != "0.0.0.0": ws_interface = "0.0.0.0" web = OnlyIP(webdir, args[4]) else: ws_interface = args[4] web = Site(webdir) reactor.listenTCP(18465, web, interface=ws_interface) # rest api api = OpenBazaarAPI(mserver, kserver, protocol) if args[3] != "127.0.0.1" and args[3] != "0.0.0.0": rest_interface = "0.0.0.0" site = OnlyIP(api, args[3], timeout=None) else: rest_interface = args[3] site = Site(api, timeout=None) if SSL: reactor.listenSSL(18469, site, ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=rest_interface) else: reactor.listenTCP(18469, site, interface=rest_interface) # blockchain if TESTNET: libbitcoin_client = LibbitcoinClient(LIBBITCOIN_SERVER_TESTNET) else: libbitcoin_client = LibbitcoinClient(LIBBITCOIN_SERVER) def heartbeat(): f = HeartbeatFactory(libbitcoin_client) if TESTNET: reactor.connectTCP(LIBBITCOIN_SERVER_TESTNET[6: LIBBITCOIN_SERVER_TESTNET.index(":", 6)], 9092, f) else: reactor.connectTCP(LIBBITCOIN_SERVER[6: LIBBITCOIN_SERVER.index(":", 6)], 9092, f) task.LoopingCall(heartbeat).start(300) # listeners nlistener = NotificationListenerImpl(ws_factory, db) mserver.protocol.add_listener(nlistener) mlistener = MessageListenerImpl(ws_factory, db) mserver.protocol.add_listener(mlistener) blistener = BroadcastListenerImpl(ws_factory, db) mserver.protocol.add_listener(blistener) protocol.set_servers(ws_factory, libbitcoin_client) reactor.run()
class KademliaProtocolTest(unittest.TestCase): def setUp(self): self.version = PROTOCOL_VERSION self.public_ip = '123.45.67.89' self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ('132.54.76.98', 54321) self.addr2 = ('231.76.45.89', 15243) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection( self.proto_mock, self.handler_mock, self.own_addr, self.addr1 ) valid_key = "63d901c4d57cde34fc1f1e28b9af5d56ed342cae5c2fb470046d0130a4226b0c" self.signing_key = nacl.signing.SigningKey(valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key h = nacl.hash.sha512(verify_key.encode()) self.storage = ForgetfulStorage() self.node = Node(unhexlify(h[:40]), self.public_ip, self.port, verify_key.encode(), None, objects.FULL_CONE, True) self.db = datastore.Database(filepath="test.db") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db, self.signing_key) self.wire_protocol = OpenBazaarProtocol(self.db, self.own_addr, objects.FULL_CONE) self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler([self.protocol], self.wire_protocol, None) self.handler.connection = self.con transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address('UDP', self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), 'getHost') self.wire_protocol.makeConnection(transport) def tearDown(self): if self.con.state != connection.State.SHUTDOWN: self.con.shutdown() self.wire_protocol.shutdown() os.remove("test.db") def test_invalid_datagram(self): self.assertFalse(self.handler.receive_message("hi")) self.assertFalse(self.handler.receive_message("hihihihihihihihihihihihihihihihihihihihih")) def test_rpc_ping(self): self._connecting_to_connected() m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("PING") m.protoVer = self.version m.testnet = False m.signature = self.signing_key.sign(m.SerializeToString())[:64] data = m.SerializeToString() m.arguments.append(self.protocol.sourceNode.getProto().SerializeToString()) m.ClearField("signature") expected_message = m.SerializeToString() self.handler.on_connection_made() self.handler.receive_message(data) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() m_calls = self.proto_mock.send_datagram.call_args_list sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) received_message = sent_packet.payload m2 = message.Message() m2.ParseFromString(received_message) m2.ClearField("signature") received_message = m2.SerializeToString() self.assertEqual(received_message, expected_message) self.assertEqual(len(m_calls), 2) def test_rpc_store(self): self._connecting_to_connected() self.protocol.router.addContact(self.protocol.sourceNode) m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("STORE") m.protoVer = self.version m.testnet = False m.arguments.extend([digest("Keyword"), "Key", self.protocol.sourceNode.getProto().SerializeToString(), str(10)]) m.signature = self.signing_key.sign(m.SerializeToString())[:64] data = m.SerializeToString() del m.arguments[-4:] m.arguments.append("True") m.ClearField("signature") expected_message = m.SerializeToString() self.handler.on_connection_made() self.handler.receive_message(data) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() m_calls = self.proto_mock.send_datagram.call_args_list sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) received_message = sent_packet.payload m2 = message.Message() m2.ParseFromString(received_message) m2.ClearField("signature") received_message = m2.SerializeToString() self.assertEqual(received_message, expected_message) self.assertEqual(len(m_calls), 2) self.assertTrue( self.storage.getSpecific(digest("Keyword"), "Key") == self.protocol.sourceNode.getProto().SerializeToString()) def test_bad_rpc_store(self): r = self.protocol.rpc_store(self.node, 'testkeyword', 'kw', 'val', 10) self.assertEqual(r, ['False']) def test_rpc_delete(self): self._connecting_to_connected() self.protocol.router.addContact(self.protocol.sourceNode) # Set a keyword to store m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("STORE") m.protoVer = self.version m.testnet = False m.arguments.extend([digest("Keyword"), "Key", self.protocol.sourceNode.getProto().SerializeToString(), str(10)]) m.signature = self.signing_key.sign(m.SerializeToString())[:64] data = m.SerializeToString() del m.arguments[-4:] m.arguments.append("True") m.ClearField("signature") expected_message1 = m.SerializeToString() self.handler.on_connection_made() self.handler.receive_message(data) self.assertTrue( self.storage.getSpecific(digest("Keyword"), "Key") == self.protocol.sourceNode.getProto().SerializeToString()) # Test bad signature m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("DELETE") m.protoVer = self.version m.testnet = False m.arguments.extend([digest("Keyword"), "Key", "Bad Signature"]) m.signature = self.signing_key.sign(m.SerializeToString())[:64] data = m.SerializeToString() del m.arguments[-3:] m.arguments.append("False") m.ClearField("signature") expected_message2 = m.SerializeToString() self.handler.receive_message(data) self.assertTrue( self.storage.getSpecific(digest("Keyword"), "Key") == self.protocol.sourceNode.getProto().SerializeToString()) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() sent_packets = tuple( packet.Packet.from_bytes(call[0][0]) for call in self.proto_mock.send_datagram.call_args_list ) m2 = message.Message() m2.ParseFromString(sent_packets[0].payload) m2.ClearField("signature") received_message1 = m2.SerializeToString() m3 = message.Message() m3.ParseFromString(sent_packets[1].payload) m3.ClearField("signature") received_message2 = m3.SerializeToString() self.assertEqual(received_message1, expected_message1) self.assertEqual(received_message2, expected_message2) self.proto_mock.send_datagram.call_args_list = [] # Test good signature m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("DELETE") m.protoVer = self.version m.testnet = False m.arguments.extend([digest("Keyword"), "Key", self.signing_key.sign("Key")[:64]]) m.signature = self.signing_key.sign(m.SerializeToString())[:64] data = m.SerializeToString() del m.arguments[-3:] m.arguments.append("True") m.ClearField("signature") expected_message3 = m.SerializeToString() self.handler.receive_message(data) self.clock.advance(100 * constants.PACKET_TIMEOUT) sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) m4 = message.Message() m4.ParseFromString(sent_packet.payload) m4.ClearField("signature") received_message = m4.SerializeToString() self.assertEqual(received_message, expected_message3) self.assertTrue(self.storage.getSpecific(digest("Keyword"), "Key") is None) def test_rpc_stun(self): self._connecting_to_connected() m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("STUN") m.protoVer = self.version m.testnet = False m.signature = self.signing_key.sign(m.SerializeToString())[:64] data = m.SerializeToString() m.arguments.extend([self.public_ip, str(self.port)]) m.ClearField("signature") expected_message = m.SerializeToString() self.handler.on_connection_made() self.handler.receive_message(data) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() m_calls = self.proto_mock.send_datagram.call_args_list sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) received_message = sent_packet.payload a = message.Message() a.ParseFromString(received_message) a.ClearField("signature") received_message = a.SerializeToString() self.assertEqual(received_message, expected_message) self.assertEqual(len(m_calls), 2) def test_rpc_find_node(self): self._connecting_to_connected() node1 = Node(digest("id1"), "127.0.0.1", 12345, digest("key1"), nat_type=objects.FULL_CONE) node2 = Node(digest("id2"), "127.0.0.1", 22222, digest("key2"), nat_type=objects.FULL_CONE) node3 = Node(digest("id3"), "127.0.0.1", 77777, digest("key3"), nat_type=objects.FULL_CONE) self.protocol.router.addContact(node1) self.protocol.router.addContact(node2) self.protocol.router.addContact(node3) m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("FIND_NODE") m.protoVer = self.version m.testnet = False m.arguments.append(digest("nodetofind")) m.signature = self.signing_key.sign(m.SerializeToString())[:64] data = m.SerializeToString() del m.arguments[-1] m.arguments.extend([node2.getProto().SerializeToString(), node1.getProto().SerializeToString(), node3.getProto().SerializeToString()]) m.ClearField("signature") expected_message = m.SerializeToString() self.handler.on_connection_made() self.handler.receive_message(data) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() m_calls = self.proto_mock.send_datagram.call_args_list sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) received_message = sent_packet.payload a = message.Message() a.ParseFromString(received_message) a.ClearField("signature") received_message = a.SerializeToString() self.assertEqual(received_message, expected_message) self.assertEqual(len(m_calls), 2) def test_rpc_find_value(self): self._connecting_to_connected() self.protocol.router.addContact(self.protocol.sourceNode) # Set a value to find m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("STORE") m.protoVer = self.version m.arguments.extend([digest("Keyword"), "Key", self.protocol.sourceNode.getProto().SerializeToString(), str(10)]) m.signature = self.signing_key.sign(m.SerializeToString())[:64] data = m.SerializeToString() self.handler.on_connection_made() self.handler.receive_message(data) self.assertTrue( self.storage.getSpecific(digest("Keyword"), "Key") == self.protocol.sourceNode.getProto().SerializeToString()) # Send the find_value rpc m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("FIND_VALUE") m.protoVer = self.version m.testnet = False m.arguments.append(digest("Keyword")) m.signature = self.signing_key.sign(m.SerializeToString())[:64] data = m.SerializeToString() self.handler.receive_message(data) del m.arguments[-1] value = objects.Value() value.valueKey = "Key" value.serializedData = self.protocol.sourceNode.getProto().SerializeToString() value.ttl = 10 m.arguments.append("value") m.arguments.append(value.SerializeToString()) m.ClearField("signature") expected_message = m.SerializeToString() self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() m_calls = self.proto_mock.send_datagram.call_args_list sent_packets = tuple( packet.Packet.from_bytes(call[0][0]) for call in self.proto_mock.send_datagram.call_args_list ) received_message = sent_packets[1].payload a = message.Message() a.ParseFromString(received_message) a.ClearField("signature") received_message = a.SerializeToString() self.assertEqual(received_message, expected_message) self.assertEqual(len(m_calls), 3) def test_rpc_find_without_value(self): self._connecting_to_connected() node1 = Node(digest("id1"), "127.0.0.1", 12345, digest("key1"), nat_type=objects.FULL_CONE) node2 = Node(digest("id2"), "127.0.0.1", 22222, digest("key2"), nat_type=objects.FULL_CONE) node3 = Node(digest("id3"), "127.0.0.1", 77777, digest("key3"), nat_type=objects.FULL_CONE) self.protocol.router.addContact(node1) self.protocol.router.addContact(node2) self.protocol.router.addContact(node3) m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("FIND_VALUE") m.protoVer = self.version m.testnet = False m.arguments.append(digest("Keyword")) m.signature = self.signing_key.sign(m.SerializeToString())[:64] data = m.SerializeToString() self.handler.on_connection_made() self.handler.receive_message(data) del m.arguments[-1] m.arguments.extend([node3.getProto().SerializeToString(), node1.getProto().SerializeToString(), node2.getProto().SerializeToString()]) m.ClearField("signature") expected_message = m.SerializeToString() self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() m_calls = self.proto_mock.send_datagram.call_args_list sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) received_message = sent_packet.payload a = message.Message() a.ParseFromString(received_message) a.ClearField("signature") received_message = a.SerializeToString() self.assertEqual(received_message, expected_message) self.assertEqual(len(m_calls), 2) def test_callPing(self): self._connecting_to_connected() n = Node(digest("guid"), self.addr1[0], self.addr1[1], digest("pubkey"), None, objects.FULL_CONE, False) self.wire_protocol[self.addr1] = self.con self.protocol.callPing(n) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload m = message.Message() m.ParseFromString(sent_message) self.assertTrue(len(m.messageID) == 20) self.assertEqual(self.protocol.sourceNode.getProto().guid, m.sender.guid) self.assertEqual(self.protocol.sourceNode.getProto().publicKey, m.sender.publicKey) self.assertTrue(m.command == message.PING) self.assertEqual(self.proto_mock.send_datagram.call_args_list[0][0][1], self.addr1) def test_callStore(self): self._connecting_to_connected() n = Node(digest("guid"), self.addr1[0], self.addr1[1], digest("pubkey"), None, objects.FULL_CONE, False) self.wire_protocol[self.addr1] = self.con self.protocol.callStore(n, digest("Keyword"), digest("Key"), self.protocol.sourceNode.getProto().SerializeToString(), 10) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload m = message.Message() m.ParseFromString(sent_message) self.assertTrue(len(m.messageID) == 20) self.assertEqual(self.protocol.sourceNode.getProto().guid, m.sender.guid) self.assertEqual(self.protocol.sourceNode.getProto().publicKey, m.sender.publicKey) self.assertTrue(m.command == message.STORE) self.assertEqual(self.proto_mock.send_datagram.call_args_list[0][0][1], self.addr1) self.assertEqual(m.arguments[0], digest("Keyword")) self.assertEqual(m.arguments[1], digest("Key")) self.assertEqual(m.arguments[2], self.protocol.sourceNode.getProto().SerializeToString()) def test_callFindValue(self): self._connecting_to_connected() n = Node(digest("S"), self.addr1[0], self.addr1[1]) self.wire_protocol[self.addr1] = self.con keyword = Node(digest("Keyword")) self.protocol.callFindValue(n, keyword) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload m = message.Message() m.ParseFromString(sent_message) self.assertTrue(len(m.messageID) == 20) self.assertEqual(self.protocol.sourceNode.getProto().guid, m.sender.guid) self.assertEqual(self.protocol.sourceNode.getProto().publicKey, m.sender.publicKey) self.assertTrue(m.command == message.FIND_VALUE) self.assertEqual(self.proto_mock.send_datagram.call_args_list[0][0][1], self.addr1) self.assertEqual(m.arguments[0], keyword.id) def test_callFindNode(self): self._connecting_to_connected() n = Node(digest("S"), self.addr1[0], self.addr1[1]) self.wire_protocol[self.addr1] = self.con keyword = Node(digest("nodetofind")) self.protocol.callFindNode(n, keyword) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload m = message.Message() m.ParseFromString(sent_message) self.assertTrue(len(m.messageID) == 20) self.assertEqual(self.protocol.sourceNode.getProto().guid, m.sender.guid) self.assertEqual(self.protocol.sourceNode.getProto().publicKey, m.sender.publicKey) self.assertTrue(m.command == message.FIND_NODE) self.assertEqual(self.proto_mock.send_datagram.call_args_list[0][0][1], self.addr1) self.assertEqual(m.arguments[0], keyword.id) def test_callDelete(self): self._connecting_to_connected() n = Node(digest("S"), self.addr1[0], self.addr1[1]) self.wire_protocol[self.addr1] = self.con self.protocol.callDelete(n, digest("Keyword"), digest("Key"), digest("Signature")) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload m = message.Message() m.ParseFromString(sent_message) self.assertEqual(self.proto_mock.send_datagram.call_args_list[0][0][1], self.addr1) self.assertTrue(len(m.messageID) == 20) self.assertEqual(self.protocol.sourceNode.getProto().guid, m.sender.guid) self.assertEqual(self.protocol.sourceNode.getProto().publicKey, m.sender.publicKey) self.assertTrue(m.command == message.DELETE) self.assertEqual(m.arguments[0], digest("Keyword")) self.assertEqual(m.arguments[1], digest("Key")) self.assertEqual(m.arguments[2], digest("Signature")) def test_acceptResponse(self): self._connecting_to_connected() def handle_response(resp): self.assertTrue(resp[0]) self.assertEqual(resp[1][0], "test") self.assertTrue(message_id not in self.protocol._outstanding) message_id = digest("msgid") n = Node(digest("S"), self.addr1[0], self.addr1[1]) d = defer.Deferred() self.protocol._outstanding[message_id] = (d, self.addr1, reactor.callLater(5, handle_response)) self.protocol._acceptResponse(message_id, ["test"], n) return d.addCallback(handle_response) def test_unknownRPC(self): self.assertFalse(self.handler.receive_message(str(random.getrandbits(1400)))) def test_timeout(self): def handle_response(resp, n): self.assertFalse(resp[0]) self.assertIsNone(resp[1]) n = Node(digest("S"), self.addr1[0], self.addr1[1]) d = defer.Deferred().addCallback(handle_response, n) self.protocol._outstanding["msgID"] = [d, self.addr1, reactor.callLater(5, handle_response)] self.protocol.router.addContact(n) self.protocol.timeout(n) def test_transferKeyValues(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.protocol.storage[digest("keyword")] = ( digest("key"), self.protocol.sourceNode.getProto().SerializeToString(), 10) self.protocol.storage[digest("keyword")] = ( digest("key2"), self.protocol.sourceNode.getProto().SerializeToString(), 10) self.protocol.transferKeyValues(Node(digest("id"), self.addr1[0], self.addr1[1])) self.clock.advance(1) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload x = message.Message() x.ParseFromString(sent_message) i = objects.Inv() i.keyword = digest("keyword") i.valueKey = digest("key") i2 = objects.Inv() i2.keyword = digest("keyword") i2.valueKey = digest("key2") m = message.Message() m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("INV") m.protoVer = self.version m.arguments.append(i.SerializeToString()) m.arguments.append(i2.SerializeToString()) self.assertEqual(x.sender.guid, m.sender.guid) self.assertEqual(x.command, m.command) self.assertTrue(x.arguments[0] in m.arguments) self.assertTrue(x.arguments[1] in m.arguments) def test_refreshIDs(self): node1 = Node(digest("id1"), "127.0.0.1", 12345, pubkey=digest("key1")) node2 = Node(digest("id2"), "127.0.0.1", 22222, pubkey=digest("key2")) node3 = Node(digest("id3"), "127.0.0.1", 77777, pubkey=digest("key3")) self.protocol.router.addContact(node1) self.protocol.router.addContact(node2) self.protocol.router.addContact(node3) for b in self.protocol.router.buckets: b.lastUpdated = (time.time() - 5000) ids = self.protocol.getRefreshIDs() self.assertTrue(len(ids) == 1) def _connecting_to_connected(self): remote_synack_packet = packet.Packet.from_data( 42, self.con.own_addr, self.con.dest_addr, ack=0, syn=True ) self.con.receive_packet(remote_synack_packet, self.addr1) self.clock.advance(0) connection.REACTOR.runUntilCurrent() self.next_remote_seqnum = 43 m_calls = self.proto_mock.send_datagram.call_args_list sent_syn_packet = packet.Packet.from_bytes(m_calls[0][0][0]) seqnum = sent_syn_packet.sequence_number self.handler_mock.reset_mock() self.proto_mock.reset_mock() self.next_seqnum = seqnum + 1 def test_badRPCDelete(self): n = Node(digest("S"), self.addr1[0], self.addr1[1]) val = self.protocol.rpc_delete(n, 'testkeyword', 'key', 'testsig') self.assertEqual(val, ["False"]) val = self.protocol.rpc_delete(n, '', '', '')
def start_server(keys, first_startup=False): # logging logFile = logfile.LogFile.fromFullPath( os.path.join(DATA_FOLDER, "debug.log"), rotateLength=15000000, maxRotatedFiles=1) log.addObserver(FileLogObserver(logFile, level=LOGLEVEL).emit) log.addObserver(FileLogObserver(level=LOGLEVEL).emit) logger = Logger(system="OpenBazaard") # NAT traversal p = PortMapper() p.add_port_mapping(PORT, PORT, "UDP") logger.info("Finding NAT Type...") response = looping_retry(stun.get_ip_info, "0.0.0.0", PORT) logger.info("%s on %s:%s" % (response[0], response[1], response[2])) ip_address = response[1] port = response[2] if response[0] == "Full Cone": nat_type = FULL_CONE elif response[0] == "Restric NAT": nat_type = RESTRICTED else: nat_type = SYMMETRIC def on_bootstrap_complete(resp): logger.info("bootstrap complete") task.LoopingCall(mserver.get_messages, mlistener).start(3600) task.LoopingCall(check_unfunded_for_payment, db, libbitcoin_client, nlistener, TESTNET).start(600) task.LoopingCall(rebroadcast_unconfirmed, db, libbitcoin_client, TESTNET).start(600) protocol = OpenBazaarProtocol(db, (ip_address, port), nat_type, testnet=TESTNET, relaying=True if nat_type == FULL_CONE else False) # kademlia SEED_URLS = SEEDS_TESTNET if TESTNET else SEEDS relay_node = None if nat_type != FULL_CONE: for seed in SEED_URLS: try: relay_node = (socket.gethostbyname(seed[0].split(":")[0]), 28469 if TESTNET else 18469) break except socket.gaierror: pass try: kserver = Server.loadState(os.path.join(DATA_FOLDER, 'cache.pickle'), ip_address, port, protocol, db, nat_type, relay_node, on_bootstrap_complete, storage) except Exception: node = Node(keys.guid, ip_address, port, keys.verify_key.encode(), relay_node, nat_type, Profile(db).get().vendor) protocol.relay_node = node.relay_node kserver = Server(node, db, keys.signing_key, KSIZE, ALPHA, storage=storage) kserver.protocol.connect_multiplexer(protocol) kserver.bootstrap(kserver.querySeed(SEED_URLS)).addCallback(on_bootstrap_complete) kserver.saveStateRegularly(os.path.join(DATA_FOLDER, 'cache.pickle'), 10) protocol.register_processor(kserver.protocol) # market mserver = network.Server(kserver, keys.signing_key, db) mserver.protocol.connect_multiplexer(protocol) protocol.register_processor(mserver.protocol) looping_retry(reactor.listenUDP, port, protocol) interface = "0.0.0.0" if ALLOWIP != ["127.0.0.1"] else "127.0.0.1" # websockets api authenticated_sessions = [] ws_api = WSFactory(mserver, kserver, only_ip=ALLOWIP) ws_factory = AuthenticatedWebSocketFactory(ws_api) ws_factory.authenticated_sessions = authenticated_sessions ws_factory.protocol = AuthenticatedWebSocketProtocol if SSL: reactor.listenSSL(WSPORT, ws_factory, ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=interface) else: reactor.listenTCP(WSPORT, ws_factory, interface=interface) # rest api rest_api = RestAPI(mserver, kserver, protocol, username, password, authenticated_sessions, only_ip=ALLOWIP) if SSL: reactor.listenSSL(RESTPORT, rest_api, ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=interface) else: reactor.listenTCP(RESTPORT, rest_api, interface=interface) # blockchain if TESTNET: libbitcoin_client = LibbitcoinClient(LIBBITCOIN_SERVERS_TESTNET, log=Logger(service="LibbitcoinClient")) else: libbitcoin_client = LibbitcoinClient(LIBBITCOIN_SERVERS, log=Logger(service="LibbitcoinClient")) heartbeat_server.libbitcoin = libbitcoin_client # listeners nlistener = NotificationListenerImpl(ws_api, db) mserver.protocol.add_listener(nlistener) mlistener = MessageListenerImpl(ws_api, db) mserver.protocol.add_listener(mlistener) blistener = BroadcastListenerImpl(ws_api, db) mserver.protocol.add_listener(blistener) protocol.set_servers(ws_api, libbitcoin_client) if first_startup: heartbeat_server.push(json.dumps({ "status": "GUID generation complete", "username": username, "password": password })) heartbeat_server.set_status("online") logger.info("startup took %s seconds" % str(round(time.time() - args[7], 2))) def shutdown(): logger.info("shutting down server") for vendor in protocol.vendors.values(): db.vendors.save_vendor(vendor.id.encode("hex"), vendor.getProto().SerializeToString()) PortMapper().clean_my_mappings(PORT) protocol.shutdown() reactor.addSystemEventTrigger('before', 'shutdown', shutdown)
def run(*args): TESTNET = args[0] SSL = args[5] # database db = Database(TESTNET) # key generation keys = KeyChain(db) # logging logFile = logfile.LogFile.fromFullPath(DATA_FOLDER + "debug.log", rotateLength=15000000, maxRotatedFiles=1) log.addObserver(FileLogObserver(logFile, level=args[1]).emit) log.addObserver(FileLogObserver(level=args[1]).emit) logger = Logger(system="OpenBazaard") # NAT traversal port = args[2] PortMapper().add_port_mapping(port, port, 'UDP') logger.info("Finding NAT Type...") while True: try: response = stun.get_ip_info(source_port=port) break except Exception: pass logger.info("%s on %s:%s" % (response[0], response[1], response[2])) ip_address = response[1] port = response[2] # TODO: use TURN if symmetric NAT def on_bootstrap_complete(resp): logger.info("bootstrap complete, downloading outstanding messages...") nlistener = NotificationListenerImpl(ws_factory, db) mserver.protocol.add_listener(nlistener) mlistener = MessageListenerImpl(ws_factory, db) mserver.get_messages(mlistener) mserver.protocol.add_listener(mlistener) blistener = BroadcastListenerImpl(ws_factory, db) mserver.protocol.add_listener(blistener) # TODO: ping seed node to establish connection if not full cone NAT # TODO: after bootstrap run through any pending contracts and see if the bitcoin address # has been funded, if not listen on the address and start the 10 minute delete timer. protocol = OpenBazaarProtocol((ip_address, port), response[0], testnet=TESTNET) # kademlia node = Node(keys.guid, ip_address, port, signed_pubkey=keys.guid_signed_pubkey, vendor=Profile(db).get().vendor) storage = ForgetfulStorage() if TESTNET else PersistentStorage(db.DATABASE) try: kserver = Server.loadState(DATA_FOLDER + 'cache.pickle', ip_address, port, protocol, db, on_bootstrap_complete, storage=storage) except Exception: kserver = Server(node, db, KSIZE, ALPHA, storage=storage) kserver.protocol.connect_multiplexer(protocol) kserver.bootstrap( kserver.querySeed("seed.openbazaar.org:8080", "5b44be5c18ced1bc9400fe5e79c8ab90204f06bebacc04dd9c70a95eaca6e117"))\ .addCallback(on_bootstrap_complete) # TODO: load seeds from config file kserver.saveStateRegularly(DATA_FOLDER + 'cache.pickle', 10) protocol.register_processor(kserver.protocol) # market mserver = network.Server(kserver, keys.signing_key, db) mserver.protocol.connect_multiplexer(protocol) protocol.register_processor(mserver.protocol) reactor.listenUDP(port, protocol) # websockets api ws_factory = WSFactory("ws://127.0.0.1:18466", mserver, kserver) ws_factory.protocol = WSProtocol ws_factory.setProtocolOptions(allowHixie76=True) listenWS(ws_factory) webdir = File(".") web = Site(webdir) if SSL: reactor.listenSSL(9000, web, ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=args[4]) else: reactor.listenTCP(9000, web, interface=args[4]) # rest api api = OpenBazaarAPI(mserver, kserver, protocol) site = Site(api, timeout=None) if SSL: reactor.listenSSL(18469, site, ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=args[3]) else: reactor.listenTCP(18469, site, interface=args[3]) # TODO: add optional SSL on rest and websocket servers # blockchain # TODO: listen on the libbitcoin heartbeat port instead fetching height def height_fetched(ec, height): # TODO: re-broadcast any unconfirmed txs in the db using height to find confirmation status logger.info("Libbitcoin server online") try: timeout.cancel() except Exception: pass def timeout(client): logger.critical("Libbitcoin server offline") client = None if TESTNET: libbitcoin_client = LibbitcoinClient(LIBBITCOIN_SERVER_TESTNET) else: libbitcoin_client = LibbitcoinClient(LIBBITCOIN_SERVER) # TODO: load libbitcoin server url from config file libbitcoin_client.fetch_last_height(height_fetched) timeout = reactor.callLater(7, timeout, libbitcoin_client) protocol.set_servers(ws_factory, libbitcoin_client) reactor.run()
def run(*args): TESTNET = args[0] # Create the database db = Database(testnet=TESTNET) # logging logFile = logfile.LogFile.fromFullPath(DATA_FOLDER + "debug.log", rotateLength=15000000, maxRotatedFiles=1) log.addObserver(FileLogObserver(logFile, level="debug").emit) log.addObserver(FileLogObserver(level="debug").emit) logger = Logger(system="Httpseed") # Load the keys keychain = KeyChain(db) if os.path.isfile(DATA_FOLDER + 'keys.pickle'): keys = pickle.load(open(DATA_FOLDER + "keys.pickle", "r")) signing_key_hex = keys["signing_privkey"] signing_key = nacl.signing.SigningKey(signing_key_hex, encoder=nacl.encoding.HexEncoder) else: signing_key = nacl.signing.SigningKey.generate() keys = { 'signing_privkey': signing_key.encode(encoder=nacl.encoding.HexEncoder), 'signing_pubkey': signing_key.verify_key.encode(encoder=nacl.encoding.HexEncoder) } pickle.dump(keys, open(DATA_FOLDER + "keys.pickle", "wb")) # Stun port = 18467 if not TESTNET else 28467 logger.info("Finding NAT Type...") response = stun.get_ip_info(stun_host="stun.l.google.com", source_port=port, stun_port=19302) logger.info("%s on %s:%s" % (response[0], response[1], response[2])) ip_address = response[1] port = response[2] # Start the kademlia server this_node = Node(keychain.guid, ip_address, port, keychain.guid_signed_pubkey, vendor=False) protocol = OpenBazaarProtocol((ip_address, port), response[0], testnet=TESTNET) try: kserver = Server.loadState('cache.pickle', ip_address, port, protocol, db) except Exception: kserver = Server(this_node, db) kserver.protocol.connect_multiplexer(protocol) protocol.register_processor(kserver.protocol) kserver.saveStateRegularly('cache.pickle', 10) # start the market server mserver = network.Server(kserver, keychain.signing_key, db) mserver.protocol.connect_multiplexer(protocol) protocol.register_processor(mserver.protocol) reactor.listenUDP(port, protocol) class WebResource(resource.Resource): def __init__(self, kserver_r): resource.Resource.__init__(self) self.kserver = kserver_r self.nodes = {} for bucket in self.kserver.protocol.router.buckets: for node in bucket.getNodes(): self.nodes[(node.ip, node.port)] = node self.nodes[(this_node.ip, this_node.port)] = this_node loopingCall = task.LoopingCall(self.crawl) loopingCall.start(180, True) def crawl(self): def gather_results(result): for proto in result: n = objects.Node() try: n.ParseFromString(proto) node = Node(n.guid, n.ip, n.port, n.signedPublicKey, n.vendor) self.nodes[(node.ip, node.port)] = node except Exception: pass def start_crawl(results): for node, result in results.items(): if not result[0]: del self.nodes[(node.ip, node.port)] node = Node(digest(random.getrandbits(255))) nearest = self.kserver.protocol.router.findNeighbors(node) spider = NodeSpiderCrawl(self.kserver.protocol, node, nearest, 100, 4) spider.find().addCallback(gather_results) ds = {} for bucket in self.kserver.protocol.router.buckets: for node in bucket.getNodes(): self.nodes[(node.ip, node.port)] = node for node in self.nodes.values(): if node.id != this_node.id: ds[node] = self.kserver.protocol.callPing(node) deferredDict(ds).addCallback(start_crawl) def getChild(self, child, request): return self def render_GET(self, request): nodes = self.nodes.values() shuffle(nodes) logger.info("Received a request for nodes, responding...") if "format" in request.args: if request.args["format"][0] == "json": json_list = [] if "type" in request.args and request.args["type"][ 0] == "vendors": for node in nodes: if node.vendor is True: node_dic = {} node_dic["ip"] = node.ip node_dic["port"] = node.port node_dic["guid"] = node.id.encode("hex") node_dic[ "signed_pubkey"] = node.signed_pubkey.encode( "hex") json_list.append(node_dic) sig = signing_key.sign(str(json_list)) resp = { "peers": json_list, "signature": hexlify(sig[:64]) } request.write(json.dumps(resp, indent=4)) else: for node in nodes[:50]: node_dic = {} node_dic["ip"] = node.ip node_dic["port"] = node.port json_list.append(node_dic) sig = signing_key.sign(str(json_list)) resp = { "peers": json_list, "signature": hexlify(sig[:64]) } request.write(json.dumps(resp, indent=4)) elif request.args["format"][0] == "protobuf": proto = peers.PeerSeeds() for node in nodes[:50]: peer = peers.PeerData() peer.ip_address = node.ip peer.port = node.port peer.vendor = node.vendor proto.peer_data.append(peer.SerializeToString()) sig = signing_key.sign("".join(proto.peer_data))[:64] proto.signature = sig uncompressed_data = proto.SerializeToString() request.write(uncompressed_data.encode("zlib")) else: proto = peers.PeerSeeds() if "type" in request.args and request.args["type"][ 0] == "vendors": for node in nodes: if node.vendor is True: peer = peers.PeerData() peer.ip_address = node.ip peer.port = node.port peer.vendor = node.vendor peer.guid = node.id peer.signedPubkey = node.signed_pubkey proto.peer_data.append(peer.SerializeToString()) sig = signing_key.sign("".join(proto.peer_data))[:64] proto.signature = sig uncompressed_data = proto.SerializeToString() request.write(uncompressed_data.encode("zlib")) else: for node in nodes[:50]: peer = peers.PeerData() peer.ip_address = node.ip peer.port = node.port peer.vendor = node.vendor proto.peer_data.append(peer.SerializeToString()) sig = signing_key.sign("".join(proto.peer_data))[:64] proto.signature = sig uncompressed_data = proto.SerializeToString() request.write(uncompressed_data.encode("zlib")) request.finish() return server.NOT_DONE_YET server_protocol = server.Site(WebResource(kserver)) reactor.listenTCP(8080, server_protocol) reactor.run()
def start_server(keys, first_startup=False): # logging logFile = logfile.LogFile.fromFullPath(os.path.join( DATA_FOLDER, "debug.log"), rotateLength=15000000, maxRotatedFiles=1) log.addObserver(FileLogObserver(logFile, level=LOGLEVEL).emit) log.addObserver(FileLogObserver(level=LOGLEVEL).emit) logger = Logger(system="OpenBazaard") # NAT traversal p = PortMapper() p.add_port_mapping(PORT, PORT, "UDP") logger.info("Finding NAT Type...") response = looping_retry(stun.get_ip_info, "0.0.0.0", PORT) logger.info("%s on %s:%s" % (response[0], response[1], response[2])) ip_address = response[1] port = response[2] if response[0] == "Full Cone": nat_type = FULL_CONE elif response[0] == "Restric NAT": nat_type = RESTRICTED else: nat_type = SYMMETRIC def on_bootstrap_complete(resp): logger.info("bootstrap complete") task.LoopingCall(mserver.get_messages, mlistener).start(3600) task.LoopingCall(check_unfunded_for_payment, db, libbitcoin_client, nlistener, TESTNET).start(600) task.LoopingCall(rebroadcast_unconfirmed, db, libbitcoin_client, TESTNET).start(600) protocol = OpenBazaarProtocol( db, (ip_address, port), nat_type, testnet=TESTNET, relaying=True if nat_type == FULL_CONE else False) # kademlia SEED_URLS = SEEDS_TESTNET if TESTNET else SEEDS relay_node = None if nat_type != FULL_CONE: for seed in SEED_URLS: try: relay_node = (socket.gethostbyname(seed[0].split(":")[0]), 28469 if TESTNET else 18469) break except socket.gaierror: pass try: kserver = Server.loadState( os.path.join(DATA_FOLDER, 'cache.pickle'), ip_address, port, protocol, db, nat_type, relay_node, on_bootstrap_complete, storage) except Exception: node = Node(keys.guid, ip_address, port, keys.verify_key.encode(), relay_node, nat_type, Profile(db).get().vendor) protocol.relay_node = node.relay_node kserver = Server(node, db, keys.signing_key, KSIZE, ALPHA, storage=storage) kserver.protocol.connect_multiplexer(protocol) kserver.bootstrap(kserver.querySeed(SEED_URLS)).addCallback( on_bootstrap_complete) kserver.saveStateRegularly(os.path.join(DATA_FOLDER, 'cache.pickle'), 10) protocol.register_processor(kserver.protocol) # market mserver = network.Server(kserver, keys.signing_key, db) mserver.protocol.connect_multiplexer(protocol) protocol.register_processor(mserver.protocol) looping_retry(reactor.listenUDP, port, protocol) interface = "0.0.0.0" if ALLOWIP != ["127.0.0.1"] else "127.0.0.1" # websockets api authenticated_sessions = [] ws_api = WSFactory(mserver, kserver, only_ip=ALLOWIP) ws_factory = AuthenticatedWebSocketFactory(ws_api) ws_factory.authenticated_sessions = authenticated_sessions ws_factory.protocol = AuthenticatedWebSocketProtocol if SSL: reactor.listenSSL(WSPORT, ws_factory, ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=interface) else: reactor.listenTCP(WSPORT, ws_factory, interface=interface) # rest api rest_api = RestAPI(mserver, kserver, protocol, username, password, authenticated_sessions, only_ip=ALLOWIP) if SSL: reactor.listenSSL(RESTPORT, rest_api, ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=interface) else: reactor.listenTCP(RESTPORT, rest_api, interface=interface) # blockchain if TESTNET: libbitcoin_client = LibbitcoinClient( LIBBITCOIN_SERVERS_TESTNET, log=Logger(service="LibbitcoinClient")) else: libbitcoin_client = LibbitcoinClient( LIBBITCOIN_SERVERS, log=Logger(service="LibbitcoinClient")) heartbeat_server.libbitcoin = libbitcoin_client # listeners nlistener = NotificationListenerImpl(ws_api, db) mserver.protocol.add_listener(nlistener) mlistener = MessageListenerImpl(ws_api, db) mserver.protocol.add_listener(mlistener) blistener = BroadcastListenerImpl(ws_api, db) mserver.protocol.add_listener(blistener) protocol.set_servers(ws_api, libbitcoin_client) if first_startup: heartbeat_server.push( json.dumps({ "status": "GUID generation complete", "username": username, "password": password })) heartbeat_server.set_status("online") logger.info("startup took %s seconds" % str(round(time.time() - args[7], 2))) def shutdown(): logger.info("shutting down server") for vendor in protocol.vendors.values(): db.vendors.save_vendor(vendor.id.encode("hex"), vendor.getProto().SerializeToString()) PortMapper().clean_my_mappings(PORT) protocol.shutdown() reactor.addSystemEventTrigger('before', 'shutdown', shutdown)
def run(*args): TESTNET = args[0] LOGLEVEL = args[1] PORT = args[2] ALLOWIP = args[3] SSL = args[4] RESTPORT = args[5] WSPORT = args[6] # database db = Database(TESTNET) # key generation keys = KeyChain(db) # logging logFile = logfile.LogFile.fromFullPath(DATA_FOLDER + "debug.log", rotateLength=15000000, maxRotatedFiles=1) log.addObserver(FileLogObserver(logFile, level=LOGLEVEL).emit) log.addObserver(FileLogObserver(level=LOGLEVEL).emit) logger = Logger(system="OpenBazaard") # NAT traversal p = PortMapper() threading.Thread(target=p.add_port_mapping, args=(PORT, PORT, "UDP")).start() logger.info("Finding NAT Type...") while True: # sometimes the stun server returns a code the client # doesn't understand so we have to try again try: response = stun.get_ip_info(source_port=PORT) break except Exception: pass logger.info("%s on %s:%s" % (response[0], response[1], response[2])) nat_type = response[0] ip_address = response[1] port = response[2] # TODO: use TURN if symmetric NAT def on_bootstrap_complete(resp): logger.info("bootstrap complete") mserver.get_messages(mlistener) task.LoopingCall(check_unfunded_for_payment, db, libbitcoin_client, nlistener, TESTNET).start(600) protocol = OpenBazaarProtocol((ip_address, port), response[0], testnet=TESTNET) # kademlia node = Node(keys.guid, ip_address, port, signed_pubkey=keys.guid_signed_pubkey, vendor=Profile(db).get().vendor) storage = ForgetfulStorage() if TESTNET else PersistentStorage(db.DATABASE) try: kserver = Server.loadState(DATA_FOLDER + 'cache.pickle', ip_address, port, protocol, db, on_bootstrap_complete, storage=storage) except Exception: kserver = Server(node, db, KSIZE, ALPHA, storage=storage) kserver.protocol.connect_multiplexer(protocol) kserver.bootstrap(kserver.querySeed(SEED)).addCallback(on_bootstrap_complete) kserver.saveStateRegularly(DATA_FOLDER + 'cache.pickle', 10) protocol.register_processor(kserver.protocol) if nat_type != "Full Cone": kserver.protocol.ping(SEED_NODE_TESTNET if TESTNET else SEED_NODE) # market mserver = network.Server(kserver, keys.signing_key, db) mserver.protocol.connect_multiplexer(protocol) protocol.register_processor(mserver.protocol) reactor.listenUDP(port, protocol) class OnlyIP(Site): def __init__(self, resource, ip, timeout=60 * 60 * 1): self.ip = ip Site.__init__(self, resource, timeout=timeout) def buildProtocol(self, addr): if addr.host == self.ip: return Site.buildProtocol(self, addr) return None # websockets api if SSL: ws_factory = WSFactory("wss://127.0.0.1:" + str(WSPORT), mserver, kserver, only_ip=ALLOWIP) contextFactory = ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT) ws_factory.protocol = WSProtocol listenWS(ws_factory, contextFactory) else: ws_factory = WSFactory("ws://127.0.0.1:" + str(WSPORT), mserver, kserver, only_ip=ALLOWIP) ws_factory.protocol = WSProtocol listenWS(ws_factory) if ALLOWIP != "127.0.0.1" and ALLOWIP != "0.0.0.0": ws_interface = "0.0.0.0" else: ws_interface = ALLOWIP webdir = File(".") web = Site(webdir) reactor.listenTCP(WSPORT - 1, web, interface=ws_interface) # rest api api = OpenBazaarAPI(mserver, kserver, protocol) if ALLOWIP != "127.0.0.1" and ALLOWIP != "0.0.0.0": rest_interface = "0.0.0.0" site = OnlyIP(api, ALLOWIP, timeout=None) else: rest_interface = ALLOWIP site = Site(api, timeout=None) if SSL: reactor.listenSSL(RESTPORT, site, ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=rest_interface) else: reactor.listenTCP(RESTPORT, site, interface=rest_interface) # blockchain if TESTNET: libbitcoin_client = LibbitcoinClient(LIBBITCOIN_SERVER_TESTNET, log=Logger(service="LibbitcoinClient")) else: libbitcoin_client = LibbitcoinClient(LIBBITCOIN_SERVER, log=Logger(service="LibbitcoinClient")) # listeners nlistener = NotificationListenerImpl(ws_factory, db) mserver.protocol.add_listener(nlistener) mlistener = MessageListenerImpl(ws_factory, db) mserver.protocol.add_listener(mlistener) blistener = BroadcastListenerImpl(ws_factory, db) mserver.protocol.add_listener(blistener) protocol.set_servers(ws_factory, libbitcoin_client) logger.info("Startup took %s seconds" % str(round(time.time() - args[7], 2))) reactor.run()
class ValueSpiderCrawlTest(unittest.TestCase): def setUp(self): self.public_ip = '123.45.67.89' self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ('132.54.76.98', 54321) self.addr2 = ('231.76.45.89', 15243) self.addr3 = ("193.193.111.00", 99999) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection(self.proto_mock, self.handler_mock, self.own_addr, self.addr1) valid_key = "1a5c8e67edb8d279d1ae32fa2da97e236b95e95c837dc8c3c7c2ff7a7cc29855" self.signing_key = nacl.signing.SigningKey( valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key signed_pubkey = self.signing_key.sign(str(verify_key)) h = nacl.hash.sha512(signed_pubkey) self.storage = ForgetfulStorage() self.node = Node(unhexlify(h[:40]), self.public_ip, self.port, signed_pubkey, None, FULL_CONE, True) self.db = Database(filepath=":memory:") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db) self.wire_protocol = OpenBazaarProtocol(self.own_addr, FULL_CONE) self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler([self.protocol], self.wire_protocol, None) transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address('UDP', self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), 'getHost') self.wire_protocol.makeConnection(transport) self.node1 = Node(digest("id1"), self.addr1[0], self.addr1[1], digest("key1"), None, FULL_CONE, True) self.node2 = Node(digest("id2"), self.addr2[0], self.addr2[1], digest("key2"), None, FULL_CONE, True) self.node3 = Node(digest("id3"), self.addr3[0], self.addr3[1], digest("key3"), None, FULL_CONE, True) def tearDown(self): self.con.shutdown() self.wire_protocol.shutdown() def test_find(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.wire_protocol[self.addr2] = self.con self.wire_protocol[self.addr3] = self.con self.protocol.router.addContact(self.node1) self.protocol.router.addContact(self.node2) self.protocol.router.addContact(self.node3) node = Node(digest("s")) nearest = self.protocol.router.findNeighbors(node) spider = ValueSpiderCrawl(self.protocol, node, nearest, 20, 3) spider.find() self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() self.assertEqual(len(self.proto_mock.send_datagram.call_args_list), 7) def test_nodesFound(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.wire_protocol[self.addr2] = self.con self.wire_protocol[self.addr3] = self.con self.protocol.router.addContact(self.node1) self.protocol.router.addContact(self.node2) self.protocol.router.addContact(self.node3) # test response with uncontacted nodes node = Node(digest("s")) nearest = self.protocol.router.findNeighbors(node) spider = ValueSpiderCrawl(self.protocol, node, nearest, 20, 3) response = (True, (self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString())) responses = {self.node1.id: response} spider._nodesFound(responses) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() self.assertEqual(len(self.proto_mock.send_datagram.call_args_list), 7) # test all been contacted spider = ValueSpiderCrawl(self.protocol, node, nearest, 20, 3) for peer in spider.nearest.getUncontacted(): spider.nearest.markContacted(peer) response = (True, (self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString())) responses = {self.node2.id: response} resp = spider._nodesFound(responses) self.assertTrue(resp is None) # test didn't happen spider = ValueSpiderCrawl(self.protocol, node, nearest, 20, 3) response = (False, (self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString())) responses = {self.node1.id: response} spider._nodesFound(responses) self.assertTrue(len(spider.nearest) == 2) # test got value val = Value() val.valueKey = digest("contractID") val.serializedData = self.protocol.sourceNode.getProto( ).SerializeToString() val.ttl = 10 response = (True, ("value", val.SerializeToString())) responses = {self.node3.id: response} spider.nearestWithoutValue = NodeHeap(node, 1) value = spider._nodesFound(responses) self.assertEqual(value[0], val.SerializeToString()) def test_handleFoundValues(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.protocol.router.addContact(self.node1) self.protocol.router.addContact(self.node2) self.protocol.router.addContact(self.node3) node = Node(digest("s")) nearest = self.protocol.router.findNeighbors(node) spider = ValueSpiderCrawl(self.protocol, node, nearest, 20, 3) val = Value() val.valueKey = digest("contractID") val.serializedData = self.node1.getProto().SerializeToString() val.ttl = 10 val1 = val.SerializeToString() value = spider._handleFoundValues([val1]) self.assertEqual(value[0], val.SerializeToString()) # test handle multiple values val.serializedData = self.node2.getProto().SerializeToString() val2 = val.SerializeToString() val.valueKey = digest("contractID2") val3 = val.SerializeToString() found_values = [val1, val2, val2, val3] self.assertEqual(spider._handleFoundValues(found_values), [val3, val2]) # test store value at nearest without value spider.nearestWithoutValue.push(self.node1) spider._handleFoundValues(found_values) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() self.assertTrue(len(self.proto_mock.send_datagram.call_args_list) > 1) self.proto_mock.send_datagram.call_args_list = [] def _connecting_to_connected(self): remote_synack_packet = packet.Packet.from_data(42, self.con.own_addr, self.con.dest_addr, ack=0, syn=True) self.con.receive_packet(remote_synack_packet, self.addr1) self.clock.advance(0) connection.REACTOR.runUntilCurrent() self.next_remote_seqnum = 43 m_calls = self.proto_mock.send_datagram.call_args_list sent_syn_packet = packet.Packet.from_bytes(m_calls[0][0][0]) seqnum = sent_syn_packet.sequence_number self.handler_mock.reset_mock() self.proto_mock.reset_mock() self.next_seqnum = seqnum + 1
class ValueSpiderCrawlTest(unittest.TestCase): def setUp(self): self.public_ip = '123.45.67.89' self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ('132.54.76.98', 54321) self.addr2 = ('231.76.45.89', 15243) self.addr3 = ("193.193.111.00", 99999) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection( self.proto_mock, self.handler_mock, self.own_addr, self.addr1 ) valid_key = "1a5c8e67edb8d279d1ae32fa2da97e236b95e95c837dc8c3c7c2ff7a7cc29855" self.signing_key = nacl.signing.SigningKey(valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key signed_pubkey = self.signing_key.sign(str(verify_key)) h = nacl.hash.sha512(signed_pubkey) self.storage = ForgetfulStorage() self.node = Node(unhexlify(h[:40]), self.public_ip, self.port, signed_pubkey, None, FULL_CONE, True) self.db = Database(filepath=":memory:") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db) self.wire_protocol = OpenBazaarProtocol(self.own_addr, FULL_CONE) self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler([self.protocol], self.wire_protocol, None) transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address('UDP', self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), 'getHost') self.wire_protocol.makeConnection(transport) self.node1 = Node(digest("id1"), self.addr1[0], self.addr1[1], digest("key1"), None, FULL_CONE, True) self.node2 = Node(digest("id2"), self.addr2[0], self.addr2[1], digest("key2"), None, FULL_CONE, True) self.node3 = Node(digest("id3"), self.addr3[0], self.addr3[1], digest("key3"), None, FULL_CONE, True) def tearDown(self): self.con.shutdown() self.wire_protocol.shutdown() def test_find(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.wire_protocol[self.addr2] = self.con self.wire_protocol[self.addr3] = self.con self.protocol.router.addContact(self.node1) self.protocol.router.addContact(self.node2) self.protocol.router.addContact(self.node3) node = Node(digest("s")) nearest = self.protocol.router.findNeighbors(node) spider = ValueSpiderCrawl(self.protocol, node, nearest, 20, 3) spider.find() self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() self.assertEqual(len(self.proto_mock.send_datagram.call_args_list), 7) def test_nodesFound(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.wire_protocol[self.addr2] = self.con self.wire_protocol[self.addr3] = self.con self.protocol.router.addContact(self.node1) self.protocol.router.addContact(self.node2) self.protocol.router.addContact(self.node3) # test response with uncontacted nodes node = Node(digest("s")) nearest = self.protocol.router.findNeighbors(node) spider = ValueSpiderCrawl(self.protocol, node, nearest, 20, 3) response = (True, (self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString())) responses = {self.node1.id: response} spider._nodesFound(responses) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() self.assertEqual(len(self.proto_mock.send_datagram.call_args_list), 7) # test all been contacted spider = ValueSpiderCrawl(self.protocol, node, nearest, 20, 3) for peer in spider.nearest.getUncontacted(): spider.nearest.markContacted(peer) response = (True, (self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString())) responses = {self.node2.id: response} resp = spider._nodesFound(responses) self.assertTrue(resp is None) # test didn't happen spider = ValueSpiderCrawl(self.protocol, node, nearest, 20, 3) response = (False, (self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString())) responses = {self.node1.id: response} spider._nodesFound(responses) self.assertTrue(len(spider.nearest) == 2) # test got value val = Value() val.valueKey = digest("contractID") val.serializedData = self.protocol.sourceNode.getProto().SerializeToString() val.ttl = 10 response = (True, ("value", val.SerializeToString())) responses = {self.node3.id: response} spider.nearestWithoutValue = NodeHeap(node, 1) value = spider._nodesFound(responses) self.assertEqual(value[0], val.SerializeToString()) def test_handleFoundValues(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.protocol.router.addContact(self.node1) self.protocol.router.addContact(self.node2) self.protocol.router.addContact(self.node3) node = Node(digest("s")) nearest = self.protocol.router.findNeighbors(node) spider = ValueSpiderCrawl(self.protocol, node, nearest, 20, 3) val = Value() val.valueKey = digest("contractID") val.serializedData = self.node1.getProto().SerializeToString() val.ttl = 10 val1 = val.SerializeToString() value = spider._handleFoundValues([val1]) self.assertEqual(value[0], val.SerializeToString()) # test handle multiple values val.serializedData = self.node2.getProto().SerializeToString() val2 = val.SerializeToString() val.valueKey = digest("contractID2") val3 = val.SerializeToString() found_values = [val1, val2, val2, val3] self.assertEqual(spider._handleFoundValues(found_values), [val3, val2]) # test store value at nearest without value spider.nearestWithoutValue.push(self.node1) spider._handleFoundValues(found_values) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() self.assertTrue(len(self.proto_mock.send_datagram.call_args_list) > 1) self.proto_mock.send_datagram.call_args_list = [] def _connecting_to_connected(self): remote_synack_packet = packet.Packet.from_data( 42, self.con.own_addr, self.con.dest_addr, ack=0, syn=True ) self.con.receive_packet(remote_synack_packet, self.addr1) self.clock.advance(0) connection.REACTOR.runUntilCurrent() self.next_remote_seqnum = 43 m_calls = self.proto_mock.send_datagram.call_args_list sent_syn_packet = packet.Packet.from_bytes(m_calls[0][0][0]) seqnum = sent_syn_packet.sequence_number self.handler_mock.reset_mock() self.proto_mock.reset_mock() self.next_seqnum = seqnum + 1
def run(*args): TESTNET = args[0] LOGLEVEL = args[1] PORT = args[2] ALLOWIP = args[3] SSL = args[4] RESTPORT = args[5] WSPORT = args[6] # database db = Database(TESTNET) # key generation keys = KeyChain(db) # logging logFile = logfile.LogFile.fromFullPath(DATA_FOLDER + "debug.log", rotateLength=15000000, maxRotatedFiles=1) log.addObserver(FileLogObserver(logFile, level=LOGLEVEL).emit) log.addObserver(FileLogObserver(level=LOGLEVEL).emit) logger = Logger(system="OpenBazaard") # NAT traversal p = PortMapper() p.add_port_mapping(PORT, PORT, "UDP") logger.info("Finding NAT Type...") response = looping_retry(stun.get_ip_info, "0.0.0.0", PORT) logger.info("%s on %s:%s" % (response[0], response[1], response[2])) ip_address = response[1] port = response[2] if response[0] == "Full Cone": nat_type = FULL_CONE elif response[0] == "Restric NAT": nat_type = RESTRICTED else: nat_type = SYMMETRIC def on_bootstrap_complete(resp): logger.info("bootstrap complete") mserver.get_messages(mlistener) task.LoopingCall(check_unfunded_for_payment, db, libbitcoin_client, nlistener, TESTNET).start(600) protocol = OpenBazaarProtocol( (ip_address, port), nat_type, testnet=TESTNET, relaying=True if nat_type == FULL_CONE else False) # kademlia storage = ForgetfulStorage() if TESTNET else PersistentStorage( db.get_database_path()) relay_node = None if nat_type != FULL_CONE: for seed in SEEDS: try: relay_node = (socket.gethostbyname(seed[0].split(":")[0]), 28469 if TESTNET else 18469) break except socket.gaierror: pass try: kserver = Server.loadState(DATA_FOLDER + 'cache.pickle', ip_address, port, protocol, db, nat_type, relay_node, on_bootstrap_complete, storage) except Exception: node = Node(keys.guid, ip_address, port, keys.verify_key.encode(), relay_node, nat_type, Profile(db).get().vendor) protocol.relay_node = node.relay_node kserver = Server(node, db, keys.signing_key, KSIZE, ALPHA, storage=storage) kserver.protocol.connect_multiplexer(protocol) kserver.bootstrap( kserver.querySeed(SEEDS)).addCallback(on_bootstrap_complete) kserver.saveStateRegularly(DATA_FOLDER + 'cache.pickle', 10) protocol.register_processor(kserver.protocol) # market mserver = network.Server(kserver, keys.signing_key, db) mserver.protocol.connect_multiplexer(protocol) protocol.register_processor(mserver.protocol) looping_retry(reactor.listenUDP, port, protocol) interface = "0.0.0.0" if ALLOWIP not in ("127.0.0.1", "0.0.0.0") else ALLOWIP # websockets api ws_api = WSFactory(mserver, kserver, only_ip=ALLOWIP) if SSL: reactor.listenSSL(WSPORT, WebSocketFactory(ws_api), ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=interface) else: reactor.listenTCP(WSPORT, WebSocketFactory(ws_api), interface=interface) # rest api rest_api = RestAPI(mserver, kserver, protocol, only_ip=ALLOWIP) if SSL: reactor.listenSSL(RESTPORT, rest_api, ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=interface) else: reactor.listenTCP(RESTPORT, rest_api, interface=interface) # blockchain if TESTNET: libbitcoin_client = LibbitcoinClient( LIBBITCOIN_SERVER_TESTNET, log=Logger(service="LibbitcoinClient")) else: libbitcoin_client = LibbitcoinClient( LIBBITCOIN_SERVER, log=Logger(service="LibbitcoinClient")) # listeners nlistener = NotificationListenerImpl(ws_api, db) mserver.protocol.add_listener(nlistener) mlistener = MessageListenerImpl(ws_api, db) mserver.protocol.add_listener(mlistener) blistener = BroadcastListenerImpl(ws_api, db) mserver.protocol.add_listener(blistener) protocol.set_servers(ws_api, libbitcoin_client) logger.info("Startup took %s seconds" % str(round(time.time() - args[7], 2))) reactor.run()
def start_server(keychain, first_startup=False): # logging logFile = logfile.LogFile.fromFullPath(DATA_FOLDER + "debug.log", rotateLength=15000000, maxRotatedFiles=1) log.addObserver(FileLogObserver(logFile, level="debug").emit) log.addObserver(FileLogObserver(level="debug").emit) logger = Logger(system="Httpseed") if os.path.isfile(DATA_FOLDER + 'keys.pickle'): keys = pickle.load(open(DATA_FOLDER + "keys.pickle", "r")) signing_key_hex = keys["signing_privkey"] signing_key = nacl.signing.SigningKey(signing_key_hex, encoder=nacl.encoding.HexEncoder) else: signing_key = nacl.signing.SigningKey.generate() keys = { 'signing_privkey': signing_key.encode(encoder=nacl.encoding.HexEncoder), 'signing_pubkey': signing_key.verify_key.encode(encoder=nacl.encoding.HexEncoder) } pickle.dump(keys, open(DATA_FOLDER + "keys.pickle", "wb")) # Stun port = 18467 if not TESTNET else 28467 logger.info("Finding NAT Type...") response = stun.get_ip_info(stun_host="stun.l.google.com", source_port=port, stun_port=19302) logger.info("%s on %s:%s" % (response[0], response[1], response[2])) ip_address = response[1] port = response[2] # Start the kademlia server this_node = Node(keychain.guid, ip_address, port, keychain.verify_key.encode(), None, objects.FULL_CONE, False) protocol = OpenBazaarProtocol(db, (ip_address, port), objects.FULL_CONE, testnet=TESTNET, relaying=True) try: kserver = Server.loadState('cache.pickle', ip_address, port, protocol, db, objects.FULL_CONE, None) except Exception: kserver = Server(this_node, db, keychain.signing_key) kserver.protocol.connect_multiplexer(protocol) protocol.register_processor(kserver.protocol) kserver.saveStateRegularly('cache.pickle', 10) reactor.listenUDP(port, protocol) class WebResource(resource.Resource): def __init__(self, kserver_r): resource.Resource.__init__(self) self.kserver = kserver_r self.nodes = {} for bucket in self.kserver.protocol.router.buckets: for node in bucket.getNodes(): self.nodes[(node.ip, node.port)] = node self.nodes[(this_node.ip, this_node.port)] = this_node loopingCall = task.LoopingCall(self.crawl) loopingCall.start(900, True) def crawl(self): def gather_results(result): for proto in result: n = objects.Node() try: n.ParseFromString(proto) node = Node(n.guid, n.nodeAddress.ip, n.nodeAddress.port, n.signedPublicKey, None if not n.HasField("relayAddress") else (n.relayAddress.ip, n.relayAddress.port), n.natType, n.vendor) self.nodes[(node.ip, node.port)] = node except Exception: pass def start_crawl(results): for node, result in results.items(): if not result[0]: del self.nodes[(node.ip, node.port)] node = Node(digest(random.getrandbits(255))) nearest = self.kserver.protocol.router.findNeighbors(node) spider = NodeSpiderCrawl(self.kserver.protocol, node, nearest, 100, 4) spider.find().addCallback(gather_results) ds = {} for bucket in self.kserver.protocol.router.buckets: for node in bucket.getNodes(): self.nodes[(node.ip, node.port)] = node for node in self.nodes.values(): if node.id != this_node.id: ds[node] = self.kserver.protocol.callPing(node) deferredDict(ds).addCallback(start_crawl) def getChild(self, child, request): return self def render_GET(self, request): nodes = self.nodes.values() shuffle(nodes) logger.info("Received a request for nodes, responding...") if "format" in request.args: if request.args["format"][0] == "json": json_list = [] if "type" in request.args and request.args["type"][0] == "vendors": for node in nodes: if node.vendor is True: node_dic = {} node_dic["ip"] = node.ip node_dic["port"] = node.port node_dic["guid"] = node.id.encode("hex") json_list.append(node_dic) sig = signing_key.sign(str(json_list)) resp = {"peers": json_list, "signature": hexlify(sig[:64])} request.write(json.dumps(resp, indent=4)) else: for node in nodes[:50]: node_dic = {} node_dic["ip"] = node.ip node_dic["port"] = node.port json_list.append(node_dic) sig = signing_key.sign(str(json_list)) resp = {"peers": json_list, "signature": hexlify(sig[:64])} request.write(json.dumps(resp, indent=4)) elif request.args["format"][0] == "protobuf": proto = peers.PeerSeeds() for node in nodes[:50]: proto.serializedNode.append(node.getProto().SerializeToString()) sig = signing_key.sign("".join(proto.serializedNode))[:64] proto.signature = sig uncompressed_data = proto.SerializeToString() request.write(uncompressed_data.encode("zlib")) else: proto = peers.PeerSeeds() if "type" in request.args and request.args["type"][0] == "vendors": for node in nodes: if node.vendor is True: proto.serializedNode.append(node.getProto().SerializeToString()) sig = signing_key.sign("".join(proto.serializedNode))[:64] proto.signature = sig uncompressed_data = proto.SerializeToString() request.write(uncompressed_data.encode("zlib")) else: for node in nodes[:50]: proto.serializedNode.append(node.getProto().SerializeToString()) sig = signing_key.sign("".join(proto.serializedNode))[:64] proto.signature = sig uncompressed_data = proto.SerializeToString() request.write(uncompressed_data.encode("zlib")) request.finish() return server.NOT_DONE_YET server_protocol = server.Site(WebResource(kserver)) reactor.listenTCP(HTTPPORT, server_protocol)
class NodeSpiderCrawlTest(unittest.TestCase): def setUp(self): self.public_ip = '123.45.67.89' self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ('132.54.76.98', 54321) self.addr2 = ('231.76.45.89', 15243) self.addr3 = ("193.193.111.00", 99999) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection( self.proto_mock, self.handler_mock, self.own_addr, self.addr1 ) valid_key = "63d901c4d57cde34fc1f1e28b9af5d56ed342cae5c2fb470046d0130a4226b0c" self.signing_key = nacl.signing.SigningKey(valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key h = nacl.hash.sha512(verify_key.encode()) self.storage = ForgetfulStorage() self.node = Node(unhexlify(h[:40]), self.public_ip, self.port, verify_key.encode(), None, FULL_CONE, True) self.db = Database(filepath="test.db") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db, self.signing_key) self.wire_protocol = OpenBazaarProtocol(self.db, self.own_addr, FULL_CONE) self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler([self.protocol], self.wire_protocol, None, self.wire_protocol.ban_score) transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address('UDP', self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), 'getHost') self.wire_protocol.makeConnection(transport) self.node1 = Node(digest("id1"), self.addr1[0], self.addr1[1], digest("key1"), None, FULL_CONE, True) self.node2 = Node(digest("id2"), self.addr2[0], self.addr2[1], digest("key2"), None, FULL_CONE, True) self.node3 = Node(digest("id3"), self.addr3[0], self.addr3[1], digest("key3"), None, FULL_CONE, True) def tearDown(self): self.con.shutdown() self.wire_protocol.shutdown() os.remove("test.db") def test_find(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.wire_protocol[self.addr2] = self.con self.wire_protocol[self.addr3] = self.con self.protocol.router.addContact(self.node1) self.protocol.router.addContact(self.node2) self.protocol.router.addContact(self.node3) node = Node(digest("s")) nearest = self.protocol.router.findNeighbors(node) spider = NodeSpiderCrawl(self.protocol, node, nearest, 20, 3) spider.find() self.clock.advance(constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() self.assertEqual(len(self.proto_mock.send_datagram.call_args_list), 4) def test_nodesFound(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.wire_protocol[self.addr2] = self.con self.wire_protocol[self.addr3] = self.con self.protocol.router.addContact(self.node1) self.protocol.router.addContact(self.node2) self.protocol.router.addContact(self.node3) node = Node(digest("s")) nearest = self.protocol.router.findNeighbors(node) spider = NodeSpiderCrawl(self.protocol, node, nearest, 20, 3) response = (True, (self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString())) responses = {self.node1.id: response} spider._nodesFound(responses) self.clock.advance(constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() self.assertEqual(len(self.proto_mock.send_datagram.call_args_list), 4) response = (True, (self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString())) responses = {self.node1.id: response} nodes = spider._nodesFound(responses) node_protos = [] for n in nodes: node_protos.append(n.getProto()) self.assertTrue(self.node1.getProto() in node_protos) self.assertTrue(self.node2.getProto() in node_protos) self.assertTrue(self.node3.getProto() in node_protos) response = (False, (self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString())) responses = {self.node1.id: response} nodes = spider._nodesFound(responses) node_protos = [] for n in nodes: node_protos.append(n.getProto()) self.assertTrue(self.node2.getProto() in node_protos) self.assertTrue(self.node3.getProto() in node_protos) def _connecting_to_connected(self): remote_synack_packet = packet.Packet.from_data( 42, self.con.own_addr, self.con.dest_addr, ack=0, syn=True ) self.con.receive_packet(remote_synack_packet, self.addr1) self.clock.advance(0) connection.REACTOR.runUntilCurrent() self.next_remote_seqnum = 43 m_calls = self.proto_mock.send_datagram.call_args_list sent_syn_packet = packet.Packet.from_bytes(m_calls[0][0][0]) seqnum = sent_syn_packet.sequence_number self.handler_mock.reset_mock() self.proto_mock.reset_mock() self.next_seqnum = seqnum + 1
def run(*args): TESTNET = args[0] LOGLEVEL = args[1] PORT = args[2] ALLOWIP = args[3] SSL = args[4] RESTPORT = args[5] WSPORT = args[6] # database db = Database(TESTNET) # key generation keys = KeyChain(db) # logging logFile = logfile.LogFile.fromFullPath(DATA_FOLDER + "debug.log", rotateLength=15000000, maxRotatedFiles=1) log.addObserver(FileLogObserver(logFile, level=LOGLEVEL).emit) log.addObserver(FileLogObserver(level=LOGLEVEL).emit) logger = Logger(system="OpenBazaard") # NAT traversal p = PortMapper() p.add_port_mapping(PORT, PORT, "UDP") logger.info("Finding NAT Type...") response = looping_retry(stun.get_ip_info, "0.0.0.0", PORT) logger.info("%s on %s:%s" % (response[0], response[1], response[2])) ip_address = response[1] port = response[2] if response[0] == "Full Cone": nat_type = FULL_CONE elif response[0] == "Restric NAT": nat_type = RESTRICTED else: nat_type = SYMMETRIC def on_bootstrap_complete(resp): logger.info("bootstrap complete") mserver.get_messages(mlistener) task.LoopingCall(check_unfunded_for_payment, db, libbitcoin_client, nlistener, TESTNET).start(600) protocol = OpenBazaarProtocol((ip_address, port), nat_type, testnet=TESTNET, relaying=True if nat_type == FULL_CONE else False) # kademlia storage = ForgetfulStorage() if TESTNET else PersistentStorage(db.get_database_path()) relay_node = None if nat_type != FULL_CONE: for seed in SEEDS: try: relay_node = (socket.gethostbyname(seed[0].split(":")[0]), 28469 if TESTNET else 18469) break except socket.gaierror: pass try: kserver = Server.loadState(DATA_FOLDER + 'cache.pickle', ip_address, port, protocol, db, nat_type, relay_node, on_bootstrap_complete, storage) except Exception: node = Node(keys.guid, ip_address, port, keys.verify_key.encode(), relay_node, nat_type, Profile(db).get().vendor) protocol.relay_node = node.relay_node kserver = Server(node, db, keys.signing_key, KSIZE, ALPHA, storage=storage) kserver.protocol.connect_multiplexer(protocol) kserver.bootstrap(kserver.querySeed(SEEDS)).addCallback(on_bootstrap_complete) kserver.saveStateRegularly(DATA_FOLDER + 'cache.pickle', 10) protocol.register_processor(kserver.protocol) # market mserver = network.Server(kserver, keys.signing_key, db) mserver.protocol.connect_multiplexer(protocol) protocol.register_processor(mserver.protocol) looping_retry(reactor.listenUDP, port, protocol) interface = "0.0.0.0" if ALLOWIP not in ("127.0.0.1", "0.0.0.0") else ALLOWIP # websockets api ws_api = WSFactory(mserver, kserver, only_ip=ALLOWIP) if SSL: reactor.listenSSL(WSPORT, WebSocketFactory(ws_api), ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=interface) else: reactor.listenTCP(WSPORT, WebSocketFactory(ws_api), interface=interface) # rest api rest_api = RestAPI(mserver, kserver, protocol, only_ip=ALLOWIP) if SSL: reactor.listenSSL(RESTPORT, rest_api, ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=interface) else: reactor.listenTCP(RESTPORT, rest_api, interface=interface) # blockchain if TESTNET: libbitcoin_client = LibbitcoinClient(LIBBITCOIN_SERVER_TESTNET, log=Logger(service="LibbitcoinClient")) else: libbitcoin_client = LibbitcoinClient(LIBBITCOIN_SERVER, log=Logger(service="LibbitcoinClient")) # listeners nlistener = NotificationListenerImpl(ws_api, db) mserver.protocol.add_listener(nlistener) mlistener = MessageListenerImpl(ws_api, db) mserver.protocol.add_listener(mlistener) blistener = BroadcastListenerImpl(ws_api, db) mserver.protocol.add_listener(blistener) protocol.set_servers(ws_api, libbitcoin_client) logger.info("Startup took %s seconds" % str(round(time.time() - args[7], 2))) reactor.run()
class NodeSpiderCrawlTest(unittest.TestCase): def setUp(self): self.public_ip = '123.45.67.89' self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ('132.54.76.98', 54321) self.addr2 = ('231.76.45.89', 15243) self.addr3 = ("193.193.111.00", 99999) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection(self.proto_mock, self.handler_mock, self.own_addr, self.addr1) valid_key = "63d901c4d57cde34fc1f1e28b9af5d56ed342cae5c2fb470046d0130a4226b0c" self.signing_key = nacl.signing.SigningKey( valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key h = nacl.hash.sha512(verify_key.encode()) self.storage = ForgetfulStorage() self.node = Node(unhexlify(h[:40]), self.public_ip, self.port, verify_key.encode(), None, FULL_CONE, True) self.db = Database(filepath="test.db") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db, self.signing_key) self.wire_protocol = OpenBazaarProtocol(self.db, self.own_addr, FULL_CONE) self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler( [self.protocol], self.wire_protocol, None, self.wire_protocol.ban_score) transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address('UDP', self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), 'getHost') self.wire_protocol.makeConnection(transport) self.node1 = Node(digest("id1"), self.addr1[0], self.addr1[1], digest("key1"), None, FULL_CONE, True) self.node2 = Node(digest("id2"), self.addr2[0], self.addr2[1], digest("key2"), None, FULL_CONE, True) self.node3 = Node(digest("id3"), self.addr3[0], self.addr3[1], digest("key3"), None, FULL_CONE, True) def tearDown(self): self.con.shutdown() self.wire_protocol.shutdown() os.remove("test.db") def test_find(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.wire_protocol[self.addr2] = self.con self.wire_protocol[self.addr3] = self.con self.protocol.router.addContact(self.node1) self.protocol.router.addContact(self.node2) self.protocol.router.addContact(self.node3) node = Node(digest("s")) nearest = self.protocol.router.findNeighbors(node) spider = NodeSpiderCrawl(self.protocol, node, nearest, 20, 3) spider.find() self.clock.advance(constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() self.assertEqual(len(self.proto_mock.send_datagram.call_args_list), 4) def test_nodesFound(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.wire_protocol[self.addr2] = self.con self.wire_protocol[self.addr3] = self.con self.protocol.router.addContact(self.node1) self.protocol.router.addContact(self.node2) self.protocol.router.addContact(self.node3) node = Node(digest("s")) nearest = self.protocol.router.findNeighbors(node) spider = NodeSpiderCrawl(self.protocol, node, nearest, 20, 3) response = (True, (self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString())) responses = {self.node1.id: response} spider._nodesFound(responses) self.clock.advance(constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() self.assertEqual(len(self.proto_mock.send_datagram.call_args_list), 4) response = (True, (self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString())) responses = {self.node1.id: response} nodes = spider._nodesFound(responses) node_protos = [] for n in nodes: node_protos.append(n.getProto()) self.assertTrue(self.node1.getProto() in node_protos) self.assertTrue(self.node2.getProto() in node_protos) self.assertTrue(self.node3.getProto() in node_protos) response = (False, (self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString())) responses = {self.node1.id: response} nodes = spider._nodesFound(responses) node_protos = [] for n in nodes: node_protos.append(n.getProto()) self.assertTrue(self.node2.getProto() in node_protos) self.assertTrue(self.node3.getProto() in node_protos) def _connecting_to_connected(self): remote_synack_packet = packet.Packet.from_data(42, self.con.own_addr, self.con.dest_addr, ack=0, syn=True) self.con.receive_packet(remote_synack_packet, self.addr1) self.clock.advance(0) connection.REACTOR.runUntilCurrent() self.next_remote_seqnum = 43 m_calls = self.proto_mock.send_datagram.call_args_list sent_syn_packet = packet.Packet.from_bytes(m_calls[0][0][0]) seqnum = sent_syn_packet.sequence_number self.handler_mock.reset_mock() self.proto_mock.reset_mock() self.next_seqnum = seqnum + 1
class KademliaProtocolTest(unittest.TestCase): def setUp(self): self.version = PROTOCOL_VERSION self.public_ip = '123.45.67.89' self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ('132.54.76.98', 54321) self.addr2 = ('231.76.45.89', 15243) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection( self.proto_mock, self.handler_mock, self.own_addr, self.addr1 ) valid_key = "1a5c8e67edb8d279d1ae32fa2da97e236b95e95c837dc8c3c7c2ff7a7cc29855" self.signing_key = nacl.signing.SigningKey(valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key signed_pubkey = self.signing_key.sign(str(verify_key)) h = nacl.hash.sha512(signed_pubkey) self.storage = ForgetfulStorage() self.node = Node(unhexlify(h[:40]), self.public_ip, self.port, signed_pubkey, True) self.db = datastore.Database(filepath="test.db") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db) self.wire_protocol = OpenBazaarProtocol(self.own_addr, "Full Cone") self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler([self.protocol], self.wire_protocol) self.handler.connection = self.con transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address('UDP', self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), 'getHost') self.wire_protocol.makeConnection(transport) def tearDown(self): if self.con.state != connection.State.SHUTDOWN: self.con.shutdown() self.wire_protocol.shutdown() os.remove("test.db") def test_invalid_datagram(self): self.assertFalse(self.handler.receive_message("hi")) self.assertFalse(self.handler.receive_message("hihihihihihihihihihihihihihihihihihihihih")) def test_rpc_ping(self): self._connecting_to_connected() m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("PING") m.protoVer = self.version m.testnet = False data = m.SerializeToString() m.arguments.append(self.protocol.sourceNode.getProto().SerializeToString()) expected_message = m.SerializeToString() self.handler.receive_message(data) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() m_calls = self.proto_mock.send_datagram.call_args_list sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) received_message = sent_packet.payload self.assertEqual(received_message, expected_message) self.assertEqual(len(m_calls), 2) def test_rpc_store(self): self._connecting_to_connected() self.protocol.router.addContact(self.protocol.sourceNode) m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("STORE") m.protoVer = self.version m.testnet = False m.arguments.extend([digest("Keyword"), "Key", self.protocol.sourceNode.getProto().SerializeToString(), str(10)]) data = m.SerializeToString() del m.arguments[-4:] m.arguments.append("True") expected_message = m.SerializeToString() self.handler.receive_message(data) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() m_calls = self.proto_mock.send_datagram.call_args_list sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) received_message = sent_packet.payload self.assertEqual(received_message, expected_message) self.assertEqual(len(m_calls), 2) self.assertTrue( self.storage.getSpecific(digest("Keyword"), "Key") == self.protocol.sourceNode.getProto().SerializeToString()) def test_bad_rpc_store(self): r = self.protocol.rpc_store(self.node, 'testkeyword', 'kw', 'val', 10) self.assertEqual(r, ['False']) def test_rpc_delete(self): self._connecting_to_connected() self.protocol.router.addContact(self.protocol.sourceNode) # Set a keyword to store m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("STORE") m.protoVer = self.version m.testnet = False m.arguments.extend([digest("Keyword"), "Key", self.protocol.sourceNode.getProto().SerializeToString(), str(10)]) data = m.SerializeToString() del m.arguments[-4:] m.arguments.append("True") expected_message1 = m.SerializeToString() self.handler.receive_message(data) self.assertTrue( self.storage.getSpecific(digest("Keyword"), "Key") == self.protocol.sourceNode.getProto().SerializeToString()) # Test bad signature m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("DELETE") m.protoVer = self.version m.testnet = False m.arguments.extend([digest("Keyword"), "Key", "Bad Signature"]) data = m.SerializeToString() del m.arguments[-3:] m.arguments.append("False") expected_message2 = m.SerializeToString() self.handler.receive_message(data) self.assertTrue( self.storage.getSpecific(digest("Keyword"), "Key") == self.protocol.sourceNode.getProto().SerializeToString()) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() sent_packets = tuple( packet.Packet.from_bytes(call[0][0]) for call in self.proto_mock.send_datagram.call_args_list ) self.assertEqual(sent_packets[0].payload, expected_message1) self.assertEqual(sent_packets[1].payload, expected_message2) self.proto_mock.send_datagram.call_args_list = [] # Test good signature m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("DELETE") m.protoVer = self.version m.testnet = False m.arguments.extend([digest("Keyword"), "Key", self.signing_key.sign("Key")[:64]]) data = m.SerializeToString() del m.arguments[-3:] m.arguments.append("True") expected_message3 = m.SerializeToString() self.handler.receive_message(data) self.clock.advance(100 * constants.PACKET_TIMEOUT) sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) self.assertEqual(sent_packet.payload, expected_message3) self.assertTrue(self.storage.getSpecific(digest("Keyword"), "Key") is None) def test_rpc_stun(self): self._connecting_to_connected() m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("STUN") m.protoVer = self.version m.testnet = False data = m.SerializeToString() m.arguments.extend([self.public_ip, str(self.port)]) expected_message = m.SerializeToString() self.handler.receive_message(data) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() m_calls = self.proto_mock.send_datagram.call_args_list sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) received_message = sent_packet.payload a = message.Message() a.ParseFromString(received_message) self.assertEqual(received_message, expected_message) self.assertEqual(len(m_calls), 2) def test_rpc_find_node(self): self._connecting_to_connected() node1 = Node(digest("id1"), "127.0.0.1", 12345, digest("key1")) node2 = Node(digest("id2"), "127.0.0.1", 22222, digest("key2")) node3 = Node(digest("id3"), "127.0.0.1", 77777, digest("key3")) self.protocol.router.addContact(node1) self.protocol.router.addContact(node2) self.protocol.router.addContact(node3) m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("FIND_NODE") m.protoVer = self.version m.testnet = False m.arguments.append(digest("nodetofind")) data = m.SerializeToString() del m.arguments[-1] m.arguments.extend([node2.getProto().SerializeToString(), node1.getProto().SerializeToString(), node3.getProto().SerializeToString()]) expected_message = m.SerializeToString() self.handler.receive_message(data) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() m_calls = self.proto_mock.send_datagram.call_args_list sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) received_message = sent_packet.payload a = message.Message() a.ParseFromString(received_message) self.assertEqual(received_message, expected_message) self.assertEqual(len(m_calls), 2) def test_rpc_find_value(self): self._connecting_to_connected() self.protocol.router.addContact(self.protocol.sourceNode) # Set a value to find m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("STORE") m.protoVer = self.version m.arguments.extend([digest("Keyword"), "Key", self.protocol.sourceNode.getProto().SerializeToString(), str(10)]) data = m.SerializeToString() self.handler.receive_message(data) self.assertTrue( self.storage.getSpecific(digest("Keyword"), "Key") == self.protocol.sourceNode.getProto().SerializeToString()) # Send the find_value rpc m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("FIND_VALUE") m.protoVer = self.version m.testnet = False m.arguments.append(digest("Keyword")) data = m.SerializeToString() self.handler.receive_message(data) del m.arguments[-1] value = objects.Value() value.valueKey = "Key" value.serializedData = self.protocol.sourceNode.getProto().SerializeToString() value.ttl = 10 m.arguments.append("value") m.arguments.append(value.SerializeToString()) expected_message = m.SerializeToString() self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() m_calls = self.proto_mock.send_datagram.call_args_list sent_packets = tuple( packet.Packet.from_bytes(call[0][0]) for call in self.proto_mock.send_datagram.call_args_list ) received_message = sent_packets[1].payload self.assertEqual(received_message, expected_message) self.assertEqual(len(m_calls), 3) def test_rpc_find_without_value(self): self._connecting_to_connected() node1 = Node(digest("id1"), "127.0.0.1", 12345, digest("key1")) node2 = Node(digest("id2"), "127.0.0.1", 22222, digest("key2")) node3 = Node(digest("id3"), "127.0.0.1", 77777, digest("key3")) self.protocol.router.addContact(node1) self.protocol.router.addContact(node2) self.protocol.router.addContact(node3) m = message.Message() m.messageID = digest("msgid") m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("FIND_VALUE") m.protoVer = self.version m.testnet = False m.arguments.append(digest("Keyword")) data = m.SerializeToString() self.handler.receive_message(data) del m.arguments[-1] m.arguments.extend([node3.getProto().SerializeToString(), node1.getProto().SerializeToString(), node2.getProto().SerializeToString()]) expected_message = m.SerializeToString() self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() m_calls = self.proto_mock.send_datagram.call_args_list sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) received_message = sent_packet.payload m = message.Message() m.ParseFromString(received_message) self.assertEqual(received_message, expected_message) self.assertEqual(len(m_calls), 2) def test_callPing(self): self._connecting_to_connected() n = Node(digest("S"), self.addr1[0], self.addr1[1]) self.wire_protocol[self.addr1] = self.con self.protocol.callPing(n) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload m = message.Message() m.ParseFromString(sent_message) self.assertTrue(len(m.messageID) == 20) self.assertEqual(self.protocol.sourceNode.getProto().guid, m.sender.guid) self.assertEqual(self.protocol.sourceNode.getProto().signedPublicKey, m.sender.signedPublicKey) self.assertTrue(m.command == message.PING) self.assertEqual(self.proto_mock.send_datagram.call_args_list[0][0][1], self.addr1) def test_callStore(self): self._connecting_to_connected() n = Node(digest("S"), self.addr1[0], self.addr1[1]) self.wire_protocol[self.addr1] = self.con self.protocol.callStore(n, digest("Keyword"), digest("Key"), self.protocol.sourceNode.getProto().SerializeToString(), 10) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload m = message.Message() m.ParseFromString(sent_message) self.assertTrue(len(m.messageID) == 20) self.assertEqual(self.protocol.sourceNode.getProto().guid, m.sender.guid) self.assertEqual(self.protocol.sourceNode.getProto().signedPublicKey, m.sender.signedPublicKey) self.assertTrue(m.command == message.STORE) self.assertEqual(self.proto_mock.send_datagram.call_args_list[0][0][1], self.addr1) self.assertEqual(m.arguments[0], digest("Keyword")) self.assertEqual(m.arguments[1], digest("Key")) self.assertEqual(m.arguments[2], self.protocol.sourceNode.getProto().SerializeToString()) def test_callFindValue(self): self._connecting_to_connected() n = Node(digest("S"), self.addr1[0], self.addr1[1]) self.wire_protocol[self.addr1] = self.con keyword = Node(digest("Keyword")) self.protocol.callFindValue(n, keyword) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload m = message.Message() m.ParseFromString(sent_message) self.assertTrue(len(m.messageID) == 20) self.assertEqual(self.protocol.sourceNode.getProto().guid, m.sender.guid) self.assertEqual(self.protocol.sourceNode.getProto().signedPublicKey, m.sender.signedPublicKey) self.assertTrue(m.command == message.FIND_VALUE) self.assertEqual(self.proto_mock.send_datagram.call_args_list[0][0][1], self.addr1) self.assertEqual(m.arguments[0], keyword.id) def test_callFindNode(self): self._connecting_to_connected() n = Node(digest("S"), self.addr1[0], self.addr1[1]) self.wire_protocol[self.addr1] = self.con keyword = Node(digest("nodetofind")) self.protocol.callFindNode(n, keyword) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload m = message.Message() m.ParseFromString(sent_message) self.assertTrue(len(m.messageID) == 20) self.assertEqual(self.protocol.sourceNode.getProto().guid, m.sender.guid) self.assertEqual(self.protocol.sourceNode.getProto().signedPublicKey, m.sender.signedPublicKey) self.assertTrue(m.command == message.FIND_NODE) self.assertEqual(self.proto_mock.send_datagram.call_args_list[0][0][1], self.addr1) self.assertEqual(m.arguments[0], keyword.id) def test_callDelete(self): self._connecting_to_connected() n = Node(digest("S"), self.addr1[0], self.addr1[1]) self.wire_protocol[self.addr1] = self.con self.protocol.callDelete(n, digest("Keyword"), digest("Key"), digest("Signature")) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload m = message.Message() m.ParseFromString(sent_message) self.assertEqual(self.proto_mock.send_datagram.call_args_list[0][0][1], self.addr1) self.assertTrue(len(m.messageID) == 20) self.assertEqual(self.protocol.sourceNode.getProto().guid, m.sender.guid) self.assertEqual(self.protocol.sourceNode.getProto().signedPublicKey, m.sender.signedPublicKey) self.assertTrue(m.command == message.DELETE) self.assertEqual(m.arguments[0], digest("Keyword")) self.assertEqual(m.arguments[1], digest("Key")) self.assertEqual(m.arguments[2], digest("Signature")) def test_acceptResponse(self): self._connecting_to_connected() def handle_response(resp): self.assertTrue(resp[0]) self.assertEqual(resp[1][0], "test") self.assertTrue(message_id not in self.protocol._outstanding) message_id = digest("msgid") n = Node(digest("S"), self.addr1[0], self.addr1[1]) d = defer.Deferred() self.protocol._outstanding[message_id] = (d, self.addr1, reactor.callLater(5, handle_response)) self.protocol._acceptResponse(message_id, ["test"], n) return d.addCallback(handle_response) def test_unknownRPC(self): self.assertFalse(self.handler.receive_message(str(random.getrandbits(1400)))) def test_timeout(self): def handle_response(resp, n): self.assertFalse(resp[0]) self.assertIsNone(resp[1]) self.assertTrue(self.protocol.router.isNewNode(n)) n = Node(digest("S"), self.addr1[0], self.addr1[1]) d = defer.Deferred().addCallback(handle_response, n) self.protocol._outstanding["msgID"] = [d, self.addr1] self.protocol.router.addContact(n) self.protocol.timeout(self.addr1, n) def test_transferKeyValues(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.protocol.router.addContact(mknode()) self.protocol.storage[digest("keyword")] = ( digest("key"), self.protocol.sourceNode.getProto().SerializeToString(), 10) self.protocol.storage[digest("keyword")] = ( digest("key2"), self.protocol.sourceNode.getProto().SerializeToString(), 10) self.protocol.transferKeyValues(Node(digest("id"), self.addr1[0], self.addr1[1])) self.clock.advance(1) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes(self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload x = message.Message() x.ParseFromString(sent_message) i = objects.Inv() i.keyword = digest("keyword") i.valueKey = digest("key") i2 = objects.Inv() i2.keyword = digest("keyword") i2.valueKey = digest("key2") m = message.Message() m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("INV") m.protoVer = self.version m.arguments.append(i.SerializeToString()) m.arguments.append(i2.SerializeToString()) self.assertEqual(x.sender, m.sender) self.assertEqual(x.command, m.command) self.assertTrue(x.arguments[0] in m.arguments) self.assertTrue(x.arguments[1] in m.arguments) def test_refreshIDs(self): node1 = Node(digest("id1"), "127.0.0.1", 12345, signed_pubkey=digest("key1")) node2 = Node(digest("id2"), "127.0.0.1", 22222, signed_pubkey=digest("key2")) node3 = Node(digest("id3"), "127.0.0.1", 77777, signed_pubkey=digest("key3")) self.protocol.router.addContact(node1) self.protocol.router.addContact(node2) self.protocol.router.addContact(node3) for b in self.protocol.router.buckets: b.lastUpdated = (time.time() - 5000) ids = self.protocol.getRefreshIDs() self.assertTrue(len(ids) == 1) def _connecting_to_connected(self): remote_synack_packet = packet.Packet.from_data( 42, self.con.own_addr, self.con.dest_addr, ack=0, syn=True ) self.con.receive_packet(remote_synack_packet) self.clock.advance(0) connection.REACTOR.runUntilCurrent() self.next_remote_seqnum = 43 m_calls = self.proto_mock.send_datagram.call_args_list sent_syn_packet = packet.Packet.from_bytes(m_calls[0][0][0]) seqnum = sent_syn_packet.sequence_number self.handler_mock.reset_mock() self.proto_mock.reset_mock() self.next_seqnum = seqnum + 1 def test_badRPCDelete(self): n = mknode() val = self.protocol.rpc_delete(n, 'testkeyword', 'key', 'testsig') self.assertEqual(val, ["False"]) val = self.protocol.rpc_delete(n, '', '', '')
class NodeSpiderCrawlTest(unittest.TestCase): def setUp(self): self.public_ip = "123.45.67.89" self.port = 12345 self.own_addr = (self.public_ip, self.port) self.addr1 = ("132.54.76.98", 54321) self.addr2 = ("231.76.45.89", 15243) self.addr3 = ("193.193.111.00", 99999) self.clock = task.Clock() connection.REACTOR.callLater = self.clock.callLater self.proto_mock = mock.Mock(spec_set=rudp.ConnectionMultiplexer) self.handler_mock = mock.Mock(spec_set=connection.Handler) self.con = connection.Connection(self.proto_mock, self.handler_mock, self.own_addr, self.addr1) valid_key = "1a5c8e67edb8d279d1ae32fa2da97e236b95e95c837dc8c3c7c2ff7a7cc29855" self.signing_key = nacl.signing.SigningKey(valid_key, encoder=nacl.encoding.HexEncoder) verify_key = self.signing_key.verify_key signed_pubkey = self.signing_key.sign(str(verify_key)) h = nacl.hash.sha512(signed_pubkey) self.storage = ForgetfulStorage() self.node = Node(unhexlify(h[:40]), self.public_ip, self.port, signed_pubkey, True) self.db = Database(filepath=":memory:") self.protocol = KademliaProtocol(self.node, self.storage, 20, self.db) self.wire_protocol = OpenBazaarProtocol(self.own_addr, "Full Cone") self.wire_protocol.register_processor(self.protocol) self.protocol.connect_multiplexer(self.wire_protocol) self.handler = self.wire_protocol.ConnHandler([self.protocol], self.wire_protocol) transport = mock.Mock(spec_set=udp.Port) ret_val = address.IPv4Address("UDP", self.public_ip, self.port) transport.attach_mock(mock.Mock(return_value=ret_val), "getHost") self.wire_protocol.makeConnection(transport) self.node1 = Node(digest("id1"), self.addr1[0], self.addr1[1], digest("key1"), True) self.node2 = Node(digest("id2"), self.addr2[0], self.addr2[1], digest("key2"), True) self.node3 = Node(digest("id3"), self.addr3[0], self.addr3[1], digest("key3"), True) def test_find(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.wire_protocol[self.addr2] = self.con self.wire_protocol[self.addr3] = self.con self.protocol.router.addContact(self.node1) self.protocol.router.addContact(self.node2) self.protocol.router.addContact(self.node3) node = Node(digest("s")) nearest = self.protocol.router.findNeighbors(node) spider = NodeSpiderCrawl(self.protocol, node, nearest, 20, 3) spider.find() self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() self.assertEqual(len(self.proto_mock.send_datagram.call_args_list), 4) def test_nodesFound(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.wire_protocol[self.addr2] = self.con self.wire_protocol[self.addr3] = self.con self.protocol.router.addContact(self.node1) self.protocol.router.addContact(self.node2) self.protocol.router.addContact(self.node3) node = Node(digest("s")) nearest = self.protocol.router.findNeighbors(node) spider = NodeSpiderCrawl(self.protocol, node, nearest, 20, 3) response = ( True, ( self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString(), ), ) responses = {self.node1.id: response} spider._nodesFound(responses) self.clock.advance(100 * constants.PACKET_TIMEOUT) connection.REACTOR.runUntilCurrent() self.assertEqual(len(self.proto_mock.send_datagram.call_args_list), 4) response = ( True, ( self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString(), ), ) responses = {self.node1.id: response} nodes = spider._nodesFound(responses) node_protos = [] for n in nodes: node_protos.append(n.getProto()) self.assertTrue(self.node1.getProto() in node_protos) self.assertTrue(self.node2.getProto() in node_protos) self.assertTrue(self.node3.getProto() in node_protos) response = ( False, ( self.node1.getProto().SerializeToString(), self.node2.getProto().SerializeToString(), self.node3.getProto().SerializeToString(), ), ) responses = {self.node1.id: response} nodes = spider._nodesFound(responses) node_protos = [] for n in nodes: node_protos.append(n.getProto()) self.assertTrue(self.node2.getProto() in node_protos) self.assertTrue(self.node3.getProto() in node_protos) def _connecting_to_connected(self): remote_synack_packet = packet.Packet.from_data(42, self.con.own_addr, self.con.dest_addr, ack=0, syn=True) self.con.receive_packet(remote_synack_packet) self.clock.advance(0) connection.REACTOR.runUntilCurrent() self.next_remote_seqnum = 43 m_calls = self.proto_mock.send_datagram.call_args_list sent_syn_packet = packet.Packet.from_bytes(m_calls[0][0][0]) seqnum = sent_syn_packet.sequence_number self.handler_mock.reset_mock() self.proto_mock.reset_mock() self.next_seqnum = seqnum + 1