Skip to content

Commit

Permalink
Fix after rebase
Browse files Browse the repository at this point in the history
  • Loading branch information
giacomocaironi committed Jun 30, 2023
1 parent 5106c2b commit cfa289c
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 72 deletions.
2 changes: 1 addition & 1 deletion btclib/script/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ def parse(stream: BinaryData, accept_unknown: bool = False) -> ScriptList:
x = 4
y = s.read(x)
if len(y) != x:
raise BTClibValueError("not enough data for pushdata length")
raise BTClibValueError("Not enough data for pushdata length")
data_length = int.from_bytes(y, byteorder="little")
if data_length > 520:
raise BTClibValueError(f"Invalid pushdata length: {data_length}")
Expand Down
76 changes: 26 additions & 50 deletions btclib/script/sig_hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@

from __future__ import annotations

from typing import Sequence

from btclib import var_bytes
from btclib.alias import Octets, ScriptList
from btclib.exceptions import BTClibValueError
Expand Down Expand Up @@ -90,6 +88,29 @@ def witness_v0_script(script_pub_key: Octets) -> list[bytes]:
return script_s[::-1]


def taproot_annex_and_ext(
tx: Tx, prevouts: list[TxOut], vin_i: int
) -> tuple[bytes, bytes]:
witness = tx.vin[vin_i].script_witness
if len(witness.stack) == 0:
raise BTClibValueError("Empty stack")

annex = b""
if len(witness.stack) >= 2 and witness.stack[-1][0] == 0x50:
annex = witness.stack[-1]
witness.stack = witness.stack[:-1]

ext = b""
if len(witness.stack) > 1:
leaf_version = witness.stack[-1][0] & 0xFE
preimage = leaf_version.to_bytes(1, "big")
preimage += var_bytes.serialize(witness.stack[-2])
tapleaf_hash = tagged_hash(b"TapLeaf", preimage)
ext = tapleaf_hash + b"\x00\xff\xff\xff\xff"

return annex, ext


def legacy(script_code: Octets, tx: Tx, vin_i: int, hash_type: int) -> bytes:
script_code = bytes_from_octets(script_code)

Expand Down Expand Up @@ -267,33 +288,20 @@ def taproot(

preimage += message_extension

return tagged_hash(b"TapSighash", preimage)
sig_hash = tagged_hash(b"TapSighash", preimage)
return sig_hash


def from_tx(prevouts: list[TxOut], tx: Tx, vin_i: int, hash_type: int) -> bytes:
script = prevouts[vin_i].script_pub_key.script

if is_p2tr(script):
return _script_from_p2tr(prevouts, tx, vin_i, hash_type)

if len(witness.stack) == 0:
raise BTClibValueError("Empty stack")

ext = b""
if len(witness.stack) > 1:
leaf_version = witness.stack[-1][0] & 0xFE
preimage = leaf_version.to_bytes(1, "big")
preimage += var_bytes.serialize(witness.stack[-2])
tapleaf_hash = tagged_hash(b"TapLeaf", preimage)
ext = tapleaf_hash + b"\x00\xff\xff\xff\xff"

annex, ext = taproot_annex_and_ext(tx, prevouts, vin_i)
return taproot(tx, vin_i, prevouts, hash_type, int(bool(ext)), annex, ext)

# handle all p2sh-wrapped scripts
if is_p2sh(script):
script = tx.vin[vin_i].script_sig
if is_p2tr(script):
raise BTClibValueError("taproot scripts cannot be wrapped in p2sh")

if is_p2wpkh(script):
script_code = witness_v0_script(script)[0]
Expand All @@ -309,35 +317,3 @@ def from_tx(prevouts: list[TxOut], tx: Tx, vin_i: int, hash_type: int) -> bytes:

script_code = legacy_script(script)[0]
return legacy(script_code, tx, vin_i, hash_type)


def _script_from_p2tr(
prevouts: Sequence[TxOut], tx: Tx, vin_i: int, hash_type: int
) -> bytes:
witness = tx.vin[vin_i].script_witness
if len(witness.stack) == 0:
raise BTClibValueError("empty stack")

annex = b""
if len(witness.stack) >= 2 and witness.stack[-1][0] == 0x50:
annex = witness.stack[-1]
witness.stack = witness.stack[:-1]

ext = b""
if len(witness.stack) > 1:
leaf_version = witness.stack[-1][0] & 0xFE
preimage = leaf_version.to_bytes(1, "big")
preimage += var_bytes.serialize(witness.stack[-2])
tapleaf_hash = tagged_hash(b"TapLeaf", preimage)
ext = tapleaf_hash + b"\x00\xff\xff\xff\xff"

return taproot(
tx,
vin_i,
[x.value for x in prevouts],
[x.script_pub_key for x in prevouts],
hash_type,
int(bool(ext)),
annex,
ext,
)
23 changes: 4 additions & 19 deletions tests/script/test_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,7 @@
from btclib.alias import ScriptList
from btclib.exceptions import BTClibValueError
from btclib.script import Script, op_int, parse, serialize
from btclib.script.script import (
BYTE_FROM_OP_CODE_NAME,
OP_CODE_NAME_FROM_INT,
_serialize_str_command,
)
from btclib.script.script import BYTE_FROM_OP_CODE_NAME, OP_CODE_NAME_FROM_INT
from btclib.utils import hex_string


Expand Down Expand Up @@ -77,17 +73,6 @@ def test_serialize_bytes_command() -> None:
assert len(serialize([b])) == (length + 1) + 3


def test_invalid_op_success() -> None:
err_msg = "invalid OP_SUCCESS number: "
with pytest.raises(BTClibValueError, match=err_msg):
_serialize_str_command("OP_SUCCESS1")
err_msg = "invalid OP_SUCCESS number: "
with pytest.raises(BTClibValueError, match=err_msg):
_serialize_str_command("OP_SUCCESS173")

assert _serialize_str_command("OP_SUCCESS80") == b"\x50"


def test_add_and_eq() -> None:
script_1 = serialize(["OP_2", "OP_3", "OP_ADD", "OP_5"])
script_2 = serialize(["OP_EQUAL"])
Expand Down Expand Up @@ -131,7 +116,7 @@ def test_exceptions() -> None:

# A script_pub_key with OP_PUSHDATA4 can't be decoded
script_bytes = "4e09020000" + "0A" * 521 + "75" # ['0A'*521, 'OP_DROP']
err_msg = "invalid pushdata length: "
err_msg = "Invalid pushdata length: "
with pytest.raises(BTClibValueError, match=err_msg):
parse(script_bytes)

Expand All @@ -155,10 +140,10 @@ def test_encoding() -> None:


def test_opcode_length() -> None:
err_msg = "not enough data for pushdata length"
err_msg = "Not enough data for pushdata length"
with pytest.raises(BTClibValueError, match=err_msg):
parse(b"\x4e\x00")
err_msg = "not enough data for pushdata"
err_msg = "Not enough data for pushdata"
with pytest.raises(BTClibValueError, match=err_msg):
parse(b"\x40\x00")

Expand Down
4 changes: 2 additions & 2 deletions tests/script/test_sig_hash_taproot.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def test_empty_stack() -> None:
tx_in = TxIn(OutPoint(), "5151", 1, Witness([]))
tx = Tx(vin=[tx_in], vout=[TxOut(100000000, "")])

err_msg = "empty stack"
err_msg = "Empty stack"
with pytest.raises(BTClibValueError, match=err_msg):
sig_hash.from_tx([utxo], tx, 0, 0)

Expand All @@ -175,7 +175,7 @@ def test_wrapped_p2tr() -> None:
tx_in = TxIn(OutPoint(), serialize(script), 1, Witness(["0A" * 32]))
tx = Tx(vin=[tx_in], vout=[TxOut(100000000, "")])

err_msg = "taproot scripts cannot be wrapped in p2sh"
err_msg = "Taproot scripts cannot be wrapped in p2sh"
with pytest.raises(BTClibValueError, match=err_msg):
sig_hash.from_tx([utxo], tx, 0, 0)

Expand Down

0 comments on commit cfa289c

Please sign in to comment.