-
Notifications
You must be signed in to change notification settings - Fork 4
Add Blockchain RPC methods #5
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
base: master
Are you sure you want to change the base?
Conversation
6543635 to
3a16fa4
Compare
ValuedMammal
left a comment
There was a problem hiding this 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_nodeto minimize the amount of manual testing needed and so we can run the integration tests in CI.
src/client.rs
Outdated
| 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) |
There was a problem hiding this comment.
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.
| 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) | |
There was a problem hiding this comment.
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
| 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) | ||
| } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
3632601 to
685e258
Compare
c5f1106 to
61599ad
Compare
- 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> { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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`.
|
I can work on testing Core Edit: tvpeter#1. |
Alright, that's fine👍. Thank you |
61599ad to
bb3f1b1
Compare
- update `corepc-types` to v0.11.0 to support Bitcoind v30
bb3f1b1 to
b0731c1
Compare
|
To consider this ready to merge I would want to check |
cbbedbe to
0778704
Compare
oleonardolima
left a comment
There was a problem hiding this 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
| /// 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) | ||
| } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
| /// Get best block hash | ||
| pub fn get_best_block_hash(&self) -> Result<BlockHash, Error> { | ||
| let res: String = self.call("getbestblockhash", &[])?; | ||
| Ok(res.parse()?) | ||
| } |
There was a problem hiding this comment.
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
| 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}")) | ||
| })?; |
There was a problem hiding this comment.
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
| 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}")) | ||
| })?; |
There was a problem hiding this comment.
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
| let block_string: String = self.call("getblock", &[json!(block_hash), json!(0)])?; | ||
| let block = deserialize_hex(&block_string)?; |
There was a problem hiding this comment.
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()?) |
There was a problem hiding this comment.
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 ? 🤔
There was a problem hiding this comment.
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
| 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) |
There was a problem hiding this comment.
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
| 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) |
There was a problem hiding this comment.
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
| let txids: GetRawMempool = self.call("getrawmempool", &[])?; | ||
| Ok(txids.0) |
There was a problem hiding this comment.
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
| #[cfg(not(feature = "29_0"))] | ||
| use corepc_types::v30::GetBlockFilter; |
There was a problem hiding this comment.
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.
yes, the corepc_node will be part of this PR. Those comments that are not already addressed will be addressed in the next push. |
src/client/v29.rs
Outdated
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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> { |
There was a problem hiding this comment.
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.
| Err(_) => { | ||
| println!("Block filters not enabled (requires -blockfilterindex=1)"); | ||
| } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
src/client/v28.rs
Outdated
| /// The verbose header as a `GetBlockHeaderVerbose` struct. | ||
| pub fn get_block_header_verbose( | ||
| &self, | ||
| hash: &BlockHash, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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.
- refactor methods
c036a8d to
17266ca
Compare
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-typesto v0.11.0Fixes #4
Depends on #3
Checklists
All Submissions:
cargo fmtandcargo clippybefore committingNew Features:
CHANGELOG.md