change(utils): Add a direct connection mode to zebra-checkpoints (#6516)
* Rename variables so it's clearer what they do * Fully document zebra-checkpoints arguments * Remove some outdated references to zcashd * Add a json-conversion feature for converting JSON to valid Heights * Simplify zebra-checkpoints code using conversion methods * Track the last checkpoint height rather than the height gap * Move all the CLI-specific code into a single function * Remove cfg(feature) from the test RPC client API * Move the RpcRequestClient into zebra-node-services * Fix the case of RpcRequestClient * Add transport and addr arguments to zebra-checkpoints * Make zebra-checkpoints support both CLI and direct JSON-RPC connections * Fix RpcRequestClient compilation * Add a suggestion for zcashd authentication failures * Document required features * Handle differences in CLI & direct parameter and response formats * Replace a custom function with an existing dependency function * Add a checkpoint list test for minimum height gaps
This commit is contained in:
parent
a1b3246d0d
commit
d3ce022ecc
10
Cargo.lock
10
Cargo.lock
|
@ -5924,6 +5924,7 @@ dependencies = [
|
|||
"itertools",
|
||||
"jubjub 0.10.0",
|
||||
"lazy_static",
|
||||
"num-integer",
|
||||
"orchard 0.4.0",
|
||||
"primitive-types",
|
||||
"proptest",
|
||||
|
@ -5938,6 +5939,7 @@ dependencies = [
|
|||
"secp256k1",
|
||||
"serde",
|
||||
"serde-big-array",
|
||||
"serde_json",
|
||||
"serde_with 2.3.2",
|
||||
"sha2 0.9.9",
|
||||
"spandoc",
|
||||
|
@ -5982,6 +5984,7 @@ dependencies = [
|
|||
"jubjub 0.10.0",
|
||||
"lazy_static",
|
||||
"metrics",
|
||||
"num-integer",
|
||||
"once_cell",
|
||||
"orchard 0.4.0",
|
||||
"proptest",
|
||||
|
@ -6049,6 +6052,11 @@ dependencies = [
|
|||
name = "zebra-node-services"
|
||||
version = "1.0.0-beta.23"
|
||||
dependencies = [
|
||||
"color-eyre",
|
||||
"jsonrpc-core",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"zebra-chain",
|
||||
]
|
||||
|
||||
|
@ -6170,6 +6178,7 @@ version = "1.0.0-beta.23"
|
|||
dependencies = [
|
||||
"color-eyre",
|
||||
"hex",
|
||||
"itertools",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"serde_json",
|
||||
|
@ -6217,7 +6226,6 @@ dependencies = [
|
|||
"rand 0.8.5",
|
||||
"rayon",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"semver 1.0.17",
|
||||
"sentry",
|
||||
"serde",
|
||||
|
|
|
@ -12,6 +12,11 @@ default = []
|
|||
|
||||
# Production features that activate extra functionality
|
||||
|
||||
# Consensus-critical conversion from JSON to Zcash types
|
||||
json-conversion = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
# Experimental mining RPC support
|
||||
getblocktemplate-rpcs = [
|
||||
"zcash_address",
|
||||
|
@ -45,6 +50,7 @@ group = "0.13.0"
|
|||
incrementalmerkletree = "0.3.1"
|
||||
jubjub = "0.10.0"
|
||||
lazy_static = "1.4.0"
|
||||
num-integer = "0.1.45"
|
||||
primitive-types = "0.11.1"
|
||||
rand_core = "0.6.4"
|
||||
ripemd = "0.1.3"
|
||||
|
@ -88,6 +94,9 @@ ed25519-zebra = "3.1.0"
|
|||
redjubjub = "0.7.0"
|
||||
reddsa = "0.5.0"
|
||||
|
||||
# Production feature json-conversion
|
||||
serde_json = { version = "1.0.95", optional = true }
|
||||
|
||||
# Experimental feature getblocktemplate-rpcs
|
||||
zcash_address = { version = "0.2.1", optional = true }
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ pub use commitment::{
|
|||
};
|
||||
pub use hash::Hash;
|
||||
pub use header::{BlockTimeError, CountedHeader, Header, ZCASH_BLOCK_VERSION};
|
||||
pub use height::{Height, HeightDiff};
|
||||
pub use height::{Height, HeightDiff, TryIntoHeight};
|
||||
pub use serialize::{SerializedBlock, MAX_BLOCK_BYTES};
|
||||
|
||||
#[cfg(any(test, feature = "proptest-impl"))]
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
use std::ops::{Add, Sub};
|
||||
|
||||
use crate::serialization::SerializationError;
|
||||
use crate::{serialization::SerializationError, BoxError};
|
||||
|
||||
#[cfg(feature = "json-conversion")]
|
||||
pub mod json_conversion;
|
||||
|
||||
/// The length of the chain back to the genesis block.
|
||||
///
|
||||
|
@ -70,6 +73,9 @@ impl Height {
|
|||
/// even if they are outside the valid height range (for example, in buggy RPC code).
|
||||
pub type HeightDiff = i64;
|
||||
|
||||
// We don't implement TryFrom<u64>, because it causes type inference issues for integer constants.
|
||||
// Instead, use 1u64.try_into_height().
|
||||
|
||||
impl TryFrom<u32> for Height {
|
||||
type Error = &'static str;
|
||||
|
||||
|
@ -84,6 +90,47 @@ impl TryFrom<u32> for Height {
|
|||
}
|
||||
}
|
||||
|
||||
/// Convenience trait for converting a type into a valid Zcash [`Height`].
|
||||
pub trait TryIntoHeight {
|
||||
/// The error type returned by [`Height`] conversion failures.
|
||||
type Error;
|
||||
|
||||
/// Convert `self` to a `Height`, if possible.
|
||||
fn try_into_height(&self) -> Result<Height, Self::Error>;
|
||||
}
|
||||
|
||||
impl TryIntoHeight for u64 {
|
||||
type Error = BoxError;
|
||||
|
||||
fn try_into_height(&self) -> Result<Height, Self::Error> {
|
||||
u32::try_from(*self)?.try_into().map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryIntoHeight for usize {
|
||||
type Error = BoxError;
|
||||
|
||||
fn try_into_height(&self) -> Result<Height, Self::Error> {
|
||||
u32::try_from(*self)?.try_into().map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryIntoHeight for str {
|
||||
type Error = BoxError;
|
||||
|
||||
fn try_into_height(&self) -> Result<Height, Self::Error> {
|
||||
self.parse().map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryIntoHeight for String {
|
||||
type Error = BoxError;
|
||||
|
||||
fn try_into_height(&self) -> Result<Height, Self::Error> {
|
||||
self.as_str().try_into_height()
|
||||
}
|
||||
}
|
||||
|
||||
// We don't implement Add<u32> or Sub<u32>, because they cause type inference issues for integer constants.
|
||||
|
||||
impl Sub<Height> for Height {
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
//! Consensus-critical conversion from JSON [`Value`] to [`Height`].
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::BoxError;
|
||||
|
||||
use super::{Height, TryIntoHeight};
|
||||
|
||||
impl TryIntoHeight for Value {
|
||||
type Error = BoxError;
|
||||
|
||||
fn try_into_height(&self) -> Result<Height, Self::Error> {
|
||||
if self.is_number() {
|
||||
let height = self.as_u64().ok_or("JSON value outside u64 range")?;
|
||||
return height.try_into_height();
|
||||
}
|
||||
|
||||
if let Some(height) = self.as_str() {
|
||||
return height.try_into_height();
|
||||
}
|
||||
|
||||
Err("JSON value must be a number or string".into())
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
use std::cmp::max;
|
||||
|
||||
use num_integer::div_ceil;
|
||||
|
||||
use crate::{
|
||||
amount::{Amount, NonNegative},
|
||||
block::MAX_BLOCK_BYTES,
|
||||
|
@ -137,19 +139,3 @@ fn conventional_actions(transaction: &Transaction) -> u32 {
|
|||
|
||||
max(GRACE_ACTIONS, logical_actions)
|
||||
}
|
||||
|
||||
/// Divide `quotient` by `divisor`, rounding the result up to the nearest integer.
|
||||
///
|
||||
/// # Correctness
|
||||
///
|
||||
/// `quotient + divisor` must be less than `usize::MAX`.
|
||||
/// `divisor` must not be zero.
|
||||
//
|
||||
// TODO: replace with usize::div_ceil() when int_roundings stabilises:
|
||||
// https://github.com/rust-lang/rust/issues/88581
|
||||
fn div_ceil(quotient: usize, divisor: usize) -> usize {
|
||||
// Rust uses truncated integer division, so this is equivalent to:
|
||||
// `ceil(quotient/divisor)`
|
||||
// as long as the addition doesn't overflow or underflow.
|
||||
(quotient + divisor - 1) / divisor
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ use proptest_derive::Arbitrary;
|
|||
/// outputs of coinbase transactions include Founders' Reward outputs and
|
||||
/// transparent Funding Stream outputs."
|
||||
/// [7.1](https://zips.z.cash/protocol/nu5.pdf#txnencodingandconsensus)
|
||||
//
|
||||
// TODO: change type to HeightDiff
|
||||
pub const MIN_TRANSPARENT_COINBASE_MATURITY: u32 = 100;
|
||||
|
||||
/// Extra coinbase data that identifies some coinbase transactions generated by Zebra.
|
||||
|
|
|
@ -75,6 +75,7 @@ color-eyre = "0.6.2"
|
|||
tinyvec = { version = "1.6.0", features = ["rustc_1_55"] }
|
||||
|
||||
hex = "0.4.3"
|
||||
num-integer = "0.1.45"
|
||||
proptest = "1.1.0"
|
||||
proptest-derive = "0.3.0"
|
||||
spandoc = "0.2.2"
|
||||
|
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
use std::sync::Arc;
|
||||
|
||||
use num_integer::div_ceil;
|
||||
|
||||
use zebra_chain::{
|
||||
block::{self, Block, HeightDiff},
|
||||
block::{self, Block, HeightDiff, MAX_BLOCK_BYTES},
|
||||
parameters::{Network, Network::*},
|
||||
serialization::ZcashDeserialize,
|
||||
};
|
||||
use zebra_node_services::constants::{MAX_CHECKPOINT_BYTE_COUNT, MAX_CHECKPOINT_HEIGHT_GAP};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -274,14 +277,21 @@ fn checkpoint_list_hard_coded_max_gap_testnet() -> Result<(), BoxError> {
|
|||
checkpoint_list_hard_coded_max_gap(Testnet)
|
||||
}
|
||||
|
||||
/// Check that the hard-coded checkpoints are within `MAX_CHECKPOINT_HEIGHT_GAP`.
|
||||
/// Check that the hard-coded checkpoints are within [`MAX_CHECKPOINT_HEIGHT_GAP`],
|
||||
/// and a calculated minimum number of blocks. This also checks the heights are in order.
|
||||
///
|
||||
/// We can't test the block byte limit, because we don't have access to the entire
|
||||
/// blockchain in the tests. But that's ok, because the byte limit only impacts
|
||||
/// performance.
|
||||
/// We can't test [`MAX_CHECKPOINT_BYTE_COUNT`] directly, because we don't have access to the
|
||||
/// entire blockchain in the tests. Instead, we check the number of maximum-size blocks in a
|
||||
/// checkpoint. (This is ok, because the byte count only impacts performance.)
|
||||
fn checkpoint_list_hard_coded_max_gap(network: Network) -> Result<(), BoxError> {
|
||||
let _init_guard = zebra_test::init();
|
||||
|
||||
let max_checkpoint_height_gap =
|
||||
HeightDiff::try_from(MAX_CHECKPOINT_HEIGHT_GAP).expect("constant fits in HeightDiff");
|
||||
let min_checkpoint_height_gap =
|
||||
HeightDiff::try_from(div_ceil(MAX_CHECKPOINT_BYTE_COUNT, MAX_BLOCK_BYTES))
|
||||
.expect("constant fits in HeightDiff");
|
||||
|
||||
let list = CheckpointList::new(network);
|
||||
let mut heights = list.0.keys();
|
||||
|
||||
|
@ -290,12 +300,27 @@ fn checkpoint_list_hard_coded_max_gap(network: Network) -> Result<(), BoxError>
|
|||
assert_eq!(heights.next(), Some(&previous_height));
|
||||
|
||||
for height in heights {
|
||||
let height_limit =
|
||||
(previous_height + (crate::MAX_CHECKPOINT_HEIGHT_GAP as HeightDiff)).unwrap();
|
||||
let height_upper_limit = (previous_height + max_checkpoint_height_gap)
|
||||
.expect("checkpoint heights are valid blockchain heights");
|
||||
|
||||
let height_lower_limit = (previous_height + min_checkpoint_height_gap)
|
||||
.expect("checkpoint heights are valid blockchain heights");
|
||||
|
||||
assert!(
|
||||
height <= &height_limit,
|
||||
"Checkpoint gaps must be within MAX_CHECKPOINT_HEIGHT_GAP"
|
||||
height <= &height_upper_limit,
|
||||
"Checkpoint gaps must be MAX_CHECKPOINT_HEIGHT_GAP or less \
|
||||
actually: {height:?} - {previous_height:?} = {} \
|
||||
should be: less than or equal to {max_checkpoint_height_gap}",
|
||||
*height - previous_height,
|
||||
);
|
||||
assert!(
|
||||
height >= &height_lower_limit,
|
||||
"Checkpoint gaps must be ceil(MAX_CHECKPOINT_BYTE_COUNT/MAX_BLOCK_BYTES) or greater \
|
||||
actually: {height:?} - {previous_height:?} = {} \
|
||||
should be: greater than or equal to {min_checkpoint_height_gap}",
|
||||
*height - previous_height,
|
||||
);
|
||||
|
||||
previous_height = *height;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,5 +16,24 @@ getblocktemplate-rpcs = [
|
|||
"zebra-chain/getblocktemplate-rpcs",
|
||||
]
|
||||
|
||||
# Tool and test features
|
||||
|
||||
rpc-client = [
|
||||
"color-eyre",
|
||||
"jsonrpc-core",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
zebra-chain = { path = "../zebra-chain" }
|
||||
|
||||
# Optional dependencies
|
||||
|
||||
# Tool and test feature rpc-client
|
||||
color-eyre = { version = "0.6.2", optional = true }
|
||||
jsonrpc-core = { version = "18.0.0", optional = true }
|
||||
reqwest = { version = "0.11.16", optional = true }
|
||||
serde = { version = "1.0.160", optional = true }
|
||||
serde_json = { version = "1.0.95", optional = true }
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
pub mod constants;
|
||||
pub mod mempool;
|
||||
|
||||
#[cfg(any(test, feature = "rpc-client"))]
|
||||
pub mod rpc_client;
|
||||
|
||||
/// Error type alias to make working with tower traits easier.
|
||||
///
|
||||
/// Note: the 'static lifetime bound means that the *type* cannot have any
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
//! A client for calling Zebra's Json-RPC methods
|
||||
//! A client for calling Zebra's JSON-RPC methods.
|
||||
//!
|
||||
//! Only used in tests and tools.
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use reqwest::Client;
|
||||
|
||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||
use color_eyre::{eyre::eyre, Result};
|
||||
|
||||
/// An http client for making Json-RPC requests
|
||||
/// An HTTP client for making JSON-RPC requests.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RPCRequestClient {
|
||||
pub struct RpcRequestClient {
|
||||
client: Client,
|
||||
rpc_address: SocketAddr,
|
||||
}
|
||||
|
||||
impl RPCRequestClient {
|
||||
impl RpcRequestClient {
|
||||
/// Creates new RPCRequestSender
|
||||
pub fn new(rpc_address: SocketAddr) -> Self {
|
||||
Self {
|
||||
|
@ -26,10 +27,12 @@ impl RPCRequestClient {
|
|||
/// Builds rpc request
|
||||
pub async fn call(
|
||||
&self,
|
||||
method: &'static str,
|
||||
params: impl Into<String>,
|
||||
method: impl AsRef<str>,
|
||||
params: impl AsRef<str>,
|
||||
) -> reqwest::Result<reqwest::Response> {
|
||||
let params = params.into();
|
||||
let method = method.as_ref();
|
||||
let params = params.as_ref();
|
||||
|
||||
self.client
|
||||
.post(format!("http://{}", &self.rpc_address))
|
||||
.body(format!(
|
||||
|
@ -43,8 +46,8 @@ impl RPCRequestClient {
|
|||
/// Builds rpc request and gets text from response
|
||||
pub async fn text_from_call(
|
||||
&self,
|
||||
method: &'static str,
|
||||
params: impl Into<String>,
|
||||
method: impl AsRef<str>,
|
||||
params: impl AsRef<str>,
|
||||
) -> reqwest::Result<String> {
|
||||
self.call(method, params).await?.text().await
|
||||
}
|
||||
|
@ -54,18 +57,16 @@ impl RPCRequestClient {
|
|||
///
|
||||
/// Returns Ok with json result from response if successful.
|
||||
/// Returns an error if the call or result deserialization fail.
|
||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||
pub async fn json_result_from_call<T: serde::de::DeserializeOwned>(
|
||||
&self,
|
||||
method: &'static str,
|
||||
params: impl Into<String>,
|
||||
method: impl AsRef<str>,
|
||||
params: impl AsRef<str>,
|
||||
) -> Result<T> {
|
||||
Self::json_result_from_response_text(&self.text_from_call(method, params).await?)
|
||||
}
|
||||
|
||||
/// Accepts response text from an RPC call
|
||||
/// Returns `Ok` with a deserialized `result` value in the expected type, or an error report.
|
||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||
fn json_result_from_response_text<T: serde::de::DeserializeOwned>(
|
||||
response_text: &str,
|
||||
) -> Result<T> {
|
|
@ -63,7 +63,7 @@ zcash_address = { version = "0.2.1", optional = true }
|
|||
# Test-only feature proptest-impl
|
||||
proptest = { version = "1.1.0", optional = true }
|
||||
|
||||
zebra-chain = { path = "../zebra-chain" }
|
||||
zebra-chain = { path = "../zebra-chain", features = ["json-conversion"] }
|
||||
zebra-consensus = { path = "../zebra-consensus" }
|
||||
zebra-network = { path = "../zebra-network" }
|
||||
zebra-node-services = { path = "../zebra-node-services" }
|
||||
|
|
|
@ -5,10 +5,16 @@ license = "MIT OR Apache-2.0"
|
|||
version = "1.0.0-beta.23"
|
||||
edition = "2021"
|
||||
|
||||
# Prevent accidental publication of this utility crate.
|
||||
publish = false
|
||||
[[bin]]
|
||||
name = "zebra-checkpoints"
|
||||
# this setting is required for Zebra's Docker build caches
|
||||
path = "src/bin/zebra-checkpoints/main.rs"
|
||||
required-features = ["zebra-checkpoints"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[[bin]]
|
||||
name = "search-issue-refs"
|
||||
path = "src/bin/search-issue-refs/main.rs"
|
||||
required-features = ["search-issue-refs"]
|
||||
|
||||
[[bin]]
|
||||
name = "block-template-to-proposal"
|
||||
|
@ -16,19 +22,25 @@ name = "block-template-to-proposal"
|
|||
path = "src/bin/block-template-to-proposal/main.rs"
|
||||
required-features = ["getblocktemplate-rpcs"]
|
||||
|
||||
[[bin]]
|
||||
name = "search-issue-refs"
|
||||
path = "src/bin/search-issue-refs/main.rs"
|
||||
required-features = ["search-issue-refs"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
search-issue-refs = ["regex", "reqwest", "tokio"]
|
||||
# Each binary has a feature that activates the extra dependencies it needs
|
||||
|
||||
# Production features that activate extra dependencies, or extra features in dependencies
|
||||
zebra-checkpoints = [
|
||||
"itertools",
|
||||
"tokio",
|
||||
"zebra-chain/json-conversion",
|
||||
"zebra-node-services/rpc-client"
|
||||
]
|
||||
|
||||
# Experimental mining RPC support
|
||||
search-issue-refs = [
|
||||
"regex",
|
||||
"reqwest",
|
||||
"tokio"
|
||||
]
|
||||
|
||||
# block-template-to-proposal uses the experimental mining RPC support feature name
|
||||
getblocktemplate-rpcs = [
|
||||
"zebra-rpc/getblocktemplate-rpcs",
|
||||
"zebra-node-services/getblocktemplate-rpcs",
|
||||
|
@ -48,13 +60,18 @@ tracing-error = "0.2.0"
|
|||
tracing-subscriber = "0.3.17"
|
||||
thiserror = "1.0.40"
|
||||
|
||||
# These crates are needed for the search-issue-refs binary
|
||||
regex = { version = "1.8.1", optional = true }
|
||||
reqwest = { version = "0.11.14", optional = true }
|
||||
tokio = { version = "1.27.0", features = ["full"], optional = true }
|
||||
|
||||
zebra-node-services = { path = "../zebra-node-services" }
|
||||
zebra-chain = { path = "../zebra-chain" }
|
||||
|
||||
# Experimental feature getblocktemplate-rpcs
|
||||
# These crates are needed for the zebra-checkpoints binary
|
||||
itertools = { version = "0.10.5", optional = true }
|
||||
|
||||
# These crates are needed for the search-issue-refs binary
|
||||
regex = { version = "1.8.1", optional = true }
|
||||
reqwest = { version = "0.11.14", optional = true }
|
||||
|
||||
# These crates are needed for the zebra-checkpoints and search-issue-refs binaries
|
||||
tokio = { version = "1.27.0", features = ["full"], optional = true }
|
||||
|
||||
# These crates are needed for the block-template-to-proposal binary
|
||||
zebra-rpc = { path = "../zebra-rpc", optional = true }
|
||||
|
|
|
@ -20,7 +20,7 @@ To create checkpoints, you need a synchronized instance of `zebrad` or `zcashd`,
|
|||
`zebra-checkpoints` is a standalone rust binary, you can compile it using:
|
||||
|
||||
```sh
|
||||
cargo install --locked --git https://github.com/ZcashFoundation/zebra zebra-utils
|
||||
cargo install --locked --features zebra-checkpoints --git https://github.com/ZcashFoundation/zebra zebra-utils
|
||||
```
|
||||
|
||||
Then update the checkpoints using these commands:
|
||||
|
|
|
@ -2,51 +2,123 @@
|
|||
//!
|
||||
//! For usage please refer to the program help: `zebra-checkpoints --help`
|
||||
|
||||
use std::{net::SocketAddr, str::FromStr};
|
||||
|
||||
use structopt::StructOpt;
|
||||
use thiserror::Error;
|
||||
|
||||
use std::str::FromStr;
|
||||
use zebra_chain::block::Height;
|
||||
|
||||
/// The backend type the zebra-checkpoints utility will use to get data from.
|
||||
///
|
||||
/// This changes which RPCs the tool calls, and which fields it expects them to have.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Backend {
|
||||
/// Expect a Zebra-style backend with limited RPCs and fields.
|
||||
///
|
||||
/// Calls these specific RPCs:
|
||||
/// - `getblock` with `verbose=0`, manually calculating `hash`, `height`, and `size`
|
||||
/// - `getblockchaininfo`, expecting a `blocks` field
|
||||
///
|
||||
/// Supports both `zebrad` and `zcashd` nodes.
|
||||
Zebrad,
|
||||
|
||||
/// Expect a `zcashd`-style backend with all available RPCs and fields.
|
||||
///
|
||||
/// Calls these specific RPCs:
|
||||
/// - `getblock` with `verbose=1`, expecting `hash`, `height`, and `size` fields
|
||||
/// - `getblockchaininfo`, expecting a `blocks` field
|
||||
///
|
||||
/// Currently only supported with `zcashd`.
|
||||
Zcashd,
|
||||
}
|
||||
|
||||
impl FromStr for Backend {
|
||||
type Err = InvalidModeError;
|
||||
type Err = InvalidBackendError;
|
||||
|
||||
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
||||
match string.to_lowercase().as_str() {
|
||||
"zebrad" => Ok(Backend::Zebrad),
|
||||
"zcashd" => Ok(Backend::Zcashd),
|
||||
_ => Err(InvalidModeError(string.to_owned())),
|
||||
_ => Err(InvalidBackendError(string.to_owned())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("Invalid mode: {0}")]
|
||||
pub struct InvalidModeError(String);
|
||||
/// An error indicating that the supplied string is not a valid [`Backend`] name.
|
||||
#[derive(Clone, Debug, Error, PartialEq, Eq)]
|
||||
#[error("Invalid backend: {0}")]
|
||||
pub struct InvalidBackendError(String);
|
||||
|
||||
/// The transport used by the zebra-checkpoints utility to connect to the [`Backend`].
|
||||
///
|
||||
/// This changes how the tool makes RPC requests.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Transport {
|
||||
/// Launch the `zcash-cli` command in a subprocess, and read its output.
|
||||
///
|
||||
/// The RPC name and parameters are sent as command-line arguments.
|
||||
/// Responses are read from the command's standard output.
|
||||
///
|
||||
/// Requires the `zcash-cli` command, which is part of `zcashd`'s tools.
|
||||
/// Supports both `zebrad` and `zcashd` nodes.
|
||||
Cli,
|
||||
|
||||
/// Connect directly to the node using TCP, and use the JSON-RPC protocol.
|
||||
///
|
||||
/// Uses JSON-RPC over HTTP for sending the RPC name and parameters, and
|
||||
/// receiving responses.
|
||||
///
|
||||
/// Always supports the `zebrad` node.
|
||||
/// Only supports `zcashd` nodes using a JSON-RPC TCP port with no authentication.
|
||||
Direct,
|
||||
}
|
||||
|
||||
impl FromStr for Transport {
|
||||
type Err = InvalidTransportError;
|
||||
|
||||
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
||||
match string.to_lowercase().as_str() {
|
||||
"cli" | "zcash-cli" | "zcashcli" | "zcli" | "z-cli" => Ok(Transport::Cli),
|
||||
"direct" => Ok(Transport::Direct),
|
||||
_ => Err(InvalidTransportError(string.to_owned())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error indicating that the supplied string is not a valid [`Transport`] name.
|
||||
#[derive(Clone, Debug, Error, PartialEq, Eq)]
|
||||
#[error("Invalid transport: {0}")]
|
||||
pub struct InvalidTransportError(String);
|
||||
|
||||
/// zebra-checkpoints arguments
|
||||
#[derive(Clone, Debug, Eq, PartialEq, StructOpt)]
|
||||
pub struct Args {
|
||||
/// Backend type
|
||||
/// Backend type: the node we're connecting to.
|
||||
#[structopt(default_value = "zebrad", short, long)]
|
||||
pub backend: Backend,
|
||||
|
||||
/// Path to zcash-cli command
|
||||
/// Transport type: the way we connect.
|
||||
#[structopt(default_value = "cli", short, long)]
|
||||
pub transport: Transport,
|
||||
|
||||
/// Path or name of zcash-cli command.
|
||||
/// Only used if the transport is [`Cli`](Transport::Cli).
|
||||
#[structopt(default_value = "zcash-cli", short, long)]
|
||||
pub cli: String,
|
||||
|
||||
/// Address and port for RPC connections.
|
||||
/// Used for all transports.
|
||||
#[structopt(short, long)]
|
||||
pub addr: Option<SocketAddr>,
|
||||
|
||||
/// Start looking for checkpoints after this height.
|
||||
/// If there is no last checkpoint, we start looking at the Genesis block (height 0).
|
||||
#[structopt(short, long)]
|
||||
pub last_checkpoint: Option<u32>,
|
||||
pub last_checkpoint: Option<Height>,
|
||||
|
||||
/// Passthrough args for `zcash-cli`
|
||||
/// Passthrough args for `zcash-cli`.
|
||||
/// Only used if the transport is [`Cli`](Transport::Cli).
|
||||
#[structopt(last = true)]
|
||||
pub zcli_args: Vec<String>,
|
||||
}
|
||||
|
|
|
@ -8,39 +8,106 @@
|
|||
//! zebra-consensus accepts an ordered list of checkpoints, starting with the
|
||||
//! genesis block. Checkpoint heights can be chosen arbitrarily.
|
||||
|
||||
use std::process::Stdio;
|
||||
use std::{ffi::OsString, process::Stdio};
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::process::ExitStatusExt;
|
||||
|
||||
use color_eyre::eyre::{ensure, Result};
|
||||
use hex::FromHex;
|
||||
use color_eyre::{
|
||||
eyre::{ensure, Result},
|
||||
Help,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use serde_json::Value;
|
||||
use structopt::StructOpt;
|
||||
|
||||
use zebra_chain::{
|
||||
block, serialization::ZcashDeserializeInto, transparent::MIN_TRANSPARENT_COINBASE_MATURITY,
|
||||
block::{self, Block, Height, HeightDiff, TryIntoHeight},
|
||||
serialization::ZcashDeserializeInto,
|
||||
transparent::MIN_TRANSPARENT_COINBASE_MATURITY,
|
||||
};
|
||||
use zebra_node_services::{
|
||||
constants::{MAX_CHECKPOINT_BYTE_COUNT, MAX_CHECKPOINT_HEIGHT_GAP},
|
||||
rpc_client::RpcRequestClient,
|
||||
};
|
||||
use zebra_node_services::constants::{MAX_CHECKPOINT_BYTE_COUNT, MAX_CHECKPOINT_HEIGHT_GAP};
|
||||
use zebra_utils::init_tracing;
|
||||
|
||||
mod args;
|
||||
pub mod args;
|
||||
|
||||
/// Return a new `zcash-cli` command, including the `zebra-checkpoints`
|
||||
/// passthrough arguments.
|
||||
fn passthrough_cmd() -> std::process::Command {
|
||||
let args = args::Args::from_args();
|
||||
let mut cmd = std::process::Command::new(&args.cli);
|
||||
use args::{Args, Backend, Transport};
|
||||
|
||||
if !args.zcli_args.is_empty() {
|
||||
cmd.args(&args.zcli_args);
|
||||
/// Make an RPC call based on `our_args` and `rpc_command`, and return the response as a [`Value`].
|
||||
async fn rpc_output<M, I>(our_args: &Args, method: M, params: I) -> Result<Value>
|
||||
where
|
||||
M: AsRef<str>,
|
||||
I: IntoIterator<Item = String>,
|
||||
{
|
||||
match our_args.transport {
|
||||
Transport::Cli => cli_output(our_args, method, params),
|
||||
Transport::Direct => direct_output(our_args, method, params).await,
|
||||
}
|
||||
cmd
|
||||
}
|
||||
|
||||
/// Run `cmd` and return its output as a string.
|
||||
fn cmd_output(cmd: &mut std::process::Command) -> Result<String> {
|
||||
// Capture stdout, but send stderr to the user
|
||||
/// Connect to the node with `our_args` and `rpc_command`, and return the response as a [`Value`].
|
||||
///
|
||||
/// Only used if the transport is [`Direct`](Transport::Direct).
|
||||
async fn direct_output<M, I>(our_args: &Args, method: M, params: I) -> Result<Value>
|
||||
where
|
||||
M: AsRef<str>,
|
||||
I: IntoIterator<Item = String>,
|
||||
{
|
||||
// Get a new RPC client that will connect to our node
|
||||
let addr = our_args
|
||||
.addr
|
||||
.unwrap_or_else(|| "127.0.0.1:8232".parse().expect("valid address"));
|
||||
let client = RpcRequestClient::new(addr);
|
||||
|
||||
// Launch a request with the RPC method and arguments
|
||||
//
|
||||
// The params are a JSON array with typed arguments.
|
||||
// TODO: accept JSON value arguments, and do this formatting using serde_json
|
||||
let params = format!("[{}]", params.into_iter().join(", "));
|
||||
let response = client.text_from_call(method, params).await?;
|
||||
|
||||
// Extract the "result" field from the RPC response
|
||||
let mut response: Value = serde_json::from_str(&response)?;
|
||||
let response = response["result"].take();
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
/// Run `cmd` with `our_args` and `rpc_command`, and return its output as a [`Value`].
|
||||
///
|
||||
/// Only used if the transport is [`Cli`](Transport::Cli).
|
||||
fn cli_output<M, I>(our_args: &Args, method: M, params: I) -> Result<Value>
|
||||
where
|
||||
M: AsRef<str>,
|
||||
I: IntoIterator<Item = String>,
|
||||
{
|
||||
// Get a new `zcash-cli` command configured for our node,
|
||||
// including the `zebra-checkpoints` passthrough arguments.
|
||||
let mut cmd = std::process::Command::new(&our_args.cli);
|
||||
cmd.args(&our_args.zcli_args);
|
||||
|
||||
// Turn the address into command-line arguments
|
||||
if let Some(addr) = our_args.addr {
|
||||
cmd.arg(format!("-rpcconnect={}", addr.ip()));
|
||||
cmd.arg(format!("-rpcport={}", addr.port()));
|
||||
}
|
||||
|
||||
// Add the RPC method and arguments
|
||||
let method: OsString = method.as_ref().into();
|
||||
cmd.arg(method);
|
||||
|
||||
for param in params {
|
||||
// Remove JSON string/int type formatting, because zcash-cli will add it anyway
|
||||
// TODO: accept JSON value arguments, and do this formatting using serde_json?
|
||||
let param = param.trim_matches('"');
|
||||
let param: OsString = param.into();
|
||||
cmd.arg(param);
|
||||
}
|
||||
|
||||
// Launch a CLI request, capturing stdout, but sending stderr to the user
|
||||
let output = cmd.stderr(Stdio::inherit()).output()?;
|
||||
|
||||
// Make sure the command was successful
|
||||
|
@ -58,87 +125,111 @@ fn cmd_output(cmd: &mut std::process::Command) -> Result<String> {
|
|||
output.status.code()
|
||||
);
|
||||
|
||||
// Make sure the output is valid UTF-8
|
||||
let s = String::from_utf8(output.stdout)?;
|
||||
Ok(s)
|
||||
// Make sure the output is valid UTF-8 JSON
|
||||
let response = String::from_utf8(output.stdout)?;
|
||||
// zcash-cli returns raw strings without JSON type info.
|
||||
// As a workaround, assume that invalid responses are strings.
|
||||
let response: Value = serde_json::from_str(&response)
|
||||
.unwrap_or_else(|_error| Value::String(response.trim().to_string()));
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
/// Process entry point for `zebra-checkpoints`
|
||||
#[tokio::main]
|
||||
#[allow(clippy::print_stdout)]
|
||||
fn main() -> Result<()> {
|
||||
async fn main() -> Result<()> {
|
||||
// initialise
|
||||
init_tracing();
|
||||
color_eyre::install()?;
|
||||
|
||||
// get the current block count
|
||||
let mut cmd = passthrough_cmd();
|
||||
cmd.arg("getblockchaininfo");
|
||||
let args = args::Args::from_args();
|
||||
|
||||
let output = cmd_output(&mut cmd)?;
|
||||
let get_block_chain_info: Value = serde_json::from_str(&output)?;
|
||||
// get the current block count
|
||||
let get_block_chain_info = rpc_output(&args, "getblockchaininfo", None)
|
||||
.await
|
||||
.with_suggestion(|| {
|
||||
"Is the RPC server address and port correct? Is authentication configured correctly?"
|
||||
})?;
|
||||
|
||||
// calculate the maximum height
|
||||
let height_limit = block::Height(get_block_chain_info["blocks"].as_u64().unwrap() as u32);
|
||||
let height_limit = get_block_chain_info["blocks"]
|
||||
.try_into_height()
|
||||
.expect("height: unexpected invalid value, missing field, or field type");
|
||||
|
||||
assert!(height_limit <= block::Height::MAX);
|
||||
// Checkpoints must be on the main chain, so we skip blocks that are within the
|
||||
// Zcash reorg limit.
|
||||
let height_limit = height_limit
|
||||
.0
|
||||
.checked_sub(MIN_TRANSPARENT_COINBASE_MATURITY)
|
||||
.map(block::Height)
|
||||
.expect("zcashd has some mature blocks: wait for zcashd to sync more blocks");
|
||||
- HeightDiff::try_from(MIN_TRANSPARENT_COINBASE_MATURITY).expect("constant fits in i32");
|
||||
let height_limit =
|
||||
height_limit.expect("node has some mature blocks: wait for it to sync more blocks");
|
||||
|
||||
let starting_height = args::Args::from_args().last_checkpoint.map(block::Height);
|
||||
if starting_height.is_some() {
|
||||
// Since we're about to add 1, height needs to be strictly less than the maximum
|
||||
assert!(starting_height.unwrap() < block::Height::MAX);
|
||||
}
|
||||
// Start at the next block after the last checkpoint.
|
||||
// If there is no last checkpoint, start at genesis (height 0).
|
||||
let starting_height = starting_height.map_or(0, |block::Height(h)| h + 1);
|
||||
let starting_height = if let Some(last_checkpoint) = args.last_checkpoint {
|
||||
(last_checkpoint + 1)
|
||||
.expect("invalid last checkpoint height, must be less than the max height")
|
||||
} else {
|
||||
Height::MIN
|
||||
};
|
||||
|
||||
assert!(
|
||||
starting_height < height_limit.0,
|
||||
"No mature blocks after the last checkpoint: wait for zcashd to sync more blocks"
|
||||
starting_height < height_limit,
|
||||
"No mature blocks after the last checkpoint: wait for node to sync more blocks"
|
||||
);
|
||||
|
||||
// set up counters
|
||||
let mut cumulative_bytes: u64 = 0;
|
||||
let mut height_gap: block::Height = block::Height(0);
|
||||
let mut last_checkpoint_height = args.last_checkpoint.unwrap_or(Height::MIN);
|
||||
let max_checkpoint_height_gap =
|
||||
HeightDiff::try_from(MAX_CHECKPOINT_HEIGHT_GAP).expect("constant fits in HeightDiff");
|
||||
|
||||
// loop through all blocks
|
||||
for x in starting_height..height_limit.0 {
|
||||
// unfortunately we need to create a process for each block
|
||||
let mut cmd = passthrough_cmd();
|
||||
for request_height in starting_height.0..height_limit.0 {
|
||||
// In `Cli` transport mode we need to create a process for each block
|
||||
|
||||
let (hash, height, size) = match args::Args::from_args().backend {
|
||||
args::Backend::Zcashd => {
|
||||
let (hash, response_height, size) = match args.backend {
|
||||
Backend::Zcashd => {
|
||||
// get block data from zcashd using verbose=1
|
||||
cmd.args(["getblock", &x.to_string(), "1"]);
|
||||
let output = cmd_output(&mut cmd)?;
|
||||
|
||||
// parse json
|
||||
let v: Value = serde_json::from_str(&output)?;
|
||||
let get_block = rpc_output(
|
||||
&args,
|
||||
"getblock",
|
||||
[format!(r#""{request_height}""#), 1.to_string()],
|
||||
)
|
||||
.await?;
|
||||
|
||||
// get the values we are interested in
|
||||
let hash: block::Hash = v["hash"].as_str().unwrap().parse()?;
|
||||
let height = block::Height(v["height"].as_u64().unwrap() as u32);
|
||||
let hash: block::Hash = get_block["hash"]
|
||||
.as_str()
|
||||
.expect("hash: unexpected missing field or field type")
|
||||
.parse()?;
|
||||
let response_height: Height = get_block["height"]
|
||||
.try_into_height()
|
||||
.expect("height: unexpected invalid value, missing field, or field type");
|
||||
|
||||
let size = v["size"].as_u64().unwrap();
|
||||
let size = get_block["size"]
|
||||
.as_u64()
|
||||
.expect("size: unexpected invalid value, missing field, or field type");
|
||||
|
||||
(hash, height, size)
|
||||
(hash, response_height, size)
|
||||
}
|
||||
args::Backend::Zebrad => {
|
||||
// get block data from zebrad by deserializing the raw block
|
||||
cmd.args(["getblock", &x.to_string(), "0"]);
|
||||
let output = cmd_output(&mut cmd)?;
|
||||
Backend::Zebrad => {
|
||||
// get block data from zebrad (or zcashd) by deserializing the raw block
|
||||
let block_bytes = rpc_output(
|
||||
&args,
|
||||
"getblock",
|
||||
[format!(r#""{request_height}""#), 0.to_string()],
|
||||
)
|
||||
.await?;
|
||||
let block_bytes = block_bytes
|
||||
.as_str()
|
||||
.expect("block bytes: unexpected missing field or field type");
|
||||
|
||||
let block_bytes = <Vec<u8>>::from_hex(output.trim_end_matches('\n'))?;
|
||||
let block_bytes: Vec<u8> = hex::decode(block_bytes)?;
|
||||
|
||||
let block = block_bytes
|
||||
.zcash_deserialize_into::<block::Block>()
|
||||
.expect("obtained block should deserialize");
|
||||
// TODO: is it faster to call both `getblock height 0` and `getblock height 1`,
|
||||
// rather than deserializing the block and calculating its hash?
|
||||
let block: Block = block_bytes.zcash_deserialize_into()?;
|
||||
|
||||
(
|
||||
block.hash(),
|
||||
|
@ -150,24 +241,27 @@ fn main() -> Result<()> {
|
|||
}
|
||||
};
|
||||
|
||||
assert!(height <= block::Height::MAX);
|
||||
assert_eq!(x, height.0);
|
||||
assert_eq!(
|
||||
request_height, response_height.0,
|
||||
"node returned a different block than requested"
|
||||
);
|
||||
|
||||
// compute
|
||||
// compute cumulative totals
|
||||
cumulative_bytes += size;
|
||||
height_gap = block::Height(height_gap.0 + 1);
|
||||
|
||||
// check if checkpoint
|
||||
if height == block::Height(0)
|
||||
let height_gap = response_height - last_checkpoint_height;
|
||||
|
||||
// check if this block should be a checkpoint
|
||||
if response_height == Height::MIN
|
||||
|| cumulative_bytes >= MAX_CHECKPOINT_BYTE_COUNT
|
||||
|| height_gap.0 >= MAX_CHECKPOINT_HEIGHT_GAP as u32
|
||||
|| height_gap >= max_checkpoint_height_gap
|
||||
{
|
||||
// print to output
|
||||
println!("{} {hash}", height.0);
|
||||
println!("{} {hash}", response_height.0);
|
||||
|
||||
// reset counters
|
||||
// reset cumulative totals
|
||||
cumulative_bytes = 0;
|
||||
height_gap = block::Height(0);
|
||||
last_checkpoint_height = response_height;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -198,8 +198,6 @@ serde_json = { version = "1.0.96", features = ["preserve_order"] }
|
|||
tempfile = "3.5.0"
|
||||
|
||||
hyper = { version = "0.14.26", features = ["http1", "http2", "server"]}
|
||||
reqwest = "0.11.16"
|
||||
|
||||
tokio = { version = "1.27.0", features = ["full", "tracing", "test-util"] }
|
||||
tokio-stream = "0.1.12"
|
||||
|
||||
|
@ -211,10 +209,13 @@ proptest = "1.1.0"
|
|||
proptest-derive = "0.3.0"
|
||||
|
||||
# enable span traces and track caller in tests
|
||||
color-eyre = { version = "0.6.2", features = ["issue-url"] }
|
||||
color-eyre = { version = "0.6.2" }
|
||||
|
||||
zebra-chain = { path = "../zebra-chain", features = ["proptest-impl"] }
|
||||
zebra-consensus = { path = "../zebra-consensus", features = ["proptest-impl"] }
|
||||
zebra-network = { path = "../zebra-network", features = ["proptest-impl"] }
|
||||
zebra-state = { path = "../zebra-state", features = ["proptest-impl"] }
|
||||
|
||||
zebra-node-services = { path = "../zebra-node-services", features = ["rpc-client"] }
|
||||
|
||||
zebra-test = { path = "../zebra-test" }
|
||||
|
|
|
@ -144,6 +144,7 @@ use zebra_chain::{
|
|||
parameters::Network::{self, *},
|
||||
};
|
||||
use zebra_network::constants::PORT_IN_USE_ERROR;
|
||||
use zebra_node_services::rpc_client::RpcRequestClient;
|
||||
use zebra_state::constants::LOCK_FILE_ERROR;
|
||||
|
||||
use zebra_test::{args, command::ContextFrom, net::random_known_port, prelude::*};
|
||||
|
@ -167,8 +168,6 @@ use common::{
|
|||
test_type::TestType::{self, *},
|
||||
};
|
||||
|
||||
use crate::common::rpc_client::RPCRequestClient;
|
||||
|
||||
/// The maximum amount of time that we allow the creation of a future to block the `tokio` executor.
|
||||
///
|
||||
/// This should be larger than the amount of time between thread time slices on a busy test VM.
|
||||
|
@ -1367,7 +1366,7 @@ async fn rpc_endpoint(parallel_cpu_threads: bool) -> Result<()> {
|
|||
)?;
|
||||
|
||||
// Create an http client
|
||||
let client = RPCRequestClient::new(config.rpc.listen_addr.unwrap());
|
||||
let client = RpcRequestClient::new(config.rpc.listen_addr.unwrap());
|
||||
|
||||
// Make the call to the `getinfo` RPC method
|
||||
let res = client.call("getinfo", "[]".to_string()).await?;
|
||||
|
@ -1435,7 +1434,7 @@ fn non_blocking_logger() -> Result<()> {
|
|||
)?;
|
||||
|
||||
// Create an http client
|
||||
let client = RPCRequestClient::new(zebra_rpc_address);
|
||||
let client = RpcRequestClient::new(zebra_rpc_address);
|
||||
|
||||
// Most of Zebra's lines are 100-200 characters long, so 500 requests should print enough to fill the unix pipe,
|
||||
// fill the channel that tracing logs are queued onto, and drop logs rather than block execution.
|
||||
|
@ -2058,7 +2057,7 @@ async fn fully_synced_rpc_test() -> Result<()> {
|
|||
|
||||
zebrad.expect_stdout_line_matches(format!("Opened RPC endpoint at {zebra_rpc_address}"))?;
|
||||
|
||||
let client = RPCRequestClient::new(zebra_rpc_address);
|
||||
let client = RpcRequestClient::new(zebra_rpc_address);
|
||||
|
||||
// Make a getblock test that works only on synced node (high block number).
|
||||
// The block is before the mandatory checkpoint, so the checkpoint cached state can be used
|
||||
|
|
|
@ -5,30 +5,27 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use tempfile::TempDir;
|
||||
use tokio::fs;
|
||||
use tower::{util::BoxService, Service};
|
||||
|
||||
use zebra_chain::block::Block;
|
||||
use zebra_chain::serialization::ZcashDeserializeInto;
|
||||
use zebra_chain::{
|
||||
block::{self, Height},
|
||||
block::{self, Block, Height},
|
||||
chain_tip::ChainTip,
|
||||
parameters::Network,
|
||||
serialization::ZcashDeserializeInto,
|
||||
};
|
||||
use zebra_state::{ChainTipChange, LatestChainTip};
|
||||
|
||||
use crate::common::config::testdir;
|
||||
use crate::common::rpc_client::RPCRequestClient;
|
||||
|
||||
use zebra_state::MAX_BLOCK_REORG_HEIGHT;
|
||||
use zebra_node_services::rpc_client::RpcRequestClient;
|
||||
use zebra_state::{ChainTipChange, LatestChainTip, MAX_BLOCK_REORG_HEIGHT};
|
||||
|
||||
use crate::common::{
|
||||
config::testdir,
|
||||
launch::spawn_zebrad_for_rpc,
|
||||
sync::{check_sync_logs_until, MempoolBehavior, SYNC_FINISHED_REGEX},
|
||||
test_type::TestType,
|
||||
|
@ -230,7 +227,7 @@ pub async fn get_raw_future_blocks(
|
|||
)?;
|
||||
|
||||
// Create an http client
|
||||
let rpc_client = RPCRequestClient::new(rpc_address);
|
||||
let rpc_client = RpcRequestClient::new(rpc_address);
|
||||
|
||||
let blockchain_info: serde_json::Value = serde_json::from_str(
|
||||
&rpc_client
|
||||
|
|
|
@ -10,7 +10,9 @@ use std::time::Duration;
|
|||
use color_eyre::eyre::{eyre, Context, Result};
|
||||
|
||||
use futures::FutureExt;
|
||||
|
||||
use zebra_chain::{parameters::Network, serialization::ZcashSerialize};
|
||||
use zebra_node_services::rpc_client::RpcRequestClient;
|
||||
use zebra_rpc::methods::get_block_template_rpcs::{
|
||||
get_block_template::{
|
||||
proposal::TimeSource, GetBlockTemplate, JsonParameters, ProposalResponse,
|
||||
|
@ -20,7 +22,6 @@ use zebra_rpc::methods::get_block_template_rpcs::{
|
|||
|
||||
use crate::common::{
|
||||
launch::{can_spawn_zebrad_for_rpc, spawn_zebrad_for_rpc},
|
||||
rpc_client::RPCRequestClient,
|
||||
sync::{check_sync_logs_until, MempoolBehavior, SYNC_FINISHED_REGEX},
|
||||
test_type::TestType,
|
||||
};
|
||||
|
@ -90,7 +91,7 @@ pub(crate) async fn run() -> Result<()> {
|
|||
true,
|
||||
)?;
|
||||
|
||||
let client = RPCRequestClient::new(rpc_address);
|
||||
let client = RpcRequestClient::new(rpc_address);
|
||||
|
||||
tracing::info!(
|
||||
"calling getblocktemplate RPC method at {rpc_address}, \
|
||||
|
@ -135,7 +136,7 @@ pub(crate) async fn run() -> Result<()> {
|
|||
.wrap_err("Possible port conflict. Are there other acceptance tests running?")
|
||||
}
|
||||
|
||||
/// Accepts an [`RPCRequestClient`], calls getblocktemplate in template mode,
|
||||
/// Accepts an [`RpcRequestClient`], calls getblocktemplate in template mode,
|
||||
/// deserializes and transforms the block template in the response into block proposal data,
|
||||
/// then calls getblocktemplate RPC in proposal mode with the serialized and hex-encoded data.
|
||||
///
|
||||
|
@ -148,7 +149,7 @@ pub(crate) async fn run() -> Result<()> {
|
|||
/// If an RPC call returns a failure
|
||||
/// If the response result cannot be deserialized to `GetBlockTemplate` in 'template' mode
|
||||
/// or `ProposalResponse` in 'proposal' mode.
|
||||
async fn try_validate_block_template(client: &RPCRequestClient) -> Result<()> {
|
||||
async fn try_validate_block_template(client: &RpcRequestClient) -> Result<()> {
|
||||
let mut response_json_result: GetBlockTemplate = client
|
||||
.json_result_from_call("getblocktemplate", "[]".to_string())
|
||||
.await
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
use color_eyre::eyre::{Context, Result};
|
||||
|
||||
use zebra_chain::parameters::Network;
|
||||
use zebra_node_services::rpc_client::RpcRequestClient;
|
||||
use zebra_rpc::methods::get_block_template_rpcs::types::peer_info::PeerInfo;
|
||||
|
||||
use crate::common::{
|
||||
launch::{can_spawn_zebrad_for_rpc, spawn_zebrad_for_rpc},
|
||||
rpc_client::RPCRequestClient,
|
||||
test_type::TestType,
|
||||
};
|
||||
|
||||
|
@ -39,7 +39,7 @@ pub(crate) async fn run() -> Result<()> {
|
|||
tracing::info!(?rpc_address, "zebrad opened its RPC port",);
|
||||
|
||||
// call `getpeerinfo` RPC method
|
||||
let peer_info_result: Vec<PeerInfo> = RPCRequestClient::new(rpc_address)
|
||||
let peer_info_result: Vec<PeerInfo> = RpcRequestClient::new(rpc_address)
|
||||
.json_result_from_call("getpeerinfo", "[]".to_string())
|
||||
.await?;
|
||||
|
||||
|
|
|
@ -11,11 +11,11 @@
|
|||
use color_eyre::eyre::{Context, Result};
|
||||
|
||||
use zebra_chain::parameters::Network;
|
||||
use zebra_node_services::rpc_client::RpcRequestClient;
|
||||
|
||||
use crate::common::{
|
||||
cached_state::get_raw_future_blocks,
|
||||
launch::{can_spawn_zebrad_for_rpc, spawn_zebrad_for_rpc},
|
||||
rpc_client::RPCRequestClient,
|
||||
test_type::TestType,
|
||||
};
|
||||
|
||||
|
@ -64,7 +64,7 @@ pub(crate) async fn run() -> Result<()> {
|
|||
tracing::info!(?rpc_address, "zebrad opened its RPC port",);
|
||||
|
||||
// Create an http client
|
||||
let client = RPCRequestClient::new(rpc_address);
|
||||
let client = RpcRequestClient::new(rpc_address);
|
||||
|
||||
for raw_block in raw_blocks {
|
||||
let res = client
|
||||
|
|
|
@ -8,12 +8,12 @@ use std::{
|
|||
|
||||
use tempfile::TempDir;
|
||||
|
||||
use zebra_node_services::rpc_client::RpcRequestClient;
|
||||
use zebra_test::prelude::*;
|
||||
|
||||
use crate::common::{
|
||||
launch::ZebradTestDirExt,
|
||||
lightwalletd::wallet_grpc::{connect_to_lightwalletd, ChainSpec},
|
||||
rpc_client::RPCRequestClient,
|
||||
test_type::TestType,
|
||||
};
|
||||
|
||||
|
@ -183,7 +183,7 @@ pub fn are_zebrad_and_lightwalletd_tips_synced(
|
|||
let lightwalletd_tip_height = lightwalletd_tip_block.height;
|
||||
|
||||
// Get the block tip from zebrad
|
||||
let client = RPCRequestClient::new(zebra_rpc_address);
|
||||
let client = RpcRequestClient::new(zebra_rpc_address);
|
||||
let zebrad_blockchain_info = client
|
||||
.text_from_call("getblockchaininfo", "[]".to_string())
|
||||
.await?;
|
||||
|
|
|
@ -13,10 +13,10 @@ pub mod cached_state;
|
|||
pub mod check;
|
||||
pub mod config;
|
||||
pub mod failure_messages;
|
||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||
pub mod get_block_template_rpcs;
|
||||
pub mod launch;
|
||||
pub mod lightwalletd;
|
||||
pub mod rpc_client;
|
||||
pub mod sync;
|
||||
pub mod test_type;
|
||||
|
||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||
pub mod get_block_template_rpcs;
|
||||
|
|
Loading…
Reference in New Issue