Skip to content

Commit 436d488

Browse files
committed
Add async client getblockchaininfo and gettxout
Add these two RPCs to the async client Trait and tests. Assisted-by: GPT-5.4
1 parent e1232c8 commit 436d488

2 files changed

Lines changed: 82 additions & 2 deletions

File tree

client/src/client_async/rpcs.rs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
//! RPC methods for the async Bitcoin Core client.
44
//! All functions return the version nonspecific, strongly typed types.
55
6-
use bitcoin::{block, Block, BlockHash, Transaction, Txid};
6+
use bitcoin::{block, Block, BlockHash, OutPoint, Transaction, Txid};
77
use serde_json::value::RawValue;
88

99
use super::{into_json, Client, IntoModelError, Result};
10-
use crate::types::model::{GetBlockFilter, GetBlockHeaderVerbose, GetBlockVerboseOne};
10+
use crate::types::model::{
11+
GetBlockFilter, GetBlockHeaderVerbose, GetBlockVerboseOne, GetBlockchainInfo, GetTxOut,
12+
};
1113

1214
/// Bitcoin Core RPC methods (v25 to v30).
1315
///
@@ -42,12 +44,22 @@ pub trait BitcoinRpcs {
4244
/// Gets the block filter for a blockhash.
4345
async fn get_block_filter(&self, hash: &BlockHash) -> Result<GetBlockFilter>;
4446

47+
/// Gets information about the current state of the blockchain.
48+
async fn get_blockchain_info(&self) -> Result<GetBlockchainInfo>;
49+
4550
/// Gets the transaction IDs currently in the mempool.
4651
async fn get_raw_mempool(&self) -> Result<Vec<Txid>>;
4752

4853
/// Gets the raw transaction by txid.
4954
async fn get_raw_transaction(&self, txid: &Txid) -> Result<Transaction>;
5055

56+
/// Gets details about an unspent transaction output.
57+
async fn get_tx_out(
58+
&self,
59+
outpoint: &OutPoint,
60+
include_mempool: bool,
61+
) -> Result<Option<GetTxOut>>;
62+
5163
/// Returns the version integer reported by the server (e.g. `250200` for v25.2.0).
5264
async fn server_version(&self) -> Result<usize>;
5365
}
@@ -112,6 +124,21 @@ impl BitcoinRpcs for Client {
112124
Ok(json.into_model().map_err(|e| IntoModelError::new("`getblockfilter`", e))?)
113125
}
114126

127+
async fn get_blockchain_info(&self) -> Result<GetBlockchainInfo> {
128+
let raw: Box<RawValue> = self.call("getblockchaininfo", &[]).await?;
129+
130+
if let Ok(json) = serde_json::from_str::<crate::types::v29::GetBlockchainInfo>(raw.get()) {
131+
Ok(json.into_model().map_err(|e| IntoModelError::new("`getblockchaininfo`", e))?)
132+
} else if let Ok(json) =
133+
serde_json::from_str::<crate::types::v28::GetBlockchainInfo>(raw.get())
134+
{
135+
Ok(json.into_model().map_err(|e| IntoModelError::new("`getblockchaininfo`", e))?)
136+
} else {
137+
let json: crate::types::v25::GetBlockchainInfo = serde_json::from_str(raw.get())?;
138+
Ok(json.into_model().map_err(|e| IntoModelError::new("`getblockchaininfo`", e))?)
139+
}
140+
}
141+
115142
async fn get_raw_mempool(&self) -> Result<Vec<Txid>> {
116143
let json: crate::types::v25::GetRawMempool = self.call("getrawmempool", &[]).await?;
117144
Ok(json.into_model().map_err(|e| IntoModelError::new("`getrawmempool`", e))?.0)
@@ -123,6 +150,28 @@ impl BitcoinRpcs for Client {
123150
Ok(json.into_model().map_err(|e| IntoModelError::new("`getrawtransaction`", e))?.0)
124151
}
125152

153+
async fn get_tx_out(
154+
&self,
155+
outpoint: &OutPoint,
156+
include_mempool: bool,
157+
) -> Result<Option<GetTxOut>> {
158+
let json: Option<crate::types::v25::GetTxOut> = self
159+
.call(
160+
"gettxout",
161+
&[
162+
into_json(outpoint.txid)?,
163+
into_json(outpoint.vout)?,
164+
into_json(include_mempool)?,
165+
],
166+
)
167+
.await?;
168+
match json {
169+
None => Ok(None),
170+
Some(json) =>
171+
Ok(Some(json.into_model().map_err(|e| IntoModelError::new("`gettxout`", e))?)),
172+
}
173+
}
174+
126175
async fn server_version(&self) -> Result<usize> {
127176
// Use a minimal type to read only the `version` field; the shape of other fields
128177
// (e.g. `warnings` changed from String to Vec<String> at v28) differs across the

integration_test/tests/bdk_client.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,19 @@ async fn async__get_block_header__modelled() {
9898
assert_eq!(model.height, 0);
9999
}
100100

101+
#[tokio::test]
102+
async fn async__get_blockchain_info__modelled() {
103+
let node = BitcoinD::with_wallet(Wallet::None, &["-prune=10000"]);
104+
let client = async_client_for(&node);
105+
106+
let model: Result<mtype::GetBlockchainInfo, AsyncClientError> =
107+
client.get_blockchain_info().await;
108+
let model = model.unwrap();
109+
110+
assert_eq!(model.blocks, 0);
111+
assert!(model.pruned);
112+
}
113+
101114
#[tokio::test]
102115
async fn async__get_raw_mempool__modelled() {
103116
let node = BitcoinD::with_wallet(Wallet::None, &[]);
@@ -129,6 +142,24 @@ async fn async__get_raw_transaction__modelled() {
129142
assert_eq!(model.compute_txid(), txid);
130143
}
131144

145+
#[tokio::test]
146+
async fn async__get_tx_out__modelled() {
147+
let node = BitcoinD::with_wallet(Wallet::Default, &[]);
148+
node.fund_wallet();
149+
let client = async_client_for(&node);
150+
let (_address, tx) = node.create_mined_transaction();
151+
let txid = tx.compute_txid();
152+
153+
let model: Result<Option<mtype::GetTxOut>, AsyncClientError> =
154+
client.get_tx_out(&bitcoin::OutPoint { txid, vout: 1 }, true).await;
155+
let model = model.unwrap().expect("unspent output");
156+
assert!(!model.coinbase);
157+
158+
let missing: Result<Option<mtype::GetTxOut>, AsyncClientError> =
159+
client.get_tx_out(&bitcoin::OutPoint { txid, vout: 2 }, true).await;
160+
assert!(missing.unwrap().is_none());
161+
}
162+
132163
fn auth_for(node: &BitcoinD) -> Auth { Auth::CookieFile(node.params.cookie_file.clone()) }
133164

134165
#[tokio::test]

0 commit comments

Comments
 (0)