Skip to content

Commit

Permalink
Check transaction amounts (#121)
Browse files Browse the repository at this point in the history
  • Loading branch information
giacomocaironi authored Dec 3, 2023
1 parent 0ed63c4 commit da0cfc1
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 5 deletions.
9 changes: 8 additions & 1 deletion btclib/script/engine/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,19 @@ def verify_input(prevouts: list[TxOut], tx: Tx, i: int, flags: list[str]) -> Non
raise BTClibValueError()


def verify_amounts(prevouts: list[TxOut], tx: Tx) -> None:
if sum(x.value for x in tx.vout) > sum(x.value for x in prevouts):
raise BTClibValueError("Invalid transaction amounts")


def verify_transaction(
prevouts: list[TxOut], tx: Tx, flags: list | None = None
prevouts: list[TxOut], tx: Tx, flags: list | None = None, check_amounts=True
) -> None:
if flags is None:
flags = ALL_FLAGS[:]
if len(prevouts) != len(tx.vin):
raise BTClibValueError()
if check_amounts:
verify_amounts(prevouts, tx)
for i in range(len(prevouts)):
verify_input(prevouts, tx, i, flags)
30 changes: 26 additions & 4 deletions tests/script_engine/test_transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
import pytest

from btclib.exceptions import BTClibValueError
from btclib.script.engine import verify_input, verify_transaction
from btclib.script.engine import verify_amounts, verify_input, verify_transaction
from btclib.script.witness import Witness
from btclib.tx.tx import Tx
from btclib.tx import OutPoint, Tx, TxIn
from btclib.tx.tx_out import ScriptPubKey, TxOut
from tests.script_engine import parse_script

Expand Down Expand Up @@ -107,13 +107,19 @@ def test_valid_legacy() -> None:
if f in flags:
flags.remove(f)

check_amounts = True

prevouts = []
for i in x[0]:
amount = 0 if len(i) == 3 else i[3]
if not amount:
check_amounts = False
script_pub_key = parse_script(i[2])
prevouts.append(TxOut(amount, ScriptPubKey(script_pub_key)))

verify_transaction(prevouts, tx, flags if flags != ["NONE"] else None)
verify_transaction(
prevouts, tx, flags if flags != ["NONE"] else None, check_amounts
)


def test_invalid_legacy() -> None:
Expand All @@ -136,13 +142,29 @@ def test_invalid_legacy() -> None:

flags = x[2].split(",") # different flags handling

check_amounts = True

prevouts = []
for i in x[0]:
amount = 0 if len(i) == 3 else i[3]
if not amount:
check_amounts = False
with warnings.catch_warnings():
warnings.simplefilter("ignore")
script_pub_key = parse_script(i[2])
prevouts.append(TxOut(amount, ScriptPubKey(script_pub_key)))

with pytest.raises((BTClibValueError, IndexError, KeyError)):
verify_transaction(prevouts, tx, flags if flags != ["NONE"] else None)
verify_transaction(
prevouts, tx, flags if flags != ["NONE"] else None, check_amounts
)


def test_invalid_amount() -> None:
prevout = TxOut(0, ScriptPubKey(""))

tx = Tx(vin=[TxIn(OutPoint(b"1" * 32, 1))], vout=[TxOut(10, ScriptPubKey(""))])

# Output amount greater than sum of inputs
with pytest.raises(BTClibValueError):
verify_amounts([prevout], tx)

0 comments on commit da0cfc1

Please sign in to comment.