Skip to content

Commit a2840af

Browse files
committed
Add support for bitcoin core 29.0
1 parent 71a6018 commit a2840af

File tree

30 files changed

+2509
-18
lines changed

30 files changed

+2509
-18
lines changed

.github/workflows/rust.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ jobs:
210210
matrix:
211211
feature:
212212
[
213+
"29_0",
213214
"28_0",
214215
"27_2",
215216
"27_1",

client/src/client_sync/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub mod v25;
1515
pub mod v26;
1616
pub mod v27;
1717
pub mod v28;
18+
pub mod v29;
1819

1920
use std::fs::File;
2021
use std::io::{BufRead, BufReader};
+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! Macros for implementing JSON-RPC methods on a client.
4+
//!
5+
//! Specifically this is methods found under the `== Blockchain ==` section of the
6+
//! API docs of Bitcoin Core `v29`.
7+
//!
8+
//! All macros require `Client` to be in scope.
9+
//!
10+
//! See or use the `define_jsonrpc_minreq_client!` macro to define a `Client`.
11+
12+
/// Implements Bitcoin Core JSON-RPC API method `getblock`
13+
#[macro_export]
14+
macro_rules! impl_client_v29__getblock {
15+
() => {
16+
impl Client {
17+
/// Gets a block by blockhash.
18+
pub fn get_block(&self, hash: BlockHash) -> Result<Block> {
19+
let json = self.get_block_verbose_zero(hash)?;
20+
Ok(json.block()?)
21+
}
22+
23+
/// Gets a block by blockhash with verbose set to 0.
24+
pub fn get_block_verbose_zero(&self, hash: BlockHash) -> Result<GetBlockVerboseZero> {
25+
self.call("getblock", &[into_json(hash)?, 0.into()])
26+
}
27+
28+
/// Gets a block by blockhash with verbose set to 1.
29+
pub fn get_block_verbose_one(&self, hash: BlockHash) -> Result<GetBlockVerboseOne> {
30+
self.call("getblock", &[into_json(hash)?, 1.into()])
31+
}
32+
}
33+
};
34+
}
35+
36+
/// Implements Bitcoin Core JSON-RPC API method `getblockheader`
37+
#[macro_export]
38+
macro_rules! impl_client_v29__getblockheader {
39+
() => {
40+
impl Client {
41+
pub fn get_block_header(&self, hash: &BlockHash) -> Result<GetBlockHeader> {
42+
self.call("getblockheader", &[into_json(hash)?, into_json(false)?])
43+
}
44+
45+
// This is the same as calling getblockheader with verbose==true.
46+
pub fn get_block_header_verbose(
47+
&self,
48+
hash: &BlockHash,
49+
) -> Result<GetBlockHeaderVerbose> {
50+
self.call("getblockheader", &[into_json(hash)?])
51+
}
52+
}
53+
};
54+
}
55+
56+
/// Implements Bitcoin Core JSON-RPC API method `getblockchaininfo`
57+
#[macro_export]
58+
macro_rules! impl_client_v29__getblockchaininfo {
59+
() => {
60+
impl Client {
61+
pub fn get_blockchain_info(&self) -> Result<GetBlockchainInfo> {
62+
self.call("getblockchaininfo", &[])
63+
}
64+
}
65+
};
66+
}
67+
68+
/// Implements Bitcoin Core JSON-RPC API method `getdescriptoractivity`
69+
#[macro_export]
70+
macro_rules! impl_client_v29__getdescriptoractivity {
71+
() => {
72+
impl Client {
73+
pub fn get_descriptor_activity(
74+
&self,
75+
blockhashes: &[BlockHash],
76+
scan_objects: &[&str],
77+
include_mempool: bool,
78+
) -> Result<GetDescriptorActivity> {
79+
let blockhashes_val = json!(blockhashes);
80+
let scan_objects_val = json!(scan_objects);
81+
let include_mempool_val = json!(include_mempool);
82+
83+
let params = vec![blockhashes_val, scan_objects_val, include_mempool_val];
84+
85+
self.call("getdescriptoractivity", &params)
86+
}
87+
}
88+
};
89+
}

client/src/client_sync/v29/mining.rs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! Macros for implementing JSON-RPC methods on a client.
4+
//!
5+
//! Specifically this is methods found under the `== Mining ==` section of the
6+
//! API docs of Bitcoin Core `v29`.
7+
//!
8+
//! All macros require `Client` to be in scope.
9+
//!
10+
//! See or use the `define_jsonrpc_minreq_client!` macro to define a `Client`.
11+
12+
/// Implements Bitcoin Core JSON-RPC API method `getmininginfo`
13+
#[macro_export]
14+
macro_rules! impl_client_v29__getmininginfo {
15+
() => {
16+
impl Client {
17+
pub fn get_mining_info(&self) -> Result<GetMiningInfo> {
18+
self.call("getmininginfo", &[])
19+
}
20+
}
21+
};
22+
}
23+
24+
#[macro_export]
25+
macro_rules! impl_client_v29__getblocktemplate {
26+
() => {
27+
impl Client {
28+
pub fn get_block_template(
29+
&self,
30+
request: &$crate::client_sync::v29::TemplateRequest,
31+
) -> Result<GetBlockTemplate> {
32+
self.call("getblocktemplate", &[into_json(request)?])
33+
}
34+
}
35+
};
36+
}

client/src/client_sync/v29/mod.rs

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! A JSON-RPC client for testing against Bitcoin Core `v29`.
4+
//!
5+
//! We ignore option arguments unless they effect the shape of the returned JSON data.
6+
pub mod blockchain;
7+
pub mod mining;
8+
9+
use std::collections::BTreeMap;
10+
use std::path::Path;
11+
12+
use bitcoin::address::{Address, NetworkChecked};
13+
use bitcoin::{Amount, Block, BlockHash, PublicKey, Txid};
14+
use serde::{Deserialize, Serialize};
15+
use serde_json::json;
16+
17+
use crate::client_sync::into_json;
18+
use crate::types::v29::*;
19+
20+
#[rustfmt::skip] // Keep public re-exports separate.
21+
pub use crate::client_sync::{
22+
v17::{Input, Output, WalletCreateFundedPsbtInput},
23+
v23::AddressType,
24+
};
25+
26+
crate::define_jsonrpc_minreq_client!("v29");
27+
crate::impl_client_check_expected_server_version!({ [290000] });
28+
29+
// == Blockchain ==
30+
crate::impl_client_v17__getbestblockhash!();
31+
crate::impl_client_v29__getblock!();
32+
crate::impl_client_v29__getblockchaininfo!();
33+
crate::impl_client_v17__getblockcount!();
34+
crate::impl_client_v19__getblockfilter!();
35+
crate::impl_client_v17__getblockhash!();
36+
crate::impl_client_v17__getblockheader!();
37+
crate::impl_client_v17__getblockstats!();
38+
crate::impl_client_v17__getchaintips!();
39+
crate::impl_client_v17__getchaintxstats!();
40+
crate::impl_client_v29__getdescriptoractivity!();
41+
crate::impl_client_v17__getdifficulty!();
42+
crate::impl_client_v17__getmempoolancestors!();
43+
crate::impl_client_v17__getmempooldescendants!();
44+
crate::impl_client_v17__getmempoolentry!();
45+
crate::impl_client_v17__getmempoolinfo!();
46+
crate::impl_client_v17__getrawmempool!();
47+
crate::impl_client_v22__gettxout!();
48+
crate::impl_client_v17__gettxoutproof!();
49+
crate::impl_client_v26__gettxoutsetinfo!();
50+
crate::impl_client_v17__preciousblock!();
51+
crate::impl_client_v17__pruneblockchain!();
52+
crate::impl_client_v23__savemempool!();
53+
crate::impl_client_v17__verifychain!();
54+
crate::impl_client_v17__verifytxoutproof!();
55+
56+
// == Control ==
57+
crate::impl_client_v17__getmemoryinfo!();
58+
crate::impl_client_v18__getrpcinfo!();
59+
crate::impl_client_v17__help!();
60+
crate::impl_client_v17__logging!();
61+
crate::impl_client_v17__stop!();
62+
crate::impl_client_v17__uptime!();
63+
64+
// == Generating ==
65+
crate::impl_client_v17__generatetoaddress!();
66+
crate::impl_client_v17__invalidateblock!();
67+
68+
// == Mining ==
69+
crate::impl_client_v29__getblocktemplate!();
70+
crate::impl_client_v29__getmininginfo!();
71+
crate::impl_client_v17__getnetworkhashps!();
72+
crate::impl_client_v26__get_prioritised_transactions!();
73+
crate::impl_client_v17__prioritisetransaction!();
74+
crate::impl_client_v17__submitblock!();
75+
76+
// == Network ==
77+
crate::impl_client_v17__getaddednodeinfo!();
78+
crate::impl_client_v17__getnettotals!();
79+
crate::impl_client_v17__getnetworkinfo!();
80+
crate::impl_client_v18__getnodeaddresses!();
81+
crate::impl_client_v17__getpeerinfo!();
82+
83+
// == Rawtransactions ==
84+
crate::impl_client_v18__analyzepsbt!();
85+
crate::impl_client_v17__combinepsbt!();
86+
crate::impl_client_v17__combinerawtransaction!();
87+
crate::impl_client_v17__converttopsbt!();
88+
crate::impl_client_v17__createpsbt!();
89+
crate::impl_client_v17__createrawtransaction!();
90+
crate::impl_client_v17__decodepsbt!();
91+
crate::impl_client_v17__decoderawtransaction!();
92+
crate::impl_client_v17__decodescript!();
93+
crate::impl_client_v17__finalizepsbt!();
94+
crate::impl_client_v17__fundrawtransaction!();
95+
crate::impl_client_v17__getrawtransaction!();
96+
crate::impl_client_v18__joinpsbts!();
97+
crate::impl_client_v17__sendrawtransaction!();
98+
crate::impl_client_v17__signrawtransaction!();
99+
crate::impl_client_v17__signrawtransactionwithkey!();
100+
crate::impl_client_v28__submitpackage!();
101+
crate::impl_client_v17__testmempoolaccept!();
102+
crate::impl_client_v18__utxoupdatepsbt!();
103+
104+
// == Wallet ==
105+
crate::impl_client_v17__addmultisigaddress!();
106+
crate::impl_client_v17__bumpfee!();
107+
crate::impl_client_v23__createwallet!();
108+
crate::impl_client_v17__dumpprivkey!();
109+
crate::impl_client_v17__dumpwallet!();
110+
crate::impl_client_v17__getaddressesbylabel!();
111+
crate::impl_client_v17__getaddressinfo!();
112+
crate::impl_client_v17__getbalance!();
113+
crate::impl_client_v19__getbalances!();
114+
crate::impl_client_v17__getnewaddress!();
115+
crate::impl_client_v17__getrawchangeaddress!();
116+
crate::impl_client_v17__getreceivedbyaddress!();
117+
crate::impl_client_v17__gettransaction!();
118+
crate::impl_client_v17__getunconfirmedbalance!();
119+
crate::impl_client_v17__getwalletinfo!();
120+
crate::impl_client_v17__listaddressgroupings!();
121+
crate::impl_client_v17__listlabels!();
122+
crate::impl_client_v17__listlockunspent!();
123+
crate::impl_client_v17__listreceivedbyaddress!();
124+
crate::impl_client_v17__listsinceblock!();
125+
crate::impl_client_v17__listtransactions!();
126+
crate::impl_client_v17__listunspent!();
127+
crate::impl_client_v17__listwallets!();
128+
crate::impl_client_v22__loadwallet!();
129+
crate::impl_client_v17__rescanblockchain!();
130+
crate::impl_client_v17__sendmany!();
131+
crate::impl_client_v17__sendtoaddress!();
132+
crate::impl_client_v17__signmessage!();
133+
crate::impl_client_v17__signrawtransactionwithwallet!();
134+
crate::impl_client_v21__unloadwallet!();
135+
crate::impl_client_v17__walletcreatefundedpsbt!();
136+
crate::impl_client_v17__walletprocesspsbt!();
137+
138+
/// Client side supported softfork deployment.
139+
#[derive(Copy, Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
140+
#[serde(rename_all = "lowercase")]
141+
pub enum TemplateRules {
142+
/// SegWit v0 supported.
143+
Segwit,
144+
/// Signet supported.
145+
Signet,
146+
/// CSV supported.
147+
Csv,
148+
/// Taproot supported.
149+
Taproot,
150+
}
151+
152+
/// Arg for the `getblocktemplate` method. (v29+).
153+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
154+
pub struct TemplateRequest {
155+
#[serde(skip_serializing_if = "Option::is_none")]
156+
pub mode: Option<String>,
157+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
158+
pub capabilities: Vec<String>,
159+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
160+
pub rules: Vec<TemplateRules>,
161+
#[serde(skip_serializing_if = "Option::is_none")]
162+
pub longpollid: Option<String>,
163+
#[serde(skip_serializing_if = "Option::is_none")]
164+
pub data: Option<String>,
165+
}

contrib/run-bitcoind.sh

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ CONFIGURATION
4242
4343
- Examples
4444
45+
v29 29.0 290 /opt/bitcoin-29.0/bin/bitcoind
4546
v28 28.1 281 /opt/bitcoin-28.0/bin/bitcoind
4647
v24 24.2 242 /opt/bitcoin-24.2/bin/bitcoind
4748
v21 0.21.2 212 /opt/bitcoin-0.21.2/bin/bitcoind

integration_test/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ edition = "2021"
1313
[features]
1414
# Enable the same feature in `node` and the version feature here.
1515
# All minor releases of the latest three versions.
16+
29_0 = ["v29", "node/29_0"]
1617
28_0 = ["v28", "node/28_0"]
1718
27_2 = ["v27", "node/27_2"]
1819
27_1 = ["v27", "node/27_1"]
@@ -33,6 +34,7 @@ edition = "2021"
3334

3435
# These features are just for internal use (feature gating).
3536
# Each major version is tested with the same client.
37+
v29 = []
3638
v28 = []
3739
v27 = []
3840
v26 = []

integration_test/tests/blockchain.rs

+11
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ fn blockchain__get_block__modelled() {
3636
// assert!(json.into_model().is_ok());
3737
}
3838

39+
#[cfg(not(feature = "v29"))]
3940
#[test]
4041
fn blockchain__get_blockchain_info__modelled() {
4142
let node = Node::with_wallet(Wallet::None, &[]);
@@ -148,6 +149,16 @@ fn blockchain__get_chain_tx_stats__modelled() {
148149
model.unwrap();
149150
}
150151

152+
#[test]
153+
#[cfg(feature = "v29")]
154+
fn blockchain__get_descriptor_activity__modelled() {
155+
let node = Node::with_wallet(Wallet::None, &["-coinstatsindex=1", "-txindex=1"]);
156+
157+
let json: GetDescriptorActivity = node.client.get_descriptor_activity(&[], &[], false).expect("getdescriptoractivity");
158+
let model: Result<mtype::GetDescriptorActivity, GetDescriptorActivityError> = json.into_model();
159+
model.unwrap();
160+
}
161+
151162
#[test]
152163
fn blockchain__get_difficulty__modelled() {
153164
let node = Node::with_wallet(Wallet::None, &[]);

integration_test/tests/mining.rs

+21-5
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,32 @@ fn mining__get_block_template__modelled() {
1414
// Requires connected nodes otherwise the RPC call errors.
1515
let (node1, node2, node3) = integration_test::three_node_network();
1616

17-
// Use the nodes otherwise they get dropped.
1817
node1.mine_a_block();
1918
node2.mine_a_block();
2019
node3.mine_a_block();
20+
std::thread::sleep(std::time::Duration::from_millis(500));
21+
22+
#[cfg(not(feature = "v29"))]
23+
{
24+
let options = TemplateRequest { rules: vec![TemplateRules::Segwit] };
25+
let json: GetBlockTemplate = node1.client.get_block_template(&options)
26+
.expect("get_block_template RPC failed");
27+
let _: Result<mtype::GetBlockTemplate, GetBlockTemplateError> = json.into_model();
28+
}
2129

22-
let options = TemplateRequest { rules: vec![TemplateRules::Segwit] };
30+
#[cfg(feature = "v29")]
31+
{
32+
let request = TemplateRequest {
33+
rules: vec![TemplateRules::Segwit],
34+
mode: Some("template".to_string()),
35+
..Default::default()
36+
};
2337

24-
let json: GetBlockTemplate = node1.client.get_block_template(&options).expect("rpc");
25-
let model: Result<mtype::GetBlockTemplate, GetBlockTemplateError> = json.into_model();
26-
model.unwrap();
38+
let json: GetBlockTemplate = node1.client.get_block_template(&request)
39+
.expect("get_block_template RPC failed");
40+
41+
let _: Result<mtype::GetBlockTemplate, GetBlockTemplateError> = json.into_model();
42+
}
2743
}
2844

2945
#[test]

0 commit comments

Comments
 (0)