Commit 428b60d
refactor(key-wallet): wire ManagedCoreKeysAccount into the collection (#742)
* refactor(key-wallet): wire ManagedCoreKeysAccount into the collection
Promotes the dead-code `ManagedCoreKeysAccount` introduced in #711 into the
active type for accounts that derive special-purpose keys but don't track
funds. Cuts ~10 keys-only accounts per wallet from carrying always-empty
`balance` / `utxos` / `spent_outpoints` state.
Storage split on `ManagedAccountCollection`:
- Identity, asset-lock, and provider fields move from
`ManagedCoreFundsAccount` → `ManagedCoreKeysAccount`.
- Standard, CoinJoin, and DashPay fields stay on `ManagedCoreFundsAccount`.
New borrowed enum `ManagedAccountRef<'a> { Funds, Keys }` (and mutable
counterpart `ManagedAccountRefMut<'a>`) plus owned `OwnedManagedCoreAccount`.
Spanning collection accessors (`get_by_account_type_match`, `all_accounts`,
…) return the borrowed enum. The enum delegates the funds-agnostic surface
(transactions, monitor revision, address-pool helpers, record/confirm
transaction) so most callers don't need to dispatch on the variant; funds-
only operations (`as_funds()`, `as_funds_mut()`) require an explicit unwrap.
`ManagedCoreKeysAccount` gains the methods needed to be a first-class
participant in transaction matching:
- `record_transaction` / `confirm_transaction` (no UTXO/balance work)
- `check_transaction_for_match`, `check_asset_lock_transaction_for_match`,
and the four `check_provider_*_key_in_transaction_for_match` variants
- `classify_address` / `check_provider_payout` helpers
`wallet/managed_wallet_info` accessors that returned `&mut
ManagedCoreFundsAccount` for identity / asset-lock / provider accounts now
return `&mut ManagedCoreKeysAccount`. Funds-only surfaces
(`account_balances`, `update_balance`, `mark_instant_send_utxos`,
matured-coinbase / immature) filter to the funds variant.
`ManagedAccountCollection::insert` accepts either variant via
`OwnedManagedCoreAccount`; explicit `insert_funds` / `insert_keys` helpers
are exposed for callers that statically know the variant. `get`, `get_mut`,
`remove`, `contains_key` now scope to the funds-bearing index lookup
(Standard BIP44/32 + CoinJoin) — keys accounts use type-keyed accessors.
C ABI preserved on the FFI side. `FFIManagedCoreAccount` now wraps an
internal `Funds | Keys` enum carrying an `Arc<…>`, with new `as_funds` /
`as_keys` / `keys_account` accessors and a `new_keys` constructor. Funds-
only entry points (`get_balance`, `get_utxo_count`) gracefully return
defaults on the keys variant; trait-shared entry points
(`get_network`, `get_account_type`, address-pool getters, transactions)
work on both. Variant-aware constructors are wired through
`managed_wallet_get_account`, `managed_wallet_get_top_up_account_with_registration_index`,
and the per-type collection getters.
This is a clean replay of the work from PR #716 on the current
architecture (the original branch carried merge noise from unrelated
discarded branches and depended on pre-#711 / pre-#733 struct layouts that
no longer exist).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(key-wallet-ffi): rustdoc + regenerate FFI_API.md
- Drop intra-doc links to private `FFIManagedCoreAccountInner` variants on
`keys_account()` so `cargo doc -D warnings` (and the Documentation CI job)
passes; the enum is internal and doesn't need to appear in public rustdoc.
- Regenerate `key-wallet-ffi/FFI_API.md` to pick up the updated descriptions
on `managed_core_account_get_balance` / `_get_utxo_count` (the verify-ffi
pre-commit hook).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(key-wallet-ffi): include all account variants in managed_wallet_get_account_count
The count was only summing standard / coinjoin / identity_registration /
identity_topup buckets — every other variant `managed_wallet_get_account`
can return (identity_topup_not_bound, identity_invitation, asset-lock,
provider, dashpay, platform-payment) was excluded. Pre-existing miscount,
made more visible by the keys-account split now exposing those getters
through the variant-aware FFI surface.
`provider_operator_keys` (BLS) and `provider_platform_keys` (EdDSA) are
feature-gated on the immutable `AccountCollection` and counted only when
the corresponding feature is enabled.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(key-wallet): add `all_funding_accounts(_mut)` and drop in-loop `as_funds()` filters
Five funds-only callsites in `wallet_info_interface.rs` were iterating
`all_accounts()` and filtering each ref via `as_funds()` / `as_funds_mut()`
inside the loop body — pure noise, since balance / UTXO state only ever
lives on Standard / CoinJoin / DashPay accounts.
Add focused accessors on `ManagedAccountCollection`:
- `all_funding_accounts(&self) -> Vec<&ManagedCoreFundsAccount>`
- `all_funding_accounts_mut(&mut self) -> Vec<&mut ManagedCoreFundsAccount>`
Migrate `account_balances`, `utxos`, `update_balance`, `immature_transactions`,
and `matured_coinbase_records` to use them. `monitored_addresses`,
`transaction_history`, `monitor_revision`, and `mark_instant_send_utxos`
keep using `all_accounts(_mut)` — they legitimately span both variants.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(key-wallet): rename insert_{funds,keys} -> insert_{funds,keys}_bearing_account
`insert_funds` / `insert_keys` were ambiguous about *what* "funds" or
"keys" referred to. The longer names make the variant intent explicit
and match the surrounding "funds-bearing" / "keys-only" terminology
already used in the doc comments and field comments.
The generic `insert(impl Into<OwnedManagedCoreAccount>)` keeps its name —
that's the variant-agnostic entry point.
No public callers existed outside this file (verified via grep across
key-wallet, key-wallet-ffi, key-wallet-manager, dash-spv) so this is a
local rename with no downstream impact.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(key-wallet): simplify keys-account `record_transaction` to its real semantics
The keys-account `record_transaction` was carrying three branches that
are statically unreachable on the keys-account data model:
- `change_addrs` — for non-Standard `CoreAccountTypeMatch` variants,
`involved_change_addresses()` is always `&[]`. Identity / asset-lock /
provider accounts own a single address pool with no external/internal
split, so the `OutputRole::Change` arm can never match.
- `OutputRole::Sent` — gated on `has_inputs = account_match.sent > 0`,
but the keys-account `check_transaction_for_match` sets `sent = 0`
unconditionally (keys accounts don't track per-account UTXOs, so
there's no signal that they contributed inputs).
- `direction = Internal | Outgoing` — both gated on `has_inputs`,
same dead-branch reason. A keys account always sees direction
`Incoming` (or `CoinJoin` for the unlikely-but-possible case where
the upstream classifier flagged a CoinJoin tx that touched a
keys-account address).
Drop the dead branches, rename `receive_addrs` → `owned_addrs` (no
receive/change distinction exists for these account types), and document
the actual semantics on the method's doc comment. Behavior is preserved
— the previous code happened to compute the right answer through dead
arms; the new code expresses it directly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(key-wallet): make keys-account `record_transaction` a thin marker
Keys-account flows (identity registration, asset lock, provider-key
registration / update) are typically funded from a Standard or CoinJoin
account in the same wallet. The funding account's `record_transaction`
already populates `input_details` (from its UTXO set) and
`output_details` (classified receive / change / sent), so the
keys-account record reproducing them would double-count and risk
drifting out of sync if the classification logic changes.
Treat the keys-account record as the thin marker it really is: "this
tx involved this keys account" plus `net_amount`, and nothing more.
- `direction = TransactionDirection::Internal` — from the wallet's
perspective, the tx moves funds from one of its accounts to another.
- `input_details = Vec::new()` — already correct (keys accounts don't
track per-account UTXOs).
- `output_details = Vec::new()` — the funding account's record carries
the per-output classification.
Drop the now-unused `OutputDetail` / `OutputRole` / `Address` imports
and gate the `HashSet` import behind the same feature flag as
`finalized_txids`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(key-wallet): cover special-tx → keys-account matching paths end-to-end
For each special-transaction type that drives one of the new keys-account
`check_*_for_match` methods on `ManagedCoreKeysAccount`, construct a
transaction and assert `ManagedWalletInfo::check_core_transaction` flags
the right `AccountTypeToCheck`. 13 tests in
`tests/special_transaction_matching_tests.rs`:
- AssetLockPayloadType → 6 tests covering each of the keys-account
variants (Identity{Registration, TopUp, TopUpNotBound, Invitation},
AssetLock{Address, Shielded}TopUp).
- ProviderRegistrationPayloadType → 4 tests, one per provider-key match
field (owner_key_hash, voting_key_hash, operator_public_key (BLS),
platform_node_id (EdDSA)). The BLS / EdDSA tests are feature-gated
the same way the matching impls are.
- ProviderUpdateRegistrarPayloadType → 2 tests (voting + operator key
changes).
- 1 test pinning the keys-account `TransactionRecord` shape: direction
Internal, empty input/output details (the post-PR thin-marker
contract).
Skipped on purpose:
- AssetUnlock / Coinbase — match Standard, not the keys-only variants.
- QuorumCommitment — no key/address fields the wallet matches against.
- ProviderUpdateRevocation — payload has no key-hash / pubkey field
for matching.
Also fixes a real PR-introduced bug surfaced by writing the IdentityTopUp
test: `add_managed_account` / `add_managed_account_from_xpub` always
constructed `ManagedCoreFundsAccount` regardless of the account type, then
relied on `insert()` accepting it — which now correctly errors for
keys-only types after the variant split. The fix dispatches via a small
`owned_from_account` helper that picks the right variant, and the BLS /
EdDSA paths (always ProviderOperatorKeys / ProviderPlatformKeys, both
keys-only) drop their `ManagedCoreFundsAccount::from_*_account` calls in
favor of `ManagedCoreKeysAccount::from_*_account`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(key-wallet): keep `from_account_collection` field-direct insertions
The earlier refactor in this PR routed every `from_account_collection`
case through `managed_collection.insert(managed_account)` where
`managed_account` was an `OwnedManagedCoreAccount`. That swapped 14
trivial field-typed inserts (e.g. `standard_bip44_accounts.insert(*index,
managed)`) for 14 generic-insert calls — each having to carry a
`.expect()` for an invariant the old code never had to articulate.
Restore the field-direct shape:
- `create_managed_account_from_account_type` (returned the owned enum) is
renamed to `build_managed_account_type` and returns the inner
[`ManagedAccountType`]. That's the actual shared work — building the
address pools.
- Per-variant thin wrappers wrap it as the right concrete type:
- `create_managed_funds_account_from_account` → `ManagedCoreFundsAccount`
- `create_managed_keys_account_from_account` → `ManagedCoreKeysAccount`
- `create_managed_keys_account_from_bls_account` (ProviderOperatorKeys, always keys)
- `create_managed_keys_account_from_eddsa_account` (ProviderPlatformKeys, always keys)
- `from_account_collection` does the field-direct insert each variant
expects — same shape as the original code.
- `is_funds_bearing_account_type` was only used by the old funnel and
is now removed.
The variant-aware `insert(impl Into<OwnedManagedCoreAccount>)` and the
explicit `insert_funds_bearing_account` / `insert_keys_bearing_account`
remain as the public entry points for callers that genuinely need the
runtime-dispatched insert (e.g. `add_managed_account`).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 478af3b commit 428b60d
17 files changed
Lines changed: 2275 additions & 465 deletions
File tree
- dash-spv/tests/dashd_sync
- key-wallet-ffi
- src
- key-wallet/src
- managed_account
- tests
- transaction_checking
- wallet/managed_wallet_info
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
6 | 5 | | |
7 | 6 | | |
8 | 7 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
233 | 233 | | |
234 | 234 | | |
235 | 235 | | |
236 | | - | |
| 236 | + | |
237 | 237 | | |
238 | 238 | | |
239 | 239 | | |
240 | 240 | | |
241 | 241 | | |
242 | 242 | | |
243 | | - | |
| 243 | + | |
244 | 244 | | |
245 | 245 | | |
246 | 246 | | |
| |||
3095 | 3095 | | |
3096 | 3096 | | |
3097 | 3097 | | |
3098 | | - | |
| 3098 | + | |
3099 | 3099 | | |
3100 | 3100 | | |
3101 | 3101 | | |
| |||
3207 | 3207 | | |
3208 | 3208 | | |
3209 | 3209 | | |
3210 | | - | |
| 3210 | + | |
3211 | 3211 | | |
3212 | 3212 | | |
3213 | 3213 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
23 | 27 | | |
24 | 28 | | |
25 | 29 | | |
26 | | - | |
| 30 | + | |
27 | 31 | | |
28 | 32 | | |
29 | 33 | | |
30 | 34 | | |
31 | 35 | | |
32 | 36 | | |
33 | | - | |
| 37 | + | |
34 | 38 | | |
35 | 39 | | |
36 | | - | |
| 40 | + | |
37 | 41 | | |
38 | 42 | | |
39 | 43 | | |
40 | 44 | | |
41 | | - | |
42 | | - | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
43 | 49 | | |
44 | 50 | | |
45 | | - | |
| 51 | + | |
46 | 52 | | |
47 | | - | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
48 | 60 | | |
49 | | - | |
50 | | - | |
51 | 61 | | |
52 | | - | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
53 | 75 | | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | 76 | | |
59 | 77 | | |
60 | 78 | | |
61 | 79 | | |
62 | 80 | | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | 81 | | |
67 | | - | |
| 82 | + | |
68 | 83 | | |
69 | 84 | | |
70 | | - | |
| 85 | + | |
| 86 | + | |
71 | 87 | | |
72 | 88 | | |
73 | 89 | | |
| |||
76 | 92 | | |
77 | 93 | | |
78 | 94 | | |
79 | | - | |
| 95 | + | |
80 | 96 | | |
81 | 97 | | |
82 | 98 | | |
83 | 99 | | |
84 | 100 | | |
85 | 101 | | |
86 | | - | |
| 102 | + | |
87 | 103 | | |
88 | 104 | | |
89 | | - | |
| 105 | + | |
90 | 106 | | |
91 | 107 | | |
92 | 108 | | |
93 | 109 | | |
94 | | - | |
95 | | - | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
96 | 114 | | |
97 | 115 | | |
98 | | - | |
| 116 | + | |
99 | 117 | | |
100 | | - | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
101 | 125 | | |
102 | | - | |
103 | | - | |
104 | 126 | | |
105 | | - | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
106 | 140 | | |
107 | | - | |
108 | | - | |
109 | | - | |
110 | | - | |
111 | 141 | | |
112 | 142 | | |
113 | 143 | | |
| |||
384 | 414 | | |
385 | 415 | | |
386 | 416 | | |
387 | | - | |
| 417 | + | |
388 | 418 | | |
389 | 419 | | |
390 | 420 | | |
| |||
471 | 501 | | |
472 | 502 | | |
473 | 503 | | |
474 | | - | |
| 504 | + | |
475 | 505 | | |
476 | 506 | | |
477 | 507 | | |
| |||
0 commit comments