feature(rpc): add fixed values to getblocktemplate response (#5558)

* add fixed values to getblocktemplate rpc call response

* suggestion: Avoid new uses of lazy_static (#5559)

* Avoid using lazy_static

* Add some missing documentation

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>

* minor fixes

* move docs to struct

* add fixed values to coinbase tx

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: teor <teor@riseup.net>
This commit is contained in:
Alfredo Garcia 2022-11-08 19:55:11 -03:00 committed by GitHub
parent 4c3f04eb80
commit 4ccd0741b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 109 additions and 54 deletions

View File

@ -34,7 +34,7 @@ pub use commitment::{
ChainHistoryBlockTxAuthCommitmentHash, ChainHistoryMmrRootHash, Commitment, CommitmentError, ChainHistoryBlockTxAuthCommitmentHash, ChainHistoryMmrRootHash, Commitment, CommitmentError,
}; };
pub use hash::Hash; pub use hash::Hash;
pub use header::{BlockTimeError, CountedHeader, Header}; pub use header::{BlockTimeError, CountedHeader, Header, ZCASH_BLOCK_VERSION};
pub use height::Height; pub use height::Height;
pub use serialize::{SerializedBlock, MAX_BLOCK_BYTES}; pub use serialize::{SerializedBlock, MAX_BLOCK_BYTES};

View File

@ -146,6 +146,12 @@ const BLOCK_HEADER_LENGTH: usize =
/// A CountedHeader has BLOCK_HEADER_LENGTH bytes + 1 or more bytes for the transaction count /// A CountedHeader has BLOCK_HEADER_LENGTH bytes + 1 or more bytes for the transaction count
pub(crate) const MIN_COUNTED_HEADER_LEN: usize = BLOCK_HEADER_LENGTH + 1; pub(crate) const MIN_COUNTED_HEADER_LEN: usize = BLOCK_HEADER_LENGTH + 1;
/// The Zcash accepted block version.
///
/// The consensus rules do not force the block version to be this value but just equal or greater than it.
/// However, it is suggested that submitted block versions to be of this exact value.
pub const ZCASH_BLOCK_VERSION: u32 = 4;
impl TrustedPreallocate for CountedHeader { impl TrustedPreallocate for CountedHeader {
fn max_allocation() -> u64 { fn max_allocation() -> u64 {
// Every vector type requires a length field of at least one byte for de/serialization. // Every vector type requires a length field of at least one byte for de/serialization.

View File

@ -13,7 +13,7 @@ use crate::{
work::{difficulty::CompactDifficulty, equihash}, work::{difficulty::CompactDifficulty, equihash},
}; };
use super::{merkle, Block, CountedHeader, Hash, Header}; use super::{header::ZCASH_BLOCK_VERSION, merkle, Block, CountedHeader, Hash, Header};
/// The maximum size of a Zcash block, in bytes. /// The maximum size of a Zcash block, in bytes.
/// ///
@ -77,7 +77,7 @@ impl ZcashDeserialize for Header {
// > The block version number MUST be greater than or equal to 4. // > The block version number MUST be greater than or equal to 4.
// //
// https://zips.z.cash/protocol/protocol.pdf#blockheader // https://zips.z.cash/protocol/protocol.pdf#blockheader
if version < 4 { if version < ZCASH_BLOCK_VERSION {
return Err(SerializationError::Parse("version must be at least 4")); return Err(SerializationError::Parse("version must be at least 4"));
} }

View File

@ -46,7 +46,7 @@ pub mod chain;
#[allow(missing_docs)] #[allow(missing_docs)]
pub mod error; pub mod error;
pub use block::VerifyBlockError; pub use block::{VerifyBlockError, MAX_BLOCK_SIGOPS};
pub use chain::VerifyChainError; pub use chain::VerifyChainError;
pub use checkpoint::{ pub use checkpoint::{
CheckpointList, VerifyCheckpointError, MAX_CHECKPOINT_BYTE_COUNT, MAX_CHECKPOINT_HEIGHT_GAP, CheckpointList, VerifyCheckpointError, MAX_CHECKPOINT_BYTE_COUNT, MAX_CHECKPOINT_HEIGHT_GAP,

View File

@ -13,14 +13,16 @@ use zebra_chain::{
block::{ block::{
self, self,
merkle::{self, AuthDataRoot}, merkle::{self, AuthDataRoot},
Block, Block, MAX_BLOCK_BYTES, ZCASH_BLOCK_VERSION,
}, },
chain_tip::ChainTip, chain_tip::ChainTip,
parameters::Network, parameters::Network,
serialization::ZcashDeserializeInto, serialization::ZcashDeserializeInto,
transaction::{UnminedTx, VerifiedUnminedTx}, transaction::{UnminedTx, VerifiedUnminedTx},
}; };
use zebra_consensus::{BlockError, VerifyBlockError, VerifyChainError, VerifyCheckpointError}; use zebra_consensus::{
BlockError, VerifyBlockError, VerifyChainError, VerifyCheckpointError, MAX_BLOCK_SIGOPS,
};
use zebra_node_services::mempool; use zebra_node_services::mempool;
use crate::methods::{ use crate::methods::{
@ -33,6 +35,7 @@ use crate::methods::{
}; };
pub mod config; pub mod config;
pub mod constants;
pub(crate) mod types; pub(crate) mod types;
/// getblocktemplate RPC method signatures. /// getblocktemplate RPC method signatures.
@ -278,7 +281,7 @@ where
let empty_string = String::from(""); let empty_string = String::from("");
return Ok(GetBlockTemplate { return Ok(GetBlockTemplate {
capabilities: vec![], capabilities: vec![],
version: 0, version: ZCASH_BLOCK_VERSION,
previous_block_hash: GetBlockHash([0; 32].into()), previous_block_hash: GetBlockHash([0; 32].into()),
block_commitments_hash: [0; 32].into(), block_commitments_hash: [0; 32].into(),
light_client_root_hash: [0; 32].into(), light_client_root_hash: [0; 32].into(),
@ -301,10 +304,13 @@ where
}, },
target: empty_string.clone(), target: empty_string.clone(),
min_time: 0, min_time: 0,
mutable: vec![], mutable: constants::GET_BLOCK_TEMPLATE_MUTABLE_FIELD
nonce_range: empty_string.clone(), .iter()
sigop_limit: 0, .map(ToString::to_string)
size_limit: 0, .collect(),
nonce_range: constants::GET_BLOCK_TEMPLATE_NONCE_RANGE_FIELD.to_string(),
sigop_limit: MAX_BLOCK_SIGOPS,
size_limit: MAX_BLOCK_BYTES,
cur_time: 0, cur_time: 0,
bits: empty_string, bits: empty_string,
height: 0, height: 0,
@ -323,7 +329,7 @@ where
Ok(GetBlockTemplate { Ok(GetBlockTemplate {
capabilities: vec![], capabilities: vec![],
version: 0, version: ZCASH_BLOCK_VERSION,
previous_block_hash: GetBlockHash([0; 32].into()), previous_block_hash: GetBlockHash([0; 32].into()),
block_commitments_hash: [0; 32].into(), block_commitments_hash: [0; 32].into(),
@ -344,12 +350,16 @@ where
min_time: 0, min_time: 0,
mutable: vec![], mutable: constants::GET_BLOCK_TEMPLATE_MUTABLE_FIELD
.iter()
.map(ToString::to_string)
.collect(),
nonce_range: empty_string.clone(), nonce_range: constants::GET_BLOCK_TEMPLATE_NONCE_RANGE_FIELD.to_string(),
sigop_limit: 0, sigop_limit: MAX_BLOCK_SIGOPS,
size_limit: 0,
size_limit: MAX_BLOCK_BYTES,
cur_time: 0, cur_time: 0,

View File

@ -0,0 +1,7 @@
//! Constant values used in mining rpcs methods.
/// A range of valid nonces that goes from `u32::MIN` to `u32::MAX` as a string.
pub const GET_BLOCK_TEMPLATE_NONCE_RANGE_FIELD: &str = "00000000ffffffff";
/// A hardcoded list of fields that the miner can change from the block.
pub const GET_BLOCK_TEMPLATE_MUTABLE_FIELD: &[&str] = &["time", "transactions", "prevblock"];

View File

@ -5,7 +5,10 @@ use zebra_chain::block::{
ChainHistoryBlockTxAuthCommitmentHash, ChainHistoryMmrRootHash, ChainHistoryBlockTxAuthCommitmentHash, ChainHistoryMmrRootHash,
}; };
/// Documentation to be added in #5452 or #5455. /// The block header roots for [`GetBlockTemplate.transactions`].
///
/// If the transactions in the block template are modified, these roots must be recalculated
/// [according to the specification](https://zcash.github.io/rpc/getblocktemplate.html).
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct DefaultRoots { pub struct DefaultRoots {
/// The merkle root of the transaction IDs in the block. /// The merkle root of the transaction IDs in the block.

View File

@ -12,35 +12,47 @@ use crate::methods::{
/// Documentation to be added after we document all the individual fields. /// Documentation to be added after we document all the individual fields.
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct GetBlockTemplate { pub struct GetBlockTemplate {
/// Add documentation. /// The getblocktemplate RPC capabilities supported by Zebra.
///
/// At the moment, Zebra does not support any of the extra capabilities from the specification:
/// - `proposal`: <https://en.bitcoin.it/wiki/BIP_0023#Block_Proposal>
/// - `longpoll`: <https://en.bitcoin.it/wiki/BIP_0022#Optional:_Long_Polling>
/// - `serverlist`: <https://en.bitcoin.it/wiki/BIP_0023#Logical_Services>
pub capabilities: Vec<String>, pub capabilities: Vec<String>,
/// The version of the block format. /// The version of the block format.
/// Always 4 for new Zcash blocks. /// Always 4 for new Zcash blocks.
//
// TODO: add a default block version constant to zebra-chain.
pub version: u32, pub version: u32,
/// Add documentation. /// The hash of the previous block.
#[serde(rename = "previousblockhash")] #[serde(rename = "previousblockhash")]
pub previous_block_hash: GetBlockHash, pub previous_block_hash: GetBlockHash,
/// Add documentation. /// The block commitment for the new block's header.
///
/// Same as [`DefaultRoots.block_commitments_hash`], see that field for details.
#[serde(rename = "blockcommitmentshash")] #[serde(rename = "blockcommitmentshash")]
#[serde(with = "hex")] #[serde(with = "hex")]
pub block_commitments_hash: ChainHistoryBlockTxAuthCommitmentHash, pub block_commitments_hash: ChainHistoryBlockTxAuthCommitmentHash,
/// Add documentation. /// Legacy backwards-compatibility header root field.
///
/// Same as [`DefaultRoots.block_commitments_hash`], see that field for details.
#[serde(rename = "lightclientroothash")] #[serde(rename = "lightclientroothash")]
#[serde(with = "hex")] #[serde(with = "hex")]
pub light_client_root_hash: ChainHistoryBlockTxAuthCommitmentHash, pub light_client_root_hash: ChainHistoryBlockTxAuthCommitmentHash,
/// Add documentation. /// Legacy backwards-compatibility header root field.
///
/// Same as [`DefaultRoots.block_commitments_hash`], see that field for details.
#[serde(rename = "finalsaplingroothash")] #[serde(rename = "finalsaplingroothash")]
#[serde(with = "hex")] #[serde(with = "hex")]
pub final_sapling_root_hash: ChainHistoryBlockTxAuthCommitmentHash, pub final_sapling_root_hash: ChainHistoryBlockTxAuthCommitmentHash,
/// Add documentation. /// The block header roots for [`GetBlockTemplate.transactions`].
///
/// If the transactions in the block template are modified, these roots must be recalculated
/// [according to the specification](https://zcash.github.io/rpc/getblocktemplate.html).
#[serde(rename = "defaultroots")] #[serde(rename = "defaultroots")]
pub default_roots: DefaultRoots, pub default_roots: DefaultRoots,
@ -62,22 +74,18 @@ pub struct GetBlockTemplate {
// TODO: use DateTime32 type? // TODO: use DateTime32 type?
pub min_time: u32, pub min_time: u32,
/// Add documentation. /// Hardcoded list of block fields the miner is allowed to change.
pub mutable: Vec<String>, pub mutable: Vec<String>,
/// Add documentation. /// A range of valid nonces that goes from `u32::MIN` to `u32::MAX`.
#[serde(rename = "noncerange")] #[serde(rename = "noncerange")]
pub nonce_range: String, pub nonce_range: String,
/// Add documentation. /// Max legacy signature operations in the block.
///
/// The same as `MAX_BLOCK_SIGOPS`.
#[serde(rename = "sigoplimit")] #[serde(rename = "sigoplimit")]
pub sigop_limit: u64, pub sigop_limit: u64,
/// Add documentation. /// Max block size in bytes
///
/// The same as `MAX_BLOCK_BYTES`.
#[serde(rename = "sizelimit")] #[serde(rename = "sizelimit")]
pub size_limit: u64, pub size_limit: u64,

View File

@ -15,7 +15,9 @@ use zebra_state::LatestChainTip;
use zebra_test::mock_service::{MockService, PanicAssertion}; use zebra_test::mock_service::{MockService, PanicAssertion};
use crate::methods::{ use crate::methods::{
get_block_template_rpcs::types::{hex_data::HexData, submit_block}, get_block_template_rpcs::types::{
get_block_template::GetBlockTemplate, hex_data::HexData, submit_block,
},
GetBlockHash, GetBlockTemplateRpc, GetBlockTemplateRpcImpl, GetBlockHash, GetBlockTemplateRpc, GetBlockTemplateRpcImpl,
}; };
@ -122,10 +124,7 @@ fn snapshot_rpc_getblockhash(block_hash: GetBlockHash, settings: &insta::Setting
} }
/// Snapshot `getblocktemplate` response, using `cargo insta` and JSON serialization. /// Snapshot `getblocktemplate` response, using `cargo insta` and JSON serialization.
fn snapshot_rpc_getblocktemplate( fn snapshot_rpc_getblocktemplate(block_template: GetBlockTemplate, settings: &insta::Settings) {
block_template: crate::methods::get_block_template_rpcs::types::get_block_template::GetBlockTemplate,
settings: &insta::Settings,
) {
settings.bind(|| insta::assert_json_snapshot!("get_block_template", block_template)); settings.bind(|| insta::assert_json_snapshot!("get_block_template", block_template));
} }

View File

@ -1,10 +1,11 @@
--- ---
source: zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs source: zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs
assertion_line: 128
expression: block_template expression: block_template
--- ---
{ {
"capabilities": [], "capabilities": [],
"version": 0, "version": 4,
"previousblockhash": "0000000000000000000000000000000000000000000000000000000000000000", "previousblockhash": "0000000000000000000000000000000000000000000000000000000000000000",
"blockcommitmentshash": "0000000000000000000000000000000000000000000000000000000000000000", "blockcommitmentshash": "0000000000000000000000000000000000000000000000000000000000000000",
"lightclientroothash": "0000000000000000000000000000000000000000000000000000000000000000", "lightclientroothash": "0000000000000000000000000000000000000000000000000000000000000000",
@ -27,10 +28,14 @@ expression: block_template
}, },
"target": "", "target": "",
"mintime": 0, "mintime": 0,
"mutable": [], "mutable": [
"noncerange": "", "time",
"sigoplimit": 0, "transactions",
"sizelimit": 0, "prevblock"
],
"noncerange": "00000000ffffffff",
"sigoplimit": 20000,
"sizelimit": 2000000,
"curtime": 0, "curtime": 0,
"bits": "", "bits": "",
"height": 0 "height": 0

View File

@ -1,10 +1,11 @@
--- ---
source: zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs source: zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs
assertion_line: 128
expression: block_template expression: block_template
--- ---
{ {
"capabilities": [], "capabilities": [],
"version": 0, "version": 4,
"previousblockhash": "0000000000000000000000000000000000000000000000000000000000000000", "previousblockhash": "0000000000000000000000000000000000000000000000000000000000000000",
"blockcommitmentshash": "0000000000000000000000000000000000000000000000000000000000000000", "blockcommitmentshash": "0000000000000000000000000000000000000000000000000000000000000000",
"lightclientroothash": "0000000000000000000000000000000000000000000000000000000000000000", "lightclientroothash": "0000000000000000000000000000000000000000000000000000000000000000",
@ -27,10 +28,14 @@ expression: block_template
}, },
"target": "", "target": "",
"mintime": 0, "mintime": 0,
"mutable": [], "mutable": [
"noncerange": "", "time",
"sigoplimit": 0, "transactions",
"sizelimit": 0, "prevblock"
],
"noncerange": "00000000ffffffff",
"sigoplimit": 20000,
"sizelimit": 2000000,
"curtime": 0, "curtime": 0,
"bits": "", "bits": "",
"height": 0 "height": 0

View File

@ -782,6 +782,12 @@ async fn rpc_getblockhash() {
async fn rpc_getblocktemplate() { async fn rpc_getblocktemplate() {
use std::panic; use std::panic;
use crate::methods::get_block_template_rpcs::constants::{
GET_BLOCK_TEMPLATE_MUTABLE_FIELD, GET_BLOCK_TEMPLATE_NONCE_RANGE_FIELD,
};
use zebra_chain::block::{MAX_BLOCK_BYTES, ZCASH_BLOCK_VERSION};
use zebra_consensus::MAX_BLOCK_SIGOPS;
let _init_guard = zebra_test::init(); let _init_guard = zebra_test::init();
// Create a continuous chain of mainnet blocks from genesis // Create a continuous chain of mainnet blocks from genesis
@ -835,14 +841,20 @@ async fn rpc_getblocktemplate() {
.expect("unexpected error in getblocktemplate RPC call"); .expect("unexpected error in getblocktemplate RPC call");
assert!(get_block_template.capabilities.is_empty()); assert!(get_block_template.capabilities.is_empty());
assert_eq!(get_block_template.version, 0); assert_eq!(get_block_template.version, ZCASH_BLOCK_VERSION);
assert!(get_block_template.transactions.is_empty()); assert!(get_block_template.transactions.is_empty());
assert!(get_block_template.target.is_empty()); assert!(get_block_template.target.is_empty());
assert_eq!(get_block_template.min_time, 0); assert_eq!(get_block_template.min_time, 0);
assert!(get_block_template.mutable.is_empty()); assert_eq!(
assert!(get_block_template.nonce_range.is_empty()); get_block_template.mutable,
assert_eq!(get_block_template.sigop_limit, 0); GET_BLOCK_TEMPLATE_MUTABLE_FIELD.to_vec()
assert_eq!(get_block_template.size_limit, 0); );
assert_eq!(
get_block_template.nonce_range,
GET_BLOCK_TEMPLATE_NONCE_RANGE_FIELD
);
assert_eq!(get_block_template.sigop_limit, MAX_BLOCK_SIGOPS);
assert_eq!(get_block_template.size_limit, MAX_BLOCK_BYTES);
assert_eq!(get_block_template.cur_time, 0); assert_eq!(get_block_template.cur_time, 0);
assert!(get_block_template.bits.is_empty()); assert!(get_block_template.bits.is_empty());
assert_eq!(get_block_template.height, 0); assert_eq!(get_block_template.height, 0);