Skip to content

feat: preserve transaction status (mempool/IS-locked/confirmed/chain-locked) in TransactionRecord #569

Description

@lklimek

User Story

As a wallet application developer, I want TransactionRecord to carry the transaction's lifecycle status (mempool → IS-locked → confirmed → chain-locked) so that I can display meaningful status indicators to users without re-deriving state from height/block_hash fields.

Problem

TransactionContext already distinguishes Mempool, InBlock, and InChainLockedBlock — but record_transaction() in ManagedAccount discards the variant after extracting height/block_hash:

// managed_account/mod.rs:385-390
let tx_record = TransactionRecord {
    height: context.block_height(),      // Some(h) or None
    block_hash: context.block_hash(),    // Some(hash) or None
    // TransactionContext variant is lost here
    ...
};

Consumers (like dash-evo-tool) can only infer height.is_some() → confirmed vs unconfirmed, losing the richer status information that was available at recording time.

Requested Changes

1. Add status field to TransactionRecord

pub struct TransactionRecord {
    // ... existing fields ...
    /// Transaction lifecycle status
    pub status: TransactionContext,
}

Preserve the TransactionContext that's already passed to record_transaction().

2. Set Utxo.is_instantlocked on InstantSend lock receipt

The is_instantlocked field exists on Utxo and is used in coin selection (is_spendable(), coin_selection.rs), but is never set to true — it's initialized as false in Utxo::new() and no code path flips it.

When SyncEvent::InstantLockReceived fires, UTXOs belonging to the locked transaction should be updated.

3. Add status to WalletEvent::TransactionReceived

WalletEvent::TransactionReceived {
    // ... existing fields ...
    status: TransactionContext,
}

So consumers know if a received transaction is mempool/confirmed/chain-locked without re-querying the wallet.

4. (Nice to have) Add WalletEvent::TransactionStatusChanged

WalletEvent::TransactionStatusChanged {
    wallet_id: WalletId,
    txid: Txid,
    old_status: TransactionContext,
    new_status: TransactionContext,
}

Fires on status transitions (Mempool → IS-locked → Confirmed → ChainLocked), enabling reactive UI updates.

Context

dash-evo-tool PR dashpay/dash-evo-tool#776 integrates the MempoolManager with BloomFilter strategy. With mempool tracking active, the wallet now sees unconfirmed transactions — but we cannot distinguish them from IS-locked transactions in the UI because the status information is discarded upstream.

We're adding a TransactionStatus enum on the evo-tool side and inferring what we can from height, but full lifecycle tracking requires these upstream changes.

🤖 Co-authored by Claudius the Magnificent AI Agent

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions