From 881281783e186971b8ebf3e527729fc589bcdd17 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Tue, 4 Nov 2025 09:41:17 +0000 Subject: [PATCH 1/3] Remove unit from modelled feerate The FeeRate type abstracts away the unit. --- types/src/model/blockchain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/src/model/blockchain.rs b/types/src/model/blockchain.rs index 87e18e59..9ba7dc16 100644 --- a/types/src/model/blockchain.rs +++ b/types/src/model/blockchain.rs @@ -639,7 +639,7 @@ pub struct GetMempoolInfo { pub mempool_min_fee: Option, /// Current minimum relay fee for transactions. pub min_relay_tx_fee: Option, - /// Minimum fee rate increment for mempool limiting or replacement in BTC/kvB. v24 and later only. + /// Minimum fee rate increment for mempool limiting or replacement. v24 and later only. pub incremental_relay_fee: Option, /// Current number of transactions that haven't passed initial broadcast yet. v21 and later only. pub unbroadcast_count: Option, From d61029ba47b8633f725776e9f17ed701257fd5b8 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Mon, 3 Nov 2025 13:23:35 +0000 Subject: [PATCH 2/3] Add getmempoolinfo v30 support Redefine the type in v30 for the changes and remove TODO from table. Update the export, into function and test feature gate. --- integration_test/tests/blockchain.rs | 1 - types/src/model/blockchain.rs | 4 ++ types/src/v17/blockchain/into.rs | 2 + types/src/v19/blockchain/into.rs | 2 + types/src/v21/blockchain/into.rs | 2 + types/src/v22/blockchain/into.rs | 2 + types/src/v24/blockchain/into.rs | 2 + types/src/v30/blockchain/into.rs | 34 ++++++++++++++++ types/src/v30/blockchain/mod.rs | 59 ++++++++++++++++++++++++++++ types/src/v30/mod.rs | 8 +++- 10 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 types/src/v30/blockchain/into.rs create mode 100644 types/src/v30/blockchain/mod.rs diff --git a/integration_test/tests/blockchain.rs b/integration_test/tests/blockchain.rs index 9c284b3c..cfe97f85 100644 --- a/integration_test/tests/blockchain.rs +++ b/integration_test/tests/blockchain.rs @@ -331,7 +331,6 @@ fn blockchain__get_mempool_entry__modelled() { } #[test] -#[cfg(feature = "v29_and_below")] fn blockchain__get_mempool_info__modelled() { let node = Node::with_wallet(Wallet::Default, &[]); node.fund_wallet(); diff --git a/types/src/model/blockchain.rs b/types/src/model/blockchain.rs index 9ba7dc16..852dab49 100644 --- a/types/src/model/blockchain.rs +++ b/types/src/model/blockchain.rs @@ -646,6 +646,10 @@ pub struct GetMempoolInfo { /// True if the mempool accepts RBF without replaceability signaling inspection. v24 and later /// only. pub full_rbf: Option, + /// True if the mempool accepts transactions with bare multisig outputs. + pub permit_bare_multisig: Option, + /// Maximum number of bytes that can be used by OP_RETURN outputs in the mempool. + pub max_data_carrier_size: Option, } /// Models the result of JSON-RPC method `getrawmempool` with verbose set to false. diff --git a/types/src/v17/blockchain/into.rs b/types/src/v17/blockchain/into.rs index d3fcdd1d..c9bdf839 100644 --- a/types/src/v17/blockchain/into.rs +++ b/types/src/v17/blockchain/into.rs @@ -472,6 +472,8 @@ impl GetMempoolInfo { incremental_relay_fee: None, unbroadcast_count: None, full_rbf: None, + permit_bare_multisig: None, + max_data_carrier_size: None, }) } } diff --git a/types/src/v19/blockchain/into.rs b/types/src/v19/blockchain/into.rs index 5e697695..6dca9877 100644 --- a/types/src/v19/blockchain/into.rs +++ b/types/src/v19/blockchain/into.rs @@ -234,6 +234,8 @@ impl GetMempoolInfo { incremental_relay_fee: None, unbroadcast_count: None, full_rbf: None, + permit_bare_multisig: None, + max_data_carrier_size: None, }) } } diff --git a/types/src/v21/blockchain/into.rs b/types/src/v21/blockchain/into.rs index 6fe372af..e62aba65 100644 --- a/types/src/v21/blockchain/into.rs +++ b/types/src/v21/blockchain/into.rs @@ -177,6 +177,8 @@ impl GetMempoolInfo { incremental_relay_fee: None, unbroadcast_count, full_rbf: None, + permit_bare_multisig: None, + max_data_carrier_size: None, }) } } diff --git a/types/src/v22/blockchain/into.rs b/types/src/v22/blockchain/into.rs index dcb9f896..5d32e348 100644 --- a/types/src/v22/blockchain/into.rs +++ b/types/src/v22/blockchain/into.rs @@ -26,6 +26,8 @@ impl GetMempoolInfo { incremental_relay_fee: None, unbroadcast_count, full_rbf: None, + permit_bare_multisig: None, + max_data_carrier_size: None, }) } } diff --git a/types/src/v24/blockchain/into.rs b/types/src/v24/blockchain/into.rs index ca2be929..4523a7e2 100644 --- a/types/src/v24/blockchain/into.rs +++ b/types/src/v24/blockchain/into.rs @@ -153,6 +153,8 @@ impl GetMempoolInfo { incremental_relay_fee, unbroadcast_count, full_rbf: Some(self.full_rbf), + permit_bare_multisig: None, + max_data_carrier_size: None, }) } } diff --git a/types/src/v30/blockchain/into.rs b/types/src/v30/blockchain/into.rs new file mode 100644 index 00000000..69fe7b3c --- /dev/null +++ b/types/src/v30/blockchain/into.rs @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: CC0-1.0 + +use super::{GetMempoolInfo, GetMempoolInfoError}; +use crate::model; + +impl GetMempoolInfo { + /// Converts version specific type to a version nonspecific, more strongly typed type. + pub fn into_model(self) -> Result { + let size = crate::to_u32(self.size, "size")?; + let bytes = crate::to_u32(self.bytes, "bytes")?; + let usage = crate::to_u32(self.usage, "usage")?; + let max_mempool = crate::to_u32(self.max_mempool, "max_mempool")?; + let mempool_min_fee = crate::btc_per_kb(self.mempool_min_fee)?; + let min_relay_tx_fee = crate::btc_per_kb(self.min_relay_tx_fee)?; + let incremental_relay_fee = crate::btc_per_kb(self.incremental_relay_fee)?; + let unbroadcast_count = Some(crate::to_u32(self.unbroadcast_count, "unbroadcast_count")?); + + Ok(model::GetMempoolInfo { + loaded: Some(self.loaded), + size, + bytes, + usage, + total_fee: Some(self.total_fee), + max_mempool, + mempool_min_fee, + min_relay_tx_fee, + incremental_relay_fee, + unbroadcast_count, + full_rbf: Some(self.full_rbf), + permit_bare_multisig: Some(self.permit_bare_multisig), + max_data_carrier_size: Some(self.max_data_carrier_size), + }) + } +} diff --git a/types/src/v30/blockchain/mod.rs b/types/src/v30/blockchain/mod.rs new file mode 100644 index 00000000..86c02c44 --- /dev/null +++ b/types/src/v30/blockchain/mod.rs @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! The JSON-RPC API for Bitcoin Core `v30` - blockchain. +//! +//! Types for methods found under the `== Blockchain ==` section of the API docs. + +mod into; + +use serde::{Deserialize, Serialize}; + +pub use super::GetMempoolInfoError; + +/// Result of JSON-RPC method `getmempoolinfo` with verbose set to `true`. +/// +/// > getmempoolinfo +/// > +/// > Returns details on the active state of the TX memory pool. +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[cfg_attr(feature = "serde-deny-unknown-fields", serde(deny_unknown_fields))] +pub struct GetMempoolInfo { + /// True if the initial load attempt of the persisted mempool finished. + pub loaded: bool, + /// Current tx count. + pub size: i64, + /// Sum of all virtual transaction sizes as defined in BIP 141. + /// + /// Differs from actual serialized size because witness data is discounted. + pub bytes: i64, + /// Total memory usage for the mempool. + pub usage: i64, + /// Total fees for the mempool in BTC, ignoring modified fees through prioritisetransaction. + pub total_fee: f64, + /// Maximum memory usage for the mempool. + #[serde(rename = "maxmempool")] + pub max_mempool: i64, + /// Minimum fee rate in BTC/kB for a transaction to be accepted. + /// + /// This is the maximum of `minrelaytxfee` and the minimum mempool fee. + #[serde(rename = "mempoolminfee")] + pub mempool_min_fee: f64, + /// Current minimum relay fee for transactions. + #[serde(rename = "minrelaytxfee")] + pub min_relay_tx_fee: f64, + /// Minimum fee rate increment for mempool limiting or replacement in BTC/kvB. + #[serde(rename = "incrementalrelayfee")] + pub incremental_relay_fee: f64, + /// Current number of transactions that haven't passed initial broadcast yet. + #[serde(rename = "unbroadcastcount")] + pub unbroadcast_count: i64, + /// True if the mempool accepts RBF without replaceability signaling inspection. + #[serde(rename = "fullrbf")] + pub full_rbf: bool, + /// True if the mempool accepts transactions with bare multisig outputs. + #[serde(rename = "permitbaremultisig")] + pub permit_bare_multisig: bool, + /// Maximum number of bytes that can be used by OP_RETURN outputs in the mempool. + #[serde(rename = "maxdatacarriersize")] + pub max_data_carrier_size: u64, +} diff --git a/types/src/v30/mod.rs b/types/src/v30/mod.rs index cd73423e..bdf2dfb6 100644 --- a/types/src/v30/mod.rs +++ b/types/src/v30/mod.rs @@ -45,7 +45,7 @@ //! | getmempoolancestors | version + model | | //! | getmempooldescendants | version + model | | //! | getmempoolentry | version + model | | -//! | getmempoolinfo | version + model | TODO | +//! | getmempoolinfo | version + model | | //! | getrawmempool | version + model | Includes additional 'verbose' type | //! | gettxout | version + model | | //! | gettxoutproof | returns string | | @@ -242,6 +242,10 @@ //! //! +mod blockchain; + +#[doc(inline)] +pub use self::{blockchain::GetMempoolInfo}; #[doc(inline)] pub use crate::{ v17::{ @@ -297,7 +301,7 @@ pub use crate::{ }, v24::{ DecodePsbt, DecodePsbtError, GetMempoolAncestors, GetMempoolAncestorsVerbose, - GetMempoolDescendants, GetMempoolDescendantsVerbose, GetMempoolEntry, GetMempoolInfo, + GetMempoolDescendants, GetMempoolDescendantsVerbose, GetMempoolEntry, GetRawMempoolVerbose, GetTransactionDetail, GetTxSpendingPrevout, GetTxSpendingPrevoutError, GlobalXpub, ListUnspent, ListUnspentItem, MempoolEntry, MigrateWallet, Proprietary, PsbtInput, PsbtOutput, SendAll, SendAllError, From 1f869f59db2f444242169dc421ada2caea5457b7 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Mon, 3 Nov 2025 13:42:28 +0000 Subject: [PATCH 3/3] Add getmininginfo v30 support Redefine the type in v30 for the changes and remove TODO from table. Update the export, into function and test feature gate. --- integration_test/tests/mining.rs | 1 - types/src/model/mining.rs | 5 ++- types/src/v17/mining/into.rs | 1 + types/src/v28/mining.rs | 1 + types/src/v29/mining/into.rs | 1 + types/src/v30/mining/error.rs | 47 ++++++++++++++++++++++++++ types/src/v30/mining/into.rs | 37 +++++++++++++++++++++ types/src/v30/mining/mod.rs | 57 ++++++++++++++++++++++++++++++++ types/src/v30/mod.rs | 23 +++++++------ 9 files changed, 161 insertions(+), 12 deletions(-) create mode 100644 types/src/v30/mining/error.rs create mode 100644 types/src/v30/mining/into.rs create mode 100644 types/src/v30/mining/mod.rs diff --git a/integration_test/tests/mining.rs b/integration_test/tests/mining.rs index dd7e9e48..897018ab 100644 --- a/integration_test/tests/mining.rs +++ b/integration_test/tests/mining.rs @@ -37,7 +37,6 @@ fn mining__get_block_template__modelled() { } #[test] -#[cfg(feature = "v29_and_below")] fn mining__get_mining_info() { let node = Node::with_wallet(Wallet::Default, &[]); diff --git a/types/src/model/mining.rs b/types/src/model/mining.rs index 6bfd8186..8d3bffcf 100644 --- a/types/src/model/mining.rs +++ b/types/src/model/mining.rs @@ -8,7 +8,8 @@ use std::collections::BTreeMap; use bitcoin::{ - block, Amount, BlockHash, CompactTarget, SignedAmount, Target, Transaction, Txid, Weight, Wtxid, + block, Amount, BlockHash, CompactTarget, FeeRate, SignedAmount, Target, Transaction, Txid, + Weight, Wtxid, }; use serde::{Deserialize, Serialize}; @@ -115,6 +116,8 @@ pub struct GetMiningInfo { pub network_hash_ps: i64, /// The size of the mempool. pub pooled_tx: i64, + /// Minimum feerate of packages selected for block inclusion. + pub block_min_tx_fee: Option, /// Current network name as defined in BIP70 (main, test, regtest). pub chain: String, /// The block challenge (aka. block script). diff --git a/types/src/v17/mining/into.rs b/types/src/v17/mining/into.rs index f21549a5..d67eecb1 100644 --- a/types/src/v17/mining/into.rs +++ b/types/src/v17/mining/into.rs @@ -100,6 +100,7 @@ impl GetMiningInfo { target: None, network_hash_ps: self.network_hash_ps, pooled_tx: self.pooled_tx, + block_min_tx_fee: None, chain: self.chain, signet_challenge: None, next: None, diff --git a/types/src/v28/mining.rs b/types/src/v28/mining.rs index a7a4ac1c..8bc949de 100644 --- a/types/src/v28/mining.rs +++ b/types/src/v28/mining.rs @@ -53,6 +53,7 @@ impl GetMiningInfo { target: None, network_hash_ps: self.network_hash_ps, pooled_tx: self.pooled_tx, + block_min_tx_fee: None, chain: self.chain, signet_challenge: None, next: None, diff --git a/types/src/v29/mining/into.rs b/types/src/v29/mining/into.rs index 7a3d0882..532c065e 100644 --- a/types/src/v29/mining/into.rs +++ b/types/src/v29/mining/into.rs @@ -25,6 +25,7 @@ impl GetMiningInfo { target: Some(target), network_hash_ps: self.network_hash_ps, pooled_tx: self.pooled_tx, + block_min_tx_fee: None, chain: self.chain, signet_challenge: self.signet_challenge, next: Some(next), diff --git a/types/src/v30/mining/error.rs b/types/src/v30/mining/error.rs new file mode 100644 index 00000000..e51711e3 --- /dev/null +++ b/types/src/v30/mining/error.rs @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: CC0-1.0 + +use core::fmt; + +use bitcoin::amount::ParseAmountError; +use bitcoin::error::UnprefixedHexError; + +use super::NextBlockInfoError; +use crate::error::write_err; + +/// Error when converting a `GetMiningInfo` type into the model type. +#[derive(Debug)] +pub enum GetMiningInfoError { + /// Conversion of the `bits` field failed. + Bits(UnprefixedHexError), + /// Conversion of the `target` field failed. + Target(UnprefixedHexError), + /// Conversion of the `block_min_tx_fee` field failed. + BlockMinTxFee(ParseAmountError), + /// Conversion of one of the items in field `next` failed. + Next(NextBlockInfoError), +} + +impl fmt::Display for GetMiningInfoError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::Bits(ref e) => write_err!(f, "conversion of the `bits` field failed"; e), + Self::Target(ref e) => write_err!(f, "conversion of the `target` field failed"; e), + Self::BlockMinTxFee(ref e) => + write_err!(f, "conversion of the `block_min_tx_fee` field failed"; e), + Self::Next(ref e) => + write_err!(f, "conversion of one of the items in field `next` failed"; e), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for GetMiningInfoError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match *self { + Self::Bits(ref e) => Some(e), + Self::Target(ref e) => Some(e), + Self::BlockMinTxFee(ref e) => Some(e), + Self::Next(ref e) => Some(e), + } + } +} diff --git a/types/src/v30/mining/into.rs b/types/src/v30/mining/into.rs new file mode 100644 index 00000000..2de3efac --- /dev/null +++ b/types/src/v30/mining/into.rs @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: CC0-1.0 + +use bitcoin::{CompactTarget, Target, Weight}; + +use super::{GetMiningInfo, GetMiningInfoError}; +use crate::model; + +impl GetMiningInfo { + /// Converts version specific type to a version nonspecific, more strongly typed type. + pub fn into_model(self) -> Result { + use GetMiningInfoError as E; + + let current_block_weight = self.current_block_weight.map(Weight::from_wu); + let bits = CompactTarget::from_unprefixed_hex(&self.bits).map_err(E::Bits)?; + let target = Target::from_unprefixed_hex(self.target.as_ref()).map_err(E::Target)?; + let block_min_tx_fee = + crate::btc_per_kb(self.block_min_tx_fee).map_err(E::BlockMinTxFee)?; + + let next = self.next.into_model().map_err(E::Next)?; + + Ok(model::GetMiningInfo { + blocks: self.blocks, + current_block_weight, + current_block_tx: self.current_block_tx, + bits: Some(bits), + difficulty: self.difficulty, + target: Some(target), + network_hash_ps: self.network_hash_ps, + pooled_tx: self.pooled_tx, + block_min_tx_fee, + chain: self.chain, + signet_challenge: self.signet_challenge, + next: Some(next), + warnings: self.warnings, + }) + } +} diff --git a/types/src/v30/mining/mod.rs b/types/src/v30/mining/mod.rs new file mode 100644 index 00000000..f9a53634 --- /dev/null +++ b/types/src/v30/mining/mod.rs @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! The JSON-RPC API for Bitcoin Core `v29` - mining. +//! +//! Types for methods found under the `== Mining ==` section of the API docs. + +mod error; +mod into; + +use serde::{Deserialize, Serialize}; + +pub use self::error::GetMiningInfoError; +pub use super::{NextBlockInfo, NextBlockInfoError}; + +/// Result of the JSON-RPC method `getmininginfo`. +/// +/// > getmininginfo +/// > +/// > Returns a json object containing mining-related information. +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[cfg_attr(feature = "serde-deny-unknown-fields", serde(deny_unknown_fields))] +pub struct GetMiningInfo { + /// The current block. + pub blocks: u64, + /// The block weight (including reserved weight for block header, txs count and coinbase tx) of + /// the last assembled block (only present if a block was ever assembled). + #[serde(rename = "currentblockweight")] + pub current_block_weight: Option, + /// The number of block transactions (excluding coinbase) of the last assembled block (only + /// present if a block was ever assembled). + #[serde(rename = "currentblocktx")] + pub current_block_tx: Option, + /// The current nBits, compact representation of the block difficulty target. + pub bits: String, + /// The current difficulty. + pub difficulty: f64, + /// The current target. + pub target: String, + /// The network hashes per second. + #[serde(rename = "networkhashps")] + pub network_hash_ps: i64, + /// The size of the mempool. + #[serde(rename = "pooledtx")] + pub pooled_tx: i64, + /// Minimum feerate of packages selected for block inclusion in BTC/kvB. + #[serde(rename = "blockmintxfee")] + pub block_min_tx_fee: f64, + /// Current network name as defined in BIP70 (main, test, regtest). + pub chain: String, + /// The block challenge (aka. block script), in hexadecimal (only present if the current network + /// is a signet). + pub signet_challenge: Option, + /// The next block. + pub next: NextBlockInfo, + /// Any network and blockchain warnings. + pub warnings: Vec, +} diff --git a/types/src/v30/mod.rs b/types/src/v30/mod.rs index bdf2dfb6..0aedbd27 100644 --- a/types/src/v30/mod.rs +++ b/types/src/v30/mod.rs @@ -86,7 +86,7 @@ //! | JSON-RPC Method Name | Returns | Notes | //! |:-----------------------------------|:---------------:|:--------------------------------------:| //! | getblocktemplate | version + model | | -//! | getmininginfo | version + model | TODO | +//! | getmininginfo | version + model | | //! | getnetworkhashps | returns boolean | | //! | getprioritisedtransactions | version + model | | //! | prioritisetransaction | returns boolean | | @@ -243,9 +243,13 @@ //! mod blockchain; +mod mining; #[doc(inline)] -pub use self::{blockchain::GetMempoolInfo}; +pub use self::{ + blockchain::GetMempoolInfo, + mining::{GetMiningInfo, GetMiningInfoError}, +}; #[doc(inline)] pub use crate::{ v17::{ @@ -301,12 +305,11 @@ pub use crate::{ }, v24::{ DecodePsbt, DecodePsbtError, GetMempoolAncestors, GetMempoolAncestorsVerbose, - GetMempoolDescendants, GetMempoolDescendantsVerbose, GetMempoolEntry, - GetRawMempoolVerbose, GetTransactionDetail, GetTxSpendingPrevout, - GetTxSpendingPrevoutError, GlobalXpub, ListUnspent, ListUnspentItem, MempoolEntry, - MigrateWallet, Proprietary, PsbtInput, PsbtOutput, SendAll, SendAllError, - SimulateRawTransaction, TaprootBip32Deriv, TaprootLeaf, TaprootScript, - TaprootScriptPathSig, + GetMempoolDescendants, GetMempoolDescendantsVerbose, GetMempoolEntry, GetRawMempoolVerbose, + GetTransactionDetail, GetTxSpendingPrevout, GetTxSpendingPrevoutError, GlobalXpub, + ListUnspent, ListUnspentItem, MempoolEntry, MigrateWallet, Proprietary, PsbtInput, + PsbtOutput, SendAll, SendAllError, SimulateRawTransaction, TaprootBip32Deriv, TaprootLeaf, + TaprootScript, TaprootScriptPathSig, }, v25::{ GenerateBlock, GenerateBlockError, GetBlockStats, ListDescriptors, MempoolAcceptanceError, @@ -334,7 +337,7 @@ pub use crate::{ GetBlockHeaderVerbose, GetBlockHeaderVerboseError, GetBlockVerboseOne, GetBlockVerboseOneError, GetBlockchainInfo, GetBlockchainInfoError, GetChainStates, GetChainStatesError, GetDescriptorActivity, GetDescriptorActivityError, GetDescriptorInfo, - GetMiningInfo, GetMiningInfoError, MempoolAcceptance, NextBlockInfo, NextBlockInfoError, - ReceiveActivity, SpendActivity, TestMempoolAccept, + MempoolAcceptance, NextBlockInfo, NextBlockInfoError, ReceiveActivity, SpendActivity, + TestMempoolAccept, }, };