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:
parent
b8448c7eed
commit
b08a0b6f08
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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`].
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue