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]
Exemple #3
0
    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())
Exemple #6
0
    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()
Exemple #8
0
    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]
Exemple #9
0
    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
Exemple #12
0
    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]
Exemple #13
0
    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())
Exemple #16
0
 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])
Exemple #17
0
    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()
Exemple #19
0
    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)
Exemple #21
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)
Exemple #22
0
    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)
Exemple #27
0
    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)
Exemple #28
0
    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)
Exemple #30
0
    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()