feat(key-wallet): gate-free provider-key derivation API (operator/platform-node at index)#881
Conversation
Add wallet-state-agnostic entry points for deriving provider keys at an index, with no is_watch_only gate in either direction: - BLSAccount::operator_public_key_at(index): legacy-scheme non-hardened public derivation off the stored account xpub; works on resident AND watch-only accounts. Returns the extended key so both the legacy and modern/IETF serializations are obtainable. Rejects non-operator accounts so a mixed-up lookup fails loudly. - BLSAccount::operator_private_key_at(seed, network, index): re-derives the full DIP-3 operator path from the raw BIP39 seed in the legacy BLS scheme, then the non-hardened child; needs no account state. - EdDSAAccount::platform_node_key_at(seed, network, index): SLIP-0010 hardened derivation of the platform node key from the raw seed. The existing convenience wrappers are gated on is_watch_only in opposite directions (public derivation requires watch-only, seed derivation requires non-watch-only), so no single upstream API served both resident and restored/external-signable wallets — forcing downstream consumers to re-compose low-level primitives (see dashpay/platform#4120 and the stale derivation bug behind #878/#879). New tests pin the entry points to the existing dashbls / SLIP-0010 golden vectors and assert they behave identically on resident and watch-only accounts. Closes #880 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 28 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev #881 +/- ##
==========================================
- Coverage 74.25% 74.22% -0.03%
==========================================
Files 326 326
Lines 74553 74585 +32
==========================================
+ Hits 55357 55360 +3
- Misses 19196 19225 +29
|
…htly)
The 2026-07-14 nightly (rustc daf2e5e18) ICEs while expanding the
libtest harness for dash-spv-ffi tests ("attribute is missing tokens:
rustc_test_entrypoint_marker" in rustc_ast/src/attr/mod.rs), breaking
the Address Sanitizer job for every PR. Pin ASAN/TSAN to the last
known-good nightly until a fixed nightly ships.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Reviewed |
…er via rust-dashcore#881 Bumps the pin to bc6cbf96 picking up the gate-free provider-key API (dashpay/rust-dashcore#881, from our #880): operator_public_key_at / operator_private_key_at / platform_node_key_at. All derivation composition in provider_key_at_index.rs is deleted — platform now resolves wallets, calls upstream, and maps types. The private-reveal keeps an always-on consistency check (secret's pubkey must equal the xpub-derived one; the two upstream paths derive from independent sources and don't verify each other). Provider key accounts are also routed through the address-pool restore so their persisted rows rehydrate the in-memory pools at load (used-flags and beyond-gap indices survive restarts). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes #880.
Problem
key-wallet's provider-key convenience wrappers are gated on
is_watch_onlyin opposite directions:BLSAccount::derive_bls_key_at_path/derive_bls_key_at_index(public derivation) requireis_watch_only == trueand fail on resident accounts.derive_from_seed_*_atroute throughderive_xpriv_from_master_xpriv, which requiresis_watch_only == falseand fails on restored/external-signable (watch-only) accounts.So no single upstream API served both wallet states, forcing downstream consumers (dashpay/platform#4120, Kotlin SDK) to re-compose derivation from low-level primitives — the duplication that caused the stale-derivation bug behind #878 / #879.
Changes
Gate-free, wallet-state-agnostic entry points, per the API proposed in the issue:
BLSAccount::operator_public_key_at(&self, index)— legacy-scheme (fLegacy = true) non-hardened public derivation off the stored account xpub. Works on resident and watch-only accounts; nois_watch_onlygate. ReturnsExtendedBLSPubKeyso both serializations are obtainable (to_bytes_legacy()for the legacy Dash format,to_bytes()for the modern/IETF format used in v19+ ProRegTx payloads). Rejects non-ProviderOperatorKeysaccounts so a mixed-up account lookup fails loudly instead of yielding valid-looking wrong keys.BLSAccount::operator_private_key_at(seed, network, index)— associated fn; re-derives the full DIP-3 operator path (m/9'/5'/3'/3'mainnet,m/9'/1'/3'/3'otherwise) from the raw BIP39 seed in the legacy BLS scheme, then the non-hardened child. Needs no account state at all.EdDSAAccount::platform_node_key_at(seed, network, index)— associated fn; SLIP-0010 hardened derivation of the platform node key (m/9'/5'/3'/4'/i') from the raw seed.This absorbs the protocol knowledge downstream currently re-encodes (legacy-scheme choice for BLS HD, hardened-leaf convention for Ed25519, account-path re-application from the raw seed) into key-wallet, next to the derivation itself. Purely additive — no existing API changed.
Tests
operator_key_at_is_wallet_state_agnostic— pinsoperator_public_key_at/operator_private_key_atto the existing dashbls golden vectors (mainnet + testnet) and asserts identical results on the resident account and itsto_watch_only()counterpart, plus that the old gated wrapper still fails on the resident account (documenting the asymmetry this fixes).operator_public_key_at_rejects_non_operator_accounts— the account-type guard.platform_node_key_at_is_wallet_state_agnostic— pins to the SLIP-0010 golden vector and cross-checks against the account-based seed path.cargo test -p key-wallet --all-features,cargo fmt --check, andcargo clippy --all-features --all-targets -- -D warningsall pass (one pre-existing timing-threshold flake inperformance_testsunder parallel load; passes in isolation).🤖 Generated with Claude Code