Skip to content

Commit ba861b9

Browse files
committed
Validate output value is non-negative
1 parent 2946f29 commit ba861b9

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

pycardano/transaction.py

+34-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from typeguard import typechecked
1212

1313
from pycardano.address import Address
14-
from pycardano.exception import InvalidOperationException
14+
from pycardano.exception import InvalidDataException, InvalidOperationException
1515
from pycardano.hash import (
1616
TRANSACTION_HASH_SIZE,
1717
AuxiliaryDataHash,
@@ -182,6 +182,24 @@ def filter(
182182

183183
return new_multi_asset
184184

185+
def count(self, criteria=Callable[[ScriptHash, AssetName, int], bool]) -> int:
186+
"""Count number of distinct assets that satisfy a certain criteria.
187+
188+
Args:
189+
criteria: A function that takes in three input arguments (policy_id, asset_name, amount) and returns a
190+
bool.
191+
192+
Returns:
193+
int: Total number of distinct assets that satisfy the criteria.
194+
"""
195+
count = 0
196+
for p in self:
197+
for n in self[p]:
198+
if criteria(p, n, self[p][n]):
199+
count += 1
200+
201+
return count
202+
185203

186204
@typechecked
187205
@dataclass(repr=False)
@@ -236,6 +254,21 @@ class TransactionOutput(ArrayCBORSerializable):
236254

237255
datum_hash: DatumHash = field(default=None, metadata={"optional": True})
238256

257+
def validate(self):
258+
if isinstance(self.amount, int) and self.amount < 0:
259+
raise InvalidDataException(
260+
f"Transaction output cannot have negative amount of ADA or "
261+
f"native asset: \n {self.amount}"
262+
)
263+
if isinstance(self.amount, Value) and (
264+
self.amount.coin < 0
265+
or self.amount.multi_asset.count(lambda p, n, v: v < 0) > 0
266+
):
267+
raise InvalidDataException(
268+
f"Transaction output cannot have negative amount of ADA or "
269+
f"native asset: \n {self.amount}"
270+
)
271+
239272
@property
240273
def lovelace(self) -> int:
241274
if isinstance(self.amount, int):

test/pycardano/test_transaction.py

+23-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44

55
from pycardano.address import Address
6-
from pycardano.exception import InvalidOperationException
6+
from pycardano.exception import InvalidDataException, InvalidOperationException
77
from pycardano.hash import SCRIPT_HASH_SIZE, ScriptHash, TransactionId
88
from pycardano.key import PaymentKeyPair, PaymentSigningKey, VerificationKey
99
from pycardano.transaction import (
@@ -42,6 +42,28 @@ def test_transaction_output():
4242
check_two_way_cbor(output)
4343

4444

45+
def test_invalid_transaction_output():
46+
addr = Address.decode(
47+
"addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x"
48+
)
49+
output = TransactionOutput(addr, -100000000000)
50+
with pytest.raises(InvalidDataException):
51+
output.to_cbor()
52+
53+
value = Value.from_primitive(
54+
[
55+
100,
56+
{
57+
b"1"
58+
* SCRIPT_HASH_SIZE: {b"TestToken1": -10000000, b"TestToken2": 20000000}
59+
},
60+
]
61+
)
62+
output = TransactionOutput(addr, value)
63+
with pytest.raises(InvalidDataException):
64+
output.to_cbor()
65+
66+
4567
def make_transaction_body():
4668
tx_id_hex = "732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e5"
4769
tx_in = TransactionInput(TransactionId(bytes.fromhex(tx_id_hex)), 0)

0 commit comments

Comments
 (0)