fix: Guards around setting Next Cardano Position [PM-19901]#763
Merged
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
Add CardanoPositionRegression and CardanoPositionExcessiveJump to the pallet Error enum, preparing for monotonicity and window-bound guards on NextCardanoPosition updates in process_tokens. Refs: PM-19901 Co-authored-by: Cursor <cursoragent@cursor.com>
Read the previous NextCardanoPosition before updating and enforce: 1. Strict monotonicity via PartialOrd (block_number, tx_index_in_block) 2. Forward bound via CardanoBlockWindowSize (default 1000 blocks) Guards use ensure! consistent with existing InherentAlreadyExecuted pattern. On failure, Substrate rolls back all storage mutations and rejects the block (Mandatory dispatch). Refs: PM-19901 Co-authored-by: Cursor <cursoragent@cursor.com>
Add 9 tests covering monotonicity and window-bound guards: - Regression: lower block_number, equal position, same-block lower tx_index - Acceptance: same-block higher tx_index, within-window jump, normal advance - Boundaries: default (zero) position, exact window boundary, exceeding window - All existing tests pass without modification Refs: PM-19901 Co-authored-by: Cursor <cursoragent@cursor.com>
Document the monotonicity and window-bound guard addition for the release changelog, addressing audit issue R (PM-19901). Refs: PM-19901 Co-authored-by: Cursor <cursoragent@cursor.com>
…into fix/PM-19901-guards-next-cardano-position
- Extract establish_position() helper to reduce boilerplate across 8 guard tests - Add position_guard_works_with_utxos_present test validating guards fire correctly when UTXOs are also present in the dispatch - Add position_guards_hold_across_multiple_advances test verifying guards remain effective after 4 sequential position advances Refs: PM-19901 Co-authored-by: Cursor <cursoragent@cursor.com>
mpskowron
reviewed
Feb 26, 2026
gilescope
approved these changes
Feb 27, 2026
Contributor
Author
|
/bot rebuild-metadata |
Contributor
|
✅ Metadata rebuild complete! Changes have been committed. |
…w equal positions, warn-only for window bound Signed-off-by: Giles Cope <gilescope@gmail.com>
60f0a89 to
5ece691
Compare
gilescope
reviewed
Feb 27, 2026
gilescope
reviewed
Feb 27, 2026
gilescope
reviewed
Feb 27, 2026
gilescope
reviewed
Feb 27, 2026
gilescope
reviewed
Feb 27, 2026
gilescope
reviewed
Feb 27, 2026
5 tasks
gilescope
pushed a commit
that referenced
this pull request
Apr 8, 2026
m2ux
added a commit
that referenced
this pull request
Apr 23, 2026
Signed-off-by: Mike Clay <mike.clay@shielded.io>
m2ux
added a commit
that referenced
this pull request
Apr 23, 2026
Signed-off-by: Mike Clay <mike.clay@shielded.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.








Summary
Add monotonicity and window-bound guards to
NextCardanoPositionupdates inprocess_tokens, preventing cursor regression and flagging unbounded forward jumps. Addresses Least Authority Q4 2025 audit issue R (Medium severity).🎫 Ticket 📐 Engineering
Motivation
The
process_tokensinherent extrinsic unconditionally writesNextCardanoPositionwithout validating that the new position advances beyond the stored value or stays within configurable bounds. A regressing cursor could replay already-handled Cardano UTXOs (risking duplicate DUST minting). An unbounded forward jump could permanently skip intermediate Cardano events (losing bridged tokens).Changes
CardanoPositionRegressionadded to the palletError<T>enumensure!(next_cardano_position >= prev)using the existingPartialOrdimplementation onCardanoPosition, which orders lexicographically on(block_number, tx_index_in_block). Equal positions are allowed since the same Cardano block is routinely referenced across consecutive Midnight blocks.log::warn!when the block_number delta exceedsCardanoBlockWindowSize(default: 1000 blocks). This is warn-only (not an assertion) because the inherent data provider does not enforce the window bound, and a fatal guard on aMandatorydispatch would cause a network halt in legitimate catch-up scenarios.establish_position()helperchanges/changed/guards-next-cardano-position.md📌 Submission Checklist
🔱 Fork Strategy
🗹 TODO before merging