Skip to content

feat: state updates via single pipeline + StagingTree#2078

Merged
sergeytimoshin merged 54 commits intomainfrom
sergey/forester-state-workers
Nov 27, 2025
Merged

feat: state updates via single pipeline + StagingTree#2078
sergeytimoshin merged 54 commits intomainfrom
sergey/forester-state-workers

Conversation

@sergeytimoshin
Copy link
Contributor

@sergeytimoshin sergeytimoshin commented Nov 25, 2025

  • replaced old state_batch_append + state_batch_nullify with a single unified pipeline
  • switched to V2 queue fetching (input + output in one call)
  • updated epoch manager with per-tree staging cache

Summary by CodeRabbit

  • New Features

    • Per-tree V2 state supervisors with parallel proof workers and ordered batch submission.
    • V2 queue API and data models to fetch state/input/output/address queue elements.
    • CLI/config flags to tune prover polling interval and max-wait time.
  • Improvements

    • Unified eligibility and batching semantics for V2 processing.
    • Simplified prover client workflow with reduced verbose logging and finer trace-level diagnostics.
  • Chores

    • Test script logging extended to include prover client debug.
    • Added async worker channels and compressed-proof conversion support.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 25, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • forester-utils/src/staging_tree.rs is excluded by none and included by none

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds a per-tree V2 state supervisor pipeline (supervisors, proof workers, TxSender), integrates supervisor lifecycle into EpochManager, extends BatchContext with prover configuration and eligibility timing, replaces legacy v2 stream processors, and adds indexer/API V2 models and calls for fetching V2 queue elements.

Changes

Cohort / File(s) Summary
Test Configuration
\forester/package.json``
Updated test script to add light_prover_client=debug to RUST_LOG.
EpochManager V2 integration
\forester/src/epoch_manager.rs``
Added state_supervisors and authority fields; added get_or_create_state_supervisor, build_batch_context, process_v2; evict/kill supervisors on epoch change.
Batch processing core
\forester/src/processor/v2/common.rs``
Simplified BatchReadyState; expanded BatchContext (authority: Arc<Keypair>, prover_config, num_proof_workers, forester_eligibility_end_slot); added Clone; updated eligibility/slot semantics and merkle-root parsing.
V2 module surface
\forester/src/processor/v2/mod.rs``
Made state module pub, re-exported ProverConfig, and routed StateV2 branch to supervisors (no direct state processing).
State supervisor pipeline (new)
\forester/src/processor/v2/state/supervisor.rs``
New StateSupervisor actor with messages (ProcessQueueUpdate, QueueWork, UpdateEligibility); coordinates batch fetching, staging tree, proof workers, TxSender, and lifecycle.
Proof worker pool (new)
\forester/src/processor/v2/state/proof_worker.rs``
New proof-worker subsystem: ProofInput/ProofJob/ProofResult, spawn_proof_workers, per-worker prover clients, concurrent proof-generation loop.
Transaction sender (new)
\forester/src/processor/v2/state/tx_sender.rs``
New TxSender that buffers ordered ProofResults, builds BatchInstruction (Append/Nullify), calls send_transaction_batch, handles NotInActivePhase and last-root updates.
State helpers (new)
\forester/src/processor/v2/state/helpers.rs``
Added fetch_zkp_batch_size and fetch_batches that call indexer V2 APIs and return zkp batch size / StateQueueDataV2.
V2 state module exports
\forester/src/processor/v2/state/mod.rs``
New submodules: helpers, proof_worker, supervisor, tx_sender; re-export ProcessQueueUpdate, QueueWork, StateSupervisor, UpdateEligibility.
Removed legacy state module
\forester/src/processor/v2/state.rs``
Removed legacy stream-based perform_nullify / perform_append implementations.
Prover client simplification
\prover/client/src/proof_client.rs``
Unified generate_proof signature (dropped circuit_type), removed attempt param from try_generate_proof, and switched some logs to trace.
Proof input constructors
\prover/client/src/proof_types/.../proof_inputs.rs``
Added BatchAppendsCircuitInputs::new, BatchUpdateCircuitInputs::new, and BatchTreeUpdateResult helpers to build circuit inputs from tree-update results.
Proof conversions
\prover/client/src/proof.rs``
Made ProofCompressed Clone, Copy and added From<ProofCompressed> for CompressedProof.
Dependencies
\forester/Cargo.toml`, `prover/client/Cargo.toml``
Added dependency async-channel = "2.3" and workspace light-compressed-account (default-features = false).
Indexer trait & client
\sdk-libs/client/src/indexer/indexer_trait.rs`, `sdk-libs/client/src/rpc/indexer.rs``
Added get_queue_elements_v2 to Indexer trait and LightClient RPC shim.
Indexer V2 options & types
\sdk-libs/client/src/indexer/options.rs`, `.../types.rs`, `.../mod.rs``
New QueueElementsV2Options builder and V2 data structs/re-exports (Output/Input/State/AddressQueueDataV2, QueueElementsV2Result).
Photon indexer implementation
\sdk-libs/client/src/indexer/photon_indexer.rs``
Implemented get_queue_elements_v2 request/response decoding and slot-sync checks (duplicate insertion observed in diff).
Photon API endpoint & models
\sdk-libs/photon-api/src/apis/default_api.rs`, `sdk-libs/photon-api/src/models/*``
Added get_queue_elements_v2_post API, error enum, request/response params/models and V2 queue data models.
Program-test indexer stubs
\sdk-libs/program-test/src/indexer/test_indexer.rs`, `sdk-libs/program-test/src/program_test/indexer.rs``
Added get_queue_elements_v2 stub for TestIndexer and delegation in LightProgramTest.
CLI/config plumbing
\forester/src/cli.rs`, `forester/src/config.rs`, `forester/tests/*``
Added prover polling interval and max-wait options to CLI/config and wired defaults in tests; increased default max_concurrent_batches from 20→60.
Minor runtime/logging
\forester/src/polling/queue_poller.rs`, `forester/src/processor/v2/address.rs``
Lowered channel-full log to debug; AddressUpdateConfig now reads prover fields from ctx.prover_config.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant EpochMgr as EpochManager
    participant Supervisor as StateSupervisor
    participant Indexer as Indexer (get_queue_elements_v2)
    participant ProofPool as ProofWorkerPool
    participant TxSender as TxSender
    participant Prover as Prover Service
    participant Solana as Solana/RPC

    EpochMgr->>Supervisor: process_v2(epoch_info, tree_accounts, queue_update, eligibility_end)
    activate Supervisor
    Supervisor->>Indexer: get_queue_elements_v2(options)
    Indexer-->>Supervisor: StateQueueDataV2 / AddressQueueDataV2
    loop per batch
        Supervisor->>ProofPool: enqueue ProofJob(seq, inputs)
    end
    ProofPool->>Prover: generate_proof(inputs_json)
    Prover-->>ProofPool: ProofResult(seq, instruction, optional_root)
    ProofPool->>TxSender: deliver ProofResult
    activate TxSender
    TxSender->>TxSender: buffer & assemble BatchInstruction (ordered by seq)
    TxSender->>Solana: send_transaction_batch(batch)
    Solana-->>TxSender: signature / new_root
    TxSender->>Supervisor: report processed count
    deactivate TxSender
    Supervisor->>EpochMgr: return processed
    deactivate Supervisor
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas needing extra attention:

  • forester/src/processor/v2/state/supervisor.rs — actor lifecycle, staging-tree construction, batching and error handling.
  • forester/src/processor/v2/state/tx_sender.rs — buffering/ordering logic, send_transaction_batch error paths, last-root updates.
  • forester/src/processor/v2/state/proof_worker.rs — concurrency, prover client usage and failure handling.
  • forester/src/epoch_manager.rs — supervisor cache lifecycle, authority ownership/Arc cloning.
  • sdk-libs/client/src/indexer/photon_indexer.rs & sdk-libs/client/src/indexer/indexer_trait.rs — base58 decoding to fixed-size arrays, duplicated insertion observed in diff.

Possibly related PRs

Suggested labels

ai-review

Suggested reviewers

  • SwenSchaeferjohann
  • ananas-block

Poem

🌲 Epochs spin, supervisors wake to start,
Workers hum proofs and stitch each root and part,
Batches queue, proofs fly, txs in order sent,
New V2 vines threaded, configs tightly bent,
A forest of code grows quiet and smart.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.92% which is insufficient. The required threshold is 70.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main architectural change: consolidating state batch operations into a unified pipeline with StagingTree caching.

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.

@sergeytimoshin sergeytimoshin changed the title feat: forester state workers feat: state updates via single pipeline + StagingTree Nov 25, 2025
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: 19

Caution

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

⚠️ Outside diff range comments (3)
prover/client/src/proof_client.rs (1)

535-559: Reconsider logging full circuit inputs and prefer structured tracing fields

The new debug!("!! generate_batch_*_proof {:?}", circuit_inputs); lines will dump the entire BatchAppendsCircuitInputs / BatchUpdateCircuitInputs structures, which (per the ZKP docs) can be large and may contain protocol‑sensitive values (roots, hash chains, nullifiers). This can bloat logs and risk exposing more internal state than needed outside local debugging sessions. I’d recommend either:

  • Switching to structured tracing fields and a clearer message, e.g. debug!(?circuit_inputs, "generate_batch_append_proof inputs");, and/or
  • Gating this behind a feature flag / config and considering truncation or redaction of large or sensitive fields.

The rename to circuit_inputs and use of update_inputs_string(&circuit_inputs) otherwise looks consistent and keeps the proof generation flow intact. Based on learnings, these inputs mirror full batch ZKP public/private data, so being deliberate about how much of them you emit is important.

forester/tests/e2e_test.rs (1)

855-888: Fixed 3s sleeps per V2 iteration can make this test extremely slow and still racey

With iterations = batch_size * 2 in V2 mode, two sleep(Duration::from_millis(3000)).await calls per loop can easily push this test into multi‑minute runtimes (or more, depending on output_queue_batch_size), and it still relies on wall‑clock timing rather than protocol/indexer state.

Consider instead:

  • gating on a meaningful condition (e.g. indexer slot, queue indices, or a WorkReport threshold) between compress/transfer steps, and/or
  • capping iterations or the per‑iteration delay for tests (e.g. use a small test batch size and shorter wait, or backoff based on progress).

This will keep CI more predictable and avoid adding a brittle time‑based dependency to the V2 path.

forester/src/epoch_manager.rs (1)

1745-1832: Supervisor lifecycle management handles epoch staleness correctly

The get_or_create_state_supervisor method properly:

  1. Checks if an existing supervisor matches the current epoch
  2. Removes stale supervisors from previous epochs with logging
  3. Creates and registers new supervisors when needed

The pattern of extracting supervisor status before modifying the DashMap (lines 1751-1762) correctly avoids borrowing issues.

However, consider extracting the default_prover_url and BatchContext construction to reduce duplication with the AddressV2 path in process_v2:

+    fn default_prover_url() -> String {
+        "http://127.0.0.1:3001".to_string()
+    }

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

Caution

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

⚠️ Outside diff range comments (2)
forester/tests/e2e_test.rs (1)

876-888: Hard-coded delays warrant documentation and extraction.

These 3-second sleeps add significant test execution time (6 seconds per iteration). If they're compensating for indexer sync delays or avoiding race conditions, this should be:

  1. Documented with a comment explaining the purpose
  2. Extracted to a named constant (e.g., const V2_OPERATION_DELAY_MS: u64 = 3000;)
  3. Ideally replaced with a condition-based wait like wait_for_indexer used elsewhere

Are these delays addressing a specific timing issue, or are they temporary debugging aids?

+            // Wait for indexer to sync after compress operation
+            const V2_OPERATION_DELAY_MS: u64 = 3000;
-            sleep(Duration::from_millis(3000)).await;
+            sleep(Duration::from_millis(V2_OPERATION_DELAY_MS)).await;
             let batch_transfer_sig = transfer::<true, R>(
                 // ...
             ).await;
             println!("{} v2 transfer: {:?}", i, batch_transfer_sig);

+            // Wait for indexer to sync after transfer operation
-            sleep(Duration::from_millis(3000)).await;
+            sleep(Duration::from_millis(V2_OPERATION_DELAY_MS)).await;
forester/src/epoch_manager.rs (1)

1807-1808: Hardcoded prover timeouts may not suit all environments.

prover_polling_interval: Duration::from_secs(1) and prover_max_wait_time: Duration::from_secs(600) are hardcoded. For production or high-throughput scenarios, these might need tuning.

Consider making these configurable via ForesterConfig:

-                    prover_polling_interval: Duration::from_secs(1),
-                    prover_max_wait_time: Duration::from_secs(600),
+                    prover_polling_interval: self.config.prover_polling_interval
+                        .unwrap_or(Duration::from_secs(1)),
+                    prover_max_wait_time: self.config.prover_max_wait_time
+                        .unwrap_or(Duration::from_secs(600)),

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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1db6f3a and 891ba99.

📒 Files selected for processing (3)
  • forester/src/processor/v2/common.rs (10 hunks)
  • forester/src/processor/v2/state/proof_worker.rs (1 hunks)
  • prover/client/src/proof.rs (2 hunks)
🧰 Additional context used
🧠 Learnings (100)
📓 Common learnings
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_input_queue method for batch nullify operations on StateV2 trees. The method must verify ZKP proving correctness of: old_root + queue nullifiers → new_root, update tree root, increment tree sequence_number, increment tree nullifier_next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Tree updates from input queue must use update_tree_from_input_queue function for state trees and update_tree_from_address_queue for address trees with ZKP verification
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount for state trees with integrated input queue (for nullifiers) and separate BatchedQueueAccount for output operations
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Prover server (prover/server/) must generate ZK proofs for batch operations (append, nullify, address append)
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch nullify operations must check that tree type is TreeType::StateV2 before processing, verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Applies to programs/registry/src/account_compression_cpi/mod.rs : Export new wrapper modules in `account_compression_cpi/mod.rs` using `pub mod new_operation;` and `pub use new_operation::*;`, then import in `lib.rs`

Applied to files:

  • prover/client/src/proof.rs
  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:55:17.323Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T17:55:17.323Z
Learning: Applies to sdk-libs/macros/src/compressible/**/pack_unpack.rs : Pubkey compression logic and `PackedXxx` struct generation with Pack/Unpack trait implementations should be in `pack_unpack.rs`

Applied to files:

  • prover/client/src/proof.rs
  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:55:17.323Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T17:55:17.323Z
Learning: Applies to sdk-libs/macros/src/compressible/**/variant_enum.rs : Account variant enum (`CompressedAccountVariant`) generation and `CompressedAccountData` wrapper struct should be implemented in `variant_enum.rs`

Applied to files:

  • prover/client/src/proof.rs
  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/Cargo.toml : Depend on light-compressed-account crate for compressed account types and utilities

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Applies to programs/registry/src/account_compression_cpi/*.rs : Create wrapper instruction module at `src/account_compression_cpi/new_operation.rs` with `NewOperationContext` struct defining required accounts

Applied to files:

  • prover/client/src/proof.rs
  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:55:17.323Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T17:55:17.323Z
Learning: Applies to sdk-libs/macros/src/compressible/**/decompress_context.rs : Decompression trait implementation (`DecompressContext`) with account accessors, PDA/token separation logic, and token processing delegation should be in `decompress_context.rs`

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T18:01:14.087Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:14.087Z
Learning: Applies to program-libs/compressible/**/*.rs : Derive PDA addresses using `derive_pda` and `derive_v1_config_pda` functions for CToken account configuration

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T18:01:42.343Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:42.343Z
Learning: Applies to programs/compressed-token/program/src/{claim,transfer2}/**/*.rs : Rent authority can only compress accounts when is_compressible() returns true; lamport distribution on close is: rent → rent_sponsor, unutilized → destination

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T17:55:17.323Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T17:55:17.323Z
Learning: Applies to sdk-libs/macros/src/compressible/**/instructions.rs : Compress/decompress instruction handlers and context struct generation should be implemented in `instructions.rs`, with compress using PDA-only and decompress supporting full PDA + ctoken

Applied to files:

  • prover/client/src/proof.rs
  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Store compressed account hashes in `BatchedQueueAccount` value vectors for immediate proof-by-index access before tree insertion

Applied to files:

  • prover/client/src/proof.rs
  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T18:00:13.178Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/docs/CONFIG_ACCOUNT.md:0-0
Timestamp: 2025-11-24T18:00:13.178Z
Learning: Applies to program-libs/compressible/docs/**/*program*.rs : Use zero-copy deserialization with `bytemuck::pod_from_bytes` in program instruction handlers for CompressibleConfig, skipping the 8-byte discriminator

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T17:55:17.323Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T17:55:17.323Z
Learning: Applies to sdk-libs/macros/src/compressible/**/traits.rs : Core trait implementations (`HasCompressionInfo`, `CompressAs`, `Compressible`) should be defined in `traits.rs`

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T17:54:20.982Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/zero-copy-derive/README.md:0-0
Timestamp: 2025-11-24T17:54:20.982Z
Learning: Applies to program-libs/zero-copy-derive/**/*.rs : Apply #[derive(ZeroCopyEq)] macro to structs to derive PartialEq comparing ZeroCopy representation with original struct

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T17:54:20.982Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/zero-copy-derive/README.md:0-0
Timestamp: 2025-11-24T17:54:20.982Z
Learning: Applies to program-libs/zero-copy-derive/**/*.rs : Apply #[derive(ZeroCopy)] macro to structs to derive ZeroCopyAt trait for zero-copy serialization

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T17:54:20.982Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/zero-copy-derive/README.md:0-0
Timestamp: 2025-11-24T17:54:20.982Z
Learning: Applies to program-libs/zero-copy-derive/**/*.rs : Nested structs in zero-copy serialization must also derive #[derive(ZeroCopy)]

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T17:54:20.982Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/zero-copy-derive/README.md:0-0
Timestamp: 2025-11-24T17:54:20.982Z
Learning: Applies to program-libs/zero-copy-derive/**/*.rs : Use Option<T> for optional values in zero-copy structs; Option<u16>, Option<u32>, and Option<u64> are optimized

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T18:01:14.087Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:14.087Z
Learning: Applies to program-libs/compressible/**/*.rs : Use Anchor serialization for CompressibleConfig account structures in Rust programs

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Validate account ownership by Light account compression program using `check_owner` from `light-account-checks` when deserializing `BatchedQueueAccount` with `output_from_account_info`

Applied to files:

  • prover/client/src/proof.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T18:00:13.178Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/docs/CONFIG_ACCOUNT.md:0-0
Timestamp: 2025-11-24T18:00:13.178Z
Learning: Applies to program-libs/compressible/docs/**/programs/**/*.rs : Use Anchor's `AccountDeserialize::try_deserialize` for CompressibleConfig when Anchor feature is enabled, which includes automatic discriminator validation

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T18:00:13.178Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/docs/CONFIG_ACCOUNT.md:0-0
Timestamp: 2025-11-24T18:00:13.178Z
Learning: Applies to program-libs/compressible/docs/**/*.rs : Use CompressibleConfig discriminator `[180, 4, 231, 26, 220, 144, 55, 168]` for account validation in Solana programs and clients

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T18:00:48.449Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/docs/SOLANA_RENT.md:0-0
Timestamp: 2025-11-24T18:00:48.449Z
Learning: Applies to program-libs/compressible/docs/**/*.rs : Light Protocol accounts must satisfy both Solana rent exemption and Light Protocol rent requirements, plus an 11,000 lamport compression incentive during creation

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T18:01:30.012Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:30.012Z
Learning: Run Light system program compression tests using `cargo test-sbf -p system-test -- test_with_compression` and `cargo test-sbf -p system-test --test test_re_init_cpi_account` to test compressed account operations

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T18:01:30.012Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:30.012Z
Learning: Run account-compression tests using `cargo test-sbf -p account-compression-test` to test core account compression program (Merkle tree management)

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T18:00:13.178Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/docs/CONFIG_ACCOUNT.md:0-0
Timestamp: 2025-11-24T18:00:13.178Z
Learning: Applies to program-libs/compressible/docs/program-libs/compressible/src/config.rs : CompressibleConfig struct must use `#[repr(C)]` for proper memory layout with fixed field ordering: version (u16, 2 bytes), state (u8, 1 byte), bump (u8, 1 byte), update_authority (Pubkey, 32 bytes), withdrawal_authority (Pubkey, 32 bytes), rent_sponsor (Pubkey, 32 bytes), compression_authority (Pubkey, 32 bytes), rent_sponsor_bump (u8, 1 byte), compression_authority_bump (u8, 1 byte), rent_config (RentConfig, 8 bytes), address_space ([Pubkey; 4], 128 bytes), and _place_holder ([u8; 32], 32 bytes) for total of 256 bytes

Applied to files:

  • prover/client/src/proof.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Verify ZKP batch append proof using `verify_batch_append_with_proofs(zkp_batch_size, public_input_hash, proof)` and error with `ProofVerificationFailed` (13006) if verification fails

Applied to files:

  • prover/client/src/proof.rs
  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_input_queue method for batch nullify operations on StateV2 trees. The method must verify ZKP proving correctness of: old_root + queue nullifiers → new_root, update tree root, increment tree sequence_number, increment tree nullifier_next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*prover*.rs : Prover V2 endpoints should be configurable via `--prover-append-url`, `--prover-update-url`, `--prover-address-append-url`, and `--prover-api-key` parameters

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Tree updates must require zero-knowledge proofs proving batch operation correctness with public inputs: old root, new root, hash chain, and for appends: start_index (output queue) or next_index (address queue)

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `src/merkle_tree.rs`, implement `BatchedMerkleTreeAccount::update_tree_from_output_queue_account` method that batch appends values from output queue to state Merkle tree with ZKP verification, verifying proof of old_root + queue_values → new_root

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Input queues (nullifier queue for state trees, address queue for address trees) must use bloom filters for non-inclusion proofs

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Prover server (prover/server/) must generate ZK proofs for batch operations (append, nullify, address append)

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount for state trees with integrated input queue (for nullifiers) and separate BatchedQueueAccount for output operations

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_address_queue method for batch address append operations on AddressV2 trees. The method must verify ZKP proving correctness of: old_root + queue addresses → new_root using indexed Merkle tree insertion, update tree root, increment tree sequence_number, increment tree next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:59:54.233Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/PACKED_ACCOUNTS.md:0-0
Timestamp: 2025-11-24T17:59:54.233Z
Learning: Applies to program-libs/account-checks/docs/program-libs/account-checks/src/**/*.rs : Provide descriptive names in ProgramPackedAccounts error messages (e.g., 'token_mint' instead of 'account')

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/main.rs : Required configuration must include: `--rpc-url`, `--ws-rpc-url`, `--indexer-url`, `--prover-url`, `--payer`, and `--derivation` parameters

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, insert compressed_account_hash into bloom filter (NOT the nullifier) for non-inclusion checks in subsequent transactions

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, perform non-inclusion check to ensure compressed_account_hash does not exist in any bloom filter to prevent double-spending

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue` (src/merkle_tree.rs), create nullifier using `Hash(compressed_account_hash, leaf_index, tx_hash)`

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T18:00:48.449Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/docs/SOLANA_RENT.md:0-0
Timestamp: 2025-11-24T18:00:48.449Z
Learning: Applies to program-libs/compressible/docs/**/*.rs : Implement account compressibility states in the following order: Funded (rent for current + 1 epoch) → Compressible (lacks rent for current + 1 epoch) → Claimable (funded but past epochs unclaimed)

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/prover/server/prover/v2/batch_append_circuit.go : Batch append circuit implementation at `prover/server/prover/v2/batch_append_circuit.go` must verify that batch append is correct by: (1) verifying public input hash matches Hash([old_root, new_root, leaves_hash_chain, start_index]), (2) verifying leaves_hash_chain matches hash chain of all new leaves, (3) for each position checking if old_leaf is zero (insert new leaf) or non-zero (keep old nullifier), (4) providing Merkle proof for old_leaf and computing root update, (5) verifying final computed root equals new_root

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Transition batch state to `Inserted` when all ZKP batches are complete and increment `pending_batch_index` to switch to other batch

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T18:01:30.012Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:30.012Z
Learning: Run batched merkle tree simulation tests using `RUST_LOG=light_prover_client=debug cargo test -p batched-merkle-tree-test -- --test test_simulate_transactions` to enable logging

Applied to files:

  • forester/src/processor/v2/state/proof_worker.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : BatchedMerkleTreeAccount must be of type `TreeType::StateV2` when updating tree from output queue

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch nullify operations must check that tree type is TreeType::StateV2 before processing, verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : After inserting an address into the batch, check if `num_inserted_elements == batch_size`. If true, transition batch state from `Fill` to `Full`, increment `currently_processing_batch_index` to switch to the other batch, and update `pending_batch_index` to mark this batch ready for tree update.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree_metadata.rs : Define `BatchedMerkleTreeMetadata` structure in `src/merkle_tree_metadata.rs`. Include tree_type, associated_queue, rollover_fee calculation, access_metadata (owner, program_owner, forester), rollover_metadata (index, rollover_fee, rollover_threshold, network_fee, close_threshold, additional_bytes), hashed_pubkey, next_index, and sequence_number fields.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `insert_into_current_queue_batch` helper, handle batch state transitions: if state is `Fill`, proceed; if state is `Inserted`, verify bloom filter is zeroed, clear hash chain stores, transition to `Fill`, and reset batch metadata; if state is `Full`, return `BatchedMerkleTreeError::BatchNotReady` (error code 14301).

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch address append operations must check that tree type is TreeType::AddressV2 before processing, verify tree capacity constraint (tree.next_index + zkp_batch_size <= tree_capacity), verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Store `BatchedMerkleTreeAccount` layout in src/merkle_tree.rs and `BatchedMerkleTreeMetadata` in src/merkle_tree_metadata.rs

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch must have ready ZKP batches for insertion: verify `num_full_zkp_batches > num_inserted_zkp_batches`; error with `BatchNotReady` (14301) if not ready

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, when batch state is `Inserted`, verify bloom filter is zeroed before clearing hash chain stores and transitioning to `Fill` state

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Zero out input queue bloom filter when all conditions are met: (1) current batch is ≥50% full (`num_inserted_elements >= batch_size / 2`), (2) current batch NOT in `Inserted` state, (3) previous batch in `Inserted` state, (4) previous batch bloom filter not already zeroed, (5) at least one tree update since batch completion (`batch.sequence_number != current_tree.sequence_number`)

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, transition batch state from `Fill` to `Full` when `num_inserted_elements == batch_size`, and switch `currently_processing_batch_index` to the other batch

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Set output queue account discriminator to b`queueacc` (8 bytes) and initialize queue metadata with QueueType::OutputStateV2

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Tree updates from input queue must use update_tree_from_input_queue function for state trees and update_tree_from_address_queue for address trees with ZKP verification

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, verify tree type is `TreeType::StateV2` before allowing nullifier insertion; reject address trees

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize a state Merkle tree with a `TreeType::StateV2` (4) tree type, storing tree roots, root history, and integrated input queue (bloom filters + hash chains for nullifiers) in the `BatchedMerkleTreeAccount` with discriminator b`BatchMta` [66, 97, 116, 99, 104, 77, 116, 97]

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : State tree nullifier insertion must use the BatchedMerkleTreeAccount::insert_nullifier_into_queue method

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : When attempting to reuse a batch in the `Inserted` state before its bloom filter has been zeroed by the forester, return `BatchedMerkleTreeError::BloomFilterNotZeroed` (error code 14312).

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Zero overlapping roots in cyclic buffer by starting at `oldest_root_index = root_history.first_index()`, zeroing `num_remaining_roots` consecutive roots with wrapping, and verifying ended at `first_safe_root_index = batch.root_index + 1`

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Overlapping roots in history must be zeroed when clearing bloom filters to prevent inclusion proofs of nullified values

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Root history is accessed via `root_history.last()` to retrieve the latest root. Validity proofs pick roots by index from root history since proofs need a static root value to verify against

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Validate root_history_capacity is at least equal to (input_queue_batch_size / input_queue_zkp_batch_size) in `src/initialize_address_tree.rs`. This ensures sufficient space for roots generated by address queue operations.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize root history as a cyclic buffer with capacity = root_history_capacity, with first entry = zero bytes for tree height

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : After successful ZKP verification, increment tree `sequence_number` by 1 (tracks number of tree updates) and append `new_root` to `root_history` cyclic buffer

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Calculate overlapping roots for zeroing using: overlapping if `batch.sequence_number > current_tree.sequence_number`; compute `num_remaining_roots = batch.sequence_number - current_tree.sequence_number`; verify `num_remaining_roots < root_history.len()` and error with `CannotZeroCompleteRootHistory` (14313) if violated

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Initialize root history as cyclic buffer with capacity=root_history_capacity and first entry = `ADDRESS_TREE_INIT_ROOT_40` in `src/initialize_address_tree.rs`.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Validate that root_history_capacity >= (output_queue_batch_size / output_queue_zkp_batch_size) + (input_queue_batch_size / input_queue_zkp_batch_size) to ensure sufficient space for roots generated by both input and output operations

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Define access control parameters: program_owner (Option<Pubkey>), forester (Option<Pubkey>) for non-Light foresters, and owner (Pubkey passed as function parameter)

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Use zero-copy deserialization for all `BatchedQueueAccount` operations

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Use two value vectors (`[ZeroCopyVecU64<[u8; 32]>; 2]`), one per batch, to store compressed account hashes in `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Compute and store hashed pubkeys by hashing and truncating to 31 bytes for bn254 field compatibility in both queue and tree accounts

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Implement two hash chain stores (`[ZeroCopyVecU64<[u8; 32]>; 2]`), one per batch, each with `batch_size / zkp_batch_size` hash chains storing Poseidon hashes of ZKP batches in `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Define bloom filter configuration for input queue: bloom_filter_capacity (u64, default batch_size * 8) and bloom_filter_num_iters (u64, default 3 for test and 10 for production)

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Store `BatchedQueueAccount` layout and `BatchedQueueMetadata` in src/queue.rs

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:24.369Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:24.369Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : When a batch is in `Inserted` state, clear the value vec and hash chain stores, advance batch state to `Fill`, and reset batch metadata before allowing new insertions

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : In `src/queue.rs`, define BatchedQueueAccount layout and implement `mark_as_inserted_in_merkle_tree` method to increment `num_inserted_zkp_batches` and transition batch state to `Inserted` when all ZKP batches are complete

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:24.369Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:24.369Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Transition batch state from `Fill` to `Full` and increment currently_processing_batch_index when num_inserted_elements reaches batch_size in the output queue

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*{transaction,batch}*.rs : Transaction V1 processing should configure `--max-concurrent-sends 50`, `--legacy-ixs-per-tx 1`, `--transaction-max-concurrent-batches 20`, `--cu-limit 1000000`, and `--enable-priority-fees false` by default

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, reject insertions when batch is in `Full` state with error code 14301

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/queue.rs : Output queue insertion must use BatchedQueueAccount::insert_into_current_batch method

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_address_into_queue`, verify that the tree type is `TreeType::AddressV2` before proceeding with address insertion. Reject state trees with `MerkleTreeMetadataError::InvalidTreeType`.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : When inserting an address into the current batch, call the bloom filter's insert method which must: insert the address into the bloom filter, perform a non-inclusion check across all bloom filters (returning `BatchedMerkleTreeError::NonInclusionCheckFailed` error code 14311 if address already exists), update the hash chain with `Poseidon(prev_hash_chain, address)`, and increment the batch's element counter.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Address tree address insertion must use the BatchedMerkleTreeAccount::insert_address_into_queue method

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize an output queue account as `BatchedQueueAccount` with `QueueType::OutputStateV2`, temporary storage for compressed account hashes before tree insertion with immediate spending capability via proof-by-index, using discriminator b`queueacc` [113, 117, 101, 117, 101, 97, 99, 99]

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Validate queue type is `OUTPUT_STATE_QUEUE_TYPE_V2` when deserializing `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Set tree_type to `TreeType::AddressV2` (5) and associated_queue to Pubkey::default() for address trees in `src/initialize_address_tree.rs`. Address trees have no separate output queue - the address queue is integrated into the tree account.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: `BatchedQueueAccount` is always an output queue of type `OutputStateV2`; input queues are integrated into `BatchedMerkleTreeAccount`

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/initialize_state_tree.rs : State tree initialization must create two Solana accounts: BatchedMerkleTreeAccount with integrated input queue and separate BatchedQueueAccount

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : When all ZKP batches for a batch are inserted, set batch sequence_number to tree_sequence_number + root_history_capacity and store root_index to identify the root that must not exist when bloom filter is zeroed.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : After successful ZKP verification, increment tree `next_index` by `zkp_batch_size` (represents leaf index for next insertion)

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : When all ZKP batches of a batch are inserted, set batch `sequence_number = tree_sequence_number + root_history_capacity` (threshold when root at root_index is overwritten) and set `root_index` to identify root that must not exist when bloom filter is zeroed

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Mark ZKP batch as inserted by calling `mark_as_inserted_in_merkle_tree` on queue batch to increment `num_inserted_zkp_batches`

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Each ZKP batch has a hash chain storing the Poseidon hash of all values in that ZKP batch, used as public inputs for ZKP verification

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Create public input hash as `Hash([old_root, new_root, leaves_hash_chain, start_index])` using old_root from tree root history and start_index from tree next_index

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: In client code, deserialize output queues using `BatchedQueueAccount::output_from_bytes(&mut account_data)?` from the `light_batched_merkle_tree::queue` module

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : In Solana programs, deserialize output queues using `BatchedQueueAccount::output_from_account_info(account_info)?` from the `light_batched_merkle_tree::queue` module

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Use `get_output_queue_account_size` function from src/queue.rs to calculate queue account size based on output_queue_batch_size and output_queue_zkp_batch_size

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Validate account discriminator is `queueacc` (bytes: [113, 117, 101, 117, 101, 97, 99, 99]) using `check_discriminator` from `light-account-checks` when deserializing `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/common.rs
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Forester e2e test
  • GitHub Check: Test program-libs-slow
  • GitHub Check: Test batched-merkle-tree-simulate
  • 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: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "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-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 -- ...

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 (1)
forester/src/polling/queue_poller.rs (1)

116-130: Lowering channel‑full log to debug is reasonable; consider complementary observability.

Treating a full per‑tree channel as a debug! (rather than warn!) makes sense if brief saturation is expected under normal load and updates are cheap to re‑poll. The drop semantics are unchanged and look intentional.

To avoid losing sight of chronically back‑pressured trees, consider adding a counter/metric or a throttled higher‑level log (e.g., once per N drops per tree) so persistent starvation is still visible in production telemetry without spamming logs.

♻️ Duplicate comments (2)
forester/src/processor/v2/state/supervisor.rs (1)

428-435: Use .expect() for safer unwrap after conditional initialization.

Lines 428 and 475 use .unwrap() on staging_tree after it's been initialized in build_staging_tree. While logically safe, this pattern is fragile during refactoring. A past review suggested using .expect() with a clear message:

-        let staging = self.staging_tree.as_mut().unwrap();
+        let staging = self.staging_tree.as_mut()
+            .expect("staging_tree must be initialized before building jobs");

This provides better context if the invariant is ever violated.

Also applies to: 475-482

forester/src/processor/v2/mod.rs (1)

25-35: Clear tree type dispatch with proper delegation.

The explicit match branches cleanly separate concerns:

  • AddressV2 continues using the BatchProcessor approach
  • StateV2 correctly defers to the StateSupervisor actor (the trace log helps with debugging)
  • Default returns Ok(0) for unsupported types

One small observation: the default branch silently returns for types like StateV1, AddressV1, and Unknown. A past review suggested adding a trace log here—if you want visibility during debugging, consider:

-        _ => Ok(0),
+        other => {
+            trace!("Skipping unsupported tree type for batched operations: {:?}", other);
+            Ok(0)
+        }

Otherwise, the dispatch logic is sound.

Comment on lines +34 to +42
#[derive(Debug, Clone)]
pub struct ProverConfig {
pub append_url: String,
pub update_url: String,
pub address_append_url: String,
pub api_key: Option<String>,
pub polling_interval: Duration,
pub max_wait_time: Duration,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Add documentation for ProverConfig fields.

The ProverConfig struct introduces several fields that would benefit from doc comments explaining their purpose:

  • What operations do append_url, update_url, and address_append_url correspond to?
  • What is the expected format/usage of api_key?
  • What do polling_interval and max_wait_time control in the proof generation flow?

Consider adding doc comments:

+/// Configuration for remote prover service integration.
 #[derive(Debug, Clone)]
 pub struct ProverConfig {
+    /// URL endpoint for batch append proof generation
     pub append_url: String,
+    /// URL endpoint for batch update proof generation
     pub update_url: String,
+    /// URL endpoint for address append proof generation
     pub address_append_url: String,
+    /// Optional API key for prover service authentication
     pub api_key: Option<String>,
+    /// Interval between polling for proof completion
     pub polling_interval: Duration,
+    /// Maximum time to wait for proof generation before timeout
     pub max_wait_time: Duration,
 }
🤖 Prompt for AI Agents
In forester/src/processor/v2/common.rs around lines 34 to 42, the ProverConfig
fields lack documentation; add concise doc comments for each field explaining
their purpose and expected formats: document that append_url is the endpoint to
submit new proofs/append operations, update_url is the endpoint to update
existing proofs or metadata, address_append_url is a specialized endpoint for
appending address-specific proof data, api_key is an optional bearer/API token
(format example: "Bearer <token>" or raw token) used for authenticating
requests, polling_interval is the duration between checks when waiting for
asynchronous proof generation, and max_wait_time is the maximum duration to wait
before timing out the proof generation flow; keep comments short, idiomatic Rust
doc style (///) and clarify units where relevant (e.g., seconds/milliseconds)
and any edge behavior (e.g., zero disables polling).

Comment on lines +130 to +138
let forester_end = context
.forester_eligibility_end_slot
.load(Ordering::Relaxed);
let eligibility_end_slot = if forester_end > 0 {
forester_end
} else {
context.epoch_phases.active.end
};
let slots_remaining = eligibility_end_slot.saturating_sub(current_slot);
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Document the eligibility slot convention and consider atomic ordering.

The code uses 0 as a sentinel value to indicate "forester-specific eligibility not set," but this convention is implicit:

let forester_end = context.forester_eligibility_end_slot.load(Ordering::Relaxed);
let eligibility_end_slot = if forester_end > 0 {
    forester_end
} else {
    context.epoch_phases.active.end
};

Two observations:

  1. Undocumented convention: Consider adding a comment or constant to clarify that 0 means "use epoch-level eligibility." For example:

    // A value of 0 indicates no forester-specific eligibility limit; fall back to epoch active phase end
  2. Atomic ordering: While Ordering::Relaxed is likely sufficient for reading a monotonically increasing slot value, using Ordering::Acquire would provide stronger guarantees about visibility of writes from other threads. In a multi-threaded forester with dynamic eligibility updates, this could prevent subtle race conditions.

Apply this diff to use a more conservative ordering:

-        let forester_end = context
-            .forester_eligibility_end_slot
-            .load(Ordering::Relaxed);
+        // Load with Acquire ordering to ensure visibility of concurrent updates
+        let forester_end = context
+            .forester_eligibility_end_slot
+            .load(Ordering::Acquire);

And add a similar change at lines 213-215 in send_transaction_batch.

🤖 Prompt for AI Agents
In forester/src/processor/v2/common.rs around lines 130 to 138, the code uses 0
as an implicit sentinel for "no forester-specific eligibility" and reads the
atomic with Ordering::Relaxed; add a short comment (or a named constant)
clarifying that 0 means "use epoch active phase end" and replace the atomic load
Ordering::Relaxed with Ordering::Acquire to provide stronger cross-thread
visibility; also apply the same Ordering::Acquire change (and add the same
comment/constant) at lines ~213-215 in send_transaction_batch so both reads use
the documented sentinel and conservative atomic ordering.

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

♻️ Duplicate comments (2)
forester/src/processor/v2/state/supervisor.rs (2)

410-518: Consider extracting shared logic between build_append_job and build_nullify_job.

Both methods share significant structural similarities:

  • Slicing batch data using batch_range
  • Computing hashchain_idx
  • Accessing staging_tree with the same error pattern
  • Calling staging.process_batch_updates
  • Retrieving leaves hashchain
  • Constructing circuit inputs
  • Calling finish_job

Based on coding guidelines, ...

You could extract the common pattern into a helper that accepts closures or an enum to handle the phase-specific differences (array sources, circuit input types). This would improve maintainability and reduce the risk of divergent behavior if one method is updated but the other isn't.

Example structure:

fn build_batch_job<F, I>(
    &mut self,
    batch_idx: usize,
    state_queue: &StateQueueDataV2,
    start: usize,
    get_batch_data: F,
    build_inputs: I,
) -> crate::Result<Option<ProofJob>>
where
    F: FnOnce(&StateQueueDataV2, Range<usize>) -> BatchData,
    I: FnOnce(BatchTreeUpdateResult, ...) -> ProofInput,
{
    // Common logic here
}

221-228: TxSender initialized with stale root before indexer sync.

TxSender::spawn receives self.current_root at line 221, but this value is only updated from the indexer inside enqueue_batches at lines 330 or 371 (called at line 228). On first run, current_root will be [0u8; 32].

Since last_seen_root in TxSender is used primarily for logging root transitions, this doesn't cause functional issues—but it means the first proof result will always log a root change from zero, which could be confusing during debugging.

Consider either:

  1. Fetching and setting current_root before spawning TxSender
  2. Passing a sentinel value (or Option) to indicate "not yet initialized"
  3. Accepting the current behavior and adding a comment explaining why it's acceptable

Based on past reviews, this appears to be an accepted trade-off, but explicit documentation would help future maintainers.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e1373cb and 697dedb.

📒 Files selected for processing (1)
  • forester/src/processor/v2/state/supervisor.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (45)
📓 Common learnings
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_input_queue method for batch nullify operations on StateV2 trees. The method must verify ZKP proving correctness of: old_root + queue nullifiers → new_root, update tree root, increment tree sequence_number, increment tree nullifier_next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Prover server (prover/server/) must generate ZK proofs for batch operations (append, nullify, address append)
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_input_queue method for batch nullify operations on StateV2 trees. The method must verify ZKP proving correctness of: old_root + queue nullifiers → new_root, update tree root, increment tree sequence_number, increment tree nullifier_next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/initialize_state_tree.rs : State tree initialization must create two Solana accounts: BatchedMerkleTreeAccount with integrated input queue and separate BatchedQueueAccount

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount for state trees with integrated input queue (for nullifiers) and separate BatchedQueueAccount for output operations

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize a state Merkle tree with a `TreeType::StateV2` (4) tree type, storing tree roots, root history, and integrated input queue (bloom filters + hash chains for nullifiers) in the `BatchedMerkleTreeAccount` with discriminator b`BatchMta` [66, 97, 116, 99, 104, 77, 116, 97]

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_address_queue method for batch address append operations on AddressV2 trees. The method must verify ZKP proving correctness of: old_root + queue addresses → new_root using indexed Merkle tree insertion, update tree root, increment tree sequence_number, increment tree next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `src/merkle_tree.rs`, implement `BatchedMerkleTreeAccount::update_tree_from_output_queue_account` method that batch appends values from output queue to state Merkle tree with ZKP verification, verifying proof of old_root + queue_values → new_root

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Set output queue account discriminator to b`queueacc` (8 bytes) and initialize queue metadata with QueueType::OutputStateV2

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize an output queue account as `BatchedQueueAccount` with `QueueType::OutputStateV2`, temporary storage for compressed account hashes before tree insertion with immediate spending capability via proof-by-index, using discriminator b`queueacc` [113, 117, 101, 117, 101, 97, 99, 99]

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Validate queue type is `OUTPUT_STATE_QUEUE_TYPE_V2` when deserializing `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Define access control parameters: program_owner (Option<Pubkey>), forester (Option<Pubkey>) for non-Light foresters, and owner (Pubkey passed as function parameter)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*{transaction,batch}*.rs : Transaction V1 processing should configure `--max-concurrent-sends 50`, `--legacy-ixs-per-tx 1`, `--transaction-max-concurrent-batches 20`, `--cu-limit 1000000`, and `--enable-priority-fees false` by default

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Validate bloom_filter_capacity is divisible by 8 in `src/initialize_address_tree.rs`. Capacity must be >= batch_size * 8.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*{pool,connection,rpc}*.rs : RPC pool settings should use `--rpc-pool-size 10` (default), `--rpc-pool-connection-timeout-secs 15`, and `--rpc-pool-idle-timeout-secs 300` for optimal connection pooling

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/{merkle_tree,merkle_tree_metadata}.rs : Trees must maintain a cyclic buffer of recent roots (default: 200) enabling validity proofs for recently spent compressed accounts

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Validate root_history_capacity is at least equal to (input_queue_batch_size / input_queue_zkp_batch_size) in `src/initialize_address_tree.rs`. This ensures sufficient space for roots generated by address queue operations.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Validate that ZKP batch sizes must be 10 or 500 (only supported circuit sizes)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : ZKP batch sizes for address trees must be 10 or 250 in `src/initialize_address_tree.rs`. Only these circuit sizes are supported for address trees.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Check `tree_capacity` (2^height) against new insertions to prevent overflow in `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Define bloom filter configuration for input queue: bloom_filter_capacity (u64, default batch_size * 8) and bloom_filter_num_iters (u64, default 3 for test and 10 for production)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Error handling must use BatchedMerkleTreeError enum from errors.rs with u32 error codes in the 14301-14312 range

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch nullify operations must check that tree type is TreeType::StateV2 before processing, verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch address append operations must check that tree type is TreeType::AddressV2 before processing, verify tree capacity constraint (tree.next_index + zkp_batch_size <= tree_capacity), verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, when batch state is `Inserted`, verify bloom filter is zeroed before clearing hash chain stores and transitioning to `Fill` state

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Verify tree capacity constraint before tree update: `tree.next_index + zkp_batch_size <= tree_capacity`; error with `TreeIsFull` (14310) if violated

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : After inserting an address into the batch, check if `num_inserted_elements == batch_size`. If true, transition batch state from `Fill` to `Full`, increment `currently_processing_batch_index` to switch to the other batch, and update `pending_batch_index` to mark this batch ready for tree update.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, verify tree type is `TreeType::StateV2` before allowing nullifier insertion; reject address trees

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Transition batch state to `Inserted` when all ZKP batches are complete and increment `pending_batch_index` to switch to other batch

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch must have ready ZKP batches for insertion: verify `num_full_zkp_batches > num_inserted_zkp_batches`; error with `BatchNotReady` (14301) if not ready

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Zero overlapping roots in cyclic buffer by starting at `oldest_root_index = root_history.first_index()`, zeroing `num_remaining_roots` consecutive roots with wrapping, and verifying ended at `first_safe_root_index = batch.root_index + 1`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : When all ZKP batches of a batch are inserted, set batch `sequence_number = tree_sequence_number + root_history_capacity` (threshold when root at root_index is overwritten) and set `root_index` to identify root that must not exist when bloom filter is zeroed

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Root history is accessed via `root_history.last()` to retrieve the latest root. Validity proofs pick roots by index from root history since proofs need a static root value to verify against

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : State trees must initialize with zero bytes root for the specified height and have a separate BatchedQueueAccount for output operations

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Overlapping roots in history must be zeroed when clearing bloom filters to prevent inclusion proofs of nullified values

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/prover/server/prover/v2/batch_append_circuit.go : Batch append circuit implementation at `prover/server/prover/v2/batch_append_circuit.go` must verify that batch append is correct by: (1) verifying public input hash matches Hash([old_root, new_root, leaves_hash_chain, start_index]), (2) verifying leaves_hash_chain matches hash chain of all new leaves, (3) for each position checking if old_leaf is zero (insert new leaf) or non-zero (keep old nullifier), (4) providing Merkle proof for old_leaf and computing root update, (5) verifying final computed root equals new_root

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : After successful ZKP verification, increment tree `next_index` by `zkp_batch_size` (represents leaf index for next insertion)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Tree updates must require zero-knowledge proofs proving batch operation correctness with public inputs: old root, new root, hash chain, and for appends: start_index (output queue) or next_index (address queue)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/prover/server/prover/v2/batch_address_append_circuit.go : Batch address append ZKP verification must validate that public_input_hash equals Hash([old_root, new_root, leaves_hash_chain, start_index]), for each address in batch perform two Merkle updates (low leaf update to maintain sorted linked list + new leaf insertion at start_index + i), verify new address fits between low_value and low_next_value, and assert new leaf position must be empty (old_leaf = 0).

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Always increment `queue_next_index` by 1 after successfully inserting an address. This value serves as a sequence number for indexers to track address insertion order.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/prover/server/prover/v2/batch_append_circuit.go : Batch append circuit must handle nullifiers in output queue by checking if position contains non-zero old_leaf (nullifier already inserted) and keeping old leaf instead of overwriting, since input and output queues are independent

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `insert_into_current_queue_batch` helper, handle batch state transitions: if state is `Fill`, proceed; if state is `Inserted`, verify bloom filter is zeroed, clear hash chain stores, transition to `Fill`, and reset batch metadata; if state is `Full`, return `BatchedMerkleTreeError::BatchNotReady` (error code 14301).

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Applies to programs/registry/src/lib.rs : In wrapper instruction handler in `lib.rs`, load account metadata, determine work units, call `check_forester()`, then call the processing function

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : BatchedMerkleTreeAccount must be of type `TreeType::StateV2` when updating tree from output queue

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : State tree nullifier insertion must use the BatchedMerkleTreeAccount::insert_nullifier_into_queue method

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize output queue value vectors (2 vectors, one per batch with capacity = batch_size each) and hash chain stores (2 vectors with capacity = batch_size / zkp_batch_size each)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
🧬 Code graph analysis (1)
forester/src/processor/v2/state/supervisor.rs (5)
forester/src/processor/v2/state/helpers.rs (2)
  • fetch_batches (34-77)
  • fetch_zkp_batch_size (12-32)
forester/src/processor/v2/state/proof_worker.rs (3)
  • spawn_proof_workers (57-95)
  • new (26-28)
  • async_channel (75-75)
forester/src/processor/v2/state/tx_sender.rs (2)
  • spawn (37-52)
  • e (110-110)
prover/client/src/proof_types/batch_append/proof_inputs.rs (1)
  • new (32-111)
prover/client/src/proof_types/batch_update/proof_inputs.rs (1)
  • new (41-111)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Test program-libs-fast
  • GitHub Check: Test batched-merkle-tree-simulate
  • GitHub Check: Test program-libs-slow
  • GitHub Check: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
  • GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
  • GitHub Check: programs (system-cpi-test-v2-functional-read-only, ["cargo-test-sbf -p system-cpi-v2-test -- func...
  • GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...


let leaves_hashchain =
Self::get_leaves_hashchain(&batch.leaves_hash_chains, hashchain_idx)?;
let start_index = leaf_indices.first().copied().unwrap_or(0) as u32;
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Lossy cast from u64 to u32 without validation.

leaf_indices contains u64 values cast to u32 using as, which truncates if the value exceeds u32::MAX. While tree heights are bounded (default 26 → max index ~67M, well within u32), using as for potentially lossy conversions without explicit validation or documentation is not ideal for defensive coding.

Consider using try_from with error handling:

-        let start_index = leaf_indices.first().copied().unwrap_or(0) as u32;
+        let start_index = u32::try_from(leaf_indices.first().copied().unwrap_or(0))
+            .map_err(|_| anyhow!("Leaf index exceeds u32::MAX"))?;

Alternatively, add a comment explaining why the cast is safe based on tree height constraints.

🤖 Prompt for AI Agents
In forester/src/processor/v2/state/supervisor.rs around line 445, the code
performs a direct cast from u64 to u32 with `as`, which can silently truncate
large values; replace the lossy cast with a checked conversion (e.g., use
u32::try_from(start_index_u64) and handle the Result or propagate an error) or,
if you can prove by invariants that values never exceed u32::MAX, add a clear
comment stating the bound and replace the cast with an assert or expect that
documents the invariant (so the conversion is explicit and fails loudly if
violated).

let new_root = result.new_root;
let leaves_hashchain =
Self::get_leaves_hashchain(&batch.leaves_hash_chains, hashchain_idx)?;
let path_indices: Vec<u32> = leaf_indices.iter().map(|idx| *idx as u32).collect();
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Same lossy cast pattern as in build_append_job.

Converting u64 leaf indices to u32 using as can truncate values silently. While safe for typical tree heights, this pattern repeats the same issue flagged at line 445.

Apply the same defensive conversion pattern:

-        let path_indices: Vec<u32> = leaf_indices.iter().map(|idx| *idx as u32).collect();
+        let path_indices: Vec<u32> = leaf_indices
+            .iter()
+            .map(|idx| u32::try_from(*idx).map_err(|_| anyhow!("Leaf index exceeds u32::MAX")))
+            .collect::<crate::Result<Vec<_>>>()?;
🤖 Prompt for AI Agents
In forester/src/processor/v2/state/supervisor.rs around line 503, the code
performs a lossy cast from u64 to u32 with `as`, which can silently truncate
large values; replace the cast with a checked conversion using u32::try_from (or
idx.try_into()) and propagate or handle the error (return a Result or map to a
specific error) the same way you did at line 445 so conversion failures are
detected instead of silently truncating.

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 (1)
forester/src/epoch_manager.rs (1)

2327-2343: Fix the pipeline failure: missing ProverConfig fields in test.

The test configuration is missing the new prover_polling_interval and prover_max_wait_time fields added to ExternalServicesConfig.

Apply this diff to fix the test configuration:

             external_services: ExternalServicesConfig {
                 rpc_url: "http://localhost:8899".to_string(),
                 ws_rpc_url: None,
                 indexer_url: None,
                 prover_url: None,
                 prover_append_url: None,
                 prover_update_url: None,
                 prover_address_append_url: None,
                 prover_api_key: None,
+                prover_polling_interval: None,
+                prover_max_wait_time: None,
                 photon_api_key: None,
                 photon_grpc_url: None,
                 pushgateway_url: None,
                 pagerduty_routing_key: None,
                 rpc_rate_limit: None,
                 photon_rate_limit: None,
                 send_tx_rate_limit: None,
             },
♻️ Duplicate comments (2)
forester/src/processor/v2/state/supervisor.rs (2)

425-425: Simplify hashchain_idx calculation.

Since start = batch_idx * zkp_batch_size, the division start / self.zkp_batch_size always equals batch_idx. The current expression works but adds unnecessary indirection:

-        let hashchain_idx = start / self.zkp_batch_size as usize;
+        let hashchain_idx = batch_idx;

This makes the relationship to the hash chain store clearer and removes a division operation.


445-445: Consider defensive conversion for start_index.

The cast leaf_indices.first().copied().unwrap_or(0) as u32 can silently truncate if the leaf index exceeds u32::MAX. While tree height 32 limits indices to ~4 billion (within u32 range), using explicit conversion documents the invariant:

-        let start_index = leaf_indices.first().copied().unwrap_or(0) as u32;
+        let start_index = u32::try_from(leaf_indices.first().copied().unwrap_or(0))
+            .expect("Leaf index within u32 range for height-32 tree");

This fails loudly if the invariant is ever violated rather than silently truncating.

Comment on lines +1755 to +1811
fn build_batch_context(
&self,
epoch_info: &Epoch,
tree_accounts: &TreeAccounts,
queue_update: Option<&QueueUpdateMessage>,
) -> Result<usize> {
input_queue_hint: Option<u64>,
output_queue_hint: Option<u64>,
forester_slot: Option<&ForesterSlot>,
) -> BatchContext<R> {
let default_prover_url = "http://127.0.0.1:3001".to_string();

let (input_queue_hint, output_queue_hint) = if let Some(update) = queue_update {
match update.queue_type {
light_compressed_account::QueueType::InputStateV2 => {
(Some(update.queue_size), None)
}
light_compressed_account::QueueType::OutputStateV2 => {
(None, Some(update.queue_size))
}
_ => (None, None),
}
} else {
(None, None)
};

let batch_context = BatchContext {
let eligibility_end = forester_slot.map(|s| s.end_solana_slot).unwrap_or(0);
BatchContext {
rpc_pool: self.rpc_pool.clone(),
authority: self.config.payer_keypair.insecure_clone(),
authority: self.authority.clone(),
derivation: self.config.derivation_pubkey,
epoch: epoch_info.epoch,
merkle_tree: tree_accounts.merkle_tree,
output_queue: tree_accounts.queue,
prover_append_url: self
.config
.external_services
.prover_append_url
.clone()
.unwrap_or_else(|| default_prover_url.clone()),
prover_update_url: self
.config
.external_services
.prover_update_url
.clone()
.unwrap_or_else(|| default_prover_url.clone()),
prover_address_append_url: self
.config
.external_services
.prover_address_append_url
.clone()
.unwrap_or_else(|| default_prover_url.clone()),
prover_api_key: self.config.external_services.prover_api_key.clone(),
prover_polling_interval: Duration::from_secs(1),
prover_max_wait_time: Duration::from_secs(600),
prover_config: ProverConfig {
append_url: self
.config
.external_services
.prover_append_url
.clone()
.unwrap_or_else(|| default_prover_url.clone()),
update_url: self
.config
.external_services
.prover_update_url
.clone()
.unwrap_or_else(|| default_prover_url.clone()),
address_append_url: self
.config
.external_services
.prover_address_append_url
.clone()
.unwrap_or_else(|| default_prover_url.clone()),
api_key: self.config.external_services.prover_api_key.clone(),
polling_interval: self
.config
.external_services
.prover_polling_interval
.unwrap_or(Duration::from_secs(1)),
max_wait_time: self
.config
.external_services
.prover_max_wait_time
.unwrap_or(Duration::from_secs(600)),
},
ops_cache: self.ops_cache.clone(),
epoch_phases: epoch_info.phases.clone(),
slot_tracker: self.slot_tracker.clone(),
input_queue_hint,
output_queue_hint,
};
num_proof_workers: self.config.transaction_config.max_concurrent_batches,
forester_eligibility_end_slot: Arc::new(AtomicU64::new(eligibility_end)),
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

LGTM: Good consolidation of BatchContext construction.

The build_batch_context helper successfully eliminates the duplication flagged in past reviews. The prover configuration properly reads from config with sensible defaults.

Optional refinement: Consider extracting the default prover URL ("http://127.0.0.1:3001") as a module-level constant for easier maintenance:

const DEFAULT_PROVER_URL: &str = "http://127.0.0.1:3001";
🤖 Prompt for AI Agents
In forester/src/epoch_manager.rs around lines 1755 to 1811, extract the literal
default prover URL "http://127.0.0.1:3001" into a module-level constant (e.g.,
DEFAULT_PROVER_URL: &str) and replace the local let default_prover_url = ...
with references to that constant; update the .unwrap_or_else(||
default_prover_url.clone()) calls to use the constant (ensuring proper String
conversion where needed) so the default value is defined once at top-level for
easier maintenance.

Comment on lines +1861 to 1931
async fn process_v2(
&self,
epoch_info: &Epoch,
tree_accounts: &TreeAccounts,
queue_update: Option<&QueueUpdateMessage>,
forester_slot_details: &ForesterSlot,
) -> Result<usize> {
match tree_accounts.tree_type {
TreeType::StateV2 => {
if let Some(update) = queue_update {
let supervisor = self
.get_or_create_state_supervisor(epoch_info, tree_accounts)
.await?;

supervisor
.ask(v2::state::UpdateEligibility {
end_slot: forester_slot_details.end_solana_slot,
})
.send()
.await
.map_err(|e| {
anyhow!(
"Failed to send UpdateEligibility to StateSupervisor for tree {}: {}",
tree_accounts.merkle_tree,
e
)
})?;

let work = v2::state::QueueWork {
queue_type: update.queue_type,
queue_size: update.queue_size,
};

Ok(supervisor
.ask(v2::state::ProcessQueueUpdate { queue_work: work })
.send()
.await
.map_err(|e| {
anyhow!(
"Failed to send message to StateSupervisor for tree {}: {}",
tree_accounts.merkle_tree,
e
)
})?)
} else {
Ok(0)
}
}
TreeType::AddressV2 => {
let input_queue_hint = queue_update.map(|u| u.queue_size);
let batch_context = self.build_batch_context(
epoch_info,
tree_accounts,
input_queue_hint,
None,
Some(forester_slot_details),
);

process_batched_operations(batch_context, tree_accounts.tree_type)
.await
.map_err(|e| anyhow!("Failed to process V2 operations: {}", e))
}
_ => {
warn!(
"Unsupported tree type for V2 processing: {:?}",
tree_accounts.tree_type
);
Ok(0)
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

LGTM: Well-structured V2 processing with actor-based StateV2 and direct AddressV2 paths.

The StateV2 path correctly obtains or creates a long-lived supervisor actor and sends it eligibility and work messages. The AddressV2 path builds a per-slot context with forester eligibility and processes directly. Error messages include tree pubkeys for debugging.

Minor optimization opportunity: UpdateEligibility is sent on every call even if end_slot hasn't changed. If this becomes a performance concern, consider tracking the last-sent end_slot to avoid redundant updates. However, the current approach is simpler and the message overhead is negligible.

🤖 Prompt for AI Agents
In forester/src/epoch_manager.rs around lines 1861 to 1931, avoid sending
UpdateEligibility every time when the end_slot hasn't changed: add a
last_sent_end_slot tracker (either on the StateSupervisor struct or in
EpochManager keyed by merkle_tree) and check it before sending
UpdateEligibility; only send if forester_slot_details.end_solana_slot !=
last_sent_end_slot, then update the tracker after a successful send. Make the
tracker concurrency-safe (e.g., AtomicU64 or a Mutex-protected map) and ensure
failure paths do not update the tracker so retries remain possible.

Comment on lines +126 to +129
self.context
.forester_eligibility_end_slot
.store(msg.end_slot, std::sync::atomic::Ordering::Relaxed);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider using Ordering::Release for eligibility store.

The load side in common.rs uses Ordering::Acquire. For proper happens-before semantics, the store should use Ordering::Release to pair with the acquire load:

         self.context
             .forester_eligibility_end_slot
-            .store(msg.end_slot, std::sync::atomic::Ordering::Relaxed);
+            .store(msg.end_slot, std::sync::atomic::Ordering::Release);

With Relaxed store and Acquire load, you get the atomicity guarantee but not the visibility ordering. In practice this may work fine since the slot value is monotonically increasing, but Release/Acquire pairing is the correct pattern for cross-thread communication.

🤖 Prompt for AI Agents
In forester/src/processor/v2/state/supervisor.rs around lines 126 to 129, the
code stores forester_eligibility_end_slot with Ordering::Relaxed which pairs
with an Acquire load elsewhere; change the store to use
std::sync::atomic::Ordering::Release to establish proper happens-before
visibility for the Acquire load in common.rs, keeping the rest of the logic
unchanged.

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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2af5e1b and 7fdc4da.

📒 Files selected for processing (1)
  • forester/src/epoch_manager.rs (15 hunks)
🧰 Additional context used
🧠 Learnings (43)
📓 Common learnings
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_input_queue method for batch nullify operations on StateV2 trees. The method must verify ZKP proving correctness of: old_root + queue nullifiers → new_root, update tree root, increment tree sequence_number, increment tree nullifier_next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount for state trees with integrated input queue (for nullifiers) and separate BatchedQueueAccount for output operations
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Tree updates from input queue must use update_tree_from_input_queue function for state trees and update_tree_from_address_queue for address trees with ZKP verification
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize a state Merkle tree with a `TreeType::StateV2` (4) tree type, storing tree roots, root history, and integrated input queue (bloom filters + hash chains for nullifiers) in the `BatchedMerkleTreeAccount` with discriminator b`BatchMta` [66, 97, 116, 99, 104, 77, 116, 97]

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Define access control parameters: program_owner (Option<Pubkey>), forester (Option<Pubkey>) for non-Light foresters, and owner (Pubkey passed as function parameter)

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount for state trees with integrated input queue (for nullifiers) and separate BatchedQueueAccount for output operations

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : BatchedMerkleTreeAccount must be of type `TreeType::StateV2` when updating tree from output queue

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Associate state tree with queue_account pubkey in tree metadata and set rollover_fee to 0 (charged on queue insertion, not tree operations)

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/initialize_state_tree.rs : State tree initialization must create two Solana accounts: BatchedMerkleTreeAccount with integrated input queue and separate BatchedQueueAccount

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Set state Merkle tree account discriminator to b`BatchMta` (8 bytes) and initialize tree metadata with TreeType::StateV2 (4)

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_input_queue method for batch nullify operations on StateV2 trees. The method must verify ZKP proving correctness of: old_root + queue nullifiers → new_root, update tree root, increment tree sequence_number, increment tree nullifier_next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/rollover_{state,address}_tree.rs : Trees must support rollover when reaching capacity (2^height leaves) by creating a new tree and marking the old tree as rolled over, preserving old tree roots

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Verify queue and tree association by matching pubkeys; error with `MerkleTreeAndQueueNotAssociated` (14001) if they don't match

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Tree updates from input queue must use update_tree_from_input_queue function for state trees and update_tree_from_address_queue for address trees with ZKP verification

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_address_queue method for batch address append operations on AddressV2 trees. The method must verify ZKP proving correctness of: old_root + queue addresses → new_root using indexed Merkle tree insertion, update tree root, increment tree sequence_number, increment tree next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_address_into_queue`, verify that the tree type is `TreeType::AddressV2` before proceeding with address insertion. Reject state trees with `MerkleTreeMetadataError::InvalidTreeType`.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : After inserting an address into the batch, check if `num_inserted_elements == batch_size`. If true, transition batch state from `Fill` to `Full`, increment `currently_processing_batch_index` to switch to the other batch, and update `pending_batch_index` to mark this batch ready for tree update.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch address append operations must check that tree type is TreeType::AddressV2 before processing, verify tree capacity constraint (tree.next_index + zkp_batch_size <= tree_capacity), verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount with integrated input queue (for addresses) for address trees without a separate output queue account

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize an output queue account as `BatchedQueueAccount` with `QueueType::OutputStateV2`, temporary storage for compressed account hashes before tree insertion with immediate spending capability via proof-by-index, using discriminator b`queueacc` [113, 117, 101, 117, 101, 97, 99, 99]

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Compute and store hashed pubkeys by hashing and truncating to 31 bytes for bn254 field compatibility in both queue and tree accounts

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch nullify operations must check that tree type is TreeType::StateV2 before processing, verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, verify tree type is `TreeType::StateV2` before allowing nullifier insertion; reject address trees

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : State tree nullifier insertion must use the BatchedMerkleTreeAccount::insert_nullifier_into_queue method

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Check `tree_capacity` (2^height) against new insertions to prevent overflow in `BatchedQueueAccount`

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Use `check_account_balance_is_rent_exempt` function from `light-account-checks` to verify rent exemption for both queue_account and merkle_tree_account during initialization

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*prover*.rs : Prover V2 endpoints should be configurable via `--prover-append-url`, `--prover-update-url`, `--prover-address-append-url`, and `--prover-api-key` parameters

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: When forester PDA is present, `check_forester()` must validate epoch registration and eligibility, track work, and require network fee; when absent, validate that authority matches the tree's designated forester (for private trees)

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Applies to programs/registry/src/lib.rs : In wrapper instruction handler in `lib.rs`, load account metadata, determine work units, call `check_forester()`, then call the processing function

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Validate queue type is `OUTPUT_STATE_QUEUE_TYPE_V2` when deserializing `BatchedQueueAccount`

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Store `BatchedQueueAccount` layout and `BatchedQueueMetadata` in src/queue.rs

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/queue.rs : Output queue insertion must use BatchedQueueAccount::insert_into_current_batch method

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Implement two hash chain stores (`[ZeroCopyVecU64<[u8; 32]>; 2]`), one per batch, each with `batch_size / zkp_batch_size` hash chains storing Poseidon hashes of ZKP batches in `BatchedQueueAccount`

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Use two value vectors (`[ZeroCopyVecU64<[u8; 32]>; 2]`), one per batch, to store compressed account hashes in `BatchedQueueAccount`

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : In `src/queue.rs`, define BatchedQueueAccount layout and implement `mark_as_inserted_in_merkle_tree` method to increment `num_inserted_zkp_batches` and transition batch state to `Inserted` when all ZKP batches are complete

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Use zero-copy deserialization for all `BatchedQueueAccount` operations

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:24.369Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:24.369Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : When a batch is in `Inserted` state, clear the value vec and hash chain stores, advance batch state to `Fill`, and reset batch metadata before allowing new insertions

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Call `check_forester()` to validate authority and track work performed, passing account metadata, authority key, target account key, forester PDA, and work units

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/main.rs : Required configuration must include: `--rpc-url`, `--ws-rpc-url`, `--indexer-url`, `--prover-url`, `--payer`, and `--derivation` parameters

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Wrapper instruction Account context must include: optional `registered_forester_pda` (mutable), `authority` signer, `cpi_authority` PDA with seeds, `registered_program_pda`, `account_compression_program`, `log_wrapper` for events, and `target_account` (mutable)

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T18:01:14.087Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:14.087Z
Learning: Applies to program-libs/compressible/**/*.rs : Implement state validation methods (`validate_active`, `validate_not_inactive`) for CompressibleConfig account state verification

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Set output queue account discriminator to b`queueacc` (8 bytes) and initialize queue metadata with QueueType::OutputStateV2

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `src/merkle_tree.rs`, implement `BatchedMerkleTreeAccount::update_tree_from_output_queue_account` method that batch appends values from output queue to state Merkle tree with ZKP verification, verifying proof of old_root + queue_values → new_root

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Set tree_type to `TreeType::AddressV2` (5) and associated_queue to Pubkey::default() for address trees in `src/initialize_address_tree.rs`. Address trees have no separate output queue - the address queue is integrated into the tree account.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Tree updates from output queue must use BatchedMerkleTreeAccount::update_tree_from_output_queue_account method with ZKP verification

Applied to files:

  • forester/src/epoch_manager.rs
🧬 Code graph analysis (1)
forester/src/epoch_manager.rs (4)
forester/src/processor/v2/mod.rs (1)
  • process_batched_operations (20-36)
forester/src/polling/queue_poller.rs (1)
  • new (68-76)
forester/src/slot_tracker.rs (2)
  • new (25-35)
  • update (37-44)
forester/src/processor/v2/state/tx_sender.rs (2)
  • spawn (37-52)
  • e (110-110)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • 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: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
  • GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
🔇 Additional comments (5)
forester/src/epoch_manager.rs (5)

71-73: Wiring of StateSupervisorMap and authority into EpochManager looks consistent

The new StateSupervisorMap<R> alias, state_supervisors field, and authority: Arc<Keypair> are initialized and cloned correctly, and they’re plumbed through EpochManager::new without changing external behavior. This gives you a single shared signer for all V2 batch contexts and per-tree supervisors, which matches how V1 already uses config.payer_keypair.

No issues from a correctness or concurrency standpoint here; the Arc-wrapped map and keypair are appropriate for the async usage patterns in this module.

Based on learnings, this aligns with the documented need for per-tree state supervisors and dedicated prover endpoints in the forester README.

Also applies to: 102-119, 121-140, 143-194


1261-1267: Improved logging for light-slot processing

Including the epoch and Solana slot window in the process_light_slot log line makes it much easier to correlate behavior with protocol phases and epoch state. No functional issues here.


1555-1576: V2 dispatch separation for StateV2 vs AddressV2 is well-structured

Routing V2 trees through process_v2 and then:

  • Using a long-lived StateSupervisor for TreeType::StateV2, with QueueWork { queue_type, queue_size } and a separate UpdateEligibility message per slot window, and
  • Building a fresh BatchContext and delegating to process_batched_operations only for TreeType::AddressV2,

matches the intended architecture where StateV2 uses the actor-based pipeline and AddressV2 stays direct. The Ok(0) behavior when there is no queue_update or when the tree type is unsupported is a sane fallback and keeps metrics consistent with the calling code.

Based on learnings, this division aligns with the docs that state trees use separate input/output queues and address trees use the integrated address queue plus ZKP-based batch append.

Also applies to: 1861-1930


1755-1811: BatchContext / ProverConfig construction and eligibility slot handling

The new build_batch_context correctly centralizes all V2 configuration:

  • Prover URLs and API key are sourced from ForesterConfig.external_services with sensible defaults, matching the CLI/README expectations for --prover-append-url, --prover-update-url, and --prover-address-append-url.
  • num_proof_workers is tied to transaction_config.max_concurrent_batches, reusing an existing concurrency knob.
  • forester_eligibility_end_slot is initialized from forester_slot.end_solana_slot for AddressV2 and to 0 for StateV2 (where it will instead be driven by UpdateEligibility).

This is a clean consolidation of the V2 runtime configuration. Just ensure that downstream consumers treat an eligibility_end_slot of 0 as “no limit / not yet set”, so StateV2 supervisors don’t accidentally short-circuit work before the first UpdateEligibility.

Based on learnings, this matches the documented need to bound work to the assigned forester slots for V2 pipelines.


2343-2345: Tests updated for new prover timing configuration

Extending ExternalServicesConfig in the test helper with prover_polling_interval: None and prover_max_wait_time: None keeps the tests compiling and ensures they exercise the default durations wired in build_batch_context.

This is the right minimal change on the test side.

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

Caution

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

⚠️ Outside diff range comments (1)
forester/src/config.rs (1)

172-183: Revisit TransactionConfig::default().max_concurrent_batches = 60 vs documented V1 defaults

The default max_concurrent_batches has been set to 60 here. Retrieved guidance for V1 transaction processing mentions a default of --transaction-max-concurrent-batches 20 for stable operation. As per coding guidelines, transaction V1 defaults are tuned to avoid overloading Solana RPC and downstream services.

A few points to double‑check:

  • TransactionConfig::default() is used in new_for_status and may be used in other call sites; raising this default to 60 could:
    • Increase concurrent load in any code paths that rely on the default rather than CLI overrides.
    • Diverge from the documented operational baseline (20), which might surprise operators.

If the intent is to raise concurrency only for specific V2 flows (or only in forester start), consider:

  • Keeping the struct default at 20 and overriding to 60 explicitly where you need the higher concurrency, or
  • Updating the docs / README / CLI default description to reflect the new 60 default, if this is an intentional global change.

Example to keep the documented default:

 impl Default for TransactionConfig {
     fn default() -> Self {
         Self {
             legacy_ixs_per_tx: 1,
-            max_concurrent_batches: 60,
+            max_concurrent_batches: 20,
             max_concurrent_sends: 50,
             cu_limit: 1_000_000,
             enable_priority_fees: false,
             tx_cache_ttl_seconds: 15,
             ops_cache_ttl_seconds: 180,
         }
     }
 }

Please confirm which behavior you want so code, CLI defaults, and docs stay aligned. Based on learnings, this default is part of the recommended V1 operational profile.

♻️ Duplicate comments (5)
forester/src/processor/v2/state/supervisor.rs (5)

416-416: Simplify hashchain_idx calculation.

Since start = batch_idx * zkp_batch_size, dividing by zkp_batch_size just gives batch_idx. The current expression adds unnecessary indirection.

-        let hashchain_idx = start / self.zkp_batch_size as usize;
+        let hashchain_idx = batch_idx;

436-436: Consider defensive conversion for leaf indices.

The as u32 cast silently truncates if the value exceeds u32::MAX. While safe for typical tree heights (height 32 → max index ~4B fits in u32), using try_from with error handling would be more defensive.

-        let start_index = leaf_indices.first().copied().unwrap_or(0) as u32;
+        let start_index = u32::try_from(leaf_indices.first().copied().unwrap_or(0))
+            .map_err(|_| anyhow!("Leaf index {} exceeds u32::MAX", leaf_indices.first().unwrap_or(&0)))?;

494-494: Same lossy cast pattern as build_append_job.

This line also uses as u32 for the conversion. If you apply defensive conversion at line 436, apply the same pattern here for consistency.

-        let path_indices: Vec<u32> = leaf_indices.iter().map(|idx| *idx as u32).collect();
+        let path_indices: Vec<u32> = leaf_indices
+            .iter()
+            .map(|idx| u32::try_from(*idx).map_err(|_| anyhow!("Leaf index {} exceeds u32::MAX", idx)))
+            .collect::<crate::Result<Vec<_>>>()?;

468-468: Apply same hashchain_idx simplification.

This is the same pattern as line 416.

-        let hashchain_idx = start / self.zkp_batch_size as usize;
+        let hashchain_idx = batch_idx;

126-129: Use Ordering::Release for proper cross-thread visibility.

The load side in common.rs uses Ordering::Acquire. For correct happens-before semantics, the store should use Ordering::Release. With Relaxed store and Acquire load, you get atomicity but not the visibility ordering guarantee that ensures the reader sees all writes that happened before this store.

         self.context
             .forester_eligibility_end_slot
-            .store(msg.end_slot, std::sync::atomic::Ordering::Relaxed);
+            .store(msg.end_slot, std::sync::atomic::Ordering::Release);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f06524 and bb99b50.

📒 Files selected for processing (3)
  • forester/package.json (1 hunks)
  • forester/src/config.rs (4 hunks)
  • forester/src/processor/v2/state/supervisor.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (76)
📓 Common learnings
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_input_queue method for batch nullify operations on StateV2 trees. The method must verify ZKP proving correctness of: old_root + queue nullifiers → new_root, update tree root, increment tree sequence_number, increment tree nullifier_next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount for state trees with integrated input queue (for nullifiers) and separate BatchedQueueAccount for output operations
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Tree updates from input queue must use update_tree_from_input_queue function for state trees and update_tree_from_address_queue for address trees with ZKP verification
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/**/*e2e*.rs : Devnet mode tests require `PHOTON_RPC_URL`, `PHOTON_WSS_RPC_URL`, `PHOTON_INDEXER_URL`, `PHOTON_PROVER_URL`, and `PHOTON_API_KEY` environment variables

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:03:13.950Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:03:13.950Z
Learning: Forester end-to-end tests should be run with `TEST_MODE=local cargo test --package forester e2e_test`

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/**/*e2e*.rs : Test environment variables should use `TEST_MODE` to specify 'local' or 'devnet' mode (default: devnet)

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/**/*e2e*.rs : Test feature flags `TEST_V1_STATE`, `TEST_V2_STATE`, `TEST_V1_ADDRESS`, and `TEST_V2_ADDRESS` should default to `true` and control which test scenarios run

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:03:13.950Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:03:13.950Z
Learning: Set LIGHT_PROTOCOL_VERSION environment variable to V1 or V2 when running JavaScript/TypeScript tests

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/**/.env.example : Copy the example environment file with `cp .env.example .env` before configuring Forester

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/**/*e2e*.rs : Tests should automatically skip minting tokens, executing transactions, and root verification for disabled test types

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:01:30.012Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:30.012Z
Learning: Run E2E extended tests after building the small compressed token program using `pnpm --filter lightprotocol/programs run build-compressed-token-small` followed by `cargo test-sbf -p e2e-test -- --test test_10_all`

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: All Forester configuration can be provided via command-line arguments or environment variables in the format `FORESTER_<OPTION_NAME>`

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:02:25.027Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:25.027Z
Learning: Supporting library unit tests must be run using: cargo test -p light-program-test, cargo test -p light-client, cargo test -p light-sparse-merkle-tree, cargo test -p light-compressed-token-types, and cargo test -p light-compressed-token-sdk

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:02:25.027Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:25.027Z
Learning: SDK core library unit tests must be run with: cargo test -p light-sdk-macros, cargo test -p light-sdk-macros --all-features, cargo test -p light-sdk, and cargo test -p light-sdk --all-features

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:01:30.012Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:30.012Z
Learning: Run registry tests using `cargo test-sbf -p registry-test` to test protocol configuration and forester registration

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:01:30.012Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:30.012Z
Learning: Run batched merkle tree simulation tests using `RUST_LOG=light_prover_client=debug cargo test -p batched-merkle-tree-test -- --test test_simulate_transactions` to enable logging

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:02:25.027Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:25.027Z
Learning: Token SDK tests must run with command: cargo test-sbf -p sdk-token-test

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:02:25.027Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:25.027Z
Learning: Anchor SDK Rust tests must run with command: cargo test-sbf -p sdk-anchor-test

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_input_queue method for batch nullify operations on StateV2 trees. The method must verify ZKP proving correctness of: old_root + queue nullifiers → new_root, update tree root, increment tree sequence_number, increment tree nullifier_next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_address_queue method for batch address append operations on AddressV2 trees. The method must verify ZKP proving correctness of: old_root + queue addresses → new_root using indexed Merkle tree insertion, update tree root, increment tree sequence_number, increment tree next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize a state Merkle tree with a `TreeType::StateV2` (4) tree type, storing tree roots, root history, and integrated input queue (bloom filters + hash chains for nullifiers) in the `BatchedMerkleTreeAccount` with discriminator b`BatchMta` [66, 97, 116, 99, 104, 77, 116, 97]

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `src/merkle_tree.rs`, implement `BatchedMerkleTreeAccount::update_tree_from_output_queue_account` method that batch appends values from output queue to state Merkle tree with ZKP verification, verifying proof of old_root + queue_values → new_root

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount for state trees with integrated input queue (for nullifiers) and separate BatchedQueueAccount for output operations

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize an output queue account as `BatchedQueueAccount` with `QueueType::OutputStateV2`, temporary storage for compressed account hashes before tree insertion with immediate spending capability via proof-by-index, using discriminator b`queueacc` [113, 117, 101, 117, 101, 97, 99, 99]

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/initialize_state_tree.rs : State tree initialization must create two Solana accounts: BatchedMerkleTreeAccount with integrated input queue and separate BatchedQueueAccount

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Set output queue account discriminator to b`queueacc` (8 bytes) and initialize queue metadata with QueueType::OutputStateV2

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Validate queue type is `OUTPUT_STATE_QUEUE_TYPE_V2` when deserializing `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Tree updates from input queue must use update_tree_from_input_queue function for state trees and update_tree_from_address_queue for address trees with ZKP verification

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*{transaction,batch}*.rs : Transaction V1 processing should configure `--max-concurrent-sends 50`, `--legacy-ixs-per-tx 1`, `--transaction-max-concurrent-batches 20`, `--cu-limit 1000000`, and `--enable-priority-fees false` by default

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/config.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Validate bloom_filter_capacity is divisible by 8 in `src/initialize_address_tree.rs`. Capacity must be >= batch_size * 8.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*{pool,connection,rpc}*.rs : RPC pool settings should use `--rpc-pool-size 10` (default), `--rpc-pool-connection-timeout-secs 15`, and `--rpc-pool-idle-timeout-secs 300` for optimal connection pooling

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/config.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/{merkle_tree,merkle_tree_metadata}.rs : Trees must maintain a cyclic buffer of recent roots (default: 200) enabling validity proofs for recently spent compressed accounts

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Validate root_history_capacity is at least equal to (input_queue_batch_size / input_queue_zkp_batch_size) in `src/initialize_address_tree.rs`. This ensures sufficient space for roots generated by address queue operations.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Validate that ZKP batch sizes must be 10 or 500 (only supported circuit sizes)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : ZKP batch sizes for address trees must be 10 or 250 in `src/initialize_address_tree.rs`. Only these circuit sizes are supported for address trees.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Check `tree_capacity` (2^height) against new insertions to prevent overflow in `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Define bloom filter configuration for input queue: bloom_filter_capacity (u64, default batch_size * 8) and bloom_filter_num_iters (u64, default 3 for test and 10 for production)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/config.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Error handling must use BatchedMerkleTreeError enum from errors.rs with u32 error codes in the 14301-14312 range

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch nullify operations must check that tree type is TreeType::StateV2 before processing, verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch address append operations must check that tree type is TreeType::AddressV2 before processing, verify tree capacity constraint (tree.next_index + zkp_batch_size <= tree_capacity), verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, when batch state is `Inserted`, verify bloom filter is zeroed before clearing hash chain stores and transitioning to `Fill` state

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Verify tree capacity constraint before tree update: `tree.next_index + zkp_batch_size <= tree_capacity`; error with `TreeIsFull` (14310) if violated

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : After inserting an address into the batch, check if `num_inserted_elements == batch_size`. If true, transition batch state from `Fill` to `Full`, increment `currently_processing_batch_index` to switch to the other batch, and update `pending_batch_index` to mark this batch ready for tree update.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, verify tree type is `TreeType::StateV2` before allowing nullifier insertion; reject address trees

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Transition batch state to `Inserted` when all ZKP batches are complete and increment `pending_batch_index` to switch to other batch

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch must have ready ZKP batches for insertion: verify `num_full_zkp_batches > num_inserted_zkp_batches`; error with `BatchNotReady` (14301) if not ready

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Zero overlapping roots in cyclic buffer by starting at `oldest_root_index = root_history.first_index()`, zeroing `num_remaining_roots` consecutive roots with wrapping, and verifying ended at `first_safe_root_index = batch.root_index + 1`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : When all ZKP batches of a batch are inserted, set batch `sequence_number = tree_sequence_number + root_history_capacity` (threshold when root at root_index is overwritten) and set `root_index` to identify root that must not exist when bloom filter is zeroed

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Root history is accessed via `root_history.last()` to retrieve the latest root. Validity proofs pick roots by index from root history since proofs need a static root value to verify against

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : State trees must initialize with zero bytes root for the specified height and have a separate BatchedQueueAccount for output operations

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Overlapping roots in history must be zeroed when clearing bloom filters to prevent inclusion proofs of nullified values

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/prover/server/prover/v2/batch_append_circuit.go : Batch append circuit implementation at `prover/server/prover/v2/batch_append_circuit.go` must verify that batch append is correct by: (1) verifying public input hash matches Hash([old_root, new_root, leaves_hash_chain, start_index]), (2) verifying leaves_hash_chain matches hash chain of all new leaves, (3) for each position checking if old_leaf is zero (insert new leaf) or non-zero (keep old nullifier), (4) providing Merkle proof for old_leaf and computing root update, (5) verifying final computed root equals new_root

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : After successful ZKP verification, increment tree `next_index` by `zkp_batch_size` (represents leaf index for next insertion)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Tree updates must require zero-knowledge proofs proving batch operation correctness with public inputs: old root, new root, hash chain, and for appends: start_index (output queue) or next_index (address queue)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/prover/server/prover/v2/batch_address_append_circuit.go : Batch address append ZKP verification must validate that public_input_hash equals Hash([old_root, new_root, leaves_hash_chain, start_index]), for each address in batch perform two Merkle updates (low leaf update to maintain sorted linked list + new leaf insertion at start_index + i), verify new address fits between low_value and low_next_value, and assert new leaf position must be empty (old_leaf = 0).

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Always increment `queue_next_index` by 1 after successfully inserting an address. This value serves as a sequence number for indexers to track address insertion order.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/prover/server/prover/v2/batch_append_circuit.go : Batch append circuit must handle nullifiers in output queue by checking if position contains non-zero old_leaf (nullifier already inserted) and keeping old leaf instead of overwriting, since input and output queues are independent

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `insert_into_current_queue_batch` helper, handle batch state transitions: if state is `Fill`, proceed; if state is `Inserted`, verify bloom filter is zeroed, clear hash chain stores, transition to `Fill`, and reset batch metadata; if state is `Full`, return `BatchedMerkleTreeError::BatchNotReady` (error code 14301).

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Applies to programs/registry/src/lib.rs : In wrapper instruction handler in `lib.rs`, load account metadata, determine work units, call `check_forester()`, then call the processing function

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : BatchedMerkleTreeAccount must be of type `TreeType::StateV2` when updating tree from output queue

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Mark ZKP batch as inserted by calling `mark_as_inserted_in_merkle_tree` on queue batch to increment `num_inserted_zkp_batches`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Implement two hash chain stores (`[ZeroCopyVecU64<[u8; 32]>; 2]`), one per batch, each with `batch_size / zkp_batch_size` hash chains storing Poseidon hashes of ZKP batches in `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Each ZKP batch has a hash chain storing the Poseidon hash of all values in that ZKP batch, used as public inputs for ZKP verification

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Calculate overlapping roots for zeroing using: overlapping if `batch.sequence_number > current_tree.sequence_number`; compute `num_remaining_roots = batch.sequence_number - current_tree.sequence_number`; verify `num_remaining_roots < root_history.len()` and error with `CannotZeroCompleteRootHistory` (14313) if violated

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Tree height must be fixed at 40 for address trees in `src/initialize_address_tree.rs`. Validate that height equals 40.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Define tree configuration parameters in `InitStateTreeAccountsInstructionData` struct: height (u32, default 32), index (u64), and root_history_capacity (u32, default 200)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Set tree_capacity = 2^height in output queue metadata

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : `InitAddressTreeAccountsInstructionData` struct in `src/initialize_address_tree.rs` must include: height (u32, default 40), index (u64), root_history_capacity (u32, default 200), input_queue_batch_size (u64, default 15,000), input_queue_zkp_batch_size (u64, default 250), bloom_filter_capacity (u64, default batch_size * 8), bloom_filter_num_iters (u64, default 3 for test/10 for production), program_owner (Option<Pubkey>), forester (Option<Pubkey>), rollover_threshold (Option<u64>, default 95%), network_fee (Option<u64>, default 10,000 lamports), and close_threshold (Option<u64>).

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Compute and store hashed pubkeys by hashing and truncating to 31 bytes for bn254 field compatibility in both queue and tree accounts

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Initialize next_index to 1 (not 0) in BatchedMerkleTreeAccount in `src/initialize_address_tree.rs`. Index 0 contains pre-initialized sentinel element.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:54:20.982Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/zero-copy-derive/README.md:0-0
Timestamp: 2025-11-24T17:54:20.982Z
Learning: Applies to program-libs/zero-copy-derive/**/*.rs : Use Option<T> for optional values in zero-copy structs; Option<u16>, Option<u32>, and Option<u64> are optimized

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : State tree nullifier insertion must use the BatchedMerkleTreeAccount::insert_nullifier_into_queue method

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize output queue value vectors (2 vectors, one per batch with capacity = batch_size each) and hash chain stores (2 vectors with capacity = batch_size / zkp_batch_size each)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*prover*.rs : Prover V2 endpoints should be configurable via `--prover-append-url`, `--prover-update-url`, `--prover-address-append-url`, and `--prover-api-key` parameters

Applied to files:

  • forester/src/config.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/main.rs : Required configuration must include: `--rpc-url`, `--ws-rpc-url`, `--indexer-url`, `--prover-url`, `--payer`, and `--derivation` parameters

Applied to files:

  • forester/src/config.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*status*.rs : The `forester status` command should support options: `--full`, `--protocol-config`, `--queue`, `--push-gateway-url`, and `--pagerduty-routing-key`

Applied to files:

  • forester/src/config.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*cache*.rs : Cache settings should support `--tx-cache-ttl-seconds 180` for transaction deduplication and `--ops-cache-ttl-seconds 180` for operations cache

Applied to files:

  • forester/src/config.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Define batch size parameters in `InitStateTreeAccountsInstructionData` struct: input_queue_batch_size (u64, default 15,000), output_queue_batch_size (u64, default 15,000), input_queue_zkp_batch_size (u64, default 500), and output_queue_zkp_batch_size (u64, default 500)

Applied to files:

  • forester/src/config.rs
🪛 GitHub Actions: forester-tests
forester/src/processor/v2/state/supervisor.rs

[error] 17-17: unused import: trace


[error] Cargo build failed due to a compiler error: unused import: trace.

🪛 GitHub Actions: lint
forester/src/processor/v2/state/supervisor.rs

[error] 17-17: Rust compilation error: unused import: trace (compiler error at forester/src/processor/v2/state/supervisor.rs:17:28).

🪛 GitHub Check: Forester e2e test
forester/src/processor/v2/state/supervisor.rs

[failure] 200-200:
unused variable: zkp_batch_size


[failure] 17-17:
unused import: trace

🪛 GitHub Check: lint
forester/src/processor/v2/state/supervisor.rs

[failure] 200-200:
unused variable: zkp_batch_size


[failure] 17-17:
unused import: trace

⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
  • GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
  • GitHub Check: programs (system-cpi-test-v2-functional-read-only, ["cargo-test-sbf -p system-cpi-v2-test -- func...
  • GitHub Check: Test program-libs-slow
  • GitHub Check: Test program-libs-fast
  • GitHub Check: Test batched-merkle-tree-simulate
🔇 Additional comments (4)
forester/src/processor/v2/state/supervisor.rs (4)

28-57: Clean actor state design.

The StateSupervisor struct maintains appropriate state for managing the v2 state processing pipeline: staging tree for proof computation, root/index tracking for state synchronization, and configuration. The message types are well-defined.


59-100: Solid actor lifecycle implementation.

The on_start correctly fetches the immutable zkp_batch_size from on-chain once, avoiding repeated RPC calls. The initialization pattern is clean and the logging provides good observability.


132-165: Well-factored helper methods.

The helper methods provide clean abstractions: get_leaves_hashchain has proper error handling with context, batch_range safely bounds the slice, and finish_job encapsulates state mutation. Good separation of concerns.


293-399: Clear batch processing pipeline.

The enqueue_batches method cleanly separates the Append and Nullify phases, each with its own data extraction and staging tree initialization. The pattern of building the staging tree from indexer data, then iterating to create jobs, is well-structured.

Comment on lines +43 to +44
pub prover_polling_interval: Option<Duration>,
pub prover_max_wait_time: Option<Duration>,
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Prover polling / max-wait wiring looks correct; consider clarifying zero-value semantics and documenting new knobs

The new prover_polling_interval and prover_max_wait_time fields are cleanly added and correctly wired from StartArgs (ms → Duration::from_millis, secs → Duration::from_secs), and default to None in new_for_status, which is consistent with status-mode not talking to a prover. This shape looks good.

Two follow‑ups worth considering:

  1. Zero values from CLI
    If a user passes --prover-polling-interval-ms 0 or --prover-max-wait-time-secs 0, this will produce Duration::from_millis(0) / Duration::from_secs(0). Depending on how these are consumed, that can mean:

    • Busy‑polling with no delay, or
    • Immediate timeout / no waiting.

    If "0" is not a meaningful configuration, it may be safer to normalize it to None or reject it early. For example:

  •            prover_polling_interval: args.prover_polling_interval_ms.map(Duration::from_millis),
    
  •            prover_max_wait_time: args.prover_max_wait_time_secs.map(Duration::from_secs),
    
  •            prover_polling_interval: args
    
  •                .prover_polling_interval_ms
    
  •                .filter(|v| *v > 0)
    
  •                .map(Duration::from_millis),
    
  •            prover_max_wait_time: args
    
  •                .prover_max_wait_time_secs
    
  •                .filter(|v| *v > 0)
    
  •                .map(Duration::from_secs),
    
    
    Or, alternatively, enforce `> 0` at CLI parsing / validation level.
    
    
  1. Docs / CLI help alignment
    Since these are new, it would be good to ensure forester/README.md and CLI help clearly document:

    • The units (ms vs secs) and typical ranges.
    • Whether None means "use internal default behavior" vs "disable polling/timeout".

    This will help operators avoid surprising behavior when tuning prover latency vs load. As per coding guidelines, prover-related configuration should be explicitly documented and discoverable from CLI flags.

Also applies to: 246-247, 336-337

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

♻️ Duplicate comments (9)
forester/src/processor/v2/common.rs (2)

1-42: Document ProverConfig and tie it to the prover CLI/config semantics.

The new ProverConfig is central to V2 prover integration but is currently undocumented. Given we configure these endpoints via flags like --prover-append-url, --prover-update-url, --prover-address-append-url, and --prover-api-key (per the forester README learnings), adding concise doc comments will make intent and expected formats obvious for future maintainers and operators.

For example:

+/// Configuration for the remote prover service used by V2 state/address workers.
 #[derive(Debug, Clone)]
 pub struct ProverConfig {
+    /// HTTP endpoint for state output-queue → tree append proofs.
     pub append_url: String,
+    /// HTTP endpoint for state nullify/update proofs.
     pub update_url: String,
+    /// HTTP endpoint for address append proofs.
     pub address_append_url: String,
+    /// Optional API key or bearer token for prover authentication.
     pub api_key: Option<String>,
+    /// Interval between polling attempts while waiting for proof completion.
     pub polling_interval: Duration,
+    /// Maximum time to wait for a proof before giving up.
     pub max_wait_time: Duration,
 }

This aligns the struct with the documented prover endpoints and makes its usage self-explanatory.
(past nit about missing docs on ProverConfig is still applicable; this is the same request, extended with the newer CLI context from the learnings)


32-42: Clarify eligibility sentinel semantics and make the “best-effort” send path intentional.

Two related points around the new eligibility logic:

  1. Implicit sentinel for forester_eligibility_end_slot:
    Using 0 to mean “no forester-specific eligibility; fall back to epoch_phases.active.end” is fine, but it’s implicit. A small comment or named constant would make this much clearer:

-const SLOTS_STOP_THRESHOLD: u64 = 1;
+const SLOTS_STOP_THRESHOLD: u64 = 1;
+/// Sentinel meaning "no forester-specific eligibility override"; use epoch active end.
+const NO_FORESTER_ELIGIBILITY_OVERRIDE: u64 = 0;
...

  • let forester_end = context
  •    .forester_eligibility_end_slot
    
  •    .load(Ordering::Acquire);
    
  • let eligibility_end_slot = if forester_end > 0 {
  • let forester_end = context
  •    .forester_eligibility_end_slot
    
  •    .load(Ordering::Acquire);
    
  • let eligibility_end_slot = if forester_end > NO_FORESTER_ELIGIBILITY_OVERRIDE {
    forester_end
    } else {
    context.epoch_phases.active.end
    };

Same pattern can be applied in `send_transaction_batch`.

2. **Best-effort send is currently a no-op in practice:**  
In `process_stream`, when `slots_remaining < SLOTS_STOP_THRESHOLD`, you:

- Log and
- Call `send_transaction_batch(...)` in a “best-effort” fashion, then `break`.

But `send_transaction_batch` recomputes the same `slots_remaining` using the same `SLOTS_STOP_THRESHOLD` and immediately returns `ForesterError::NotInActivePhase` when this condition holds. That means the best-effort call can never actually send a transaction; it will always be rejected by the inner check.

To make this path intentional and easier to reason about, consider one of:

- **Option A:** Let `send_transaction_batch` own the stop decision and remove the explicit slot check in `process_stream`, breaking out when you see `ForesterError::NotInActivePhase`.  
- **Option B:** Use two clearly named thresholds, e.g. `STREAM_STOP_MARGIN` (higher) and `SEND_STOP_MARGIN` (lower), and document that the “best-effort” send uses the stricter margin so it can still succeed in a narrow window.

Either way, the goal is to avoid a code path that looks like it might send “one last batch” but can never actually do so under the current thresholds. The use of `Ordering::Acquire` on the atomic loads is good and matches the previous concurrency guidance.  




Also applies to: 129-144, 198-228, 235-241

</blockquote></details>
<details>
<summary>forester/src/processor/v2/state/supervisor.rs (7)</summary><blockquote>

`461-461`: **Same redundant calculation as in `build_append_job`.**

The `hashchain_idx` calculation can be simplified to `batch_idx` for the same reason as in the append case.




```diff
-        let hashchain_idx = start / self.zkp_batch_size as usize;
+        let hashchain_idx = batch_idx;

126-129: Use Ordering::Release for proper synchronization semantics.

The eligibility end slot is loaded with Ordering::Acquire elsewhere in the codebase. To establish proper happens-before visibility guarantees, the store should use Ordering::Release rather than Relaxed.

         self.context
             .forester_eligibility_end_slot
-            .store(msg.end_slot, std::sync::atomic::Ordering::Relaxed);
+            .store(msg.end_slot, std::sync::atomic::Ordering::Release);

205-212: TxSender receives stale root at spawn time.

TxSender::spawn is called at line 205 with self.current_root, which is still the initial value [0u8; 32] at this point. The actual root from the indexer is only fetched and assigned at lines 314 and 355 inside enqueue_batches, which runs after the spawn at line 212.

While last_seen_root in TxSender is primarily used for logging, this creates semantic confusion and could mislead debugging. The supervisor's current_root is updated correctly before jobs are sent, so the functional impact is minimal.

Consider either:

  1. Accepting that the initial logged root will be zero (add a comment explaining this)
  2. Moving the root update logic before TxSender spawn (more complex refactoring)

409-409: Simplify hashchain_idx calculation.

Since start = batch_idx * zkp_batch_size (from the calling loop at line 335), the division start / self.zkp_batch_size as usize mathematically equals batch_idx. Using batch_idx directly would be clearer and avoid the division operation.

-        let hashchain_idx = start / self.zkp_batch_size as usize;
+        let hashchain_idx = batch_idx;

133-135: Consider direct field access instead of trivial accessor.

The zkp_batch_size() method simply returns self.zkp_batch_size without any transformation. Internal methods could access the field directly to reduce indirection.

-    fn zkp_batch_size(&self) -> u64 {
-        self.zkp_batch_size
-    }

Then replace calls like self.zkp_batch_size() with self.zkp_batch_size throughout the impl block.


429-429: Use checked conversion instead of lossy cast to u32.

Converting u64 leaf indices to u32 using as can silently truncate large values. While tree heights are bounded (typically ≤32, giving max index ~4B, within u32), defensive coding suggests using try_from with explicit error handling.

-        let start_index = leaf_indices.first().copied().unwrap_or(0) as u32;
+        let start_index = u32::try_from(leaf_indices.first().copied().unwrap_or(0))
+            .map_err(|_| anyhow!("Leaf index exceeds u32::MAX"))?;

Alternatively, document the tree height constraint with a comment justifying the cast safety.


487-487: Use checked conversion for path_indices mapping.

The .map(|idx| *idx as u32) pattern performs a lossy cast that can silently truncate values exceeding u32::MAX. Apply the same defensive pattern as suggested for build_append_job.

-        let path_indices: Vec<u32> = leaf_indices.iter().map(|idx| *idx as u32).collect();
+        let path_indices: Vec<u32> = leaf_indices
+            .iter()
+            .map(|idx| u32::try_from(*idx).map_err(|_| anyhow!("Leaf index exceeds u32::MAX")))
+            .collect::<crate::Result<Vec<_>>>()?;

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

♻️ Duplicate comments (4)
forester/src/processor/v2/common.rs (1)

34-42: Add documentation for ProverConfig fields.

This struct was flagged in a previous review for missing documentation. Adding doc comments would clarify the purpose of each URL endpoint and timing parameter, especially for developers unfamiliar with the prover integration.

forester/src/processor/v2/state/supervisor.rs (3)

126-129: Use Ordering::Release to pair with Acquire loads.

The corresponding load in common.rs uses Ordering::Acquire. For proper happens-before semantics, this store should use Ordering::Release:

         self.context
             .forester_eligibility_end_slot
-            .store(msg.end_slot, std::sync::atomic::Ordering::Relaxed);
+            .store(msg.end_slot, std::sync::atomic::Ordering::Release);

With Relaxed store and Acquire load, you get atomicity but not guaranteed visibility ordering across threads.


429-429: Lossy cast from u64 to u32 - safe for state trees but consider defensive validation.

This cast is safe for state trees (height ≤32, max index fits u32), but using as for potentially lossy conversions without validation is fragile if code is refactored to handle larger trees.

Consider adding a comment or using try_from for defensive coding:

// Safe: state tree height ≤32 guarantees indices fit u32
let start_index = leaf_indices.first().copied().unwrap_or(0) as u32;

409-409: Consider simplifying hashchain_idx calculation.

Since start = batch_idx * zkp_batch_size, the expression start / self.zkp_batch_size simplifies to just batch_idx. While mathematically correct, the current form adds unnecessary indirection.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb99b50 and 4b9614c.

📒 Files selected for processing (3)
  • forester/package.json (1 hunks)
  • forester/src/processor/v2/common.rs (10 hunks)
  • forester/src/processor/v2/state/supervisor.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (102)
📓 Common learnings
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_input_queue method for batch nullify operations on StateV2 trees. The method must verify ZKP proving correctness of: old_root + queue nullifiers → new_root, update tree root, increment tree sequence_number, increment tree nullifier_next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount for state trees with integrated input queue (for nullifiers) and separate BatchedQueueAccount for output operations
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Tree updates from input queue must use update_tree_from_input_queue function for state trees and update_tree_from_address_queue for address trees with ZKP verification
📚 Learning: 2025-11-24T18:03:13.950Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:03:13.950Z
Learning: Forester end-to-end tests should be run with `TEST_MODE=local cargo test --package forester e2e_test`

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/**/*e2e*.rs : Test environment variables should use `TEST_MODE` to specify 'local' or 'devnet' mode (default: devnet)

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/**/*e2e*.rs : Test feature flags `TEST_V1_STATE`, `TEST_V2_STATE`, `TEST_V1_ADDRESS`, and `TEST_V2_ADDRESS` should default to `true` and control which test scenarios run

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*prover*.rs : Prover V2 endpoints should be configurable via `--prover-append-url`, `--prover-update-url`, `--prover-address-append-url`, and `--prover-api-key` parameters

Applied to files:

  • forester/package.json
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/**/*e2e*.rs : Devnet mode tests require `PHOTON_RPC_URL`, `PHOTON_WSS_RPC_URL`, `PHOTON_INDEXER_URL`, `PHOTON_PROVER_URL`, and `PHOTON_API_KEY` environment variables

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:03:13.950Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:03:13.950Z
Learning: Set LIGHT_PROTOCOL_VERSION environment variable to V1 or V2 when running JavaScript/TypeScript tests

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:00:48.449Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/docs/SOLANA_RENT.md:0-0
Timestamp: 2025-11-24T18:00:48.449Z
Learning: Applies to program-libs/compressible/docs/**/*.rs : In test environments, mock Solana rent exemption instead of calling the actual Rent sysvar, using a hardcoded value like 2_282_880 lamports

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:02:25.027Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:25.027Z
Learning: Supporting library unit tests must be run using: cargo test -p light-program-test, cargo test -p light-client, cargo test -p light-sparse-merkle-tree, cargo test -p light-compressed-token-types, and cargo test -p light-compressed-token-sdk

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:01:30.012Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:30.012Z
Learning: Run registry tests using `cargo test-sbf -p registry-test` to test protocol configuration and forester registration

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:02:25.027Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:25.027Z
Learning: SDK core library unit tests must be run with: cargo test -p light-sdk-macros, cargo test -p light-sdk-macros --all-features, cargo test -p light-sdk, and cargo test -p light-sdk --all-features

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:01:30.012Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:30.012Z
Learning: Run batched merkle tree simulation tests using `RUST_LOG=light_prover_client=debug cargo test -p batched-merkle-tree-test -- --test test_simulate_transactions` to enable logging

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:01:30.012Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:30.012Z
Learning: Run E2E extended tests after building the small compressed token program using `pnpm --filter lightprotocol/programs run build-compressed-token-small` followed by `cargo test-sbf -p e2e-test -- --test test_10_all`

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:02:25.027Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:25.027Z
Learning: Token SDK tests must run with command: cargo test-sbf -p sdk-token-test

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T18:02:25.027Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:25.027Z
Learning: Anchor SDK Rust tests must run with command: cargo test-sbf -p sdk-anchor-test

Applied to files:

  • forester/package.json
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_input_queue method for batch nullify operations on StateV2 trees. The method must verify ZKP proving correctness of: old_root + queue nullifiers → new_root, update tree root, increment tree sequence_number, increment tree nullifier_next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_address_queue method for batch address append operations on AddressV2 trees. The method must verify ZKP proving correctness of: old_root + queue addresses → new_root using indexed Merkle tree insertion, update tree root, increment tree sequence_number, increment tree next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize a state Merkle tree with a `TreeType::StateV2` (4) tree type, storing tree roots, root history, and integrated input queue (bloom filters + hash chains for nullifiers) in the `BatchedMerkleTreeAccount` with discriminator b`BatchMta` [66, 97, 116, 99, 104, 77, 116, 97]

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount for state trees with integrated input queue (for nullifiers) and separate BatchedQueueAccount for output operations

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `src/merkle_tree.rs`, implement `BatchedMerkleTreeAccount::update_tree_from_output_queue_account` method that batch appends values from output queue to state Merkle tree with ZKP verification, verifying proof of old_root + queue_values → new_root

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/initialize_state_tree.rs : State tree initialization must create two Solana accounts: BatchedMerkleTreeAccount with integrated input queue and separate BatchedQueueAccount

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Validate queue type is `OUTPUT_STATE_QUEUE_TYPE_V2` when deserializing `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Set output queue account discriminator to b`queueacc` (8 bytes) and initialize queue metadata with QueueType::OutputStateV2

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize an output queue account as `BatchedQueueAccount` with `QueueType::OutputStateV2`, temporary storage for compressed account hashes before tree insertion with immediate spending capability via proof-by-index, using discriminator b`queueacc` [113, 117, 101, 117, 101, 97, 99, 99]

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Tree updates from input queue must use update_tree_from_input_queue function for state trees and update_tree_from_address_queue for address trees with ZKP verification

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*{transaction,batch}*.rs : Transaction V1 processing should configure `--max-concurrent-sends 50`, `--legacy-ixs-per-tx 1`, `--transaction-max-concurrent-batches 20`, `--cu-limit 1000000`, and `--enable-priority-fees false` by default

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Validate bloom_filter_capacity is divisible by 8 in `src/initialize_address_tree.rs`. Capacity must be >= batch_size * 8.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*{pool,connection,rpc}*.rs : RPC pool settings should use `--rpc-pool-size 10` (default), `--rpc-pool-connection-timeout-secs 15`, and `--rpc-pool-idle-timeout-secs 300` for optimal connection pooling

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/{merkle_tree,merkle_tree_metadata}.rs : Trees must maintain a cyclic buffer of recent roots (default: 200) enabling validity proofs for recently spent compressed accounts

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Validate root_history_capacity is at least equal to (input_queue_batch_size / input_queue_zkp_batch_size) in `src/initialize_address_tree.rs`. This ensures sufficient space for roots generated by address queue operations.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Validate that ZKP batch sizes must be 10 or 500 (only supported circuit sizes)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : ZKP batch sizes for address trees must be 10 or 250 in `src/initialize_address_tree.rs`. Only these circuit sizes are supported for address trees.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Check `tree_capacity` (2^height) against new insertions to prevent overflow in `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Define bloom filter configuration for input queue: bloom_filter_capacity (u64, default batch_size * 8) and bloom_filter_num_iters (u64, default 3 for test and 10 for production)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Error handling must use BatchedMerkleTreeError enum from errors.rs with u32 error codes in the 14301-14312 range

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch nullify operations must check that tree type is TreeType::StateV2 before processing, verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch address append operations must check that tree type is TreeType::AddressV2 before processing, verify tree capacity constraint (tree.next_index + zkp_batch_size <= tree_capacity), verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, when batch state is `Inserted`, verify bloom filter is zeroed before clearing hash chain stores and transitioning to `Fill` state

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Verify tree capacity constraint before tree update: `tree.next_index + zkp_batch_size <= tree_capacity`; error with `TreeIsFull` (14310) if violated

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : After inserting an address into the batch, check if `num_inserted_elements == batch_size`. If true, transition batch state from `Fill` to `Full`, increment `currently_processing_batch_index` to switch to the other batch, and update `pending_batch_index` to mark this batch ready for tree update.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Transition batch state to `Inserted` when all ZKP batches are complete and increment `pending_batch_index` to switch to other batch

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, verify tree type is `TreeType::StateV2` before allowing nullifier insertion; reject address trees

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch must have ready ZKP batches for insertion: verify `num_full_zkp_batches > num_inserted_zkp_batches`; error with `BatchNotReady` (14301) if not ready

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Zero overlapping roots in cyclic buffer by starting at `oldest_root_index = root_history.first_index()`, zeroing `num_remaining_roots` consecutive roots with wrapping, and verifying ended at `first_safe_root_index = batch.root_index + 1`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : When all ZKP batches of a batch are inserted, set batch `sequence_number = tree_sequence_number + root_history_capacity` (threshold when root at root_index is overwritten) and set `root_index` to identify root that must not exist when bloom filter is zeroed

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Root history is accessed via `root_history.last()` to retrieve the latest root. Validity proofs pick roots by index from root history since proofs need a static root value to verify against

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : State trees must initialize with zero bytes root for the specified height and have a separate BatchedQueueAccount for output operations

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Overlapping roots in history must be zeroed when clearing bloom filters to prevent inclusion proofs of nullified values

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/prover/server/prover/v2/batch_append_circuit.go : Batch append circuit implementation at `prover/server/prover/v2/batch_append_circuit.go` must verify that batch append is correct by: (1) verifying public input hash matches Hash([old_root, new_root, leaves_hash_chain, start_index]), (2) verifying leaves_hash_chain matches hash chain of all new leaves, (3) for each position checking if old_leaf is zero (insert new leaf) or non-zero (keep old nullifier), (4) providing Merkle proof for old_leaf and computing root update, (5) verifying final computed root equals new_root

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : After successful ZKP verification, increment tree `next_index` by `zkp_batch_size` (represents leaf index for next insertion)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Tree updates must require zero-knowledge proofs proving batch operation correctness with public inputs: old root, new root, hash chain, and for appends: start_index (output queue) or next_index (address queue)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/prover/server/prover/v2/batch_address_append_circuit.go : Batch address append ZKP verification must validate that public_input_hash equals Hash([old_root, new_root, leaves_hash_chain, start_index]), for each address in batch perform two Merkle updates (low leaf update to maintain sorted linked list + new leaf insertion at start_index + i), verify new address fits between low_value and low_next_value, and assert new leaf position must be empty (old_leaf = 0).

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Always increment `queue_next_index` by 1 after successfully inserting an address. This value serves as a sequence number for indexers to track address insertion order.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/prover/server/prover/v2/batch_append_circuit.go : Batch append circuit must handle nullifiers in output queue by checking if position contains non-zero old_leaf (nullifier already inserted) and keeping old leaf instead of overwriting, since input and output queues are independent

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `insert_into_current_queue_batch` helper, handle batch state transitions: if state is `Fill`, proceed; if state is `Inserted`, verify bloom filter is zeroed, clear hash chain stores, transition to `Fill`, and reset batch metadata; if state is `Full`, return `BatchedMerkleTreeError::BatchNotReady` (error code 14301).

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Applies to programs/registry/src/lib.rs : In wrapper instruction handler in `lib.rs`, load account metadata, determine work units, call `check_forester()`, then call the processing function

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : BatchedMerkleTreeAccount must be of type `TreeType::StateV2` when updating tree from output queue

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Mark ZKP batch as inserted by calling `mark_as_inserted_in_merkle_tree` on queue batch to increment `num_inserted_zkp_batches`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Implement two hash chain stores (`[ZeroCopyVecU64<[u8; 32]>; 2]`), one per batch, each with `batch_size / zkp_batch_size` hash chains storing Poseidon hashes of ZKP batches in `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Each ZKP batch has a hash chain storing the Poseidon hash of all values in that ZKP batch, used as public inputs for ZKP verification

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Calculate overlapping roots for zeroing using: overlapping if `batch.sequence_number > current_tree.sequence_number`; compute `num_remaining_roots = batch.sequence_number - current_tree.sequence_number`; verify `num_remaining_roots < root_history.len()` and error with `CannotZeroCompleteRootHistory` (14313) if violated

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Tree height must be fixed at 40 for address trees in `src/initialize_address_tree.rs`. Validate that height equals 40.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Define tree configuration parameters in `InitStateTreeAccountsInstructionData` struct: height (u32, default 32), index (u64), and root_history_capacity (u32, default 200)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Set tree_capacity = 2^height in output queue metadata

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : `InitAddressTreeAccountsInstructionData` struct in `src/initialize_address_tree.rs` must include: height (u32, default 40), index (u64), root_history_capacity (u32, default 200), input_queue_batch_size (u64, default 15,000), input_queue_zkp_batch_size (u64, default 250), bloom_filter_capacity (u64, default batch_size * 8), bloom_filter_num_iters (u64, default 3 for test/10 for production), program_owner (Option<Pubkey>), forester (Option<Pubkey>), rollover_threshold (Option<u64>, default 95%), network_fee (Option<u64>, default 10,000 lamports), and close_threshold (Option<u64>).

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Compute and store hashed pubkeys by hashing and truncating to 31 bytes for bn254 field compatibility in both queue and tree accounts

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Initialize next_index to 1 (not 0) in BatchedMerkleTreeAccount in `src/initialize_address_tree.rs`. Index 0 contains pre-initialized sentinel element.

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:54:20.982Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/zero-copy-derive/README.md:0-0
Timestamp: 2025-11-24T17:54:20.982Z
Learning: Applies to program-libs/zero-copy-derive/**/*.rs : Use Option<T> for optional values in zero-copy structs; Option<u16>, Option<u32>, and Option<u64> are optimized

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Verify ZKP batch append proof using `verify_batch_append_with_proofs(zkp_batch_size, public_input_hash, proof)` and error with `ProofVerificationFailed` (13006) if verification fails

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : State tree nullifier insertion must use the BatchedMerkleTreeAccount::insert_nullifier_into_queue method

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize output queue value vectors (2 vectors, one per batch with capacity = batch_size each) and hash chain stores (2 vectors with capacity = batch_size / zkp_batch_size each)

Applied to files:

  • forester/src/processor/v2/state/supervisor.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree_metadata.rs : Define `BatchedMerkleTreeMetadata` structure in `src/merkle_tree_metadata.rs`. Include tree_type, associated_queue, rollover_fee calculation, access_metadata (owner, program_owner, forester), rollover_metadata (index, rollover_fee, rollover_threshold, network_fee, close_threshold, additional_bytes), hashed_pubkey, next_index, and sequence_number fields.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Zero out input queue bloom filter when all conditions are met: (1) current batch is ≥50% full (`num_inserted_elements >= batch_size / 2`), (2) current batch NOT in `Inserted` state, (3) previous batch in `Inserted` state, (4) previous batch bloom filter not already zeroed, (5) at least one tree update since batch completion (`batch.sequence_number != current_tree.sequence_number`)

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, transition batch state from `Fill` to `Full` when `num_inserted_elements == batch_size`, and switch `currently_processing_batch_index` to the other batch

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : When attempting to reuse a batch in the `Inserted` state before its bloom filter has been zeroed by the forester, return `BatchedMerkleTreeError::BloomFilterNotZeroed` (error code 14312).

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize root history as a cyclic buffer with capacity = root_history_capacity, with first entry = zero bytes for tree height

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : After successful ZKP verification, increment tree `sequence_number` by 1 (tracks number of tree updates) and append `new_root` to `root_history` cyclic buffer

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Initialize root history as cyclic buffer with capacity=root_history_capacity and first entry = `ADDRESS_TREE_INIT_ROOT_40` in `src/initialize_address_tree.rs`.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Validate that root_history_capacity >= (output_queue_batch_size / output_queue_zkp_batch_size) + (input_queue_batch_size / input_queue_zkp_batch_size) to ensure sufficient space for roots generated by both input and output operations

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : When deserializing BatchedMerkleTreeAccount in client code, use `BatchedMerkleTreeAccount::state_from_bytes()` for state trees and `BatchedMerkleTreeAccount::address_from_bytes()` for address trees

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Account validation for address trees must check: (1) account ownership by Light account compression program, (2) account discriminator is `BatchMta`, and (3) tree type is `ADDRESS_MERKLE_TREE_TYPE_V2` (5)

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:53.312Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/TREE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:53.312Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Account validation for state trees must check: (1) account ownership by Light account compression program, (2) account discriminator is `BatchMta`, and (3) tree type is `STATE_MERKLE_TREE_TYPE_V2` (4)

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Define access control parameters: program_owner (Option<Pubkey>), forester (Option<Pubkey>) for non-Light foresters, and owner (Pubkey passed as function parameter)

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Use zero-copy deserialization for all `BatchedQueueAccount` operations

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Use two value vectors (`[ZeroCopyVecU64<[u8; 32]>; 2]`), one per batch, to store compressed account hashes in `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Store `BatchedQueueAccount` layout and `BatchedQueueMetadata` in src/queue.rs

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Prover server (prover/server/) must generate ZK proofs for batch operations (append, nullify, address append)

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:24.369Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:24.369Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : When a batch is in `Inserted` state, clear the value vec and hash chain stores, advance batch state to `Fill`, and reset batch metadata before allowing new insertions

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:24.369Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:24.369Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Transition batch state from `Fill` to `Full` and increment currently_processing_batch_index when num_inserted_elements reaches batch_size in the output queue

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, reject insertions when batch is in `Full` state with error code 14301

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_address_into_queue`, verify that the tree type is `TreeType::AddressV2` before proceeding with address insertion. Reject state trees with `MerkleTreeMetadataError::InvalidTreeType`.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : When inserting an address into the current batch, call the bloom filter's insert method which must: insert the address into the bloom filter, perform a non-inclusion check across all bloom filters (returning `BatchedMerkleTreeError::NonInclusionCheckFailed` error code 14311 if address already exists), update the hash chain with `Poseidon(prev_hash_chain, address)`, and increment the batch's element counter.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Address tree address insertion must use the BatchedMerkleTreeAccount::insert_address_into_queue method

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Set tree_type to `TreeType::AddressV2` (5) and associated_queue to Pubkey::default() for address trees in `src/initialize_address_tree.rs`. Address trees have no separate output queue - the address queue is integrated into the tree account.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : In `src/queue.rs`, define BatchedQueueAccount layout and implement `mark_as_inserted_in_merkle_tree` method to increment `num_inserted_zkp_batches` and transition batch state to `Inserted` when all ZKP batches are complete

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : When all ZKP batches for a batch are inserted, set batch sequence_number to tree_sequence_number + root_history_capacity and store root_index to identify the root that must not exist when bloom filter is zeroed.

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Create public input hash as `Hash([old_root, new_root, leaves_hash_chain, start_index])` using old_root from tree root history and start_index from tree next_index

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: In client code, deserialize output queues using `BatchedQueueAccount::output_from_bytes(&mut account_data)?` from the `light_batched_merkle_tree::queue` module

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : In Solana programs, deserialize output queues using `BatchedQueueAccount::output_from_account_info(account_info)?` from the `light_batched_merkle_tree::queue` module

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Use `get_output_queue_account_size` function from src/queue.rs to calculate queue account size based on output_queue_batch_size and output_queue_zkp_batch_size

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Validate account ownership by Light account compression program using `check_owner` from `light-account-checks` when deserializing `BatchedQueueAccount` with `output_from_account_info`

Applied to files:

  • forester/src/processor/v2/common.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Validate account discriminator is `queueacc` (bytes: [113, 117, 101, 117, 101, 97, 99, 99]) using `check_discriminator` from `light-account-checks` when deserializing `BatchedQueueAccount`

Applied to files:

  • forester/src/processor/v2/common.rs
🧬 Code graph analysis (1)
forester/src/processor/v2/state/supervisor.rs (2)
forester/src/processor/v2/state/helpers.rs (2)
  • fetch_batches (34-77)
  • fetch_zkp_batch_size (12-32)
forester/src/processor/v2/state/tx_sender.rs (2)
  • spawn (37-52)
  • e (110-110)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test batched-merkle-tree-simulate

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

♻️ Duplicate comments (1)
forester/src/epoch_manager.rs (1)

1765-1821: LGTM: Good consolidation, with minor optimization opportunity.

The build_batch_context helper successfully eliminates the duplication flagged in past reviews. The prover configuration properly reads from config with sensible defaults.

Minor observation: Line 1774 defaults eligibility_end to 0 when None is provided. While this is acceptable for long-lived supervisors (which receive UpdateEligibility messages later), consider documenting this behavior in a comment for clarity.

Optional refinement from past reviews: The default_prover_url (line 1773) could be extracted as a module-level constant for easier maintenance:

const DEFAULT_PROVER_URL: &str = "http://127.0.0.1:3001";
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00cadc7 and 162ea99.

⛔ Files ignored due to path filters (1)
  • forester-utils/src/forester_epoch.rs is excluded by none and included by none
📒 Files selected for processing (1)
  • forester/src/epoch_manager.rs (21 hunks)
🧰 Additional context used
🧠 Learnings (43)
📓 Common learnings
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_input_queue method for batch nullify operations on StateV2 trees. The method must verify ZKP proving correctness of: old_root + queue nullifiers → new_root, update tree root, increment tree sequence_number, increment tree nullifier_next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount for state trees with integrated input queue (for nullifiers) and separate BatchedQueueAccount for output operations
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Tree updates from input queue must use update_tree_from_input_queue function for state trees and update_tree_from_address_queue for address trees with ZKP verification
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize a state Merkle tree with a `TreeType::StateV2` (4) tree type, storing tree roots, root history, and integrated input queue (bloom filters + hash chains for nullifiers) in the `BatchedMerkleTreeAccount` with discriminator b`BatchMta` [66, 97, 116, 99, 104, 77, 116, 97]

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/initialize_state_tree.rs : State tree initialization must create two Solana accounts: BatchedMerkleTreeAccount with integrated input queue and separate BatchedQueueAccount

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_input_queue method for batch nullify operations on StateV2 trees. The method must verify ZKP proving correctness of: old_root + queue nullifiers → new_root, update tree root, increment tree sequence_number, increment tree nullifier_next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In src/merkle_tree.rs, implement BatchedMerkleTreeAccount::update_tree_from_address_queue method for batch address append operations on AddressV2 trees. The method must verify ZKP proving correctness of: old_root + queue addresses → new_root using indexed Merkle tree insertion, update tree root, increment tree sequence_number, increment tree next_index by zkp_batch_size, mark ZKP batch as inserted, transition batch state to Inserted when all ZKP batches complete, and zero out bloom filter when current batch is 50% inserted.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : BatchedMerkleTreeAccount must be of type `TreeType::StateV2` when updating tree from output queue

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Define access control parameters: program_owner (Option<Pubkey>), forester (Option<Pubkey>) for non-Light foresters, and owner (Pubkey passed as function parameter)

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount for state trees with integrated input queue (for nullifiers) and separate BatchedQueueAccount for output operations

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch nullify operations must check that tree type is TreeType::StateV2 before processing, verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Verify queue and tree association by matching pubkeys; error with `MerkleTreeAndQueueNotAssociated` (14001) if they don't match

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Tree updates from input queue must use update_tree_from_input_queue function for state trees and update_tree_from_address_queue for address trees with ZKP verification

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_address_into_queue`, verify that the tree type is `TreeType::AddressV2` before proceeding with address insertion. Reject state trees with `MerkleTreeMetadataError::InvalidTreeType`.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : After inserting an address into the batch, check if `num_inserted_elements == batch_size`. If true, transition batch state from `Fill` to `Full`, increment `currently_processing_batch_index` to switch to the other batch, and update `pending_batch_index` to mark this batch ready for tree update.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:10.392Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:10.392Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Batch address append operations must check that tree type is TreeType::AddressV2 before processing, verify tree capacity constraint (tree.next_index + zkp_batch_size <= tree_capacity), verify batch has ready ZKP batches (num_full_zkp_batches > num_inserted_zkp_batches), and reject if batch is already in Inserted state.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Use BatchedMerkleTreeAccount with integrated input queue (for addresses) for address trees without a separate output queue account

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Initialize an output queue account as `BatchedQueueAccount` with `QueueType::OutputStateV2`, temporary storage for compressed account hashes before tree insertion with immediate spending capability via proof-by-index, using discriminator b`queueacc` [113, 117, 101, 117, 101, 97, 99, 99]

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Compute and store hashed pubkeys by hashing and truncating to 31 bytes for bn254 field compatibility in both queue and tree accounts

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/**/*prover*.rs : Prover V2 endpoints should be configurable via `--prover-append-url`, `--prover-update-url`, `--prover-address-append-url`, and `--prover-api-key` parameters

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: When forester PDA is present, `check_forester()` must validate epoch registration and eligibility, track work, and require network fee; when absent, validate that authority matches the tree's designated forester (for private trees)

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Applies to programs/registry/src/lib.rs : In wrapper instruction handler in `lib.rs`, load account metadata, determine work units, call `check_forester()`, then call the processing function

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Validate queue type is `OUTPUT_STATE_QUEUE_TYPE_V2` when deserializing `BatchedQueueAccount`

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Store `BatchedQueueAccount` layout and `BatchedQueueMetadata` in src/queue.rs

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/queue.rs : Output queue insertion must use BatchedQueueAccount::insert_into_current_batch method

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Implement two hash chain stores (`[ZeroCopyVecU64<[u8; 32]>; 2]`), one per batch, each with `batch_size / zkp_batch_size` hash chains storing Poseidon hashes of ZKP batches in `BatchedQueueAccount`

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Use two value vectors (`[ZeroCopyVecU64<[u8; 32]>; 2]`), one per batch, to store compressed account hashes in `BatchedQueueAccount`

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : In `src/queue.rs`, define BatchedQueueAccount layout and implement `mark_as_inserted_in_merkle_tree` method to increment `num_inserted_zkp_batches` and transition batch state to `Inserted` when all ZKP batches are complete

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Use zero-copy deserialization for all `BatchedQueueAccount` operations

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:24.369Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:24.369Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : When a batch is in `Inserted` state, clear the value vec and hash chain stores, advance batch state to `Fill`, and reset batch metadata before allowing new insertions

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Call `check_forester()` to validate authority and track work performed, passing account metadata, authority key, target account key, forester PDA, and work units

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:53:53.971Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: forester/README.md:0-0
Timestamp: 2025-11-24T17:53:53.971Z
Learning: Applies to forester/src/main.rs : Required configuration must include: `--rpc-url`, `--ws-rpc-url`, `--indexer-url`, `--prover-url`, `--payer`, and `--derivation` parameters

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Wrapper instruction Account context must include: optional `registered_forester_pda` (mutable), `authority` signer, `cpi_authority` PDA with seeds, `registered_program_pda`, `account_compression_program`, `log_wrapper` for events, and `target_account` (mutable)

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T18:01:14.087Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:01:14.087Z
Learning: Applies to program-libs/compressible/**/*.rs : Implement state validation methods (`validate_active`, `validate_not_inactive`) for CompressibleConfig account state verification

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Set output queue account discriminator to b`queueacc` (8 bytes) and initialize queue metadata with QueueType::OutputStateV2

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:02.558Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_ADDRESS_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:02.558Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : Always increment `queue_next_index` by 1 after successfully inserting an address. This value serves as a sequence number for indexers to track address insertion order.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:14.561Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_INPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:14.561Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `BatchedMerkleTreeAccount::insert_nullifier_into_queue`, verify tree type is `TreeType::StateV2` before allowing nullifier insertion; reject address trees

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:58:35.079Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/UPDATE_FROM_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:58:35.079Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/merkle_tree.rs : In `src/merkle_tree.rs`, implement `BatchedMerkleTreeAccount::update_tree_from_output_queue_account` method that batch appends values from output queue to state Merkle tree with ZKP verification, verifying proof of old_root + queue_values → new_root

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:24.369Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:24.369Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Insert Into Output Queue: Inserts a compressed account hash into the output queue's currently processing batch by calling `BatchedQueueAccount::insert_into_current_batch` with hash_chain_value and current_slot parameters, updating value vec, hash chain, and managing batch state transitions in src/queue.rs

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:20.711Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_ADDRESS_TREE.md:0-0
Timestamp: 2025-11-24T17:56:20.711Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_address_tree.rs : Set tree_type to `TreeType::AddressV2` (5) and associated_queue to Pubkey::default() for address trees in `src/initialize_address_tree.rs`. Address trees have no separate output queue - the address queue is integrated into the tree account.

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T18:00:48.449Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/docs/SOLANA_RENT.md:0-0
Timestamp: 2025-11-24T18:00:48.449Z
Learning: Use epoch-based accounting (432,000 slots ≈ 2.5 days) instead of continuous time for Light Protocol rent collection

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Use `check_account_balance_is_rent_exempt` function from `light-account-checks` to verify rent exemption for both queue_account and merkle_tree_account during initialization

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:39.230Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/QUEUE_ACCOUNT.md:0-0
Timestamp: 2025-11-24T17:57:39.230Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Check `tree_capacity` (2^height) against new insertions to prevent overflow in `BatchedQueueAccount`

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:57:24.369Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INSERT_OUTPUT_QUEUE.md:0-0
Timestamp: 2025-11-24T17:57:24.369Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/queue.rs : Before inserting into the output queue, validate that the tree is not full by checking that next_index < tree_capacity

Applied to files:

  • forester/src/epoch_manager.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/merkle_tree.rs : Tree updates from output queue must use BatchedMerkleTreeAccount::update_tree_from_output_queue_account method with ZKP verification

Applied to files:

  • forester/src/epoch_manager.rs
🧬 Code graph analysis (1)
forester/src/epoch_manager.rs (3)
forester/src/processor/v2/mod.rs (1)
  • process_batched_operations (20-36)
forester/src/processor/v2/common.rs (2)
  • new (264-266)
  • e (173-173)
forester/src/processor/v2/state/tx_sender.rs (2)
  • spawn (37-52)
  • e (110-110)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test batched-merkle-tree-simulate
  • GitHub Check: Test program-libs-fast
🔇 Additional comments (9)
forester/src/epoch_manager.rs (9)

1-73: LGTM: Clean infrastructure additions.

The new imports and StateSupervisorMap type alias properly support the per-tree supervisor pattern. The type alias Arc<DashMap<Pubkey, (u64, ActorRef<...>)>> clearly expresses that each tree (by pubkey) maps to an epoch number and its supervisor actor reference, with thread-safe concurrent access via DashMap.


103-141: LGTM: Proper field additions with complete Clone implementation.

The authority and state_supervisors fields are appropriately typed and the Clone implementation correctly clones both Arc-wrapped values. The authority field eliminates repeated keypair access, and the supervisors map enables per-tree actor lifecycle management.


156-194: LGTM: Proper initialization of new fields.

The authority is initialized from config.payer_keypair.insecure_clone() (line 176) and state_supervisors starts as an empty DashMap (line 191). Both fields are correctly initialized for their intended usage patterns.


388-400: LGTM: Supervisor cleanup on epoch transition is correct.

The code properly kills all supervisor actors and clears the map when a new epoch is detected. Using .kill() ensures immediate termination, preventing stale supervisors from processing work in the new epoch. This is the right trade-off at epoch boundaries—any in-flight work that fails can be retried in the new epoch.


1187-1189: LGTM: Consecutive eligibility calculation is correct.

The code properly calculates consecutive_end by querying the tree schedule (line 1187-1188) and falls back to the current slot's end if unavailable (line 1189). This allows the V2 processor to understand if the forester has consecutive eligible slots, optimizing batch processing.


1265-1357: LGTM: V1 processing correctly adapted to new signature.

The log message now includes the epoch number (line 1266-1270) for better debugging context. The dispatch_tree_processing call (line 1317) correctly passes forester_slot_details.end_solana_slot as the consecutive_eligibility_end parameter—for V1 trees, this is simply the current slot's end since consecutive eligibility is a V2 concept.


1360-1502: LGTM: V2 processing correctly threads consecutive eligibility through the call chain.

The consecutive_eligibility_end parameter is properly added to the function signature (line 1371), logged for debugging (line 1375), and passed to dispatch_tree_processing (line 1443). This enables V2 trees to understand their eligibility window and batch work across consecutive slots efficiently.


1554-1587: LGTM: Clean dispatcher refactoring.

The signature change from forester_slot_details: &ForesterSlot to consecutive_eligibility_end: u64 (line 1561) appropriately simplifies the interface. The function now has 7 parameters, warranting the #[allow(clippy::too_many_arguments)] (line 1554), but this is acceptable for a dispatcher. V1 processing ignores the parameter while V2 processing correctly uses it (line 1582).


1871-1941: LGTM: Well-structured V2 processing with proper actor-based StateV2 and direct AddressV2 paths.

The StateV2 path correctly obtains or creates a long-lived supervisor actor (lines 1881-1883) and sends it eligibility (lines 1885-1897) and work messages (lines 1899-1914). The AddressV2 path builds a per-slot context with forester eligibility (lines 1920-1927) and processes directly (lines 1929-1931). Error messages include tree pubkeys for debugging (lines 1892-1895, 1909-1913).

Minor note: UpdateEligibility is sent on every call (line 1885) even if consecutive_eligibility_end hasn't changed. If this becomes a performance concern under high load, consider tracking the last-sent end_slot per tree to avoid redundant updates. However, the current approach is simpler and the message overhead is negligible for typical workloads.

Comment on lines +1823 to +1869
async fn get_or_create_state_supervisor(
&self,
epoch_info: &Epoch,
tree_accounts: &TreeAccounts,
) -> Result<ActorRef<v2::state::StateSupervisor<R>>> {
use dashmap::mapref::entry::Entry;

let entry = self.state_supervisors.entry(tree_accounts.merkle_tree);

match entry {
Entry::Occupied(mut occupied) => {
let (stored_epoch, supervisor_ref) = occupied.get();
if *stored_epoch == epoch_info.epoch {
Ok(supervisor_ref.clone())
} else {
info!(
"Removing stale StateSupervisor for tree {} (epoch {} -> {})",
tree_accounts.merkle_tree, *stored_epoch, epoch_info.epoch
);
// Don't pass forester_slot - StateSupervisor is long-lived across forester slots,
// so it should use the global active phase end for safety checks
let batch_context =
self.build_batch_context(epoch_info, tree_accounts, None, None, None);
let supervisor = v2::state::StateSupervisor::spawn(batch_context);
info!(
"Created StateSupervisor actor for tree {} (epoch {})",
tree_accounts.merkle_tree, epoch_info.epoch
);
occupied.insert((epoch_info.epoch, supervisor.clone()));
Ok(supervisor)
}
}
Entry::Vacant(vacant) => {
// Don't pass forester_slot - StateSupervisor is long-lived across forester slots,
// so it should use the global active phase end for safety checks
let batch_context =
self.build_batch_context(epoch_info, tree_accounts, None, None, None);
let supervisor = v2::state::StateSupervisor::spawn(batch_context);
info!(
"Created StateSupervisor actor for tree {} (epoch {})",
tree_accounts.merkle_tree, epoch_info.epoch
);
vacant.insert((epoch_info.epoch, supervisor.clone()));
Ok(supervisor)
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

LGTM: Race condition fixed with DashMap::entry, minor cleanup opportunity.

Using DashMap::entry (line 1830) removes the check-then-insert race condition from earlier reviews, ensuring only one StateSupervisor is spawned per tree/epoch pair. The comments (lines 1842-1843, 1856-1857) helpfully explain why forester_slot isn't passed—supervisors are long-lived across forester slots.

Minor observation: In the epoch-mismatch branch (lines 1838-1851), the code overwrites the stale supervisor without explicitly calling .kill() on it. In normal operation, monitor_epochs kills all supervisors on epoch bumps, so this should be rare. However, if this branch is reached (e.g., in tests or race conditions), the old actor could continue running without a map handle. Consider explicitly terminating the stale supervisor before insertion:

let old_supervisor = occupied.get().1.clone();
old_supervisor.kill();
occupied.insert((epoch_info.epoch, new_supervisor.clone()));
🤖 Prompt for AI Agents
In forester/src/epoch_manager.rs around lines 1823 to 1869 the epoch-mismatch
branch replaces a stale StateSupervisor in the DashMap without terminating the
old actor, which can leave the old supervisor running without a map handle;
before inserting the new supervisor, clone and call .kill() on the existing
supervisor reference (and await or handle the result if the kill is async) to
ensure the old actor is terminated, then insert the new (epoch, supervisor) pair
and optionally log the termination outcome for clarity.

@sergeytimoshin sergeytimoshin merged commit e1f7d11 into main Nov 27, 2025
43 checks passed
@sergeytimoshin sergeytimoshin deleted the sergey/forester-state-workers branch November 27, 2025 12:28
@coderabbitai coderabbitai bot mentioned this pull request Jan 9, 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.

2 participants