]> Untitled Git - bdk/commitdiff
Add `last_seen` to the the `ConfirmationTime::Unconfirmed` variant
author志宇 <hello@evanlinjin.me>
Thu, 11 May 2023 14:56:26 +0000 (22:56 +0800)
committer志宇 <hello@evanlinjin.me>
Sat, 3 Jun 2023 19:32:17 +0000 (03:32 +0800)
This allows us to skip adding an extra input to `Wallet::insert_tx`.

Also remove redundant logic.

crates/bdk/src/wallet/coin_selection.rs
crates/bdk/src/wallet/export.rs
crates/bdk/src/wallet/mod.rs
crates/bdk/src/wallet/tx_builder.rs
crates/bdk/tests/common.rs
crates/bdk/tests/wallet.rs
crates/chain/src/chain_data.rs
crates/chain/tests/test_keychain_tracker.rs
crates/electrum/src/lib.rs
crates/esplora/src/lib.rs

index 373dbdc38cc4b6f27391c4653a99b648ae0e510a..e7927cabb3e2eb41e4bf6d6635196612dea6075b 100644 (file)
@@ -722,9 +722,13 @@ mod test {
 
     fn get_test_utxos() -> Vec<WeightedUtxo> {
         vec![
-            utxo(100_000, 0, ConfirmationTime::Unconfirmed),
-            utxo(FEE_AMOUNT - 40, 1, ConfirmationTime::Unconfirmed),
-            utxo(200_000, 2, ConfirmationTime::Unconfirmed),
+            utxo(100_000, 0, ConfirmationTime::Unconfirmed { last_seen: 0 }),
+            utxo(
+                FEE_AMOUNT - 40,
+                1,
+                ConfirmationTime::Unconfirmed { last_seen: 0 },
+            ),
+            utxo(200_000, 2, ConfirmationTime::Unconfirmed { last_seen: 0 }),
         ]
     }
 
@@ -780,7 +784,7 @@ mod test {
                             time: rng.next_u64(),
                         }
                     } else {
-                        ConfirmationTime::Unconfirmed
+                        ConfirmationTime::Unconfirmed { last_seen: 0 }
                     },
                 }),
             });
@@ -803,7 +807,7 @@ mod test {
                 keychain: KeychainKind::External,
                 is_spent: false,
                 derivation_index: 42,
-                confirmation_time: ConfirmationTime::Unconfirmed,
+                confirmation_time: ConfirmationTime::Unconfirmed { last_seen: 0 },
             }),
         };
         vec![utxo; utxos_number]
@@ -1091,7 +1095,11 @@ mod test {
 
         let required = vec![utxos[0].clone()];
         let mut optional = utxos[1..].to_vec();
-        optional.push(utxo(500_000, 3, ConfirmationTime::Unconfirmed));
+        optional.push(utxo(
+            500_000,
+            3,
+            ConfirmationTime::Unconfirmed { last_seen: 0 },
+        ));
 
         // Defensive assertions, for sanity and in case someone changes the test utxos vector.
         let amount: u64 = required.iter().map(|u| u.utxo.txout().value).sum();
index 36b75ea2000da98a82c4ac775c45ef7879620a43..fe87fedd367f0465f12e68b561558af25fda7504 100644 (file)
@@ -247,7 +247,6 @@ mod test {
                     height: 5000,
                     time: 0,
                 },
-                None,
             )
             .unwrap();
         wallet
index 2d2a70f92938796c794969d849e3e11a3cfe5dfe..5fabc6d1422f2d306739e5ca393f4da47ade2a52 100644 (file)
@@ -504,9 +504,7 @@ impl<D> Wallet<D> {
     {
         let changeset = self.chain.insert_block(block_id)?;
         let changed = !changeset.is_empty();
-        if changed {
-            self.persist.stage(changeset.into());
-        }
+        self.persist.stage(changeset.into());
         Ok(changed)
     }
 
@@ -528,24 +526,13 @@ impl<D> Wallet<D> {
         &mut self,
         tx: Transaction,
         position: ConfirmationTime,
-        seen_at: Option<u64>,
     ) -> Result<bool, InsertTxError>
     where
         D: PersistBackend<ChangeSet>,
     {
         let tip = self.chain.tip();
 
-        if let ConfirmationTime::Confirmed { height, .. } = position {
-            let tip_height = tip.map(|b| b.height);
-            if Some(height) > tip_height {
-                return Err(InsertTxError::ConfirmationHeightCannotBeGreaterThanTip {
-                    tip_height,
-                    tx_height: height,
-                });
-            }
-        }
-
-        let anchor = match position {
+        let (anchor, last_seen) = match position {
             ConfirmationTime::Confirmed { height, time } => {
                 let tip_height = tip.map(|b| b.height);
                 if Some(height) > tip_height {
@@ -554,20 +541,21 @@ impl<D> Wallet<D> {
                         tx_height: height,
                     });
                 }
-                Some(ConfirmationTimeAnchor {
-                    anchor_block: tip.expect("already checked if tip_height > height"),
-                    confirmation_height: height,
-                    confirmation_time: time,
-                })
+                (
+                    Some(ConfirmationTimeAnchor {
+                        anchor_block: tip.expect("already checked if tip_height > height"),
+                        confirmation_height: height,
+                        confirmation_time: time,
+                    }),
+                    None,
+                )
             }
-            ConfirmationTime::Unconfirmed => None,
+            ConfirmationTime::Unconfirmed { last_seen } => (None, Some(last_seen)),
         };
 
-        let changeset: ChangeSet = self.indexed_graph.insert_tx(&tx, anchor, seen_at).into();
+        let changeset: ChangeSet = self.indexed_graph.insert_tx(&tx, anchor, last_seen).into();
         let changed = !changeset.is_empty();
-        if changed {
-            self.persist.stage(changeset);
-        }
+        self.persist.stage(changeset);
         Ok(changed)
     }
 
@@ -1032,7 +1020,7 @@ impl<D> Wallet<D> {
         let transaction_details = TransactionDetails {
             transaction: None,
             txid,
-            confirmation_time: ConfirmationTime::Unconfirmed,
+            confirmation_time: ConfirmationTime::Unconfirmed { last_seen: 0 },
             received,
             sent,
             fee: Some(fee_amount),
@@ -1541,7 +1529,7 @@ impl<D> Wallet<D> {
                                 spendable &=
                                     (current_height.saturating_sub(height)) >= COINBASE_MATURITY;
                             }
-                            ConfirmationTime::Unconfirmed => spendable = false,
+                            ConfirmationTime::Unconfirmed { .. } => spendable = false,
                         }
                     }
                 }
@@ -1771,9 +1759,7 @@ impl<D> Wallet<D> {
         changeset.append(self.indexed_graph.apply_update(update.graph).into());
 
         let changed = !changeset.is_empty();
-        if changed {
-            self.persist.stage(changeset);
-        }
+        self.persist.stage(changeset);
         Ok(changed)
     }
 
@@ -1797,16 +1783,18 @@ impl<D> Wallet<D> {
         self.persist.staged()
     }
 
-    /// Get a reference to the inner [`TxGraph`](bdk_chain::tx_graph::TxGraph).
-    pub fn as_graph(&self) -> &TxGraph<ConfirmationTimeAnchor> {
+    /// Get a reference to the inner [`TxGraph`].
+    pub fn tx_graph(&self) -> &TxGraph<ConfirmationTimeAnchor> {
         self.indexed_graph.graph()
     }
 
-    pub fn as_index(&self) -> &KeychainTxOutIndex<KeychainKind> {
+    /// Get a reference to the inner [`KeychainTxOutIndex`].
+    pub fn spk_index(&self) -> &KeychainTxOutIndex<KeychainKind> {
         &self.indexed_graph.index
     }
 
-    pub fn as_chain(&self) -> &LocalChain {
+    /// Get a reference to the inner [`LocalChain`].
+    pub fn local_chain(&self) -> &LocalChain {
         &self.chain
     }
 }
@@ -1949,7 +1937,7 @@ macro_rules! doctest_wallet {
         let _ = wallet.insert_tx(tx.clone(), ConfirmationTime::Confirmed {
             height: 500,
             time: 50_000
-        }, None);
+        });
 
         wallet
     }}
index 5d10626098e8d5f1571ad9f4c669af6fdb7b9174..165f01f25f1cbb53da1858d7d93a1ac2125958f3 100644 (file)
@@ -884,7 +884,7 @@ mod test {
                 txout: Default::default(),
                 keychain: KeychainKind::External,
                 is_spent: false,
-                confirmation_time: ConfirmationTime::Unconfirmed,
+                confirmation_time: ConfirmationTime::Unconfirmed { last_seen: 0 },
                 derivation_index: 0,
             },
             LocalUtxo {
index cbf74f249e68f90c8d595399e238ba19ba6fcdfd..de94670321465d8372dd3557cb1ad63f5e6981eb 100644 (file)
@@ -35,7 +35,6 @@ pub fn get_funded_wallet_with_change(
                 height: 1_000,
                 time: 100,
             },
-            None,
         )
         .unwrap();
 
index 6291df1d9e42be9bea3a7413354c9c21c983d2a5..c5bf8e1643d5c8ebd78352c73cb0b38416642686 100644 (file)
@@ -42,9 +42,8 @@ fn receive_output(wallet: &mut Wallet, value: u64, height: TxHeight) -> OutPoint
                     height,
                     time: 42_000,
                 },
-                TxHeight::Unconfirmed => ConfirmationTime::Unconfirmed,
+                TxHeight::Unconfirmed => ConfirmationTime::Unconfirmed { last_seen: 0 },
             },
-            None,
         )
         .unwrap();
 
@@ -812,7 +811,10 @@ fn test_create_tx_add_utxo() {
         lock_time: PackedLockTime(0),
     };
     wallet
-        .insert_tx(small_output_tx.clone(), ConfirmationTime::Unconfirmed, None)
+        .insert_tx(
+            small_output_tx.clone(),
+            ConfirmationTime::Unconfirmed { last_seen: 0 },
+        )
         .unwrap();
 
     let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
@@ -849,7 +851,10 @@ fn test_create_tx_manually_selected_insufficient() {
     };
 
     wallet
-        .insert_tx(small_output_tx.clone(), ConfirmationTime::Unconfirmed, None)
+        .insert_tx(
+            small_output_tx.clone(),
+            ConfirmationTime::Unconfirmed { last_seen: 0 },
+        )
         .unwrap();
 
     let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
@@ -891,7 +896,7 @@ fn test_create_tx_policy_path_no_csv() {
         }],
     };
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     let external_policy = wallet.policies(KeychainKind::External).unwrap().unwrap();
@@ -1218,7 +1223,7 @@ fn test_bump_fee_irreplaceable_tx() {
     let tx = psbt.extract_tx();
     let txid = tx.txid();
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
     wallet.build_fee_bump(txid).unwrap().finish().unwrap();
 }
@@ -1242,7 +1247,6 @@ fn test_bump_fee_confirmed_tx() {
                 height: 42,
                 time: 42_000,
             },
-            None,
         )
         .unwrap();
 
@@ -1264,7 +1268,7 @@ fn test_bump_fee_low_fee_rate() {
     let txid = tx.txid();
 
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     let mut builder = wallet.build_fee_bump(txid).unwrap();
@@ -1287,7 +1291,7 @@ fn test_bump_fee_low_abs() {
     let txid = tx.txid();
 
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     let mut builder = wallet.build_fee_bump(txid).unwrap();
@@ -1309,7 +1313,7 @@ fn test_bump_fee_zero_abs() {
     let tx = psbt.extract_tx();
     let txid = tx.txid();
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     let mut builder = wallet.build_fee_bump(txid).unwrap();
@@ -1329,7 +1333,7 @@ fn test_bump_fee_reduce_change() {
     let tx = psbt.extract_tx();
     let txid = tx.txid();
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     let mut builder = wallet.build_fee_bump(txid).unwrap();
@@ -1416,7 +1420,7 @@ fn test_bump_fee_reduce_single_recipient() {
     let tx = psbt.extract_tx();
     let txid = tx.txid();
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     let mut builder = wallet.build_fee_bump(txid).unwrap();
@@ -1449,7 +1453,7 @@ fn test_bump_fee_absolute_reduce_single_recipient() {
     let tx = psbt.extract_tx();
     let txid = tx.txid();
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     let mut builder = wallet.build_fee_bump(txid).unwrap();
@@ -1489,7 +1493,6 @@ fn test_bump_fee_drain_wallet() {
                 height: wallet.latest_checkpoint().unwrap().height,
                 time: 42_000,
             },
-            None,
         )
         .unwrap();
     let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
@@ -1508,7 +1511,7 @@ fn test_bump_fee_drain_wallet() {
     let tx = psbt.extract_tx();
     let txid = tx.txid();
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
     assert_eq!(original_details.sent, 25_000);
 
@@ -1553,7 +1556,6 @@ fn test_bump_fee_remove_output_manually_selected_only() {
                 .observed_as
                 .cloned()
                 .into(),
-            None,
         )
         .unwrap();
     let outpoint = OutPoint {
@@ -1572,7 +1574,7 @@ fn test_bump_fee_remove_output_manually_selected_only() {
     let tx = psbt.extract_tx();
     let txid = tx.txid();
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
     assert_eq!(original_details.sent, 25_000);
 
@@ -1602,7 +1604,7 @@ fn test_bump_fee_add_input() {
         .observed_as
         .cloned()
         .into();
-    wallet.insert_tx(init_tx, pos, None).unwrap();
+    wallet.insert_tx(init_tx, pos).unwrap();
 
     let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
     let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
@@ -1613,7 +1615,7 @@ fn test_bump_fee_add_input() {
     let tx = psbt.extract_tx();
     let txid = tx.txid();
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     let mut builder = wallet.build_fee_bump(txid).unwrap();
@@ -1659,7 +1661,7 @@ fn test_bump_fee_absolute_add_input() {
     let tx = psbt.extract_tx();
     let txid = tx.txid();
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     let mut builder = wallet.build_fee_bump(txid).unwrap();
@@ -1711,7 +1713,7 @@ fn test_bump_fee_no_change_add_input_and_change() {
     let tx = psbt.extract_tx();
     let txid = tx.txid();
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     // now bump the fees without using `allow_shrinking`. the wallet should add an
@@ -1769,7 +1771,7 @@ fn test_bump_fee_add_input_change_dust() {
     assert_eq!(tx.output.len(), 2);
     let txid = tx.txid();
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     let mut builder = wallet.build_fee_bump(txid).unwrap();
@@ -1830,7 +1832,7 @@ fn test_bump_fee_force_add_input() {
         txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature
     }
     wallet
-        .insert_tx(tx.clone(), ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx.clone(), ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
     // the new fee_rate is low enough that just reducing the change would be fine, but we force
     // the addition of an extra input with `add_utxo()`
@@ -1885,7 +1887,7 @@ fn test_bump_fee_absolute_force_add_input() {
         txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature
     }
     wallet
-        .insert_tx(tx.clone(), ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx.clone(), ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     // the new fee_rate is low enough that just reducing the change would be fine, but we force
@@ -1946,7 +1948,7 @@ fn test_bump_fee_unconfirmed_inputs_only() {
         txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature
     }
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
     let mut builder = wallet.build_fee_bump(txid).unwrap();
     builder.fee_rate(FeeRate::from_sat_per_vb(25.0));
@@ -1977,7 +1979,7 @@ fn test_bump_fee_unconfirmed_input() {
         txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature
     }
     wallet
-        .insert_tx(tx, ConfirmationTime::Unconfirmed, None)
+        .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
 
     let mut builder = wallet.build_fee_bump(txid).unwrap();
@@ -3072,7 +3074,6 @@ fn test_spend_coinbase() {
                 height: confirmation_height,
                 time: 30_000,
             },
-            None,
         )
         .unwrap();
 
index 9baa643e237211d54a06f1e659d00f5f9bd2db35..022e12993f64b5b7f9d0b23c3c9d31298705472d 100644 (file)
@@ -99,14 +99,14 @@ impl TxHeight {
 )]
 pub enum ConfirmationTime {
     Confirmed { height: u32, time: u64 },
-    Unconfirmed,
+    Unconfirmed { last_seen: u64 },
 }
 
 impl sparse_chain::ChainPosition for ConfirmationTime {
     fn height(&self) -> TxHeight {
         match self {
             ConfirmationTime::Confirmed { height, .. } => TxHeight::Confirmed(*height),
-            ConfirmationTime::Unconfirmed => TxHeight::Unconfirmed,
+            ConfirmationTime::Unconfirmed { .. } => TxHeight::Unconfirmed,
         }
     }
 
@@ -116,7 +116,7 @@ impl sparse_chain::ChainPosition for ConfirmationTime {
                 height,
                 time: u64::MAX,
             },
-            TxHeight::Unconfirmed => Self::Unconfirmed,
+            TxHeight::Unconfirmed => Self::Unconfirmed { last_seen: 0 },
         }
     }
 
@@ -126,7 +126,7 @@ impl sparse_chain::ChainPosition for ConfirmationTime {
                 height,
                 time: u64::MIN,
             },
-            TxHeight::Unconfirmed => Self::Unconfirmed,
+            TxHeight::Unconfirmed => Self::Unconfirmed { last_seen: 0 },
         }
     }
 }
@@ -144,7 +144,7 @@ impl From<ObservedAs<ConfirmationTimeAnchor>> for ConfirmationTime {
                 height: a.confirmation_height,
                 time: a.confirmation_time,
             },
-            ObservedAs::Unconfirmed(_) => Self::Unconfirmed,
+            ObservedAs::Unconfirmed(_) => Self::Unconfirmed { last_seen: 0 },
         }
     }
 }
index bd8c6e0313dfbd4f36e675163c97b90836a77677..fe725ea47b61fb550780a89d2fdf9eb3e0639353 100644 (file)
@@ -33,7 +33,7 @@ fn test_insert_tx() {
     let _ = tracker.txout_index.reveal_to_target(&(), 5);
 
     let changeset = tracker
-        .insert_tx_preview(tx.clone(), ConfirmationTime::Unconfirmed)
+        .insert_tx_preview(tx.clone(), ConfirmationTime::Unconfirmed { last_seen: 0 })
         .unwrap();
     tracker.apply_changeset(changeset);
     assert_eq!(
@@ -41,7 +41,7 @@ fn test_insert_tx() {
             .chain_graph()
             .transactions_in_chain()
             .collect::<Vec<_>>(),
-        vec![(&ConfirmationTime::Unconfirmed, &tx,)]
+        vec![(&ConfirmationTime::Unconfirmed { last_seen: 0 }, &tx,)]
     );
 
     assert_eq!(
index bddbd8f25286d9f6bd1b3fbf1cd7f14830e91946..6d352ca10eef11635780f8877cbfe59b890d7d55 100644 (file)
@@ -296,7 +296,7 @@ impl<K: Ord + Clone + Debug> ElectrumUpdate<K, TxHeight> {
                     height,
                     time: height_to_time[&height],
                 },
-                TxHeight::Unconfirmed => ConfirmationTime::Unconfirmed,
+                TxHeight::Unconfirmed => ConfirmationTime::Unconfirmed { last_seen: 0 },
             };
             let _ = new_update.insert_tx(txid, conf_time).expect("must insert");
         }
index 8398fcb354bf6015dee868edbb9073c7b2d48230..a6af0fadb62b8ed50f96572b0bd190a3fdcd6035 100644 (file)
@@ -22,6 +22,6 @@ pub(crate) fn map_confirmation_time(
         (Some(time), Some(height)) if height <= height_at_start => {
             ConfirmationTime::Confirmed { height, time }
         }
-        _ => ConfirmationTime::Unconfirmed,
+        _ => ConfirmationTime::Unconfirmed { last_seen: 0 },
     }
 }