Skip to content

Add support for bitcoin core 29.0 #131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/rust.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ jobs:
matrix:
feature:
[
"29_0",
"28_0",
"27_2",
"27_1",
Expand Down
1 change: 1 addition & 0 deletions client/src/client_sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub mod v25;
pub mod v26;
pub mod v27;
pub mod v28;
pub mod v29;

use std::collections::HashMap;
use std::fs::File;
Expand Down
89 changes: 89 additions & 0 deletions client/src/client_sync/v29/blockchain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// SPDX-License-Identifier: CC0-1.0

//! Macros for implementing JSON-RPC methods on a client.
//!
//! Specifically this is methods found under the `== Blockchain ==` section of the
//! API docs of Bitcoin Core `v29`.
//!
//! All macros require `Client` to be in scope.
//!
//! See or use the `define_jsonrpc_minreq_client!` macro to define a `Client`.

/// Implements Bitcoin Core JSON-RPC API method `getblock`
#[macro_export]
macro_rules! impl_client_v29__getblock {
() => {
impl Client {
/// Gets a block by blockhash.
pub fn get_block(&self, hash: BlockHash) -> Result<Block> {
let json = self.get_block_verbose_zero(hash)?;
Ok(json.block()?)
}

/// Gets a block by blockhash with verbose set to 0.
pub fn get_block_verbose_zero(&self, hash: BlockHash) -> Result<GetBlockVerboseZero> {
self.call("getblock", &[into_json(hash)?, 0.into()])
}

/// Gets a block by blockhash with verbose set to 1.
pub fn get_block_verbose_one(&self, hash: BlockHash) -> Result<GetBlockVerboseOne> {
self.call("getblock", &[into_json(hash)?, 1.into()])
}
}
};
}

/// Implements Bitcoin Core JSON-RPC API method `getblockheader`
#[macro_export]
macro_rules! impl_client_v29__getblockheader {
() => {
impl Client {
pub fn get_block_header(&self, hash: &BlockHash) -> Result<GetBlockHeader> {
self.call("getblockheader", &[into_json(hash)?, into_json(false)?])
}

// This is the same as calling getblockheader with verbose==true.
pub fn get_block_header_verbose(
&self,
hash: &BlockHash,
) -> Result<GetBlockHeaderVerbose> {
self.call("getblockheader", &[into_json(hash)?])
}
}
};
}

/// Implements Bitcoin Core JSON-RPC API method `getblockchaininfo`
#[macro_export]
macro_rules! impl_client_v29__getblockchaininfo {
() => {
impl Client {
pub fn get_blockchain_info(&self) -> Result<GetBlockchainInfo> {
self.call("getblockchaininfo", &[])
}
}
};
}

/// Implements Bitcoin Core JSON-RPC API method `getdescriptoractivity`
#[macro_export]
macro_rules! impl_client_v29__getdescriptoractivity {
() => {
impl Client {
pub fn get_descriptor_activity(
&self,
blockhashes: &[BlockHash],
scan_objects: &[&str],
include_mempool: bool,
) -> Result<GetDescriptorActivity> {
let blockhashes_val = json!(blockhashes);
let scan_objects_val = json!(scan_objects);
let include_mempool_val = json!(include_mempool);

let params = vec![blockhashes_val, scan_objects_val, include_mempool_val];

self.call("getdescriptoractivity", &params)
}
}
};
}
36 changes: 36 additions & 0 deletions client/src/client_sync/v29/mining.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: CC0-1.0

//! Macros for implementing JSON-RPC methods on a client.
//!
//! Specifically this is methods found under the `== Mining ==` section of the
//! API docs of Bitcoin Core `v29`.
//!
//! All macros require `Client` to be in scope.
//!
//! See or use the `define_jsonrpc_minreq_client!` macro to define a `Client`.

/// Implements Bitcoin Core JSON-RPC API method `getmininginfo`
#[macro_export]
macro_rules! impl_client_v29__getmininginfo {
() => {
impl Client {
pub fn get_mining_info(&self) -> Result<GetMiningInfo> {
self.call("getmininginfo", &[])
}
}
};
}

#[macro_export]
macro_rules! impl_client_v29__getblocktemplate {
() => {
impl Client {
pub fn get_block_template(
&self,
request: &$crate::client_sync::v29::TemplateRequest,
) -> Result<GetBlockTemplate> {
self.call("getblocktemplate", &[into_json(request)?])
}
}
};
}
159 changes: 159 additions & 0 deletions client/src/client_sync/v29/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// SPDX-License-Identifier: CC0-1.0

//! A JSON-RPC client for testing against Bitcoin Core `v29`.
//!
//! We ignore option arguments unless they effect the shape of the returned JSON data.
pub mod blockchain;
pub mod mining;

use std::collections::BTreeMap;
use std::path::Path;

use bitcoin::address::{Address, NetworkChecked};
use bitcoin::{Amount, Block, BlockHash, PublicKey, Txid};
use serde::{Deserialize, Serialize};
use serde_json::json;

use crate::client_sync::into_json;
use crate::types::v29::*;

#[rustfmt::skip] // Keep public re-exports separate.
pub use crate::client_sync::{v23::AddressType, WalletCreateFundedPsbtInput};

crate::define_jsonrpc_minreq_client!("v29");
crate::impl_client_check_expected_server_version!({ [290000] });

// == Blockchain ==
crate::impl_client_v17__getbestblockhash!();
crate::impl_client_v29__getblock!();
crate::impl_client_v29__getblockchaininfo!();
crate::impl_client_v17__getblockcount!();
crate::impl_client_v19__getblockfilter!();
crate::impl_client_v17__getblockhash!();
crate::impl_client_v17__getblockheader!();
crate::impl_client_v17__getblockstats!();
crate::impl_client_v17__getchaintips!();
crate::impl_client_v17__getchaintxstats!();
crate::impl_client_v29__getdescriptoractivity!();
crate::impl_client_v17__getdifficulty!();
crate::impl_client_v19__getmempoolancestors!();
crate::impl_client_v19__getmempooldescendants!();
crate::impl_client_v19__getmempoolentry!();
crate::impl_client_v17__getmempoolinfo!();
crate::impl_client_v17__getrawmempool!();
crate::impl_client_v22__gettxout!();
crate::impl_client_v17__gettxoutproof!();
crate::impl_client_v26__gettxoutsetinfo!();
crate::impl_client_v17__preciousblock!();
crate::impl_client_v17__pruneblockchain!();
crate::impl_client_v17__verifytxoutproof!();

// == Control ==
crate::impl_client_v17__getmemoryinfo!();
crate::impl_client_v18__getrpcinfo!();
crate::impl_client_v17__help!();
crate::impl_client_v17__logging!();
crate::impl_client_v17__stop!();
crate::impl_client_v17__uptime!();

// == Generating ==
crate::impl_client_v17__generatetoaddress!();
crate::impl_client_v17__invalidateblock!();

// == Mining ==
crate::impl_client_v29__getblocktemplate!();
crate::impl_client_v29__getmininginfo!();
crate::impl_client_v17__getnetworkhashps!();
crate::impl_client_v26__get_prioritised_transactions!();
crate::impl_client_v17__prioritisetransaction!();
crate::impl_client_v17__submitblock!();

// == Network ==
crate::impl_client_v17__getaddednodeinfo!();
crate::impl_client_v17__getnettotals!();
crate::impl_client_v17__getnetworkinfo!();
crate::impl_client_v17__getpeerinfo!();

// == Rawtransactions ==
crate::impl_client_v18__analyzepsbt!();
crate::impl_client_v17__combinepsbt!();
crate::impl_client_v17__combinerawtransaction!();
crate::impl_client_v17__converttopsbt!();
crate::impl_client_v17__createpsbt!();
crate::impl_client_v17__createrawtransaction!();
crate::impl_client_v17__decodepsbt!();
crate::impl_client_v17__decoderawtransaction!();
crate::impl_client_v17__decodescript!();
crate::impl_client_v17__finalizepsbt!();
crate::impl_client_v17__fundrawtransaction!();
crate::impl_client_v17__getrawtransaction!();
crate::impl_client_v18__joinpsbts!();
crate::impl_client_v17__sendrawtransaction!();
crate::impl_client_v17__signrawtransaction!();
crate::impl_client_v17__signrawtransactionwithkey!();
crate::impl_client_v28__submitpackage!();
crate::impl_client_v17__testmempoolaccept!();
crate::impl_client_v18__utxoupdatepsbt!();

// == Wallet ==
crate::impl_client_v17__addmultisigaddress!();
crate::impl_client_v17__bumpfee!();
crate::impl_client_v23__createwallet!();
crate::impl_client_v17__dumpprivkey!();
crate::impl_client_v17__dumpwallet!();
crate::impl_client_v17__getaddressesbylabel!();
crate::impl_client_v17__getaddressinfo!();
crate::impl_client_v17__getbalance!();
crate::impl_client_v19__getbalances!();
crate::impl_client_v17__getnewaddress!();
crate::impl_client_v17__getrawchangeaddress!();
crate::impl_client_v17__getreceivedbyaddress!();
crate::impl_client_v17__gettransaction!();
crate::impl_client_v17__getunconfirmedbalance!();
crate::impl_client_v17__getwalletinfo!();
crate::impl_client_v17__listaddressgroupings!();
crate::impl_client_v17__listlabels!();
crate::impl_client_v17__listlockunspent!();
crate::impl_client_v17__listreceivedbyaddress!();
crate::impl_client_v17__listsinceblock!();
crate::impl_client_v17__listtransactions!();
crate::impl_client_v17__listunspent!();
crate::impl_client_v17__listwallets!();
crate::impl_client_v22__loadwallet!();
crate::impl_client_v17__rescanblockchain!();
crate::impl_client_v17__sendmany!();
crate::impl_client_v17__sendtoaddress!();
crate::impl_client_v17__signmessage!();
crate::impl_client_v17__signrawtransactionwithwallet!();
crate::impl_client_v21__unloadwallet!();
crate::impl_client_v17__walletcreatefundedpsbt!();
crate::impl_client_v17__walletprocesspsbt!();

/// Client side supported softfork deployment.
#[derive(Copy, Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum TemplateRules {
/// SegWit v0 supported.
Segwit,
/// Signet supported.
Signet,
/// CSV supported.
Csv,
/// Taproot supported.
Taproot,
}

/// Arg for the `getblocktemplate` method. (v29+).
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
pub struct TemplateRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub capabilities: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub rules: Vec<TemplateRules>,
#[serde(skip_serializing_if = "Option::is_none")]
pub longpollid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<String>,
}
1 change: 1 addition & 0 deletions contrib/run-bitcoind.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ CONFIGURATION

- Examples

v29 29.0 290 /opt/bitcoin-29.0/bin/bitcoind
v28 28.1 281 /opt/bitcoin-28.0/bin/bitcoind
v24 24.2 242 /opt/bitcoin-24.2/bin/bitcoind
v21 0.21.2 212 /opt/bitcoin-0.21.2/bin/bitcoind
Expand Down
2 changes: 2 additions & 0 deletions integration_test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ edition = "2021"
[features]
# Enable the same feature in `node` and the version feature here.
# All minor releases of the latest three versions.
29_0 = ["v29", "node/29_0"]
28_0 = ["v28", "node/28_0"]
27_2 = ["v27", "node/27_2"]
27_1 = ["v27", "node/27_1"]
Expand All @@ -33,6 +34,7 @@ edition = "2021"

# These features are just for internal use (feature gating).
# Each major version is tested with the same client.
v29 = []
v28 = []
v27 = []
v26 = []
Expand Down
10 changes: 10 additions & 0 deletions integration_test/tests/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ fn blockchain__get_block__modelled() {
// assert!(json.into_model().is_ok());
}

#[cfg(not(feature = "v29"))]
#[test]
fn blockchain__get_blockchain_info__modelled() {
let node = Node::with_wallet(Wallet::None, &[]);
Expand Down Expand Up @@ -305,3 +306,12 @@ fn verify_tx_out_proof(node: &Node) -> Result<(), client_sync::Error> {

Ok(())
}

#[test]
#[cfg(feature = "v29")]
fn blockchain__get_descriptor_activity__modelled() {
let node = Node::with_wallet(Wallet::None, &["-coinstatsindex=1", "-txindex=1"]);

let res: GetDescriptorActivity = node.client.get_descriptor_activity(&[], &[], false).expect("get_descriptor_activity(None, None, None) failed");
let _: Result<mtype::GetDescriptorActivity, GetDescriptorActivityError> = res.into_model();
}
28 changes: 22 additions & 6 deletions integration_test/tests/mining.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use bitcoin::SignedAmount;
use integration_test::{Node, NodeExt as _, Wallet};
use node::client::client_sync::{TemplateRequest, TemplateRules};
use node::client::client_sync::{v29, TemplateRequest, TemplateRules};
use node::vtype::*; // All the version specific types.
use node::mtype;

Expand All @@ -15,16 +15,32 @@ fn mining__get_block_template__modelled() {
// Requires connected nodes otherwise the RPC call errors.
let (node1, node2, node3) = integration_test::three_node_network();

// Use the nodes otherwise they get dropped.
node1.mine_a_block();
node2.mine_a_block();
node3.mine_a_block();
std::thread::sleep(std::time::Duration::from_millis(500));

#[cfg(not(feature = "v29"))]
{
let options = TemplateRequest { rules: vec![TemplateRules::Segwit] };
let json: GetBlockTemplate = node1.client.get_block_template(&options)
.expect("get_block_template RPC failed (pre-v29)");
let _: Result<mtype::GetBlockTemplate, GetBlockTemplateError> = json.into_model();
}

let options = TemplateRequest { rules: vec![TemplateRules::Segwit] };
#[cfg(feature = "v29")]
{
let request = v29::TemplateRequest {
rules: vec![v29::TemplateRules::Segwit],
mode: Some("template".to_string()),
..Default::default()
};

let json: GetBlockTemplate = node1.client.get_block_template(&options).expect("rpc");
let model: Result<mtype::GetBlockTemplate, GetBlockTemplateError> = json.into_model();
model.unwrap();
let json: GetBlockTemplate = node1.client.get_block_template(&request)
.expect("get_block_template RPC failed (v29)");

let _: Result<mtype::GetBlockTemplate, GetBlockTemplateError> = json.into_model();
}
}

#[test]
Expand Down
Loading