Skip to content

Commit

Permalink
feat: use lazy static and clone to init sequencer (#609)
Browse files Browse the repository at this point in the history
* use lazy static and clone to init sequencer

* clean

* remove InitializeSequencer trait

* fix clippy
  • Loading branch information
greged93 authored Dec 7, 2023
1 parent e90d1ff commit c31eb22
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 142 deletions.
14 changes: 4 additions & 10 deletions crates/ef-testing/src/evm_sequencer/evm_state/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
15 changes: 5 additions & 10 deletions crates/ef-testing/src/evm_sequencer/evm_state/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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,
Expand All @@ -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(),
Expand Down
37 changes: 0 additions & 37 deletions crates/ef-testing/src/evm_sequencer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> = Result<T, InitializationError>;

#[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());
}
}
37 changes: 18 additions & 19 deletions crates/ef-testing/src/evm_sequencer/sequencer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Self>
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<State>);

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)
}
}
Expand Down
49 changes: 24 additions & 25 deletions crates/ef-testing/src/evm_sequencer/sequencer/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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<Self> {
let storage = [
("Ownable_owner", *KAKAROT_OWNER_ADDRESS.0.key()),
("native_token_address", *ETH_FEE_TOKEN_ADDRESS.0.key()),
Expand All @@ -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<ContractClass, InitializationError> {
Result::<ContractClass, InitializationError>::Ok(ContractClass::V0(
fn convert_contract_class(class: &LegacyContractClass) -> Result<ContractClass, eyre::Error> {
Result::<ContractClass, eyre::Error>::Ok(ContractClass::V0(
ContractClassV0::try_from_json_string(
&serde_json::to_string(class).map_err(ProgramError::Parse)?,
)?,
Expand Down
59 changes: 30 additions & 29 deletions crates/ef-testing/src/evm_sequencer/sequencer/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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<Self>
where
Self: Sized,
{
let storage = [
("owner", *KAKAROT_OWNER_ADDRESS.0.key()),
("chain_id", StarkFelt::from(*CHAIN_ID)),
Expand All @@ -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<ContractClass, eyre::Error> {
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<ContractClass, InitializationError> {
fn convert_contract_class(class: &CompiledClass) -> Result<ContractClass, eyre::Error> {
let casm_contract_class = CasmContractClassWrapper::try_from(class)?;
let casm_contract_class: CasmContractClass = casm_contract_class.into();
Ok(ContractClass::V1(ContractClassV1::try_from(
Expand Down
9 changes: 2 additions & 7 deletions crates/ef-testing/src/models/case.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -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(())
}
Expand Down
5 changes: 0 additions & 5 deletions crates/ef-testing/src/models/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ use starknet::{
};
use starknet_api::StarknetApiError;

use crate::evm_sequencer::InitializationError;

/// Error type based off <https://github.com/paradigmxyz/reth/blob/main/testing/ef-tests/src/result.rs>
#[derive(Debug, thiserror::Error)]
pub enum RunnerError {
Expand All @@ -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),
Expand Down
1 change: 1 addition & 0 deletions crates/sequencer/src/sequencer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<S>
where
for<'any> &'any mut S: State + StateReader,
Expand Down

0 comments on commit c31eb22

Please sign in to comment.