示例#1
0
    def run_test(self):

        # Create a block with 2500 stakeable outputs
        self.build_coins_to_stake()

        # Propagate it to nodes 1 and 2 and stop them for now
        self.sync_first_block()

        # Key Management for node 0
        keytool = KeyTool.for_node(self.nodes[0])

        # Connect to node0
        p2p0 = self.nodes[0].add_p2p_connection(BaseNode())

        network_thread_start()
        self.nodes[0].p2p.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 = keytool.make_privkey()
        coinbase_pubkey = bytes(coinbase_key.get_pubkey())

        keytool.upload_key(coinbase_key)

        self.log.info("Create the first block with a coinbase output to our key")
        height = 2
        snapshot_meta = get_tip_snapshot_meta(self.nodes[0])
        coin = self.get_coin_to_stake()
        coinbase = sign_coinbase(self.nodes[0], create_coinbase(height, coin, snapshot_meta.hash, coinbase_pubkey))
        block = create_block(self.tip, coinbase, 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

        utxo1 = UTXO(height, TxType.COINBASE, COutPoint(coinbase.sha256, 0), coinbase.vout[0])
        snapshot_meta = update_snapshot_with_tx(self.nodes[0], snapshot_meta, height, coinbase)
        height += 1

        self.log.info("Bury the block 100 deep so the coinbase output is spendable")
        for i in range(100):
            coin = self.get_coin_to_stake()
            coinbase = sign_coinbase(self.nodes[0], create_coinbase(height, coin, snapshot_meta.hash, coinbase_pubkey))
            block = create_block(self.tip, coinbase, self.block_time)
            block.solve()
            self.blocks.append(block)
            self.tip = block.sha256
            self.block_time += 1
            utxo = UTXO(height, TxType.COINBASE, COutPoint(coinbase.sha256, 0), coinbase.vout[0])
            snapshot_meta = update_snapshot_with_tx(self.nodes[0], snapshot_meta, height, coinbase)
            height += 1

        self.log.info("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((PROPOSER_REWARD - 1) * 100000000, CScript([OP_TRUE])))
        tx.calc_sha256()

        coin = self.get_coin_to_stake()
        coinbase = sign_coinbase(self.nodes[0], create_coinbase(height, coin, snapshot_meta.hash, coinbase_pubkey))
        block102 = create_block(self.tip, coinbase, self.block_time)
        self.block_time += 1
        block102.vtx.extend([tx])
        block102.compute_merkle_trees()
        block102.rehash()
        block102.solve()
        self.blocks.append(block102)
        self.tip = block102.sha256
        self.block_time += 1

        snapshot_meta = update_snapshot_with_tx(self.nodes[0], snapshot_meta, height, coinbase)

        utxo2 = UTXO(height, tx.get_type(), COutPoint(tx.sha256, 0), tx.vout[0])
        snapshot_meta = calc_snapshot_hash(self.nodes[0], snapshot_meta, height, [utxo1], [utxo2])

        height += 1

        self.log.info("Bury the assumed valid block 2100 deep")
        for i in range(2100):
            coin = self.get_coin_to_stake()
            coinbase = sign_coinbase(self.nodes[0], create_coinbase(height, coin, snapshot_meta.hash, coinbase_pubkey))
            block = create_block(self.tip, coinbase, self.block_time)
            block.nVersion = 4
            block.solve()
            self.blocks.append(block)
            self.tip = block.sha256
            self.block_time += 1
            utxo = UTXO(height, TxType.COINBASE, COutPoint(coinbase.sha256, 0), coinbase.vout[0])
            snapshot_meta = update_snapshot_with_tx(self.nodes[0], snapshot_meta, height, coinbase)
            height += 1

        # We're adding new connections so terminate the network thread
        self.nodes[0].disconnect_p2ps()
        network_thread_join()

        self.log.info("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)])
        self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)])

        p2p0 = self.nodes[0].add_p2p_connection(BaseNode())
        p2p1 = self.nodes[1].add_p2p_connection(BaseNode())
        p2p2 = self.nodes[2].add_p2p_connection(BaseNode())

        network_thread_start()

        p2p0.wait_for_verack()
        p2p1.wait_for_verack()
        p2p2.wait_for_verack()

        self.log.info("send header lists to all three nodes")
        p2p0.send_header_for_blocks(self.blocks[0:2000])
        p2p0.send_header_for_blocks(self.blocks[2000:])
        p2p1.send_header_for_blocks(self.blocks[0:2000])
        p2p1.send_header_for_blocks(self.blocks[2000:])
        p2p2.send_header_for_blocks(self.blocks[0:200])

        self.log.info("Send blocks to node0. Block 103 will be rejected.")
        self.send_blocks_until_disconnected(p2p0)
        self.assert_blockchain_height(self.nodes[0], 102)

        self.log.info("Send all blocks to node1. All blocks will be accepted.")
        for i in range(2202):
            p2p1.send_message(msg_witness_block(self.blocks[i]))
        # Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync.
        p2p1.sync_with_ping(120)
        assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2203)

        self.log.info("Send blocks to node2. Block 102 will be rejected.")
        self.send_blocks_until_disconnected(p2p2)
        self.assert_blockchain_height(self.nodes[2], 102)