def createIncorectGenesisBlock(genesis_coinbase, signblockprivkeys):
    genesis = CBlock()
    genesis.nTime = int(time.time() + 600)
    genesis.hashPrevBlock = 0
    genesis.vtx.append(genesis_coinbase)
    genesis.hashMerkleRoot = genesis.calc_merkle_root()
    genesis.hashImMerkleRoot = genesis.calc_immutable_merkle_root()
    genesis.solve(signblockprivkeys)
    return genesis
def createIncorectGenesisBlock(genesis_coinbase, signblockprivkey, signblockpubkey):
    genesis = CBlock()
    genesis.nTime = int(time.time() + 600)
    genesis.hashPrevBlock = 0
    genesis.vtx.append(genesis_coinbase)
    genesis.hashMerkleRoot = genesis.calc_merkle_root()
    genesis.hashImMerkleRoot = genesis.calc_immutable_merkle_root()
    genesis.xfieldType = 1
    genesis.xfield = hex_str_to_bytes(signblockpubkey)
    genesis.solve(signblockprivkey)
    return genesis
Exemplo n.º 3
0
 def create_coinbase_block(self, coinbase_txs):
     tmpl = self.nodes[0].getblock(self.nodes[0].getbestblockhash())
     block = CBlock()
     block.nVersion = 4
     block.hashPrevBlock = int(tmpl["hash"], 16)
     block.nTime = tmpl['time'] + 1
     block.nBits = int(tmpl["bits"], 16)
     block.nNonce = 0
     block.vtx = coinbase_txs
     block.hashMerkleRoot = block.calc_merkle_root()
     block.solve()
     return block
Exemplo n.º 4
0
def mine_large_blocks(node, n):
    # Make a large scriptPubKey for the coinbase transaction. This is OP_RETURN
    # followed by 950k of OP_NOP. This would be non-standard in a non-coinbase
    # transaction but is consensus valid.

    # Set the nTime if this is the first time this function has been called.
    # A static variable ensures that time is monotonicly increasing and is therefore
    # different for each block created => blockhash is unique.
    if "nTimes" not in mine_large_blocks.__dict__:
        mine_large_blocks.nTime = 0

    # Get the block parameters for the first block
    big_script = CScript([OP_RETURN] + [OP_NOP] * 950000)
    best_block = node.getblock(node.getbestblockhash())
    height = int(best_block["height"]) + 1
    mine_large_blocks.nTime = max(mine_large_blocks.nTime,
                                  int(best_block["time"])) + 1
    previousblockhash = int(best_block["hash"], 16)

    for _ in range(n):
        # Build the coinbase transaction (with large scriptPubKey)
        coinbase_tx = create_coinbase(height)
        coinbase_tx.vin[0].nSequence = 2**32 - 1
        coinbase_tx.vout[0].scriptPubKey = big_script
        coinbase_tx.rehash()

        # Build the block
        block = CBlock()
        block.nVersion = best_block["version"]
        block.hashPrevBlock = previousblockhash
        block.nTime = mine_large_blocks.nTime
        block.nBits = int('207fffff', 16)
        block.nNonce = 0
        block.vtx = [coinbase_tx]
        block.hashMerkleRoot = block.calc_merkle_root()
        block.solve()

        # Submit to the node
        node.submitblock(block.serialize().hex())

        previousblockhash = block.sha256
        height += 1
        mine_large_blocks.nTime += 1
Exemplo n.º 5
0
def mine_large_blocks(node, n):
    # Make a large scriptPubKey for the coinbase transaction. This is OP_RETURN
    # followed by 950k of OP_NOP. This would be non-standard in a non-coinbase
    # transaction but is consensus valid.

    # Set the nTime if this is the first time this function has been called.
    # A static variable ensures that time is monotonicly increasing and is therefore
    # different for each block created => blockhash is unique.
    if "nTimes" not in mine_large_blocks.__dict__:
        mine_large_blocks.nTime = 0

    # Get the block parameters for the first block
    big_script = CScript([OP_RETURN] + [OP_NOP] * 950000)
    best_block = node.getblock(node.getbestblockhash())
    height = int(best_block["height"]) + 1
    mine_large_blocks.nTime = max(mine_large_blocks.nTime, int(best_block["time"])) + 1
    previousblockhash = int(best_block["hash"], 16)

    for _ in range(n):
        # Build the coinbase transaction (with large scriptPubKey)
        coinbase_tx = create_coinbase(height)
        coinbase_tx.vin[0].nSequence = 2 ** 32 - 1
        coinbase_tx.vout[0].scriptPubKey = big_script
        coinbase_tx.rehash()

        # Build the block
        block = CBlock()
        block.nVersion = best_block["version"]
        block.hashPrevBlock = previousblockhash
        block.nTime = mine_large_blocks.nTime
        block.nBits = int('207fffff', 16)
        block.nNonce = 0
        block.vtx = [coinbase_tx]
        block.hashMerkleRoot = block.calc_merkle_root()
        block.solve()

        # Submit to the node
        node.submitblock(ToHex(block))

        previousblockhash = block.sha256
        height += 1
        mine_large_blocks.nTime += 1
Exemplo n.º 6
0
    def mine_large_block(self, prefork=True):
        best_block = self.nodes[0].getblock(self.nodes[0].getbestblockhash())
        height = int(best_block["height"]) + 1

        # Build the coinbase transaction (with large scriptPubKey)
        coinbase_tx = create_coinbase(height)
        coinbase_tx.vin[0].nSequence = 2**32 - 1
        coinbase_tx.vout[0].scriptPubKey = CScript(
            [OP_RETURN] + [OP_NOP] * (1500000 if prefork else 950000))
        coinbase_tx.rehash()

        # Build the block
        block = CBlock()
        block.nVersion = best_block["version"]
        block.hashPrevBlock = int(best_block["hash"], 16)
        block.nTime = int(best_block["time"]) + 1
        block.nBits = int('207fffff', 16)
        block.nNonce = 0
        block.vtx = [coinbase_tx]
        block.hashMerkleRoot = block.calc_merkle_root()
        block.solve()

        # Submit to the node
        return self.nodes[0].submitblock(hexdata=block.serialize().hex())
Exemplo n.º 7
0
    def run_test(self):
        node0 = self.nodes[0]
        node1 = self.nodes[1]

        node0.importprivkey(mandatory_privkey)

        self.log.info(
            "generatetoaddress: Making blocks of various kinds, checking for rejection"
        )
        # Create valid blocks to get out of IBD and get some funds (subsidy goes to permitted addr)
        node0.generatetoaddress(101, mandatory_address)

        # Generating for another address will not work
        assert_raises_rpc_error(
            -1, "CreateNewBlock: TestBlockValidity failed: bad-coinbase-txos",
            node0.generatetoaddress, 1, node0.getnewaddress())

        # Have non-mandatory node make a template
        self.sync_all()
        tmpl = node1.getblocktemplate()

        # We make a block with OP_TRUE coinbase output that will fail on node0
        coinbase_tx = create_coinbase(height=int(tmpl["height"]))
        # sequence numbers must not be max for nLockTime to have effect
        coinbase_tx.vin[0].nSequence = 2**32 - 2
        coinbase_tx.rehash()

        block = CBlock()
        block.nVersion = tmpl["version"]
        block.hashPrevBlock = int(tmpl["previousblockhash"], 16)
        block.nTime = tmpl["curtime"]
        block.nBits = int(tmpl["bits"], 16)
        block.nNonce = 0
        block.proof = CProof(bytearray.fromhex('51'))
        block.vtx = [coinbase_tx]
        block.block_height = int(tmpl["height"])
        block.hashMerkleRoot = block.calc_merkle_root()

        self.log.info("getblocktemplate: Test block on both nodes")
        assert_template(node1, block, None)
        assert_template(node0, block, 'bad-coinbase-txos')

        self.log.info("getblocktemplate: Test non-subsidy block on both nodes")
        # Without block reward anything goes, this allows commitment outputs like segwit
        coinbase_tx.vout[0].nValue = CTxOutValue(0)
        coinbase_tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
        coinbase_tx.rehash()
        block.vtx = [coinbase_tx]
        assert_template(node0, block, None)
        assert_template(node1, block, None)

        #
        # Also test that coinbases can't have fees.
        self.sync_all()
        tmpl = node1.getblocktemplate()
        coinbase_tx = create_coinbase(height=int(tmpl["height"]))
        # sequence numbers must not be max for nLockTime to have effect
        coinbase_tx.vin[0].nSequence = 2**32 - 2
        # Add fee output.
        coinbase_tx.vout[0].nValue.setToAmount(
            coinbase_tx.vout[0].nValue.getAmount() - 1)
        coinbase_tx.vout.append(CTxOut(1))
        coinbase_tx.rehash()
        block = CBlock()
        block.nVersion = tmpl["version"]
        block.hashPrevBlock = int(tmpl["previousblockhash"], 16)
        block.nTime = tmpl["curtime"]
        block.nBits = int(tmpl["bits"], 16)
        block.nNonce = 0
        block.proof = CProof(bytearray.fromhex('51'))
        block.vtx = [coinbase_tx]
        block.block_height = int(tmpl["height"])
        block.hashMerkleRoot = block.calc_merkle_root()

        # should not be accepted
        assert_template(node0, block, "bad-cb-fee")
        assert_template(node1, block, "bad-cb-fee")
Exemplo n.º 8
0
    def run_test(self):
        node = self.nodes[0]  # convenience reference to the node

        self.bootstrap_p2p()  # Add one p2p connection to the node

        self.block_heights = {}
        self.coinbase_key = ECKey()
        self.coinbase_key.generate()
        self.coinbase_pubkey = self.coinbase_key.get_pubkey().get_bytes()
        self.tip = None
        self.blocks = {}
        self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)
        self.block_heights[self.genesis_hash] = 0
        self.spendable_outputs = []

        # Create a new block
        b0 = self.next_block(0)
        self.save_spendable_output()
        self.sync_blocks([b0])

        # Allow the block to mature
        blocks = []
        for i in range(99):
            blocks.append(self.next_block(5000 + i))
            self.save_spendable_output()
        self.sync_blocks(blocks)

        # collect spendable outputs now to avoid cluttering the code later on
        out = []
        for i in range(33):
            out.append(self.get_spendable_output())

        # Start by building a couple of blocks on top (which output is spent is
        # in parentheses):
        #     genesis -> b1 (0) -> b2 (1)
        b1 = self.next_block(1, spend=out[0])
        self.save_spendable_output()

        b2 = self.next_block(2, spend=out[1])
        self.save_spendable_output()

        self.sync_blocks([b1, b2])

        # Fork like this:
        #
        #     genesis -> b1 (0) -> b2 (1)
        #                      \-> b3 (1)
        #
        # Nothing should happen at this point. We saw b2 first so it takes
        # priority.
        self.log.info("Don't reorg to a chain of the same length")
        self.move_tip(1)
        b3 = self.next_block(3, spend=out[1])
        txout_b3 = b3.vtx[1]
        self.sync_blocks([b3], False)

        # Now we add another block to make the alternative chain longer.
        #
        #     genesis -> b1 (0) -> b2 (1)
        #                      \-> b3 (1) -> b4 (2)
        self.log.info("Reorg to a longer chain")
        b4 = self.next_block(4, spend=out[2])
        self.sync_blocks([b4])

        # ... and back to the first chain.
        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
        #                      \-> b3 (1) -> b4 (2)
        self.move_tip(2)
        b5 = self.next_block(5, spend=out[2])
        self.save_spendable_output()
        self.sync_blocks([b5], False)

        self.log.info("Reorg back to the original chain")
        b6 = self.next_block(6, spend=out[3])
        self.sync_blocks([b6], True)

        # Try to create a fork that double-spends
        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
        #                                          \-> b7 (2) -> b8 (4)
        #                      \-> b3 (1) -> b4 (2)
        self.log.info(
            "Reject a chain with a double spend, even if it is longer")
        self.move_tip(5)
        b7 = self.next_block(7, spend=out[2])
        self.sync_blocks([b7], False)

        b8 = self.next_block(8, spend=out[4])
        self.sync_blocks([b8], False, reconnect=True)

        # Try to create a block that has too much fee
        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
        #                                                    \-> b9 (4)
        #                      \-> b3 (1) -> b4 (2)
        self.log.info(
            "Reject a block where the miner creates too much coinbase reward")
        self.move_tip(6)
        b9 = self.next_block(9, spend=out[4], additional_coinbase_value=1)
        self.sync_blocks([b9], success=False,
                         reject_reason='bad-cb-amount', reconnect=True)

        # Create a fork that ends in a block with too much fee (the one that causes the reorg)
        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)
        #                                          \-> b10 (3) -> b11 (4)
        #                      \-> b3 (1) -> b4 (2)
        self.log.info(
            "Reject a chain where the miner creates too much coinbase reward, even if the chain is longer")
        self.move_tip(5)
        b10 = self.next_block(10, spend=out[3])
        self.sync_blocks([b10], False)

        b11 = self.next_block(11, spend=out[4], additional_coinbase_value=1)
        self.sync_blocks([b11], success=False,
                         reject_reason='bad-cb-amount', reconnect=True)

        # Try again, but with a valid fork first
        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)
        #                                          \-> b12 (3) -> b13 (4) -> b14 (5)
        #                      \-> b3 (1) -> b4 (2)
        self.log.info(
            "Reject a chain where the miner creates too much coinbase reward, even if the chain is longer (on a forked chain)")
        self.move_tip(5)
        b12 = self.next_block(12, spend=out[3])
        self.save_spendable_output()
        b13 = self.next_block(13, spend=out[4])
        self.save_spendable_output()
        b14 = self.next_block(14, spend=out[5], additional_coinbase_value=1)
        self.sync_blocks([b12, b13, b14], success=False,
                         reject_reason='bad-cb-amount', reconnect=True)

        # New tip should be b13.
        assert_equal(node.getbestblockhash(), b13.hash)

        self.log.info("Skipped sigops tests")
        # tests were moved to feature_block_sigops.py
        self.move_tip(13)
        b15 = self.next_block(15)
        self.save_spendable_output()
        self.sync_blocks([b15], True)

        # Attempt to spend a transaction created on a different fork
        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)
        #                                          \-> b12 (3) -> b13 (4) -> b15 (5) -> b17 (b3.vtx[1])
        #                      \-> b3 (1) -> b4 (2)
        self.log.info("Reject a block with a spend from a re-org'ed out tx")
        self.move_tip(15)
        b17 = self.next_block(17, spend=txout_b3)
        self.sync_blocks([b17], success=False,
                         reject_reason='bad-txns-inputs-missingorspent', reconnect=True)

        # Attempt to spend a transaction created on a different fork (on a fork this time)
        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)
        #                                          \-> b12 (3) -> b13 (4) -> b15 (5)
        #                                                                \-> b18 (b3.vtx[1]) -> b19 (6)
        #                      \-> b3 (1) -> b4 (2)
        self.log.info(
            "Reject a block with a spend from a re-org'ed out tx (on a forked chain)")
        self.move_tip(13)
        b18 = self.next_block(18, spend=txout_b3)
        self.sync_blocks([b18], False)

        b19 = self.next_block(19, spend=out[6])
        self.sync_blocks([b19], success=False,
                         reject_reason='bad-txns-inputs-missingorspent', reconnect=True)

        # Attempt to spend a coinbase at depth too low
        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)
        #                                          \-> b12 (3) -> b13 (4) -> b15 (5) -> b20 (7)
        #                      \-> b3 (1) -> b4 (2)
        self.log.info("Reject a block spending an immature coinbase.")
        self.move_tip(15)
        b20 = self.next_block(20, spend=out[7])
        self.sync_blocks([b20], success=False,
                         reject_reason='bad-txns-premature-spend-of-coinbase')

        # Attempt to spend a coinbase at depth too low (on a fork this time)
        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)
        #                                          \-> b12 (3) -> b13 (4) -> b15 (5)
        #                                                                \-> b21 (6) -> b22 (5)
        #                      \-> b3 (1) -> b4 (2)
        self.log.info(
            "Reject a block spending an immature coinbase (on a forked chain)")
        self.move_tip(13)
        b21 = self.next_block(21, spend=out[6])
        self.sync_blocks([b21], False)

        b22 = self.next_block(22, spend=out[5])
        self.sync_blocks([b22], success=False,
                         reject_reason='bad-txns-premature-spend-of-coinbase')

        # Create a block on either side of LEGACY_MAX_BLOCK_SIZE and make sure its accepted/rejected
        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)
        #                                          \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6)
        #                                                                           \-> b24 (6) -> b25 (7)
        #                      \-> b3 (1) -> b4 (2)
        self.log.info("Accept a block of size LEGACY_MAX_BLOCK_SIZE")
        self.move_tip(15)
        b23 = self.next_block(23, spend=out[6])
        tx = CTransaction()
        script_length = LEGACY_MAX_BLOCK_SIZE - len(b23.serialize()) - 69
        script_output = CScript([b'\x00' * script_length])
        tx.vout.append(CTxOut(0, script_output))
        tx.vin.append(CTxIn(COutPoint(b23.vtx[1].sha256, 0)))
        b23 = self.update_block(23, [tx])
        # Make sure the math above worked out to produce a max-sized block
        assert_equal(len(b23.serialize()), LEGACY_MAX_BLOCK_SIZE)
        self.sync_blocks([b23], True)
        self.save_spendable_output()

        # Create blocks with a coinbase input script size out of range
        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)
        #                                          \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7)
        #                                                                           \-> ... (6) -> ... (7)
        #                      \-> b3 (1) -> b4 (2)
        self.log.info(
            "Reject a block with coinbase input script size out of range")
        self.move_tip(15)
        b26 = self.next_block(26, spend=out[6])
        b26.vtx[0].vin[0].scriptSig = b'\x00'
        b26.vtx[0].rehash()
        # update_block causes the merkle root to get updated, even with no new
        # transactions, and updates the required state.
        b26 = self.update_block(26, [])
        self.sync_blocks([b26], success=False,
                         reject_reason='bad-cb-length', reconnect=True)

        # Extend the b26 chain to make sure bitcoind isn't accepting b26
        b27 = self.next_block(27, spend=out[7])
        self.sync_blocks([b27], False)

        # Now try a too-large-coinbase script
        self.move_tip(15)
        b28 = self.next_block(28, spend=out[6])
        b28.vtx[0].vin[0].scriptSig = b'\x00' * 101
        b28.vtx[0].rehash()
        b28 = self.update_block(28, [])
        self.sync_blocks([b28], success=False,
                         reject_reason='bad-cb-length', reconnect=True)

        # Extend the b28 chain to make sure bitcoind isn't accepting b28
        b29 = self.next_block(29, spend=out[7])
        self.sync_blocks([b29], False)

        # b30 has a max-sized coinbase scriptSig.
        self.move_tip(23)
        b30 = self.next_block(30)
        b30.vtx[0].vin[0].scriptSig = b'\x00' * 100
        b30.vtx[0].rehash()
        b30 = self.update_block(30, [])
        self.sync_blocks([b30], True)
        self.save_spendable_output()

        self.log.info("Skipped sigops tests")
        # tests were moved to feature_block_sigops.py
        b31 = self.next_block(31)
        self.save_spendable_output()
        b33 = self.next_block(33)
        self.save_spendable_output()
        b35 = self.next_block(35)
        self.save_spendable_output()
        self.sync_blocks([b31, b33, b35], True)

        # Check spending of a transaction in a block which failed to connect
        #
        # b6  (3)
        # b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10)
        #                                                                                     \-> b37 (11)
        #                                                                                     \-> b38 (11/37)
        #

        # save 37's spendable output, but then double-spend out11 to invalidate
        # the block
        self.log.info(
            "Reject a block spending transaction from a block which failed to connect")
        self.move_tip(35)
        b37 = self.next_block(37, spend=out[11])
        txout_b37 = b37.vtx[1]
        tx = self.create_and_sign_transaction(out[11], 0)
        b37 = self.update_block(37, [tx])
        self.sync_blocks([b37], success=False,
                         reject_reason='bad-txns-inputs-missingorspent', reconnect=True)

        # attempt to spend b37's first non-coinbase tx, at which point b37 was
        # still considered valid
        self.move_tip(35)
        b38 = self.next_block(38, spend=txout_b37)
        self.sync_blocks([b38], success=False,
                         reject_reason='bad-txns-inputs-missingorspent', reconnect=True)

        self.log.info("Skipped sigops tests")
        # tests were moved to feature_block_sigops.py
        self.move_tip(35)
        b39 = self.next_block(39)
        self.save_spendable_output()
        b41 = self.next_block(41)
        self.sync_blocks([b39, b41], True)

        # Fork off of b39 to create a constant base again
        #
        # b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13)
        #                                                                  \-> b41 (12)
        #
        self.move_tip(39)
        b42 = self.next_block(42, spend=out[12])
        self.save_spendable_output()

        b43 = self.next_block(43, spend=out[13])
        self.save_spendable_output()
        self.sync_blocks([b42, b43], True)

        # Test a number of really invalid scenarios
        #
        #  -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b44 (14)
        #                                                                                   \-> ??? (15)

        # The next few blocks are going to be created "by hand" since they'll do funky things, such as having
        # the first transaction be non-coinbase, etc.  The purpose of b44 is to
        # make sure this works.
        self.log.info("Build block 44 manually")
        height = self.block_heights[self.tip.sha256] + 1
        coinbase = create_coinbase(height, self.coinbase_pubkey)
        b44 = CBlock()
        b44.nTime = self.tip.nTime + 1
        b44.hashPrevBlock = self.tip.sha256
        b44.nBits = 0x207fffff
        b44.vtx.append(coinbase)
        b44.hashMerkleRoot = b44.calc_merkle_root()
        b44.solve()
        self.tip = b44
        self.block_heights[b44.sha256] = height
        self.blocks[44] = b44
        self.sync_blocks([b44], True)

        self.log.info("Reject a block with a non-coinbase as the first tx")
        non_coinbase = self.create_tx(out[15], 0, 1)
        b45 = CBlock()
        b45.nTime = self.tip.nTime + 1
        b45.hashPrevBlock = self.tip.sha256
        b45.nBits = 0x207fffff
        b45.vtx.append(non_coinbase)
        b45.hashMerkleRoot = b45.calc_merkle_root()
        b45.calc_sha256()
        b45.solve()
        self.block_heights[b45.sha256] = self.block_heights[
            self.tip.sha256] + 1
        self.tip = b45
        self.blocks[45] = b45
        self.sync_blocks([b45], success=False,
                         reject_reason='bad-cb-missing', reconnect=True)

        self.log.info("Reject a block with no transactions")
        self.move_tip(44)
        b46 = CBlock()
        b46.nTime = b44.nTime + 1
        b46.hashPrevBlock = b44.sha256
        b46.nBits = 0x207fffff
        b46.vtx = []
        b46.hashMerkleRoot = 0
        b46.solve()
        self.block_heights[b46.sha256] = self.block_heights[b44.sha256] + 1
        self.tip = b46
        assert 46 not in self.blocks
        self.blocks[46] = b46
        self.sync_blocks([b46], success=False,
                         reject_reason='bad-cb-missing', reconnect=True)

        self.log.info("Reject a block with invalid work")
        self.move_tip(44)
        b47 = self.next_block(47, solve=False)
        target = uint256_from_compact(b47.nBits)
        while b47.sha256 < target:
            b47.nNonce += 1
            b47.rehash()
        self.sync_blocks([b47], False, request_block=False)

        self.log.info("Reject a block with a timestamp >2 hours in the future")
        self.move_tip(44)
        b48 = self.next_block(48, solve=False)
        b48.nTime = int(time.time()) + 60 * 60 * 3
        b48.solve()
        self.sync_blocks([b48], False, request_block=False)

        self.log.info("Reject a block with invalid merkle hash")
        self.move_tip(44)
        b49 = self.next_block(49)
        b49.hashMerkleRoot += 1
        b49.solve()
        self.sync_blocks([b49], success=False,
                         reject_reason='bad-txnmrklroot', reconnect=True)

        self.log.info("Reject a block with incorrect POW limit")
        self.move_tip(44)
        b50 = self.next_block(50)
        b50.nBits = b50.nBits - 1
        b50.solve()
        self.sync_blocks([b50], False, request_block=False, reconnect=True)

        self.log.info("Reject a block with two coinbase transactions")
        self.move_tip(44)
        b51 = self.next_block(51)
        cb2 = create_coinbase(51, self.coinbase_pubkey)
        b51 = self.update_block(51, [cb2])
        self.sync_blocks([b51], success=False,
                         reject_reason='bad-tx-coinbase', reconnect=True)

        self.log.info("Reject a block with duplicate transactions")
        self.move_tip(44)
        b52 = self.next_block(52, spend=out[15])
        b52 = self.update_block(52, [b52.vtx[1]])
        self.sync_blocks([b52], success=False,
                         reject_reason='tx-duplicate', reconnect=True)

        # Test block timestamps
        #  -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15)
        #                                                                                   \-> b54 (15)
        #
        self.move_tip(43)
        b53 = self.next_block(53, spend=out[14])
        self.sync_blocks([b53], False)
        self.save_spendable_output()

        self.log.info("Reject a block with timestamp before MedianTimePast")
        b54 = self.next_block(54, spend=out[15])
        b54.nTime = b35.nTime - 1
        b54.solve()
        self.sync_blocks([b54], False, request_block=False)

        # valid timestamp
        self.move_tip(53)
        b55 = self.next_block(55, spend=out[15])
        b55.nTime = b35.nTime
        self.update_block(55, [])
        self.sync_blocks([b55], True)
        self.save_spendable_output()

        # Test Merkle tree malleability
        #
        # -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57p2 (16)
        #                                                \-> b57   (16)
        #                                                \-> b56p2 (16)
        #                                                \-> b56   (16)
        #
        # Merkle tree malleability (CVE-2012-2459): repeating sequences of transactions in a block without
        #                           affecting the merkle root of a block, while still invalidating it.
        #                           See:  src/consensus/merkle.h
        #
        #  b57 has three txns:  coinbase, tx, tx1.  The merkle root computation will duplicate tx.
        #  Result:  OK
        #
        #  b56 copies b57 but duplicates tx1 and does not recalculate the block hash.  So it has a valid merkle
        #  root but duplicate transactions.
        #  Result:  Fails
        #
        #  b57p2 has six transactions in its merkle tree:
        #       - coinbase, tx, tx1, tx2, tx3, tx4
        #  Merkle root calculation will duplicate as necessary.
        #  Result:  OK.
        #
        #  b56p2 copies b57p2 but adds both tx3 and tx4.  The purpose of the test is to make sure the code catches
        #  duplicate txns that are not next to one another with the "bad-txns-duplicate" error (which indicates
        #  that the error was caught early, avoiding a DOS vulnerability.)

        # b57 - a good block with 2 txs, don't submit until end
        self.move_tip(55)
        b57 = self.next_block(57)
        tx = self.create_and_sign_transaction(out[16], 1)
        tx1 = self.create_tx(tx, 0, 1)
        b57 = self.update_block(57, [tx, tx1])

        # b56 - copy b57, add a duplicate tx
        self.log.info(
            "Reject a block with a duplicate transaction in the Merkle Tree (but with a valid Merkle Root)")
        self.move_tip(55)
        b56 = copy.deepcopy(b57)
        self.blocks[56] = b56
        assert_equal(len(b56.vtx), 3)
        b56 = self.update_block(56, [b57.vtx[2]])
        assert_equal(b56.hash, b57.hash)
        self.sync_blocks([b56], success=False,
                         reject_reason='bad-txns-duplicate', reconnect=True)

        # b57p2 - a good block with 6 tx'es, don't submit until end
        self.move_tip(55)
        b57p2 = self.next_block("57p2")
        tx = self.create_and_sign_transaction(out[16], 1)
        tx1 = self.create_tx(tx, 0, 1)
        tx2 = self.create_tx(tx1, 0, 1)
        tx3 = self.create_tx(tx2, 0, 1)
        tx4 = self.create_tx(tx3, 0, 1)
        b57p2 = self.update_block("57p2", [tx, tx1, tx2, tx3, tx4])

        # b56p2 - copy b57p2, duplicate two non-consecutive tx's
        self.log.info(
            "Reject a block with two duplicate transactions in the Merkle Tree (but with a valid Merkle Root)")
        self.move_tip(55)
        b56p2 = copy.deepcopy(b57p2)
        self.blocks["b56p2"] = b56p2
        assert_equal(len(b56p2.vtx), 6)
        b56p2 = self.update_block("b56p2", b56p2.vtx[4:6], reorder=False)
        assert_equal(b56p2.hash, b57p2.hash)
        self.sync_blocks([b56p2], success=False,
                         reject_reason='bad-txns-duplicate', reconnect=True)

        self.move_tip("57p2")
        self.sync_blocks([b57p2], True)

        self.move_tip(57)
        # The tip is not updated because 57p2 seen first
        self.sync_blocks([b57], False)
        self.save_spendable_output()

        # Test a few invalid tx types
        #
        # -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17)
        #                                                                                    \-> ??? (17)
        #

        # tx with prevout.n out of range
        self.log.info(
            "Reject a block with a transaction with prevout.n out of range")
        self.move_tip(57)
        b58 = self.next_block(58, spend=out[17])
        tx = CTransaction()
        assert(len(out[17].vout) < 42)
        tx.vin.append(
            CTxIn(COutPoint(out[17].sha256, 42), CScript([OP_TRUE]), 0xffffffff))
        tx.vout.append(CTxOut(0, b""))
        pad_tx(tx)
        tx.calc_sha256()
        b58 = self.update_block(58, [tx])
        self.sync_blocks([b58], success=False,
                         reject_reason='bad-txns-inputs-missingorspent', reconnect=True)

        # tx with output value > input value
        self.log.info(
            "Reject a block with a transaction with outputs > inputs")
        self.move_tip(57)
        b59 = self.next_block(59)
        tx = self.create_and_sign_transaction(out[17], 51 * COIN)
        b59 = self.update_block(59, [tx])
        self.sync_blocks([b59], success=False,
                         reject_reason='bad-txns-in-belowout', reconnect=True)

        # reset to good chain
        self.move_tip(57)
        b60 = self.next_block(60, spend=out[17])
        self.sync_blocks([b60], True)
        self.save_spendable_output()

        # Test BIP30
        #
        # -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17)
        #                                                                                    \-> b61 (18)
        #
        # Blocks are not allowed to contain a transaction whose id matches that of an earlier,
        # not-fully-spent transaction in the same chain. To test, make identical coinbases;
        # the second one should be rejected.
        #
        self.log.info(
            "Reject a block with a transaction with a duplicate hash of a previous transaction (BIP30)")
        self.move_tip(60)
        b61 = self.next_block(61, spend=out[18])
        # Equalize the coinbases
        b61.vtx[0].vin[0].scriptSig = b60.vtx[0].vin[0].scriptSig
        b61.vtx[0].rehash()
        b61 = self.update_block(61, [])
        assert_equal(b60.vtx[0].serialize(), b61.vtx[0].serialize())
        self.sync_blocks([b61], success=False,
                         reject_reason='bad-txns-BIP30', reconnect=True)

        # Test tx.isFinal is properly rejected (not an exhaustive tx.isFinal test, that should be in data-driven transaction tests)
        #
        #   -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17)
        #                                                                                     \-> b62 (18)
        #
        self.log.info(
            "Reject a block with a transaction with a nonfinal locktime")
        self.move_tip(60)
        b62 = self.next_block(62)
        tx = CTransaction()
        tx.nLockTime = 0xffffffff  # this locktime is non-final
        # don't set nSequence
        tx.vin.append(CTxIn(COutPoint(out[18].sha256, 0)))
        tx.vout.append(CTxOut(0, CScript([OP_TRUE])))
        assert tx.vin[0].nSequence < 0xffffffff
        tx.calc_sha256()
        b62 = self.update_block(62, [tx])
        self.sync_blocks([b62], success=False,
                         reject_reason='bad-txns-nonfinal')

        # Test a non-final coinbase is also rejected
        #
        #   -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17)
        #                                                                                     \-> b63 (-)
        #
        self.log.info(
            "Reject a block with a coinbase transaction with a nonfinal locktime")
        self.move_tip(60)
        b63 = self.next_block(63)
        b63.vtx[0].nLockTime = 0xffffffff
        b63.vtx[0].vin[0].nSequence = 0xDEADBEEF
        b63.vtx[0].rehash()
        b63 = self.update_block(63, [])
        self.sync_blocks([b63], success=False,
                         reject_reason='bad-txns-nonfinal')

        #  This checks that a block with a bloated VARINT between the block_header and the array of tx such that
        #  the block is > LEGACY_MAX_BLOCK_SIZE with the bloated varint, but <= LEGACY_MAX_BLOCK_SIZE without the bloated varint,
        #  does not cause a subsequent, identical block with canonical encoding to be rejected.  The test does not
        #  care whether the bloated block is accepted or rejected; it only cares that the second block is accepted.
        #
        #  What matters is that the receiving node should not reject the bloated block, and then reject the canonical
        #  block on the basis that it's the same as an already-rejected block (which would be a consensus failure.)
        #
        #  -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18)
        #                                                                                        \
        #                                                                                         b64a (18)
        #  b64a is a bloated block (non-canonical varint)
        #  b64 is a good block (same as b64 but w/ canonical varint)
        #
        self.log.info(
            "Accept a valid block even if a bloated version of the block has previously been sent")
        self.move_tip(60)
        regular_block = self.next_block("64a", spend=out[18])

        # make it a "broken_block," with non-canonical serialization
        b64a = CBrokenBlock(regular_block)
        b64a.initialize(regular_block)
        self.blocks["64a"] = b64a
        self.tip = b64a
        tx = CTransaction()

        # use canonical serialization to calculate size
        script_length = LEGACY_MAX_BLOCK_SIZE - \
            len(b64a.normal_serialize()) - 69
        script_output = CScript([b'\x00' * script_length])
        tx.vout.append(CTxOut(0, script_output))
        tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0)))
        b64a = self.update_block("64a", [tx])
        assert_equal(len(b64a.serialize()), LEGACY_MAX_BLOCK_SIZE + 8)
        self.sync_blocks([b64a], success=False,
                         reject_reason='non-canonical ReadCompactSize()')

        # bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently
        # resend the header message, it won't send us the getdata message again. Just
        # disconnect and reconnect and then call sync_blocks.
        # TODO: improve this test to be less dependent on P2P DOS behaviour.
        node.disconnect_p2ps()
        self.reconnect_p2p()

        self.move_tip(60)
        b64 = CBlock(b64a)
        b64.vtx = copy.deepcopy(b64a.vtx)
        assert_equal(b64.hash, b64a.hash)
        assert_equal(len(b64.serialize()), LEGACY_MAX_BLOCK_SIZE)
        self.blocks[64] = b64
        b64 = self.update_block(64, [])
        self.sync_blocks([b64], True)
        self.save_spendable_output()

        # Spend an output created in the block itself
        #
        # -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19)
        #
        self.log.info(
            "Accept a block with a transaction spending an output created in the same block")
        self.move_tip(64)
        b65 = self.next_block(65)
        tx1 = self.create_and_sign_transaction(out[19], out[19].vout[0].nValue)
        tx2 = self.create_and_sign_transaction(tx1, 0)
        b65 = self.update_block(65, [tx1, tx2])
        self.sync_blocks([b65], True)
        self.save_spendable_output()

        # Attempt to double-spend a transaction created in a block
        #
        # -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19)
        #                                                                                    \-> b67 (20)
        #
        #
        self.log.info(
            "Reject a block with a transaction double spending a transaction created in the same block")
        self.move_tip(65)
        b67 = self.next_block(67)
        tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)
        tx2 = self.create_and_sign_transaction(tx1, 1)
        tx3 = self.create_and_sign_transaction(tx1, 2)
        b67 = self.update_block(67, [tx1, tx2, tx3])
        self.sync_blocks([b67], success=False,
                         reject_reason='bad-txns-inputs-missingorspent', reconnect=True)

        # More tests of block subsidy
        #
        # -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20)
        #                                                                                    \-> b68 (20)
        #
        # b68 - coinbase with an extra 10 satoshis,
        #       creates a tx that has 9 satoshis from out[20] go to fees
        #       this fails because the coinbase is trying to claim 1 satoshi too much in fees
        #
        # b69 - coinbase with extra 10 satoshis, and a tx that gives a 10 satoshi fee
        #       this succeeds
        #
        self.log.info(
            "Reject a block trying to claim too much subsidy in the coinbase transaction")
        self.move_tip(65)
        b68 = self.next_block(68, additional_coinbase_value=10)
        tx = self.create_and_sign_transaction(
            out[20], out[20].vout[0].nValue - 9)
        b68 = self.update_block(68, [tx])
        self.sync_blocks([b68], success=False,
                         reject_reason='bad-cb-amount', reconnect=True)

        self.log.info(
            "Accept a block claiming the correct subsidy in the coinbase transaction")
        self.move_tip(65)
        b69 = self.next_block(69, additional_coinbase_value=10)
        tx = self.create_and_sign_transaction(
            out[20], out[20].vout[0].nValue - 10)
        self.update_block(69, [tx])
        self.sync_blocks([b69], True)
        self.save_spendable_output()

        # Test spending the outpoint of a non-existent transaction
        #
        # -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20)
        #                                                                                    \-> b70 (21)
        #
        self.log.info(
            "Reject a block containing a transaction spending from a non-existent input")
        self.move_tip(69)
        b70 = self.next_block(70, spend=out[21])
        bogus_tx = CTransaction()
        bogus_tx.sha256 = uint256_from_str(
            b"23c70ed7c0506e9178fc1a987f40a33946d4ad4c962b5ae3a52546da53af0c5c")
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", 0xffffffff))
        tx.vout.append(CTxOut(1, b""))
        pad_tx(tx)
        b70 = self.update_block(70, [tx])
        self.sync_blocks([b70], success=False,
                         reject_reason='bad-txns-inputs-missingorspent', reconnect=True)

        # Test accepting an invalid block which has the same hash as a valid one (via merkle tree tricks)
        #
        #  -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) -> b72 (21)
        #                                                                                      \-> b71 (21)
        #
        # b72 is a good block.
        # b71 is a copy of 72, but re-adds one of its transactions.  However,
        # it has the same hash as b72.
        self.log.info(
            "Reject a block containing a duplicate transaction but with the same Merkle root (Merkle tree malleability")
        self.move_tip(69)
        b72 = self.next_block(72)
        tx1 = self.create_and_sign_transaction(out[21], 2)
        tx2 = self.create_and_sign_transaction(tx1, 1)
        b72 = self.update_block(72, [tx1, tx2])  # now tip is 72
        b71 = copy.deepcopy(b72)
        # add duplicate last transaction
        b71.vtx.append(b72.vtx[-1])
        # b71 builds off b69
        self.block_heights[b71.sha256] = self.block_heights[b69.sha256] + 1
        self.blocks[71] = b71

        assert_equal(len(b71.vtx), 4)
        assert_equal(len(b72.vtx), 3)
        assert_equal(b72.sha256, b71.sha256)

        self.move_tip(71)
        self.sync_blocks([b71], success=False,
                         reject_reason='bad-txns-duplicate', reconnect=True)

        self.move_tip(72)
        self.sync_blocks([b72], True)
        self.save_spendable_output()

        self.log.info("Skipped sigops tests")
        # tests were moved to feature_block_sigops.py
        b75 = self.next_block(75)
        self.save_spendable_output()
        b76 = self.next_block(76)
        self.save_spendable_output()
        self.sync_blocks([b75, b76], True)

        # Test transaction resurrection
        #
        # -> b77 (24) -> b78 (25) -> b79 (26)
        #            \-> b80 (25) -> b81 (26) -> b82 (27)
        #
        #    b78 creates a tx, which is spent in b79. After b82, both should be in mempool
        #
        #    The tx'es must be unsigned and pass the node's mempool policy.  It is unsigned for the
        #    rather obscure reason that the Python signature code does not distinguish between
        #    Low-S and High-S values (whereas the bitcoin code has custom code which does so);
        #    as a result of which, the odds are 50% that the python code will use the right
        #    value and the transaction will be accepted into the mempool. Until we modify the
        #    test framework to support low-S signing, we are out of luck.
        #
        #    To get around this issue, we construct transactions which are not signed and which
        #    spend to OP_TRUE.  If the standard-ness rules change, this test would need to be
        #    updated.  (Perhaps to spend to a P2SH OP_TRUE script)
        self.log.info("Test transaction resurrection during a re-org")
        self.move_tip(76)
        b77 = self.next_block(77)
        tx77 = self.create_and_sign_transaction(out[24], 10 * COIN)
        b77 = self.update_block(77, [tx77])
        self.sync_blocks([b77], True)
        self.save_spendable_output()

        b78 = self.next_block(78)
        tx78 = self.create_tx(tx77, 0, 9 * COIN)
        b78 = self.update_block(78, [tx78])
        self.sync_blocks([b78], True)

        b79 = self.next_block(79)
        tx79 = self.create_tx(tx78, 0, 8 * COIN)
        b79 = self.update_block(79, [tx79])
        self.sync_blocks([b79], True)

        # mempool should be empty
        assert_equal(len(self.nodes[0].getrawmempool()), 0)

        self.move_tip(77)
        b80 = self.next_block(80, spend=out[25])
        self.sync_blocks([b80], False, request_block=False)
        self.save_spendable_output()

        b81 = self.next_block(81, spend=out[26])
        # other chain is same length
        self.sync_blocks([b81], False, request_block=False)
        self.save_spendable_output()

        b82 = self.next_block(82, spend=out[27])
        # now this chain is longer, triggers re-org
        self.sync_blocks([b82], True)
        self.save_spendable_output()

        # now check that tx78 and tx79 have been put back into the peer's
        # mempool
        mempool = self.nodes[0].getrawmempool()
        assert_equal(len(mempool), 2)
        assert tx78.hash in mempool
        assert tx79.hash in mempool

        # Test invalid opcodes in dead execution paths.
        #
        #  -> b81 (26) -> b82 (27) -> b83 (28)
        #
        self.log.info(
            "Accept a block with invalid opcodes in dead execution paths")
        b83 = self.next_block(83)
        op_codes = [OP_IF, INVALIDOPCODE, OP_ELSE, OP_TRUE, OP_ENDIF]
        script = CScript(op_codes)
        tx1 = self.create_and_sign_transaction(
            out[28], out[28].vout[0].nValue, script)

        tx2 = self.create_and_sign_transaction(tx1, 0, CScript([OP_TRUE]))
        tx2.vin[0].scriptSig = CScript([OP_FALSE])
        tx2.rehash()

        b83 = self.update_block(83, [tx1, tx2])
        self.sync_blocks([b83], True)
        self.save_spendable_output()

        # Reorg on/off blocks that have OP_RETURN in them (and try to spend them)
        #
        #  -> b81 (26) -> b82 (27) -> b83 (28) -> b84 (29) -> b87 (30) -> b88 (31)
        #                                    \-> b85 (29) -> b86 (30)            \-> b89a (32)
        #
        self.log.info("Test re-orging blocks with OP_RETURN in them")
        b84 = self.next_block(84)
        tx1 = self.create_tx(out[29], 0, 0, CScript([OP_RETURN]))
        vout_offset = len(tx1.vout)
        tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
        tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
        tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
        tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
        tx1.calc_sha256()
        self.sign_tx(tx1, out[29])
        tx1.rehash()
        tx2 = self.create_tx(tx1, vout_offset, 0, CScript([OP_RETURN]))
        tx2.vout.append(CTxOut(0, CScript([OP_RETURN])))
        tx3 = self.create_tx(tx1, vout_offset + 1, 0, CScript([OP_RETURN]))
        tx3.vout.append(CTxOut(0, CScript([OP_TRUE])))
        tx4 = self.create_tx(tx1, vout_offset + 2, 0, CScript([OP_TRUE]))
        tx4.vout.append(CTxOut(0, CScript([OP_RETURN])))
        tx5 = self.create_tx(tx1, vout_offset + 3, 0, CScript([OP_RETURN]))

        b84 = self.update_block(84, [tx1, tx2, tx3, tx4, tx5])
        self.sync_blocks([b84], True)
        self.save_spendable_output()

        self.move_tip(83)
        b85 = self.next_block(85, spend=out[29])
        self.sync_blocks([b85], False)  # other chain is same length

        b86 = self.next_block(86, spend=out[30])
        self.sync_blocks([b86], True)

        self.move_tip(84)
        b87 = self.next_block(87, spend=out[30])
        self.sync_blocks([b87], False)  # other chain is same length
        self.save_spendable_output()

        b88 = self.next_block(88, spend=out[31])
        self.sync_blocks([b88], True)
        self.save_spendable_output()

        # trying to spend the OP_RETURN output is rejected
        b89a = self.next_block("89a", spend=out[32])
        tx = self.create_tx(tx1, 0, 0, CScript([OP_TRUE]))
        b89a = self.update_block("89a", [tx])
        self.sync_blocks([b89a], success=False,
                         reject_reason='bad-txns-inputs-missingorspent', reconnect=True)

        self.log.info(
            "Test a re-org of one week's worth of blocks (1088 blocks)")

        self.move_tip(88)
        LARGE_REORG_SIZE = 1088
        blocks = []
        spend = out[32]
        for i in range(89, LARGE_REORG_SIZE + 89):
            b = self.next_block(i, spend)
            tx = CTransaction()
            script_length = LEGACY_MAX_BLOCK_SIZE - len(b.serialize()) - 69
            script_output = CScript([b'\x00' * script_length])
            tx.vout.append(CTxOut(0, script_output))
            tx.vin.append(CTxIn(COutPoint(b.vtx[1].sha256, 0)))
            b = self.update_block(i, [tx])
            assert_equal(len(b.serialize()), LEGACY_MAX_BLOCK_SIZE)
            blocks.append(b)
            self.save_spendable_output()
            spend = self.get_spendable_output()

        self.sync_blocks(blocks, True, timeout=960)
        chain1_tip = i

        # now create alt chain of same length
        self.move_tip(88)
        blocks2 = []
        for i in range(89, LARGE_REORG_SIZE + 89):
            blocks2.append(self.next_block("alt" + str(i)))
        self.sync_blocks(blocks2, False, request_block=False)

        # extend alt chain to trigger re-org
        block = self.next_block("alt" + str(chain1_tip + 1))
        self.sync_blocks([block], True, timeout=960)

        # ... and re-org back to the first chain
        self.move_tip(chain1_tip)
        block = self.next_block(chain1_tip + 1)
        self.sync_blocks([block], False, request_block=False)
        block = self.next_block(chain1_tip + 2)
        self.sync_blocks([block], True, timeout=960)
    def run_test(self):
        self.stop_node(0)
        shutil.rmtree(self.nodes[0].datadir)

        initialize_datadir(self.options.tmpdir, 0)

        self.log.info("Test with no genesis file")
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: unable to read genesis file', match=ErrorMatch.PARTIAL_REGEX)

        self.log.info("Phase 1: Tests using genesis block")
        self.log.info("Test correct genesis file")
        self.writeGenesisBlockToFile(self.nodes[0].datadir)
        self.start_node(0)
        self.stop_node(0)

        self.log.info("Restart with correct genesis file")
        self.start_node(0)
        self.stop_node(0)

        self.log.info("Test incorrect genesis block - No Coinbase")
        genesis_coinbase = createGenesisCoinbase(self.signblockpubkey)
        genesis_coinbase.vin[0].prevout.hash = 111111
        genesis = createIncorectGenesisBlock(genesis_coinbase, self.signblockprivkey, self.signblockpubkey)

        writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis)
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis block', match=ErrorMatch.PARTIAL_REGEX)

        self.log.info("Test incorrect genesis block - Incorrect height")
        genesis_coinbase_height = createGenesisCoinbase(self.signblockpubkey)
        genesis_coinbase_height.vin[0].prevout.n = 10
        genesis = createIncorectGenesisBlock(genesis_coinbase_height, self.signblockprivkey, self.signblockpubkey)

        writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis)
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid height in genesis block', match=ErrorMatch.PARTIAL_REGEX)

        self.log.info("Test incorrect genesis block - Multiple transactions")
        genesis_coinbase = createGenesisCoinbase(self.signblockpubkey)
        genesis = createIncorectGenesisBlock(genesis_coinbase, self.signblockprivkey, self.signblockpubkey)
        genesis.vtx.append(CTransaction())
        genesis.hashMerkleRoot = genesis.calc_merkle_root()
        genesis.hashImMerkleRoot = genesis.calc_immutable_merkle_root()
        genesis.solve(self.signblockprivkey)

        writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis)
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis block', match=ErrorMatch.PARTIAL_REGEX)

        self.log.info("Test incorrect genesis block - No proof")
        genesis = createIncorectGenesisBlock(genesis_coinbase, self.signblockprivkey, self.signblockpubkey)
        genesis.proof.clear()

        writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis)
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis block', match=ErrorMatch.PARTIAL_REGEX)

        self.log.info("Test incorrect genesis block - Insufficient Proof")
        genesis = createIncorectGenesisBlock(genesis_coinbase, self.signblockprivkey, self.signblockpubkey)
        genesis.proof = genesis.proof[:-1]

        writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis)
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis block', match=ErrorMatch.PARTIAL_REGEX)

        self.log.info("Test incorrect genesis block - Incorrect xfieldType")
        genesis_coinbase = createGenesisCoinbase(self.signblockpubkey)
        genesis = CBlock()
        genesis.nTime = int(time.time() + 600)
        genesis.hashPrevBlock = 0
        genesis.vtx.append(genesis_coinbase)
        genesis.hashMerkleRoot = genesis.calc_merkle_root()
        genesis.hashImMerkleRoot = genesis.calc_immutable_merkle_root()
        genesis.xfieldType = 0
        genesis.xfield = hex_str_to_bytes(self.signblockpubkey)
        genesis.solve(self.signblockprivkey)

        writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis)
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid xfieldType in genesis block', match=ErrorMatch.PARTIAL_REGEX)

        self.log.info("Test incorrect genesis block - Incorrect xfield")
        genesis_coinbase = createGenesisCoinbase(self.signblockpubkey)
        genesis = CBlock()
        genesis.nTime = int(time.time() + 600)
        genesis.hashPrevBlock = 0
        genesis.vtx.append(genesis_coinbase)
        genesis.hashMerkleRoot = genesis.calc_merkle_root()
        genesis.hashImMerkleRoot = genesis.calc_immutable_merkle_root()
        genesis.xfieldType = 1
        genesis.xfield = hex_str_to_bytes(self.signblockpubkey[:32])
        genesis.solve(self.signblockprivkey)

        writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis)
        self.nodes[0].assert_start_raises_init_error([], 'Aggregate Public Key for Signed Block is invalid', match=ErrorMatch.PARTIAL_REGEX)

        self.log.info("Test incorrect genesis block - No hashMerkleRoot")
        genesis_coinbase = createGenesisCoinbase(self.signblockpubkey)
        genesis = CBlock()
        genesis.nTime = int(time.time() + 600)
        genesis.hashPrevBlock = 0
        genesis.vtx.append(genesis_coinbase)
        genesis.xfieldType = 1
        genesis.xfield = hex_str_to_bytes(self.signblockpubkey)
        # not populating hashMerkleRoot and hashImMerkleRoot
        genesis.solve(self.signblockprivkey)

        writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis)
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid MerkleRoot in genesis block', match=ErrorMatch.PARTIAL_REGEX)

        self.log.info("Test incorrect genesis block - No hashImMerkleRoot")
        genesis_coinbase = createGenesisCoinbase(self.signblockpubkey)
        genesis = CBlock()
        genesis.nTime = int(time.time() + 600)
        genesis.hashPrevBlock = 0
        genesis.vtx.append(genesis_coinbase)
        genesis.hashMerkleRoot = genesis.calc_merkle_root()
        genesis.xfieldType = 1
        genesis.xfield = hex_str_to_bytes(self.signblockpubkey)
        # not populating hashImMerkleRoot
        genesis.solve(self.signblockprivkey)

        writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis)
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid MerkleRoot in genesis block', match=ErrorMatch.PARTIAL_REGEX)

        self.log.info("Phase 2: Tests using genesis.dat file")
        self.log.info("Test new genesis file")
        self.genesisBlock = None
        self.writeGenesisBlockToFile(self.nodes[0].datadir, nTime=int(time.time()))
        #different genesis file
        self.nodes[0].assert_start_raises_init_error([], 'Error: Incorrect or no genesis block found.', match=ErrorMatch.PARTIAL_REGEX)

        datadir = self.nodes[0].datadir
        genesisFile = os.path.join(datadir, "genesis.dat")

        self.log.info("Test incorrect genesis file - append 2 bytes")
        self.writeGenesisBlockToFile(self.nodes[0].datadir)
        with open(genesisFile, 'a', encoding='utf8') as f:
            f.write("abcd")
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis file', match=ErrorMatch.PARTIAL_REGEX)
        os.remove(genesisFile)

        self.log.info("Test incorrect genesis file - append many bytes")
        self.writeGenesisBlockToFile(self.nodes[0].datadir)
        with open(genesisFile, 'a', encoding='utf8') as f:
            s = "".join([str(i) for i in range(0,16) for j in range(0, 100)])
            f.write(s)
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis file', match=ErrorMatch.PARTIAL_REGEX)
        os.remove(genesisFile)

        self.log.info("Test incorrect genesis file - replace 2 bytes")
        self.writeGenesisBlockToFile(self.nodes[0].datadir)
        with open(genesisFile, 'r+', encoding='utf8') as f:
            content = f.readline()
            clen = len(content)
            content = content[:500] + "0000" + content[504:]
            assert(len(content) == clen)
            f.write(content)
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis file', match=ErrorMatch.PARTIAL_REGEX)
        os.remove(genesisFile)

        self.log.info("Test incorrect genesis file - insert 2 bytes")
        content = ""
        self.writeGenesisBlockToFile(self.nodes[0].datadir)
        with open(genesisFile, 'r+', encoding='utf8') as f:
            content = f.readline()
            clen = len(content)
            content = content[:550] + "1111" + content[550:]
            assert(len(content) == clen + 4)
            f.write(content)
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis file', match=ErrorMatch.PARTIAL_REGEX)
        os.remove(genesisFile)

        self.log.info("Test incorrect genesis file - remove 2 bytes")
        content = ""
        self.writeGenesisBlockToFile(self.nodes[0].datadir)
        with open(genesisFile, 'r+', encoding='utf8') as f:
            content = f.readline()
            clen = len(content)
            content = content[:100] + content[104:]
            assert(len(content) == clen - 4)
            f.write(content)
        self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis file', match=ErrorMatch.PARTIAL_REGEX)
        os.remove(genesisFile)

        self.log.info("Test incorrect genesis file - truncate file")
        self.writeGenesisBlockToFile(self.nodes[0].datadir)
        with open(genesisFile, 'r+', encoding='utf8') as f:
            f.truncate(500)
        self.nodes[0].assert_start_raises_init_error([], 'CDataStream::read().*end of data', match=ErrorMatch.PARTIAL_REGEX)

        self.log.info("Phase 3: Edit genesis file after sarting the blockchain")
        self.stop_node(0)
        shutil.rmtree(self.nodes[0].datadir)
        initialize_datadir(self.options.tmpdir, 0)

        self.log.info("Starting node")
        self.writeGenesisBlockToFile(self.nodes[0].datadir)
        self.start_node(0)
        self.nodes[0].add_p2p_connection(P2PInterface())

        self.log.info("Generating 10 blocks")
        blocks = self.nodes[0].generate(10, self.signblockprivkey_wif)
        self.sync_all([self.nodes[0:1]])
        assert_equal(self.nodes[0].getbestblockhash(), blocks[-1])
        self.stop_node(0)
        shutil.copytree(self.nodes[0].datadir, os.path.join(self.options.tmpdir, "backup")) 

        self.log.info("Creating corrupt genesis file")
        with open(genesisFile, 'r+', encoding='utf8') as f:
            content = f.readline()
            clen = len(content)
            content = content[:500] + "0000" + content[504:]
            assert(len(content) == clen)
            f.write(content)
        self.nodes[0].assert_start_raises_init_error([])

        self.log.info("Starting node again")
        self.genesisBlock = None
        self.writeGenesisBlockToFile(self.nodes[0].datadir)
        self.nodes[0].assert_start_raises_init_error([], 'Error: Incorrect or no genesis block found.', match=ErrorMatch.PARTIAL_REGEX)

        self.log.info("Recovering original blockchain")
        shutil.rmtree(self.nodes[0].datadir)
        shutil.copytree(os.path.join(self.options.tmpdir, "backup"), self.nodes[0].datadir)
        self.start_node(0)
        self.nodes[0].add_p2p_connection(P2PInterface())
        self.sync_all([self.nodes[0:1]])

        assert_equal(self.nodes[0].getbestblockhash(), blocks[-1])
        self.log.info("Blockchain intact!")
    def run_test(self):
        node = self.nodes[0]
        node.add_p2p_connection(P2PDataStore())

        # OP_TRUE in P2SH
        address = node.decodescript('51')['p2sh']
        # burn script
        p2sh_script = CScript([OP_HASH160, bytes(20), OP_EQUAL])

        prevblockhash = node.getbestblockhash()

        coinbase = create_coinbase(201)
        coinbase.vout[1].scriptPubKey = p2sh_script
        coinbase.rehash()
        sample_block = CBlock()
        sample_block.vtx = [coinbase]
        sample_block.hashPrevBlock = int(prevblockhash, 16)
        sample_block.nBits = 0x207fffff
        sample_block.nTime = 1600000036
        sample_block.nReserved = 0
        sample_block.nHeaderVersion = 1
        sample_block.nHeight = 201
        sample_block.hashEpochBlock = 0
        sample_block.hashMerkleRoot = sample_block.calc_merkle_root()
        sample_block.hashExtendedMetadata = hash256_int(b'\0')
        sample_block.update_size()

        # Using legacy hashing algo
        block = copy.deepcopy(sample_block)
        target = uint256_from_compact(block.nBits)
        block.rehash()
        while hash256_int(
                block.serialize()) > target or block.sha256 <= target:
            block.nNonce += 1
            block.rehash()
        self.fail_block(block, force_send=True, reject_reason='high-hash')
        del block

        # Claimed size already excessive (before doing any other checks)
        block = copy.deepcopy(sample_block)
        block.nSize = 32_000_001
        block.solve()
        self.fail_block(block, force_send=True, reject_reason='bad-blk-size')
        del block

        # Incorrect nBits
        block = copy.deepcopy(sample_block)
        block.nBits = 0x207ffffe
        block.solve()
        self.fail_block(block, force_send=True, reject_reason='bad-diffbits')
        del block

        # Block too old
        block = copy.deepcopy(sample_block)
        block.nTime = 1600000035
        block.solve()
        self.fail_block(block, force_send=True, reject_reason='time-too-old')
        del block

        # nReserved must be 0
        block = copy.deepcopy(sample_block)
        block.nReserved = 0x0100
        block.solve()
        self.fail_block(block,
                        force_send=True,
                        reject_reason='bad-blk-reserved')
        del block

        # nHeaderVersion must be 1
        block = copy.deepcopy(sample_block)
        block.nHeaderVersion = 0
        block.solve()
        self.fail_block(block,
                        force_send=True,
                        reject_reason='bad-blk-version')
        block.nHeaderVersion = 2
        block.solve()
        self.fail_block(block,
                        force_send=True,
                        reject_reason='bad-blk-version')
        del block

        # Incorrect claimed height
        block = copy.deepcopy(sample_block)
        block.nHeight = 200
        block.solve()
        self.fail_block(block, force_send=True, reject_reason='bad-blk-height')
        block.nHeight = 202
        block.solve()
        self.fail_block(block, force_send=True, reject_reason='bad-blk-height')
        del block

        # Invalid epoch block
        block = copy.deepcopy(sample_block)
        block.hashEpochBlock = 1
        block.solve()
        self.fail_block(block, force_send=True, reject_reason='bad-blk-epoch')
        del block

        # Time too far into the future
        block = copy.deepcopy(sample_block)
        block.nTime = int(time.time()) + 2 * 60 * 60 + 1
        block.solve()
        self.fail_block(block, force_send=True, reject_reason='time-too-new')
        del block

        # Invalid merkle root
        block = copy.deepcopy(sample_block)
        block.hashMerkleRoot = 0
        block.solve()
        self.fail_block(block, reject_reason='bad-txnmrklroot')
        del block

        # Invalid metadata hash
        block = copy.deepcopy(sample_block)
        block.hashExtendedMetadata = 0
        block.solve()
        self.fail_block(block, reject_reason='bad-metadata-hash')
        del block

        # Non-empty metadata
        block = copy.deepcopy(sample_block)
        block.vMetadata.append(CBlockMetadataField(0, b''))
        block.rehash_extended_metadata()
        block.solve()
        self.fail_block(block, reject_reason='bad-metadata')
        del block

        # Claimed nSize doesn't match actual size
        block = copy.deepcopy(sample_block)
        block.nSize = 1
        block.solve()
        self.fail_block(block, reject_reason='blk-size-mismatch')
        del block

        block_template = node.getblocktemplate()
        assert_equal(block_template.pop('capabilities'), ['proposal'])
        assert_equal(block_template.pop('version'), 1)
        assert_equal(block_template.pop('previousblockhash'), prevblockhash)
        assert_equal(
            block_template.pop('epochblockhash'),
            '0000000000000000000000000000000000000000000000000000000000000000')
        assert_equal(
            block_template.pop('extendedmetadatahash'),
            '9a538906e6466ebd2617d321f71bc94e56056ce213d366773699e28158e00614')
        assert_equal(block_template.pop('transactions'), [])
        assert_equal(block_template.pop('coinbaseaux'), {})
        assert_equal(block_template.pop('coinbasevalue'), int(SUBSIDY * COIN))
        assert_equal(block_template.pop('coinbasetxn'),
                     {'minerfund': {
                         'outputs': []
                     }})
        block_template.pop('longpollid')
        assert_equal(
            block_template.pop('target'),
            '7fffff0000000000000000000000000000000000000000000000000000000000')
        assert_equal(block_template.pop('mintime'), 1600000036)
        assert_equal(block_template.pop('mutable'),
                     ['time', 'transactions', 'prevblock'])
        assert_equal(block_template.pop('noncerange'), '00000000ffffffff')
        assert_equal(block_template.pop('sigoplimit'), 226950)
        assert_equal(block_template.pop('sizelimit'), 32000000)
        block_template.pop('curtime')
        assert_equal(block_template.pop('bits'), '207fffff')
        assert_equal(block_template.pop('height'), 201)
        assert_equal(block_template, {})

        # Check epoch hash is 0 for the first 20 blocks
        for height in range(201, 221):
            block_template = node.getblocktemplate()
            assert_equal(block_template['epochblockhash'], '00' * 32)
            block = self.block_from_template(block_template)
            block.hashEpochBlock = 0
            prepare_block(block)
            node.p2p.send_blocks_and_test([block], node)
            del block

        # Move to end of epoch
        node.generatetoaddress(4819, address)
        assert_equal(node.getblockcount(), 5039)

        epochblockhash = node.getbestblockhash()
        epochblock = node.getblock(epochblockhash)
        assert_equal(epochblock['epochblockhash'], '00' * 32)

        # getblocktemplate gives us current tip as epoch block hash
        block_template = node.getblocktemplate()
        assert_equal(block_template['epochblockhash'], epochblockhash)
        assert_equal(block_template['previousblockhash'], epochblockhash)

        # Using 0 as epoch block hash is now invalid
        block = self.block_from_template(block_template)
        block.hashEpochBlock = 0
        prepare_block(block)
        self.fail_block(block, force_send=True, reject_reason='bad-blk-epoch')

        # Setting current tip as epoch hash makes the block valid
        block.hashEpochBlock = int(epochblockhash, 16)
        prepare_block(block)
        node.p2p.send_blocks_and_test([block], node)
        del block

        # getblocktemplate still gives us the same epoch block hash
        block_template = node.getblocktemplate()
        assert_equal(block_template['epochblockhash'], epochblockhash)
        assert_equal(block_template['previousblockhash'],
                     node.getbestblockhash())

        # Block after that still requires epoch block hash
        block = self.block_from_template(block_template)
        block.hashEpochBlock = int(epochblockhash, 16)
        prepare_block(block)
        node.p2p.send_blocks_and_test([block], node)
        del block

        # Test 48-bit nTime
        node.setmocktime(
            2**32)  # smallest number that does not fit in 32-bit number
        block_template = node.getblocktemplate()
        assert_equal(block_template['curtime'], 2**32)
        block = self.block_from_template(block_template)
        block.nTime = 2**32
        prepare_block(block)
        node.p2p.send_blocks_and_test([block], node)
        del block

        node.setmocktime(2**48 - 1)  # biggest possible 48-bit number
        block_template = node.getblocktemplate()
        assert_equal(block_template['curtime'], 2**48 - 1)
        block = self.block_from_template(block_template)
        block.nTime = 2**48 - 1
        prepare_block(block)
        node.p2p.send_blocks_and_test([block], node)
        del block
Exemplo n.º 11
0
 def update_block(block: CBlock,
                  new_transactions: Sequence[CTransaction]):
     block.vtx.extend(new_transactions)
     make_conform_to_ctor(block)
     block.hashMerkleRoot = block.calc_merkle_root()
     block.solve()