Move network_upgrade check into zebra-chain (#2354)

* move network_upgrade check into zebra-chain

* fix the errors

* rename function

* typo fix

* rename the check function

* make changes from last code review
This commit is contained in:
Alfredo Garcia 2021-06-21 23:06:52 -03:00 committed by GitHub
parent 76ad543ec5
commit 7638c43a7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 60 additions and 24 deletions

View File

@ -1,6 +1,7 @@
//! Blocks and block-related structures (heights, headers, etc.) //! Blocks and block-related structures (heights, headers, etc.)
mod commitment; mod commitment;
mod error;
mod hash; mod hash;
mod header; mod header;
mod height; mod height;
@ -28,7 +29,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
fmt::DisplayToDebug, fmt::DisplayToDebug,
parameters::Network, parameters::{Network, NetworkUpgrade},
serialization::{TrustedPreallocate, MAX_PROTOCOL_MESSAGE_LEN}, serialization::{TrustedPreallocate, MAX_PROTOCOL_MESSAGE_LEN},
transaction::Transaction, transaction::Transaction,
transparent, transparent,
@ -86,6 +87,35 @@ impl Block {
Some(height) => Commitment::from_bytes(self.header.commitment_bytes, network, height), Some(height) => Commitment::from_bytes(self.header.commitment_bytes, network, height),
} }
} }
/// Check if the `network_upgrade` fields from each transaction in the block matches
/// the network upgrade calculated from the `network` and block height.
///
/// # Consensus rule:
///
/// The nConsensusBranchId field MUST match the consensus branch ID used for
/// SIGHASH transaction hashes, as specifed in [ZIP-244] ([7.1]).
///
/// [ZIP-244]: https://zips.z.cash/zip-0244
/// [7.1]: https://zips.z.cash/protocol/nu5.pdf#txnencodingandconsensus
pub fn check_transaction_network_upgrade_consistency(
&self,
network: Network,
) -> Result<(), error::BlockError> {
let block_nu =
NetworkUpgrade::current(network, self.coinbase_height().expect("a valid height"));
if self
.transactions
.iter()
.filter_map(|trans| trans.as_ref().network_upgrade())
.any(|trans_nu| trans_nu != block_nu)
{
return Err(error::BlockError::WrongTransactionConsensusBranchId);
}
Ok(())
}
} }
impl<'a> From<&'a Block> for Hash { impl<'a> From<&'a Block> for Hash {

View File

@ -0,0 +1,10 @@
//! Errors that can occur when checking Block consensus rules.
use thiserror::Error;
#[allow(dead_code, missing_docs)]
#[derive(Error, Debug, PartialEq)]
pub enum BlockError {
#[error("transaction has wrong consensus branch id for block network upgrade")]
WrongTransactionConsensusBranchId,
}

View File

@ -192,6 +192,22 @@ impl Transaction {
} }
} }
/// Get this transaction's network upgrade field, if any.
/// This field is serialized as `nConsensusBranchId` ([7.1]).
///
/// [7.1]: https://zips.z.cash/protocol/nu5.pdf#txnencodingandconsensus
pub fn network_upgrade(&self) -> Option<NetworkUpgrade> {
match self {
Transaction::V1 { .. }
| Transaction::V2 { .. }
| Transaction::V3 { .. }
| Transaction::V4 { .. } => None,
Transaction::V5 {
network_upgrade, ..
} => Some(*network_upgrade),
}
}
// transparent // transparent
/// Access the transparent inputs of this transaction, regardless of version. /// Access the transparent inputs of this transaction, regardless of version.

View File

@ -97,13 +97,7 @@ fn transaction_valid_network_upgrade_strategy() -> Result<()> {
}); });
proptest!(|((network, block) in strategy)| { proptest!(|((network, block) in strategy)| {
// TODO: replace with check_transaction_network_upgrade from #2343 block.check_transaction_network_upgrade_consistency(network)?;
let block_network_upgrade = NetworkUpgrade::current(network, block.coinbase_height().unwrap());
for transaction in block.transactions {
if let Transaction::V5 { network_upgrade, .. } = transaction.as_ref() {
prop_assert_eq!(network_upgrade, &block_network_upgrade);
}
}
}); });
Ok(()) Ok(())

View File

@ -189,23 +189,9 @@ pub fn merkle_root_validity(
block: &Block, block: &Block,
transaction_hashes: &[transaction::Hash], transaction_hashes: &[transaction::Hash],
) -> Result<(), BlockError> { ) -> Result<(), BlockError> {
use transaction::Transaction;
let block_nu =
NetworkUpgrade::current(network, block.coinbase_height().expect("a valid height"));
if block if block
.transactions .check_transaction_network_upgrade_consistency(network)
.iter() .is_err()
.filter_map(|trans| match *trans.as_ref() {
Transaction::V5 {
network_upgrade, ..
} => Some(network_upgrade),
Transaction::V1 { .. }
| Transaction::V2 { .. }
| Transaction::V3 { .. }
| Transaction::V4 { .. } => None,
})
.any(|trans_nu| trans_nu != block_nu)
{ {
return Err(BlockError::WrongTransactionConsensusBranchId); return Err(BlockError::WrongTransactionConsensusBranchId);
} }