Skip to content

Commit da0cfc1

Browse files
Check transaction amounts (#121)
1 parent 0ed63c4 commit da0cfc1

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

btclib/script/engine/__init__.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,19 @@ def verify_input(prevouts: list[TxOut], tx: Tx, i: int, flags: list[str]) -> Non
180180
raise BTClibValueError()
181181

182182

183+
def verify_amounts(prevouts: list[TxOut], tx: Tx) -> None:
184+
if sum(x.value for x in tx.vout) > sum(x.value for x in prevouts):
185+
raise BTClibValueError("Invalid transaction amounts")
186+
187+
183188
def verify_transaction(
184-
prevouts: list[TxOut], tx: Tx, flags: list | None = None
189+
prevouts: list[TxOut], tx: Tx, flags: list | None = None, check_amounts=True
185190
) -> None:
186191
if flags is None:
187192
flags = ALL_FLAGS[:]
188193
if len(prevouts) != len(tx.vin):
189194
raise BTClibValueError()
195+
if check_amounts:
196+
verify_amounts(prevouts, tx)
190197
for i in range(len(prevouts)):
191198
verify_input(prevouts, tx, i, flags)

tests/script_engine/test_transactions.py

+26-4
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
import pytest
1717

1818
from btclib.exceptions import BTClibValueError
19-
from btclib.script.engine import verify_input, verify_transaction
19+
from btclib.script.engine import verify_amounts, verify_input, verify_transaction
2020
from btclib.script.witness import Witness
21-
from btclib.tx.tx import Tx
21+
from btclib.tx import OutPoint, Tx, TxIn
2222
from btclib.tx.tx_out import ScriptPubKey, TxOut
2323
from tests.script_engine import parse_script
2424

@@ -107,13 +107,19 @@ def test_valid_legacy() -> None:
107107
if f in flags:
108108
flags.remove(f)
109109

110+
check_amounts = True
111+
110112
prevouts = []
111113
for i in x[0]:
112114
amount = 0 if len(i) == 3 else i[3]
115+
if not amount:
116+
check_amounts = False
113117
script_pub_key = parse_script(i[2])
114118
prevouts.append(TxOut(amount, ScriptPubKey(script_pub_key)))
115119

116-
verify_transaction(prevouts, tx, flags if flags != ["NONE"] else None)
120+
verify_transaction(
121+
prevouts, tx, flags if flags != ["NONE"] else None, check_amounts
122+
)
117123

118124

119125
def test_invalid_legacy() -> None:
@@ -136,13 +142,29 @@ def test_invalid_legacy() -> None:
136142

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

145+
check_amounts = True
146+
139147
prevouts = []
140148
for i in x[0]:
141149
amount = 0 if len(i) == 3 else i[3]
150+
if not amount:
151+
check_amounts = False
142152
with warnings.catch_warnings():
143153
warnings.simplefilter("ignore")
144154
script_pub_key = parse_script(i[2])
145155
prevouts.append(TxOut(amount, ScriptPubKey(script_pub_key)))
146156

147157
with pytest.raises((BTClibValueError, IndexError, KeyError)):
148-
verify_transaction(prevouts, tx, flags if flags != ["NONE"] else None)
158+
verify_transaction(
159+
prevouts, tx, flags if flags != ["NONE"] else None, check_amounts
160+
)
161+
162+
163+
def test_invalid_amount() -> None:
164+
prevout = TxOut(0, ScriptPubKey(""))
165+
166+
tx = Tx(vin=[TxIn(OutPoint(b"1" * 32, 1))], vout=[TxOut(10, ScriptPubKey(""))])
167+
168+
# Output amount greater than sum of inputs
169+
with pytest.raises(BTClibValueError):
170+
verify_amounts([prevout], tx)

0 commit comments

Comments
 (0)