docs: Transaction consensus rules: Coinbase rules (#3464)
* refactor coinbase transaction consensus rules docs * add missing rule * nit Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
parent
9be13a4fb7
commit
e703bd3512
|
@ -65,6 +65,21 @@ impl ZcashDeserialize for OutPoint {
|
|||
///
|
||||
/// The height may consume `0..=5` bytes at the stat of the coinbase data.
|
||||
/// The genesis block does not include an encoded coinbase height.
|
||||
///
|
||||
/// # Consensus
|
||||
///
|
||||
/// > 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.
|
||||
/// > For height in the range {1..16}, the encoding is a single byte of value
|
||||
/// > 0x50 height. Otherwise, let heightBytes be the signed little-endian
|
||||
/// > representation of height, using the minimum nonzero number of bytes such that
|
||||
/// > the most significant byte is < 0x80.
|
||||
/// > The length of heightBytes MUST be in the range {1..5}.
|
||||
/// > Then the encoding is the length of heightBytes encoded as one byte,
|
||||
/// > followed by heightBytes itself. This matches the encoding used by Bitcoin in the
|
||||
/// > implementation of [BIP-34] (but the description here is to be considered normative).
|
||||
///
|
||||
/// <https://zips.z.cash/protocol/protocol.pdf#txnconsensus>
|
||||
pub(crate) fn parse_coinbase_height(
|
||||
mut data: Vec<u8>,
|
||||
) -> Result<(block::Height, CoinbaseData), SerializationError> {
|
||||
|
|
|
@ -184,10 +184,12 @@ pub fn miner_fees_are_valid(
|
|||
let block_subsidy = subsidy::general::block_subsidy(height, network)
|
||||
.expect("a valid block subsidy for this height and network");
|
||||
|
||||
// Consensus rule: The total value in zatoshi of transparent outputs from a
|
||||
// coinbase transaction, minus vbalanceSapling, minus vbalanceOrchard, MUST NOT
|
||||
// be greater than the value in zatoshi of block subsidy plus the transaction fees
|
||||
// paid by transactions in this block.
|
||||
// # Consensus
|
||||
//
|
||||
// > The total value in zatoshi of transparent outputs from a coinbase transaction,
|
||||
// > minus vbalanceSapling, minus vbalanceOrchard, MUST NOT be greater than the value
|
||||
// > in zatoshi of block subsidy plus the transaction fees paid by transactions in this block.
|
||||
//
|
||||
// https://zips.z.cash/protocol/protocol.pdf#txnconsensus
|
||||
let left = (transparent_value_balance - sapling_value_balance - orchard_value_balance)
|
||||
.map_err(|_| SubsidyError::SumOverflow)?;
|
||||
|
|
|
@ -99,14 +99,20 @@ pub fn has_enough_orchard_flags(tx: &Transaction) -> Result<(), TransactionError
|
|||
|
||||
/// Check that a coinbase transaction has no PrevOut inputs, JoinSplits, or spends.
|
||||
///
|
||||
/// A coinbase transaction MUST NOT have any transparent inputs, JoinSplit descriptions,
|
||||
/// or Spend descriptions.
|
||||
/// # Consensus
|
||||
///
|
||||
/// In a version 5 coinbase transaction, the enableSpendsOrchard flag MUST be 0.
|
||||
/// > A coinbase transaction MUST NOT have any transparent inputs with non-null prevout fields,
|
||||
/// > JoinSplit descriptions, or Spend descriptions.
|
||||
///
|
||||
/// > [NU5 onward] In a version 5 coinbase transaction, the enableSpendsOrchard flag MUST be 0.
|
||||
///
|
||||
/// This check only counts `PrevOut` transparent inputs.
|
||||
///
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#txnencodingandconsensus
|
||||
/// > [Pre-Heartwood] A coinbase transaction also MUST NOT have any Output descriptions.
|
||||
///
|
||||
/// Zebra does not validate this last rule explicitly because we checkpoint until Canopy activation.
|
||||
///
|
||||
/// <https://zips.z.cash/protocol/protocol.pdf#txnconsensus>
|
||||
pub fn coinbase_tx_no_prevout_joinsplit_spend(tx: &Transaction) -> Result<(), TransactionError> {
|
||||
if tx.has_valid_coinbase_transaction_inputs() {
|
||||
if tx.contains_prevout_input() {
|
||||
|
@ -245,6 +251,8 @@ where
|
|||
///
|
||||
/// This is used to validate coinbase transactions:
|
||||
///
|
||||
/// # Consensus
|
||||
///
|
||||
/// > [Heartwood onward] All Sapling and Orchard outputs in coinbase transactions MUST decrypt to a note
|
||||
/// > plaintext, i.e. the procedure in § 4.19.3 ‘Decryption using a Full Viewing Key ( Sapling and Orchard )’ on p. 67
|
||||
/// > does not return ⊥, using a sequence of 32 zero bytes as the outgoing viewing key. (This implies that before
|
||||
|
@ -255,7 +263,8 @@ where
|
|||
/// > according to the preceding rule MUST have note plaintext lead byte equal to 0x02. (This applies even during
|
||||
/// > the "grace period" specified in [ZIP-212].)
|
||||
///
|
||||
/// [3.10]: https://zips.z.cash/protocol/protocol.pdf#coinbasetransactions
|
||||
/// <https://zips.z.cash/protocol/protocol.pdf#txnconsensus>
|
||||
///
|
||||
/// [ZIP-212]: https://zips.z.cash/zip-0212#consensus-rule-change-for-coinbase-transactions
|
||||
///
|
||||
/// TODO: Currently, a 0x01 lead byte is allowed in the "grace period" mentioned since we're
|
||||
|
@ -298,8 +307,12 @@ pub fn coinbase_expiry_height(
|
|||
// If Nu5 does not have a height, apply the pre-Nu5 rule.
|
||||
None => validate_expiry_height_max(expiry_height, true, block_height, coinbase),
|
||||
Some(activation_height) => {
|
||||
// Consensus rule: from NU5 activation, the nExpiryHeight field of a
|
||||
// coinbase transaction MUST be set equal to the block height.
|
||||
// # Consensus
|
||||
//
|
||||
// > [NU5 onward] The nExpiryHeight field of a coinbase transaction MUST be equal
|
||||
// > to its block height.
|
||||
//
|
||||
// https://zips.z.cash/protocol/protocol.pdf#txnconsensus
|
||||
if *block_height >= activation_height {
|
||||
match expiry_height {
|
||||
None => Err(TransactionError::CoinbaseExpiryBlockHeight {
|
||||
|
|
|
@ -168,16 +168,19 @@ fn transparent_spend_chain_order(
|
|||
|
||||
/// Check that `utxo` is spendable, based on the coinbase `spend_restriction`.
|
||||
///
|
||||
/// "A transaction with one or more transparent inputs from coinbase transactions
|
||||
/// MUST have no transparent outputs (i.e.tx_out_count MUST be 0)."
|
||||
/// # Consensus
|
||||
///
|
||||
/// "A transaction MUST NOT spend a transparent output of a coinbase transaction
|
||||
/// from a block less than 100 blocks prior to the spend.
|
||||
/// > A transaction with one or more transparent inputs from coinbase transactions
|
||||
/// > MUST have no transparent outputs (i.e. tx_out_count MUST be 0).
|
||||
/// > Inputs from coinbase transactions include Founders’ Reward outputs and
|
||||
/// > funding stream outputs.
|
||||
///
|
||||
/// Note that transparent outputs of coinbase transactions include Founders’
|
||||
/// Reward outputs and transparent funding stream outputs."
|
||||
/// > A transaction MUST NOT spend a transparent output of a coinbase transaction
|
||||
/// > from a block less than 100 blocks prior to the spend.
|
||||
/// > Note that transparent outputs of coinbase transactions include
|
||||
/// > Founders’ Reward outputs and transparent funding stream outputs.
|
||||
///
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#txnencodingandconsensus
|
||||
/// <https://zips.z.cash/protocol/protocol.pdf#txnconsensus>
|
||||
pub fn transparent_coinbase_spend(
|
||||
outpoint: transparent::OutPoint,
|
||||
spend_restriction: transparent::CoinbaseSpendRestriction,
|
||||
|
|
|
@ -344,8 +344,11 @@ impl FinalizedState {
|
|||
batch.zs_insert(height_by_hash, hash, height);
|
||||
batch.zs_insert(block_by_height, height, &block);
|
||||
|
||||
// "A transaction MUST NOT spend an output of the genesis block coinbase transaction.
|
||||
// (There is one such zero-valued output, on each of Testnet and Mainnet .)"
|
||||
// # Consensus
|
||||
//
|
||||
// > A transaction MUST NOT spend an output of the genesis block coinbase transaction.
|
||||
// > (There is one such zero-valued output, on each of Testnet and Mainnet.)
|
||||
//
|
||||
// https://zips.z.cash/protocol/protocol.pdf#txnconsensus
|
||||
if block.header.previous_block_hash == GENESIS_PREVIOUS_BLOCK_HASH {
|
||||
// Insert empty note commitment trees. Note that these can't be
|
||||
|
|
Loading…
Reference in New Issue