Skip to content

Commit a2e8187

Browse files
committed
WIP: feat(rpc/v17 - v28) Add initial implementation for pruneblockchain (rust-bitcoin#115)
1 parent 2643b9d commit a2e8187

File tree

14 files changed

+115
-7
lines changed

14 files changed

+115
-7
lines changed

client/src/client_sync/v17/blockchain.rs

+13
Original file line numberDiff line numberDiff line change
@@ -297,3 +297,16 @@ macro_rules! impl_client_v17__verifytxoutproof {
297297
}
298298
};
299299
}
300+
301+
/// Implements Bitcoin Core JSON-RPC API method `pruneblockchain`
302+
#[macro_export]
303+
macro_rules! impl_client_v17__pruneblockchain {
304+
() => {
305+
impl Client {
306+
/// Instructs the node to prune the blockchain up to a specified height or timestamp.
307+
pub fn prune_blockchain(&self, target: u64) -> Result<PruneBlockchain> {
308+
self.call("pruneblockchain", &[into_json(target)?])
309+
}
310+
}
311+
};
312+
}

client/src/client_sync/v17/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ crate::impl_client_v17__gettxoutproof!();
4949
crate::impl_client_v17__gettxoutsetinfo!();
5050
crate::impl_client_v17__preciousblock!();
5151
crate::impl_client_v17__verifytxoutproof!();
52+
crate::impl_client_v17__pruneblockchain!();
5253

5354
// == Control ==
5455
crate::impl_client_v17__getmemoryinfo!();

client/src/client_sync/v28/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ crate::impl_client_v17__gettxoutproof!();
4242
crate::impl_client_v26__gettxoutsetinfo!();
4343
crate::impl_client_v17__preciousblock!();
4444
crate::impl_client_v17__verifytxoutproof!();
45+
crate::impl_client_v17__pruneblockchain!();
4546

4647
// == Control ==
4748
crate::impl_client_v17__getmemoryinfo!();

integration_test/tests/blockchain.rs

+27
Original file line numberDiff line numberDiff line change
@@ -255,3 +255,30 @@ fn verify_tx_out_proof() {
255255
let txids = node.client.verify_tx_out_proof(&proof).expect("verifytxoutproof");
256256
assert_eq!(txids.0.len(), 1);
257257
}
258+
259+
// Implicitly tests the omitted method `pruneblockchain`
260+
#[test]
261+
fn prune_blockchain() {
262+
let node = Node::with_wallet(Wallet::Default, &["-prune=550"]);
263+
// Generate 1001 blocks to exceed regtest's nPruneAfterHeight (1000)
264+
let num_blocks_to_mine = 1001;
265+
// (Using a loop with mine_a_block is necessary as generate() is deprecated in v28)
266+
for _ in 0..num_blocks_to_mine {
267+
node.mine_a_block();
268+
}
269+
270+
// Verify block count
271+
let count = node.client.get_block_count().expect("getblockcount").0;
272+
assert!(
273+
count >= num_blocks_to_mine as u64,
274+
"Failed to mine enough blocks. Expected: {}, Got: {}",
275+
num_blocks_to_mine,
276+
count
277+
);
278+
279+
let target_height: u64 = 500;
280+
281+
let _ = node.client
282+
.prune_blockchain(target_height)
283+
.expect("pruneblockchain RPC call failed");
284+
}

node/src/versions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// An explicit version of Bitcoin Core must be selected by enabling some feature.
22
// We check this here instead of in `lib.rs` because this file is included in `build.rs`.
33
#[cfg(all(
4-
not(feature = "28_0"),
4+
feature = "28_0",
55
not(feature = "27_2"),
66
not(feature = "27_1"),
77
not(feature = "27_0"),

types/src/model/blockchain.rs

+4
Original file line numberDiff line numberDiff line change
@@ -486,3 +486,7 @@ pub struct GetTxOutSetInfo {
486486
/// Models the result of JSON-RPC method `verifytxoutproof`.
487487
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
488488
pub struct VerifyTxOutProof(pub Vec<Txid>);
489+
490+
/// Models the result of JSON-RPC method `pruneblockchain`.
491+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
492+
pub struct PruneBlockchain(pub u32);

types/src/model/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub use self::{
2727
GetBlockchainInfo, GetChainTips, GetChainTxStats, GetDifficulty, GetMempoolAncestors,
2828
GetMempoolAncestorsVerbose, GetMempoolDescendants, GetMempoolDescendantsVerbose,
2929
GetMempoolEntry, GetMempoolInfo, GetRawMempool, GetRawMempoolVerbose, GetTxOut,
30-
GetTxOutSetInfo, MempoolEntry, MempoolEntryFees, Softfork, SoftforkType, VerifyTxOutProof,
30+
GetTxOutSetInfo, MempoolEntry, MempoolEntryFees, Softfork, SoftforkType, VerifyTxOutProof, PruneBlockchain,
3131
},
3232
generating::{Generate, GenerateToAddress},
3333
mining::{

types/src/v17/blockchain/error.rs

+34
Original file line numberDiff line numberDiff line change
@@ -560,3 +560,37 @@ impl std::error::Error for GetTxOutSetInfoError {
560560
impl From<NumericError> for GetTxOutSetInfoError {
561561
fn from(e: NumericError) -> Self { Self::Numeric(e) }
562562
}
563+
564+
/// Error when converting the `PruneBlockchain` JSON type to the Model type.
565+
#[derive(Debug)]
566+
pub enum PruneBlockchainError {
567+
/// Conversion of the returned height to the expected numeric type failed.
568+
Numeric(NumericError),
569+
}
570+
571+
impl fmt::Display for PruneBlockchainError {
572+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
573+
use PruneBlockchainError::*;
574+
575+
match *self {
576+
Numeric(ref e) => write_err!(f, "numeric conversion of pruned height failed"; e),
577+
}
578+
}
579+
}
580+
581+
#[cfg(feature = "std")]
582+
impl std::error::Error for PruneBlockchainError {
583+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
584+
use PruneBlockchainError::*;
585+
586+
match *self {
587+
Numeric(ref e) => Some(e),
588+
}
589+
}
590+
}
591+
592+
impl From<NumericError> for PruneBlockchainError {
593+
fn from(e: NumericError) -> Self {
594+
Self::Numeric(e)
595+
}
596+
}

types/src/v17/blockchain/into.rs

+10
Original file line numberDiff line numberDiff line change
@@ -545,3 +545,13 @@ impl VerifyTxOutProof {
545545
Ok(model::VerifyTxOutProof(proofs))
546546
}
547547
}
548+
549+
impl PruneBlockchain {
550+
/// Converts version specific type to a version nonspecific, more strongly typed type.
551+
pub fn into_model(self) -> Result<model::PruneBlockchain, PruneBlockchainError> {
552+
// Use the helper function to convert the i64 height to u32, handling potential errors.
553+
let height = crate::to_u32(self.0, "pruned_height")?;
554+
// Wrap the u32 height in the model struct.
555+
Ok(model::PruneBlockchain(height))
556+
}
557+
}

types/src/v17/blockchain/mod.rs

+17
Original file line numberDiff line numberDiff line change
@@ -667,3 +667,20 @@ pub struct GetTxOutSetInfo {
667667
/// Inner field is the txid(s) which the proof commits to, or empty array if the proof can not be validated.
668668
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
669669
pub struct VerifyTxOutProof(pub Vec<String>);
670+
671+
672+
/// Result of JSON-RPC method `pruneblockchain`.
673+
///
674+
/// > pruneblockchain height
675+
/// >
676+
/// > Arguments:
677+
/// > 1. "height" (numeric, required) The block height to prune up to. May be set to a discrete height, or a unix timestamp
678+
/// > to prune blocks whose block time is at least 2 hours older than the provided timestamp.
679+
/// >
680+
/// > Result:
681+
/// > n (numeric) Height of the last block pruned.
682+
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
683+
pub struct PruneBlockchain(
684+
/// The height of the last block pruned.
685+
pub i64
686+
);

types/src/v17/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ pub use self::{
235235
GetRawMempool, GetRawMempoolVerbose, GetTxOut, GetTxOutError, GetTxOutSetInfo,
236236
GetTxOutSetInfoError, MapMempoolEntryError, MempoolEntry, MempoolEntryError,
237237
MempoolEntryFees, MempoolEntryFeesError, ScriptPubkey, Softfork, SoftforkReject,
238-
VerifyTxOutProof,
238+
VerifyTxOutProof, PruneBlockchain
239239
},
240240
control::{GetMemoryInfoStats, Locked, Logging},
241241
generating::{Generate, GenerateToAddress},

types/src/v28/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ pub use crate::{
280280
ListTransactionsItem, ListUnspent, ListUnspentItem, ListWallets, Locked, PeerInfo,
281281
RescanBlockchain, SendMany, SendRawTransaction, SendToAddress, SignErrorData, SignMessage,
282282
SignRawTransactionWithWallet, SoftforkReject, TransactionCategory, UploadTarget,
283-
VerifyTxOutProof, WalletCreateFundedPsbt, WalletProcessPsbt,
283+
VerifyTxOutProof, WalletCreateFundedPsbt, WalletProcessPsbt, PruneBlockchain,
284284
},
285285
v18::{ActiveCommand, GetRpcInfo},
286286
v19::{

verify/rpc-api-v17.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ gettxout "txid" n ( include_mempool )
1818
gettxoutproof ["txid",...] ( blockhash )
1919
gettxoutsetinfo
2020
preciousblock "blockhash"
21-
pruneblockchain
21+
pruneblockchain height
2222
savemempool
2323
scantxoutset <action> ( <scanobjects> )
2424
verifychain ( checklevel nblocks )
@@ -85,7 +85,7 @@ abandontransaction "txid"
8585
abortrescan
8686
addmultisigaddress nrequired ["key",...] ( "label" "address_type" )
8787
backupwallet "destination"
88-
bumpfee "txid" ( options )
88+
bumpfee "txid" ( options )
8989
createwallet "wallet_name" ( disable_private_keys )
9090
dumpprivkey "address"
9191
dumpwallet "filename"

verify/src/method/v17.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@ pub const METHODS: &[Method] = &[
2929
Method::new_string("gettxoutproof", "get_tx_out_proof"),
3030
Method::new_modeled("gettxoutsetinfo", "GetTxOutSetInfo", "get_tx_out_set_info"),
3131
Method::new_nothing("preciousblock", "precious_block"),
32-
Method::new_numeric("pruneblockchain", "prune_blockchain"),
3332
Method::new_nothing("savemempool", "save_mempool"),
3433
Method::new_modeled("scantxoutset", "ScanTxOutSet", "scan_tx_out_set"),
3534
Method::new_bool("verifychain", "verify_chain"),
3635
Method::new_modeled("verifytxoutproof", "VerifyTxOutProof", "verify_tx_out_proof"),
36+
Method::new_no_model("pruneblockchain", "PruneBlockchain", "prune_blockchain"),
37+
3738
Method::new_no_model("getmemoryinfo", "GetMemoryInfoStats", "get_memory_info"),
3839
Method::new_string("help", "help"),
3940
Method::new_no_model("logging", "Logging", "logging"),

0 commit comments

Comments
 (0)