From ae3c2e5c206564b75fa0950606c5285d5e4aaafb Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Fri, 23 Dec 2022 20:55:54 -0300 Subject: [PATCH 1/9] make `zebra-checkpoint` util work with zebra as the backend --- zebra-rpc/src/methods.rs | 64 ++++++++++++------- zebra-rpc/src/methods/tests/vectors.rs | 5 +- zebra-rpc/src/tests/vectors.rs | 5 +- zebra-utils/src/bin/zebra-checkpoints/main.rs | 12 +++- 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/zebra-rpc/src/methods.rs b/zebra-rpc/src/methods.rs index 4b4fd72888f..8318108acd8 100644 --- a/zebra-rpc/src/methods.rs +++ b/zebra-rpc/src/methods.rs @@ -139,7 +139,9 @@ pub trait Rpc { /// /// With verbosity=1, [`lightwalletd` only reads the `tx` field of the /// result](https://github.com/zcash/lightwalletd/blob/dfac02093d85fb31fb9a8475b884dd6abca966c7/common/common.go#L152), - /// so we only return that for now. + /// so we return that. + /// + /// Additionally, we return block height, hash and size to be compatible with our `zebra-checkpoints` utility. /// /// `lightwalletd` only requests blocks by height, so we don't support /// getting blocks by hash. (But we parse the height as a JSON string, not an integer). @@ -575,29 +577,29 @@ where data: None, })?; - if verbosity == 0 { - let request = zebra_state::ReadRequest::Block(hash_or_height); - let response = state - .ready() - .and_then(|service| service.call(request)) - .await - .map_err(|error| Error { - code: ErrorCode::ServerError(0), - message: error.to_string(), - data: None, - })?; + let request = zebra_state::ReadRequest::Block(hash_or_height); + let response = state + .ready() + .and_then(|service| service.call(request)) + .await + .map_err(|error| Error { + code: ErrorCode::ServerError(0), + message: error.to_string(), + data: None, + })?; - match response { - zebra_state::ReadResponse::Block(Some(block)) => { - Ok(GetBlock::Raw(block.into())) - } - zebra_state::ReadResponse::Block(None) => Err(Error { - code: MISSING_BLOCK_ERROR_CODE, - message: "Block not found".to_string(), - data: None, - }), - _ => unreachable!("unmatched response to a block request"), - } + let block = match response { + zebra_state::ReadResponse::Block(Some(block)) => Ok(block), + zebra_state::ReadResponse::Block(None) => Err(Error { + code: MISSING_BLOCK_ERROR_CODE, + message: "Block not found".to_string(), + data: None, + }), + _ => unreachable!("unmatched response to a block request"), + }?; + + if verbosity == 0 { + Ok(GetBlock::Raw(block.into())) } else if verbosity == 1 { let request = zebra_state::ReadRequest::TransactionIdsForBlock(hash_or_height); let response = state @@ -613,7 +615,14 @@ where match response { zebra_state::ReadResponse::TransactionIdsForBlock(Some(tx_ids)) => { let tx_ids = tx_ids.iter().map(|tx_id| tx_id.encode_hex()).collect(); - Ok(GetBlock::Object { tx: tx_ids }) + Ok(GetBlock::Object { + hash: block.hash(), + height: block + .coinbase_height() + .expect("all blocks should have a coinbase height"), + size: SerializedBlock::from(block).as_ref().len(), + tx: tx_ids, + }) } zebra_state::ReadResponse::TransactionIdsForBlock(None) => Err(Error { code: MISSING_BLOCK_ERROR_CODE, @@ -1182,6 +1191,13 @@ pub enum GetBlock { Raw(#[serde(with = "hex")] SerializedBlock), /// The block object. Object { + /// Requested block hash. + #[serde(with = "hex")] + hash: block::Hash, + /// Requested block height. + height: Height, + /// Requested block size. + size: usize, /// List of transaction IDs in block order, hex-encoded. tx: Vec, }, diff --git a/zebra-rpc/src/methods/tests/vectors.rs b/zebra-rpc/src/methods/tests/vectors.rs index 465917319da..ca62fd6477f 100644 --- a/zebra-rpc/src/methods/tests/vectors.rs +++ b/zebra-rpc/src/methods/tests/vectors.rs @@ -113,7 +113,10 @@ async fn rpc_getblock() { .transactions .iter() .map(|tx| tx.hash().encode_hex()) - .collect() + .collect(), + height: block.coinbase_height().unwrap(), + hash: block.hash(), + size: SerializedBlock::from(block.clone()).as_ref().len(), } ); } diff --git a/zebra-rpc/src/tests/vectors.rs b/zebra-rpc/src/tests/vectors.rs index 45eb4e2d67b..326353bb710 100644 --- a/zebra-rpc/src/tests/vectors.rs +++ b/zebra-rpc/src/tests/vectors.rs @@ -30,8 +30,11 @@ pub fn test_block_serialization() { let expected_tx = GetBlock::Object { tx: vec!["42".into()], + height: zebra_chain::block::Height(1), + hash: zebra_chain::block::Hash([0; 32]), + size: 1, }; - let expected_json = r#"{"tx":["42"]}"#; + let expected_json = r#"{"hash":"0000000000000000000000000000000000000000000000000000000000000000","height":1,"size":1,"tx":["42"]}"#; let j = serde_json::to_string(&expected_tx).unwrap(); assert_eq!(j, expected_json); diff --git a/zebra-utils/src/bin/zebra-checkpoints/main.rs b/zebra-utils/src/bin/zebra-checkpoints/main.rs index ce9dd27d517..63c53b62113 100644 --- a/zebra-utils/src/bin/zebra-checkpoints/main.rs +++ b/zebra-utils/src/bin/zebra-checkpoints/main.rs @@ -66,9 +66,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. @@ -102,8 +107,9 @@ fn main() -> Result<()> { let mut cmd = passthrough_cmd(); // get block data - cmd.args(["getblock", &x.to_string()]); + cmd.args(["getblock", &x.to_string(), "1"]); let output = cmd_output(&mut cmd)?; + // parse json let v: Value = serde_json::from_str(&output)?; From cadcf6ed195c9aa4e8768770fae3ae62757aa0f3 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Sat, 24 Dec 2022 09:47:56 -0300 Subject: [PATCH 2/9] update snapshots --- .../methods/tests/snapshots/get_block_verbose@mainnet_10.snap | 3 +++ .../methods/tests/snapshots/get_block_verbose@testnet_10.snap | 3 +++ 2 files changed, 6 insertions(+) diff --git a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@mainnet_10.snap index b9fc9794fa8..db2abe7b931 100644 --- a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@mainnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@mainnet_10.snap @@ -3,6 +3,9 @@ source: zebra-rpc/src/methods/tests/snapshot.rs expression: block --- { + "hash": "0007bc227e1c57a4a70e237cad00e7b7ce565155ab49166bc57397a26d339283", + "height": 1, + "size": 1617, "tx": [ "851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609" ] diff --git a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@testnet_10.snap index dbc2ce43d5e..86efdf8e2f8 100644 --- a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@testnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@testnet_10.snap @@ -3,6 +3,9 @@ source: zebra-rpc/src/methods/tests/snapshot.rs expression: block --- { + "hash": "025579869bcf52a989337342f5f57a84f3a28b968f7d6a8307902b065a668d23", + "height": 1, + "size": 1618, "tx": [ "f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75" ] From 0189c7531014f48cc32ead1467464cd9ffe45d89 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Sat, 24 Dec 2022 10:00:27 -0300 Subject: [PATCH 3/9] update documentation --- book/src/dev/zebra-checkpoints.md | 2 +- zebra-consensus/src/checkpoint/README.md | 4 ++-- zebra-utils/README.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/book/src/dev/zebra-checkpoints.md b/book/src/dev/zebra-checkpoints.md index 5ca2b19c158..84363be4f07 100644 --- a/book/src/dev/zebra-checkpoints.md +++ b/book/src/dev/zebra-checkpoints.md @@ -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.) diff --git a/zebra-consensus/src/checkpoint/README.md b/zebra-consensus/src/checkpoint/README.md index ddb7d1ca199..a5a47fc5d37 100644 --- a/zebra-consensus/src/checkpoint/README.md +++ b/zebra-consensus/src/checkpoint/README.md @@ -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). @@ -43,7 +43,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. diff --git a/zebra-utils/README.md b/zebra-utils/README.md index ae4730ab235..54acfbd58ff 100644 --- a/zebra-utils/README.md +++ b/zebra-utils/README.md @@ -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: From 898dcaac729da55ded62deb6bfc68a5ba4283210 Mon Sep 17 00:00:00 2001 From: arya2 Date: Mon, 2 Jan 2023 17:45:01 -0500 Subject: [PATCH 4/9] applies suggestions from code review --- zebra-rpc/src/methods.rs | 4 ++-- zebra-rpc/src/methods/tests/vectors.rs | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/zebra-rpc/src/methods.rs b/zebra-rpc/src/methods.rs index 8318108acd8..eabb84e0fa4 100644 --- a/zebra-rpc/src/methods.rs +++ b/zebra-rpc/src/methods.rs @@ -24,7 +24,7 @@ use zebra_chain::{ orchard, parameters::{ConsensusBranchId, Network, NetworkUpgrade}, sapling, - serialization::{SerializationError, ZcashDeserialize}, + serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}, transaction::{self, SerializedTransaction, Transaction, UnminedTx}, transparent::{self, Address}, }; @@ -620,7 +620,7 @@ where height: block .coinbase_height() .expect("all blocks should have a coinbase height"), - size: SerializedBlock::from(block).as_ref().len(), + size: block.zcash_serialized_size(), tx: tx_ids, }) } diff --git a/zebra-rpc/src/methods/tests/vectors.rs b/zebra-rpc/src/methods/tests/vectors.rs index ca62fd6477f..ef91b442a6d 100644 --- a/zebra-rpc/src/methods/tests/vectors.rs +++ b/zebra-rpc/src/methods/tests/vectors.rs @@ -114,9 +114,11 @@ async fn rpc_getblock() { .iter() .map(|tx| tx.hash().encode_hex()) .collect(), - height: block.coinbase_height().unwrap(), + height: block + .coinbase_height() + .expect("test block should have coinbase height"), hash: block.hash(), - size: SerializedBlock::from(block.clone()).as_ref().len(), + size: block.zcash_serialized_size(), } ); } From d5b480af07dd35233bb6be0c5644b804a0616b10 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 19 Jan 2023 15:45:42 -0300 Subject: [PATCH 5/9] irefactor zebra-checkpoints to work with zebra using deserialization of the raw block --- Cargo.lock | 1 + zebra-rpc/src/methods.rs | 64 ++++++++----------- .../get_block_verbose@mainnet_10.snap | 4 +- .../get_block_verbose@testnet_10.snap | 4 +- zebra-rpc/src/methods/tests/vectors.rs | 5 -- zebra-rpc/src/tests/vectors.rs | 5 +- zebra-utils/Cargo.toml | 1 + zebra-utils/src/bin/zebra-checkpoints/args.rs | 29 +++++++++ zebra-utils/src/bin/zebra-checkpoints/main.rs | 46 ++++++++++--- 9 files changed, 95 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74fdbaa36cb..bb639701812 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5638,6 +5638,7 @@ dependencies = [ "hex", "serde_json", "structopt", + "thiserror", "tinyvec", "tracing-error", "tracing-subscriber 0.3.16", diff --git a/zebra-rpc/src/methods.rs b/zebra-rpc/src/methods.rs index eabb84e0fa4..ff303cda9cc 100644 --- a/zebra-rpc/src/methods.rs +++ b/zebra-rpc/src/methods.rs @@ -24,7 +24,7 @@ use zebra_chain::{ orchard, parameters::{ConsensusBranchId, Network, NetworkUpgrade}, sapling, - serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}, + serialization::{SerializationError, ZcashDeserialize}, transaction::{self, SerializedTransaction, Transaction, UnminedTx}, transparent::{self, Address}, }; @@ -139,7 +139,7 @@ pub trait Rpc { /// /// With verbosity=1, [`lightwalletd` only reads the `tx` field of the /// result](https://github.com/zcash/lightwalletd/blob/dfac02093d85fb31fb9a8475b884dd6abca966c7/common/common.go#L152), - /// so we return that. + /// so we only return that for now. /// /// Additionally, we return block height, hash and size to be compatible with our `zebra-checkpoints` utility. /// @@ -577,29 +577,29 @@ where data: None, })?; - let request = zebra_state::ReadRequest::Block(hash_or_height); - let response = state - .ready() - .and_then(|service| service.call(request)) - .await - .map_err(|error| Error { - code: ErrorCode::ServerError(0), - message: error.to_string(), - data: None, - })?; - - let block = match response { - zebra_state::ReadResponse::Block(Some(block)) => Ok(block), - zebra_state::ReadResponse::Block(None) => Err(Error { - code: MISSING_BLOCK_ERROR_CODE, - message: "Block not found".to_string(), - data: None, - }), - _ => unreachable!("unmatched response to a block request"), - }?; - if verbosity == 0 { - Ok(GetBlock::Raw(block.into())) + let request = zebra_state::ReadRequest::Block(hash_or_height); + let response = state + .ready() + .and_then(|service| service.call(request)) + .await + .map_err(|error| Error { + code: ErrorCode::ServerError(0), + message: error.to_string(), + data: None, + })?; + + match response { + zebra_state::ReadResponse::Block(Some(block)) => { + Ok(GetBlock::Raw(block.into())) + } + zebra_state::ReadResponse::Block(None) => Err(Error { + code: MISSING_BLOCK_ERROR_CODE, + message: "Block not found".to_string(), + data: None, + }), + _ => unreachable!("unmatched response to a block request"), + } } else if verbosity == 1 { let request = zebra_state::ReadRequest::TransactionIdsForBlock(hash_or_height); let response = state @@ -615,14 +615,7 @@ where match response { zebra_state::ReadResponse::TransactionIdsForBlock(Some(tx_ids)) => { let tx_ids = tx_ids.iter().map(|tx_id| tx_id.encode_hex()).collect(); - Ok(GetBlock::Object { - hash: block.hash(), - height: block - .coinbase_height() - .expect("all blocks should have a coinbase height"), - size: block.zcash_serialized_size(), - tx: tx_ids, - }) + Ok(GetBlock::Object { tx: tx_ids }) } zebra_state::ReadResponse::TransactionIdsForBlock(None) => Err(Error { code: MISSING_BLOCK_ERROR_CODE, @@ -1191,13 +1184,6 @@ pub enum GetBlock { Raw(#[serde(with = "hex")] SerializedBlock), /// The block object. Object { - /// Requested block hash. - #[serde(with = "hex")] - hash: block::Hash, - /// Requested block height. - height: Height, - /// Requested block size. - size: usize, /// List of transaction IDs in block order, hex-encoded. tx: Vec, }, diff --git a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@mainnet_10.snap index db2abe7b931..8d40ccb391e 100644 --- a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@mainnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@mainnet_10.snap @@ -1,11 +1,9 @@ --- source: zebra-rpc/src/methods/tests/snapshot.rs +assertion_line: 246 expression: block --- { - "hash": "0007bc227e1c57a4a70e237cad00e7b7ce565155ab49166bc57397a26d339283", - "height": 1, - "size": 1617, "tx": [ "851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609" ] diff --git a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@testnet_10.snap index 86efdf8e2f8..4846f650a4f 100644 --- a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@testnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@testnet_10.snap @@ -1,11 +1,9 @@ --- source: zebra-rpc/src/methods/tests/snapshot.rs +assertion_line: 246 expression: block --- { - "hash": "025579869bcf52a989337342f5f57a84f3a28b968f7d6a8307902b065a668d23", - "height": 1, - "size": 1618, "tx": [ "f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75" ] diff --git a/zebra-rpc/src/methods/tests/vectors.rs b/zebra-rpc/src/methods/tests/vectors.rs index ef91b442a6d..0b8cc30a911 100644 --- a/zebra-rpc/src/methods/tests/vectors.rs +++ b/zebra-rpc/src/methods/tests/vectors.rs @@ -114,11 +114,6 @@ async fn rpc_getblock() { .iter() .map(|tx| tx.hash().encode_hex()) .collect(), - height: block - .coinbase_height() - .expect("test block should have coinbase height"), - hash: block.hash(), - size: block.zcash_serialized_size(), } ); } diff --git a/zebra-rpc/src/tests/vectors.rs b/zebra-rpc/src/tests/vectors.rs index 326353bb710..45eb4e2d67b 100644 --- a/zebra-rpc/src/tests/vectors.rs +++ b/zebra-rpc/src/tests/vectors.rs @@ -30,11 +30,8 @@ pub fn test_block_serialization() { let expected_tx = GetBlock::Object { tx: vec!["42".into()], - height: zebra_chain::block::Height(1), - hash: zebra_chain::block::Hash([0; 32]), - size: 1, }; - let expected_json = r#"{"hash":"0000000000000000000000000000000000000000000000000000000000000000","height":1,"size":1,"tx":["42"]}"#; + let expected_json = r#"{"tx":["42"]}"#; let j = serde_json::to_string(&expected_tx).unwrap(); assert_eq!(j, expected_json); diff --git a/zebra-utils/Cargo.toml b/zebra-utils/Cargo.toml index ed5837fdda5..f1c408f7437 100644 --- a/zebra-utils/Cargo.toml +++ b/zebra-utils/Cargo.toml @@ -18,6 +18,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-chain = { path = "../zebra-chain" } zebra-consensus = { path = "../zebra-consensus" } diff --git a/zebra-utils/src/bin/zebra-checkpoints/args.rs b/zebra-utils/src/bin/zebra-checkpoints/args.rs index 283b5f557a5..44bcdabfa4d 100644 --- a/zebra-utils/src/bin/zebra-checkpoints/args.rs +++ b/zebra-utils/src/bin/zebra-checkpoints/args.rs @@ -5,11 +5,40 @@ #![deny(missing_docs)] #![allow(clippy::try_err)] +use std::str::FromStr; use structopt::StructOpt; +use thiserror::Error; + +/// +#[derive(Debug)] +pub enum Mode { + Zebra, + Zcash, +} + +impl FromStr for Mode { + type Err = InvalidModeError; + + fn from_str(string: &str) -> Result { + match string.to_lowercase().as_str() { + "zebra" => Ok(Mode::Zebra), + "zcash" => Ok(Mode::Zcash), + _ => Err(InvalidModeError(string.to_owned())), + } + } +} + +#[derive(Clone, Debug, Error)] +#[error("Invalid mode: {0}")] +pub struct InvalidModeError(String); /// zebra-checkpoints arguments #[derive(Debug, StructOpt)] pub struct Args { + /// Mode + #[structopt(default_value = "zebra", short, long)] + pub mode: Mode, + /// Path to zcash-cli command #[structopt(default_value = "zcash-cli", short, long)] pub cli: String, diff --git a/zebra-utils/src/bin/zebra-checkpoints/main.rs b/zebra-utils/src/bin/zebra-checkpoints/main.rs index 63c53b62113..e12f0419a05 100644 --- a/zebra-utils/src/bin/zebra-checkpoints/main.rs +++ b/zebra-utils/src/bin/zebra-checkpoints/main.rs @@ -9,11 +9,12 @@ //! genesis block. Checkpoint heights can be chosen arbitrarily. use color_eyre::eyre::{ensure, Result}; +use hex::FromHex; use serde_json::Value; use std::process::Stdio; use structopt::StructOpt; -use zebra_chain::block; +use zebra_chain::{block, serialization::ZcashDeserializeInto}; use zebra_utils::init_tracing; #[cfg(unix)] @@ -106,19 +107,44 @@ 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(), "1"]); - let output = cmd_output(&mut cmd)?; + let (hash, height, size) = match args::Args::from_args().mode { + args::Mode::Zcash => { + // get block data + cmd.args(["getblock", &x.to_string(), "1"]); + let output = cmd_output(&mut cmd)?; - // parse json - let v: Value = serde_json::from_str(&output)?; + // 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::Mode::Zebra => { + // get block data + cmd.args(["getblock", &x.to_string(), "0"]); + let output = cmd_output(&mut cmd)?; + + let block_bytes = >::from_hex(output.trim_end_matches('\n'))?; + + let block = block_bytes + .zcash_deserialize_into::() + .expect("obtained block should deserialize"); + + ( + block.hash(), + block.coinbase_height().expect("wat"), + 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; From 670d3254ec513b690fe09a34df64c8a86cbeb2e9 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 19 Jan 2023 16:45:17 -0300 Subject: [PATCH 6/9] fix imports and derives --- zebra-utils/src/bin/zebra-checkpoints/args.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/zebra-utils/src/bin/zebra-checkpoints/args.rs b/zebra-utils/src/bin/zebra-checkpoints/args.rs index 5bc39a289b4..ddcf0b7c9bd 100644 --- a/zebra-utils/src/bin/zebra-checkpoints/args.rs +++ b/zebra-utils/src/bin/zebra-checkpoints/args.rs @@ -5,8 +5,10 @@ use structopt::StructOpt; use thiserror::Error; -/// -#[derive(Debug)] +use std::str::FromStr; + +/// Backend +#[derive(Clone, Debug, PartialEq, Eq)] pub enum Mode { Zebra, Zcash, @@ -24,7 +26,7 @@ impl FromStr for Mode { } } -#[derive(Clone, Debug, Error)] +#[derive(Debug, Error)] #[error("Invalid mode: {0}")] pub struct InvalidModeError(String); From a2067923fe56ea1fb0f4597d99ff213bddc6644e Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 19 Jan 2023 17:01:42 -0300 Subject: [PATCH 7/9] rename mode to backend --- zebra-utils/src/bin/zebra-checkpoints/args.rs | 20 +++++++++---------- zebra-utils/src/bin/zebra-checkpoints/main.rs | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/zebra-utils/src/bin/zebra-checkpoints/args.rs b/zebra-utils/src/bin/zebra-checkpoints/args.rs index ddcf0b7c9bd..9326b444263 100644 --- a/zebra-utils/src/bin/zebra-checkpoints/args.rs +++ b/zebra-utils/src/bin/zebra-checkpoints/args.rs @@ -7,20 +7,20 @@ use thiserror::Error; use std::str::FromStr; -/// Backend +/// The backend type the zebra-checkpoints utility will use to get data from. #[derive(Clone, Debug, PartialEq, Eq)] -pub enum Mode { - Zebra, - Zcash, +pub enum Backend { + Zebrad, + Zcashd, } -impl FromStr for Mode { +impl FromStr for Backend { type Err = InvalidModeError; fn from_str(string: &str) -> Result { match string.to_lowercase().as_str() { - "zebra" => Ok(Mode::Zebra), - "zcash" => Ok(Mode::Zcash), + "zebrad" => Ok(Backend::Zebrad), + "zcashd" => Ok(Backend::Zcashd), _ => Err(InvalidModeError(string.to_owned())), } } @@ -33,9 +33,9 @@ pub struct InvalidModeError(String); /// zebra-checkpoints arguments #[derive(Clone, Debug, Eq, PartialEq, StructOpt)] pub struct Args { - /// Mode - #[structopt(default_value = "zebra", short, long)] - pub mode: Mode, + /// Backend type + #[structopt(default_value = "zebrad", short, long)] + pub backend: Backend, /// Path to zcash-cli command #[structopt(default_value = "zcash-cli", short, long)] diff --git a/zebra-utils/src/bin/zebra-checkpoints/main.rs b/zebra-utils/src/bin/zebra-checkpoints/main.rs index 5f1c6ac941f..298a31089a0 100644 --- a/zebra-utils/src/bin/zebra-checkpoints/main.rs +++ b/zebra-utils/src/bin/zebra-checkpoints/main.rs @@ -112,9 +112,9 @@ fn main() -> Result<()> { // unfortunately we need to create a process for each block let mut cmd = passthrough_cmd(); - let (hash, height, size) = match args::Args::from_args().mode { - args::Mode::Zcash => { - // get block data + 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)?; @@ -129,8 +129,8 @@ fn main() -> Result<()> { (hash, height, size) } - args::Mode::Zebra => { - // get block data + 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)?; From 22f63d99494e5c9ade2f34594d18c863cb6991a6 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 19 Jan 2023 17:06:10 -0300 Subject: [PATCH 8/9] remove old stuff --- zebra-rpc/src/methods.rs | 2 -- .../methods/tests/snapshots/get_block_verbose@mainnet_10.snap | 1 - .../methods/tests/snapshots/get_block_verbose@testnet_10.snap | 1 - zebra-rpc/src/methods/tests/vectors.rs | 2 +- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/zebra-rpc/src/methods.rs b/zebra-rpc/src/methods.rs index 05ad4a08157..43b53a8e240 100644 --- a/zebra-rpc/src/methods.rs +++ b/zebra-rpc/src/methods.rs @@ -141,8 +141,6 @@ pub trait Rpc { /// result](https://github.com/zcash/lightwalletd/blob/dfac02093d85fb31fb9a8475b884dd6abca966c7/common/common.go#L152), /// so we only return that for now. /// - /// Additionally, we return block height, hash and size to be compatible with our `zebra-checkpoints` utility. - /// /// `lightwalletd` only requests blocks by height, so we don't support /// getting blocks by hash. (But we parse the height as a JSON string, not an integer). /// `lightwalletd` also does not use verbosity=2, so we don't support it. diff --git a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@mainnet_10.snap index 8d40ccb391e..b9fc9794fa8 100644 --- a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@mainnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@mainnet_10.snap @@ -1,6 +1,5 @@ --- source: zebra-rpc/src/methods/tests/snapshot.rs -assertion_line: 246 expression: block --- { diff --git a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@testnet_10.snap index 4846f650a4f..dbc2ce43d5e 100644 --- a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@testnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose@testnet_10.snap @@ -1,6 +1,5 @@ --- source: zebra-rpc/src/methods/tests/snapshot.rs -assertion_line: 246 expression: block --- { diff --git a/zebra-rpc/src/methods/tests/vectors.rs b/zebra-rpc/src/methods/tests/vectors.rs index c5ec767f067..2c23ea5f2c0 100644 --- a/zebra-rpc/src/methods/tests/vectors.rs +++ b/zebra-rpc/src/methods/tests/vectors.rs @@ -113,7 +113,7 @@ async fn rpc_getblock() { .transactions .iter() .map(|tx| tx.hash().encode_hex()) - .collect(), + .collect() } ); } From 3117bb704d9368375a1a052359f26d98f4bfd513 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 19 Jan 2023 17:25:57 -0300 Subject: [PATCH 9/9] fix docs --- zebra-consensus/src/checkpoint/README.md | 2 ++ zebra-utils/src/bin/zebra-checkpoints/main.rs | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/zebra-consensus/src/checkpoint/README.md b/zebra-consensus/src/checkpoint/README.md index a5a47fc5d37..b811e542b74 100644 --- a/zebra-consensus/src/checkpoint/README.md +++ b/zebra-consensus/src/checkpoint/README.md @@ -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 diff --git a/zebra-utils/src/bin/zebra-checkpoints/main.rs b/zebra-utils/src/bin/zebra-checkpoints/main.rs index 298a31089a0..c4db8c7838a 100644 --- a/zebra-utils/src/bin/zebra-checkpoints/main.rs +++ b/zebra-utils/src/bin/zebra-checkpoints/main.rs @@ -142,7 +142,9 @@ fn main() -> Result<()> { ( block.hash(), - block.coinbase_height().expect("wat"), + block + .coinbase_height() + .expect("block has always a coinbase height"), block_bytes.len().try_into()?, ) }