Example #1
0
def test_tx_out() -> None:
    tx_out = TxOut(0, b"")
    assert tx_out.value == 0
    assert tx_out.script_pub_key.script == b""
    assert tx_out.script_pub_key.type == "unknown"
    assert tx_out.script_pub_key.network == "mainnet"
    assert tx_out.script_pub_key.addresses == [""]
    assert tx_out.nValue == tx_out.value
    assert tx_out.scriptPubKey == tx_out.script_pub_key.script
    assert tx_out == TxOut.parse(tx_out.serialize())
    assert tx_out == TxOut.from_dict(tx_out.to_dict())

    value = 3259343370
    script = "0020ed8e9600561000f722bd26e850be7d80f24d174fabeff98baef967325e2b5a86"
    tx_out = TxOut(value, script)
    assert tx_out.value == value
    assert tx_out.script_pub_key.script.hex() == script
    assert tx_out.script_pub_key.type == "p2wsh"
    assert tx_out.script_pub_key.network == "mainnet"
    addr = "bc1qak8fvqzkzqq0wg4aym59p0nasrey696040hlnzawl9nnyh3tt2rqzgmhmv"
    assert tx_out.script_pub_key.addresses == [addr]
    assert tx_out.nValue == tx_out.value
    assert tx_out.scriptPubKey == tx_out.script_pub_key.script
    assert tx_out == TxOut.parse(tx_out.serialize())
    assert tx_out == TxOut.from_dict(tx_out.to_dict())
    assert tx_out == TxOut.from_address(
        tx_out.value, tx_out.script_pub_key.addresses[0]
    )
Example #2
0
def test_valid_script_path() -> None:
    fname = "tapscript_test_vector.json"
    filename = path.join(path.dirname(__file__), "_data", fname)
    with open(filename, "r", encoding="ascii") as file_:
        data = json.load(file_)

    for x in data:

        prevouts = [TxOut.parse(prevout) for prevout in x["prevouts"]]
        index = x["index"]

        if not is_p2tr(prevouts[index].script_pub_key.script):
            continue

        script_sig = x["success"]["scriptSig"]
        assert not script_sig

        witness = Witness(x["success"]["witness"])
        if len(witness.stack) >= 2 and witness.stack[-1][0] == 0x50:
            witness.stack = witness.stack[:-1]

        # check script paths
        if len(witness.stack) < 2:
            continue

        Q = type_and_payload(prevouts[index].script_pub_key.script)[1]

        script = witness.stack[-2]
        control = witness.stack[-1]

        assert check_output_pubkey(Q, script, control)
Example #3
0
def _deserialize_witness_utxo(k: bytes, v: bytes) -> TxOut:
    "Return the dataclass element from its binary representation."

    if len(k) != 1:
        err_msg = f"invalid witness-utxo key length: {len(k)}"
        raise BTClibValueError(err_msg)
    return TxOut.parse(v)
Example #4
0
def test_valid_taproot_script_path() -> None:
    tx_data = "26dc279d02d8b1a203b653fc4e0f27f408432f3f540136d33f8f930eaeba655910095142980402000000fd697cd4eb5278f1e34545cd57b6670df806fa3a0a064fd8e385a19f1a53d9ce8d8971a30f02000000378d5fb502335dbe02000000001976a9140053a23441c8478caac4c6b769c51f8476cd4b4b88ac58020000000000001976a914f2aae94a43e0d173354201d7832b46c5269c8a2488ac4a08671e"
    prevouts_data = [
        "91ca4c010000000017a9145658b58602cdf7b7e962cfe44e024cb0e366f27087",
        "cb127401000000002251201ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc",
    ]
    witness_data = [
        "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602",
        "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba",
        "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac",
        "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c",
    ]

    tx = Tx.parse(tx_data)
    prevouts = [TxOut.parse(prevout) for prevout in prevouts_data]
    index = 1
    witness = Witness(witness_data)
    tx.vin[index].script_witness = witness

    sighash_type = 0  # all
    signature = witness.stack[0][:64]
    if len(witness.stack[0]) == 65:
        sighash_type = witness.stack[0][-1]
        assert sighash_type != 0

    msg_hash = sig_hash.from_tx(prevouts, tx, index, sighash_type)

    tapscript = parse(witness.stack[-2])
    pub_key = bytes.fromhex(str(tapscript[1]))

    ssa.assert_as_valid_(msg_hash, pub_key, signature)
Example #5
0
    def parse(cls: Type[_Tx],
              data: BinaryData,
              check_validity: bool = True) -> _Tx:
        "Return a Tx by parsing binary data."

        stream = bytesio_from_binarydata(data)

        # version is a signed int (int32_t, not uint32_t)
        version = int.from_bytes(stream.read(4),
                                 byteorder="little",
                                 signed=True)

        segwit = stream.read(2) == _SEGWIT_MARKER
        if not segwit:
            # Change stream position: seek to byte offset relative to position
            stream.seek(-2, SEEK_CUR)  # current position

        n = var_int.parse(stream)
        vin = [TxIn.parse(stream) for _ in range(n)]

        n = var_int.parse(stream)
        vout = [TxOut.parse(stream) for _ in range(n)]

        if segwit:
            for tx_in in vin:
                tx_in.script_witness = Witness.parse(stream, check_validity)

        lock_time = int.from_bytes(stream.read(4),
                                   byteorder="little",
                                   signed=False)

        return cls(version, lock_time, vin, vout, check_validity)
Example #6
0
def test_invalid_taproot_key_path() -> None:
    fname = "tapscript_test_vector.json"
    filename = path.join(path.dirname(__file__), "_data", fname)
    with open(filename, "r", encoding="ascii") as file_:
        data = json.load(file_)

    for x in filter(lambda x: "failure" in x.keys(), data):

        tx = Tx.parse(x["tx"])
        prevouts = [TxOut.parse(prevout) for prevout in x["prevouts"]]
        index = x["index"]

        if not is_p2tr(prevouts[index].script_pub_key.script):
            continue

        witness = Witness(x["failure"]["witness"])
        tx.vin[index].script_witness = witness

        # check only key paths
        if (len(witness.stack) == 1
                or len(witness.stack) == 2 and witness.stack[-1][0] == 0x50):

            with pytest.raises(
                (BTClibRuntimeError, BTClibValueError, AssertionError)):

                assert not x["failure"]["scriptSig"]

                sighash_type = 0  # all
                signature = witness.stack[0][:64]
                if len(witness.stack[0]) == 65:
                    sighash_type = witness.stack[0][-1]
                    if sighash_type == 0:
                        raise BTClibValueError(
                            "invalid sighash 0 in 65 bytes signature")

                msg_hash = sig_hash.from_tx(prevouts, tx, index, sighash_type)

                pub_key = type_and_payload(
                    prevouts[index].script_pub_key.script)[1]

                ssa.assert_as_valid_(msg_hash, pub_key, signature)
Example #7
0
def test_coinbase_block_1() -> None:

    coinbase_out = "00f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac"
    tx_out = TxOut.parse(coinbase_out)
    assert tx_out.serialize().hex() == coinbase_out

    coinbase_inp = (  # prev_out
        "0000000000000000000000000000000000000000000000000000000000000000ffffffff"
        "0704ffff001d0104"  # script_sig
        "ffffffff"  # sequence
    )
    tx_in = TxIn.parse(coinbase_inp)
    assert tx_in.serialize().hex() == coinbase_inp
    assert tx_in.prev_out.is_coinbase

    coinbase = "01000000" "01" + coinbase_inp + "01" + coinbase_out + "00000000"
    tx = Tx.parse(coinbase)
    assert tx.serialize(include_witness=True).hex() == coinbase
    assert tx == Tx.from_dict(tx.to_dict())

    assert tx.version == 1
    assert tx.lock_time == 0
    assert len(tx.vin) == 1
    assert len(tx.vout) == 1

    assert tx.vin[0].script_sig == tx_in.script_sig
    assert tx.vout[0].script_pub_key == tx_out.script_pub_key

    tx_id = "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098"
    assert tx.id.hex() == tx_id
    assert tx.id == tx.hash

    assert tx.size == 134
    assert tx.vsize == tx.size
    assert tx.weight == tx.size * 4
    assert not tx.is_segwit()
    assert not any(bool(w) for w in tx.vwitness)
    assert not any(bool(tx_in.script_witness) for tx_in in tx.vin)
    assert tx.is_coinbase()
Example #8
0
    def parse(cls: Type["Tx"],
              data: BinaryData,
              check_validity: bool = True) -> "Tx":
        "Return a Tx by parsing binary data."

        stream = bytesio_from_binarydata(data)

        # version is a signed int (int32_t) in bitcoin_core
        # However there are at least two transactions:
        # 35e79ee733fad376e76d16d1f10088273c2f4c2eaba1374a837378a88e530005
        # c659729a7fea5071361c2c1a68551ca2bf77679b27086cc415adeeb03852e369
        # where the version number is negative if it is considered as a signed
        # integer. As such in btclib the version is an UNSIGNED integer.
        # This has been discussed in: https://github.com/bitcoin/bitcoin/pull/16525
        version = int.from_bytes(stream.read(4),
                                 byteorder="little",
                                 signed=False)

        segwit = stream.read(2) == _SEGWIT_MARKER
        if not segwit:
            # Change stream position: seek to byte offset relative to position
            stream.seek(-2, SEEK_CUR)  # current position

        n = var_int.parse(stream)
        vin = [TxIn.parse(stream) for _ in range(n)]

        n = var_int.parse(stream)
        vout = [TxOut.parse(stream) for _ in range(n)]

        if segwit:
            for tx_in in vin:
                tx_in.script_witness = Witness.parse(stream, check_validity)

        lock_time = int.from_bytes(stream.read(4),
                                   byteorder="little",
                                   signed=False)

        return cls(version, lock_time, vin, vout, check_validity)
Example #9
0
def test_valid_taproot_key_path() -> None:
    fname = "tapscript_test_vector.json"
    filename = path.join(path.dirname(__file__), "_data", fname)
    with open(filename, "r", encoding="ascii") as file_:
        data = json.load(file_)

    for x in filter(lambda x: "TAPROOT" in x["flags"], data):

        tx = Tx.parse(x["tx"])

        prevouts = [TxOut.parse(prevout) for prevout in x["prevouts"]]
        index = x["index"]

        if not is_p2tr(prevouts[index].script_pub_key.script):
            continue

        assert not x["success"]["scriptSig"]

        witness = Witness(x["success"]["witness"])
        tx.vin[index].script_witness = witness

        if (len(witness.stack) == 1
                or len(witness.stack) == 2 and witness.stack[-1][0] == 0x50):

            sighash_type = 0  # all
            signature = witness.stack[0][:64]
            if len(witness.stack[0]) == 65:
                sighash_type = witness.stack[0][-1]
                assert sighash_type != 0

            msg_hash = sig_hash.from_tx(prevouts, tx, index, sighash_type)

            pub_key = type_and_payload(
                prevouts[index].script_pub_key.script)[1]

            ssa.assert_as_valid_(msg_hash, pub_key, signature)