Skip to content

fix(plutus): base collateral on whole tx fee#3540

Merged
mkoura merged 2 commits into
masterfrom
collateral-computation
Jul 20, 2026
Merged

fix(plutus): base collateral on whole tx fee#3540
mkoura merged 2 commits into
masterfrom
collateral-computation

Conversation

@mkoura

@mkoura mkoura commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Description

Fix collateral computation in plutus_common.compute_cost() so it matches
what the ledger actually requires.

Base collateral on the whole transaction fee

The ledger requires collateral to cover collateralPercentage of the whole
transaction fee, not just the Plutus script execution cost (see
validateInsufficientCollateral in cardano-ledger:
balance ∗ 100 ≥ txfee ∗ collateralPercent). The previous computation used
only the script cost, so the computed min_collateral underestimated the real
requirement.

Since the exact fee is unknown before the transaction is built, a new
base_fee parameter provides a pessimistic estimate of the non-script part of
the fee, defaulting to the fee for a transaction of maximum size
(txFeeFixed + txFeePerByte * maxTxSize). Overestimating is harmless:
collateral is not spent for valid scripts, and any excess over the total
collateral comes back in the return collateral output.

Rounding now uses ceiling, matching the ledger (rationalToCoinViaCeiling in
validateInsufficientCollateral and calcReturnAndTotalCollateral in
cardano-api).

The collateral_fraction_offset multiplier is applied only to the script part
of the fee, so tests that use a large offset to inflate collateral for a cheap
script (e.g. test_collaterals with offset 250 000) don't multiply the
size-based fee estimate as well.

Derive the collateral buffer from min UTxO value

The return collateral txout must itself satisfy the min UTxO value:
(160 + serialized txout size) * utxoCostPerByte (see babbageMinUTxOValue
in cardano-ledger). Replace the arbitrary 1M lovelace buffer with the min UTxO
value for a 67-byte ada-only txout (payment + staking credentials) derived
from protocol parameters, so the buffer tracks utxoCostPerByte if the
parameter changes.

Test fix

test_minting_with_limited_collateral hardcoded the funded collateral UTxO
amount to 2M lovelace, which only matched the old compute_cost() output.
It now uses minting_cost.collateral, and the deliberately insufficient
total collateral is derived from the actual transaction fee (half of it)
instead of min_collateral, which now includes the pessimistic base fee and
could exceed the required collateral, making the transaction unexpectedly
valid.

mkoura added 2 commits July 20, 2026 13:56
The ledger requires collateral to cover `collateralPercentage` of the
whole transaction fee, not just the Plutus script execution cost.
Add pessimistic `base_fee` estimate (fee for tx of max size by
default) to the script cost when computing `min_collateral`, and use
ceiling to match the ledger's rounding.

Replace the arbitrary 1M lovelace buffer in `collateral` with a min
UTxO value derived from protocol parameters, so the return collateral
output stays above the min UTxO limit.
`test_minting_with_limited_collateral` hardcoded the funded
collateral UTxO amount to 2M lovelace, which only matched the old
`compute_cost` output. Use `minting_cost.collateral` so the return
collateral txout is balanced against the real UTxO value.

Base the limited total collateral on the actual tx fee instead of
`min_collateral`, which now includes the pessimistic base fee and
could exceed the required collateral, making the tx valid.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns Plutus collateral computation with ledger rules by basing min_collateral on the whole transaction fee (script fee + estimated non-script “base” fee) and matching the ledger’s ceiling rounding. It also replaces the previous fixed 1 ADA buffer with a min-UTxO-derived buffer that tracks utxoCostPerByte, and updates one negative minting test to derive collateral amounts from the computed cost values.

Changes:

  • Update plutus_common.compute_cost() to:
    • include a base_fee estimate in collateral computation,
    • use math.ceil for collateral rounding,
    • derive the return-collateral buffer from utxoCostPerByte (instead of a fixed 1_000_000).
  • Fix test_minting_with_limited_collateral to use minting_cost.collateral and derive an insufficient total_collateral_amount from the actual tx fee used in the test.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
cardano_node_tests/tests/plutus_common.py Adjusts collateral/min-collateral calculation to match ledger semantics (whole-fee basis + ceiling rounding) and makes the return-collateral buffer depend on utxoCostPerByte.
cardano_node_tests/tests/tests_plutus_v2/test_mint_negative_raw.py Updates a negative minting test to use computed collateral and to construct a reliably insufficient total collateral based on the tx fee.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cardano_node_tests/tests/plutus_common.py
Comment thread cardano_node_tests/tests/plutus_common.py
@mkoura
mkoura merged commit 74fc20e into master Jul 20, 2026
4 checks passed
@mkoura
mkoura deleted the collateral-computation branch July 20, 2026 15:53
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 this pull request may close these issues.

2 participants