def run_test(self): block_count = 0 # Create a P2P connections node0 = NodeConnCB() connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0) node0.add_connection(connection) node1 = NodeConnCB() connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node1) node1.add_connection(connection) NetworkThread().start() # wait_for_verack ensures that the P2P connection is fully up. node0.wait_for_verack() node1.wait_for_verack() # send one to get out of IBD state self.chain.set_genesis_hash(int(self.nodes[0].getbestblockhash(), 16)) block = self.chain.next_block(block_count) block_count += 1 node0.send_message(msg_block(block)) self.nodes[0].waitforblockheight(1) block = self.chain.next_block(block_count) # set block validating status to wait after validation self.nodes[0].waitaftervalidatingblock(block.hash, "add") # make sure block hashes are in waiting list wait_for_waiting_blocks({block.hash}, self.nodes[0], self.log) node0.send_message(msg_block(block)) node1.send_message(msg_block(block)) # make sure we started validating blocks. # One is validating the other is ignored. wait_for_validating_blocks({block.hash}, self.nodes[0], self.log) def wait_for_log(): line_text = block.hash + " will not be considered by the current" for line in open(glob.glob(self.options.tmpdir + "/node0" + "/regtest/bitcoind.log")[0]): if line_text in line: self.log.info("Found line: %s", line) return True return False # wait for the log of the ignored block. wait_until(wait_for_log) # remove block validating status to finish validation self.nodes[0].waitaftervalidatingblock(block.hash, "remove") # wait till validation of block finishes node0.sync_with_ping() self.nodes[0].waitforblockheight(2) assert_equal(block.hash, self.nodes[0].getbestblockhash())
def run_test(self): nobf_node = TestNode() bf_node = TestNode() connections = [] connections.append( NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], nobf_node)) connections.append( NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], bf_node)) nobf_node.add_connection(connections[0]) bf_node.add_connection(connections[1]) # Start up network handling in another thread NetworkThread().start() nobf_node.wait_for_verack() bf_node.wait_for_verack() # Verify mininodes are connected to bitcoinloved nodes peerinfo = self.nodes[0].getpeerinfo() versions = [x["version"] for x in peerinfo] assert_equal(1, versions.count(SPROUT_PROTO_VERSION)) peerinfo = self.nodes[1].getpeerinfo() versions = [x["version"] for x in peerinfo] assert_equal(1, versions.count(SPROUT_PROTO_VERSION)) # Mininodes send filterclear message to bitcoinloved node. nobf_node.send_message(msg_filterclear()) bf_node.send_message(msg_filterclear()) time.sleep(3) # Verify mininodes are still connected to bitcoinloved nodes peerinfo = self.nodes[0].getpeerinfo() versions = [x["version"] for x in peerinfo] assert_equal(1, versions.count(SPROUT_PROTO_VERSION)) peerinfo = self.nodes[1].getpeerinfo() versions = [x["version"] for x in peerinfo] assert_equal(1, versions.count(SPROUT_PROTO_VERSION)) # Mininodes send filteradd message to bitcoinloved node. nobf_node.send_message(msg_filteradd()) bf_node.send_message(msg_filteradd()) time.sleep(3) # Verify NoBF mininode has been dropped, and BF mininode is still connected. peerinfo = self.nodes[0].getpeerinfo() versions = [x["version"] for x in peerinfo] assert_equal(0, versions.count(SPROUT_PROTO_VERSION)) peerinfo = self.nodes[1].getpeerinfo() versions = [x["version"] for x in peerinfo] assert_equal(1, versions.count(SPROUT_PROTO_VERSION)) [c.disconnect_node() for c in connections]
def run_test(self): # Setup the p2p connections and start up the network thread. self.no_verack_node = TestNode() # never send verack self.no_version_node = TestNode() # never send version (just ping) self.no_send_node = TestNode() # never send anything connections = [] connections.append( NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_verack_node)) connections.append( NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_version_node, send_version=False)) connections.append( NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_send_node, send_version=False)) self.no_verack_node.add_connection(connections[0]) self.no_version_node.add_connection(connections[1]) self.no_send_node.add_connection(connections[2]) NetworkThread().start() # Start up network handling in another thread sleep(1) assert (self.no_verack_node.connected) assert (self.no_version_node.connected) assert (self.no_send_node.connected) ping_msg = msg_ping() connections[0].send_message(ping_msg) connections[1].send_message(ping_msg) sleep(30) assert "version" in self.no_verack_node.last_message assert (self.no_verack_node.connected) assert (self.no_version_node.connected) assert (self.no_send_node.connected) connections[0].send_message(ping_msg) connections[1].send_message(ping_msg) sleep(31) assert (not self.no_verack_node.connected) assert (not self.no_version_node.connected) assert (not self.no_send_node.connected)
def bootstrap_p2p(self): """Add a P2P connection to the node. Helper to connect and wait for version handshake.""" self.p2p = P2PNode() self.connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.p2p) self.connection2 = NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], self.p2p) self.p2p.add_connection(self.connection) self.p2p.add_connection(self.connection2) NetworkThread().start() self.p2p.wait_for_verack() assert(self.p2p.connection.state == "connected")
def run_test(self): block_count = 0 # Create a P2P connections node0 = NodeConnCB() connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0) node0.add_connection(connection) NetworkThread().start() # wait_for_verack ensures that the P2P connection is fully up. node0.wait_for_verack() # send one to get out of IBD state self.chain.set_genesis_hash(int(self.nodes[0].getbestblockhash(), 16)) ancestor_block_hash = self.nodes[0].getbestblockhash() parent_block = self.chain.next_block(block_count) block_count += 1 headers_message = msg_headers() headers_message.headers = [CBlockHeader(parent_block)] connection.cb.send_message(headers_message) child_block = self.chain.next_block(block_count) node0.send_message(msg_block(child_block)) # wait till validation of block finishes node0.sync_with_ping() assert_equal(ancestor_block_hash, self.nodes[0].getbestblockhash()) self.stop_node(0) self.start_node(0) # Create a P2P connections node0 = NodeConnCB() connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0) node0.add_connection(connection) NetworkThread().start() # wait_for_verack ensures that the P2P connection is fully up. node0.wait_for_verack() assert_equal(ancestor_block_hash, self.nodes[0].getbestblockhash()) node0.send_message(msg_block(parent_block)) # wait till validation of block finishes node0.sync_with_ping() assert_equal(child_block.hash, self.nodes[0].getbestblockhash())
def run_test(self): block_count = 0 # Create a P2P connections node0 = NodeConnCB() connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0) node0.add_connection(connection) node1 = NodeConnCB() connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node1) node1.add_connection(connection) NetworkThread().start() # wait_for_verack ensures that the P2P connection is fully up. node0.wait_for_verack() node1.wait_for_verack() # send one to get out of IBD state self.chain.set_genesis_hash(int(self.nodes[0].getbestblockhash(), 16)) block = self.chain.next_block(block_count) block_count += 1 node0.send_message(msg_block(block)) self.nodes[0].waitforblockheight(1) block = self.chain.next_block(block_count) # set block validating status to wait after validation self.nodes[0].waitaftervalidatingblock(block.hash, "add") # make sure block hashes are in waiting list wait_for_waiting_blocks({block.hash}, self.nodes[0], self.log) node0.send_message(msg_block(block)) node1.send_message(msg_block(block)) # make sure we started validating blocks. # One is validating the other is ignored. wait_for_validating_blocks({block.hash}, self.nodes[0], self.log) # wait for the log of the ignored block. wait_until(lambda: check_for_log_msg(self, block.hash + " will not be considered by the current", "/node0")) # remove block validating status to finish validation self.nodes[0].waitaftervalidatingblock(block.hash, "remove") # wait till validation of block finishes node0.sync_with_ping() self.nodes[0].waitforblockheight(2) assert_equal(block.hash, self.nodes[0].getbestblockhash())
def run_test(self): node1 = self.nodes[1] node0 = self.nodes[0] # Get out of IBD node1.generate(1) sync_blocks(self.nodes) # Setup the p2p connections and start up the network thread. test_node = TestNode() connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node) test_node.add_connection(connection) NetworkThread().start() test_node.wait_for_verack() # Test that invs are received for all txs at feerate of 2,000,000 sats node1.settxfee(Decimal("0.02000000")) txids = [ node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3) ] assert (allInvsMatch(txids, test_node)) test_node.clear_invs() # Set a filter of 1,500,000 sats (must be above 1,000,000 sats (min fee is enforced) test_node.send_and_ping(msg_feefilter(1500000)) # Test that txs are still being received (paying 70 sat/byte) txids = [ node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3) ] assert (allInvsMatch(txids, test_node)) test_node.clear_invs() # Change tx fee rate to 1,350,000 sats and test they are no longer received node1.settxfee(Decimal("0.013500000")) [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)] sync_mempools(self.nodes) # must be sure node 0 has received all txs # Raise the tx fee back up above the mintxfee, submit 1 tx on node 0, # then sync nodes 0 and 1 - we should only have 1 tx (this one below since # the one above was below the min txfee). # Send one transaction from node0 that should be received, so that we # we can sync the test on receipt (if node1's txs were relayed, they'd # be received by the time this node0 tx is received). This is # unfortunately reliant on the current relay behavior where we batch up # to 35 entries in an inv, which means that when this next transaction # is eligible for relay, the prior transactions from node1 are eligible # as well. node0.settxfee(Decimal("0.01600000")) txids = [node0.sendtoaddress(node0.getnewaddress(), 1)] # assert (allInvsMatch(txids, test_node)) test_node.clear_invs() # Remove fee filter and check that txs are received again test_node.send_and_ping(msg_feefilter(0)) txids = [ node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3) ] assert (allInvsMatch(txids, test_node)) test_node.clear_invs()
def run_test(self): gen_node = self.nodes[0] # The block and tx generating node gen_node.generate(1) # Setup the attacking p2p connection and start up the network thread. self.inbound_peer = TestNode() connections = [NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.inbound_peer)] self.inbound_peer.add_connection(connections[0]) NetworkThread().start() # Start up network handling in another thread max_repeats = 48 self.log.info("Running test up to {} times.".format(max_repeats)) for i in range(max_repeats): self.log.info('Run repeat {}'.format(i + 1)) txid = gen_node.sendtoaddress(gen_node.getnewaddress(), 0.01) want_tx = MsgGetdata() want_tx.inv.append(CInv(t=1, h=int(txid, 16))) self.inbound_peer.last_message.pop('notfound', None) connections[0].send_message(want_tx) self.inbound_peer.sync_with_ping() if self.inbound_peer.last_message.get('notfound'): self.log.debug('tx {} was not yet announced to us.'.format(txid)) self.log.debug("node has responded with a notfound message. End test.") assert_equal(self.inbound_peer.last_message['notfound'].vec[0].hash, int(txid, 16)) self.inbound_peer.last_message.pop('notfound') break else: self.log.debug('tx {} was already announced to us. Try test again.'.format(txid)) assert int(txid, 16) in [inv.hash for inv in self.inbound_peer.last_message['inv'].inv]
def _init(self): node_no = 0 # Create a P2P connections node = NodeConnCB() connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[node_no], node) node.add_connection(connection) NetworkThread().start() # wait_for_verack ensures that the P2P connection is fully up. node.wait_for_verack() self.chain.set_genesis_hash(int(self.nodes[node_no].getbestblockhash(), 16)) block = self.chain.next_block(self.block_count) self.block_count += 1 self.chain.save_spendable_output() node.send_message(msg_block(block)) for i in range(100): block = self.chain.next_block(self.block_count) self.block_count += 1 self.chain.save_spendable_output() node.send_message(msg_block(block)) self.log.info("Waiting for block height 101 via rpc") self.nodes[node_no].waitforblockheight(101) return node
def run_test(self): # Create a P2P connection to the first node node0 = NodeConnCB() connections = [] connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0)) node0.add_connection(connections[0]) # Start up network handling in another thread. This needs to be called # after the P2P connections have been created. NetworkThread().start() # wait_for_verack ensures that the P2P connection is fully up. node0.wait_for_verack() # Out of IBD self.nodes[0].generate(1) # Create shortcuts. conn = connections[0] rpc = conn.rpc # Use p2p interface. self.test_case(rpcsend=None, conn=conn) # Use sendrawtransaction rpc interface. self.test_case(rpc.sendrawtransaction) # Use sendrawtransactions rpc interface. self.test_case(rpc.sendrawtransactions)
def __init__(self, testRig, node): self.peer = NodeConnCB() self.peer.add_connection( NodeConn('127.0.0.1', p2p_port(0), node, self.peer)) NetworkThread().start() self.peer.wait_for_verack() testRig.dsdetector = self self.message = None
def run_test(self): test_node = TestNode() connections = [] connections.append( NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node, "regtest", True)) test_node.add_connection(connections[0]) # Start up network handling in another thread NetworkThread().start() test_node.wait_for_verack() # Verify mininodes are connected to zcashd nodes peerinfo = self.nodes[0].getpeerinfo() versions = [x["version"] for x in peerinfo] assert_equal(1, versions.count(OVERWINTER_PROTO_VERSION)) assert_equal(0, peerinfo[0]["banscore"]) self.coinbase_blocks = self.nodes[0].generate(1) self.nodes[0].generate(100) self.nodeaddress = self.nodes[0].getnewaddress() # Mininodes send transaction to zcashd node. def setExpiryHeight(tx): tx.nExpiryHeight = 101 spendtx = self.create_transaction(self.nodes[0], self.coinbase_blocks[0], self.nodeaddress, 1.0, txModifier=setExpiryHeight) test_node.send_message(msg_tx(spendtx)) time.sleep(3) # Verify test mininode has not been dropped # and still has a banscore of 0. peerinfo = self.nodes[0].getpeerinfo() versions = [x["version"] for x in peerinfo] assert_equal(1, versions.count(OVERWINTER_PROTO_VERSION)) assert_equal(0, peerinfo[0]["banscore"]) # Mine a block and resend the transaction self.nodes[0].generate(1) test_node.send_message(msg_tx(spendtx)) time.sleep(3) # Verify test mininode has not been dropped # but has a banscore of 10. peerinfo = self.nodes[0].getpeerinfo() versions = [x["version"] for x in peerinfo] assert_equal(1, versions.count(OVERWINTER_PROTO_VERSION)) assert_equal(10, peerinfo[0]["banscore"]) [c.disconnect_node() for c in connections]
def run_test(self): # Create all the connections we will need to node0 at the start because they all need to be # setup before we call NetworkThread().start() # Create a P2P connection just so that the test framework is happy we're connected dummyCB = NodeConnCB() dummyConn = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], dummyCB, nullAssocID=True) dummyCB.add_connection(dummyConn) # By setting the assocID on this second NodeConn we prevent it sending a version message badConnCB = TestNode() badConn = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], badConnCB, assocID=0x01) badConnCB.add_connection(badConn) # Start up network handling in another thread. This needs to be called # after the P2P connections have been created. NetworkThread().start() # Check initial state dummyCB.wait_for_protoconf() with mininode_lock: assert_equal(len(badConnCB.message_count), 0) # Send a badly formatted version message badConn.send_message(msg_version_bad()) # Connection will be closed with a reject wait_until(lambda: badConnCB.last_reject is not None, lock=mininode_lock, timeout=5) wait_until(lambda: badConn.state == "closed", lock=mininode_lock, timeout=5) # Check clear log message was generated assert check_for_log_msg( self, "Failed to process version: (Badly formatted association ID", "/node0")
def bootstrap_p2p(self): """Add a P2P connection to the node.""" self.p2p = P2PDataStore() self.connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.p2p) self.p2p.add_connection(self.connection) NetworkThread().start() self.p2p.wait_for_verack() assert (self.p2p.connection.state == "connected")
def run_test(self): block_count = 0 # Create a P2P connections node0 = NodeConnCB() connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0) node0.add_connection(connection) NetworkThread().start() # wait_for_verack ensures that the P2P connection is fully up. node0.wait_for_verack() self.chain.set_genesis_hash(int(self.nodes[0].getbestblockhash(), 16)) _, out, block_count = prepare_init_chain(self.chain, 101, 100, start_block=0, block_0=False, node=node0) self.log.info("waiting for block height 101 via rpc") self.nodes[0].waitforblockheight(101) # wait till validation of block or blocks finishes node0.sync_with_ping() block1 = self.chain.next_block(block_count, spend=out[0], extra_txns=8) block_count += 1 # send block but block him at validation point self.nodes[0].waitaftervalidatingblock(block1.hash, "add") node0.send_message(msg_block(block1)) self.log.info(f"block1 hash: {block1.hash}") # make sure block hash is in waiting list wait_for_waiting_blocks({block1.hash}, self.nodes[0], self.log) # send child block block2 = self.chain.next_block(block_count, spend=out[1], extra_txns=10) block_count += 1 node0.send_message(msg_block(block2)) self.log.info(f"block2 hash: {block2.hash}") wait_until(lambda: check_for_log_msg( self, block2.hash + " will not be considered by the current", "/node0")) self.nodes[0].waitaftervalidatingblock(block1.hash, "remove") # wait till validation of block or blocks finishes node0.sync_with_ping() # block that arrived last on competing chain should be active assert_equal(block2.hash, self.nodes[0].getbestblockhash())
def add_all_connections(self, nodes): for i in range(len(nodes)): # Create a p2p connection to each node test_node = MyNode(self.block_store, self.tx_store, self.blocks_recvd) self.test_nodes.append(test_node) self.connections.append( NodeConn('127.0.0.1', p2p_port(i), nodes[i], test_node)) # Make sure the TestNode (callback class) has a reference to its associated NodeConn test_node.add_connection(self.connections[-1])
def __init__(self, remote_node, node_number): super(RunnerNode, self).__init__() self.chain = ChainManager() self.next_block = 0 self.remote_node = remote_node self.node_number = node_number connections = [] connections.append( NodeConn('127.0.0.1', p2p_port(self.node_number), self.remote_node, self)) self.add_connection(connections[0])
def restart_node(self, extra_args=None): self.log.info("Restarting node ...") self.rpc.stop_node() self.rpc.wait_until_stopped() self.rpc.start(True, extra_args) self.rpc.wait_for_rpc_connection() self.p2p = NodeConnCB() connection = NodeConn('127.0.0.1', p2p_port(0), self.rpc, self.p2p) NetworkThread().start() self.p2p.add_connection(connection) self.p2p.wait_for_verack() self._register_on_reject()
def run_test(self): no_version_bannode = CNodeNoVersionBan() no_version_idlenode = CNodeNoVersionIdle() no_verack_idlenode = CNodeNoVerackIdle() CLazyNode() CLazyNode() connections = [NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_bannode, send_version=False), NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_idlenode, send_version=False), NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_verack_idlenode)] no_version_bannode.add_connection(connections[0]) no_version_idlenode.add_connection(connections[1]) no_verack_idlenode.add_connection(connections[2]) NetworkThread().start() # Start up network handling in another thread wait_until(lambda: no_version_bannode.ever_connected, err_msg="Wait for no Version BanNode", timeout=10, lock=mininode_lock) wait_until(lambda: no_version_idlenode.ever_connected, err_msg="Wait for no Version IdleNode", timeout=10, lock=mininode_lock) wait_until(lambda: no_verack_idlenode.version_received, err_msg="Wait for VerAck IdleNode", timeout=10, lock=mininode_lock) # Mine a block and make sure that it's not sent to the connected nodes self.nodes[0].generate(1) #Give the node enough time to possibly leak out a message time.sleep(5) #This node should have been banned assert not no_version_bannode.connected [conn.disconnect_node() for conn in connections] # Wait until all connections are closed wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0, err_msg="Wait for Connection Close") # Make sure no unexpected messages came in assert(no_version_bannode.unexpected_msg == False) assert(no_version_idlenode.unexpected_msg == False) assert(no_verack_idlenode.unexpected_msg == False) NetworkThread().start() # Network thread stopped when all previous NodeConnCBs disconnected. Restart it
def run_test(self): #connect a mininode aTestNode = NodeConnCB() node = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], aTestNode) aTestNode.add_connection(node) NetworkThread().start() aTestNode.wait_for_verack() #request mempool aTestNode.send_message(MsgMempool()) aTestNode.wait_for_disconnect() #mininode must be disconnected at this point assert_equal(len(self.nodes[0].getpeerinfo()), 0)
def run_test(self): self.xt_node = self.nodes[0] # generate a block to get out of IBD self.xt_node.generate(1) self.test_node = TestNode() self.test_node.add_connection( NodeConn('127.0.0.1', p2p_port(0), self.xt_node, self.test_node)) NetworkThread().start() self.test_node.handshake() self.test_basics(self.xt_node, self.test_node) self.test_garbage(self.test_node) self.test_big_bitmap(self.xt_node, self.test_node, 8 * 2) self.test_big_bitmap(self.xt_node, self.test_node, 8 * 128)
def run_test(self): node0 = NodeConnCB() node0.add_connection(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0)) NetworkThread().start() node0.wait_for_verack() self.log.info("#1. generate 1 block by node0==================================================================") self.nodes[0].generate(nblocks=1) self.tip = int(self.nodes[0].getbestblockhash(), 16) self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1 self.height = 1 self.coinbase_txs = [] self.log.info("#2. create 100 blocks and send to node0========================================================") for i in range(100): coinbase_tx = create_coinbase(self.height) self.coinbase_txs.append(coinbase_tx) self.create_block_and_send([coinbase_tx], node0) self.nodes[0].waitforblockheight(101) self.fork_point_hash = self.tip self.fork_height = self.height self.log.info("#3. create one fork chain with one block=======================================================") for i in range(1): block_fee, txns = self.create_txns_from(self.coinbase_txs[i], 2) coinbase = create_coinbase(self.height, None, block_fee) self.create_block_and_send([coinbase] + txns, node0) self.nodes[0].waitforblockheight(102) self.log.info("#4. create another fork chain with two blocks==================================================") self.tip = self.fork_point_hash self.height = self.fork_height for i in range(2): block_fee, txns = self.create_txns_from(self.coinbase_txs[i], 2) coinbase = create_coinbase(self.height, None, block_fee) self.create_block_and_send([coinbase] + txns, node0) self.log.info("#5. expect node0 switch to new chain===========================================================") self.nodes[0].waitforblockheight(103)
def init_(self, nodes_count): nodes = [] for no in range(0, nodes_count): # Create a P2P connections node = NodeConnCB() connection = NodeConn('127.0.0.1', p2p_port(no), self.nodes[no], node) node.add_connection(connection) nodes.append(node) NetworkThread().start() for no in range(0, nodes_count): # wait_for_verack ensures that the P2P connection is fully up. nodes[no].wait_for_verack() self.init_chain_(nodes[0], nodes_count) return nodes
def start_node_with_protoconf(self, maxprotocolrecvpayloadlength, recvinvqueuefactor=0): """ This method starts the node and creates a connection to the node. It takes care of exchanging protoconf messages between node and python connection. Max size of bitcoin nodes' inv message is determined by maxprotocolrecvpayloadlength. Max size of python connections' inv message is LEGACY_MAX_PROTOCOL_PAYLOAD_LENGTH. If called with parameter recvinvqueuefactor it also sets this setting on the node. :returns test_node """ # Start the node with maxprotocolrecvpayloadlength, recvinvqueuefactor (if set) start_params = [] if maxprotocolrecvpayloadlength: start_params.append("-maxprotocolrecvpayloadlength={} ".format(maxprotocolrecvpayloadlength)) if recvinvqueuefactor: start_params.append("-recvinvqueuefactor={} ".format(recvinvqueuefactor)) self.start_node(0, start_params) # Create a connection and connect to the node test_node = NodeConnCB() test_node.wanted_inv_lengths = [] def on_getdata(conn, message): test_node.wanted_inv_lengths.append(len(message.inv)) test_node.on_getdata = on_getdata # Send protoconf message from python node to bitcoind node def send_protoconf_default_msg_length(conn): conn.send_message(msg_protoconf(CProtoconf(1, LEGACY_MAX_PROTOCOL_PAYLOAD_LENGTH))) test_node.send_protoconf = send_protoconf_default_msg_length connections = [NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node)] test_node.add_connection(connections[0]) NetworkThread().start() # Start up network handling in another thread # Prepare initial block. Needed so that GETDATA can be send back. self.nodes[0].generate(1) # Receive bitcoind's protoconf and save max_recv_payload_length. test_node.wait_for_protoconf() test_node.max_recv_payload_length = test_node.last_message["protoconf"].protoconf.max_recv_payload_length return test_node
def run_test(self): block_count = 0 # Create a P2P connections node0 = NodeConnCB() connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0) node0.add_connection(connection) NetworkThread().start() node0.wait_for_verack() self.chain.set_genesis_hash(int(self.nodes[0].getbestblockhash(), 16)) block = self.chain.next_block(block_count) block_count += 1 node0.send_message(msg_block(block)) block = self.chain.next_block(block_count) self.log.info(f"block hash: {block.hash}") self.nodes[0].waitaftervalidatingblock(block.hash, "add") # make sure block hash is in waiting list wait_for_waiting_blocks({block.hash}, self.nodes[0], self.log) self.log.info("sending block") node0.send_message(msg_block(block)) # make sure we started validating block wait_for_validating_blocks({block.hash}, self.nodes[0], self.log) # sleep a bit and check that in the meantime validation hasn't proceeded time.sleep(1) assert (block.hash != self.nodes[0].getbestblockhash()) # after validating the block we release its waiting status self.nodes[0].waitaftervalidatingblock(block.hash, "remove") # wait till validation of block or blocks finishes node0.sync_with_ping() assert_equal(block.hash, self.nodes[0].getbestblockhash())
def run_test(self): block_count = 0 # Create a P2P connection node0 = NodeConnCB() connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0) node0.add_connection(connection) NetworkThread().start() # wait_for_verack ensures that the P2P connection is fully up. node0.wait_for_verack() # send one to get out of IBD state self.chain.set_genesis_hash(int(self.nodes[0].getbestblockhash(), 16)) block = self.chain.next_block(block_count) block_count += 1 node0.send_message(msg_block(block)) self.nodes[0].waitforblockheight(1) block_count = self.__test_getdata(node0, block_count) block_count = self.__test_getblocks(node0, block_count)
def run_test(self): node0conn = BaseNode() node0conn.add_connection( NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0conn)) NetworkThread().start() node0conn.wait_for_verack() node0 = self.nodes[0] tip = int(node0.getbestblockhash(), 16) height = node0.getblockcount() + 1 time = node0.getblock(node0.getbestblockhash())['time'] + 1 blocks = [] for i in range(NUM_IBD_BLOCKS * 2): block = create_block(tip, create_coinbase(height), time) block.solve() blocks.append(block) tip = block.sha256 height += 1 time += 1 # Headers need to be sent in-order for b in blocks: node0conn.send_header(b) # Send blocks in some random order for b in random.sample(blocks, len(blocks)): node0conn.send_block(b) # The node should eventually, completely sync without getting stuck def node_synced(): return node0.getbestblockhash() == blocks[-1].hash wait_until(node_synced)
def run_test(self): node0 = NodeConnCB() connections = [] connections.append( NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0)) node0.add_connection(connections[0]) NetworkThread().start() node0.wait_for_verack() # Set node time to 60 days ago self.nodes[0].setmocktime(int(time.time()) - 60 * 24 * 60 * 6) # Generating a chain of 10 blocks block_hashes = self.nodes[0].generate(nblocks=10) # Create longer chain starting 2 blocks before current tip height = len(block_hashes) - 2 block_hash = block_hashes[height - 1] block_time = self.nodes[0].getblockheader(block_hash)["mediantime"] + 1 new_blocks = self.build_chain(5, block_hash, height, block_time) # Force reorg to a longer chain node0.send_message(msg_headers(new_blocks)) node0.wait_for_getdata() for block in new_blocks: node0.send_and_ping(msg_block(block)) # Check that reorg succeeded assert_equal(self.nodes[0].getblockcount(), 13) stale_hash = int(block_hashes[-1], 16) # Check that getdata request for stale block succeeds self.send_block_request(stale_hash, node0) test_function = lambda: self.last_block_equals(stale_hash, node0) wait_until(test_function, timeout=3) # Check that getheader request for stale block header succeeds self.send_header_request(stale_hash, node0) test_function = lambda: self.last_header_equals(stale_hash, node0) wait_until(test_function, timeout=3) # Longest chain is extended so stale is much older than chain tip self.nodes[0].setmocktime(0) tip = self.nodes[0].generate(nblocks=1)[0] assert_equal(self.nodes[0].getblockcount(), 14) # Send getdata & getheaders to refresh last received getheader message block_hash = int(tip, 16) self.send_block_request(block_hash, node0) self.send_header_request(block_hash, node0) node0.sync_with_ping() # Request for very old stale block should now fail self.send_block_request(stale_hash, node0) time.sleep(3) assert not self.last_block_equals(stale_hash, node0) # Request for very old stale block header should now fail self.send_header_request(stale_hash, node0) time.sleep(3) assert not self.last_header_equals(stale_hash, node0) # Verify we can fetch very old blocks and headers on the active chain block_hash = int(block_hashes[2], 16) self.send_block_request(block_hash, node0) self.send_header_request(block_hash, node0) node0.sync_with_ping() self.send_block_request(block_hash, node0) test_function = lambda: self.last_block_equals(block_hash, node0) wait_until(test_function, timeout=3) self.send_header_request(block_hash, node0) test_function = lambda: self.last_header_equals(block_hash, node0) wait_until(test_function, timeout=3)
def run_test(self): # Connect to node0 node0 = BaseNode() connections = [] connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0)) node0.add_connection(connections[0]) NetworkThread().start() # Start up network handling in another thread node0.wait_for_verack() # Build the blockchain self.tip = int(self.nodes[0].getbestblockhash(), 16) self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1 self.blocks = [] # Get a pubkey for the coinbase TXO coinbase_key = CECKey() coinbase_key.set_secretbytes(b"horsebattery") coinbase_pubkey = coinbase_key.get_pubkey() # Create the first block with a coinbase output to our key height = 1 block = create_block(self.tip, create_coinbase(height, coinbase_pubkey), self.block_time) self.blocks.append(block) self.block_time += 1 block.solve() # Save the coinbase for later self.block1 = block self.tip = block.sha256 height += 1 # Bury the block 100 deep so the coinbase output is spendable for i in range(100): block = create_block(self.tip, create_coinbase(height), self.block_time) block.solve() self.blocks.append(block) self.tip = block.sha256 self.block_time += 1 height += 1 # Create a transaction spending the coinbase output with an invalid (null) signature tx = CTransaction() tx.vin.append(CTxIn(COutPoint(self.block1.vtx[0].sha256, 0), scriptSig=b"")) tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE]))) tx.calc_sha256() block102 = create_block(self.tip, create_coinbase(height), self.block_time) self.block_time += 1 block102.vtx.extend([tx]) block102.hashMerkleRoot = block102.calc_merkle_root() block102.rehash() block102.solve() self.blocks.append(block102) self.tip = block102.sha256 self.block_time += 1 height += 1 # Bury the assumed valid block 2100 deep for i in range(2100): block = create_block(self.tip, create_coinbase(height), self.block_time) block.nVersion = 4 block.solve() self.blocks.append(block) self.tip = block.sha256 self.block_time += 1 height += 1 # Start node1 and node2 with assumevalid so they accept a block with a bad signature. self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)]) node1 = BaseNode() # connects to node1 connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], node1)) node1.add_connection(connections[1]) node1.wait_for_verack() self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)]) node2 = BaseNode() # connects to node2 connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], node2)) node2.add_connection(connections[2]) node2.wait_for_verack() # send header lists to all three nodes node0.send_header_for_blocks(self.blocks[0:2000]) node0.send_header_for_blocks(self.blocks[2000:]) node1.send_header_for_blocks(self.blocks[0:2000]) node1.send_header_for_blocks(self.blocks[2000:]) node2.send_header_for_blocks(self.blocks[0:200]) # Send blocks to node0. Block 102 will be rejected. self.send_blocks_until_disconnected(node0) self.assert_blockchain_height(self.nodes[0], 101) # Send all blocks to node1. All blocks will be accepted. for i in range(2202): node1.send_message(msg_block(self.blocks[i])) # Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync. node1.sync_with_ping(120) assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202) # Send blocks to node2. Block 102 will be rejected. self.send_blocks_until_disconnected(node2) self.assert_blockchain_height(self.nodes[2], 101)
def run_test(self): # Set up test nodes. # - test_nodes[0] will only request v4 transactions # - test_nodes[1] will only request v5 transactions # - test_nodes[2] will test invalid v4 request using MSG_WTXID # - test_nodes[3] will test invalid v5 request using MSG_TX test_nodes = [] connections = [] for i in range(4): test_nodes.append(TestNode()) connections.append( NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_nodes[i], protocol_version=NU5_PROTO_VERSION)) test_nodes[i].add_connection(connections[i]) NetworkThread().start() # Start up network handling in another thread [x.wait_for_verack() for x in test_nodes] net_version = self.nodes[0].getnetworkinfo()["protocolversion"] if net_version < NU5_PROTO_VERSION: # Sending a getdata message containing a MSG_WTX CInv message type # results in a reject message. self.verify_invalid_cinv( test_nodes[0], connections[0], 5, "Negotiated protocol version does not support CInv message type MSG_WTX", ) # Sending a getdata message containing an invalid CInv message type # results in a reject message. self.verify_invalid_cinv(test_nodes[1], connections[1], 0xffff, "Unknown CInv message type") print( "Node's block index is not NU5-aware, skipping remaining tests" ) return # Load funds into the Sprout address sproutzaddr = self.nodes[0].z_getnewaddress('sprout') result = self.nodes[2].z_shieldcoinbase("*", sproutzaddr, 0) wait_and_assert_operationid_status(self.nodes[2], result['opid']) self.sync_all() self.nodes[1].generate(1) self.sync_all() # Activate NU5. Block height after this is 210. self.nodes[0].generate(9) self.sync_all() # Add v4 transaction to the mempool. node1_taddr = self.nodes[1].getnewaddress() opid = self.nodes[0].z_sendmany(sproutzaddr, [{ 'address': node1_taddr, 'amount': 1, }]) v4_txid = uint256_from_str( hex_str_to_bytes( wait_and_assert_operationid_status(self.nodes[0], opid))[::-1]) # Add v5 transaction to the mempool. v5_txid = self.nodes[0].sendtoaddress(node1_taddr, 1, "", "", True) v5_tx = self.nodes[0].getrawtransaction(v5_txid, 1) assert_equal(v5_tx['version'], 5) v5_txid = uint256_from_str(hex_str_to_bytes(v5_txid)[::-1]) v5_auth_digest = uint256_from_str( hex_str_to_bytes(v5_tx['authdigest'])[::-1]) # Wait for the mempools to sync. self.sync_all() # # inv # # On a mempool request, nodes should return an inv message containing: # - the v4 tx, with type MSG_TX. # - the v5 tx, with type MSG_WTX. for testnode in test_nodes: self.verify_inv(testnode, [ self.cinv_for(v4_txid), self.cinv_for(v5_txid, v5_auth_digest), ]) # # getdata # # We can request a v4 transaction with MSG_TX. self.send_data_message(test_nodes[0], v4_txid) self.verify_last_tx(test_nodes[0], v4_txid) # We can request a v5 transaction with MSG_WTX. self.send_data_message(test_nodes[1], v5_txid, v5_auth_digest) self.verify_last_tx(test_nodes[1], v5_txid, v5_auth_digest) # Requesting with a different authDigest results in a notfound. self.send_data_message(test_nodes[1], v5_txid, 1) self.verify_last_notfound(test_nodes[1], v5_txid, 1) # Requesting a v4 transaction with MSG_WTX causes a disconnect. self.send_data_message(test_nodes[2], v4_txid, (1 << 256) - 1) self.verify_disconnected(test_nodes[2]) # Requesting a v5 transaction with MSG_TX causes a disconnect. self.send_data_message(test_nodes[3], v5_txid) self.verify_disconnected(test_nodes[3]) # Sending a getdata message containing an invalid CInv message type # results in a reject message. self.verify_invalid_cinv(test_nodes[0], connections[0], 0xffff, "Unknown CInv message type") [c.disconnect_node() for c in connections] self.log_stderr.close()