Skip to content

Conversation

@pauldelucia
Copy link
Member

@pauldelucia pauldelucia commented Dec 2, 2025

Summary

  • Add DIP-17 Platform Payment account type for key derivation
  • Add derivation path support: m/9'/coin_type'/17'/account'/key_class'/index
  • Add FFI bindings for Platform Payment accounts

Details

This PR adds support for DIP-17 Platform Payment key derivation to the key-wallet crate. The address encoding (DIP-18 bech32m with dashevo/tdashevo HRP) is handled by the Platform repo.

Changes

  • AccountType::PlatformPayment - New account type with account and key_class indices
  • ManagedAccountType::PlatformPayment - Managed account with address pool
  • DIP-17 derivation paths - PLATFORM_PAYMENT_PATH_MAINNET and PLATFORM_PAYMENT_PATH_TESTNET
  • FFI support - FFIAccountType::PlatformPayment with conversion functions
  • Test vectors - DIP-17 key derivation tests verifying private key, public key, and HASH160

Notes

  • Key derivation produces standard ECDSA keys with HASH160
  • Address encoding uses bech32m format (implemented in Platform repo)
  • Platform Payment accounts use a single address pool (no internal/external distinction)

Test plan

  • DIP-17 test vectors pass (key derivation)
  • cargo test -p key-wallet passes
  • Full workspace builds

Summary by CodeRabbit

  • New Features

    • Full support for Platform Payment (DIP‑17) accounts: account type, management, address derivation/pooling, platform root paths; recognized by wallet but not used for Core‑chain transactions.
    • ECDSA-derived keys now consistently produce P2PKH-style addresses.
    • Added public DIP‑17 gap limit constant.
  • Tests

    • Added comprehensive DIP‑17 derivation test vectors for mainnet, testnet, and non-default key_class scenarios.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

Walkthrough

A new PlatformPayment (DIP-17) account type was added across core and FFI layers: new enum variants, derivation path constants and gap limit, new account/key types and collections, managed-account plumbing and address-pool handling, transaction-checking wiring (no Core-chain processing), FFI mappings, and derivation tests.

Changes

Cohort / File(s) Summary
Core account model
key-wallet/src/account/account_type.rs, key-wallet/src/account/account_collection.rs
Added AccountType::PlatformPayment { account, key_class }, PlatformPaymentAccountKey and platform_payment_accounts collection; extended insert/lookup/aggregation and derivation-path logic for DIP-17.
Derivation & constants
key-wallet/src/dip9.rs, key-wallet/src/gap_limit.rs
Added DerivationPathReference::PlatformPayment, FEATURE_PURPOSE_PLATFORM_PAYMENT, mainnet/testnet PLATFORM_PAYMENT root paths, and DIP17_GAP_LIMIT = 20.
Managed accounts & pools
key-wallet/src/managed_account/managed_account_type.rs, key-wallet/src/managed_account/managed_account_collection.rs, key-wallet/src/managed_account/mod.rs, key-wallet/src/managed_account/address_pool.rs
Added ManagedAccountType::PlatformPayment with AddressPool; added platform_payment_accounts to managed collection; create/insert/contains/from_account_collection updated; address generation for ECDSA simplified to P2PKH.
Transaction checking & routing
key-wallet/src/transaction_checking/account_checker.rs, key-wallet/src/transaction_checking/transaction_router/mod.rs, key-wallet/src/transaction_checking/wallet_checker.rs, key-wallet/src/wallet/helper.rs
Introduced AccountTypeMatch::PlatformPayment and AccountTypeToCheck::PlatformPayment; wired through checking and routing; wallet helper returns None for PlatformPayment extended public key (no Core-chain usage); wallet checker treats PlatformPayment as no-op.
FFI surface
key-wallet-ffi/include/key_wallet_ffi.h, key-wallet-ffi/src/types.rs, key-wallet-ffi/src/managed_account.rs, key-wallet-ffi/src/address_pool.rs, key-wallet-ffi/src/transaction_checking.rs
Added FFIAccountType::PlatformPayment = 13; mapped conversions and panic path for unsupported to_account_type; FFI managed-account lookups and address-pool resolution updated to handle PlatformPayment; transaction-checking conversion maps PlatformPayment into FFI match struct.
Tests
key-wallet/tests/derivation_tests.rs
Added DIP-17 Platform Payment derivation test vectors (mainnet/testnet, non-default key_class) verifying derived keys/HASH160s and basic encoding expectations.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Wallet / Creator
    participant AccountColl as AccountCollection
    participant ManagedColl as ManagedAccountCollection
    participant AddrPool as AddressPool
    participant FFI as FFI boundary
    participant TxChecker as TransactionChecker

    Caller->>AccountColl: insert AccountType::PlatformPayment{account,key_class}
    AccountColl->>ManagedColl: from_account_collection(...) (copies platform_payment_accounts)
    ManagedColl->>AddrPool: AddressPool::new(DIP17_GAP_LIMIT, derivation_path)
    AddrPool-->>ManagedColl: addresses
    ManagedColl-->>FFI: exposed via FFIAccountType::PlatformPayment (enum value 13)
    Note right of FFI: External client may request account info
    FFI->>ManagedColl: lookup managed account by PlatformPayment
    ManagedColl-->>FFI: returns ManagedAccountType::PlatformPayment (addresses)
    FFI->>TxChecker: pass account type to transaction checking
    TxChecker-->>FFI: returns no-op / empty match (PlatformPayment not used on Core chain)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus areas:
    • key-wallet/src/account/account_type.rs — DIP-17 derivation_path construction (hardened indices).
    • ManagedAccountCollectionAccountCollection conversions and initialization (platform_payment_accounts).
    • FFI enum/value alignment and to_account_type panic semantics in key-wallet-ffi/src/types.rs and include/key_wallet_ffi.h.
    • Transaction-checking paths and wallet helper behavior to confirm PlatformPayment is intentionally no-op for Core-chain flows.

Possibly related PRs

  • feat: dashpay support #177 — Adds a new account-type variant and extends matching/handling in similar code paths (managed accounts, FFI types, transaction checking); closely related implementation pattern.

Poem

🐰 A platform hop, DIP‑17 in tow,
Paths and keys in a moonlit row,
Pools gather addresses, FFI chants "thirteen",
Tests nod along, the derivations keen —
Hop, little rabbit, the ledger's aglow! 🎉

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 title accurately summarizes the main change: adding DIP-17 Platform Payment account support to the key-wallet crate.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/platform-addresses

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.

@pauldelucia pauldelucia changed the title Feat/platform addresses feat(key-wallet): Implement DIP17/DIP18 Platform Payment Addresses Dec 2, 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: 3

Caution

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

⚠️ Outside diff range comments (2)
key-wallet/src/account/account_collection.rs (2)

553-576: is_empty() missing check for platform_payment_accounts.

The is_empty() method doesn't include a check for platform_payment_accounts.is_empty(), which means it will incorrectly return true if only PlatformPayment accounts exist.

         && self.provider_owner_keys.is_none();
 
     #[cfg(feature = "bls")]
     {
         is_empty = is_empty && self.provider_operator_keys.is_none();
     }
 
     #[cfg(feature = "eddsa")]
     {
         is_empty = is_empty && self.provider_platform_keys.is_none();
     }
 
+    is_empty = is_empty
+        && self.dashpay_receival_accounts.is_empty()
+        && self.dashpay_external_accounts.is_empty()
+        && self.platform_payment_accounts.is_empty();
+
     is_empty

Note: dashpay_receival_accounts and dashpay_external_accounts also appear to be missing from the is_empty() check.


579-597: clear() missing cleanup for several account maps.

The clear() method doesn't clear dashpay_receival_accounts, dashpay_external_accounts, or the new platform_payment_accounts, which could leave stale data after clearing.

     pub fn clear(&mut self) {
         self.standard_bip44_accounts.clear();
         self.standard_bip32_accounts.clear();
         self.coinjoin_accounts.clear();
         self.identity_registration = None;
         self.identity_topup.clear();
         self.identity_topup_not_bound = None;
         self.identity_invitation = None;
         self.provider_voting_keys = None;
         self.provider_owner_keys = None;
         #[cfg(feature = "bls")]
         {
             self.provider_operator_keys = None;
         }
         #[cfg(feature = "eddsa")]
         {
             self.provider_platform_keys = None;
         }
+        self.dashpay_receival_accounts.clear();
+        self.dashpay_external_accounts.clear();
+        self.platform_payment_accounts.clear();
     }
🧹 Nitpick comments (4)
key-wallet-ffi/src/transaction_checking.rs (1)

458-478: PlatformPayment mapping into FFITransactionCheckResult is correct

The AccountTypeMatch::PlatformPayment arm correctly:

  • propagates account_index, received, and sent,
  • derives external_addresses_count/has_external_addresses from involved_addresses,
  • sets account_type to 13 in line with FFIAccountType::PLATFORM_PAYMENT.

This mirrors DashPay handling and keeps FFI in sync with the new account type, while remaining defensive about platform addresses not being used on Core chain.

If you ever touch this area again, consider defining a shared Rust FFIAccountType enum or constants instead of raw integers (0–13) to avoid accidental drift with the generated C header.

key-wallet/src/managed_account/address_pool.rs (1)

397-418: Platform address pool support is correct; consider tightening PlatformP2sh handling

  • new_platform cleanly reuses new_without_generation, flips address_type to PlatformP2pkh, and optionally pre‑generates up to the gap limit when a key source is available, matching the existing pool semantics but with DIP‑18 address types.
  • is_platform gives a simple, type‑level way to gate Platform pools (e.g., exclude them from Core‑chain transaction checking), which aligns with the DIP‑17 requirement that Platform addresses not be used on Core.
  • Extending generate_address_at_index to call Address::platform_p2pkh for AddressType::PlatformP2pkh is exactly what we want for Platform payment addresses.

The only nuance is the AddressType::PlatformP2sh branch currently defaulting to platform_p2pkh, which is safe but potentially surprising if anyone later assumes genuine P2SH semantics.

Consider, when you need stricter behavior, returning a dedicated error for AddressType::PlatformP2sh in this context (e.g., “PlatformP2sh generation not supported in AddressPool; script required”) instead of silently mapping it to P2PKH. That keeps library code non‑panicking per guidelines while making any misuse explicit.

Also applies to: 425-428, 513-519

key-wallet/src/managed_account/managed_account_collection.rs (1)

730-777: all_accounts() does not include platform_payment_accounts.

The all_accounts() method returns all accounts but does not include platform_payment_accounts. Similarly, all_accounts_mut() (lines 781-828), is_empty() (lines 856-870), and clear() (lines 873-887) also omit this field.

This may be intentional to exclude Platform accounts from Core wallet operations, but could cause issues if these methods are used for wallet-wide operations like serialization or total balance calculation.

If Platform accounts should be accessible via these methods, add them:

 // In all_accounts()
 accounts.extend(self.dashpay_receival_accounts.values());
 accounts.extend(self.dashpay_external_accounts.values());
+accounts.extend(self.platform_payment_accounts.values());

 accounts

 // In is_empty()
 && self.dashpay_receival_accounts.is_empty()
 && self.dashpay_external_accounts.is_empty()
+&& self.platform_payment_accounts.is_empty()

 // In clear()
 self.dashpay_receival_accounts.clear();
 self.dashpay_external_accounts.clear();
+self.platform_payment_accounts.clear();
dash/src/address.rs (1)

535-548: Potential risk: Platform addresses can generate Core-compatible scripts.

The script_pubkey() method generates equivalent P2PKH/P2SH scripts for Platform addresses. While documented with a warning, this could lead to accidental fund loss if a developer calls script_pubkey() on a Platform address and uses it in a Core transaction.

Consider returning an error or a distinct script type for Platform addresses to prevent accidental misuse:

/// Generates a script pubkey spending to this [Payload].
///
/// Note: For Platform addresses, this generates the equivalent Core chain script,
/// but Platform addresses should NOT be used in Core chain transactions.
/// Consider using `script_pubkey_checked()` which returns an error for Platform addresses.
pub fn script_pubkey(&self) -> ScriptBuf {
    // ... existing implementation
}

/// Generates a script pubkey, returning an error for Platform addresses.
pub fn script_pubkey_checked(&self) -> Result<ScriptBuf, Error> {
    if self.is_platform() {
        return Err(Error::PlatformAddressNotForCore);
    }
    Ok(self.script_pubkey())
}

Alternatively, add a runtime check or logging when script_pubkey() is called on Platform addresses to help catch misuse during development.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e24799d and 9f8a29c.

📒 Files selected for processing (19)
  • dash/src/address.rs (17 hunks)
  • dash/src/blockdata/constants.rs (1 hunks)
  • key-wallet-ffi/include/key_wallet_ffi.h (1 hunks)
  • key-wallet-ffi/src/address_pool.rs (2 hunks)
  • key-wallet-ffi/src/managed_account.rs (3 hunks)
  • key-wallet-ffi/src/transaction_checking.rs (1 hunks)
  • key-wallet-ffi/src/types.rs (3 hunks)
  • key-wallet/src/account/account_collection.rs (9 hunks)
  • key-wallet/src/account/account_type.rs (5 hunks)
  • key-wallet/src/dip9.rs (3 hunks)
  • key-wallet/src/managed_account/address_pool.rs (2 hunks)
  • key-wallet/src/managed_account/managed_account_collection.rs (7 hunks)
  • key-wallet/src/managed_account/managed_account_type.rs (6 hunks)
  • key-wallet/src/managed_account/mod.rs (4 hunks)
  • key-wallet/src/transaction_checking/account_checker.rs (6 hunks)
  • key-wallet/src/transaction_checking/transaction_router/mod.rs (3 hunks)
  • key-wallet/src/transaction_checking/wallet_checker.rs (1 hunks)
  • key-wallet/src/wallet/helper.rs (1 hunks)
  • key-wallet/tests/derivation_tests.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Never hardcode network parameters, addresses, or keys in Rust code
Use proper error types with thiserror crate and propagate errors appropriately in Rust code
Use tokio runtime for async operations in Rust code
Use conditional compilation with feature flags for optional features
Write unit tests for new functionality in Rust
Format Rust code with cargo fmt before committing
Ensure clippy passes with all warnings as errors on all Rust code

**/*.rs: Each crate keeps sources in src/; unit tests live alongside code with #[cfg(test)]
Maintain MSRV of 1.89 for Rust code
Format Rust code with rustfmt (see rustfmt.toml); run cargo fmt --all before commits
Lint Rust code with clippy; avoid unwrap()/expect() in library code; use error types (e.g., thiserror)
Use snake_case for function and variable names in Rust
Use UpperCamelCase for types and traits in Rust
Use SCREAMING_SNAKE_CASE for constants in Rust
Follow mixed editions (2021/2024) and crate-specific idioms; prefer async via tokio where applicable
Unit tests should be placed near code with descriptive names (e.g., test_parse_address_mainnet)
Use #[ignore] for network-dependent or long-running tests; run with -- --ignored flag
Never commit secrets or real keys; avoid logging sensitive data in Rust code
Keep test vectors deterministic in Rust test code

Files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/dip9.rs
  • key-wallet/src/wallet/helper.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet-ffi/src/managed_account.rs
  • dash/src/blockdata/constants.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet/tests/derivation_tests.rs
  • key-wallet-ffi/src/transaction_checking.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/transaction_checking/account_checker.rs
  • dash/src/address.rs
key-wallet/**/transaction_checking/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/transaction_checking/**/*.rs: Use TransactionRouter::classify_transaction() to determine transaction type and get_relevant_account_types() to avoid checking all accounts for every transaction; route CoinJoin and other specialized transactions only to relevant account types
In SPV sync integration, use wallet_info.check_transaction() with appropriate TransactionContext and update wallet state atomically only when is_relevant flag is true

Files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet/src/transaction_checking/account_checker.rs
key-wallet/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/*.rs: Never panic in library code; use Result<T> for all fallible operations with custom Error type variants and provide context in error messages
Use ? operator for error propagation in Rust code to maintain clean error handling patterns

Files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/dip9.rs
  • key-wallet/src/wallet/helper.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet/tests/derivation_tests.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/transaction_checking/account_checker.rs
key-wallet/**/{wallet,account,managed_account,address_pool}/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

Always validate network consistency: use the account's network type when creating addresses and assert that operations use the expected network to prevent mainnet/testnet mixing

Files:

  • key-wallet/src/wallet/helper.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
key-wallet/**/{wallet,account,managed_account}/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/{wallet,account,managed_account}/**/*.rs: Use BTreeMap for ordered data structures (accounts, transactions) and HashMap for quick lookups (address to index mapping) to optimize data structure performance
Clearly separate watch-only wallets from full wallets using the wallet type system; never attempt signing operations on watch-only accounts and validate external signatures match expected pubkeys

Files:

  • key-wallet/src/wallet/helper.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
key-wallet/**/{account,managed_account}/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/{account,managed_account}/**/*.rs: Separate immutable and mutable concerns: Use Account for immutable identity information (keys, derivation paths) and ManagedAccount for mutable state (address pools, metadata, balances)
Use strongly typed enum-based system for AccountType with specific variants (Standard, Identity, Masternode, etc.) to provide compile-time safety for different account purposes

Files:

  • key-wallet/src/account/account_type.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
key-wallet/**/{bip32,derivation,account}/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

Use ExtendedPubKey and ExtendedPrivKey from the BIP32 implementation for key derivation; avoid direct private key exposure or serialization in logs

Files:

  • key-wallet/src/account/account_type.rs
  • key-wallet/src/account/account_collection.rs
**/*-ffi/src/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Careful handling of memory safety at FFI boundaries in Rust code

Files:

  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet-ffi/src/transaction_checking.rs
key-wallet/**/managed_account/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

Implement atomic state updates in ManagedAccount: when processing transactions, update address usage state, UTXO set, transaction history, and balance calculations together to maintain consistency

Files:

  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
**/tests/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/tests/**/*.rs: Write integration tests for network operations in Rust
Test both mainnet and testnet configurations
Use proptest for property-based testing where appropriate in Rust

Integration tests use tests/ directory (e.g., rpc-integration-test)

Files:

  • key-wallet/tests/derivation_tests.rs
key-wallet/**/tests/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/tests/**/*.rs: Use deterministic test vectors with fixed seeds and known test vectors in unit tests for key derivation, mnemonic generation, and address generation to ensure reproducibility
Organize tests by functionality: BIP32 key derivation, mnemonic generation/validation, address generation/validation, path derivation, and PSBT serialization in separate test files

Files:

  • key-wallet/tests/derivation_tests.rs
🧠 Learnings (32)
📓 Common learnings
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Keep test vectors updated with Dash Core, monitor for new DIPs affecting wallet structure, maintain backward compatibility for serialized wallets, and update derivation paths for Platform features
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Support future enhancements: prepare architecture for Schnorr/Taproot support, descriptor wallets, native multisig account types, and Lightning Network payment channel key management
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{bip32,derivation,account}/**/*.rs : Use `ExtendedPubKey` and `ExtendedPrivKey` from the BIP32 implementation for key derivation; avoid direct private key exposure or serialization in logs
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Support multiple `KeySource` variants (Private, Public, NoKeySource) in address pool initialization to enable both full wallets and watch-only wallets with the same interface
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: dash-spv/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:17.379Z
Learning: Applies to dash-spv/src/wallet/**/*.rs : Implement wallet functionality with UTXO tracking, balance calculation with confirmation states, and transaction processing
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T08:01:18.174Z
Learning: Organize workspace with crates: `dash`, `hashes`, `internals`, `dash-network`, `dash-spv`, `key-wallet`, `rpc-*`, utilities (`fuzz`, `test-utils`), and FFI crates (`*-ffi`)
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: swift-dash-core-sdk/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:50.618Z
Learning: Applies to swift-dash-core-sdk/**/*.rs : Implement new FFI functions in Rust with `#[no_mangle] extern "C"` annotation in dash-spv-ffi
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Use strongly typed enum-based system for `AccountType` with specific variants (Standard, Identity, Masternode, etc.) to provide compile-time safety for different account purposes
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account}/**/*.rs : Clearly separate watch-only wallets from full wallets using the wallet type system; never attempt signing operations on watch-only accounts and validate external signatures match expected pubkeys
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/transaction_checking/**/*.rs : Use `TransactionRouter::classify_transaction()` to determine transaction type and `get_relevant_account_types()` to avoid checking all accounts for every transaction; route CoinJoin and other specialized transactions only to relevant account types

Applied to files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/wallet/helper.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet-ffi/src/transaction_checking.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/transaction_checking/account_checker.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account}/**/*.rs : Clearly separate watch-only wallets from full wallets using the wallet type system; never attempt signing operations on watch-only accounts and validate external signatures match expected pubkeys

Applied to files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/dip9.rs
  • key-wallet/src/wallet/helper.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet-ffi/src/transaction_checking.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/transaction_checking/account_checker.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Use strongly typed enum-based system for `AccountType` with specific variants (Standard, Identity, Masternode, etc.) to provide compile-time safety for different account purposes

Applied to files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet-ffi/include/key_wallet_ffi.h
  • key-wallet/src/dip9.rs
  • key-wallet/src/wallet/helper.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet-ffi/src/transaction_checking.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/transaction_checking/account_checker.rs
  • dash/src/address.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account,address_pool}/**/*.rs : Always validate network consistency: use the account's network type when creating addresses and assert that operations use the expected network to prevent mainnet/testnet mixing

Applied to files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet/tests/derivation_tests.rs
  • key-wallet-ffi/src/transaction_checking.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/transaction_checking/account_checker.rs
  • dash/src/address.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/transaction_checking/**/*.rs : In SPV sync integration, use `wallet_info.check_transaction()` with appropriate `TransactionContext` and update wallet state atomically only when `is_relevant` flag is true

Applied to files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet-ffi/src/transaction_checking.rs
  • key-wallet/src/transaction_checking/account_checker.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/managed_account/**/*.rs : Implement atomic state updates in ManagedAccount: when processing transactions, update address usage state, UTXO set, transaction history, and balance calculations together to maintain consistency

Applied to files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet-ffi/src/transaction_checking.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/transaction_checking/account_checker.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Separate immutable and mutable concerns: Use `Account` for immutable identity information (keys, derivation paths) and `ManagedAccount` for mutable state (address pools, metadata, balances)

Applied to files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/wallet/helper.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet-ffi/src/transaction_checking.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/transaction_checking/account_checker.rs
📚 Learning: 2025-12-01T08:00:17.379Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: dash-spv/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:17.379Z
Learning: Applies to dash-spv/src/wallet/**/*.rs : Implement wallet functionality with UTXO tracking, balance calculation with confirmation states, and transaction processing

Applied to files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet-ffi/src/transaction_checking.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{bip32,derivation,account}/**/*.rs : Use `ExtendedPubKey` and `ExtendedPrivKey` from the BIP32 implementation for key derivation; avoid direct private key exposure or serialization in logs

Applied to files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/dip9.rs
  • key-wallet/src/wallet/helper.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet/tests/derivation_tests.rs
  • key-wallet-ffi/src/transaction_checking.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/transaction_checking/account_checker.rs
  • dash/src/address.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account}/**/*.rs : Use BTreeMap for ordered data structures (accounts, transactions) and HashMap for quick lookups (address to index mapping) to optimize data structure performance

Applied to files:

  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet-ffi/src/transaction_checking.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/transaction_checking/account_checker.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Keep test vectors updated with Dash Core, monitor for new DIPs affecting wallet structure, maintain backward compatibility for serialized wallets, and update derivation paths for Platform features

Applied to files:

  • key-wallet/src/dip9.rs
  • dash/src/blockdata/constants.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet/tests/derivation_tests.rs
  • dash/src/address.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{bip32,derivation}/**/*.rs : Cache intermediate derivation results and use hardened derivation only when required; batch derive child keys when possible to optimize derivation performance

Applied to files:

  • key-wallet/src/dip9.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Support multiple `KeySource` variants (Private, Public, NoKeySource) in address pool initialization to enable both full wallets and watch-only wallets with the same interface

Applied to files:

  • key-wallet/src/dip9.rs
  • key-wallet/src/wallet/helper.rs
  • key-wallet/src/account/account_type.rs
  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet/src/account/account_collection.rs
  • key-wallet/src/transaction_checking/transaction_router/mod.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet/tests/derivation_tests.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/transaction_checking/account_checker.rs
  • dash/src/address.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/tests/**/*.rs : Organize tests by functionality: BIP32 key derivation, mnemonic generation/validation, address generation/validation, path derivation, and PSBT serialization in separate test files

Applied to files:

  • key-wallet/src/dip9.rs
  • key-wallet/tests/derivation_tests.rs
  • dash/src/address.rs
📚 Learning: 2025-06-15T15:31:44.136Z
Learnt from: QuantumExplorer
Repo: dashpay/rust-dashcore PR: 74
File: key-wallet/src/address.rs:30-40
Timestamp: 2025-06-15T15:31:44.136Z
Learning: In the key-wallet crate, QuantumExplorer prefers keeping wildcard arms that default unknown Network variants to testnet prefixes rather than using exhaustive matches or panics. This fallback behavior is intentional.

Applied to files:

  • key-wallet/src/wallet/helper.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/*.rs : Never panic in library code; use `Result<T>` for all fallible operations with custom `Error` type variants and provide context in error messages

Applied to files:

  • key-wallet/src/wallet/helper.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Support future enhancements: prepare architecture for Schnorr/Taproot support, descriptor wallets, native multisig account types, and Lightning Network payment channel key management

Applied to files:

  • key-wallet/src/account/account_type.rs
  • key-wallet/src/account/account_collection.rs
  • dash/src/address.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Implement staged gap limit management using `GapLimitStage` structure with tracking of last_used_index and used_indices HashSet to enable efficient address discovery without loading entire address chains into memory

Applied to files:

  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet/src/managed_account/managed_account_collection.rs
  • dash/src/address.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Pre-generate addresses in batches (typically 20-100) and store in address pools; only derive on-demand when pool is exhausted to optimize performance and memory usage

Applied to files:

  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/src/managed_account/address_pool.rs
  • key-wallet/tests/derivation_tests.rs
  • dash/src/address.rs
📚 Learning: 2025-06-15T16:42:18.187Z
Learnt from: QuantumExplorer
Repo: dashpay/rust-dashcore PR: 74
File: key-wallet-ffi/src/lib_tests.rs:41-48
Timestamp: 2025-06-15T16:42:18.187Z
Learning: In key-wallet-ffi, the HDWallet::derive_xpriv method returns Result<String, KeyWalletError>, not an ExtPrivKey wrapper. When unwrapped, it yields a String that can have .is_empty() called on it.

Applied to files:

  • key-wallet-ffi/src/types.rs
  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T08:00:50.618Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: swift-dash-core-sdk/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:50.618Z
Learning: Applies to swift-dash-core-sdk/**/*.rs : Implement new FFI functions in Rust with `#[no_mangle] extern "C"` annotation in dash-spv-ffi

Applied to files:

  • dash/src/blockdata/constants.rs
  • dash/src/address.rs
📚 Learning: 2025-06-26T15:47:37.438Z
Learnt from: DCG-Claude
Repo: dashpay/rust-dashcore PR: 0
File: :0-0
Timestamp: 2025-06-26T15:47:37.438Z
Learning: Transaction IDs (txids) and block hashes in Dash are always 32 bytes and should be passed as fixed-size byte arrays in FFI interfaces, not as C strings, to avoid inefficiency and encoding issues.

Applied to files:

  • dash/src/blockdata/constants.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Maintain Minimum Supported Rust Version (MSRV) of 1.89; ensure compatibility with Dash Core versions 0.18.0 - 0.21.0

Applied to files:

  • dash/src/blockdata/constants.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/tests/**/*.rs : Use deterministic test vectors with fixed seeds and known test vectors in unit tests for key derivation, mnemonic generation, and address generation to ensure reproducibility

Applied to files:

  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T08:00:17.379Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: dash-spv/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:17.379Z
Learning: Applies to dash-spv/tests/**/*.rs : Add integration tests in the `tests/` directory for comprehensive test suites

Applied to files:

  • key-wallet/tests/derivation_tests.rs
  • dash/src/address.rs
📚 Learning: 2025-12-01T08:00:17.379Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: dash-spv/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:17.379Z
Learning: Applies to dash-spv/src/**/*.rs : Add comprehensive unit tests in-module for individual components

Applied to files:

  • key-wallet/tests/derivation_tests.rs
  • dash/src/address.rs
📚 Learning: 2025-12-01T08:00:17.379Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: dash-spv/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:17.379Z
Learning: Applies to dash-spv/tests/**/*.rs : Add real network tests with live Dash Core node integration that gracefully handle node unavailability

Applied to files:

  • key-wallet/tests/derivation_tests.rs
  • dash/src/address.rs
📚 Learning: 2025-12-01T07:59:46.015Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T07:59:46.015Z
Learning: Applies to **/tests/**/*.rs : Test both mainnet and testnet configurations

Applied to files:

  • key-wallet/tests/derivation_tests.rs
  • dash/src/address.rs
📚 Learning: 2025-12-01T08:00:17.379Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: dash-spv/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:17.379Z
Learning: Follow a layered architecture with clear separation of concerns: `client/`, `network/`, `storage/`, `sync/`, `validation/`, `wallet/`, `types.rs`, and `error.rs`

Applied to files:

  • key-wallet/src/managed_account/managed_account_collection.rs
📚 Learning: 2025-12-01T08:01:18.174Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T08:01:18.174Z
Learning: Organize workspace with crates: `dash`, `hashes`, `internals`, `dash-network`, `dash-spv`, `key-wallet`, `rpc-*`, utilities (`fuzz`, `test-utils`), and FFI crates (`*-ffi`)

Applied to files:

  • dash/src/address.rs
📚 Learning: 2025-12-01T08:01:18.174Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T08:01:18.174Z
Learning: Applies to **/*.rs : Unit tests should be placed near code with descriptive names (e.g., `test_parse_address_mainnet`)

Applied to files:

  • dash/src/address.rs
🧬 Code graph analysis (7)
key-wallet/src/account/account_type.rs (1)
key-wallet/src/transaction_checking/transaction_router/mod.rs (2)
  • from (187-237)
  • from (241-291)
key-wallet-ffi/src/types.rs (1)
key-wallet/src/derivation.rs (1)
  • account (224-227)
key-wallet/src/managed_account/managed_account_type.rs (2)
key-wallet/src/managed_account/address_pool.rs (3)
  • network (1135-1138)
  • new_platform (402-418)
  • key_source (1153-1156)
key-wallet/src/bip32.rs (1)
  • master (1302-1304)
key-wallet/tests/derivation_tests.rs (2)
key-wallet/src/derivation.rs (5)
  • from_seed (72-75)
  • new (64-69)
  • new (161-166)
  • new (200-209)
  • new (366-372)
dash/src/address.rs (7)
  • from_str (225-236)
  • from_str (294-297)
  • from_str (1493-1572)
  • encode (949-954)
  • encode (985-990)
  • new (479-499)
  • new (1136-1144)
key-wallet-ffi/src/transaction_checking.rs (1)
key-wallet/src/transaction_checking/account_checker.rs (1)
  • account_index (178-210)
key-wallet/src/managed_account/managed_account_collection.rs (2)
key-wallet/src/account/account_collection.rs (1)
  • new (81-100)
key-wallet/src/managed_account/address_pool.rs (6)
  • new (357-372)
  • new (1094-1104)
  • new_platform (402-418)
  • base_path (1107-1110)
  • network (1135-1138)
  • key_source (1153-1156)
key-wallet/src/transaction_checking/account_checker.rs (2)
key-wallet/src/managed_account/managed_account_collection.rs (1)
  • new (58-75)
key-wallet/src/managed_account/mod.rs (1)
  • new (63-73)
🪛 Gitleaks (8.30.0)
key-wallet/tests/derivation_tests.rs

[high] 126-126: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 227-227: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 310-310: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ 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). (20)
  • GitHub Check: RPC Tests (stable, true)
  • GitHub Check: Core Components Tests
  • GitHub Check: SPV Components Tests
  • GitHub Check: fuzz (dash_deserialize_witness)
  • GitHub Check: fuzz (dash_deserialize_script)
  • GitHub Check: fuzz (hashes_sha256)
  • GitHub Check: fuzz (hashes_json)
  • GitHub Check: fuzz (hashes_sha1)
  • GitHub Check: fuzz (hashes_ripemd160)
  • GitHub Check: fuzz (hashes_sha512)
  • GitHub Check: Pre-commit (ubuntu-latest)
  • GitHub Check: fuzz (hashes_sha512_256)
  • GitHub Check: fuzz (dash_deser_net_msg)
  • GitHub Check: fuzz (dash_deserialize_block)
  • GitHub Check: fuzz (hashes_cbor)
  • GitHub Check: fuzz (dash_outpoint_string)
  • GitHub Check: fuzz (dash_deserialize_amount)
  • GitHub Check: fuzz (dash_deserialize_address)
  • GitHub Check: fuzz (dash_script_bytes_to_asm_fmt)
  • GitHub Check: Pre-commit (macos-latest)
🔇 Additional comments (34)
key-wallet/src/wallet/helper.rs (1)

876-880: LGTM! Correct handling of PlatformPayment account type.

The implementation correctly returns None for PlatformPayment accounts, consistent with DIP-17/DIP-18 requirements that Platform Payment addresses are not used for Core chain transactions. This prevents xpub retrieval through this helper for platform-side-only account types.

key-wallet/src/managed_account/mod.rs (1)

247-251: LGTM! Consistent integration of PlatformPayment across address pool methods.

PlatformPayment is correctly grouped with DashpayExternalAccount in all address pool management methods (get_next_address_index, next_address, next_address_with_info, and gap_limit). This maintains consistent behavior for single-pool account types and properly integrates the new variant into the existing address generation and gap limit management flows.

Also applies to: 499-503, 588-592, 817-821

key-wallet/src/transaction_checking/wallet_checker.rs (1)

144-150: LGTM! Appropriate defensive handling for PlatformPayment.

The implementation correctly returns None for PlatformPayment accounts with clear documentation that this branch should never be reached by design. Per DIP-17/DIP-18, Platform Payment addresses are not used in Core chain transactions, so preventing any state updates here is correct. This represents good defensive programming for exhaustive pattern matching.

key-wallet-ffi/src/address_pool.rs (1)

62-67: LGTM! Correct FFI handling for PlatformPayment accounts.

Both helper functions properly handle PlatformPayment by returning None, consistent with the architecture where Platform Payment accounts are not persisted in ManagedAccountCollection. This aligns with DashPay account handling and correctly prevents retrieval of platform-side-only accounts through the FFI boundary.

Also applies to: 111-116

key-wallet-ffi/include/key_wallet_ffi.h (1)

95-99: FFIAccountType extension for PlatformPayment looks consistent

PLATFORM_PAYMENT = 13 cleanly extends the existing 0–12 range and matches the Rust-side mapping in transaction_checking.rs. No behavioral concerns as long as cbindgen and all FFI consumers (Swift, etc.) are regenerated/updated together.

Please confirm that all language bindings consuming FFIAccountType have been re-generated or updated so they see the new PLATFORM_PAYMENT case.

key-wallet/tests/derivation_tests.rs (1)

114-388: DIP‑17/DIP‑18 platform payment test vectors are thorough and deterministic

The new tests validate full paths (including non‑default key_class'), private keys, compressed pubkeys, HASH160, and final PlatformP2PKH encodings on both mainnet and testnet, all derived from a fixed mnemonic. This gives strong regression coverage for the DIP‑17 derivation scheme and DIP‑18 Base58 encodings and matches the deterministic‑vector guidance for key-wallet tests.

dash/src/blockdata/constants.rs (1)

58-71: DIP‑18 platform prefix constants are well‑placed and consistent

Defining PLATFORM_P2PKH_PREFIX_* and PLATFORM_P2SH_PREFIX_* here, alongside the existing pubkey/script prefixes, keeps all Base58 version bytes centralized. The values and doc comments align with the DIP‑18 handling in dash::address and the new platform address tests.

key-wallet/src/transaction_checking/transaction_router/mod.rs (2)

181-183: Correct exclusion from Core chain transaction checking.

The PlatformPayment variant is properly documented as not being checked for Core chain transactions, aligning with the DIP-17 security requirement. The get_relevant_account_types() method correctly excludes PlatformPayment from all transaction type checks (lines 72-128), which is the intended behavior per the PR objectives.


233-235: Consistent conversion implementations for PlatformPayment.

Both From<ManagedAccountType> and From<&ManagedAccountType> implementations correctly map PlatformPayment to AccountTypeToCheck::PlatformPayment, maintaining consistency with other account type conversions.

Also applies to: 287-289

key-wallet/src/dip9.rs (3)

30-30: PlatformPayment derivation reference correctly positioned.

The PlatformPayment = 16 variant is properly sequenced within the DerivationPathReference enum, maintaining the established pattern for new references.


382-419: Platform Payment root paths correctly implement DIP-17 structure.

The root paths (m/9'/5'/17' for mainnet, m/9'/1'/17' for testnet) correctly use:

  • Hardened FEATURE_PURPOSE (9')
  • Hardened coin type (5' for mainnet, 1' for testnet)
  • Hardened FEATURE_PURPOSE_PLATFORM_PAYMENT (17')

The CLEAR_FUNDS path type is appropriate for payment addresses, consistent with other payment-related paths like DashPay.


135-136: DIP-17 feature index constant is correctly defined.

The FEATURE_PURPOSE_PLATFORM_PAYMENT = 17 constant aligns with DIP-17 HD derivation specifications. Test vectors in key-wallet/tests/derivation_tests.rs confirm the constant's correctness with validated derivation paths (m/9'/5'/17'/0'/0'/0) and expected addresses.

key-wallet-ffi/src/types.rs (2)

269-270: FFI enum variant correctly added for PlatformPayment.

The PlatformPayment = 13 variant is properly sequenced and the doc comment correctly references DIP-17/DIP-18 with the derivation path structure.


424-427: Correct extraction of PlatformPayment fields for FFI.

The from_account_type implementation correctly maps account to the primary index and key_class to the optional secondary index, following the established tuple return pattern.

key-wallet-ffi/src/managed_account.rs (3)

533-535: Correct FFI type mapping for PlatformPayment.

The managed_account_get_account_type function correctly maps AccountType::PlatformPayment to FFIAccountType::PlatformPayment, maintaining consistency with other account type conversions.


1019-1022: PlatformPayment correctly exposed via Single address pool.

The managed_account_get_address_pool function correctly handles PlatformPayment by returning its addresses field when FFIAddressPoolType::Single is requested, consistent with other non-standard account types like CoinJoin and Identity accounts.


181-183: PlatformPayment correctly excluded from generic account lookup.

Returning None for PlatformPayment is consistent with how DashpayReceivingFunds and DashpayExternalAccount are handled. This follows the established pattern where account types requiring dedicated handling return None from the generic lookup function.

Currently, no dedicated retrieval function exists for PlatformPayment accounts (unlike the dedicated managed_wallet_get_dashpay_receiving_account and managed_wallet_get_dashpay_external_account functions). If FFI callers need direct access to PlatformPayment accounts, consider adding a similar dedicated function for consistency and completeness.

key-wallet/src/account/account_type.rs (3)

86-95: Well-documented PlatformPayment variant with security warning.

The PlatformPayment variant is properly documented with:

  • DIP-17 reference and path structure
  • DIP-18 encoding format note ("D"/"d" prefix)
  • Critical warning that Platform addresses must not be used in Core chain transactions

The account and key_class fields with their documentation align with DIP-17 path structure.


156-159: Correct primary index extraction for PlatformPayment.

Returning Some(*account) as the primary index is appropriate since account represents the account-level index in the derivation path, similar to how other account types expose their primary index.


413-437: DIP-17 Platform Payment derivation path implementation is correct.

The code correctly implements the DIP-17 path structure (m/9'/coin_type'/17'/account'/key_class') using network-appropriate root path constants and appending hardened indices. Restricting support to Mainnet and Testnet is intentional—no constants are defined in dip9.rs for Regtest/Devnet. This aligns with the design of other Platform-related variants (Masternode, Platform), which similarly support only Mainnet and Testnet.

key-wallet/src/account/account_collection.rs (4)

31-40: Clean key structure for PlatformPayment accounts.

The PlatformPaymentAccountKey struct correctly models the composite key with account and key_class fields, properly deriving necessary traits including Ord for BTreeMap compatibility. The doc comment references DIP-17.


75-76: Consistent storage pattern for PlatformPayment accounts.

Using BTreeMap<PlatformPaymentAccountKey, Account> follows the established pattern for account types with composite keys (like DashPay accounts). Initialization in new() is correct.

Also applies to: 98-98


174-183: Complete CRUD implementation for PlatformPayment.

The insert(), contains_account_type(), account_of_type(), and account_of_type_mut() methods all correctly handle PlatformPayment by constructing the composite key and delegating to the platform_payment_accounts map.

Also applies to: 267-276, 330-336, 390-396


433-435: Aggregation methods include PlatformPayment accounts.

Both all_accounts() and all_accounts_mut() correctly extend their results with platform_payment_accounts.values(), ensuring PlatformPayment accounts are included in collection-wide operations.

Also applies to: 473-475

key-wallet/src/transaction_checking/account_checker.rs (4)

106-112: Well-structured PlatformPayment variant with clear documentation.

The PlatformPayment variant correctly captures account_index, key_class, and involved_addresses, matching the DIP-17 derivation path structure. The doc comment clearly warns that Platform addresses are not used in Core chain transactions.


387-392: Correct enforcement of DIP-17 security requirement.

Returning an empty Vec for AccountTypeToCheck::PlatformPayment correctly implements the DIP-17 mandate that Platform Payment addresses must not be used in Core chain transactions. The comment clearly explains this design decision.


648-654: PlatformPayment match arm correctly extracts account and key_class.

The match arm properly destructures ManagedAccountType::PlatformPayment and constructs the corresponding AccountTypeMatch::PlatformPayment with the correct field mappings.


914-994: find_address_account does not check platform_payment_accounts.

This method searches for addresses across account types but does not include platform_payment_accounts. This is likely intentional per DIP-17 (Platform addresses shouldn't appear in Core transactions), but if Platform addresses should be discoverable for other purposes (e.g., wallet display), this method may need updating in the future.

Confirm this omission is intentional. If Platform addresses should be findable via this method for non-transaction purposes, consider adding:

// Check Platform Payment accounts
for ((account, key_class), account_obj) in &collection.platform_payment_accounts {
    if account_obj.contains_address(address) {
        return Some((AccountTypeToCheck::PlatformPayment, Some(*account)));
    }
}
key-wallet/src/managed_account/managed_account_type.rs (1)

107-118: Clear and well-documented PlatformPayment variant.

The variant definition includes:

  • DIP-17 derivation path in the doc comment
  • DIP-18 encoding format note
  • Critical warning about not using in Core chain transactions
  • Appropriate fields matching the derivation path structure
key-wallet/src/managed_account/managed_account_collection.rs (2)

52-53: Platform payment accounts field follows established patterns.

The platform_payment_accounts field uses BTreeMap<PlatformPaymentAccountKey, ManagedAccount> consistent with other keyed account collections like dashpay_receival_accounts. This follows the coding guideline to use BTreeMap for ordered data structures.

Also applies to: 73-73


607-624: Consistent Platform account creation in factory method.

The create_managed_account_from_account_type correctly uses AddressPool::new_platform() for Platform Payment accounts, ensuring addresses are generated with the correct PlatformP2pkh address type.

dash/src/address.rs (3)

201-206: Platform address types clearly documented with usage warning.

The PlatformP2pkh and PlatformP2sh variants include clear doc comments explaining they are for Dash Platform only and MUST NOT be used in Core chain transactions. This is critical for preventing fund loss.


2296-2422: Comprehensive DIP-18 test coverage.

The tests cover:

  • Mainnet and testnet P2PKH Platform addresses with DIP-18 vectors
  • Multiple test vectors for different HASH160 values
  • P2SH Platform addresses
  • Round-trip parsing verification
  • Distinction between Platform and Core addresses
  • is_platform() flag verification

This provides strong confidence in the DIP-18 implementation correctness.


1005-1006: bincode serialization uses sequential integer values.

Values 5 and 6 are assigned for PlatformP2pkh and PlatformP2sh respectively, continuing the sequence from P2tr = 4. This maintains backward compatibility for existing serialized data.

Also applies to: 1024-1025

@xdustinface
Copy link
Collaborator

Just reopening to trigger CI after pre-commit fix.

@xdustinface xdustinface closed this Dec 2, 2025
@xdustinface xdustinface reopened this Dec 2, 2025
Copy link
Collaborator

@xdustinface xdustinface left a comment

Choose a reason for hiding this comment

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

Just had a quick glance and wondered about all the comments like "this will never be reached because its not used in core", "this must not be used" etc.. ? Sounds like this shouldnt be in here then to begin with? Cant this go into one of the platform repos? @QuantumExplorer didnt you say there is some platform wallet also around somewhere which is built on the wallet in here?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (4)
key-wallet/src/managed_account/managed_account_collection.rs (4)

730-778: Platform Payment accounts excluded from all_accounts().

The all_accounts() method does not include platform_payment_accounts, causing Platform Payment accounts to be invisible to any code that iterates over all accounts.

Add Platform Payment accounts to the collection:

         // Add DashPay accounts
         accounts.extend(self.dashpay_receival_accounts.values());
         accounts.extend(self.dashpay_external_accounts.values());
+        accounts.extend(self.platform_payment_accounts.values());
 
         accounts
     }

781-829: Platform Payment accounts excluded from all_accounts_mut().

The all_accounts_mut() method does not include platform_payment_accounts, preventing mutable access to Platform Payment accounts through collection-wide operations.

Add Platform Payment accounts to the collection:

         // Add DashPay accounts
         accounts.extend(self.dashpay_receival_accounts.values_mut());
         accounts.extend(self.dashpay_external_accounts.values_mut());
+        accounts.extend(self.platform_payment_accounts.values_mut());
 
         accounts
     }

856-870: Platform Payment accounts not checked in is_empty().

The is_empty() method does not check if platform_payment_accounts is empty, which could cause the collection to be considered empty even when Platform Payment accounts exist.

Add the check:

             && self.provider_platform_keys.is_none()
             && self.dashpay_receival_accounts.is_empty()
             && self.dashpay_external_accounts.is_empty()
+            && self.platform_payment_accounts.is_empty()
     }

873-887: Platform Payment accounts not cleared in clear().

The clear() method does not clear platform_payment_accounts, leaving Platform Payment accounts in the collection after clearing.

Add the clear call:

         self.provider_platform_keys = None;
         self.dashpay_receival_accounts.clear();
         self.dashpay_external_accounts.clear();
+        self.platform_payment_accounts.clear();
     }
🧹 Nitpick comments (3)
key-wallet/tests/derivation_tests.rs (3)

114-124: DIP‑17 test section is clearly delineated

The banner + comments nicely scope the Platform Payment derivation vectors and document mnemonic/passphrase. If this section grows, consider moving it into a dedicated dip17_platform_payment_tests.rs to keep derivation tests grouped by feature.

Based on learnings, grouping tests by functionality (BIP32 vs. DIP‑17) will help long‑term maintenance.


125-173: Mainnet DIP‑17 vector 1 is a strong deterministic regression test

This test fully pins private key, compressed pubkey, and HASH160 for m/9'/5'/17'/0'/0'/0 using the canonical “abandon … about” mnemonic, which is ideal for catching derivation regressions. One practical follow‑up: static-analysis tools like gitleaks may flag these hex constants as secrets, so it’s worth adding a brief comment or repository‑level allow‑list entry noting they’re public DIP‑17 test vectors to avoid CI noise.

Based on learnings, this satisfies the deterministic test‑vector requirement for mainnet derivation.


175-204: Strengthen testnet coverage: is_empty() on fixed-size arrays is a no-op

In all three testnet branches you only assert !pubkey_hash.to_byte_array().is_empty(). Since to_byte_array() returns a fixed-length array, is_empty() is always false, so these assertions can never fail and don’t actually validate derivation correctness.

It would be more robust to:

  • Capture the expected testnet HASH160 (and optionally priv/pub keys) for each path, and
  • Assert equality against those hex strings, mirroring the mainnet vectors.

That would give you real, deterministic regression coverage for testnet as well, instead of a compile‑time tautology.

Based on learnings, both mainnet and testnet derivations should use fixed, known test vectors rather than non‑emptiness checks.

Also applies to: 253-263, 315-325

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 66e86ab and bc65463.

📒 Files selected for processing (4)
  • key-wallet/src/managed_account/address_pool.rs (1 hunks)
  • key-wallet/src/managed_account/managed_account_collection.rs (7 hunks)
  • key-wallet/src/managed_account/managed_account_type.rs (7 hunks)
  • key-wallet/tests/derivation_tests.rs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • key-wallet/src/managed_account/address_pool.rs
🧰 Additional context used
📓 Path-based instructions (8)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Never hardcode network parameters, addresses, or keys in Rust code
Use proper error types with thiserror crate and propagate errors appropriately in Rust code
Use tokio runtime for async operations in Rust code
Use conditional compilation with feature flags for optional features
Write unit tests for new functionality in Rust
Format Rust code with cargo fmt before committing
Ensure clippy passes with all warnings as errors on all Rust code

**/*.rs: Each crate keeps sources in src/; unit tests live alongside code with #[cfg(test)]
Maintain MSRV of 1.89 for Rust code
Format Rust code with rustfmt (see rustfmt.toml); run cargo fmt --all before commits
Lint Rust code with clippy; avoid unwrap()/expect() in library code; use error types (e.g., thiserror)
Use snake_case for function and variable names in Rust
Use UpperCamelCase for types and traits in Rust
Use SCREAMING_SNAKE_CASE for constants in Rust
Follow mixed editions (2021/2024) and crate-specific idioms; prefer async via tokio where applicable
Unit tests should be placed near code with descriptive names (e.g., test_parse_address_mainnet)
Use #[ignore] for network-dependent or long-running tests; run with -- --ignored flag
Never commit secrets or real keys; avoid logging sensitive data in Rust code
Keep test vectors deterministic in Rust test code

Files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/tests/derivation_tests.rs
key-wallet/**/{account,managed_account}/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/{account,managed_account}/**/*.rs: Separate immutable and mutable concerns: Use Account for immutable identity information (keys, derivation paths) and ManagedAccount for mutable state (address pools, metadata, balances)
Use strongly typed enum-based system for AccountType with specific variants (Standard, Identity, Masternode, etc.) to provide compile-time safety for different account purposes

Files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
key-wallet/**/{wallet,account,managed_account,address_pool}/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

Always validate network consistency: use the account's network type when creating addresses and assert that operations use the expected network to prevent mainnet/testnet mixing

Files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
key-wallet/**/managed_account/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

Implement atomic state updates in ManagedAccount: when processing transactions, update address usage state, UTXO set, transaction history, and balance calculations together to maintain consistency

Files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
key-wallet/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/*.rs: Never panic in library code; use Result<T> for all fallible operations with custom Error type variants and provide context in error messages
Use ? operator for error propagation in Rust code to maintain clean error handling patterns

Files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/tests/derivation_tests.rs
key-wallet/**/{wallet,account,managed_account}/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/{wallet,account,managed_account}/**/*.rs: Use BTreeMap for ordered data structures (accounts, transactions) and HashMap for quick lookups (address to index mapping) to optimize data structure performance
Clearly separate watch-only wallets from full wallets using the wallet type system; never attempt signing operations on watch-only accounts and validate external signatures match expected pubkeys

Files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
**/tests/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/tests/**/*.rs: Write integration tests for network operations in Rust
Test both mainnet and testnet configurations
Use proptest for property-based testing where appropriate in Rust

Integration tests use tests/ directory (e.g., rpc-integration-test)

Files:

  • key-wallet/tests/derivation_tests.rs
key-wallet/**/tests/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/tests/**/*.rs: Use deterministic test vectors with fixed seeds and known test vectors in unit tests for key derivation, mnemonic generation, and address generation to ensure reproducibility
Organize tests by functionality: BIP32 key derivation, mnemonic generation/validation, address generation/validation, path derivation, and PSBT serialization in separate test files

Files:

  • key-wallet/tests/derivation_tests.rs
🧠 Learnings (21)
📓 Common learnings
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Keep test vectors updated with Dash Core, monitor for new DIPs affecting wallet structure, maintain backward compatibility for serialized wallets, and update derivation paths for Platform features
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Support future enhancements: prepare architecture for Schnorr/Taproot support, descriptor wallets, native multisig account types, and Lightning Network payment channel key management
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{bip32,derivation,account}/**/*.rs : Use `ExtendedPubKey` and `ExtendedPrivKey` from the BIP32 implementation for key derivation; avoid direct private key exposure or serialization in logs
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Use strongly typed enum-based system for `AccountType` with specific variants (Standard, Identity, Masternode, etc.) to provide compile-time safety for different account purposes
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account}/**/*.rs : Clearly separate watch-only wallets from full wallets using the wallet type system; never attempt signing operations on watch-only accounts and validate external signatures match expected pubkeys
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Support multiple `KeySource` variants (Private, Public, NoKeySource) in address pool initialization to enable both full wallets and watch-only wallets with the same interface
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Separate immutable and mutable concerns: Use `Account` for immutable identity information (keys, derivation paths) and `ManagedAccount` for mutable state (address pools, metadata, balances)
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Separate immutable and mutable concerns: Use `Account` for immutable identity information (keys, derivation paths) and `ManagedAccount` for mutable state (address pools, metadata, balances)

Applied to files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Use strongly typed enum-based system for `AccountType` with specific variants (Standard, Identity, Masternode, etc.) to provide compile-time safety for different account purposes

Applied to files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/managed_account/**/*.rs : Implement atomic state updates in ManagedAccount: when processing transactions, update address usage state, UTXO set, transaction history, and balance calculations together to maintain consistency

Applied to files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account}/**/*.rs : Use BTreeMap for ordered data structures (accounts, transactions) and HashMap for quick lookups (address to index mapping) to optimize data structure performance

Applied to files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{bip32,derivation,account}/**/*.rs : Use `ExtendedPubKey` and `ExtendedPrivKey` from the BIP32 implementation for key derivation; avoid direct private key exposure or serialization in logs

Applied to files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account}/**/*.rs : Clearly separate watch-only wallets from full wallets using the wallet type system; never attempt signing operations on watch-only accounts and validate external signatures match expected pubkeys

Applied to files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account,address_pool}/**/*.rs : Always validate network consistency: use the account's network type when creating addresses and assert that operations use the expected network to prevent mainnet/testnet mixing

Applied to files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Support multiple `KeySource` variants (Private, Public, NoKeySource) in address pool initialization to enable both full wallets and watch-only wallets with the same interface

Applied to files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/transaction_checking/**/*.rs : Use `TransactionRouter::classify_transaction()` to determine transaction type and `get_relevant_account_types()` to avoid checking all accounts for every transaction; route CoinJoin and other specialized transactions only to relevant account types

Applied to files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Implement staged gap limit management using `GapLimitStage` structure with tracking of last_used_index and used_indices HashSet to enable efficient address discovery without loading entire address chains into memory

Applied to files:

  • key-wallet/src/managed_account/managed_account_collection.rs
  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Pre-generate addresses in batches (typically 20-100) and store in address pools; only derive on-demand when pool is exhausted to optimize performance and memory usage

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Keep test vectors updated with Dash Core, monitor for new DIPs affecting wallet structure, maintain backward compatibility for serialized wallets, and update derivation paths for Platform features

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/tests/**/*.rs : Organize tests by functionality: BIP32 key derivation, mnemonic generation/validation, address generation/validation, path derivation, and PSBT serialization in separate test files

Applied to files:

  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/tests/**/*.rs : Use deterministic test vectors with fixed seeds and known test vectors in unit tests for key derivation, mnemonic generation, and address generation to ensure reproducibility

Applied to files:

  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{bip32,derivation}/**/*.rs : Cache intermediate derivation results and use hardened derivation only when required; batch derive child keys when possible to optimize derivation performance

Applied to files:

  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T07:59:46.015Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T07:59:46.015Z
Learning: Applies to **/tests/**/*.rs : Test both mainnet and testnet configurations

Applied to files:

  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-04T15:51:59.632Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: dash-spv/CLAUDE.md:0-0
Timestamp: 2025-12-04T15:51:59.632Z
Learning: Applies to dash-spv/tests/**/*.rs : Integration tests should be organized in `tests/` directory with comprehensive test suites for network layer, storage layer, header sync, and real network integration

Applied to files:

  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-06-15T16:42:18.187Z
Learnt from: QuantumExplorer
Repo: dashpay/rust-dashcore PR: 74
File: key-wallet-ffi/src/lib_tests.rs:41-48
Timestamp: 2025-06-15T16:42:18.187Z
Learning: In key-wallet-ffi, the HDWallet::derive_xpriv method returns Result<String, KeyWalletError>, not an ExtPrivKey wrapper. When unwrapped, it yields a String that can have .is_empty() called on it.

Applied to files:

  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-06-15T15:31:44.136Z
Learnt from: QuantumExplorer
Repo: dashpay/rust-dashcore PR: 74
File: key-wallet/src/address.rs:30-40
Timestamp: 2025-06-15T15:31:44.136Z
Learning: In the key-wallet crate, QuantumExplorer prefers keeping wildcard arms that default unknown Network variants to testnet prefixes rather than using exhaustive matches or panics. This fallback behavior is intentional.

Applied to files:

  • key-wallet/tests/derivation_tests.rs
📚 Learning: 2025-12-01T08:01:18.174Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T08:01:18.174Z
Learning: Applies to **/*.rs : Keep test vectors deterministic in Rust test code

Applied to files:

  • key-wallet/tests/derivation_tests.rs
🧬 Code graph analysis (2)
key-wallet/src/managed_account/managed_account_collection.rs (1)
key-wallet/src/account/account_collection.rs (1)
  • new (81-100)
key-wallet/tests/derivation_tests.rs (2)
key-wallet/src/mnemonic.rs (1)
  • from_phrase (220-227)
key-wallet/src/derivation.rs (5)
  • from_seed (72-75)
  • new (64-69)
  • new (167-172)
  • new (206-215)
  • new (372-378)
🪛 Gitleaks (8.30.0)
key-wallet/tests/derivation_tests.rs

[high] 127-127: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 150-150: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 208-208: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 230-230: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 270-270: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 292-292: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ 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). (18)
  • GitHub Check: fuzz (hashes_sha512)
  • GitHub Check: fuzz (hashes_sha512_256)
  • GitHub Check: fuzz (hashes_cbor)
  • GitHub Check: fuzz (hashes_ripemd160)
  • GitHub Check: fuzz (hashes_json)
  • GitHub Check: fuzz (dash_deserialize_witness)
  • GitHub Check: fuzz (dash_deserialize_amount)
  • GitHub Check: fuzz (dash_deserialize_block)
  • GitHub Check: fuzz (dash_deserialize_script)
  • GitHub Check: fuzz (dash_script_bytes_to_asm_fmt)
  • GitHub Check: fuzz (dash_deserialize_address)
  • GitHub Check: fuzz (dash_deser_net_msg)
  • GitHub Check: fuzz (dash_outpoint_string)
  • GitHub Check: Core Components Tests
  • GitHub Check: RPC Tests (stable, true)
  • GitHub Check: SPV Components Tests
  • GitHub Check: Pre-commit (ubuntu-latest)
  • GitHub Check: Pre-commit (macos-latest)
🔇 Additional comments (16)
key-wallet/src/managed_account/managed_account_type.rs (7)

5-5: LGTM!

The import of DIP17_GAP_LIMIT is correctly added and used in the Platform Payment account initialization.


107-118: LGTM!

The PlatformPayment variant is well-documented with clear DIP-17/DIP-18 references and includes an important security warning about not using Platform addresses in Core chain transactions.


167-170: LGTM!

The index() method correctly returns the account index for PlatformPayment, consistent with other indexed account types.


246-249: LGTM!

The address_pools() method correctly returns the single address pool for PlatformPayment, consistent with other single-pool account types.


309-312: LGTM!

The address_pools_mut() method correctly returns the mutable address pool, consistent with the immutable version.


428-435: LGTM!

The to_account_type() conversion correctly maps the PlatformPayment managed type to its corresponding account type.


679-700: The code at lines 679-700 is correct as written. AddressPool::new() with AddressPoolType::Absent is the standard pattern used throughout the codebase for all special account types (Platform accounts, Identity accounts, etc.) that don't distinguish between external and internal address pools. There is no new_platform() constructor in the AddressPool implementation; all address pools are created using the single new() method with appropriate AddressPoolType variants.

Likely an incorrect or invalid review comment.

key-wallet/src/managed_account/managed_account_collection.rs (6)

6-6: LGTM!

The import of PlatformPaymentAccountKey is correctly added to support the new Platform Payment account type.


52-53: LGTM!

The platform_payment_accounts field is correctly defined using BTreeMap for ordered storage, consistent with other account collections. As per coding guidelines.


73-73: LGTM!

The field is correctly initialized in the new() constructor.


149-159: LGTM!

The contains_managed_account_type() method correctly checks for Platform Payment accounts using the composite key, consistent with DashPay account patterns.


253-263: LGTM!

The insert() method correctly handles Platform Payment accounts with proper key construction. The use of acc_index avoids variable shadowing.


360-365: LGTM!

The conversion from AccountCollection correctly processes Platform Payment accounts, consistent with other account type conversions.

key-wallet/tests/derivation_tests.rs (3)

3-3: Hash trait import is correct for HASH160 usage

Bringing dashcore::hashes::Hash into scope is required for pubkey_hash.to_byte_array() to compile; this is the right, minimal import.


206-252: Vector 2 mainnet adds valuable coverage at a different index

Checking m/9'/5'/17'/0'/0'/1 with full privkey/pubkey/HASH160 expectations is a good complement to vector 1 and should catch index/path mixups in the DIP‑17 implementation.

Based on learnings, adding multiple deterministic vectors per path family is preferred for key-derivation tests.


267-314: Non‑default key_class' = 1' vector meaningfully exercises alternate path branch

This vector for m/9'/5'/17'/0'/1'/0 (non‑default key_class) with pinned privkey/pubkey/HASH160 is important coverage for the extra hardened step and guards against future changes to the key_class slot logic.

Based on learnings, this strengthens coverage for alternate account/key classes in DIP‑17.

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)
key-wallet/src/managed_account/managed_account_type.rs (1)

107-117: PlatformPayment variant is correctly integrated; double‑check DIP‑18 doc wording

The PlatformPayment variant is wired consistently with existing patterns:

  • account is treated as the primary index (returned by index()), matching the “Account index (hardened)” doc.
  • address_pools() / address_pools_mut() correctly include the single addresses pool alongside other single‑pool account types.
  • to_account_type() maps cleanly to AccountType::PlatformPayment { account, key_class }, preserving both parameters.

Functionally this all looks coherent and in line with the other managed account variants.

One minor documentation nit: the comment says “Address encoding (DIP-18 bech32m) is handled by the Platform repo.” Given that this PR also introduces Base58Check encodings with D/d and P/p prefixes in the dashcore crate, please confirm that this wording accurately reflects the Platform‑side encoding (and whether both encodings coexist) to avoid confusion for future maintainers.

Also applies to: 166-169, 241-247, 304-311, 427-434

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc65463 and 8e331a2.

📒 Files selected for processing (2)
  • key-wallet/src/account/account_type.rs (5 hunks)
  • key-wallet/src/managed_account/managed_account_type.rs (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • key-wallet/src/account/account_type.rs
🧰 Additional context used
📓 Path-based instructions (6)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Never hardcode network parameters, addresses, or keys in Rust code
Use proper error types with thiserror crate and propagate errors appropriately in Rust code
Use tokio runtime for async operations in Rust code
Use conditional compilation with feature flags for optional features
Write unit tests for new functionality in Rust
Format Rust code with cargo fmt before committing
Ensure clippy passes with all warnings as errors on all Rust code

**/*.rs: Each crate keeps sources in src/; unit tests live alongside code with #[cfg(test)]
Maintain MSRV of 1.89 for Rust code
Format Rust code with rustfmt (see rustfmt.toml); run cargo fmt --all before commits
Lint Rust code with clippy; avoid unwrap()/expect() in library code; use error types (e.g., thiserror)
Use snake_case for function and variable names in Rust
Use UpperCamelCase for types and traits in Rust
Use SCREAMING_SNAKE_CASE for constants in Rust
Follow mixed editions (2021/2024) and crate-specific idioms; prefer async via tokio where applicable
Unit tests should be placed near code with descriptive names (e.g., test_parse_address_mainnet)
Use #[ignore] for network-dependent or long-running tests; run with -- --ignored flag
Never commit secrets or real keys; avoid logging sensitive data in Rust code
Keep test vectors deterministic in Rust test code

Files:

  • key-wallet/src/managed_account/managed_account_type.rs
key-wallet/**/{account,managed_account}/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/{account,managed_account}/**/*.rs: Separate immutable and mutable concerns: Use Account for immutable identity information (keys, derivation paths) and ManagedAccount for mutable state (address pools, metadata, balances)
Use strongly typed enum-based system for AccountType with specific variants (Standard, Identity, Masternode, etc.) to provide compile-time safety for different account purposes

Files:

  • key-wallet/src/managed_account/managed_account_type.rs
key-wallet/**/{wallet,account,managed_account,address_pool}/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

Always validate network consistency: use the account's network type when creating addresses and assert that operations use the expected network to prevent mainnet/testnet mixing

Files:

  • key-wallet/src/managed_account/managed_account_type.rs
key-wallet/**/managed_account/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

Implement atomic state updates in ManagedAccount: when processing transactions, update address usage state, UTXO set, transaction history, and balance calculations together to maintain consistency

Files:

  • key-wallet/src/managed_account/managed_account_type.rs
key-wallet/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/*.rs: Never panic in library code; use Result<T> for all fallible operations with custom Error type variants and provide context in error messages
Use ? operator for error propagation in Rust code to maintain clean error handling patterns

Files:

  • key-wallet/src/managed_account/managed_account_type.rs
key-wallet/**/{wallet,account,managed_account}/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/{wallet,account,managed_account}/**/*.rs: Use BTreeMap for ordered data structures (accounts, transactions) and HashMap for quick lookups (address to index mapping) to optimize data structure performance
Clearly separate watch-only wallets from full wallets using the wallet type system; never attempt signing operations on watch-only accounts and validate external signatures match expected pubkeys

Files:

  • key-wallet/src/managed_account/managed_account_type.rs
🧠 Learnings (13)
📓 Common learnings
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Keep test vectors updated with Dash Core, monitor for new DIPs affecting wallet structure, maintain backward compatibility for serialized wallets, and update derivation paths for Platform features
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Support future enhancements: prepare architecture for Schnorr/Taproot support, descriptor wallets, native multisig account types, and Lightning Network payment channel key management
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{bip32,derivation,account}/**/*.rs : Use `ExtendedPubKey` and `ExtendedPrivKey` from the BIP32 implementation for key derivation; avoid direct private key exposure or serialization in logs
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Use strongly typed enum-based system for `AccountType` with specific variants (Standard, Identity, Masternode, etc.) to provide compile-time safety for different account purposes
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Separate immutable and mutable concerns: Use `Account` for immutable identity information (keys, derivation paths) and `ManagedAccount` for mutable state (address pools, metadata, balances)
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account}/**/*.rs : Clearly separate watch-only wallets from full wallets using the wallet type system; never attempt signing operations on watch-only accounts and validate external signatures match expected pubkeys
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/managed_account/**/*.rs : Implement atomic state updates in ManagedAccount: when processing transactions, update address usage state, UTXO set, transaction history, and balance calculations together to maintain consistency
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account,address_pool}/**/*.rs : Always validate network consistency: use the account's network type when creating addresses and assert that operations use the expected network to prevent mainnet/testnet mixing
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Use strongly typed enum-based system for `AccountType` with specific variants (Standard, Identity, Masternode, etc.) to provide compile-time safety for different account purposes

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Separate immutable and mutable concerns: Use `Account` for immutable identity information (keys, derivation paths) and `ManagedAccount` for mutable state (address pools, metadata, balances)

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/managed_account/**/*.rs : Implement atomic state updates in ManagedAccount: when processing transactions, update address usage state, UTXO set, transaction history, and balance calculations together to maintain consistency

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Support multiple `KeySource` variants (Private, Public, NoKeySource) in address pool initialization to enable both full wallets and watch-only wallets with the same interface

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account}/**/*.rs : Clearly separate watch-only wallets from full wallets using the wallet type system; never attempt signing operations on watch-only accounts and validate external signatures match expected pubkeys

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account,address_pool}/**/*.rs : Always validate network consistency: use the account's network type when creating addresses and assert that operations use the expected network to prevent mainnet/testnet mixing

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Implement staged gap limit management using `GapLimitStage` structure with tracking of last_used_index and used_indices HashSet to enable efficient address discovery without loading entire address chains into memory

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{bip32,derivation,account}/**/*.rs : Use `ExtendedPubKey` and `ExtendedPrivKey` from the BIP32 implementation for key derivation; avoid direct private key exposure or serialization in logs

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account}/**/*.rs : Use BTreeMap for ordered data structures (accounts, transactions) and HashMap for quick lookups (address to index mapping) to optimize data structure performance

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/transaction_checking/**/*.rs : Use `TransactionRouter::classify_transaction()` to determine transaction type and `get_relevant_account_types()` to avoid checking all accounts for every transaction; route CoinJoin and other specialized transactions only to relevant account types

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Pre-generate addresses in batches (typically 20-100) and store in address pools; only derive on-demand when pool is exhausted to optimize performance and memory usage

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Keep test vectors updated with Dash Core, monitor for new DIPs affecting wallet structure, maintain backward compatibility for serialized wallets, and update derivation paths for Platform features

Applied to files:

  • key-wallet/src/managed_account/managed_account_type.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: Pre-commit (macos-latest)
  • GitHub Check: Core Components Tests
  • GitHub Check: RPC Tests (stable, true)
  • GitHub Check: SPV Components Tests
  • GitHub Check: fuzz (dash_deserialize_script)
  • GitHub Check: fuzz (dash_script_bytes_to_asm_fmt)
  • GitHub Check: fuzz (hashes_sha512)
  • GitHub Check: fuzz (hashes_sha512_256)
  • GitHub Check: fuzz (dash_deserialize_address)
  • GitHub Check: fuzz (hashes_sha1)
  • GitHub Check: fuzz (dash_deserialize_amount)
  • GitHub Check: fuzz (dash_deser_net_msg)
  • GitHub Check: fuzz (dash_outpoint_string)
  • GitHub Check: fuzz (dash_deserialize_block)
  • GitHub Check: fuzz (dash_deserialize_witness)
  • GitHub Check: fuzz (hashes_cbor)
  • GitHub Check: fuzz (hashes_json)
  • GitHub Check: fuzz (hashes_sha256)
🔇 Additional comments (1)
key-wallet/src/managed_account/managed_account_type.rs (1)

5-5: DIP‑17 gap limit and AddressPool configuration for PlatformPayment look correct

The AccountType::PlatformPayment branch in from_account_type() is consistent and respects the DIP‑17 design:

  • Uses account_type.derivation_path(network) as the base path, which should already implement m/9'/coin_type'/17'/account'/key_class'.
  • Instantiates a single AddressPool with AddressPoolType::Absent, matching other special, non‑Core‑UTXO account types that shouldn’t be scanned as regular Core transaction addresses.
  • Applies the dedicated DIP17_GAP_LIMIT, decoupling DIP‑17 semantics from DEFAULT_SPECIAL_GAP_LIMIT and resolving earlier ambiguity.
  • Returns ManagedAccountType::PlatformPayment { account, key_class, addresses: pool }, preserving both hardened indices and the pool.

No functional issues spotted here; this is a clean addition.

Also applies to: 678-699

@pauldelucia pauldelucia changed the title feat(key-wallet): Implement DIP17/DIP18 Platform Payment Addresses feat(key-wallet): Add DIP-17 Platform Payment account support Dec 10, 2025
Copy link
Collaborator

@xdustinface xdustinface left a comment

Choose a reason for hiding this comment

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

Looks good, just got two questions.

let addresses = AddressPool::new(
base_path,
AddressPoolType::Absent,
DEFAULT_SPECIAL_GAP_LIMIT,
Copy link
Collaborator

Choose a reason for hiding this comment

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

You introduced a DIP17_GAP_LIMIT, was this supposed to be used here?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

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

⚠️ Outside diff range comments (23)
dash-spv/CLAUDE.md (1)

18-18: Remove the stale sync/sequential/ entry from line 18.

The sync/sequential/ directory does not exist in the codebase. The synchronization logic is handled by SyncManager defined in sync/manager.rs. Remove line 18 or consolidate its description into the parent sync/ module entry.

dash-spv/tests/handshake_test.rs (3)

10-11: Add #[ignore] attribute for network-dependent test.

This test requires a live Dash Core node at 127.0.0.1:9999, making it network-dependent. As per coding guidelines, it should be marked with #[ignore] and run explicitly with -- --ignored flag.

Apply this diff:

+#[ignore]
 #[tokio::test]
 async fn test_handshake_with_mainnet_peer() {

Based on coding guidelines: "Use #[ignore] for network-dependent or long-running tests; run with -- --ignored flag"


51-52: Add #[ignore] attribute for network-dependent test.

Although this test uses a non-routable IP, it still performs network operations and may behave differently across environments. Mark it with #[ignore] per coding guidelines.

Apply this diff:

+#[ignore]
 #[tokio::test]
 async fn test_handshake_timeout() {

Based on coding guidelines: "Use #[ignore] for network-dependent or long-running tests"


86-87: Add #[ignore] attribute for network-dependent test.

This test requires a live Dash Core node, making it network-dependent. Mark it with #[ignore] per coding guidelines.

Apply this diff:

+#[ignore]
 #[tokio::test]
 async fn test_multiple_connect_disconnect_cycles() {

Based on coding guidelines: "Use #[ignore] for network-dependent or long-running tests; run with -- --ignored flag"

dash-spv/tests/segmented_storage_test.rs (1)

185-210: Ensure the shared DiskStorageManager is cleanly shut down (avoid leaking the background worker).
With Arc<DiskStorageManager>, you currently can’t call shutdown() (if it requires &mut self). If Drop doesn’t reliably stop the worker, this can cause test flakiness/hangs.

One option is to unwrap after all tasks finish and then call shutdown:

     // Wait for all readers
     for handle in handles {
         handle.await.unwrap();
     }
+
+    // Clean shutdown (only works if all task Arcs were dropped)
+    let mut storage = Arc::try_unwrap(storage).expect("storage Arc still has outstanding refs");
+    storage.shutdown().await.unwrap();

Based on learnings, the storage API uses interior mutability and concurrency patterns—explicitly shutting down here helps keep tests deterministic.

dash-spv/src/sync/filters/requests.rs (2)

17-49: Critical: unsigned underflow when count == 0

If count is Some(0), (start + c - 1) underflows and can turn into a massive end, potentially building/sending an unbounded queue.

-        let end = if let Some(c) = count {
-            (start + c - 1).min(filter_header_tip_height)
-        } else {
-            filter_header_tip_height
-        };
+        let end = if let Some(c) = count {
+            if c == 0 {
+                tracing::warn!("Filter sync requested with count=0; nothing to do");
+                return Ok(());
+            }
+            start
+                .saturating_add(c.saturating_sub(1))
+                .min(filter_header_tip_height)
+        } else {
+            filter_header_tip_height
+        };

133-240: Remove the unused _storage parameter from process_filter_request_queue

The _storage parameter is passed from the callsite in download.rs:93 but never used in the function body. Remove the parameter from both the function signature (requests.rs:137-140) and the callsite (download.rs:93).

The queue pumping and flow-control accounting logic itself is sound—pending_filter_requests, active_filter_requests, and MAX_CONCURRENT_FILTER_REQUESTS are properly defined and tracked with no dead state detected.

dash-spv-ffi/src/bin/ffi_cli.rs (1)

120-125: Don’t ignore dash_spv_ffi_init_logging result; print last_error on failure.

Suggested tweak:

-        let _ = dash_spv_ffi_init_logging(level_c.as_ptr(), true, std::ptr::null(), 0);
+        let rc = dash_spv_ffi_init_logging(level_c.as_ptr(), true, std::ptr::null(), 0);
+        if rc != FFIErrorCode::Success as i32 {
+            eprintln!("Logging init failed: {}", ffi_string_to_rust(dash_spv_ffi_get_last_error()));
+        }
dash-spv-ffi/src/error.rs (1)

39-45: FFI error pointer lifetime not guaranteed across threads; refactor error ownership model.

dash_spv_ffi_get_last_error() returns a direct pointer into a CString protected by a global Mutex. If another thread calls set_last_error() or clear_last_error() while a caller holds the pointer, the returned *const c_char becomes invalid—a potential use-after-free bug in multi-threaded contexts.

Recommended fix: Return a newly allocated C string and require callers to free it with dash_string_free() (consistent with other FFI allocations like config objects). This aligns with FFI robustness and matches the pattern used elsewhere in the crate.

dash-spv/src/storage/disk/manager.rs (1)

83-92: Lock acquisition should open the file without truncating; acquire lock first, then write PID.

LockFile::new currently uses File::create, which truncates the lock file before attempting try_lock(). When two processes start concurrently, both truncate the file, and the one that fails to acquire the lock has already wiped its contents. Although the lock is held for the application's lifetime in this implementation, the proper pattern is to open without truncation, acquire the lock, then safely write the PID.

Suggested change in dash-spv/src/storage/disk/lockfile.rs:

-use std::fs::File;
+use std::fs::OpenOptions;

 pub(super) fn new(path: PathBuf) -> StorageResult<Self> {
-        let mut file = File::create(&path)
+        let mut file = OpenOptions::new()
+            .create(true)
+            .read(true)
+            .write(true)
+            .open(&path)
             .map_err(|e| StorageError::WriteFailed(format!("Failed to create lock file: {}", e)))?;

         file.try_lock().map_err(|e| match e {
             std::fs::TryLockError::WouldBlock => StorageError::DirectoryLocked(format!(
                 "Data directory '{}' is already in use by another process",
                 path.parent().map(|p| p.display().to_string()).unwrap_or_default()
             )),
             std::fs::TryLockError::Error(io_err) => {
                 StorageError::WriteFailed(format!("Failed to acquire lock: {}", io_err))
             }
         })?;

+        let _ = file.set_len(0);
         if let Err(e) = writeln!(file, "{}", std::process::id()) {
             tracing::warn!("Failed to write PID to lock file: {}", e);
         }
dash-spv/src/sync/filters/retry.rs (1)

160-188: When CFHeaders retries are exhausted, consider failing the sync (don’t silently “give up”).
Currently, once retry_count >= self.max_cfheader_retries you log and return Ok(()) (Line 203-210). If that request was needed for contiguous CFHeaders, this can stall the sync indefinitely without a clear failure signal.

One option is to return an error that bubbles up and transitions the client/sync state to “failed”:

         if retry_count >= self.max_cfheader_retries {
             tracing::error!(
                 "❌ CFHeaders request for height {} failed after {} retries, giving up",
                 start_height,
                 retry_count
             );
-            return Ok(());
+            return Err(SyncError::Network(format!(
+                "CFHeaders request timed out at start_height={} after {} retries",
+                start_height, retry_count
+            )));
         }

(Adjust the error variant if a more appropriate one exists.)

Also applies to: 190-233

dash-spv/src/storage/memory.rs (1)

20-50: Possible base-height source-of-truth mismatch (chain_state vs sync_state).

sync_base_height() derives from self.chain_state, but store_sync_state() / load_sync_state() now operate on self.sync_state. If sync_state is restored/used without a corresponding chain_state (or if chain_state lags), header/filter absolute-height mapping can silently fall back to base=0.

Consider falling back to self.sync_state.as_ref().map(|s| s.sync_base_height) (or whatever field represents the base) when chain_state is None.

As per retrieved learnings, document the thread-safety / state-source expectations clearly since StorageManager is Send + Sync but uses &mut self.

dash-spv/src/sync/phase_execution.rs (1)

138-171: Guard against unsigned underflow when computing count for filter downloads.

If start_height > filter_header_tip, filter_header_tip - start_height + 1 underflows and becomes a huge u32, causing pathological behavior.

- let start_height = self.header_sync.get_sync_base_height().max(1);
- let count = filter_header_tip - start_height + 1;
+ let start_height = self.header_sync.get_sync_base_height().max(1);
+ if filter_header_tip < start_height {
+     tracing::warn!(
+         "Filter header tip {} is below start_height {}, skipping filter download",
+         filter_header_tip, start_height
+     );
+     self.transition_to_next_phase(storage, network, "No filters to download").await?;
+     return Ok(());
+ }
+ let count = filter_header_tip - start_height + 1;
dash-spv/src/client/sync_coordinator.rs (1)

918-965: Restore validation misses cross-batch continuity (can accept a broken chain at batch boundaries).

validate_headers() skips continuity for the first header in the slice, so a discontinuity between prev_batch_last and this_batch_first won’t be caught.

Suggested minimal fix: compare headers.first().prev_blockhash against the previous tip hash (from ChainState or the last loaded header) before calling validate_headers().

dash-spv/src/sync/filters/download.rs (1)

73-110: Ensure syncing_filters is reset on early error paths (currently can get stuck “in progress”).

sync_filters() sets self.syncing_filters = true (Line 84) and then performs fallible work (build_filter_request_queue, process_filter_request_queue). Any ? early-return will leave syncing_filters true and the cleared queues partially initialized, preventing later retries.

Suggested fix (keep syncing_filters true only after successful init, or explicitly unwind on error). For example:

 pub async fn sync_filters(
     &mut self,
     network: &mut N,
     storage: &mut S,
     start_height: Option<u32>,
     count: Option<u32>,
 ) -> SyncResult<SyncProgress> {
     if self.syncing_filters {
         return Err(SyncError::SyncInProgress);
     }
-
-    self.syncing_filters = true;
-
-    // Clear any stale state from previous attempts
-    self.clear_filter_sync_state();
-
-    // Build the queue of filter requests
-    self.build_filter_request_queue(storage, start_height, count).await?;
-
-    // Start processing the queue
-    self.process_filter_request_queue(network, storage).await?;
+    // Clear any stale state from previous attempts
+    self.clear_filter_sync_state();
+
+    // Build the queue of filter requests
+    self.build_filter_request_queue(storage, start_height, count).await?;
+
+    // Start processing the queue
+    self.process_filter_request_queue(network, storage).await?;
+
+    // Mark in-progress only after successful init
+    self.syncing_filters = true;

     tracing::info!(
         "✅ Filter sync initiated ({} requests queued, {} active)",
         self.pending_filter_requests.len(),
         self.active_filter_requests.len()
     );
dash-spv/src/storage/disk/state.rs (1)

330-345: store_metadata() allows path traversal via key → filename.

self.base_path.join(format!("state/{}.dat", key)) will happily accept key = "../foo" (or path separators), escaping the state directory. If key can ever be influenced outside trusted code paths, this is a security bug.

Recommend enforcing a strict key charset and rejecting anything else (or mapping keys to a safe encoding). For example:

 pub async fn store_metadata(&mut self, key: &str, value: &[u8]) -> StorageResult<()> {
+    if key.is_empty()
+        || !key
+            .chars()
+            .all(|c| c.is_ascii_alphanumeric() || matches!(c, '_' | '-' | '.'))
+    {
+        return Err(crate::error::StorageError::WriteFailed(format!(
+            "Invalid metadata key: {key}"
+        )));
+    }
     let path = self.base_path.join(format!("state/{}.dat", key));
     atomic_write(&path, value).await?;
     Ok(())
 }
dash-spv/src/client/message_handler.rs (1)

8-58: Rename lingering “Sequential sync manager” log messages to “SyncManager” to avoid confusion.

Even after the type switch, error logs still read “Sequential sync manager error …”, which will mislead debugging (and grepping). (E.g., Line 89, 102, 130, 146, 163, 196 in this file.)

dash-spv/src/sync/filters/headers.rs (2)

144-155: Blocker: start_sync_headers() is incompatible with the new queue-based handle_filter_headers() and can stall sync forever.

After Line 154, CFHeaders handling always goes through handle_filter_headers(), which relies on self.next_cfheader_height_to_process being initialized (Line 610). start_sync_headers() does not set it (nor build the CFHeaders queue), so the first received batch will be buffered as “out of order” and never processed.

Fix: make start_sync_headers() a thin wrapper around the new entrypoint (or delete/privatize it). Minimal safe change:

 pub async fn start_sync_headers(
     &mut self,
     network: &mut N,
     storage: &mut S,
 ) -> SyncResult<bool> {
-    // (old one-shot request logic)
-    ...
+    self.start_sync_filter_headers(network, storage).await
 }

This also reduces the chance that callers accidentally pick the wrong entrypoint. As per sync learnings, keeping a single SyncManager-driven phase entry is preferable.

Also applies to: 157-333, 375-460


579-652: Active-request tracking removal is keyed inconsistently; handle truncated CFHeaders responses explicitly.

You insert active_cfheader_requests by request.start_height (Line 567), but on response you remove by batch_start_height computed from stop_hash and filter_hashes.len() (Line 607). If a peer returns fewer entries than requested, batch_start_height != request.start_height, so the active entry won’t be removed and available slots won’t refill correctly.

Recommendation:

  1. Identify the active request by stop_hash (stored in ActiveCFHeaderRequest), remove by that key.
  2. Validate batch_start_height == request_start_height; if not, treat as protocol/peer issue and retry with an adjusted range rather than silently buffering.

(If you want, I can draft a concrete patch once you confirm whether you expect partial CFHeaders batches in practice.)

dash-spv/src/sync/headers/manager.rs (3)

164-214: Validation logging uses tracing::error! in a confusing/likely-wrong way

This:

  • Line 210: tracing::error!(error);

will emit an event with a field named error (and typically no human-readable message). Prefer tracing::error!(%error); or tracing::error!("{}", error);.

         if self.config.validation_mode != ValidationMode::None {
             validate_headers(&cached_headers).map_err(|e| {
                 let error = format!("Header validation failed: {}", e);
-                tracing::error!(error);
+                tracing::error!(%error);
                 SyncError::Validation(error)
             })?;
         }

319-451: request_headers() can emit an empty locator for normal GetHeaders even though headers2 is disabled

Because the “empty locator for headers2 genesis sync” branch is keyed off network.has_headers2_peer().await rather than use_headers2, you can still send GetHeaders with locator_hashes = [] when base_hash is genesis. That’s a behavior change (and could cause peers to respond from genesis / unexpected ancestor logic).

Suggested fix: only apply the empty-locator special-case when you’re actually sending headers2.

-                } else if network.has_headers2_peer().await && !self.headers2_failed {
+                } else if use_headers2 && network.has_headers2_peer().await && !self.headers2_failed {
                     // Check if this is genesis and we're using headers2
                     let genesis_hash = self.config.network.known_genesis_block_hash();
                     if genesis_hash == Some(hash) {
                         tracing::info!("📍 Using empty locator for headers2 genesis sync");
                         vec![]
                     } else {
                         vec![hash]
                     }
                 } else {
                     vec![hash]
                 }

(You’ll need to hoist let use_headers2 = false; above the locator computation, or compute locator after deciding the protocol.)


456-563: handle_headers2_message() is permanently erroring but still carries a large unreachable implementation

Right now the function always returns an error and keeps a large #[allow(unreachable_code)] block. This makes maintenance risky (it will silently rot) and increases review surface.

Recommendation: either remove the unreachable code entirely, or feature-gate the whole decompression path (e.g., #[cfg(feature = "headers2")]) and keep the stub in the default build.

dash-spv/src/sync/manager.rs (1)

403-421: get_blockchain_height_from_storage() likely double-counts height when synced from checkpoint

Other codepaths treat storage.get_tip_height() as an absolute chain height (e.g., comparisons to get_sync_base_height(), querying get_header(0) for genesis). If so, adding sync_base_height + storage_height is wrong and will overstate height.

Suggested fix (assuming storage heights are absolute):

     pub(super) async fn get_blockchain_height_from_storage(&self, storage: &S) -> SyncResult<u32> {
         let storage_height = storage
@@
             .unwrap_or(0);
 
-        // Check if we're syncing from a checkpoint
-        if self.header_sync.is_synced_from_checkpoint() {
-            // For checkpoint sync, blockchain height = sync_base_height + storage_height
-            Ok(self.header_sync.get_sync_base_height() + storage_height)
-        } else {
-            // Normal sync: storage height IS the blockchain height
-            Ok(storage_height)
-        }
+        // Storage height is already an absolute chain height.
+        Ok(storage_height)
     }

If storage heights are actually relative in some backends, please add a clarifying doc comment + a single canonical conversion helper used everywhere (to avoid the current mixed assumptions). Based on learnings, clearer documentation around StorageManager semantics would help.

🧹 Nitpick comments (20)
.github/workflows/conflict-check.yml (1)

18-22: Pin the 3rd‑party action to a commit SHA (supply‑chain hardening).

Using eps1lon/actions-label-merge-conflict@v3 is fine, but for a workflow with write permissions, pin to a full commit SHA instead of a mutable tag. The v3 release corresponds to commit SHA 1df065ebe6e3310545d4f4c4e862e43bdca146f0.

Recommended change:

uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0

GitHub recommends SHA pinning to make actions immutable and reduce supply-chain risk.

dash-spv/src/sync/filters/stats.rs (1)

20-26: Silent failure on lock contention may mislead callers.

When try_lock() fails due to lock contention, returning 0 is indistinguishable from actually having zero received filters. For statistics/monitoring purposes this is usually acceptable, but callers cannot differentiate between "no filters received" and "couldn't read count."

Consider returning Option<u32> or documenting this behavior clearly:

-    /// Get the total number of filters received.
-    pub fn get_received_filter_count(&self) -> u32 {
+    /// Get the total number of filters received.
+    /// Returns 0 if the lock cannot be acquired (non-blocking).
+    pub fn get_received_filter_count(&self) -> u32 {
dash-spv/src/storage/disk/filters.rs (1)

186-190: Consider async existence check in load_filter to avoid sync FS call on async path.
path.exists() is a blocking metadata check; tokio::fs::try_exists (or just attempt read and map NotFound → Ok(None)) avoids mixing sync FS calls into async code.

dash-spv/src/sync/masternodes/embedded_data.rs (1)

9-15: Stabilize include_bytes! paths to reduce refactor breakage.
The deep relative paths will keep breaking as modules move; consider anchoring via env!("CARGO_MANIFEST_DIR") (or moving these artifacts into this crate) to make builds less fragile.

dash-spv-ffi/examples/basic_usage.c (1)

6-10: Improve example error reporting by printing dash_spv_ffi_get_last_error() on failure.
Proposed tweak:

-    if (dash_spv_ffi_init_logging("info", true, NULL, 0) != 0) {
-        fprintf(stderr, "Failed to initialize logging\n");
+    if (dash_spv_ffi_init_logging("info", true, NULL, 0) != 0) {
+        fprintf(stderr, "Failed to initialize logging: %s\n", dash_spv_ffi_get_last_error());
         return 1;
     }

Based on learnings, check dash_spv_ffi_get_last_error() when debugging FFI issues.

dash-spv/src/storage/disk/mod.rs (1)

22-28: Module visibility/layout update looks good; consider documenting lock + thread-safety expectations.
Given the lockfile/atomic-write design and the StorageManager API shape (Send+Sync with &mut self methods), a short note in module docs about the intended concurrency model would reduce confusion. Based on learnings, clarify thread-safety expectations/rationale.

dash-spv/src/storage/disk/io.rs (1)

32-69: Solid atomic write implementation with crash resilience.

The temp-file → sync → rename pattern is correctly implemented. Error handling properly cleans up temp files on both write and rename failures.

Minor consideration: For full POSIX durability guarantees on some filesystems (ext4 with default mount options), you may want to also fsync the parent directory after the rename to ensure the directory entry is persisted. This is a defense-in-depth measure for edge cases:

// Optional: sync parent directory for full durability
if let Some(parent) = path.parent() {
    if let Ok(dir) = tokio::fs::File::open(parent).await {
        let _ = dir.sync_all().await;
    }
}

This is a nice-to-have rather than essential, as the current implementation handles the common crash scenarios correctly.

dash-spv/src/client/core.rs (1)

23-24: Clarify the “Arc<Mutex>” doc to avoid ambiguity about which Mutex you mean.
The module uses tokio::sync::Mutex (Line 12), but the comment (Line 129-131) reads like std::sync::Mutex. Consider spelling it explicitly (e.g., Arc<tokio::sync::Mutex<SyncManager<...>>>) to prevent architectural confusion.

Also applies to: 129-135

dash-spv/src/sync/message_handlers.rs (1)

585-646: Consider consolidating stats.write().await to avoid double write-locking in the hot path.
Right now you lock once for filters_received (Line 627-630) and again for filters_matched (Line 635-637). You can update both under one lock without holding it across any .await.

-        {
-            let mut stats_lock = self.stats.write().await;
-            stats_lock.filters_received += 1;
-            stats_lock.last_filter_received_time = Some(std::time::Instant::now());
-        }
+        let mut filters_matched_inc = false;
 
         if matches {
-            // Update filter match statistics
-            {
-                let mut stats = self.stats.write().await;
-                stats.filters_matched += 1;
-            }
+            filters_matched_inc = true;
 
             tracing::info!("🎯 Filter match found! Requesting block {}", cfilter.block_hash);
             // Request the full block
             let inv = Inventory::Block(cfilter.block_hash);
             network
                 .send_message(NetworkMessage::GetData(vec![inv]))
                 .await
                 .map_err(|e| SyncError::Network(format!("Failed to request block: {}", e)))?;
         }
+
+        {
+            let mut stats = self.stats.write().await;
+            stats.filters_received += 1;
+            stats.last_filter_received_time = Some(std::time::Instant::now());
+            if filters_matched_inc {
+                stats.filters_matched += 1;
+            }
+        }
dash-spv/src/storage/memory.rs (1)

299-308: Prefer saturating add for absolute height math in get_header_height_by_hash().

This avoids any theoretical overflow if base heights ever approach u32::MAX.

-Ok(Some(self.sync_base_height() + storage_index))
+Ok(Some(self.sync_base_height().saturating_add(storage_index)))
dash-spv/src/sync/phase_execution.rs (1)

71-87: Drop or use _safe_height (currently dead computation).

The computed _safe_height isn’t used, so it’s either leftover debug or missing logic to actually clamp subsequent operations.

dash-spv/src/client/sync_coordinator.rs (1)

942-957: Consider moving validate_headers() CPU work off the async executor thread.

Even though Rayon uses its own pool, the async task still blocks until completion (and this runs repeatedly for many batches). Wrapping the validation in tokio::task::spawn_blocking would keep the runtime more responsive during restores.

dash-spv/src/sync/filters/download.rs (1)

112-160: Potential hot-path contention: mark_filter_received + is_request_complete scans ranges under lock.

is_request_complete() locks received_filter_heights and does contains() for every height in [start..=end]; mark_filter_received() repeats this for each active range. If ranges are large and filters arrive frequently, this can become a bottleneck. Consider tracking remaining-per-range counters (decrement on receipt) or storing per-range bitsets to avoid repeated full scans.

dash-spv/src/storage/disk/state.rs (1)

51-99: Guard load_chain_state() against sync_base_height > tip_height to avoid silent “empty state”.

If state.sync_base_height is ahead of the on-disk tip (corrupt/mismatched files), load_headers(range_start..tip+1) becomes an empty range and you’ll return a partially-initialized ChainState without signalling inconsistency. Consider:

  • If range_start > tip_height, return an explicit StorageError (or clamp + warn), and
  • Similar guard for filter headers.
dash-spv/src/sync/filters/headers.rs (1)

785-792: Consider resetting next_cfheader_height_to_process when clearing CFHeaders sync state.

clear_filter_header_sync_state() clears queues/maps but leaves next_cfheader_height_to_process as-is. Not strictly wrong (it’s reinitialized in start_sync_filter_headers()), but resetting it here would reduce “stale state” surprises when future refactors add alternate entrypoints.

dash-spv/src/logging.rs (2)

146-249: Rotation/cleanup: tighten a couple edge cases (max_files semantics + TOCTOU)

  • cleanup_old_logs(..., max_files) currently treats max_files as “archived logs to keep” (good), but the function name/docs could be explicit that it does not include run.log.
  • The .exists() + .find(|p| !p.exists()) pattern in rotate_previous_log() is inherently TOCTOU; if you want to harden it, loop rename attempts instead of pre-checking existence.

No must-fix correctness bug seen in this block.


251-629: Tests: potential flakiness from mtime resolution + sleep()

Several tests depend on std::thread::sleep(...) to ensure distinct mtimes. On filesystems with coarse timestamp resolution, this can still collapse mtimes and reduce coverage of the “oldest first” behavior. If this bites CI, consider setting mtimes explicitly (e.g., via a dev-dependency like filetime) instead of sleeping.

dash-spv/src/sync/headers/manager.rs (1)

104-137: Checkpoint/base-height cache: good direction; watch division-by-zero-ish logging

  • Base-height-derived is_synced_from_checkpoint() is simpler and matches the tip_height() pattern (nice).
  • Minor: the “headers/sec” log can emit NaN/inf when elapsed.as_secs_f64() is ~0 or loaded_count == 0. Consider guarding the rate calculation for cleaner logs.

Also applies to: 944-955

dash-spv/src/sync/manager.rs (2)

160-176: wallet_birth_height_hint() holds a RwLock guard across .await

This can cause avoidable contention (and can deadlock if earliest_required_height() tries to re-enter codepaths needing the same lock). If feasible, adjust WalletInterface / call shape so the async work doesn’t require holding the lock the whole time. Based on learnings, consider documenting this tradeoff explicitly if it’s intentional.


250-262: reset_pending_requests() drops header reset errors

let _ = self.header_sync.reset_pending_requests(); silently ignores failures. If this can fail in meaningful ways, consider surfacing it (or at least logging at warn!) so restart issues aren’t masked.

@pauldelucia pauldelucia force-pushed the feat/platform-addresses branch 2 times, most recently from 4475aad to 8e331a2 Compare December 12, 2025 06:21
Co-authored-by: Kevin Rombach <35775977+xdustinface@users.noreply.github.com>
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 (2)
key-wallet/src/transaction_checking/account_checker.rs (1)

648-656: Consider making the no-match policy explicit in this method.

While check_account_type() correctly returns an empty vector for PlatformPayment (line 387-392), this method will still construct a match if called directly. Since Platform addresses should never match Core chain transactions by design, consider adding an early return for PlatformPayment accounts before the address checking logic, similar to how the type is handled in check_account_type().

Example:

 pub fn check_transaction_for_match(
     &self,
     tx: &Transaction,
     index: Option<u32>,
 ) -> Option<AccountMatch> {
+    // Platform Payment addresses are not used in Core chain transactions
+    if matches!(self.account_type, ManagedAccountType::PlatformPayment { .. }) {
+        return None;
+    }
+
     // Check regular outputs
     let mut involved_receive_addresses = Vec::new();

This would make the no-match policy explicit and prevent confusion if this public method is called directly.

key-wallet-ffi/src/types.rs (1)

424-427: LGTM! Correct mapping of PlatformPayment indices to FFI tuple.

The from_account_type mapping correctly returns both account (as primary index) and key_class (as optional secondary index) using the tuple format (FFIAccountType, u32, Option<u32>). This is consistent with how other multi-index account types like IdentityTopUp use the same tuple structure.

Consider adding a test for the from_account_type direction.

While the panic behavior is tested at lines 450-456, there's no test verifying that from_account_type correctly maps a PlatformPayment account type to the expected FFI tuple with both indices. Add a test to verify the tuple structure:

#[test]
fn test_platform_payment_from_account_type() {
    let account_type = key_wallet::AccountType::PlatformPayment {
        account: 5,
        key_class: 3,
    };
    let (ffi_type, primary_index, secondary_index) = 
        FFIAccountType::from_account_type(&account_type);
    
    assert_eq!(ffi_type, FFIAccountType::PlatformPayment);
    assert_eq!(primary_index, 5);
    assert_eq!(secondary_index, Some(3));
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb330d1 and 089e7f2.

📒 Files selected for processing (5)
  • key-wallet-ffi/include/key_wallet_ffi.h (1 hunks)
  • key-wallet-ffi/src/transaction_checking.rs (1 hunks)
  • key-wallet-ffi/src/types.rs (4 hunks)
  • key-wallet/src/transaction_checking/account_checker.rs (6 hunks)
  • key-wallet/src/transaction_checking/wallet_checker.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet-ffi/src/transaction_checking.rs
  • key-wallet-ffi/include/key_wallet_ffi.h
🧰 Additional context used
📓 Path-based instructions (4)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Never hardcode network parameters, addresses, or keys in Rust code
Use proper error types with thiserror crate and propagate errors appropriately in Rust code
Use tokio runtime for async operations in Rust code
Use conditional compilation with feature flags for optional features
Write unit tests for new functionality in Rust
Format Rust code with cargo fmt before committing
Ensure clippy passes with all warnings as errors on all Rust code

**/*.rs: Each crate keeps sources in src/; unit tests live alongside code with #[cfg(test)]
Maintain MSRV of 1.89 for Rust code
Format Rust code with rustfmt (see rustfmt.toml); run cargo fmt --all before commits
Lint Rust code with clippy; avoid unwrap()/expect() in library code; use error types (e.g., thiserror)
Use snake_case for function and variable names in Rust
Use UpperCamelCase for types and traits in Rust
Use SCREAMING_SNAKE_CASE for constants in Rust
Follow mixed editions (2021/2024) and crate-specific idioms; prefer async via tokio where applicable
Unit tests should be placed near code with descriptive names (e.g., test_parse_address_mainnet)
Use #[ignore] for network-dependent or long-running tests; run with -- --ignored flag
Never commit secrets or real keys; avoid logging sensitive data in Rust code
Keep test vectors deterministic in Rust test code

Files:

  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet-ffi/src/types.rs
key-wallet/**/transaction_checking/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/transaction_checking/**/*.rs: Use TransactionRouter::classify_transaction() to determine transaction type and get_relevant_account_types() to avoid checking all accounts for every transaction; route CoinJoin and other specialized transactions only to relevant account types
In SPV sync integration, use wallet_info.check_transaction() with appropriate TransactionContext and update wallet state atomically only when is_relevant flag is true

Files:

  • key-wallet/src/transaction_checking/account_checker.rs
key-wallet/**/*.rs

📄 CodeRabbit inference engine (key-wallet/CLAUDE.md)

key-wallet/**/*.rs: Never panic in library code; use Result<T> for all fallible operations with custom Error type variants and provide context in error messages
Use ? operator for error propagation in Rust code to maintain clean error handling patterns

Files:

  • key-wallet/src/transaction_checking/account_checker.rs
**/*-ffi/src/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Careful handling of memory safety at FFI boundaries in Rust code

Files:

  • key-wallet-ffi/src/types.rs
🧠 Learnings (20)
📓 Common learnings
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Keep test vectors updated with Dash Core, monitor for new DIPs affecting wallet structure, maintain backward compatibility for serialized wallets, and update derivation paths for Platform features
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Support future enhancements: prepare architecture for Schnorr/Taproot support, descriptor wallets, native multisig account types, and Lightning Network payment channel key management
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{bip32,derivation,account}/**/*.rs : Use `ExtendedPubKey` and `ExtendedPrivKey` from the BIP32 implementation for key derivation; avoid direct private key exposure or serialization in logs
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Support multiple `KeySource` variants (Private, Public, NoKeySource) in address pool initialization to enable both full wallets and watch-only wallets with the same interface
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Use strongly typed enum-based system for `AccountType` with specific variants (Standard, Identity, Masternode, etc.) to provide compile-time safety for different account purposes
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Separate immutable and mutable concerns: Use `Account` for immutable identity information (keys, derivation paths) and `ManagedAccount` for mutable state (address pools, metadata, balances)
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/managed_account/**/*.rs : Implement atomic state updates in ManagedAccount: when processing transactions, update address usage state, UTXO set, transaction history, and balance calculations together to maintain consistency
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account}/**/*.rs : Clearly separate watch-only wallets from full wallets using the wallet type system; never attempt signing operations on watch-only accounts and validate external signatures match expected pubkeys
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account,address_pool}/**/*.rs : Always validate network consistency: use the account's network type when creating addresses and assert that operations use the expected network to prevent mainnet/testnet mixing
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Use strongly typed enum-based system for `AccountType` with specific variants (Standard, Identity, Masternode, etc.) to provide compile-time safety for different account purposes

Applied to files:

  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/transaction_checking/**/*.rs : Use `TransactionRouter::classify_transaction()` to determine transaction type and `get_relevant_account_types()` to avoid checking all accounts for every transaction; route CoinJoin and other specialized transactions only to relevant account types

Applied to files:

  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{account,managed_account}/**/*.rs : Separate immutable and mutable concerns: Use `Account` for immutable identity information (keys, derivation paths) and `ManagedAccount` for mutable state (address pools, metadata, balances)

Applied to files:

  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account}/**/*.rs : Clearly separate watch-only wallets from full wallets using the wallet type system; never attempt signing operations on watch-only accounts and validate external signatures match expected pubkeys

Applied to files:

  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/managed_account/**/*.rs : Implement atomic state updates in ManagedAccount: when processing transactions, update address usage state, UTXO set, transaction history, and balance calculations together to maintain consistency

Applied to files:

  • key-wallet/src/transaction_checking/account_checker.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account,address_pool}/**/*.rs : Always validate network consistency: use the account's network type when creating addresses and assert that operations use the expected network to prevent mainnet/testnet mixing

Applied to files:

  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{wallet,account,managed_account}/**/*.rs : Use BTreeMap for ordered data structures (accounts, transactions) and HashMap for quick lookups (address to index mapping) to optimize data structure performance

Applied to files:

  • key-wallet/src/transaction_checking/account_checker.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/{bip32,derivation,account}/**/*.rs : Use `ExtendedPubKey` and `ExtendedPrivKey` from the BIP32 implementation for key derivation; avoid direct private key exposure or serialization in logs

Applied to files:

  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/transaction_checking/**/*.rs : In SPV sync integration, use `wallet_info.check_transaction()` with appropriate `TransactionContext` and update wallet state atomically only when `is_relevant` flag is true

Applied to files:

  • key-wallet/src/transaction_checking/account_checker.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/address_pool/**/*.rs : Support multiple `KeySource` variants (Private, Public, NoKeySource) in address pool initialization to enable both full wallets and watch-only wallets with the same interface

Applied to files:

  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/*.rs : Never panic in library code; use `Result<T>` for all fallible operations with custom `Error` type variants and provide context in error messages

Applied to files:

  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T08:00:50.618Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: swift-dash-core-sdk/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:50.618Z
Learning: Applies to swift-dash-core-sdk/**/*.rs : Implement new FFI functions in Rust with `#[no_mangle] extern "C"` annotation in dash-spv-ffi

Applied to files:

  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/*ffi*.rs : For FFI bindings, expose safe C interfaces with appropriate memory management and use #[no_mangle] for public FFI functions

Applied to files:

  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T07:59:58.608Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: dash-spv-ffi/CLAUDE.md:0-0
Timestamp: 2025-12-01T07:59:58.608Z
Learning: Applies to dash-spv-ffi/tests/unit/**/*.rs : Add corresponding unit tests in `tests/unit/` for each new FFI function

Applied to files:

  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Keep test vectors updated with Dash Core, monitor for new DIPs affecting wallet structure, maintain backward compatibility for serialized wallets, and update derivation paths for Platform features

Applied to files:

  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/tests/**/*.rs : Organize tests by functionality: BIP32 key derivation, mnemonic generation/validation, address generation/validation, path derivation, and PSBT serialization in separate test files

Applied to files:

  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-01T08:00:37.919Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: key-wallet/CLAUDE.md:0-0
Timestamp: 2025-12-01T08:00:37.919Z
Learning: Applies to key-wallet/**/tests/**/*.rs : Use deterministic test vectors with fixed seeds and known test vectors in unit tests for key derivation, mnemonic generation, and address generation to ensure reproducibility

Applied to files:

  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-12-04T15:51:59.632Z
Learnt from: CR
Repo: dashpay/rust-dashcore PR: 0
File: dash-spv/CLAUDE.md:0-0
Timestamp: 2025-12-04T15:51:59.632Z
Learning: Define traits for abstractions when adding new features, implement concrete types following existing patterns, add unit and integration tests, and update error types in `error.rs`

Applied to files:

  • key-wallet-ffi/src/types.rs
📚 Learning: 2025-06-15T16:42:18.187Z
Learnt from: QuantumExplorer
Repo: dashpay/rust-dashcore PR: 74
File: key-wallet-ffi/src/lib_tests.rs:41-48
Timestamp: 2025-06-15T16:42:18.187Z
Learning: In key-wallet-ffi, the HDWallet::derive_xpriv method returns Result<String, KeyWalletError>, not an ExtPrivKey wrapper. When unwrapped, it yields a String that can have .is_empty() called on it.

Applied to files:

  • key-wallet-ffi/src/types.rs
🧬 Code graph analysis (2)
key-wallet/src/transaction_checking/account_checker.rs (3)
key-wallet/src/managed_account/managed_account_collection.rs (1)
  • new (58-75)
key-wallet/src/account/account_collection.rs (1)
  • new (81-100)
key-wallet/src/managed_account/mod.rs (1)
  • new (63-73)
key-wallet-ffi/src/types.rs (1)
key-wallet/src/derivation.rs (1)
  • account (230-233)
⏰ 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). (20)
  • GitHub Check: SPV Components Tests
  • GitHub Check: Core Components Tests
  • GitHub Check: RPC Tests (stable, true)
  • GitHub Check: fuzz (hashes_cbor)
  • GitHub Check: fuzz (hashes_ripemd160)
  • GitHub Check: fuzz (hashes_json)
  • GitHub Check: fuzz (hashes_sha512)
  • GitHub Check: fuzz (dash_deserialize_witness)
  • GitHub Check: fuzz (dash_deserialize_block)
  • GitHub Check: fuzz (hashes_sha256)
  • GitHub Check: fuzz (dash_script_bytes_to_asm_fmt)
  • GitHub Check: fuzz (dash_deserialize_address)
  • GitHub Check: fuzz (hashes_sha1)
  • GitHub Check: fuzz (hashes_sha512_256)
  • GitHub Check: fuzz (dash_outpoint_string)
  • GitHub Check: fuzz (dash_deserialize_script)
  • GitHub Check: fuzz (dash_deserialize_amount)
  • GitHub Check: fuzz (dash_deser_net_msg)
  • GitHub Check: Pre-commit (ubuntu-latest)
  • GitHub Check: Pre-commit (macos-latest)
🔇 Additional comments (7)
key-wallet/src/transaction_checking/account_checker.rs (4)

106-112: LGTM: PlatformPayment variant correctly added.

The enum variant is properly structured with the necessary fields for DIP-17 support (account_index, key_class, involved_addresses). The comment clearly documents that these addresses are not used in Core chain transactions, which aligns with the PR's stated design.


170-173: LGTM: Helper methods correctly extended.

The all_involved_addresses() and account_index() methods are properly extended to handle the PlatformPayment variant, following the established pattern for single-pool account types.

Also applies to: 204-207


254-256: LGTM: Routing mapping correctly implemented.

The to_account_type_to_check() method properly maps PlatformPayment to AccountTypeToCheck::PlatformPayment, completing the transaction routing chain.


387-392: LGTM: Correctly implements no-match policy for Platform addresses.

The implementation correctly returns an empty vector for PlatformPayment, as these addresses are exclusively for Platform-side payments and should never match Core chain transactions. The comment clearly documents this design decision.

key-wallet-ffi/src/types.rs (3)

269-270: LGTM! Enum variant follows established pattern.

The PlatformPayment variant is correctly added with sequential value 13 and appropriate documentation referencing DIP-17 and the derivation path.


332-339: LGTM! Panic correctly prevents unsupported conversion.

The panic follows the established pattern for FFI account types that cannot be converted due to API limitations. The message clearly explains that account and key_class indices cannot be passed through the current to_account_type(index: u32) signature, which only accepts a single index parameter. The corresponding panic test has been added at lines 450-456 per previous review feedback.


450-456: LGTM! Panic test correctly verifies unsupported conversion.

The test properly verifies that attempting to convert FFIAccountType::PlatformPayment to AccountType panics as expected. This follows the established pattern for DashPay panic tests and addresses the previous review feedback requesting this test.

@xdustinface xdustinface merged commit 8f97c4b into v0.41-dev Dec 12, 2025
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants