move `is_coinbase_first` from chain to consensus
This commit is contained in:
parent
e67d3fc5e3
commit
4dac4d4df7
|
@ -50,29 +50,6 @@ impl Block {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check that there is exactly one coinbase transaction in `Block`, and that
|
|
||||||
/// the coinbase transaction is the first transaction in the block.
|
|
||||||
///
|
|
||||||
/// "The first (and only the first) transaction in a block is a coinbase
|
|
||||||
/// transaction, which collects and spends any miner subsidy and transaction
|
|
||||||
/// fees paid by transactions included in this block." [§3.10][3.10]
|
|
||||||
///
|
|
||||||
/// [3.10]: https://zips.z.cash/protocol/protocol.pdf#coinbasetransactions
|
|
||||||
pub fn is_coinbase_first(&self) -> Result<(), Error> {
|
|
||||||
let first = self
|
|
||||||
.transactions
|
|
||||||
.get(0)
|
|
||||||
.ok_or_else(|| "block has no transactions")?;
|
|
||||||
let mut rest = self.transactions.iter().skip(1);
|
|
||||||
if !first.is_coinbase() {
|
|
||||||
return Err("first transaction must be coinbase".into());
|
|
||||||
}
|
|
||||||
if rest.any(|tx| tx.contains_coinbase_input()) {
|
|
||||||
return Err("coinbase input found in non-coinbase transaction".into());
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the hash for the current block
|
/// Get the hash for the current block
|
||||||
pub fn hash(&self) -> Hash {
|
pub fn hash(&self) -> Hash {
|
||||||
Hash::from(self)
|
Hash::from(self)
|
||||||
|
|
|
@ -8,9 +8,12 @@
|
||||||
//! Verification is provided via a `tower::Service`, to support backpressure and batch
|
//! Verification is provided via a `tower::Service`, to support backpressure and batch
|
||||||
//! verification.
|
//! verification.
|
||||||
|
|
||||||
|
mod checks;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
use checks::*;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use color_eyre::eyre::{eyre, Report};
|
use color_eyre::eyre::{eyre, Report};
|
||||||
use futures_util::FutureExt;
|
use futures_util::FutureExt;
|
||||||
|
@ -106,7 +109,7 @@ where
|
||||||
// Field validity and structure checks
|
// Field validity and structure checks
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
block.header.is_time_valid_at(now)?;
|
block.header.is_time_valid_at(now)?;
|
||||||
block.is_coinbase_first()?;
|
is_coinbase_first(&block)?;
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - context-free header verification: merkle root
|
// - context-free header verification: merkle root
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
//! Consensus check functions
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use zebra_chain::block::Block;
|
||||||
|
|
||||||
|
/// Check that there is exactly one coinbase transaction in `Block`, and that
|
||||||
|
/// the coinbase transaction is the first transaction in the block.
|
||||||
|
///
|
||||||
|
/// "The first (and only the first) transaction in a block is a coinbase
|
||||||
|
/// transaction, which collects and spends any miner subsidy and transaction
|
||||||
|
/// fees paid by transactions included in this block." [§3.10][3.10]
|
||||||
|
///
|
||||||
|
/// [3.10]: https://zips.z.cash/protocol/protocol.pdf#coinbasetransactions
|
||||||
|
pub fn is_coinbase_first(block: &Block) -> Result<(), Error> {
|
||||||
|
let first = block
|
||||||
|
.transactions
|
||||||
|
.get(0)
|
||||||
|
.ok_or_else(|| "block has no transactions")?;
|
||||||
|
let mut rest = block.transactions.iter().skip(1);
|
||||||
|
if !first.is_coinbase() {
|
||||||
|
return Err("first transaction must be coinbase".into());
|
||||||
|
}
|
||||||
|
if rest.any(|tx| tx.contains_coinbase_input()) {
|
||||||
|
return Err("coinbase input found in non-coinbase transaction".into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue