Skip to content

Commit 1ccfdf2

Browse files
committed
feat: add get_tx_outspends
1 parent e32fb11 commit 1ccfdf2

File tree

3 files changed

+47
-4
lines changed

3 files changed

+47
-4
lines changed

src/async.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ use reqwest::{header, Client, Response};
3030

3131
use crate::api::AddressStats;
3232
use crate::{
33-
BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputStatus, Tx, TxStatus, Utxo,
34-
BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES,
33+
BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputSpendStatus, OutputStatus, Tx,
34+
TxStatus, Utxo, BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES,
3535
};
3636

3737
#[derive(Debug, Clone)]
@@ -315,6 +315,12 @@ impl<S: Sleeper> AsyncClient<S> {
315315
self.get_opt_response_json(&format!("/tx/{txid}")).await
316316
}
317317

318+
/// Get the spend status of a [`Transaction`]'s outputs, given it's [`Txid`].
319+
pub async fn get_tx_outspends(&self, txid: &Txid) -> Result<Vec<OutputSpendStatus>, Error> {
320+
self.get_response_json(&format!("/tx/{txid}/outspends"))
321+
.await
322+
}
323+
318324
/// Get a [`BlockHeader`] given a particular block hash.
319325
pub async fn get_header_by_hash(&self, block_hash: &BlockHash) -> Result<BlockHeader, Error> {
320326
self.get_response_hex(&format!("/block/{block_hash}/header"))

src/blocking.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ use bitcoin::{
3131

3232
use crate::api::AddressStats;
3333
use crate::{
34-
BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputStatus, Tx, TxStatus, Utxo,
35-
BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES,
34+
BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputSpendStatus, OutputStatus, Tx,
35+
TxStatus, Utxo, BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES,
3636
};
3737

3838
#[derive(Debug, Clone)]
@@ -229,6 +229,11 @@ impl BlockingClient {
229229
self.get_opt_response_json(&format!("/tx/{txid}"))
230230
}
231231

232+
/// Get the spend status of a [`Transaction`]'s outputs, given it's [`Txid`].
233+
pub fn get_tx_outspends(&self, txid: &Txid) -> Result<Vec<OutputSpendStatus>, Error> {
234+
self.get_response_json(&format!("/tx/{txid}/outspends"))
235+
}
236+
232237
/// Get a [`BlockHeader`] given a particular block hash.
233238
pub fn get_header_by_hash(&self, block_hash: &BlockHash) -> Result<BlockHeader, Error> {
234239
self.get_response_hex(&format!("/block/{block_hash}/header"))

src/lib.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,4 +1065,36 @@ mod test {
10651065
assert_ne!(address_utxos_async.len(), 0);
10661066
assert_eq!(address_utxos_blocking, address_utxos_async);
10671067
}
1068+
1069+
#[cfg(all(feature = "blocking", feature = "async"))]
1070+
#[tokio::test]
1071+
async fn test_get_tx_outspends() {
1072+
let (blocking_client, async_client) = setup_clients().await;
1073+
1074+
let address = BITCOIND
1075+
.client
1076+
.new_address_with_type(AddressType::Legacy)
1077+
.unwrap();
1078+
1079+
let txid = BITCOIND
1080+
.client
1081+
.send_to_address(&address, Amount::from_sat(21000))
1082+
.unwrap()
1083+
.txid()
1084+
.unwrap();
1085+
1086+
let _miner = MINER.lock().await;
1087+
generate_blocks_and_wait(1);
1088+
1089+
let txid_outspends_blocking = blocking_client.get_tx_outspends(&txid).unwrap();
1090+
let txid_outspends_async = async_client.get_tx_outspends(&txid).await.unwrap();
1091+
1092+
// Assert that there are 2 outputs: 21K sat and (coinbase - 21K sat).
1093+
assert_eq!(txid_outspends_blocking.len(), 2);
1094+
assert_eq!(txid_outspends_async.len(), 2);
1095+
assert_eq!(txid_outspends_blocking, txid_outspends_async);
1096+
1097+
// Assert that both outputs are returned as unspent (spend == false).
1098+
assert!(txid_outspends_blocking.iter().all(|output| !output.spent));
1099+
}
10681100
}

0 commit comments

Comments
 (0)