Skip to content

Comments

test: random unit tests light program compress decompress#2303

Open
ananas-block wants to merge 4 commits intomainfrom
jorrit/test-random-unit-tests-light-program-compress-decompres
Open

test: random unit tests light program compress decompress#2303
ananas-block wants to merge 4 commits intomainfrom
jorrit/test-random-unit-tests-light-program-compress-decompres

Conversation

@ananas-block
Copy link
Contributor

@ananas-block ananas-block commented Feb 19, 2026

Summary by CodeRabbit

Release Notes

  • Refactor

    • Restructured compression and decompression processors with a builder pattern for improved modularity and control flow.
    • Enhanced idempotent behavior across account processing operations.
  • Tests

    • Expanded test coverage with comprehensive test suites for compression and decompression workflows.
    • Added testing utilities for account construction and validation.
  • Chores

    • Added development dependencies to support enhanced testing infrastructure.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2026

📝 Walkthrough

Walkthrough

This PR introduces a builder pattern for CPI (Cross-Program Invocation) data construction in the compression/decompression processor modules. New builder functions validate accounts and construct CPI data structures, which are then invoked by updated processor functions with idempotent behavior. Development dependencies are added to support testing.

Changes

Cohort / File(s) Summary
Development Dependencies
sdk-libs/sdk-types/Cargo.toml
Added four dev-dependencies: solana-account-info, light-account-checks (with solana, test-only features), light-compressed-account (with keccak feature), and rand for testing and utility support.
Compression Processor Builder
sdk-libs/sdk-types/src/interface/program/compression/processor.rs
Introduced CompressPdaBuilt<'a, AI> struct and build_compress_pda_cpi_data() builder function that validates accounts and returns optional built CPI data. Updated process_compress_pda_accounts_idempotent() to accept additional parameters and delegate to the builder, enabling idempotent execution (skips CPI when non-compressible).
Decompression Processor Builders
sdk-libs/sdk-types/src/interface/program/decompression/processor.rs
Added two builder pathways: DecompressPdaBuilt<'a, AI> with build_decompress_pda_cpi_data() for PDA-only flows, and DecompressAccountsBuilt<'a, AI> with build_decompress_accounts_cpi_data() for combined PDA+token flows. Both builders validate accounts, construct CPI data, and return optional/result types. Updated processor functions to delegate to builders and invoke CPIs conditionally.
Test Utilities
sdk-libs/sdk-types/tests/common/mod.rs
Added helper functions: make_config_account() to construct a valid LightConfig account with PDAs, and make_dummy_account() to create writable test accounts with specified parameters.
Compression Processor Tests
sdk-libs/sdk-types/tests/compress_processor.rs
Comprehensive test suite covering builder validation errors (invalid system offset, missing accounts, config/ownership violations), idempotent behavior (returning None when non-compressible), and successful CPI data construction with correct instruction data and PDA close indices.
Decompression Processor Tests
sdk-libs/sdk-types/tests/decompress_processor.rs
Extensive test module validating decompression builder with mock DecompressVariant implementations, error path coverage (offset bounds, account constraints), idempotent behavior, and successful InstructionDataInvokeCpiWithAccountInfo construction.
Decompression Accounts Processor Tests
sdk-libs/sdk-types/tests/decompress_accounts_processor.rs
Large test suite with mock variant implementations (Skip, PDA, Token paths), helper account constructors for PDA-only and PDA+token layouts, comprehensive error validation, and randomized mixed scenarios testing DecompressAccountsBuilt structure correctness across has_pda_accounts, has_token_accounts, cpi_context, compressed_account_infos, and in_token_data fields.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Builder as build_compress_pda_cpi_data()
    participant Processor as process_compress_pda_accounts_idempotent()
    participant CPI as CPI Invocation
    participant PdaClose as Close PDAs

    Caller->>Builder: remaining_accounts, params, dispatch_fn
    Builder->>Builder: Validate system_accounts_offset
    Builder->>Builder: Validate config & rent_sponsor
    Builder->>Builder: Dispatch for each PDA account
    Builder->>Builder: Collect cpi_ix_data, cpi_accounts, pda_indices
    Builder-->>Caller: Ok(Some(CompressPdaBuilt)) or Ok(None)
    
    alt CompressPdaBuilt Present
        Caller->>Processor: built_data, cpi_signer, program_id
        Processor->>CPI: Invoke with cpi_accounts
        CPI-->>Processor: Success
        Processor->>PdaClose: Close PDAs at indices
        Processor-->>Caller: Ok(())
    else No CompressPdaBuilt (Non-compressible)
        Caller-->>Caller: Skip CPI invocation
    end
Loading
sequenceDiagram
    participant Caller
    participant PdaBuilder as build_decompress_pda_cpi_data()
    participant AcctBuilder as build_decompress_accounts_cpi_data()
    participant Processor as process_decompress_accounts_idempotent()
    participant PdaCPI as PDA CPI
    participant TokenCPI as Token CPI

    Caller->>AcctBuilder: remaining_accounts, params, variant_fn
    AcctBuilder->>AcctBuilder: Validate system_accounts_offset
    AcctBuilder->>AcctBuilder: Split PDA vs Token accounts
    AcctBuilder->>AcctBuilder: Build cpi_accounts, gather compressed_account_infos
    AcctBuilder->>AcctBuilder: Collect token_data, tlv, token_seeds
    AcctBuilder-->>Caller: Ok(DecompressAccountsBuilt)
    
    Caller->>Processor: built_accounts_data, dispatch_fn, cpi_signer
    Processor->>PdaBuilder: Validate PDA path exists
    alt PDAs to Decompress
        PdaBuilder-->>Processor: Ok(Some(DecompressPdaBuilt))
        Processor->>PdaCPI: Invoke PDA decompression
        PdaCPI-->>Processor: Success
    else No PDAs (Idempotent)
        PdaBuilder-->>Processor: Ok(None)
    end
    Processor-->>Caller: Ok(())
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • chore: csdk macros3 #2062: Shares the same compression/decompression CPI processing refactoring, RENT_SPONSOR constants, and builder pattern introduction.
  • chore: program trait #2178: Directly modifies the same process_compress_pda_accounts_idempotent and process_decompress_* APIs and CPI-building flows.
  • refactor: libs to nostd #1997: Refactors CpiSigner and CpiAccounts types that are now consumed by the updated processor function signatures taking CpiSigner and program_id parameters.

Suggested labels

ai-review

Suggested reviewers

  • sergeytimoshin
  • SwenSchaeferjohann

Poem

🏗️ Builder patterns rise in light,
Separating validation from invocation's flight,
Idempotent and clean, the two-phase way,
PDAs compress, decompress arrays all day!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 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 70.00%.
Title check ✅ Passed The title 'test: random unit tests light program compress decompress' clearly describes the primary change: adding random unit tests for compression/decompression. However, 'random' is somewhat vague about whether it means randomized test cases or random test additions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jorrit/test-random-unit-tests-light-program-compress-decompres

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.

@ananas-block
Copy link
Contributor Author

@CodeRabbit pls review despite the test keyword

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2026

@ananas-block: Understood! I'll review the PR despite the test keyword in the title. Initiating the review now.


🧠 Learnings used
Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: account-comparison/CLAUDE.md:0-0
Timestamp: 2026-01-10T19:26:01.412Z
Learning: Applies to account-comparison/programs/**/tests/test_compressed_account.rs : Include Light Protocol tests in test_compressed_account.rs to verify compressed account operations using LightAccount primitives

Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/sdk-token-test/CLAUDE.md:0-0
Timestamp: 2026-01-22T17:21:16.870Z
Learning: This test program tests ctoken instructions with light-token functions, using light-token from sdk-libs/compressed-token-sdk, light-token-interface from program-libs/token-interface, and light-compressed-token-program from programs/compressed-token/program/

Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/CLAUDE.md:0-0
Timestamp: 2026-01-31T16:39:11.741Z
Learning: Applies to sdk-libs/macros/src/light_pdas/program/**/*.rs : Generate compress and decompress instruction handlers automatically from Light accounts, extracting seed information and field data for CPI execution

Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: zk/nullifier/README.md:0-0
Timestamp: 2026-01-15T02:04:23.014Z
Learning: Use Light CLI for testing and validation - install via 'npm install -g lightprotocol/zk-compression-cli'

Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: counter/anchor/README.md:0-0
Timestamp: 2026-01-10T19:25:21.661Z
Learning: Applies to counter/anchor/**/*.test.ts : Demonstrate client-side interaction with compressed accounts using `lightprotocol/stateless.js` and `lightprotocol/zk-compression-cli` libraries in TypeScript tests

Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-tests/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:28.451Z
Learning: Account compression tests should verify Merkle tree management functionality in the core account compression program

Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/README.md:0-0
Timestamp: 2026-02-04T00:56:17.813Z
Learning: Applies to program-libs/compressible/**/*.rs : Program module structure should include CompressionInfo, CompressibleConfig, and RentConfig types

Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: basic-operations/anchor/README.md:0-0
Timestamp: 2026-01-10T19:25:03.366Z
Learning: Applies to basic-operations/anchor/**/*.test.ts : TypeScript tests must demonstrate client-side interaction with compressed accounts using 'lightprotocol/stateless.js'

Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/program-test/README.md:0-0
Timestamp: 2026-01-29T22:54:48.916Z
Learning: Use `light-program-test` for fast test execution with unit/integration tests for Solana programs or client code

Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/README.md:0-0
Timestamp: 2026-02-04T00:56:17.813Z
Learning: Applies to program-libs/compressible/**/compression_info.rs : Implement compression_info module with is_compressible, claim, and top-up logic
✅ Actions performed

Review triggered.

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

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 (2)
sdk-libs/sdk-types/src/interface/program/decompression/processor.rs (2)

136-246: ⚠️ Potential issue | 🟠 Major

Builder pattern for PDA decompression mirrors compression — same system_accounts_offset bounds gap applies.

The build_decompress_pda_cpi_data function has the same potential slice panic as the compression processor: system_accounts_offset is validated against remaining_accounts.len() (line 156), but not against hot_accounts_start (line 178). At line 190, remaining_accounts[system_accounts_offset..hot_accounts_start] will panic if system_accounts_offset > hot_accounts_start.

Same fix applies: add a guard system_accounts_offset <= hot_accounts_start after computing hot_accounts_start.

Proposed fix
     let hot_accounts_start = remaining_accounts
         .len()
         .checked_sub(num_hot_accounts)
         .ok_or(LightSdkTypesError::NotEnoughAccountKeys)?;
+    if system_accounts_offset > hot_accounts_start {
+        return Err(LightSdkTypesError::InvalidInstructionData);
+    }
     let hot_account_infos = &remaining_accounts[hot_accounts_start..];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk-libs/sdk-types/src/interface/program/decompression/processor.rs` around
lines 136 - 246, The function build_decompress_pda_cpi_data can still panic when
creating cpi_accounts because system_accounts_offset is only validated against
remaining_accounts.len() but not against hot_accounts_start; after computing
hot_accounts_start (the start of hot_account_infos) add a guard verifying
system_accounts_offset <= hot_accounts_start and return an appropriate error
(e.g., LightSdkTypesError::InvalidInstructionData or NotEnoughAccountKeys) if it
fails, before calling CpiAccounts::new and slicing
remaining_accounts[system_accounts_offset..hot_accounts_start].

308-434: ⚠️ Potential issue | 🟠 Major

Same bounds gap in build_decompress_accounts_cpi_data at line 359.

The remaining_accounts[system_accounts_offset..hot_accounts_start] slice at line 359 can panic if system_accounts_offset > hot_accounts_start, same root cause. Add the same guard here.

Proposed fix
     let hot_accounts_start = remaining_accounts
         .len()
         .checked_sub(num_hot_accounts)
         .ok_or(LightSdkTypesError::NotEnoughAccountKeys)?;
+    if system_accounts_offset > hot_accounts_start {
+        return Err(LightSdkTypesError::InvalidInstructionData);
+    }
     let hot_account_infos = &remaining_accounts[hot_accounts_start..];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk-libs/sdk-types/src/interface/program/decompression/processor.rs` around
lines 308 - 434, The slice
remaining_accounts[system_accounts_offset..hot_accounts_start] in
build_decompress_accounts_cpi_data can panic when system_accounts_offset >
hot_accounts_start; add a bounds check after computing hot_accounts_start (e.g.
if system_accounts_offset > hot_accounts_start { return
Err(LightSdkTypesError::NotEnoughAccountKeys); }) and use that validated
system_accounts_offset when constructing CpiAccounts::new_with_config to prevent
the panic; reference symbols: build_decompress_accounts_cpi_data,
system_accounts_offset, hot_accounts_start, CpiAccounts::new_with_config,
LightSdkTypesError::NotEnoughAccountKeys.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@sdk-libs/sdk-types/src/interface/program/compression/processor.rs`:
- Around line 84-86: The current bounds check only ensures
system_accounts_offset <= remaining_accounts.len() but can still allow
system_accounts_offset > pda_start causing a panic when slicing; after computing
pda_start in the compression processor (the variable named pda_start used for
slicing remaining_accounts[system_accounts_offset..pda_start]), add a validation
that returns Err(LightSdkTypesError::InvalidInstructionData) if
system_accounts_offset > pda_start; likewise, in the decompression processor
after computing hot_accounts_start (the variable used for slicing with
system_accounts_offset), add the same check to prevent system_accounts_offset >
hot_accounts_start and return the same error.

In `@sdk-libs/sdk-types/tests/decompress_accounts_processor.rs`:
- Around line 618-763: The test_randomized_pda_and_token_decompression currently
runs a single random configuration via rand::thread_rng(), which reduces
coverage and makes failures hard to reproduce; update the test to (1) loop
multiple iterations (e.g., for _ in 0..N) around the existing body so it
exercises many random combos, (2) switch to a reproducible RNG by creating a
SeedableRng (e.g., StdRng::from_seed(seed)) and log or print the seed before
each run so failing cases are reproducible, and (3) include an explicit sub-case
to exercise n_pdas==0 && n_tokens==0 (or remove the clamp) to ensure that edge
path is tested; locate and modify the setup using rng, n_pdas, n_tokens, and the
test function name to implement these changes.

In `@sdk-libs/sdk-types/tests/decompress_processor.rs`:
- Around line 70-91: The helper make_valid_accounts (and related test-only types
like SkipVariant) are duplicated across decompress_processor.rs,
decompress_accounts_processor.rs, and compress_processor.rs; move these shared
helpers into common/mod.rs next to make_config_account and make_dummy_account,
export them (pub) from common, then update the three test files to remove the
duplicated definitions and import make_valid_accounts and SkipVariant from
common:: so tests reuse the single implementation.

---

Outside diff comments:
In `@sdk-libs/sdk-types/src/interface/program/decompression/processor.rs`:
- Around line 136-246: The function build_decompress_pda_cpi_data can still
panic when creating cpi_accounts because system_accounts_offset is only
validated against remaining_accounts.len() but not against hot_accounts_start;
after computing hot_accounts_start (the start of hot_account_infos) add a guard
verifying system_accounts_offset <= hot_accounts_start and return an appropriate
error (e.g., LightSdkTypesError::InvalidInstructionData or NotEnoughAccountKeys)
if it fails, before calling CpiAccounts::new and slicing
remaining_accounts[system_accounts_offset..hot_accounts_start].
- Around line 308-434: The slice
remaining_accounts[system_accounts_offset..hot_accounts_start] in
build_decompress_accounts_cpi_data can panic when system_accounts_offset >
hot_accounts_start; add a bounds check after computing hot_accounts_start (e.g.
if system_accounts_offset > hot_accounts_start { return
Err(LightSdkTypesError::NotEnoughAccountKeys); }) and use that validated
system_accounts_offset when constructing CpiAccounts::new_with_config to prevent
the panic; reference symbols: build_decompress_accounts_cpi_data,
system_accounts_offset, hot_accounts_start, CpiAccounts::new_with_config,
LightSdkTypesError::NotEnoughAccountKeys.

Entire-Checkpoint: 7c9c24f71fe9
@ananas-block ananas-block changed the title test: random unit tests light program compress decompres test: random unit tests light program compress decompress Feb 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant