Skip to content
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

feat(rpc): introduce getblocktemplate-rpcs feature #5357

Merged
merged 12 commits into from
Oct 19, 2022
1 change: 1 addition & 0 deletions zebra-rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ edition = "2021"
[features]
default = []
proptest-impl = ["proptest", "proptest-derive", "zebra-chain/proptest-impl", "zebra-state/proptest-impl"]
getblocktemplate-rpcs = []
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved

[dependencies]
chrono = { version = "0.4.22", default-features = false, features = ["clock", "std"] }
Expand Down
3 changes: 3 additions & 0 deletions zebra-rpc/src/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ use crate::queue::Queue;
#[cfg(test)]
mod tests;

#[cfg(feature = "getblocktemplate-rpcs")]
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
pub mod getblocktemplate;

/// The RPC error code used by `zcashd` for missing blocks.
///
/// `lightwalletd` expects error code `-8` when a block is not found:
Expand Down
44 changes: 44 additions & 0 deletions zebra-rpc/src/methods/getblocktemplate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//! RPC methods related to mining only available with `getblocktemplate-rpcs` rust feature.
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
use jsonrpc_core::{self, Error, ErrorCode, Result};
use jsonrpc_derive::rpc;
use tower::Service;

use crate::methods::{Rpc, RpcImpl};
use zebra_chain::chain_tip::ChainTip;
use zebra_node_services::{mempool, BoxError};

#[rpc(server)]
/// Additional RPC methods for mining pools.
pub trait GetBlockTemplateRpc: Rpc {
/// Add documentation
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
#[rpc(name = "getblockcount")]
fn get_block_count(&self) -> Result<u32>;
}

impl<Mempool, State, Tip> GetBlockTemplateRpc for RpcImpl<Mempool, State, Tip>
where
Mempool:
tower::Service<mempool::Request, Response = mempool::Response, Error = BoxError> + 'static,
Mempool::Future: Send,
State: Service<
zebra_state::ReadRequest,
Response = zebra_state::ReadResponse,
Error = zebra_state::BoxError,
> + Clone
+ Send
+ Sync
+ 'static,
State::Future: Send,
Tip: ChainTip + Send + Sync + 'static,
{
fn get_block_count(&self) -> Result<u32> {
self.latest_chain_tip
.best_tip_height()
.map(|height| height.0)
.ok_or(Error {
code: ErrorCode::ServerError(0),
message: "No blocks in state".to_string(),
data: None,
})
}
}
50 changes: 50 additions & 0 deletions zebra-rpc/src/methods/tests/vectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,3 +612,53 @@ async fn rpc_getaddressutxos_response() {

mempool.expect_no_requests().await;
}

#[tokio::test(flavor = "multi_thread")]
#[cfg(feature = "getblocktemplate-rpcs")]
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
async fn rpc_getblockcount() {
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
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();

// Get the height of the block at the tip using hardcoded block tip bytes.
// We want to test the RPC response is equal to this hash
let tip_block = blocks.last().unwrap();
let tip_block_hight = tip_block.coinbase_height().unwrap();
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved

// Get a mempool handle
let mut mempool: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
// Create a populated state service, the tip will be in `NUMBER_OF_BLOCKS`.
let (_state, read_state, latest_chain_tip, _chain_tip_change) =
zebra_state::populated_state(blocks.clone(), Mainnet).await;

// Init RPC
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
"RPC test",
Mainnet,
false,
Buffer::new(mempool.clone(), 1),
read_state,
latest_chain_tip,
);

use crate::methods::getblocktemplate::GetBlockTemplateRpc;

// Get the tip height using RPC method `get_block_count`
let get_block_count = rpc
.get_block_count()
.expect("We should have a GetBestBlockHash struct");
//let response_height = get_block_count;

// Check if response is equal to block 10 hash.
assert_eq!(get_block_count, tip_block_hight.0);
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved

mempool.expect_no_requests().await;

// The queue task should continue without errors or panics
let rpc_tx_queue_task_result = rpc_tx_queue_task_handle.now_or_never();
assert!(matches!(rpc_tx_queue_task_result, None));
}
11 changes: 10 additions & 1 deletion zebra-rpc/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ use crate::{
pub mod compatibility;
mod tracing_middleware;

#[cfg(feature = "getblocktemplate-rpcs")]
use crate::methods::getblocktemplate::GetBlockTemplateRpc;

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -77,7 +80,13 @@ impl RpcServer {
// Create handler compatible with V1 and V2 RPC protocols
let mut io: MetaIoHandler<(), _> =
MetaIoHandler::new(Compatibility::Both, TracingMiddleware);
io.extend_with(rpc_impl.to_delegate());
if cfg!(feature = "getblocktemplate-rpcs") {
#[cfg(feature = "getblocktemplate-rpcs")]
//io.extend_with(Rpc::to_delegate(rpc_impl));
io.extend_with(GetBlockTemplateRpc::to_delegate(rpc_impl));
} else {
io.extend_with(Rpc::to_delegate(rpc_impl));
}
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved

// If zero, automatically scale threads to the number of CPU cores
let mut parallel_cpu_threads = config.parallel_cpu_threads;
Expand Down