예제 #1
0
def test_invalid_schnorr():
    sighash = bytes.fromhex("00" * 32)
    sig = ssa.serialize(*ssa._sign(sighash, 1))
    pubkey = bytes_from_point(mult(1))
    pubkey_hash = hash256(pubkey)
    script = Script([
        [0x00, 0x00, pubkey],
        [0x01, 0x00, sig],
        [0x02, 0x00, pubkey_hash],  # push pubkey_hash
        [0x03, 0x02, b"\x00"],  # hash of pub key from unlocking script
        [0xFF, 0x01, b"\x03\x02"],  # check equality
        [0xFF, 0x04, b"\xff"],  # exit if not equal
        [0xFF, 0x03, b"\x00\x01"],  # schnorr verify
        [0xFF, 0x04, b"\xff"],
    ]  # exit if not equal])  # push signature
                    )
    assert script.execute(memory={0x100: sighash})
예제 #2
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()
예제 #3
0
def lock_p2pk(pubkey):
    return Script(
        [
            [0x02, OP_PUSHDATA, bytes.fromhex(pubkey)],  # push pubkey
            [0xFF, OP_EQUAL, b"\x02\x00"],  # check equality
            [0xFF, OP_VERIFY, b"\xff"],  # exit if not equal
            [0xFF, OP_SHNORR_CHECKSIG, b"\x00\x01"],  # schnorr verify
            [0xFF, OP_VERIFY, b"\xff"],  # exit if not equal
        ]
    )
예제 #4
0
def lock_p2pkh(pubkey_hash):
    return Script(
        [
            [0x02, OP_PUSHDATA, bytes.fromhex(pubkey_hash)],  # push pubkey_hash
            [0x03, OP_HASH256, b"\x00"],  # hash of pub key from unlocking script
            [0xFF, OP_EQUAL, b"\x03\x02"],  # check equality
            [0xFF, OP_VERIFY, b"\xff"],  # exit if not equal
            [0xFF, OP_SHNORR_CHECKSIG, b"\x00\x01"],  # schnorr verify
            [0xFF, OP_VERIFY, b"\xff"],  # exit if not equal
        ]
    )
예제 #5
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()
예제 #6
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()
예제 #7
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()
예제 #8
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()
예제 #9
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()
예제 #10
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()
예제 #11
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()
예제 #12
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()
예제 #13
0
class TxOut:
    value: int = 0
    locking_script: Script = Script()

    def serialize(self):
        out = self.value.to_bytes(8, "big")
        script_bytes = self.locking_script.serialize()
        out += len(script_bytes).to_bytes(2, "big") + script_bytes
        return out

    @classmethod
    def deserialize(cls, data):
        out = int.from_bytes(data[:8], "big")
        script_len = int.from_bytes(data[8:10], "big")
        locking_script = Script.deserialize(data[10:10 + script_len])
        return TxOut(out, locking_script)

    def is_valid(self):
        if not self.locking_script.is_valid():
            return False
        if self.value < 0 or self.value >= 256**8:
            return False
        return True
예제 #14
0
def test_double_spend():
    coinbase_1 = Tx(
        [TxIn(OutPoint("00" * 32, 0), Script.from_hex("00030000aa"))],
        [TxOut(10**10, Script())],
    )
    tx_1 = Tx(
        [TxIn(OutPoint("aa" * 32, 0), Script.from_hex("00030000bb"))],
        [TxOut(10**10, Script())],
    )
    tx_2 = Tx(
        [TxIn(OutPoint("aa" * 32, 0), Script.from_hex("00030000cc"))],
        [TxOut(10**10, Script())],
    )
    header = BlockHeader()
    block = Block(header, [coinbase_1, tx_1, tx_2])
    header.merkle_root = generate_merkle_root(block.transactions)
    header.previous_pow = "00" * 32
    assert not block.is_valid()
예제 #15
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()
예제 #16
0
 def deserialize(cls, data):
     prevout = OutPoint.deserialize(data)
     script_len = int.from_bytes(data[34:36], "big")
     unlocking_script = Script.deserialize(data[36:36 + script_len])
     return TxIn(prevout, unlocking_script)
예제 #17
0
def test_coinbase():

    tx_in = TxIn(OutPoint("00" * 32, 0), Script())
    assert tx_in.is_coinbase()
예제 #18
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()
예제 #19
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()
예제 #20
0
def test_invalid_outpoint_index():
    tx_in = TxIn(OutPoint("00" * 32, -1), Script())
    assert not tx_in.is_valid()

    tx_in = TxIn(OutPoint("00" * 32, 0xFFFF + 1), Script())
    assert not tx_in.is_valid()
예제 #21
0
def test_invalid_output_value():
    tx_out = TxOut(-1, Script())
    assert not tx_out.is_valid()

    tx_out = TxOut(0xFFFFFFFFFFFFFFFF + 1, Script())
    assert not tx_out.is_valid()
예제 #22
0
def unlock_p2pkh(sighash, prvkey):
    sig = ssa.serialize(*ssa._sign(sighash, prvkey))
    pubkey = bytes_from_point(mult(prvkey))
    return Script(
        [[0x00, OP_PUSHDATA, pubkey], [0x01, OP_PUSHDATA, sig]]
    )  # push signature
예제 #23
0
 def deserialize(cls, data):
     out = int.from_bytes(data[:8], "big")
     script_len = int.from_bytes(data[8:10], "big")
     locking_script = Script.deserialize(data[10:10 + script_len])
     return TxOut(out, locking_script)
예제 #24
0
 def get_utxo(self, id):
     self.cursor.execute("SELECT * FROM utxo WHERE id = ?", (id, ))
     utxo = self.cursor.fetchall()
     return TxOut(utxo[0][1], Script.deserialize(
         utxo[0][2])) if utxo else None
예제 #25
0
def test_serialization():
    assert Script() == Script.from_hex("")
    assert Script.from_hex(Script().hex) == Script()