Skip to content

Preflight oversized committor transactions before delivery prep#1286

Closed
GabrielePicco wants to merge 2 commits into
masterfrom
fix/committor-oversized-preflight
Closed

Preflight oversized committor transactions before delivery prep#1286
GabrielePicco wants to merge 2 commits into
masterfrom
fix/committor-oversized-preflight

Conversation

@GabrielePicco
Copy link
Copy Markdown
Collaborator

@GabrielePicco GabrielePicco commented Jun 3, 2026

Summary

  • Reject oversized assembled committor transactions with FailedToFitError before they are sent.
  • Split delivery preparation so the real ALT-backed transaction layout is checked before buffer accounts are created.
  • Route pre-send FailedToFitError through the existing single-stage split fallback and recognize the shorter RPC base64 encoded too large error message.

Root cause

Oversized single-stage transactions could still reach delivery preparation, or be classified only after sendTransaction, because the final assembled transaction size was not checked at the same boundary used for actual submission.

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Enhanced detection of oversized transactions to catch additional error scenarios.
    • Improved error recovery handling for transaction preparation edge cases.
  • Refactor

    • Optimized transaction preparation process with better sequencing of internal operations.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

Warning

Review limit reached

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

More reviews will be available in 23 minutes and 49 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

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.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f6e95046-7532-4dc0-86f7-e8ae52464862

📥 Commits

Reviewing files that changed from the base of the PR and between 84dc484 and ba21952.

📒 Files selected for processing (4)
  • magicblock-committor-service/src/intent_executor/mod.rs
  • magicblock-committor-service/src/intent_executor/utils.rs
  • magicblock-committor-service/src/transaction_preparator/error.rs
  • magicblock-committor-service/src/transaction_preparator/mod.rs
📝 Walkthrough

Walkthrough

This PR adds comprehensive transaction size validation to prevent oversized transaction assembly and implements proper error recovery. The core addition is a post-signing size check in assemble_tx_raw that validates base64-encoded transaction size. Error detection is expanded to recognize both "base64 encoded too large" and "VersionedTransaction too large" RPC error patterns. Error recovery logic is updated to treat single-stage split-limit errors as patched/recoverable. Delivery preparation is refactored into two smaller public methods (prepare_tasks_for_delivery and prepare_lookup_tables_for_delivery) that execute sequentially, and transaction preparation orchestration is updated to use these new methods in the correct order.

Suggested reviewers

  • thlorenz
  • snawaz
  • bmuddha
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/committor-oversized-preflight

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 and usage tips.

@GabrielePicco
Copy link
Copy Markdown
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2026

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@GabrielePicco GabrielePicco marked this pull request as ready for review June 3, 2026 17:08
@GabrielePicco GabrielePicco requested review from snawaz and taco-paco June 3, 2026 17:08
Copy link
Copy Markdown

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

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: 84dc4847a2

ℹ️ 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 Outdated
Copy link
Copy Markdown

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

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: ba21952ddd

ℹ️ 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/transaction_preparator/mod.rs
Copy link
Copy Markdown
Contributor

@taco-paco taco-paco left a comment

Choose a reason for hiding this comment

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

Thanks for the fix!
Overall seems like the main point was

        if serialize_and_encode_base64(&tx).len() > MAX_ENCODED_TRANSACTION_SIZE
        {
            return Err(TaskStrategistError::FailedToFitError);
        }

But PR included other changes on delivery preparation. Hope in the future we could make PRs more atomic.

Added comments on both matters.

Additionally as new patching logic appeared it would be good add tests in corresponding file that checks exactly patching correctness and recovery of intents. See
test-integration/test-committor-service/tests/test_intent_executor.rs

}
Err(IntentExecutorError::FailedFinalizePreparationError(
TransactionPreparatorError::FailedToFitError,
)) if !committed_pubkeys.is_empty() => (None, true),
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.

If this error is handled by splitting into two stage flow, I'd assume we want to add it into patched report. Anything that is recoverd would be there, why do we return None here?

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.

sane as

handle_cpi_limit_error(
&self.authority.pubkey(),
strategy,
cleanup_lookup_tables,
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.

Additionally the tests are missing for new logic. To validate this case please add test into test-integration/test-committor-service/tests/test_intent_executor.rs

Comment on lines +88 to 111
pub async fn prepare_lookup_tables_for_delivery(
&self,
authority: &Keypair,
strategy: &TransactionStrategy,
) -> DeliveryPreparatorResult<Vec<AddressLookupTableAccount>> {
let _timer = metrics::observe_committor_intent_alt_preparation_time();
self.prepare_lookup_tables(authority, &strategy.lookup_tables_keys)
.await
.map_err(DeliveryPreparatorError::FailedToCreateALTError)
}

/// Prepares buffers and necessary pieces for optimized TX
pub async fn prepare_for_delivery<P: IntentPersister>(
&self,
authority: &Keypair,
strategy: &mut TransactionStrategy,
persister: &Option<P>,
) -> DeliveryPreparatorResult<Vec<AddressLookupTableAccount>> {
let lookup_tables = self
.prepare_lookup_tables_for_delivery(authority, strategy)
.await?;
self.prepare_tasks_for_delivery(authority, strategy, persister)
.await?;
Ok(lookup_tables)
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.

What is the reason for split up here?
Now instead of preparing in parallel we prepare ALTs first and then buffers.

Both of them need to be prepared and one doesn't depend on another, those should be prepared in parallel as before

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.

can be discussed in this thread

Comment on lines +106 to +107
// Prepare lookup tables before buffers so real ALT layout is checked
// before creating buffer accounts.
Copy link
Copy Markdown
Contributor

@taco-paco taco-paco Jun 4, 2026

Choose a reason for hiding this comment

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

Could you elaborate on what is ALT layout check? Why buffer preparation should be concerned with it?

Buffer preparation is agnostic to ALTs and don't use it, additionally buffer accounts are deterministically defined from commit id and will be the same anyway. If they're in ALTs they will be there in next run.

Buffer preparation also handles already prepared state. For now I don't see reason for this split as it will just make preparation slower

);
execution_report.dispose(cleanup);
execution_report.add_patched_error(execution_err);
if let Some(execution_err) = execution_err {
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.

If we got here it means we handled some error by splitting into two stage, that error should be added in report.

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.

In case we don't want some errors in report for whatever reason, we could add fn reportable(&self) -> bool on Error which would be a cleaner solution

)?;
)
.map_err(|err| match err {
TaskStrategistError::FailedToFitError => {
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.

This highlights my doubts on need of new PreflightFailedToFitError variant.

FailedToFitError is error returned "preflight". TaskStrategist returns it preflight, new assemble_tasks_tx_with_standalone_action_nonce returns it preflight.

What is a reason for another enum variant?

Open to renaming it if it is confusing.

)) if !committed_pubkeys.is_empty() => (None, true),
Err(IntentExecutorError::FailedFinalizePreparationError(
TransactionPreparatorError::PreflightFailedToFitError,
)) if !committed_pubkeys.is_empty() => (None, false),
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 we return false here while true for FailedToFitError?

let strategy = single_stage_executor.consume_strategy();
let (commit_strategy, finalize_strategy, cleanup) =
handle_cpi_limit_error(&self.authority.pubkey(), strategy);
handle_cpi_limit_error(
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.

Let's rename function for clarity as it not only handle cpi limit error now

@GabrielePicco
Copy link
Copy Markdown
Collaborator Author

Closing as this PR seems the proper fix: #1285 rather than the defensive logic applied here

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