Skip to content

Commit 5d70885

Browse files
committed
WIP: IntentTracker requirements
1 parent 71bf887 commit 5d70885

File tree

3 files changed

+39
-31
lines changed

3 files changed

+39
-31
lines changed

wallet/examples/intent_tracker.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@ where
3030
Ok(())
3131
}
3232

33+
/// Demonstate how we handle the following situations:
34+
///
35+
/// ## An outgoing transaction depends on an incoming transaction that gets replaced.
36+
///
37+
/// Given:
38+
/// * Wallet receives an incoming unconfirmed transaction.
39+
/// * Wallet creates outgoing transaction that spends from the incoming transaction.
40+
/// * The wallet tracks the outgoing transaction (with `wallet.track_tx`).
41+
/// * The incoming transaction gets replaced.
42+
///
43+
/// When:
44+
/// * `wallet.uncanonical_txs` is called, expect:
45+
/// * 1 transaction is returned (the created outgoing transaction).
46+
/// * `UncanonicalTx::is_safe_to_untrack(0)` should return true.
47+
/// * `UncanonicalTx::is_safe_to_untrack(>0)` should return false.
48+
/// * TODO: Can replace == false, no inputs available.
49+
3350
/// Receive an unconfirmed tx, spend from it, and the unconfirmed tx get's RBF'ed.
3451
/// Our API should be able to recognise that the outgoing tx became evicted and allow the caller
3552
/// to respond accordingly.

wallet/src/wallet/intent_tracker.rs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ impl NetworkSeen {
128128
/// This struct models an input that attempts to spend an output via a transaction path
129129
/// that is not part of the canonical network view (e.g., evicted, conflicted, or unknown).
130130
#[derive(Debug, Clone)]
131-
pub struct SpendInfo<A> {
131+
pub struct UncanonicalSpendInfo<A> {
132132
/// Non-canonical ancestor transactions reachable from this input.
133133
///
134134
/// Each entry maps an ancestor `Txid` to its observed status in the network.
@@ -144,19 +144,19 @@ pub struct SpendInfo<A> {
144144
/// position of the conflict.
145145
///
146146
/// [`uncanonical_ancestors`]: Self::uncanonical_ancestors
147-
pub conflicting_txs: BTreeMap<Txid, ChainPosition<A>>,
147+
pub canonical_conflicts: BTreeMap<Txid, ChainPosition<A>>,
148148
}
149149

150-
impl<A> Default for SpendInfo<A> {
150+
impl<A> Default for UncanonicalSpendInfo<A> {
151151
fn default() -> Self {
152152
Self {
153153
uncanonical_ancestors: BTreeMap::new(),
154-
conflicting_txs: BTreeMap::new(),
154+
canonical_conflicts: BTreeMap::new(),
155155
}
156156
}
157157
}
158158

159-
impl<A: Anchor> SpendInfo<A> {
159+
impl<A: Anchor> UncanonicalSpendInfo<A> {
160160
pub(crate) fn new<C>(
161161
chain: &C,
162162
chain_tip: BlockId,
@@ -205,7 +205,7 @@ impl<A: Anchor> SpendInfo<A> {
205205

206206
// Find conflicts to populate `conflicting_txs`.
207207
if let Some((conflict_txid, conflict_tx, reason)) = network_view.spend(prev_op) {
208-
let conflict_tx_entry = match spend_info.conflicting_txs.entry(conflict_txid) {
208+
let conflict_tx_entry = match spend_info.canonical_conflicts.entry(conflict_txid) {
209209
Entry::Vacant(vacant_entry) => vacant_entry,
210210
// Skip if conflicting tx already visited.
211211
Entry::Occupied(_) => continue,
@@ -224,11 +224,12 @@ impl<A: Anchor> SpendInfo<A> {
224224

225225
// Find descendants of `conflict_tx` too.
226226
for (conflict_txid, _, reason) in network_view.descendants(conflict_tx) {
227-
let conflict_tx_entry = match spend_info.conflicting_txs.entry(conflict_txid) {
228-
Entry::Vacant(vacant_entry) => vacant_entry,
229-
// Skip if conflicting tx already visited.
230-
Entry::Occupied(_) => continue,
231-
};
227+
let conflict_tx_entry =
228+
match spend_info.canonical_conflicts.entry(conflict_txid) {
229+
Entry::Vacant(vacant_entry) => vacant_entry,
230+
// Skip if conflicting tx already visited.
231+
Entry::Occupied(_) => continue,
232+
};
232233
let conflict_tx_node = match tx_graph.get_tx_node(conflict_txid) {
233234
Some(tx_node) => tx_node,
234235
// Skip if conflict tx does not exist in our graph.
@@ -308,7 +309,7 @@ impl<A: Anchor> SpendInfo<A> {
308309
/// If the spend info is empty, then it can belong in the canonical history without displacing
309310
/// existing transactions or need to add additional transactions other than itself.
310311
pub fn is_empty(&self) -> bool {
311-
self.uncanonical_ancestors.is_empty() && self.conflicting_txs.is_empty()
312+
self.uncanonical_ancestors.is_empty() && self.canonical_conflicts.is_empty()
312313
}
313314
}
314315

@@ -319,16 +320,17 @@ pub struct UncanonicalTx<A> {
319320
pub txid: Txid,
320321
/// The uncanonical transaction.
321322
pub tx: Arc<Transaction>,
322-
/// Whether the transaction was one seen by the network.
323+
/// Whether the transaction was once seen by the network.
323324
pub network_seen: NetworkSeen,
324325
/// Spends, identified by prevout, which are uncanonical.
325-
pub uncanonical_spends: BTreeMap<OutPoint, SpendInfo<A>>,
326+
pub uncanonical_spends: BTreeMap<OutPoint, UncanonicalSpendInfo<A>>,
326327
}
327328

328329
impl<A: Anchor> UncanonicalTx<A> {
329330
/// Whether the transaction was once observed in the network.
330331
///
331-
/// Assuming that the chain-source does not lie, we can safely remove transactions that
332+
/// Assuming that the chain-source does not lie, we can safely remove transactions that were
333+
/// never seen by the network.
332334
pub fn was_seen(&self) -> bool {
333335
self.network_seen.was_seen()
334336
}
@@ -355,14 +357,14 @@ impl<A: Anchor> UncanonicalTx<A> {
355357
}
356358

357359
/// Iterate over transactions that are currently canonical in the network, but would be rendered
358-
/// uncanonical if this transaction were to become canonical.
360+
/// uncanonical (be replaced) if this transaction were to become canonical.
359361
///
360362
/// This includes both direct and indirect conflicts, such as any transaction that relies on
361363
/// conflicting ancestry.
362364
pub fn conflicts(&self) -> impl Iterator<Item = (Txid, &ChainPosition<A>)> {
363365
self.uncanonical_spends
364366
.values()
365-
.flat_map(|spend| &spend.conflicting_txs)
367+
.flat_map(|spend| &spend.canonical_conflicts)
366368
.map(|(&txid, pos)| (txid, pos))
367369
.filter({
368370
let mut dedup = HashSet::<Txid>::new();
@@ -487,7 +489,7 @@ impl IntentTracker {
487489
false
488490
}
489491

490-
/// Push a `txid` to the broadcast queue (if it does not exist already) and displaces all
492+
/// Push a `txid` in the `IntentTracker` (if it does not exist already) and displaces all
491493
/// coflicting txids in the queue.
492494
pub fn push_and_displace_conflicts<A>(&mut self, tx_graph: &TxGraph<A>, txid: Txid) -> ChangeSet
493495
where

wallet/src/wallet/mod.rs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use alloc::{
2121
};
2222
use chain::CanonicalReason;
2323
use core::{cmp::Ordering, fmt, mem, ops::Deref};
24-
use intent_tracker::{CanonicalView, NetworkSeen, SpendInfo, UncanonicalTx};
24+
use intent_tracker::{CanonicalView, NetworkSeen, UncanonicalSpendInfo, UncanonicalTx};
2525

2626
use bdk_chain::{
2727
indexer::keychain_txout::KeychainTxOutIndex,
@@ -2709,17 +2709,6 @@ impl Wallet {
27092709
.filter(|old_txid| !view.txs.contains_key(old_txid))
27102710
}
27112711

2712-
// <<<<<<< HEAD
2713-
// fn update_views(&mut self) {
2714-
// self.update_network_view();
2715-
// let _ = self.update_intent_view();
2716-
// }
2717-
2718-
// /// Stage changes and return evicted txids from intent canonical view.
2719-
// ///
2720-
// /// TODO: Do we also need to return evicted txids from network canonical view.
2721-
// =======
2722-
27232712
/// Stage changes, rebuild views and return evicted txids from intent canonical view.
27242713
pub(crate) fn stage_changes<C: Into<ChangeSet>>(&mut self, changeset: C) -> Vec<Txid> {
27252714
let changeset: ChangeSet = changeset.into();
@@ -2814,7 +2803,7 @@ impl Wallet {
28142803
.iter()
28152804
.filter_map(|txin| {
28162805
let op = txin.previous_output;
2817-
let spend_info = SpendInfo::new(
2806+
let spend_info = UncanonicalSpendInfo::new(
28182807
&self.chain,
28192808
tip.block_id(),
28202809
graph,

0 commit comments

Comments
 (0)