Ejemplo n.º 1
0
def test_flow_9():
    """
    This MUST fail
    The transaction tries to spend an unkown utxo
    """
    coinbase_0 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(10**10, Script())],
    )
    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)

    blockchain = Blockchain()
    blockchain._add_block(origin)

    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000bb"))],
        [TxOut(10**10, Script())],
    )
    # tries to spend the coinbase output at index 1, which doesn't exist
    tx = Tx([TxIn(OutPoint(coinbase_0.txid, 1), Script())],
            [TxOut(10**5, Script())])
    block_1_transactions = [coinbase_1, tx]
    block_1_header = BlockHeader(origin.header.pow,
                                 generate_merkle_root(block_1_transactions), 0)
    block_1 = Block(block_1_header, block_1_transactions)
    with pytest.raises(Exception):
        blockchain._add_block(block_1)

    reset_blockchain()
Ejemplo n.º 2
0
def test_flow_13():

    coinbase_0 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])

    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)

    blockchain = Blockchain()
    blockchain._add_block(origin)
    assert blockchain.last_block_pow == origin.header.pow

    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(10**10, Script())],
    )
    block_1_header = BlockHeader("ff" * 32, generate_merkle_root([coinbase_1]),
                                 0)
    block_1 = Block(block_1_header, [coinbase_1])
    with pytest.raises(Exception):
        blockchain._add_block(block_1)

    reset_blockchain()
Ejemplo n.º 3
0
def test_flow_1():
    """
    This MUST NOT fail
    We simply add two blocks, each one with only the coinbase transaction
    """

    coinbase_0 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(10**10, Script())],
    )

    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)

    blockchain = Blockchain()
    blockchain._add_block(origin)
    assert blockchain.last_block_pow == origin.header.pow

    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000bb"))],
        [TxOut(10**10, Script())],
    )
    block_1_header = BlockHeader(origin.header.pow,
                                 generate_merkle_root([coinbase_1]), 0)
    block_1 = Block(block_1_header, [coinbase_1])
    blockchain._add_block(block_1)
    assert blockchain.last_block_pow == block_1.header.pow

    reset_blockchain()
Ejemplo n.º 4
0
def test_flow_6():
    """
    This MUST fail
    The block 1 coinbase collects more fees than it should
    """
    coinbase_0 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])
    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)

    blockchain = Blockchain()
    blockchain._add_block(origin)

    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(2 * 10**10 - 10**5 + 1, Script())],
    )
    tx = Tx([TxIn(OutPoint(coinbase_0.txid, 0), Script())],
            [TxOut(10**5, Script())])
    block_1_transactions = [coinbase_1, tx]
    block_1_header = BlockHeader(origin.header.pow,
                                 generate_merkle_root(block_1_transactions), 0)
    block_1 = Block(block_1_header, block_1_transactions)
    with pytest.raises(Exception):
        blockchain._add_block(block_1)

    reset_blockchain()
Ejemplo n.º 5
0
def test_flow_3():
    """
    This MUST NOT fail
    We add two blocks to the blockchain, the second one with a transaction which spends
    the coinbase 0 output
    """
    coinbase_0 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(10**10, Script())],
    )
    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)

    blockchain = Blockchain()
    blockchain._add_block(origin)

    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000bb"))],
        [TxOut(10**10, Script())],
    )
    tx = Tx([TxIn(OutPoint(coinbase_0.txid, 0), Script())],
            [TxOut(10**5, Script())])
    block_1_transactions = [coinbase_1, tx]
    block_1_header = BlockHeader(origin.header.pow,
                                 generate_merkle_root(block_1_transactions), 0)
    block_1 = Block(block_1_header, block_1_transactions)
    blockchain._add_block(block_1)

    reset_blockchain()
Ejemplo n.º 6
0
def test_flow_4():
    """
    This MUST fail
    The second block transaction tries to spend more than its input
    """
    coinbase_0 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])
    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)

    blockchain = Blockchain()
    blockchain._add_block(origin)

    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(10**10, Script())],
    )
    # overspends
    tx = Tx([TxIn(OutPoint(coinbase_0.txid, 0), Script())],
            [TxOut(10**10 + 1, Script())])
    block_1_transactions = [coinbase_1, tx]
    block_1_header = BlockHeader(origin.header.pow,
                                 generate_merkle_root(block_1_transactions), 0)
    block_1 = Block(block_1_header, block_1_transactions)
    with pytest.raises(Exception):
        blockchain._add_block(block_1)

    reset_blockchain()
Ejemplo n.º 7
0
def test_flow_10():
    """
    This MUST fail
    Test of block reverse
    """
    coinbase_0 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])
    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)

    blockchain = Blockchain()
    rev_block_0 = blockchain._add_block(origin)

    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(2 * 10**10 - 10**5, Script())],
    )
    tx = Tx([TxIn(OutPoint(coinbase_0.txid, 0), Script())],
            [TxOut(10**5, Script())])
    block_1_transactions = [coinbase_1, tx]
    block_1_header = BlockHeader(origin.header.pow,
                                 generate_merkle_root(block_1_transactions), 0)
    block_1 = Block(block_1_header, block_1_transactions)
    blockchain._add_block(block_1)

    with pytest.raises(Exception):
        blockchain._reverse_block(rev_block_0)

    reset_blockchain()
Ejemplo n.º 8
0
def test_flow_7():
    """
    This MUST fail
    The two coinbases have the same txid
    """

    coinbase_0 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])

    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)

    blockchain = Blockchain()
    blockchain._add_block(origin)
    assert blockchain.last_block_pow == origin.header.pow

    coinbase_1 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])
    block_1_header = BlockHeader(origin.header.pow,
                                 generate_merkle_root([coinbase_1]), 0)
    block_1 = Block(block_1_header, [coinbase_1])
    with pytest.raises(Exception):
        blockchain._add_block(block_1)

    reset_blockchain()
Ejemplo n.º 9
0
def test_invalid_coinbase():
    tx = Tx(
        [
            TxIn(OutPoint("00" * 32, 0), Script()),
            TxIn(OutPoint("00" * 32, 0), Script()),
        ],
        [TxOut(1, Script())],
    )
    assert not tx.is_valid()
Ejemplo n.º 10
0
def test_double_coinbase():
    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(10**10, Script())],
    )
    coinbase_2 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000bb"))],
        [TxOut(10**10, Script())],
    )
    header = BlockHeader()
    block = Block(header, [coinbase_1, coinbase_2])
    header.merkle_root = generate_merkle_root(block.transactions)
    header.previous_pow = "00" * 32
    assert not block.is_valid()
Ejemplo n.º 11
0
def test_validation_3():

    tx_in = TxIn(OutPoint("ff" * 32, 256**2 - 1), Script())
    tx_out = TxOut(10, Script())
    tx_1 = Tx([tx_in], [tx_out])
    tx_in_2 = TxIn(OutPoint("ff" * 32, 256**2 - 1), Script())
    tx_out_2 = TxOut(10, Script())
    tx_2 = Tx([tx_in_2], [tx_out_2])
    header = BlockHeader()
    block = Block(header, [tx_1, tx_2])

    header.merkle_root = generate_merkle_root(block.transactions)
    header.previous_pow = "00" * 32
    assert header.is_valid()
    assert not block.is_valid()  # two coinbases
Ejemplo n.º 12
0
def test_flow_14():
    """
    This MUST NOT fail
    """

    blockchain = Blockchain()

    coinbase_0 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])
    origin_header = BlockHeader("00" * 32, generate_merkle_root([coinbase_0]),
                                0)
    origin = Block(origin_header, [coinbase_0])

    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(5 * 10**9, Script()),
         TxOut(5 * 10**9, Script())],
    )
    block_1_header = BlockHeader(origin.header.pow,
                                 generate_merkle_root([coinbase_1]), 0)
    block_1 = Block(block_1_header, [coinbase_1])

    coinbase_2 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000bb"))],
        [TxOut(10**10, Script())],
    )
    block_2_header = BlockHeader(block_1.header.pow,
                                 generate_merkle_root([coinbase_2]), 0)
    block_2 = Block(block_2_header, [coinbase_2])

    # we try adding the origin again, no problem, it is skipped
    assert blockchain.add_blocks([origin, block_1, block_2])
    # invalid coinbase
    coinbase_3 = Tx(
        [
            TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa")),
            TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000bb")),
        ],
        [TxOut(10**10, Script())],
    )
    block_3_header = BlockHeader(block_1.header.pow,
                                 generate_merkle_root([coinbase_3]), 0)
    block_3 = Block(block_3_header, [coinbase_3])
    assert not blockchain.add_blocks([origin, block_1, block_2, block_3])

    reset_blockchain()
Ejemplo n.º 13
0
def test_valid_serialization():

    tx_in = TxIn(OutPoint("ff" * 32, 0), Script())
    tx_out = TxOut(10, Script())
    tx = Tx([tx_in], [tx_out])
    assert tx == Tx.deserialize(tx.serialize())

    tx_in_2 = TxIn(OutPoint("ff" * 32, 1), Script())
    tx = Tx([tx_in, tx_in_2], [tx_out])
    assert tx == Tx.deserialize(tx.serialize())
Ejemplo n.º 14
0
def test_valid_serialization_1():

    tx_in = TxIn(OutPoint("ff" * 32, 0), Script())
    tx_out = TxOut(10, Script())
    tx_1 = Tx([tx_in], [tx_out])
    header = BlockHeader()
    block = Block(header, [tx_1])
    header.merkle_root = generate_merkle_root(block.transactions)
    header.previous_pow = "00" * 32
    assert Block.deserialize(block.serialize()) == block
Ejemplo n.º 15
0
def test_invalid_merkleroot():

    tx_in = TxIn(OutPoint("ff" * 32, 0), Script())
    tx_out = TxOut(10, Script())
    tx_1 = Tx([tx_in], [tx_out])
    header = BlockHeader()
    block = Block(header, [tx_1])
    header.merkle_root = "00" * 32
    header.previous_pow = "00" * 32
    assert not block.is_valid()
Ejemplo n.º 16
0
def test_invalid_tx():
    utxo_set = UTXOSet()
    tx = Tx(
        [
            TxIn(OutPoint("00" * 32, 0), Script()),
            TxIn(OutPoint("00" * 32, 0), Script()),
        ],
        [TxOut(10**10, Script())],
    )
    assert not utxo_set.validate_transaction(tx)
 def deserialize(cls, data):
     header = BlockHeader.deserialize(data[:76])
     transactions = []
     transaction_count = int.from_bytes(data[76:78], "big")
     data = data[78:]
     for i in range(transaction_count):
         tx_size = int.from_bytes(data[:2], "big")
         transactions.append(Tx.deserialize(data[2:2 + tx_size]))
         data = data[2 + tx_size:]
     return Block(header, transactions)
Ejemplo n.º 18
0
def test_mining():
    target = 16**4
    coinbase_0 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])

    transactions = [coinbase_0]
    header = BlockHeader("00" * 32, generate_merkle_root(transactions), 0)

    nonce = calculate_nonce(header, target)
    header.nonce = nonce
    assert work_from_chain([header.pow]) > target
Ejemplo n.º 19
0
def test_flow_8():
    """
    This MUST NOT fail
    Test of block reverse
    """
    coinbase_0 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])
    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)

    blockchain = Blockchain()
    rev_origin = blockchain._add_block(origin)

    old_utxo_list = blockchain.main_utxo_set.get_utxo_list()

    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(2 * 10**10 - 10**5, Script())],
    )
    tx = Tx([TxIn(OutPoint(coinbase_0.txid, 0), Script())],
            [TxOut(10**5, Script())])
    block_1_transactions = [coinbase_1, tx]
    block_1_header = BlockHeader(origin.header.pow,
                                 generate_merkle_root(block_1_transactions), 0)
    block_1 = Block(block_1_header, block_1_transactions)
    rev_block = blockchain._add_block(block_1)

    assert not blockchain.main_utxo_set.get_utxo_list() == old_utxo_list
    blockchain._reverse_block(rev_block)
    assert blockchain.main_utxo_set.get_utxo_list() == old_utxo_list

    with pytest.raises(Exception):
        blockchain._reverse_block(rev_block)

    blockchain._reverse_block(rev_origin)
    assert blockchain.main_utxo_set.get_utxo_list() == []

    reset_blockchain()
Ejemplo n.º 20
0
def test_validation_2():

    tx_in = TxIn(OutPoint("00" * 32, 0), Script())
    tx_out = TxOut(10**10, Script())
    tx_1 = Tx([tx_in], [tx_out])
    header = BlockHeader()
    block = Block(header, [tx_1])
    assert not block.is_valid()

    header.merkle_root = generate_merkle_root(block.transactions)
    header.previous_pow = "00" * 32
    assert header.is_valid()
    assert block.is_valid()  # has a coinbase tx
Ejemplo n.º 21
0
def test_flow_16():
    """
    This MUST NOT fail
    """

    blockchain = Blockchain()

    coinbase_0 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])
    coinbase_0.outputs[0].locking_script = lock_p2pkh(
        pubkey_hash_from_prvkey(1))
    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)
    assert blockchain.add_blocks([origin])

    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script())],
        [TxOut(5 * 10**9, Script()),
         TxOut(5 * 10**9, Script())],
    )
    tx = Tx(
        [TxIn(OutPoint(coinbase_0.txid, 0), Script())],
        [TxOut(10**10 - 100, Script()),
         TxOut(50, Script())],
    )

    tx.inputs[0].unlocking_script = unlock_p2pkh(sighash_all(tx), 1)

    block_1_transactions = [coinbase_1, tx]
    block_1_header = BlockHeader(origin.header.pow,
                                 generate_merkle_root(block_1_transactions), 0)
    block_1 = Block(block_1_header, block_1_transactions)

    assert blockchain.add_blocks([block_1])

    reset_blockchain()
Ejemplo n.º 22
0
def test_flow_2():
    """
    This MUST fail
    We add a block without a coinbase transaction
    """
    coinbase_0 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])
    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)

    blockchain = Blockchain()
    blockchain._add_block(origin)

    tx = Tx([TxIn(OutPoint(coinbase_0.txid, 0), Script())],
            [TxOut(10**10, Script())])
    block_1_header = BlockHeader(origin.header.pow, generate_merkle_root([tx]),
                                 0)
    block_1 = Block(block_1_header, [tx])
    with pytest.raises(Exception):  # missing coinbase
        blockchain._add_block(block_1)

    reset_blockchain()
Ejemplo n.º 23
0
def test_flow_11():
    """
    This MUST NOT fail
    """
    coinbase_0 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])
    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)

    blockchain = Blockchain()
    blockchain._add_block(origin)

    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(5 * 10**9, Script()),
         TxOut(5 * 10**9, Script())],
    )
    tx = Tx(
        [TxIn(OutPoint(coinbase_0.txid, 0), Script())],
        [TxOut(10**10 - 100, Script()),
         TxOut(50, Script())],
    )
    block_1_transactions = [coinbase_1, tx]
    block_1_header = BlockHeader(origin.header.pow,
                                 generate_merkle_root(block_1_transactions), 0)
    block_1 = Block(block_1_header, block_1_transactions)
    blockchain._add_block(block_1)

    coinbase_2 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000bb"))],
        [TxOut(10**10, Script())],
    )
    tx_2 = Tx([TxIn(OutPoint(tx.txid, 0), Script())],
              [TxOut(10**10 - 200, Script())])
    tx_3 = Tx(
        [
            TxIn(OutPoint(coinbase_1.txid, 0), Script()),
            TxIn(OutPoint(coinbase_1.txid, 1), Script()),
            TxIn(OutPoint(tx.txid, 1), Script()),
        ],
        [TxOut(10**10 + 50, Script())],
    )
    block_2_transactions = [coinbase_2, tx_2, tx_3]
    block_2_header = BlockHeader(block_1.header.pow,
                                 generate_merkle_root(block_2_transactions), 0)
    block_2 = Block(block_2_header, block_2_transactions)
    blockchain._add_block(block_2)

    reset_blockchain()
Ejemplo n.º 24
0
def test_validation():

    tx_in = TxIn(OutPoint("ff" * 32, 0), Script())
    assert tx_in.is_valid()

    tx_out = TxOut(10, Script())
    assert tx_out.is_valid()

    tx_in_valid = TxIn(OutPoint("ff" * 32, 0),
                       Script.from_hex("fffd" + "ff" * (256**2 - 3)))
    assert tx_in_valid.is_valid()

    tx_out_valid = TxOut(10, Script.from_hex("fffd" + "ff" * (256**2 - 3)))
    assert tx_out_valid.is_valid()

    tx_in_invalid = TxIn(OutPoint("ff" * 32, 0),
                         Script.from_hex("fffe" + "ff" * (256**2 - 2)))
    assert not tx_in_invalid.is_valid()

    tx_out_invalid = TxOut(10, Script.from_hex("fffe" + "ff" * (256**2 - 2)))
    assert not tx_out_invalid.is_valid()

    tx = Tx([tx_in_invalid], [tx_out_valid])
    assert not tx.is_valid()

    tx = Tx([tx_in_valid], [tx_out_invalid])
    assert not tx.is_valid()

    tx_in = TxIn(OutPoint("ff" * 32, 0), Script())
    tx_out = TxOut(10, Script())
    tx = Tx([tx_in], [tx_out])
    assert tx.is_valid()

    tx_in_2 = TxIn(OutPoint("ff" * 32, 0), Script())
    tx = Tx([tx_in, tx_in_2], [tx_out])
    assert not tx.is_valid()
Ejemplo n.º 25
0
def test_flow_12():
    """
    This MUST NOT fail
    """

    blockchain = Blockchain()

    coinbase_0 = Tx([TxIn(OutPoint("00" * 32, 0), Script())],
                    [TxOut(10**10, Script())])
    origin_transactions = [coinbase_0]
    origin_header = BlockHeader("00" * 32,
                                generate_merkle_root(origin_transactions), 0)
    origin = Block(origin_header, origin_transactions)
    blockchain._add_block(origin)

    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(5 * 10**9, Script()),
         TxOut(5 * 10**9, Script())],
    )
    tx = Tx(
        [TxIn(OutPoint(coinbase_0.txid, 0), Script())],
        [TxOut(10**10 - 100, Script()),
         TxOut(50, Script())],
    )
    block_1_transactions = [coinbase_1, tx]
    block_1_header = BlockHeader(origin.header.pow,
                                 generate_merkle_root(block_1_transactions), 0)
    block_1 = Block(block_1_header, block_1_transactions)

    coinbase_2 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000bb"))],
        [TxOut(10**10, Script())],
    )
    tx_2 = Tx([TxIn(OutPoint(tx.txid, 0), Script())],
              [TxOut(10**10 - 200, Script())])
    tx_3 = Tx(
        [
            TxIn(OutPoint(coinbase_1.txid, 0), Script()),
            TxIn(OutPoint(coinbase_1.txid, 1), Script()),
            TxIn(OutPoint(tx.txid, 1), Script()),
        ],
        [TxOut(10**10 + 50, Script())],
    )
    block_2_transactions = [coinbase_2, tx_2, tx_3]
    block_2_header = BlockHeader(block_1.header.pow,
                                 generate_merkle_root(block_2_transactions), 0)
    block_2 = Block(block_2_header, block_2_transactions)

    # we try adding the origin again, no problem, it is skipped
    assert blockchain.add_blocks([origin, block_1, block_2])

    coinbase_3 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000cc"))],
        [TxOut(10**10, Script())],
    )
    # tx_4 speds the same inputs as tx_2, but it is in a different chain so it is OK
    tx_4 = Tx(
        [TxIn(OutPoint(tx.txid, 0), Script.from_hex("00030000dd"))],
        [TxOut(10**10 - 200, Script())],
    )
    block_3_transactions = [coinbase_3, tx_4]
    block_3_header = BlockHeader(block_1.header.pow,
                                 generate_merkle_root(block_3_transactions), 0)
    block_3 = Block(block_3_header, block_3_transactions)
    block_3.header.nonce = calculate_nonce(block_3_header, 100)

    coinbase_4 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000ee"))],
        [TxOut(10**10, Script())],
    )
    block_4_transactions = [coinbase_4]
    # invalid reference, must be block_3 header, not block_2
    block_4_header = BlockHeader(block_2.header.pow,
                                 generate_merkle_root(block_4_transactions), 0)
    block_4 = Block(block_4_header, block_4_transactions)

    assert blockchain.add_blocks([block_3, block_4])
    assert blockchain.get_last_blocks()[0][0] == block_3.header.pow

    block_4.header = BlockHeader(block_3.header.pow,
                                 generate_merkle_root(block_4_transactions), 0)
    assert blockchain.add_blocks([block_3, block_4])
    assert blockchain.get_last_blocks()[0][0] == block_4.header.pow

    reset_blockchain()