From c31eb223a1442b3e18624d8a87841515ade4001f Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Thu, 7 Dec 2023 18:40:09 +0100 Subject: [PATCH] feat: use lazy static and clone to init sequencer (#609) * use lazy static and clone to init sequencer * clean * remove InitializeSequencer trait * fix clippy --- .../src/evm_sequencer/evm_state/v0.rs | 14 ++--- .../src/evm_sequencer/evm_state/v1.rs | 15 ++--- crates/ef-testing/src/evm_sequencer/mod.rs | 37 ------------ .../src/evm_sequencer/sequencer/mod.rs | 37 ++++++------ .../src/evm_sequencer/sequencer/v0.rs | 49 ++++++++------- .../src/evm_sequencer/sequencer/v1.rs | 59 ++++++++++--------- crates/ef-testing/src/models/case.rs | 9 +-- crates/ef-testing/src/models/error.rs | 5 -- crates/sequencer/src/sequencer.rs | 1 + 9 files changed, 84 insertions(+), 142 deletions(-) diff --git a/crates/ef-testing/src/evm_sequencer/evm_state/v0.rs b/crates/ef-testing/src/evm_sequencer/evm_state/v0.rs index 1e5b0192..f6499471 100644 --- a/crates/ef-testing/src/evm_sequencer/evm_state/v0.rs +++ b/crates/ef-testing/src/evm_sequencer/evm_state/v0.rs @@ -201,25 +201,19 @@ impl Evm for KakarotSequencer { #[cfg(test)] mod tests { use super::*; - use crate::evm_sequencer::{ - constants::{ - tests::{PRIVATE_KEY, PUBLIC_KEY, TEST_CONTRACT_ADDRESS}, - CHAIN_ID, - }, - sequencer::InitializeSequencer, + use crate::evm_sequencer::constants::{ + tests::{PRIVATE_KEY, PUBLIC_KEY, TEST_CONTRACT_ADDRESS}, + CHAIN_ID, }; use blockifier::{abi::abi_utils::get_storage_var_address, state::state_api::StateReader}; use reth_primitives::{sign_message, AccessList, Signature, TransactionSigned, TxEip1559}; use revm_primitives::B256; - use sequencer::state::State as SequencerState; use starknet_api::hash::StarkFelt; #[test] fn test_execute_simple_contract() { // Given - let sequencer = - crate::evm_sequencer::sequencer::KakarotSequencer::new(SequencerState::default()); - let mut sequencer = sequencer.initialize().unwrap(); + let mut sequencer = crate::evm_sequencer::sequencer::KakarotSequencer::new(); let mut transaction = TransactionSigned { hash: B256::default(), diff --git a/crates/ef-testing/src/evm_sequencer/evm_state/v1.rs b/crates/ef-testing/src/evm_sequencer/evm_state/v1.rs index 9797ba29..b1cbd197 100644 --- a/crates/ef-testing/src/evm_sequencer/evm_state/v1.rs +++ b/crates/ef-testing/src/evm_sequencer/evm_state/v1.rs @@ -269,16 +269,12 @@ pub(crate) fn offset_storage_base_address(base_address: StorageKey, offset: i64) #[cfg(test)] mod tests { use super::*; - use crate::evm_sequencer::{ - constants::{ - tests::{PRIVATE_KEY, PUBLIC_KEY, TEST_CONTRACT_ADDRESS}, - CHAIN_ID, - }, - sequencer::InitializeSequencer, + use crate::evm_sequencer::constants::{ + tests::{PRIVATE_KEY, PUBLIC_KEY, TEST_CONTRACT_ADDRESS}, + CHAIN_ID, }; use reth_primitives::{sign_message, AccessList, Signature, TransactionSigned, TxEip1559}; use revm_primitives::B256; - use sequencer::state::State as SequencerState; use starknet::core::types::FieldElement; use starknet_api::hash::StarkFelt; @@ -305,7 +301,7 @@ mod tests { #[test] fn test_store_bytecode() { // Given - let mut sequencer = KakarotSequencer::new(SequencerState::default()); + let mut sequencer = KakarotSequencer::new(); let bytecode = Bytes::from(vec![ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, @@ -331,8 +327,7 @@ mod tests { #[test] fn test_execute_simple_contract() { // Given - let sequencer = KakarotSequencer::new(SequencerState::default()); - let mut sequencer = sequencer.initialize().unwrap(); + let mut sequencer = KakarotSequencer::new(); let mut transaction = TransactionSigned { hash: B256::default(), diff --git a/crates/ef-testing/src/evm_sequencer/mod.rs b/crates/ef-testing/src/evm_sequencer/mod.rs index 625ddc9d..88d44d0e 100644 --- a/crates/ef-testing/src/evm_sequencer/mod.rs +++ b/crates/ef-testing/src/evm_sequencer/mod.rs @@ -4,40 +4,3 @@ pub mod evm_state; pub mod sequencer; pub mod types; pub mod utils; - -use blockifier::state::errors::StateError; -use cairo_vm::types::errors::program_errors::ProgramError; - -use self::types::contract_class::ContractClassConversionError; -use thiserror::Error; - -type InitializationResult = Result; - -#[derive(Debug, Error)] -pub enum InitializationError { - #[error(transparent)] - ClassConversionError(#[from] ContractClassConversionError), - #[error(transparent)] - ProgramError(#[from] ProgramError), - #[error(transparent)] - StateError(#[from] StateError), -} - -#[cfg(test)] -mod tests { - use crate::evm_sequencer::sequencer::{InitializeSequencer, KakarotSequencer}; - use ::sequencer::state::State; - - #[test] - fn test_initialize() { - // Given - let state = State::default(); - let sequencer = KakarotSequencer::new(state); - - // When - let result = sequencer.initialize(); - - // Then - assert!(result.is_ok()); - } -} diff --git a/crates/ef-testing/src/evm_sequencer/sequencer/mod.rs b/crates/ef-testing/src/evm_sequencer/sequencer/mod.rs index 0a84b510..fefa1304 100644 --- a/crates/ef-testing/src/evm_sequencer/sequencer/mod.rs +++ b/crates/ef-testing/src/evm_sequencer/sequencer/mod.rs @@ -11,30 +11,29 @@ use blockifier::transaction::{ }; use sequencer::{execution::Execution, sequencer::Sequencer, state::State}; -use super::{constants::BLOCK_CONTEXT, InitializationResult}; - -/// Sequencer initialization interface. Initializes the sequencer state -/// by setting contract, its storage, declares all necessary classes and -/// deploys the fee token contract. -/// Default implementation is used when no feature flag is enabled. -pub trait InitializeSequencer { - fn initialize(self) -> InitializationResult - where - Self: Sized, - { - panic!("Not implemented, use features flag \"v0\" or \"v1\"") - } -} - -#[cfg(not(any(feature = "v0", feature = "v1")))] -impl InitializeSequencer for KakarotSequencer {} +use super::constants::BLOCK_CONTEXT; /// Kakarot wrapper around a sequencer. +#[derive(Clone)] pub(crate) struct KakarotSequencer(Sequencer); impl KakarotSequencer { - pub fn new(state: State) -> Self { - let sequencer = Sequencer::new(BLOCK_CONTEXT.clone(), state); + pub fn new() -> Self { + let initial_state = { + #[cfg(feature = "v0")] + { + v0::INITIAL_SEQUENCER_STATE.clone() + } + #[cfg(feature = "v1")] + { + v1::INITIAL_SEQUENCER_STATE.clone() + } + #[cfg(not(any(feature = "v0", feature = "v1")))] + { + State::default() + } + }; + let sequencer = Sequencer::new(BLOCK_CONTEXT.clone(), initial_state); Self(sequencer) } } diff --git a/crates/ef-testing/src/evm_sequencer/sequencer/v0.rs b/crates/ef-testing/src/evm_sequencer/sequencer/v0.rs index 98b43065..07e790f4 100644 --- a/crates/ef-testing/src/evm_sequencer/sequencer/v0.rs +++ b/crates/ef-testing/src/evm_sequencer/sequencer/v0.rs @@ -7,6 +7,7 @@ use blockifier::{ execution::contract_class::{ContractClass, ContractClassV0}, }; use cairo_vm::types::errors::program_errors::ProgramError; +use lazy_static::lazy_static; use starknet::core::types::contract::legacy::LegacyContractClass; use crate::evm_sequencer::{ @@ -18,13 +19,13 @@ use crate::evm_sequencer::{ ETH_FEE_TOKEN_ADDRESS, FEE_TOKEN_CLASS, FEE_TOKEN_CLASS_HASH, KAKAROT_ADDRESS, KAKAROT_OWNER_ADDRESS, }, - InitializationError, }; +use sequencer::state::State as SequencerState; -use super::{InitializationResult, InitializeSequencer, KakarotSequencer}; +lazy_static! { + pub static ref INITIAL_SEQUENCER_STATE: SequencerState = { + let mut state = SequencerState::default(); -impl InitializeSequencer for KakarotSequencer { - fn initialize(mut self) -> InitializationResult { let storage = [ ("Ownable_owner", *KAKAROT_OWNER_ADDRESS.0.key()), ("native_token_address", *ETH_FEE_TOKEN_ADDRESS.0.key()), @@ -35,37 +36,35 @@ impl InitializeSequencer for KakarotSequencer { // Write all the storage vars to the sequencer state. for (k, v) in storage { - (&mut self.state).set_storage_at(*KAKAROT_ADDRESS, get_storage_var_address(k, &[]), v); + (&mut state).set_storage_at(*KAKAROT_ADDRESS, get_storage_var_address(k, &[]), v); } // Write the kakarot class and class hash. - (&mut self.state).set_class_hash_at(*KAKAROT_ADDRESS, *KAKAROT_CLASS_HASH)?; - (&mut self.state) - .set_contract_class(&KAKAROT_CLASS_HASH, convert_contract_class(&KAKAROT_CLASS)?)?; + (&mut state).set_class_hash_at(*KAKAROT_ADDRESS, *KAKAROT_CLASS_HASH).expect("Failed to set kakarot class hash"); + (&mut state) + .set_contract_class(&KAKAROT_CLASS_HASH, convert_contract_class(&KAKAROT_CLASS).expect("Failed to convert KAKAROT CLASS to contract class")).expect("Failed to set kakarot contract class"); // Write proxy, eoa, contract account and erc20 classes and class hashes. - (&mut self.state) - .set_contract_class(&PROXY_CLASS_HASH, convert_contract_class(&PROXY_CLASS)?)?; - (&mut self.state).set_contract_class( + (&mut state) + .set_contract_class(&PROXY_CLASS_HASH, convert_contract_class(&PROXY_CLASS).expect("Failed to convert PROXY CLASS to contract class")).expect("Failed to set proxy contract class"); + (&mut state).set_contract_class( &CONTRACT_ACCOUNT_CLASS_HASH, - convert_contract_class(&CONTRACT_ACCOUNT_CLASS)?, - )?; - (&mut self.state) - .set_contract_class(&EOA_CLASS_HASH, convert_contract_class(&EOA_CLASS)?)?; - (&mut self.state).set_contract_class( + convert_contract_class(&CONTRACT_ACCOUNT_CLASS).expect("Failed to convert CONTRACT ACCOUNT CLASS to contract class"), + ).expect("Failed to set contract account class"); + (&mut state) + .set_contract_class(&EOA_CLASS_HASH, convert_contract_class(&EOA_CLASS).expect("Failed to convert EOA CLASS to contract class")).expect("Failed to set eoa contract class"); + (&mut state).set_contract_class( &FEE_TOKEN_CLASS_HASH, - convert_contract_class(&FEE_TOKEN_CLASS)?, - )?; - (&mut self.state).set_class_hash_at(*ETH_FEE_TOKEN_ADDRESS, *FEE_TOKEN_CLASS_HASH)?; + convert_contract_class(&FEE_TOKEN_CLASS).expect("Failed to convert FEE TOKEN CLASS to contract class"), + ).expect("Failed to set sequencer contract class"); + (&mut state).set_class_hash_at(*ETH_FEE_TOKEN_ADDRESS, *FEE_TOKEN_CLASS_HASH).expect("Failed to set fee token class hash"); - Ok(self) - } + state + }; } -fn convert_contract_class( - class: &LegacyContractClass, -) -> Result { - Result::::Ok(ContractClass::V0( +fn convert_contract_class(class: &LegacyContractClass) -> Result { + Result::::Ok(ContractClass::V0( ContractClassV0::try_from_json_string( &serde_json::to_string(class).map_err(ProgramError::Parse)?, )?, diff --git a/crates/ef-testing/src/evm_sequencer/sequencer/v1.rs b/crates/ef-testing/src/evm_sequencer/sequencer/v1.rs index eaa3bc9d..2028c90e 100644 --- a/crates/ef-testing/src/evm_sequencer/sequencer/v1.rs +++ b/crates/ef-testing/src/evm_sequencer/sequencer/v1.rs @@ -5,7 +5,8 @@ use blockifier::{ }; use cairo_lang_starknet::casm_contract_class::CasmContractClass; use cairo_vm::types::errors::program_errors::ProgramError; -use starknet::core::types::contract::CompiledClass; +use lazy_static::lazy_static; +use starknet::core::types::contract::{legacy::LegacyContractClass, CompiledClass}; use starknet_api::hash::StarkFelt; use crate::evm_sequencer::{ @@ -19,16 +20,13 @@ use crate::evm_sequencer::{ KAKAROT_OWNER_ADDRESS, }, types::contract_class::CasmContractClassWrapper, - InitializationError, InitializationResult, }; +use sequencer::state::State as SequencerState; -use super::{InitializeSequencer, KakarotSequencer}; +lazy_static! { + pub static ref INITIAL_SEQUENCER_STATE: SequencerState = { + let mut state = SequencerState::default(); -impl InitializeSequencer for KakarotSequencer { - fn initialize(mut self) -> InitializationResult - where - Self: Sized, - { let storage = [ ("owner", *KAKAROT_OWNER_ADDRESS.0.key()), ("chain_id", StarkFelt::from(*CHAIN_ID)), @@ -41,39 +39,42 @@ impl InitializeSequencer for KakarotSequencer { // Write all the storage vars to the sequencer state. for (k, v) in storage { - (&mut self.state).set_storage_at(*KAKAROT_ADDRESS, get_storage_var_address(k, &[]), v); + (&mut state).set_storage_at(*KAKAROT_ADDRESS, get_storage_var_address(k, &[]), v); } // Write the kakarot class and class hash. - (&mut self.state).set_class_hash_at(*KAKAROT_ADDRESS, *KAKAROT_CLASS_HASH)?; - (&mut self.state) - .set_contract_class(&KAKAROT_CLASS_HASH, convert_contract_class(&KAKAROT_CLASS)?)?; + (&mut state).set_class_hash_at(*KAKAROT_ADDRESS, *KAKAROT_CLASS_HASH).expect("Failed to set kakarot class hash"); + (&mut state) + .set_contract_class(&KAKAROT_CLASS_HASH, convert_contract_class(&KAKAROT_CLASS).expect("Failed to convert KAKAROT CLASS to contract class")).expect("Failed to set kakarot contract class"); // Write eoa, contract account and uninitialized account. - (&mut self.state).set_contract_class( + (&mut state).set_contract_class( &CONTRACT_ACCOUNT_CLASS_HASH, - convert_contract_class(&CONTRACT_ACCOUNT_CLASS)?, - )?; - (&mut self.state) - .set_contract_class(&EOA_CLASS_HASH, convert_contract_class(&EOA_CLASS)?)?; - (&mut self.state).set_contract_class( + convert_contract_class(&CONTRACT_ACCOUNT_CLASS).expect("Failed to convert CONTRACT ACCOUNT CLASS to contract class"), + ).expect("Failed to set contract account class"); + (&mut state) + .set_contract_class(&EOA_CLASS_HASH, convert_contract_class(&EOA_CLASS).expect("Failed to convert EOA CLASS to contract class")).expect("Failed to set eoa contract class"); + (&mut state).set_contract_class( &UNINITIALIZED_ACCOUNT_CLASS_HASH, - convert_contract_class(&UNINITIALIZED_ACCOUNT_CLASS)?, - )?; + convert_contract_class(&UNINITIALIZED_ACCOUNT_CLASS).expect("Failed to convert UNINITIALIZED ACCOUNT CLASS to contract class"), + ).expect("Failed to set uninitialized account class"); - (&mut self.state).set_contract_class( + let convert_class = |class: &LegacyContractClass| -> Result { + Ok(ContractClass::V0(ContractClassV0::try_from_json_string( + &serde_json::to_string(&class).map_err(ProgramError::Parse)?, + )?)) + }; + (&mut state).set_contract_class( &FEE_TOKEN_CLASS_HASH, - ContractClass::V0(ContractClassV0::try_from_json_string( - &serde_json::to_string(&*FEE_TOKEN_CLASS).map_err(ProgramError::Parse)?, - )?), - )?; - (&mut self.state).set_class_hash_at(*ETH_FEE_TOKEN_ADDRESS, *FEE_TOKEN_CLASS_HASH)?; + convert_class(&FEE_TOKEN_CLASS).expect("Failed to convert FEE TOKEN CLASS to contract class"), + ).expect("Failed to set fee token contract class"); + (&mut state).set_class_hash_at(*ETH_FEE_TOKEN_ADDRESS, *FEE_TOKEN_CLASS_HASH).expect("Failed to set fee token class hash"); - Ok(self) - } + state + }; } -fn convert_contract_class(class: &CompiledClass) -> Result { +fn convert_contract_class(class: &CompiledClass) -> Result { let casm_contract_class = CasmContractClassWrapper::try_from(class)?; let casm_contract_class: CasmContractClass = casm_contract_class.into(); Ok(ContractClass::V1(ContractClassV1::try_from( diff --git a/crates/ef-testing/src/models/case.rs b/crates/ef-testing/src/models/case.rs index 88bd0044..a357f33a 100644 --- a/crates/ef-testing/src/models/case.rs +++ b/crates/ef-testing/src/models/case.rs @@ -1,9 +1,8 @@ // Inspired by https://github.com/paradigmxyz/reth/tree/main/testing/ef-tests - use super::error::RunnerError; use super::result::log_execution_result; use crate::evm_sequencer::evm_state::Evm; -use crate::evm_sequencer::sequencer::{InitializeSequencer, KakarotSequencer}; +use crate::evm_sequencer::sequencer::KakarotSequencer; use crate::{ evm_sequencer::{account::KakarotAccount, constants::CHAIN_ID}, traits::Case, @@ -17,7 +16,6 @@ use ethers_signers::{LocalWallet, Signer}; use reth_primitives::{sign_message, SealedBlock}; use reth_rlp::Decodable as _; use revm_primitives::B256; -use sequencer::state::State as SequencerState; #[derive(Debug)] pub struct BlockchainTestCase { @@ -192,15 +190,12 @@ impl BlockchainTestCase { #[async_trait] impl Case for BlockchainTestCase { fn run(&self) -> Result<(), RunnerError> { - let sequencer = KakarotSequencer::new(SequencerState::default()); - let mut sequencer = sequencer.initialize()?; + let mut sequencer = KakarotSequencer::new(); self.handle_pre_state(&mut sequencer)?; - // handle transaction self.handle_transaction(&mut sequencer)?; - // handle post state self.handle_post_state(&mut sequencer)?; Ok(()) } diff --git a/crates/ef-testing/src/models/error.rs b/crates/ef-testing/src/models/error.rs index 2236543d..7291ea4d 100644 --- a/crates/ef-testing/src/models/error.rs +++ b/crates/ef-testing/src/models/error.rs @@ -10,8 +10,6 @@ use starknet::{ }; use starknet_api::StarknetApiError; -use crate::evm_sequencer::InitializationError; - /// Error type based off #[derive(Debug, thiserror::Error)] pub enum RunnerError { @@ -29,9 +27,6 @@ pub enum RunnerError { /// The specific error error: String, }, - /// Sequencer initialization error - #[error("An error occurred while initializing the sequencer: {0}")] - InitializationError(#[from] InitializationError), /// Sequencer error #[error("An error occurred while running the sequencer: {0}")] SequencerError(#[from] StateError), diff --git a/crates/sequencer/src/sequencer.rs b/crates/sequencer/src/sequencer.rs index ac95a0bb..c6a6cd0b 100644 --- a/crates/sequencer/src/sequencer.rs +++ b/crates/sequencer/src/sequencer.rs @@ -20,6 +20,7 @@ use starknet_api::core::ContractAddress; /// must implement State and `StateReader`. The `for` keyword /// indicates that the bound must hold for any lifetime 'any. /// For more details, check out [rust-lang docs](https://doc.rust-lang.org/nomicon/hrtb.html) +#[derive(Clone)] pub struct Sequencer where for<'any> &'any mut S: State + StateReader,