Skip to content

Commit d8d2a25

Browse files
committed
feat(client): add get_scripthash_stats
1 parent b22e3f7 commit d8d2a25

File tree

3 files changed

+158
-14
lines changed

3 files changed

+158
-14
lines changed

src/async.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,20 @@ use std::collections::HashMap;
1515
use std::marker::PhantomData;
1616
use std::str::FromStr;
1717

18+
use bitcoin::block::Header as BlockHeader;
1819
use bitcoin::consensus::{deserialize, serialize, Decodable, Encodable};
1920
use bitcoin::hashes::{sha256, Hash};
2021
use bitcoin::hex::{DisplayHex, FromHex};
21-
use bitcoin::Address;
22-
use bitcoin::{
23-
block::Header as BlockHeader, Block, BlockHash, MerkleBlock, Script, Transaction, Txid,
24-
};
22+
use bitcoin::{Address, Block, BlockHash, MerkleBlock, Script, Transaction, Txid};
2523

2624
#[allow(unused_imports)]
2725
use log::{debug, error, info, trace};
2826

2927
use reqwest::{header, Client, Response};
3028

31-
use crate::api::AddressStats;
3229
use crate::{
33-
BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputSpendStatus, OutputStatus, Tx,
34-
TxStatus, Utxo, BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES,
30+
AddressStats, BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputSpendStatus,
31+
OutputStatus, ScriptHashStats, Tx, TxStatus, Utxo, BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES,
3532
};
3633

3734
#[derive(Debug, Clone)]
@@ -397,6 +394,13 @@ impl<S: Sleeper> AsyncClient<S> {
397394
self.get_response_json(&path).await
398395
}
399396

397+
/// Get statistics about a particular [`Script`] hash's confirmed and mempool transactions.
398+
pub async fn get_scripthash_stats(&self, script: &Script) -> Result<ScriptHashStats, Error> {
399+
let script_hash = sha256::Hash::hash(script.as_bytes());
400+
let path = format!("/scripthash/{script_hash}");
401+
self.get_response_json(&path).await
402+
}
403+
400404
/// Get transaction history for the specified address/scripthash, sorted with newest first.
401405
///
402406
/// Returns up to 50 mempool transactions plus the first 25 confirmed transactions.

src/blocking.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,15 @@ use log::{debug, error, info, trace};
2121

2222
use minreq::{Proxy, Request, Response};
2323

24+
use bitcoin::block::Header as BlockHeader;
2425
use bitcoin::consensus::{deserialize, serialize, Decodable};
2526
use bitcoin::hashes::{sha256, Hash};
2627
use bitcoin::hex::{DisplayHex, FromHex};
27-
use bitcoin::Address;
28-
use bitcoin::{
29-
block::Header as BlockHeader, Block, BlockHash, MerkleBlock, Script, Transaction, Txid,
30-
};
28+
use bitcoin::{Address, Block, BlockHash, MerkleBlock, Script, Transaction, Txid};
3129

32-
use crate::api::AddressStats;
3330
use crate::{
34-
BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputSpendStatus, OutputStatus, Tx,
35-
TxStatus, Utxo, BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES,
31+
AddressStats, BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputSpendStatus,
32+
OutputStatus, ScriptHashStats, Tx, TxStatus, Utxo, BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES,
3633
};
3734

3835
#[derive(Debug, Clone)]
@@ -331,6 +328,13 @@ impl BlockingClient {
331328
self.get_response_json(&path)
332329
}
333330

331+
/// Get statistics about a particular [`Script`] hash's confirmed and mempool transactions.
332+
pub fn get_scripthash_stats(&self, script: &Script) -> Result<ScriptHashStats, Error> {
333+
let script_hash = sha256::Hash::hash(script.as_bytes());
334+
let path = format!("/scripthash/{script_hash}");
335+
self.get_response_json(&path)
336+
}
337+
334338
/// Get transaction history for the specified address/scripthash, sorted with newest first.
335339
///
336340
/// Returns up to 50 mempool transactions plus the first 25 confirmed transactions.

src/lib.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,142 @@ mod test {
10131013
assert_eq!(address_stats_async.chain_stats.funded_txo_sum, 1000);
10141014
}
10151015

1016+
#[cfg(all(feature = "blocking", feature = "async"))]
1017+
#[tokio::test]
1018+
async fn test_get_scripthash_stats() {
1019+
let (blocking_client, async_client) = setup_clients().await;
1020+
1021+
// Create an address of each type.
1022+
let address_legacy = BITCOIND
1023+
.client
1024+
.new_address_with_type(AddressType::Legacy)
1025+
.unwrap();
1026+
let address_p2sh_segwit = BITCOIND
1027+
.client
1028+
.new_address_with_type(AddressType::P2shSegwit)
1029+
.unwrap();
1030+
let address_bech32 = BITCOIND
1031+
.client
1032+
.new_address_with_type(AddressType::Bech32)
1033+
.unwrap();
1034+
let address_bech32m = BITCOIND
1035+
.client
1036+
.new_address_with_type(AddressType::Bech32m)
1037+
.unwrap();
1038+
1039+
// Send a transaction to each address.
1040+
let _txid = BITCOIND
1041+
.client
1042+
.send_to_address(&address_legacy, Amount::from_sat(1000))
1043+
.unwrap()
1044+
.txid()
1045+
.unwrap();
1046+
let _txid = BITCOIND
1047+
.client
1048+
.send_to_address(&address_p2sh_segwit, Amount::from_sat(1000))
1049+
.unwrap()
1050+
.txid()
1051+
.unwrap();
1052+
let _txid = BITCOIND
1053+
.client
1054+
.send_to_address(&address_bech32, Amount::from_sat(1000))
1055+
.unwrap()
1056+
.txid()
1057+
.unwrap();
1058+
let _txid = BITCOIND
1059+
.client
1060+
.send_to_address(&address_bech32m, Amount::from_sat(1000))
1061+
.unwrap()
1062+
.txid()
1063+
.unwrap();
1064+
1065+
let _miner = MINER.lock().await;
1066+
generate_blocks_and_wait(1);
1067+
1068+
// Derive each addresses script.
1069+
let script_legacy = address_legacy.script_pubkey();
1070+
let script_p2sh_segwit = address_p2sh_segwit.script_pubkey();
1071+
let script_bech32 = address_bech32.script_pubkey();
1072+
let script_bech32m = address_bech32m.script_pubkey();
1073+
1074+
// P2PKH
1075+
let scripthash_stats_blocking_legacy = blocking_client
1076+
.get_scripthash_stats(&script_legacy)
1077+
.unwrap();
1078+
let scripthash_stats_async_legacy = async_client
1079+
.get_scripthash_stats(&script_legacy)
1080+
.await
1081+
.unwrap();
1082+
assert_eq!(
1083+
scripthash_stats_blocking_legacy,
1084+
scripthash_stats_async_legacy
1085+
);
1086+
assert_eq!(
1087+
scripthash_stats_blocking_legacy.chain_stats.funded_txo_sum,
1088+
1000
1089+
);
1090+
assert_eq!(scripthash_stats_blocking_legacy.chain_stats.tx_count, 1);
1091+
1092+
// P2SH-P2WSH
1093+
let scripthash_stats_blocking_p2sh_segwit = blocking_client
1094+
.get_scripthash_stats(&script_p2sh_segwit)
1095+
.unwrap();
1096+
let scripthash_stats_async_p2sh_segwit = async_client
1097+
.get_scripthash_stats(&script_p2sh_segwit)
1098+
.await
1099+
.unwrap();
1100+
assert_eq!(
1101+
scripthash_stats_blocking_p2sh_segwit,
1102+
scripthash_stats_async_p2sh_segwit
1103+
);
1104+
assert_eq!(
1105+
scripthash_stats_blocking_p2sh_segwit
1106+
.chain_stats
1107+
.funded_txo_sum,
1108+
1000
1109+
);
1110+
assert_eq!(
1111+
scripthash_stats_blocking_p2sh_segwit.chain_stats.tx_count,
1112+
1
1113+
);
1114+
1115+
// P2WPKH / P2WSH
1116+
let scripthash_stats_blocking_bech32 = blocking_client
1117+
.get_scripthash_stats(&script_bech32)
1118+
.unwrap();
1119+
let scripthash_stats_async_bech32 = async_client
1120+
.get_scripthash_stats(&script_bech32)
1121+
.await
1122+
.unwrap();
1123+
assert_eq!(
1124+
scripthash_stats_blocking_bech32,
1125+
scripthash_stats_async_bech32
1126+
);
1127+
assert_eq!(
1128+
scripthash_stats_blocking_bech32.chain_stats.funded_txo_sum,
1129+
1000
1130+
);
1131+
assert_eq!(scripthash_stats_blocking_bech32.chain_stats.tx_count, 1);
1132+
1133+
// P2TR
1134+
let scripthash_stats_blocking_bech32m = blocking_client
1135+
.get_scripthash_stats(&script_bech32m)
1136+
.unwrap();
1137+
let scripthash_stats_async_bech32m = async_client
1138+
.get_scripthash_stats(&script_bech32m)
1139+
.await
1140+
.unwrap();
1141+
assert_eq!(
1142+
scripthash_stats_blocking_bech32m,
1143+
scripthash_stats_async_bech32m
1144+
);
1145+
assert_eq!(
1146+
scripthash_stats_blocking_bech32m.chain_stats.funded_txo_sum,
1147+
1000
1148+
);
1149+
assert_eq!(scripthash_stats_blocking_bech32m.chain_stats.tx_count, 1);
1150+
}
1151+
10161152
#[cfg(all(feature = "blocking", feature = "async"))]
10171153
#[tokio::test]
10181154
async fn test_get_address_txs() {

0 commit comments

Comments
 (0)