From 05beb25b6acfb8afa356fa6cea7d2e3cc800edb2 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 15 Dec 2022 17:22:38 +1000 Subject: [PATCH 1/8] Make Zebra's getblocktemplate like zcashd's --- zebra-chain/src/transaction/builder.rs | 82 ++++++++++++- zebra-chain/src/transaction/serialize.rs | 4 +- .../src/block/subsidy/funding_streams.rs | 4 +- zebra-consensus/src/lib.rs | 9 +- .../src/methods/get_block_template_rpcs.rs | 9 +- .../get_block_template.rs | 112 ++++++++++++++++-- .../types/get_block_template.rs | 20 +++- .../methods/get_block_template_rpcs/zip317.rs | 20 +++- 8 files changed, 226 insertions(+), 34 deletions(-) diff --git a/zebra-chain/src/transaction/builder.rs b/zebra-chain/src/transaction/builder.rs index 6940eb9b8b5..6b3dfb178cc 100644 --- a/zebra-chain/src/transaction/builder.rs +++ b/zebra-chain/src/transaction/builder.rs @@ -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). + // // - 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, 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, + } + } } diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index 8d7a613460e..b432b0e222f 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -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, } diff --git a/zebra-consensus/src/block/subsidy/funding_streams.rs b/zebra-consensus/src/block/subsidy/funding_streams.rs index 8ce85bcc4f1..8e6f76665c2 100644 --- a/zebra-consensus/src/block/subsidy/funding_streams.rs +++ b/zebra-consensus/src/block/subsidy/funding_streams.rs @@ -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; diff --git a/zebra-consensus/src/lib.rs b/zebra-consensus/src/lib.rs index a10850b701a..669e14dd83b 100644 --- a/zebra-consensus/src/lib.rs +++ b/zebra-consensus/src/lib.rs @@ -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`]. diff --git a/zebra-rpc/src/methods/get_block_template_rpcs.rs b/zebra-rpc/src/methods/get_block_template_rpcs.rs index 895bb7543d2..deac8245dff 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs.rs @@ -317,6 +317,11 @@ where &self, parameters: Option, ) -> BoxFuture> { + // 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) diff --git a/zebra-rpc/src/methods/get_block_template_rpcs/get_block_template.rs b/zebra-rpc/src/methods/get_block_template_rpcs/get_block_template.rs index 8af438884a7..bda902bbac1 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs/get_block_template.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs/get_block_template.rs @@ -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, + like_zcashd: bool, ) -> (TransactionTemplate, 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, + 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, + like_zcashd: bool, ) -> Vec<(Amount, 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, 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, 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,8 +273,8 @@ 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; - coinbase_outputs.push((miner_reward, miner_address)); + let coinbase_outputs = + combine_coinbase_outputs(funding_streams, miner_address, miner_reward, like_zcashd); coinbase_outputs .iter() @@ -257,6 +282,67 @@ pub fn standard_coinbase_outputs( .collect() } +/// 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( + mut funding_streams: HashMap< + FundingStreamReceiver, + (Amount, transparent::Address), + >, + miner_address: transparent::Address, + miner_reward: Amount, + like_zcashd: bool, +) -> Vec<(Amount, transparent::Address)> { + // Combine all the funding streams with the miner reward. + if like_zcashd { + use FundingStreamReceiver::*; + + // zcashd uses the order: [miner, ECC, MG, ZF], so we apply that custom order here. + let mut coinbase_outputs = vec![(miner_reward, miner_address)]; + + for funding_stream in [Ecc, MajorGrants, ZcashFoundation] { + if let Some((amount, address)) = funding_streams.remove(&funding_stream) { + coinbase_outputs.push((amount, address)); + } + } + + // Sort remaining funding streams by amount then address. + // + // (There aren't any of these yet, but we don't want to break consensus if they are added.) + let mut remaining_funding_streams: Vec<(Amount, transparent::Address)> = + funding_streams + .into_iter() + .map(|(_receiver, (amount, address))| (amount, address)) + .collect(); + + // Since sort_by() uses a stable sort, we can just sort by address first, then amount, + // and any equal amounts will be in address order. + remaining_funding_streams.sort_by_key(|(_amount, address)| address.to_string()); + remaining_funding_streams.sort_by_key(|(amount, _address)| *amount); + + coinbase_outputs.extend(remaining_funding_streams); + + coinbase_outputs + } else { + // Zebra sorts by amount then address. + let mut coinbase_outputs: Vec<(Amount, transparent::Address)> = + funding_streams + .into_iter() + .map(|(_receiver, (amount, address))| (amount, address)) + .collect(); + coinbase_outputs.push((miner_reward, miner_address)); + + // The HashMap returns funding streams in an arbitrary order, + // but Zebra's snapshot tests expect the same order every time. + coinbase_outputs.sort_by_key(|(_amount, address)| address.to_string()); + coinbase_outputs.sort_by_key(|(amount, _address)| *amount); + + coinbase_outputs + } +} + // - Transaction roots processing /// Returns the default block roots for the supplied coinbase and mempool transactions, diff --git a/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template.rs b/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template.rs index 77134e16c56..12bc79cb280 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template.rs @@ -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,31 @@ 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, mempool_txs: &[VerifiedUnminedTx], default_roots: DefaultRoots, submit_old: Option, + 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> = + mempool_txs.iter().map(Into::into).collect(); + + // Sort in lexicographic data order, like `zcashd` does. + // (This is not required, but it simplifies testing by comparing with `zcashd`.) + if like_zcashd { + mempool_txs.sort_by_key(|tx| tx.data.clone()); + } // Convert difficulty let target = chain_tip_and_local_time diff --git a/zebra-rpc/src/methods/get_block_template_rpcs/zip317.rs b/zebra-rpc/src/methods/get_block_template_rpcs/zip317.rs index 26561215be4..185f569c4ba 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs/zip317.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs/zip317.rs @@ -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, + like_zcashd: bool, ) -> Vec { // 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 { // 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) } From d3ae4aa261183207e99d3c9eefefe202ecc2b6fd Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 15 Dec 2022 17:28:51 +1000 Subject: [PATCH 2/8] Update snapshots --- ...template_basic.coinbase_tx@mainnet_10.snap | 23 ++++++++++--------- ...template_basic.coinbase_tx@testnet_10.snap | 23 ++++++++++--------- .../get_block_template_basic@mainnet_10.snap | 18 +++++++-------- .../get_block_template_basic@testnet_10.snap | 18 +++++++-------- ...late_long_poll.coinbase_tx@mainnet_10.snap | 23 ++++++++++--------- ...late_long_poll.coinbase_tx@testnet_10.snap | 23 ++++++++++--------- ...t_block_template_long_poll@mainnet_10.snap | 18 +++++++-------- ...t_block_template_long_poll@testnet_10.snap | 18 +++++++-------- 8 files changed, 84 insertions(+), 80 deletions(-) diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@mainnet_10.snap index a25fbaf5e70..633e24938fa 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@mainnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@mainnet_10.snap @@ -2,21 +2,20 @@ 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"), + value: 250000000, + lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), ), Output( value: 21875000, @@ -27,10 +26,12 @@ V5( lock_script: Script("a914931fec54c1fea86e574462cc32013f5400b8912987"), ), Output( - value: 250000000, - lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), + 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, ) diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@testnet_10.snap index 9879c10f18f..8db8e508245 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@testnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@testnet_10.snap @@ -2,21 +2,20 @@ 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: [ Output( - value: 15625000, - lock_script: Script("a9140c0bcca02f3cba01a5d7423ac3903d40586399eb87"), + value: 250000000, + lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), ), Output( value: 21875000, @@ -27,10 +26,12 @@ V5( lock_script: Script("a91471e1df05024288a00802de81e08c437859586c8787"), ), Output( - value: 250000000, - lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), + value: 15625000, + lock_script: Script("a9140c0bcca02f3cba01a5d7423ac3903d40586399eb87"), ), ], + lock_time: Height(Height(0)), + expiry_height: Height(1842421), + joinsplit_data: None, sapling_shielded_data: None, - orchard_shielded_data: None, ) diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@mainnet_10.snap index 7d6e5f22648..c5caec6e903 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@mainnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@mainnet_10.snap @@ -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": "7df8ce149b9beafc09b649c2ccfd866ce96d1b94331d9f7f3728cbefa36431f6", "chainhistoryroot": "94470fa66ebd1a5fdb109a5aa3f3204f14de3a42135e71aa7f4c44055847e0b5", - "authdataroot": "0dbb78de9fdcd494307971e36dd049fc82d0ee9ee53aec8fd2a54dc0e426289b", - "blockcommitmentshash": "fe03d8236b0835c758f59d279230ebaee2128754413103b9edb17c07451c2c82" + "authdataroot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockcommitmentshash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a" }, "transactions": [], "coinbasetxn": { - "data": "050000800a27a726b4d0d6c20000000041be1900010000000000000000000000000000000000000000000000000000000000000000ffffffff040341be190000000004286bee000000000017a914d45cb1adffb5215a42720532a076f02c7c778c908738c94d010000000017a91469a9f95a98fe581b6eb52841ef4806dc4402eb908740787d010000000017a914931fec54c1fea86e574462cc32013f5400b891298780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad87000000", - "hash": "6b370584714ab567c9c014ce72d325ab6c5927e181ac891acb35e6d4b6cc19a1", - "authdigest": "0dbb78de9fdcd494307971e36dd049fc82d0ee9ee53aec8fd2a54dc0e426289b", + "data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff050341be1900ffffffff0480b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad8738c94d010000000017a91469a9f95a98fe581b6eb52841ef4806dc4402eb908740787d010000000017a914931fec54c1fea86e574462cc32013f5400b8912987286bee000000000017a914d45cb1adffb5215a42720532a076f02c7c778c90870000000041be19000000000000000000000000", + "hash": "7df8ce149b9beafc09b649c2ccfd866ce96d1b94331d9f7f3728cbefa36431f6", + "authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "depends": [], "fee": 0, "sigops": 0, diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@testnet_10.snap index e6284e9c8c6..3bed42baea2 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@testnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@testnet_10.snap @@ -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": "2ae1e14870d362d79abf1b5274826ab9175166e9b4bae333ac59a9a320887ef7", "chainhistoryroot": "03bc75f00c307a05aed2023819e18c2672cbe15fbd3200944997def141967387", - "authdataroot": "a44375f0c0dd5ba612bd7b0efd77683cde8edf5055aff9fbfda443cc8d46bd3e", - "blockcommitmentshash": "cb1f1c6a5ad5ff9c4a170e3b747a24f3aec79817adba9a9451f19914481bb422" + "authdataroot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockcommitmentshash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792" }, "transactions": [], "coinbasetxn": { - "data": "050000800a27a726b4d0d6c200000000f51c1c00010000000000000000000000000000000000000000000000000000000000000000ffffffff0403f51c1c0000000004286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8738c94d010000000017a9144e3f0d9a33a2721604cbae2de8d9171e21f8fbe48740787d010000000017a91471e1df05024288a00802de81e08c437859586c878780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad87000000", - "hash": "623400cc122baa015d3a4209f5903ebe215170c7e6e74831dce8372c5fd5b3cc", - "authdigest": "a44375f0c0dd5ba612bd7b0efd77683cde8edf5055aff9fbfda443cc8d46bd3e", + "data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0503f51c1c00ffffffff0480b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad8738c94d010000000017a9144e3f0d9a33a2721604cbae2de8d9171e21f8fbe48740787d010000000017a91471e1df05024288a00802de81e08c437859586c8787286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8700000000f51c1c000000000000000000000000", + "hash": "2ae1e14870d362d79abf1b5274826ab9175166e9b4bae333ac59a9a320887ef7", + "authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "depends": [], "fee": 0, "sigops": 0, diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@mainnet_10.snap index a25fbaf5e70..633e24938fa 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@mainnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@mainnet_10.snap @@ -2,21 +2,20 @@ 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"), + value: 250000000, + lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), ), Output( value: 21875000, @@ -27,10 +26,12 @@ V5( lock_script: Script("a914931fec54c1fea86e574462cc32013f5400b8912987"), ), Output( - value: 250000000, - lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), + 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, ) diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@testnet_10.snap index 9879c10f18f..8db8e508245 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@testnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@testnet_10.snap @@ -2,21 +2,20 @@ 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: [ Output( - value: 15625000, - lock_script: Script("a9140c0bcca02f3cba01a5d7423ac3903d40586399eb87"), + value: 250000000, + lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), ), Output( value: 21875000, @@ -27,10 +26,12 @@ V5( lock_script: Script("a91471e1df05024288a00802de81e08c437859586c8787"), ), Output( - value: 250000000, - lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), + value: 15625000, + lock_script: Script("a9140c0bcca02f3cba01a5d7423ac3903d40586399eb87"), ), ], + lock_time: Height(Height(0)), + expiry_height: Height(1842421), + joinsplit_data: None, sapling_shielded_data: None, - orchard_shielded_data: None, ) diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@mainnet_10.snap index d143fb26149..7090e4b5a7b 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@mainnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@mainnet_10.snap @@ -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": "7df8ce149b9beafc09b649c2ccfd866ce96d1b94331d9f7f3728cbefa36431f6", "chainhistoryroot": "94470fa66ebd1a5fdb109a5aa3f3204f14de3a42135e71aa7f4c44055847e0b5", - "authdataroot": "0dbb78de9fdcd494307971e36dd049fc82d0ee9ee53aec8fd2a54dc0e426289b", - "blockcommitmentshash": "fe03d8236b0835c758f59d279230ebaee2128754413103b9edb17c07451c2c82" + "authdataroot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockcommitmentshash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a" }, "transactions": [], "coinbasetxn": { - "data": "050000800a27a726b4d0d6c20000000041be1900010000000000000000000000000000000000000000000000000000000000000000ffffffff040341be190000000004286bee000000000017a914d45cb1adffb5215a42720532a076f02c7c778c908738c94d010000000017a91469a9f95a98fe581b6eb52841ef4806dc4402eb908740787d010000000017a914931fec54c1fea86e574462cc32013f5400b891298780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad87000000", - "hash": "6b370584714ab567c9c014ce72d325ab6c5927e181ac891acb35e6d4b6cc19a1", - "authdigest": "0dbb78de9fdcd494307971e36dd049fc82d0ee9ee53aec8fd2a54dc0e426289b", + "data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff050341be1900ffffffff0480b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad8738c94d010000000017a91469a9f95a98fe581b6eb52841ef4806dc4402eb908740787d010000000017a914931fec54c1fea86e574462cc32013f5400b8912987286bee000000000017a914d45cb1adffb5215a42720532a076f02c7c778c90870000000041be19000000000000000000000000", + "hash": "7df8ce149b9beafc09b649c2ccfd866ce96d1b94331d9f7f3728cbefa36431f6", + "authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "depends": [], "fee": 0, "sigops": 0, diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@testnet_10.snap index fae337970a6..c151a2f637f 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@testnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@testnet_10.snap @@ -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": "2ae1e14870d362d79abf1b5274826ab9175166e9b4bae333ac59a9a320887ef7", "chainhistoryroot": "03bc75f00c307a05aed2023819e18c2672cbe15fbd3200944997def141967387", - "authdataroot": "a44375f0c0dd5ba612bd7b0efd77683cde8edf5055aff9fbfda443cc8d46bd3e", - "blockcommitmentshash": "cb1f1c6a5ad5ff9c4a170e3b747a24f3aec79817adba9a9451f19914481bb422" + "authdataroot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockcommitmentshash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792" }, "transactions": [], "coinbasetxn": { - "data": "050000800a27a726b4d0d6c200000000f51c1c00010000000000000000000000000000000000000000000000000000000000000000ffffffff0403f51c1c0000000004286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8738c94d010000000017a9144e3f0d9a33a2721604cbae2de8d9171e21f8fbe48740787d010000000017a91471e1df05024288a00802de81e08c437859586c878780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad87000000", - "hash": "623400cc122baa015d3a4209f5903ebe215170c7e6e74831dce8372c5fd5b3cc", - "authdigest": "a44375f0c0dd5ba612bd7b0efd77683cde8edf5055aff9fbfda443cc8d46bd3e", + "data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0503f51c1c00ffffffff0480b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad8738c94d010000000017a9144e3f0d9a33a2721604cbae2de8d9171e21f8fbe48740787d010000000017a91471e1df05024288a00802de81e08c437859586c8787286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8700000000f51c1c000000000000000000000000", + "hash": "2ae1e14870d362d79abf1b5274826ab9175166e9b4bae333ac59a9a320887ef7", + "authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "depends": [], "fee": 0, "sigops": 0, From 092d8a9753616bb7498d8023231f8d4f1b5e3cc1 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 15 Dec 2022 17:46:44 +1000 Subject: [PATCH 3/8] Add missing docs --- zebra-consensus/src/parameters/subsidy.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zebra-consensus/src/parameters/subsidy.rs b/zebra-consensus/src/parameters/subsidy.rs index 8456fdc36b8..ce190574e68 100644 --- a/zebra-consensus/src/parameters/subsidy.rs +++ b/zebra-consensus/src/parameters/subsidy.rs @@ -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 (Boostrap Foundation) funding stream. Ecc, + + /// The Zcash Foundation funding stream. ZcashFoundation, + + /// The Major Grants (Zcash Community Grants) funding stream. MajorGrants, } From 1b341447458c1af583f26f348ab77dc2f4986516 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 15 Dec 2022 17:54:07 +1000 Subject: [PATCH 4/8] Fix typo --- zebra-consensus/src/parameters/subsidy.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra-consensus/src/parameters/subsidy.rs b/zebra-consensus/src/parameters/subsidy.rs index ce190574e68..7bd813fa20f 100644 --- a/zebra-consensus/src/parameters/subsidy.rs +++ b/zebra-consensus/src/parameters/subsidy.rs @@ -48,7 +48,7 @@ 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 (Boostrap Foundation) funding stream. + /// The Electric Coin Company (Bootstrap Foundation) funding stream. Ecc, /// The Zcash Foundation funding stream. From ad8f7935d32a7f86bd07c3fdcb0eae833629f9b9 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 16 Dec 2022 13:09:55 +1000 Subject: [PATCH 5/8] Sort coinbase outputs by serialized script for zcashd --- zebra-chain/src/transparent/script.rs | 2 +- .../get_block_template.rs | 82 +++++++------------ 2 files changed, 30 insertions(+), 54 deletions(-) diff --git a/zebra-chain/src/transparent/script.rs b/zebra-chain/src/transparent/script.rs index de028563311..ebc442450ae 100644 --- a/zebra-chain/src/transparent/script.rs +++ b/zebra-chain/src/transparent/script.rs @@ -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) diff --git a/zebra-rpc/src/methods/get_block_template_rpcs/get_block_template.rs b/zebra-rpc/src/methods/get_block_template_rpcs/get_block_template.rs index bda902bbac1..22e678be306 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs/get_block_template.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs/get_block_template.rs @@ -14,6 +14,7 @@ use zebra_chain::{ chain_sync_status::ChainSyncStatus, chain_tip::ChainTip, parameters::Network, + serialization::ZcashSerialize, transaction::{Transaction, UnminedTx, VerifiedUnminedTx}, transparent, }; @@ -273,13 +274,7 @@ pub fn standard_coinbase_outputs( let miner_reward = miner_reward.expect("reward calculations are valid for reasonable chain heights"); - let coinbase_outputs = - combine_coinbase_outputs(funding_streams, miner_address, miner_reward, like_zcashd); - - coinbase_outputs - .iter() - .map(|(amount, address)| (*amount, address.create_script_from_address())) - .collect() + 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. @@ -287,60 +282,41 @@ pub fn standard_coinbase_outputs( /// If `like_zcashd` is true, try to match the coinbase transactions generated by `zcashd` /// in the `getblocktemplate` RPC. fn combine_coinbase_outputs( - mut funding_streams: HashMap< - FundingStreamReceiver, - (Amount, transparent::Address), - >, + funding_streams: HashMap, transparent::Address)>, miner_address: transparent::Address, miner_reward: Amount, like_zcashd: bool, -) -> Vec<(Amount, transparent::Address)> { +) -> Vec<(Amount, transparent::Script)> { // Combine all the funding streams with the miner reward. - if like_zcashd { - use FundingStreamReceiver::*; - - // zcashd uses the order: [miner, ECC, MG, ZF], so we apply that custom order here. - let mut coinbase_outputs = vec![(miner_reward, miner_address)]; - - for funding_stream in [Ecc, MajorGrants, ZcashFoundation] { - if let Some((amount, address)) = funding_streams.remove(&funding_stream) { - coinbase_outputs.push((amount, address)); - } - } - - // Sort remaining funding streams by amount then address. - // - // (There aren't any of these yet, but we don't want to break consensus if they are added.) - let mut remaining_funding_streams: Vec<(Amount, transparent::Address)> = - funding_streams - .into_iter() - .map(|(_receiver, (amount, address))| (amount, address)) - .collect(); - - // Since sort_by() uses a stable sort, we can just sort by address first, then amount, - // and any equal amounts will be in address order. - remaining_funding_streams.sort_by_key(|(_amount, address)| address.to_string()); - remaining_funding_streams.sort_by_key(|(amount, _address)| *amount); + let mut coinbase_outputs: Vec<(Amount, transparent::Address)> = funding_streams + .into_iter() + .map(|(_receiver, (amount, address))| (amount, address)) + .collect(); + coinbase_outputs.push((miner_reward, miner_address)); - coinbase_outputs.extend(remaining_funding_streams); + let mut coinbase_outputs: Vec<(Amount, transparent::Script)> = coinbase_outputs + .iter() + .map(|(amount, address)| (*amount, address.create_script_from_address())) + .collect(); - coinbase_outputs + // 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 + coinbase_outputs.sort_by_key(|(_amount, script)| { + script + .zcash_serialize_to_vec() + .expect("serialization to Vec never fails") + }); } else { - // Zebra sorts by amount then address. - let mut coinbase_outputs: Vec<(Amount, transparent::Address)> = - funding_streams - .into_iter() - .map(|(_receiver, (amount, address))| (amount, address)) - .collect(); - coinbase_outputs.push((miner_reward, miner_address)); - - // The HashMap returns funding streams in an arbitrary order, - // but Zebra's snapshot tests expect the same order every time. - coinbase_outputs.sort_by_key(|(_amount, address)| address.to_string()); - coinbase_outputs.sort_by_key(|(amount, _address)| *amount); - - coinbase_outputs + // 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 From 9da331216661dc0e979c3c32e4bec1eaa4c86149 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 16 Dec 2022 13:30:39 +1000 Subject: [PATCH 6/8] Sort excluding the length byte, make transaction order always stable --- .../get_block_template_rpcs/get_block_template.rs | 9 ++------- .../get_block_template_rpcs/types/get_block_template.rs | 9 +++++++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/zebra-rpc/src/methods/get_block_template_rpcs/get_block_template.rs b/zebra-rpc/src/methods/get_block_template_rpcs/get_block_template.rs index 22e678be306..d2cfdb78549 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs/get_block_template.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs/get_block_template.rs @@ -14,7 +14,6 @@ use zebra_chain::{ chain_sync_status::ChainSyncStatus, chain_tip::ChainTip, parameters::Network, - serialization::ZcashSerialize, transaction::{Transaction, UnminedTx, VerifiedUnminedTx}, transparent, }; @@ -302,12 +301,8 @@ fn combine_coinbase_outputs( // 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 - coinbase_outputs.sort_by_key(|(_amount, script)| { - script - .zcash_serialize_to_vec() - .expect("serialization to Vec never fails") - }); + // 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. // diff --git a/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template.rs b/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template.rs index 12bc79cb280..922d2955323 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template.rs @@ -185,10 +185,15 @@ impl GetBlockTemplate { let mut mempool_txs: Vec> = mempool_txs.iter().map(Into::into).collect(); - // Sort in lexicographic data order, like `zcashd` does. - // (This is not required, but it simplifies testing by comparing with `zcashd`.) + // 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, like `zcashd` does. + // (This is not required, but it simplifies testing by comparing with `zcashd`.) 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 From f816c8ef5a662718efa482e22972e55cb4fb2d21 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 16 Dec 2022 13:34:54 +1000 Subject: [PATCH 7/8] Update snapshots --- .../get_block_template_basic.coinbase_tx@mainnet_10.snap | 8 ++++---- .../get_block_template_basic.coinbase_tx@testnet_10.snap | 8 ++++---- .../snapshots/get_block_template_basic@mainnet_10.snap | 6 +++--- .../snapshots/get_block_template_basic@testnet_10.snap | 6 +++--- ...t_block_template_long_poll.coinbase_tx@mainnet_10.snap | 8 ++++---- ...t_block_template_long_poll.coinbase_tx@testnet_10.snap | 8 ++++---- .../get_block_template_long_poll@mainnet_10.snap | 6 +++--- .../get_block_template_long_poll@testnet_10.snap | 6 +++--- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@mainnet_10.snap index 633e24938fa..09651b869b7 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@mainnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@mainnet_10.snap @@ -13,10 +13,6 @@ V4( ), ], outputs: [ - Output( - value: 250000000, - lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), - ), Output( value: 21875000, lock_script: Script("a91469a9f95a98fe581b6eb52841ef4806dc4402eb9087"), @@ -25,6 +21,10 @@ V4( value: 25000000, lock_script: Script("a914931fec54c1fea86e574462cc32013f5400b8912987"), ), + Output( + value: 250000000, + lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), + ), Output( value: 15625000, lock_script: Script("a914d45cb1adffb5215a42720532a076f02c7c778c9087"), diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@testnet_10.snap index 8db8e508245..1c46a9f0147 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@testnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic.coinbase_tx@testnet_10.snap @@ -14,8 +14,8 @@ V4( ], outputs: [ Output( - value: 250000000, - lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), + value: 15625000, + lock_script: Script("a9140c0bcca02f3cba01a5d7423ac3903d40586399eb87"), ), Output( value: 21875000, @@ -26,8 +26,8 @@ V4( lock_script: Script("a91471e1df05024288a00802de81e08c437859586c8787"), ), Output( - value: 15625000, - lock_script: Script("a9140c0bcca02f3cba01a5d7423ac3903d40586399eb87"), + value: 250000000, + lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), ), ], lock_time: Height(Height(0)), diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@mainnet_10.snap index c5caec6e903..d0853e4a2ea 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@mainnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@mainnet_10.snap @@ -10,15 +10,15 @@ expression: block_template "lightclientroothash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a", "finalsaplingroothash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a", "defaultroots": { - "merkleroot": "7df8ce149b9beafc09b649c2ccfd866ce96d1b94331d9f7f3728cbefa36431f6", + "merkleroot": "e049ed10466f566a045702ad712bbb596c6863cd08cdb4646da749b2287bc219", "chainhistoryroot": "94470fa66ebd1a5fdb109a5aa3f3204f14de3a42135e71aa7f4c44055847e0b5", "authdataroot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "blockcommitmentshash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a" }, "transactions": [], "coinbasetxn": { - "data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff050341be1900ffffffff0480b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad8738c94d010000000017a91469a9f95a98fe581b6eb52841ef4806dc4402eb908740787d010000000017a914931fec54c1fea86e574462cc32013f5400b8912987286bee000000000017a914d45cb1adffb5215a42720532a076f02c7c778c90870000000041be19000000000000000000000000", - "hash": "7df8ce149b9beafc09b649c2ccfd866ce96d1b94331d9f7f3728cbefa36431f6", + "data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff050341be1900ffffffff0438c94d010000000017a91469a9f95a98fe581b6eb52841ef4806dc4402eb908740787d010000000017a914931fec54c1fea86e574462cc32013f5400b891298780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad87286bee000000000017a914d45cb1adffb5215a42720532a076f02c7c778c90870000000041be19000000000000000000000000", + "hash": "e049ed10466f566a045702ad712bbb596c6863cd08cdb4646da749b2287bc219", "authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "depends": [], "fee": 0, diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@testnet_10.snap index 3bed42baea2..0b6e9e0bd54 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@testnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_basic@testnet_10.snap @@ -10,15 +10,15 @@ expression: block_template "lightclientroothash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792", "finalsaplingroothash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792", "defaultroots": { - "merkleroot": "2ae1e14870d362d79abf1b5274826ab9175166e9b4bae333ac59a9a320887ef7", + "merkleroot": "f1f2db76c33c4a81f799d0c5cfba83c99c20cc8c51958a615d410fe7fbf92b34", "chainhistoryroot": "03bc75f00c307a05aed2023819e18c2672cbe15fbd3200944997def141967387", "authdataroot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "blockcommitmentshash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792" }, "transactions": [], "coinbasetxn": { - "data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0503f51c1c00ffffffff0480b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad8738c94d010000000017a9144e3f0d9a33a2721604cbae2de8d9171e21f8fbe48740787d010000000017a91471e1df05024288a00802de81e08c437859586c8787286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8700000000f51c1c000000000000000000000000", - "hash": "2ae1e14870d362d79abf1b5274826ab9175166e9b4bae333ac59a9a320887ef7", + "data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0503f51c1c00ffffffff04286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8738c94d010000000017a9144e3f0d9a33a2721604cbae2de8d9171e21f8fbe48740787d010000000017a91471e1df05024288a00802de81e08c437859586c878780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad8700000000f51c1c000000000000000000000000", + "hash": "f1f2db76c33c4a81f799d0c5cfba83c99c20cc8c51958a615d410fe7fbf92b34", "authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "depends": [], "fee": 0, diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@mainnet_10.snap index 633e24938fa..09651b869b7 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@mainnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@mainnet_10.snap @@ -13,10 +13,6 @@ V4( ), ], outputs: [ - Output( - value: 250000000, - lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), - ), Output( value: 21875000, lock_script: Script("a91469a9f95a98fe581b6eb52841ef4806dc4402eb9087"), @@ -25,6 +21,10 @@ V4( value: 25000000, lock_script: Script("a914931fec54c1fea86e574462cc32013f5400b8912987"), ), + Output( + value: 250000000, + lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), + ), Output( value: 15625000, lock_script: Script("a914d45cb1adffb5215a42720532a076f02c7c778c9087"), diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@testnet_10.snap index 8db8e508245..1c46a9f0147 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@testnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll.coinbase_tx@testnet_10.snap @@ -14,8 +14,8 @@ V4( ], outputs: [ Output( - value: 250000000, - lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), + value: 15625000, + lock_script: Script("a9140c0bcca02f3cba01a5d7423ac3903d40586399eb87"), ), Output( value: 21875000, @@ -26,8 +26,8 @@ V4( lock_script: Script("a91471e1df05024288a00802de81e08c437859586c8787"), ), Output( - value: 15625000, - lock_script: Script("a9140c0bcca02f3cba01a5d7423ac3903d40586399eb87"), + value: 250000000, + lock_script: Script("a914adadadadadadadadadadadadadadadadadadadad87"), ), ], lock_time: Height(Height(0)), diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@mainnet_10.snap index 7090e4b5a7b..686028d69c8 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@mainnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@mainnet_10.snap @@ -10,15 +10,15 @@ expression: block_template "lightclientroothash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a", "finalsaplingroothash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a", "defaultroots": { - "merkleroot": "7df8ce149b9beafc09b649c2ccfd866ce96d1b94331d9f7f3728cbefa36431f6", + "merkleroot": "e049ed10466f566a045702ad712bbb596c6863cd08cdb4646da749b2287bc219", "chainhistoryroot": "94470fa66ebd1a5fdb109a5aa3f3204f14de3a42135e71aa7f4c44055847e0b5", "authdataroot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "blockcommitmentshash": "02990723c6b62a724651322d141b4a72a4ffd66518167d809badbd5117d5518a" }, "transactions": [], "coinbasetxn": { - "data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff050341be1900ffffffff0480b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad8738c94d010000000017a91469a9f95a98fe581b6eb52841ef4806dc4402eb908740787d010000000017a914931fec54c1fea86e574462cc32013f5400b8912987286bee000000000017a914d45cb1adffb5215a42720532a076f02c7c778c90870000000041be19000000000000000000000000", - "hash": "7df8ce149b9beafc09b649c2ccfd866ce96d1b94331d9f7f3728cbefa36431f6", + "data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff050341be1900ffffffff0438c94d010000000017a91469a9f95a98fe581b6eb52841ef4806dc4402eb908740787d010000000017a914931fec54c1fea86e574462cc32013f5400b891298780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad87286bee000000000017a914d45cb1adffb5215a42720532a076f02c7c778c90870000000041be19000000000000000000000000", + "hash": "e049ed10466f566a045702ad712bbb596c6863cd08cdb4646da749b2287bc219", "authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "depends": [], "fee": 0, diff --git a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@testnet_10.snap index c151a2f637f..ba44908e62e 100644 --- a/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@testnet_10.snap +++ b/zebra-rpc/src/methods/tests/snapshot/snapshots/get_block_template_long_poll@testnet_10.snap @@ -10,15 +10,15 @@ expression: block_template "lightclientroothash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792", "finalsaplingroothash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792", "defaultroots": { - "merkleroot": "2ae1e14870d362d79abf1b5274826ab9175166e9b4bae333ac59a9a320887ef7", + "merkleroot": "f1f2db76c33c4a81f799d0c5cfba83c99c20cc8c51958a615d410fe7fbf92b34", "chainhistoryroot": "03bc75f00c307a05aed2023819e18c2672cbe15fbd3200944997def141967387", "authdataroot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "blockcommitmentshash": "3b25791957f9383b6ce851d728a78309664d5d7a82ca87b6a9125a2f2c529792" }, "transactions": [], "coinbasetxn": { - "data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0503f51c1c00ffffffff0480b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad8738c94d010000000017a9144e3f0d9a33a2721604cbae2de8d9171e21f8fbe48740787d010000000017a91471e1df05024288a00802de81e08c437859586c8787286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8700000000f51c1c000000000000000000000000", - "hash": "2ae1e14870d362d79abf1b5274826ab9175166e9b4bae333ac59a9a320887ef7", + "data": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0503f51c1c00ffffffff04286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8738c94d010000000017a9144e3f0d9a33a2721604cbae2de8d9171e21f8fbe48740787d010000000017a91471e1df05024288a00802de81e08c437859586c878780b2e60e0000000017a914adadadadadadadadadadadadadadadadadadadad8700000000f51c1c000000000000000000000000", + "hash": "f1f2db76c33c4a81f799d0c5cfba83c99c20cc8c51958a615d410fe7fbf92b34", "authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "depends": [], "fee": 0, From 5385774b350429ec7b62456ae9cb940ca77e312a Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 16 Dec 2022 13:43:31 +1000 Subject: [PATCH 8/8] Explain that `zcashd` doesn't seem to have a fixed transaction order --- .../get_block_template_rpcs/types/get_block_template.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template.rs b/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template.rs index 922d2955323..510871067d9 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template.rs @@ -188,8 +188,8 @@ impl GetBlockTemplate { // 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, like `zcashd` does. - // (This is not required, but it simplifies testing by comparing with `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.