Skip to content

Conversation

@Dodecahedr0x
Copy link
Contributor

@Dodecahedr0x Dodecahedr0x commented Nov 18, 2025

Summary by CodeRabbit

  • New Features

    • Compressed delegation support across services and programs.
    • Photon indexer integration for fetching compressed account data.
    • Compression configuration (endpoint + API key) and CLI/config wiring.
  • Bug Fixes

    • Updated Solana account import paths and validator/test runner fixes.
    • Various instruction/serialization consistency improvements.
  • Tests

    • Expanded integration and unit tests for compressed delegation flows and new test utilities.
  • Documentation

    • Added integration test notes and updated READMEs/config samples.

✏️ Tip: You can customize this high-level summary in your review settings.

thlorenz and others added 30 commits September 8, 2025 17:37
also use the latest SVM patch
* bmuddha/epic/rpc:
  tests: added fee test, fixed mutator tests
* bmuddha/epic/rpc:
  chore: rename magicblock-gateway to magicblock-aperture
* bmuddha/epic/rpc:
  fix: use port retries in test, fix blockstore
* bmuddha/epic/rpc:
  fixes: use random ports with retries in tests
since accountsdb snapshots take place in async context
(due to the slot advancement happening in tickers),
we end up blocking the runtime, while trying to acquire
a sync lock. In order to avoid that, this PR moves the
whole lock acquisition and snapshot logic a separate thread
and performs it in the background, which makes slot advancement
a non-blocking operation.
Copy link
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: 27

Caution

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

⚠️ Outside diff range comments (2)
magicblock-config/src/validator.rs (1)

37-38: Inconsistent pattern with other optional fields.

The base_fees field now lacks a #[serde(default)] attribute, while the fqdn field (lines 30-33) retains #[serde(default = "default_fqdn")] despite both being Option types. Since Option<T> automatically defaults to None during deserialization when the field is missing, the explicit serde default is technically redundant in both cases.

For consistency and maintainability, consider either:

  • Removing #[serde(default = "default_fqdn")] from fqdn to match the simpler pattern now used for base_fees, or
  • Adding back #[serde(default = "default_base_fees")] to base_fees to maintain the explicit pattern used for fqdn

</comment_end>

magicblock-aperture/src/state/blocks.rs (1)

55-69: Consider seeding the expiring cache with the initial latest block in BlocksCache::new

BlocksCache::new now accepts a latest: LastCachedBlock and stores it in self.latest, but the underlying ExpiringCache starts empty and only receives entries via set_latest. That means the block returned by ledger.latest_block().load() is immediately visible through get_latest()/block_height(), but not through cache lookups until the first BlockUpdate arrives.

If any callers rely on validating the current latest blockhash via the cache (using the Deref interface) before the first set_latest call, this is a behavioral change. If you want the initial ledger block to be usable for cache‑based validation as well, consider pushing it into cache inside new:

pub(crate) fn new(blocktime: u64, latest: LastCachedBlock) -> Self {
    const BLOCK_CACHE_TTL: Duration = Duration::from_secs(60);
    assert!(blocktime != 0, "blocktime cannot be zero");

    let blocktime_ratio = SOLANA_BLOCK_TIME / blocktime as f64;
    let block_validity = blocktime_ratio * MAX_VALID_BLOCKHASH_SLOTS;
-   let cache = ExpiringCache::new(BLOCK_CACHE_TTL);
-   Self {
-       latest: ArcSwapAny::new(latest.into()),
-       block_validity: block_validity as u64,
-       cache,
-   }
+   let mut cache = ExpiringCache::new(BLOCK_CACHE_TTL);
+   cache.push(latest.blockhash, BlockMeta { slot: latest.slot, /* fill other fields as appropriate */ });
+   Self {
+       latest: ArcSwapAny::new(latest.into()),
+       block_validity: block_validity as u64,
+       cache,
+   }
}

(Adjust the BlockMeta construction to match your actual type.) If no callers depend on cache visibility for the initial block, leaving it as‑is is fine, but it’s worth confirming the intended semantics.

♻️ Duplicate comments (9)
magicblock-processor/src/executor/processing.rs (1)

342-410: Critical security vulnerability: gasless feepayer protection is ineffective due to mutating inner status instead of converting to hard error.

This is a duplicate of the previously flagged issue. Despite being marked as addressed, both security concerns persist in the current code:

Issue 1: Account mutations are still persisted despite error status

Lines 368-369 and 401 set executed.execution_details.status = Err(...), but leave result as Ok(ProcessedTransaction::Executed(...)). This means:

  • Line 76 still calls commit_accounts(feepayer, &processed, is_replay)
  • For failed transactions, lines 290-295 persist the feepayer account (first account)
  • Lines 323-326 write dirty feepayer accounts to AccountsDb
  • Illegal feepayer mutations get persisted despite the error, defeating the protection described in lines 353-357

Issue 2: Auto-airdrop condition polarity appears inverted

Line 361 uses !self.is_auto_airdrop_lamports_enabled, applying the guard only when auto-airdrop is disabled. However:

  • The comment (lines 353-357) aims to prevent "validator losing funds upon balance settling"
  • This risk only exists when auto-airdrop is enabled (validator funds accounts)
  • Current logic is backwards

Apply the previously suggested fix:

 fn verify_account_states(&self, processed: &mut ProcessedTransaction) {
-    let ProcessedTransaction::Executed(executed) = processed else {
+    let ProcessedTransaction::Executed(ref mut executed) = processed else {
         return;
     };
     let txn = &executed.loaded_transaction;
     // ... existing checks ...
     
     if gasless {
         let undelegated_feepayer_was_modified = feepayer
             .map(|acc| {
                 (acc.1.is_dirty()
-                    && !self.is_auto_airdrop_lamports_enabled
+                    && self.is_auto_airdrop_lamports_enabled
                     && (acc.1.lamports() != 0 || rollback_lamports != 0))
                     && !acc.1.delegated()
                     && !acc.1.privileged()
             })
             .unwrap_or_default();
         if undelegated_feepayer_was_modified {
-            executed.execution_details.status =
-                Err(TransactionError::InvalidAccountForFee);
-            let logs = executed
-                .execution_details
-                .log_messages
-                .get_or_insert_default();
-            let msg = "Feepayer balance has been modified illegally".into();
-            logs.push(msg);
-            return;
+            // Convert to hard error so no account mutations are committed
+            *processed = ProcessedTransaction::FeesOnly(/* construct appropriate FeesOnly variant */);
+            // OR better: change process() to return Err(TransactionError::InvalidAccountForFee)
+            // when verify_account_states detects violations
         }
     }
 }

Better approach: Have verify_account_states return a Result, and in process() (lines 174-177) convert the Ok(processed) to Err(...) when validation fails. This ensures the execution takes the early-return path in execute() (lines 56-68), which skips commit_accounts entirely.

Based on learnings.

programs/magicblock/src/mutate_accounts/process_mutate_accounts.rs (1)

329-331: Fix the rent_epoch assertion to match the modified value.

The modification at line 329 sets rent_epoch: Some(88), which is applied by the processor at lines 202-209. However, the assertion at line 383 still expects rent_epoch: u64::MAX. The test should verify that the account's rent_epoch is 88, not u64::MAX.

The compressed field handling (lines 331 and 375) is correct.

Apply this diff to fix the assertion:

         assert_matches!(
             modified_account.into(),
             Account {
                 lamports: 200,
                 owner: owner_key,
                 executable: true,
                 data,
-                rent_epoch: u64::MAX,
+                rent_epoch: 88,
             } => {
                 assert_eq!(data, modification.data.unwrap());
                 assert_eq!(owner_key, modification.owner.unwrap());
             }
         );

Also applies to: 375-388

magicblock-committor-service/src/intent_executor/task_info_fetcher.rs (1)

233-251: Guard against mismatched lengths between Photon results and requested pubkeys

compressed_accounts.items.into_iter().zip(pubkeys.iter()) will silently drop trailing pubkeys if items.len() < pubkeys.len(), so some requested accounts would never get a CompressedDelegationRecord or cached commit_id. That’s a latent correctness bug if the indexer ever returns fewer items than requested (even transiently).

Consider asserting or explicitly handling a length mismatch before zipping, e.g.:

-        let compressed_delegation_records = compressed_accounts
-            .items
+        let items = compressed_accounts.items;
+
+        debug_assert_eq!(
+            items.len(),
+            pubkeys.len(),
+            "expected one compressed account per pubkey ({} pubkeys, {} items)",
+            pubkeys.len(),
+            items.len(),
+        );
+
+        let compressed_delegation_records = items
             .into_iter()
             .zip(pubkeys.iter())
             .map(|(acc, pubkey)| {

If you’d rather fail loudly in release builds too, replace the debug_assert_eq! with a runtime check that returns a suitable TaskInfoFetcherError when the lengths differ.

test-integration/test-chainlink/src/ixtest_context.rs (1)

98-101: Fix PackedAddressTreeInfo queue index wiring and remove unused pda_seeds.

Two things to tighten up in delegate_compressed_counter:

  1. address_queue_pubkey_index is set to the merkle-tree index

    In the non‑redelegate branch:

    let address_merkle_tree_pubkey_index =
        remaining_accounts.insert_or_get(ADDRESS_TREE_PUBKEY);
    let state_queue_pubkey_index =
        remaining_accounts.insert_or_get(OUTPUT_QUEUE_PUBKEY);
    
    let packed_address_tree_info = PackedAddressTreeInfo {
        root_index: rpc_result.addresses[0].root_index,
        address_merkle_tree_pubkey_index,
        address_queue_pubkey_index: address_merkle_tree_pubkey_index,
    };

    address_queue_pubkey_index should reference the address‑queue account index, not the merkle‑tree index. Otherwise the Light CPI will see the wrong account in that slot. Consider:

    • Introducing a dedicated address‑queue constant (e.g., ADDRESS_QUEUE_PUBKEY) and inserting it into remaining_accounts to obtain address_queue_pubkey_index, or
    • If OUTPUT_QUEUE_PUBKEY is truly the address queue, rename the variable (and constant) accordingly and pass that index into address_queue_pubkey_index.

    Similarly, double‑check that state_queue_pubkey_index really is the intended value to feed into output_state_tree_index; the name suggests a queue rather than the state tree.

  2. Remove unused pda_seeds

    In the same function:

    let pda_seeds = FlexiCounter::seeds(&auth);
    let (pda, bump) = FlexiCounter::pda(&auth);

    pda_seeds is never read, so this binding can be dropped.

Also applies to: 401-494

magicblock-committor-service/src/tasks/args_task.rs (1)

1-8: Wire UndelegateArgs into compressed undelegate instructions (builder still incomplete).

ArgsTaskType::CompressedUndelegate now sets payer, delegated account, owner program, system program, and remaining accounts, but it never passes the actual undelegate arguments:

ArgsTaskType::CompressedUndelegate(value) => {
    compressed_delegation_client::UndelegateBuilder::new()
        .payer(*validator)
        .delegated_account(value.delegated_account)
        .owner_program(value.owner_program)
        .system_program(system_program::ID)
        .add_remaining_accounts(&value.compressed_data.remaining_accounts)
        .instruction()
}

By contrast, the test helper in ixtest_context.rs calls .args(UndelegateArgs { validity_proof, delegation_record_account_meta, compressed_delegated_record, .. }) before .add_remaining_accounts(..).instruction(). Here you already have:

  • value.compressed_data.proof
  • value.compressed_data.account_meta
  • value.compressed_data.compressed_delegation_record_bytes

but they are never used.

To avoid building an underspecified CPI:

  • Construct an UndelegateArgs from the compressed data (decoding CompressedDelegationRecord from the stored bytes, as done in the helper), and
  • Pass it via .args(UndelegateArgs { .. }) on the builder before .add_remaining_accounts(..).

Also double‑check whether *validator is the intended payer for compressed undelegation or whether this should instead be the delegated account owner (mirroring the helper).

Also applies to: 65-167, 203-213, 247-302

magicblock-committor-service/src/tasks/task_builder.rs (1)

260-279: Compressed finalize with base actions still silently downgrades on compressed-data fetch errors

In process_commit for CommitType::WithBaseActions, the compressed path still swallows get_compressed_data errors:

if is_compressed {
    let photon_client = photon_client.as_ref().ok_or(
        TaskBuilderError::PhotonClientNotFound,
    )?;
    compressed_data.push(
        get_compressed_data(
            &account.pubkey,
            photon_client,
            None,
        )
        .await
        .ok(),           // <-- error converted to None
    );
} else {
    compressed_data.push(None);
}

Whereas the CommitType::Standalone + is_compressed branch now correctly propagates failures (.await?).

If compressed finalize is expected to be required whenever the intent is compressed, silently converting failures into None (falling back to non-compressed FinalizeTask) can hide Photon/indexer issues and produce inconsistent behavior between pure compressed commits and compressed+base-action commits.

Options:

  • If silent downgrade is desired, at least log/metric the error before pushing None so operators can see compressed finalize is failing:
match get_compressed_data(&account.pubkey, photon_client, None).await {
    Ok(data) => compressed_data.push(Some(data)),
    Err(err) => {
        warn!(
            "Failed to fetch compressed data for {} in finalize+base-actions: {err}",
            account.pubkey
        );
        compressed_data.push(None);
    }
}
  • If downgrade is not desired, mirror the Standalone path and propagate TaskBuilderError::CompressedDataFetchError instead of using .ok().

This would make compressed behavior consistent across commit/finalize paths.

magicblock-chainlink/src/remote_account_provider/mod.rs (2)

1177-1193: Critical: Unwrap will panic on Photon indexer errors.

Line 1180 contains .unwrap() on the Photon client call which will panic if the indexer is unavailable, returns an error, or times out.

This was previously flagged and marked as addressed (commits 3dd8b8d to fcf3260), but appears to still be present. If this is a regression, it should be re-fixed.

Apply proper error handling:

-        // TODO: @@@ unwrap and/or retry
-        let (compressed_accounts, slot) = photon_client
+        let (compressed_accounts, slot) = photon_client
             .get_multiple_accounts(&pubkeys, Some(min_context_slot))
             .await
-            .unwrap();
+            .map_err(|e| {
+                error!("Failed to fetch from Photon: {:?}", e);
+                RemoteAccountProviderError::FailedFetchingAccounts(
+                    format!("Photon fetch failed: {e:?}")
+                )
+            })?;

Update return type to:

async fn fetch_from_photon(...) -> Result<(FetchedRemoteAccounts, u64, u64), RemoteAccountProviderError>

1161-1169: Critical: Double unwrap will panic on task spawn or RPC errors.

Line 1161 contains .await.unwrap().unwrap() which will panic on either:

  • JoinError if the spawned task fails
  • The inner Result error from RPC operations

This was flagged and marked as addressed in previous reviews (commits 3dd8b8d to fcf3260), but appears to still be present in the current code. If this is a regression, it needs to be re-fixed.

Apply the previous fix pattern:

-            }).await.unwrap().unwrap();
-        // TODO: @@@ unwrap
-
-        (
-            FetchedRemoteAccounts::Rpc(remote_accounts),
+            }).await.unwrap()?;
+
+        Ok((
+            FetchedRemoteAccounts::Rpc(remote_accounts),
             found_count,
             not_found_count,
-        )
+        ))

Then update the return type of fetch_from_rpc to:

async fn fetch_from_rpc(...) -> Result<(FetchedRemoteAccounts, u64, u64), RemoteAccountProviderError>

And handle the error in the consolidation caller.

test-integration/programs/flexi-counter/src/processor.rs (1)

650-687: Tighten process_external_undelegate_compressed refund and data-restore logic

A couple of minor improvements here:

  1. Skip zero-lamport transfers

You already guard against underflow with checked_sub, but you still construct a transfer for amount 0 when the delegated account is already at the recorded lamports. You can avoid an unnecessary CPI:

-    invoke(
-        &system_instruction::transfer(
-            payer.key,
-            delegated_account.key,
-            args.delegation_record
-                .lamports
-                .checked_sub(delegated_account.lamports())
-                .ok_or(ProgramError::ArithmeticOverflow)?,
-        ),
-        &[payer.clone(), delegated_account.clone()],
-    )?;
+    let target_lamports = args.delegation_record.lamports;
+    let current_lamports = delegated_account.lamports();
+    let delta = target_lamports
+        .checked_sub(current_lamports)
+        .ok_or(ProgramError::ArithmeticOverflow)?;
+    if delta > 0 {
+        invoke(
+            &system_instruction::transfer(
+                payer.key,
+                delegated_account.key,
+                delta,
+            ),
+            &[payer.clone(), delegated_account.clone()],
+        )?;
+    }
  1. Optional: assert owner before realloc

Given this program is meant to restore the original flexi-counter account, you may also want an explicit owner check before realloc:

+    if delegated_account.owner != &crate::ID {
+        msg!(
+            "Unexpected owner for delegated account: {}",
+            delegated_account.owner
+        );
+        return Err(ProgramError::InvalidAccountData);
+    }

This would fail fast with a clearer error if the compressed delegation flow ever calls this entrypoint without reassigning the account back to crate::ID first, improving debuggability of the integration tests.

Comment on lines 108 to 128
#[test]
fn test_account_was_undelegated_and_remained_so() {
// Case A: The account was undelegated and remained so.
// Conditions:
// - is_delegated: false (account is not delegated to us on chain)
// - deleg_record: None (no delegation record associated)
// Expected: true (should override/clone as is)

let pubkey = Pubkey::default();
let is_delegated = false;
let remote_slot = 100;
let deleg_record = None;

assert!(!account_still_undelegating_on_chain(
&pubkey,
is_delegated,
remote_slot,
deleg_record,
&Pubkey::default(),
));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Correct the test comment - expected value is false, not true.

Line 114 states "Expected: true (should override/clone as is)" but the assertion on line 121 expects false (via !account_still_undelegating_on_chain(...)). The assertion is correct since Case A should return false to allow cloning the remote state. The comment should be updated to match.

-        // Expected: true (should override/clone as is)
+        // Expected: false (should override/clone remote state)
🤖 Prompt for AI Agents
In magicblock-chainlink/src/chainlink/account_still_undelegating_on_chain.rs
around lines 108 to 128, the test comment for Case A incorrectly says "Expected:
true"; update that line to "Expected: false (should override/clone as is)" so
the comment matches the assertion on line 121 which expects false; no code
changes are required beyond correcting the comment text to reflect the actual
expected value.

Copy link
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: 8

Caution

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

⚠️ Outside diff range comments (3)
test-integration/programs/schedulecommit/src/api.rs (1)

220-270: Remove duplicate function definition.

The function schedule_commit_and_undelegate_cpi_twice is defined twice (lines 220-244 and lines 246-270) with identical signatures and implementations. This will cause a compilation error.

Remove one of the duplicate definitions and update the remaining one to use the build_instruction helper for consistency:

-pub fn schedule_commit_and_undelegate_cpi_twice(
-    payer: Pubkey,
-    magic_program_id: Pubkey,
-    magic_context_id: Pubkey,
-    players: &[Pubkey],
-    committees: &[Pubkey],
-) -> Instruction {
-    let program_id = crate::id();
-    let mut account_metas = vec![
-        AccountMeta::new(payer, true),
-        AccountMeta::new(magic_context_id, false),
-        AccountMeta::new_readonly(magic_program_id, false),
-    ];
-    for committee in committees {
-        account_metas.push(AccountMeta::new(*committee, false));
-    }
-
-    Instruction::new_with_borsh(
-        program_id,
-        &ScheduleCommitInstruction::ScheduleCommitAndUndelegateCpiTwice(
-            players.to_vec(),
-        ),
-        account_metas,
-    )
-}
-
 pub fn schedule_commit_and_undelegate_cpi_twice(
     payer: Pubkey,
     magic_program_id: Pubkey,
     magic_context_id: Pubkey,
     players: &[Pubkey],
     committees: &[Pubkey],
 ) -> Instruction {
     let program_id = crate::id();
     let mut account_metas = vec![
         AccountMeta::new(payer, true),
         AccountMeta::new(magic_context_id, false),
         AccountMeta::new_readonly(magic_program_id, false),
     ];
     for committee in committees {
         account_metas.push(AccountMeta::new(*committee, false));
     }
 
-    Instruction::new_with_borsh(
+    let ix = ScheduleCommitInstruction::ScheduleCommitAndUndelegateCpiTwice(
+        players.to_vec(),
+    );
+    build_instruction(program_id, ix, account_metas)
-        program_id,
-        &ScheduleCommitInstruction::ScheduleCommitAndUndelegateCpiTwice(
-            players.to_vec(),
-        ),
-        account_metas,
-    )
 }
magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs (1)

592-620: Remove dead code variants from InternalError enum

The search confirms that CompressedDataNotFound, TransactionCreationError, and TransactionSigningError are never constructed or used anywhere in the codebase—they only appear in the enum definition.

Remove these three variants from the InternalError enum in magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs:595,604-607 to keep the error surface clean and avoid confusion about which error paths are actually reachable.

magicblock-chainlink/src/chainlink/fetch_cloner.rs (1)

678-749: Fix fold accumulator arity when introducing owned_by_deleg_compressed

The fold that partitions fetched accounts now destructures five accumulators (not_found, plain, owned_by_deleg, owned_by_deleg_compressed, programs) but the initializer only provides four vec![]. This won’t compile and also makes the intent less clear.

Initialize all five buckets explicitly:

-        let (not_found, plain, owned_by_deleg, owned_by_deleg_compressed, programs) =
-            accs.into_iter().zip(pubkeys).fold(
-                (vec![], vec![], vec![], vec![]),
+        let (not_found, plain, owned_by_deleg, owned_by_deleg_compressed, programs) =
+            accs.into_iter().zip(pubkeys).fold(
+                (vec![], vec![], vec![], vec![], vec![]),
                 |(
                     mut not_found,
                     mut plain,
                     mut owned_by_deleg,
                     mut owned_by_deleg_compressed,
                     mut programs,
                 ),
                  (acc, &pubkey)| {
                     …
                 },
             );
♻️ Duplicate comments (5)
magicblock-committor-service/src/intent_execution_manager/intent_execution_engine.rs (1)

778-784: Previous review suggestions have been addressed.

The addition of the _compressed parameter and the idiomatic closure pattern are correct and align with the trait signature changes for compressed delegation support.

programs/magicblock/src/schedule_transactions/process_schedule_commit.rs (1)

267-283: Intent selection for compressed vs non‑compressed flows looks correct; optional match refactor.

The four branches correctly cover all combinations of request_undelegation and compressed, mapping to the expected MagicBaseIntent variants and using CommitType::Standalone(committed_accounts) consistently. Ownership of committed_accounts is sound in this if/else chain.

As previously noted in an earlier review, you could switch to a match on (opts.request_undelegation, compressed) to make the exhaustiveness explicit and a bit more idiomatic, but this is purely stylistic and non‑blocking.

magicblock-committor-service/src/intent_executor/two_stage_executor.rs (1)

109-119: [Duplicate] Avoid silently swallowing errors when fetching commit transaction slot

The commit slot fetch at lines 111–119 uses .ok() to discard RPC errors without logging. Any network issue, node error, or transaction pruning collapses to None, losing observability into why the finalize preparation runs without slot information.

Consider logging the error before converting to None:

-        let commit_slot = self
-            .rpc_client
-            .get_transaction(
-                &commit_signature,
-                Some(RpcTransactionConfig::default()),
-            )
-            .await
-            .map(|tx| tx.slot)
-            .ok();
+        let commit_slot = match self
+            .rpc_client
+            .get_transaction(
+                &commit_signature,
+                Some(RpcTransactionConfig::default()),
+            )
+            .await
+        {
+            Ok(tx) => Some(tx.slot),
+            Err(err) => {
+                warn!("Failed to fetch commit transaction slot for {}: {err}", commit_signature);
+                None
+            }
+        };

This preserves existing behavior (finalize proceeds with None) while improving debuggability for Photon-indexed flows.

magicblock-chainlink/src/remote_account_provider/mod.rs (1)

900-1210: Handle JoinSet::join_all results and async errors instead of unwrapping

The new parallel RPC+Photon fetch path has a few correctness issues that can lead to panics or ignored errors:

  1. JoinSet::join_all() result is mis‑destructured

At lines around 937–952:

let (remote_accounts_results, found_count, not_found_count) =
    join_set.join_all().await.into_iter().fold(
        (vec![], 0, 0),
        |(remote_accounts_results, found_count, not_found_count),
         (accs, found_cnt, not_found_cnt)| {
            ( [remote_accounts_results, vec![accs]].concat(),
              found_count + found_cnt,
              not_found_count + not_found_cnt )
        },
    );

JoinSet::join_all() returns Vec<Result<T, JoinError>>, not Vec<T>. Destructuring directly as (accs, found_cnt, not_found_cnt) will not compile and, even if adjusted, would be ignoring potential JoinErrors. You need to pattern match each element, handle Ok((...)) vs Err(e), and decide how to treat failed fetch tasks.

  1. Double .unwrap() on tokio::spawn in fetch_from_rpc

In fetch_from_rpc:

let (remote_accounts, found_count, not_found_count) =
    tokio::spawn(async move {Ok((pubkeys.iter().zip(response.value).map(...).collect(), found_count, not_found_count))
    }).await.unwrap().unwrap();
// TODO: @@@ unwrap

This can panic in two ways:

  • If the spawned task panics or is cancelled (JoinError).
  • If the inner Result is Err(RemoteAccountProviderError::FailedFetchingAccounts(_)), which you already use to signal hard failures.

Because notify_error inside the spawned future already sends Err to all pending requests for these pubkeys, the outer .unwrap().unwrap() is both redundant and dangerous: it can crash the task after the error was already handled and reported.

  1. Unwrap on photon fetch

In fetch_from_photon:

let (compressed_accounts, slot) = photon_client
    .get_multiple_accounts(&pubkeys, Some(min_context_slot))
    .await
    .unwrap(); // TODO: @@@ unwrap and/or retry

Any indexer/network error will panic here, again taking down the task instead of being reported as a structured failure. That’s particularly risky since this code runs in the background spawned by fetch, not in a test.


A minimal, localized fix would:

  • Treat both RPC and Photon fetches as fallible, and never unwrap their results.
  • Accumulate only successful (FetchedRemoteAccounts, found_count, not_found_count) into the remote_accounts_results vector and log+metric‑increment failures.
  • If all fetch tasks fail, return early from the outer tokio::spawn in fetch (pending requests will already have been signalled via notify_error on the RPC side; for Photon failures you can just log and let RPC be the source of truth).

Sketch of the pattern inside fetch (omitting metrics/trace details for brevity):

-        tokio::spawn(async move {
-            let mut join_set = JoinSet::new();
-            join_set.spawn(Self::fetch_from_rpc(...));
-            if let Some(photon_client) = photon_client {
-                let photon_client = photon_client.clone();
-                join_set.spawn(Self::fetch_from_photon(...));
-            }
-
-            let (remote_accounts_results, found_count, not_found_count) =
-                join_set.join_all().await.into_iter().fold(
-                    (vec![], 0, 0),
-                    |(remote_accounts_results, found_count, not_found_count),
-                     (accs, found_cnt, not_found_cnt)| {
-                        (
-                            [remote_accounts_results, vec![accs]].concat(),
-                            found_count + found_cnt,
-                            not_found_count + not_found_cnt,
-                        )
-                    },
-                );
+        tokio::spawn(async move {
+            let mut join_set = JoinSet::new();
+            join_set.spawn(Self::fetch_from_rpc(
+                rpc_client,
+                pubkeys.clone(),
+                fetching_accounts.clone(),
+                mark_empty_if_not_found,
+                min_context_slot,
+            ));
+            if let Some(photon_client) = photon_client {
+                let photon_client = photon_client.clone();
+                join_set.spawn(Self::fetch_from_photon(
+                    photon_client,
+                    pubkeys.clone(),
+                    min_context_slot,
+                ));
+            }
+
+            let mut remote_accounts_results = Vec::new();
+            let mut found_count = 0u64;
+            let mut not_found_count = 0u64;
+
+            for res in join_set.join_all().await {
+                match res {
+                    Ok((accs, found_cnt, not_found_cnt)) => {
+                        remote_accounts_results.push(accs);
+                        found_count += found_cnt;
+                        not_found_count += not_found_cnt;
+                    }
+                    Err(join_err) => {
+                        warn!("Background fetch task failed: {join_err:?}");
+                        // Optionally inc_account_fetches_failed(pubkeys.len() as u64);
+                    }
+                }
+            }
+
+            if remote_accounts_results.is_empty() {
+                // All tasks failed; pending requests should already have been
+                // signalled via notify_error or equivalent. Nothing more to do.
+                return;
+            }
@@
-            let (remote_accounts, found_count, not_found_count) =
-            tokio::spawn(async move {
+            let (remote_accounts, found_count, not_found_count) =
+            tokio::spawn(async move {-                Ok((pubkeys
+                Ok((pubkeys
                     .iter()
                     .zip(response.value)
                     .map(|(pubkey, acc)| { … })
-                    .collect(), found_count, not_found_count))
-            }).await.unwrap().unwrap();
-        // TODO: @@@ unwrap
+                    .collect(), found_count, not_found_count))
+            }).await
+              .map_err(|e| {
+                  RemoteAccountProviderError::FailedFetchingAccounts(
+                      format!("RPC fetch join failed: {e:?}")
+                  )
+              })?
+              .map_err(|e| {
+                  // notify_error already ran; just propagate/log
+                  e
+              })?;
@@
-        let (compressed_accounts, slot) = photon_client
-            .get_multiple_accounts(&pubkeys, Some(min_context_slot))
-            .await
-            .unwrap();
+        let (compressed_accounts, slot) = match photon_client
+            .get_multiple_accounts(&pubkeys, Some(min_context_slot))
+            .await
+        {
+            Ok(res) => res,
+            Err(err) => {
+                warn!("Photon fetch failed for [{}]: {err:?}", pubkeys_str(&pubkeys));
+                // Treat as "no compressed data" and let RPC results drive behavior.
+                return (FetchedRemoteAccounts::Compressed(vec![]), 0, 0);
+            }
+        };

You can refine the error mapping to your existing RemoteAccountProviderError variants and metrics, but the key points are:

  • No .unwrap() on async joins or external calls.
  • Explicit handling of JoinError and Photon errors.
  • Avoiding double‑signalling (first with notify_error, then via panic or second Ok).
What is the return type of `tokio::task::JoinSet::join_all` in the current stable Tokio, and does it wrap the task result in `Result<T, JoinError>`?
magicblock-committor-service/src/intent_executor/mod.rs (1)

333-376: Use TransactionStrategy::compressed and assert invariants instead of rescanning tasks for compression

handle_commit_id_error now passes a compressed flag into fetch_next_commit_ids by re‑scanning strategy.optimized_tasks with any(|task| task.is_compressed()), and there’s still a TODO about mixed compressed/non‑compressed tasks. Since TransactionStrategy already carries a compressed flag (and you propagate it through all error handlers), you can:

  • Treat strategy.compressed as the single source of truth for this flag, and
  • Add a debug_assert! that all tasks agree with it, so any future mixed‑compression regression fails loudly in debug builds.

This removes the TODO, avoids recomputing the same property, and codifies the “no mixed compression in a strategy” invariant you’ve introduced via InconsistentTaskCompression.

A concrete refactor:

-        let commit_ids = self
-            .task_info_fetcher
-            .fetch_next_commit_ids(
-                committed_pubkeys,
-                // TODO(dode): Handle cases where some tasks are compressed and some are not
-                strategy
-                    .optimized_tasks
-                    .iter()
-                    .any(|task| task.is_compressed()),
-            )
+        debug_assert!(
+            strategy
+                .optimized_tasks
+                .iter()
+                .all(|task| task.is_compressed()) == strategy.compressed,
+            "TransactionStrategy.compressed inconsistent with tasks; mixed compressed/non-compressed tasks are not supported",
+        );
+
+        let commit_ids = self
+            .task_info_fetcher
+            .fetch_next_commit_ids(
+                committed_pubkeys,
+                strategy.compressed,
+            )

This keeps fetch_next_commit_ids deterministic with respect to the strategy and aligned with the new InconsistentTaskCompression error path. Based on learnings, this also addresses the earlier concern about mixed compressed/non‑compressed handling without re‑opening that design discussion.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcd1a5e and e7d6fdb.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • test-integration/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (40)
  • Cargo.toml (5 hunks)
  • magicblock-accounts/src/scheduled_commits_processor.rs (2 hunks)
  • magicblock-api/src/magic_validator.rs (8 hunks)
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs (19 hunks)
  • magicblock-chainlink/src/chainlink/mod.rs (8 hunks)
  • magicblock-chainlink/src/remote_account_provider/mod.rs (26 hunks)
  • magicblock-chainlink/src/testing/mod.rs (1 hunks)
  • magicblock-chainlink/tests/01_ensure-accounts.rs (3 hunks)
  • magicblock-chainlink/tests/03_deleg_after_sub.rs (2 hunks)
  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs (3 hunks)
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs (2 hunks)
  • magicblock-chainlink/tests/utils/test_context.rs (4 hunks)
  • magicblock-committor-service/src/intent_execution_manager/intent_execution_engine.rs (1 hunks)
  • magicblock-committor-service/src/intent_executor/error.rs (2 hunks)
  • magicblock-committor-service/src/intent_executor/mod.rs (27 hunks)
  • magicblock-committor-service/src/intent_executor/single_stage_executor.rs (4 hunks)
  • magicblock-committor-service/src/intent_executor/two_stage_executor.rs (4 hunks)
  • magicblock-committor-service/src/tasks/args_task.rs (7 hunks)
  • magicblock-committor-service/src/tasks/buffer_task.rs (3 hunks)
  • magicblock-committor-service/src/tasks/mod.rs (7 hunks)
  • magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs (10 hunks)
  • magicblock-metrics/src/metrics/mod.rs (3 hunks)
  • programs/magicblock/src/magic_scheduled_base_intent.rs (8 hunks)
  • programs/magicblock/src/schedule_transactions/process_schedule_base_intent.rs (1 hunks)
  • programs/magicblock/src/schedule_transactions/process_schedule_commit.rs (2 hunks)
  • test-integration/programs/flexi-counter/src/processor.rs (10 hunks)
  • test-integration/programs/flexi-counter/src/state.rs (1 hunks)
  • test-integration/programs/schedulecommit/src/api.rs (6 hunks)
  • test-integration/schedulecommit/test-scenarios/tests/01_commits.rs (1 hunks)
  • test-integration/test-chainlink/src/programs.rs (1 hunks)
  • test-integration/test-chainlink/src/test_context.rs (4 hunks)
  • test-integration/test-chainlink/tests/ix_01_ensure-accounts.rs (1 hunks)
  • test-integration/test-chainlink/tests/ix_03_deleg_after_sub.rs (1 hunks)
  • test-integration/test-chainlink/tests/ix_06_redeleg_us_separate_slots.rs (4 hunks)
  • test-integration/test-chainlink/tests/ix_07_redeleg_us_same_slot.rs (1 hunks)
  • test-integration/test-chainlink/tests/ix_remote_account_provider.rs (2 hunks)
  • test-integration/test-committor-service/tests/test_intent_executor.rs (14 hunks)
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs (23 hunks)
  • test-integration/test-committor-service/tests/utils/instructions.rs (3 hunks)
  • test-integration/test-committor-service/tests/utils/transactions.rs (7 hunks)
🧰 Additional context used
🧠 Learnings (25)
📓 Common learnings
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: test-integration/test-chainlink/tests/ix_01_ensure-accounts.rs:85-114
Timestamp: 2025-11-19T11:31:24.218Z
Learning: In the magicblock-validator codebase, compressed delegation records are never subscribed to by design. Tests for compressed delegation flows should focus on verifying that the delegated account (e.g., counter PDA) is cloned as delegated and not subscribed, but do not need to check for subscription to delegation-record-like PDAs in the compressed path because subscriptions to compressed delegation records never occur.
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: magicblock-chainlink/tests/04_redeleg_other_separate_slots.rs:158-165
Timestamp: 2025-11-18T08:47:39.702Z
Learning: In magicblock-chainlink tests involving compressed accounts, `set_remote_slot()` sets the slot of the `AccountSharedData`, while `compressed_account_shared_with_owner_and_slot()` sets the slot of the delegation record. These are two different fields and both calls are necessary.
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/requests/websocket/account_subscribe.rs:18-27
Timestamp: 2025-10-21T14:00:54.642Z
Learning: In magicblock-aperture account_subscribe handler (src/requests/websocket/account_subscribe.rs), the RpcAccountInfoConfig fields data_slice, commitment, and min_context_slot are currently ignored—only encoding is applied. This is tracked as technical debt in issue #579: https://github.com/magicblock-labs/magicblock-validator/issues/579
📚 Learning: 2025-11-19T11:31:24.218Z
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: test-integration/test-chainlink/tests/ix_01_ensure-accounts.rs:85-114
Timestamp: 2025-11-19T11:31:24.218Z
Learning: In the magicblock-validator codebase, compressed delegation records are never subscribed to by design. Tests for compressed delegation flows should focus on verifying that the delegated account (e.g., counter PDA) is cloned as delegated and not subscribed, but do not need to check for subscription to delegation-record-like PDAs in the compressed path because subscriptions to compressed delegation records never occur.

Applied to files:

  • test-integration/test-chainlink/tests/ix_03_deleg_after_sub.rs
  • magicblock-committor-service/src/intent_executor/error.rs
  • test-integration/test-chainlink/tests/ix_01_ensure-accounts.rs
  • test-integration/test-chainlink/tests/ix_07_redeleg_us_same_slot.rs
  • test-integration/test-chainlink/tests/ix_06_redeleg_us_separate_slots.rs
  • magicblock-chainlink/tests/01_ensure-accounts.rs
  • magicblock-metrics/src/metrics/mod.rs
  • magicblock-committor-service/src/intent_execution_manager/intent_execution_engine.rs
  • test-integration/test-chainlink/tests/ix_remote_account_provider.rs
  • magicblock-committor-service/src/tasks/args_task.rs
  • magicblock-chainlink/tests/03_deleg_after_sub.rs
  • test-integration/test-committor-service/tests/utils/transactions.rs
  • magicblock-api/src/magic_validator.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • test-integration/test-committor-service/tests/utils/instructions.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
  • magicblock-chainlink/src/remote_account_provider/mod.rs
  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs
  • programs/magicblock/src/magic_scheduled_base_intent.rs
  • magicblock-committor-service/src/tasks/mod.rs
  • Cargo.toml
  • magicblock-committor-service/src/intent_executor/mod.rs
  • test-integration/programs/schedulecommit/src/api.rs
📚 Learning: 2025-10-14T09:56:14.047Z
Learnt from: taco-paco
Repo: magicblock-labs/magicblock-validator PR: 564
File: test-integration/programs/flexi-counter/src/processor/call_handler.rs:122-125
Timestamp: 2025-10-14T09:56:14.047Z
Learning: The file test-integration/programs/flexi-counter/src/processor/call_handler.rs contains a test smart contract used for integration testing, not production code.

Applied to files:

  • test-integration/test-chainlink/tests/ix_03_deleg_after_sub.rs
  • test-integration/schedulecommit/test-scenarios/tests/01_commits.rs
  • test-integration/test-chainlink/tests/ix_01_ensure-accounts.rs
  • test-integration/test-chainlink/tests/ix_07_redeleg_us_same_slot.rs
  • test-integration/test-chainlink/tests/ix_06_redeleg_us_separate_slots.rs
  • test-integration/programs/flexi-counter/src/state.rs
  • test-integration/test-committor-service/tests/utils/transactions.rs
  • programs/magicblock/src/schedule_transactions/process_schedule_base_intent.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • magicblock-chainlink/src/testing/mod.rs
  • test-integration/test-chainlink/src/programs.rs
  • magicblock-committor-service/src/intent_executor/mod.rs
📚 Learning: 2025-11-18T08:47:39.702Z
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: magicblock-chainlink/tests/04_redeleg_other_separate_slots.rs:158-165
Timestamp: 2025-11-18T08:47:39.702Z
Learning: In magicblock-chainlink tests involving compressed accounts, `set_remote_slot()` sets the slot of the `AccountSharedData`, while `compressed_account_shared_with_owner_and_slot()` sets the slot of the delegation record. These are two different fields and both calls are necessary.

Applied to files:

  • test-integration/test-chainlink/tests/ix_03_deleg_after_sub.rs
  • test-integration/schedulecommit/test-scenarios/tests/01_commits.rs
  • test-integration/test-chainlink/tests/ix_01_ensure-accounts.rs
  • test-integration/test-chainlink/tests/ix_07_redeleg_us_same_slot.rs
  • test-integration/test-chainlink/tests/ix_06_redeleg_us_separate_slots.rs
  • magicblock-chainlink/tests/01_ensure-accounts.rs
  • magicblock-metrics/src/metrics/mod.rs
  • test-integration/test-chainlink/tests/ix_remote_account_provider.rs
  • magicblock-committor-service/src/tasks/args_task.rs
  • magicblock-chainlink/tests/03_deleg_after_sub.rs
  • test-integration/test-committor-service/tests/utils/transactions.rs
  • magicblock-api/src/magic_validator.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • test-integration/test-committor-service/tests/utils/instructions.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
  • magicblock-chainlink/src/remote_account_provider/mod.rs
  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs
  • programs/magicblock/src/magic_scheduled_base_intent.rs
  • magicblock-committor-service/src/intent_executor/mod.rs
📚 Learning: 2025-11-19T09:34:37.917Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 621
File: test-integration/test-chainlink/tests/ix_remote_account_provider.rs:62-63
Timestamp: 2025-11-19T09:34:37.917Z
Learning: In test-integration/test-chainlink/tests/ix_remote_account_provider.rs and similar test files, the `_fwd_rx` receiver returned by `init_remote_account_provider()` is intentionally kept alive (but unused) to prevent "receiver dropped" errors on the sender side. The pattern `let (remote_account_provider, _fwd_rx) = init_remote_account_provider().await;` should NOT be changed to `let (remote_account_provider, _) = ...` because dropping the receiver would cause send() operations to fail.

Applied to files:

  • test-integration/test-chainlink/tests/ix_03_deleg_after_sub.rs
  • test-integration/test-chainlink/tests/ix_01_ensure-accounts.rs
  • test-integration/test-chainlink/tests/ix_07_redeleg_us_same_slot.rs
  • test-integration/test-chainlink/tests/ix_06_redeleg_us_separate_slots.rs
  • magicblock-chainlink/tests/01_ensure-accounts.rs
  • magicblock-metrics/src/metrics/mod.rs
  • magicblock-committor-service/src/intent_execution_manager/intent_execution_engine.rs
  • test-integration/test-chainlink/tests/ix_remote_account_provider.rs
  • magicblock-chainlink/tests/03_deleg_after_sub.rs
  • test-integration/test-committor-service/tests/utils/transactions.rs
  • magicblock-api/src/magic_validator.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • magicblock-accounts/src/scheduled_commits_processor.rs
  • magicblock-chainlink/src/testing/mod.rs
  • magicblock-chainlink/tests/utils/test_context.rs
  • test-integration/test-chainlink/src/programs.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs
  • test-integration/test-chainlink/src/test_context.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
  • magicblock-chainlink/src/remote_account_provider/mod.rs
  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs
  • magicblock-committor-service/src/tasks/mod.rs
  • Cargo.toml
  • magicblock-committor-service/src/intent_executor/mod.rs
  • test-integration/programs/schedulecommit/src/api.rs
  • magicblock-chainlink/src/chainlink/mod.rs
📚 Learning: 2025-11-07T14:20:31.457Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 621
File: magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs:457-495
Timestamp: 2025-11-07T14:20:31.457Z
Learning: In magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs, the unsubscribe closure returned by PubSubConnection::account_subscribe(...) resolves to () (unit), not a Result. Downstream code should not attempt to inspect an unsubscribe result and can optionally wrap it in a timeout to guard against hangs.

Applied to files:

  • test-integration/test-chainlink/tests/ix_03_deleg_after_sub.rs
  • test-integration/test-chainlink/tests/ix_01_ensure-accounts.rs
  • test-integration/test-chainlink/tests/ix_06_redeleg_us_separate_slots.rs
  • magicblock-metrics/src/metrics/mod.rs
  • magicblock-committor-service/src/intent_execution_manager/intent_execution_engine.rs
  • test-integration/test-chainlink/tests/ix_remote_account_provider.rs
  • magicblock-chainlink/tests/03_deleg_after_sub.rs
  • magicblock-api/src/magic_validator.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • magicblock-accounts/src/scheduled_commits_processor.rs
  • magicblock-chainlink/tests/utils/test_context.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs
  • test-integration/test-chainlink/src/test_context.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
  • magicblock-chainlink/src/remote_account_provider/mod.rs
  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs
  • magicblock-committor-service/src/intent_executor/two_stage_executor.rs
  • Cargo.toml
  • magicblock-chainlink/src/chainlink/mod.rs
📚 Learning: 2025-10-21T14:00:54.642Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/requests/websocket/account_subscribe.rs:18-27
Timestamp: 2025-10-21T14:00:54.642Z
Learning: In magicblock-aperture account_subscribe handler (src/requests/websocket/account_subscribe.rs), the RpcAccountInfoConfig fields data_slice, commitment, and min_context_slot are currently ignored—only encoding is applied. This is tracked as technical debt in issue #579: https://github.com/magicblock-labs/magicblock-validator/issues/579

Applied to files:

  • test-integration/test-chainlink/tests/ix_03_deleg_after_sub.rs
  • magicblock-committor-service/src/intent_executor/error.rs
  • test-integration/schedulecommit/test-scenarios/tests/01_commits.rs
  • test-integration/test-chainlink/tests/ix_01_ensure-accounts.rs
  • test-integration/test-chainlink/tests/ix_07_redeleg_us_same_slot.rs
  • test-integration/test-chainlink/tests/ix_06_redeleg_us_separate_slots.rs
  • magicblock-chainlink/tests/01_ensure-accounts.rs
  • magicblock-metrics/src/metrics/mod.rs
  • magicblock-committor-service/src/intent_execution_manager/intent_execution_engine.rs
  • test-integration/test-chainlink/tests/ix_remote_account_provider.rs
  • magicblock-committor-service/src/tasks/args_task.rs
  • magicblock-chainlink/tests/03_deleg_after_sub.rs
  • test-integration/test-committor-service/tests/utils/transactions.rs
  • magicblock-api/src/magic_validator.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • test-integration/test-committor-service/tests/utils/instructions.rs
  • magicblock-chainlink/src/testing/mod.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs
  • programs/magicblock/src/schedule_transactions/process_schedule_commit.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
  • magicblock-chainlink/src/remote_account_provider/mod.rs
  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs
  • magicblock-committor-service/src/intent_executor/two_stage_executor.rs
  • programs/magicblock/src/magic_scheduled_base_intent.rs
  • magicblock-committor-service/src/tasks/mod.rs
  • Cargo.toml
  • magicblock-committor-service/src/intent_executor/mod.rs
  • magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs
  • test-integration/programs/schedulecommit/src/api.rs
  • magicblock-chainlink/src/chainlink/mod.rs
📚 Learning: 2025-11-21T10:22:07.520Z
Learnt from: taco-paco
Repo: magicblock-labs/magicblock-validator PR: 661
File: magicblock-committor-service/src/intent_executor/single_stage_executor.rs:20-28
Timestamp: 2025-11-21T10:22:07.520Z
Learning: In magicblock-committor-service's SingleStageExecutor and TwoStageExecutor (single_stage_executor.rs and two_stage_executor.rs), the fields transaction_strategy, junk, and patched_errors are intentionally public because these executors are designed to be used independently outside of the IntentExecutor scope, and callers need access to these execution reports for cleanup and error handling.

Applied to files:

  • magicblock-committor-service/src/intent_executor/error.rs
  • magicblock-committor-service/src/intent_execution_manager/intent_execution_engine.rs
  • magicblock-committor-service/src/intent_executor/single_stage_executor.rs
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • programs/magicblock/src/schedule_transactions/process_schedule_commit.rs
  • test-integration/test-committor-service/tests/test_intent_executor.rs
  • magicblock-committor-service/src/intent_executor/two_stage_executor.rs
  • programs/magicblock/src/magic_scheduled_base_intent.rs
  • magicblock-committor-service/src/tasks/mod.rs
  • magicblock-committor-service/src/intent_executor/mod.rs
  • magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs
📚 Learning: 2025-11-07T13:09:52.253Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 589
File: test-kit/src/lib.rs:275-0
Timestamp: 2025-11-07T13:09:52.253Z
Learning: In test-kit, the transaction scheduler in ExecutionTestEnv is not expected to shut down during tests. Therefore, using `.unwrap()` in test helper methods like `schedule_transaction` is acceptable and will not cause issues in the test environment.

Applied to files:

  • test-integration/schedulecommit/test-scenarios/tests/01_commits.rs
  • test-integration/test-committor-service/tests/test_intent_executor.rs
📚 Learning: 2025-10-21T11:00:18.396Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/encoder.rs:176-187
Timestamp: 2025-10-21T11:00:18.396Z
Learning: In the magicblock validator, the current slot is always the root slot. The SlotEncoder in magicblock-aperture/src/encoder.rs correctly sets `root: slot` because there is no lag between current and root slots in this architecture.

Applied to files:

  • magicblock-chainlink/tests/01_ensure-accounts.rs
  • magicblock-chainlink/src/testing/mod.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
📚 Learning: 2025-11-20T08:57:07.217Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 650
File: magicblock-chainlink/src/submux/subscription_task.rs:13-99
Timestamp: 2025-11-20T08:57:07.217Z
Learning: In the magicblock-validator repository, avoid posting review comments that merely confirm code is correct or matches intended behavior without providing actionable feedback, suggestions for improvement, or identifying potential issues. Such confirmatory comments are considered unhelpful noise by the maintainers.

Applied to files:

  • magicblock-committor-service/src/intent_execution_manager/intent_execution_engine.rs
  • test-integration/test-chainlink/tests/ix_remote_account_provider.rs
  • magicblock-api/src/magic_validator.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • magicblock-chainlink/src/testing/mod.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
  • magicblock-committor-service/src/tasks/mod.rs
  • Cargo.toml
  • magicblock-committor-service/src/intent_executor/mod.rs
📚 Learning: 2025-11-21T11:03:26.756Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 664
File: magicblock-chainlink/src/testing/mod.rs:342-370
Timestamp: 2025-11-21T11:03:26.756Z
Learning: In the magicblock-validator codebase, avoid leaving review comments that merely acknowledge code is correct or well-structured when there is no actionable suggestion, improvement, or issue to flag. Only comment when there is something specific to recommend, fix, or clarify.

Applied to files:

  • magicblock-committor-service/src/intent_execution_manager/intent_execution_engine.rs
  • magicblock-api/src/magic_validator.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • magicblock-chainlink/src/testing/mod.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
  • magicblock-chainlink/src/remote_account_provider/mod.rs
  • magicblock-committor-service/src/tasks/mod.rs
  • Cargo.toml
  • magicblock-committor-service/src/intent_executor/mod.rs
📚 Learning: 2025-10-26T08:49:31.543Z
Learnt from: taco-paco
Repo: magicblock-labs/magicblock-validator PR: 585
File: magicblock-committor-service/src/tasks/buffer_task.rs:111-115
Timestamp: 2025-10-26T08:49:31.543Z
Learning: In the magicblock-committor-service, compute units returned by the `compute_units()` method in task implementations (such as `BufferTask`, `ArgsTask`, etc.) represent the compute budget for a single task. Transactions can comprise multiple tasks, and the total compute budget for a transaction is computed as the sum of the compute units of all tasks included in that transaction.

Applied to files:

  • magicblock-committor-service/src/tasks/args_task.rs
  • magicblock-committor-service/src/tasks/buffer_task.rs
  • magicblock-committor-service/src/intent_executor/mod.rs
📚 Learning: 2025-11-19T12:55:48.931Z
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: test-integration/test-tools/src/validator.rs:193-197
Timestamp: 2025-11-19T12:55:48.931Z
Learning: In the magicblock-validator codebase, when constructing arguments for the light CLI test validator in start_light_validator_with_config (test-integration/test-tools/src/validator.rs), the shlex::split approach is necessary because the light CLI does not handle whitespaces properly in validator arguments. The string concatenation + shlex parsing pattern should not be refactored to direct argument construction in this specific case.

Applied to files:

  • magicblock-api/src/magic_validator.rs
  • magicblock-chainlink/src/testing/mod.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
  • Cargo.toml
📚 Learning: 2025-10-26T16:53:29.820Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 587
File: magicblock-chainlink/src/remote_account_provider/mod.rs:134-0
Timestamp: 2025-10-26T16:53:29.820Z
Learning: In magicblock-chainlink/src/remote_account_provider/mod.rs, the `Endpoint::separate_pubsub_url_and_api_key()` method uses `split_once("?api-key=")` because the api-key parameter is always the only query parameter right after `?`. No additional query parameter parsing is needed for this use case.

Applied to files:

  • magicblock-api/src/magic_validator.rs
  • magicblock-chainlink/src/remote_account_provider/mod.rs
📚 Learning: 2025-11-12T09:46:27.553Z
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 614
File: magicblock-task-scheduler/src/db.rs:26-0
Timestamp: 2025-11-12T09:46:27.553Z
Learning: In magicblock-task-scheduler, task parameter validation (including ensuring iterations > 0 and enforcing minimum execution intervals) is performed in the Magic program (on-chain) before ScheduleTaskRequest instances reach the scheduler service. The From<&ScheduleTaskRequest> conversion in db.rs does not need additional validation because inputs are already validated at the program level.

Applied to files:

  • test-integration/programs/flexi-counter/src/processor.rs
📚 Learning: 2025-11-07T13:20:13.793Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 589
File: magicblock-processor/src/scheduler/coordinator.rs:227-238
Timestamp: 2025-11-07T13:20:13.793Z
Learning: In magicblock-processor's ExecutionCoordinator (scheduler/coordinator.rs), the `account_contention` HashMap intentionally does not call `shrink_to_fit()`. Maintaining slack capacity is beneficial for performance by avoiding frequent reallocations during high transaction throughput. As long as empty entries are removed from the map (which `clear_account_contention` does), the capacity overhead is acceptable.

Applied to files:

  • test-integration/programs/flexi-counter/src/processor.rs
  • magicblock-chainlink/src/remote_account_provider/mod.rs
  • magicblock-chainlink/src/chainlink/mod.rs
📚 Learning: 2025-11-20T17:25:23.444Z
Learnt from: JMirval
Repo: magicblock-labs/magicblock-validator PR: 656
File: programs/guinea/src/lib.rs:33-33
Timestamp: 2025-11-20T17:25:23.444Z
Learning: In the magicblock-validator codebase, task IDs (task_id) are i64 values that can be negative. The task scheduler is designed to handle any i64 value including negative task IDs. Task IDs are randomly generated using rand::random() which produces values across the full i64 range. No validation is needed to restrict task IDs to positive values.

Applied to files:

  • test-integration/programs/flexi-counter/src/processor.rs
📚 Learning: 2025-11-24T14:21:00.948Z
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: Cargo.toml:58-58
Timestamp: 2025-11-24T14:21:00.948Z
Learning: In the magicblock-validator codebase, magicblock-api/Cargo.toml intentionally uses borsh = "1.5.3" (instead of the workspace version 0.10.4) because it needs to deserialize types from the magic-domain-program external dependency, which requires borsh 1.5.x compatibility. This is an intentional exception for interoperability with the magic domain program.

Applied to files:

  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • Cargo.toml
  • magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs
📚 Learning: 2025-10-28T13:15:42.706Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 596
File: magicblock-processor/src/scheduler.rs:1-1
Timestamp: 2025-10-28T13:15:42.706Z
Learning: In magicblock-processor, transaction indexes were always set to 0 even before the changes in PR #596. The proper transaction indexing within slots will be addressed during the planned ledger rewrite.

Applied to files:

  • magicblock-chainlink/src/testing/mod.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
  • Cargo.toml
  • magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs
📚 Learning: 2025-10-21T13:06:38.900Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/requests/http/get_program_accounts.rs:17-25
Timestamp: 2025-10-21T13:06:38.900Z
Learning: The magicblock validator does not support ledger forking, so commitment-based state queries (processed/confirmed/finalized) are not applicable. RPC methods can safely ignore commitment and minContextSlot parameters from Solana RPC config objects.

Applied to files:

  • magicblock-chainlink/src/testing/mod.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
  • Cargo.toml
📚 Learning: 2025-10-26T16:54:39.084Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 587
File: test-manual/Cargo.toml:0-0
Timestamp: 2025-10-26T16:54:39.084Z
Learning: In the magicblock-validator repository, use git branch references (not commit hashes or tags) for the helius-laserstream dependency to allow automatic updates when the branch is pushed to.

Applied to files:

  • magicblock-chainlink/src/testing/mod.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
  • Cargo.toml
📚 Learning: 2025-11-04T13:22:38.811Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 589
File: magicblock-aperture/src/requests/http/get_fee_for_message.rs:25-31
Timestamp: 2025-11-04T13:22:38.811Z
Learning: In magicblock-aperture, request size validation (including limits on message size) is enforced at the request ingestion layer, before handlers like get_fee_for_message are invoked. Therefore, handlers do not need additional size guards on decoded data.

Applied to files:

  • magicblock-chainlink/src/testing/mod.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
  • Cargo.toml
📚 Learning: 2025-10-21T10:34:59.140Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-accounts-db/src/lib.rs:63-72
Timestamp: 2025-10-21T10:34:59.140Z
Learning: In magicblock-validator, the AccountsDb "stop-the-world" synchronizer is managed at the processor/executor level, not at the AccountsDb API level. Transaction executors in magicblock-processor hold a read lock (sync.read()) for the duration of each slot and release it only at slot boundaries, ensuring all account writes happen under the read lock. Snapshot operations acquire a write lock, blocking until all executors release their read locks. This pattern ensures mutual exclusion between writes and snapshots without requiring read guards in AccountsDb write APIs.

Applied to files:

  • magicblock-chainlink/src/testing/mod.rs
  • magicblock-chainlink/tests/07_redeleg_us_same_slot.rs
📚 Learning: 2025-11-24T08:45:11.154Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 675
File: Cargo.toml:145-145
Timestamp: 2025-11-24T08:45:11.154Z
Learning: The reqwest dependency version 0.11 is intentionally used in the magicblock-validator project to maintain compatibility with the Solana client dependencies.

Applied to files:

  • Cargo.toml
🧬 Code graph analysis (16)
test-integration/test-chainlink/tests/ix_06_redeleg_us_separate_slots.rs (2)
test-integration/test-chainlink/src/ixtest_context.rs (2)
  • init (103-108)
  • counter_pda (209-211)
test-integration/test-chainlink/src/lib.rs (1)
  • sleep_ms (8-11)
magicblock-chainlink/tests/03_deleg_after_sub.rs (1)
magicblock-chainlink/tests/utils/accounts.rs (2)
  • compressed_account_shared_with_owner_and_slot (22-49)
  • account_shared_with_owner_and_slot (12-20)
magicblock-committor-service/src/intent_executor/single_stage_executor.rs (2)
magicblock-committor-service/src/intent_executor/mod.rs (2)
  • None (918-918)
  • None (938-938)
test-integration/test-committor-service/tests/test_intent_executor.rs (14)
  • None (149-149)
  • None (150-150)
  • None (200-200)
  • None (201-201)
  • None (261-261)
  • None (262-262)
  • None (319-319)
  • None (320-320)
  • None (368-368)
  • None (419-419)
  • None (468-468)
  • None (527-527)
  • None (599-599)
  • None (600-600)
test-integration/test-committor-service/tests/utils/transactions.rs (2)
test-integration/test-committor-service/tests/utils/instructions.rs (2)
  • init_account_and_delegate_compressed_ixs (81-159)
  • init_account_and_delegate_ixs (48-79)
test-integration/test-committor-service/tests/utils/mod.rs (1)
  • sleep_millis (16-18)
magicblock-api/src/magic_validator.rs (1)
magicblock-chainlink/src/remote_account_provider/mod.rs (1)
  • new (300-359)
magicblock-committor-service/src/tasks/buffer_task.rs (6)
magicblock-committor-service/src/tasks/args_task.rs (5)
  • is_compressed (248-255)
  • set_compressed_data (257-270)
  • get_compressed_data (272-285)
  • delegated_account (287-303)
  • value (307-314)
magicblock-committor-service/src/tasks/mod.rs (4)
  • is_compressed (100-100)
  • set_compressed_data (103-103)
  • get_compressed_data (106-106)
  • delegated_account (109-109)
magicblock-committor-service/src/tasks/task_builder.rs (1)
  • get_compressed_data (412-463)
magicblock-committor-service/src/intent_executor/mod.rs (3)
  • None (918-918)
  • None (938-938)
  • value (75-83)
test-integration/test-committor-service/tests/test_intent_executor.rs (13)
  • None (149-149)
  • None (150-150)
  • None (200-200)
  • None (201-201)
  • None (261-261)
  • None (262-262)
  • None (319-319)
  • None (320-320)
  • None (368-368)
  • None (419-419)
  • None (468-468)
  • None (527-527)
  • None (599-599)
magicblock-committor-service/src/intent_executor/error.rs (1)
  • value (113-120)
test-integration/programs/flexi-counter/src/processor.rs (3)
compressed-delegation-client/src/generated/instructions/undelegate_compressed.rs (2)
  • args (112-115)
  • args (303-306)
compressed-delegation-client/src/generated/instructions/delegate_compressed.rs (2)
  • args (162-165)
  • args (430-433)
compressed-delegation-client/src/lib.rs (1)
  • id (61-63)
test-integration/test-committor-service/tests/utils/instructions.rs (4)
magicblock-core/src/compression/mod.rs (1)
  • derive_cda_from_pda (10-22)
test-integration/programs/flexi-counter/src/instruction.rs (2)
  • create_delegate_compressed_ix (514-533)
  • create_init_ix (227-240)
test-integration/programs/flexi-counter/src/state.rs (2)
  • pda (45-48)
  • new (27-33)
test-integration/test-committor-service/tests/common.rs (1)
  • new (64-67)
magicblock-chainlink/tests/utils/test_context.rs (2)
magicblock-chainlink/src/remote_account_provider/photon_client.rs (1)
  • new (27-29)
magicblock-chainlink/src/testing/photon_client_mock.rs (1)
  • new (26-30)
magicblock-chainlink/src/chainlink/fetch_cloner.rs (2)
magicblock-chainlink/src/remote_account_provider/photon_client.rs (1)
  • new (27-29)
compressed-delegation-client/src/lib.rs (1)
  • id (61-63)
test-integration/test-chainlink/src/test_context.rs (1)
magicblock-chainlink/tests/utils/test_context.rs (1)
  • init (62-132)
magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs (3)
magicblock-chainlink/src/testing/accounts.rs (1)
  • account_shared_with_owner (4-10)
magicblock-chainlink/src/testing/utils.rs (1)
  • init_logger (51-59)
magicblock-chainlink/tests/utils/accounts.rs (2)
  • compressed_account_shared_with_owner_and_slot (22-49)
  • account_shared_with_owner_and_slot (12-20)
magicblock-committor-service/src/intent_executor/two_stage_executor.rs (2)
magicblock-committor-service/src/intent_executor/mod.rs (2)
  • None (918-918)
  • None (938-938)
test-integration/test-committor-service/tests/test_intent_executor.rs (14)
  • None (149-149)
  • None (150-150)
  • None (200-200)
  • None (201-201)
  • None (261-261)
  • None (262-262)
  • None (319-319)
  • None (320-320)
  • None (368-368)
  • None (419-419)
  • None (468-468)
  • None (527-527)
  • None (599-599)
  • None (600-600)
programs/magicblock/src/magic_scheduled_base_intent.rs (4)
magicblock-committor-service/src/tasks/mod.rs (1)
  • is_compressed (100-100)
test-integration/test-committor-service/tests/test_ix_commit_local.rs (1)
  • base_intent (811-816)
magicblock-committor-service/src/tasks/task_builder.rs (1)
  • committed_accounts (280-286)
magicblock-committor-service/src/intent_executor/task_info_fetcher.rs (2)
  • Self (305-313)
  • Self (315-323)
magicblock-committor-service/src/tasks/mod.rs (3)
magicblock-committor-service/src/tasks/args_task.rs (4)
  • is_compressed (248-255)
  • set_compressed_data (257-270)
  • get_compressed_data (272-285)
  • delegated_account (287-303)
magicblock-committor-service/src/tasks/buffer_task.rs (4)
  • is_compressed (147-149)
  • set_compressed_data (151-156)
  • get_compressed_data (158-162)
  • delegated_account (164-170)
magicblock-committor-service/src/tasks/task_builder.rs (1)
  • get_compressed_data (412-463)
magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs (2)
magicblock-committor-service/src/tasks/args_task.rs (2)
  • get_compressed_data (272-285)
  • from (40-42)
magicblock-committor-service/src/tasks/task_builder.rs (1)
  • get_compressed_data (412-463)

Comment on lines 891 to 896
async fn fetch_rent_reimbursements(
&self,
pubkeys: &[Pubkey],
accounts: &[Pubkey],
) -> TaskInfoFetcherResult<Vec<Pubkey>> {
Ok(pubkeys.iter().map(|_| Pubkey::new_unique()).collect())
Ok(accounts.iter().map(|_| Pubkey::new_unique()).collect())
}
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 24, 2025

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Make MockInfoFetcher::fetch_rent_reimbursements preserve input pubkeys for clearer semantics

The mock currently returns a vector of Pubkey::new_unique() with the same length as accounts, which breaks the natural 1:1 relationship between the input accounts and their “reimbursement” pubkeys. If tests start asserting on actual keys (not just length), this behaviour becomes misleading.

Since this is a test helper and you don’t care about deriving new values, you can simply echo the inputs back:

-        async fn fetch_rent_reimbursements(
-            &self,
-            accounts: &[Pubkey],
-        ) -> TaskInfoFetcherResult<Vec<Pubkey>> {
-            Ok(accounts.iter().map(|_| Pubkey::new_unique()).collect())
-        }
+        async fn fetch_rent_reimbursements(
+            &self,
+            accounts: &[Pubkey],
+        ) -> TaskInfoFetcherResult<Vec<Pubkey>> {
+            Ok(accounts.to_vec())
+        }

This keeps the mock behaviour intuitive and future‑proofs tests that may rely on the actual identities of reimbursed accounts.

🤖 Prompt for AI Agents
In magicblock-committor-service/src/intent_executor/mod.rs around lines 891 to
896, the mock implementation of fetch_rent_reimbursements constructs new random
Pubkeys instead of returning the input accounts, breaking the 1:1 mapping and
confusing tests; change the body to simply return the input pubkeys (e.g.,
Ok(accounts.to_vec()) or accounts.iter().cloned().collect()) so the mock echoes
the provided Pubkeys in order.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not necessary

Copy link
Contributor

Choose a reason for hiding this comment

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

@Dodecahedr0x Understood, we'll keep the current implementation. The mock generating unique pubkeys works fine for the existing tests.


🧠 Learnings used
Learnt from: taco-paco
Repo: magicblock-labs/magicblock-validator PR: 661
File: magicblock-committor-service/src/intent_executor/single_stage_executor.rs:20-28
Timestamp: 2025-11-21T10:22:07.520Z
Learning: In magicblock-committor-service's SingleStageExecutor and TwoStageExecutor (single_stage_executor.rs and two_stage_executor.rs), the fields transaction_strategy, junk, and patched_errors are intentionally public because these executors are designed to be used independently outside of the IntentExecutor scope, and callers need access to these execution reports for cleanup and error handling.

Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/requests/websocket/account_subscribe.rs:18-27
Timestamp: 2025-10-21T14:00:54.642Z
Learning: In magicblock-aperture account_subscribe handler (src/requests/websocket/account_subscribe.rs), the RpcAccountInfoConfig fields data_slice, commitment, and min_context_slot are currently ignored—only encoding is applied. This is tracked as technical debt in issue #579: https://github.com/magicblock-labs/magicblock-validator/issues/579

Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 621
File: test-integration/test-chainlink/tests/ix_remote_account_provider.rs:62-63
Timestamp: 2025-11-19T09:34:37.917Z
Learning: In test-integration/test-chainlink/tests/ix_remote_account_provider.rs and similar test files, the `_fwd_rx` receiver returned by `init_remote_account_provider()` is intentionally kept alive (but unused) to prevent "receiver dropped" errors on the sender side. The pattern `let (remote_account_provider, _fwd_rx) = init_remote_account_provider().await;` should NOT be changed to `let (remote_account_provider, _) = ...` because dropping the receiver would cause send() operations to fail.

Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: test-integration/test-chainlink/tests/ix_01_ensure-accounts.rs:85-114
Timestamp: 2025-11-19T11:31:24.218Z
Learning: In the magicblock-validator codebase, compressed delegation records are never subscribed to by design. Tests for compressed delegation flows should focus on verifying that the delegated account (e.g., counter PDA) is cloned as delegated and not subscribed, but do not need to check for subscription to delegation-record-like PDAs in the compressed path because subscriptions to compressed delegation records never occur.

Comment on lines 221 to 233
fn task_type(&self) -> TaskType {
match &self.task_type {
ArgsTaskType::Commit(_) => TaskType::Commit,
ArgsTaskType::CompressedCommit(_) => TaskType::CompressedCommit,
ArgsTaskType::BaseAction(_) => TaskType::Action,
ArgsTaskType::Undelegate(_) => TaskType::Undelegate,
ArgsTaskType::CompressedUndelegate(_) => {
TaskType::CompressedUndelegate
}
ArgsTaskType::Finalize(_) => TaskType::Finalize,
ArgsTaskType::CompressedFinalize(_) => TaskType::CompressedFinalize,
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

LabelValue match is non‑exhaustive for new compressed variants and currently moves task_type

ArgsTaskType now has compressed variants, but LabelValue::value still only matches the four legacy cases:

impl LabelValue for ArgsTask {
    fn value(&self) -> &str {
        match self.task_type {
            ArgsTaskType::Commit(_) => "args_commit",
            ArgsTaskType::BaseAction(_) => "args_action",
            ArgsTaskType::Finalize(_) => "args_finalize",
            ArgsTaskType::Undelegate(_) => "args_undelegate",
        }
    }
}

Issues:

  1. The match is now non‑exhaustive and will fail to compile once compressed variants are enabled.
  2. match self.task_type attempts to move task_type out of &self; this only works if ArgsTaskType is Copy (which it isn’t, given #[derive(Clone)] and the inner types).

You probably want both exhaustive coverage and to keep task_type borrowed:

 impl LabelValue for ArgsTask {
     fn value(&self) -> &str {
-        match self.task_type {
-            ArgsTaskType::Commit(_) => "args_commit",
-            ArgsTaskType::BaseAction(_) => "args_action",
-            ArgsTaskType::Finalize(_) => "args_finalize",
-            ArgsTaskType::Undelegate(_) => "args_undelegate",
-        }
+        match &self.task_type {
+            ArgsTaskType::Commit(_) => "args_commit",
+            ArgsTaskType::CompressedCommit(_) => "args_compressed_commit",
+            ArgsTaskType::BaseAction(_) => "args_action",
+            ArgsTaskType::Finalize(_) => "args_finalize",
+            ArgsTaskType::CompressedFinalize(_) => "args_compressed_finalize",
+            ArgsTaskType::Undelegate(_) => "args_undelegate",
+            ArgsTaskType::CompressedUndelegate(_) => "args_compressed_undelegate",
+        }
     }
 }

This restores exhaustiveness and keeps metric labeling in sync with the new compressed task variants.

Also applies to: 306-314

🤖 Prompt for AI Agents
In magicblock-committor-service/src/tasks/args_task.rs around lines 221-233 (and
also apply the same change at 306-314), the LabelValue::value match is
non-exhaustive for the new compressed ArgsTaskType variants and currently
attempts to move self.task_type; change the match to borrow the enum (match
&self.task_type) and add arms for the compressed variants mapping them to the
same label strings as their legacy counterparts (e.g., CompressedCommit ->
"args_commit", CompressedFinalize -> "args_finalize", CompressedUndelegate ->
"args_undelegate", etc.) so all variants are covered and no move occurs from
&self.

Copy link
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: 8

♻️ Duplicate comments (2)
magicblock-committor-service/src/tasks/args_task.rs (1)

126-136: Add missing .args() call to UndelegateBuilder and import UndelegateArgs.

The UndelegateBuilder.instruction() method panics with "args is not set" if .args() is not called. The code at lines 126-136 is missing this mandatory call. The required UndelegateArgs struct needs validity_proof, delegation_record_account_meta, and compressed_delegated_record, which are all available in value.compressed_data.

Add to imports (line 1):

use compressed_delegation_client::types::{CommitArgs, FinalizeArgs, UndelegateArgs};

Update lines 126-136 to include .args():

ArgsTaskType::CompressedUndelegate(value) => {
    compressed_delegation_client::UndelegateBuilder::new()
        .payer(*validator)
        .delegated_account(value.delegated_account)
        .owner_program(value.owner_program)
        .system_program(system_program::ID)
        .args(UndelegateArgs {
            validity_proof: value.compressed_data.proof,
            delegation_record_account_meta: value.compressed_data.account_meta,
            compressed_delegated_record: CompressedDelegationRecord::try_from_slice(
                &value.compressed_data.compressed_delegation_record_bytes,
            ).expect("failed to deserialize compressed delegation record"),
        })
        .add_remaining_accounts(
            &value.compressed_data.remaining_accounts,
        )
        .instruction()
}

Also add CompressedDelegationRecord to imports from compressed_delegation_client::types.

test-integration/programs/flexi-counter/src/processor.rs (1)

548-555: Improve error semantics when refunding excess lamports in process_delegate_compressed

The checked_sub here correctly avoids a panic if the counter PDA somehow has fewer lamports than min_rent(0), but surfacing that as ProgramError::ArithmeticOverflow makes debugging harder and conflates an impossible arithmetic condition with a logical “account under‑funded” state:

let min_rent = rent.minimum_balance(0);
**payer_info.try_borrow_mut_lamports()? += counter_pda_info
    .lamports()
    .checked_sub(min_rent)
    .ok_or(ProgramError::ArithmeticOverflow)?;
**counter_pda_info.try_borrow_mut_lamports()? = min_rent;

Consider making the under‑funded case explicit and returning a more descriptive error (and/or logging):

-    let min_rent = rent.minimum_balance(0);
-    **payer_info.try_borrow_mut_lamports()? += counter_pda_info
-        .lamports()
-        .checked_sub(min_rent)
-        .ok_or(ProgramError::ArithmeticOverflow)?;
-    **counter_pda_info.try_borrow_mut_lamports()? = min_rent;
+    let min_rent = rent.minimum_balance(0);
+    let current_lamports = counter_pda_info.lamports();
+    if current_lamports < min_rent {
+        msg!(
+            "Counter PDA has {} lamports, expected at least {} before delegation",
+            current_lamports,
+            min_rent
+        );
+        return Err(ProgramError::InsufficientFunds);
+    }
+    let refund = current_lamports - min_rent;
+    **payer_info.try_borrow_mut_lamports()? += refund;
+    **counter_pda_info.try_borrow_mut_lamports()? = min_rent;

This keeps the behavior safe but turns a low‑signal arithmetic error into a clear “bad precondition” signal for tests.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e7d6fdb and ba2a791.

⛔ Files ignored due to path filters (1)
  • test-integration/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs (19 hunks)
  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs (3 hunks)
  • magicblock-committor-service/src/tasks/args_task.rs (9 hunks)
  • magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs (10 hunks)
  • programs/magicblock/src/schedule_transactions/process_schedule_commit.rs (2 hunks)
  • test-integration/programs/flexi-counter/src/processor.rs (10 hunks)
  • test-integration/programs/schedulecommit/src/api.rs (7 hunks)
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs (23 hunks)
  • test-integration/test-committor-service/tests/utils/transactions.rs (7 hunks)
🧰 Additional context used
🧠 Learnings (17)
📓 Common learnings
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: test-integration/test-chainlink/tests/ix_01_ensure-accounts.rs:85-114
Timestamp: 2025-11-19T11:31:24.218Z
Learning: In the magicblock-validator codebase, compressed delegation records are never subscribed to by design. Tests for compressed delegation flows should focus on verifying that the delegated account (e.g., counter PDA) is cloned as delegated and not subscribed, but do not need to check for subscription to delegation-record-like PDAs in the compressed path because subscriptions to compressed delegation records never occur.
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: magicblock-chainlink/tests/04_redeleg_other_separate_slots.rs:158-165
Timestamp: 2025-11-18T08:47:39.702Z
Learning: In magicblock-chainlink tests involving compressed accounts, `set_remote_slot()` sets the slot of the `AccountSharedData`, while `compressed_account_shared_with_owner_and_slot()` sets the slot of the delegation record. These are two different fields and both calls are necessary.
📚 Learning: 2025-10-14T09:56:14.047Z
Learnt from: taco-paco
Repo: magicblock-labs/magicblock-validator PR: 564
File: test-integration/programs/flexi-counter/src/processor/call_handler.rs:122-125
Timestamp: 2025-10-14T09:56:14.047Z
Learning: The file test-integration/programs/flexi-counter/src/processor/call_handler.rs contains a test smart contract used for integration testing, not production code.

Applied to files:

  • test-integration/programs/schedulecommit/src/api.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • test-integration/test-committor-service/tests/utils/transactions.rs
📚 Learning: 2025-10-21T14:00:54.642Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/requests/websocket/account_subscribe.rs:18-27
Timestamp: 2025-10-21T14:00:54.642Z
Learning: In magicblock-aperture account_subscribe handler (src/requests/websocket/account_subscribe.rs), the RpcAccountInfoConfig fields data_slice, commitment, and min_context_slot are currently ignored—only encoding is applied. This is tracked as technical debt in issue #579: https://github.com/magicblock-labs/magicblock-validator/issues/579

Applied to files:

  • test-integration/programs/schedulecommit/src/api.rs
  • programs/magicblock/src/schedule_transactions/process_schedule_commit.rs
  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • magicblock-committor-service/src/tasks/args_task.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs
  • test-integration/test-committor-service/tests/utils/transactions.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs
📚 Learning: 2025-11-19T11:31:24.218Z
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: test-integration/test-chainlink/tests/ix_01_ensure-accounts.rs:85-114
Timestamp: 2025-11-19T11:31:24.218Z
Learning: In the magicblock-validator codebase, compressed delegation records are never subscribed to by design. Tests for compressed delegation flows should focus on verifying that the delegated account (e.g., counter PDA) is cloned as delegated and not subscribed, but do not need to check for subscription to delegation-record-like PDAs in the compressed path because subscriptions to compressed delegation records never occur.

Applied to files:

  • test-integration/programs/schedulecommit/src/api.rs
  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • magicblock-committor-service/src/tasks/args_task.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • test-integration/test-committor-service/tests/utils/transactions.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs
📚 Learning: 2025-11-19T09:34:37.917Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 621
File: test-integration/test-chainlink/tests/ix_remote_account_provider.rs:62-63
Timestamp: 2025-11-19T09:34:37.917Z
Learning: In test-integration/test-chainlink/tests/ix_remote_account_provider.rs and similar test files, the `_fwd_rx` receiver returned by `init_remote_account_provider()` is intentionally kept alive (but unused) to prevent "receiver dropped" errors on the sender side. The pattern `let (remote_account_provider, _fwd_rx) = init_remote_account_provider().await;` should NOT be changed to `let (remote_account_provider, _) = ...` because dropping the receiver would cause send() operations to fail.

Applied to files:

  • test-integration/programs/schedulecommit/src/api.rs
  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • test-integration/test-committor-service/tests/utils/transactions.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs
📚 Learning: 2025-11-21T10:22:07.520Z
Learnt from: taco-paco
Repo: magicblock-labs/magicblock-validator PR: 661
File: magicblock-committor-service/src/intent_executor/single_stage_executor.rs:20-28
Timestamp: 2025-11-21T10:22:07.520Z
Learning: In magicblock-committor-service's SingleStageExecutor and TwoStageExecutor (single_stage_executor.rs and two_stage_executor.rs), the fields transaction_strategy, junk, and patched_errors are intentionally public because these executors are designed to be used independently outside of the IntentExecutor scope, and callers need access to these execution reports for cleanup and error handling.

Applied to files:

  • programs/magicblock/src/schedule_transactions/process_schedule_commit.rs
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs
📚 Learning: 2025-11-18T08:47:39.702Z
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: magicblock-chainlink/tests/04_redeleg_other_separate_slots.rs:158-165
Timestamp: 2025-11-18T08:47:39.702Z
Learning: In magicblock-chainlink tests involving compressed accounts, `set_remote_slot()` sets the slot of the `AccountSharedData`, while `compressed_account_shared_with_owner_and_slot()` sets the slot of the delegation record. These are two different fields and both calls are necessary.

Applied to files:

  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs
  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • magicblock-committor-service/src/tasks/args_task.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • test-integration/test-committor-service/tests/utils/transactions.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs
📚 Learning: 2025-11-25T11:07:19.985Z
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: test-integration/programs/flexi-counter/src/processor.rs:643-680
Timestamp: 2025-11-25T11:07:19.985Z
Learning: In the compressed delegation architecture, ownership reassignment during undelegation is handled by the delegation program itself, not by the owner program's external undelegate handler. The external undelegate handler (e.g., `process_external_undelegate_compressed` in flexi-counter) is a callback for program-specific cleanup (restoring lamports and data) after the delegation program has already reassigned ownership back to the original owner stored in the CompressedDelegationRecord.

Applied to files:

  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs
  • magicblock-committor-service/src/tasks/args_task.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • test-integration/test-committor-service/tests/utils/transactions.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs
📚 Learning: 2025-11-07T14:20:31.457Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 621
File: magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs:457-495
Timestamp: 2025-11-07T14:20:31.457Z
Learning: In magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs, the unsubscribe closure returned by PubSubConnection::account_subscribe(...) resolves to () (unit), not a Result. Downstream code should not attempt to inspect an unsubscribe result and can optionally wrap it in a timeout to guard against hangs.

Applied to files:

  • magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs
  • test-integration/programs/flexi-counter/src/processor.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner.rs
📚 Learning: 2025-11-24T14:21:00.948Z
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 639
File: Cargo.toml:58-58
Timestamp: 2025-11-24T14:21:00.948Z
Learning: In the magicblock-validator codebase, magicblock-api/Cargo.toml intentionally uses borsh = "1.5.3" (instead of the workspace version 0.10.4) because it needs to deserialize types from the magic-domain-program external dependency, which requires borsh 1.5.x compatibility. This is an intentional exception for interoperability with the magic domain program.

Applied to files:

  • test-integration/test-committor-service/tests/test_ix_commit_local.rs
  • magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs
📚 Learning: 2025-10-26T08:49:31.543Z
Learnt from: taco-paco
Repo: magicblock-labs/magicblock-validator PR: 585
File: magicblock-committor-service/src/tasks/buffer_task.rs:111-115
Timestamp: 2025-10-26T08:49:31.543Z
Learning: In the magicblock-committor-service, compute units returned by the `compute_units()` method in task implementations (such as `BufferTask`, `ArgsTask`, etc.) represent the compute budget for a single task. Transactions can comprise multiple tasks, and the total compute budget for a transaction is computed as the sum of the compute units of all tasks included in that transaction.

Applied to files:

  • magicblock-committor-service/src/tasks/args_task.rs
📚 Learning: 2025-11-20T08:57:07.217Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 650
File: magicblock-chainlink/src/submux/subscription_task.rs:13-99
Timestamp: 2025-11-20T08:57:07.217Z
Learning: In the magicblock-validator repository, avoid posting review comments that merely confirm code is correct or matches intended behavior without providing actionable feedback, suggestions for improvement, or identifying potential issues. Such confirmatory comments are considered unhelpful noise by the maintainers.

Applied to files:

  • test-integration/programs/flexi-counter/src/processor.rs
📚 Learning: 2025-11-21T11:03:26.756Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 664
File: magicblock-chainlink/src/testing/mod.rs:342-370
Timestamp: 2025-11-21T11:03:26.756Z
Learning: In the magicblock-validator codebase, avoid leaving review comments that merely acknowledge code is correct or well-structured when there is no actionable suggestion, improvement, or issue to flag. Only comment when there is something specific to recommend, fix, or clarify.

Applied to files:

  • test-integration/programs/flexi-counter/src/processor.rs
📚 Learning: 2025-11-12T09:46:27.553Z
Learnt from: Dodecahedr0x
Repo: magicblock-labs/magicblock-validator PR: 614
File: magicblock-task-scheduler/src/db.rs:26-0
Timestamp: 2025-11-12T09:46:27.553Z
Learning: In magicblock-task-scheduler, task parameter validation (including ensuring iterations > 0 and enforcing minimum execution intervals) is performed in the Magic program (on-chain) before ScheduleTaskRequest instances reach the scheduler service. The From<&ScheduleTaskRequest> conversion in db.rs does not need additional validation because inputs are already validated at the program level.

Applied to files:

  • test-integration/programs/flexi-counter/src/processor.rs
📚 Learning: 2025-11-07T13:20:13.793Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 589
File: magicblock-processor/src/scheduler/coordinator.rs:227-238
Timestamp: 2025-11-07T13:20:13.793Z
Learning: In magicblock-processor's ExecutionCoordinator (scheduler/coordinator.rs), the `account_contention` HashMap intentionally does not call `shrink_to_fit()`. Maintaining slack capacity is beneficial for performance by avoiding frequent reallocations during high transaction throughput. As long as empty entries are removed from the map (which `clear_account_contention` does), the capacity overhead is acceptable.

Applied to files:

  • test-integration/programs/flexi-counter/src/processor.rs
📚 Learning: 2025-11-20T17:25:23.444Z
Learnt from: JMirval
Repo: magicblock-labs/magicblock-validator PR: 656
File: programs/guinea/src/lib.rs:33-33
Timestamp: 2025-11-20T17:25:23.444Z
Learning: In the magicblock-validator codebase, task IDs (task_id) are i64 values that can be negative. The task scheduler is designed to handle any i64 value including negative task IDs. Task IDs are randomly generated using rand::random() which produces values across the full i64 range. No validation is needed to restrict task IDs to positive values.

Applied to files:

  • test-integration/programs/flexi-counter/src/processor.rs
📚 Learning: 2025-10-28T13:15:42.706Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 596
File: magicblock-processor/src/scheduler.rs:1-1
Timestamp: 2025-10-28T13:15:42.706Z
Learning: In magicblock-processor, transaction indexes were always set to 0 even before the changes in PR #596. The proper transaction indexing within slots will be addressed during the planned ledger rewrite.

Applied to files:

  • magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs
🧬 Code graph analysis (6)
programs/magicblock/src/schedule_transactions/process_schedule_commit.rs (4)
programs/magicblock/src/utils/instruction_utils.rs (1)
  • schedule_commit (33-40)
magicblock-chainlink/src/remote_account_provider/remote_account.rs (1)
  • compressed (154-156)
test-integration/test-committor-service/tests/test_ix_commit_local.rs (1)
  • base_intent (811-816)
magicblock-committor-service/src/tasks/task_builder.rs (1)
  • committed_accounts (280-286)
magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs (1)
magicblock-chainlink/tests/utils/accounts.rs (2)
  • compressed_account_shared_with_owner_and_slot (22-49)
  • account_shared_with_owner_and_slot (12-20)
test-integration/test-committor-service/tests/test_ix_commit_local.rs (6)
magicblock-core/src/compression/mod.rs (1)
  • derive_cda_from_pda (10-22)
magicblock-committor-service/src/tasks/args_task.rs (2)
  • new (46-63)
  • is_compressed (248-255)
magicblock-committor-service/src/config.rs (1)
  • local (29-35)
magicblock-chainlink/src/remote_account_provider/remote_account.rs (1)
  • compressed (154-156)
magicblock-config/src/compression.rs (1)
  • default (24-29)
compressed-delegation-client/src/lib.rs (1)
  • id (61-63)
magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs (2)
magicblock-committor-service/src/tasks/buffer_task.rs (3)
  • get_compressed_data (158-162)
  • strategy (122-124)
  • delegated_account (164-170)
magicblock-committor-service/src/tasks/task_builder.rs (1)
  • get_compressed_data (412-463)
test-integration/test-committor-service/tests/utils/transactions.rs (2)
test-integration/test-committor-service/tests/utils/instructions.rs (1)
  • init_account_and_delegate_compressed_ixs (81-159)
test-integration/test-committor-service/tests/utils/mod.rs (1)
  • sleep_millis (16-18)
magicblock-chainlink/src/chainlink/fetch_cloner.rs (2)
magicblock-chainlink/src/remote_account_provider/photon_client.rs (1)
  • new (27-29)
compressed-delegation-client/src/lib.rs (1)
  • id (61-63)
🔇 Additional comments (26)
test-integration/test-committor-service/tests/test_ix_commit_local.rs (7)

7-22: LGTM!

The new imports for compressed delegation support are well-organized and appropriate for the added functionality.


130-135: LGTM!

The CommitAccountMode enum cleanly captures the four test scenarios and simplifies the mode-driven branching throughout the test helpers.


613-654: LGTM!

The create_bundles helper cleanly handles both regular and compressed account initialization with efficient parallel spawning via JoinSet.


680-689: LGTM!

Good use of matches! macro to determine the compressed flag from the mode enum.


840-875: LGTM!

The compressed account validation path correctly:

  1. Validates the on-chain PDA is owned by compressed_delegation_client::ID with minimal rent
  2. Derives the CDA address and fetches compressed state from the Photon indexer
  3. Validates the compressed delegation record contains expected data

1026-1042: LGTM!

The validate_compressed_account function correctly parses the CompressedDelegationRecord from the compressed account data and validates the embedded state matches expectations.


440-478: LGTM!

Good test coverage for single compressed account commits with both small (100 bytes) and medium (500 bytes) data sizes, including commit-only and commit-and-undelegate variants.

test-integration/programs/schedulecommit/src/api.rs (2)

28-32: Consistent use of build_instruction across all builders looks good

All updated builders now delegate to build_instruction with the appropriate program_id, ScheduleCommitInstruction variant, and account_metas. This removes duplication from the file and keeps the serialization/encoding path consistent for all schedule-commit flows.

Also applies to: 86-90, 193-195, 214-218, 237-243, 249-253


285-295: Helper neatly centralizes Borsh serialization for schedule-commit instructions

build_instruction correctly wraps ScheduleCommitInstruction serialization via borsh::to_vec and constructs the Instruction with the provided program_id and account_metas. Centralizing this logic improves maintainability and aligns this test program with the broader instruction-building pattern used elsewhere in the PR.

magicblock-committor-service/src/transaction_preparator/delivery_preparator.rs (5)

1-1: LGTM: Imports properly support PhotonIndexer integration.

The added imports correctly support the new compressed delegation data flow with proper type safety (BufferPreparationTask, TaskBuilderError) and PhotonIndexer client integration.

Also applies to: 5-5, 36-39


66-90: LGTM: PhotonIndexer context properly threaded through preparation pipeline.

The photon_client and commit_slot parameters are correctly propagated to task preparation, enabling compressed delegation data flows while remaining optional for non-compressed paths.


171-192: Note: Past review comments about this section appear to be outdated.

Previous comments mentioned:

  1. A TODO with a 1000ms sleep that should be replaced (lines 171-177 in past version)
  2. Error handling that discarded context using let Ok(...) pattern (lines 159-165 in past version)

The current code no longer contains these issues:

  • No sleep is present in the compressed path
  • Error handling at line 190 uses the ? operator, which preserves error context via the From<TaskBuilderError> impl (line 615)

592-620: LGTM: Error variants comprehensively support compressed delegation flows.

The new InternalError variants properly model all failure modes in the compressed path:

  • CompressedDataNotFound, DelegatedAccountNotFound, PhotonClientNotFound provide specific error context
  • TaskBuilderError with From impl enables clean error propagation via ? operator at line 190
  • All variants follow Rust best practices with proper #[error] and #[from] attributes

128-170: LGTM: Buffer path refactored with improved type safety.

The use of BufferPreparationTask as a specific type (instead of generic preparation task) improves type safety throughout the buffer initialization flow. State transitions are clearly modeled and persisted at each stage.

Also applies to: 264-265, 313-313

magicblock-committor-service/src/tasks/args_task.rs (6)

23-31: LGTM!

The new compressed task variants are well-structured and follow the existing pattern consistently.


45-63: LGTM!

The constructor properly initializes preparation_state per variant at construction time, addressing the previous concern about returning references to temporaries.


83-102: LGTM!

The CompressedCommit instruction builder is well-structured, properly sourcing all arguments from the task's compressed data.


109-124: LGTM!

The CompressedFinalize instruction builder correctly mirrors the CompressedCommit pattern with appropriate arguments.


192-202: LGTM!

The state transition now properly persists the new state, addressing the previous concern about compressed tasks remaining in Required state indefinitely.


306-319: LGTM!

All compressed variants are now covered, resolving the previous non-exhaustive match concern. The implementation correctly handles metrics labeling for all task types.

programs/magicblock/src/schedule_transactions/process_schedule_commit.rs (2)

34-55: Wrapper refactor cleanly centralizes commit scheduling logic

Delegating both process_schedule_commit and process_schedule_compressed_commit into a single schedule_commit(..., compressed: bool) keeps the external API clear while centralizing validation and scheduling logic. The ownership of signers and opts is preserved and there’s no behavior change for the non‑compressed path.


267-285: Intent selection for compressed vs non‑compressed paths looks correct

The match (opts.request_undelegation, compressed) cleanly and exhaustively maps the four combinations to the expected MagicBaseIntent variants, and for compressed == false preserves the prior Commit/CommitAndUndelegate behavior. Moving committed_accounts into CommitType::Standalone in each arm is consistent with the previous implementation and only consumed once.

magicblock-chainlink/src/chainlink/fetch_cloner.rs (4)

49-56: LGTM: PhotonClient generic parameter properly threaded through the codebase.

The addition of the P: PhotonClient generic parameter and its propagation through FetchCloner, impl blocks, and helper functions is consistent and correct.

Also applies to: 135-142, 145-145, 1702-1707


1796-1958: LGTM: Test scaffolding properly updated for PhotonClient integration.

All test type signatures, helpers, and setup functions correctly include PhotonClientMock as the new generic parameter. The updates are consistent across the test suite.


878-902: Verify whether compressed delegation authority handling is intentionally different.

The code shows an inconsistency in authority checks between standard and compressed delegation processing:

Standard delegation (lines 949-952):

delegation_record.authority.eq(&self.validator_pubkey) ||
// TODO(thlorenz): @ once the delegation program supports
// delegating to specific authority we need to remove the below
delegation_record.authority.eq(&Pubkey::default());

Compressed delegation (lines 889-896):

if delegation_record.authority.eq(&self.validator_pubkey) {
    account.set_delegated(true);
} else {
    account.set_delegated(false);
}

The standard delegation explicitly includes a fallback to Pubkey::default() (marked as temporary via TODO), but the compressed delegation does not. Both use identical Pubkey authority fields from their respective record types.

This could be intentional (compressed delegation program doesn't support default authority), or an oversight. Please verify:

  • Does the compressed delegation program support Pubkey::default() as a valid authority value?
  • If yes, should the fallback be added for consistency?
  • If no, should a comment document why the compressed path omits this check?

468-497: The review comment is based on incorrect assumptions about the subscription data flow.

The code at lines 468-497 is not only reachable but essential. When an account delegated to the validator arrives as a subscription update with owner compressed_delegation_client::id(), it arrives with empty data (as confirmed by test line 228: Account::default()). The try_from_slice at line 471 necessarily fails because there is no CompressedDelegationRecord in the subscription payload.

The photon fallback at lines 477-495 is not redundant—it is the intended design. Subscription updates carry the empty wrapper account, while the actual delegation record data resides in photon. The fallback is essential and will succeed because photon has the properly formatted account data.

The review incorrectly assumes that "subscription update should already contain the latest data." In the compressed delegation flow, subscriptions deliberately carry only the wrapper account (with owner marker), and the actual delegation data must be fetched separately from photon.

Likely an incorrect or invalid review comment.

Comment on lines +189 to +192
let undelegated_acc = account_shared_with_owner_and_slot(
&acc.account,
program_pubkey,
rpc_client.get_slot(),
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Use the slot variable for consistency.

Line 192 calls rpc_client.get_slot() to retrieve the slot, but the slot variable was just updated at line 181 and should contain the same value. For consistency with the rest of the test (which uses the slot variable at lines 194, 220, 225, and 230), use the variable directly.

Apply this diff:

 let undelegated_acc = account_shared_with_owner_and_slot(
     &acc.account,
     program_pubkey,
-    rpc_client.get_slot(),
+    slot,
 );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let undelegated_acc = account_shared_with_owner_and_slot(
&acc.account,
program_pubkey,
rpc_client.get_slot(),
let undelegated_acc = account_shared_with_owner_and_slot(
&acc.account,
program_pubkey,
slot,
);
🤖 Prompt for AI Agents
In magicblock-chainlink/tests/06_redeleg_us_separate_slots.rs around lines 189
to 192, the call uses rpc_client.get_slot() to fetch the current slot even
though the slot variable was updated at line 181 and is used elsewhere; replace
the rpc_client.get_slot() call with the existing slot variable to keep
consistency and avoid an extra RPC call.

Comment on lines +257 to +270
fn set_compressed_data(&mut self, compressed_data: CompressedData) {
match &mut self.task_type {
ArgsTaskType::CompressedCommit(value) => {
value.compressed_data = compressed_data;
}
ArgsTaskType::CompressedFinalize(value) => {
value.compressed_data = compressed_data;
}
ArgsTaskType::CompressedUndelegate(value) => {
value.compressed_data = compressed_data;
}
_ => {}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider adding a debug assertion for non-compressed variants.

The _ => {} arm silently ignores calls on non-compressed tasks, which could mask caller bugs. A debug assertion or trace log would help catch misuse during development.

-            _ => {}
+            _ => {
+                debug_assert!(
+                    false,
+                    "set_compressed_data called on non-compressed task variant"
+                );
+            }
🤖 Prompt for AI Agents
In magicblock-committor-service/src/tasks/args_task.rs around lines 257 to 270,
the set_compressed_data method currently ignores non-compressed task variants
with `_ => {}`, which can hide misuse; change that arm to assert in debug builds
(e.g., use debug_assert!(matches!(self.task_type,
ArgsTaskType::CompressedCommit(_) | ArgsTaskType::CompressedFinalize(_) |
ArgsTaskType::CompressedUndelegate(_))) or call unreachable!() behind
cfg!(debug_assertions)), or alternatively log a trace/error, so calls on
non-compressed variants are detected during development.

Comment on lines +171 to +192
PreparationTask::Compressed => {
// Trying to fetch fresh data from the indexer
let photon_config = commit_slot.map(|slot| IndexerRpcConfig {
slot,
..Default::default()
});

let delegated_account = task
.delegated_account()
.ok_or(InternalError::DelegatedAccountNotFound)?;
let photon_client = photon_client
.as_ref()
.ok_or(InternalError::PhotonClientNotFound)?;

let compressed_data = get_compressed_data(
&delegated_account,
photon_client,
photon_config,
)
.await?;
task.set_compressed_data(compressed_data);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Consider: Add validation that the indexer has reached the required slot.

When commit_slot is provided, the code creates an IndexerRpcConfig to constrain the fetch, but doesn't verify that the Photon indexer has actually indexed up to that slot. If the indexer lags behind, get_compressed_data may:

  • Return stale data from an earlier slot
  • Fail with an indexer-specific error
  • Return successfully but with inconsistent state

Consider adding a slot-readiness check or documenting the expected behavior when the indexer hasn't reached commit_slot.

Based on learnings, compressed delegation flows require the indexer to be up-to-date for correctness.


🏁 Script executed:

#!/bin/bash
# Description: Check if there's slot validation logic in PhotonIndexer or get_compressed_data

# Search for slot validation in get_compressed_data and PhotonIndexer methods
rg -n -C3 'slot.*valid|min.*slot|indexer.*slot|slot.*check' --type rust

Length of output: 87506


🏁 Script executed:

#!/bin/bash
# Find get_compressed_data function definition
rg -n -A10 'async fn get_compressed_data|fn get_compressed_data' --type rust

Length of output: 3943


🏁 Script executed:

#!/bin/bash
# Search for get_compressed_data calls to see patterns
rg -n -B2 'get_compressed_data\(' --type rust | head -100

Length of output: 3238


Add validation that the Photon indexer returns data from the requested slot or later.

The code passes commit_slot via IndexerRpcConfig to hint at the desired slot, but doesn't verify the response. Unlike the remote_account_provider path (which validates response.context.slot >= min_context_slot), the compressed data fetch accepts whatever the Photon indexer returns. If the indexer lags, get_compressed_data may return stale account state from an earlier slot.

Consider adding an explicit check after line 190 to validate the returned compressed data's slot meets the requirement, or document why this validation is not needed.

Comment on lines +659 to +668
// Refund account
invoke(
&system_instruction::transfer(
payer.key,
delegated_account.key,
args.delegation_record
.lamports
.checked_sub(delegated_account.lamports())
.ok_or(ProgramError::ArithmeticOverflow)?,
),
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Handle “overfunded” delegated accounts more explicitly in process_external_undelegate_compressed

The top‑up amount is computed via:

args.delegation_record
    .lamports
    .checked_sub(delegated_account.lamports())
    .ok_or(ProgramError::ArithmeticOverflow)?

If delegated_account.lamports() ends up greater than args.delegation_record.lamports (e.g., a test transfers extra lamports in while delegated), this produces ProgramError::ArithmeticOverflow, which doesn’t clearly describe the state and prevents a more intentional choice (either “no‑op top‑up” or a targeted error).

You could make the invariant explicit and pick clearer semantics, for example:

-    invoke(
-        &system_instruction::transfer(
-            payer.key,
-            delegated_account.key,
-            args.delegation_record
-                .lamports
-                .checked_sub(delegated_account.lamports())
-                .ok_or(ProgramError::ArithmeticOverflow)?,
-        ),
-        &[payer.clone(), delegated_account.clone()],
-    )?;
+    let target = args.delegation_record.lamports;
+    let current = delegated_account.lamports();
+    if current > target {
+        msg!(
+            "Delegated account has {} lamports, expected at most {} from delegation record",
+            current,
+            target
+        );
+        // Either treat as invalid state …
+        return Err(ProgramError::InvalidAccountData);
+        // … or, if you prefer, skip the transfer entirely instead of erroring:
+        // return Ok(());
+    }
+
+    let top_up = target
+        .checked_sub(current)
+        .ok_or(ProgramError::ArithmeticOverflow)?;
+    if top_up > 0 {
+        invoke(
+            &system_instruction::transfer(payer.key, delegated_account.key, top_up),
+            &[payer.clone(), delegated_account.clone()],
+        )?;
+    }

This makes the post‑delegation lamport invariant explicit and gives tests a clearer failure mode instead of a generic arithmetic overflow.

🤖 Prompt for AI Agents
In test-integration/programs/flexi-counter/src/processor.rs around lines
659-668, the code uses checked_sub which yields ProgramError::ArithmeticOverflow
when delegated_account.lamports() > args.delegation_record.lamports, producing
an unclear error; replace that expression with an explicit branch: first compare
delegated_account.lamports() and args.delegation_record.lamports(), and if
delegated_account.lamports() >= args.delegation_record.lamports() either return
a clear program error (add or use a descriptive custom error variant like
DelegatedAccountOverfunded) or treat it as a no-op by setting the
transfer/top-up amount to zero and skipping the invoke, and otherwise compute
the positive top-up via subtraction and proceed with the transfer; ensure the
chosen behavior is documented in comments and tests updated accordingly.

Comment on lines +161 to +176
let (pubkey, mut account) = match mode {
CommitAccountMode::Commit | CommitAccountMode::CommitAndUndelegate => {
init_and_delegate_account_on_chain(
&counter_auth,
bytes as u64,
None,
)
.await
}
_ => {
let (pubkey, _hash, account) =
init_and_delegate_compressed_account_on_chain(&counter_auth)
.await;
(pubkey, account)
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider explicit matching for compressed variants.

The wildcard _ pattern works correctly here but makes it implicit which modes use compressed initialization. Consider explicit matching for clarity and to catch future enum additions at compile time:

-        _ => {
+        CommitAccountMode::CompressedCommit
+        | CommitAccountMode::CompressedCommitAndUndelegate => {
             let (pubkey, _hash, account) =
                 init_and_delegate_compressed_account_on_chain(&counter_auth)
                     .await;
             (pubkey, account)
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let (pubkey, mut account) = match mode {
CommitAccountMode::Commit | CommitAccountMode::CommitAndUndelegate => {
init_and_delegate_account_on_chain(
&counter_auth,
bytes as u64,
None,
)
.await
}
_ => {
let (pubkey, _hash, account) =
init_and_delegate_compressed_account_on_chain(&counter_auth)
.await;
(pubkey, account)
}
};
let (pubkey, mut account) = match mode {
CommitAccountMode::Commit | CommitAccountMode::CommitAndUndelegate => {
init_and_delegate_account_on_chain(
&counter_auth,
bytes as u64,
None,
)
.await
}
CommitAccountMode::CompressedCommit
| CommitAccountMode::CompressedCommitAndUndelegate => {
let (pubkey, _hash, account) =
init_and_delegate_compressed_account_on_chain(&counter_auth)
.await;
(pubkey, account)
}
};
🤖 Prompt for AI Agents
In test-integration/test-committor-service/tests/test_ix_commit_local.rs around
lines 161 to 176, the match uses a wildcard `_` to select the compressed
initialization branch which hides exactly which CommitAccountMode variants use
compressed setup; replace the wildcard with explicit matches for the compressed
variants (e.g., CommitAccountMode::Compressed and
CommitAccountMode::CompressedAndSomething) so each enum variant is handled
explicitly, ensuring clarity and that future enum additions produce a
compile-time match error; update the match arms to list all current compressed
variants explicitly and keep the Commit/CommitAndUndelegate arm as-is.

Comment on lines +535 to +544
#[tokio::test]
async fn test_commit_5_compressed_accounts_100bytes_bundle_size_2_undelegate_all(
) {
commit_5_compressed_accounts_100bytes(
2,
expect_strategies(&[(CommitStrategy::Args, 2)]),
CommitAccountMode::CompressedCommitAndUndelegate,
)
.await;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Incorrect expected strategy count - test will likely fail.

This test creates 5 accounts but expects only 2 commits in the strategies assertion. Comparing with the non-compressed equivalent test_commit_5_accounts_1kb_bundle_size_3_undelegate_all (lines 320-332) which correctly expects 5 total commits (3+2), this should also expect 5:

 async fn test_commit_5_compressed_accounts_100bytes_bundle_size_2_undelegate_all(
 ) {
     commit_5_compressed_accounts_100bytes(
         2,
-        expect_strategies(&[(CommitStrategy::Args, 2)]),
+        expect_strategies(&[(CommitStrategy::Args, 5)]),
         CommitAccountMode::CompressedCommitAndUndelegate,
     )
     .await;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[tokio::test]
async fn test_commit_5_compressed_accounts_100bytes_bundle_size_2_undelegate_all(
) {
commit_5_compressed_accounts_100bytes(
2,
expect_strategies(&[(CommitStrategy::Args, 2)]),
CommitAccountMode::CompressedCommitAndUndelegate,
)
.await;
}
#[tokio::test]
async fn test_commit_5_compressed_accounts_100bytes_bundle_size_2_undelegate_all(
) {
commit_5_compressed_accounts_100bytes(
2,
expect_strategies(&[(CommitStrategy::Args, 5)]),
CommitAccountMode::CompressedCommitAndUndelegate,
)
.await;
}
🤖 Prompt for AI Agents
In test-integration/test-committor-service/tests/test_ix_commit_local.rs around
lines 535 to 544, the test creates 5 accounts but the expected strategies
assertion only expects 2 commits; update the expectation to match the
non-compressed equivalent so the total expected commits are 5 by changing the
expect_strategies call to include both strategy counts (3 and 2) so the
assertion expects 5 commits in total.

Comment on lines +1059 to +1071
if !matches_undelegation {
trace!(
"Compressed account ({}) is {} but should be. Owner {} != {}",
account_pubkey,
if is_undelegate {
"not undelegated"
} else {
"undelegated"
},
acc.owner,
expected_owner,
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent owner logged vs owner compared.

Similar to the lamports fix applied earlier, the trace message logs acc.owner (line 1068) but the comparison at line 1045 uses data.owner. Log the value actually being compared:

         if !matches_undelegation {
             trace!(
                 "Compressed account ({}) is {} but should be. Owner {} != {}",
                 account_pubkey,
                 if is_undelegate {
                     "not undelegated"
                 } else {
                     "undelegated"
                 },
-                acc.owner,
+                data.owner,
                 expected_owner,
             );
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if !matches_undelegation {
trace!(
"Compressed account ({}) is {} but should be. Owner {} != {}",
account_pubkey,
if is_undelegate {
"not undelegated"
} else {
"undelegated"
},
acc.owner,
expected_owner,
);
}
if !matches_undelegation {
trace!(
"Compressed account ({}) is {} but should be. Owner {} != {}",
account_pubkey,
if is_undelegate {
"not undelegated"
} else {
"undelegated"
},
data.owner,
expected_owner,
);
}
🤖 Prompt for AI Agents
In test-integration/test-committor-service/tests/test_ix_commit_local.rs around
lines 1059 to 1071, the trace message logs acc.owner but the comparison uses
data.owner; update the trace to log data.owner (the value actually compared) so
the logged output matches the comparison, keeping the rest of the message and
variables unchanged.

Comment on lines +83 to +87
let acc = $photon_client
.get_compressed_account($address, None)
.await
.ok()
.and_then(|acc| Some(acc.value.clone()));
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Use .map() instead of .and_then() for clarity.

Line 87 uses .and_then(|acc| Some(acc.value.clone())), but since the closure always returns Some(...), this should be .map() instead. The and_then combinator is designed for operations that might return None, while map is for straightforward transformations.

Apply this diff:

         let acc = $photon_client
             .get_compressed_account($address, None)
             .await
             .ok()
-            .and_then(|acc| Some(acc.value.clone()));
+            .map(|acc| acc.value.clone());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let acc = $photon_client
.get_compressed_account($address, None)
.await
.ok()
.and_then(|acc| Some(acc.value.clone()));
let acc = $photon_client
.get_compressed_account($address, None)
.await
.ok()
.map(|acc| acc.value.clone());
🤖 Prompt for AI Agents
In test-integration/test-committor-service/tests/utils/transactions.rs around
lines 83 to 87, replace the use of .and_then(|acc| Some(acc.value.clone())) with
.map(|acc| acc.value.clone()) so the closure is a simple transformation (map)
rather than an option-producing combinator; keep the surrounding .ok() and await
as-is and ensure the resulting expression compiles with the changed combinator.

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.

8 participants