Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic collateral selection does not go well with mustNotSpendUtxos #1581

Open
jstolarek opened this issue Dec 18, 2023 · 5 comments · May be fixed by #1650
Open

Automatic collateral selection does not go well with mustNotSpendUtxos #1581

jstolarek opened this issue Dec 18, 2023 · 5 comments · May be fixed by #1650

Comments

@jstolarek
Copy link

When using mustNotSpendUtxos and mustNotSpendUtxosWithOutRefs it sometimes happens that one of the forbidden UTxOs is selected as a collateral. Collateral selection should honour the list of forbidden UTxOs defined by the user.

@klntsky
Copy link
Member

klntsky commented Dec 19, 2023

Which revision are you on?
I was quite sure we already fixed this: #1512

@jankun4
Copy link

jankun4 commented Dec 20, 2023

We are on rev: b7e8d396711f95e7a7b755a2a7e7089df712aaf5 which seems to have the fix. However I don't think the fix does the job in some cases. For example, we have a test case where the first transaction submitted requires a collateral and also have a specified non spendable utxo. Depending on the initial configuration of wallet utxos we can make the system reject the transaction due to missing collateral. To give some concrete example:

Scenario 1

Initial utxo distribution:

[ BigInt.fromInt 1_000_000
, BigInt.fromInt 150_000_000
]

Non spendable utxo:

(Just (TransactionOutput { address: (Address { addressCredential: (PubKeyCredential (PubKeyHash (Ed25519KeyHash 05ff9c2520f604a8e344755d00f6000d9d6e43345ba6711363bcd58b))), addressStakingCredential: Nothing }), amount: (PlutusValue (Map [(Tuple (CurrencySymbol (hexToByteArrayUnsafe "")) (Map [(Tuple (TokenName (hexToRawBytesUnsafe "")) fromString "1000000")]))])), datum: NoOutputDatum, referenceScript: Nothing }))

Result of getWalletCollateral

(Just [(TransactionUnspentOutput { input: (TransactionInput { index: 1u, transactionId: (TransactionHash (hexToByteArrayUnsafe "ba46501ccee2f425fc515149757c4606811ba4e7e19228d6fd38d8d593a157ee")) }), output: (TransactionOutputWithRefScript { output: (TransactionOutput { address: (Address { addressCredential: (PubKeyCredential (PubKeyHash (Ed25519KeyHash 05ff9c2520f604a8e344755d00f6000d9d6e43345ba6711363bcd58b))), addressStakingCredential: Nothing }), amount: (PlutusValue (Map [(Tuple (CurrencySymbol (hexToByteArrayUnsafe "")) (Map [(Tuple (TokenName (hexToRawBytesUnsafe "")) fromString "150000000")]))])), datum: NoOutputDatum, referenceScript: Nothing }), scriptRef: Nothing }) })])

The 1Ada utxo is not chosen as a possible collateral so its not a problem that we forbid spending it. The transaction succeeds without a problem.

Scenario 2

Initial utxo distribution:

[ BigInt.fromInt 6_000_000
, BigInt.fromInt 150_000_000
]

Non spendable utxo:

(Just (TransactionOutput { address: (Address { addressCredential: (PubKeyCredential (PubKeyHash (Ed25519KeyHash 36409f4f12b733a9c3df403885aff2ed7316add1e37b13dd2b283d08))), addressStakingCredential: Nothing }), amount: (PlutusValue (Map [(Tuple (CurrencySymbol (hexToByteArrayUnsafe "")) (Map [(Tuple (TokenName (hexToRawBytesUnsafe "")) fromString "6000000")]))])), datum: NoOutputDatum, referenceScript: Nothing }))

Result of getWalletCollateral:

(Just [(TransactionUnspentOutput { input: (TransactionInput { index: 0u, transactionId: (TransactionHash (hexToByteArrayUnsafe "2566916395d2f593dfe6f3dbc692604aebd89d0c60b03e9f16197e0454ade90d")) }), output: (TransactionOutputWithRefScript { output: (TransactionOutput { address: (Address { addressCredential: (PubKeyCredential (PubKeyHash (Ed25519KeyHash 36409f4f12b733a9c3df403885aff2ed7316add1e37b13dd2b283d08))), addressStakingCredential: Nothing }), amount: (PlutusValue (Map [(Tuple (CurrencySymbol (hexToByteArrayUnsafe "")) (Map [(Tuple (TokenName (hexToRawBytesUnsafe "")) fromString "6000000")]))])), datum: NoOutputDatum, referenceScript: Nothing }), scriptRef: Nothing }) })])

In this case the non spendable utxo was also selected as the only available collateral candidate. If we try to submit a transaction in this case, we'll get an error like:

Expected failure (and got failure): Failed to submit tx:
(ClientOtherError [{"missingCollateralInputs":null},{"collateralTooSmall":{"requiredCollateral":662097,"actualCollateral":0}}])

Basically there can be the case where the algorithm will choose only a single utxo as a candidate for a collateral. In this case if this utxo is also non spendable during some transaction, this transaction will fail to be successfully built.

@klntsky
Copy link
Member

klntsky commented Jan 6, 2024

@jankun4 could you please provide a reproducible test to simplify debugging for us?

@klntsky
Copy link
Member

klntsky commented Jan 6, 2024

Basically there can be the case where the algorithm will choose only a single utxo as a candidate for a collateral. In this case if this utxo is also non spendable during some transaction, this transaction will fail to be successfully built.

What do you think should be the correct behavior?

@jstolarek
Copy link
Author

could you please provide a reproducible test to simplify debugging for us?

I don't think we can easily provide a minimal test case - we'd need to get the time to build a minimal example approved by our managers.

What do you think should be the correct behavior?

The correct behaviour would be to never select forbidden UTxOs as a collateral. In case the forbidden UTxOs are the only viable collaterals, this should lead to balancing error.

@errfrom errfrom linked a pull request Sep 16, 2024 that will close this issue
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants