Skip to content

Conversation

@QuantumExplorer
Copy link
Member

@QuantumExplorer QuantumExplorer commented Dec 29, 2025

What was done?

New Query API

  • Added getRecentAddressBalanceChanges gRPC endpoint that returns address balance changes from a specified block height onwards
  • Returns both SetBalance (absolute balance after spending) and AddToBalance (credits added) operations per address per block

Address Balance Change Tracking

  • Added CreditOperation enum in DPP (SetCredits, AddToCredits) to represent how address balances are modified
  • Extended StateTransitionExecutionResult::SuccessfulExecution to include address_balance_changes map
  • Extended StateTransitionsProcessingResult to aggregate address balance changes across all state transitions in a block
  • Added add_address_balances_in_update() method with proper merging logic for combining operations (Set+Set, Set+Add, Add+Add, Add+Set)

Historical Storage

  • Added new SavedBlockTransactions root tree in GroveDB for storing historical data
  • Added AddressBalances subtree under SavedBlockTransactions to store per-block address balance changes
  • Implemented store_address_balances_for_block to serialize and store balance changes keyed by block height (big-endian for proper ordering)
  • Implemented fetch_recent_address_balance_changes and prove_recent_address_balance_changes for retrieval

Execution Event Updates

  • Added added_to_balance_outputs field to ExecutionEvent::Paid to track outputs from IdentityCreditTransferToAddresses
  • Updated execute_event to populate address_balances map during execution

Test Updates

  • Added comprehensive tests in address_tests.rs covering:
    • run_chain_address_withdrawal_transitions - withdrawal operations
    • run_chain_identity_credit_transfer_to_addresses - identity to address transfers
    • run_chain_all_address_transitions - comprehensive test with all 5 address state transition types
  • Updated existing tests to use new struct-style execution result variants

How Has This Been Tested?

  • All 9 address tests pass:
    • run_chain_address_transitions
    • run_chain_identity_to_addresses_transitions
    • run_chain_identity_create_from_addresses_transitions
    • run_chain_address_transitions_with_checkpoints
    • run_chain_address_transitions_with_checkpoints_stop_and_restart
    • run_chain_address_withdrawal_transitions
    • run_chain_identity_credit_transfer_to_addresses
    • run_chain_all_address_transitions
    • run_chain_address_transitions_with_proof_signature_verification

Tests verify:

  • Address balance changes are correctly recorded for all address-related state transitions
  • The query API returns correct SetBalance and AddToBalance operations
  • Balance changes from funding, transfers, withdrawals, and identity operations are all tracked

Breaking Changes

Yes, a new tree was introduced.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

  • New Features

    • New RPCs and SDK queries to fetch recent per-block address balance changes and compacted history, with optional provable responses and client-side proof verification.
    • Persistent per-block address balance tracking (set/add) and automatic compaction for longer-term lookups.
  • Chores

    • Versioning and configuration extended to support saved-block-transactions, storage, compaction, query and verification flows.
  • Tests

    • End-to-end and unit tests expanded to validate address-balance recording, querying, compaction and proof paths.

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

@github-actions github-actions bot added this to the v3.0.0 milestone Dec 29, 2025
@github-actions
Copy link

github-actions bot commented Dec 29, 2025

✅ gRPC Query Coverage Report

================================================================================
gRPC Query Coverage Report - NEW QUERIES ONLY
================================================================================

Total queries in proto: 53
Previously known queries: 47
New queries found: 6

================================================================================

New Query Implementation Status:
--------------------------------------------------------------------------------
✓ getAddressInfo                                /home/runner/work/platform/platform/packages/rs-sdk/src/platform/query.rs
✓ getAddressesBranchState                       /home/runner/work/platform/platform/packages/rs-sdk/src/platform/address_sync/mod.rs
✓ getAddressesInfos                             /home/runner/work/platform/platform/packages/rs-sdk/src/platform/fetch_many.rs
✓ getAddressesTrunkState                        /home/runner/work/platform/platform/packages/rs-sdk/src/platform/address_sync/mod.rs
✓ getRecentAddressBalanceChanges                /home/runner/work/platform/platform/packages/rs-sdk/src/platform/query.rs
✓ getRecentCompactedAddressBalanceChanges       /home/runner/work/platform/platform/packages/rs-sdk/src/platform/query.rs

================================================================================
Summary:
--------------------------------------------------------------------------------
New queries implemented: 6 (100.0%)
New queries missing: 0 (0.0%)

Total known queries: 53
  - Implemented: 50
  - Not implemented: 2
  - Excluded: 1

Not implemented queries:
  - getConsensusParams
  - getTokenPreProgrammedDistributions

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 29, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds end-to-end support for tracking and exposing recent per-address balance changes: new proto/RPCs, per-event balance accumulation, Drive storage with compaction/proving, verification helpers, version gating, SDK/client wiring, and broad test updates.

Changes

Cohort / File(s) Summary
Protocol / gRPC
packages/dapi-grpc/protos/platform/v0/platform.proto, packages/dapi-grpc/build.rs
New proto messages and two RPCs for recent and compacted address balance changes; versioned request/response entries updated.
Platform query handlers & service
packages/rs-drive-abci/src/query/address_funds/recent_address_balance_changes/{mod.rs,v0/mod.rs}, packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/{mod.rs,v0/mod.rs}, packages/rs-drive-abci/src/query/service.rs
New versioned query entry points with prove/non‑prove branches, version validation, response wrapping, and service routing.
dAPI wiring
packages/rs-dapi/src/services/platform_service/mod.rs, packages/rs-dapi-client/src/transport/grpc.rs
Added drive_method hooks and gRPC transport implementations to surface the two new RPCs.
Drive saved-blocks root & paths
packages/rs-drive/src/drive/mod.rs, packages/rs-drive/src/drive/saved_block_transactions/queries.rs, packages/rs-drive/src/drive/saved_block_transactions/mod.rs
New SavedBlockTransactions root-tree variant, path helpers, and constants for address balances and compacted address balances.
Drive store/fetch/prove APIs
packages/rs-drive/src/drive/saved_block_transactions/{store_address_balances/*,fetch_address_balances/*,fetch_compacted_address_balances/*}
Versioned APIs to store per-block address balance maps, fetch recent/compacted data, and produce proofs; (de)serialization and error mapping implemented.
Compaction & merging
packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/{mod.rs,v0/mod.rs}
Compaction logic that merges per-block maps into compacted ranges with deterministic merge semantics and atomic GroveDB batch updates.
Execution: collect & persist
packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/{mod.rs,store_address_balances_to_recent_block_storage/*,execute_event/*,process_raw_state_transitions/v0/mod.rs}, packages/rs-drive-abci/src/execution/engine/run_block_proposal/v0/mod.rs
Thread optional per-address balance map through event execution, collect CreditOperation updates, add Platform method to persist to recent block storage, and call it after block processing; BlockExecutionContext extended.
Types & merge rules
packages/rs-dpp/src/balances/credits.rs, packages/rs-drive-abci/src/execution/types/execution_event/mod.rs, packages/rs-drive-abci/src/execution/types/block_execution_context/v0/mod.rs
New CreditOperation enum with merge rules; ExecutionEvent::Paid gains optional added_to_balance_outputs; BlockExecutionContextV0 adds block_address_balance_changes.
State transition results & aggregation
packages/rs-drive-abci/src/platform_types/state_transitions_processing_result/mod.rs, packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs, many tests
Converted PaidConsensusError/SuccessfulExecution to struct-like variants; SuccessfulExecution now carries address_balance_changes; aggregation and merging of address balances added to processing result; tests updated.
Verification & proof helpers
packages/rs-drive-proof-verifier/src/{proof.rs,types.rs}, packages/rs-drive/src/verify/address_funds/*
New types for recent/compacted responses, FromProof implementations, and Drive proof verification helpers for recent and compacted address-balance proofs.
Platform versioning & feature gates
packages/rs-platform-version/src/version/{drive_abci_versions/*,drive_versions/*,drive_verify_method_versions/*,mocks/*}
Added saved_block_transactions method group, compaction parameters, new query/verify feature bounds, and gating for store_address_balances_to_recent_block_storage across versions/mocks.
SDK / client / mocks
packages/rs-sdk/src/{platform.rs,platform/fetch.rs,platform/query.rs,mock/requests.rs}
SDK query/fetch types and mocks for new RPCs/results; new queries require prove=true in current SDK implementation.
Tests & strategies
packages/rs-drive-abci/tests/strategy_tests/*, many validation tests under packages/rs-drive-abci/src/execution/validation/state_transition/..., packages/rs-drive/src/drive/initialization/*
New/expanded strategy tests asserting per-block balance-change semantics; many assertions updated to struct-like patterns; SavedBlockTransactions init expectations updated.
Misc wiring & refactors
packages/rs-drive-abci/src/abci/*, packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs, packages/rs-drive/src/util/batch/grovedb_op_batch/mod.rs
Pattern-match refactors (tuple → struct), optional arg threading, new KnownPath variant for SavedBlockTransactions, and small initialization adjustments.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant gRPC as gRPC Service
    participant Platform as Platform Query
    participant Drive as Drive Storage
    participant Grove as GroveDB

    Client->>gRPC: getRecentAddressBalanceChanges(start_height, prove)
    activate gRPC
    gRPC->>Platform: query_recent_address_balance_changes(request)
    activate Platform
    Platform->>Platform: validate request version & bounds
    alt prove == true
        Platform->>Drive: prove_recent_address_balance_changes(start_height, limit)
        activate Drive
        Drive->>Grove: grove_get_proved_path_query(SavedBlockTransactions/address_balances)
        Grove-->>Drive: proof bytes
        Drive-->>Platform: proof + metadata
        deactivate Drive
    else
        Platform->>Drive: fetch_recent_address_balance_changes(start_height, limit)
        activate Drive
        Drive->>Grove: grove_get_raw_path_query(SavedBlockTransactions/address_balances)
        Grove-->>Drive: [(height, serialized_map)]*
        Drive->>Drive: deserialize to AddressBalanceChange structs
        Drive-->>Platform: AddressBalanceUpdateEntries + metadata
        deactivate Drive
    end
    Platform-->>gRPC: GetRecentAddressBalanceChangesResponse
    deactivate Platform
    gRPC-->>Client: Response
    deactivate gRPC
Loading
sequenceDiagram
    participant BlockProcessor
    participant StateProc as State Transition Processor
    participant Executor as Execute Event
    participant Drive as Drive Store
    participant Grove as GroveDB

    BlockProcessor->>StateProc: process_raw_state_transitions()
    activate StateProc
    StateProc->>StateProc: address_balances = BTreeMap::new()
    loop per state transition
        StateProc->>Executor: execute_event(Some(&mut address_balances))
        activate Executor
        alt event includes address outputs or fees
            Executor->>StateProc: record SetCredits/AddToCredits per address
            note right of StateProc: Merge rules applied<br/>Set+Set → last Set<br/>Set+Add → Set with combined value<br/>Add+Add → add/saturating<br/>Add+Set → Set wins
        end
        Executor-->>StateProc: returns with address_balance_changes
        deactivate Executor
    end
    StateProc->>Drive: store_address_balances_to_recent_block_storage(address_balances, block_info)
    activate Drive
    Drive->>Grove: grove_insert(SavedBlockTransactions/address_balances, key=height, value=serialized_map)
    Grove-->>Drive: ok
    deactivate Drive
    deactivate StateProc
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Poem

🐇 I hopped through blocks with bright-eyed cheer,

Collected each nibble of balance near and far,
I set and I added, then folded by height,
Compacted the carrots, proved them by night,
Now queries fetch carrots — ledger tasty and clear!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(platform)!: historical address balance storage' accurately summarizes the main change: adding historical address balance storage and query capabilities to the platform.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea816b6 and a431ed6.

📒 Files selected for processing (1)
  • packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs

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

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (2)
packages/rs-drive-abci/src/query/service.rs (1)

120-135: counter in the height‑sync loop is re‑initialized each iteration (saturation guard never triggers)

In handle_blocking_query, the inner loop that waits for platform_state.last_committed_block_height() to match committed_block_height_guard declares let mut counter = 0; inside the loop body. That re‑initializes counter on every iteration, so if counter >= 100 is effectively unreachable and the intended “give up after ~1s and restart” behavior never happens. In a pathological mismatch, this can spin indefinitely.

You can fix this by moving counter outside the inner loop so it actually counts iterations:

Proposed fix for the wait‑loop
-                let mut needs_restart = false;
-
-                loop {
-                    let committed_block_height_guard = platform
-                        .committed_block_height_guard
-                        .load(Ordering::Relaxed);
-                    let mut counter = 0;
+                let mut needs_restart = false;
+                let mut counter = 0;
+
+                loop {
+                    let committed_block_height_guard = platform
+                        .committed_block_height_guard
+                        .load(Ordering::Relaxed);
@@
-                    } else {
-                        counter += 1;
-                        sleep(Duration::from_millis(10))
-                    }
-
-                    // We try for up to 1 second
-                    if counter >= 100 {
-                        query_counter += 1;
-                        needs_restart = true;
-                        break;
-                    }
+                    } else {
+                        counter += 1;
+                        sleep(Duration::from_millis(10));
+                        // We try for up to 1 second
+                        if counter >= 100 {
+                            query_counter += 1;
+                            needs_restart = true;
+                            break;
+                        }
+                    }
                 }
packages/rs-drive/src/drive/mod.rs (1)

274-296: Missing AddressBalances and GroupActions cases in TryFrom<u8>.

The TryFrom<u8> implementation is missing cases for:

  • 56 => Ok(RootTree::AddressBalances)
  • 88 => Ok(RootTree::GroupActions)

These are present in the enum definition and the From<RootTree> for &'static [u8; 1] implementation but missing here.

🔎 Proposed fix
             40 => Ok(RootTree::PreFundedSpecializedBalances),
             36 => Ok(RootTree::SavedBlockTransactions),
+            56 => Ok(RootTree::AddressBalances),
             72 => Ok(RootTree::SpentAssetLockTransactions),
             104 => Ok(RootTree::Misc),
             80 => Ok(RootTree::WithdrawalTransactions),
             96 => Ok(RootTree::Balances),
             16 => Ok(RootTree::Tokens),
             120 => Ok(RootTree::Versions),
             112 => Ok(RootTree::Votes),
+            88 => Ok(RootTree::GroupActions),
             _ => Err(Error::Drive(DriveError::NotSupported(
🧹 Nitpick comments (14)
packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs (4)

122-123: Test naming convention: Consider using should_* prefix.

Per coding guidelines, test names should start with "should …" (e.g., should_execute_address_transitions). However, the existing run_chain_* pattern may be established in this test suite. Consider aligning with the guideline for new tests or documenting the team's preferred convention.


526-526: Consider removing unused variable.

The _platform_version variable is defined but never used in this test. Consider removing it to reduce noise.

🔎 Proposed fix
-    let _platform_version = PlatformVersion::latest();

1020-1020: Consider moving import to module level.

The use dpp::dashcore::Txid; import inside the function is valid Rust but unconventional. Consider moving it to the module-level imports for consistency with the rest of the file.


1619-1648: Minor: Comment numbering inconsistency.

The operation comments say "5. Create identity" and "6. Top up identity" but should be "4." and "5." since operation 4 (IdentityCreditTransferToAddresses) was skipped. This is a minor documentation inconsistency.

🔎 Proposed fix
                     // Note: IdentityTransferToAddresses requires identities with transfer keys
                     // which need special setup - skipped for now
-                    // 5. Create identity from address funds
+                    // 4. Create identity from address funds
                     Operation {
                         op_type: OperationType::IdentityCreateFromAddresses(
                             dash_to_credits!(5)..=dash_to_credits!(10),
                             Some(dash_to_credits!(1)..=dash_to_credits!(2)),
                             None,
                             3,
                             [(
                                 Purpose::AUTHENTICATION,
                                 [(SecurityLevel::CRITICAL, vec![KeyType::ECDSA_SECP256K1])].into(),
                             )]
                             .into(),
                         ),
                         frequency: Frequency {
                             times_per_block_range: 0..2,
                             chance_per_block: Some(0.3),
                         },
                     },
-                    // 6. Top up identity from address funds
+                    // 5. Top up identity from address funds
                     Operation {
packages/rs-drive/src/drive/saved_block_transactions/fetch_address_balances/v0/mod.rs (1)

80-102: Consider extracting shared query construction logic.

The query construction (lines 88-94) duplicates the logic in fetch_recent_address_balance_changes_v0 (lines 26-32). Consider extracting a private helper method to build the PathQuery from start_height and limit.

🔎 Suggested helper extraction
fn build_address_balance_changes_path_query(start_height: u64, limit: Option<u16>) -> PathQuery {
    let path = Self::saved_block_transactions_address_balances_path_vec();
    let mut query = Query::new();
    query.insert_range_from(start_height.to_be_bytes().to_vec()..);
    PathQuery::new(path, SizedQuery::new(query, limit, None))
}
packages/rs-drive-abci/src/platform_types/state_transitions_processing_result/mod.rs (1)

117-128: Consider taking ownership of execution_result to avoid clone.

The address_balance_changes.clone() on line 127 is necessary because add() takes execution_result by reference. If add() took ownership instead, the clone could be avoided for the successful execution case. This is a minor performance consideration.

packages/rs-drive/src/drive/initialization/v0/mod.rs (1)

319-319: Updated root count and proof sizes for latest protocol version are consistent

  • Line 319: Expecting elements.len() == 16 for PlatformVersion::latest() aligns with the additional root trees introduced in newer protocols (e.g. AddressBalances, SavedBlockTransactions on top of earlier roots).
  • Line 1141: The adjusted proof length for PreFundedSpecializedBalances in the latest version reflects the deeper/more complex root layout; using the exact byte length keeps this test a strict regression guard on the merk structure.
  • Lines 1250–1269: The new Merk Level 4 check for RootTree::SavedBlockTransactions with proof length 286 correctly exercises the added subtree and ensures the new root participates in proofs as expected.

Given these tests are deliberately layout‑sensitive, the hard-coded lengths look intentional and appropriate for guarding structural regressions.

If proof encoding changes frequently in future, consider factoring these “expected proof len” constants behind small helpers or comments tied to a diagram of the merk tree, to make future updates less error‑prone, but this is optional.

Also applies to: 1141-1141, 1250-1269

packages/rs-dpp/src/balances/credits.rs (1)

42-49: LGTM! Well-designed CreditOperation enum.

The CreditOperation enum is simple, clear, and appropriately derives all necessary traits including Copy (since Credits is u64) and bincode serialization traits for storage.

Optional: Consider adding helper methods

You might consider adding convenience methods to apply operations or combine them:

+impl CreditOperation {
+    /// Apply this operation to a base credit amount
+    pub fn apply(&self, base: Credits) -> Option<Credits> {
+        match self {
+            CreditOperation::SetCredits(amount) => Some(*amount),
+            CreditOperation::AddToCredits(amount) => base.checked_add(*amount),
+        }
+    }
+}

This would centralize the logic for applying operations, though it may not be necessary if operations are always applied at higher layers.

packages/rs-drive-abci/src/execution/engine/run_block_proposal/v0/mod.rs (1)

370-370: Consider using Default::default() for consistency.

Line 370 uses std::collections::BTreeMap::new() while other similar initializations in the codebase (e.g., line 276 in add_process_epoch_change_operations/v0/mod.rs) use Default::default().

Suggestion for consistency
-            block_address_balance_changes: std::collections::BTreeMap::new(),
+            block_address_balance_changes: Default::default(),

This aligns with the pattern used in test helpers and avoids the fully-qualified type path.

packages/rs-drive/src/drive/saved_block_transactions/mod.rs (1)

6-6: Consider explicit re-exports instead of glob import.

Using pub use queries::* re-exports all public items from the queries module, which could unintentionally expand the public API surface. If only specific items are intended for external use, consider listing them explicitly for better API control and documentation.

🔎 Example of explicit re-exports
-pub use queries::*;
+pub use queries::{specific_query_fn, another_query_fn}; // List intended exports
packages/rs-drive-abci/src/execution/types/block_execution_context/v0/mod.rs (1)

2-2: Add accessors for block_address_balance_changes to keep the traits consistent

You added block_address_balance_changes as a public field, but the BlockExecutionContextV0Getters / BlockExecutionContextV0MutableGetters / BlockExecutionContextV0OwnedGetters and BlockExecutionContextV0Setters traits don’t expose it. For API consistency and future refactors, it’s worth adding corresponding methods so callers don’t need to reach into the struct field directly.

Example trait & impl additions
 pub trait BlockExecutionContextV0Getters {
@@
     /// Returns a reference of the withdrawal_transactions field.
     fn unsigned_withdrawal_transactions(&self) -> &UnsignedWithdrawalTxs;
+
+    /// Returns a reference of the recent address balance changes.
+    fn block_address_balance_changes(
+        &self,
+    ) -> &BTreeMap<PlatformAddress, Credits>;
@@
 impl BlockExecutionContextV0Getters for BlockExecutionContextV0 {
@@
     fn unsigned_withdrawal_transactions(&self) -> &UnsignedWithdrawalTxs {
         &self.unsigned_withdrawal_transactions
     }
+
+    fn block_address_balance_changes(
+        &self,
+    ) -> &BTreeMap<PlatformAddress, Credits> {
+        &self.block_address_balance_changes
+    }
 }

Similar small additions can be made for the mutable, owned, and setter traits if you want full symmetry.

Also applies to: 8-9, 21-22

packages/rs-drive-abci/src/execution/types/execution_event/mod.rs (1)

416-444: Confirm removed_balance derivation for IdentityCreditTransferToAddressesAction

Here removed_balance is computed as recipient_addresses().values().sum(), and the same map is stored in added_to_balance_outputs. This is reasonable, but it assumes the sum of recipient amounts is the canonical amount to remove from the identity.

If the action type already tracks a total transfer amount or enforces invariants between the declared amount and the per‑address map, it may be safer either to:

  • derive removed_balance from that canonical field, or
  • add an internal debug assertion that the declared total equals recipient_addresses().values().sum().

That would prevent silent drift if the action structure changes in future.

packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs (1)

101-227: Address balance tracking in paid_from_address_inputs_and_outputs is logically sound

The new address_balances_in_update handling for inputs/outputs correctly captures net per-address changes with coherent merge rules:

  • Outputs: you record AddToCredits(adjusted_amount) (post-fee), and combine:
    • SetCredits + AddToCreditsSetCredits(set_val + adjusted_amount)
    • AddToCredits + AddToCreditsAddToCredits(sum) (saturating).
  • Inputs: you always emit SetCredits(adjusted_remaining), overwriting any prior Add or Set, so input addresses end up with an absolute final balance, which is appropriate when you know the remaining balance after fees.
  • Processing outputs before inputs ensures that when an address appears in both, the final operation is a SetCredits from the input pass, as intended.

Behavioral semantics (tracking net changes, not intermediate fee deductions) look consistent with the CreditOperation design. The duplicated merge logic for outputs and inputs could be factored into a small helper for clarity, but that's optional.

Also applies to: 229-267

packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs (1)

223-293: Address balance tracking and struct-like execution results are wired correctly

  • Invalid transitions:
    • You pass None for address_balances_in_update into execute_event, and map paid/ free/unpaid cases to PaidConsensusError { error, actual_fees } or UnpaidConsensusError exactly as before, which is appropriate since you don’t want to expose address deltas for invalid STs.
  • Valid transitions:
    • You initialize let mut address_balances = BTreeMap::new(); and pass Some(&mut address_balances) into execute_event, so downstream code can accumulate CreditOperations per address.
    • SuccessfulPaidExecution(estimated_fees, actual_fees) maps to:
      • SuccessfulExecution { estimated_fees, fee_result: actual_fees, address_balance_changes: address_balances }, which pairs the actual fee result with the collected address changes.
    • UnsuccessfulPaidExecution correctly yields PaidConsensusError { error, actual_fees } without address changes, aligning with the idea that these STs are invalid from a consensus perspective.
    • SuccessfulFreeExecution returns SuccessfulExecution { estimated_fees: None, fee_result: FeeResult::default(), address_balance_changes: BTreeMap::new() }, which keeps free transitions free and with no tracked address changes.

One minor improvement: in the SuccessfulFreeExecution arm you could reuse the local address_balances instead of constructing a new BTreeMap::new(). Today both are empty, but using address_balances would automatically propagate any future address tracking for free events without touching this code.

Also applies to: 362-482

@QuantumExplorer QuantumExplorer changed the title feat: historical storage feat(platform)!: historical address balance storage Dec 30, 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: 0

🧹 Nitpick comments (10)
packages/rs-drive-proof-verifier/src/proof.rs (2)

970-970: Hardcoded limit should match the query handler or be derived from request.

The limit is hardcoded to 100 with a comment referencing the query handler. If the query handler's limit changes, this would cause a mismatch leading to proof verification failures. Consider:

  1. Extracting the limit from the request if available
  2. Defining a shared constant
  3. At minimum, add a TODO or document the coupling
-        let limit = Some(100u16); // Same limit as in query handler
+        // TODO: This limit must match the query handler's limit.
+        // Consider extracting from a shared constant or the request.
+        let limit = Some(100u16);

1027-1027: Same hardcoded limit concern applies here.

The limit is also hardcoded to 100 in the compacted balance changes implementation. The same recommendation applies: ensure this stays synchronized with the query handler or extract to a shared constant.

packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/v0/mod.rs (1)

8-9: Import ADDRESS_BALANCES_KEY_U8 from the shared constants module.

This constant is defined locally here but has a canonical definition in packages/rs-drive/src/drive/saved_block_transactions/queries.rs. Import it instead: use crate::drive::saved_block_transactions::ADDRESS_BALANCES_KEY_U8;. The same applies to COMPACTED_ADDRESS_BALANCES_KEY_U8 defined on line 9.

packages/rs-sdk/src/platform/query.rs (1)

901-946: Consider consistent field naming between the two query types.

RecentAddressBalanceChangesQuery uses start_height while RecentCompactedAddressBalanceChangesQuery uses start_block_height. For API consistency, consider using the same naming convention for both structs.

🔎 Suggested refactor for naming consistency
 /// Query for fetching recent address balance changes starting from a block height
 #[derive(Debug, Clone)]
 pub struct RecentAddressBalanceChangesQuery {
     /// The block height to start fetching from
-    pub start_height: u64,
+    pub start_block_height: u64,
 }
 
 impl RecentAddressBalanceChangesQuery {
     /// Create a new query starting from a specific block height
-    pub fn new(start_height: u64) -> Self {
-        Self { start_height }
+    pub fn new(start_block_height: u64) -> Self {
+        Self { start_block_height }
     }
 }
 
 impl Query<proto::GetRecentAddressBalanceChangesRequest> for RecentAddressBalanceChangesQuery {
     fn query(self, prove: bool) -> Result<proto::GetRecentAddressBalanceChangesRequest, Error> {
         if !prove {
             unimplemented!("queries without proofs are not supported yet");
         }
 
         Ok(proto::GetRecentAddressBalanceChangesRequest {
             version: Some(
                 proto::get_recent_address_balance_changes_request::Version::V0(
                     proto::get_recent_address_balance_changes_request::GetRecentAddressBalanceChangesRequestV0 {
-                        start_height: self.start_height,
+                        start_height: self.start_block_height,
                         prove,
                     },
                 ),
             ),
         })
     }
 }
packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/v0/mod.rs (1)

30-31: Consider making the limit configurable or documenting the rationale.

The hardcoded limit of 100 entries works, but consider either:

  1. Accepting a limit parameter from the request (with an upper bound validation), or
  2. Adding a brief comment explaining why 100 is the chosen default

This would improve maintainability and transparency.

packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/v0/mod.rs (1)

93-119: LGTM!

The prove implementation correctly builds the same query structure and delegates to the appropriate GroveDB method for proof generation.

Note: There's some code duplication in query construction between fetch_compacted_address_balance_changes_v0 and prove_compacted_address_balance_changes_v0. Consider extracting a helper function in the future if more methods need this same query pattern.

packages/rs-drive/src/drive/saved_block_transactions/fetch_address_balances/v0/mod.rs (2)

26-32: Consider extracting the query construction logic.

The query construction code (creating the range query and PathQuery) is duplicated between fetch_recent_address_balance_changes_v0 and prove_recent_address_balance_changes_v0. This duplication could be eliminated by extracting a helper method that builds the PathQuery.

🔎 Proposed refactor

Add a private helper method:

fn build_address_balance_changes_path_query(
    start_height: u64,
    limit: Option<u16>,
) -> PathQuery {
    let path = Self::saved_block_transactions_address_balances_path_vec();
    let mut query = Query::new();
    query.insert_range_from(start_height.to_be_bytes().to_vec()..);
    PathQuery::new(path, SizedQuery::new(query, limit, None))
}

Then use it in both methods:

let path_query = Self::build_address_balance_changes_path_query(start_height, limit);

Also applies to: 89-95


19-25: Consider documenting the limit parameter behavior.

The limit parameter is Option<u16>, but the documentation doesn't explain what None means. Does it return all records from start_height onwards? This could be clarified in the doc comment.

packages/rs-drive/src/drive/saved_block_transactions/queries.rs (1)

31-36: Consider simplifying the Into trait syntax.

The explicit Into::<&[u8; 1]>::into(RootTree::SavedBlockTransactions) syntax on lines 33 and 49 is verbose. Since the target type is known from the return type annotation, you could use .into() or directly use the byte slice representation.

🔎 Alternative approaches

Option 1: Use direct byte representation

 pub fn saved_block_transactions_address_balances_path() -> [&'static [u8]; 2] {
     [
-        Into::<&[u8; 1]>::into(RootTree::SavedBlockTransactions),
+        &[RootTree::SavedBlockTransactions as u8],
         &[ADDRESS_BALANCES_KEY_U8],
     ]
 }

Option 2: Keep the Into but make it less verbose

-        Into::<&[u8; 1]>::into(RootTree::SavedBlockTransactions),
+        RootTree::SavedBlockTransactions.into(),

Also applies to: 47-52

packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs (1)

64-64: Consider defensive check for the type cast.

The cast address_balances.len() as i64 could theoretically overflow if the map contains more than i64::MAX entries (extremely unlikely in practice). While this scenario is essentially impossible, adding a defensive check or using try_into() would make the code more robust.

🔎 Suggested defensive approach
-        let entry_count = address_balances.len() as i64;
+        let entry_count = address_balances.len().try_into()
+            .map_err(|_| Error::Protocol(Box::new(ProtocolError::Overflow(
+                "address balances count exceeds i64::MAX"
+            ))))?;
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 328b47d and c15aa4a.

📒 Files selected for processing (41)
  • packages/dapi-grpc/build.rs
  • packages/dapi-grpc/protos/platform/v0/platform.proto
  • packages/rs-dapi-client/src/transport/grpc.rs
  • packages/rs-dapi/src/services/platform_service/mod.rs
  • packages/rs-dpp/src/balances/credits.rs
  • packages/rs-drive-abci/src/query/address_funds/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/v0/mod.rs
  • packages/rs-drive-abci/src/query/service.rs
  • packages/rs-drive-proof-verifier/src/proof.rs
  • packages/rs-drive-proof-verifier/src/types.rs
  • packages/rs-drive/src/drive/initialization/v2/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/v0/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_address_balances/v0/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/v0/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/queries.rs
  • packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs
  • packages/rs-drive/src/verify/address_funds/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/v0/mod.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/v2.rs
  • packages/rs-platform-version/src/version/drive_versions/v3.rs
  • packages/rs-platform-version/src/version/drive_versions/v4.rs
  • packages/rs-platform-version/src/version/drive_versions/v5.rs
  • packages/rs-platform-version/src/version/drive_versions/v6.rs
  • packages/rs-platform-version/src/version/mocks/v2_test.rs
  • packages/rs-sdk/src/mock/requests.rs
  • packages/rs-sdk/src/platform.rs
  • packages/rs-sdk/src/platform/fetch.rs
  • packages/rs-sdk/src/platform/query.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/rs-dapi/src/services/platform_service/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/v4.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Rust code must pass cargo clippy --workspace linter checks
Rust code must be formatted using cargo fmt --all

**/*.rs: Use 4-space indent for Rust files
Follow rustfmt defaults and keep code clippy-clean for Rust modules
Use snake_case for Rust module names
Use PascalCase for Rust type names
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs
  • packages/rs-sdk/src/platform.rs
  • packages/rs-sdk/src/platform/fetch.rs
  • packages/rs-platform-version/src/version/mocks/v2_test.rs
  • packages/rs-dapi-client/src/transport/grpc.rs
  • packages/rs-drive/src/verify/address_funds/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/v6.rs
  • packages/rs-platform-version/src/version/drive_versions/v5.rs
  • packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/v0/mod.rs
  • packages/rs-sdk/src/mock/requests.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/mod.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/v2.rs
  • packages/rs-drive-abci/src/query/service.rs
  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/mod.rs
  • packages/dapi-grpc/build.rs
  • packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/v0/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/v0/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/mod.rs
  • packages/rs-drive-proof-verifier/src/proof.rs
  • packages/rs-dpp/src/balances/credits.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs
  • packages/rs-drive-proof-verifier/src/types.rs
  • packages/rs-platform-version/src/version/drive_versions/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/v0/mod.rs
  • packages/rs-sdk/src/platform/query.rs
  • packages/rs-platform-version/src/version/drive_versions/v3.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs
  • packages/rs-drive/src/drive/initialization/v2/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_address_balances/v0/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/queries.rs
🧠 Learnings (33)
📓 Common learnings
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/src/mimic/test_quorum.rs:159-164
Timestamp: 2024-11-20T16:16:01.830Z
Learning: QuantumExplorer prefers not to receive auto-generated messages asking to post on social media.
📚 Learning: 2024-10-08T13:28:03.529Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-drive-abci/src/platform_types/platform_state/mod.rs:141-141
Timestamp: 2024-10-08T13:28:03.529Z
Learning: When converting `PlatformStateV0` to `PlatformStateForSavingV1` in `packages/rs-drive-abci/src/platform_types/platform_state/mod.rs`, only version `0` needs to be handled in the match on `platform_state_for_saving_structure_default` because the changes are retroactive.

Applied to files:

  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs
  • packages/rs-platform-version/src/version/mocks/v2_test.rs
  • packages/rs-platform-version/src/version/drive_versions/v6.rs
  • packages/rs-platform-version/src/version/drive_versions/v5.rs
  • packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/v0/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/v2.rs
  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/v0/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/v0/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/v3.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs
  • packages/rs-drive/src/drive/initialization/v2/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_address_balances/v0/mod.rs
📚 Learning: 2025-05-28T16:22:26.334Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2644
File: packages/rs-drive/src/cache/system_contracts.rs:18-19
Timestamp: 2025-05-28T16:22:26.334Z
Learning: In packages/rs-drive/src/cache/system_contracts.rs, the `active_since_protocol_version` field in `ActiveSystemDataContract` struct is intentionally added for future use, not current implementation. QuantumExplorer confirmed this is "meant for later" when questioned about the `#[allow(unused)]` attribute.

Applied to files:

  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/v6.rs
  • packages/rs-platform-version/src/version/drive_versions/v5.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/v2.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/v3.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2201
File: packages/rs-platform-version/src/version/v2.rs:1186-1188
Timestamp: 2024-10-09T00:22:57.778Z
Learning: In the `IdentityTransitionVersions` structure within `packages/rs-platform-version/src/version/v2.rs`, the field `credit_withdrawal` does not need the `identity_` prefix since it is already encompassed within identity state transitions.

Applied to files:

  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/mod.rs
  • packages/rs-dpp/src/balances/credits.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs
  • packages/rs-drive/src/drive/initialization/v2/mod.rs
📚 Learning: 2024-10-29T14:40:54.727Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/src/core/transaction.rs:0-0
Timestamp: 2024-10-29T14:40:54.727Z
Learning: In `packages/rs-sdk/src/platform/document_query.rs` and `packages/rs-sdk/src/core/transaction.rs`, certain places don't implement `IntoInner`, so direct error mappings cannot be simplified using `IntoInner`. A TODO comment has been added to address this in a future PR.

Applied to files:

  • packages/rs-sdk/src/platform.rs
  • packages/rs-drive-proof-verifier/src/types.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/v0/mod.rs
  • packages/rs-sdk/src/platform/query.rs
  • packages/rs-drive/src/drive/saved_block_transactions/queries.rs
📚 Learning: 2024-10-18T15:39:51.172Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2254
File: packages/rs-sdk/src/sdk.rs:585-585
Timestamp: 2024-10-18T15:39:51.172Z
Learning: The 'platform' project uses Rust version 1.80, so code in 'packages/rs-sdk' can use features available in Rust 1.80, such as the `abs_diff()` method.

Applied to files:

  • packages/rs-sdk/src/platform.rs
📚 Learning: 2024-11-28T13:49:17.301Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2317
File: packages/rs-dapi-client/src/address_list.rs:175-180
Timestamp: 2024-11-28T13:49:17.301Z
Learning: In Rust code in `packages/rs-dapi-client/src/address_list.rs`, do not change the interface of deprecated methods like `add_uri`, even to fix potential panics.

Applied to files:

  • packages/rs-sdk/src/platform.rs
  • packages/rs-drive/src/verify/address_funds/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/mod.rs
  • packages/rs-drive-abci/src/query/service.rs
  • packages/dapi-grpc/build.rs
📚 Learning: 2024-10-30T11:04:33.634Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/src/platform/fetch_unproved.rs:0-0
Timestamp: 2024-10-30T11:04:33.634Z
Learning: In `packages/rs-sdk/src/platform/fetch_unproved.rs`, the `execute()` method consumes the request object, so cloning the request is necessary before passing it to `execute()` and `maybe_from_unproved_with_metadata`.

Applied to files:

  • packages/rs-sdk/src/platform/fetch.rs
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2206
File: packages/rs-drive-abci/tests/strategy_tests/main.rs:1162-1162
Timestamp: 2024-10-09T00:22:57.778Z
Learning: In the Rust test file `packages/rs-drive-abci/tests/strategy_tests/main.rs`, specific protocol versions like `PROTOCOL_VERSION_1` are intentionally used in tests instead of `PROTOCOL_VERSION_LATEST`.

Applied to files:

  • packages/rs-platform-version/src/version/mocks/v2_test.rs
  • packages/rs-platform-version/src/version/drive_versions/v6.rs
  • packages/rs-platform-version/src/version/drive_versions/v5.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/v2.rs
  • packages/rs-platform-version/src/version/drive_versions/v3.rs
📚 Learning: 2024-10-04T09:07:11.452Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2206
File: packages/rs-drive-abci/tests/strategy_tests/main.rs:89-89
Timestamp: 2024-10-04T09:07:11.452Z
Learning: In tests located in the `packages/rs-drive-abci/tests` directory, the team prefers to use specific protocol versions (e.g., `PROTOCOL_VERSION_1`) instead of `PROTOCOL_VERSION_LATEST`.

Applied to files:

  • packages/rs-platform-version/src/version/mocks/v2_test.rs
📚 Learning: 2024-11-22T08:19:14.448Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2345
File: packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs:93-99
Timestamp: 2024-11-22T08:19:14.448Z
Learning: In `packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs`, the `insert_contract` method requires an owned `BlockInfo`, so cloning `block_info` is necessary when calling it.

Applied to files:

  • packages/rs-platform-version/src/version/mocks/v2_test.rs
  • packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/v0/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/v0/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/v0/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_address_balances/v0/mod.rs
📚 Learning: 2024-11-20T20:43:41.185Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/tests/strategy_tests/masternodes.rs:212-220
Timestamp: 2024-11-20T20:43:41.185Z
Learning: In `packages/rs-drive-abci/tests/strategy_tests/masternodes.rs`, the pattern of generating a `PrivateKey`, converting it to bytes, and reconstructing a `BlsPrivateKey` from those bytes is intentional. Avoid suggesting to simplify this code in future reviews.

Applied to files:

  • packages/rs-platform-version/src/version/mocks/v2_test.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs
  • packages/rs-drive/src/drive/initialization/v2/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/queries.rs
📚 Learning: 2024-11-25T01:17:02.001Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2347
File: packages/rs-drive/tests/query_tests.rs:438-460
Timestamp: 2024-11-25T01:17:02.001Z
Learning: In Rust test files (`packages/rs-drive/tests/query_tests.rs`), when code is used only in tests, defining explicit enums for fields (like the `status` field in the `Withdrawal` struct) may not be necessary; using primitive types is acceptable.

Applied to files:

  • packages/rs-platform-version/src/version/mocks/v2_test.rs
📚 Learning: 2025-01-19T07:36:46.042Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2431
File: packages/rs-drive/Cargo.toml:55-60
Timestamp: 2025-01-19T07:36:46.042Z
Learning: The grovedb dependencies in packages/rs-drive/Cargo.toml and related files are intentionally kept at specific revisions rather than using the latest stable version, with plans to update them at a later time.

Applied to files:

  • packages/rs-platform-version/src/version/drive_versions/v6.rs
  • packages/rs-platform-version/src/version/drive_versions/v5.rs
  • packages/rs-platform-version/src/version/drive_versions/v2.rs
  • packages/rs-platform-version/src/version/drive_versions/v3.rs
📚 Learning: 2024-10-10T10:30:19.883Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2232
File: packages/rs-sdk/src/mock/sdk.rs:90-95
Timestamp: 2024-10-10T10:30:19.883Z
Learning: In `packages/rs-sdk/src/mock/sdk.rs`, the `load_expectations` method in `MockDashPlatformSdk` remains asynchronous (`async`) for backward compatibility, even though it now delegates to the synchronous `load_expectations_sync` method.

Applied to files:

  • packages/rs-sdk/src/mock/requests.rs
📚 Learning: 2024-10-29T14:44:01.184Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-dapi-client/src/executor.rs:38-38
Timestamp: 2024-10-29T14:44:01.184Z
Learning: In `packages/rs-dapi-client/src/executor.rs`, for the structs `ExecutionError<E>` and `ExecutionResponse<R>`, only the serde derives (`Serialize`, `Deserialize`) should be conditional based on the "mocks" feature; the other derives (`Debug`, `Clone`, `Eq`, `PartialEq`) should always be present.

Applied to files:

  • packages/rs-sdk/src/mock/requests.rs
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2139
File: packages/rs-sdk/Cargo.toml:0-0
Timestamp: 2024-10-09T00:22:57.778Z
Learning: `bincode` is used in the `mocks` feature of the `rs-sdk`.

Applied to files:

  • packages/rs-sdk/src/mock/requests.rs
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2207
File: packages/rs-drive-proof-verifier/src/proof.rs:1646-1664
Timestamp: 2024-10-09T00:22:57.778Z
Learning: In the implementation of `FromProof<platform::GetContestedResourceIdentityVotesRequest>` in `packages/rs-drive-proof-verifier/src/proof.rs`, when matching `maybe_votes`, using `.expect()` on `v.into_iter().next()` is acceptable because the prior match arm `Some(v) if v.is_empty()` ensures that the map is not empty, preventing a panic.

Applied to files:

  • packages/rs-sdk/src/mock/requests.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/mod.rs
  • packages/rs-drive-proof-verifier/src/proof.rs
📚 Learning: 2024-10-29T14:13:35.584Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/dapi-grpc/src/mock.rs:95-109
Timestamp: 2024-10-29T14:13:35.584Z
Learning: In test code (e.g., `packages/dapi-grpc/src/mock.rs`), panicking on deserialization errors is acceptable behavior.

Applied to files:

  • packages/rs-sdk/src/mock/requests.rs
📚 Learning: 2024-11-20T10:01:50.837Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/src/platform_types/platform_state/v0/old_structures/mod.rs:94-94
Timestamp: 2024-11-20T10:01:50.837Z
Learning: In `packages/rs-drive-abci/src/platform_types/platform_state/v0/old_structures/mod.rs`, when converting with `PublicKey::try_from`, it's acceptable to use `.expect()` to handle potential conversion errors.

Applied to files:

  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/mod.rs
📚 Learning: 2025-11-25T13:10:23.481Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T13:10:23.481Z
Learning: Use `rs-drive-proof-verifier` for cryptographic proof verification

Applied to files:

  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/v0/mod.rs
  • packages/rs-drive-proof-verifier/src/proof.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs
📚 Learning: 2024-10-06T16:17:34.571Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:105-105
Timestamp: 2024-10-06T16:17:34.571Z
Learning: In `run_block_proposal` in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, when retrieving `last_block_time_ms`, it's acceptable to use `platform_state` instead of `block_platform_state`, even after updating the protocol version.

Applied to files:

  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/v0/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_address_balances/v0/mod.rs
  • packages/dapi-grpc/protos/platform/v0/platform.proto
📚 Learning: 2024-10-06T16:18:07.994Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:119-120
Timestamp: 2024-10-06T16:18:07.994Z
Learning: In the `run_block_proposal` function in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, it's acceptable to pass `platform_state` to `perform_events_on_first_block_of_protocol_change`, even if `block_platform_state` has been updated.

Applied to files:

  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/v0/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/mod.rs
📚 Learning: 2024-11-03T10:39:11.242Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2305
File: packages/rs-drive-abci/src/abci/handler/finalize_block.rs:81-0
Timestamp: 2024-11-03T10:39:11.242Z
Learning: In `packages/rs-drive-abci/src/abci/handler/finalize_block.rs`, the use of `.expect("commit transaction")` after `app.commit_transaction(platform_version)` is intentional due to the provided comment explaining its necessity. Do not flag this usage in future reviews.

Applied to files:

  • packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/mod.rs
  • packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/v0/mod.rs
📚 Learning: 2024-11-15T14:39:23.704Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2332
File: packages/rs-drive-proof-verifier/src/error.rs:21-23
Timestamp: 2024-11-15T14:39:23.704Z
Learning: In the `packages/rs-drive-proof-verifier`, avoid suggesting size limits for `proof_bytes` in errors unless there's a specific need, as it may not be necessary.

Applied to files:

  • packages/rs-drive-proof-verifier/src/proof.rs
📚 Learning: 2025-08-05T13:55:39.147Z
Learnt from: thephez
Repo: dashpay/platform PR: 2718
File: packages/wasm-sdk/index.html:0-0
Timestamp: 2025-08-05T13:55:39.147Z
Learning: The get_identity_keys_with_proof_info function in the Rust WASM bindings does not support the "search" key request type and lacks the searchPurposeMap parameter. When proof mode is enabled with keyRequestType === 'search', the implementation falls back to the non-proof version (get_identity_keys) to maintain functionality.

Applied to files:

  • packages/rs-drive-proof-verifier/src/proof.rs
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2182
File: packages/rs-dpp/src/withdrawal/daily_withdrawal_limit/v0/mod.rs:23-31
Timestamp: 2024-10-09T00:22:57.778Z
Learning: `Credits` is a `u64`, and division by 10 won't cause an overflow.

Applied to files:

  • packages/rs-dpp/src/balances/credits.rs
📚 Learning: 2025-01-20T16:20:59.791Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2432
File: packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs:222-225
Timestamp: 2025-01-20T16:20:59.791Z
Learning: In the Dash Platform codebase, TokenAmount from crate::balances::credits is compatible with u64 when used for token base supply.

Applied to files:

  • packages/rs-dpp/src/balances/credits.rs
📚 Learning: 2025-01-20T16:20:59.791Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2432
File: packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs:222-225
Timestamp: 2025-01-20T16:20:59.791Z
Learning: In the Dash Platform codebase, TokenAmount is defined as `type TokenAmount = u64` in balances/credits.rs, making it directly compatible with u64 values without any conversion needed.

Applied to files:

  • packages/rs-dpp/src/balances/credits.rs
📚 Learning: 2024-09-29T13:13:54.230Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2182
File: packages/rs-platform-version/src/version/drive_abci_versions.rs:116-121
Timestamp: 2024-09-29T13:13:54.230Z
Learning: In the `DriveAbciWithdrawalConstants` struct, prefer verbose field names even if they are lengthy.

Applied to files:

  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs
📚 Learning: 2024-11-20T16:05:40.200Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs:148-151
Timestamp: 2024-11-20T16:05:40.200Z
Learning: In `packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs`, when converting public keys from `QuorumForSavingV0` to `VerificationQuorum`, it's acceptable to use `.expect()` for public key conversion, as the conversion has been verified and panics are acceptable in this context.

Applied to files:

  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs
  • packages/rs-drive/src/drive/saved_block_transactions/queries.rs
📚 Learning: 2025-02-03T23:39:10.579Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2450
File: packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/v0/methods.rs:10-12
Timestamp: 2025-02-03T23:39:10.579Z
Learning: Block interval calculations in token distribution logic should use checked arithmetic operations (checked_sub, checked_add) to prevent potential overflows, especially when dealing with block heights and intervals.

Applied to files:

  • packages/dapi-grpc/protos/platform/v0/platform.proto
📚 Learning: 2025-10-09T15:59:18.338Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2716
File: packages/wallet-lib/src/plugins/Workers/TransactionsSyncWorker/TransactionsReader.js:325-334
Timestamp: 2025-10-09T15:59:18.338Z
Learning: In `packages/wallet-lib/src/plugins/Workers/TransactionsSyncWorker/TransactionsReader.js`, the continuous sync restart intentionally uses `Math.max(1, lastSyncedBlockHeight)` rather than `lastSyncedBlockHeight + 1` because the last block's processing status is uncertain at restart time. This conservative approach ensures no blocks are missed by reprocessing the last synced block, accepting potential duplicate processing for data completeness.

Applied to files:

  • packages/dapi-grpc/protos/platform/v0/platform.proto
🧬 Code graph analysis (19)
packages/rs-dapi-client/src/transport/grpc.rs (1)
packages/rs-drive-abci/src/query/service.rs (2)
  • get_recent_address_balance_changes (858-868)
  • get_recent_compacted_address_balance_changes (870-880)
packages/rs-drive/src/verify/address_funds/mod.rs (2)
packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs (1)
  • verify_compacted_address_balance_changes (35-62)
packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/mod.rs (1)
  • verify_recent_address_balance_changes (33-60)
packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/v0/mod.rs (2)
packages/rs-drive/src/drive/initialization/v2/mod.rs (1)
  • drive (70-103)
packages/rs-drive/src/drive/saved_block_transactions/queries.rs (2)
  • saved_block_transactions_address_balances_path_vec (23-28)
  • saved_compacted_block_transactions_address_balances_path_vec (39-44)
packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs (1)
packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs (1)
  • verify_compacted_address_balance_changes_v0 (18-97)
packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/mod.rs (1)
packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/v0/mod.rs (1)
  • verify_recent_address_balance_changes_v0 (18-89)
packages/rs-drive/src/drive/saved_block_transactions/compact_address_balances/mod.rs (1)
packages/rs-drive/src/drive/initialization/v2/mod.rs (1)
  • drive (70-103)
packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/v0/mod.rs (3)
packages/rs-sdk/src/platform/query.rs (16)
  • query (103-103)
  • query (111-116)
  • query (120-130)
  • query (134-144)
  • query (148-165)
  • query (170-188)
  • query (245-267)
  • query (271-284)
  • query (288-300)
  • query (304-310)
  • query (361-376)
  • query (380-387)
  • query (391-397)
  • query (401-413)
  • query (418-420)
  • query (425-427)
packages/rs-drive/src/drive/initialization/v2/mod.rs (1)
  • drive (70-103)
packages/rs-dpp/src/validation/validation_result.rs (1)
  • new_with_data (90-95)
packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/v0/mod.rs (2)
packages/rs-drive/src/drive/initialization/v2/mod.rs (1)
  • drive (70-103)
packages/rs-drive-proof-verifier/src/proof.rs (1)
  • Drive (915-918)
packages/rs-drive-abci/src/query/address_funds/recent_compacted_address_balance_changes/mod.rs (2)
packages/rs-sdk/src/platform/query.rs (16)
  • query (103-103)
  • query (111-116)
  • query (120-130)
  • query (134-144)
  • query (148-165)
  • query (170-188)
  • query (245-267)
  • query (271-284)
  • query (288-300)
  • query (304-310)
  • query (361-376)
  • query (380-387)
  • query (391-397)
  • query (401-413)
  • query (418-420)
  • query (425-427)
packages/rs-dpp/src/validation/validation_result.rs (1)
  • new_with_error (104-109)
packages/rs-drive-proof-verifier/src/proof.rs (2)
packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/mod.rs (1)
  • verify_recent_address_balance_changes (33-60)
packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs (1)
  • verify_compacted_address_balance_changes (35-62)
packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/mod.rs (1)
packages/rs-drive/src/drive/initialization/v2/mod.rs (1)
  • drive (70-103)
packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs (2)
packages/rs-drive/src/drive/initialization/v2/mod.rs (1)
  • drive (70-103)
packages/rs-drive/src/drive/saved_block_transactions/queries.rs (2)
  • saved_block_transactions_address_balances_path (31-36)
  • saved_block_transactions_path (18-20)
packages/rs-drive-proof-verifier/src/types.rs (3)
packages/rs-dpp/src/errors/consensus/basic/unsupported_feature_error.rs (1)
  • feature (32-34)
packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs (1)
  • balances (573-577)
packages/rs-dapi-client/src/executor.rs (4)
  • into_inner (27-27)
  • into_inner (73-75)
  • into_inner (111-113)
  • into_inner (146-151)
packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/v0/mod.rs (2)
packages/rs-drive/src/drive/initialization/v2/mod.rs (1)
  • drive (70-103)
packages/rs-drive/src/drive/saved_block_transactions/queries.rs (1)
  • saved_compacted_block_transactions_address_balances_path_vec (39-44)
packages/rs-sdk/src/platform/query.rs (2)
packages/rs-sdk/src/platform/documents/document_query.rs (1)
  • new (60-78)
packages/rs-sdk/src/platform/types/epoch.rs (1)
  • query (90-92)
packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs (1)
packages/rs-drive/src/drive/initialization/v2/mod.rs (1)
  • drive (70-103)
packages/rs-drive/src/drive/initialization/v2/mod.rs (1)
packages/rs-drive/src/drive/saved_block_transactions/queries.rs (1)
  • saved_block_transactions_path (18-20)
packages/rs-drive/src/drive/saved_block_transactions/fetch_address_balances/v0/mod.rs (2)
packages/rs-drive/src/drive/initialization/v0/mod.rs (2)
  • drive (38-187)
  • drive (190-225)
packages/rs-drive/src/drive/saved_block_transactions/queries.rs (1)
  • saved_block_transactions_address_balances_path_vec (23-28)
packages/rs-drive/src/drive/saved_block_transactions/queries.rs (1)
packages/rs-drive/src/drive/initialization/v2/mod.rs (1)
  • drive (70-103)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci, SDK_TEST_DATA=true
    ) / Build Drive image
  • GitHub Check: Build JS packages / Build JS
  • GitHub Check: Rust crates security audit
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs (1)

122-151: Consider handling unexpected element types explicitly.

The pattern match only handles Some(Element::CountSumTree(...)). If the element exists but is a different type (e.g., due to data corruption or a bug), the function silently proceeds without compaction checks. This could mask underlying issues.

Consider adding a match arm for unexpected element types:

🔎 Proposed defensive handling
         if let Some(Element::CountSumTree(_, count, sum, _)) = tree_element {
             // ... existing logic ...
+        } else if tree_element.is_some() {
+            // Unexpected element type - log warning or return error
+            tracing::warn!(
+                "Expected CountSumTree for address balances but found different element type"
+            );
         }

         Ok(false)
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c15aa4a and 45f4716.

📒 Files selected for processing (1)
  • packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Rust code must pass cargo clippy --workspace linter checks
Rust code must be formatted using cargo fmt --all

**/*.rs: Use 4-space indent for Rust files
Follow rustfmt defaults and keep code clippy-clean for Rust modules
Use snake_case for Rust module names
Use PascalCase for Rust type names
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs
🧠 Learnings (3)
📓 Common learnings
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/src/mimic/test_quorum.rs:159-164
Timestamp: 2024-11-20T16:16:01.830Z
Learning: QuantumExplorer prefers not to receive auto-generated messages asking to post on social media.
📚 Learning: 2024-10-08T13:28:03.529Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-drive-abci/src/platform_types/platform_state/mod.rs:141-141
Timestamp: 2024-10-08T13:28:03.529Z
Learning: When converting `PlatformStateV0` to `PlatformStateForSavingV1` in `packages/rs-drive-abci/src/platform_types/platform_state/mod.rs`, only version `0` needs to be handled in the match on `platform_state_for_saving_structure_default` because the changes are retroactive.

Applied to files:

  • packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs
📚 Learning: 2024-11-22T08:19:14.448Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2345
File: packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs:93-99
Timestamp: 2024-11-22T08:19:14.448Z
Learning: In `packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs`, the `insert_contract` method requires an owned `BlockInfo`, so cloning `block_info` is necessary when calling it.

Applied to files:

  • packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs
🧬 Code graph analysis (1)
packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs (1)
packages/rs-drive/src/drive/saved_block_transactions/queries.rs (1)
  • saved_block_transactions_address_balances_path (31-36)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (dapi-grpc) / Linting
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (dapi-grpc) / Unused dependencies
  • GitHub Check: Rust packages (dapi-grpc) / Check each feature
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci, SDK_TEST_DATA=true
    ) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build JS packages / Build JS
  • GitHub Check: Rust crates security audit
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
🔇 Additional comments (5)
packages/rs-drive/src/drive/saved_block_transactions/store_address_balances/v0/mod.rs (5)

1-12: LGTM!

Imports are well-organized and appropriate for the functionality implemented.


26-96: LGTM - Well-structured storage implementation.

The function correctly:

  • Early exits on empty balances to avoid unnecessary operations
  • Delegates compaction check before storing
  • Uses big-endian encoding for block height keys to ensure proper ordering
  • Properly handles serialization errors with descriptive messages

155-166: LGTM - Well-organized test setup.

The test constants and helper function provide a clean foundation for the comprehensive test suite.


186-489: Comprehensive test coverage for core functionality.

The tests thoroughly cover:

  • Block count threshold triggering compaction
  • Address count threshold triggering compaction
  • Correct merging of AddToCredits operations (summing)
  • Correct merging of SetCredits + AddToCredits (set value + add)
  • Override behavior when SetCredits follows AddToCredits
  • Empty balance handling
  • Multiple compaction cycles

491-742: Good query and filter tests.

Tests cover:

  • Start height filtering for compacted data
  • Limit constraints on query results
  • Coexistence of recent and compacted data
  • Start height filtering for recent data

One observation: all tests use None for the transaction argument. Consider adding a test with an actual transaction to verify transactional behavior if the production code path uses transactions.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs (1)

166-226: Refactor to eliminate code duplication.

The balance tracking logic in lines 179-201 and 203-225 is identical. Both branches track adjusted_amount using the same merge rules, regardless of whether fees were taken. The tracking should be moved outside the if-else block to improve maintainability.

🔎 Proposed refactor
             for (address, original_amount) in added_to_balance_outputs.iter() {
                 let adjusted_amount = adjusted_outputs.get(address).copied().unwrap_or(0);
                 if original_amount > &adjusted_amount {
                     let amount_to_remove = original_amount - adjusted_amount;
                     self.drive.remove_balance_from_address(
                         *address,
                         amount_to_remove,
                         &mut None,
                         &mut fee_drive_operations,
                         Some(transaction),
                         platform_version,
                     )?;
+                }
 
-                    // Track the adjusted amount being added (after fee deduction)
-                    if let Some(balance_updates) = address_balances_in_update.as_mut() {
-                        let new_op = CreditOperation::AddToCredits(adjusted_amount);
-                        balance_updates
-                            .entry(*address)
-                            .and_modify(|existing| {
-                                *existing = match existing {
-                                    // Set + Add = Set to combined value
-                                    CreditOperation::SetCredits(set_val) => {
-                                        CreditOperation::SetCredits(
-                                            set_val.saturating_add(adjusted_amount),
-                                        )
-                                    }
-                                    // Add + Add = saturating add
-                                    CreditOperation::AddToCredits(add_val) => {
-                                        CreditOperation::AddToCredits(
-                                            add_val.saturating_add(adjusted_amount),
-                                        )
-                                    }
-                                };
-                            })
-                            .or_insert(new_op);
-                    }
-                } else {
-                    // No fee taken from this output, track the full amount being added
-                    if let Some(balance_updates) = address_balances_in_update.as_mut() {
-                        let new_op = CreditOperation::AddToCredits(adjusted_amount);
-                        balance_updates
-                            .entry(*address)
-                            .and_modify(|existing| {
-                                *existing = match existing {
-                                    // Set + Add = Set to combined value
-                                    CreditOperation::SetCredits(set_val) => {
-                                        CreditOperation::SetCredits(
-                                            set_val.saturating_add(adjusted_amount),
-                                        )
-                                    }
-                                    // Add + Add = saturating add
-                                    CreditOperation::AddToCredits(add_val) => {
-                                        CreditOperation::AddToCredits(
-                                            add_val.saturating_add(adjusted_amount),
-                                        )
-                                    }
-                                };
-                            })
-                            .or_insert(new_op);
-                    }
+                // Track the adjusted amount being added (after any fee deduction)
+                if let Some(balance_updates) = address_balances_in_update.as_mut() {
+                    let new_op = CreditOperation::AddToCredits(adjusted_amount);
+                    balance_updates
+                        .entry(*address)
+                        .and_modify(|existing| {
+                            *existing = match existing {
+                                // Set + Add = Set to combined value
+                                CreditOperation::SetCredits(set_val) => {
+                                    CreditOperation::SetCredits(
+                                        set_val.saturating_add(adjusted_amount),
+                                    )
+                                }
+                                // Add + Add = saturating add
+                                CreditOperation::AddToCredits(add_val) => {
+                                    CreditOperation::AddToCredits(
+                                        add_val.saturating_add(adjusted_amount),
+                                    )
+                                }
+                            };
+                        })
+                        .or_insert(new_op);
                 }
             }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 45f4716 and ea816b6.

📒 Files selected for processing (2)
  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/mod.rs
  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Rust code must pass cargo clippy --workspace linter checks
Rust code must be formatted using cargo fmt --all

**/*.rs: Use 4-space indent for Rust files
Follow rustfmt defaults and keep code clippy-clean for Rust modules
Use snake_case for Rust module names
Use PascalCase for Rust type names
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/mod.rs
  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs
🧠 Learnings (13)
📓 Common learnings
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/src/mimic/test_quorum.rs:159-164
Timestamp: 2024-11-20T16:16:01.830Z
Learning: QuantumExplorer prefers not to receive auto-generated messages asking to post on social media.
📚 Learning: 2024-10-06T16:18:07.994Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:119-120
Timestamp: 2024-10-06T16:18:07.994Z
Learning: In the `run_block_proposal` function in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, it's acceptable to pass `platform_state` to `perform_events_on_first_block_of_protocol_change`, even if `block_platform_state` has been updated.

Applied to files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/mod.rs
  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs
📚 Learning: 2024-10-08T13:28:03.529Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-drive-abci/src/platform_types/platform_state/mod.rs:141-141
Timestamp: 2024-10-08T13:28:03.529Z
Learning: When converting `PlatformStateV0` to `PlatformStateForSavingV1` in `packages/rs-drive-abci/src/platform_types/platform_state/mod.rs`, only version `0` needs to be handled in the match on `platform_state_for_saving_structure_default` because the changes are retroactive.

Applied to files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/mod.rs
  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs
📚 Learning: 2024-11-22T08:19:14.448Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2345
File: packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs:93-99
Timestamp: 2024-11-22T08:19:14.448Z
Learning: In `packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs`, the `insert_contract` method requires an owned `BlockInfo`, so cloning `block_info` is necessary when calling it.

Applied to files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/mod.rs
  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs
📚 Learning: 2024-10-06T16:17:34.571Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:105-105
Timestamp: 2024-10-06T16:17:34.571Z
Learning: In `run_block_proposal` in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, when retrieving `last_block_time_ms`, it's acceptable to use `platform_state` instead of `block_platform_state`, even after updating the protocol version.

Applied to files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/mod.rs
📚 Learning: 2024-11-20T10:01:50.837Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/src/platform_types/platform_state/v0/old_structures/mod.rs:94-94
Timestamp: 2024-11-20T10:01:50.837Z
Learning: In `packages/rs-drive-abci/src/platform_types/platform_state/v0/old_structures/mod.rs`, when converting with `PublicKey::try_from`, it's acceptable to use `.expect()` to handle potential conversion errors.

Applied to files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/mod.rs
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v1/mod.rs:19-30
Timestamp: 2024-10-09T00:22:57.778Z
Learning: In the Rust file `packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v1/mod.rs`, within the `create_owner_identity_v1` function, the `add_public_keys` method of the `Identity` struct cannot fail and does not require explicit error handling.

Applied to files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/mod.rs
📚 Learning: 2024-10-28T10:38:49.538Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2259
File: packages/rs-dapi-client/src/executor.rs:49-56
Timestamp: 2024-10-28T10:38:49.538Z
Learning: In `packages/rs-dapi-client/src/executor.rs`, the `ExecutionResponse` struct always has a non-optional `address` field of type `Address` because an address is always present when there's a successful response.

Applied to files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/mod.rs
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2201
File: packages/rs-platform-version/src/version/v2.rs:1186-1188
Timestamp: 2024-10-09T00:22:57.778Z
Learning: In the `IdentityTransitionVersions` structure within `packages/rs-platform-version/src/version/v2.rs`, the field `credit_withdrawal` does not need the `identity_` prefix since it is already encompassed within identity state transitions.

Applied to files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/mod.rs
  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs
📚 Learning: 2025-10-09T15:59:28.329Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2716
File: packages/rs-dapi/src/services/platform_service/broadcast_state_transition.rs:181-187
Timestamp: 2025-10-09T15:59:28.329Z
Learning: In `packages/rs-dapi/src/services/platform_service/broadcast_state_transition.rs`, the maintainer requires logging full state transition bytes (`tx_bytes = hex::encode(st_bytes)`) at debug level when a state transition passes CheckTx but is removed from the block by the proposer, to facilitate debugging of this rare edge case.

Applied to files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2186
File: packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_credit_withdrawal/mod.rs:48-54
Timestamp: 2024-10-09T00:22:57.778Z
Learning: In the identity credit withdrawal transition code, the field `platform_version.drive_abci.validation_and_processing.state_transitions.identity_credit_withdrawal_state_transition.transform_into_action` is not an `Option` type, so handling `None` cases is unnecessary.

Applied to files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs
📚 Learning: 2025-05-02T18:13:31.615Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2584
File: packages/rs-dpp/src/data_contract/methods/registration_cost/v1/mod.rs:31-78
Timestamp: 2025-05-02T18:13:31.615Z
Learning: In fee calculation contexts, saturating arithmetic operations (like saturating_add and saturating_mul) are acceptable as users would never practically be able to pay fees approaching u64::MAX. Explicit overflow checking is unnecessary in these scenarios.

Applied to files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs
📚 Learning: 2024-10-21T01:03:42.458Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-dpp/src/fee/default_costs/mod.rs:140-153
Timestamp: 2024-10-21T01:03:42.458Z
Learning: In the method `active_fee_version` in `packages/rs-dpp/src/fee/default_costs/mod.rs`, using `.unwrap_or_else(|| FeeVersion::first())` is appropriate and does not cause lifetime issues when returning `&'static FeeVersion`.

Applied to files:

  • packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs
🧬 Code graph analysis (1)
packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/mod.rs (2)
packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_address_balances_to_recent_block_storage/mod.rs (1)
  • execution (34-60)
packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs (1)
  • execution (39-80)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (wasm-dpp) / Tests
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (dpp) / Unused dependencies
  • GitHub Check: Rust packages (wasm-dpp2) / Tests
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci, SDK_TEST_DATA=true
    ) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build JS packages / Build JS
  • GitHub Check: Rust crates security audit
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
🔇 Additional comments (9)
packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/mod.rs (3)

8-12: LGTM!

The new imports are necessary for the address_balances_in_update parameter and are correctly placed.


30-30: LGTM!

The documentation for the new parameter is clear, and the clippy allow is appropriate given the additional parameter for threading context through execution layers.

Also applies to: 44-44


51-51: LGTM!

The parameter type and passing are correct. The Option wrapper appropriately allows callers to opt out of balance tracking when not needed.

Also applies to: 66-66

packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs (6)

15-15: LGTM!

The CreditOperation import is necessary for the balance tracking functionality.


115-115: LGTM!

The parameter signature is correct for threading balance updates through the execution path.


230-267: LGTM!

The input balance tracking logic is correct. Using SetCredits for inputs (rather than AddToCredits for outputs) properly reflects that input balances are set to their final adjusted value. The merge rules correctly handle all combinations.


323-323: LGTM!

The parameter addition and clippy allow are appropriate for threading balance tracking through the execution pipeline.

Also applies to: 330-330


373-426: LGTM!

The tracking of added_to_balance_outputs after the identity function is correct. This properly captures balance changes for state transitions like IdentityCreditTransferToAddresses where outputs are separate from the identity's own balance adjustment. The merge logic is consistent with the rules used elsewhere in the file.


452-452: LGTM!

The parameter is correctly passed through to handle balance tracking for address-input-based payments.

Copy link
Member Author

@QuantumExplorer QuantumExplorer left a comment

Choose a reason for hiding this comment

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

Self Reviewed

@QuantumExplorer QuantumExplorer merged commit c81b1fe into v3.0-dev Dec 30, 2025
13 of 15 checks passed
@QuantumExplorer QuantumExplorer deleted the feat/historicalStorage branch December 30, 2025 17:07
@thephez thephez added the dapi-endpoint DAPI endpoint addition or modification label Dec 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dapi-endpoint DAPI endpoint addition or modification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants