Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/consensus/src/transaction/compress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ impl Compress for TaikoTxEnvelope {
type Compressed = Vec<u8>;

fn compress_to_buf<B: bytes::BufMut + AsMut<[u8]>>(&self, buf: &mut B) {
let _ = Compact::to_compact(self, buf); // Delegates to your Compact impl!
let _ = Compact::to_compact(self, buf);
}
}

Expand Down
109 changes: 104 additions & 5 deletions crates/consensus/src/validation.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
use std::{fmt::Debug, sync::Arc};

use alloy_consensus::{BlockHeader as AlloyBlockHeader, EMPTY_OMMER_ROOT_HASH, Transaction};
use alloy_consensus::{
BlockHeader as AlloyBlockHeader, EMPTY_OMMER_ROOT_HASH, Transaction, TxReceipt,
proofs::calculate_receipt_root,
};
use alloy_eips::{Encodable2718, eip7685::Requests};
use alloy_hardforks::EthereumHardforks;
use alloy_primitives::{Address, U256};
use alloy_primitives::{Address, B256, Bloom, Bytes, U256};
use alloy_sol_types::{SolCall, sol};
use reth_chainspec::EthChainSpec;
use reth_consensus::{Consensus, ConsensusError, FullConsensus, HeaderValidator};
use reth_consensus_common::validation::{
validate_against_parent_hash_number, validate_body_against_header, validate_header_base_fee,
validate_header_extra_data, validate_header_gas,
};
use reth_ethereum_consensus::validate_block_post_execution;
use reth_evm::block::BlockExecutionResult;
use reth_primitives_traits::{
Block, BlockBody, BlockHeader, GotExpected, NodePrimitives, RecoveredBlock, SealedBlock,
SealedHeader, SignedTransaction,
Block, BlockBody, BlockHeader, GotExpected, NodePrimitives, Receipt, RecoveredBlock,
SealedBlock, SealedHeader, SignedTransaction, receipt::gas_spent_by_transactions,
};
use reth_storage_api::BlockReader;

Expand Down Expand Up @@ -332,6 +335,102 @@ fn validate_input_selector(
Ok(())
}

/// Validate a block with regard to execution results:
///
/// - Compares the receipts root in the block header to the block body
/// - Compares the gas used in the block header to the actual gas usage after execution
///
/// Not: Taiko does not use requests hash validation, so that part is omitted.
pub fn validate_block_post_execution<B, R, ChainSpec>(
block: &RecoveredBlock<B>,
chain_spec: &ChainSpec,
receipts: &[R],
_requests: &Requests,
) -> Result<(), ConsensusError>
where
B: Block,
R: Receipt,
ChainSpec: EthereumHardforks,
{
// Check if gas used matches the value set in header.
let cumulative_gas_used =
receipts.last().map(|receipt| receipt.cumulative_gas_used()).unwrap_or(0);
if block.header().gas_used() != cumulative_gas_used {
return Err(ConsensusError::BlockGasUsed {
gas: GotExpected { got: cumulative_gas_used, expected: block.header().gas_used() },
gas_spent_by_tx: gas_spent_by_transactions(receipts),
})
}

// Before Byzantium, receipts contained state root that would mean that expensive
// operation as hashing that is required for state root got calculated in every
// transaction This was replaced with is_success flag.
// See more about EIP here: https://eips.ethereum.org/EIPS/eip-658
if chain_spec.is_byzantium_active_at_block(block.header().number()) &&
let Err(error) = verify_receipts(
block.header().receipts_root(),
block.header().logs_bloom(),
receipts,
)
{
let receipts = receipts
.iter()
.map(|r| Bytes::from(r.with_bloom_ref().encoded_2718()))
.collect::<Vec<_>>();
tracing::debug!(%error, ?receipts, "receipts verification failed");
return Err(error)
}

Ok(())
}

/// Calculate the receipts root, and compare it against the expected receipts root and logs
/// bloom.
fn verify_receipts<R: Receipt>(
expected_receipts_root: B256,
expected_logs_bloom: Bloom,
receipts: &[R],
) -> Result<(), ConsensusError> {
// Calculate receipts root.
let receipts_with_bloom = receipts.iter().map(TxReceipt::with_bloom_ref).collect::<Vec<_>>();
let receipts_root = calculate_receipt_root(&receipts_with_bloom);

// Calculate header logs bloom.
let logs_bloom = receipts_with_bloom.iter().fold(Bloom::ZERO, |bloom, r| bloom | r.bloom_ref());

compare_receipts_root_and_logs_bloom(
receipts_root,
logs_bloom,
expected_receipts_root,
expected_logs_bloom,
)?;

Ok(())
}

/// Compare the calculated receipts root with the expected receipts root, also compare
/// the calculated logs bloom with the expected logs bloom.
fn compare_receipts_root_and_logs_bloom(
calculated_receipts_root: B256,
calculated_logs_bloom: Bloom,
expected_receipts_root: B256,
expected_logs_bloom: Bloom,
) -> Result<(), ConsensusError> {
if calculated_receipts_root != expected_receipts_root {
return Err(ConsensusError::BodyReceiptRootDiff(
GotExpected { got: calculated_receipts_root, expected: expected_receipts_root }.into(),
))
}

if calculated_logs_bloom != expected_logs_bloom {
return Err(ConsensusError::BodyBloomLogDiff(
GotExpected { got: calculated_logs_bloom, expected: expected_logs_bloom }.into(),
))
}

Ok(())
}

#[cfg(test)]
mod test {
use alloy_consensus::Header;
Expand Down
4 changes: 0 additions & 4 deletions crates/evm/src/handler/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,6 @@ pub fn blob_basefee<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) {
context.interpreter.halt_not_activated();

return;
}

/// Custom implementation of BLOBHASH instruction for Taiko EVM.
Expand All @@ -95,6 +93,4 @@ pub fn blob_hash<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) {
context.interpreter.halt_not_activated();

return;
}
4 changes: 2 additions & 2 deletions crates/evm/src/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl TaikoSpecId {
/// Converts the [`TaikoSpecId`] into a [`SpecId`].
pub const fn into_eth_spec(self) -> SpecId {
match self {
Self::GENESIS | Self::ONTAKE | Self::PACAYA | Self::SHASTA => SpecId::CANCUN,
Self::GENESIS | Self::ONTAKE | Self::PACAYA | Self::SHASTA => SpecId::PRAGUE,
}
}

Expand Down Expand Up @@ -84,7 +84,7 @@ mod tests {
(SpecId::MERGE, true),
(SpecId::SHANGHAI, true),
(SpecId::CANCUN, true),
(SpecId::default(), false),
(SpecId::PRAGUE, true),
],
vec![
(TaikoSpecId::GENESIS, true),
Expand Down
Loading