Skip to main content

OutputLockStore

Trait OutputLockStore 

Source
pub trait OutputLockStore {
    type Error: Debug;
    type AccountId: Copy + Debug + Eq + Hash;

    // Required methods
    fn lock_outputs(
        &mut self,
        outputs: &[OutputRef],
        owner: LockOwner,
        lock_expiry_height: BlockHeight,
    ) -> Result<usize, LockError<Self::Error>>;
    fn unlock_output(
        &mut self,
        output: &OutputRef,
        owner: LockOwner,
    ) -> Result<bool, Self::Error>;
    fn clear_locked_outputs(
        &mut self,
        account: Self::AccountId,
    ) -> Result<usize, Self::Error>;
    fn get_locked_outputs(
        &self,
        account: Self::AccountId,
    ) -> Result<Vec<OutputRef>, Self::Error>;
}
Expand description

The subset of wallet-storage operations that manage output locks.

WalletWrite requires this trait with its Self::AccountId and Self::Error types tied to the corresponding WalletRead types, so every writable wallet backend is an OutputLockStore. The separate trait exists so that lock storage can be implemented, delegated, and reasoned about independently of the full wallet-mutation surface.

Required Associated Types§

Source

type Error: Debug

The type of errors produced by the lock store.

Source

type AccountId: Copy + Debug + Eq + Hash

The type of the account identifier.

Required Methods§

Source

fn lock_outputs( &mut self, outputs: &[OutputRef], owner: LockOwner, lock_expiry_height: BlockHeight, ) -> Result<usize, LockError<Self::Error>>

Locks the specified outputs on behalf of owner so that, by default, they are not selected for spending at any height less than or equal to the given height.

Locks are advisory. Input selection excludes locked outputs by default, but a caller may deliberately draw on them by supplying an owner-scoped LockedInputPolicy (via SpendPolicy::with_locked_input_policy), scoped to the lock owners it names; doing so spends through the lock during selection but never releases it. A locked output can be released only via Self::unlock_output (by its owner) or Self::clear_locked_outputs.

Returns the number of row updates performed on success (equal to the number of provided references; a duplicated reference is counted per occurrence), or a LockError on failure, wrapping either an error from the underlying storage backend or the first output that could not be locked.

A lock may be acquired when the output holds no lock, when its existing lock has expired as of the chain tip, or when its existing lock is held by the same owner; in the latter case the lock’s expiry height is updated. Same-owner re-locking makes the operation idempotent, so a caller that crashes between locking and persisting its proposal can safely retry the flow under the same LockOwner. Acquisition fails only when an unexpired lock is held by a different owner.

Implementations of this method must either succeed completely, successfully locking each provided output on success, or fail completely leaving all lock state unmodified if any of the outputs is actively locked by a different owner.

This is the mechanism by which overlapping proposals for the same account avoid selecting the same inputs by default. Because note selection and locking cannot be performed as a single atomic step above the storage layer, two callers may independently select an overlapping set of outputs before either locks them (a time-of-check/time-of-use race); the conflict is resolved here, at the storage layer, where the second caller’s lock_outputs fails with LockError::LockFailure naming the already-locked output. Callers that lock via a proposal-creation function surface this as ProposalError::InputsLocked. The losing caller has not partially locked anything and should treat the failure as “the account is busy” and retry.

Source

fn unlock_output( &mut self, output: &OutputRef, owner: LockOwner, ) -> Result<bool, Self::Error>

Unlocks the specified output if it is locked by the given owner, making it once again available for spending and balance computations.

Returns true if a lock held by owner (whether or not it had already expired) was removed from the output, and false otherwise: in particular, a lock held by a different owner is left in place, so one flow cannot accidentally release another’s locks.

Source

fn clear_locked_outputs( &mut self, account: Self::AccountId, ) -> Result<usize, Self::Error>

Unlocks every currently-locked output belonging to the specified account, regardless of lock expiry height.

This is intended as a recovery mechanism for callers that have lost track of their in-flight proposals or PCZTs (for example, because the application was terminated by the operating system before the corresponding transactions could be built). By clearing all locks for the account, the caller declares that it has no pending proposals holding those outputs.

§Warning

This releases every lock for the account regardless of its owner, including locks held by proposals that are still legitimately in flight; those proposals’ inputs immediately become selectable by new proposals, re-creating the conflict that locking exists to prevent. Only call this when no in-flight proposal or PCZT for the account remains.

Returns the number of outputs that were unlocked.

Source

fn get_locked_outputs( &self, account: Self::AccountId, ) -> Result<Vec<OutputRef>, Self::Error>

Returns the set of currently locked outputs for the given account.

Locked outputs are excluded from note selection, and are tallied separately in balance computations. A wallet needs this to show the user which funds are reserved by an in-flight proposal, so it is part of the ordinary interface rather than a testing affordance.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§

Source§

impl OutputLockStore for MockWalletDb

Available on crate features test-dependencies only.