]> Untitled Git - bdk/commitdiff
feat(core)!: Make `TxUpdate` non-exhaustive
author志宇 <hello@evanlinjin.me>
Fri, 24 Jan 2025 04:31:41 +0000 (15:31 +1100)
committer志宇 <hello@evanlinjin.me>
Fri, 28 Feb 2025 03:11:38 +0000 (14:11 +1100)
If we introduce new fields to `TxUpdate`, they can be minor
non-breaking updates.

crates/chain/benches/canonicalization.rs
crates/chain/src/tx_graph.rs
crates/chain/tests/test_tx_graph.rs
crates/core/src/tx_update.rs
crates/electrum/src/bdk_electrum_client.rs

index 3002a7ca309f7fc0fd8841de983a1a8ff51d9d77..52cbf51d68f8293cc4f5944d9bf726ebbf4469c6 100644 (file)
@@ -132,10 +132,8 @@ pub fn many_conflicting_unconfirmed(c: &mut Criterion) {
                 }],
                 ..new_tx(i)
             };
-            let update = TxUpdate {
-                txs: vec![Arc::new(tx)],
-                ..Default::default()
-            };
+            let mut update = TxUpdate::default();
+            update.txs = vec![Arc::new(tx)];
             let _ = tx_graph.apply_update_at(update, Some(i as u64));
         }
     }));
@@ -169,10 +167,8 @@ pub fn many_chained_unconfirmed(c: &mut Criterion) {
                 ..new_tx(i)
             };
             let txid = tx.compute_txid();
-            let update = TxUpdate {
-                txs: vec![Arc::new(tx)],
-                ..Default::default()
-            };
+            let mut update = TxUpdate::default();
+            update.txs = vec![Arc::new(tx)];
             let _ = tx_graph.apply_update_at(update, Some(i as u64));
             // Store the next prevout.
             previous_output = OutPoint::new(txid, 0);
index 2d512cfeaea5e197232b32c10e0e7312eb2b17d8..d0f7380a1db0a983335a5059d159731f1ade7c66 100644 (file)
@@ -110,19 +110,19 @@ use core::{
 
 impl<A: Ord> From<TxGraph<A>> for TxUpdate<A> {
     fn from(graph: TxGraph<A>) -> Self {
-        Self {
-            txs: graph.full_txs().map(|tx_node| tx_node.tx).collect(),
-            txouts: graph
-                .floating_txouts()
-                .map(|(op, txo)| (op, txo.clone()))
-                .collect(),
-            anchors: graph
-                .anchors
-                .into_iter()
-                .flat_map(|(txid, anchors)| anchors.into_iter().map(move |a| (a, txid)))
-                .collect(),
-            seen_ats: graph.last_seen.into_iter().collect(),
-        }
+        let mut tx_update = TxUpdate::default();
+        tx_update.txs = graph.full_txs().map(|tx_node| tx_node.tx).collect();
+        tx_update.txouts = graph
+            .floating_txouts()
+            .map(|(op, txo)| (op, txo.clone()))
+            .collect();
+        tx_update.anchors = graph
+            .anchors
+            .into_iter()
+            .flat_map(|(txid, anchors)| anchors.into_iter().map(move |a| (a, txid)))
+            .collect();
+        tx_update.seen_ats = graph.last_seen.into_iter().collect();
+        tx_update
     }
 }
 
index ef57ac15b65ed5fdc5d6af3eb541c391fb6abb0c..16d2e6c6d4bdcef21b967437e7d8c003d36dfb4c 100644 (file)
@@ -1231,69 +1231,60 @@ fn tx_graph_update_conversion() {
 
     let test_cases: &[TestCase] = &[
         ("empty_update", TxUpdate::default()),
-        (
-            "single_tx",
-            TxUpdate {
-                txs: vec![make_tx(0).into()],
-                ..Default::default()
-            },
-        ),
-        (
-            "two_txs",
-            TxUpdate {
-                txs: vec![make_tx(0).into(), make_tx(1).into()],
-                ..Default::default()
-            },
-        ),
-        (
-            "with_floating_txouts",
-            TxUpdate {
-                txs: vec![make_tx(0).into(), make_tx(1).into()],
-                txouts: [
-                    (OutPoint::new(hash!("a"), 0), make_txout(0)),
-                    (OutPoint::new(hash!("a"), 1), make_txout(1)),
-                    (OutPoint::new(hash!("b"), 0), make_txout(2)),
-                ]
-                .into(),
-                ..Default::default()
-            },
-        ),
-        (
-            "with_anchors",
-            TxUpdate {
-                txs: vec![make_tx(0).into(), make_tx(1).into()],
-                txouts: [
-                    (OutPoint::new(hash!("a"), 0), make_txout(0)),
-                    (OutPoint::new(hash!("a"), 1), make_txout(1)),
-                    (OutPoint::new(hash!("b"), 0), make_txout(2)),
-                ]
-                .into(),
-                anchors: [
-                    (ConfirmationBlockTime::default(), hash!("a")),
-                    (ConfirmationBlockTime::default(), hash!("b")),
-                ]
-                .into(),
-                ..Default::default()
-            },
-        ),
-        (
-            "with_seen_ats",
-            TxUpdate {
-                txs: vec![make_tx(0).into(), make_tx(1).into()],
-                txouts: [
-                    (OutPoint::new(hash!("a"), 0), make_txout(0)),
-                    (OutPoint::new(hash!("a"), 1), make_txout(1)),
-                    (OutPoint::new(hash!("d"), 0), make_txout(2)),
-                ]
-                .into(),
-                anchors: [
-                    (ConfirmationBlockTime::default(), hash!("a")),
-                    (ConfirmationBlockTime::default(), hash!("b")),
-                ]
-                .into(),
-                seen_ats: [(hash!("c"), 12346)].into_iter().collect(),
-            },
-        ),
+        ("single_tx", {
+            let mut tx_update = TxUpdate::default();
+            tx_update.txs = vec![make_tx(0).into()];
+            tx_update
+        }),
+        ("two_txs", {
+            let mut tx_update = TxUpdate::default();
+            tx_update.txs = vec![make_tx(0).into(), make_tx(1).into()];
+            tx_update
+        }),
+        ("with_floating_txouts", {
+            let mut tx_update = TxUpdate::default();
+            tx_update.txs = vec![make_tx(0).into(), make_tx(1).into()];
+            tx_update.txouts = [
+                (OutPoint::new(hash!("a"), 0), make_txout(0)),
+                (OutPoint::new(hash!("a"), 1), make_txout(1)),
+                (OutPoint::new(hash!("b"), 0), make_txout(2)),
+            ]
+            .into();
+            tx_update
+        }),
+        ("with_anchors", {
+            let mut tx_update = TxUpdate::default();
+            tx_update.txs = vec![make_tx(0).into(), make_tx(1).into()];
+            tx_update.txouts = [
+                (OutPoint::new(hash!("a"), 0), make_txout(0)),
+                (OutPoint::new(hash!("a"), 1), make_txout(1)),
+                (OutPoint::new(hash!("b"), 0), make_txout(2)),
+            ]
+            .into();
+            tx_update.anchors = [
+                (ConfirmationBlockTime::default(), hash!("a")),
+                (ConfirmationBlockTime::default(), hash!("b")),
+            ]
+            .into();
+            tx_update
+        }),
+        ("with_seen_ats", {
+            let mut tx_update = TxUpdate::default();
+            tx_update.txs = vec![make_tx(0).into(), make_tx(1).into()];
+            tx_update.txouts = [
+                (OutPoint::new(hash!("a"), 0), make_txout(0)),
+                (OutPoint::new(hash!("a"), 1), make_txout(1)),
+                (OutPoint::new(hash!("d"), 0), make_txout(2)),
+            ]
+            .into();
+            tx_update.anchors = [
+                (ConfirmationBlockTime::default(), hash!("a")),
+                (ConfirmationBlockTime::default(), hash!("b")),
+            ]
+            .into();
+            tx_update.seen_ats = [(hash!("c"), 12346)].into_iter().collect();
+            tx_update
+        }),
     ];
 
     for (test_name, update) in test_cases {
index 7707578eea6e93905fe79c202dc5addf7f736a52..5da2bff8770acb0ac13c83909fe7df7c5698bc64 100644 (file)
@@ -4,7 +4,22 @@ use bitcoin::{OutPoint, Transaction, TxOut, Txid};
 
 /// Data object used to communicate updates about relevant transactions from some chain data source
 /// to the core model (usually a `bdk_chain::TxGraph`).
+///
+/// ```rust
+/// use bdk_core::TxUpdate;
+/// # use std::sync::Arc;
+/// # use bitcoin::{Transaction, transaction::Version, absolute::LockTime};
+/// # let version = Version::ONE;
+/// # let lock_time = LockTime::ZERO;
+/// # let tx = Arc::new(Transaction { input: vec![], output: vec![], version, lock_time });
+/// # let txid = tx.compute_txid();
+/// # let anchor = ();
+/// let mut tx_update = TxUpdate::default();
+/// tx_update.txs.push(tx);
+/// tx_update.anchors.insert((anchor, txid));
+/// ```
 #[derive(Debug, Clone)]
+#[non_exhaustive]
 pub struct TxUpdate<A = ()> {
     /// Full transactions. These are transactions that were determined to be relevant to the wallet
     /// given the request.
index 621a69e11ae9297c6fd5b9443971c296cc906072..e187bf3667ce65f463d78158aea82cef18aa47e0 100644 (file)
@@ -571,10 +571,8 @@ mod test {
         // `fetch_prev_txout` on a coinbase transaction will trigger a `fetch_tx` on a transaction
         // with a txid of all zeros. If `fetch_prev_txout` attempts to fetch this transaction, this
         // assertion will fail.
-        let mut tx_update = TxUpdate {
-            txs: vec![Arc::new(coinbase_tx)],
-            ..Default::default()
-        };
+        let mut tx_update = TxUpdate::default();
+        tx_update.txs = vec![Arc::new(coinbase_tx)];
         assert!(client.fetch_prev_txout(&mut tx_update).is_ok());
 
         // Ensure that the txouts are empty.