From: Rafael Turon <3598269+rafaelturon@users.noreply.github.com>
Date: Thu, 5 Mar 2026 21:02:06 +0000 (-0300)
Subject: docs: document TxUpdate temporal context requirements
X-Git-Url: http://internal-gitweb-vhost/parse/src/example_cli/%22https:/encode/struct.EncoderStringWriter.html?a=commitdiff_plain;h=b69d7bfce32d20a5849052a2e61bf8d8bff813a6;p=bdk
docs: document TxUpdate temporal context requirements
This introduces clear temporal context documentation to the `TxUpdate`
struct, explicitly stating that entries must have either `anchors` or
`seen_ats` to be considered canonical and contribute to wallet balances.
This fulfills the recommendation outlined in the Wizardsardine
BDK Audit Report (Q4 2024).
Signed-off-by: Rafael Turon <3598269+rafaelturon@users.noreply.github.com>
---
diff --git a/crates/chain/src/indexed_tx_graph.rs b/crates/chain/src/indexed_tx_graph.rs
index 9adf7ed9..69337840 100644
--- a/crates/chain/src/indexed_tx_graph.rs
+++ b/crates/chain/src/indexed_tx_graph.rs
@@ -178,6 +178,10 @@ where
///
/// `update` is a [`tx_graph::TxUpdate`] and the resultant changes is returned as
/// [`ChangeSet`].
+ ///
+ /// **Note**: Transactions in the `update` without temporal context (anchors or seen_ats)
+ /// will be stored but will not be considered canonical. See [`tx_graph::TxUpdate`] for
+ /// more details.
pub fn apply_update(&mut self, update: tx_graph::TxUpdate) -> ChangeSet {
let tx_graph = self.graph.apply_update(update);
let indexer = self.index_tx_graph_changeset(&tx_graph);
diff --git a/crates/chain/src/tx_graph.rs b/crates/chain/src/tx_graph.rs
index 701de335..c2e77d34 100644
--- a/crates/chain/src/tx_graph.rs
+++ b/crates/chain/src/tx_graph.rs
@@ -913,6 +913,9 @@ impl TxGraph {
///
/// The returned [`ChangeSet`] is the set difference between `update` and `self` (transactions
/// that exist in `update` but not in `self`).
+ ///
+ /// **Note**: Transactions in the `update` without temporal context (anchors or seen_ats)
+ /// will be stored but will not be considered canonical. See [`TxUpdate`] for more details.
pub fn apply_update(&mut self, update: TxUpdate) -> ChangeSet {
let mut changeset = ChangeSet::::default();
for tx in update.txs {
diff --git a/crates/core/src/tx_update.rs b/crates/core/src/tx_update.rs
index 47489070..f92cf3e9 100644
--- a/crates/core/src/tx_update.rs
+++ b/crates/core/src/tx_update.rs
@@ -18,6 +18,13 @@ use bitcoin::{OutPoint, Transaction, TxOut, Txid};
/// tx_update.txs.push(tx);
/// tx_update.anchors.insert((anchor, txid));
/// ```
+/// ## Temporal context
+/// To contribute to a wallet's balance, transactions must have an entry in either:
+/// - [`Self::anchors`]: for confirmed transactions.
+/// - [`Self::seen_ats`]: for unconfirmed transactions.
+///
+/// The built-in chain-source crates (`bdk_electrum`, `bdk_esplora`, `bdk_bitcoind_rpc`) handle this
+/// automatically. Transactions lacking temporal context are stored but ignored by canonicalization.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct TxUpdate {