diff --git a/etherlink/kernel_latest/kernel/src/block.rs b/etherlink/kernel_latest/kernel/src/block.rs index 1baa7fd9147daafc429499c2b2bb134415b8e0d0..d61a6ed68c785c3cf885ef288baad70f1654ad55 100644 --- a/etherlink/kernel_latest/kernel/src/block.rs +++ b/etherlink/kernel_latest/kernel/src/block.rs @@ -8,22 +8,25 @@ use crate::apply::{ apply_transaction, ExecutionInfo, ExecutionResult, Validity, WITHDRAWAL_OUTBOX_QUEUE, }; +use crate::blueprint::Blueprint; use crate::blueprint_storage::{ - drop_blueprint, read_blueprint, read_current_block_header_for_family, - store_current_block_header, BlockHeader, ChainHeader, + drop_blueprint, read_blueprint, read_current_block_header, + store_current_block_header, BlockHeader, ChainHeader, EVMBlockHeader, +}; +use crate::chains::{ + BlockInProgressTrait, ChainConfigTrait, ChainHeaderTrait, EvmChainConfig, EvmLimits, }; -use crate::chains::{ChainConfig, EvmLimits}; use crate::configuration::ConfigurationMode; use crate::delayed_inbox::DelayedInbox; use crate::error::Error; use crate::event::Event; use crate::l2block::L2Block; -use crate::transaction::Transaction; +use crate::storage; +use crate::transaction::{Transaction, Transactions}; use crate::upgrade; use crate::upgrade::KernelUpgrade; use crate::Configuration; use crate::{block_in_progress, tick_model}; -use crate::{block_storage, storage}; use anyhow::Context; use block_in_progress::EthBlockInProgress; use evm::Config; @@ -40,7 +43,6 @@ 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 tezos_tezlink::block::TezBlock; use tick_model::estimate_remaining_ticks_for_transaction_execution; pub const GENESIS_PARENT_HASH: H256 = H256([0xff; 32]); @@ -49,8 +51,8 @@ pub const GAS_LIMIT: u64 = 1 << 50; /// Struct used to allow the compiler to check that the tick counter value is /// correctly moved and updated. Copy and Clone should NOT be derived. -struct TickCounter { - c: u64, +pub struct TickCounter { + pub c: u64, } impl TickCounter { @@ -246,56 +248,70 @@ fn compute( }) } -#[allow(clippy::large_enum_variant)] -pub enum BlockInProgress { - Etherlink(EthBlockInProgress), - Tezlink { - number: U256, - timestamp: Timestamp, - previous_hash: H256, - }, +enum BlueprintParsing { + Next(Box), + None, } -impl BlockInProgress { - pub fn number(&self) -> U256 { - match self { - Self::Etherlink(bip) => bip.number, - Self::Tezlink { number, .. } => *number, - } - } -} +pub fn eth_bip_from_blueprint( + host: &Host, + chain_config: &EvmChainConfig, + tick_counter: &TickCounter, + next_bip_number: U256, + header: EVMBlockHeader, + blueprint: Blueprint, +) -> EthBlockInProgress { + let gas_price = crate::gas_price::base_fee_per_gas( + host, + blueprint.timestamp, + chain_config.get_limits().minimum_base_fee_per_gas, + ); -enum BlueprintParsing { - Next(Box), - None, + let bip = EthBlockInProgress::from_blueprint( + blueprint, + next_bip_number, + header.hash, + tick_counter.c, + gas_price, + header.receipts_root, + header.transactions_root, + ); + + tezos_evm_logging::log!(host, tezos_evm_logging::Level::Debug, "bip: {bip:?}"); + bip } #[cfg_attr(feature = "benchmark", inline(never))] -fn next_bip_from_blueprints( +fn next_bip_from_blueprints( host: &mut Host, tick_counter: &TickCounter, + chain_config: &ChainConfig, config: &mut Configuration, kernel_upgrade: &Option, -) -> Result { - let chain_family = config.chain_config.get_chain_family(); - let (next_bip_number, timestamp, chain_header) = - match read_current_block_header_for_family(host, &chain_family) { - Err(_) => ( - U256::zero(), - Timestamp::from(0), - ChainHeader::genesis_header(chain_family), - ), - Ok(BlockHeader { - blueprint_header, - chain_header, - }) => ( - blueprint_header.number + 1, - blueprint_header.timestamp, - chain_header, - ), - }; - let (blueprint, size) = - read_blueprint(host, config, next_bip_number, timestamp, &chain_header)?; +) -> Result, anyhow::Error> { + let (next_bip_number, timestamp, chain_header) = match read_current_block_header(host) + { + Err(_) => ( + U256::zero(), + Timestamp::from(0), + ChainConfig::ChainHeader::genesis_header(), + ), + Ok(BlockHeader { + blueprint_header, + chain_header, + }) => ( + blueprint_header.number + 1, + blueprint_header.timestamp, + chain_header, + ), + }; + let (blueprint, size) = read_blueprint::<_, ChainConfig>( + host, + config, + next_bip_number, + timestamp, + &chain_header, + )?; log!(host, Benchmarking, "Size of blueprint: {}", size); match blueprint { Some(blueprint) => { @@ -307,56 +323,22 @@ fn next_bip_from_blueprints( return Ok(BlueprintParsing::None); } } - match (&config.chain_config, chain_header) { - (ChainConfig::Evm(chain_config), ChainHeader::Eth(header)) => { - let gas_price = crate::gas_price::base_fee_per_gas( - host, - blueprint.timestamp, - chain_config.limits.minimum_base_fee_per_gas, - ); - - let bip = block_in_progress::EthBlockInProgress::from_blueprint( - blueprint, - next_bip_number, - header.hash, - tick_counter.c, - gas_price, - header.receipts_root, - header.transactions_root, - ); - - tezos_evm_logging::log!( - host, - tezos_evm_logging::Level::Debug, - "bip: {bip:?}" - ); - Ok(BlueprintParsing::Next(Box::new( - BlockInProgress::Etherlink(bip), - ))) - } - (ChainConfig::Michelson(_), ChainHeader::Tez(header)) => { - Ok(BlueprintParsing::Next(Box::new(BlockInProgress::Tezlink { - number: next_bip_number, - timestamp: blueprint.timestamp, - previous_hash: header.hash, - }))) - } - (_, _) => { - log!( - host, - Fatal, - "Incoherent state between the configuration and the header read in the durable storage" - ); - Ok(BlueprintParsing::None) - } - } + let bip: ChainConfig::BlockInProgress = chain_config + .block_in_progress_from_blueprint( + host, + tick_counter, + next_bip_number, + chain_header, + blueprint, + ); + Ok(BlueprintParsing::Next(Box::new(bip))) } None => Ok(BlueprintParsing::None), } } #[allow(clippy::too_many_arguments)] -fn compute_bip( +pub fn compute_bip( host: &mut Host, outbox_queue: &OutboxQueue<'_, impl Path>, mut block_in_progress: EthBlockInProgress, @@ -496,13 +478,13 @@ fn promote_block( Ok(()) } -pub fn produce( +pub fn produce( host: &mut Host, + chain_config: &ChainConfig, config: &mut Configuration, sequencer_pool_address: Option, tracer_input: Option, ) -> Result { - let chain_id = config.chain_config.get_chain_id(); let da_fee_per_byte = crate::retrieve_da_fee(host)?; let kernel_upgrade = upgrade::read_kernel_upgrade(host)?; @@ -520,13 +502,9 @@ pub fn produce( // Check if there's a BIP in storage to resume its execution let (block_in_progress_provenance, block_in_progress) = - match storage::read_block_in_progress(&safe_host)? { + match ChainConfig::read_block_in_progress(&safe_host)? { Some(block_in_progress) => { - // We don't yet support saving Tez block in progress in the durable storage and restoring them. - ( - BlockInProgressProvenance::Storage, - BlockInProgress::Etherlink(block_in_progress), - ) + (BlockInProgressProvenance::Storage, block_in_progress) } None => { // Using `safe_host.host` allows to escape from the failsafe storage, which is necessary @@ -537,6 +515,7 @@ pub fn produce( let block_in_progress = match next_bip_from_blueprints( safe_host.host, &tick_counter, + chain_config, config, &kernel_upgrade, )? { @@ -559,66 +538,18 @@ pub fn produce( }; let processed_blueprint = block_in_progress.number(); - let computation_result = match (&config.chain_config, block_in_progress) { - ( - ChainConfig::Evm(chain_config), - BlockInProgress::Etherlink(block_in_progress), - ) => { - log!( - safe_host, - Debug, - "Computing the BlockInProgress for Etherlink" - ); - compute_bip( - &mut safe_host, - &outbox_queue, - block_in_progress, - &precompiles, - &mut tick_counter, - sequencer_pool_address, - &chain_config.limits, - config.maximum_allowed_ticks, - tracer_input, - chain_id, - da_fee_per_byte, - coinbase, - &chain_config.evm_config, - ) - } - ( - ChainConfig::Michelson(_), - BlockInProgress::Tezlink { - number, - timestamp, - previous_hash, - }, - ) => { - log!( - safe_host, - Debug, - "Computing the BlockInProgress for Tezlink at level {}", - number - ); - - let tezblock = TezBlock::new(number, timestamp, previous_hash); - let new_block = L2Block::Tezlink(tezblock); - block_storage::store_current(&mut safe_host, &new_block) - .context("Failed to store the current block")?; - Ok(BlockComputationResult::Finished { - included_delayed_transactions: vec![], - block: new_block, - }) - } - (_, _) => { - // This case should be correctly handled by this MR https://gitlab.com/tezos/tezos/-/merge_requests/17259 - log!( - safe_host, - Fatal, - "Incoherent BlockInProgress found with the Chain running in the kernel" - ); - return Ok(ComputationResult::Finished); - } - }; + let computation_result = chain_config.compute_bip( + &mut safe_host, + &outbox_queue, + block_in_progress, + &precompiles, + &mut tick_counter, + sequencer_pool_address, + config.maximum_allowed_ticks, + tracer_input, + da_fee_per_byte, + coinbase, + ); match computation_result { Ok(BlockComputationResult::Finished { included_delayed_transactions, @@ -680,8 +611,9 @@ mod tests { use crate::blueprint_storage::read_next_blueprint; use crate::blueprint_storage::store_inbox_blueprint; use crate::blueprint_storage::store_inbox_blueprint_by_number; - use crate::chains::ChainFamily; - use crate::chains::MichelsonChainConfig; + use crate::chains::{ + ChainFamily, EvmChainConfig, MichelsonChainConfig, TezTransactions, + }; use crate::fees::DA_FEE_PER_BYTE; use crate::fees::MINIMUM_BASE_FEE_PER_GAS; use crate::storage::read_block_in_progress; @@ -710,16 +642,16 @@ mod tests { use tezos_smart_rollup_encoding::timestamp::Timestamp; use tezos_smart_rollup_host::runtime::Runtime as SdkRuntime; - fn blueprint(transactions: Vec) -> Blueprint { + fn blueprint(transactions: Vec) -> Blueprint { Blueprint { transactions: Transactions::EthTxs(transactions), timestamp: Timestamp::from(0i64), } } - fn tezlink_blueprint() -> Blueprint { + fn tezlink_blueprint() -> Blueprint { Blueprint { - transactions: Transactions::TezTxs, + transactions: TezTransactions {}, timestamp: Timestamp::from(0i64), } } @@ -765,24 +697,20 @@ mod tests { const DUMMY_BASE_FEE_PER_GAS: u64 = MINIMUM_BASE_FEE_PER_GAS; const DUMMY_DA_FEE: u64 = DA_FEE_PER_BYTE; - fn dummy_configuration(evm_configuration: Config) -> Configuration { - Configuration { - chain_config: ChainConfig::new_evm_config( - DUMMY_CHAIN_ID, - EvmLimits::default(), - evm_configuration, - ), - ..Configuration::default() - } + fn dummy_evm_config(evm_configuration: Config) -> EvmChainConfig { + EvmChainConfig::create_config( + DUMMY_CHAIN_ID, + EvmLimits::default(), + evm_configuration, + ) } - fn dummy_tez_configuration() -> Configuration { - Configuration { - chain_config: ChainConfig::Michelson(MichelsonChainConfig::create_config( - DUMMY_CHAIN_ID, - )), - ..Configuration::default() - } + fn dummy_tez_config() -> MichelsonChainConfig { + MichelsonChainConfig::create_config(DUMMY_CHAIN_ID) + } + + fn dummy_configuration() -> Configuration { + Configuration::default() } fn dummy_block_fees() -> BlockFees { @@ -905,7 +833,10 @@ mod tests { ) } - fn store_blueprints(host: &mut Host, blueprints: Vec) { + fn store_blueprints( + host: &mut Host, + blueprints: Vec>, + ) { for (i, blueprint) in blueprints.into_iter().enumerate() { store_inbox_blueprint_by_number(host, blueprint, U256::from(i)) .expect("Should have stored blueprint"); @@ -942,7 +873,7 @@ mod tests { }, ]; - store_blueprints(host, vec![blueprint(transactions)]); + store_blueprints::<_, EvmChainConfig>(host, vec![blueprint(transactions)]); let sender = dummy_eth_caller(); set_balance( @@ -955,7 +886,8 @@ mod tests { produce( host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -976,9 +908,10 @@ mod tests { fn test_produce_tezlink_block() { let mut host = MockKernelHost::default(); - let mut config = dummy_tez_configuration(); + let chain_config = dummy_tez_config(); + let mut config = dummy_configuration(); - store_blueprints( + store_blueprints::<_, MichelsonChainConfig>( &mut host, vec![ tezlink_blueprint(), @@ -987,13 +920,13 @@ mod tests { ], ); - produce(&mut host, &mut config, None, None) + produce(&mut host, &chain_config, &mut config, None, None) .expect("The block production should have succeeded."); - produce(&mut host, &mut config, None, None) + produce(&mut host, &chain_config, &mut config, None, None) .expect("The block production should have succeeded."); - produce(&mut host, &mut config, None, None) + produce(&mut host, &chain_config, &mut config, None, None) .expect("The block production should have succeeded."); - let computation = produce(&mut host, &mut config, None, None) + let computation = produce(&mut host, &chain_config, &mut config, None, None) .expect("The block production should have succeeded."); assert_eq!(ComputationResult::Finished, computation); assert_eq!(U256::from(2), read_current_number(&host).unwrap()); @@ -1017,7 +950,7 @@ mod tests { }; let transactions: Vec = vec![invalid_tx]; - store_blueprints(&mut host, vec![blueprint(transactions)]); + store_blueprints::<_, EvmChainConfig>(&mut host, vec![blueprint(transactions)]); let mut evm_account_storage = init_account_storage().unwrap(); let sender = dummy_eth_caller(); @@ -1030,7 +963,8 @@ mod tests { store_block_fees(&mut host, &dummy_block_fees()).unwrap(); produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1060,7 +994,7 @@ mod tests { }; let transactions: Vec = vec![valid_tx]; - store_blueprints(&mut host, vec![blueprint(transactions)]); + store_blueprints::<_, EvmChainConfig>(&mut host, vec![blueprint(transactions)]); let sender = dummy_eth_caller(); let mut evm_account_storage = init_account_storage().unwrap(); @@ -1074,7 +1008,8 @@ mod tests { produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1102,7 +1037,7 @@ mod tests { }; let transactions: Vec = vec![valid_tx]; - store_blueprints(&mut host, vec![blueprint(transactions)]); + store_blueprints::<_, EvmChainConfig>(&mut host, vec![blueprint(transactions)]); let sender = H160::from_str("af1276cbb260bb13deddb4209ae99ae6e497f446").unwrap(); let mut evm_account_storage = init_account_storage().unwrap(); @@ -1116,7 +1051,8 @@ mod tests { produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1179,7 +1115,7 @@ mod tests { content: Ethereum(dummy_eth_transaction_one()), }]; - store_blueprints( + store_blueprints::<_, EvmChainConfig>( &mut host, vec![blueprint(transaction_0), blueprint(transaction_1)], ); @@ -1197,7 +1133,8 @@ mod tests { // Produce block for blueprint containing transaction_0 produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1205,7 +1142,8 @@ mod tests { // Produce block for blueprint containing transaction_1 produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1248,7 +1186,7 @@ mod tests { }, ]; - store_blueprints(&mut host, vec![blueprint(transactions)]); + store_blueprints::<_, EvmChainConfig>(&mut host, vec![blueprint(transactions)]); let sender = dummy_eth_caller(); let mut evm_account_storage = init_account_storage().unwrap(); @@ -1262,7 +1200,8 @@ mod tests { produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1303,7 +1242,7 @@ mod tests { }; let transactions = vec![tx.clone(), tx]; - store_blueprints( + store_blueprints::<_, EvmChainConfig>( &mut host, vec![blueprint(transactions.clone()), blueprint(transactions)], ); @@ -1321,7 +1260,8 @@ mod tests { produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1356,7 +1296,7 @@ mod tests { let blocks_index = block_storage::internal_for_tests::init_blocks_index().unwrap(); - store_blueprints(&mut host, vec![blueprint(vec![])]); + store_blueprints::<_, EvmChainConfig>(&mut host, vec![blueprint(vec![])]); let number_of_blocks_indexed = blocks_index.length(&host).unwrap(); let sender = dummy_eth_caller(); @@ -1370,7 +1310,8 @@ mod tests { store_block_fees(&mut host, &dummy_block_fees()).unwrap(); produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1524,13 +1465,17 @@ mod tests { tx_hash, content: Ethereum(tx), }; - store_blueprints(&mut host, vec![blueprint(vec![transaction])]); + store_blueprints::<_, EvmChainConfig>( + &mut host, + vec![blueprint(vec![transaction])], + ); // Apply the transaction store_block_fees(&mut host, &dummy_block_fees()).unwrap(); produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1546,7 +1491,7 @@ mod tests { } /// A blueprint that should produce 1 block with an invalid transaction - fn almost_empty_blueprint() -> Blueprint { + fn almost_empty_blueprint() -> Blueprint { let tx_hash = [0; TRANSACTION_HASH_SIZE]; // transaction should be invalid @@ -1576,7 +1521,8 @@ mod tests { store_block_fees(&mut host, &dummy_block_fees()).unwrap(); produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1588,7 +1534,8 @@ mod tests { store_inbox_blueprint(&mut host, blueprint).expect("Should store a blueprint"); produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1600,7 +1547,8 @@ mod tests { store_inbox_blueprint(&mut host, blueprint).expect("Should store a blueprint"); produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1724,19 +1672,21 @@ mod tests { wrap_transaction(2, loop_4600_tx), ]; - store_blueprints(&mut host, vec![blueprint(proposals)]); + store_blueprints::<_, EvmChainConfig>(&mut host, vec![blueprint(proposals)]); host.reboot_left().expect("should be some reboot left"); // Set the tick limit to 11bn ticks - 2bn, which is the old limit minus the safety margin. + let chain_config = dummy_evm_config(EVMVersion::current_test_config()); let mut configuration = Configuration { maximum_allowed_ticks: 9_000_000_000, - ..dummy_configuration(EVMVersion::current_test_config()) + ..dummy_configuration() }; store_block_fees(&mut host, &dummy_block_fees()).unwrap(); - let computation_result = produce(&mut host, &mut configuration, None, None) - .expect("Should have produced"); + let computation_result = + produce(&mut host, &chain_config, &mut configuration, None, None) + .expect("Should have produced"); // test no new block assert!( @@ -1752,6 +1702,7 @@ mod tests { fn test_reboot_many_tx_many_proposal() { // init host let mut host = MockKernelHost::default(); + let mut config = Configuration::default(); crate::storage::store_minimum_base_fee_per_gas( &mut host, @@ -1801,21 +1752,24 @@ mod tests { ]), ]; - store_blueprints(&mut host, proposals); + store_blueprints::<_, EvmChainConfig>(&mut host, proposals); // Set the tick limit to 11bn ticks - 2bn, which is the old limit minus the safety margin. + let chain_config = dummy_evm_config(EVMVersion::current_test_config()); let mut configuration = Configuration { maximum_allowed_ticks: 9_000_000_000, - ..dummy_configuration(EVMVersion::current_test_config()) + ..dummy_configuration() }; store_block_fees(&mut host, &dummy_block_fees()).unwrap(); - let computation_result = produce(&mut host, &mut configuration, None, None) - .expect("Should have produced"); + let computation_result = + produce(&mut host, &chain_config, &mut configuration, None, None) + .expect("Should have produced"); // test reboot is set matches!(computation_result, ComputationResult::RebootNeeded); - let computation_result = produce(&mut host, &mut configuration, None, None) - .expect("Should have produced"); + let computation_result = + produce(&mut host, &chain_config, &mut configuration, None, None) + .expect("Should have produced"); // test no new block assert_eq!( @@ -1839,9 +1793,8 @@ mod tests { "There should be some transactions left" ); - let _next_blueprint = - read_next_blueprint(&mut host, &mut Configuration::default()) - .expect("The next blueprint should be available"); + let _next_blueprint = read_next_blueprint(&mut host, &mut config) + .expect("The next blueprint should be available"); } #[test] @@ -1885,7 +1838,7 @@ mod tests { let transactions: Vec = vec![tx]; - store_blueprints(&mut host, vec![blueprint(transactions)]); + store_blueprints::<_, EvmChainConfig>(&mut host, vec![blueprint(transactions)]); let sender = H160::from_str("05f32b3cc3888453ff71b01135b34ff8e41263f2").unwrap(); let mut evm_account_storage = init_account_storage().unwrap(); @@ -1898,7 +1851,8 @@ mod tests { produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) @@ -1956,9 +1910,10 @@ mod tests { store_inbox_blueprint(&mut host, blueprint(proposals_first_reboot)).unwrap(); // Set the tick limit to 11bn ticks - 2bn, which is the old limit minus the safety margin. + let chain_config = dummy_evm_config(EVMVersion::current_test_config()); let mut configuration = Configuration { maximum_allowed_ticks: 9_000_000_000, - ..dummy_configuration(EVMVersion::current_test_config()) + ..dummy_configuration() }; // sanity check: no current block assert!( @@ -1966,7 +1921,8 @@ mod tests { "Should not have found current block number" ); store_block_fees(&mut host, &dummy_block_fees()).unwrap(); - produce(&mut host, &mut configuration, None, None).expect("Should have produced"); + produce(&mut host, &chain_config, &mut configuration, None, None) + .expect("Should have produced"); assert!( block_storage::read_current_number(&host).is_ok(), @@ -1980,7 +1936,8 @@ mod tests { store_inbox_blueprint(&mut host, blueprint(proposals_second_reboot)).unwrap(); store_block_fees(&mut host, &dummy_block_fees()).unwrap(); - produce(&mut host, &mut configuration, None, None).expect("Should have produced"); + produce(&mut host, &chain_config, &mut configuration, None, None) + .expect("Should have produced"); let block = block_storage::read_current(&mut host, &ChainFamily::Evm) .expect("Should have found a block"); @@ -2047,7 +2004,7 @@ mod tests { let transactions: Vec = vec![valid_tx, valid_tx_eip1559, valid_tx_eip2930]; - store_blueprints(&mut host, vec![blueprint(transactions)]); + store_blueprints::<_, EvmChainConfig>(&mut host, vec![blueprint(transactions)]); let sender = dummy_eth_caller(); let mut evm_account_storage = init_account_storage().unwrap(); @@ -2061,7 +2018,8 @@ mod tests { produce( &mut host, - &mut dummy_configuration(EVMVersion::current_test_config()), + &dummy_evm_config(EVMVersion::current_test_config()), + &mut dummy_configuration(), None, None, ) diff --git a/etherlink/kernel_latest/kernel/src/block_in_progress.rs b/etherlink/kernel_latest/kernel/src/block_in_progress.rs index 7bb71fa274897736db10dc5a013d7fcc2fcfdf38..cd075b025a8935a32262b49420ecde654bec0450 100644 --- a/etherlink/kernel_latest/kernel/src/block_in_progress.rs +++ b/etherlink/kernel_latest/kernel/src/block_in_progress.rs @@ -13,7 +13,7 @@ use crate::gas_price::base_fee_per_gas; use crate::l2block::L2Block; use crate::storage::{self, object_path, receipt_path}; use crate::tick_model; -use crate::transaction::{Transaction, Transactions::EthTxs, Transactions::TezTxs}; +use crate::transaction::{Transaction, Transactions, Transactions::EthTxs}; use anyhow::Context; use evm_execution::account_storage::EVM_ACCOUNTS_PATH; use primitive_types::{H160, H256, U256}; @@ -277,7 +277,7 @@ impl EthBlockInProgress { } pub fn from_blueprint( - blueprint: crate::blueprint::Blueprint, + blueprint: crate::blueprint::Blueprint, number: U256, parent_hash: H256, tick_counter: u64, @@ -288,11 +288,6 @@ impl EthBlockInProgress { // blueprint is turn into a ring to allow popping from the front let ring = match blueprint.transactions { EthTxs(transactions) => transactions.into(), - TezTxs => - // This should never happen as we are in an Ethereum block in progress - { - VecDeque::new() - } }; EthBlockInProgress::new_with_ticks( number, diff --git a/etherlink/kernel_latest/kernel/src/blueprint.rs b/etherlink/kernel_latest/kernel/src/blueprint.rs index 9f17143847a09ecda1ff713a12cfcd63387248ff..a585acb070a74bcc7da4dabac910bf7663b30f09 100644 --- a/etherlink/kernel_latest/kernel/src/blueprint.rs +++ b/etherlink/kernel_latest/kernel/src/blueprint.rs @@ -5,7 +5,6 @@ // // SPDX-License-Identifier: MIT -use crate::transaction::Transactions; use rlp::{Decodable, DecoderError, Encodable}; use tezos_ethereum::rlp_helpers::{ self, append_timestamp, decode_field, decode_timestamp, @@ -15,12 +14,12 @@ use tezos_smart_rollup_encoding::timestamp::Timestamp; /// The blueprint of a block is a list of transactions. #[derive(PartialEq, Debug, Clone)] -pub struct Blueprint { - pub transactions: Transactions, +pub struct Blueprint { + pub transactions: Txs, pub timestamp: Timestamp, } -impl Encodable for Blueprint { +impl Encodable for Blueprint { fn rlp_append(&self, stream: &mut rlp::RlpStream) { stream.begin_list(2); stream.append(&self.transactions); @@ -28,7 +27,7 @@ impl Encodable for Blueprint { } } -impl Decodable for Blueprint { +impl Decodable for Blueprint { fn decode(decoder: &rlp::Rlp) -> Result { if !decoder.is_list() { return Err(DecoderError::RlpExpectedToBeList); diff --git a/etherlink/kernel_latest/kernel/src/blueprint_storage.rs b/etherlink/kernel_latest/kernel/src/blueprint_storage.rs index 1760b5998516e23a1f2f55f27b86ec1c6b9fc7f4..34d713a1338f67354e3659f1ed64405be7cafdcc 100644 --- a/etherlink/kernel_latest/kernel/src/blueprint_storage.rs +++ b/etherlink/kernel_latest/kernel/src/blueprint_storage.rs @@ -3,9 +3,8 @@ // // SPDX-License-Identifier: MIT -use crate::block::GENESIS_PARENT_HASH; use crate::blueprint::Blueprint; -use crate::chains::ChainFamily; +use crate::chains::{ChainConfigTrait, ChainHeaderTrait, TransactionsTrait}; use crate::configuration::{Configuration, ConfigurationMode}; use crate::error::{Error, StorageError}; use crate::l2block::L2Block; @@ -13,7 +12,7 @@ use crate::sequencer_blueprint::{ BlueprintWithDelayedHashes, UnsignedSequencerBlueprint, }; use crate::storage::read_last_info_per_level_timestamp; -use crate::transaction::{Transaction, TransactionContent, Transactions::EthTxs}; +use crate::transaction::{Transaction, TransactionContent, Transactions}; use crate::{delayed_inbox, DelayedInbox}; use primitive_types::{H256, U256}; use rlp::{Decodable, DecoderError, Encodable}; @@ -48,15 +47,15 @@ const EVM_CURRENT_BLOCK_HEADER: RefPath = /// inbox messages. Note that the latter are only to be /// used when the kernel isn't running with a sequencer. #[derive(PartialEq, Debug, Clone)] -enum StoreBlueprint { +enum StoreBlueprint { SequencerChunk(Vec), - InboxBlueprint(Blueprint), + InboxBlueprint(Blueprint), } const SEQUENCER_CHUNK_TAG: u8 = 0; const INBOX_BLUEPRINT_TAG: u8 = 1; -impl Encodable for StoreBlueprint { +impl Encodable for StoreBlueprint { fn rlp_append(&self, stream: &mut rlp::RlpStream) { stream.begin_list(2); match &self { @@ -72,7 +71,7 @@ impl Encodable for StoreBlueprint { } } -impl Decodable for StoreBlueprint { +impl Decodable for StoreBlueprint { fn decode(decoder: &rlp::Rlp) -> Result { if !decoder.is_list() { return Err(DecoderError::RlpExpectedToBeList); @@ -133,36 +132,6 @@ pub enum ChainHeader { Eth(EVMBlockHeader), } -impl ChainHeader { - fn evm_genesis() -> Self { - Self::Eth(EVMBlockHeader { - hash: GENESIS_PARENT_HASH, - receipts_root: vec![0; 32], - transactions_root: vec![0; 32], - }) - } - - fn tez_genesis() -> Self { - Self::Tez(TezBlockHeader { - hash: TezBlock::genesis_block_hash(), - }) - } - - pub fn genesis_header(chain_family: ChainFamily) -> ChainHeader { - match chain_family { - ChainFamily::Evm => Self::evm_genesis(), - ChainFamily::Michelson => Self::tez_genesis(), - } - } - - pub fn hash(&self) -> H256 { - match self { - Self::Eth(header) => header.hash, - Self::Tez(header) => header.hash, - } - } -} - impl From for BlockHeader { fn from(block: EthBlock) -> Self { Self { @@ -251,13 +220,16 @@ pub fn store_sequencer_blueprint( store_blueprint_nb_chunks(host, &blueprint_path, blueprint.nb_chunks)?; let blueprint_chunk_path = blueprint_chunk_path(&blueprint_path, blueprint.chunk_index)?; - let store_blueprint = StoreBlueprint::SequencerChunk(blueprint.chunk); + // The `Transactions` type parameter of `StoreBlueprint` is not + // used in the `SequencerChunk` case so it is irrelevant here, we could pass + // any type implementing the `Encodable` trait. + let store_blueprint = StoreBlueprint::>::SequencerChunk(blueprint.chunk); store_rlp(&store_blueprint, host, &blueprint_chunk_path).map_err(Error::from) } -pub fn store_inbox_blueprint_by_number( +pub fn store_inbox_blueprint_by_number( host: &mut Host, - blueprint: Blueprint, + blueprint: Blueprint, number: U256, ) -> Result<(), Error> { let blueprint_path = blueprint_path(number)?; @@ -267,9 +239,9 @@ pub fn store_inbox_blueprint_by_number( store_rlp(&store_blueprint, host, &chunk_path).map_err(Error::from) } -pub fn store_inbox_blueprint( +pub fn store_inbox_blueprint( host: &mut Host, - blueprint: Blueprint, + blueprint: Blueprint, ) -> anyhow::Result<()> { let number = read_next_blueprint_number(host)?; Ok(store_inbox_blueprint_by_number(host, blueprint, number)?) @@ -287,9 +259,9 @@ pub fn read_next_blueprint_number(host: &Host) -> Result( +pub fn store_forced_blueprint( host: &mut Host, - blueprint: Blueprint, + blueprint: Blueprint, number: U256, ) -> Result<(), Error> { let blueprint_path = blueprint_path(number)?; @@ -412,34 +384,6 @@ pub fn read_current_blueprint_header( Ok(block_header.blueprint_header) } -pub fn read_current_block_header_for_family( - host: &Host, - chain_family: &ChainFamily, -) -> Result, Error> { - match chain_family { - ChainFamily::Evm => { - let BlockHeader { - blueprint_header, - chain_header, - } = read_current_block_header::(host)?; - Ok(BlockHeader { - blueprint_header, - chain_header: ChainHeader::Eth(chain_header), - }) - } - ChainFamily::Michelson => { - let BlockHeader { - blueprint_header, - chain_header, - } = read_current_block_header::(host)?; - Ok(BlockHeader { - blueprint_header, - chain_header: ChainHeader::Tez(chain_header), - }) - } - } -} - /// For the tick model we only accept blueprints where cumulative size of chunks /// less or equal than 512kB. A chunk weights 4kB, then (512 * 1024) / 4096 = /// 128. @@ -454,8 +398,8 @@ const MAXIMUM_SIZE_OF_DELAYED_TRANSACTION: usize = MAX_INPUT_MESSAGE_SIZE; /// Only used for test, as all errors are handled in the same way #[cfg_attr(feature = "benchmark", allow(dead_code))] #[derive(Debug, PartialEq)] -pub enum BlueprintValidity { - Valid(Blueprint), +pub enum BlueprintValidity { + Valid(Blueprint), InvalidParentHash, TimestampFromPast, TimestampFromFuture, @@ -464,33 +408,52 @@ pub enum BlueprintValidity { BlueprintTooLarge, } -fn fetch_delayed_txs( +pub enum DelayedTransactionFetchingResult { + Ok(Txs), + BlueprintTooLarge, + DelayedHashMissing(delayed_inbox::Hash), +} + +pub fn fetch_hashes_from_delayed_inbox( host: &mut Host, - blueprint_with_hashes: BlueprintWithDelayedHashes, + delayed_hashes: Vec, delayed_inbox: &mut DelayedInbox, current_blueprint_size: usize, -) -> anyhow::Result<(BlueprintValidity, usize)> { +) -> anyhow::Result<(DelayedTransactionFetchingResult, usize)> { let mut delayed_txs = vec![]; let mut total_size = current_blueprint_size; - for tx_hash in blueprint_with_hashes.delayed_hashes { + for tx_hash in delayed_hashes { let tx = delayed_inbox.find_transaction(host, tx_hash)?; // This is overestimated, as the transactions cannot be chunked in the // delayed bridge. total_size += MAXIMUM_SIZE_OF_DELAYED_TRANSACTION; // If the size would overflow the 512KB, reject the blueprint if MAXIMUM_SIZE_OF_BLUEPRINT < total_size { - return Ok((BlueprintValidity::BlueprintTooLarge, total_size)); + return Ok(( + DelayedTransactionFetchingResult::BlueprintTooLarge, + total_size, + )); } match tx { Some(tx) => delayed_txs.push(tx.0), None => { - return Ok((BlueprintValidity::DelayedHashMissing(tx_hash), total_size)) + return Ok(( + DelayedTransactionFetchingResult::DelayedHashMissing(tx_hash), + total_size, + )) } } } + Ok(( + DelayedTransactionFetchingResult::Ok(Transactions::EthTxs(delayed_txs)), + total_size, + )) +} - let transactions_with_hashes = blueprint_with_hashes - .transactions +pub fn transactions_from_bytes( + transactions: Vec>, +) -> anyhow::Result> { + transactions .into_iter() .map(|tx_common| { let tx_hash = Keccak256::digest(&tx_common).into(); @@ -501,12 +464,40 @@ fn fetch_delayed_txs( content: TransactionContent::Ethereum(tx_common), }) }) - .collect::>>()?; + .collect::>>() +} + +pub fn fetch_delayed_txs( + host: &mut Host, + blueprint_with_hashes: BlueprintWithDelayedHashes, + delayed_inbox: &mut DelayedInbox, + current_blueprint_size: usize, +) -> anyhow::Result<(BlueprintValidity, usize)> { + let (mut delayed_txs, total_size) = + match ChainConfig::fetch_hashes_from_delayed_inbox( + host, + blueprint_with_hashes.delayed_hashes, + delayed_inbox, + current_blueprint_size, + )? { + (DelayedTransactionFetchingResult::Ok(delayed_txs), total_size) => { + (delayed_txs, total_size) + } + (DelayedTransactionFetchingResult::BlueprintTooLarge, total_size) => { + return Ok((BlueprintValidity::BlueprintTooLarge, total_size)); + } + (DelayedTransactionFetchingResult::DelayedHashMissing(hash), total_size) => { + return Ok((BlueprintValidity::DelayedHashMissing(hash), total_size)); + } + }; + + let transactions_with_hashes = + ChainConfig::transactions_from_bytes(blueprint_with_hashes.transactions)?; delayed_txs.extend(transactions_with_hashes); Ok(( BlueprintValidity::Valid(Blueprint { - transactions: EthTxs(delayed_txs), + transactions: delayed_txs, timestamp: blueprint_with_hashes.timestamp, }), total_size, @@ -521,16 +512,16 @@ fn fetch_delayed_txs( pub const DEFAULT_MAX_BLUEPRINT_LOOKAHEAD_IN_SECONDS: i64 = 300i64; #[allow(clippy::too_many_arguments)] -fn parse_and_validate_blueprint( +fn parse_and_validate_blueprint( host: &mut Host, bytes: &[u8], delayed_inbox: &mut DelayedInbox, current_blueprint_size: usize, evm_node_flag: bool, max_blueprint_lookahead_in_seconds: i64, - parent_chain_header: &ChainHeader, + parent_chain_header: &ChainConfig::ChainHeader, head_timestamp: Timestamp, -) -> anyhow::Result<(BlueprintValidity, usize)> { +) -> anyhow::Result<(BlueprintValidity, usize)> { // Decode match rlp::decode::(bytes) { Err(e) => Ok((BlueprintValidity::DecoderError(e), bytes.len())), @@ -582,7 +573,7 @@ fn parse_and_validate_blueprint( } // Fetch delayed transactions - fetch_delayed_txs( + fetch_delayed_txs::<_, ChainConfig>( host, blueprint_with_hashes, delayed_inbox, @@ -592,10 +583,10 @@ fn parse_and_validate_blueprint( } } -fn invalidate_blueprint( +fn invalidate_blueprint( host: &mut Host, blueprint_path: &OwnedPath, - error: &BlueprintValidity, + error: &BlueprintValidity, ) -> Result<(), RuntimeError> { log!( host, @@ -608,18 +599,18 @@ fn invalidate_blueprint( host.store_delete(blueprint_path) } -fn read_all_chunks_and_validate( +fn read_all_chunks_and_validate( host: &mut Host, blueprint_path: &OwnedPath, nb_chunks: u16, config: &mut Configuration, - previous_chain_header: &ChainHeader, + previous_chain_header: &ChainConfig::ChainHeader, previous_timestamp: Timestamp, -) -> anyhow::Result<(Option, usize)> { +) -> anyhow::Result<(Option>, usize)> { let mut chunks = vec![]; let mut size = 0; if nb_chunks > MAXIMUM_NUMBER_OF_CHUNKS { - invalidate_blueprint( + invalidate_blueprint::<_, ChainConfig::Transactions>( host, blueprint_path, &BlueprintValidity::BlueprintTooLarge, @@ -648,16 +639,17 @@ fn read_all_chunks_and_validate( max_blueprint_lookahead_in_seconds, .. } => { - let validity = parse_and_validate_blueprint( - host, - chunks.concat().as_slice(), - delayed_inbox, - size, - *evm_node_flag, - *max_blueprint_lookahead_in_seconds, - previous_chain_header, - previous_timestamp, - )?; + let validity: (BlueprintValidity, usize) = + parse_and_validate_blueprint::<_, ChainConfig>( + host, + chunks.concat().as_slice(), + delayed_inbox, + size, + *evm_node_flag, + *max_blueprint_lookahead_in_seconds, + previous_chain_header, + previous_timestamp, + )?; if let (BlueprintValidity::Valid(blueprint), size_with_delayed_transactions) = validity { @@ -676,13 +668,13 @@ fn read_all_chunks_and_validate( } } -pub fn read_blueprint( +pub fn read_blueprint( host: &mut Host, config: &mut Configuration, number: U256, previous_timestamp: Timestamp, - previous_chain_header: &ChainHeader, -) -> anyhow::Result<(Option, usize)> { + previous_chain_header: &ChainConfig::ChainHeader, +) -> anyhow::Result<(Option>, usize)> { let blueprint_path = blueprint_path(number)?; let exists = host.store_has(&blueprint_path)?.is_some(); if exists { @@ -697,7 +689,7 @@ 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( + let (blueprint, size) = read_all_chunks_and_validate::<_, ChainConfig>( host, &blueprint_path, nb_chunks, @@ -733,10 +725,9 @@ pub fn read_blueprint( pub fn read_next_blueprint( host: &mut Host, config: &mut Configuration, -) -> anyhow::Result<(Option, usize)> { - let chain_family = config.chain_config.get_chain_family(); +) -> anyhow::Result<(Option>, usize)> { let (number, previous_timestamp, block_header) = - match read_current_block_header_for_family(host, &chain_family) { + match read_current_block_header::<_, EVMBlockHeader>(host) { Ok(BlockHeader { blueprint_header, chain_header, @@ -748,10 +739,16 @@ pub fn read_next_blueprint( Err(_) => ( U256::zero(), Timestamp::from(0), - ChainHeader::genesis_header(chain_family), + EVMBlockHeader::genesis_header(), ), }; - read_blueprint(host, config, number, previous_timestamp, &block_header) + read_blueprint::<_, crate::chains::EvmChainConfig>( + host, + config, + number, + previous_timestamp, + &block_header, + ) } pub fn drop_blueprint(host: &mut Host, number: U256) -> Result<(), Error> { @@ -772,7 +769,7 @@ mod tests { use super::*; use crate::block::GENESIS_PARENT_HASH; - use crate::chains::ChainConfig; + use crate::chains::EvmChainConfig; use crate::configuration::{DalConfiguration, TezosContracts}; use crate::delayed_inbox::Hash; use crate::sequencer_blueprint::{rlp_roundtrip, rlp_roundtrip_f}; @@ -815,7 +812,6 @@ mod tests { }, maximum_allowed_ticks: MAX_ALLOWED_TICKS, enable_fa_bridge: false, - chain_config: ChainConfig::default(), garbage_collect_blocks: false, }; @@ -850,18 +846,18 @@ mod tests { let mut delayed_inbox = DelayedInbox::new(&mut host).expect("Delayed inbox should be created"); // Blueprint should have invalid parent hash - let validity = parse_and_validate_blueprint( + let validity = parse_and_validate_blueprint::<_, EvmChainConfig>( &mut host, blueprint_with_hashes_bytes.as_ref(), &mut delayed_inbox, 0, false, 500, - &ChainHeader::Eth(EVMBlockHeader { + &EVMBlockHeader { hash: GENESIS_PARENT_HASH, receipts_root: vec![0; 32], transactions_root: vec![0; 32], - }), + }, Timestamp::from(0), ) .expect("Should be able to parse blueprint"); @@ -916,18 +912,18 @@ mod tests { let mut delayed_inbox = DelayedInbox::new(&mut host).expect("Delayed inbox should be created"); // Blueprint should have invalid parent hash - let validity = parse_and_validate_blueprint( + let validity = parse_and_validate_blueprint::<_, EvmChainConfig>( &mut host, blueprint_with_hashes_bytes.as_ref(), &mut delayed_inbox, 0, false, 500, - &ChainHeader::Eth(EVMBlockHeader { + &EVMBlockHeader { hash: GENESIS_PARENT_HASH, receipts_root: vec![0; 32], transactions_root: vec![0; 32], - }), + }, Timestamp::from(0), ) .expect("Should be able to parse blueprint"); diff --git a/etherlink/kernel_latest/kernel/src/chains.rs b/etherlink/kernel_latest/kernel/src/chains.rs index 7f82548251e7e817fb7ae56579e3858b3f85a351..40bce1e399b558147bd7450b9c866cec7b23dbb9 100644 --- a/etherlink/kernel_latest/kernel/src/chains.rs +++ b/etherlink/kernel_latest/kernel/src/chains.rs @@ -2,13 +2,33 @@ // // SPDX-License-Identifier: MIT -use evm_execution::configuration::EVMVersion; -use primitive_types::U256; - use crate::{ - configuration::CHAIN_ID, fees::MINIMUM_BASE_FEE_PER_GAS, + block::{eth_bip_from_blueprint, BlockComputationResult, TickCounter}, + block_in_progress::EthBlockInProgress, + blueprint::Blueprint, + blueprint_storage::{ + DelayedTransactionFetchingResult, EVMBlockHeader, TezBlockHeader, + }, + delayed_inbox::DelayedInbox, + fees::MINIMUM_BASE_FEE_PER_GAS, + l2block::L2Block, + simulation::start_simulation_mode, tick_model::constants::MAXIMUM_GAS_LIMIT, + transaction::Transactions::EthTxs, + CHAIN_ID, +}; +use anyhow::Context; +use evm_execution::{ + configuration::EVMVersion, precompiles::PrecompileBTreeMap, trace::TracerInput, }; +use primitive_types::{H160, H256, U256}; +use rlp::{Decodable, Encodable}; +use std::fmt::{Debug, Display}; +use tezos_evm_logging::{log, Level::*}; +use tezos_evm_runtime::runtime::Runtime; +use tezos_smart_rollup::{outbox::OutboxQueue, types::Timestamp}; +use tezos_smart_rollup_host::path::Path; +use tezos_tezlink::block::TezBlock; #[derive(Clone, Copy, Debug)] pub enum ChainFamily { @@ -32,10 +52,279 @@ impl From for ChainFamily { } } +#[derive(Debug)] pub struct EvmChainConfig { - pub chain_id: U256, - pub limits: EvmLimits, - pub evm_config: evm_execution::Config, + chain_id: U256, + limits: EvmLimits, + evm_config: evm_execution::Config, +} + +#[derive(Debug)] +pub struct MichelsonChainConfig { + chain_id: U256, +} + +pub trait BlockInProgressTrait { + fn number(&self) -> U256; +} + +impl BlockInProgressTrait for EthBlockInProgress { + fn number(&self) -> U256 { + self.number + } +} + +pub struct TezBlockInProgress { + number: U256, + timestamp: Timestamp, + previous_hash: H256, +} + +impl BlockInProgressTrait for TezBlockInProgress { + fn number(&self) -> U256 { + self.number + } +} + +pub enum ChainConfig { + Evm(Box), + Michelson(MichelsonChainConfig), +} + +pub trait TransactionsTrait { + fn extend(&mut self, other: Self); + fn number_of_txs(&self) -> usize; +} + +impl TransactionsTrait for crate::transaction::Transactions { + fn extend(&mut self, other: Self) { + let EthTxs(ref mut txs) = self; + let EthTxs(other) = other; + txs.extend(other) + } + fn number_of_txs(&self) -> usize { + let EthTxs(txs) = self; + txs.len() + } +} + +#[derive(Debug)] +pub struct TezTransactions {} + +impl TransactionsTrait for TezTransactions { + fn extend(&mut self, _: Self) {} + + fn number_of_txs(&self) -> usize { + 0 + } +} + +impl Encodable for TezTransactions { + fn rlp_append(&self, stream: &mut rlp::RlpStream) { + let Self {} = self; + stream.begin_list(0); + } +} + +impl Decodable for TezTransactions { + fn decode(_decoder: &rlp::Rlp) -> Result { + Ok(Self {}) + } +} + +pub trait ChainHeaderTrait { + fn hash(&self) -> H256; + + fn genesis_header() -> Self; +} + +impl ChainHeaderTrait for crate::blueprint_storage::EVMBlockHeader { + fn hash(&self) -> H256 { + self.hash + } + fn genesis_header() -> Self { + EVMBlockHeader { + hash: crate::block::GENESIS_PARENT_HASH, + receipts_root: vec![0; 32], + transactions_root: vec![0; 32], + } + } +} + +impl ChainHeaderTrait for crate::blueprint_storage::TezBlockHeader { + fn hash(&self) -> H256 { + self.hash + } + + fn genesis_header() -> Self { + Self { + hash: TezBlock::genesis_block_hash(), + } + } +} + +pub trait ChainConfigTrait: Debug { + type Transactions: TransactionsTrait + Encodable + Decodable + Debug; + + type BlockInProgress: BlockInProgressTrait; + + type ChainHeader: ChainHeaderTrait + Decodable; + + fn get_chain_id(&self) -> U256; + + fn get_chain_family(&self) -> ChainFamily; + + fn fmt_with_family(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let chain_family = self.get_chain_family(); + write!(f, "{{Chain family: {}, {:?}}}", chain_family, self) + } + + fn fetch_hashes_from_delayed_inbox( + host: &mut impl Runtime, + delayed_hashes: Vec, + delayed_inbox: &mut DelayedInbox, + current_blueprint_size: usize, + ) -> anyhow::Result<(DelayedTransactionFetchingResult, usize)>; + + fn transactions_from_bytes(bytes: Vec>) + -> anyhow::Result; + + fn block_in_progress_from_blueprint( + &self, + host: &impl Runtime, + tick_counter: &crate::block::TickCounter, + current_block_number: U256, + previous_chain_header: Self::ChainHeader, + blueprint: Blueprint, + ) -> Self::BlockInProgress; + + fn read_block_in_progress( + host: &impl Runtime, + ) -> anyhow::Result>; + + #[allow(clippy::too_many_arguments)] + fn compute_bip( + &self, + host: &mut Host, + outbox_queue: &OutboxQueue<'_, impl Path>, + block_in_progress: Self::BlockInProgress, + precompiles: &PrecompileBTreeMap, + tick_counter: &mut TickCounter, + sequencer_pool_address: Option, + maximum_allowed_ticks: u64, + tracer_input: Option, + da_fee_per_byte: U256, + coinbase: H160, + ) -> anyhow::Result; + + fn start_simulation_mode( + &self, + host: &mut impl Runtime, + enable_fa_bridge: bool, + ) -> anyhow::Result<()>; +} + +impl ChainConfigTrait for EvmChainConfig { + type Transactions = crate::transaction::Transactions; + + type BlockInProgress = crate::block_in_progress::EthBlockInProgress; + + type ChainHeader = crate::blueprint_storage::EVMBlockHeader; + + fn get_chain_id(&self) -> U256 { + self.chain_id + } + + fn get_chain_family(&self) -> ChainFamily { + ChainFamily::Evm + } + + fn block_in_progress_from_blueprint( + &self, + host: &impl Runtime, + tick_counter: &crate::block::TickCounter, + current_block_number: U256, + header: Self::ChainHeader, + blueprint: Blueprint, + ) -> Self::BlockInProgress { + eth_bip_from_blueprint( + host, + self, + tick_counter, + current_block_number, + header, + blueprint, + ) + } + + fn transactions_from_bytes( + bytes: Vec>, + ) -> anyhow::Result { + Ok(EthTxs(crate::blueprint_storage::transactions_from_bytes( + bytes, + )?)) + } + + fn fetch_hashes_from_delayed_inbox( + host: &mut impl Runtime, + delayed_hashes: Vec, + delayed_inbox: &mut DelayedInbox, + current_blueprint_size: usize, + ) -> anyhow::Result<(DelayedTransactionFetchingResult, usize)> + { + crate::blueprint_storage::fetch_hashes_from_delayed_inbox( + host, + delayed_hashes, + delayed_inbox, + current_blueprint_size, + ) + } + + fn read_block_in_progress( + host: &impl Runtime, + ) -> anyhow::Result> { + crate::storage::read_block_in_progress(host) + } + + fn compute_bip( + &self, + host: &mut Host, + outbox_queue: &OutboxQueue<'_, impl Path>, + block_in_progress: Self::BlockInProgress, + precompiles: &PrecompileBTreeMap, + tick_counter: &mut TickCounter, + sequencer_pool_address: Option, + maximum_allowed_ticks: u64, + tracer_input: Option, + da_fee_per_byte: U256, + coinbase: H160, + ) -> anyhow::Result { + log!(host, Debug, "Computing the BlockInProgress for Etherlink"); + + crate::block::compute_bip( + host, + outbox_queue, + block_in_progress, + precompiles, + tick_counter, + sequencer_pool_address, + &self.limits, + maximum_allowed_ticks, + tracer_input, + self.chain_id, + da_fee_per_byte, + coinbase, + &self.evm_config, + ) + } + + fn start_simulation_mode( + &self, + host: &mut impl Runtime, + enable_fa_bridge: bool, + ) -> anyhow::Result<()> { + start_simulation_mode(host, enable_fa_bridge, &self.evm_config) + } } impl EvmChainConfig { @@ -50,10 +339,111 @@ impl EvmChainConfig { evm_config, } } + + pub fn get_limits(&self) -> &EvmLimits { + &self.limits + } + + pub fn get_evm_config(&self) -> &evm_execution::Config { + &self.evm_config + } } -pub struct MichelsonChainConfig { - pub chain_id: U256, +impl ChainConfigTrait for MichelsonChainConfig { + type Transactions = TezTransactions; + type BlockInProgress = TezBlockInProgress; + type ChainHeader = TezBlockHeader; + + fn get_chain_id(&self) -> U256 { + self.chain_id + } + + fn get_chain_family(&self) -> ChainFamily { + ChainFamily::Michelson + } + + fn block_in_progress_from_blueprint( + &self, + _host: &impl Runtime, + _tick_counter: &crate::block::TickCounter, + current_block_number: U256, + header: Self::ChainHeader, + blueprint: Blueprint, + ) -> Self::BlockInProgress { + TezBlockInProgress { + number: current_block_number, + timestamp: blueprint.timestamp, + previous_hash: header.hash, + } + } + + fn fetch_hashes_from_delayed_inbox( + _host: &mut impl Runtime, + _delayed_hashes: Vec, + _delayed_inbox: &mut DelayedInbox, + current_blueprint_size: usize, + ) -> anyhow::Result<(DelayedTransactionFetchingResult, usize)> + { + Ok(( + DelayedTransactionFetchingResult::Ok(TezTransactions {}), + current_blueprint_size, + )) + } + + fn transactions_from_bytes( + _bytes: Vec>, + ) -> anyhow::Result { + Ok(TezTransactions {}) + } + + fn read_block_in_progress( + _host: &impl Runtime, + ) -> anyhow::Result> { + Ok(None) + } + + fn compute_bip( + &self, + host: &mut Host, + _outbox_queue: &OutboxQueue<'_, impl Path>, + block_in_progress: Self::BlockInProgress, + _precompiles: &PrecompileBTreeMap, + _tick_counter: &mut TickCounter, + _sequencer_pool_address: Option, + _maximum_allowed_ticks: u64, + _tracer_input: Option, + _da_fee_per_byte: U256, + _coinbase: H160, + ) -> anyhow::Result { + let TezBlockInProgress { + number, + timestamp, + previous_hash, + } = block_in_progress; + log!( + host, + Debug, + "Computing the BlockInProgress for Tezlink at level {}", + number + ); + + let tezblock = TezBlock::new(number, timestamp, previous_hash); + let new_block = L2Block::Tezlink(tezblock); + crate::block_storage::store_current(host, &new_block) + .context("Failed to store the current block")?; + Ok(BlockComputationResult::Finished { + included_delayed_transactions: vec![], + block: new_block, + }) + } + + fn start_simulation_mode( + &self, + _host: &mut impl Runtime, + _enable_fa_bridge: bool, + ) -> anyhow::Result<()> { + Ok(()) + } } impl MichelsonChainConfig { @@ -62,19 +452,15 @@ impl MichelsonChainConfig { } } -#[allow(clippy::large_enum_variant)] -pub enum ChainConfig { - Evm(EvmChainConfig), - Michelson(MichelsonChainConfig), -} - impl ChainConfig { pub fn new_evm_config( chain_id: U256, limits: EvmLimits, evm_config: evm_execution::Config, ) -> Self { - ChainConfig::Evm(EvmChainConfig::create_config(chain_id, limits, evm_config)) + ChainConfig::Evm(Box::new(EvmChainConfig::create_config( + chain_id, limits, evm_config, + ))) } pub fn new_michelson_config(chain_id: U256) -> Self { @@ -90,15 +476,15 @@ impl ChainConfig { pub fn get_chain_id(&self) -> U256 { match self { - ChainConfig::Evm(evm_chain_config) => evm_chain_config.chain_id, + ChainConfig::Evm(evm_chain_config) => evm_chain_config.get_chain_id(), ChainConfig::Michelson(michelson_chain_config) => { - michelson_chain_config.chain_id + michelson_chain_config.get_chain_id() } } } } -impl std::fmt::Display for ChainFamily { +impl Display for ChainFamily { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Evm => write!(f, "EVM"), @@ -122,44 +508,43 @@ impl Default for EvmLimits { } } -impl std::fmt::Display for ChainConfig { +impl Default for ChainConfig { + fn default() -> Self { + ChainConfig::Evm(Box::default()) + } +} + +impl Display for ChainConfig { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - ChainConfig::Evm(chain_config) => write!( - f, - "{{Chain id: {}, Chain family: {}, Limits: {:?}, VMConfig: {:?}}}", - chain_config.chain_id, - ChainFamily::Evm, - chain_config.limits, - chain_config.evm_config - ), - ChainConfig::Michelson(chain_config) => { - write!( - f, - "{{Chain id: {}, Chain family: {}}}", - chain_config.chain_id, - ChainFamily::Michelson - ) + ChainConfig::Evm(evm_chain_config) => evm_chain_config.fmt_with_family(f), + ChainConfig::Michelson(michelson_chain_config) => { + michelson_chain_config.fmt_with_family(f) } } } } -impl Default for ChainConfig { +impl Default for EvmChainConfig { fn default() -> Self { - Self::Evm(EvmChainConfig::create_config( + Self::create_config( U256::from(CHAIN_ID), EvmLimits::default(), EVMVersion::to_config(&EVMVersion::default()), - )) + ) } } #[cfg(test)] -pub fn test_chain_config() -> ChainConfig { - ChainConfig::new_evm_config( +pub fn test_evm_chain_config() -> EvmChainConfig { + EvmChainConfig::create_config( U256::from(CHAIN_ID), EvmLimits::default(), EVMVersion::current_test_config(), ) } + +#[cfg(test)] +pub fn test_chain_config() -> ChainConfig { + ChainConfig::Evm(Box::new(test_evm_chain_config())) +} diff --git a/etherlink/kernel_latest/kernel/src/configuration.rs b/etherlink/kernel_latest/kernel/src/configuration.rs index 1719fabf22375fb3b758e79a07d0826e6efc7622..63c13837e2ebefb531e61cbeec68552c98c687c4 100644 --- a/etherlink/kernel_latest/kernel/src/configuration.rs +++ b/etherlink/kernel_latest/kernel/src/configuration.rs @@ -70,7 +70,6 @@ pub struct Configuration { pub mode: ConfigurationMode, pub maximum_allowed_ticks: u64, pub enable_fa_bridge: bool, - pub chain_config: ChainConfig, pub garbage_collect_blocks: bool, } @@ -81,7 +80,6 @@ impl Default for Configuration { mode: ConfigurationMode::Proxy, maximum_allowed_ticks: MAX_ALLOWED_TICKS, enable_fa_bridge: false, - chain_config: ChainConfig::default(), garbage_collect_blocks: false, } } @@ -91,8 +89,8 @@ impl std::fmt::Display for Configuration { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "Tezos Contracts: {}, Mode: {}, Enable FA Bridge: {}, Chain Config: {}, Garbage collect blocks: {}", - &self.tezos_contracts, &self.mode, &self.enable_fa_bridge, &self.chain_config, &self.garbage_collect_blocks + "Tezos Contracts: {}, Mode: {}, Enable FA Bridge: {}, Garbage collect blocks: {}", + &self.tezos_contracts, &self.mode, &self.enable_fa_bridge, &self.garbage_collect_blocks ) } } @@ -209,10 +207,7 @@ pub fn fetch_chain_configuration( } } -pub fn fetch_configuration( - host: &mut Host, - chain_id: U256, -) -> Configuration { +pub fn fetch_configuration(host: &mut Host) -> Configuration { let tezos_contracts = fetch_tezos_contracts(host); let maximum_allowed_ticks = read_maximum_allowed_ticks(host).unwrap_or(MAX_ALLOWED_TICKS); @@ -220,7 +215,6 @@ pub fn fetch_configuration( let enable_fa_bridge = is_enable_fa_bridge(host).unwrap_or_default(); let dal: Option = fetch_dal_configuration(host); let evm_node_flag = evm_node_flag(host).unwrap_or(false); - let chain_config = fetch_chain_configuration(host, chain_id); match sequencer { Some(sequencer) => { let delayed_bridge = read_delayed_transaction_bridge(host) @@ -249,15 +243,11 @@ pub fn fetch_configuration( }, maximum_allowed_ticks, enable_fa_bridge, - chain_config, garbage_collect_blocks: !evm_node_flag, }, Err(err) => { log!(host, Fatal, "The kernel failed to created the delayed inbox, reverting configuration to proxy ({:?})", err); - Configuration { - chain_config, - ..Configuration::default() - } + Configuration::default() } } } @@ -266,7 +256,6 @@ pub fn fetch_configuration( mode: ConfigurationMode::Proxy, maximum_allowed_ticks, enable_fa_bridge, - chain_config, garbage_collect_blocks: false, }, } diff --git a/etherlink/kernel_latest/kernel/src/inbox.rs b/etherlink/kernel_latest/kernel/src/inbox.rs index ebc6e3daf197fb412ec97a122acb212e33859c70..6ec24efe5532c4dbe789463e39e4d84116208038 100644 --- a/etherlink/kernel_latest/kernel/src/inbox.rs +++ b/etherlink/kernel_latest/kernel/src/inbox.rs @@ -7,7 +7,7 @@ use crate::blueprint_storage::store_sequencer_blueprint; use crate::bridge::Deposit; -use crate::chains::{ChainConfig, ChainFamily}; +use crate::chains::{ChainConfigTrait, ChainFamily, EvmChainConfig}; use crate::configuration::{DalConfiguration, TezosContracts}; use crate::dal::fetch_and_parse_sequencer_blueprint_from_dal; use crate::dal_slot_import_signal::DalSlotImportSignals; @@ -26,13 +26,10 @@ use crate::storage::{ }; use crate::tick_model::constants::TICKS_FOR_BLUEPRINT_INTERCEPT; use crate::tick_model::maximum_ticks_for_sequencer_chunk; -use crate::transaction::{ - Transaction, TransactionContent, Transactions, - Transactions::{EthTxs, TezTxs}, -}; +use crate::transaction::{Transaction, TransactionContent, Transactions}; +use crate::upgrade; use crate::upgrade::*; use crate::Error; -use crate::{simulation, upgrade}; use evm_execution::fa_bridge::deposit::FaDeposit; use primitive_types::U256; use sha3::{Digest, Keccak256}; @@ -416,7 +413,11 @@ enum ReadStatus { } #[allow(clippy::too_many_arguments)] -fn read_and_dispatch_input( +fn read_and_dispatch_input< + Host: Runtime, + Mode: Parsable + InputHandler, + ChainConfig: ChainConfigTrait, +>( host: &mut Host, smart_rollup_address: [u8; 20], tezos_contracts: &TezosContracts, @@ -453,14 +454,7 @@ fn read_and_dispatch_input( // kernel enters in simulation mode, reading will be done by the // simulation and all the previous and next transactions are // discarded. - match chain_configuration { - ChainConfig::Evm(evm) => simulation::start_simulation_mode( - host, - enable_fa_bridge, - &evm.evm_config, - ), - ChainConfig::Michelson(_) => Ok(()), - }?; + chain_configuration.start_simulation_mode(host, enable_fa_bridge)?; Ok(ReadStatus::FinishedIgnore) } InputResult::Input(input) => { @@ -482,20 +476,18 @@ pub fn read_proxy_inbox( tezos_contracts: &TezosContracts, enable_fa_bridge: bool, garbage_collect_blocks: bool, - chain_configuration: &ChainConfig, + chain_configuration: &EvmChainConfig, ) -> Result, anyhow::Error> { - let transactions = match ChainConfig::get_chain_family(chain_configuration) { - ChainFamily::Evm => EthTxs(vec![]), - ChainFamily::Michelson => TezTxs, + let mut res = ProxyInboxContent { + transactions: Transactions::EthTxs(vec![]), }; - let mut res = ProxyInboxContent { transactions }; // The mutable variable is used to retrieve the information of whether the // inbox was empty or not. As we consume all the inbox in one go, if the // variable remains true, that means that the inbox was already consumed // during this kernel run. let mut inbox_is_empty = true; loop { - match read_and_dispatch_input::( + match read_and_dispatch_input::( host, smart_rollup_address, tezos_contracts, @@ -546,7 +538,7 @@ pub enum StageOneStatus { } #[allow(clippy::too_many_arguments)] -pub fn read_sequencer_inbox( +pub fn read_sequencer_inbox( host: &mut Host, smart_rollup_address: [u8; 20], tezos_contracts: &TezosContracts, @@ -587,7 +579,7 @@ pub fn read_sequencer_inbox( ); return Ok(StageOneStatus::Reboot); }; - match read_and_dispatch_input::( + match read_and_dispatch_input::( host, smart_rollup_address, tezos_contracts, @@ -633,7 +625,7 @@ mod tests { blueprint_path, store_current_block_header, BlockHeader, BlueprintHeader, ChainHeader, EVMBlockHeader, }; - use crate::chains::test_chain_config; + use crate::chains::test_evm_chain_config; use crate::configuration::TezosContracts; use crate::dal_slot_import_signal::{ DalSlotIndicesList, DalSlotIndicesOfLevel, UnsignedDalSlotSignals, @@ -641,7 +633,7 @@ mod tests { use crate::parsing::RollupType; use crate::storage::*; use crate::tick_model::constants::MAX_ALLOWED_TICKS; - use crate::transaction::TransactionContent::Ethereum; + use crate::transaction::{TransactionContent::Ethereum, Transactions::EthTxs}; use primitive_types::U256; use rlp::Encodable; use std::fmt::Write; @@ -789,7 +781,7 @@ mod tests { &TezosContracts::default(), false, false, - &test_chain_config(), + &test_evm_chain_config(), ) .unwrap() .unwrap(); @@ -821,7 +813,7 @@ mod tests { &TezosContracts::default(), false, false, - &test_chain_config(), + &test_evm_chain_config(), ) .unwrap() .unwrap(); @@ -878,7 +870,7 @@ mod tests { }, false, false, - &test_chain_config(), + &test_evm_chain_config(), ) .unwrap() .unwrap(); @@ -925,7 +917,7 @@ mod tests { &TezosContracts::default(), false, false, - &test_chain_config(), + &test_evm_chain_config(), ) .unwrap(); @@ -977,7 +969,7 @@ mod tests { &TezosContracts::default(), false, false, - &test_chain_config(), + &test_evm_chain_config(), ) .unwrap(); @@ -1017,7 +1009,7 @@ mod tests { &TezosContracts::default(), false, false, - &test_chain_config(), + &test_evm_chain_config(), ) .unwrap(); @@ -1074,7 +1066,7 @@ mod tests { &TezosContracts::default(), false, false, - &test_chain_config(), + &test_evm_chain_config(), ) .unwrap() .unwrap(); @@ -1096,7 +1088,7 @@ mod tests { &TezosContracts::default(), false, false, - &test_chain_config(), + &test_evm_chain_config(), ) .unwrap() .unwrap(); @@ -1159,7 +1151,7 @@ mod tests { &TezosContracts::default(), false, false, - &test_chain_config(), + &test_evm_chain_config(), ) .unwrap() .unwrap(); @@ -1184,7 +1176,7 @@ mod tests { &TezosContracts::default(), false, false, - &test_chain_config(), + &test_evm_chain_config(), ) .unwrap(); assert!(inbox_content.is_some()); @@ -1196,7 +1188,7 @@ mod tests { &TezosContracts::default(), false, false, - &test_chain_config(), + &test_evm_chain_config(), ) .unwrap(); assert!(inbox_content.is_none()); @@ -1303,7 +1295,7 @@ mod tests { MAX_ALLOWED_TICKS, None, false, - &test_chain_config(), + &test_evm_chain_config(), ) .unwrap(); diff --git a/etherlink/kernel_latest/kernel/src/lib.rs b/etherlink/kernel_latest/kernel/src/lib.rs index 37462d3effa502abacf4e4f230e13cbd6839689d..2d9b6c0634d22b07b01cc584389321add1579c10 100644 --- a/etherlink/kernel_latest/kernel/src/lib.rs +++ b/etherlink/kernel_latest/kernel/src/lib.rs @@ -5,7 +5,9 @@ // // SPDX-License-Identifier: MIT -use crate::configuration::{fetch_configuration, Configuration, CHAIN_ID}; +use crate::configuration::{ + fetch_chain_configuration, fetch_configuration, Configuration, CHAIN_ID, +}; use crate::error::Error; use crate::error::UpgradeProcessError::Fallback; use crate::migration::storage_migration; @@ -106,12 +108,14 @@ pub fn stage_zero(host: &mut Host) -> Result( host: &mut Host, smart_rollup_address: [u8; 20], + chain_config: &chains::ChainConfig, configuration: &mut Configuration, ) -> Result { log!(host, Debug, "Entering stage one."); + log!(host, Debug, "Chain Configuration: {}", chain_config); log!(host, Debug, "Configuration: {}", configuration); - fetch_blueprints(host, smart_rollup_address, configuration) + fetch_blueprints(host, smart_rollup_address, chain_config, configuration) } fn set_kernel_version(host: &mut Host) -> Result<(), Error> { @@ -235,7 +239,7 @@ pub fn main(host: &mut Host) -> Result<(), anyhow::Error> { // in the storage. set_kernel_version(host)?; host.mark_for_reboot()?; - let configuration = fetch_configuration(host, chain_id); + let configuration = fetch_configuration(host); log!( host, Info, @@ -269,16 +273,21 @@ pub fn main(host: &mut Host) -> Result<(), anyhow::Error> { let smart_rollup_address = host.reveal_metadata().raw_rollup_address; // 2. Fetch the per mode configuration of the kernel. Returns the default // configuration if it fails. - let mut configuration = fetch_configuration(host, chain_id); + let chain_configuration = fetch_chain_configuration(host, chain_id); + let mut configuration = fetch_configuration(host); let sequencer_pool_address = read_sequencer_pool_address(host); // Run the stage one, this is a no-op if the inbox was already consumed // by another kernel run. This ensures that if the migration does not // consume all reboots. At least one reboot will be used to consume the // inbox. - if let StageOneStatus::Reboot = - stage_one(host, smart_rollup_address, &mut configuration) - .context("Failed during stage 1")? + if let StageOneStatus::Reboot = stage_one( + host, + smart_rollup_address, + &chain_configuration, + &mut configuration, + ) + .context("Failed during stage 1")? { host.mark_for_reboot()?; return Ok(()); @@ -290,12 +299,22 @@ pub fn main(host: &mut Host) -> Result<(), anyhow::Error> { #[cfg(not(feature = "benchmark-bypass-stage2"))] { log!(host, Debug, "Entering stage two."); - if let block::ComputationResult::RebootNeeded = block::produce( - host, - &mut configuration, - sequencer_pool_address, - trace_input, - ) + if let block::ComputationResult::RebootNeeded = match chain_configuration { + chains::ChainConfig::Evm(chain_configuration) => block::produce( + host, + &*chain_configuration, + &mut configuration, + sequencer_pool_address, + trace_input, + ), + chains::ChainConfig::Michelson(chain_configuration) => block::produce( + host, + &chain_configuration, + &mut configuration, + sequencer_pool_address, + trace_input, + ), + } .context("Failed during stage 2")? { host.mark_for_reboot()?; @@ -373,7 +392,7 @@ mod tests { use crate::block_storage; use crate::blueprint_storage::store_inbox_blueprint_by_number; - use crate::chains::{ChainConfig, EvmLimits}; + use crate::chains::test_evm_chain_config; use crate::configuration::Configuration; use crate::fees; use crate::main; @@ -383,12 +402,10 @@ mod tests { }; use crate::{ blueprint::Blueprint, - transaction::{Transaction, TransactionContent}, + transaction::{Transaction, TransactionContent, Transactions}, upgrade::KernelUpgrade, }; - use evm::Config; use evm_execution::account_storage::{self, EthereumAccountStorage}; - use evm_execution::configuration::EVMVersion; use evm_execution::fa_bridge::deposit::{ticket_hash, FaDeposit}; use evm_execution::fa_bridge::test_utils::{ convert_h160, convert_u256, dummy_ticket, kernel_wrapper, ticket_balance_add, @@ -430,17 +447,6 @@ mod tests { const DUMMY_BASE_FEE_PER_GAS: u64 = 12345u64; const DUMMY_DA_FEE: u64 = 2_000_000_000_000u64; - fn dummy_configuration(evm_configuration: Config) -> Configuration { - Configuration { - chain_config: ChainConfig::new_evm_config( - DUMMY_CHAIN_ID, - EvmLimits::default(), - evm_configuration, - ), - ..Configuration::default() - } - } - fn dummy_block_fees() -> BlockFees { BlockFees::new( DUMMY_BASE_FEE_PER_GAS.into(), @@ -484,7 +490,7 @@ mod tests { } } - fn blueprint(transactions: Vec) -> Blueprint { + fn blueprint(transactions: Vec) -> Blueprint { Blueprint { transactions: EthTxs(transactions), timestamp: Timestamp::from(0i64), @@ -607,7 +613,7 @@ mod tests { // Set the tick limit to 11bn ticks - 2bn, which is the old limit minus the safety margin. let mut configuration = Configuration { maximum_allowed_ticks: 9_000_000_000, - ..dummy_configuration(EVMVersion::current_test_config()) + ..Configuration::default() }; crate::storage::store_minimum_base_fee_per_gas( @@ -618,9 +624,14 @@ mod tests { crate::storage::store_da_fee(&mut host, block_fees.da_fee_per_byte()).unwrap(); // If the upgrade is started, it should raise an error - let computation_result = - crate::block::produce(&mut host, &mut configuration, None, None) - .expect("Should have produced"); + let computation_result = crate::block::produce( + &mut host, + &test_evm_chain_config(), + &mut configuration, + None, + None, + ) + .expect("Should have produced"); // test there is a new block assert_eq!( diff --git a/etherlink/kernel_latest/kernel/src/reveal_storage.rs b/etherlink/kernel_latest/kernel/src/reveal_storage.rs index 49a0db13293de3b96436331229b934d4c6934e52..6eeb7e9aa78b3d754df2027386a2ded3b6996e91 100644 --- a/etherlink/kernel_latest/kernel/src/reveal_storage.rs +++ b/etherlink/kernel_latest/kernel/src/reveal_storage.rs @@ -6,7 +6,7 @@ //! chain into a new deployment. It is not tick-safe, and should obviously not be used in a //! production setup. -use crate::configuration::{fetch_configuration, CHAIN_ID}; +use crate::configuration::{fetch_chain_configuration, fetch_configuration, CHAIN_ID}; use crate::storage::{read_chain_id, ADMIN, SEQUENCER}; use primitive_types::U256; use rlp::{Decodable, DecoderError, Rlp}; @@ -107,6 +107,8 @@ pub fn reveal_storage( log!(host, Info, "Done revealing"); let chain_id = read_chain_id(host).unwrap_or(U256::from(CHAIN_ID)); - let configuration = fetch_configuration(host, chain_id); + let chain_config = fetch_chain_configuration(host, chain_id); + let configuration = fetch_configuration(host); + log!(host, Info, "Chain Configuration {}", chain_config); log!(host, Info, "Configuration {}", configuration); } diff --git a/etherlink/kernel_latest/kernel/src/stage_one.rs b/etherlink/kernel_latest/kernel/src/stage_one.rs index ff7bd59edc8b04969461293b4e52652f3b48f079..780aa81d45e5e116486d2c6afae2353a854bd3e1 100644 --- a/etherlink/kernel_latest/kernel/src/stage_one.rs +++ b/etherlink/kernel_latest/kernel/src/stage_one.rs @@ -8,7 +8,7 @@ use crate::blueprint_storage::{ clear_all_blueprints, read_current_blueprint_header, store_forced_blueprint, store_inbox_blueprint, }; -use crate::chains::ChainConfig; +use crate::chains::{ChainConfig, ChainConfigTrait, EvmChainConfig}; use crate::configuration::{ Configuration, ConfigurationMode, DalConfiguration, TezosContracts, }; @@ -33,7 +33,7 @@ pub fn fetch_proxy_blueprints( tezos_contracts: &TezosContracts, enable_fa_bridge: bool, garbage_collect_blocks: bool, - chain_configuration: &ChainConfig, + chain_configuration: &EvmChainConfig, ) -> Result { if let Some(ProxyInboxContent { transactions }) = read_proxy_inbox( host, @@ -117,7 +117,7 @@ fn fetch_delayed_transactions( } #[allow(clippy::too_many_arguments)] -fn fetch_sequencer_blueprints( +fn fetch_sequencer_blueprints( host: &mut Host, smart_rollup_address: [u8; RAW_ROLLUP_ADDRESS_SIZE], tezos_contracts: &TezosContracts, @@ -164,17 +164,21 @@ fn fetch_sequencer_blueprints( pub fn fetch_blueprints( host: &mut Host, smart_rollup_address: [u8; RAW_ROLLUP_ADDRESS_SIZE], + chain_config: &crate::chains::ChainConfig, config: &mut Configuration, ) -> Result { - match &mut config.mode { - ConfigurationMode::Sequencer { - delayed_bridge, - delayed_inbox, - sequencer, - dal, - evm_node_flag: _, - max_blueprint_lookahead_in_seconds: _, - } => fetch_sequencer_blueprints( + match (chain_config, &mut config.mode) { + ( + ChainConfig::Evm(chain_config), + ConfigurationMode::Sequencer { + delayed_bridge, + delayed_inbox, + sequencer, + dal, + evm_node_flag: _, + max_blueprint_lookahead_in_seconds: _, + }, + ) => fetch_sequencer_blueprints( host, smart_rollup_address, &config.tezos_contracts, @@ -185,24 +189,55 @@ pub fn fetch_blueprints( config.maximum_allowed_ticks, config.enable_fa_bridge, config.garbage_collect_blocks, - &config.chain_config, + &**chain_config, ), - ConfigurationMode::Proxy => fetch_proxy_blueprints( + ( + ChainConfig::Michelson(chain_config), + ConfigurationMode::Sequencer { + delayed_bridge, + delayed_inbox, + sequencer, + dal, + evm_node_flag: _, + max_blueprint_lookahead_in_seconds: _, + }, + ) => fetch_sequencer_blueprints( host, smart_rollup_address, &config.tezos_contracts, + delayed_bridge.clone(), + delayed_inbox, + sequencer.clone(), + dal.clone(), + config.maximum_allowed_ticks, config.enable_fa_bridge, config.garbage_collect_blocks, - &config.chain_config, + chain_config, ), + (ChainConfig::Evm(chain_config), ConfigurationMode::Proxy) => { + fetch_proxy_blueprints( + host, + smart_rollup_address, + &config.tezos_contracts, + config.enable_fa_bridge, + config.garbage_collect_blocks, + chain_config, + ) + } + (ChainConfig::Michelson(_), ConfigurationMode::Proxy) => { + // Proxy mode is only available for the EVM chain. + Ok(StageOneStatus::Done) + } } } #[cfg(test)] mod tests { use crate::{ - blueprint_storage::ChainHeader, - chains::{test_chain_config, ChainFamily}, + blueprint_storage::EVMBlockHeader, + chains::{ + test_chain_config, test_evm_chain_config, ChainHeaderTrait, TransactionsTrait, + }, dal_slot_import_signal::{ DalSlotImportSignals, DalSlotIndicesList, DalSlotIndicesOfLevel, UnsignedDalSlotSignals, @@ -281,7 +316,6 @@ mod tests { }, maximum_allowed_ticks: MAX_ALLOWED_TICKS, enable_fa_bridge: false, - chain_config: test_chain_config(), garbage_collect_blocks: false, } } @@ -296,7 +330,6 @@ mod tests { mode: ConfigurationMode::Proxy, maximum_allowed_ticks: MAX_ALLOWED_TICKS, enable_fa_bridge: false, - chain_config: test_chain_config(), garbage_collect_blocks: false, } } @@ -407,7 +440,13 @@ mod tests { host.host .add_external(Bytes::from(hex::decode(DUMMY_TRANSACTION).unwrap())); let mut conf = dummy_proxy_configuration(); - fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); + fetch_blueprints( + &mut host, + DEFAULT_SR_ADDRESS, + &test_chain_config(), + &mut conf, + ) + .expect("fetch failed"); match read_next_blueprint(&mut host, &mut conf) .expect("Blueprint reading shouldn't fail") @@ -430,7 +469,13 @@ mod tests { host.host .add_external(Bytes::from(hex::decode(DUMMY_CHUNK2).unwrap())); let mut conf = dummy_proxy_configuration(); - fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); + fetch_blueprints( + &mut host, + DEFAULT_SR_ADDRESS, + &test_chain_config(), + &mut conf, + ) + .expect("fetch failed"); match read_next_blueprint(&mut host, &mut conf) .expect("Blueprint reading shouldn't fail") @@ -448,7 +493,13 @@ mod tests { host.host .add_external(Bytes::from(hex::decode(DUMMY_TRANSACTION).unwrap())); let mut conf = dummy_sequencer_config(enable_dal, None); - fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); + fetch_blueprints( + &mut host, + DEFAULT_SR_ADDRESS, + &test_chain_config(), + &mut conf, + ) + .expect("fetch failed"); if read_next_blueprint(&mut host, &mut conf) .expect("Blueprint reading shouldn't fail") @@ -478,7 +529,13 @@ mod tests { host.host .add_external(Bytes::from(hex::decode(DUMMY_CHUNK2).unwrap())); let mut conf = dummy_sequencer_config(enable_dal, None); - fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); + fetch_blueprints( + &mut host, + DEFAULT_SR_ADDRESS, + &test_chain_config(), + &mut conf, + ) + .expect("fetch failed"); if read_next_blueprint(&mut host, &mut conf) .expect("Blueprint reading shouldn't fail") @@ -505,15 +562,21 @@ mod tests { hex::decode(DUMMY_BLUEPRINT_CHUNK_NUMBER_10).unwrap(), )); let mut conf = dummy_sequencer_config(enable_dal, None); - fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); + fetch_blueprints( + &mut host, + DEFAULT_SR_ADDRESS, + &test_chain_config(), + &mut conf, + ) + .expect("fetch failed"); // The dummy chunk in the inbox is registered at block 10 - if read_blueprint( + if read_blueprint::<_, EvmChainConfig>( &mut host, &mut conf, U256::from(10), Timestamp::from(0), - &ChainHeader::genesis_header(ChainFamily::Evm), + &EVMBlockHeader::genesis_header(), ) .expect("Blueprint reading shouldn't fail") .0 @@ -539,7 +602,13 @@ mod tests { hex::decode(DUMMY_BLUEPRINT_CHUNK_UNPARSABLE).unwrap(), )); let mut conf = dummy_sequencer_config(enable_dal, None); - fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); + fetch_blueprints( + &mut host, + DEFAULT_SR_ADDRESS, + &test_chain_config(), + &mut conf, + ) + .expect("fetch failed"); if read_next_blueprint(&mut host, &mut conf) .expect("Blueprint reading shouldn't fail") @@ -573,7 +642,7 @@ mod tests { &conf.tezos_contracts, false, false, - &conf.chain_config, + &test_evm_chain_config(), ) .unwrap() { @@ -616,7 +685,13 @@ mod tests { for message in dummy_delayed_transaction() { host.host.add_transfer(message, &metadata); } - fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); + fetch_blueprints( + &mut host, + DEFAULT_SR_ADDRESS, + &test_chain_config(), + &mut conf, + ) + .expect("fetch failed"); if read_next_blueprint(&mut host, &mut conf) .expect("Blueprint reading shouldn't fail") @@ -651,7 +726,13 @@ mod tests { for message in dummy_delayed_transaction() { host.host.add_transfer(message, &metadata); } - fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); + fetch_blueprints( + &mut host, + DEFAULT_SR_ADDRESS, + &test_chain_config(), + &mut conf, + ) + .expect("fetch failed"); if read_next_blueprint(&mut host, &mut conf) .expect("Blueprint reading shouldn't fail") @@ -687,7 +768,13 @@ mod tests { for message in dummy_delayed_transaction() { host.host.add_transfer(message, &metadata) } - fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); + fetch_blueprints( + &mut host, + DEFAULT_SR_ADDRESS, + &test_chain_config(), + &mut conf, + ) + .expect("fetch failed"); match read_next_blueprint(&mut host, &mut conf) .expect("Blueprint reading shouldn't fail").0 @@ -711,7 +798,13 @@ mod tests { dummy_deposit(conf.tezos_contracts.ticketer.clone().unwrap()), &metadata, ); - fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); + fetch_blueprints( + &mut host, + DEFAULT_SR_ADDRESS, + &test_chain_config(), + &mut conf, + ) + .expect("fetch failed"); match read_next_blueprint(&mut host, &mut conf) .expect("Blueprint reading shouldn't fail") @@ -740,7 +833,13 @@ mod tests { ), &metadata, ); - fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); + fetch_blueprints( + &mut host, + DEFAULT_SR_ADDRESS, + &test_chain_config(), + &mut conf, + ) + .expect("fetch failed"); match read_next_blueprint(&mut host, &mut conf) .expect("Blueprint reading shouldn't fail") @@ -766,7 +865,13 @@ mod tests { dummy_deposit(conf.tezos_contracts.ticketer.clone().unwrap()), &metadata, ); - fetch_blueprints(&mut host, DEFAULT_SR_ADDRESS, &mut conf).expect("fetch failed"); + fetch_blueprints( + &mut host, + DEFAULT_SR_ADDRESS, + &test_chain_config(), + &mut conf, + ) + .expect("fetch failed"); if read_next_blueprint(&mut host, &mut conf) .expect("Blueprint reading shouldn't fail") @@ -842,7 +947,8 @@ mod tests { let filled_slots = filled_slots.unwrap_or(dal_slots); fill_slots(host, filled_slots); - fetch_blueprints(host, DEFAULT_SR_ADDRESS, conf).expect("fetch failed"); + fetch_blueprints(host, DEFAULT_SR_ADDRESS, &test_chain_config(), conf) + .expect("fetch failed"); } #[test] diff --git a/etherlink/kernel_latest/kernel/src/transaction.rs b/etherlink/kernel_latest/kernel/src/transaction.rs index de228d038fd127192027f0d8b4b49f8017d67c03..f05e746fd75d1d5a2a294d993a413f143426de14 100644 --- a/etherlink/kernel_latest/kernel/src/transaction.rs +++ b/etherlink/kernel_latest/kernel/src/transaction.rs @@ -90,21 +90,12 @@ impl Decodable for TransactionContent { #[derive(PartialEq, Debug, Clone)] pub enum Transactions { EthTxs(Vec), - TezTxs, } impl Transactions { - pub fn number_of_txs(&self) -> usize { - match self { - Self::EthTxs(transactions) => transactions.len(), - Self::TezTxs => 0, - } - } - pub fn push(&mut self, tx: Transaction) { match self { Self::EthTxs(transactions) => transactions.push(tx), - Self::TezTxs => (), } } } @@ -115,9 +106,6 @@ impl Encodable for Transactions { Self::EthTxs(transactions) => { s.append_list(transactions); } - Self::TezTxs => { - s.append_list::(&[]); - } } } }