Skip to content

Conversation

@tvpeter
Copy link
Collaborator

@tvpeter tvpeter commented Nov 18, 2025

Description

This PR adds the following methods for versions 28, 29, and 30 of bitcoind:

  • getblock

  • getblockverbose

  • getblockcount

  • getblockhash

  • getblockfilter

  • getblockheader

  • getrawmempool

  • getrawtransaction

  • also updates corepc-types to v0.11.0

Fixes #4

Depends on #3

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature
  • [] I've updated CHANGELOG.md

@oleonardolima oleonardolima self-requested a review November 19, 2025 17:38
@oleonardolima oleonardolima added the enhancement New feature or request label Nov 19, 2025
@tvpeter tvpeter force-pushed the feat/blockchain-rpc-methods branch 2 times, most recently from 6543635 to 3a16fa4 Compare November 25, 2025 05:22
Copy link
Collaborator

@ValuedMammal ValuedMammal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So far I agree with the way you've defined the client methods. I mainly focused on reviewing the implementation of the client code, and haven't spent as much time looking at the test code yet.

By convention, the commits should appear as type(module): Summary, for example

3a16fa4 test: Add integration tests
6f95a7f feat(client): Add blockchain methods

Other notes:

  • Going forward try to have more descriptive API docs
  • We should look into testing the client using corepc_node to minimize the amount of manual testing needed and so we can run the integration tests in CI.

src/client.rs Outdated
Comment on lines 118 to 123
let bytes: Vec<u8> = Vec::<u8>::from_hex(&hex_string).map_err(Error::HexToBytes)?;

let block: Block = deserialize(&bytes)
.map_err(|e| Error::InvalidResponse(format!("failed to deserialize block: {e}")))?;

Ok(block)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For things that can be consensus decoded directly from a hex string, like Block, Header, and Transaction, I think it will be easier to use deserialize_hex and have a new Error::DecodeHex error that wraps the FromHexError.

Suggested change
let bytes: Vec<u8> = Vec::<u8>::from_hex(&hex_string).map_err(Error::HexToBytes)?;
let block: Block = deserialize(&bytes)
.map_err(|e| Error::InvalidResponse(format!("failed to deserialize block: {e}")))?;
Ok(block)
bitcoin::consensus::encode::deserialize_hex(&hex_string).map_err(Error::DecodeHex)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency I would apply the same suggestion to get_block_header and get_raw_transaction.

src/client.rs Outdated
Comment on lines 127 to 158
pub fn get_block_verbose(&self, block_hash: &BlockHash) -> Result<GetBlockVerboseOne, Error> {
let res: GetBlockVerboseOne = self.call("getblock", &[json!(block_hash), json!(1)])?;
Ok(res)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume we first want to deserialize the response as a type from corepc_types (e.g. v29::GetBlockVerboseOne), and then call into_model on it. Also we'll need a test for it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, but the getblock RPC with verbosity 1 returns a JSON object that deserializes directly into GetBlockVerboseOne here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should return the model type corepc_types::model::GetBlockVerboseOne by calling into_model.

@tvpeter tvpeter force-pushed the feat/blockchain-rpc-methods branch 2 times, most recently from 3632601 to 685e258 Compare December 10, 2025 17:16
@tvpeter tvpeter force-pushed the feat/blockchain-rpc-methods branch from c5f1106 to 61599ad Compare December 11, 2025 14:06
@tvpeter tvpeter requested a review from ValuedMammal December 11, 2025 14:10
- getblockcount
- getblockhash
- getblockfilter
- getblockheader
- getrawmempool
- getrawtransaction
- add integration tests for blockchain methods
src/client.rs Outdated
///
/// # Returns
/// The block count as a `u64`
pub fn get_block_count(&self) -> Result<u64, Error> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should return a u32, as it is typically how height is represented.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Can you add a newline after the doc headings?

/// # Returns
///
/// The block count as a `u64`.

@ValuedMammal
Copy link
Collaborator

ValuedMammal commented Dec 12, 2025

I can work on testing Core v28.

Edit: tvpeter#1.

@tvpeter
Copy link
Collaborator Author

tvpeter commented Dec 12, 2025

I can work on testing Core v28.

Alright, that's fine👍. Thank you

@tvpeter tvpeter force-pushed the feat/blockchain-rpc-methods branch from 61599ad to bb3f1b1 Compare December 13, 2025 09:47
- update `corepc-types` to v0.11.0 to support
Bitcoind v30
@tvpeter tvpeter force-pushed the feat/blockchain-rpc-methods branch from bb3f1b1 to b0731c1 Compare December 13, 2025 09:59
@ValuedMammal
Copy link
Collaborator

To consider this ready to merge I would want to check Client compatibility with the 3 latest versions of Bitcoin Core, I think we should tackle #19 as well, and it would be great to have a draft PR on bdk_bitcoind_rpc using the new Client struct.

@tvpeter tvpeter force-pushed the feat/blockchain-rpc-methods branch from cbbedbe to 0778704 Compare December 18, 2025 07:34
@oleonardolima oleonardolima moved this to Needs Review in BDK Chain Dec 19, 2025
Copy link
Collaborator

@oleonardolima oleonardolima left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cACK 6a38a71

I did a first round of review in this one, I reviewed commit by commit, so some comments might not apply as they were addressed in other commits. However, I didn't tested it yet.

Overall, I'd like to mention my comment about the verbose options, I don't those are necessary w.r.t to bdk_bitcoind_rpc usage as we don't use those AFAICT.

I think most of the methods could just be a one-line fn call, it's just decoding/deserializing it either by accessing a specific field or calling .into_model(), but that's my personal taste.

About the method's documentation, you could update it to link it to the types (e.g [Header]).

About the tests, do you plan to integrate the usage of corepc_node for it in this PR, or in a follow-up one ?

src/client.rs Outdated
Comment on lines 125 to 129
/// Get block verboseone
pub fn get_block_verbose(&self, block_hash: &BlockHash) -> Result<GetBlockVerboseOne, Error> {
let res: GetBlockVerboseOne = self.call("getblock", &[json!(block_hash), json!(1)])?;
Ok(res)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to have support for getblock with the verbose flag? I don't see it being used by bdk_bitcoind_rpc.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the same as get_block_info that is used by the Emitter.

src/client.rs Outdated
Comment on lines 131 to 135
/// Get best block hash
pub fn get_best_block_hash(&self) -> Result<BlockHash, Error> {
let res: String = self.call("getbestblockhash", &[])?;
Ok(res.parse()?)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, I don't think we need to support it.

src/client.rs Outdated
Comment on lines 174 to 178
let bytes = Vec::<u8>::from_hex(&hex_string).map_err(Error::HexToBytes)?;

let header = deserialize(&bytes).map_err(|e| {
Error::InvalidResponse(format!("failed to deserialize block header: {e}"))
})?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you actually need to convert it to bytes and then deserialize it? Can't we use the consensus encode/decode from rust-bitcoin directly to the hex response?

src/client.rs Outdated
Comment on lines 193 to 197
let bytes = Vec::<u8>::from_hex(&hex_string).map_err(Error::HexToBytes)?;

let transaction = deserialize(&bytes).map_err(|e| {
Error::InvalidResponse(format!("transaction deserialization failed: {e}"))
})?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, can't the same be accomplished directly through rust-bitcoin consensus encode/decode?

src/client.rs Outdated
Comment on lines 140 to 141
let block_string: String = self.call("getblock", &[json!(block_hash), json!(0)])?;
let block = deserialize_hex(&block_string)?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The returned type still a hex, having it named as block_hex would be better IMHO.

src/client.rs Outdated
let res: String = self.call("getbestblockhash", &[])?;
Ok(res.parse()?)
let best_block_hash: String = self.call("getbestblockhash", &[])?;
Ok(best_block_hash.parse()?)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the .parse() uses the rust-bitcoin consensus encode/decode in the background ? 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it doesn't. Rust-bitcoin implements the FromStr trait for BlockHash making .parse() method available (as it is available on any type that implements the trait). It is preferred for handling endianness representations

src/client.rs Outdated
Comment on lines 153 to 157
let block: corepc_types::v30::GetBlockVerboseOne =
self.call("getblock", &[json!(block_hash), json!(1)])?;
Ok(block_verbose_one)
let block_model = block.into_model()?;

Ok(block_model)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think you can do it all in a one-liner.

src/client.rs Outdated
Comment on lines 174 to 177
let block_count: GetBlockCount = self.call("getblockcount", &[])?;
let block_count_u64 = block_count.0;
let block_count_u32 = block_count_u64.try_into()?;
Ok(block_count_u32)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Same here, you can probably do it in a one-liner. Also, are we properly mapping the conversion error to a different error variant?, Now I saw the new error variant.

src/client.rs Outdated
Comment on lines 223 to 224
let txids: GetRawMempool = self.call("getrawmempool", &[])?;
Ok(txids.0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have an .into_model() for this one that would return a Vec already ? Also, can be a one-liner.

src/client.rs Outdated
Comment on lines 9 to 10
#[cfg(not(feature = "29_0"))]
use corepc_types::v30::GetBlockFilter;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we can import the type directly on the method scope, as it's being done for the other ones.

@tvpeter
Copy link
Collaborator Author

tvpeter commented Dec 19, 2025

About the tests, do you plan to integrate the usage of corepc_node for it in this PR, or in a follow-up one ?

yes, the corepc_node will be part of this PR.

Those comments that are not already addressed will be addressed in the next push.
Thank you.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this v29 module. The GetBlockFilter type is the same since v19.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You were right. They returned the same thing when I tested against v29 and v30.

src/client.rs Outdated
///
/// The `GetBlockFilter` structure containing the filter data
#[cfg(not(feature = "29_0"))]
pub fn get_block_filter(&self, block_hash: &BlockHash) -> Result<v30::GetBlockFilter, Error> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this should return the model type.

Comment on lines +404 to +406
Err(_) => {
println!("Block filters not enabled (requires -blockfilterindex=1)");
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because you're dropping the error, we don't know if it's caused by a misconfigured bitcoind or a faulty client implementation. If it's an error here the test should probably just fail.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will clarify whether there is a need for the v29 module, as it did not return any filter even after enabling it in the config when I tested on the v29 node until I specifically imported v29::GetBlockFilter

/// The verbose header as a `GetBlockHeaderVerbose` struct.
pub fn get_block_header_verbose(
&self,
hash: &BlockHash,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
hash: &BlockHash,
block_hash: &BlockHash,

To stay consistent with the arguments in the docs. Same suggestion for all *_verbose methods. This was originally my mistake, sorry about that.

@tvpeter tvpeter force-pushed the feat/blockchain-rpc-methods branch from c036a8d to 17266ca Compare December 21, 2025 04:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Needs Review

Development

Successfully merging this pull request may close these issues.

Add RPC Blockchain methods for Core v28, v29 and v30

3 participants