feat(zebra-checkpoints): make `zebra-checkpoints` work for zebrad backend (#5894)

* make `zebra-checkpoint` util work with zebra as the backend

* update snapshots

* update documentation

* applies suggestions from code review

* irefactor zebra-checkpoints to work with zebra using deserialization of the raw block

* fix imports and derives

* rename mode to backend

* remove old stuff

* fix docs

Co-authored-by: arya2 <aryasolhi@gmail.com>
This commit is contained in:
Alfredo Garcia 2023-01-23 01:50:45 -03:00 committed by GitHub
parent d5399d1eea
commit d72211fbbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 86 additions and 16 deletions

1
Cargo.lock generated
View File

@ -5634,6 +5634,7 @@ dependencies = [
"hex",
"serde_json",
"structopt",
"thiserror",
"tinyvec",
"tracing-error",
"tracing-subscriber 0.3.16",

View File

@ -1,6 +1,6 @@
# zebra-checkpoints
`zebra-checkpoints` uses a local `zcashd` instance to generate a list of checkpoints for Zebra's checkpoint verifier.
`zebra-checkpoints` uses a local `zebrad` or `zcashd` instance to generate a list of checkpoints for Zebra's checkpoint verifier.
Developers should run this tool every few months to add new checkpoints to Zebra.
(By default, Zebra uses these checkpoints to sync to the chain tip.)

View File

@ -22,7 +22,7 @@ Or jump straight to [the exact commands for updating the lists](https://github.c
### Use the `zebra-checkpoints` utility
`zebra-checkpoints` is the program we use to collect checkpoints. Currently this program uses `zcash-cli` to get the hashes. `zcash-cli` must be available in your machine and it must be connected to a synchronized (Mainnet or Testnet) instance of `zcashd` to get the most recent hashes.
`zebra-checkpoints` is the program we use to collect checkpoints. Currently this program uses `zcash-cli` to get the hashes. `zcash-cli` must be available in your machine and it must be connected to a synchronized (Mainnet or Testnet) instance of `zebrad` or `zcashd` to get the most recent hashes.
First, [build the `zebra-checkpoints` binary](https://github.com/ZcashFoundation/zebra/tree/main/zebra-utils/README.md#zebra-checkpoints).
@ -30,6 +30,8 @@ When updating the lists there is no need to start from the genesis block. The pr
It is easier if `zcash-cli` is in your execution path however you can specify the location of it anywhere in the filesystem with option `--cli`.
By default, `zebra-checkpoints` will use a `zebrad` backend. If the running instance is `zcashd`, please add `-b zcashd` to your command.
To update the checkpoint list, run:
```sh
@ -43,7 +45,7 @@ $ zebra-checkpoints --last-checkpoint $(tail -1 zebra-consensus/src/checkpoint/m
...
```
If we are looking to update the testnet hashes we must make sure the cli is connected with a testnet chain. If we have our `zcashd` running locally we can make this by starting with `zcashd -testnet`.
If we are looking to update the testnet hashes we must make sure the cli is connected with a testnet chain. If we are using `zcashd` as the backend and this is running locally, we can make this by starting with `zcashd -testnet`. If we are using `zebrad` as the backend, then we must start with a configuration file where the `network` field of the `[network]` section is `Testnet`.
Anything we add after `--` will pass through into the `zcash-cli` program so we can specify the testnet here.

View File

@ -39,6 +39,7 @@ hex = "0.4.3"
serde_json = "1.0.91"
tracing-error = "0.2.0"
tracing-subscriber = "0.3.16"
thiserror = "1.0.38"
zebra-node-services = { path = "../zebra-node-services" }
zebra-chain = { path = "../zebra-chain" }

View File

@ -15,7 +15,7 @@ Binaries are easier to use if they are located in your system execution path.
This command generates a list of zebra checkpoints, and writes them to standard output. Each checkpoint consists of a block height and hash.
To create checkpoints, you need a synchronized instance of `zcashd`, and the `zcash-cli` RPC client.
To create checkpoints, you need a synchronized instance of `zebrad` or `zcashd`, and the `zcash-cli` RPC client.
`zebra-checkpoints` is a standalone rust binary, you can compile it using:

View File

@ -3,10 +3,40 @@
//! For usage please refer to the program help: `zebra-checkpoints --help`
use structopt::StructOpt;
use thiserror::Error;
use std::str::FromStr;
/// The backend type the zebra-checkpoints utility will use to get data from.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Backend {
Zebrad,
Zcashd,
}
impl FromStr for Backend {
type Err = InvalidModeError;
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())),
}
}
}
#[derive(Debug, Error)]
#[error("Invalid mode: {0}")]
pub struct InvalidModeError(String);
/// zebra-checkpoints arguments
#[derive(Clone, Debug, Eq, PartialEq, StructOpt)]
pub struct Args {
/// Backend type
#[structopt(default_value = "zebrad", short, long)]
pub backend: Backend,
/// Path to zcash-cli command
#[structopt(default_value = "zcash-cli", short, long)]
pub cli: String,

View File

@ -14,10 +14,13 @@ use std::process::Stdio;
use std::os::unix::process::ExitStatusExt;
use color_eyre::eyre::{ensure, Result};
use hex::FromHex;
use serde_json::Value;
use structopt::StructOpt;
use zebra_chain::{block, transparent::MIN_TRANSPARENT_COINBASE_MATURITY};
use zebra_chain::{
block, serialization::ZcashDeserializeInto, transparent::MIN_TRANSPARENT_COINBASE_MATURITY,
};
use zebra_node_services::constants::{MAX_CHECKPOINT_BYTE_COUNT, MAX_CHECKPOINT_HEIGHT_GAP};
use zebra_utils::init_tracing;
@ -69,9 +72,14 @@ fn main() -> Result<()> {
// get the current block count
let mut cmd = passthrough_cmd();
cmd.arg("getblockcount");
cmd.arg("getblockchaininfo");
let output = cmd_output(&mut cmd)?;
let get_block_chain_info: Value = serde_json::from_str(&output)?;
// calculate the maximum height
let height_limit: block::Height = cmd_output(&mut cmd)?.trim().parse()?;
let height_limit = block::Height(get_block_chain_info["blocks"].as_u64().unwrap() as u32);
assert!(height_limit <= block::Height::MAX);
// Checkpoints must be on the main chain, so we skip blocks that are within the
// Zcash reorg limit.
@ -104,18 +112,46 @@ fn main() -> Result<()> {
// unfortunately we need to create a process for each block
let mut cmd = passthrough_cmd();
// get block data
cmd.args(["getblock", &x.to_string()]);
let output = cmd_output(&mut cmd)?;
// parse json
let v: Value = serde_json::from_str(&output)?;
let (hash, height, size) = match args::Args::from_args().backend {
args::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)?;
// 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 size = v["size"].as_u64().unwrap();
(hash, 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)?;
let block_bytes = <Vec<u8>>::from_hex(output.trim_end_matches('\n'))?;
let block = block_bytes
.zcash_deserialize_into::<block::Block>()
.expect("obtained block should deserialize");
(
block.hash(),
block
.coinbase_height()
.expect("block has always a coinbase height"),
block_bytes.len().try_into()?,
)
}
};
// 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);
assert!(height <= block::Height::MAX);
assert_eq!(x, height.0);
let size = v["size"].as_u64().unwrap();
// compute
cumulative_bytes += size;