Skip to content

refactor: split monitor timer into finalize and resubmit#120

Merged
lpahlavi merged 8 commits intomainfrom
lpahlavi/split-monitor-timer
Apr 14, 2026
Merged

refactor: split monitor timer into finalize and resubmit#120
lpahlavi merged 8 commits intomainfrom
lpahlavi/split-monitor-timer

Conversation

@lpahlavi
Copy link
Copy Markdown
Contributor

@lpahlavi lpahlavi commented Apr 10, 2026

Summary

Splits the single monitor_submitted_transactions timer into two separate timers with different intervals:

  • finalize_transactions: checks all submitted transactions, finalizes succeeded/failed ones, and marks expired transactions (older than MAX_BLOCKHASH_AGE slots) for resubmission
  • resubmit_transactions: processes the resubmission queue by fetching a fresh blockhash and resubmitting each expired transaction

Adds FinalizeTransactions and ResubmitTransactions task types, replacing MonitorSubmittedTransactions.

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings April 10, 2026 14:18
@lpahlavi lpahlavi force-pushed the lpahlavi/split-monitor-timer branch 3 times, most recently from 0336ff9 to a15018c Compare April 10, 2026 15:26
@lpahlavi lpahlavi changed the base branch from main to lpahlavi/resubmission-queue April 10, 2026 15:28
@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/split-monitor-timer branch from a15018c to e56c658 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
@lpahlavi lpahlavi force-pushed the lpahlavi/split-monitor-timer branch from e56c658 to a205385 Compare April 10, 2026 16:24
@lpahlavi lpahlavi force-pushed the lpahlavi/resubmission-queue branch from 0b635f9 to a7040bf Compare April 10, 2026 18:32
@lpahlavi lpahlavi force-pushed the lpahlavi/split-monitor-timer branch from a205385 to 57d3713 Compare April 10, 2026 18:33
@lpahlavi lpahlavi force-pushed the lpahlavi/resubmission-queue branch from a7040bf to 7d47203 Compare April 10, 2026 18:39
@lpahlavi lpahlavi force-pushed the lpahlavi/split-monitor-timer branch from 57d3713 to 519bcf0 Compare April 10, 2026 18:39
lpahlavi added a commit that referenced this pull request Apr 13, 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

- Followed by: #120 (split monitor timer into finalize and resubmit)
- Followed by: #97 (single-round timers with immediate rescheduling)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Base automatically changed from lpahlavi/resubmission-queue to main April 13, 2026 10:23
@lpahlavi lpahlavi force-pushed the lpahlavi/split-monitor-timer branch 4 times, most recently from 9e81446 to 6918ffa Compare April 13, 2026 20:03
- Rename `monitor_submitted_transactions` to two separate timers:
  `finalize_transactions` (2 min) and `resubmit_transactions` (3 min)
- `finalize_transactions` checks submitted transactions, marks
  succeeded/failed ones and expired ones for resubmission
- `resubmit_transactions` processes transactions in the resubmit queue
- Staggered intervals avoid concurrent timer execution in steady state
- Add `FinalizeTransactions` and `ResubmitTransactions` task types,
  replacing `MonitorSubmittedTransactions`
- Update integration tests to use the new timer delays

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lpahlavi lpahlavi force-pushed the lpahlavi/split-monitor-timer branch from 0264072 to e4a94e8 Compare April 13, 2026 21:55
@lpahlavi lpahlavi marked this pull request as ready for review April 13, 2026 21:55
@lpahlavi lpahlavi requested a review from a team as a code owner April 13, 2026 21:55
Comment thread integration_tests/tests/tests.rs Outdated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
lpahlavi and others added 5 commits April 14, 2026 11:26
The expiry check is `slot + MAX_BLOCKHASH_AGE < current_slot` (strict),
so the minimal expired slot is `INITIAL_SLOT + MAX_BLOCKHASH_AGE + 1`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…riants

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…behavior

The sol-rpc canister rounds the slot from getSlot down to the nearest
multiple of 20 before making getBlock requests. Update get_block_request
in the mock fixtures to match this behavior, so tests work with any slot
value rather than requiring the slot to already be a multiple of 20.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… met

The SOL RPC canister rounds getSlot results down to the nearest multiple
of 20 before returning the slot to callers. Using INITIAL_SLOT +
MAX_BLOCKHASH_AGE + 1 as resubmission_slot gave 350_000_151, which rounds
down to 350_000_140 — not enough to trigger the expiry check
(350_000_150 < 350_000_140 is false).

Adding SOL_RPC_SLOT_ROUNDING + 1 ensures the rounded slot is strictly
greater than the expiry threshold.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lpahlavi lpahlavi merged commit 0c77279 into main Apr 14, 2026
10 checks passed
@lpahlavi lpahlavi deleted the lpahlavi/split-monitor-timer branch April 14, 2026 11:54
lpahlavi added a commit that referenced this pull request Apr 14, 2026
## Summary

Refactors all timer-based processing functions to a single-round,
immediately-rescheduling pattern:

- Each timer invocation processes one round of up to
`MAX_CONCURRENT_RPC_CALLS` batches, then immediately reschedules itself
with `Duration::ZERO` if work remains
- Rescheduling uses a `scopeguard` that fires on drop (including
panics); defused when all work fits in the current round
- The `more_to_process` flag is computed from a snapshot of the queue
**before** processing begins, so items added concurrently during
execution don't trigger a spurious reschedule

## Stack

- Based on: #120 (split monitor timer)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

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