Skip to content

Commit ae2c905

Browse files
committed
Add more details to the message of expection when UTxO selectors fail
1 parent 8b89932 commit ae2c905

File tree

3 files changed

+46
-2
lines changed

3 files changed

+46
-2
lines changed

pycardano/txbuilder.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,10 +608,12 @@ def build(self, change_address: Optional[Address] = None) -> TransactionBody:
608608
# When there are positive coin or native asset quantity in unfulfilled Value
609609
if Value() < unfulfilled_amount:
610610
additional_utxo_pool = []
611+
additional_amount = Value()
611612
for address in self.input_addresses:
612613
for utxo in self.context.utxos(str(address)):
613614
if utxo not in selected_utxos and utxo not in self.excluded_inputs:
614615
additional_utxo_pool.append(utxo)
616+
additional_amount += utxo.output.amount
615617

616618
for i, selector in enumerate(self.utxo_selectors):
617619
try:
@@ -631,7 +633,28 @@ def build(self, change_address: Optional[Address] = None) -> TransactionBody:
631633
logger.info(e)
632634
logger.info(f"{selector} failed. Trying next selector.")
633635
else:
634-
raise UTxOSelectionException("All UTxO selectors failed.")
636+
trimmed_additional_amount = Value(
637+
additional_amount.coin,
638+
additional_amount.multi_asset.filter(
639+
lambda p, n, v: p in requested_amount.multi_asset
640+
and n in requested_amount.multi_asset[p]
641+
),
642+
)
643+
diff = (
644+
requested_amount
645+
- trimmed_selected_amount
646+
- trimmed_additional_amount
647+
)
648+
diff.multi_asset = diff.multi_asset.filter(
649+
lambda p, n, v: v > 0
650+
)
651+
raise UTxOSelectionException(
652+
f"All UTxO selectors failed.\n"
653+
f"Requested output:\n {requested_amount} \n"
654+
f"Pre-selected inputs:\n {selected_amount} \n"
655+
f"Additional UTxO pool:\n {additional_utxo_pool} \n"
656+
f"Unfulfilled amount:\n {diff}"
657+
)
635658

636659
selected_utxos.sort(
637660
key=lambda utxo: (str(utxo.input.transaction_id), utxo.input.index)

test/pycardano/test_coinselection.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
InputUTxODepletedException,
1010
InsufficientUTxOBalanceException,
1111
MaxInputCountExceededException,
12-
UTxOSelectionException,
1312
)
1413
from pycardano.transaction import TransactionInput, TransactionOutput, UTxO, Value
1514

test/pycardano/test_txbuilder.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from pycardano.exception import (
1313
InsufficientUTxOBalanceException,
1414
InvalidTransactionException,
15+
UTxOSelectionException,
1516
)
1617
from pycardano.hash import SCRIPT_HASH_SIZE, ScriptHash
1718
from pycardano.key import VerificationKey
@@ -141,6 +142,27 @@ def test_tx_builder_multi_asset(chain_context):
141142
assert expected == tx_body.to_primitive()
142143

143144

145+
def test_tx_builder_raises_utxo_selection(chain_context):
146+
tx_builder = TransactionBuilder(chain_context)
147+
sender = "addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x"
148+
sender_address = Address.from_primitive(sender)
149+
150+
# Add sender address as input
151+
tx_builder.add_input_address(sender).add_output(
152+
TransactionOutput.from_primitive([sender, 1000000000])
153+
).add_output(
154+
TransactionOutput.from_primitive(
155+
[sender, [2000000, {b"1" * 28: {b"NewToken": 1}}]]
156+
)
157+
)
158+
159+
with pytest.raises(UTxOSelectionException) as e:
160+
tx_body = tx_builder.build(change_address=sender_address)
161+
assert "Unfulfilled amount:" in e.value.args[0]
162+
assert "'coin': 991000000" in e.value.args[0]
163+
assert "{AssetName(b'NewToken'): 1}" in e.value.args[0]
164+
165+
144166
def test_tx_too_big_exception(chain_context):
145167
tx_builder = TransactionBuilder(chain_context)
146168
sender = "addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x"

0 commit comments

Comments
 (0)