Skip to content

Fix mapScriptWitnessesCertificates silently dropping key-witnessed certs#1136

Merged
Jimbo4350 merged 2 commits intomasterfrom
fix/cert-witnesses-drop-none
Mar 18, 2026
Merged

Fix mapScriptWitnessesCertificates silently dropping key-witnessed certs#1136
Jimbo4350 merged 2 commits intomasterfrom
fix/cert-witnesses-drop-none

Conversation

@Jimbo4350
Copy link
Contributor

@Jimbo4350 Jimbo4350 commented Mar 17, 2026

Changelog

- description: |
    Fix mapScriptWitnessesCertificates silently dropping key-witnessed certs
    (e.g. shelley stake registration certificates) when rebuilding the
    transaction body during fee balancing. The function previously iterated
    only over script-witnessed certs, so certs stored with a Nothing witness
    were omitted from the balanced transaction.
  type:
  - bugfix
  projects:
  - cardano-api

Context

During auto-balance, mapScriptWitnessesCertificates called indexTxCertificates (which filters to script-witnessed certs only) and reconstructed a TxCertificates from that subset. Any cert stored with no script witness — (cert, Nothing) in the OMap — was silently dropped, so it never appeared in the final transaction body.

Fix: iterate over all certs in the OMap. Certs without a script witness (Nothing) pass through as Right Nothing; script-witnessed certs go through substituteExecUnits as before.

Fixes the bug reported in IntersectMBO/cardano-cli#1347 where a shelley-era stake registration certificate was silently omitted from a Conway transaction built with cardano-cli conway transaction build.

Checklist

  • Commit sequence broadly makes sense and commits have useful messages
  • New tests are added if needed and existing tests are updated. See Running tests for more details
  • Self-reviewed the diff

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a bug in experimental transaction fee balancing where rebuilding TxCertificates during exec-unit substitution could silently drop certificates that had no script witness (Nothing), causing key-witnessed / witnessless certs (e.g., some stake registration-style certs) to disappear from the balanced transaction body.

Changes:

  • Update mapScriptWitnessesCertificates to iterate over all certificates in the TxCertificates OMap, passing through Nothing witnesses unchanged.
  • Retain exec-unit substitution behavior for witnessed certificates via substituteExecUnits.

Comment on lines +1026 to +1030
-- We iterate over all certs, not just the script-witnessed ones from
-- indexTxCertificates. TxCertificates holds certs both with and without
-- script witnesses; certs without a witness (Nothing) must pass through
-- unchanged. Iterating only over the indexed subset would silently drop
-- all key-witnessed certs from the rebuilt TxCertificates.
Comment on lines +1010 to +1014
let witnessLookup =
Map.fromList
[ (cert, (ix, stakeCred, wit))
| (ix, cert, stakeCred, wit) <- indexTxCertificates txCertificates'
]
-> Either (TxBodyErrorAutoBalance (LedgerEra era)) (TxCertificates (LedgerEra era))
mapScriptWitnessesCertificates txCertificates' = do
let mappedScriptWitnesses
mapScriptWitnessesCertificates txCertificates'@(TxCertificates certsMap) = do
Previously, the function iterated only over script-witnessed certs (via
indexTxCertificates), so certs with no witness (Nothing) were silently
omitted from the rebuilt TxCertificates. Now all certs are traversed;
those without a script witness are preserved as-is with Right Nothing.
@Jimbo4350 Jimbo4350 force-pushed the fix/cert-witnesses-drop-none branch from 8bfb09a to a53807d Compare March 17, 2026 21:51
Test that both Nothing-witnessed and Just-witnessed certificates in
TxCertificates survive mapScriptWitnessesCertificates unchanged when
substituteExecutionUnits is called with an empty execution unit map.
Also exports substituteExecutionUnits from Cardano.Api.Experimental.
Copy link
Contributor

@palas palas left a comment

Choose a reason for hiding this comment

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

Looks good 👍

Comment on lines +529 to +534
inputCerts =
Exp.mkTxCertificates
Exp.ConwayEra
[ (regCert, Exp.AnyKeyWitnessPlaceholder)
, (unRegCert, Exp.AnyKeyWitnessPlaceholder)
]
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it would be more interesting to randomise the cert list too, in case there is a bug where they only get lost on a certain order, for example

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do so in a follow up PR. Want to get this in before the 10.7 integration.

@Jimbo4350 Jimbo4350 added this pull request to the merge queue Mar 18, 2026
Merged via the queue into master with commit fb07218 Mar 18, 2026
32 checks passed
@Jimbo4350 Jimbo4350 deleted the fix/cert-witnesses-drop-none branch March 18, 2026 13:04
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.

3 participants