Skip to content

Commit f9eb45b

Browse files
committed
Merge #62: Add sendrawtransaction and getblockchaininfo RPC methods
b2db191 feat(bitreq): Add tests for rpc methods (Vihiga Tyonum) cbc6937 feat(bitreq): Add send tx & blockchain info mthds (Vihiga Tyonum) Pull request description: <!-- You can erase any parts of this template not applicable to your Pull Request. --> ### Description This PR adds the `sendrawtransaction` and `getblockchaininfo` rpc methods to the bitreq module. Fixes #58 <!-- Describe the purpose of this PR, what's being adding and/or fixed --> ## Changelog notice <!-- Notice the release manager should include in the release tag message changelog --> <!-- See https://keepachangelog.com/en/1.0.0/ for examples --> ### Checklists #### All Submissions: * [x] I've signed all my commits * [x] I ran `just pre-push` before committing * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) #### New Features: * [x] I've added tests for the new feature * [ ] I've added docs for the new feature * [ ] I've updated `CHANGELOG.md` ACKs for top commit: ValuedMammal: tACK b2db191 Tree-SHA512: 8c33c886ff1bfc7f65f83651bd861ecf32bae63f220e6f0940463c781cdfb3188d4107602c9f454843af235f8d81d176582b8b49f5d3011e2ce912cf5842d43f
2 parents 7e7c56c + b2db191 commit f9eb45b

4 files changed

Lines changed: 133 additions & 3 deletions

File tree

src/bitreq.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ use std::{
1212

1313
use corepc_types::{
1414
bitcoin::{
15-
Block, BlockHash, Transaction, Txid, block::Header, consensus::encode::deserialize_hex,
15+
Block, BlockHash, Transaction, Txid,
16+
block::Header,
17+
consensus::encode::{deserialize_hex, serialize_hex},
1618
},
1719
model, v30,
1820
};
@@ -226,6 +228,21 @@ impl Client {
226228
self.call::<String>(Rpc::GetRawTransaction, &[json!(txid)])
227229
.and_then(|tx_hex| deserialize_hex(&tx_hex).map_err(Error::DecodeHex))
228230
}
231+
232+
/// Submits a raw transaction to the network.
233+
///
234+
/// # Arguments
235+
///
236+
/// * `tx`: The transaction to broadcast.
237+
///
238+
/// # Returns
239+
///
240+
/// The transaction ID (`Txid`) of the broadcasted transaction.
241+
pub fn send_raw_transaction(&self, tx: &Transaction) -> Result<Txid, Error> {
242+
let hex_tx = serialize_hex(tx);
243+
let txid: Txid = self.call(Rpc::SendRawTransaction, &[json!(hex_tx)])?;
244+
Ok(txid)
245+
}
229246
}
230247

231248
#[cfg(feature = "29_0")]
@@ -265,6 +282,16 @@ impl Client {
265282
self.call(Rpc::GetBlock, &[json!(block_hash), json!(1)])?;
266283
block_info.into_model().map_err(Error::model)
267284
}
285+
286+
/// Retrieves information about the blockchain state.
287+
///
288+
/// # Returns
289+
///
290+
/// State information as a `GetBlockchainInfo` struct.
291+
pub fn get_blockchain_info(&self) -> Result<model::GetBlockchainInfo, Error> {
292+
let info: v30::GetBlockchainInfo = self.call(Rpc::GetBlockchainInfo, &[])?;
293+
info.into_model().map_err(Error::model)
294+
}
268295
}
269296

270297
#[cfg(test)]

src/bitreq/v28.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use bitcoin::BlockHash;
66
use corepc_types::{
77
bitcoin,
8-
model::{GetBlockHeaderVerbose, GetBlockVerboseOne},
8+
model::{GetBlockHeaderVerbose, GetBlockVerboseOne, GetBlockchainInfo},
99
v28,
1010
};
1111
use jsonrpc::serde_json::json;
@@ -46,4 +46,14 @@ impl Client {
4646
self.call(Rpc::GetBlock, &[json!(block_hash), json!(1)])?;
4747
block_info.into_model().map_err(Error::model)
4848
}
49+
50+
/// Retrieves information about the blockchain state.
51+
///
52+
/// # Returns
53+
///
54+
/// State information as a `GetBlockchainInfo` struct.
55+
pub fn get_blockchain_info(&self) -> Result<GetBlockchainInfo, Error> {
56+
let info: v28::GetBlockchainInfo = self.call(Rpc::GetBlockchainInfo, &[])?;
57+
info.into_model().map_err(Error::model)
58+
}
4959
}

src/rpc.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ pub enum Rpc {
3030
GetRawMempool,
3131
/// `getrawtransaction` — returns raw transaction data for a given txid.
3232
GetRawTransaction,
33+
/// `getblockchaininfo` - returns information about the blockchain state.
34+
GetBlockchainInfo,
35+
/// `sendrawtransaction` - send raw transaction to the network.
36+
SendRawTransaction,
3337
}
3438

3539
impl core::fmt::Display for Rpc {
@@ -43,6 +47,8 @@ impl core::fmt::Display for Rpc {
4347
Self::GetBlockHeader => "getblockheader",
4448
Self::GetRawMempool => "getrawmempool",
4549
Self::GetRawTransaction => "getrawtransaction",
50+
Self::GetBlockchainInfo => "getblockchaininfo",
51+
Self::SendRawTransaction => "sendrawtransaction",
4652
};
4753
write!(f, "{s}")
4854
}
@@ -62,5 +68,7 @@ mod tests {
6268
assert_eq!(Rpc::GetBlockHeader.to_string(), "getblockheader");
6369
assert_eq!(Rpc::GetRawMempool.to_string(), "getrawmempool");
6470
assert_eq!(Rpc::GetRawTransaction.to_string(), "getrawtransaction");
71+
assert_eq!(Rpc::SendRawTransaction.to_string(), "sendrawtransaction");
72+
assert_eq!(Rpc::GetBlockchainInfo.to_string(), "getblockchaininfo");
6573
}
6674
}

tests/rpc_client.rs

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
//! These tests require a running Bitcoin Core node in regtest mode. To setup, refer to [`bitcoind`].
66
77
use core::str::FromStr;
8+
use std::collections::BTreeMap;
89

910
use bdk_bitcoind_client::bitreq::{Auth, Client};
10-
use corepc_types::bitcoin::{Amount, BlockHash, Txid};
11+
use corepc_types::bitcoin::{
12+
Amount, BlockHash, Network, Transaction, Txid, absolute, transaction::Version,
13+
};
1114

1215
mod testenv;
1316

@@ -312,3 +315,85 @@ fn test_get_block_filter() {
312315

313316
assert!(!result.filter.is_empty());
314317
}
318+
319+
#[test]
320+
fn test_get_blockchain_info() {
321+
let env = TestEnv::setup().unwrap();
322+
323+
env.mine_blocks(2, None).expect("failed to mine blocks");
324+
325+
let blockchain_info = env
326+
.client
327+
.get_blockchain_info()
328+
.expect("failed to get blockchain info");
329+
330+
assert_eq!(blockchain_info.chain, Network::Regtest);
331+
assert!(blockchain_info.blocks >= 2);
332+
333+
let best_hash = env.client.get_best_block_hash().unwrap();
334+
assert_eq!(blockchain_info.best_block_hash, best_hash);
335+
}
336+
337+
#[test]
338+
fn test_send_raw_transaction() {
339+
let env = TestEnv::setup().unwrap();
340+
341+
env.mine_blocks(101, None).expect("failed to mine blocks");
342+
343+
let recipient_address = env.bitcoind.client.new_address().unwrap();
344+
345+
let mut outputs = BTreeMap::new();
346+
outputs.insert(recipient_address, Amount::from_btc(0.001).unwrap());
347+
348+
let funded_psbt = env
349+
.bitcoind
350+
.client
351+
.wallet_create_funded_psbt(vec![], vec![outputs])
352+
.unwrap()
353+
.into_model()
354+
.unwrap();
355+
356+
let signed_psbt = env
357+
.bitcoind
358+
.client
359+
.wallet_process_psbt(&funded_psbt.psbt)
360+
.unwrap()
361+
.into_model()
362+
.unwrap();
363+
364+
assert!(signed_psbt.complete, "PSBT was not completely signed");
365+
366+
let finalized = env
367+
.bitcoind
368+
.client
369+
.finalize_psbt(&signed_psbt.psbt)
370+
.unwrap()
371+
.into_model()
372+
.unwrap();
373+
374+
let raw_hex = finalized.psbt.unwrap().extract_tx().unwrap();
375+
376+
let txid = env
377+
.client
378+
.send_raw_transaction(&raw_hex)
379+
.expect("failed to broadcast transaction");
380+
381+
let mempool = env.client.get_raw_mempool().expect("failed to get mempool");
382+
assert!(mempool.contains(&txid));
383+
}
384+
385+
#[test]
386+
fn test_send_raw_transaction_invalid() {
387+
let env = TestEnv::setup().unwrap();
388+
389+
let invalid_tx = Transaction {
390+
version: Version::ONE,
391+
lock_time: absolute::LockTime::ZERO,
392+
input: vec![],
393+
output: vec![],
394+
};
395+
396+
let result = env.client.send_raw_transaction(&invalid_tx);
397+
398+
assert!(result.is_err(), "Expected transaction to be rejected");
399+
}

0 commit comments

Comments
 (0)