Expand description
§Output locking
This module is the single home for the wallet’s advisory output-locking
vocabulary: the identity of a lock holder (LockOwner), the error surface
of lock acquisition (LockError), the storage contract through which
wallet backends persist lock state (OutputLockStore), the request
through which proposal-creation functions acquire locks (LockRequest
and unlock_proposal_inputs), and the policy types through which input
selection interacts with lock state (LockedInputPolicy and
LockFilter).
§Semantics
All lock state is a pair of columns on each received output: a
lock_expiry_height and a lock_owner. Every behavior is derived from the
following invariants, stated here once:
- Locked: an output is locked while
lock_expiry_height >= target_height, where the target height is the height at which a new transaction would be mined (chain tip + 1). Balance computations tally an output as locked under exactly this condition. - Eligible for selection: input selection eligibility is the exact
complement of the locked condition, owner-scoped under a
LockedInputPolicy: an output is eligible when it carries no lock, when its lock has expired (lock_expiry_height < target_height), or when itslock_owneris one of the owners the policy admits. An output locked by any other owner is never selected. - Acquisition: a lock may be acquired (
OutputLockStore::lock_outputs) when the output is unlocked, when its existing lock has expired as of the chain tip, or when the existing lock is held by the same owner (an idempotent re-acquire/extend, so a flow that crashed after locking may safely retry under its original owner token). Acquisition fails only on an active foreign lock. There is no stealing: because “expired as of the chain tip” (h <= chain_tip) is exactly “not locked for selection” (h < target_height), a foreign lock is replaceable exactly when the output has already become selectable again. - Advisory: locks are advisory in selection. An owner-scoped policy override spends through a lock during selection; it never releases the lock.
- Release: there are exactly four release paths: owner-scoped unlock
(
OutputLockStore::unlock_output,unlock_proposal_inputs), owner-agnostic clearing (OutputLockStore::clear_locked_outputs), unlock-on-store (implementations ofWalletWrite::store_transactions_to_be_sentunlock outputs recorded as spent, the spend records having taken over double-selection protection), and expiry (the passage of the chain tip beyondlock_expiry_height). - Expiry re-opens the race: if an operation outlasts its lock window, the lock expires and a concurrent proposal may select and spend the same outputs. Lock windows must be chosen conservatively with respect to the worst-case time between proposal creation and transaction storage.
§Integration map
The locking feature touches the codebase at the following points, by role:
- Schema: the
note_lockingmigration inzcash_client_sqlite(wallet::init::migrations::note_locking) adds thelock_expiry_heightandlock_ownercolumns to the four received-output tables; the table definitions inzcash_client_sqlite::wallet::dbcarry them forward. - Acquisition: the five proposal-creation functions
(
propose_transfer,propose_standard_transfer_to_address,propose_send_max_transfer,propose_shielding, andpropose_shielding_coinbase) accept an optionalLockRequestand lock every selected input viaOutputLockStore::lock_outputs. - Selection: the seven
zcash_client_sqliteleaf queries that select spendable outputs (get_spendable_note,select_unspent_notes,select_spendable_notes_matching_value, andunspent_notes_metainwallet::common;get_spendable_transparent_outputs,get_spendable_transparent_outputs_for_addresses, andselect_spendable_transparent_outputsinwallet::transparent) embed the eligibility fragment parameterized by aLockFilter. - Balance: four classification sites tally locked value separately:
the shielded-note branch of
get_wallet_summaryand the three transparent tallies (get_transparent_balancesand the two branches ofadd_transparent_account_balances, including the coinbase arm) inzcash_client_sqlite. - Release: the four release paths listed under Semantics above.
- Proposal decoding: proposal decoding in
crate::protoreads wallet contents withLockFilter::Unfiltered, since a persisted proposal must be reconstructible regardless of current lock state. - Consumers:
zcash_client_sqlite’sPoolMigrations::migration_lock_ownersexposes the owners of a pool migration’s in-flight locks so callers can construct owner-scoped policies; Zallet consumes the locking API for its transaction flows.
Macros§
- ambassador_
impl_ Output Lock Store - A macro to be used by [
ambassador::Delegate] to delegateOutputLockStore
Structs§
- Lock
Owner - An opaque token identifying the holder of an output lock.
- Lock
Request - A request to lock the inputs selected by a proposal, made when calling one of the
proposal-creation functions (
propose_transferand friends).
Enums§
- Lock
Error - Errors that occur when attempting to lock an output.
- Lock
Filter - How a query filters candidate outputs by lock state.
- Locked
Input Policy - Governs whether input selection may draw on locked outputs, and with what preference.
Traits§
- Output
Lock Store - The subset of wallet-storage operations that manage output locks.
Functions§
- unlock_
proposal_ inputs - Unlocks all inputs selected by the given proposal, reversing the locks acquired when the
proposal was created with a
LockRequestunder the sameowner.