ReadModelStorage class abstract

Abstract interface for read-model storage operations.

This interface handles query operations for wallet data projections, including UTXOs, transactions, block headers, and merkle proofs. This represents the "read side" of CQRS pattern.

Rules every backend follows (audit 2026-09-14 S-15, S-19; contract tests in test/storage/wallet_lifecycle_contract.dart):

Implementers

Constructors

ReadModelStorage()

Properties

hashCode → int
The hash code for this object.
no setterinherited
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited

Methods

checkAddresses(String walletId, List<String> addresses) → Future<Map<String, bool>>
Batch check if addresses belong to wallet (optimized for bulk operations)
countSpentUTXOs(String walletId) → Future<int>
How many of the wallet's UTXO rows are spent.
deletePaymentChannel(String channelId) → Future<void>
Delete a payment channel
deleteUTXO(String walletId, String txid, int vout) → Future<void>
Delete a UTXO from the read model.
deleteWallet(String walletId) → Future<void>
Delete all data for a specific wallet.
getAddressCount(String walletId) → Future<int>
Get the count of addresses for a wallet (for verification during import)
getAddressesByPurpose(String walletId, String purpose) → Future<List<AddressMetadata>>
The wallet's address rows whose purpose is purpose (for example watch), in no particular order. Filtered in the backend: only the matching rows are loaded (bead libspiffy-p4kv).
getAddressesWithMetadata(String walletId, {bool? includeUnused, bool? isChange, int? limit, int? offset}) → Future<List<AddressMetadata>>
Get all addresses for a wallet with pagination
getAddressMetadata(String walletId, String address) → Future<AddressMetadata?>
Get address metadata if it belongs to wallet
getAddressRange(String walletId, {required int startIndex, required int count, bool isChange = false}) → Future<List<AddressMetadata>>
Get addresses by derivation range (efficient for HD wallets)
getAddressTransactionCount(String walletId, String address) → Future<int>
Get transaction count for an address
getAncestorTransactionsBatch(List<String> txids) → Future<Map<String, String>>
The raw hex of every stored ancestor transaction among txids, as a map txid → rawHex (txids without a row are absent).
getAvailableUTXOs(String walletId) → Future<List<BitcoinUtxo>>
Get only available (unspent and unreserved) UTXOs for a wallet.
getBalance(String walletId) → Future<BigInt>
Calculate the total balance for a wallet.
getBestHeight() → Future<int>
Get current best block height
getBlockHeaderByHash(String hash) → Future<BlockHeader?>
Get block header by hash
getBlockHeaderByHeight(int height) → Future<BlockHeader?>
Get block header by height
getBlockHeaderRange(int fromHeight, int toHeight) → Future<List<BlockHeader>>
Get range of block headers
getChainTip() → Future<BlockHeader?>
Get current chain tip header
getConfirmedTransactionsFromHeight(int minHeight, {bool includeWithoutHeight = false}) → Future<List<BitcoinTransaction>>
Confirmed rows of every wallet whose blockHeight is at least minHeight; with includeWithoutHeight, also confirmed rows that have no block height (bead libspiffy-ctkm). Rows come newest first (createdAt descending).
getDeferredPayment(String walletId, String txid) → Future<DeferredPayment?>
The deferred payment txid of walletId, or null.
getHeightByBlockHash(String hash) → Future<int?>
Get height for a block hash
getInvoice(String invoiceId) → Future<InvoiceReadModel?>
Get a specific invoice by ID.
getInvoicesByStatus(InvoiceStatus status, {String? walletId}) → Future<List<InvoiceReadModel>>
Get all invoices with a specific status, newest first.
getInvoicesByWallet(String walletId) → Future<List<InvoiceReadModel>>
Get all invoices for a specific wallet, newest first.
getMerkleProof(String txid) → Future<MerkleProof?>
The current proof of txid: its one MerkleProof.isCurrent row (MerkleProofStatus.verified or MerkleProofStatus.pendingHeader), or null. Orphaned and rejected rows are never returned.
getMerkleProofCount({String? walletId}) → Future<int>
Get the count of stored merkle proofs.
getMerkleProofHistory(String txid) → Future<List<MerkleProof>>
Every proof row stored for txid, orphaned and rejected ones included, oldest first.
getMerkleProofsBatch(List<String> txids) → Future<Map<String, MerkleProof>>
Batch get the current proofs by txid list (see getMerkleProof).
getMerkleProofsByStatus(MerkleProofStatus status) → Future<List<MerkleProof>>
Every proof row with status (for example the MerkleProofStatus.pendingHeader proofs to check once headers arrive).
getMerkleProofsByStatusBetweenHeights(MerkleProofStatus status, int fromHeight, int toHeight) → Future<List<MerkleProof>>
The proof rows with status whose block height is between fromHeight and toHeight (both inclusive), oldest first (bead libspiffy-hg0).
getMerkleProofsByStatusChangedSince(MerkleProofStatus status, DateTime since) → Future<List<MerkleProof>>
The proof rows with status whose status changed at or after since (MerkleProof.statusChangedAt), oldest first (bead libspiffy-hccp). Rows without a statusChangedAt are not returned.
getMerkleProofsForBlock(String blockHash) → Future<List<MerkleProof>>
The current (MerkleProof.isCurrent) proofs that name blockHash.
getOutputsAwaitingAncestorProof(String walletId, {int maxDepth = 20}) → Future<List<OutputAwaitingProof>>
The wallet's unspent outputs that cannot be proven to a counterparty right now, each with the ancestors that stand in the way (bead libspiffy-0lx).
getPaymentChannel(String channelId) → Future<PaymentChannel?>
Get a payment channel by ID.
getPaymentChannelsForWallet(String walletId) → Future<List<PaymentChannel>>
Get all payment channels for a wallet.
getPaymentUTXOs(String walletId) → Future<List<BitcoinUtxo>>
Get available UTXOs suitable for BSV payments.
getPendingReceive(String walletId, String txid) → Future<PendingReceive?>
The parked receive of (walletId, txid), resolved or not.
getPendingReceivesUpToHeight(int height, {int limit = 64}) → Future<List<PendingReceive>>
The receives still waiting (PendingReceive.isWaiting) whose neededHeight is at most height, oldest first, at most limit of them.
getRecentHeaders(int count) → Future<List<BlockHeader>>
Get recent block headers
getTransaction(String txid, {String? walletId}) → Future<BitcoinTransaction?>
Get a specific transaction by ID.
getTransactionAddresses(String walletId, String txid) → Future<TransactionAddresses>
Get all addresses involved in a transaction
getTransactionHistory(String walletId, {int? limit, int? offset}) → Future<List<BitcoinTransaction>>
Get transaction history for a wallet
getTransactionsBatch(List<String> txids) → Future<Map<String, BitcoinTransaction>>
Batch get transactions by txid list
getTransactionsByAddress(String walletId, String address, {String? direction, int? limit, int? offset}) → Future<List<String>>
Get all transactions involving a specific address
getTransactionsByStatus(TransactionStatus status, {String? walletId}) → Future<List<BitcoinTransaction>>
Get transactions by status
getTransactionsByStatusSince(TransactionStatus status, DateTime since, {int limit = 100}) → Future<List<BitcoinTransaction>>
The rows with status last updated at or after since, newest first (updatedAt descending), at most limit of them (bead libspiffy-5bju).
getTransactionsByTxids(List<String> txids) → Future<List<BitcoinTransaction>>
Every wallet's row for each of txids (bead libspiffy-ctkm).
getUTXO(String walletId, String txid, int vout) → Future<BitcoinUtxo?>
The wallet's UTXO row for one outpoint, or null when it holds none.
getUTXOs(String walletId, {bool includeSpent = false}) → Future<List<BitcoinUtxo>>
Get all UTXOs for a specific wallet.
getUTXOsByPlugin(String walletId, String pluginId, {Map<String, dynamic>? metadataFilter}) → Future<List<BitcoinUtxo>>
Get UTXOs managed by a specific plugin.
getUTXOsByTxid(String walletId, String txid, {bool includeSpent = false}) → Future<List<BitcoinUtxo>>
The wallet's UTXO rows created by txid, newest first.
getWallet(String walletId) → Future<Map<String, dynamic>?>
Get wallet metadata; null for an unknown or deleted wallet. The metadata entry is a map, empty when the wallet has none, never null.
getWalletAddresses(String walletId) → Future<List<String>>
Get all addresses for a wallet
getWalletIds() → Future<List<String>>
Get a list of all wallet IDs in storage.
getWatchOnlyBalance(String walletId) → Future<BigInt>
The watch-only part of the wallet's getPaymentUTXOs: available UTXOs the wallet holds no key for because a key they need is a watch address (bead libspiffy-vsap). Not part of getBalance; the coordinator's BalanceResponse.watchOnlyBalance.
isWalletAddress(String walletId, String address) → Future<bool>
Check if an address belongs to a wallet (O(1) hash lookup)
listDeferredPayments(String walletId, {DeferredPaymentQuery query = const DeferredPaymentQuery()}) → Future<DeferredPaymentPage>
A page of walletId's deferred payments matching query, in its order (createdAt, then txid; newest first unless DeferredPaymentQuery.oldestFirst). Backends answer the default outstanding-only query from an index on (wallet, state, createdAt), never by reading every row. Throws FormatException for a cursor this API did not produce.
listInvoices({String? walletId, InvoiceStatus? status}) → Future<List<InvoiceReadModel>>
List invoices, newest first.
listWallets() → Future<List<String>>
List the IDs of all existing wallets, newest first.
markHeaderAsOrphaned(String hash) → Future<void>
Mark a block header as orphaned due to reorganization
markMerkleProofOrphaned(String txid, {String? blockHash, List<String>? onlyIfMerkleProof, DateTime? at}) → Future<bool>
Mark the current proof of txid orphaned: its block left the active chain (audit 3b0, bead libspiffy-mny). The row is kept and stays readable through getMerkleProofHistory; getMerkleProof no longer returns it.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
resolvePendingReceive(String walletId, String txid, String resolution, {DateTime? at}) → Future<bool>
Record that the receive of (walletId, txid) stopped waiting: resolution says why (it was recorded, or it failed for a reason more headers cannot change). The row is kept, and no longer replayed.
storeAncestorTransaction(String txid, String rawHex) → Future<void>
Store the raw transaction rawHex of txid as ancestor evidence.
storeBlockHeader(BlockHeader header, int height) → Future<void>
Store a block header as part of the active chain at height.
storeBlockHeadersBulk(List<(BlockHeader, int)> headers) → Future<void>
Bulk store block headers for fast initial sync (CDN import).
storeDeferredPayment(DeferredPayment payment) → Future<void>
Insert or replace the row of payment (key: walletId, txid).
storeInvoice(InvoiceReadModel invoice) → Future<void>
Store an invoice read model (insert, or replace an existing row with the same invoiceId).
storeMerkleProof(String txid, MerkleProof proof) → Future<void>
Store merkle proof for a transaction.
storePaymentChannel(PaymentChannel channel) → Future<void>
Store a payment channel (insert, or replace every mutable column of an existing row with the same channelId).
storePendingReceive(PendingReceive receive) → Future<void>
Park receive until headers reach its neededHeight, or update the row already parked for its (walletId, txid).
storeRevertedTransaction(String walletId, BitcoinTransaction transaction) → Future<void>
Stores transaction as the row of (walletId, txid) with the status, block height and confirmations it carries, even when that lowers a confirmed status: the one way a confirmation is taken back, used for a reorganization past the confirming block or a proof its block header contradicts (audit 3b0, bead libspiffy-7dj). A non-confirmed record clears the stored block height. Raw hex and the other rules of storeTransaction apply; nothing is deleted.
storeTransaction(String walletId, BitcoinTransaction transaction) → Future<void>
Store a raw transaction in the read model.
storeTransactionAddresses(String walletId, String txid, List<TransactionAddressLink> links) → Future<void>
Store transaction-address junction records.
storeWallet(String walletId, String name, {String? rootAddress, String? networkType, Map<String, dynamic>? metadata}) → Future<void>
Store or update wallet metadata.
toString() → String
A string representation of this object.
inherited
updateAddressUsage(String walletId, String address, {DateTime? usedAt, BigInt? balanceDelta}) → Future<void>
Update address usage statistics.
updateInvoiceStatus(String invoiceId, InvoiceStatus status, {String? txid, BigInt? amountReceived, DateTime? paidAt}) → Future<void>
Update the status of an invoice.
updatePaymentChannelBalance(String channelId, BigInt clientBalance, BigInt serverBalance) → Future<void>
Update payment channel balances
updatePaymentChannelState(String channelId, String state) → Future<void>
Update payment channel state.
upsertAddress(String walletId, AddressMetadata metadata) → Future<void>
Store or update address metadata
upsertUTXO(String walletId, BitcoinUtxo utxo) → Future<void>
Upsert (insert or update) a UTXO in the read model.
walletExists(String walletId) → Future<bool>
Check if a wallet exists in storage.

Operators

operator ==(Object other) → bool
The equality operator.
inherited