feat(rpc): introduce getblocktemplate rpc call with stub fields (#5462)
* introduce getblocktemplate rpc call * remove optional `longpollid` field * add underscore * create modules for types
This commit is contained in:
parent
a3302850d6
commit
fae9473076
|
@ -35,10 +35,10 @@ use zebra_state::{OutputIndex, OutputLocation, TransactionLocation};
|
|||
use crate::queue::Queue;
|
||||
|
||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||
mod get_block_template;
|
||||
mod get_block_template_rpcs;
|
||||
|
||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||
pub use get_block_template::{GetBlockTemplateRpc, GetBlockTemplateRpcImpl};
|
||||
pub use get_block_template_rpcs::{GetBlockTemplateRpc, GetBlockTemplateRpcImpl};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
@ -6,7 +6,14 @@ use jsonrpc_core::{self, BoxFuture, Error, ErrorCode, Result};
|
|||
use jsonrpc_derive::rpc;
|
||||
use tower::{Service, ServiceExt};
|
||||
|
||||
use crate::methods::{GetBlockHash, MISSING_BLOCK_ERROR_CODE};
|
||||
pub(crate) mod types;
|
||||
|
||||
use crate::methods::{
|
||||
get_block_template_rpcs::types::{
|
||||
coinbase::Coinbase, default_roots::DefaultRoots, get_block_template::GetBlockTemplate,
|
||||
},
|
||||
GetBlockHash, MISSING_BLOCK_ERROR_CODE,
|
||||
};
|
||||
|
||||
/// getblocktemplate RPC method signatures.
|
||||
#[rpc(server)]
|
||||
|
@ -35,8 +42,19 @@ pub trait GetBlockTemplateRpc {
|
|||
///
|
||||
/// - If `index` is positive then index = block height.
|
||||
/// - If `index` is negative then -1 is the last known valid block.
|
||||
/// - This rpc method is available only if zebra is built with `--features getblocktemplate-rpcs`.
|
||||
#[rpc(name = "getblockhash")]
|
||||
fn get_block_hash(&self, index: i32) -> BoxFuture<Result<GetBlockHash>>;
|
||||
|
||||
/// Documentation to be filled as we go.
|
||||
///
|
||||
/// zcashd reference: [`getblocktemplate`](https://zcash-rpc.github.io/getblocktemplate.html)
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// - This rpc method is available only if zebra is built with `--features getblocktemplate-rpcs`.
|
||||
#[rpc(name = "getblocktemplate")]
|
||||
fn get_block_template(&self) -> BoxFuture<Result<GetBlockTemplate>>;
|
||||
}
|
||||
|
||||
/// RPC method implementations.
|
||||
|
@ -139,6 +157,40 @@ where
|
|||
}
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn get_block_template(&self) -> BoxFuture<Result<GetBlockTemplate>> {
|
||||
async move {
|
||||
let empty_string = String::from("");
|
||||
|
||||
// Returns empty `GetBlockTemplate`
|
||||
Ok(GetBlockTemplate {
|
||||
capabilities: vec![],
|
||||
version: 0,
|
||||
previous_block_hash: empty_string.clone(),
|
||||
block_commitments_hash: empty_string.clone(),
|
||||
light_client_root_hash: empty_string.clone(),
|
||||
final_sapling_root_hash: empty_string.clone(),
|
||||
default_roots: DefaultRoots {
|
||||
merkle_root: empty_string.clone(),
|
||||
chain_history_root: empty_string.clone(),
|
||||
auth_data_root: empty_string.clone(),
|
||||
block_commitments_hash: empty_string.clone(),
|
||||
},
|
||||
transactions: vec![],
|
||||
coinbase_txn: Coinbase {},
|
||||
target: empty_string.clone(),
|
||||
min_time: 0,
|
||||
mutable: vec![],
|
||||
nonce_range: empty_string.clone(),
|
||||
sigop_limit: 0,
|
||||
size_limit: 0,
|
||||
cur_time: 0,
|
||||
bits: empty_string,
|
||||
height: 0,
|
||||
})
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a potentially negative index, find the corresponding `Height`.
|
|
@ -0,0 +1,6 @@
|
|||
//! Types used in mining RPC methods.
|
||||
|
||||
pub(crate) mod coinbase;
|
||||
pub(crate) mod default_roots;
|
||||
pub(crate) mod get_block_template;
|
||||
pub(crate) mod transaction;
|
|
@ -0,0 +1,5 @@
|
|||
//! The `Coinbase` type is part of the `getblocktemplate` RPC method output.
|
||||
|
||||
/// documentation and fields to be added in #5453.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Coinbase {}
|
|
@ -0,0 +1,18 @@
|
|||
//! The `DefaultRoots` type is part of the `getblocktemplate` RPC method output.
|
||||
|
||||
/// Documentation to be added in #5452 or #5455.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct DefaultRoots {
|
||||
/// Add documentation.
|
||||
#[serde(rename = "merkleroot")]
|
||||
pub merkle_root: String,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "chainhistoryroot")]
|
||||
pub chain_history_root: String,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "authdataroot")]
|
||||
pub auth_data_root: String,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "blockcommitmentshash")]
|
||||
pub block_commitments_hash: String,
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
//! The `GetBlockTempate` type is the output of the `getblocktemplate` RPC method.
|
||||
|
||||
use crate::methods::get_block_template_rpcs::types::{
|
||||
coinbase::Coinbase, default_roots::DefaultRoots, transaction::Transaction,
|
||||
};
|
||||
|
||||
/// Documentation to be added after we document all the individual fields.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct GetBlockTemplate {
|
||||
/// Add documentation.
|
||||
pub capabilities: Vec<String>,
|
||||
/// Add documentation.
|
||||
pub version: usize,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "previousblockhash")]
|
||||
pub previous_block_hash: String,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "blockcommitmentshash")]
|
||||
pub block_commitments_hash: String,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "lightclientroothash")]
|
||||
pub light_client_root_hash: String,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "finalsaplingroothash")]
|
||||
pub final_sapling_root_hash: String,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "defaultroots")]
|
||||
pub default_roots: DefaultRoots,
|
||||
/// Add documentation.
|
||||
pub transactions: Vec<Transaction>,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "coinbasetxn")]
|
||||
pub coinbase_txn: Coinbase,
|
||||
/// Add documentation.
|
||||
pub target: String,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "mintime")]
|
||||
pub min_time: u32,
|
||||
/// Add documentation.
|
||||
pub mutable: Vec<String>,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "noncerange")]
|
||||
pub nonce_range: String,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "sigoplimit")]
|
||||
pub sigop_limit: u32,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "sizelimit")]
|
||||
pub size_limit: u32,
|
||||
/// Add documentation.
|
||||
#[serde(rename = "curtime")]
|
||||
pub cur_time: u32,
|
||||
/// Add documentation.
|
||||
pub bits: String,
|
||||
/// Add documentation.
|
||||
pub height: u32,
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
//! The `Transaction` type is part of the `getblocktemplate` RPC method output.
|
||||
|
||||
/// Documentation and fields to be added in #5454.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Transaction {}
|
|
@ -191,6 +191,13 @@ async fn test_rpc_response_data_for_network(network: Network) {
|
|||
.expect("We should have a GetBlockHash struct");
|
||||
|
||||
snapshot_rpc_getblockhash(get_block_hash, &settings);
|
||||
|
||||
// `getblocktemplate`
|
||||
let get_block_template = get_block_template_rpc
|
||||
.get_block_template()
|
||||
.await
|
||||
.expect("We should have a GetBlockTemplate struct");
|
||||
snapshot_rpc_getblocktemplate(get_block_template, &settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,6 +299,15 @@ fn snapshot_rpc_getblockhash(block_hash: GetBlockHash, settings: &insta::Setting
|
|||
settings.bind(|| insta::assert_json_snapshot!("get_block_hash", block_hash));
|
||||
}
|
||||
|
||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||
/// Snapshot `getblocktemplate` response, using `cargo insta` and JSON serialization.
|
||||
fn snapshot_rpc_getblocktemplate(
|
||||
block_template: crate::methods::get_block_template_rpcs::types::get_block_template::GetBlockTemplate,
|
||||
settings: &insta::Settings,
|
||||
) {
|
||||
settings.bind(|| insta::assert_json_snapshot!("get_block_template", block_template));
|
||||
}
|
||||
|
||||
/// Utility function to convert a `Network` to a lowercase string.
|
||||
fn network_string(network: Network) -> String {
|
||||
let mut net_suffix = network.to_string();
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
source: zebra-rpc/src/methods/tests/snapshot.rs
|
||||
assertion_line: 308
|
||||
expression: block_template
|
||||
---
|
||||
{
|
||||
"capabilities": [],
|
||||
"version": 0,
|
||||
"previousblockhash": "",
|
||||
"blockcommitmentshash": "",
|
||||
"lightclientroothash": "",
|
||||
"finalsaplingroothash": "",
|
||||
"defaultroots": {
|
||||
"merkleroot": "",
|
||||
"chainhistoryroot": "",
|
||||
"authdataroot": "",
|
||||
"blockcommitmentshash": ""
|
||||
},
|
||||
"transactions": [],
|
||||
"coinbasetxn": {},
|
||||
"target": "",
|
||||
"mintime": 0,
|
||||
"mutable": [],
|
||||
"noncerange": "",
|
||||
"sigoplimit": 0,
|
||||
"sizelimit": 0,
|
||||
"curtime": 0,
|
||||
"bits": "",
|
||||
"height": 0
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
source: zebra-rpc/src/methods/tests/snapshot.rs
|
||||
assertion_line: 308
|
||||
expression: block_template
|
||||
---
|
||||
{
|
||||
"capabilities": [],
|
||||
"version": 0,
|
||||
"previousblockhash": "",
|
||||
"blockcommitmentshash": "",
|
||||
"lightclientroothash": "",
|
||||
"finalsaplingroothash": "",
|
||||
"defaultroots": {
|
||||
"merkleroot": "",
|
||||
"chainhistoryroot": "",
|
||||
"authdataroot": "",
|
||||
"blockcommitmentshash": ""
|
||||
},
|
||||
"transactions": [],
|
||||
"coinbasetxn": {},
|
||||
"target": "",
|
||||
"mintime": 0,
|
||||
"mutable": [],
|
||||
"noncerange": "",
|
||||
"sigoplimit": 0,
|
||||
"sizelimit": 0,
|
||||
"curtime": 0,
|
||||
"bits": "",
|
||||
"height": 0
|
||||
}
|
|
@ -647,7 +647,7 @@ async fn rpc_getblockcount() {
|
|||
|
||||
// Init RPC
|
||||
let get_block_template_rpc =
|
||||
get_block_template::GetBlockTemplateRpcImpl::new(latest_chain_tip.clone(), read_state);
|
||||
get_block_template_rpcs::GetBlockTemplateRpcImpl::new(latest_chain_tip.clone(), read_state);
|
||||
|
||||
// Get the tip height using RPC method `get_block_count`
|
||||
let get_block_count = get_block_template_rpc
|
||||
|
@ -686,7 +686,7 @@ async fn rpc_getblockcount_empty_state() {
|
|||
);
|
||||
|
||||
let get_block_template_rpc =
|
||||
get_block_template::GetBlockTemplateRpcImpl::new(latest_chain_tip.clone(), read_state);
|
||||
get_block_template_rpcs::GetBlockTemplateRpcImpl::new(latest_chain_tip.clone(), read_state);
|
||||
|
||||
// Get the tip height using RPC method `get_block_count
|
||||
let get_block_count = get_block_template_rpc.get_block_count();
|
||||
|
@ -730,7 +730,7 @@ async fn rpc_getblockhash() {
|
|||
latest_chain_tip.clone(),
|
||||
);
|
||||
let get_block_template_rpc =
|
||||
get_block_template::GetBlockTemplateRpcImpl::new(latest_chain_tip, read_state);
|
||||
get_block_template_rpcs::GetBlockTemplateRpcImpl::new(latest_chain_tip, read_state);
|
||||
|
||||
// Query the hashes using positive indexes
|
||||
for (i, block) in blocks.iter().enumerate() {
|
||||
|
@ -757,3 +757,70 @@ async fn rpc_getblockhash() {
|
|||
|
||||
mempool.expect_no_requests().await;
|
||||
}
|
||||
|
||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn rpc_getblocktemplate() {
|
||||
let _init_guard = zebra_test::init();
|
||||
|
||||
// Create a continuous chain of mainnet blocks from genesis
|
||||
let blocks: Vec<Arc<Block>> = zebra_test::vectors::CONTINUOUS_MAINNET_BLOCKS
|
||||
.iter()
|
||||
.map(|(_height, block_bytes)| block_bytes.zcash_deserialize_into().unwrap())
|
||||
.collect();
|
||||
|
||||
let mut mempool: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
|
||||
// Create a populated state service
|
||||
let (_state, read_state, latest_chain_tip, _chain_tip_change) =
|
||||
zebra_state::populated_state(blocks.clone(), Mainnet).await;
|
||||
|
||||
// Init RPCs
|
||||
let _rpc = RpcImpl::new(
|
||||
"RPC test",
|
||||
Mainnet,
|
||||
false,
|
||||
Buffer::new(mempool.clone(), 1),
|
||||
Buffer::new(read_state.clone(), 1),
|
||||
latest_chain_tip.clone(),
|
||||
);
|
||||
let get_block_template_rpc =
|
||||
get_block_template_rpcs::GetBlockTemplateRpcImpl::new(latest_chain_tip, read_state);
|
||||
|
||||
let get_block_template = get_block_template_rpc
|
||||
.get_block_template()
|
||||
.await
|
||||
.expect("We should have a GetBlockTemplate struct");
|
||||
|
||||
assert!(get_block_template.capabilities.is_empty());
|
||||
assert_eq!(get_block_template.version, 0);
|
||||
assert!(get_block_template.previous_block_hash.is_empty());
|
||||
assert!(get_block_template.block_commitments_hash.is_empty());
|
||||
assert!(get_block_template.light_client_root_hash.is_empty());
|
||||
assert!(get_block_template.final_sapling_root_hash.is_empty());
|
||||
assert!(get_block_template.default_roots.merkle_root.is_empty());
|
||||
assert!(get_block_template
|
||||
.default_roots
|
||||
.chain_history_root
|
||||
.is_empty());
|
||||
assert!(get_block_template.default_roots.auth_data_root.is_empty());
|
||||
assert!(get_block_template
|
||||
.default_roots
|
||||
.block_commitments_hash
|
||||
.is_empty());
|
||||
assert!(get_block_template.transactions.is_empty());
|
||||
assert_eq!(
|
||||
get_block_template.coinbase_txn,
|
||||
get_block_template_rpcs::types::coinbase::Coinbase {}
|
||||
);
|
||||
assert!(get_block_template.target.is_empty());
|
||||
assert_eq!(get_block_template.min_time, 0);
|
||||
assert!(get_block_template.mutable.is_empty());
|
||||
assert!(get_block_template.nonce_range.is_empty());
|
||||
assert_eq!(get_block_template.sigop_limit, 0);
|
||||
assert_eq!(get_block_template.size_limit, 0);
|
||||
assert_eq!(get_block_template.cur_time, 0);
|
||||
assert!(get_block_template.bits.is_empty());
|
||||
assert_eq!(get_block_template.height, 0);
|
||||
|
||||
mempool.expect_no_requests().await;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue