Add HasCallStack constraints to functions containing error calls#1175
Add HasCallStack constraints to functions containing error calls#1175
Conversation
4e83260 to
77d1ec0
Compare
5b44c18 to
3082fdd
Compare
There was a problem hiding this comment.
Pull request overview
This PR improves runtime debuggability by adding HasCallStack constraints to selected standalone functions that can reach error, and by replacing placeholder “Dijkstra”/empty error messages with more descriptive ones across a few era-bridging/conversion helpers.
Changes:
- Add
HasCallStackconstraints to a small set of functions so call stacks include their callers whenerroris triggered. - Improve several Dijkstra-era placeholder
errormessages to include the function name and a clearer reason. - Add
GHC.Stack (HasCallStack)imports where newly required.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| cardano-api/src/Cardano/Api/Tx/Internal/Sign.hs | Adds HasCallStack to makeShelleySignature and imports HasCallStack. |
| cardano-api/src/Cardano/Api/Tx/Internal/Body.hs | Adds HasCallStack constraint to getTxIdByron for better stacks on the “impossible” hash-size path. |
| cardano-api/src/Cardano/Api/Query/Internal/Type/QueryInMode.hs | Adds HasCallStack to toConsensusQueryShelleyBased to improve stacks for wrong-era query errors. |
| cardano-api/src/Cardano/Api/Plutus/Internal/Script.hs | Replaces empty/placeholder error messages with descriptive “Dijkstra era not supported” messages. |
| cardano-api/src/Cardano/Api/Network/Internal/NetworkId.hs | Adds HasCallStack to fromShelleyNetwork and imports HasCallStack. |
| cardano-api/src/Cardano/Api/LedgerState.hs | Adds HasCallStack to chain-sync/ledger-state folding entrypoints and imports HasCallStack. |
| cardano-api/src/Cardano/Api/Key/Internal/Class.hs | Adds HasCallStack to generateInsecureSigningKey and imports HasCallStack. |
| cardano-api/src/Cardano/Api/Experimental/Tx/Internal/AnyWitness.hs | Improves a Dijkstra placeholder error message in getPlutusDatum. |
| cardano-api/src/Cardano/Api/Certificate/Internal.hs | Improves Dijkstra placeholder error messages in getAnchorDataFromCertificate. |
3082fdd to
ac36214
Compare
Wrong link |
There was a problem hiding this comment.
That's a good direction, but I think we can do better.
-
It would be nice to enhance all the callers of the modified functions here with
HasCallstackfor complete call stacks. -
Currently all
errors for dijkstra are not following any convention. It would be better to update all of them to follow the same pattern so they're easier to find. Here's what exists across ~26 Dijkstra placeholder errors:Three patterns in use
- Descriptive (majority, ~22 instances) -- already follows "functionName: Dijkstra era not supported":
error "caseByronOrShelleyBasedEra: DijkstraEra is not supported" -- Era/Internal/Case.hs error "shelleyBasedEraConstraints: Dijkstra is not yet supported" -- Eon/ShelleyBasedEra.hs error "makeShelleyTransactionBody: Dijkstra is not supported" -- Tx/Internal/Body.hs (note: double space typo) error "estimateBalancedTxBody: DijkstraEra is not supported for fee estimation" -- Fee.hs
- Bare placeholders (4 instances) -- the ones the PR fixes:
error "dijkstra" -- 3 places error "" -- 1 place (fromShelleyMultiSig)
- TODO-prefixed error (1 instance):
error "TODO: makeStakeAddressDelegationCertificate DijkstraEra" -- Certificate/Compatible.hs:74
8f67488 to
6d531d5
Compare
264534d to
53c7673
Compare
| kind: | ||
| - compatible | ||
| description: | | ||
| Add HasCallStack constraints to standalone functions that call error |
There was a problem hiding this comment.
line breaks will be carried over to changelog. You should tell your Claude that's 2026 and we're not using 80 character line length limit anymore.
Idk why mine was insisting on doing that too...
| kind: | ||
| - compatible | ||
| description: | | ||
| Add HasCallStack constraints to standalone functions that call error |
There was a problem hiding this comment.
| Add HasCallStack constraints to standalone functions that call error | |
| Add `HasCallStack` constraints to standalone functions that call error |
Can you elaborate? Address in what sense? |
53c7673 to
db74111
Compare
Add HasCallStack constraints to standalone functions that call error directly or indirectly. Improve bare Dijkstra-era placeholder error messages to follow the convention: functionName: Dijkstra era not supported.
Add HasCallStack constraints to callers of makeShelleySignature so that stack traces show the full signing call chain: makeShelleyKeyWitness, makeShelleyKeyWitness', makeShelleyBootstrapWitness, makeShelleyBasedBootstrapWitness, makeKeyWitness, issueOperationalCertificate.
Add HasCallStack to toConsensusQuery so it propagates the stack trace from toConsensusQueryShelleyBased's error calls for wrong-era queries.
Add HasCallStack to fromShelleyGenesis so it propagates the stack trace from fromShelleyNetwork's error call on wrong mainnet network magic.
Add HasCallStack to makeShelleyTransactionBody, createAndValidateTransactionBody, fromLegacyTxOut, and toShelleyUTxO, which call functions like mkCommonTxBody, toShelleyTxOutAny, toShelleyTxOut, and createTransactionBody that already carry the constraint.
Add HasCallStack to calcMinFeeRecursive, estimateOrCalculateBalancedTxBody, and constructBalancedTx, which call balanceTxOuts, makeTransactionBodyAutoBalance, estimateBalancedTxBody, and calculateMinimumUTxO that already carry the constraint.
db74111 to
f50ea7e
Compare
|
@Jimbo4350 There are different error messages in Pattern A - error "Dijkstra era is not active yet" (12 hits, identical message):
Pattern B - -- TODO dijkstra: (1 hit):
Pattern C - -- TODO: with dijkstra mentioned in the text (1 hit):
The main problem: patterns A, B, and C use three different conventions. grep 'TODO.*dijkstra' misses all 12 error stubs. grep 'Dijkstra era is not active' misses the two TODO comments. No single grep Unifying them all under e.g. |
f50ea7e to
9f7b1df
Compare
Will open a follow up PR |
|
Thanks @carbolymer — good catch. The four files you cite are in cardano-node, not cardano-api, so I'll track them over there separately. For cardano-api itself I audited the same thing and found 27 Two sites were intentionally excluded from the cardano-api unification, both documented in #1187's description:
|
Changelog
Context
Closes #809
Phase 1: HasCallStack at error sites
Each placement is justified by a real
errorcall in the function body. We addHasCallStackrather than replacingerrorwith proper error handling for the reasons noted:HasCallStackrather than replacingerrorgenerateInsecureSigningKeyerroron deserialization failurefoldBlockserror "Impossible! Missing Ledger state"in nested chain sync clientEitherwithout rearchitecting the protocol clientchainSyncClientWithLedgerStateerror "Impossible! History should always be non-empty"chainSyncClientPipelinedWithLedgerStatefoldEpochStateerror "Impossible! Missing Ledger state"in nested functionfromShelleyNetworkerroron wrong mainnet network magicEither, but it's called fromfromShelleyGenesisand other pure conversion functions — changing the return type would ripple through the genesis/network conversion chaintoConsensusQueryShelleyBasederrorfor wrong-era queriesEither, but feeds into the consensus query pipeline which expects a pure value — would require reworking the query infrastructuregetTxIdByronfromMaybe impossible(hash size mismatch)makeShelleySignaturefromMaybe impossible(signature size mismatch)Phase 2: Propagation to callers
After adding
HasCallStackto the error sites, it was propagated up the call chain so stack traces show the full path rather than stopping at the immediate error site. Each line below is a call chain — read→as "calls". The rightmost function is where theerrorlives; each function to its left getsHasCallStackso its frame appears in the stack trace.Propagation from Phase 1 error sites
Tx signing (all paths end at
makeShelleySignature):Query:
Genesis:
The remaining Phase 1 error sites (
generateInsecureSigningKey,foldBlocks,chainSyncClientWithLedgerState,chainSyncClientPipelinedWithLedgerState,foldEpochState,getTxIdByron) are top-level entry points with no internal callers in this repo to propagate to.Propagation from pre-existing master constraints
These functions call downstream functions that already carried
HasCallStackon master but were themselves missing the constraint:Tx body construction & output (callees pre-existing on master:
mkCommonTxBody,toShelleyTxOut,toShelleyTxOutAny,createTransactionBody):Fee calculation (callees pre-existing on master:
balanceTxOuts,makeTransactionBodyAutoBalance,estimateBalancedTxBody,calculateMinimumUTxO):Error message improvements (no HasCallStack)
Dijkstra-era placeholder
errorcalls had unhelpful messages (error "dijkstra",error ""). These are replaced with descriptive messages naming the function and the reason, e.g.error "getPlutusDatum: Dijkstra era not supported".What was excluded and why
Dijkstra-era placeholders (~20 calls across Era/Internal/Case.hs, Eon/*.hs, etc.): All temporary
errorcalls that will be replaced with real implementations when Dijkstra support lands. AddingHasCallStackwould create churn across many signatures that will be rewritten anyway.Class method instances (
castVerificationKey,deterministicSigningKey): The failing cases guard impossible code paths (e.g. ed25519-bip32 extended key byte length can never mismatch ed25519).HasCallStackon instance methods viaInstanceSigsdoesn't propagate the caller's stack through class dispatch, and putting it on the class method would force the constraint on all instances including those that can never fail.Certificate validation functions (
toShelleyPoolParams,toShelleyDnsName,toShelleyUrl,fromShelleyPoolMetadata): These have realerrorcalls for validation failures, but they carryTODO: proper validationcomments — they should be converted to proper error handling rather than patched withHasCallStack.How to trust this PR
HasCallStackplacement is justified by a realerrorcall in the function body — see table above-Wredundant-constraints— every constraint is actually usedChecklist