change(rpc): Match `zcashd`'s block template exactly (#5867)

* Make Zebra's getblocktemplate like zcashd's

* Update snapshots

* Add missing docs

* Fix typo

* Sort coinbase outputs by serialized script for zcashd

* Sort excluding the length byte, make transaction order always stable

* Update snapshots

* Explain that `zcashd` doesn't seem to have a fixed transaction order
This commit is contained in:
teor 2022-12-20 04:52:43 +10:00 committed by GitHub
parent b8448c7eed
commit b08a0b6f08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 285 additions and 108 deletions

View File

@ -20,6 +20,10 @@ impl Transaction {
//
// These consensus rules apply to v5 coinbase transactions after NU5 activation:
//
// > If effectiveVersion ≥ 5 then this condition MUST hold:
// > tx_in_count > 0 or nSpendsSapling > 0 or
// > (nActionsOrchard > 0 and enableSpendsOrchard = 1).
//
// > A coinbase transaction for a block at block height greater than 0 MUST have
// > a script that, as its first item, encodes the block height height as follows. ...
// > let heightBytes be the signed little-endian representation of height,
@ -49,24 +53,34 @@ impl Transaction {
// > the value in zatoshi of block subsidy plus the transaction fees
// > paid by transactions in this block.
//
// > If effectiveVersion ≥ 5 then this condition MUST hold:
// > tx_out_count > 0 or nOutputsSapling > 0 or
// > (nActionsOrchard > 0 and enableOutputsOrchard = 1).
//
// <https://zips.z.cash/protocol/protocol.pdf#txnconsensus>
let outputs = outputs
let outputs: Vec<_> = outputs
.into_iter()
.map(|(amount, lock_script)| transparent::Output::new_coinbase(amount, lock_script))
.collect();
assert!(
!outputs.is_empty(),
"invalid coinbase transaction: must have at least one output"
);
Transaction::V5 {
// > The transaction version number MUST be 4 or 5. ...
// > If the transaction version number is 5 then the version group ID MUST be 0x26A7270A.
// > If the transaction version number is 5 then the version group ID
// > MUST be 0x26A7270A.
// > If effectiveVersion ≥ 5, the nConsensusBranchId field MUST match the consensus
// > branch ID used for SIGHASH transaction hashes, as specified in [ZIP-244].
network_upgrade: NetworkUpgrade::current(network, height),
// There is no documented consensus rule for the lock time field in coinbase transactions,
// so we just leave it unlocked. (We could also set it to `height`.)
// There is no documented consensus rule for the lock time field in coinbase
// transactions, so we just leave it unlocked. (We could also set it to `height`.)
lock_time: LockTime::unlocked(),
// > The nExpiryHeight field of a coinbase transaction MUST be equal to its block height.
// > The nExpiryHeight field of a coinbase transaction MUST be equal to its
// > block height.
expiry_height: height,
inputs,
@ -83,4 +97,62 @@ impl Transaction {
orchard_shielded_data: None,
}
}
/// Returns a new version 4 coinbase transaction for `network` and `height`,
/// which contains the specified `outputs`.
///
/// If `like_zcashd` is true, try to match the coinbase transactions generated by `zcashd`
/// in the `getblocktemplate` RPC.
pub fn new_v4_coinbase(
_network: Network,
height: Height,
outputs: impl IntoIterator<Item = (Amount<NonNegative>, transparent::Script)>,
like_zcashd: bool,
) -> Transaction {
// `zcashd` includes an extra byte after the coinbase height in the coinbase data,
// and a sequence number of u32::MAX.
let mut extra_data = None;
let mut sequence = None;
if like_zcashd {
extra_data = Some(vec![0x00]);
sequence = Some(u32::MAX);
}
// # Consensus
//
// See the other consensus rules above in new_v5_coinbase().
//
// > If effectiveVersion < 5, then at least one of tx_in_count, nSpendsSapling,
// > and nJoinSplit MUST be nonzero.
let inputs = vec![transparent::Input::new_coinbase(
height, extra_data, sequence,
)];
// > If effectiveVersion < 5, then at least one of tx_out_count, nOutputsSapling,
// > and nJoinSplit MUST be nonzero.
let outputs: Vec<_> = outputs
.into_iter()
.map(|(amount, lock_script)| transparent::Output::new_coinbase(amount, lock_script))
.collect();
assert!(
!outputs.is_empty(),
"invalid coinbase transaction: must have at least one output"
);
// > The transaction version number MUST be 4 or 5. ...
// > If the transaction version number is 4 then the version group ID MUST be 0x892F2085.
Transaction::V4 {
lock_time: LockTime::unlocked(),
expiry_height: height,
inputs,
outputs,
// Zebra does not support shielded coinbase yet.
joinsplit_data: None,
sapling_shielded_data: None,
}
}
}

View File

@ -990,7 +990,9 @@ impl TrustedPreallocate for transparent::Output {
/// A serialized transaction.
///
/// Stores bytes that are guaranteed to be deserializable into a [`Transaction`].
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
///
/// Sorts in lexicographic order of the transaction's serialized data.
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SerializedTransaction {
bytes: Vec<u8>,
}

View File

@ -9,7 +9,7 @@ use crate::serialization::{
};
/// An encoding of a Bitcoin script.
#[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
#[cfg_attr(
any(test, feature = "proptest-impl"),
derive(proptest_derive::Arbitrary)

View File

@ -2,6 +2,8 @@
//!
//! [7.8]: https://zips.z.cash/protocol/protocol.pdf#subsidies
use std::{collections::HashMap, str::FromStr};
use zebra_chain::{
amount::{Amount, Error, NonNegative},
block::Height,
@ -12,8 +14,6 @@ use zebra_chain::{
use crate::{block::subsidy::general::block_subsidy, parameters::subsidy::*};
use std::{collections::HashMap, str::FromStr};
#[cfg(test)]
mod tests;

View File

@ -47,9 +47,11 @@ pub mod chain;
pub mod error;
pub use block::{
subsidy::funding_streams::funding_stream_address,
subsidy::funding_streams::funding_stream_values, subsidy::funding_streams::new_coinbase_script,
subsidy::general::miner_subsidy, VerifyBlockError, MAX_BLOCK_SIGOPS,
subsidy::{
funding_streams::{funding_stream_address, funding_stream_values, new_coinbase_script},
general::miner_subsidy,
},
VerifyBlockError, MAX_BLOCK_SIGOPS,
};
pub use chain::VerifyChainError;
pub use checkpoint::{
@ -57,6 +59,7 @@ pub use checkpoint::{
};
pub use config::Config;
pub use error::BlockError;
pub use parameters::FundingStreamReceiver;
pub use primitives::{ed25519, groth16, halo2, redjubjub, redpallas};
/// A boxed [`std::error::Error`].

View File

@ -48,8 +48,13 @@ pub const FIRST_HALVING_TESTNET: Height = Height(1_116_000);
/// The funding stream receiver categories.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum FundingStreamReceiver {
/// The Electric Coin Company (Bootstrap Foundation) funding stream.
Ecc,
/// The Zcash Foundation funding stream.
ZcashFoundation,
/// The Major Grants (Zcash Community Grants) funding stream.
MajorGrants,
}

View File

@ -317,6 +317,11 @@ where
&self,
parameters: Option<get_block_template::JsonParameters>,
) -> BoxFuture<Result<GetBlockTemplate>> {
// Should we generate coinbase transactions that are exactly like zcashd's?
//
// This is useful for testing, but either way Zebra should obey the consensus rules.
const COINBASE_LIKE_ZCASHD: bool = true;
// Clone Config
let network = self.network;
let miner_address = self.miner_address;
@ -549,6 +554,7 @@ where
next_block_height,
miner_address,
mempool_txs,
COINBASE_LIKE_ZCASHD,
)
.await;
@ -563,16 +569,17 @@ where
miner_address,
&mempool_txs,
chain_tip_and_local_time.history_tree.clone(),
COINBASE_LIKE_ZCASHD,
);
let response = GetBlockTemplate::new(
next_block_height,
&chain_tip_and_local_time,
server_long_poll_id,
coinbase_txn,
&mempool_txs,
default_roots,
submit_old,
COINBASE_LIKE_ZCASHD,
);
Ok(response)

View File

@ -1,6 +1,6 @@
//! Support functions for the `get_block_template()` RPC.
use std::{iter, sync::Arc};
use std::{collections::HashMap, iter, sync::Arc};
use jsonrpc_core::{Error, ErrorCode, Result};
use tower::{Service, ServiceExt};
@ -17,7 +17,9 @@ use zebra_chain::{
transaction::{Transaction, UnminedTx, VerifiedUnminedTx},
transparent,
};
use zebra_consensus::{funding_stream_address, funding_stream_values, miner_subsidy};
use zebra_consensus::{
funding_stream_address, funding_stream_values, miner_subsidy, FundingStreamReceiver,
};
use zebra_node_services::mempool;
use zebra_state::GetBlockTemplateChainInfo;
@ -175,16 +177,21 @@ where
// - Response processing
/// Generates and returns the coinbase transaction and default roots.
///
/// If `like_zcashd` is true, try to match the coinbase transactions generated by `zcashd`
/// in the `getblocktemplate` RPC.
pub fn generate_coinbase_and_roots(
network: Network,
height: Height,
miner_address: transparent::Address,
mempool_txs: &[VerifiedUnminedTx],
history_tree: Arc<zebra_chain::history_tree::HistoryTree>,
like_zcashd: bool,
) -> (TransactionTemplate<NegativeOrZero>, DefaultRoots) {
// Generate the coinbase transaction
let miner_fee = calculate_miner_fee(mempool_txs);
let coinbase_txn = generate_coinbase_transaction(network, height, miner_address, miner_fee);
let coinbase_txn =
generate_coinbase_transaction(network, height, miner_address, miner_fee, like_zcashd);
// Calculate block default roots
//
@ -199,15 +206,23 @@ pub fn generate_coinbase_and_roots(
// - Coinbase transaction processing
/// Returns a coinbase transaction for the supplied parameters.
///
/// If `like_zcashd` is true, try to match the coinbase transactions generated by `zcashd`
/// in the `getblocktemplate` RPC.
pub fn generate_coinbase_transaction(
network: Network,
height: Height,
miner_address: transparent::Address,
miner_fee: Amount<NonNegative>,
like_zcashd: bool,
) -> UnminedTx {
let outputs = standard_coinbase_outputs(network, height, miner_address, miner_fee);
let outputs = standard_coinbase_outputs(network, height, miner_address, miner_fee, like_zcashd);
Transaction::new_v5_coinbase(network, height, outputs).into()
if like_zcashd {
Transaction::new_v4_coinbase(network, height, outputs, like_zcashd).into()
} else {
Transaction::new_v5_coinbase(network, height, outputs).into()
}
}
/// Returns the total miner fee for `mempool_txs`.
@ -225,22 +240,32 @@ pub fn calculate_miner_fee(mempool_txs: &[VerifiedUnminedTx]) -> Amount<NonNegat
/// for `network`, `height` and `miner_fee`.
///
/// Only works for post-Canopy heights.
///
/// If `like_zcashd` is true, try to match the coinbase transactions generated by `zcashd`
/// in the `getblocktemplate` RPC.
pub fn standard_coinbase_outputs(
network: Network,
height: Height,
miner_address: transparent::Address,
miner_fee: Amount<NonNegative>,
like_zcashd: bool,
) -> Vec<(Amount<NonNegative>, transparent::Script)> {
let funding_streams = funding_stream_values(height, network)
.expect("funding stream value calculations are valid for reasonable chain heights");
let mut funding_streams: Vec<(Amount<NonNegative>, transparent::Address)> = funding_streams
.iter()
.map(|(receiver, amount)| (*amount, funding_stream_address(height, network, *receiver)))
// Optional TODO: move this into a zebra_consensus function?
let funding_streams: HashMap<
FundingStreamReceiver,
(Amount<NonNegative>, transparent::Address),
> = funding_streams
.into_iter()
.map(|(receiver, amount)| {
(
receiver,
(amount, funding_stream_address(height, network, receiver)),
)
})
.collect();
// The HashMap returns funding streams in an arbitrary order,
// but Zebra's snapshot tests expect the same order every time.
funding_streams.sort_by_key(|(amount, _address)| *amount);
let miner_reward = miner_subsidy(height, network)
.expect("reward calculations are valid for reasonable chain heights")
@ -248,13 +273,45 @@ pub fn standard_coinbase_outputs(
let miner_reward =
miner_reward.expect("reward calculations are valid for reasonable chain heights");
let mut coinbase_outputs = funding_streams;
combine_coinbase_outputs(funding_streams, miner_address, miner_reward, like_zcashd)
}
/// Combine the miner reward and funding streams into a list of coinbase amounts and addresses.
///
/// If `like_zcashd` is true, try to match the coinbase transactions generated by `zcashd`
/// in the `getblocktemplate` RPC.
fn combine_coinbase_outputs(
funding_streams: HashMap<FundingStreamReceiver, (Amount<NonNegative>, transparent::Address)>,
miner_address: transparent::Address,
miner_reward: Amount<NonNegative>,
like_zcashd: bool,
) -> Vec<(Amount<NonNegative>, transparent::Script)> {
// Combine all the funding streams with the miner reward.
let mut coinbase_outputs: Vec<(Amount<NonNegative>, transparent::Address)> = funding_streams
.into_iter()
.map(|(_receiver, (amount, address))| (amount, address))
.collect();
coinbase_outputs.push((miner_reward, miner_address));
coinbase_outputs
let mut coinbase_outputs: Vec<(Amount<NonNegative>, transparent::Script)> = coinbase_outputs
.iter()
.map(|(amount, address)| (*amount, address.create_script_from_address()))
.collect()
.collect();
// The HashMap returns funding streams in an arbitrary order,
// but Zebra's snapshot tests expect the same order every time.
if like_zcashd {
// zcashd sorts outputs in serialized data order, excluding the length field
coinbase_outputs.sort_by_key(|(_amount, script)| script.clone());
} else {
// Zebra sorts by amount then script.
//
// Since the sort is stable, equal amounts will remain sorted by script.
coinbase_outputs.sort_by_key(|(_amount, script)| script.clone());
coinbase_outputs.sort_by_key(|(amount, _script)| *amount);
}
coinbase_outputs
}
// - Transaction roots processing

View File

@ -2,7 +2,7 @@
use zebra_chain::{
amount,
block::{ChainHistoryBlockTxAuthCommitmentHash, Height, MAX_BLOCK_BYTES, ZCASH_BLOCK_VERSION},
block::{ChainHistoryBlockTxAuthCommitmentHash, MAX_BLOCK_BYTES, ZCASH_BLOCK_VERSION},
serialization::DateTime32,
transaction::VerifiedUnminedTx,
work::difficulty::{CompactDifficulty, ExpandedDifficulty},
@ -165,17 +165,36 @@ impl GetBlockTemplate {
/// Returns a new [`GetBlockTemplate`] struct, based on the supplied arguments and defaults.
///
/// The result of this method only depends on the supplied arguments and constants.
///
/// If `like_zcashd` is true, try to match the coinbase transactions generated by `zcashd`
/// in the `getblocktemplate` RPC.
pub fn new(
next_block_height: Height,
chain_tip_and_local_time: &GetBlockTemplateChainInfo,
long_poll_id: LongPollId,
coinbase_txn: TransactionTemplate<amount::NegativeOrZero>,
mempool_txs: &[VerifiedUnminedTx],
default_roots: DefaultRoots,
submit_old: Option<bool>,
like_zcashd: bool,
) -> Self {
// Calculate the next block height.
let next_block_height =
(chain_tip_and_local_time.tip_height + 1).expect("tip is far below Height::MAX");
// Convert transactions into TransactionTemplates
let mempool_txs = mempool_txs.iter().map(Into::into).collect();
let mut mempool_txs: Vec<TransactionTemplate<amount::NonNegative>> =
mempool_txs.iter().map(Into::into).collect();
// Transaction selection returns transactions in an arbitrary order,
// but Zebra's snapshot tests expect the same order every time.
if like_zcashd {
// Sort in serialized data order, excluding the length byte.
// `zcashd` sometimes seems to do this, but other times the order is arbitrary.
mempool_txs.sort_by_key(|tx| tx.data.clone());
} else {
// Sort by hash, this is faster.
mempool_txs.sort_by_key(|tx| tx.hash.bytes_in_display_order());
}
// Convert difficulty
let target = chain_tip_and_local_time

View File

@ -15,13 +15,13 @@ use zebra_chain::{
amount::NegativeOrZero,
block::{Height, MAX_BLOCK_BYTES},
parameters::Network,
transaction::{Transaction, VerifiedUnminedTx},
transaction::VerifiedUnminedTx,
transparent,
};
use zebra_consensus::MAX_BLOCK_SIGOPS;
use crate::methods::get_block_template_rpcs::{
get_block_template::standard_coinbase_outputs, types::transaction::TransactionTemplate,
get_block_template::generate_coinbase_transaction, types::transaction::TransactionTemplate,
};
/// The ZIP-317 recommended limit on the number of unpaid actions per block.
@ -34,6 +34,8 @@ pub const BLOCK_PRODUCTION_UNPAID_ACTION_LIMIT: u32 = 50;
/// The fake coinbase transaction's serialized size and sigops must be at least as large
/// as the real coinbase transaction. (The real coinbase transaction depends on the total
/// fees from the transactions returned by this function.)
/// If `like_zcashd` is true, try to match the coinbase transactions generated by `zcashd`
/// in the `getblocktemplate` RPC.
///
/// Returns selected transactions from `mempool_txs`.
///
@ -43,10 +45,12 @@ pub async fn select_mempool_transactions(
next_block_height: Height,
miner_address: transparent::Address,
mempool_txs: Vec<VerifiedUnminedTx>,
like_zcashd: bool,
) -> Vec<VerifiedUnminedTx> {
// Use a fake coinbase transaction to break the dependency between transaction
// selection, the miner fee, and the fee payment in the coinbase transaction.
let fake_coinbase_tx = fake_coinbase_transaction(network, next_block_height, miner_address);
let fake_coinbase_tx =
fake_coinbase_transaction(network, next_block_height, miner_address, like_zcashd);
// Setup the transaction lists.
let (conventional_fee_txs, low_fee_txs): (Vec<_>, Vec<_>) = mempool_txs
@ -105,10 +109,14 @@ pub async fn select_mempool_transactions(
///
/// This transaction's serialized size and sigops must be at least as large as the real coinbase
/// transaction with the correct height and fee.
///
/// If `like_zcashd` is true, try to match the coinbase transactions generated by `zcashd`
/// in the `getblocktemplate` RPC.
pub fn fake_coinbase_transaction(
network: Network,
block_height: Height,
height: Height,
miner_address: transparent::Address,
like_zcashd: bool,
) -> TransactionTemplate<NegativeOrZero> {
// Block heights are encoded as variable-length (script) and `u32` (lock time, expiry height).
// They can also change the `u32` consensus branch id.
@ -121,8 +129,8 @@ pub fn fake_coinbase_transaction(
// https://developer.bitcoin.org/reference/transactions.html#txout-a-transaction-output
let miner_fee = 1.try_into().expect("amount is valid and non-negative");
let outputs = standard_coinbase_outputs(network, block_height, miner_address, miner_fee);
let coinbase_tx = Transaction::new_v5_coinbase(network, block_height, outputs).into();
let coinbase_tx =
generate_coinbase_transaction(network, height, miner_address, miner_fee, like_zcashd);
TransactionTemplate::from_coinbase(&coinbase_tx, miner_fee)
}

View File

@ -2,22 +2,17 @@
source: zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs
expression: coinbase_tx
---
V5(
network_upgrade: Nu5,
lock_time: Height(Height(0)),
expiry_height: Height(1687105),
V4(
inputs: [
Coinbase(
height: Height(1687105),
data: CoinbaseData([]),
sequence: 0,
data: CoinbaseData([
0,
]),
sequence: 4294967295,
),
],
outputs: [
Output(
value: 15625000,
lock_script: Script("a914d45cb1adffb5215a42720532a076f02c7c778c9087"),
),
Output(
value: 21875000,
lock_script: Script("a91469a9f95a98fe581b6eb52841ef4806dc4402eb9087"),
@ -30,7 +25,13 @@ V5(
value: 250000000,
lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"),
),
Output(
value: 15625000,
lock_script: Script("a914d45cb1adffb5215a42720532a076f02c7c778c9087"),
),
],
lock_time: Height(Height(0)),
expiry_height: Height(1687105),
joinsplit_data: None,
sapling_shielded_data: None,
orchard_shielded_data: None,
)

View File

@ -2,15 +2,14 @@
source: zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs
expression: coinbase_tx
---
V5(
network_upgrade: Nu5,
lock_time: Height(Height(0)),
expiry_height: Height(1842421),
V4(
inputs: [
Coinbase(
height: Height(1842421),
data: CoinbaseData([]),
sequence: 0,
data: CoinbaseData([
0,
]),
sequence: 4294967295,
),
],
outputs: [
@ -31,6 +30,8 @@ V5(
lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"),
),
],
lock_time: Height(Height(0)),
expiry_height: Height(1842421),
joinsplit_data: None,
sapling_shielded_data: None,
orchard_shielded_data: None,
)

View File

@ -6,20 +6,20 @@ expression: block_template
"capabilities": [],
"version": 4,
"previousblockhash": "0000000000d723156d9b65ffcf4984da7a19675ed7e2f06d9e5d5188af087bf8",
"blockcommitmentshash": "fe03d8236b0835c758f59d279230ebaee2128754413103b9edb17c07451c2c82",
"lightclientroothash": "fe03d8236b0835c758f59d279230ebaee2128754413103b9edb17c07451c2c82",
"finalsaplingroothash": "fe03d8236b0835c758f59d279230ebaee2128754413103b9edb17c07451c2c82",
"blockcommitmentshash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a",
"lightclientroothash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a",
"finalsaplingroothash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a",
"defaultroots": {
"merkleroot": "6b370584714ab567c9c014ce72d325ab6c5927e181ac891acb35e6d4b6cc19a1",
"merkleroot": "e049ed10466f566a045702ad712bbb596c6863cd08cdb4646da749b2287bc219",
"chainhistoryroot": "94470fa66ebd1a5fdb109a5aa3f3204f14de3a42135e71aa7f4c44055847e0b5",
"authdataroot": "0dbb78de9fdcd494307971e36dd049fc82d0ee9ee53aec8fd2a54dc0e426289b",
"blockcommitmentshash": "fe03d8236b0835c758f59d279230ebaee2128754413103b9edb17c07451c2c82"
"authdataroot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"blockcommitmentshash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a"
},
"transactions": [],
"coinbasetxn": {
"data": "050000800a27a726b4d0d6c20000000041be1900010000000000000000000000000000000000000000000000000000000000000000ffffffff040341be190000000004286bee000000000017a914d45cb1adffb5215a42720532a076f02c7c778c908738c94d010000000017a91469a9f95a98fe581b6eb52841ef4806dc4402eb908740787d010000000017a914931fec54c1fea86e574462cc32013f5400b891298780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad87000000",
"hash": "6b370584714ab567c9c014ce72d325ab6c5927e181ac891acb35e6d4b6cc19a1",
"authdigest": "0dbb78de9fdcd494307971e36dd049fc82d0ee9ee53aec8fd2a54dc0e426289b",
"data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff050341be1900ffffffff0438c94d010000000017a91469a9f95a98fe581b6eb52841ef4806dc4402eb908740787d010000000017a914931fec54c1fea86e574462cc32013f5400b891298780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad87286bee000000000017a914d45cb1adffb5215a42720532a076f02c7c778c90870000000041be19000000000000000000000000",
"hash": "e049ed10466f566a045702ad712bbb596c6863cd08cdb4646da749b2287bc219",
"authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"depends": [],
"fee": 0,
"sigops": 0,

View File

@ -6,20 +6,20 @@ expression: block_template
"capabilities": [],
"version": 4,
"previousblockhash": "0000000000d723156d9b65ffcf4984da7a19675ed7e2f06d9e5d5188af087bf8",
"blockcommitmentshash": "cb1f1c6a5ad5ff9c4a170e3b747a24f3aec79817adba9a9451f19914481bb422",
"lightclientroothash": "cb1f1c6a5ad5ff9c4a170e3b747a24f3aec79817adba9a9451f19914481bb422",
"finalsaplingroothash": "cb1f1c6a5ad5ff9c4a170e3b747a24f3aec79817adba9a9451f19914481bb422",
"blockcommitmentshash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792",
"lightclientroothash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792",
"finalsaplingroothash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792",
"defaultroots": {
"merkleroot": "623400cc122baa015d3a4209f5903ebe215170c7e6e74831dce8372c5fd5b3cc",
"merkleroot": "f1f2db76c33c4a81f799d0c5cfba83c99c20cc8c51958a615d410fe7fbf92b34",
"chainhistoryroot": "03bc75f00c307a05aed2023819e18c2672cbe15fbd3200944997def141967387",
"authdataroot": "a44375f0c0dd5ba612bd7b0efd77683cde8edf5055aff9fbfda443cc8d46bd3e",
"blockcommitmentshash": "cb1f1c6a5ad5ff9c4a170e3b747a24f3aec79817adba9a9451f19914481bb422"
"authdataroot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"blockcommitmentshash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792"
},
"transactions": [],
"coinbasetxn": {
"data": "050000800a27a726b4d0d6c200000000f51c1c00010000000000000000000000000000000000000000000000000000000000000000ffffffff0403f51c1c0000000004286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8738c94d010000000017a9144e3f0d9a33a2721604cbae2de8d9171e21f8fbe48740787d010000000017a91471e1df05024288a00802de81e08c437859586c878780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad87000000",
"hash": "623400cc122baa015d3a4209f5903ebe215170c7e6e74831dce8372c5fd5b3cc",
"authdigest": "a44375f0c0dd5ba612bd7b0efd77683cde8edf5055aff9fbfda443cc8d46bd3e",
"data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0503f51c1c00ffffffff04286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8738c94d010000000017a9144e3f0d9a33a2721604cbae2de8d9171e21f8fbe48740787d010000000017a91471e1df05024288a00802de81e08c437859586c878780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad8700000000f51c1c000000000000000000000000",
"hash": "f1f2db76c33c4a81f799d0c5cfba83c99c20cc8c51958a615d410fe7fbf92b34",
"authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"depends": [],
"fee": 0,
"sigops": 0,

View File

@ -2,22 +2,17 @@
source: zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs
expression: coinbase_tx
---
V5(
network_upgrade: Nu5,
lock_time: Height(Height(0)),
expiry_height: Height(1687105),
V4(
inputs: [
Coinbase(
height: Height(1687105),
data: CoinbaseData([]),
sequence: 0,
data: CoinbaseData([
0,
]),
sequence: 4294967295,
),
],
outputs: [
Output(
value: 15625000,
lock_script: Script("a914d45cb1adffb5215a42720532a076f02c7c778c9087"),
),
Output(
value: 21875000,
lock_script: Script("a91469a9f95a98fe581b6eb52841ef4806dc4402eb9087"),
@ -30,7 +25,13 @@ V5(
value: 250000000,
lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"),
),
Output(
value: 15625000,
lock_script: Script("a914d45cb1adffb5215a42720532a076f02c7c778c9087"),
),
],
lock_time: Height(Height(0)),
expiry_height: Height(1687105),
joinsplit_data: None,
sapling_shielded_data: None,
orchard_shielded_data: None,
)

View File

@ -2,15 +2,14 @@
source: zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs
expression: coinbase_tx
---
V5(
network_upgrade: Nu5,
lock_time: Height(Height(0)),
expiry_height: Height(1842421),
V4(
inputs: [
Coinbase(
height: Height(1842421),
data: CoinbaseData([]),
sequence: 0,
data: CoinbaseData([
0,
]),
sequence: 4294967295,
),
],
outputs: [
@ -31,6 +30,8 @@ V5(
lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"),
),
],
lock_time: Height(Height(0)),
expiry_height: Height(1842421),
joinsplit_data: None,
sapling_shielded_data: None,
orchard_shielded_data: None,
)

View File

@ -6,20 +6,20 @@ expression: block_template
"capabilities": [],
"version": 4,
"previousblockhash": "0000000000d723156d9b65ffcf4984da7a19675ed7e2f06d9e5d5188af087bf8",
"blockcommitmentshash": "fe03d8236b0835c758f59d279230ebaee2128754413103b9edb17c07451c2c82",
"lightclientroothash": "fe03d8236b0835c758f59d279230ebaee2128754413103b9edb17c07451c2c82",
"finalsaplingroothash": "fe03d8236b0835c758f59d279230ebaee2128754413103b9edb17c07451c2c82",
"blockcommitmentshash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a",
"lightclientroothash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a",
"finalsaplingroothash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a",
"defaultroots": {
"merkleroot": "6b370584714ab567c9c014ce72d325ab6c5927e181ac891acb35e6d4b6cc19a1",
"merkleroot": "e049ed10466f566a045702ad712bbb596c6863cd08cdb4646da749b2287bc219",
"chainhistoryroot": "94470fa66ebd1a5fdb109a5aa3f3204f14de3a42135e71aa7f4c44055847e0b5",
"authdataroot": "0dbb78de9fdcd494307971e36dd049fc82d0ee9ee53aec8fd2a54dc0e426289b",
"blockcommitmentshash": "fe03d8236b0835c758f59d279230ebaee2128754413103b9edb17c07451c2c82"
"authdataroot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"blockcommitmentshash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a"
},
"transactions": [],
"coinbasetxn": {
"data": "050000800a27a726b4d0d6c20000000041be1900010000000000000000000000000000000000000000000000000000000000000000ffffffff040341be190000000004286bee000000000017a914d45cb1adffb5215a42720532a076f02c7c778c908738c94d010000000017a91469a9f95a98fe581b6eb52841ef4806dc4402eb908740787d010000000017a914931fec54c1fea86e574462cc32013f5400b891298780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad87000000",
"hash": "6b370584714ab567c9c014ce72d325ab6c5927e181ac891acb35e6d4b6cc19a1",
"authdigest": "0dbb78de9fdcd494307971e36dd049fc82d0ee9ee53aec8fd2a54dc0e426289b",
"data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff050341be1900ffffffff0438c94d010000000017a91469a9f95a98fe581b6eb52841ef4806dc4402eb908740787d010000000017a914931fec54c1fea86e574462cc32013f5400b891298780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad87286bee000000000017a914d45cb1adffb5215a42720532a076f02c7c778c90870000000041be19000000000000000000000000",
"hash": "e049ed10466f566a045702ad712bbb596c6863cd08cdb4646da749b2287bc219",
"authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"depends": [],
"fee": 0,
"sigops": 0,

View File

@ -6,20 +6,20 @@ expression: block_template
"capabilities": [],
"version": 4,
"previousblockhash": "0000000000d723156d9b65ffcf4984da7a19675ed7e2f06d9e5d5188af087bf8",
"blockcommitmentshash": "cb1f1c6a5ad5ff9c4a170e3b747a24f3aec79817adba9a9451f19914481bb422",
"lightclientroothash": "cb1f1c6a5ad5ff9c4a170e3b747a24f3aec79817adba9a9451f19914481bb422",
"finalsaplingroothash": "cb1f1c6a5ad5ff9c4a170e3b747a24f3aec79817adba9a9451f19914481bb422",
"blockcommitmentshash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792",
"lightclientroothash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792",
"finalsaplingroothash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792",
"defaultroots": {
"merkleroot": "623400cc122baa015d3a4209f5903ebe215170c7e6e74831dce8372c5fd5b3cc",
"merkleroot": "f1f2db76c33c4a81f799d0c5cfba83c99c20cc8c51958a615d410fe7fbf92b34",
"chainhistoryroot": "03bc75f00c307a05aed2023819e18c2672cbe15fbd3200944997def141967387",
"authdataroot": "a44375f0c0dd5ba612bd7b0efd77683cde8edf5055aff9fbfda443cc8d46bd3e",
"blockcommitmentshash": "cb1f1c6a5ad5ff9c4a170e3b747a24f3aec79817adba9a9451f19914481bb422"
"authdataroot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"blockcommitmentshash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792"
},
"transactions": [],
"coinbasetxn": {
"data": "050000800a27a726b4d0d6c200000000f51c1c00010000000000000000000000000000000000000000000000000000000000000000ffffffff0403f51c1c0000000004286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8738c94d010000000017a9144e3f0d9a33a2721604cbae2de8d9171e21f8fbe48740787d010000000017a91471e1df05024288a00802de81e08c437859586c878780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad87000000",
"hash": "623400cc122baa015d3a4209f5903ebe215170c7e6e74831dce8372c5fd5b3cc",
"authdigest": "a44375f0c0dd5ba612bd7b0efd77683cde8edf5055aff9fbfda443cc8d46bd3e",
"data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0503f51c1c00ffffffff04286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8738c94d010000000017a9144e3f0d9a33a2721604cbae2de8d9171e21f8fbe48740787d010000000017a91471e1df05024288a00802de81e08c437859586c878780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad8700000000f51c1c000000000000000000000000",
"hash": "f1f2db76c33c4a81f799d0c5cfba83c99c20cc8c51958a615d410fe7fbf92b34",
"authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"depends": [],
"fee": 0,
"sigops": 0,