Skip to content

Fix result ordering in get_multiple_accounts_with_config#1094

Open
LisaMoore01 wants to merge 5 commits intomagicblock-labs:masterfrom
LisaMoore01:LisaMoore01-patch-1
Open

Fix result ordering in get_multiple_accounts_with_config#1094
LisaMoore01 wants to merge 5 commits intomagicblock-labs:masterfrom
LisaMoore01:LisaMoore01-patch-1

Conversation

@LisaMoore01
Copy link
Copy Markdown

@LisaMoore01 LisaMoore01 commented Mar 25, 2026

Summary

This PR fixes a issue in get_multiple_accounts_with_config where the results of parallel RPC requests could be returned out of order.

Previously, chunks of pubkeys were processed in parallel using JoinSet, and results were collected in completion order. This could break the positional correspondence between input pubkeys and returned accounts, leading to subtle bugs for consumers relying on correct ordering.

Changes:

  • Preserve chunk indices when spawning tasks
  • Reassemble results according to chunk index to maintain correct order
  • Ensure proper error handling for missing or failed chunks

This guarantees deterministic, correctly ordered results for RPC methods like getMultipleAccounts.

Compatibility

  • No breaking changes
  • Config change (describe):
  • Migration needed (describe):

Testing

  • tests (or explain)

Checklist

  • docs updated (if needed)
  • closes #

Summary by CodeRabbit

  • Bug Fixes

    • Batch account retrieval now preserves the original input order when fetching concurrently, ensuring results align with request positions.
  • Error Handling

    • Calls with an invalid batch size (zero) now return a clear error instead of proceeding.
    • Improved error reporting and detection for unexpected failures or missing pieces during parallel chunked fetches, making failures easier to diagnose.

This PR fixes a critical issue in `get_multiple_accounts_with_config` where the results of parallel RPC requests could be returned out of order. 

Previously, chunks of pubkeys were processed in parallel using `JoinSet`, and results were collected in completion order. This could break the positional correspondence between input pubkeys and returned accounts, leading to subtle bugs for consumers relying on correct ordering.

Changes:
- Preserve chunk indices when spawning tasks
- Reassemble results according to chunk index to maintain correct order
- Ensure proper error handling for missing or failed chunks

This guarantees deterministic, correctly ordered results for RPC methods like `getMultipleAccounts`.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 25, 2026

📝 Walkthrough

Walkthrough

Added an Other(String) variant to MagicBlockRpcClientError. MagicblockRpcClient::get_multiple_accounts_with_config now returns an Other error when max_per_fetch == 0. Concurrent fetching spawns tasks that return (chunk_idx, rpc_result); after joining, per-chunk results are placed into a preallocated chunks vector sized from pubkeys.len() and max_per_fetch. The final output Vec is reconstructed by iterating chunks in index order, with explicit errors for out-of-bounds chunk indices and for any missing chunk results.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@magicblock-rpc-client/src/lib.rs`:
- Line 323: The assignment to max_per_fetch (let max_per_fetch =
max_per_fetch.unwrap_or(MAX_MULTIPLE_ACCOUNTS);) should guard against a caller
passing Some(0) which would later cause a division-by-zero; update this to
coerce 0 to a safe minimum (e.g., 1 or MAX_MULTIPLE_ACCOUNTS) before use — for
example by replacing the unwrap_or with a match or check that maps 0 to a
nonzero default so downstream math (division or modulo) using max_per_fetch
cannot panic.
- Around line 355-360: The code attempts to construct
MagicBlockRpcClientError::Other in get_multiple_accounts_with_config when
chunk_idx is out of bounds, but the MagicBlockRpcClientError enum lacks an Other
variant; add an Other(String) error variant to the MagicBlockRpcClientError enum
(with the same error display attribute pattern used by the other variants, e.g.
#[error("{0}")]) so the calls in get_multiple_accounts_with_config (and any
other sites constructing Other) compile cleanly.
🪄 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: 7e432dc9-ff34-4c6c-9594-3eb7b46dfec9

📥 Commits

Reviewing files that changed from the base of the PR and between 55f969d and 97286d9.

📒 Files selected for processing (1)
  • magicblock-rpc-client/src/lib.rs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In `@magicblock-rpc-client/src/lib.rs`:
- Around line 358-371: The loop is destructuring a tuple already produced by
JoinSet::join_all(), so remove the erroneous match-on-Result and directly
destructure the tuple from chunked_results; i.e., for each result from
chunked_results do let (chunk_idx, rpc_result) = result; then use let accs =
rpc_result?; to propagate task errors (or map them as needed) and keep the
existing bounds check and assignment to chunks[chunk_idx]; adjust error
conversions so the ? on rpc_result produces the correct MagicBlockRpcClientError
if necessary.
🪄 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: c1f0311c-e061-47bf-91aa-19fbdd108a88

📥 Commits

Reviewing files that changed from the base of the PR and between 97286d9 and fe2bee8.

📒 Files selected for processing (1)
  • magicblock-rpc-client/src/lib.rs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@magicblock-rpc-client/src/lib.rs`:
- Around line 326-378: Add two regression tests for
get_multiple_accounts_with_config: one that passes max_per_fetch = Some(0) (or
None that resolves to 0) and asserts the function returns the expected error
variant (MagicBlockRpcClientError::Other with the "max_per_fetch must be > 0"
message), and another that simulates multiple RPC chunks completing out of order
(e.g., by mocking/self-hosting the client so chunk N completes before chunk M)
and asserts the flattened results preserve positional correspondence with the
input pubkeys; target the async chunking behavior around JoinSet and the
reassembly logic that writes into chunks[chunk_idx] to ensure ordering doesn't
regress.
- Around line 351-377: The code uses JoinSet::join_all() which can panic on
JoinError and computes num_chunks with a potentially overflowing formula; change
to iteratively call join_next().await in a loop until no more tasks, map any
JoinError or task panics into a MagicBlockRpcClientError (e.g., from
get_multiple_accounts_with_config), collect (chunk_idx, rpc_result) pairs as
they complete, and build the chunks Vec by deriving its length from the actual
chunk indices observed (or from the chunking logic that created the tasks)
instead of using (pubkeys.len() + max_per_fetch - 1) / max_per_fetch; keep the
existing bounds check on chunk_idx and error paths for missing chunks.
🪄 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: ae1c6769-df73-47f6-8360-6460572a4388

📥 Commits

Reviewing files that changed from the base of the PR and between fe2bee8 and 4f17c33.

📒 Files selected for processing (1)
  • magicblock-rpc-client/src/lib.rs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@magicblock-rpc-client/src/lib.rs`:
- Around line 371-380: The loop over chunks currently calls
chunk.ok_or_else(...) and returns MagicBlockRpcClientError::Other with a generic
message; change the loop to use enumerate (for (i, chunk) in chunks.enumerate())
and include the chunk index in the error text (e.g.,
format!("get_multiple_accounts_with_config: missing chunk result at index {}",
i)) so the MagicBlockRpcClientError::Other payload identifies which chunk failed
(update the ok_or_else closure to capture i and build the formatted message).
- Around line 335-339: The loop currently reassigns chunk_count each iteration;
instead compute chunk_count once before iterating over pubkeys.chunks by
calculating the number of chunks from pubkeys.len() and max_per_fetch (e.g., use
integer ceiling division or (len + max_per_fetch - 1) / max_per_fetch) and then
iterate with for (chunk_idx, pubkey_chunk) in
pubkeys.chunks(max_per_fetch).enumerate() without mutating chunk_count inside
the loop; update references to chunk_count accordingly.
🪄 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: 6a9dd75c-6af1-4f37-a8dc-24fde98e715b

📥 Commits

Reviewing files that changed from the base of the PR and between 4f17c33 and 398754d.

📒 Files selected for processing (1)
  • magicblock-rpc-client/src/lib.rs

@GabrielePicco GabrielePicco requested a review from bmuddha April 3, 2026 07:54
@bmuddha bmuddha requested review from thlorenz and removed request for bmuddha April 3, 2026 09:03
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