Skip to content

feat: add ExpiredTransaction event and resubmission queue#122

Merged
lpahlavi merged 5 commits intomainfrom
lpahlavi/resubmission-queue
Apr 13, 2026
Merged

feat: add ExpiredTransaction event and resubmission queue#122
lpahlavi merged 5 commits intomainfrom
lpahlavi/resubmission-queue

Conversation

@lpahlavi
Copy link
Copy Markdown
Contributor

@lpahlavi lpahlavi commented Apr 10, 2026

Summary

  • Adds ExpiredTransaction event type (CBOR tag n(10)) that records when a submitted transaction has an expired blockhash and a null on-chain status — meaning it will never be executed and must be resubmitted
  • Adds transactions_to_resubmit: BTreeSet<Signature> state field, populated by ExpiredTransaction events and cleared on resubmission/finalization — survives canister upgrades since it is rebuilt by replaying the event log

This PR is the prerequisite for #120, which splits monitor_submitted_transactions into two independent timers: finalize_transactions emits ExpiredTransaction events, and resubmit_transactions drains the queue.

Stack

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings April 10, 2026 15:28
@lpahlavi lpahlavi changed the title feat: add ExpiredTransaction event and resubmission queue feat: add ExpiredTransaction event and resubmission queue Apr 10, 2026
@lpahlavi lpahlavi force-pushed the lpahlavi/resubmission-queue branch from b427300 to 99c4f76 Compare April 10, 2026 15:55
@lpahlavi lpahlavi force-pushed the lpahlavi/resubmission-queue branch from 99c4f76 to 0b635f9 Compare April 10, 2026 16:24
Snapshot the current slot before calling getSignatureStatuses so that
a transaction which finalizes between the slot snapshot and the status
check is seen as finalized (not missing), preventing it from being
incorrectly marked as expired.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lpahlavi lpahlavi force-pushed the lpahlavi/resubmission-queue branch from 0b635f9 to a7040bf Compare April 10, 2026 18:32
@lpahlavi lpahlavi changed the base branch from main to lpahlavi/toctou-fix April 10, 2026 18:34
Introduces EventType::ExpiredTransaction fired when a submitted
transaction's blockhash expires without being finalized. Adds a
transactions_to_resubmit BTreeSet to state so that expired transactions
are queued for resubmission and survived across upgrades.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lpahlavi lpahlavi force-pushed the lpahlavi/resubmission-queue branch from a7040bf to 7d47203 Compare April 10, 2026 18:39
@lpahlavi lpahlavi requested a review from THLO April 11, 2026 17:01
@lpahlavi lpahlavi marked this pull request as ready for review April 11, 2026 17:02
@lpahlavi lpahlavi requested a review from a team as a code owner April 11, 2026 17:02
Base automatically changed from lpahlavi/toctou-fix to main April 13, 2026 08:50
lpahlavi and others added 2 commits April 13, 2026 11:00
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- In `process_transaction_resubmitted`: assert old_signature was in the
  queue (mirrors the insert assertion in `process_transaction_expired`)
- In `process_transaction_succeeded/failed`: replace the defensive remove
  with an assertion that the signature is NOT queued — a transaction
  being finalized must still be in `submitted_transactions`, which means
  it was never fully resubmitted, so it cannot be in the resubmission
  queue at the same time

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread minter/src/state/audit.rs Outdated
state.process_transaction_failed(signature);
}
EventType::ExpiredTransaction { signature } => {
state.process_transaction_expired(*signature);
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.

Why is the signature dereferenced here (unlike for other process_transaction functions)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point. I changed process_transaction_expired to take a &Signature for consistency with other similar methods.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lpahlavi lpahlavi merged commit cafc8dd into main Apr 13, 2026
10 checks passed
@lpahlavi lpahlavi deleted the lpahlavi/resubmission-queue branch April 13, 2026 10:23
lpahlavi added a commit that referenced this pull request Apr 15, 2026
Canisters deployed before ExpiredTransaction was introduced (#122) have
event logs where ResubmittedTransaction events have no preceding
ExpiredTransaction. The updated state machine requires the transaction
to be in transactions_to_resubmit before it can be resubmitted, so
replaying such logs would panic.

The fix is a fallback in process_transaction_resubmitted: if the old
signature is in submitted_transactions rather than transactions_to_resubmit,
process_transaction_expired is called inline first. This makes every
replay of old event logs correct.

To be removed after the staging migration is complete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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