Skip to content

Conversation

@ananas-block
Copy link
Contributor

@ananas-block ananas-block commented Oct 25, 2025

Summary by CodeRabbit

  • New Features

    • Introduced separate V1 and V2 address tree network fee constants (5000 and 10000 respectively).
    • Added authorization validation for batched merkle tree initialization.
    • Implemented version-aware input compressed account tracking.
  • Bug Fixes

    • Improved error handling for missing legacy merkle context.
  • Refactor

    • Updated default network fees and introduced distinct address network fee configuration.
    • Reorganized fee calculation logic into per-input and per-address components.
    • Deprecated program-owned tree creation paths; V1 address trees now loaded from persistent storage.
    • Simplified feature defaults across multiple programs.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 25, 2025

Walkthrough

This PR introduces fee structure versioning (v1/v2 for input accounts), consolidates network fee configuration (address_network_fee), deprecates program-owned state trees, adds authorization checks to batched merkle tree initialization, refactors system context fee handling, and updates test infrastructure to load accounts from JSON files.

Changes

Cohort / File(s) Summary
Fee Configuration Refactoring
sdk-libs/client/src/fee.rs, program-tests/utils/src/e2e_test_env.rs, program-tests/system-test/tests/test.rs, program-tests/system-cpi-v2-test/tests/invoke_cpi_with_read_only.rs, program-tests/system-cpi-test/tests/test_program_owned_trees.rs
Replaced single num_input_compressed_accounts field with versioned v1_input_compressed_accounts (u8) and v2_input_compressed_accounts (bool); updated fee calculation logic to apply network fees per-input for v1 or once for v2; added fee_config field to TransactionParams.
Network Fee Consolidation
programs/registry/src/protocol_config/state.rs, program-libs/batched-merkle-tree/src/initialize_address_tree.rs, program-tests/registry-test/tests/tests.rs
Renamed place_holder_a to address_network_fee in ProtocolConfig struct; updated defaults from 0/5000 to 10000; updated all test initializations and registry logic to reference new field name.
Batched Tree Initialization Authorization
programs/account-compression/src/instructions/initialize_batched_address_merkle_tree.rs, programs/account-compression/src/instructions/initialize_batched_state_merkle_tree.rs
Removed public re-exports of validation functions; added non-test authorization checks requiring registered program PDA with specific group authority; returns UnsupportedParameters if checks fail; preserved test-mode path with fully-qualified validation calls.
Migrate State Feature Gating
programs/account-compression/Cargo.toml, programs/account-compression/src/lib.rs, programs/package.json
Added migrate-state feature flag; changed default features from ["test"] to []; conditionally compiles migrate_state instruction based on feature flag; updated build script to include both test and migrate-state features.
System Context Fee Handling Restructure
programs/system/src/context.rs, programs/system/src/processor/cpi.rs, programs/system/src/processor/create_outputs_cpi_data.rs
Removed address_fee_is_set field; added network_fee: u64 to MerkleTreeContext; converted set_address_fee and set_network_fee to return Result; introduced set_network_fee_v1 and set_network_fee_v2 methods; added private set_additive_fee helper with overflow checks.
System Processor Fee Application
programs/system/src/processor/create_inputs_cpi_data.rs, programs/system/src/processor/create_address_cpi_data.rs, programs/system/src/accounts/remaining_account_checks.rs
Replaced direct fee calls with versioned methods (set_network_fee_v1/set_network_fee_v2); updated legacy merkle context retrieval with explicit error handling; consolidated fee setup via set_legacy_merkle_context for all account types.
Program-owned Trees Deprecation
program-tests/system-cpi-test/tests/test.rs, program-tests/system-cpi-test/tests/test_program_owned_trees.rs
Replaced program-owned token ID with None; commented out program-owned tree creation tests; marked test as ignored; updated parameter structure to use versioned input fields.
Registry Tree Initialization Validation
programs/registry/src/lib.rs, programs/registry/src/account_compression_cpi/rollover_batched_address_tree.rs, programs/registry/src/errors.rs
Added program_owner: Option<Pubkey> parameter to initialization paths; added checks requiring program owner for v1 address trees and rejecting it for v2; added ProgramOwnerDefined/ProgramOwnerUndefined error variants; replaced network_fee with address_network_fee in rollover CPI calls.
System Feature Flag Updates
programs/system/Cargo.toml
Reduced default features from ["debug", "readonly", "reinit"] to ["reinit"].
Test Infrastructure Updates
sdk-libs/program-test/src/accounts/initialize.rs, sdk-libs/program-test/src/indexer/test_indexer.rs, sdk-libs/program-test/src/program_test/light_program_test.rs, sdk-libs/program-test/src/utils/load_accounts.rs
Removed in-memory v1 address tree creation; added loading from JSON files; introduced load_account_from_dir utility; added forester publisher configuration for owned trees; replaced direct byte mutation with account set operations.
Registry Test Updates
program-tests/registry-test/tests/tests.rs
Removed feature gates; updated ProtocolConfig initialization with address_network_fee; added forester/program owner validation tests; added error assertions for missing forester/program owner; updated test structures to match new field names and parameter requirements.
Test Utility Error Handling
program-tests/utils/src/lib.rs
Added early error return after address merkle tree creation; added clippy silence annotation.
JavaScript Constants Versioning
js/stateless.js/src/constants.ts, js/stateless.js/tests/e2e/compress.test.ts, js/stateless.js/tests/e2e/test-rpc.test.ts
Replaced single ADDRESS_TREE_NETWORK_FEE with ADDRESS_TREE_NETWORK_FEE_V1 (5000) and ADDRESS_TREE_NETWORK_FEE_V2 (10000); updated fee calculation logic to branch on v2 flag; updated test assertions to compute and reuse expected fees.
Error Handling Extension
programs/system/src/errors.rs
Added MissingLegacyMerkleContext error variant with code 6066.

Sequence Diagram(s)

sequenceDiagram
    participant Test
    participant InitBatched as initialize_batched_address_merkle_tree
    participant Validation
    participant Registry as registered_program_pda
    participant TreeInit as init_batched_address_merkle_tree

    Test->>InitBatched: Call with params
    
    alt Non-Test Build
        InitBatched->>Validation: Check params == default
        alt Params != default
            Validation-->>InitBatched: UnsupportedParameters
            InitBatched-->>Test: Error
        else Params == default
            InitBatched->>Registry: Fetch registered_program_pda
            alt registered_program_pda exists
                Registry-->>InitBatched: Some(pda)
                InitBatched->>Validation: Verify group_authority matches
                alt Authority matches hardcoded key
                    Validation-->>InitBatched: Ok
                    InitBatched->>TreeInit: Initialize tree
                    TreeInit-->>InitBatched: Success
                else Authority mismatch
                    Validation-->>InitBatched: UnsupportedParameters
                    InitBatched-->>Test: Error
                end
            else No registered_program_pda
                Registry-->>InitBatched: None
                InitBatched-->>Test: UnsupportedParameters
            end
        end
    else Test Build
        InitBatched->>Validation: Validate params via qualified path
        Validation-->>InitBatched: Ok/Error
        alt Validation passes
            InitBatched->>TreeInit: Initialize tree
            TreeInit-->>InitBatched: Success
        else Validation fails
            InitBatched-->>Test: Error
        end
    end
Loading
sequenceDiagram
    participant Processor
    participant SystemCtx as SystemContext
    participant MerkleCtx as MerkleTreeContext
    participant FeeHelper as set_additive_fee

    Processor->>SystemCtx: Call set_network_fee_v1(fee, index)
    SystemCtx->>FeeHelper: Delegate with fee & index
    
    alt Overflow check passes
        FeeHelper->>MerkleCtx: Accumulate fee
        MerkleCtx-->>FeeHelper: Updated
        FeeHelper-->>SystemCtx: Ok(())
    else Overflow detected
        FeeHelper-->>SystemCtx: ArithmeticOverflow
    end
    
    SystemCtx-->>Processor: Result<()>
    
    Processor->>SystemCtx: Call set_network_fee_v2(fee, index)
    SystemCtx->>MerkleCtx: Mark network fee set
    SystemCtx->>MerkleCtx: Queue initial fee
    MerkleCtx-->>SystemCtx: Complete
    SystemCtx-->>Processor: ()
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • Fee versioning logic (sdk-libs/client/src/fee.rs, programs/system/src/processor/create_inputs_cpi_data.rs): Verify v1 per-input multiplication vs v2 single-fee application across all code paths and test scenarios.
  • Authorization checks in batched tree initialization (programs/account-compression/src/instructions/initialize_batched_address_merkle_tree.rs, initialize_batched_state_merkle_tree.rs): Ensure hardcoded group authority verification is intentional and secure; confirm feature-gating logic is correct.
  • SystemContext restructuring (programs/system/src/context.rs): Review overflow checks in set_additive_fee, verify all callsites updated to handle new Result<()> returns, and confirm field removals don't break existing logic.
  • Registry parameter additions (programs/registry/src/lib.rs): Validate all program_owner checks across initialization paths and ensure ProgramOwnerDefined/Undefined errors propagate correctly.
  • Test account loading refactoring (sdk-libs/program-test/src/program_test/light_program_test.rs): Confirm JSON account deserialization and guard logic for exactly-one v1 address tree works across all test scenarios.
  • Feature flag changes: Verify migrate-state feature is correctly gated and that changing default features in programs/system/Cargo.toml doesn't break existing builds.

Possibly related PRs

  • #1976: Shares modifications to sdk-libs/program-test/src/utils/load_accounts.rs for account-loading utilities in test infrastructure and devenv account handling.

Suggested reviewers

  • sergeytimoshin

🐰 Hops through versioned fees so bright,
V1 and V2 now get it right,
Trees are blessed with auth so keen,
And contexts handle overflow serene,
A refactor worthy of a test-time treat!

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title Check ❓ Inconclusive The title "chore: pre release" is vague and generic, lacking specific information about what the changeset actually accomplishes. While the PR does appear to involve preparation for a release (given the structured changes throughout), the title fails to communicate the nature or significance of the changes. The changeset includes substantial modifications such as network fee restructuring, introduction of V1/V2 address tree versioning, addition of program owner validation, breaking changes to public APIs (TransactionParams, ProtocolConfig, method signatures), and deprecation of program-owned trees. A teammate scanning commit history would not understand the scope or purpose of these changes from the title alone. Consider revising the title to be more specific and descriptive of the main changes, such as "refactor: restructure network fees with address tree versioning" or "refactor: introduce v1/v2 address tree handling and program owner validation". This would give reviewers and future maintainers clearer insight into what was changed without requiring them to examine the full changeset.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jorrit/chore-pre-release

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

❤️ Share

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

@@ -1,5 +1,3 @@
#![cfg(feature = "test-sbf")]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed on purpose, these are not necessary since we dont run non sbf tests in the same test crate and prevent rust analyzer from compiling the file.

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

Caution

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

⚠️ Outside diff range comments (6)
sdk-libs/program-test/src/program_test/light_program_test.rs (1)

254-259: Replace unwraps with proper error mapping to avoid panics.

Parsing failures should return RpcError instead of panicking.

-                            let mut tree = BatchedMerkleTreeAccount::state_from_bytes(
+                            let mut tree = BatchedMerkleTreeAccount::state_from_bytes(
                                 tree_account_data.data_as_mut_slice(),
                                 &merkle_tree_pubkey.into(),
-                            )
-                            .unwrap();
+                            )
+                            .map_err(|e| RpcError::CustomError(format!(
+                                "Failed to parse batched state tree {}: {}",
+                                merkle_tree_pubkey, e
+                            )))?;-                            let mut queue = BatchedQueueAccount::output_from_bytes(
-                                queue_account_data.data_as_mut_slice(),
-                            )
-                            .unwrap();
+                            let mut queue = BatchedQueueAccount::output_from_bytes(
+                                queue_account_data.data_as_mut_slice(),
+                            )
+                            .map_err(|e| RpcError::CustomError(format!(
+                                "Failed to parse batched output queue {}: {}",
+                                output_queue_pubkey, e
+                            )))?;

Also applies to: 269-273

program-tests/account-compression-test/tests/address_merkle_tree_tests.rs (2)

1382-1392: One leftover 5000 conflicts with new 10000 default.

If not intentional, update to 10000 to keep test expectations coherent.

Apply:

-                            network_fee: Some(5000),
+                            network_fee: Some(10000),

146-155: Update network_fee at line 1389 in address_merkle_tree_tests.rs from 5000 to 10000.

Verification found that line 1389 in the same file still has network_fee: Some(5000), which is inconsistent with the updated value at lines 146-155. Update this occurrence to network_fee: Some(10000) to maintain consistency within the file.

programs/system/src/processor/create_address_cpi_data.rs (1)

54-61: Likely index mix-up for legacy rollover_fee (queue vs tree).

Elsewhere (e.g., create_outputs_cpi_data) legacy context is keyed by Merkle tree index. Using address_queue_index here risks wrong fee on multi-queue setups.

Apply:

-                    context
-                        .get_legacy_merkle_context(new_address_params.address_queue_index())
+                    context
+                        .get_legacy_merkle_context(
+                            new_address_params.address_merkle_tree_account_index()
+                        )
                         .unwrap()
                         .rollover_fee,

Optional: replace unwrap with error propagation similar to the previous comment.

programs/registry/src/lib.rs (1)

294-311: Inconsistent error handling and contradictory validation logic.

The deprecation checks contain several issues:

  1. Lines 298-301: Returns ForesterUndefined when program_owner.is_none(), but the semantic issue is that program_owner is missing, not forester. Consider using RegistryError::ProgramOwnerUndefined or similar.

  2. Lines 307-311: After establishing that program_owned trees are required and network fees are forbidden (deprecation restrictions), the code then checks if forester.is_none() and returns ForesterUndefined. This contradicts the deprecation intent stated in lines 294-297. If V1 address trees must be program-owned with no fees, why require a forester?

  3. The comment on line 308 states "Trees without a network fee will not be serviced by light foresters", but line 303 already enforces that network_fee must be None. This creates a logical contradiction.

Consider this correction:

-        // Address V1 trees are deprecated.
-        // Disable creation of forested address V1 trees.
-        // All address V1 trees must be program owned.
-        // All address V1 trees must not have fees.
-        if program_owner.is_none() {
-            msg!("Program owner must be defined.");
-            return err!(RegistryError::ForesterUndefined);
-        }
-        if merkle_tree_config.network_fee.is_some() {
-            msg!("Network fee must be None.");
-            return err!(RegistryError::InvalidNetworkFee);
-        }
-        // Only trees with a network fee will be serviced by light foresters.
-        if forester.is_none() {
-            msg!("Forester pubkey required for trees without a network fee.");
-            msg!("Trees without a network fee will not be serviced by light foresters.");
-            return err!(RegistryError::ForesterUndefined);
-        }
+        // Address V1 trees are deprecated.
+        // All address V1 trees must be program owned with a designated forester.
+        // All address V1 trees must not have network fees.
+        if program_owner.is_none() {
+            msg!("Program owner must be defined for deprecated V1 address trees.");
+            return err!(RegistryError::ProgramOwnerUndefined);
+        }
+        if forester.is_none() {
+            msg!("Forester must be defined for program-owned V1 address trees.");
+            return err!(RegistryError::ForesterUndefined);
+        }
+        if merkle_tree_config.network_fee.is_some() {
+            msg!("Network fee must be None for deprecated V1 address trees.");
+            return err!(RegistryError::InvalidNetworkFee);
+        }
programs/system/Cargo.toml (1)

13-30: Remove reinit from default features—it should not compile by default.

The documentation (lines 18–23) explicitly outlines a 4-step deployment process where step 3 requires recompiling without the reinit feature before final redeployment. Having reinit in default = ["reinit"] contradicts this intent: the migration code will compile by default, when it should only be enabled during the specific deployment window.

Additionally, a survey of 40+ Cargo.toml files across the codebase shows that programs/system/Cargo.toml is the sole outlier with a non-empty feature in defaults. All other programs use either default = [] or optional infrastructure features like ["custom-heap"]. This pattern reinforces that reinit should not ship by default.

Change default = ["reinit"] to default = [] and require the feature to be explicitly enabled during deployment via --features reinit.

🧹 Nitpick comments (16)
program-tests/system-cpi-v2-test/tests/invoke_cpi_with_read_only.rs (1)

2941-2941: Remove unnecessary println macro import from use statement.

The println! macro is part of the standard prelude and does not require an explicit import. Explicitly importing it is non-idiomatic and redundant.

-    use std::{collections::HashMap, println};
+    use std::collections::HashMap;
program-tests/system-cpi-test/tests/test_program_owned_trees.rs (1)

50-50: Consider removing the test entirely if the feature is permanently deprecated.

While ignoring the test is appropriate for deprecated functionality, ignored tests can accumulate bit rot and become maintenance burdens. If program-owned state trees are permanently deprecated with no plan to restore them, consider removing this test entirely. If there's value in keeping it for historical reference or potential future use, document that rationale in a comment.

sdk-libs/program-test/src/indexer/test_indexer.rs (2)

1392-1400: Consider clarifying the comment about custom fees.

The comment "We only allow program owned address trees with custom fees" could be misinterpreted. Setting network_fee: None indicates that the owning program handles fees through its own mechanism rather than using the standard network fee. Consider rephrasing to make this clearer.

-        let config = if owning_program_id.is_some() {
-            // We only allow program owned address trees with custom fees.
+        let config = if owning_program_id.is_some() {
+            // Program-owned address trees use custom fee handling (network_fee = None).
             AddressMerkleTreeConfig {
                 network_fee: None,
                 ..AddressMerkleTreeConfig::default()
             }

1408-1412: Consider improving error handling and comment clarity.

While this is test code where panics are somewhat acceptable, the .unwrap() on line 1410 could provide a more helpful error message if FORESTER_TEST_KEYPAIR conversion fails. Additionally, the inline comment on line 1412 could be more descriptive about why the forester is now required.

-            Some(
-                Keypair::try_from(FORESTER_TEST_KEYPAIR.as_slice())
-                    .unwrap()
-                    .pubkey(),
-            ), // std forester, we now need to set it.
+            Some(
+                Keypair::try_from(FORESTER_TEST_KEYPAIR.as_slice())
+                    .expect("FORESTER_TEST_KEYPAIR should be a valid keypair")
+                    .pubkey(),
+            ), // Forester is now required for address merkle tree initialization.
sdk-libs/program-test/src/program_test/light_program_test.rs (2)

112-121: Gate V1 JSON loading behind skip_v1_trees to honor config.

If skip_v1_trees is true, this block should be skipped to avoid enforcing “exactly 1 V1 address tree.” Wrap the block accordingly.

Apply around this block:

-                // Load V1 address tree accounts from JSON files
-                {
+                // Load V1 address tree accounts from JSON files
+                if !config.skip_v1_trees {
                   use crate::utils::load_accounts::load_account_from_dir;

                   if context.test_accounts.v1_address_trees.len() != 1 {
                     return Err(RpcError::CustomError(format!(
                       "Expected exactly 1 V1 address tree, found {}. V1 address trees are deprecated and only one is supported.",
                       context.test_accounts.v1_address_trees.len()
                     )));
                   }
                   …
-                }
+                }

126-151: Validate owner program before set_account to prevent mismatched artifacts.

Check that loaded V1 address tree and queue are owned by account_compression::ID before injecting.

Apply after each load:

-                    let tree_account =
-                        load_account_from_dir(&address_mt, Some("address_merkle_tree"))?;
+                    let tree_account =
+                        load_account_from_dir(&address_mt, Some("address_merkle_tree"))?;
+                    if tree_account.owner != account_compression::ID {
+                        return Err(RpcError::CustomError(format!(
+                            "Unexpected owner for V1 address tree {}: {}, expected {}",
+                            address_mt, tree_account.owner, account_compression::ID
+                        )));
+                    }-                    let queue_account = load_account_from_dir(
+                    let queue_account = load_account_from_dir(
                         &address_queue_pubkey,
                         Some("address_merkle_tree_queue"),
                     )?;
+                    if queue_account.owner != account_compression::ID {
+                        return Err(RpcError::CustomError(format!(
+                            "Unexpected owner for V1 address queue {}: {}, expected {}",
+                            address_queue_pubkey, queue_account.owner, account_compression::ID
+                        )));
+                    }

Based on learnings.

sdk-libs/program-test/src/accounts/initialize.rs (1)

151-167: LGTM on deprecating V1 address tree creation; keep docs in sync.

Since V1 address trees are now loaded from JSON, ensure related comments/utilities (e.g., find_accounts_dir notes) reflect this usage to avoid confusion.

programs/account-compression/src/instructions/initialize_address_merkle_tree_and_queue.rs (1)

44-46: Default fee bump looks fine; consider a named constant.

Use a shared DEFAULT_ADDRESS_NETWORK_FEE to avoid magic numbers and keep defaults in sync across crates.

program-libs/batched-merkle-tree/src/initialize_address_tree.rs (1)

47-50: Consistent fee default update.

Changes are coherent with the wider bump to 10000. Consider centralizing the default in one place (const) to prevent drift between runtime and test utils.

Also applies to: 205-209, 222-226, 238-242

programs/package.json (1)

6-6: Harden cargo invocation.

Add --no-default-features and use space‑separated features for portability.

-    "build": "cd system/ && cargo build-sbf && cd ..  && cd  account-compression/ && cargo build-sbf --features 'test, migrate-state' && cd .. && cd  registry/ && cargo build-sbf && cd .. && cd compressed-token/program && cargo build-sbf && cd ../../..",
+    "build": "cd system/ && cargo build-sbf && cd .. && cd account-compression/ && cargo build-sbf --no-default-features --features \"test migrate-state\" && cd .. && cd registry/ && cargo build-sbf && cd .. && cd compressed-token/program && cargo build-sbf && cd ../../..",
program-tests/system-cpi-test/tests/test.rs (1)

1485-1498: Don’t leave large blocks commented out; gate or replace with an ignored test.

Prefer #[ignore = "Program owned state trees are deprecated"] (or a feature gate) over commented code to keep intent explicit and test list clean.

Example:

-    // Program owned state trees are deprecated.
-    // perform_create_pda_failing(
-    //   ...
-    // ).await.unwrap();
+    #[ignore = "Program-owned state trees are deprecated"]
+    #[allow(unused_variables)]
+    async fn deprecated_program_owned_state_tree_case() {
+        // Retained for reference; remove once fully obsolete.
+        // perform_create_pda_failing(...).await.unwrap();
+    }
programs/account-compression/src/instructions/initialize_batched_state_merkle_tree.rs (1)

41-53: Pre‑release hard gate is OK; make it explicit, traceable, and maintainable.

  • Replace magic pubkey with a named const and log a reason on failure.
  • Consider guarding this whole block behind a dedicated cargo feature (e.g., pre-release-gate) so mainnet/testnet builds opt‑in explicitly.
  • Use a specific error code for “not allowed in this build” if available.
-        if let Some(registered_program_pda) = ctx.accounts.registered_program_pda.as_ref() {
-            if registered_program_pda.group_authority_pda
-                != pubkey!("24rt4RgeyjUCWGS2eF7L7gyNMuz6JWdqYpAvb1KRoHxs")
-            {
-                return err!(AccountCompressionErrorCode::UnsupportedParameters);
-            }
-        } else {
-            return err!(AccountCompressionErrorCode::UnsupportedParameters);
-        }
+        const ALLOWED_GROUP_AUTHORITY: Pubkey =
+            pubkey!("24rt4RgeyjUCWGS2eF7L7gyNMuz6JWdqYpAvb1KRoHxs");
+        if let Some(registered_program_pda) = ctx.accounts.registered_program_pda.as_ref() {
+            if registered_program_pda.group_authority_pda != ALLOWED_GROUP_AUTHORITY {
+                msg!("initialize_batched_state_merkle_tree: group_authority mismatch");
+                return err!(AccountCompressionErrorCode::UnsupportedParameters);
+            }
+        } else {
+            msg!("initialize_batched_state_merkle_tree: registered_program_pda is required");
+            return err!(AccountCompressionErrorCode::UnsupportedParameters);
+        }

Optionally wrap this whole block with #[cfg(feature = "pre-release-gate")]. Based on learnings.

programs/system/src/processor/create_address_cpi_data.rs (1)

43-53: Legacy fee bump: avoid magic number and unwrap.

  • Magic 5000: define a named const to document intent and keep changes centralized.
  • unwrap on legacy context can trap; prefer explicit error propagation.

Apply:

+const LEGACY_V1_ADDRESS_FEE_ADDEND: u64 = 5_000;
@@
-                let mut network_fee = context
-                    .get_legacy_merkle_context(
-                        new_address_params.address_merkle_tree_account_index(),
-                    )
-                    .unwrap()
-                    .network_fee;
+                let mut network_fee = context
+                    .get_legacy_merkle_context(
+                        new_address_params.address_merkle_tree_account_index(),
+                    )
+                    .ok_or(SystemProgramError::DeriveAddressError)?
+                    .network_fee;
                 if network_fee != 0 {
-                    network_fee += 5000;
+                    network_fee += LEGACY_V1_ADDRESS_FEE_ADDEND;
                 }
programs/account-compression/src/instructions/initialize_batched_address_merkle_tree.rs (1)

47-47: Harden the non-test gate: extract the authority pubkey to a constant and fix the comment.

  • Replace the inlined pubkey with a module-level constant; easier audits and reuse.
  • The TODO mentions “state trees” but this instruction initializes address trees; fix to avoid confusion.

Apply within the shown lines:

-        // TODO: test that only security group 24rt4RgeyjUCWGS2eF7L7gyNMuz6JWdqYpAvb1KRoHxs can create batched state trees
+        // TODO: test that only the security group can create batched address trees
         if let Some(registered_program_pda) = ctx.accounts.registered_program_pda.as_ref() {
-            if registered_program_pda.group_authority_pda
-                != pubkey!("24rt4RgeyjUCWGS2eF7L7gyNMuz6JWdqYpAvb1KRoHxs")
+            if registered_program_pda.group_authority_pda != SECURITY_GROUP_AUTHORITY
             {
                 return err!(AccountCompressionErrorCode::UnsupportedParameters);
             }

Add outside this range (top of file suggested):

const SECURITY_GROUP_AUTHORITY: Pubkey = pubkey!("24rt4RgeyjUCWGS2eF7L7gyNMuz6JWdqYpAvb1KRoHxs");

Optionally consider distinct errors for:

  • UnsupportedParameters (non-default params)
  • MissingRegisteredProgram
  • UnauthorizedGroup

Also applies to: 51-60

program-tests/account-compression-test/tests/batched_merkle_tree_test.rs (2)

68-154: Good negative test for non-test build gate (state trees).

Covers the Unauthorized/UnsupportedParameters path with the expected instruction index; ignored by default to avoid CI noise.

You could also wrap with #[cfg(not(feature = "test"))] to avoid compiling this test in test-feature builds.


156-183: Good negative test for non-test build gate (address trees).

Mirrors state tree failing path; error index 1 matches the second instruction in the tx.

Same optional #[cfg(not(feature = "test"))] gating applies if you prefer compile-time exclusion over #[ignore].

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a536e8 and ae542d0.

📒 Files selected for processing (32)
  • program-libs/batched-merkle-tree/src/initialize_address_tree.rs (4 hunks)
  • program-tests/account-compression-test/tests/address_merkle_tree_tests.rs (2 hunks)
  • program-tests/account-compression-test/tests/batched_merkle_tree_test.rs (1 hunks)
  • program-tests/registry-test/tests/tests.rs (7 hunks)
  • program-tests/system-cpi-test/tests/test.rs (4 hunks)
  • program-tests/system-cpi-test/tests/test_program_owned_trees.rs (2 hunks)
  • program-tests/system-cpi-v2-test/tests/invoke_cpi_with_read_only.rs (1 hunks)
  • program-tests/system-test/tests/test.rs (5 hunks)
  • program-tests/utils/src/e2e_test_env.rs (15 hunks)
  • program-tests/utils/src/lib.rs (1 hunks)
  • programs/account-compression/Cargo.toml (1 hunks)
  • programs/account-compression/src/instructions/initialize_address_merkle_tree_and_queue.rs (1 hunks)
  • programs/account-compression/src/instructions/initialize_batched_address_merkle_tree.rs (2 hunks)
  • programs/account-compression/src/instructions/initialize_batched_state_merkle_tree.rs (2 hunks)
  • programs/account-compression/src/lib.rs (1 hunks)
  • programs/package.json (1 hunks)
  • programs/registry/src/account_compression_cpi/rollover_batched_address_tree.rs (1 hunks)
  • programs/registry/src/errors.rs (1 hunks)
  • programs/registry/src/lib.rs (5 hunks)
  • programs/registry/src/protocol_config/state.rs (3 hunks)
  • programs/system/Cargo.toml (1 hunks)
  • programs/system/src/accounts/remaining_account_checks.rs (3 hunks)
  • programs/system/src/context.rs (4 hunks)
  • programs/system/src/processor/cpi.rs (0 hunks)
  • programs/system/src/processor/create_address_cpi_data.rs (2 hunks)
  • programs/system/src/processor/create_inputs_cpi_data.rs (2 hunks)
  • programs/system/src/processor/create_outputs_cpi_data.rs (1 hunks)
  • sdk-libs/client/src/fee.rs (5 hunks)
  • sdk-libs/program-test/src/accounts/initialize.rs (1 hunks)
  • sdk-libs/program-test/src/indexer/test_indexer.rs (1 hunks)
  • sdk-libs/program-test/src/program_test/light_program_test.rs (2 hunks)
  • sdk-libs/program-test/src/utils/load_accounts.rs (1 hunks)
💤 Files with no reviewable changes (1)
  • programs/system/src/processor/cpi.rs
🧰 Additional context used
📓 Path-based instructions (3)
programs/registry/src/account_compression_cpi/**/*.rs

📄 CodeRabbit inference engine (programs/registry/CLAUDE.md)

programs/registry/src/account_compression_cpi/**/*.rs: CPI processing functions must derive PDA signer seeds as [CPI_AUTHORITY_PDA_SEED, bump] and use CpiContext::new_with_signer with cpi_authority as the authority account and mapped target accounts.
Pass the data Vec through unchanged from the wrapper to the target program CPI; the target program performs deserialization.

Files:

  • programs/registry/src/account_compression_cpi/rollover_batched_address_tree.rs
programs/registry/src/account_compression_cpi/*.rs

📄 CodeRabbit inference engine (programs/registry/CLAUDE.md)

programs/registry/src/account_compression_cpi/*.rs: Each new operation module must define an Anchor context struct (e.g., NewOperationContext) with required accounts and a process_ function that prepares signer seeds, maps accounts to the target program, and executes the CPI.
Context structs for wrapper instructions must include standard accounts: optional registered_forester_pda (mut), authority Signer, cpi_authority with seeds/bump for CPI_AUTHORITY_PDA_SEED, registered_program_pda, target program handle, log_wrapper, and mutable target_account.

Files:

  • programs/registry/src/account_compression_cpi/rollover_batched_address_tree.rs
programs/registry/src/lib.rs

📄 CodeRabbit inference engine (programs/registry/CLAUDE.md)

programs/registry/src/lib.rs: Wrapper instruction handlers must: (1) load the target account metadata; (2) call check_forester with correct authority, target, forester PDA (optional), and computed work_units; (3) delegate via a CPI using a PDA signer.
Instruction handlers must compute work_units by operation type: batch operations use account.queue_batches.batch_size; single operations use DEFAULT_WORK_V1; custom operations compute based on complexity.
Load accounts according to type before check_forester: batched via BatchedMerkleTreeAccount::type_from_account_info(); regular via ctx.accounts.account.load()?.metadata; use custom deserialization when required.
Apply forester eligibility rules: with a forester PDA, validate epoch registration, eligibility, track work, and require network fee; without a forester PDA, ensure authority matches the tree’s designated forester.

Files:

  • programs/registry/src/lib.rs
🧠 Learnings (10)
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/error.rs : Maintain stable mapping of AccountError to ProgramError, including Pinocchio code mapping (1–11), in error.rs

Applied to files:

  • programs/registry/src/errors.rs
  • programs/system/src/context.rs
📚 Learning: 2025-10-15T03:46:26.767Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-10-15T03:46:26.767Z
Learning: Applies to programs/registry/src/lib.rs : Load accounts according to type before check_forester: batched via BatchedMerkleTreeAccount::type_from_account_info(); regular via ctx.accounts.account.load()?.metadata; use custom deserialization when required.

Applied to files:

  • sdk-libs/program-test/src/utils/load_accounts.rs
  • sdk-libs/program-test/src/accounts/initialize.rs
  • programs/account-compression/src/instructions/initialize_batched_address_merkle_tree.rs
  • programs/account-compression/src/instructions/initialize_batched_state_merkle_tree.rs
  • sdk-libs/program-test/src/program_test/light_program_test.rs
  • program-tests/registry-test/tests/tests.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/**/Cargo.toml : Define features solana, pinocchio, and test-only in Cargo.toml; default build should enable none

Applied to files:

  • programs/account-compression/Cargo.toml
  • programs/package.json
  • programs/system/Cargo.toml
📚 Learning: 2025-10-15T03:46:26.767Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-10-15T03:46:26.767Z
Learning: Applies to programs/registry/src/account_compression_cpi/**/*.rs : CPI processing functions must derive PDA signer seeds as [CPI_AUTHORITY_PDA_SEED, bump] and use CpiContext::new_with_signer with cpi_authority as the authority account and mapped target accounts.

Applied to files:

  • programs/registry/src/account_compression_cpi/rollover_batched_address_tree.rs
📚 Learning: 2025-10-16T06:33:19.426Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2025-10-16T06:33:19.426Z
Learning: Applies to program-libs/compressible/src/config.rs : Ensure serialization compatibility across Anchor, Pinocchio, and Borsh for core account types used by dependent programs

Applied to files:

  • program-tests/system-cpi-test/tests/test.rs
  • sdk-libs/program-test/src/program_test/light_program_test.rs
  • program-tests/account-compression-test/tests/batched_merkle_tree_test.rs
  • program-tests/registry-test/tests/tests.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/account_info/{solana.rs,pinocchio.rs,test_account_info.rs} : Gate SDK-specific implementations with #[cfg(feature = "solana"|"pinocchio"|"test-only")]

Applied to files:

  • program-tests/system-cpi-test/tests/test.rs
  • programs/system/src/context.rs
  • program-tests/account-compression-test/tests/batched_merkle_tree_test.rs
  • program-tests/registry-test/tests/tests.rs
📚 Learning: 2025-10-16T06:33:19.426Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2025-10-16T06:33:19.426Z
Learning: Applies to program-libs/compressible/src/config.rs : Maintain CompressibleConfig account structure with Anchor/Borsh/Pod (Pinocchio/Pod) serialization and related state validation methods (validate_active, validate_not_inactive) in src/config.rs

Applied to files:

  • program-tests/system-cpi-test/tests/test.rs
  • program-tests/account-compression-test/tests/batched_merkle_tree_test.rs
📚 Learning: 2025-10-15T03:46:26.767Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-10-15T03:46:26.767Z
Learning: Applies to programs/registry/src/lib.rs : Apply forester eligibility rules: with a forester PDA, validate epoch registration, eligibility, track work, and require network fee; without a forester PDA, ensure authority matches the tree’s designated forester.

Applied to files:

  • programs/registry/src/lib.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/!(account_info)/**/*.rs : Use AccountInfoTrait for runtime-agnostic account handling; avoid direct solana-program or pinocchio AccountInfo in general logic

Applied to files:

  • programs/system/src/context.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/account_info/{solana.rs,pinocchio.rs,test_account_info.rs} : Provide SDK-specific AccountInfoTrait implementations in account_info/{solana.rs,pinocchio.rs,test_account_info.rs}

Applied to files:

  • programs/system/src/context.rs
🧬 Code graph analysis (9)
programs/registry/src/account_compression_cpi/rollover_batched_address_tree.rs (1)
program-libs/merkle-tree-metadata/src/utils.rs (1)
  • if_equals_zero_u64 (1-7)
programs/account-compression/src/instructions/initialize_batched_address_merkle_tree.rs (1)
program-libs/batched-merkle-tree/src/initialize_address_tree.rs (3)
  • init_batched_address_merkle_tree_from_account_info (57-81)
  • validate_batched_address_tree_params (132-167)
  • default (36-51)
programs/account-compression/src/instructions/initialize_batched_state_merkle_tree.rs (1)
program-libs/batched-merkle-tree/src/initialize_state_tree.rs (2)
  • init_batched_state_merkle_tree_from_account_info (69-114)
  • validate_batched_tree_params (203-248)
sdk-libs/program-test/src/program_test/light_program_test.rs (1)
sdk-libs/program-test/src/utils/load_accounts.rs (1)
  • load_account_from_dir (144-195)
sdk-libs/program-test/src/indexer/test_indexer.rs (2)
program-libs/batched-merkle-tree/src/initialize_address_tree.rs (1)
  • default (36-51)
sdk-libs/program-test/src/accounts/address_tree.rs (1)
  • create_address_merkle_tree_and_queue_account (53-138)
program-tests/utils/src/e2e_test_env.rs (3)
program-tests/utils/src/system_program.rs (9)
  • inputs (329-333)
  • inputs (344-352)
  • inputs (396-400)
  • inputs (403-407)
  • inputs (469-473)
  • input_compressed_accounts (134-137)
  • input_compressed_accounts (191-194)
  • input_compressed_accounts (244-247)
  • input_compressed_accounts (251-254)
program-tests/system-test/tests/test.rs (4)
  • input_compressed_accounts (202-205)
  • input_compressed_accounts (244-247)
  • input_compressed_accounts (272-275)
  • input_compressed_accounts (276-279)
program-tests/utils/src/spl.rs (8)
  • input_compressed_accounts (630-634)
  • input_compressed_accounts (650-653)
  • input_compressed_accounts (760-763)
  • input_compressed_accounts (764-772)
  • input_compressed_accounts (783-786)
  • input_compressed_accounts (795-800)
  • input_compressed_accounts (802-806)
  • input_compressed_accounts (1137-1140)
program-tests/account-compression-test/tests/batched_merkle_tree_test.rs (6)
program-libs/batched-merkle-tree/src/initialize_address_tree.rs (2)
  • default (36-51)
  • test_default (194-209)
program-libs/batched-merkle-tree/src/initialize_state_tree.rs (2)
  • default (45-63)
  • test_default (292-310)
sdk-libs/program-test/src/program_test/light_program_test.rs (1)
  • new (66-362)
program-libs/batched-merkle-tree/src/queue.rs (1)
  • get_output_queue_account_size (550-565)
program-libs/batched-merkle-tree/src/merkle_tree.rs (1)
  • get_merkle_tree_account_size (957-982)
sdk-libs/program-test/src/utils/assert.rs (1)
  • assert_rpc_error (7-144)
programs/account-compression/src/lib.rs (1)
programs/account-compression/src/instructions/migrate_state.rs (1)
  • process_migrate_state (59-97)
program-tests/registry-test/tests/tests.rs (7)
program-libs/batched-merkle-tree/src/initialize_address_tree.rs (2)
  • default (36-51)
  • test_default (194-209)
programs/registry/src/protocol_config/state.rs (1)
  • default (51-70)
sdk-libs/program-test/src/program_test/config.rs (3)
  • default (121-161)
  • new (58-67)
  • default_test_forester (97-105)
program-libs/batched-merkle-tree/src/initialize_state_tree.rs (2)
  • default (45-63)
  • test_default (292-310)
sdk-libs/program-test/src/program_test/light_program_test.rs (1)
  • new (66-362)
program-tests/utils/src/lib.rs (1)
  • create_address_merkle_tree_and_queue_account_with_assert (78-182)
sdk-libs/program-test/src/utils/assert.rs (1)
  • assert_rpc_error (7-144)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (21)
  • GitHub Check: system-programs (sdk-libs, light-sdk-macros light-sdk light-program-test light-client light-compr...
  • GitHub Check: system-programs (anchor & pinocchio, ["cargo-test-sbf -p sdk-anchor-test", "cargo-test-sbf -p sdk...
  • GitHub Check: system-programs (token test, ["cargo-test-sbf -p sdk-token-test"])
  • GitHub Check: system-programs (native, ["cargo-test-sbf -p sdk-native-test", "cargo-test-sbf -p sdk-v1-native-t...
  • GitHub Check: cli-v2
  • GitHub Check: Forester e2e test
  • GitHub Check: cli-v1
  • GitHub Check: Test batched-merkle-tree-simulate
  • GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
  • GitHub Check: Test program-libs-slow
  • GitHub Check: programs (system-cpi-test-v2-functional-read-only, ["cargo-test-sbf -p system-cpi-v2-test -- func...
  • GitHub Check: Test program-libs-fast
  • GitHub Check: programs (compressed-token-and-e2e, ["cargo-test-sbf -p compressed-token-test --test v1", "cargo-...
  • GitHub Check: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
  • GitHub Check: programs (compressed-token-batched-tree, ["cargo-test-sbf -p compressed-token-test -- test_transf...
  • GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
  • GitHub Check: stateless-js-v1
  • GitHub Check: programs (light-system-program-address, ["cargo-test-sbf -p system-test -- test_with_address", "c...
  • GitHub Check: lint
  • GitHub Check: programs (light-system-program-compression, ["cargo-test-sbf -p system-test -- test_with_compress...
  • GitHub Check: stateless-js-v2
🔇 Additional comments (35)
program-tests/system-cpi-test/tests/test_program_owned_trees.rs (1)

110-111: LGTM! Transaction parameters updated to versioned input tracking.

The change from num_input_compressed_accounts to separate v1_input_compressed_accounts and v2_input_compressed_accounts fields aligns with the broader refactoring mentioned in the PR summary. Setting both to 0/false is appropriate for this test case with no input compressed accounts.

sdk-libs/program-test/src/indexer/test_indexer.rs (1)

1390-1390: LGTM: Import added for test keypair.

The import is necessary for the forester configuration changes below.

sdk-libs/program-test/src/program_test/light_program_test.rs (2)

112-151: ✓ Address merkle tree JSON files verified.

Confirmed exactly 1 tree and 1 queue JSON file exist in cli/accounts:

  • address_merkle_tree_amt1Ayt45jfbdw5YSo7iz6WZxUmnZsQTYXy82hVwyC2.json
  • address_merkle_tree_queue_aq1S9z4reTSQAdgWHGD2zDaS39sjGrAxbR31vxJ2F4F.json

The "exactly 1" invariant checked at lines 116–122 is satisfied by the test setup.


300-347: Original verification script did not verify stated goal; script only confirmed base64 encoding format, not batch_size field presence or offset correctness.

The provided shell script (fd -t f '.json$' "$ACC_DIR"...) checks only that JSON account data uses base64 encoding (.account.data[1] == "base64"), which all accounts pass. However, the script does not:

  1. Decode base64 data to verify batch_size field exists at offset 240
  2. Validate the BatchedQueueMetadata layout claimed in the code comment
  3. Confirm consistency of batch_size values across accounts

To properly verify the batch_size extraction logic, you would need to decode account data and inspect bytes at offset 240-248, then confirm the offset matches the actual queue account structure.

The code's defensive practices are sound (length check ≥ 248 bytes, error handling via try_into(), consistency verification). However, the semantic correctness of offset 240 cannot be confirmed without access to the queue account struct definition or sample decoded account data.

program-tests/utils/src/lib.rs (1)

104-107: Prefer ? over manual error branching; remove clippy allow.

Restructure to bind the Ok value and return it at the end. This avoids #[allow(clippy::question_mark)] and keeps flow clear.

[ suggest_recommended_refactor ]

Apply:

-    let result = create_address_merkle_tree_and_queue_account(
+    let sig = create_address_merkle_tree_and_queue_account(
         payer,
         registry,
         context,
         address_merkle_tree_keypair,
         address_queue_keypair,
         program_owner,
         forester,
         merkle_tree_config,
         queue_config,
         index,
     )
     .await;
-
-    #[allow(clippy::question_mark)]
-    if result.is_err() {
-        return result;
-    }
+    let sig = match sig {
+        Ok(s) => s,
+        Err(e) => return Err(e),
+    };
@@
-    result
+    Ok(sig)
programs/account-compression/Cargo.toml (1)

21-26: Good: empty default features and explicit migrate-state.

Matches the “default build enables none” guidance. Ensure CI/build scripts pass --features test where needed (already adjusted in package.json). Based on learnings.

program-tests/system-cpi-test/tests/test.rs (1)

988-990: Aligns with deprecation of program‑owned state trees.

Passing None for program owner is consistent with the new policy.

Please confirm all helper APIs ignore/assume user-owned trees when None.

Also applies to: 1471-1473, 1511-1514

program-tests/account-compression-test/tests/address_merkle_tree_tests.rs (1)

1140-1149: Consistent fee across custom wrap-around tests.

This 10000 bump matches defaults; ensure all other custom configs in the suite use the same address network fee unless intentionally testing non-defaults.

To auto-fix a remaining 5000 in this file (if not intentional), apply:

-                            network_fee: Some(5000),
+                            network_fee: Some(10000),
programs/system/src/processor/create_address_cpi_data.rs (1)

78-82: Good: propagate errors from set_address_fee in V2 path.

Adding ? keeps behavior consistent with nearby fallible calls.

programs/system/src/processor/create_outputs_cpi_data.rs (1)

73-79: All call sites properly updated; API rename verified.

Verification confirms set_network_fee_v2 is defined in context.rs:73 and both call sites have been updated:

  • create_outputs_cpi_data.rs:75 (this file)
  • create_inputs_cpi_data.rs:62

No stale references to the old function name remain. The versioning strategy (v1 for legacy, v2 for current) is intentionally applied.

programs/registry/src/account_compression_cpi/rollover_batched_address_tree.rs (1)

50-53: Address network fee configuration is correctly sourced.

Verification confirms both address_network_fee and network_fee fields exist in ProtocolConfig and are intentionally used for their respective operations. The CPI seed/signer pattern and if_equals_zero_u64 wrapper are correct.

programs/registry/src/errors.rs (1)

31-34: Add #[msg] for error visibility, but discriminant concern is invalid.

The enum lacks #[msg] on ProgramOwnerDefined for better error reporting to clients. However, the discriminant stability risk is unfounded: adding #[msg] does not alter enum variant values, and no code relies on numeric error positions. All 60+ error references use symbolic RegistryError:: calls or standard Solana error casting, not hardcoded numeric codes.

Apply the suggestion for improved error messages:

-    ProgramOwnerDefined,
+    #[msg("Program owner already defined")]
+    ProgramOwnerDefined,
programs/account-compression/src/instructions/initialize_batched_address_merkle_tree.rs (2)

4-4: Import/use changes look fine.

No issues with the re-export path; consistent with program-libs layout.


42-44: Verify feature enablement for test validation path.

The feature test is properly defined in programs/account-compression/Cargo.toml and correctly gates the strict validation via #[cfg(feature = "test")]. However, program-tests/account-compression-test/ declares account-compression = { workspace = true } without enabling this feature. Since the program's default features are empty, the strict validation code will not execute during tests—only the fallback logic will run. Either enable --features test when building the program in tests, or confirm this is intentional.

programs/system/src/processor/create_inputs_cpi_data.rs (1)

62-66: Setting v2 network fee early is good.

Fee is set alongside selecting the batched tree and before sequence handling; ordering looks correct.

programs/system/src/accounts/remaining_account_checks.rs (1)

134-134: Code is correct: all v1 discriminators that require legacy context have it properly set.

Verification confirms:

  • STATE_MERKLE_TREE_ACCOUNT_DISCRIMINATOR (line 128): context retrieved in both input and output hashing
  • ADDRESS_MERKLE_TREE_ACCOUNT_DISCRIMINATOR (line 167): context retrieved for address creation
  • QUEUE_ACCOUNT_DISCRIMINATOR AddressV1 (line 201): context retrieved for address creation

All three set_legacy_merkle_context calls are necessary and actively used across the processor pipeline.

programs/registry/src/lib.rs (3)

335-350: LGTM! Correct enforcement of program-owned tree restriction.

The validation correctly forbids program-owned state trees and uses the appropriate ProgramOwnerDefined error. The network fee validation logic properly distinguishes between light-forester-serviced trees (with network_fee) and custom-forester trees (without network_fee but with explicit forester).


516-518: Breaking change: batched state trees now require network fees.

The else branch at lines 516-518 changes the behavior from allowing trees without network fees (if they have a custom forester) to requiring all batched state trees to have network fees. This enforces that batched state trees can only be serviced by light foresters.

This is a significant policy change that prevents custom foresters from operating batched state trees. Ensure this aligns with the intended deprecation strategy.

Based on learnings.


604-606: Breaking change: batched address trees now require network fees.

Similar to batched state trees, this changes the behavior to require all batched address trees to have network fees. Custom foresters can no longer operate batched address trees.

Ensure this policy change is intentional and documented.

Based on learnings.

program-tests/system-test/tests/test.rs (2)

926-927: LGTM! Consistent field renames for versioned input tracking.

All occurrences of TransactionParams correctly update from num_input_compressed_accounts to v1_input_compressed_accounts and add the new v2_input_compressed_accounts boolean field. The changes are mechanically consistent across the test file.

Also applies to: 1067-1068, 2016-2017, 2636-2637


1711-1716: Informative deprecation comment.

The comment correctly documents that V1 address trees are deprecated and no longer regenerated in tests, relying on existing JSON files in devenv mode. This provides useful context for test maintenance.

program-tests/registry-test/tests/tests.rs (4)

490-527: Test logic inconsistency: conflicting program_owner and forester requirements.

The test at lines 505-527 creates an address V1 tree with:

  • program_owner: Some(Pubkey::new_unique()) (line 516)
  • forester: None (line 517)
  • network_fee: None (line 520)

Based on the registry code changes (lines 294-311 in lib.rs), this should fail because:

  1. Line 307-311 in lib.rs requires forester.is_some() even for program-owned trees

However, the test expects ForesterUndefined error (line 526), which suggests the test is correctly expecting failure. But the comment says "Deprecated should fail" and "initialize a Merkle tree without a forester", implying the test validates that deprecated V1 trees without foresters are rejected.

This aligns with the registry logic, but the registry logic itself is contradictory (as noted in the earlier review comment).

Verify that the test expectations align with the corrected registry validation logic after fixing the issue identified in lines 294-311 of lib.rs.


1808-1816: Test validates breaking change: custom forester state trees now forbidden.

The test at lines 1808-1816 confirms that attempting to create a batched state tree with:

  • forester: Some(custom_forester)
  • network_fee: None

Now fails with InvalidNetworkFee. This validates the breaking change that batched state trees must have network fees and cannot use custom foresters.


2083-2133: Good test coverage for mainnet initialization constraints.

The new tests validate that mainnet initialization (without test features) enforces production-ready parameters and rejects test-only configurations. This helps prevent accidental deployment of test trees to mainnet.


1671-1671: Verify unused parameter: _input – Review comment is incorrect.

The _input parameter in the migrate_state function is not unused. In programs/account-compression/src/lib.rs (line 297), it's actively passed to process_migrate_state(&_ctx, _input). The underscore prefix is a Rust naming convention, not an indicator that the parameter is unused. The migration operation properly receives and uses its input parameters.

Likely an incorrect or invalid review comment.

sdk-libs/client/src/fee.rs (1)

76-86: Fee calculation logic for v1/v2 inputs is correctly implemented and intentionally asymmetric.

Based on codebase verification:

  • v1 implementation (lines 77-78): Fee scales linearly with v1_input_compressed_accounts count
  • v2 implementation (line 80): Fee is flat, charged once per transaction regardless of batch size

This asymmetry is confirmed as intentional and correct:

  1. Both code paths are tested extensively in program-tests/system-test/tests/test.rs (e.g., lines 2016-2023)
  2. The if/else if structure explicitly ensures mutual exclusion between v1 and v2 charging
  3. Registry program validation in programs/registry/src/lib.rs accepts both fee structures without complaint
  4. The TransactionParams structure correctly distinguishes v1 as a count (u8) and v2 as a flag (bool), supporting the different charging models

The flat fee for v2 batched trees makes sense architecturally—since v2 processes multiple inputs in a single batch atomically, charging a single fee aligns with the batched processing model.

program-tests/utils/src/e2e_test_env.rs (2)

1317-1317: LGTM - Address network fee update aligns with protocol changes.

The increase from 5000 to 10000 lamports correctly reflects the documented address creation fee structure introduced in this PR. Per the updated documentation in context.rs, address creation charges 10000 lamports per address.


1546-1564: LGTM - TransactionParams refactoring correctly implements versioned input accounting.

The replacement of num_input_compressed_accounts with separate v1_input_compressed_accounts and v2_input_compressed_accounts fields correctly implements the new fee model:

  • StateV2 (batched trees): inputs=0, is_v2=true - fees charged once per tree regardless of input count
  • StateV1 (legacy trees): inputs=count, is_v2=false - fees charged per input

This pattern is consistently applied across all transaction types throughout the file (sol transfers, compressions, address creation, spl operations), ensuring uniform fee handling.

programs/system/src/context.rs (6)

12-15: LGTM - Necessary import for overflow protection.

The addition of ProgramError import enables proper error handling for arithmetic overflow checks introduced in the fee accumulation methods.


43-43: LGTM - Field addition supports separate network fee tracking.

The network_fee field enables independent tracking of network fees in the legacy Merkle tree context, supporting the PR's fee separation objectives.


73-78: LGTM - Appropriate fee charging for V2 batched trees.

The set_network_fee_v2 method correctly implements the "charge once per tree" model for V2 batched state trees. The network_fee_is_set guard prevents double-charging, and no overflow check is needed since this performs a single insertion rather than accumulation.


80-93: LGTM - Proper fee accumulation for V1 legacy trees with overflow protection.

The set_network_fee_v1 method correctly implements per-input fee accumulation for V1 trees with appropriate overflow protection. The logic mirrors set_address_fee, allowing both address fees and network fees to accumulate for the same tree index, which is the expected behavior for comprehensive fee accounting.


165-178: LGTM - Clear and comprehensive fee structure documentation.

The updated documentation provides excellent clarity on the network fee distribution model:

  • V1 state trees: per-input charging (5000 lamports each)
  • V2 batched state trees: per-tree charging (5000 lamports once)
  • Address creation: per-address charging (10000 lamports each)

The concrete examples help developers understand how fees accumulate across different transaction types.


59-71: LGTM - Critical security improvement with proper error handling throughout.

The addition of checked_add and Result<()> return type effectively prevents arithmetic overflow vulnerabilities. Both callers in derive_new_addresses correctly propagate the Result using the ? operator, ensuring errors are handled appropriately up the call stack.

programs/system/Cargo.toml (1)

25-27: Clarify the removal of debug and readonly features.

The readonly feature (line 27) remains defined but is no longer in the default set. Additionally, based on the AI summary, a debug feature was removed from defaults but is not visible in the provided code snippet—it appears to have been entirely removed.

Please clarify:

  • readonly: Is this feature still used elsewhere, or should it be removed entirely if no longer needed?
  • debug: Was this feature completely removed, or is it still defined elsewhere in the codebase?

This will help confirm the simplification is intentional and complete.

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

Caution

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

⚠️ Outside diff range comments (4)
programs/account-compression/src/instructions/initialize_batched_address_merkle_tree.rs (1)

63-72: Unreachable code: The None case is impossible in production builds.

Lines 57-59 ensure that registered_program_pda cannot be None in non-test builds, making the None branch at line 71 unreachable in production. This creates maintenance confusion because the code structure suggests flexibility that doesn't exist at runtime.

Consider:

  1. Extracting the non-test authorization logic into a separate function to make the control flow clearer
  2. Adding a comment explaining that the None case only applies to test builds
  3. If the flexibility is intentional for tests, document why tests require different ownership semantics

Example refactor to clarify the flow:

 #[cfg(not(feature = "test"))]
 {
     use crate::errors::AccountCompressionErrorCode;
     if params != InitAddressTreeAccountsInstructionData::default() {
         return err!(AccountCompressionErrorCode::UnsupportedParameters);
     }
-    if let Some(registered_program_pda) = ctx.accounts.registered_program_pda.as_ref() {
-        if registered_program_pda.group_authority_pda
-            != pubkey!("24rt4RgeyjUCWGS2eF7L7gyNMuz6JWdqYpAvb1KRoHxs")
-        {
-            return err!(AccountCompressionErrorCode::UnsupportedParameters);
-        }
-    } else {
-        return err!(AccountCompressionErrorCode::UnsupportedParameters);
-    }
+    // Production builds require authorized group PDA
+    let registered_program_pda = ctx.accounts.registered_program_pda.as_ref()
+        .ok_or(AccountCompressionErrorCode::UnsupportedParameters)?;
+    if registered_program_pda.group_authority_pda
+        != pubkey!("24rt4RgeyjUCWGS2eF7L7gyNMuz6JWdqYpAvb1KRoHxs")
+    {
+        return err!(AccountCompressionErrorCode::UnsupportedParameters);
+    }
 }

 // Check signer.
+// Note: In production, registered_program_pda is guaranteed to be Some by the check above.
+// The None case only applies when running with the 'test' feature.
 let owner = match ctx.accounts.registered_program_pda.as_ref() {
programs/registry/src/lib.rs (1)

356-365: On-chain panic risk: unwrap() on optional CPI context.

Avoid unwrap() in programs; it aborts the TX. Return a typed error if missing and proceed safely.

-        check_cpi_context(
-            ctx.accounts
-                .cpi_context_account
-                .as_ref()
-                .unwrap()
-                .to_account_info(),
-            &ctx.accounts.protocol_config_pda.config,
-        )?;
+        let cpi_ai = ctx
+            .accounts
+            .cpi_context_account
+            .as_ref()
+            .ok_or(RegistryError::MissingCpiContext)?
+            .to_account_info();
+        check_cpi_context(cpi_ai, &ctx.accounts.protocol_config_pda.config)?;

If RegistryError::MissingCpiContext does not exist, add it in errors.rs. Based on learnings.

programs/system/src/context.rs (2)

154-163: Overflow risk in set_rollover_fee; align with checked_add + fallible return.

This path still uses += without overflow checks and returns () unlike the new setters.

-    pub fn set_rollover_fee(&mut self, ix_data_index: u8, fee: u64) {
+    pub fn set_rollover_fee(&mut self, ix_data_index: u8, fee: u64) -> Result<()> {
         let payment = self
             .rollover_fee_payments
             .iter_mut()
             .find(|a| a.0 == ix_data_index);
         match payment {
-            Some(payment) => payment.1 += fee,
-            None => self.rollover_fee_payments.push((ix_data_index, fee)),
+            Some(payment) => {
+                payment.1 = payment.1.checked_add(fee).ok_or(ProgramError::ArithmeticOverflow)?
+            }
+            None => self.rollover_fee_payments.push((ix_data_index, fee)),
         };
+        Ok(())
     }

Update call sites accordingly.


181-186: Possible panic on out-of-bounds account index in transfer_fees.

Indexing accounts[*i as usize] can panic. Return a typed error instead, consistent with get_index_or_insert.

-    for (i, fee) in self.rollover_fee_payments.iter() {
-        transfer_lamports_invoke(fee_payer, &accounts[*i as usize], *fee)?;
-    }
+    for (i, fee) in self.rollover_fee_payments.iter() {
+        let account = accounts
+            .get(*i as usize)
+            .ok_or(SystemProgramError::PackedAccountIndexOutOfBounds)?;
+        transfer_lamports_invoke(fee_payer, account, *fee)?;
+    }

Prevents program aborts on malformed indices.

♻️ Duplicate comments (1)
programs/registry/src/lib.rs (1)

592-599: Remove debug logging of fees (duplicate of prior review).

The msg! prints add log noise and compute cost; drop them before release.

-            if network_fee != ctx.accounts.protocol_config_pda.config.address_network_fee {
-                msg!(
-                    "ctx.accounts.protocol_config_pda.config.address_network_fee {:?}",
-                    ctx.accounts.protocol_config_pda.config.address_network_fee
-                );
-                msg!("network_fee {:?}", network_fee);
+            if network_fee != ctx.accounts.protocol_config_pda.config.address_network_fee {
                 return err!(RegistryError::InvalidNetworkFee);
             }
🧹 Nitpick comments (2)
js/stateless.js/tests/e2e/compress.test.ts (1)

48-59: Fee calculation logic now adapts to V1/V2 semantics.

The updated logic correctly implements versioned fee semantics:

  • V2: Charges STATE_MERKLE_TREE_NETWORK_FEE once per transaction (if inputs or outputs exist)
  • V1: Charges STATE_MERKLE_TREE_NETWORK_FEE per input account
  • Adds networkAddressFee using the updated ADDRESS_TREE_NETWORK_FEE constant

However, the nested ternary operators (lines 48-54) reduce readability.

Consider extracting the conditional logic into a helper function for clarity:

-        const networkInFee = tx.in
-            ? featureFlags.isV2()
-                ? STATE_MERKLE_TREE_NETWORK_FEE
-                : STATE_MERKLE_TREE_NETWORK_FEE.mul(bn(tx.in))
-            : tx.out && featureFlags.isV2()
-              ? STATE_MERKLE_TREE_NETWORK_FEE
-              : bn(0);
+        const networkInFee = (() => {
+            if (featureFlags.isV2()) {
+                // V2: charge once if there are inputs or outputs
+                return tx.in || tx.out ? STATE_MERKLE_TREE_NETWORK_FEE : bn(0);
+            }
+            // V1: charge per input
+            return tx.in ? STATE_MERKLE_TREE_NETWORK_FEE.mul(bn(tx.in)) : bn(0);
+        })();
programs/system/src/context.rs (1)

59-71: Good: switched to checked_add and fallible API; consider de‑duping with a small helper.

Both setters share identical “find-or-insert + checked_add” logic. Extract a private helper to reduce drift:

+impl SystemContext<'_> {
+    #[inline]
+    fn add_fee_checked(&mut self, index: u8, fee: u64) -> Result<()> {
+        if let Some(p) = self.rollover_fee_payments.iter_mut().find(|a| a.0 == index) {
+            p.1 = p.1.checked_add(fee).ok_or(ProgramError::ArithmeticOverflow)?;
+        } else {
+            self.rollover_fee_payments.push((index, fee));
+        }
+        Ok(())
+    }
+}
@@
-    pub fn set_address_fee(&mut self, fee: u64, index: u8) -> Result<()> {
-        let payment = self.rollover_fee_payments.iter_mut().find(|a| a.0 == index);
-        match payment { /* ... */ }
-        Ok(())
-    }
+    pub fn set_address_fee(&mut self, fee: u64, index: u8) -> Result<()> {
+        self.add_fee_checked(index, fee)
+    }
@@
-    pub fn set_network_fee_v1(&mut self, fee: u64, index: u8) -> Result<()> {
-        let payment = self.rollover_fee_payments.iter_mut().find(|a| a.0 == index);
-        match payment { /* ... */ }
-        Ok(())
-    }
+    pub fn set_network_fee_v1(&mut self, fee: u64, index: u8) -> Result<()> {
+        self.add_fee_checked(index, fee)
+    }

Keeps arithmetic and error handling consistent across fee types.

Also applies to: 80-93

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae542d0 and 0656cb8.

📒 Files selected for processing (6)
  • js/stateless.js/src/constants.ts (1 hunks)
  • js/stateless.js/tests/e2e/compress.test.ts (3 hunks)
  • js/stateless.js/tests/e2e/test-rpc.test.ts (1 hunks)
  • programs/account-compression/src/instructions/initialize_batched_address_merkle_tree.rs (2 hunks)
  • programs/registry/src/lib.rs (5 hunks)
  • programs/system/src/context.rs (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
programs/registry/src/lib.rs

📄 CodeRabbit inference engine (programs/registry/CLAUDE.md)

programs/registry/src/lib.rs: Wrapper instruction handlers must: (1) load the target account metadata; (2) call check_forester with correct authority, target, forester PDA (optional), and computed work_units; (3) delegate via a CPI using a PDA signer.
Instruction handlers must compute work_units by operation type: batch operations use account.queue_batches.batch_size; single operations use DEFAULT_WORK_V1; custom operations compute based on complexity.
Load accounts according to type before check_forester: batched via BatchedMerkleTreeAccount::type_from_account_info(); regular via ctx.accounts.account.load()?.metadata; use custom deserialization when required.
Apply forester eligibility rules: with a forester PDA, validate epoch registration, eligibility, track work, and require network fee; without a forester PDA, ensure authority matches the tree’s designated forester.

Files:

  • programs/registry/src/lib.rs
🧠 Learnings (6)
📚 Learning: 2025-10-15T03:46:26.767Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-10-15T03:46:26.767Z
Learning: Applies to programs/registry/src/lib.rs : Load accounts according to type before check_forester: batched via BatchedMerkleTreeAccount::type_from_account_info(); regular via ctx.accounts.account.load()?.metadata; use custom deserialization when required.

Applied to files:

  • programs/account-compression/src/instructions/initialize_batched_address_merkle_tree.rs
📚 Learning: 2025-10-15T03:46:26.767Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-10-15T03:46:26.767Z
Learning: Applies to programs/registry/src/lib.rs : Apply forester eligibility rules: with a forester PDA, validate epoch registration, eligibility, track work, and require network fee; without a forester PDA, ensure authority matches the tree’s designated forester.

Applied to files:

  • programs/registry/src/lib.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/error.rs : Maintain stable mapping of AccountError to ProgramError, including Pinocchio code mapping (1–11), in error.rs

Applied to files:

  • programs/system/src/context.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/account_info/{solana.rs,pinocchio.rs,test_account_info.rs} : Gate SDK-specific implementations with #[cfg(feature = "solana"|"pinocchio"|"test-only")]

Applied to files:

  • programs/system/src/context.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/!(account_info)/**/*.rs : Use AccountInfoTrait for runtime-agnostic account handling; avoid direct solana-program or pinocchio AccountInfo in general logic

Applied to files:

  • programs/system/src/context.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/account_info/{solana.rs,pinocchio.rs,test_account_info.rs} : Provide SDK-specific AccountInfoTrait implementations in account_info/{solana.rs,pinocchio.rs,test_account_info.rs}

Applied to files:

  • programs/system/src/context.rs
🧬 Code graph analysis (3)
programs/account-compression/src/instructions/initialize_batched_address_merkle_tree.rs (1)
program-libs/batched-merkle-tree/src/initialize_address_tree.rs (3)
  • init_batched_address_merkle_tree_from_account_info (57-81)
  • validate_batched_address_tree_params (132-167)
  • default (36-51)
js/stateless.js/tests/e2e/compress.test.ts (2)
js/stateless.js/src/constants.ts (3)
  • featureFlags (16-35)
  • STATE_MERKLE_TREE_NETWORK_FEE (356-356)
  • ADDRESS_TREE_NETWORK_FEE (361-361)
js/stateless.js/src/state/bn.ts (1)
  • bn (3-12)
js/stateless.js/tests/e2e/test-rpc.test.ts (1)
js/stateless.js/src/constants.ts (2)
  • featureFlags (16-35)
  • STATE_MERKLE_TREE_NETWORK_FEE (356-356)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (21)
  • GitHub Check: lint
  • GitHub Check: stateless-js-v2
  • GitHub Check: system-programs (sdk-libs, light-sdk-macros light-sdk light-program-test light-client light-compr...
  • GitHub Check: system-programs (token test, ["cargo-test-sbf -p sdk-token-test"])
  • GitHub Check: cli-v2
  • GitHub Check: system-programs (anchor & pinocchio, ["cargo-test-sbf -p sdk-anchor-test", "cargo-test-sbf -p sdk...
  • GitHub Check: system-programs (native, ["cargo-test-sbf -p sdk-native-test", "cargo-test-sbf -p sdk-v1-native-t...
  • GitHub Check: programs (compressed-token-batched-tree, ["cargo-test-sbf -p compressed-token-test -- test_transf...
  • GitHub Check: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
  • GitHub Check: programs (system-cpi-test-v2-functional-read-only, ["cargo-test-sbf -p system-cpi-v2-test -- func...
  • GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
  • GitHub Check: programs (light-system-program-compression, ["cargo-test-sbf -p system-test -- test_with_compress...
  • GitHub Check: programs (light-system-program-address, ["cargo-test-sbf -p system-test -- test_with_address", "c...
  • GitHub Check: programs (compressed-token-and-e2e, ["cargo-test-sbf -p compressed-token-test --test v1", "cargo-...
  • GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
  • GitHub Check: Test program-libs-slow
  • GitHub Check: Test batched-merkle-tree-simulate
  • GitHub Check: Test program-libs-fast
  • GitHub Check: Forester e2e test
  • GitHub Check: cli-v1
  • GitHub Check: stateless-js-v1
🔇 Additional comments (13)
js/stateless.js/src/constants.ts (1)

361-361: Address network fee doubled from 5000 to 10000.

The constant ADDRESS_TREE_NETWORK_FEE changed from new BN(5000) to new BN(10000), effectively doubling the per-address creation fee. This aligns with the PR objective to raise address network fees and matches other changes in the PR that raise default network_fee values to 10000.

Ensure that:

  • This breaking change is documented in release notes or migration guides
  • Dependent systems and integrations are aware of the fee increase
  • The rationale for the 100% increase is communicated to users
js/stateless.js/tests/e2e/test-rpc.test.ts (1)

63-73: Conditional fee calculation adapts to V1/V2 behavior.

The test now correctly computes expectedFee based on featureFlags.isV2(), charging STATE_MERKLE_TREE_NETWORK_FEE for V2 and zero for V1. This aligns with the PR's versioned fee semantics and improves test maintainability.

js/stateless.js/tests/e2e/compress.test.ts (1)

241-244: Good refactoring: compute fee once and reuse.

Storing the result in expectedTxFees and reusing it eliminates redundant computation and improves readability.

programs/account-compression/src/instructions/initialize_batched_address_merkle_tree.rs (2)

51-59: Add documentation explaining the intentional group authority security gate for batched operations.

This hardcoded check is a deliberate security gate (feature-gated for production only), but lacks documentation. Add a comment explaining:

  • Why only the batched initialization functions require this specific group authority
  • That 24rt4RgeyjUCWGS2eF7L7gyNMuz6JWdqYpAvb1KRoHxs is a Light Protocol group authority PDA
  • That this gate is intentional and not intended to be configurable

41-60: ****

The test at program-tests/registry-test/tests/tests.rs:1838-1844 does not exercise custom parameters as a passing case. Rather, it validates that custom parameters are properly rejected: assert_rpc_error(result, 1, RegistryError::InvalidNetworkFee.into()).unwrap() confirms the initialization fails when non-default parameters are provided. This test actually validates the production restriction, meaning there is no testing gap—the code correctly rejects non-default parameters in both test and production environments when the appropriate validation runs.

Likely an incorrect or invalid review comment.

programs/registry/src/lib.rs (6)

335-340: Program-owned state trees disabled — OK.

The ownership guard is correct and uses ProgramOwnerDefined consistently.


503-507: Program-owned batched State trees disabled — OK.

Consistent with the State V2 ownership policy.


516-518: Require network_fee for batched State init — OK.

For light foresters, fee must be present and match config.


586-590: Program-owned batched Address trees disabled — OK.

Matches the V2 ownership constraints.


604-606: Explicitly error on missing fee — OK.

Keeps init paths unambiguous for light foresters.


342-346: Code is correct; State/Address tree fee fields properly split in ProtocolConfig.

Verification confirms the split you questioned is implemented correctly:

  • ProtocolConfig defines network_fee (State trees) and address_network_fee (Address trees) on lines 37 and 42
  • No "state_network_fee" field exists
  • Lines 342–346 correctly compare State tree fees against config.network_fee
  • Address tree fees consistently use config.address_network_fee (e.g., line 591)
  • CPI calls reflect this same pattern throughout
programs/system/src/context.rs (2)

43-44: No concerns—MerkleTreeContext is purely in-memory and not serialized.

MerkleTreeContext has no serialization derives (Borsh, ZeroCopy, bytemuck, Account) and is only used in-memory within SystemContext's runtime state. Adding the network_fee field poses no ABI or layout risks.


12-15: No action needed—review comment is incorrect.

The code uses the correct type matching. The Result<T> type alias in programs/system/src/lib.rs:48 is defined as std::result::Result<T, ProgramError> where ProgramError is pinocchio::program_error::ProgramError. The ? operator on .ok_or(ProgramError::ArithmeticOverflow) in context.rs (lines 66, 88) produces the same error type, so propagation works without any conversion impl. No From<pinocchio::program_error::ProgramError> implementation is needed because the error type is already the pinocchio type directly.

Likely an incorrect or invalid review comment.

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

♻️ Duplicate comments (1)
programs/registry/src/lib.rs (1)

593-597: Remove debug logging from production code.

These debug msg! calls printing protocol config and network fee values should be removed before merging to production as they add unnecessary noise to transaction logs and increase compute costs.

Apply this diff:

             if network_fee != ctx.accounts.protocol_config_pda.config.address_network_fee {
-                msg!(
-                    "ctx.accounts.protocol_config_pda.config.address_network_fee {:?}",
-                    ctx.accounts.protocol_config_pda.config.address_network_fee
-                );
-                msg!("network_fee {:?}", network_fee);
                 return err!(RegistryError::InvalidNetworkFee);
             }
🧹 Nitpick comments (4)
programs/registry/src/errors.rs (1)

33-34: Add descriptive error messages for new variants.

The new error variants ProgramOwnerDefined and ProgramOwnerUndefined lack #[msg(...)] attributes. While some variants in this enum omit messages, adding descriptive messages improves developer experience and debugging.

Apply this diff to add error messages:

     #[msg("Insufficient funds in pool")]
     InsufficientFunds,
+    #[msg("Program owner must not be defined")]
     ProgramOwnerDefined,
+    #[msg("Program owner must be defined")]
     ProgramOwnerUndefined,
programs/registry/src/lib.rs (2)

516-518: Add explanatory message for mandatory network fee requirement.

The else branch now requires network_fee to be defined for batched state trees, representing a breaking change from optional behavior. Adding a msg!() call would help developers understand why None is invalid.

Apply this diff:

         } else {
+            msg!("Network fee is required for batched state trees serviced by light foresters.");
             return err!(RegistryError::InvalidNetworkFee);
         }

604-606: Add explanatory message for mandatory network fee requirement.

The else branch now requires network_fee to be defined for batched address trees, similar to the change in batched state trees. Adding a msg!() call would help developers understand why None is invalid.

Apply this diff:

         } else {
+            msg!("Network fee is required for batched address trees serviced by light foresters.");
             return err!(RegistryError::InvalidNetworkFee);
         }
sdk-libs/client/src/fee.rs (1)

69-69: Update comment to reflect v1 vs v2 fee charging models.

The comment states "Network fee is charged per input and per address," but this is only accurate for v1 transactions. For v2, the network fee is charged as a flat rate (line 77), not per input.

Update the comment to clarify:

-        // Network fee is charged per input and per address
+        // Network fee: v1 charges per input, v2 charges flat rate; both charge per address
         let mut network_fee: i64 = 0;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0656cb8 and 894f472.

📒 Files selected for processing (7)
  • programs/registry/src/errors.rs (1 hunks)
  • programs/registry/src/lib.rs (5 hunks)
  • programs/system/src/errors.rs (2 hunks)
  • programs/system/src/processor/create_address_cpi_data.rs (2 hunks)
  • programs/system/src/processor/create_inputs_cpi_data.rs (2 hunks)
  • programs/system/src/processor/create_outputs_cpi_data.rs (2 hunks)
  • sdk-libs/client/src/fee.rs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • programs/system/src/processor/create_outputs_cpi_data.rs
  • programs/system/src/processor/create_address_cpi_data.rs
🧰 Additional context used
📓 Path-based instructions (1)
programs/registry/src/lib.rs

📄 CodeRabbit inference engine (programs/registry/CLAUDE.md)

programs/registry/src/lib.rs: Wrapper instruction handlers must: (1) load the target account metadata; (2) call check_forester with correct authority, target, forester PDA (optional), and computed work_units; (3) delegate via a CPI using a PDA signer.
Instruction handlers must compute work_units by operation type: batch operations use account.queue_batches.batch_size; single operations use DEFAULT_WORK_V1; custom operations compute based on complexity.
Load accounts according to type before check_forester: batched via BatchedMerkleTreeAccount::type_from_account_info(); regular via ctx.accounts.account.load()?.metadata; use custom deserialization when required.
Apply forester eligibility rules: with a forester PDA, validate epoch registration, eligibility, track work, and require network fee; without a forester PDA, ensure authority matches the tree’s designated forester.

Files:

  • programs/registry/src/lib.rs
🧠 Learnings (4)
📚 Learning: 2025-10-16T06:33:19.426Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2025-10-16T06:33:19.426Z
Learning: Applies to program-libs/compressible/src/error.rs : Define error types with numeric codes in the 19xxx range and propagate hasher errors in the 7xxx range; include ProgramError conversions (Anchor, Pinocchio, Solana) in src/error.rs

Applied to files:

  • programs/system/src/errors.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/error.rs : Maintain stable mapping of AccountError to ProgramError, including Pinocchio code mapping (1–11), in error.rs

Applied to files:

  • programs/system/src/errors.rs
  • programs/registry/src/errors.rs
📚 Learning: 2025-10-15T03:46:26.767Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-10-15T03:46:26.767Z
Learning: Applies to programs/registry/src/account_compression_cpi/*.rs : Context structs for wrapper instructions must include standard accounts: optional registered_forester_pda (mut), authority Signer, cpi_authority with seeds/bump for CPI_AUTHORITY_PDA_SEED, registered_program_pda, target program handle, log_wrapper, and mutable target_account.

Applied to files:

  • programs/system/src/processor/create_inputs_cpi_data.rs
📚 Learning: 2025-10-15T03:46:26.767Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-10-15T03:46:26.767Z
Learning: Applies to programs/registry/src/lib.rs : Apply forester eligibility rules: with a forester PDA, validate epoch registration, eligibility, track work, and require network fee; without a forester PDA, ensure authority matches the tree’s designated forester.

Applied to files:

  • programs/registry/src/lib.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (21)
  • GitHub Check: Test program-libs-slow
  • GitHub Check: Test program-libs-fast
  • GitHub Check: Test batched-merkle-tree-simulate
  • GitHub Check: stateless-js-v1
  • GitHub Check: cli-v1
  • GitHub Check: lint
  • GitHub Check: cli-v2
  • GitHub Check: programs (system-cpi-test-v2-functional-read-only, ["cargo-test-sbf -p system-cpi-v2-test -- func...
  • GitHub Check: system-programs (token test, ["cargo-test-sbf -p sdk-token-test"])
  • GitHub Check: system-programs (native, ["cargo-test-sbf -p sdk-native-test", "cargo-test-sbf -p sdk-v1-native-t...
  • GitHub Check: system-programs (sdk-libs, light-sdk-macros light-sdk light-program-test light-client light-compr...
  • GitHub Check: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
  • GitHub Check: programs (light-system-program-compression, ["cargo-test-sbf -p system-test -- test_with_compress...
  • GitHub Check: system-programs (anchor & pinocchio, ["cargo-test-sbf -p sdk-anchor-test", "cargo-test-sbf -p sdk...
  • GitHub Check: programs (compressed-token-batched-tree, ["cargo-test-sbf -p compressed-token-test -- test_transf...
  • GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
  • GitHub Check: programs (light-system-program-address, ["cargo-test-sbf -p system-test -- test_with_address", "c...
  • GitHub Check: programs (compressed-token-and-e2e, ["cargo-test-sbf -p compressed-token-test --test v1", "cargo-...
  • GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
  • GitHub Check: Forester e2e test
  • GitHub Check: stateless-js-v2
🔇 Additional comments (9)
programs/system/src/errors.rs (1)

143-144: LGTM! Error variant correctly added.

The new MissingLegacyMerkleContext error variant is well-defined with a clear message and correctly mapped to error code 6066 in the conversion implementation. This follows the existing pattern and provides proper error handling for missing legacy Merkle tree contexts.

Also applies to: 228-228

programs/system/src/processor/create_inputs_cpi_data.rs (2)

62-62: LGTM! Versioned method aligns with V2 semantics.

The call to set_network_fee_v2 for BatchedStateTree appropriately uses the versioned method, distinguishing V2 batched trees from legacy V1 trees handled below.


79-85: Excellent fix! Previous panic risk resolved with proper error handling.

The unwrap has been replaced with .ok_or(SystemProgramError::MissingLegacyMerkleContext)?, which was the critical safety concern raised in the previous review. This change:

  • Prevents on-chain panics when legacy context is missing
  • Explicitly extracts network_fee and hashed_pubkey from the legacy context
  • Uses versioned set_network_fee_v1 for V1 state trees
  • Properly propagates errors via the ? operator

The new error variant has been correctly added to SystemProgramError with error code 6066.

programs/registry/src/lib.rs (2)

294-311: Address V1 deprecation policy correctly enforced.

The updated logic properly implements the deprecation policy for Address V1 trees:

  • Requires program ownership (lines 298-301)
  • Disallows network fees (lines 302-305)
  • Requires a designated forester (lines 308-310)

The error variants ProgramOwnerUndefined and InvalidNetworkFee are used appropriately, and the comments clearly explain the constraints.


335-339: State tree ownership policy correctly enforced.

The check properly rejects program-owned state trees using the new ProgramOwnerDefined error variant. This aligns with the architectural distinction between Address V1 trees (which must be program-owned) and state trees (which must not be).

sdk-libs/client/src/fee.rs (4)

28-28: Verify the address network fee increase is intentional.

The address_network_fee has been increased from the default of 5,000 to 10,000 in both the Default and test_batched() configurations. This doubles the cost per new address created (line 81-82). Ensure this change aligns with economic/pricing requirements and has been communicated to stakeholders.

Also applies to: 41-41


49-50: Clarify the behavior when both v1 and v2 input fields are set.

The fee logic (lines 73-78) uses if v1 != 0 followed by else if v2, meaning that if both v1_input_compressed_accounts > 0 AND v2_input_compressed_accounts = true, only the v1 fee will be charged. Consider:

  1. Adding validation to reject transactions with both fields set if this combination is invalid
  2. Documenting the precedence if the combination is valid but discouraged
  3. Returning an error if this represents a malformed transaction

Should this code enforce mutual exclusivity between v1 and v2 input fields? If yes, add validation before the fee calculation:

if transaction_params.v1_input_compressed_accounts != 0 
    && transaction_params.v2_input_compressed_accounts {
    return Err(RpcError::CustomError(
        "Cannot set both v1 and v2 input compressed accounts".to_string()
    ));
}

73-78: LGTM: Fee calculation correctly implements v1 per-input and v2 flat-rate charging.

The fee calculation properly handles the two versioning schemes:

  • v1: Charges network_fee * v1_input_compressed_accounts for per-input billing
  • v2: Charges a single network_fee as a flat rate

The type conversions from u8/u64 to i64 are safe and won't overflow.


80-83: LGTM: Address fee calculation and enhanced debug logging.

The per-address fee calculation correctly multiplies address_network_fee by the number of new addresses. The added debug logging for the full fee_config (lines 112-115) will improve troubleshooting when fee mismatches occur.

Also applies to: 112-115

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

🧹 Nitpick comments (1)
program-tests/registry-test/tests/tests.rs (1)

1696-1816: Update misleading test documentation comment.

The test documentation at line 1700 states:

/// 4. failing: create with state tree with custom forester and invalid non-zero network fee

However, the actual test implementation at line 1801 sets params.network_fee = None, not a non-zero value. The comment should be updated to accurately reflect what the test validates.

Apply this diff to correct the documentation:

-/// 4. failing: create with state tree with custom forester and invalid non-zero network fee
+/// 4. failing: create with state tree with custom forester and None network fee (unsupported configuration)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 894f472 and bf961c5.

📒 Files selected for processing (1)
  • program-tests/registry-test/tests/tests.rs (8 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-10-16T06:33:19.426Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2025-10-16T06:33:19.426Z
Learning: Applies to program-libs/compressible/src/config.rs : Ensure serialization compatibility across Anchor, Pinocchio, and Borsh for core account types used by dependent programs

Applied to files:

  • program-tests/registry-test/tests/tests.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/account_info/{solana.rs,pinocchio.rs,test_account_info.rs} : Gate SDK-specific implementations with #[cfg(feature = "solana"|"pinocchio"|"test-only")]

Applied to files:

  • program-tests/registry-test/tests/tests.rs
📚 Learning: 2025-10-15T03:46:26.767Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-10-15T03:46:26.767Z
Learning: Applies to programs/registry/src/lib.rs : Load accounts according to type before check_forester: batched via BatchedMerkleTreeAccount::type_from_account_info(); regular via ctx.accounts.account.load()?.metadata; use custom deserialization when required.

Applied to files:

  • program-tests/registry-test/tests/tests.rs
🧬 Code graph analysis (1)
program-tests/registry-test/tests/tests.rs (12)
sdk-libs/program-test/src/utils/assert.rs (1)
  • assert_rpc_error (7-144)
sdk-libs/program-test/src/program_test/rpc.rs (2)
  • None (472-472)
  • new (36-43)
sdk-libs/client/src/fee.rs (1)
  • default (19-31)
program-libs/batched-merkle-tree/src/initialize_address_tree.rs (2)
  • default (36-51)
  • test_default (194-209)
programs/account-compression/src/instructions/initialize_address_merkle_tree_and_queue.rs (1)
  • default (37-48)
programs/registry/src/protocol_config/state.rs (1)
  • default (51-70)
program-libs/compressed-account/src/lib.rs (1)
  • default (200-202)
sdk-libs/program-test/src/program_test/config.rs (3)
  • default (121-161)
  • new (58-67)
  • default_test_forester (97-105)
program-libs/batched-merkle-tree/src/initialize_state_tree.rs (2)
  • default (45-63)
  • test_default (292-310)
sdk-libs/program-test/src/program_test/light_program_test.rs (1)
  • new (66-362)
program-tests/utils/src/lib.rs (1)
  • create_address_merkle_tree_and_queue_account_with_assert (78-182)
program-tests/utils/src/batched_address_tree.rs (1)
  • create_address_merkle_tree_and_queue_account_with_assert (20-120)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (21)
  • GitHub Check: cli-v1
  • GitHub Check: stateless-js-v1
  • GitHub Check: cli-v2
  • GitHub Check: lint
  • GitHub Check: Test program-libs-fast
  • GitHub Check: Test program-libs-slow
  • GitHub Check: Test batched-merkle-tree-simulate
  • GitHub Check: programs (light-system-program-address, ["cargo-test-sbf -p system-test -- test_with_address", "c...
  • GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
  • GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
  • GitHub Check: programs (light-system-program-compression, ["cargo-test-sbf -p system-test -- test_with_compress...
  • GitHub Check: programs (compressed-token-and-e2e, ["cargo-test-sbf -p compressed-token-test --test v1", "cargo-...
  • GitHub Check: programs (system-cpi-test-v2-functional-read-only, ["cargo-test-sbf -p system-cpi-v2-test -- func...
  • GitHub Check: system-programs (token test, ["cargo-test-sbf -p sdk-token-test"])
  • GitHub Check: programs (compressed-token-batched-tree, ["cargo-test-sbf -p compressed-token-test -- test_transf...
  • GitHub Check: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
  • GitHub Check: system-programs (sdk-libs, light-sdk-macros light-sdk light-program-test light-client light-compr...
  • GitHub Check: system-programs (native, ["cargo-test-sbf -p sdk-native-test", "cargo-test-sbf -p sdk-v1-native-t...
  • GitHub Check: system-programs (anchor & pinocchio, ["cargo-test-sbf -p sdk-anchor-test", "cargo-test-sbf -p sdk...
  • GitHub Check: Forester e2e test
  • GitHub Check: stateless-js-v2
🔇 Additional comments (5)
program-tests/registry-test/tests/tests.rs (5)

108-108: LGTM! ProtocolConfig field correctly updated.

The field rename from place_holder_a to address_network_fee aligns with the ProtocolConfig changes across the codebase, and the value of 10000 matches the documented defaults.

Also applies to: 127-127


429-429: LGTM! Error expectation matches test inputs.

The test correctly expects ProgramOwnerUndefined when attempting to initialize a state Merkle tree without a program owner or forester.


528-549: LGTM! Previous issue resolved.

The test now correctly expects ProgramOwnerUndefined when program_owner is None but forester is Some(...). This properly validates the invariant that both must be provided together for program-owned trees.


1671-1671: LGTM! MigrateState field correctly updated.

The field rename from input to _input aligns with the updated account_compression::instruction::MigrateState structure.


2083-2133: LGTM! Good validation for production readiness.

These ignored tests properly validate that:

  1. V2 trees can initialize with production-safe default configs
  2. Test-only configs (using test_default()) are rejected in production builds

The #[ignore] attributes with descriptive reasons are appropriate since these tests require building the account compression program without test features.

@ananas-block ananas-block force-pushed the jorrit/chore-pre-release branch from bf961c5 to 8633b7a Compare October 26, 2025 00:43
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: 0

🧹 Nitpick comments (3)
program-tests/registry-test/tests/tests.rs (3)

505-506: Missing forester should fail with ForesterUndefined.

Test reflects the deprecation and expected error. Consider clarifying the comment text.

-// Deprecated should fail
-// initialize a Merkle tree without a forester
+// V1 address trees without a forester are deprecated and must fail
+// Expect RegistryError::ForesterUndefined

Also applies to: 510-527


550-571: V1 address: reject non-zero network_fee.

Assertion against InvalidNetworkFee is correct. Minor: use a consistent error-code conversion style across the file (prefer .into() everywhere) to avoid offset mistakes.


1809-1815: Init failure path: verify asserted instruction index.

LightProgramTest::new performs multiple setup instructions; index 3 can drift. Please re-run to confirm the index, or consider a helper that asserts by error code irrespective of index to reduce brittleness.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf961c5 and 8633b7a.

📒 Files selected for processing (1)
  • program-tests/registry-test/tests/tests.rs (7 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-10-16T06:33:19.426Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2025-10-16T06:33:19.426Z
Learning: Applies to program-libs/compressible/src/config.rs : Ensure serialization compatibility across Anchor, Pinocchio, and Borsh for core account types used by dependent programs

Applied to files:

  • program-tests/registry-test/tests/tests.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/account_info/{solana.rs,pinocchio.rs,test_account_info.rs} : Gate SDK-specific implementations with #[cfg(feature = "solana"|"pinocchio"|"test-only")]

Applied to files:

  • program-tests/registry-test/tests/tests.rs
📚 Learning: 2025-10-15T03:46:26.767Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-10-15T03:46:26.767Z
Learning: Applies to programs/registry/src/lib.rs : Load accounts according to type before check_forester: batched via BatchedMerkleTreeAccount::type_from_account_info(); regular via ctx.accounts.account.load()?.metadata; use custom deserialization when required.

Applied to files:

  • program-tests/registry-test/tests/tests.rs
🧬 Code graph analysis (1)
program-tests/registry-test/tests/tests.rs (8)
sdk-libs/client/src/fee.rs (1)
  • default (19-31)
program-libs/batched-merkle-tree/src/initialize_address_tree.rs (2)
  • default (36-51)
  • test_default (194-209)
programs/account-compression/src/instructions/initialize_address_merkle_tree_and_queue.rs (1)
  • default (37-48)
sdk-libs/program-test/src/program_test/config.rs (3)
  • default (121-161)
  • new (58-67)
  • default_test_forester (97-105)
program-libs/batched-merkle-tree/src/initialize_state_tree.rs (2)
  • default (45-63)
  • test_default (292-310)
sdk-libs/program-test/src/program_test/light_program_test.rs (1)
  • new (66-362)
program-tests/utils/src/lib.rs (1)
  • create_address_merkle_tree_and_queue_account_with_assert (78-182)
sdk-libs/program-test/src/utils/assert.rs (1)
  • assert_rpc_error (7-144)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (21)
  • GitHub Check: Test batched-merkle-tree-simulate
  • GitHub Check: Test program-libs-slow
  • GitHub Check: Test program-libs-fast
  • GitHub Check: programs (system-cpi-test-v2-functional-read-only, ["cargo-test-sbf -p system-cpi-v2-test -- func...
  • GitHub Check: stateless-js-v1
  • GitHub Check: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
  • GitHub Check: programs (light-system-program-compression, ["cargo-test-sbf -p system-test -- test_with_compress...
  • GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
  • GitHub Check: programs (compressed-token-batched-tree, ["cargo-test-sbf -p compressed-token-test -- test_transf...
  • GitHub Check: programs (light-system-program-address, ["cargo-test-sbf -p system-test -- test_with_address", "c...
  • GitHub Check: programs (compressed-token-and-e2e, ["cargo-test-sbf -p compressed-token-test --test v1", "cargo-...
  • GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
  • GitHub Check: Forester e2e test
  • GitHub Check: cli-v2
  • GitHub Check: system-programs (native, ["cargo-test-sbf -p sdk-native-test", "cargo-test-sbf -p sdk-v1-native-t...
  • GitHub Check: lint
  • GitHub Check: cli-v1
  • GitHub Check: system-programs (anchor & pinocchio, ["cargo-test-sbf -p sdk-anchor-test", "cargo-test-sbf -p sdk...
  • GitHub Check: system-programs (sdk-libs, light-sdk-macros light-sdk light-program-test light-client light-compr...
  • GitHub Check: system-programs (token test, ["cargo-test-sbf -p sdk-token-test"])
  • GitHub Check: stateless-js-v2
🔇 Additional comments (7)
program-tests/registry-test/tests/tests.rs (7)

108-108: ProtocolConfig: address_network_fee wired correctly (10000).

Matches SDK/client defaults and init params. LGTM.

Also applies to: 127-127


490-491: V1 address init: network_fee None for both tree and queue.

Semantics are correct for V1 (no per-address network fee). LGTM.

Also applies to: 496-499


528-549: Missing program owner should fail with ProgramOwnerUndefined.

Good correction; aligns with prior feedback and registry logic.


1671-1671: MigrateState input rename handled.

Switch to _input matches the instruction struct; prevents serialization mismatch. LGTM. (Based on learnings)


2083-2094: Ignored mainnet-style init test added.

Appropriate gating; no concerns. (Based on learnings)


2099-2115: Mainnet state-tree init fail (UnsupportedParameters).

Expectation looks right for test-default params; OK.


2116-2133: Mainnet address-tree init fail (UnsupportedParameters).

Consistent with parameter gating; OK.

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

Caution

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

⚠️ Outside diff range comments (1)
program-tests/utils/src/e2e_test_env.rs (1)

1577-1627: Fix: Incorrect fee params for v2 compressed accounts.

The function hardcodes v1_input_compressed_accounts and v2_input_compressed_accounts without checking the actual tree type of the input accounts (lines 1605-1606). While get_random_compressed_sol_accounts filters accounts to ensure they're all the same version, it doesn't communicate which version to the caller. If the returned accounts are from StateV2 trees, setting v1_input_compressed_accounts: input_compressed_accounts.len() and v2_input_compressed_accounts: false is incorrect—it should be v1_input_compressed_accounts: 0 and v2_input_compressed_accounts: true.

This will cause fee assertion failures when fee_assert is enabled and v2 accounts are randomly selected.

Apply a similar pattern to transfer_sol_deterministic (lines 1546-1550):

         let output_merkle_trees = self.get_merkle_tree_pubkeys(num_output_merkle_trees);
         let transaction_parameters = if self.keypair_action_config.fee_assert {
+            let first_tree_type = if !input_compressed_accounts.is_empty() {
+                self.indexer
+                    .get_state_merkle_trees()
+                    .iter()
+                    .find(|x| {
+                        x.accounts.merkle_tree.to_bytes()
+                            == input_compressed_accounts[0].merkle_context.merkle_tree_pubkey.to_bytes()
+                    })
+                    .unwrap()
+                    .tree_type
+            } else {
+                TreeType::StateV1
+            };
+            let (inputs, is_v2) = if first_tree_type == TreeType::StateV2 {
+                (0u8, true)
+            } else {
+                (input_compressed_accounts.len() as u8, false)
+            };
             Some(TransactionParams {
                 num_new_addresses: 0,
-                v1_input_compressed_accounts: input_compressed_accounts.len() as u8,
-                v2_input_compressed_accounts: false,
+                v1_input_compressed_accounts: inputs,
+                v2_input_compressed_accounts: is_v2,
                 num_output_compressed_accounts: num_output_merkle_trees as u8,
                 compress: 0,
                 fee_config: FeeConfig::default(),
             })

Note: This same issue affects multiple functions in this file (see subsequent comments).

♻️ Duplicate comments (14)
program-tests/utils/src/e2e_test_env.rs (10)

1629-1671: Fix: Same tree type issue in decompress_sol.

Lines 1647-1648 hardcode v1 fee parameters without checking the tree type of input_compressed_accounts, identical to the issue in transfer_sol. This will cause incorrect fee assertions when v2 accounts are used.

Apply the same fix pattern shown in the transfer_sol comment to determine the correct tree type before constructing TransactionParams.


1739-1785: Fix: Same tree type issue in compress_sol.

Lines 1756-1757 hardcode v1 fee parameters without checking the tree type of input_compressed_accounts, identical to the issue in transfer_sol. This will cause incorrect fee assertions when v2 accounts are used.

Apply the same fix pattern shown in the transfer_sol comment.


1873-1951: Fix: Same tree type issue in transfer_spl.

Lines 1925-1926 hardcode v1 fee parameters without checking the tree type of the token accounts. Token accounts include tree_info.tree, which can be looked up in self.indexer.get_state_merkle_trees() to determine the tree type, similar to the SOL transfer functions.

Check the tree type of the first token account's merkle tree before constructing TransactionParams.


1953-2008: Fix: Same tree type issue in approve_spl.

Lines 1985-1986 hardcode v1 fee parameters without checking tree type.

Apply the tree type checking pattern from transfer_sol_deterministic.


2010-2058: Fix: Same tree type issue in revoke_spl.

Lines 2039-2040 hardcode v1 fee parameters without checking tree type.

Apply the tree type checking pattern from transfer_sol_deterministic.


2060-2113: Fix: Same tree type issue in burn_spl.

Lines 2089-2090 hardcode v1 fee parameters without checking tree type.

Apply the tree type checking pattern from transfer_sol_deterministic.


2115-2159: Fix: Same tree type issue in freeze_spl.

Lines 2140-2141 hardcode v1 fee parameters without checking tree type.

Apply the tree type checking pattern from transfer_sol_deterministic.


2161-2199: Fix: Same tree type issue in thaw_spl.

Lines 2179-2180 hardcode v1 fee parameters without checking tree type.

Apply the tree type checking pattern from transfer_sol_deterministic.


2201-2264: Fix: Same tree type issue in compress_spl.

Lines 2239-2240 hardcode v1 fee parameters without checking tree type.

Apply the tree type checking pattern from transfer_sol_deterministic.


2266-2343: Fix: Same tree type issue in decompress_spl.

Lines 2318-2319 hardcode v1 fee parameters without checking tree type.

Apply the tree type checking pattern from transfer_sol_deterministic.

programs/system/src/context.rs (4)

83-89: V2 fee gating is still global; violates “once per tree” semantics and risks duplicates.

This repeats earlier feedback: with multiple V2 trees in one instruction, a single boolean undercharges; pushing blindly risks duplicate entries and lacks overflow safeguards. Please switch to per-index idempotency and call the additive helper; update signature to Result for consistency.

#!/bin/bash
# Find all call sites to assess multiplicity per instruction and ensure '?' is used.
rg -nP --type=rust -C2 '\bset_network_fee_v2\s*\(' programs/system/src/

150-159: Use checked_add in set_rollover_fee to prevent overflow.

Replace += with checked_add and map to a proper error, mirroring set_additive_fee.

-            Some(payment) => payment.1 += fee,
+            Some(payment) => {
+                payment.1 = payment
+                    .1
+                    .checked_add(fee)
+                    .ok_or(ProgramError::ArithmeticOverflow)?
+            },

161-176: Replace magic numbers with named constants and align docs/tests.

5_000 and 10_000 should come from constants (e.g., NETWORK_FEE_PER_V1_INPUT, NETWORK_FEE_PER_ADDRESS) to keep code/docs/tests in sync.


177-182: Bounds-check indices before indexing accounts in transfer_fees.

Potential OOB panic on malformed indexes; return a typed error instead.

-        for (i, fee) in self.rollover_fee_payments.iter() {
-            transfer_lamports_invoke(fee_payer, &accounts[*i as usize], *fee)?;
-        }
+        for (i, fee) in self.rollover_fee_payments.iter() {
+            let idx = *i as usize;
+            if idx >= accounts.len() {
+                return Err(SystemProgramError::AccountIndexOutOfBounds.into());
+            }
+            transfer_lamports_invoke(fee_payer, &accounts[idx], *fee)?;
+        }
🧹 Nitpick comments (7)
sdk-libs/client/src/fee.rs (2)

47-55: Consider validating v1/v2 mutual exclusivity.

The fee structure assumes v1_input_compressed_accounts and v2_input_compressed_accounts are mutually exclusive (either count v1 inputs or flag v2 usage). However, there's no validation enforcing this invariant. If both are set (e.g., v1_input_compressed_accounts = 5 and v2_input_compressed_accounts = true), the fee calculation at lines 73-78 would only charge the v1 fee due to the if-else logic, potentially leading to incorrect fee assertions.

Consider adding validation in a constructor or making the relationship explicit with an enum:

+impl TransactionParams {
+    pub fn new(
+        input_type: InputType,
+        num_output_compressed_accounts: u8,
+        num_new_addresses: u8,
+        compress: i64,
+        fee_config: FeeConfig,
+    ) -> Self {
+        let (v1_input_compressed_accounts, v2_input_compressed_accounts) = match input_type {
+            InputType::V1(count) => (count, false),
+            InputType::V2 => (0, true),
+            InputType::None => (0, false),
+        };
+        Self {
+            v1_input_compressed_accounts,
+            v2_input_compressed_accounts,
+            num_output_compressed_accounts,
+            num_new_addresses,
+            compress,
+            fee_config,
+        }
+    }
+}
+
+pub enum InputType {
+    V1(u8),
+    V2,
+    None,
+}

Alternatively, document the mutual exclusivity assumption clearly in the struct's doc comments.


69-83: Update comment to reflect v2 flat fee structure.

The comment at line 69 states "Network fee is charged per input and per address," but this is only accurate for v1 inputs. For v2 inputs, a single flat network_fee is charged regardless of the number of inputs. The per-address fee remains accurate.

Update the comment to clarify the versioned fee structure:

-        // Network fee is charged per input and per address
+        // Network fee: v1 charges per input, v2 charges a flat fee; address fee is always per-address
         let mut network_fee: i64 = 0;
js/stateless.js/src/constants.ts (1)

359-366: Versioned address-network fee: confirm semantics and add a version-aware helper/alias.

  • The JSDoc text for V1 and V2 is identical (“per address”). The PR summary hints V1 historically differed. Please confirm intended V1 semantics and align comments accordingly.
  • To reduce churn in callers and avoid future regressions, expose a version-aware export (and optional deprecated alias) so tests and apps don’t need to branch everywhere.

Example additions (placed after these constants):

+/**
+ * Returns the address network fee per created address for the active protocol version.
+ */
+export const addressNetworkFeePerAddress = () =>
+  featureFlags.isV2() ? ADDRESS_TREE_NETWORK_FEE_V2 : ADDRESS_TREE_NETWORK_FEE_V1;
+
+/**
+ * @deprecated Use ADDRESS_TREE_NETWORK_FEE_V1/ADDRESS_TREE_NETWORK_FEE_V2
+ * or addressNetworkFeePerAddress(). Will be removed after the next release.
+ */
+export const ADDRESS_TREE_NETWORK_FEE =
+  addressNetworkFeePerAddress();

If V1 is truly per-tx (not per-address), reflect that in both the JSDoc and helper naming (e.g., addressNetworkFeeForTx vs …PerAddress).

js/stateless.js/tests/e2e/compress.test.ts (2)

49-56: V2 input-fee branching matches “per-tx” charge; add parity check against program logic.
Logic LGTM. Please confirm that in V2 a tx with no inputs but with outputs still pays STATE_MERKLE_TREE_NETWORK_FEE, matching on-chain behavior. Consider adding a focused test for the V2 path.


57-67: Address network fee is hard-coded to V1; branch on feature flag now.
Implement the version-aware branch (or assert V1 in this suite) to prevent silent drift when tests run under V2.

-        /// Network fee charged per address created
-        const networkAddressFee = tx.addr
-            ? ADDRESS_TREE_NETWORK_FEE_V1.mul(bn(tx.addr))
-            : bn(0);
-        // TODO: adapt once we use v2 address trees in tests.
-        // tx.addr
-        //   ? featureFlags.isV2()
-        //       ? ADDRESS_TREE_NETWORK_FEE_V2.mul(bn(tx.addr))
-        //       : ADDRESS_TREE_NETWORK_FEE_V1.mul(bn(tx.addr))
-        //   : bn(0);
+        /// Network fee charged per address created
+        const networkAddressFee = tx.addr
+            ? (featureFlags.isV2()
+                  ? ADDRESS_TREE_NETWORK_FEE_V2.mul(bn(tx.addr))
+                  : ADDRESS_TREE_NETWORK_FEE_V1.mul(bn(tx.addr)))
+            : bn(0);
programs/system/src/context.rs (1)

41-44: Add network_fee to MerkleTreeContext — OK, but document units/source.

Field addition is fine. Please document units (lamports) and whether it mirrors registry’s address_network_fee to avoid drift.

programs/system/src/processor/create_address_cpi_data.rs (1)

43-50: Legacy network_fee fetch + fee enqueue — LGTM (minor naming nit).

Logic is correct. Consider renaming network_fee to address_network_fee_legacy for clarity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8633b7a and f6c990e.

📒 Files selected for processing (6)
  • js/stateless.js/src/constants.ts (1 hunks)
  • js/stateless.js/tests/e2e/compress.test.ts (3 hunks)
  • program-tests/utils/src/e2e_test_env.rs (14 hunks)
  • programs/system/src/context.rs (4 hunks)
  • programs/system/src/processor/create_address_cpi_data.rs (2 hunks)
  • sdk-libs/client/src/fee.rs (3 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/error.rs : Maintain stable mapping of AccountError to ProgramError, including Pinocchio code mapping (1–11), in error.rs

Applied to files:

  • programs/system/src/context.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/account_info/{solana.rs,pinocchio.rs,test_account_info.rs} : Gate SDK-specific implementations with #[cfg(feature = "solana"|"pinocchio"|"test-only")]

Applied to files:

  • programs/system/src/context.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/!(account_info)/**/*.rs : Use AccountInfoTrait for runtime-agnostic account handling; avoid direct solana-program or pinocchio AccountInfo in general logic

Applied to files:

  • programs/system/src/context.rs
📚 Learning: 2025-10-11T21:59:25.222Z
Learnt from: CR
PR: Lightprotocol/light-protocol#0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2025-10-11T21:59:25.222Z
Learning: Applies to program-libs/account-checks/src/account_info/{solana.rs,pinocchio.rs,test_account_info.rs} : Provide SDK-specific AccountInfoTrait implementations in account_info/{solana.rs,pinocchio.rs,test_account_info.rs}

Applied to files:

  • programs/system/src/context.rs
🧬 Code graph analysis (2)
programs/system/src/processor/create_address_cpi_data.rs (2)
program-libs/compressed-account/src/address.rs (1)
  • derive_address_legacy (5-12)
programs/system/src/errors.rs (2)
  • from (160-236)
  • from (240-242)
js/stateless.js/tests/e2e/compress.test.ts (2)
js/stateless.js/src/constants.ts (3)
  • featureFlags (16-35)
  • STATE_MERKLE_TREE_NETWORK_FEE (356-356)
  • ADDRESS_TREE_NETWORK_FEE_V1 (361-361)
js/stateless.js/src/state/bn.ts (1)
  • bn (3-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (21)
  • GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
  • GitHub Check: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
  • GitHub Check: programs (light-system-program-compression, ["cargo-test-sbf -p system-test -- test_with_compress...
  • GitHub Check: programs (system-cpi-test-v2-functional-read-only, ["cargo-test-sbf -p system-cpi-v2-test -- func...
  • GitHub Check: programs (compressed-token-and-e2e, ["cargo-test-sbf -p compressed-token-test --test v1", "cargo-...
  • GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
  • GitHub Check: programs (compressed-token-batched-tree, ["cargo-test-sbf -p compressed-token-test -- test_transf...
  • GitHub Check: programs (light-system-program-address, ["cargo-test-sbf -p system-test -- test_with_address", "c...
  • GitHub Check: stateless-js-v2
  • GitHub Check: lint
  • GitHub Check: cli-v2
  • GitHub Check: cli-v1
  • GitHub Check: system-programs (token test, ["cargo-test-sbf -p sdk-token-test"])
  • GitHub Check: system-programs (sdk-libs, light-sdk-macros light-sdk light-program-test light-client light-compr...
  • GitHub Check: Forester e2e test
  • GitHub Check: system-programs (native, ["cargo-test-sbf -p sdk-native-test", "cargo-test-sbf -p sdk-v1-native-t...
  • GitHub Check: system-programs (anchor & pinocchio, ["cargo-test-sbf -p sdk-anchor-test", "cargo-test-sbf -p sdk...
  • GitHub Check: Test program-libs-slow
  • GitHub Check: Test program-libs-fast
  • GitHub Check: Test batched-merkle-tree-simulate
  • GitHub Check: stateless-js-v1
🔇 Additional comments (12)
sdk-libs/client/src/fee.rs (2)

35-44: LGTM: Batched config increases address network fee.

The test_batched() configuration appropriately sets a higher address_network_fee (10,000 vs default 5,000) for batched operations.


112-115: LGTM: Enhanced logging for fee debugging.

The additional logging of the complete fee_config structure will help diagnose fee calculation mismatches during testing.

program-tests/utils/src/e2e_test_env.rs (3)

1546-1561: LGTM: Correct tree type handling in deterministic transfer.

The function correctly checks bundle.tree_type and sets v1_input_compressed_accounts and v2_input_compressed_accounts accordingly. StateV2 trees use a flat fee (v2=true, inputs=0), while v1 trees charge per input.


1704-1720: LGTM: Correct tree type handling in deterministic compress.

Like transfer_sol_deterministic, this function correctly checks bundle.tree_type to set the appropriate v1/v2 fee parameters.


1787-1871: LGTM: Address creation correctly sets no inputs.

The create_address function correctly sets v1_input_compressed_accounts: 0 and v2_input_compressed_accounts: false since address creation transactions don't consume input compressed accounts.

js/stateless.js/tests/e2e/compress.test.ts (2)

247-247: Readability win with expectedTxFees variable.
Nice improvement; keeps assertions cleaner and consistent.

Also applies to: 251-251


7-10: Verification complete: no unversioned uses found.

The search confirms all uses of ADDRESS_TREE_NETWORK_FEE are properly versioned:

  • ADDRESS_TREE_NETWORK_FEE_V1 at line 59 and exported at constants.ts:361
  • ADDRESS_TREE_NETWORK_FEE_V2 in comments at lines 64–65 and exported at constants.ts:366
  • Imports in compress.test.ts are correct

No unversioned ADDRESS_TREE_NETWORK_FEE exists anywhere in the codebase.

programs/system/src/context.rs (4)

12-15: Import change looks good.

Brings ProgramError into scope for overflow handling; consistent with Result alias usage.


59-61: Good: set_address_fee now returns Result and reuses the helper.

Error propagation and dedup via helper are consistent with other setters.


64-66: Good: set_network_fee_v1 unified through additive helper.

Consistent overflow handling and error propagation.


68-81: Helper implementation is solid.

Uses checked_add and returns ProgramError::ArithmeticOverflow; matches crate::Result conventions.

programs/system/src/processor/create_address_cpi_data.rs (1)

75-79: Confirm target account for V2 address fee.

Here you enqueue the address fee against the V2 tree index (not a queue). If that’s intentional for batched trees, add a short comment; if not, align with V1 behavior.

Copy link
Contributor

@SwenSchaeferjohann SwenSchaeferjohann left a comment

Choose a reason for hiding this comment

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

LGTM

@ananas-block ananas-block merged commit d82d1f5 into main Oct 26, 2025
32 of 33 checks passed
@ananas-block ananas-block deleted the jorrit/chore-pre-release branch October 26, 2025 20:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants