From 7fedf93eb9810b10e62043620ac87e901b840ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Cauderlier?= Date: Wed, 26 Feb 2025 17:09:23 +0100 Subject: [PATCH 1/2] Etherlink/Kernel: propagate parent block hash instead of re-reading it To validate a blueprint from the sequencer, we need to check that its parent hash is exactly the hash of the head block. We already have the information at hand so we don't need to fetch it again from the storage. --- etherlink/kernel_evm/kernel/src/block.rs | 7 ++++- .../kernel/src/blueprint_storage.rs | 31 +++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/etherlink/kernel_evm/kernel/src/block.rs b/etherlink/kernel_evm/kernel/src/block.rs index acfa7c92d6c8..664bc9b9920d 100644 --- a/etherlink/kernel_evm/kernel/src/block.rs +++ b/etherlink/kernel_evm/kernel/src/block.rs @@ -254,7 +254,12 @@ fn next_bip_from_blueprints( kernel_upgrade: &Option, minimum_base_fee_per_gas: U256, ) -> Result { - let (blueprint, size) = read_blueprint(host, config, current_block_number)?; + let (blueprint, size) = read_blueprint( + host, + config, + current_block_number, + current_block_parent_hash, + )?; log!(host, Benchmarking, "Size of blueprint: {}", size); match blueprint { Some(blueprint) => { diff --git a/etherlink/kernel_evm/kernel/src/blueprint_storage.rs b/etherlink/kernel_evm/kernel/src/blueprint_storage.rs index 0548f72af084..22ebd6325789 100644 --- a/etherlink/kernel_evm/kernel/src/blueprint_storage.rs +++ b/etherlink/kernel_evm/kernel/src/blueprint_storage.rs @@ -3,7 +3,6 @@ // // SPDX-License-Identifier: MIT -use crate::block::GENESIS_PARENT_HASH; use crate::block_storage; use crate::blueprint::Blueprint; use crate::configuration::{Configuration, ConfigurationMode}; @@ -14,7 +13,7 @@ use crate::sequencer_blueprint::{ }; use crate::storage::read_last_info_per_level_timestamp; use crate::{delayed_inbox, DelayedInbox}; -use primitive_types::U256; +use primitive_types::{H256, U256}; use rlp::{Decodable, DecoderError, Encodable}; use sha3::{Digest, Keccak256}; use tezos_ethereum::rlp_helpers; @@ -275,20 +274,21 @@ fn parse_and_validate_blueprint( current_blueprint_size: usize, evm_node_flag: bool, max_blueprint_lookahead_in_seconds: i64, + parent_hash: H256, ) -> anyhow::Result<(BlueprintValidity, usize)> { // Decode match rlp::decode::(bytes) { Err(e) => Ok((BlueprintValidity::DecoderError(e), bytes.len())), Ok(blueprint_with_hashes) => { let head = block_storage::read_current(host); - let (head_hash, head_timestamp) = match head { - Ok(block) => (block.hash, block.timestamp), - Err(_) => (GENESIS_PARENT_HASH, Timestamp::from(0)), + let head_timestamp = match head { + Ok(block) => block.timestamp, + Err(_) => Timestamp::from(0), }; // Validate parent hash #[cfg(not(feature = "benchmark"))] - if head_hash != blueprint_with_hashes.parent_hash { + if parent_hash != blueprint_with_hashes.parent_hash { return Ok((BlueprintValidity::InvalidParentHash, bytes.len())); } @@ -364,6 +364,7 @@ fn read_all_chunks_and_validate( blueprint_path: &OwnedPath, nb_chunks: u16, config: &mut Configuration, + parent_hash: H256, ) -> anyhow::Result<(Option, usize)> { let mut chunks = vec![]; let mut size = 0; @@ -404,6 +405,7 @@ fn read_all_chunks_and_validate( size, *evm_node_flag, *max_blueprint_lookahead_in_seconds, + parent_hash, )?; if let (BlueprintValidity::Valid(blueprint), size_with_delayed_transactions) = validity @@ -427,6 +429,7 @@ pub fn read_blueprint( host: &mut Host, config: &mut Configuration, number: U256, + parent_hash: H256, ) -> anyhow::Result<(Option, usize)> { let blueprint_path = blueprint_path(number)?; let exists = host.store_has(&blueprint_path)?.is_some(); @@ -442,8 +445,13 @@ pub fn read_blueprint( let available_chunks = n_subkeys as u16 - 1; if available_chunks == nb_chunks { // All chunks are available - let (blueprint, size) = - read_all_chunks_and_validate(host, &blueprint_path, nb_chunks, config)?; + let (blueprint, size) = read_all_chunks_and_validate( + host, + &blueprint_path, + nb_chunks, + config, + parent_hash, + )?; Ok((blueprint, size)) } else { if available_chunks > nb_chunks { @@ -474,7 +482,9 @@ pub fn read_next_blueprint( config: &mut Configuration, ) -> anyhow::Result<(Option, usize)> { let number = read_next_blueprint_number(host)?; - read_blueprint(host, config, number) + let parent_hash = block_storage::read_current_hash(host) + .unwrap_or(crate::block::GENESIS_PARENT_HASH); + read_blueprint(host, config, number, parent_hash) } pub fn drop_blueprint(host: &mut Host, number: U256) -> Result<(), Error> { @@ -494,6 +504,7 @@ pub fn clear_all_blueprints(host: &mut Host) -> Result<(), Error> mod tests { use super::*; + use crate::block::GENESIS_PARENT_HASH; use crate::configuration::{DalConfiguration, Limits, TezosContracts}; use crate::delayed_inbox::Hash; use crate::storage::store_last_info_per_level_timestamp; @@ -575,6 +586,7 @@ mod tests { 0, false, 500, + GENESIS_PARENT_HASH, ) .expect("Should be able to parse blueprint"); assert_eq!( @@ -635,6 +647,7 @@ mod tests { 0, false, 500, + GENESIS_PARENT_HASH, ) .expect("Should be able to parse blueprint"); assert_eq!(validity.0, BlueprintValidity::InvalidParentHash); -- GitLab From a04d65cb41d283685df27e800b9713db18e3b2b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Cauderlier?= Date: Wed, 26 Feb 2025 17:25:43 +0100 Subject: [PATCH 2/2] Etherlink/Kernel: also propagate the timestamp --- etherlink/kernel_evm/kernel/src/block.rs | 15 +++++++++- .../kernel/src/blueprint_storage.rs | 28 ++++++++++++------- etherlink/kernel_evm/kernel/src/stage_one.rs | 19 +++++++++---- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/etherlink/kernel_evm/kernel/src/block.rs b/etherlink/kernel_evm/kernel/src/block.rs index 664bc9b9920d..3593f0bbd148 100644 --- a/etherlink/kernel_evm/kernel/src/block.rs +++ b/etherlink/kernel_evm/kernel/src/block.rs @@ -34,6 +34,7 @@ use tezos_evm_logging::{log, Level::*, Verbosity}; use tezos_evm_runtime::runtime::Runtime; use tezos_evm_runtime::safe_storage::SafeStorage; use tezos_smart_rollup::outbox::OutboxQueue; +use tezos_smart_rollup::types::Timestamp; use tezos_smart_rollup_host::path::Path; use tick_model::estimate_remaining_ticks_for_transaction_execution; @@ -245,10 +246,12 @@ enum BlueprintParsing { } #[cfg_attr(feature = "benchmark", inline(never))] +#[allow(clippy::too_many_arguments)] fn next_bip_from_blueprints( host: &mut Host, current_block_number: U256, current_block_parent_hash: H256, + previous_timestamp: Timestamp, tick_counter: &TickCounter, config: &mut Configuration, kernel_upgrade: &Option, @@ -259,6 +262,7 @@ fn next_bip_from_blueprints( config, current_block_number, current_block_parent_hash, + previous_timestamp, )?; log!(host, Benchmarking, "Size of blueprint: {}", size); match blueprint { @@ -460,16 +464,24 @@ pub fn produce( let ( current_block_number, current_block_parent_hash, + previous_timestamp, previous_receipts_root, previous_transactions_root, ) = match block_storage::read_current(host) { Ok(block) => ( block.number + 1, block.hash, + block.timestamp, block.receipts_root, block.transactions_root, ), - Err(_) => (U256::zero(), GENESIS_PARENT_HASH, vec![0; 32], vec![0; 32]), + Err(_) => ( + U256::zero(), + GENESIS_PARENT_HASH, + Timestamp::from(0), + vec![0; 32], + vec![0; 32], + ), }; let mut evm_account_storage = init_account_storage().context("Failed to initialize EVM account storage")?; @@ -498,6 +510,7 @@ pub fn produce( safe_host.host, current_block_number, current_block_parent_hash, + previous_timestamp, &tick_counter, config, &kernel_upgrade, diff --git a/etherlink/kernel_evm/kernel/src/blueprint_storage.rs b/etherlink/kernel_evm/kernel/src/blueprint_storage.rs index 22ebd6325789..2f566a4095f3 100644 --- a/etherlink/kernel_evm/kernel/src/blueprint_storage.rs +++ b/etherlink/kernel_evm/kernel/src/blueprint_storage.rs @@ -267,6 +267,7 @@ fn fetch_delayed_txs( // wish to refuse such blueprints. pub const DEFAULT_MAX_BLUEPRINT_LOOKAHEAD_IN_SECONDS: i64 = 300i64; +#[allow(clippy::too_many_arguments)] fn parse_and_validate_blueprint( host: &mut Host, bytes: &[u8], @@ -275,17 +276,12 @@ fn parse_and_validate_blueprint( evm_node_flag: bool, max_blueprint_lookahead_in_seconds: i64, parent_hash: H256, + head_timestamp: Timestamp, ) -> anyhow::Result<(BlueprintValidity, usize)> { // Decode match rlp::decode::(bytes) { Err(e) => Ok((BlueprintValidity::DecoderError(e), bytes.len())), Ok(blueprint_with_hashes) => { - let head = block_storage::read_current(host); - let head_timestamp = match head { - Ok(block) => block.timestamp, - Err(_) => Timestamp::from(0), - }; - // Validate parent hash #[cfg(not(feature = "benchmark"))] if parent_hash != blueprint_with_hashes.parent_hash { @@ -365,6 +361,7 @@ fn read_all_chunks_and_validate( nb_chunks: u16, config: &mut Configuration, parent_hash: H256, + previous_timestamp: Timestamp, ) -> anyhow::Result<(Option, usize)> { let mut chunks = vec![]; let mut size = 0; @@ -406,6 +403,7 @@ fn read_all_chunks_and_validate( *evm_node_flag, *max_blueprint_lookahead_in_seconds, parent_hash, + previous_timestamp, )?; if let (BlueprintValidity::Valid(blueprint), size_with_delayed_transactions) = validity @@ -430,6 +428,7 @@ pub fn read_blueprint( config: &mut Configuration, number: U256, parent_hash: H256, + previous_timestamp: Timestamp, ) -> anyhow::Result<(Option, usize)> { let blueprint_path = blueprint_path(number)?; let exists = host.store_has(&blueprint_path)?.is_some(); @@ -451,6 +450,7 @@ pub fn read_blueprint( nb_chunks, config, parent_hash, + previous_timestamp, )?; Ok((blueprint, size)) } else { @@ -481,10 +481,16 @@ pub fn read_next_blueprint( host: &mut Host, config: &mut Configuration, ) -> anyhow::Result<(Option, usize)> { - let number = read_next_blueprint_number(host)?; - let parent_hash = block_storage::read_current_hash(host) - .unwrap_or(crate::block::GENESIS_PARENT_HASH); - read_blueprint(host, config, number, parent_hash) + let (number, parent_hash, previous_timestamp) = + match block_storage::read_current(host) { + Ok(block) => (block.number + 1, block.hash, block.timestamp), + Err(_) => ( + U256::zero(), + crate::block::GENESIS_PARENT_HASH, + Timestamp::from(0), + ), + }; + read_blueprint(host, config, number, parent_hash, previous_timestamp) } pub fn drop_blueprint(host: &mut Host, number: U256) -> Result<(), Error> { @@ -587,6 +593,7 @@ mod tests { false, 500, GENESIS_PARENT_HASH, + Timestamp::from(0), ) .expect("Should be able to parse blueprint"); assert_eq!( @@ -648,6 +655,7 @@ mod tests { false, 500, GENESIS_PARENT_HASH, + Timestamp::from(0), ) .expect("Should be able to parse blueprint"); assert_eq!(validity.0, BlueprintValidity::InvalidParentHash); diff --git a/etherlink/kernel_evm/kernel/src/stage_one.rs b/etherlink/kernel_evm/kernel/src/stage_one.rs index 119b5da0498d..eba15df16691 100644 --- a/etherlink/kernel_evm/kernel/src/stage_one.rs +++ b/etherlink/kernel_evm/kernel/src/stage_one.rs @@ -226,7 +226,9 @@ mod tests { use crate::{ block_storage::internal_for_tests::store_current_number, - blueprint_storage::read_next_blueprint, dal::tests::*, parsing::RollupType, + blueprint_storage::{read_blueprint, read_next_blueprint}, + dal::tests::*, + parsing::RollupType, }; use super::*; @@ -495,11 +497,16 @@ mod tests { fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); // The dummy chunk in the inbox is registered at block 10 - store_current_number(&mut host, U256::from(9)).unwrap(); - if read_next_blueprint(&mut host, &mut conf) - .expect("Blueprint reading shouldn't fail") - .0 - .is_none() + if read_blueprint( + &mut host, + &mut conf, + U256::from(10), + crate::block::GENESIS_PARENT_HASH, + Timestamp::from(0), + ) + .expect("Blueprint reading shouldn't fail") + .0 + .is_none() { panic!("There should be a blueprint") } -- GitLab