2a. refactor(rpc): Add the ChainTip and Network to RpcImpl (#3863)

* Add the ChainTip and Network to RpcImpl

* Add the new RpcImpl fields to the tests

* Simplify RPC version field using generics

* Temporarily allow unused struct fields
This commit is contained in:
teor 2022-03-16 08:29:15 +10:00 committed by GitHub
parent 5c62dd62cd
commit 641f488915
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 33 deletions

View File

@ -14,6 +14,8 @@ use tower::{buffer::Buffer, Service, ServiceExt};
use zebra_chain::{
block::{self, SerializedBlock},
chain_tip::ChainTip,
parameters::Network,
serialization::{SerializationError, ZcashDeserialize},
transaction::{self, Transaction},
};
@ -104,7 +106,7 @@ pub trait Rpc {
}
/// RPC method implementations.
pub struct RpcImpl<Mempool, State>
pub struct RpcImpl<Mempool, State, Tip>
where
Mempool: Service<mempool::Request, Response = mempool::Response, Error = BoxError>,
State: Service<
@ -112,16 +114,27 @@ where
Response = zebra_state::Response,
Error = zebra_state::BoxError,
>,
Tip: ChainTip,
{
/// Zebra's application version.
app_version: String,
/// A handle to the mempool service.
mempool: Buffer<Mempool, mempool::Request>,
/// A handle to the state service.
state: State,
/// Allows efficient access to the best tip of the blockchain.
#[allow(dead_code)]
latest_chain_tip: Tip,
/// The configured network for this RPC service.
#[allow(dead_code)]
network: Network,
}
impl<Mempool, State> RpcImpl<Mempool, State>
impl<Mempool, State, Tip> RpcImpl<Mempool, State, Tip>
where
Mempool: Service<mempool::Request, Response = mempool::Response, Error = BoxError>,
State: Service<
@ -129,22 +142,30 @@ where
Response = zebra_state::Response,
Error = zebra_state::BoxError,
>,
Tip: ChainTip + Send + Sync,
{
/// Create a new instance of the RPC handler.
pub fn new(
app_version: String,
pub fn new<Version>(
app_version: Version,
mempool: Buffer<Mempool, mempool::Request>,
state: State,
) -> Self {
latest_chain_tip: Tip,
network: Network,
) -> Self
where
Version: ToString,
{
RpcImpl {
app_version,
app_version: app_version.to_string(),
mempool,
state,
latest_chain_tip,
network,
}
}
}
impl<Mempool, State> Rpc for RpcImpl<Mempool, State>
impl<Mempool, State, Tip> Rpc for RpcImpl<Mempool, State, Tip>
where
Mempool:
tower::Service<mempool::Request, Response = mempool::Response, Error = BoxError> + 'static,
@ -158,6 +179,7 @@ where
+ Sync
+ 'static,
State::Future: Send,
Tip: ChainTip + Send + Sync + 'static,
{
fn get_info(&self) -> Result<GetInfo> {
let response = GetInfo {
@ -170,6 +192,8 @@ where
fn get_blockchain_info(&self) -> Result<GetBlockChainInfo> {
// TODO: dummy output data, fix in the context of #3143
// use self.latest_chain_tip.estimate_network_chain_tip_height()
// to estimate the current block height on the network
let response = GetBlockChainInfo {
chain: "TODO: main".to_string(),
};

View File

@ -1,3 +1,5 @@
//! Randomised property tests for RPC methods.
use std::collections::HashSet;
use hex::ToHex;
@ -7,6 +9,8 @@ use thiserror::Error;
use tower::buffer::Buffer;
use zebra_chain::{
chain_tip::NoChainTip,
parameters::Network::*,
serialization::{ZcashDeserialize, ZcashSerialize},
transaction::{Transaction, UnminedTx, UnminedTxId},
};
@ -27,9 +31,11 @@ proptest! {
let mut mempool = MockService::build().for_prop_tests();
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
let rpc = RpcImpl::new(
"RPC test".to_owned(),
"RPC test",
Buffer::new(mempool.clone(), 1),
Buffer::new(state.clone(), 1),
NoChainTip,
Mainnet,
);
let hash = SentTransactionHash(transaction.hash());
@ -73,9 +79,11 @@ proptest! {
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
let rpc = RpcImpl::new(
"RPC test".to_owned(),
"RPC test",
Buffer::new(mempool.clone(), 1),
Buffer::new(state.clone(), 1),
NoChainTip,
Mainnet,
);
let transaction_bytes = transaction
@ -124,9 +132,11 @@ proptest! {
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
let rpc = RpcImpl::new(
"RPC test".to_owned(),
"RPC test",
Buffer::new(mempool.clone(), 1),
Buffer::new(state.clone(), 1),
NoChainTip,
Mainnet,
);
let transaction_bytes = transaction
@ -183,9 +193,11 @@ proptest! {
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
let rpc = RpcImpl::new(
"RPC test".to_owned(),
"RPC test",
Buffer::new(mempool.clone(), 1),
Buffer::new(state.clone(), 1),
NoChainTip,
Mainnet,
);
let send_task = tokio::spawn(rpc.send_raw_transaction(non_hex_string));
@ -231,9 +243,11 @@ proptest! {
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
let rpc = RpcImpl::new(
"RPC test".to_owned(),
"RPC test",
Buffer::new(mempool.clone(), 1),
Buffer::new(state.clone(), 1),
NoChainTip,
Mainnet,
);
let send_task = tokio::spawn(rpc.send_raw_transaction(hex::encode(random_bytes)));
@ -278,9 +292,11 @@ proptest! {
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
let rpc = RpcImpl::new(
"RPC test".to_owned(),
"RPC test",
Buffer::new(mempool.clone(), 1),
Buffer::new(state.clone(), 1),
NoChainTip,
Mainnet,
);
let call_task = tokio::spawn(rpc.get_raw_mempool());

View File

@ -4,7 +4,12 @@ use std::sync::Arc;
use tower::buffer::Buffer;
use zebra_chain::{block::Block, parameters::Network, serialization::ZcashDeserializeInto};
use zebra_chain::{
block::Block,
chain_tip::NoChainTip,
parameters::Network::{self, *},
serialization::ZcashDeserializeInto,
};
use zebra_network::constants::USER_AGENT;
use zebra_node_services::BoxError;
@ -23,16 +28,18 @@ async fn rpc_getinfo() {
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
let rpc = RpcImpl::new(
"Zebra version test".to_string(),
"RPC test",
Buffer::new(mempool.clone(), 1),
Buffer::new(state.clone(), 1),
NoChainTip,
Mainnet,
);
let get_info = rpc.get_info().expect("We should have a GetInfo struct");
// make sure there is a `build` field in the response,
// and that is equal to the provided string.
assert_eq!(get_info.build, "Zebra version test");
assert_eq!(get_info.build, "RPC test");
// make sure there is a `subversion` field,
// and that is equal to the Zebra user agent.
@ -57,11 +64,13 @@ async fn rpc_getblock() {
let state = zebra_state::populated_state(blocks.clone(), Network::Mainnet).await;
// Init RPC
let rpc = RpcImpl {
app_version: "Zebra version test".to_string(),
mempool: Buffer::new(mempool.clone(), 1),
let rpc = RpcImpl::new(
"RPC test",
Buffer::new(mempool.clone(), 1),
state,
};
NoChainTip,
Mainnet,
);
// Make calls and check response
for (i, block) in blocks.into_iter().enumerate() {
@ -84,11 +93,13 @@ async fn rpc_getblock_error() {
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
// Init RPC
let rpc = RpcImpl {
app_version: "Zebra version test".to_string(),
mempool: Buffer::new(mempool.clone(), 1),
state: Buffer::new(state.clone(), 1),
};
let rpc = RpcImpl::new(
"RPC test",
Buffer::new(mempool.clone(), 1),
Buffer::new(state.clone(), 1),
NoChainTip,
Mainnet,
);
// Make sure we get an error if Zebra can't parse the block height.
assert!(rpc
@ -123,11 +134,13 @@ async fn rpc_getbestblockhash() {
let state = zebra_state::populated_state(blocks.clone(), Network::Mainnet).await;
// Init RPC
let rpc = RpcImpl {
app_version: "Zebra version test".to_string(),
mempool: Buffer::new(mempool.clone(), 1),
let rpc = RpcImpl::new(
"RPC test",
Buffer::new(mempool.clone(), 1),
state,
};
NoChainTip,
Mainnet,
);
// Get the tip hash using RPC method `get_best_block_hash`
let get_best_block_hash = rpc

View File

@ -13,6 +13,7 @@ use tower::{buffer::Buffer, Service};
use tracing::*;
use tracing_futures::Instrument;
use zebra_chain::{chain_tip::ChainTip, parameters::Network};
use zebra_node_services::{mempool, BoxError};
use crate::{
@ -29,13 +30,16 @@ pub struct RpcServer;
impl RpcServer {
/// Start a new RPC server endpoint
pub fn spawn<Mempool, State>(
pub fn spawn<Version, Mempool, State, Tip>(
config: Config,
app_version: String,
app_version: Version,
mempool: Buffer<Mempool, mempool::Request>,
state: State,
latest_chain_tip: Tip,
network: Network,
) -> tokio::task::JoinHandle<()>
where
Version: ToString,
Mempool: tower::Service<mempool::Request, Response = mempool::Response, Error = BoxError>
+ 'static,
Mempool::Future: Send,
@ -48,12 +52,13 @@ impl RpcServer {
+ Sync
+ 'static,
State::Future: Send,
Tip: ChainTip + Send + Sync + 'static,
{
if let Some(listen_addr) = config.listen_addr {
info!("Trying to open RPC endpoint at {}...", listen_addr,);
// Initialize the rpc methods with the zebra version
let rpc_impl = RpcImpl::new(app_version, mempool, state);
let rpc_impl = RpcImpl::new(app_version, mempool, state, latest_chain_tip, network);
// Create handler compatible with V1 and V2 RPC protocols
let mut io =

View File

@ -162,9 +162,11 @@ impl StartCmd {
// Launch RPC server
let rpc_task_handle = RpcServer::spawn(
config.rpc,
app_version().to_string(),
app_version(),
mempool.clone(),
read_only_state_service,
latest_chain_tip.clone(),
config.network.network,
);
let setup_data = InboundSetupData {