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,
};
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 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
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 {
fn max_allocation() -> u64 {
// 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},
};
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.
///
@ -77,7 +77,7 @@ impl ZcashDeserialize for Header {
// > The block version number MUST be greater than or equal to 4.
//
// 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"));
}

View File

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

View File

@ -13,14 +13,16 @@ use zebra_chain::{
block::{
self,
merkle::{self, AuthDataRoot},
Block,
Block, MAX_BLOCK_BYTES, ZCASH_BLOCK_VERSION,
},
chain_tip::ChainTip,
parameters::Network,
serialization::ZcashDeserializeInto,
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 crate::methods::{
@ -33,6 +35,7 @@ use crate::methods::{
};
pub mod config;
pub mod constants;
pub(crate) mod types;
/// getblocktemplate RPC method signatures.
@ -273,12 +276,12 @@ where
TODO: create a method Transaction::new_v5_coinbase(network, tip_height, miner_fee),
and call it here.
*/
*/
let coinbase_tx = if mempool_txs.is_empty() {
let empty_string = String::from("");
return Ok(GetBlockTemplate {
capabilities: vec![],
version: 0,
version: ZCASH_BLOCK_VERSION,
previous_block_hash: GetBlockHash([0; 32].into()),
block_commitments_hash: [0; 32].into(),
light_client_root_hash: [0; 32].into(),
@ -301,10 +304,13 @@ where
},
target: empty_string.clone(),
min_time: 0,
mutable: vec![],
nonce_range: empty_string.clone(),
sigop_limit: 0,
size_limit: 0,
mutable: constants::GET_BLOCK_TEMPLATE_MUTABLE_FIELD
.iter()
.map(ToString::to_string)
.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,
bits: empty_string,
height: 0,
@ -323,7 +329,7 @@ where
Ok(GetBlockTemplate {
capabilities: vec![],
version: 0,
version: ZCASH_BLOCK_VERSION,
previous_block_hash: GetBlockHash([0; 32].into()),
block_commitments_hash: [0; 32].into(),
@ -344,12 +350,16 @@ where
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,
size_limit: 0,
sigop_limit: MAX_BLOCK_SIGOPS,
size_limit: MAX_BLOCK_BYTES,
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,
};
/// 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)]
pub struct DefaultRoots {
/// 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.
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
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>,
/// The version of the block format.
/// Always 4 for new Zcash blocks.
//
// TODO: add a default block version constant to zebra-chain.
pub version: u32,
/// Add documentation.
/// The hash of the previous block.
#[serde(rename = "previousblockhash")]
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(with = "hex")]
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(with = "hex")]
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(with = "hex")]
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")]
pub default_roots: DefaultRoots,
@ -62,22 +74,18 @@ pub struct GetBlockTemplate {
// TODO: use DateTime32 type?
pub min_time: u32,
/// Add documentation.
/// Hardcoded list of block fields the miner is allowed to change.
pub mutable: Vec<String>,
/// Add documentation.
/// A range of valid nonces that goes from `u32::MIN` to `u32::MAX`.
#[serde(rename = "noncerange")]
pub nonce_range: String,
/// Add documentation.
///
/// The same as `MAX_BLOCK_SIGOPS`.
/// Max legacy signature operations in the block.
#[serde(rename = "sigoplimit")]
pub sigop_limit: u64,
/// Add documentation.
///
/// The same as `MAX_BLOCK_BYTES`.
/// Max block size in bytes
#[serde(rename = "sizelimit")]
pub size_limit: u64,

View File

@ -15,7 +15,9 @@ use zebra_state::LatestChainTip;
use zebra_test::mock_service::{MockService, PanicAssertion};
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,
};
@ -122,10 +124,7 @@ fn snapshot_rpc_getblockhash(block_hash: GetBlockHash, settings: &insta::Setting
}
/// Snapshot `getblocktemplate` response, using `cargo insta` and JSON serialization.
fn snapshot_rpc_getblocktemplate(
block_template: crate::methods::get_block_template_rpcs::types::get_block_template::GetBlockTemplate,
settings: &insta::Settings,
) {
fn snapshot_rpc_getblocktemplate(block_template: GetBlockTemplate, settings: &insta::Settings) {
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
assertion_line: 128
expression: block_template
---
{
"capabilities": [],
"version": 0,
"version": 4,
"previousblockhash": "0000000000000000000000000000000000000000000000000000000000000000",
"blockcommitmentshash": "0000000000000000000000000000000000000000000000000000000000000000",
"lightclientroothash": "0000000000000000000000000000000000000000000000000000000000000000",
@ -27,10 +28,14 @@ expression: block_template
},
"target": "",
"mintime": 0,
"mutable": [],
"noncerange": "",
"sigoplimit": 0,
"sizelimit": 0,
"mutable": [
"time",
"transactions",
"prevblock"
],
"noncerange": "00000000ffffffff",
"sigoplimit": 20000,
"sizelimit": 2000000,
"curtime": 0,
"bits": "",
"height": 0

View File

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

View File

@ -782,6 +782,12 @@ async fn rpc_getblockhash() {
async fn rpc_getblocktemplate() {
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();
// Create a continuous chain of mainnet blocks from genesis
@ -835,14 +841,20 @@ async fn rpc_getblocktemplate() {
.expect("unexpected error in getblocktemplate RPC call");
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.target.is_empty());
assert_eq!(get_block_template.min_time, 0);
assert!(get_block_template.mutable.is_empty());
assert!(get_block_template.nonce_range.is_empty());
assert_eq!(get_block_template.sigop_limit, 0);
assert_eq!(get_block_template.size_limit, 0);
assert_eq!(
get_block_template.mutable,
GET_BLOCK_TEMPLATE_MUTABLE_FIELD.to_vec()
);
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!(get_block_template.bits.is_empty());
assert_eq!(get_block_template.height, 0);