Skip to content

fix: prevent intent tx signature aliasing on first commit after re-delegation#1408

Merged
GabrielePicco merged 7 commits into
masterfrom
fix/first-commit-tx-uniqueness
Jul 10, 2026
Merged

fix: prevent intent tx signature aliasing on first commit after re-delegation#1408
GabrielePicco merged 7 commits into
masterfrom
fix/first-commit-tx-uniqueness

Conversation

@GabrielePicco

@GabrielePicco GabrielePicco commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Problem

The committor builds intent transactions from fully deterministic inputs. After an undelegate → re-delegate cycle the delegation metadata nonce restarts at 0, so the next intent's first commit (nonce 1) can be byte-identical to a prior instance's landed commit:

Fix

Intents whose commit uses nonce ≤ 1 are tagged with the existing per-intent uniqueness noop (spl-noop instruction carrying the intent id, already used for standalone-action intents), on all their stages — the two-stage finalize tx carries no nonce bytes, so it aliases across cycles exactly like the commit tx. Collisions are only possible at first-commit (the on-chain nonce never regresses otherwise), so other intents are left untouched. Retries of the same intent keep the same id, preserving intentional dedup.

Summary by CodeRabbit

  • New Features
    • Added per-intent uniqueness no-op markers to commit/finalize flows to improve action/message distinction.
    • Transaction sizing and lookup-table planning now reserve and simulate space for the marker instruction.
    • Added the required noop program to integration-test devnet configurations.
  • Bug Fixes
    • Improved recovery when cached/stale commit IDs or transaction-size limits occur by preserving the correct uniqueness marker across retries.
  • Tests
    • Expanded coverage for first-commit vs non-first commits, finalize-only, empty inputs, and verifying marker instruction presence/fit behavior.

…legation

The committor builds intent transactions from fully deterministic inputs.
After an undelegate -> re-delegate cycle the delegation metadata nonce
restarts at 0, so the next intent's first commit (nonce 1) can produce a
transaction byte-identical to a prior instance's landed commit: same nonce,
same committed state, same cached blockhash (5s TTL). Identical bytes yield
an identical ed25519 signature, the skip-preflight send is deduped by the
network, and the status-based confirmer instantly matches the old
transaction - the intent is reported successful without anything being
sent, leaving the account stuck delegated.

Tag intents whose commit uses nonce <= 1 with the existing per-intent
uniqueness noop (spl-noop instruction carrying the intent id) on all their
stages, and reserve the noop's constant size in the strategist fit checks
so strategy selection matches the assembled transaction. Retries of the
same intent keep the same id, preserving intentional dedup.
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@GabrielePicco, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 35 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: dccd2e1c-af31-4533-885c-431bd09e7050

📥 Commits

Reviewing files that changed from the base of the PR and between 8593231 and 4bb1f43.

📒 Files selected for processing (2)
  • .agents/context/crates/magicblock-committor-service.md
  • magicblock-committor-service/src/intent_executor/two_stage_executor.rs
📝 Walkthrough

Walkthrough

The committor derives a per-intent uniqueness nonce for first commits and propagates it through single-stage and two-stage execution. Recovery paths preserve or restore the nonce. Strategy sizing, ALT fitting, and transaction preparation include the uniqueness noop, while tests and integration configurations are updated accordingly.

Suggested reviewers: snawaz, bmuddha

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/first-commit-tx-uniqueness

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fa0ac8fd6d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread magicblock-committor-service/src/tasks/task_strategist.rs Outdated
Reserve the noop's space only for strategies that will actually carry it,
instead of unconditionally padding every fit estimate: non-first commits at
the wire-size boundary would otherwise be forced into buffer/ALT paths or
rejected with FailedToFitError for transactions that fit. The strategist now
receives the nonce, accounts for it in both fit checks, and sets it on the
strategies it returns.
Intent transactions for first commits now carry the spl-noop uniqueness
instruction, so the program must exist on the base layer like it does on
mainnet/devnet. Dump of noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV from
mainnet, registered in every devnet config that loads dlp.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 708b229f7a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread magicblock-committor-service/src/tasks/task_strategist.rs

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
magicblock-committor-service/src/intent_executor/mod.rs (1)

620-666: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add test coverage for CommitFinalize tasks in requires_uniqueness_nonce.

The function handles BaseTaskImpl::CommitFinalize(task) => task.commit_id <= 1, but the test only covers Commit and Finalize variants. A CommitFinalize task with commit_id <= 1 is untested.

🧪 Suggested test additions
     fn test_requires_uniqueness_nonce_on_first_commit_only() {
         let finalize = BaseTaskImpl::Finalize(FinalizeTask {
             delegated_account: Pubkey::new_unique(),
         });
+        let commit_finalize = BaseTaskImpl::CommitFinalize(
+            CommitFinalizeTask {
+                commit_id: 1,
+                committed_account: CommittedAccount {
+                    pubkey: Pubkey::new_unique(),
+                    account: Account::default(),
+                    remote_slot: Default::default(),
+                },
+                delivery_details: CommitDelivery::StateInArgs,
+            }
+        );

         assert!(requires_uniqueness_nonce(&[commit_task(1)]));
         assert!(requires_uniqueness_nonce(&[commit_task(5), commit_task(1)]));
         assert!(!requires_uniqueness_nonce(&[commit_task(2)]));
         assert!(!requires_uniqueness_nonce(&[finalize]));
+        assert!(requires_uniqueness_nonce(&[commit_finalize]));
+        assert!(!requires_uniqueness_nonce(&[commit_task(2), finalize]));
         assert!(!requires_uniqueness_nonce(&[]));
     }

Note: The exact CommitFinalizeTask struct fields may differ; adjust the constructor to match the actual type definition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-committor-service/src/intent_executor/mod.rs` around lines 620 -
666, Add test coverage for the CommitFinalize branch in
requires_uniqueness_nonce. Construct CommitFinalizeTask values using the actual
required fields, then assert commit_id values 1 (or 0) return true and a value
greater than 1 returns false; retain the existing Commit and Finalize
assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@magicblock-committor-service/src/intent_executor/mod.rs`:
- Around line 620-666: Add test coverage for the CommitFinalize branch in
requires_uniqueness_nonce. Construct CommitFinalizeTask values using the actual
required fields, then assert commit_id values 1 (or 0) return true and a value
greater than 1 returns false; retain the existing Commit and Finalize
assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bc6f2923-f9aa-427a-ae65-577b0f27b0ee

📥 Commits

Reviewing files that changed from the base of the PR and between fa0ac8f and 708b229.

⛔ Files ignored due to path filters (1)
  • test-integration/schedulecommit/elfs/noop.so is excluded by !**/*.so
📒 Files selected for processing (13)
  • magicblock-committor-service/src/intent_executor/mod.rs
  • magicblock-committor-service/src/tasks/task_strategist.rs
  • test-integration/configs/aml.devnet.toml
  • test-integration/configs/chainlink-conf.devnet.toml
  • test-integration/configs/claim-fees-test.toml
  • test-integration/configs/cloning-conf.devnet.toml
  • test-integration/configs/committor-conf.devnet.toml
  • test-integration/configs/config-conf.devnet.toml
  • test-integration/configs/restore-ledger-conf.devnet.toml
  • test-integration/configs/schedule-task.devnet.toml
  • test-integration/configs/schedulecommit-conf.devnet.toml
  • test-integration/configs/validator-offline.devnet.toml
  • test-integration/test-committor-service/tests/test_intent_executor.rs

The first-commit uniqueness noop occupies 44 bytes of the 1232-byte packet,
moving the diff-in-args boundary for these order-book commits from 680/681
to 636/637 (verified against a local devnet). Document the noop's rationale,
scope, and fit accounting in the committor-service guide.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 63c7992c56

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread magicblock-committor-service/src/intent_executor/mod.rs

@taco-paco taco-paco left a comment

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.

Looks good! Some renamings are due + some places have divergence in logic now which has to be corrected.

attempt_lookup_tables( could be simplified and made less error prone by reusing existing logic and avoiding duplication

Comment thread magicblock-committor-service/src/tasks/task_strategist.rs Outdated
Comment thread magicblock-committor-service/src/intent_executor/utils.rs Outdated
Comment thread magicblock-committor-service/src/tasks/task_strategist.rs Outdated
Comment thread magicblock-committor-service/src/tasks/task_strategist.rs Outdated
Comment thread magicblock-committor-service/src/tasks/task_strategist.rs Outdated
Comment thread magicblock-committor-service/src/tasks/task_strategist.rs Outdated
…ecovery

- Rename standalone_action_nonce/noop naming to uniqueness_nonce/noop now
  that it covers first-commit intents, not only standalone actions.
- attempt_lookup_tables reuses assemble_tasks_tx_with_uniqueness_nonce and
  collect_lookup_table_keys (which now folds the noop into involved-pubkey
  collection), so fit checks cannot diverge from assembled transactions.
- handle_commit_id_error re-tags the strategy with the intent id when a
  stale-cache retry lands back on commit nonce 1 after a re-delegation:
  that retry is exactly the first-commit transaction the noop must
  disambiguate. Executors carry the intent id for this.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 859323163b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread magicblock-committor-service/src/intent_executor/utils.rs

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.agents/context/crates/magicblock-committor-service.md:
- Around line 243-246: Reword the finalize-stage sentence in the “Per-intent
uniqueness noop” section to state that finalize stages also receive the same
per-intent uniqueness noop protection, removing the implication that they omit
nonce bytes or alias without the noop.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4cd08678-9f9c-463d-8891-8a9cd54bd8f0

📥 Commits

Reviewing files that changed from the base of the PR and between 708b229 and 8593231.

📒 Files selected for processing (12)
  • .agents/context/crates/magicblock-committor-service.md
  • magicblock-committor-service/src/intent_executor/mod.rs
  • magicblock-committor-service/src/intent_executor/single_stage_executor.rs
  • magicblock-committor-service/src/intent_executor/two_stage_executor.rs
  • magicblock-committor-service/src/intent_executor/utils.rs
  • magicblock-committor-service/src/tasks/task_strategist.rs
  • magicblock-committor-service/src/tasks/utils.rs
  • magicblock-committor-service/src/transaction_preparator/mod.rs
  • test-integration/test-committor-service/tests/test_delivery_preparator.rs
  • test-integration/test-committor-service/tests/test_intent_executor.rs
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • test-integration/test-committor-service/tests/test_transaction_preparator.rs

Comment thread .agents/context/crates/magicblock-committor-service.md
When commit-id recovery re-tags the commit stage as a first commit, the
already-built finalize strategy must carry the noop too: its bytes contain
nothing per-instance and alias a prior delegation's finalize signature the
same way. A boundary-sized stage that no longer fits with the noop fails
loudly at the preparator's fit check rather than silently aliasing.
@GabrielePicco GabrielePicco requested a review from taco-paco July 10, 2026 08:37
Comment thread magicblock-committor-service/src/intent_executor/utils.rs
@GabrielePicco GabrielePicco requested a review from taco-paco July 10, 2026 09:20
@GabrielePicco GabrielePicco merged commit 8365a7f into master Jul 10, 2026
54 checks passed
@GabrielePicco GabrielePicco deleted the fix/first-commit-tx-uniqueness branch July 10, 2026 12:52
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