]> Untitled Git - bdk/commitdiff
Split get_tx into its own trait
authorLLFourn <lloyd.fourn@gmail.com>
Tue, 22 Feb 2022 23:38:35 +0000 (10:38 +1100)
committerLLFourn <lloyd.fourn@gmail.com>
Thu, 24 Feb 2022 09:39:00 +0000 (20:39 +1100)
to make supporting verify_tx easier

src/blockchain/any.rs
src/blockchain/compact_filters/mod.rs
src/blockchain/electrum.rs
src/blockchain/esplora/reqwest.rs
src/blockchain/esplora/ureq.rs
src/blockchain/mod.rs
src/blockchain/rpc.rs
src/testutils/blockchain_tests.rs
src/wallet/mod.rs
src/wallet/verify.rs

index ef4abffacb1c3e948b1c0d48a9f8249e3ba0a8a0..079524ae3ca2529804aa5814803aea2deafaa6fb 100644 (file)
@@ -89,9 +89,6 @@ impl Blockchain for AnyBlockchain {
         maybe_await!(impl_inner_method!(self, get_capabilities))
     }
 
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        maybe_await!(impl_inner_method!(self, get_tx, txid))
-    }
     fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
         maybe_await!(impl_inner_method!(self, broadcast, tx))
     }
@@ -108,6 +105,13 @@ impl GetHeight for AnyBlockchain {
     }
 }
 
+#[maybe_async]
+impl GetTx for AnyBlockchain {
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        maybe_await!(impl_inner_method!(self, get_tx, txid))
+    }
+}
+
 #[maybe_async]
 impl WalletSync for AnyBlockchain {
     fn wallet_sync<D: BatchDatabase>(
index d0b96421ab2e78eb509848f550e33c4e8a749046..e7e235b5b95ea047e11ed8eb917fe2b685052864 100644 (file)
@@ -67,7 +67,7 @@ mod peer;
 mod store;
 mod sync;
 
-use super::{Blockchain, Capability, ConfigurableBlockchain, GetHeight, Progress, WalletSync};
+use crate::blockchain::*;
 use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
 use crate::error::Error;
 use crate::types::{KeychainKind, LocalUtxo, TransactionDetails};
@@ -225,12 +225,6 @@ impl Blockchain for CompactFiltersBlockchain {
         vec![Capability::FullHistory].into_iter().collect()
     }
 
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        Ok(self.peers[0]
-            .get_mempool()
-            .get_tx(&Inventory::Transaction(*txid)))
-    }
-
     fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
         self.peers[0].broadcast_tx(tx.clone())?;
 
@@ -249,6 +243,14 @@ impl GetHeight for CompactFiltersBlockchain {
     }
 }
 
+impl GetTx for CompactFiltersBlockchain {
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(self.peers[0]
+            .get_mempool()
+            .get_tx(&Inventory::Transaction(*txid)))
+    }
+}
+
 impl WalletSync for CompactFiltersBlockchain {
     #[allow(clippy::mutex_atomic)] // Mutex is easier to understand than a CAS loop.
     fn wallet_setup<D: BatchDatabase>(
index b10b90d508cbad4643db7996a4aafde322004f2c..0b8691bc1fb2f95c39cdc59172c190b47602c4ec 100644 (file)
@@ -68,10 +68,6 @@ impl Blockchain for ElectrumBlockchain {
         .collect()
     }
 
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        Ok(self.client.transaction_get(txid).map(Option::Some)?)
-    }
-
     fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
         Ok(self.client.transaction_broadcast(tx).map(|_| ())?)
     }
@@ -94,6 +90,12 @@ impl GetHeight for ElectrumBlockchain {
     }
 }
 
+impl GetTx for ElectrumBlockchain {
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(self.client.transaction_get(txid).map(Option::Some)?)
+    }
+}
+
 impl WalletSync for ElectrumBlockchain {
     fn wallet_setup<D: BatchDatabase>(
         &self,
index 0a9ed4dd397f5e6d8033fb28f136a558667e463f..2141b8e678d1118463264b6930feeecd2f41076c 100644 (file)
@@ -91,10 +91,6 @@ impl Blockchain for EsploraBlockchain {
         .collect()
     }
 
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        Ok(await_or_block!(self.url_client._get_tx(txid))?)
-    }
-
     fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
         Ok(await_or_block!(self.url_client._broadcast(tx))?)
     }
@@ -112,6 +108,13 @@ impl GetHeight for EsploraBlockchain {
     }
 }
 
+#[maybe_async]
+impl GetTx for EsploraBlockchain {
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(await_or_block!(self.url_client._get_tx(txid))?)
+    }
+}
+
 #[maybe_async]
 impl WalletSync for EsploraBlockchain {
     fn wallet_setup<D: BatchDatabase>(
index 3e240f43fd75efe5173eb0722c538f29367ed9b3..9bfa378fc445afe6c009e28040b5ea99a9b8ceb5 100644 (file)
@@ -87,10 +87,6 @@ impl Blockchain for EsploraBlockchain {
         .collect()
     }
 
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        Ok(self.url_client._get_tx(txid)?)
-    }
-
     fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
         let _txid = self.url_client._broadcast(tx)?;
         Ok(())
@@ -108,6 +104,12 @@ impl GetHeight for EsploraBlockchain {
     }
 }
 
+impl GetTx for EsploraBlockchain {
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(self.url_client._get_tx(txid)?)
+    }
+}
+
 impl WalletSync for EsploraBlockchain {
     fn wallet_setup<D: BatchDatabase>(
         &self,
index 5962fca253d5c218bdb594b93145d53710c2ca6d..714fdf6a95bf000dca46bee718cf0d82f86640e0 100644 (file)
@@ -86,11 +86,9 @@ pub enum Capability {
 
 /// Trait that defines the actions that must be supported by a blockchain backend
 #[maybe_async]
-pub trait Blockchain: WalletSync + GetHeight {
+pub trait Blockchain: WalletSync + GetHeight + GetTx {
     /// Return the set of [`Capability`] supported by this backend
     fn get_capabilities(&self) -> HashSet<Capability>;
-    /// Fetch a transaction from the blockchain given its txid
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error>;
     /// Broadcast a transaction
     fn broadcast(&self, tx: &Transaction) -> Result<(), Error>;
     /// Estimate the fee rate required to confirm a transaction in a given `target` of blocks
@@ -104,6 +102,13 @@ pub trait GetHeight {
     fn get_height(&self) -> Result<u32, Error>;
 }
 
+#[maybe_async]
+/// Trait for getting a transaction by txid
+pub trait GetTx {
+    /// Fetch a transaction given its txid
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error>;
+}
+
 /// Trait for blockchains that can sync by updating the database directly.
 #[maybe_async]
 pub trait WalletSync {
@@ -230,9 +235,6 @@ impl<T: Blockchain> Blockchain for Arc<T> {
         maybe_await!(self.deref().get_capabilities())
     }
 
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        maybe_await!(self.deref().get_tx(txid))
-    }
     fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
         maybe_await!(self.deref().broadcast(tx))
     }
@@ -242,6 +244,13 @@ impl<T: Blockchain> Blockchain for Arc<T> {
     }
 }
 
+#[maybe_async]
+impl<T: GetTx> GetTx for Arc<T> {
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        maybe_await!(self.deref().get_tx(txid))
+    }
+}
+
 #[maybe_async]
 impl<T: GetHeight> GetHeight for Arc<T> {
     fn get_height(&self) -> Result<u32, Error> {
index b96af9937826ec36420fb0a52af2170e792dc8b7..a474a0e2855113b9f5ae11fc01aeade05d3b8261 100644 (file)
@@ -33,9 +33,7 @@
 
 use crate::bitcoin::consensus::deserialize;
 use crate::bitcoin::{Address, Network, OutPoint, Transaction, TxOut, Txid};
-use crate::blockchain::{
-    Blockchain, Capability, ConfigurableBlockchain, GetHeight, Progress, WalletSync,
-};
+use crate::blockchain::*;
 use crate::database::{BatchDatabase, DatabaseUtils};
 use crate::{BlockTime, Error, FeeRate, KeychainKind, LocalUtxo, TransactionDetails};
 use bitcoincore_rpc::json::{
@@ -141,10 +139,6 @@ impl Blockchain for RpcBlockchain {
         self.capabilities.clone()
     }
 
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        Ok(Some(self.client.get_raw_transaction(txid, None)?))
-    }
-
     fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
         Ok(self.client.send_raw_transaction(tx).map(|_| ())?)
     }
@@ -161,6 +155,12 @@ impl Blockchain for RpcBlockchain {
     }
 }
 
+impl GetTx for RpcBlockchain {
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(Some(self.client.get_raw_transaction(txid, None)?))
+    }
+}
+
 impl GetHeight for RpcBlockchain {
     fn get_height(&self) -> Result<u32, Error> {
         Ok(self.client.get_blockchain_info().map(|i| i.blocks as u32)?)
index 68858a84108e56c32a7045ab72c2ca2fe37bfd25..eefdd75bd60d7984623088468133b1583b6a9dd0 100644 (file)
@@ -1097,7 +1097,7 @@ macro_rules! bdk_blockchain_tests {
                 // 2.
                 // Core (#2) -> Us   (#4)
 
-                let (wallet, _, mut test_client) = init_single_sig();
+                let (wallet, blockchain, _, mut test_client) = init_single_sig();
                 let bdk_address = wallet.get_address(AddressIndex::New).unwrap().address;
                 let core_address = test_client.get_new_address(None, None).unwrap();
                 let tx = testutils! {
@@ -1108,7 +1108,7 @@ macro_rules! bdk_blockchain_tests {
                 let txid_1 = test_client.receive(tx);
                 let tx_1: Transaction = deserialize(&test_client.get_transaction(&txid_1, None).unwrap().hex).unwrap();
                 let vout_1 = tx_1.output.into_iter().position(|o| o.script_pubkey == core_address.script_pubkey()).unwrap() as u32;
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, SyncOptions::default()).unwrap();
                 let tx_1 = wallet.list_transactions(false).unwrap().into_iter().find(|tx| tx.txid == txid_1).unwrap();
                 assert_eq!(tx_1.received, 50_000);
                 assert_eq!(tx_1.sent, 0);
@@ -1119,7 +1119,7 @@ macro_rules! bdk_blockchain_tests {
                 };
                 let txid_2 = test_client.receive(tx);
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, SyncOptions::default()).unwrap();
                 let tx_2 = wallet.list_transactions(false).unwrap().into_iter().find(|tx| tx.txid == txid_2).unwrap();
                 assert_eq!(tx_2.received, 10_000);
                 assert_eq!(tx_2.sent, 0);
index b37a108c671381d1e3e637ede6570d5268a8e8a3..d0f8634484fa4bc72f86af255edb501a3c8dfe9c 100644 (file)
@@ -171,7 +171,6 @@ impl<D> Wallet<D>
 where
     D: BatchDatabase,
 {
-
     #[deprecated = "Just use Wallet::new -- all wallets are offline now!"]
     /// Create a new "offline" wallet
     pub fn new_offline<E: IntoWalletDescriptor>(
index 9b56333986fb9f869e98ff82d0be9b4e90106f73..0f12e05609d05260cfddf51354f3db1cea049e7d 100644 (file)
@@ -17,7 +17,7 @@ use std::fmt;
 use bitcoin::consensus::serialize;
 use bitcoin::{OutPoint, Transaction, Txid};
 
-use crate::blockchain::Blockchain;
+use crate::blockchain::GetTx;
 use crate::database::Database;
 use crate::error::Error;
 
@@ -29,7 +29,7 @@ use crate::error::Error;
 /// Depending on the [capabilities](crate::blockchain::Blockchain::get_capabilities) of the
 /// [`Blockchain`] backend, the method could fail when called with old "historical" transactions or
 /// with unconfirmed transactions that have been evicted from the backend's memory.
-pub fn verify_tx<D: Database, B: Blockchain>(
+pub fn verify_tx<D: Database, B: GetTx>(
     tx: &Transaction,
     database: &D,
     blockchain: &B,
@@ -104,43 +104,18 @@ impl_error!(bitcoinconsensus::Error, Consensus, VerifyError);
 
 #[cfg(test)]
 mod test {
-    use std::collections::HashSet;
-
+    use super::*;
+    use crate::database::{BatchOperations, MemoryDatabase};
     use bitcoin::consensus::encode::deserialize;
     use bitcoin::hashes::hex::FromHex;
     use bitcoin::{Transaction, Txid};
 
-    use crate::blockchain::{Blockchain, Capability, Progress};
-    use crate::database::{BatchDatabase, BatchOperations, MemoryDatabase};
-    use crate::FeeRate;
-
-    use super::*;
-
     struct DummyBlockchain;
 
-    impl Blockchain for DummyBlockchain {
-        fn get_capabilities(&self) -> HashSet<Capability> {
-            Default::default()
-        }
-        fn setup<D: BatchDatabase, P: 'static + Progress>(
-            &self,
-            _database: &mut D,
-            _progress_update: P,
-        ) -> Result<(), Error> {
-            Ok(())
-        }
+    impl GetTx for DummyBlockchain {
         fn get_tx(&self, _txid: &Txid) -> Result<Option<Transaction>, Error> {
             Ok(None)
         }
-        fn broadcast(&self, _tx: &Transaction) -> Result<(), Error> {
-            Ok(())
-        }
-        fn get_height(&self) -> Result<u32, Error> {
-            Ok(42)
-        }
-        fn estimate_fee(&self, _target: usize) -> Result<FeeRate, Error> {
-            Ok(FeeRate::default_min_relay_fee())
-        }
     }
 
     #[test]