Skip to content

key-wallet: restore persisted used addresses together with UTXOs, with a checked refill plan #1350

Open

Description

@PastaPastaPasta

ManagedWalletInfo::restore_utxos (#1295) places each restored UTXO in the account whose pools derive its script, and grows the pools to their gap limit as it goes. A wallet loaded from storage often has more to restore than its UTXOs. It also has the addresses that were used and whose coins have since been spent. Today a caller has to rebuild that state around restore_utxos itself, and doing that correctly is subtle.

What callers currently have to do (dashpay/platform#5780 does all of it in platform-wallet-storage):

  • Mark the persisted used addresses in whichever account derives them. Then refill, and repeat until nothing new is marked and no refill derives anything new. A spent address only becomes reachable after an earlier coin's refill, and it can in turn lead to a deeper coin, so the coins and the used addresses must reach one fixed point.
  • Call restore_utxos with no UTXOs just to trigger a refill, and compare highest_generated per pool to see whether a pass derived anything.
  • Check each refill's size before running it, which means mirroring AddressPool::maintain_gap_limit's target arithmetic outside the crate. That arithmetic is unchecked, and a pool whose refill would be too large or unrepresentable gives no structured refusal.
  • When one pool can't be refilled, still place the coins whose scripts are already derived, with the same account precedence and copy removal as restore_utxos. There is no public way to place coins without a refill. fix(platform-wallet-storage): restore UTXOs into the account that derives them platform#5780 works around it by calling restore_utxos with a Wallet that carries no accounts, so extend_pools finds no key source and skips every pool. That relies on how restore_utxos uses the wallet internally, and a public no-refill placement would replace it.

Proposed API shape:

  • A restore entry point that takes the persisted used addresses (or scripts) alongside the UTXOs, and owns the combined fixed point: mark, refill and match until stable, then place each UTXO by script with the existing precedence and copy removal.
  • A checked refill plan: per pool, the refill a gap-limit maintenance would perform (target index, count), computed with checked arithmetic. The caller can then apply its own bound before anything is derived.
  • Structured per-pool refusals (account type, pool type, reason) instead of an opaque error, and a mode that places by already-derived scripts when a pool is refused, returning the coins it couldn't place.

Out of scope: storage, SQL attribution, allocation budgets and load policy. Those stay with the caller.

Related:

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions