def test_getdata_message_with_two_blocks(self): cblock1 = CBlock() block1 = Block(cblock1, BlockOrigin.private) block1.cblock = cblock1 cInv1 = CInv() cInv1.type = networking.inv_typemap['Block'] cInv1.hash = cblock1.GetHash() cblock2 = CBlock() block2 = Block(cblock2, BlockOrigin.private) block2.cblock = cblock2 cInv2 = CInv() cInv2.type = networking.inv_typemap['Block'] cInv2.hash = cblock2.GetHash() message = messages.msg_getdata() message.inv = [cInv1, cInv2] self.chain.blocks = { cblock1.GetHash(): block1, cblock2.GetHash(): block2 } self.networking.getdata_message(self.public_connection1, message) self.assertTrue(self.public_connection1.send.called) self.assertEqual(self.public_connection1.send.call_count, 2)
def connection_mock(signed_transaction): connection = MagicMock() connection.getsockname.return_value = ('127.0.0.1', 8800) connection.getpeername.return_value = ('127.0.0.1', 8800) connection.getpeername.return_value = ('127.0.0.1', 8800) protocol_version = 6002 version = msg_version(protocol_version).to_bytes() verack = msg_verack(protocol_version).to_bytes() getdata = msg_getdata(protocol_version) getdata = getdata.msg_deser(BytesIO(b'\x01\x01\x00\x00\x00' + signed_transaction.tx.GetHash())).to_bytes() connection.recv.side_effect = ( version + verack, getdata, ) capture = BitcoinTestNet.capture_messages def capture_messages_mock(*args, **kwargs): if msg_reject in args[1]: return None else: return capture(*args, **kwargs) with patch('socket.create_connection', return_value=connection): with patch('socket.gethostbyname_ex', return_value=(None, None, ['127.0.0.1'])): with patch.object(BitcoinTestNet, 'capture_messages', new=capture_messages_mock): yield
def request_blocks(self, connection, inv): if len(inv) > 0: for hash_ in inv: self.blocks_in_flight[hash_] = BlockInFlight(hash_, time.time()) message = messages.msg_getdata() message.inv = [hash_to_inv('Block', hash_) for hash_ in inv] connection.send('getdata', message) logging.info('requested getdata for {} blocks'.format(len(inv)))
def got_message(self, msg): if msg.command == 'ping': pong = msg_pong(nonce=msg.nonce) self.sock.send(pong.to_bytes()) elif msg.command == 'inv': for i in msg.inv: # transaction/block/txlrequest/txlvote if i.type in (1, 2, 4, 5): gd = msg_getdata() gd.inv.append(i) self.sock.send(gd.to_bytes()) if msg.command in self.route: self.route[msg.command](msg)
def send_getblocks(self): our_height = self.chaindb.getheight() if our_height < 0: gd = messages.msg_getdata(protover=self.ver_send) inv = net.CInv() inv.type = 2 inv.hash = self.params.GENESIS_BLOCK.GetHash() gd.inv.append(inv) self.send_message(gd) elif our_height < self.remote_height: gb = messages.msg_getblocks(protover=self.ver_send) if our_height >= 0: gb.locator.vHave.append(self.chaindb.gettophash()) self.send_message(gb)
def test_getdata_message_without_tx(self): message = messages.msg_getdata() inv = CInv() inv.type = networking.inv_typemap['TX'] inv.hash = 'hash1' message.inv = [inv] self.networking.get_tx = MagicMock() self.networking.get_tx.return_value = None self.networking.getdata_message(self.public_connection1, message) self.assertFalse(self.private_connection.send.called) self.assertFalse(self.public_connection1.send.called) self.assertFalse(self.public_connection2.send.called)
def test_getdata_message_with_unknown_hashes(self): message = messages.msg_getdata() cInv1 = CInv() cInv1.type = networking.inv_typemap['Block'] cInv1.hash = 'hash1' cInv2 = CInv() cInv2.type = networking.inv_typemap['Block'] cInv2.hash = 'hash2' message.inv = [cInv1, cInv2] self.chain.blocks = {} self.networking.getdata_message(self.public_connection1, message) self.assertFalse(self.public_connection1.send.called)
def test_getdata_message_cblock_not_available(self): cblock = CBlock() hash_ = cblock.GetHash() block = Block(cblock, BlockOrigin.private) message = messages.msg_getdata() cInv = CInv() cInv.type = networking.inv_typemap['Block'] cInv.hash = hash_ message.inv = [cInv] self.chain.blocks = {hash_: block} self.networking.deferred_block_requests = {} self.networking.getdata_message(self.public_connection1, message) self.assertFalse(self.public_connection1.called) self.assertIn(hash_, self.networking.deferred_block_requests) self.assertIn(self.public_connection1.host[0], self.networking.deferred_block_requests[hash_])
def test_getdata_message_with_block(self): cblock = CBlock() block = Block(cblock, BlockOrigin.private) block.cblock = cblock message = messages.msg_getdata() cInv = CInv() cInv.type = networking.inv_typemap['Block'] cInv.hash = cblock.GetHash() message.inv = [cInv] self.chain.blocks = {cblock.GetHash(): block} self.networking.getdata_message(self.public_connection1, message) self.assertTrue(self.public_connection1.send.called) self.assertEqual(self.public_connection1.send.call_args[0][0], 'block') self.assertEqual(self.public_connection1.send.call_args[0][1].block, cblock)
def send_getblocks(self, timecheck=True): if not self.getblocks_ok: return now = time.time() # if timecheck and (now - self.last_getblocks) < 1: # return self.last_getblocks = now our_height = self.chaindb.getheight() if our_height < 0: gd = msg_getdata(self.ver_send) inv = CInv() inv.type = 2 inv.hash = bitcoin.params.GENESIS_BLOCK.GetHash() gd.inv.append(inv) self.send_message(gd) elif our_height < self.remote_height: gb = msg_getblocks(self.ver_send) if our_height >= 0: gb.locator.vHave = self.chaindb.getlocator() self.send_message(gb)
def send_getdata(self): start_block_hash = self.parameters_store.get_last_block_analized() block_hashes = self.block_chain.get_next_n_blocks_hashes( start_block_hash, 5000) if len(block_hashes) == 0: self.stop_client = True print("Analysis ended!") self.data_request = len(block_hashes) invs = [] for block_hash in block_hashes: inv = CInv() ''' MSG_FILTERED_BLOCK Indicates the reply should be a merkleblock message rather than a block message; this only works if a bloom filter has been set. ''' inv.type = 3 inv.hash = lx(block_hash) invs.append(inv) msg = msg_getdata() msg.inv = invs self.send_message(msg)
def send_getblocks(self, timecheck=True): if not self.getblocks_ok: return now = time.time() # if timecheck and (now - self.last_getblocks) < 1: # return self.last_getblocks = now our_height = self.chaindb.getheight() if our_height < 0: gd = msg_getdata(self.ver_send) inv = CInv() inv.type = 2 inv.hash = lx( 'cf7938a048f1442dd34f87ce56d3e25455b22a44f676325f1ae8c7a33d0731c7' ) gd.inv.append(inv) self.send_message(gd) elif our_height < self.remote_height: gb = msg_getblocks(self.ver_send) if our_height >= 0: gb.locator.vHave = self.chaindb.getlocator() self.send_message(gb)
def got_message(self, message): gevent.sleep() if self.last_sent + 30 * 60 < time.time(): self.send_message(msg_ping(self.ver_send)) if verbose_recvmsg(message): self.log.info("recv %s" % repr(message)) if message.command == b"version": self.ver_send = min(PROTO_VERSION, message.nVersion) if self.ver_send < MIN_PROTO_VERSION: self.log.info("Obsolete version %d, closing" % (self.ver_send, )) self.handle_close() return self.remote_height = message.nStartingHeight self.send_message(msg_verack(self.ver_send)) # if self.ver_send >= CADDR_TIME_VERSION: # self.send_message(msg_getaddr(self.ver_send)) self.send_getblocks() elif message.command == b'ping': if self.ver_send > BIP0031_VERSION: self.send_message(msg_pong(self.ver_send)) elif message.command == b"verack": self.ver_recv = self.ver_send self.send_message(msg_addr()) # self.send_getaddr() elif message.command == b"inv": # special message sent to kick getblocks # if (len(message.inv) == 1 and # message.inv[0].type == MSG_BLOCK and # self.chaindb.haveblock(message.inv[0].hash, True)): # self.send_getblocks(False) # return want = msg_getdata(self.ver_send) for i in message.inv: if i.type == 1: want.inv.append(i) elif i.type == 2: want.inv.append(i) # break #UNDO self.last_want = i.hash if len(want.inv): self.send_message(want) elif message.command == b"tx": if self.chaindb.tx_is_orphan(message.tx): self.log.info("MemPool: Ignoring orphan TX %s" % (b2lx(message.tx.GetHash()), )) # elif not self.chaindb.tx_signed(message.tx, None, True): # self.log.info("MemPool: Ignoring failed-sig TX %s" % (b2lx(message.tx.GetHash()),)) else: self.chaindb.mempool_add(message.tx) elif message.command == b"block": bhash = b2lx(message.block.GetHash()) self.chaindb.putblock(message.block) # b = BytesIO() # message.block.stream_serialize(b) # s = b.getvalue() # print(b2lx(s)) self.last_block_rx = time.time() #UNDO if self.last_want == 0: gevent.spawn(self.send_getblocks) elif bhash == b2lx(self.last_want): gevent.spawn(self.send_getblocks) elif message.command == b"getheaders": self.getheaders(message) # elif message.command == b"addr": # if len(message.addrs) == 1: # gevent.spawn(self.send_getblocks) # for addr in message.addrs: # host = '%s:%s' % (addr.ip, addr.port) # if host not in self.addresses_seen: # self.addresses_seen.append(host) # elif message.command == b'tx': # for idx, vout in enumerate(message.tx.vout): # script = vout.scriptPubKey # if len(script) >= 38 and script[:6] == bitcoin.core.WITNESS_COINBASE_SCRIPTPUBKEY_MAGIC: # continue # script = CScript(vout.scriptPubKey) # if script.is_unspendable(): # print("Unspendable %s" % vout.scriptPubKey) # if vout.scriptPubKey[:4] == b'j\x07\xfe\xab': # print(vout.scriptPubKey[4:].decode('utf-8')) # continue last_blkmsg = time.time() - self.last_block_rx if last_blkmsg > 5: self.send_getblocks()
def got_message(self, message): gevent.sleep() if self.last_sent + 30 * 60 < time.time(): self.send_message(messages.msg_ping(self.ver_send)) self.log.debug("recv %s" % repr(message)) if message.command == "version": self.ver_send = min(self.params.PROTO_VERSION, message.nVersion) if self.ver_send < self.params.MIN_PROTO_VERSION: self.log.info("Obsolete version %d, closing" % (self.ver_send,)) self.handle_close() return if (self.ver_send >= self.params.NOBLKS_VERSION_START and self.ver_send <= self.params.NOBLKS_VERSION_END): self.getblocks_ok = False self.remote_height = message.nStartingHeight self.send_message(messages.msg_verack(self.ver_send)) if self.ver_send >= self.params.CADDR_TIME_VERSION: self.send_message(messages.msg_getaddr(self.ver_send)) self.request_latest() self.client_version = message.strSubVer elif message.command == "verack": self.ver_recv = self.ver_send if self.ver_send >= self.params.MEMPOOL_GD_VERSION: self.send_message(messages.msg_mempool()) elif message.command == "ping": if self.ver_send > self.params.BIP0031_VERSION: self.send_message(messages.msg_pong(self.ver_send)) elif message.command == "addr": self.peermgr.new_addrs(message.addrs) elif message.command == "inv": # special message sent to kick getblocks if (len(message.inv) == 1 and message.inv[0].type == messages.MSG_BLOCK and self.chaindb.haveblock(message.inv[0].hash, True)): self.request_latest(False) return want = messages.msg_getdata(self.ver_send) for i in message.inv: if i.type == 1: want.inv.append(i) elif i.type == 2: want.inv.append(i) if len(want.inv): self.send_message(want) elif message.command == "tx": if self.chaindb.tx_is_orphan(message.tx): self.log.info( "MemPool: Ignoring orphan TX {}" .format(message.tx.GetHash().encode('hex'))) elif not self.chaindb.tx_signed(message.tx, None, True): self.log.info( "MemPool: Ignoring failed-sig TX {}" .format(message.tx.GetHash().encode('hex'))) else: self.mempool.add(message.tx) elif message.command == "block": self.chaindb.putblock(message.block) self.last_block_rx = time.time() elif message.command == "headers": self.chaindb.putblock(message.block) self.last_block_rx = time.time() elif message.command == "getdata": self.getdata(message) elif message.command == "getblocks": self.getblocks(message) elif message.command == "getheaders": self.getheaders(message) elif message.command == "getaddr": msg = messages.msg_addr() msg.addrs = self.peermgr.random_addrs() self.send_message(msg) elif message.command == "mempool": msg = messages.msg_inv() for k in self.mempool.pool.iterkeys(): inv = net.CInv() inv.type = messages.MSG_TX inv.hash = k msg.inv.append(inv) if len(msg.inv) == 50000: break self.send_message(msg) # if we haven't seen a 'block' message in a little while, # and we're still not caught up, send another getblocks last_blkmsg = time.time() - self.last_block_rx if last_blkmsg > 5: self.request_latest()
def got_message(self, message): gevent.sleep() if self.last_sent + 30 * 60 < time.time(): self.send_message(msg_ping(self.ver_send)) if verbose_recvmsg(message): self.log.info("recv %s" % repr(message)) if message.command == b"version": self.ver_send = min(PROTO_VERSION, message.nVersion) if self.ver_send < MIN_PROTO_VERSION: self.log.info("Obsolete version %d, closing" % (self.ver_send, )) self.handle_close() return self.remote_height = message.nStartingHeight self.send_message(msg_verack(self.ver_send)) if self.ver_send >= CADDR_TIME_VERSION: self.send_message(msg_getaddr(self.ver_send)) # self.send_getblocks() elif message.command == b'ping': if self.ver_send > BIP0031_VERSION: self.send_message(msg_pong(self.ver_send)) elif message.command == b"verack": self.ver_recv = self.ver_send self.send_message(msg_addr()) self.send_getaddr() elif message.command == b"inv": # special message sent to kick getblocks # if (len(message.inv) == 1 and # message.inv[0].type == MSG_BLOCK and # self.chaindb.haveblock(message.inv[0].hash, True)): # self.send_getblocks(False) # return want = msg_getdata(self.ver_send) for i in message.inv: if i.type == 1: want.inv.append(i) elif i.type == 2: want.inv.append(i) self.last_want = i.hash if len(want.inv): self.send_message(want) # elif message.command == b"block": # bhash = b2lx(message.block.GetHash()) # self.chaindb.putblock(message.block) # self.last_block_rx = time.time() # if self.last_want == 0: # gevent.spawn(self.send_getblocks) # elif bhash == b2lx(self.last_want): # gevent.spawn(self.send_getblocks) elif message.command == b"addr": self.peermgr.new_addrs(message.addrs) for addr in message.addrs: self.peermgr.add(addr.ip, addr.port) elif message.command == b'getheaders': self.send_message(msg_headers())
def got_message(self, message): gevent.sleep() if self.last_sent + 30 * 60 < time.time(): self.send_message(messages.msg_ping(self.ver_send)) self.log.debug("recv %s" % repr(message)) if message.command == "version": self.ver_send = min(self.params.PROTO_VERSION, message.nVersion) if self.ver_send < self.params.MIN_PROTO_VERSION: self.log.info("Obsolete version %d, closing" % (self.ver_send, )) self.handle_close() return if (self.ver_send >= self.params.NOBLKS_VERSION_START and self.ver_send <= self.params.NOBLKS_VERSION_END): self.getblocks_ok = False self.remote_height = message.nStartingHeight self.send_message(messages.msg_verack(self.ver_send)) if self.ver_send >= self.params.CADDR_TIME_VERSION: self.send_message(messages.msg_getaddr(self.ver_send)) self.request_latest() self.client_version = message.strSubVer elif message.command == "verack": self.ver_recv = self.ver_send if self.ver_send >= self.params.MEMPOOL_GD_VERSION: self.send_message(messages.msg_mempool()) elif message.command == "ping": if self.ver_send > self.params.BIP0031_VERSION: self.send_message(messages.msg_pong(self.ver_send)) elif message.command == "addr": self.peermgr.new_addrs(message.addrs) elif message.command == "inv": # special message sent to kick getblocks if (len(message.inv) == 1 and message.inv[0].type == messages.MSG_BLOCK and self.chaindb.haveblock(message.inv[0].hash, True)): self.request_latest(False) return want = messages.msg_getdata(self.ver_send) for i in message.inv: if i.type == 1: want.inv.append(i) elif i.type == 2: want.inv.append(i) if len(want.inv): self.send_message(want) elif message.command == "tx": if self.chaindb.tx_is_orphan(message.tx): self.log.info("MemPool: Ignoring orphan TX {}".format( message.tx.GetHash().encode('hex'))) elif not self.chaindb.tx_signed(message.tx, None, True): self.log.info("MemPool: Ignoring failed-sig TX {}".format( message.tx.GetHash().encode('hex'))) else: self.mempool.add(message.tx) elif message.command == "block": self.chaindb.putblock(message.block) self.last_block_rx = time.time() elif message.command == "headers": self.chaindb.putblock(message.block) self.last_block_rx = time.time() elif message.command == "getdata": self.getdata(message) elif message.command == "getblocks": self.getblocks(message) elif message.command == "getheaders": self.getheaders(message) elif message.command == "getaddr": msg = messages.msg_addr() msg.addrs = self.peermgr.random_addrs() self.send_message(msg) elif message.command == "mempool": msg = messages.msg_inv() for k in self.mempool.pool.iterkeys(): inv = net.CInv() inv.type = messages.MSG_TX inv.hash = k msg.inv.append(inv) if len(msg.inv) == 50000: break self.send_message(msg) # if we haven't seen a 'block' message in a little while, # and we're still not caught up, send another getblocks last_blkmsg = time.time() - self.last_block_rx if last_blkmsg > 5: self.request_latest()