def run_test(self): self.stop_node(0) with self.run_node_with_connections( "logging difference between block created timestamp and header received timestamp", 0, [], 2) as p2p_connections: # initialize self.nodes[0].generate(1) connection1 = p2p_connections[0] connection2 = p2p_connections[1] # 1. create first block (creation time is set) block = self.prepareBlock(2) # 2. sleep five seconds time.sleep(5) # 3. connection1 sends HEADERS msg to bitcoind and waits for GETDATA (received time is set) headers_message = msg_headers() headers_message.headers = [CBlockHeader(block)] connection1.cb.send_message(headers_message) connection1.cb.wait_for_getdata(block.sha256) # 4. connection1 sends BLOCK connection1.cb.send_message(msg_block(block)) # 5. create second block block = self.prepareBlock(2) # 6. connection2 sends HEADERS msg to bitcoind headers_message = msg_headers() headers_message.headers = [CBlockHeader(block)] connection2.cb.send_message(headers_message) # 7. connection2 waits for GETDATA and sends BLOCK connection2.cb.wait_for_getdata(block.sha256) connection2.cb.send_message(msg_block(block)) # syncing connection1.cb.sync_with_ping() connection2.cb.sync_with_ping() # check log file for logging about block timestamp and received headers timestamp difference time_difference_log_found = False for line in open( glob.glob(self.options.tmpdir + "/node0" + "/regtest/bitcoind.log")[0]): if "Chain tip timestamp-to-received-time difference" in line: time_difference_log_found = True logger.info("Found line: %s", line) break assert_equal(time_difference_log_found, True)
def get_tests(self): # shorthand for functions block = self.chain.next_block node = self.nodes[0] self.chain.set_genesis_hash(int(node.getbestblockhash(), 16)) # Now we need that block to mature so we can spend the coinbase. test = TestInstance(sync_every_block=False) for i in range(105): block(5000 + i) test.blocks_and_transactions.append([self.chain.tip, True]) self.chain.save_spendable_output() yield test # collect spendable outputs now to avoid cluttering the code later on out = [] for i in range(105): out.append(self.chain.get_spendable_output()) assert_equal(node.getblock(node.getbestblockhash())['height'], 105) block(1) redeem_script = CScript([OP_TRUE, OP_RETURN, b"a" * 5000]) spend_tx1 = CTransaction() spend_tx1.vin.append( CTxIn(COutPoint(out[2].tx.sha256, out[2].n), CScript(), 0xffffffff)) spend_tx1.vout.append(CTxOut(500, redeem_script)) spend_tx1.vout.append(CTxOut(500, redeem_script)) spend_tx1.calc_sha256() self.log.info(spend_tx1.hash) self.chain.update_block(1, [spend_tx1]) yield self.accepted() tx1 = CTransaction() tx1.vout = [CTxOut(499, CScript([OP_TRUE]))] tx1.vin.append( CTxIn(COutPoint(spend_tx1.sha256, 0), CScript(), 0xfffffff)) tx1.vin.append( CTxIn(COutPoint(spend_tx1.sha256, 1), CScript(), 0xfffffff)) tx1.calc_sha256() self.log.info(tx1.hash) yield TestInstance( [[tx1, RejectResult(16, b'bad-txns-inputs-too-large')]])
def run_test(self): self.stop_node(0) askedFor = {} rejectSent = False def on_getdata(conn, message): if (conn in askedFor): askedFor[conn] += 1 else: askedFor[conn] = 1 nonlocal rejectSent # First node that receives GetData should send reject. if not rejectSent: rejectSent = True conn.send_message(msg_reject(message=b"getdata", code=self.REJECT_TOOBUSY, reason=b"node too busy")) with self.run_node_with_connections("Scenario 1: sending TOOBUSY reject message with 2 nodes", 0, [], self.num_peers) as connections: block = self.prepareBlock() for connection in connections: connection.cb.on_getdata = on_getdata headers_message = msg_headers() headers_message.headers = [CBlockHeader(block)] connection.cb.send_message(headers_message) connection.cb.wait_for_getdata(block.sha256) connection.cb.sync_with_ping() for key, value in askedFor.items(): assert_equal(value, 1) assert_equal(len(askedFor), 2) self.num_peers = 1 askedFor = {} rejectSent = False with self.run_node_with_connections("Scenario 2: sending TOOBUSY reject message with 1 node", 0, [], self.num_peers) as connections: block = self.prepareBlock() connection = connections[0] connection.cb.on_getdata = on_getdata headers_message = msg_headers() headers_message.headers = [CBlockHeader(block)] begin_test = datetime.datetime.now() connection.cb.send_message(headers_message) connection.cb.wait_for_getdata(block.sha256) connection.cb.last_message["getdata"] = [] connection.cb.wait_for_getdata(block.sha256) end_test = datetime.datetime.now() assert(end_test - begin_test > datetime.timedelta(seconds = 5)) assert_equal(next(iter(askedFor.values())), 2) assert_equal(len(askedFor), 1)
def get_tests(self): # shorthand for functions block = self.chain.next_block node = self.nodes[0] self.chain.set_genesis_hash(int(node.getbestblockhash(), 16)) test, out, _ = prepare_init_chain(self.chain, 105, 105, block_0=False) yield test assert_equal(node.getblock(node.getbestblockhash())['height'], 105) block(1) redeem_script = CScript([OP_TRUE, OP_RETURN, b"a" * 5000]) spend_tx1 = CTransaction() spend_tx1.vin.append( CTxIn(COutPoint(out[2].tx.sha256, out[2].n), CScript(), 0xffffffff)) spend_tx1.vout.append(CTxOut(500, redeem_script)) spend_tx1.vout.append(CTxOut(500, redeem_script)) spend_tx1.calc_sha256() self.log.info(spend_tx1.hash) self.chain.update_block(1, [spend_tx1]) yield self.accepted() tx1 = CTransaction() tx1.vout = [CTxOut(499, CScript([OP_TRUE]))] tx1.vin.append( CTxIn(COutPoint(spend_tx1.sha256, 0), CScript(), 0xfffffff)) tx1.vin.append( CTxIn(COutPoint(spend_tx1.sha256, 1), CScript(), 0xfffffff)) tx1.calc_sha256() self.log.info(tx1.hash) yield TestInstance( [[tx1, RejectResult(16, b'bad-txns-inputs-too-large')]])
def run_test(self): self.stop_node(0) with self.run_node_with_connections("send GETDATA messages and check responses", 0, [], 1) as p2p_connections: receivedBlocks = set() def on_block(conn, message): nonlocal receivedBlocks receivedBlocks.add(message.block.hash) receivedTxs = set() def on_tx(conn, message): nonlocal receivedTxs receivedTxs.add(message.tx.hash) receivedTxsNotFound = set() def on_notfound(conn, message): nonlocal receivedTxsNotFound for inv in message.inv: receivedTxsNotFound.add(inv.hash) self.nodes[0].generate(5) connection = p2p_connections[0] connection.cb.on_block = on_block connection.cb.on_tx = on_tx connection.cb.on_notfound = on_notfound # 1. Check that sending GETDATA of unknown block does no action. unknown_hash = 0xdecaf connection.cb.send_message(msg_getdata([CInv(CInv.BLOCK, unknown_hash)])) # 2. Check that sending GETDATA of known block returns BLOCK message. known_hash = self.nodes[0].getbestblockhash() connection.cb.send_message(msg_getdata([CInv(CInv.BLOCK, int(known_hash, 16))])) wait_until(lambda: known_hash in receivedBlocks) # previously requested unknown block is not in the received list assert_equal(unknown_hash not in receivedBlocks, True) assert_equal(len(receivedBlocks), 1) # 3. Check that sending GETDATA of unknown transaction returns NOTFOUND message. connection.cb.send_message(msg_getdata([CInv(CInv.TX, unknown_hash)])) wait_until(lambda: unknown_hash in receivedTxsNotFound) # 4. Check that sending GETDATA of known transaction returns TX message. known_hash = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1.0) connection.cb.send_message(msg_getdata([CInv(CInv.TX, int(known_hash, 16))])) wait_until(lambda: known_hash in receivedTxs) assert_equal(len(receivedTxs), 1)
def run_test(self): @contextlib.contextmanager def run_connection(title): logger.debug("setup %s", title) self.start_node(0) test_nodes = [] for i in range(self.num_peers): test_nodes.append(NodeConnCB()) connections = [] for test_node in test_nodes: connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node) connections.append(connection) test_node.add_connection(connection) thr = NetworkThread() thr.start() for test_node in test_nodes: test_node.wait_for_verack() logger.debug("before %s", title) yield test_nodes logger.debug("after %s", title) for connection in connections: connection.close() del connections # once all connection.close() are complete, NetworkThread run loop completes and thr.join() returns success thr.join() disconnect_nodes(self.nodes[0], 1) self.stop_node(0) logger.debug("finished %s", title) self.stop_node(0) askedFor = {} rejectSent = False def on_getdata(conn, message): if (conn in askedFor): askedFor[conn] += 1 else: askedFor[conn] = 1 nonlocal rejectSent # First node that receives GetData should send reject. if not rejectSent: rejectSent = True test_node.send_message( msg_reject(message=b"getdata", code=self.REJECT_TOOBUSY, reason=b"node too busy")) with run_connection( "Scenario 1: sending TOOBUSY reject message with 2 nodes" ) as test_nodes: block = self.prepareBlock() for test_node in test_nodes: test_node.on_getdata = on_getdata headers_message = msg_headers() headers_message.headers = [CBlockHeader(block)] test_node.send_message(headers_message) test_node.wait_for_getdata(block.sha256) test_node.sync_with_ping() for key, value in askedFor.items(): assert_equal(value, 1) assert_equal(len(askedFor), 2) self.num_peers = 1 askedFor = {} rejectSent = False with run_connection( "Scenario 2: sending TOOBUSY reject message with 1 node" ) as test_nodes: block = self.prepareBlock() test_node = test_nodes[0] test_node.on_getdata = on_getdata headers_message = msg_headers() headers_message.headers = [CBlockHeader(block)] begin_test = datetime.datetime.now() test_node.send_message(headers_message) test_node.wait_for_getdata(block.sha256) test_node.last_message["getdata"] = [] test_node.wait_for_getdata(block.sha256) end_test = datetime.datetime.now() assert (end_test - begin_test > datetime.timedelta(seconds=5)) assert_equal(next(iter(askedFor.values())), 2) assert_equal(len(askedFor), 1)