Split get_tx into its own trait
to make supporting verify_tx easier
This commit is contained in:
parent
dcd90f8b61
commit
c0e75fc1a8
@ -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>(
|
||||
|
@ -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>(
|
||||
|
@ -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,
|
||||
|
@ -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>(
|
||||
|
@ -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,
|
||||
|
@ -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> {
|
||||
|
@ -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)?)
|
||||
|
@ -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);
|
||||
|
@ -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>(
|
||||
|
@ -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]
|
||||
|
Loading…
x
Reference in New Issue
Block a user