Skip to content

Commit 3e3144c

Browse files
committed
feat: add get_scripthash_stats
1 parent 673264f commit 3e3144c

File tree

3 files changed

+160
-14
lines changed

3 files changed

+160
-14
lines changed

src/async.rs

Lines changed: 12 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,14 @@ impl<S: Sleeper> AsyncClient<S> {
397394
self.get_response_json(&path).await
398395
}
399396

397+
/// Get information about a specific scripthash, includes confirmed balance and transactions in
398+
/// the mempool.
399+
pub async fn get_scripthash_stats(&self, script: &Script) -> Result<ScriptHashStats, Error> {
400+
let script_hash = sha256::Hash::hash(script.as_bytes());
401+
let path = format!("/scripthash/{script_hash}");
402+
self.get_response_json(&path).await
403+
}
404+
400405
/// Get transaction history for the specified address/scripthash, sorted with newest first.
401406
///
402407
/// Returns up to 50 mempool transactions plus the first 25 confirmed transactions.

src/blocking.rs

Lines changed: 12 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,14 @@ impl BlockingClient {
331328
self.get_response_json(&path)
332329
}
333330

331+
/// Get information about a specific scripthash, includes confirmed balance and transactions in
332+
/// the mempool.
333+
pub fn get_scripthash_stats(&self, script: &Script) -> Result<ScriptHashStats, Error> {
334+
let script_hash = sha256::Hash::hash(script.as_bytes());
335+
let path = format!("/scripthash/{script_hash}");
336+
self.get_response_json(&path)
337+
}
338+
334339
/// Get transaction history for the specified address/scripthash, sorted with newest first.
335340
///
336341
/// 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
@@ -1011,6 +1011,142 @@ mod test {
10111011
assert_eq!(address_stats_async.chain_stats.funded_txo_sum, 1000);
10121012
}
10131013

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

0 commit comments

Comments
 (0)