Skip to content

Commit

Permalink
feat(btcio): refactor and Clone (#659)
Browse files Browse the repository at this point in the history
* fix!(btcio): move submit_package to BroadcastRpc from ReaderRpc

* feat(btcio): make BitcoinClient Clone
  • Loading branch information
storopoli authored Feb 11, 2025
1 parent ab6cc42 commit a11c914
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 41 deletions.
27 changes: 17 additions & 10 deletions crates/btcio/src/rpc/client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::{
env::var,
fmt,
sync::atomic::{AtomicUsize, Ordering},
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
time::Duration,
};

Expand Down Expand Up @@ -54,14 +57,18 @@ where
}

/// An `async` client for interacting with a `bitcoind` instance.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct BitcoinClient {
/// The URL of the `bitcoind` instance.
url: String,
/// The underlying `async` HTTP client.
client: Client,
/// The ID of the current request.
id: AtomicUsize,
///
/// # Implementation Details
///
/// Using an [`Arc`] so that [`BitcoinClient`] is [`Clone`].
id: Arc<AtomicUsize>,
/// The maximum number of retries for a request.
max_retries: u8,
/// Interval between retries for a request in ms.
Expand Down Expand Up @@ -107,7 +114,7 @@ impl BitcoinClient {
.build()
.map_err(|e| ClientError::Other(format!("Could not create client: {e}")))?;

let id = AtomicUsize::new(0);
let id = Arc::new(AtomicUsize::new(0));

let max_retries = max_retries.unwrap_or(DEFAULT_MAX_RETRIES);
let retry_interval = retry_interval.unwrap_or(DEFAULT_RETRY_INTERVAL_MS);
Expand Down Expand Up @@ -301,12 +308,6 @@ impl ReaderRpc for BitcoinClient {
.await
}

async fn submit_package(&self, txs: &[Transaction]) -> ClientResult<SubmitPackage> {
let txstrs: Vec<String> = txs.iter().map(serialize_hex).collect();
self.call::<SubmitPackage>("submitpackage", &[to_value(txstrs)?])
.await
}

async fn network(&self) -> ClientResult<Network> {
Ok(self
.call::<GetBlockchainInfo>("getblockchaininfo", &[])
Expand Down Expand Up @@ -345,6 +346,12 @@ impl BroadcasterRpc for BitcoinClient {
self.call::<Vec<TestMempoolAccept>>("testmempoolaccept", &[to_value([txstr])?])
.await
}

async fn submit_package(&self, txs: &[Transaction]) -> ClientResult<SubmitPackage> {
let txstrs: Vec<String> = txs.iter().map(serialize_hex).collect();
self.call::<SubmitPackage>("submitpackage", &[to_value(txstrs)?])
.await
}
}

#[async_trait]
Expand Down
24 changes: 12 additions & 12 deletions crates/btcio/src/rpc/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,6 @@ pub trait ReaderRpc {
include_mempool: bool,
) -> ClientResult<GetTxOut>;

/// Submit a package of raw transactions (serialized, hex-encoded) to local node.
///
/// The package will be validated according to consensus and mempool policy rules. If any
/// transaction passes, it will be accepted to mempool. This RPC is experimental and the
/// interface may be unstable. Refer to doc/policy/packages.md for documentation on package
/// policies.
///
/// # Warning
///
/// Successful submission does not mean the transactions will propagate throughout the network.
async fn submit_package(&self, txs: &[Transaction]) -> ClientResult<SubmitPackage>;

/// Gets the underlying [`Network`] information.
async fn network(&self) -> ClientResult<Network>;
}
Expand Down Expand Up @@ -119,6 +107,18 @@ pub trait BroadcasterRpc {

/// Tests if a raw transaction is valid.
async fn test_mempool_accept(&self, tx: &Transaction) -> ClientResult<Vec<TestMempoolAccept>>;

/// Submit a package of raw transactions (serialized, hex-encoded) to local node.
///
/// The package will be validated according to consensus and mempool policy rules. If any
/// transaction passes, it will be accepted to mempool. This RPC is experimental and the
/// interface may be unstable. Refer to doc/policy/packages.md for documentation on package
/// policies.
///
/// # Warning
///
/// Successful submission does not mean the transactions will propagate throughout the network.
async fn submit_package(&self, txs: &[Transaction]) -> ClientResult<SubmitPackage>;
}

/// Wallet functionality that any Bitcoin client **without private keys** that
Expand Down
38 changes: 19 additions & 19 deletions crates/btcio/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,25 @@ impl ReaderRpc for TestBitcoinClient {
})
}

async fn network(&self) -> ClientResult<Network> {
Ok(Network::Regtest)
}
}

#[async_trait]
impl BroadcasterRpc for TestBitcoinClient {
// send_raw_transaction sends a raw transaction to the network
async fn send_raw_transaction(&self, _tx: &Transaction) -> ClientResult<Txid> {
Ok(Txid::from_slice(&[1u8; 32]).unwrap())
}
async fn test_mempool_accept(&self, _tx: &Transaction) -> ClientResult<Vec<TestMempoolAccept>> {
let some_tx: Transaction = consensus::encode::deserialize_hex(SOME_TX).unwrap();
Ok(vec![TestMempoolAccept {
txid: some_tx.compute_txid(),
reject_reason: None,
}])
}

async fn submit_package(&self, _txs: &[Transaction]) -> ClientResult<SubmitPackage> {
let some_tx: Transaction = consensus::encode::deserialize_hex(SOME_TX).unwrap();
let wtxid = some_tx.compute_wtxid();
Expand All @@ -160,25 +179,6 @@ impl ReaderRpc for TestBitcoinClient {
replaced_transactions: vec![],
})
}

async fn network(&self) -> ClientResult<Network> {
Ok(Network::Regtest)
}
}

#[async_trait]
impl BroadcasterRpc for TestBitcoinClient {
// send_raw_transaction sends a raw transaction to the network
async fn send_raw_transaction(&self, _tx: &Transaction) -> ClientResult<Txid> {
Ok(Txid::from_slice(&[1u8; 32]).unwrap())
}
async fn test_mempool_accept(&self, _tx: &Transaction) -> ClientResult<Vec<TestMempoolAccept>> {
let some_tx: Transaction = consensus::encode::deserialize_hex(SOME_TX).unwrap();
Ok(vec![TestMempoolAccept {
txid: some_tx.compute_txid(),
reject_reason: None,
}])
}
}

#[async_trait]
Expand Down

0 comments on commit a11c914

Please sign in to comment.