From 43310b47f1ffc812439a41fa1d5c0ab4567ebaac Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Wed, 27 Sep 2023 11:22:01 +0200 Subject: [PATCH 01/24] add possibility to set state nonce --- Cargo.lock | 3 +++ Cargo.toml | 1 + crates/ef-testing/Cargo.toml | 2 ++ crates/sequencer/Cargo.toml | 2 +- crates/sequencer/src/sequencer.rs | 6 +++--- crates/sequencer/src/state.rs | 6 ++++++ 6 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ad1c882..04a030e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2450,6 +2450,7 @@ name = "ef-testing" version = "0.1.0" dependencies = [ "async-trait", + "blockifier", "bytes", "chrono", "ctor", @@ -2467,6 +2468,7 @@ dependencies = [ "reth-rlp", "revm-primitives", "rstest", + "sequencer", "serde", "serde_json", "serde_yaml", @@ -7903,6 +7905,7 @@ name = "sequencer" version = "0.1.0" dependencies = [ "blockifier", + "eyre", "lazy_static", "rustc-hash", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index f362a662..dff93f83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ kakarot-rpc-core = { git = "https://github.com/kkrt-labs/kakarot-rpc.git", rev = kakarot-test-utils = { git = "https://github.com/kkrt-labs/kakarot-rpc.git", rev = "ae5e220" } # Starknet deps +blockifier = { package = "blockifier", git = "https://github.com/starkware-libs/blockifier.git", tag = "v0.3.0-rc0" } katana-core = { git = 'https://github.com/dojoengine/dojo', rev = "b924dac" } dojo-test-utils = { git = 'https://github.com/dojoengine/dojo', rev = "b924dac" } diff --git a/crates/ef-testing/Cargo.toml b/crates/ef-testing/Cargo.toml index 9f898b93..db2b56d4 100644 --- a/crates/ef-testing/Cargo.toml +++ b/crates/ef-testing/Cargo.toml @@ -20,8 +20,10 @@ reth-rlp = { workspace = true } # Kakarot deps kakarot-rpc-core = { workspace = true } kakarot-test-utils = { workspace = true } +sequencer = { path = "../sequencer" } # Starknet deps +blockifier = { workspace = true } dojo-test-utils = { workspace = true } katana-core = { workspace = true } starknet_api = { workspace = true } diff --git a/crates/sequencer/Cargo.toml b/crates/sequencer/Cargo.toml index 94d64421..4b097cd5 100644 --- a/crates/sequencer/Cargo.toml +++ b/crates/sequencer/Cargo.toml @@ -14,7 +14,7 @@ license.workspace = true [dependencies] # Starknet # TODO: remove the blockifier patch on the workspace once we can remove Katana. -blockifier = { package = "blockifier", git = "https://github.com/starkware-libs/blockifier.git", tag = "v0.3.0-rc0" } +blockifier = { workspace = true } starknet_api = { workspace = true } starknet = { workspace = true } diff --git a/crates/sequencer/src/sequencer.rs b/crates/sequencer/src/sequencer.rs index 4a11d48a..a6f6b58e 100644 --- a/crates/sequencer/src/sequencer.rs +++ b/crates/sequencer/src/sequencer.rs @@ -86,10 +86,10 @@ mod tests { TransactionSignature, }; + use crate::constants::test_constants::{FEE_TOKEN_ADDRESS, SEQUENCER_ADDRESS}; use crate::constants::test_constants::{ - FEE_TOKEN_ADDRESS, ONE_BLOCK_NUMBER, ONE_BLOCK_TIMESTAMP, ONE_CLASS_HASH, - SEQUENCER_ADDRESS, TEST_ADDRESS, TEST_CONTRACT_ACCOUNT, TEST_CONTRACT_ADDRESS, - TWO_CLASS_HASH, ZERO_FELT, + ONE_BLOCK_NUMBER, ONE_BLOCK_TIMESTAMP, ONE_CLASS_HASH, TEST_ADDRESS, TEST_CONTRACT_ACCOUNT, + TEST_CONTRACT_ADDRESS, TWO_CLASS_HASH, ZERO_FELT, }; use crate::state::State; diff --git a/crates/sequencer/src/state.rs b/crates/sequencer/src/state.rs index 9734e6da..87ac5d54 100644 --- a/crates/sequencer/src/state.rs +++ b/crates/sequencer/src/state.rs @@ -31,6 +31,12 @@ pub struct State { nonces: FxHashMap, } +impl State { + pub fn set_nonce(&mut self, contract_address: ContractAddress, nonce: Nonce) { + self.nonces.insert(contract_address, nonce); + } +} + impl Committer for &mut State {} /// State implementation for the sequencer. We use a mutable reference to the state From 6a4302363cf2ca09f6c1da8ba6930aa417a7545a Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Wed, 27 Sep 2023 11:23:26 +0200 Subject: [PATCH 02/24] kakarot sequencer --- crates/ef-testing/src/sequencer/mod.rs | 71 ++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 crates/ef-testing/src/sequencer/mod.rs diff --git a/crates/ef-testing/src/sequencer/mod.rs b/crates/ef-testing/src/sequencer/mod.rs new file mode 100644 index 00000000..61443c9f --- /dev/null +++ b/crates/ef-testing/src/sequencer/mod.rs @@ -0,0 +1,71 @@ +pub mod constants; +pub mod setup; +pub mod types; +pub mod utils; + +use std::collections::HashMap; +use std::sync::Arc; + +use blockifier::block_context::BlockContext; +use reth_primitives::Address; +use sequencer::sequencer::Sequencer; +use sequencer::state::State; +use starknet::core::utils::get_contract_address; +use starknet_api::block::{BlockNumber, BlockTimestamp}; +use starknet_api::core::ChainId; + +use self::constants::{FEE_TOKEN_ADDRESS, KAKAROT_ADDRESS, PROXY_CLASS_HASH, SEQUENCER_ADDRESS}; +use self::types::FeltSequencer; + +pub(crate) struct KakarotSequencer(Sequencer); + +#[allow(dead_code)] +impl KakarotSequencer { + pub fn new(state: State) -> Self { + let sequencer = Sequencer::new(Self::default_kakarot_block_context(), state); + Self(sequencer) + } + + fn default_kakarot_block_context() -> BlockContext { + BlockContext { + chain_id: ChainId("KKRT".into()), + block_number: BlockNumber(0), + block_timestamp: BlockTimestamp(0), + sequencer_address: *SEQUENCER_ADDRESS, + fee_token_address: *FEE_TOKEN_ADDRESS, + vm_resource_fee_cost: Arc::new(Self::default_vm_resource_fee_cost()), + gas_price: 1, + invoke_tx_max_n_steps: 2u32.pow(24), + validate_max_n_steps: 2u32.pow(24), + max_recursion_depth: 1024, + } + } + + fn default_vm_resource_fee_cost() -> HashMap { + [ + (String::from("n_steps"), 1_f64), + ("pedersen_builtin".to_string(), 1_f64), + ("range_check_builtin".to_string(), 1_f64), + ("ecdsa_builtin".to_string(), 1_f64), + ("bitwise_builtin".to_string(), 1_f64), + ("poseidon_builtin".to_string(), 1_f64), + ("output_builtin".to_string(), 1_f64), + ("ec_op_builtin".to_string(), 1_f64), + ("keccak_builtin".to_string(), 1_f64), + ("segment_arena_builtin".to_string(), 1_f64), + ] + .into_iter() + .collect() + } + + pub fn compute_starknet_address(&self, evm_address: &Address) -> FeltSequencer { + let evm_address: FeltSequencer = (*evm_address).into(); + let starknet_address = get_contract_address( + evm_address.into(), + PROXY_CLASS_HASH.0.into(), + &[], + (*KAKAROT_ADDRESS.0.key()).into(), + ); + starknet_address.into() + } +} From fadef6605a7fd3d3932fccc5eb6fd37c43a3e302 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Wed, 27 Sep 2023 11:23:37 +0200 Subject: [PATCH 03/24] add default constants used in the sequencer --- crates/ef-testing/src/sequencer/constants.rs | 38 ++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 crates/ef-testing/src/sequencer/constants.rs diff --git a/crates/ef-testing/src/sequencer/constants.rs b/crates/ef-testing/src/sequencer/constants.rs new file mode 100644 index 00000000..64e60047 --- /dev/null +++ b/crates/ef-testing/src/sequencer/constants.rs @@ -0,0 +1,38 @@ +use lazy_static::lazy_static; +use starknet::core::types::FieldElement; +use starknet_api::{ + core::{ClassHash, ContractAddress, PatriciaKey}, + hash::StarkFelt, +}; + +lazy_static! { + // Main addresses + pub static ref SEQUENCER_ADDRESS: ContractAddress = ContractAddress( + TryInto::::try_into(StarkFelt::from( + FieldElement::from_hex_be( + "0x01176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8" + ) + .unwrap() + )) + .unwrap() + ); + pub static ref FEE_TOKEN_ADDRESS: ContractAddress = ContractAddress( + TryInto::::try_into(StarkFelt::from( + FieldElement::from_hex_be( + "0x049D36570D4e46f48e99674bd3fcc84644DdD6b96F7C741B1562B82f9e004dC7" + ) + .unwrap() + )) + .unwrap() + ); + pub static ref KAKAROT_ADDRESS: ContractAddress = + ContractAddress(TryInto::::try_into(StarkFelt::from(1u8)).unwrap()); + pub static ref KAKAROT_OWNER_ADDRESS: ContractAddress = + ContractAddress(TryInto::::try_into(StarkFelt::from(2u8)).unwrap()); + + // Main class hashes + pub static ref KAKAROT_CLASS_HASH: ClassHash = ClassHash(StarkFelt::from(1u8)); + pub static ref PROXY_CLASS_HASH: ClassHash = ClassHash(StarkFelt::from(2u8)); + pub static ref CONTRACT_ACCOUNT_CLASS_HASH: ClassHash = ClassHash(StarkFelt::from(3u8)); + pub static ref EOA_CLASS_HASH: ClassHash = ClassHash(StarkFelt::from(4u8)); +} From c523dbe564e109416047ec2335ae53cb9a2323e3 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Wed, 27 Sep 2023 11:24:24 +0200 Subject: [PATCH 04/24] add felt sequencer to avoid dep on rpc --- crates/ef-testing/src/sequencer/types.rs | 45 ++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 crates/ef-testing/src/sequencer/types.rs diff --git a/crates/ef-testing/src/sequencer/types.rs b/crates/ef-testing/src/sequencer/types.rs new file mode 100644 index 00000000..19091ad1 --- /dev/null +++ b/crates/ef-testing/src/sequencer/types.rs @@ -0,0 +1,45 @@ +use reth_primitives::Address; +use starknet::core::types::FieldElement; +use starknet_api::{ + core::{ContractAddress, PatriciaKey}, + hash::StarkFelt, + StarknetApiError, +}; + +#[derive(Debug, Clone, Copy)] +pub struct FeltSequencer(FieldElement); + +impl From for FeltSequencer { + fn from(felt: FieldElement) -> Self { + Self(felt) + } +} + +impl From for FieldElement { + fn from(felt: FeltSequencer) -> Self { + felt.0 + } +} + +impl From
for FeltSequencer { + fn from(address: Address) -> Self { + let address = FieldElement::from_byte_slice_be(&address.0[..]).unwrap(); // safe unwrap since Address is 20 bytes + Self(address) + } +} + +impl From for StarkFelt { + fn from(felt: FeltSequencer) -> Self { + StarkFelt::from(felt.0) + } +} + +impl TryFrom for ContractAddress { + type Error = StarknetApiError; + + fn try_from(felt: FeltSequencer) -> Result { + let felt: StarkFelt = felt.into(); + let contract_address = ContractAddress(TryInto::::try_into(felt)?); + Ok(contract_address) + } +} From 588ad48138111525baaa149732af09e443fe903b Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Wed, 27 Sep 2023 11:24:43 +0200 Subject: [PATCH 05/24] setup for contract deployed, kakarot and funding --- Cargo.lock | 1 - crates/ef-testing/src/lib.rs | 1 + crates/ef-testing/src/sequencer/setup.rs | 236 +++++++++++++++++++++++ crates/ef-testing/src/sequencer/utils.rs | 41 ++++ 4 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 crates/ef-testing/src/sequencer/setup.rs create mode 100644 crates/ef-testing/src/sequencer/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 04a030e6..81f790ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7905,7 +7905,6 @@ name = "sequencer" version = "0.1.0" dependencies = [ "blockifier", - "eyre", "lazy_static", "rustc-hash", "serde_json", diff --git a/crates/ef-testing/src/lib.rs b/crates/ef-testing/src/lib.rs index 6c04c317..abc3987e 100644 --- a/crates/ef-testing/src/lib.rs +++ b/crates/ef-testing/src/lib.rs @@ -1,4 +1,5 @@ pub mod models; +pub mod sequencer; pub mod storage; pub mod traits; pub mod utils; diff --git a/crates/ef-testing/src/sequencer/setup.rs b/crates/ef-testing/src/sequencer/setup.rs new file mode 100644 index 00000000..21dd1cf2 --- /dev/null +++ b/crates/ef-testing/src/sequencer/setup.rs @@ -0,0 +1,236 @@ +use blockifier::abi::abi_utils::{ + get_erc20_balance_var_addresses, get_uint256_storage_var_addresses, +}; +use blockifier::state::state_api::{State, StateResult}; +use reth_primitives::{Address, Bytes}; +use revm_primitives::U256; +use starknet_api::core::Nonce; +use starknet_api::hash::StarkFelt; +use starknet_api::StarknetApiError; + +use super::constants::{ + CONTRACT_ACCOUNT_CLASS_HASH, EOA_CLASS_HASH, FEE_TOKEN_ADDRESS, KAKAROT_ADDRESS, + KAKAROT_CLASS_HASH, KAKAROT_OWNER_ADDRESS, PROXY_CLASS_HASH, +}; +use super::types::FeltSequencer; +use super::utils::{ + class_hash_to_starkfelt, contract_address_to_starkfelt, get_storage_var_address, + split_bytecode_to_starkfelt, split_u256, +}; +use super::KakarotSequencer; + +pub trait InitializeEvmState { + fn initialize_contract( + &mut self, + evm_address: &Address, + bytecode: &Bytes, + nonce: U256, + storage: Vec<(U256, U256)>, + ) -> StateResult<()>; + + fn initialize_kakarot(&mut self, evm_addresses: Vec<&Address>) -> StateResult<()>; + + fn fund(&mut self, evm_address: &Address, balance: U256) -> StateResult<()>; +} + +impl InitializeEvmState for KakarotSequencer { + fn initialize_contract( + &mut self, + evm_address: &Address, + bytecode: &Bytes, + nonce: U256, + evm_storage: Vec<(U256, U256)>, + ) -> StateResult<()> { + let starknet_address = self.compute_starknet_address(evm_address); + let mut storage = vec![]; + + // Initialize the contract evm_address. + let evm_address: FeltSequencer = (*evm_address).into(); + let evm_address_storage = ( + get_storage_var_address("evm_address", &[]).unwrap(), // safe unwrap: var is ASCII + evm_address.into(), + ); + storage.push(evm_address_storage); + + // Initialize the is_initialized_ storage var. + let is_initialize_storage = ( + get_storage_var_address("is_initialized_", &[]).unwrap(), // safe unwrap: var is ASCII + StarkFelt::from(1u8), + ); + storage.push(is_initialize_storage); + + // Initialize the contract owner + let owner_storage = ( + get_storage_var_address("Ownable_owner", &[]).unwrap(), // safe unwrap: var is ASCII + contract_address_to_starkfelt(&KAKAROT_ADDRESS), + ); + storage.push(owner_storage); + + // Initialize the bytecode storage var. + let bytecode_storage = &mut split_bytecode_to_starkfelt(bytecode) + .into_iter() + .enumerate() + .map(|(i, bytes)| { + ( + get_storage_var_address("bytecode_", &[StarkFelt::from(i as u32)]).unwrap(), // safe unwrap: var is ASCII + bytes, + ) + }) + .collect(); + let bytecode_len_storage = ( + get_storage_var_address("bytecode_len_", &[]).unwrap(), // safe unwrap: var is ASCII + StarkFelt::from(bytecode.len() as u32), + ); + storage.append(bytecode_storage); + storage.push(bytecode_len_storage); + + // Initialize the kakarot address. + let kakarot_address_storage = ( + get_storage_var_address("kakarot_address", &[]).unwrap(), // safe unwrap: var is ASCII + contract_address_to_starkfelt(&KAKAROT_ADDRESS), + ); + storage.push(kakarot_address_storage); + + // Initialize the nonce storage var. + let nonce = StarkFelt::from(TryInto::::try_into(nonce).map_err(|err| { + StarknetApiError::OutOfRange { + string: err.to_string(), + } + })?); + let nonce_storage = ( + get_storage_var_address("nonce", &[]).unwrap(), // safe unwrap: var is ASCII + nonce, + ); + storage.push(nonce_storage); + + // Initialize the storage vars. + let is_evm_storage_empty = evm_storage.is_empty(); + let evm_storage_storage = &mut evm_storage + .into_iter() + .flat_map(|(k, v)| { + let keys = + get_uint256_storage_var_addresses("storage_", &split_u256(k).map(Into::into)) + .unwrap(); + let values = split_u256(v).map(Into::into); + vec![(keys.0, values[0]), (keys.1, values[1])] + }) + .collect(); + storage.append(evm_storage_storage); + + // Initialize the implementation. + let implementation_storage = ( + get_storage_var_address("_implementation", &[]).unwrap(), // safe unwrap: var is ASCII + if bytecode.is_empty() && is_evm_storage_empty { + class_hash_to_starkfelt(&EOA_CLASS_HASH) + } else { + class_hash_to_starkfelt(&CONTRACT_ACCOUNT_CLASS_HASH) + }, + ); + storage.push(implementation_storage); + + // Write all the storage vars to the sequencer state. + let starknet_address = starknet_address.try_into()?; + for (k, v) in storage { + (&mut self.0.state).set_storage_at(starknet_address, k, v); + } + + // Set up the contract class hash and nonce. + self.0.state.set_nonce(starknet_address, Nonce(nonce)); + (&mut self.0.state).set_class_hash_at(starknet_address, *PROXY_CLASS_HASH)?; + Ok(()) + } + + fn initialize_kakarot(&mut self, evm_addresses: Vec<&Address>) -> StateResult<()> { + let mut storage = vec![]; + + // Initialize the kakarot owner. + let kakarot_owner_storage = ( + get_storage_var_address("Ownable_owner", &[]).unwrap(), // safe unwrap: var is ASCII + contract_address_to_starkfelt(&KAKAROT_OWNER_ADDRESS), + ); + storage.push(kakarot_owner_storage); + + // Initialize the kakarot fee token address. + let kakarot_fee_token_storage = ( + get_storage_var_address("native_token_address", &[]).unwrap(), // safe unwrap: var is ASCII + contract_address_to_starkfelt(&FEE_TOKEN_ADDRESS), + ); + storage.push(kakarot_fee_token_storage); + + // Initialize the kakarot various class hashes. + let kakarot_class_hashes = &mut vec![ + ( + get_storage_var_address("contract_account_class_hash", &[]).unwrap(), + class_hash_to_starkfelt(&CONTRACT_ACCOUNT_CLASS_HASH), + ), + ( + get_storage_var_address("externally_owned_account_class_hash", &[]).unwrap(), + class_hash_to_starkfelt(&EOA_CLASS_HASH), + ), + ( + get_storage_var_address("account_proxy_class_hash", &[]).unwrap(), + class_hash_to_starkfelt(&PROXY_CLASS_HASH), + ), + ]; + storage.append(kakarot_class_hashes); + + // Initialize the kakarot address mapping. + let evm_starknet_address_mapping_storage = &mut evm_addresses + .into_iter() + .map(|addr| { + let evm_address = FeltSequencer::from(*addr); + let starknet_address = self.compute_starknet_address(addr); + ( + get_storage_var_address("evm_to_starknet_address", &[evm_address.into()]) + .unwrap(), // safe unwrap: var is ASCII + starknet_address.into(), + ) + }) + .collect(); + storage.append(evm_starknet_address_mapping_storage); + + // Write all the storage vars to the sequencer state. + for (k, v) in storage { + (&mut self.0.state).set_storage_at(*KAKAROT_ADDRESS, k, v); + } + + // Write the kakarot class hash. + (&mut self.0.state).set_class_hash_at(*KAKAROT_ADDRESS, *KAKAROT_CLASS_HASH)?; + Ok(()) + } + + fn fund(&mut self, evm_address: &Address, balance: U256) -> StateResult<()> { + let starknet_address = self.compute_starknet_address(evm_address); + let balance_values = split_u256(balance); + let mut storage = vec![]; + + // Initialize the balance storage var. + let balance_keys = get_erc20_balance_var_addresses(&FEE_TOKEN_ADDRESS)?; + let balance_keys = [balance_keys.0, balance_keys.1]; + let balance_storage = &mut balance_keys + .into_iter() + .zip(balance_values.into_iter()) + .map(|(k, v)| (k, StarkFelt::from(v))) + .collect(); + storage.append(balance_storage); + + // Initialize the allowance storage var. + let allowance_keys = get_uint256_storage_var_addresses( + "ERC20_allowances", + &[*FEE_TOKEN_ADDRESS.0.key(), starknet_address.into()], + )?; + let allowance_keys = [allowance_keys.0, allowance_keys.1]; + let allowance_storage = &mut allowance_keys + .into_iter() + .map(|k| (k, StarkFelt::from(u128::MAX))) + .collect(); + storage.append(allowance_storage); + + // Write all the storage vars to the sequencer state. + let starknet_address = starknet_address.try_into()?; + for (k, v) in storage { + (&mut self.0.state).set_storage_at(starknet_address, k, v); + } + Ok(()) + } +} diff --git a/crates/ef-testing/src/sequencer/utils.rs b/crates/ef-testing/src/sequencer/utils.rs new file mode 100644 index 00000000..cdc885fd --- /dev/null +++ b/crates/ef-testing/src/sequencer/utils.rs @@ -0,0 +1,41 @@ +use blockifier::abi::abi_utils::get_storage_var_address as blockifier_get_storage_var_address; +use reth_primitives::Bytes; +use revm_primitives::U256; +use starknet_api::{ + core::{ClassHash, ContractAddress}, + hash::StarkFelt, + state::StorageKey, +}; + +pub(crate) fn get_storage_var_address( + storage_var: &str, + keys: &[StarkFelt], +) -> Result { + Ok(blockifier_get_storage_var_address(storage_var, keys)?) +} + +pub(crate) fn split_bytecode_to_starkfelt(bytecode: &Bytes) -> Vec { + bytecode + .chunks(16) + .map(|x| { + let mut storage_value = [0u8; 16]; + storage_value[..x.len()].copy_from_slice(x); + StarkFelt::from(u128::from_be_bytes(storage_value)) + }) + .collect() +} + +pub(crate) fn split_u256(value: U256) -> [u128; 2] { + [ + (value & U256::from(u128::MAX)).try_into().unwrap(), // safe unwrap <= U128::MAX. + (value >> 128).try_into().unwrap(), // safe unwrap <= U128::MAX. + ] +} + +pub(crate) fn contract_address_to_starkfelt(contract_address: &ContractAddress) -> StarkFelt { + *contract_address.0.key() +} + +pub(crate) fn class_hash_to_starkfelt(class_hash: &ClassHash) -> StarkFelt { + class_hash.0 +} From 1b75b58ea72cc6eb06eb55ec8a927a18e68f8b60 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 28 Sep 2023 11:47:39 +0200 Subject: [PATCH 06/24] introduce kakarot as submodule --- .gitmodules | 3 +++ Cargo.lock | 2 ++ Cargo.toml | 1 + Makefile | 5 ++++- crates/ef-testing/Cargo.toml | 1 + lib/kakarot | 1 + 6 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .gitmodules create mode 160000 lib/kakarot diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..629d95e3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "kakarot"] + path = lib/kakarot + url = https://github.com/kkrt-labs/kakarot.git diff --git a/Cargo.lock b/Cargo.lock index 81f790ce..e6d0845c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2452,6 +2452,7 @@ dependencies = [ "async-trait", "blockifier", "bytes", + "cairo-vm", "chrono", "ctor", "dojo-test-utils", @@ -7905,6 +7906,7 @@ name = "sequencer" version = "0.1.0" dependencies = [ "blockifier", + "eyre", "lazy_static", "rustc-hash", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index dff93f83..293571e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ kakarot-rpc-core = { git = "https://github.com/kkrt-labs/kakarot-rpc.git", rev = kakarot-test-utils = { git = "https://github.com/kkrt-labs/kakarot-rpc.git", rev = "ae5e220" } # Starknet deps +cairo-vm = "0.8.2" blockifier = { package = "blockifier", git = "https://github.com/starkware-libs/blockifier.git", tag = "v0.3.0-rc0" } katana-core = { git = 'https://github.com/dojoengine/dojo', rev = "b924dac" } dojo-test-utils = { git = 'https://github.com/dojoengine/dojo', rev = "b924dac" } diff --git a/Makefile b/Makefile index 12e9c387..f9561e3b 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,10 @@ KAKAROT_COMMIT := .katana/remote_kakarot_sha # Ensures the commands for $(EF_TESTS_DIR) always run on `make setup`, regardless if the directory exists .PHONY: $(EF_TESTS_DIR) -setup: $(EF_TESTS_DIR) +setup: $(EF_TESTS_DIR) setup-kakarot + +setup-kakarot: + git submodules update --init --recursive fetch-dump: fetch-kakarot-submodule-commit cargo run --features dump --bin fetch-dump-katana diff --git a/crates/ef-testing/Cargo.toml b/crates/ef-testing/Cargo.toml index db2b56d4..e2d509f9 100644 --- a/crates/ef-testing/Cargo.toml +++ b/crates/ef-testing/Cargo.toml @@ -24,6 +24,7 @@ sequencer = { path = "../sequencer" } # Starknet deps blockifier = { workspace = true } +cairo-vm = { workspace = true } dojo-test-utils = { workspace = true } katana-core = { workspace = true } starknet_api = { workspace = true } diff --git a/lib/kakarot b/lib/kakarot new file mode 160000 index 00000000..93fb7369 --- /dev/null +++ b/lib/kakarot @@ -0,0 +1 @@ +Subproject commit 93fb736954b29802d9e49d82cd2b0aa7b9b29b69 From c01a19b6cbb446cc2c1c094805c31e4c774aa8e9 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 28 Sep 2023 11:48:13 +0200 Subject: [PATCH 07/24] load contract classes in lazy static --- crates/ef-testing/src/sequencer/constants.rs | 75 ++++++++++++++++++-- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/crates/ef-testing/src/sequencer/constants.rs b/crates/ef-testing/src/sequencer/constants.rs index 64e60047..fb4b0dbd 100644 --- a/crates/ef-testing/src/sequencer/constants.rs +++ b/crates/ef-testing/src/sequencer/constants.rs @@ -1,11 +1,48 @@ +use std::{collections::HashMap, sync::Arc}; + +use blockifier::block_context::BlockContext; use lazy_static::lazy_static; -use starknet::core::types::FieldElement; +use starknet::core::types::{contract::legacy::LegacyContractClass, FieldElement}; use starknet_api::{ - core::{ClassHash, ContractAddress, PatriciaKey}, + block::{BlockNumber, BlockTimestamp}, + core::{ChainId, ClassHash, ContractAddress, PatriciaKey}, hash::StarkFelt, }; lazy_static! { + // Chain params + pub static ref CHAIN_ID: u64 = 1_263_227_476; + + // Vm resources + pub static ref VM_RESOURCES: HashMap = [ + (String::from("n_steps"), 1f64), + ("pedersen_builtin".to_string(), 1f64), + ("range_check_builtin".to_string(), 1f64), + ("ecdsa_builtin".to_string(), 1f64), + ("bitwise_builtin".to_string(), 1f64), + ("poseidon_builtin".to_string(), 1f64), + ("output_builtin".to_string(), 1f64), + ("ec_op_builtin".to_string(), 1f64), + ("keccak_builtin".to_string(), 1f64), + ("segment_arena_builtin".to_string(), 1f64), + ] + .into_iter() + .collect(); + + // Block context + pub static ref BLOCK_CONTEXT: BlockContext = BlockContext { + chain_id: ChainId("KKRT".into()), + block_number: BlockNumber(0), + block_timestamp: BlockTimestamp(0), + sequencer_address: *SEQUENCER_ADDRESS, + fee_token_address: *FEE_TOKEN_ADDRESS, + vm_resource_fee_cost: Arc::new(VM_RESOURCES.clone()), + gas_price: 1, + invoke_tx_max_n_steps: 2u32.pow(24), + validate_max_n_steps: 2u32.pow(24), + max_recursion_depth: 1024, + }; + // Main addresses pub static ref SEQUENCER_ADDRESS: ContractAddress = ContractAddress( TryInto::::try_into(StarkFelt::from( @@ -30,9 +67,35 @@ lazy_static! { pub static ref KAKAROT_OWNER_ADDRESS: ContractAddress = ContractAddress(TryInto::::try_into(StarkFelt::from(2u8)).unwrap()); + // Main contract classes + pub static ref KAKAROT_CLASS: LegacyContractClass = serde_json::from_reader::<_, LegacyContractClass>(std::fs::File::open("../../lib/kakarot/build/kakarot.json").unwrap()).unwrap(); + pub static ref CONTRACT_ACCOUNT_CLASS: LegacyContractClass = serde_json::from_reader::<_, LegacyContractClass>(std::fs::File::open("../../lib/kakarot/build/contract_account.json").unwrap()).unwrap(); + pub static ref EOA_CLASS: LegacyContractClass = serde_json::from_reader::<_, LegacyContractClass>(std::fs::File::open("../../lib/kakarot/build/externally_owned_account.json").unwrap()).unwrap(); + pub static ref PROXY_CLASS: LegacyContractClass = serde_json::from_reader::<_, LegacyContractClass>(std::fs::File::open("../../lib/kakarot/build/proxy.json").unwrap()).unwrap(); + // Main class hashes - pub static ref KAKAROT_CLASS_HASH: ClassHash = ClassHash(StarkFelt::from(1u8)); - pub static ref PROXY_CLASS_HASH: ClassHash = ClassHash(StarkFelt::from(2u8)); - pub static ref CONTRACT_ACCOUNT_CLASS_HASH: ClassHash = ClassHash(StarkFelt::from(3u8)); - pub static ref EOA_CLASS_HASH: ClassHash = ClassHash(StarkFelt::from(4u8)); + pub static ref KAKAROT_CLASS_HASH: ClassHash = ClassHash(KAKAROT_CLASS.class_hash().unwrap().into()); + pub static ref CONTRACT_ACCOUNT_CLASS_HASH: ClassHash = ClassHash(CONTRACT_ACCOUNT_CLASS.class_hash().unwrap().into()); + pub static ref EOA_CLASS_HASH: ClassHash = ClassHash(EOA_CLASS.class_hash().unwrap().into()); + pub static ref PROXY_CLASS_HASH: ClassHash = ClassHash(PROXY_CLASS.class_hash().unwrap().into()); + +} + +#[cfg(test)] +pub mod tests { + use std::str::FromStr; + + use lazy_static::lazy_static; + use reth_primitives::{Address, Bytes}; + use revm_primitives::B256; + + lazy_static! { + pub static ref PRIVATE_KEY: B256 = + B256::from_str("0x6ae82d865482a203603ecbf25c865e082396d7705a6bbce92c1ff1d6ab9b503c") + .unwrap(); + pub static ref PUBLIC_KEY: Address = + Address::from_str("0x7513A12F74fFF533ee12F20EE524e4883CBd1945").unwrap(); + pub static ref TEST_CONTRACT_ADDRESS: Address = Address::from_low_u64_be(10); + pub static ref SELECTOR: Bytes = Bytes::from_str("0x693c6139").unwrap(); + } } From 62e450918f358a77076b93ea4bbbf32f4a7a5493 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 28 Sep 2023 11:48:56 +0200 Subject: [PATCH 08/24] init sequencer with all classes --- crates/ef-testing/src/sequencer/mod.rs | 138 +++++++++++++++++------ crates/ef-testing/src/sequencer/setup.rs | 68 ++--------- 2 files changed, 111 insertions(+), 95 deletions(-) diff --git a/crates/ef-testing/src/sequencer/mod.rs b/crates/ef-testing/src/sequencer/mod.rs index 61443c9f..7931c5e5 100644 --- a/crates/ef-testing/src/sequencer/mod.rs +++ b/crates/ef-testing/src/sequencer/mod.rs @@ -3,59 +3,107 @@ pub mod setup; pub mod types; pub mod utils; -use std::collections::HashMap; -use std::sync::Arc; - -use blockifier::block_context::BlockContext; +use blockifier::execution::contract_class::{ContractClass, ContractClassV0}; +use blockifier::state::errors::StateError; +use blockifier::state::state_api::{State as BlockifierState, StateResult}; +use cairo_vm::types::errors::program_errors::ProgramError; use reth_primitives::Address; use sequencer::sequencer::Sequencer; use sequencer::state::State; use starknet::core::utils::get_contract_address; -use starknet_api::block::{BlockNumber, BlockTimestamp}; -use starknet_api::core::ChainId; -use self::constants::{FEE_TOKEN_ADDRESS, KAKAROT_ADDRESS, PROXY_CLASS_HASH, SEQUENCER_ADDRESS}; +use self::constants::{ + BLOCK_CONTEXT, CONTRACT_ACCOUNT_CLASS, CONTRACT_ACCOUNT_CLASS_HASH, EOA_CLASS, EOA_CLASS_HASH, + FEE_TOKEN_ADDRESS, KAKAROT_ADDRESS, KAKAROT_CLASS, KAKAROT_CLASS_HASH, KAKAROT_OWNER_ADDRESS, + PROXY_CLASS, PROXY_CLASS_HASH, +}; use self::types::FeltSequencer; +use self::utils::{ + class_hash_to_starkfelt, contract_address_to_starkfelt, get_storage_var_address, +}; pub(crate) struct KakarotSequencer(Sequencer); #[allow(dead_code)] impl KakarotSequencer { pub fn new(state: State) -> Self { - let sequencer = Sequencer::new(Self::default_kakarot_block_context(), state); + let sequencer = Sequencer::new(BLOCK_CONTEXT.clone(), state); Self(sequencer) } - fn default_kakarot_block_context() -> BlockContext { - BlockContext { - chain_id: ChainId("KKRT".into()), - block_number: BlockNumber(0), - block_timestamp: BlockTimestamp(0), - sequencer_address: *SEQUENCER_ADDRESS, - fee_token_address: *FEE_TOKEN_ADDRESS, - vm_resource_fee_cost: Arc::new(Self::default_vm_resource_fee_cost()), - gas_price: 1, - invoke_tx_max_n_steps: 2u32.pow(24), - validate_max_n_steps: 2u32.pow(24), - max_recursion_depth: 1024, + pub fn initialize(mut self) -> StateResult { + let mut storage = vec![]; + + // Initialize the kakarot owner. + let kakarot_owner_storage = ( + get_storage_var_address("Ownable_owner", &[]).unwrap(), // safe unwrap: var is ASCII + contract_address_to_starkfelt(&KAKAROT_OWNER_ADDRESS), + ); + storage.push(kakarot_owner_storage); + + // Initialize the kakarot fee token address. + let kakarot_fee_token_storage = ( + get_storage_var_address("native_token_address", &[]).unwrap(), // safe unwrap: var is ASCII + contract_address_to_starkfelt(&FEE_TOKEN_ADDRESS), + ); + storage.push(kakarot_fee_token_storage); + + // Initialize the kakarot various class hashes. + let kakarot_class_hashes = &mut vec![ + ( + get_storage_var_address("contract_account_class_hash", &[]).unwrap(), + class_hash_to_starkfelt(&CONTRACT_ACCOUNT_CLASS_HASH), + ), + ( + get_storage_var_address("externally_owned_account_class_hash", &[]).unwrap(), + class_hash_to_starkfelt(&EOA_CLASS_HASH), + ), + ( + get_storage_var_address("account_proxy_class_hash", &[]).unwrap(), + class_hash_to_starkfelt(&PROXY_CLASS_HASH), + ), + ]; + storage.append(kakarot_class_hashes); + + // Write all the storage vars to the sequencer state. + for (k, v) in storage { + (&mut self.0.state).set_storage_at(*KAKAROT_ADDRESS, k, v); } - } - fn default_vm_resource_fee_cost() -> HashMap { - [ - (String::from("n_steps"), 1_f64), - ("pedersen_builtin".to_string(), 1_f64), - ("range_check_builtin".to_string(), 1_f64), - ("ecdsa_builtin".to_string(), 1_f64), - ("bitwise_builtin".to_string(), 1_f64), - ("poseidon_builtin".to_string(), 1_f64), - ("output_builtin".to_string(), 1_f64), - ("ec_op_builtin".to_string(), 1_f64), - ("keccak_builtin".to_string(), 1_f64), - ("segment_arena_builtin".to_string(), 1_f64), - ] - .into_iter() - .collect() + // Write the kakarot class and class hash. + (&mut self.0.state).set_class_hash_at(*KAKAROT_ADDRESS, *KAKAROT_CLASS_HASH)?; + (&mut self.0.state).set_contract_class( + &KAKAROT_CLASS_HASH, + ContractClass::V0(ContractClassV0::try_from_json_string( + &serde_json::to_string(&*KAKAROT_CLASS) + .map_err(|err| StateError::ProgramError(ProgramError::Parse(err)))?, + )?), + )?; + + // Write proxy, eoa and contract account classes and class hashes. + (&mut self.0.state).set_contract_class( + &PROXY_CLASS_HASH, + ContractClass::V0(ContractClassV0::try_from_json_string( + &serde_json::to_string(&*PROXY_CLASS) + .map_err(|err| StateError::ProgramError(ProgramError::Parse(err)))?, + )?), + )?; + (&mut self.0.state).set_contract_class( + &CONTRACT_ACCOUNT_CLASS_HASH, + ContractClass::V0(ContractClassV0::try_from_json_string( + &serde_json::to_string(&*CONTRACT_ACCOUNT_CLASS) + .map_err(|err| StateError::ProgramError(ProgramError::Parse(err)))?, + )?), + )?; + (&mut self.0.state).set_contract_class( + &EOA_CLASS_HASH, + ContractClass::V0(ContractClassV0::try_from_json_string( + &serde_json::to_string(&*EOA_CLASS) + .map_err(|err| StateError::ProgramError(ProgramError::Parse(err)))?, + )?), + )?; + + Ok(self) } pub fn compute_starknet_address(&self, evm_address: &Address) -> FeltSequencer { @@ -69,3 +117,21 @@ impl KakarotSequencer { starknet_address.into() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[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/sequencer/setup.rs b/crates/ef-testing/src/sequencer/setup.rs index 21dd1cf2..22183e24 100644 --- a/crates/ef-testing/src/sequencer/setup.rs +++ b/crates/ef-testing/src/sequencer/setup.rs @@ -10,7 +10,7 @@ use starknet_api::StarknetApiError; use super::constants::{ CONTRACT_ACCOUNT_CLASS_HASH, EOA_CLASS_HASH, FEE_TOKEN_ADDRESS, KAKAROT_ADDRESS, - KAKAROT_CLASS_HASH, KAKAROT_OWNER_ADDRESS, PROXY_CLASS_HASH, + PROXY_CLASS_HASH, }; use super::types::FeltSequencer; use super::utils::{ @@ -28,8 +28,6 @@ pub trait InitializeEvmState { storage: Vec<(U256, U256)>, ) -> StateResult<()>; - fn initialize_kakarot(&mut self, evm_addresses: Vec<&Address>) -> StateResult<()>; - fn fund(&mut self, evm_address: &Address, balance: U256) -> StateResult<()>; } @@ -137,65 +135,17 @@ impl InitializeEvmState for KakarotSequencer { // Set up the contract class hash and nonce. self.0.state.set_nonce(starknet_address, Nonce(nonce)); (&mut self.0.state).set_class_hash_at(starknet_address, *PROXY_CLASS_HASH)?; - Ok(()) - } - - fn initialize_kakarot(&mut self, evm_addresses: Vec<&Address>) -> StateResult<()> { - let mut storage = vec![]; - // Initialize the kakarot owner. - let kakarot_owner_storage = ( - get_storage_var_address("Ownable_owner", &[]).unwrap(), // safe unwrap: var is ASCII - contract_address_to_starkfelt(&KAKAROT_OWNER_ADDRESS), + // Add the address to the Kakarot evm to starknet mapping + let evm_starknet_address_mapping_storage = ( + get_storage_var_address("evm_to_starknet_address", &[evm_address.into()]).unwrap(), // safe unwrap: var is ASCII + contract_address_to_starkfelt(&starknet_address), ); - storage.push(kakarot_owner_storage); - - // Initialize the kakarot fee token address. - let kakarot_fee_token_storage = ( - get_storage_var_address("native_token_address", &[]).unwrap(), // safe unwrap: var is ASCII - contract_address_to_starkfelt(&FEE_TOKEN_ADDRESS), + (&mut self.0.state).set_storage_at( + *KAKAROT_ADDRESS, + evm_starknet_address_mapping_storage.0, + evm_starknet_address_mapping_storage.1, ); - storage.push(kakarot_fee_token_storage); - - // Initialize the kakarot various class hashes. - let kakarot_class_hashes = &mut vec![ - ( - get_storage_var_address("contract_account_class_hash", &[]).unwrap(), - class_hash_to_starkfelt(&CONTRACT_ACCOUNT_CLASS_HASH), - ), - ( - get_storage_var_address("externally_owned_account_class_hash", &[]).unwrap(), - class_hash_to_starkfelt(&EOA_CLASS_HASH), - ), - ( - get_storage_var_address("account_proxy_class_hash", &[]).unwrap(), - class_hash_to_starkfelt(&PROXY_CLASS_HASH), - ), - ]; - storage.append(kakarot_class_hashes); - - // Initialize the kakarot address mapping. - let evm_starknet_address_mapping_storage = &mut evm_addresses - .into_iter() - .map(|addr| { - let evm_address = FeltSequencer::from(*addr); - let starknet_address = self.compute_starknet_address(addr); - ( - get_storage_var_address("evm_to_starknet_address", &[evm_address.into()]) - .unwrap(), // safe unwrap: var is ASCII - starknet_address.into(), - ) - }) - .collect(); - storage.append(evm_starknet_address_mapping_storage); - - // Write all the storage vars to the sequencer state. - for (k, v) in storage { - (&mut self.0.state).set_storage_at(*KAKAROT_ADDRESS, k, v); - } - - // Write the kakarot class hash. - (&mut self.0.state).set_class_hash_at(*KAKAROT_ADDRESS, *KAKAROT_CLASS_HASH)?; Ok(()) } From 7c8f63050187b003a0bad18b4f7711d9b7c910e5 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 28 Sep 2023 11:49:34 +0200 Subject: [PATCH 09/24] transaction conversion --- crates/sequencer/Cargo.toml | 1 + crates/sequencer/src/lib.rs | 1 + crates/sequencer/src/transaction.rs | 61 +++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 crates/sequencer/src/transaction.rs diff --git a/crates/sequencer/Cargo.toml b/crates/sequencer/Cargo.toml index 4b097cd5..c72c2b3f 100644 --- a/crates/sequencer/Cargo.toml +++ b/crates/sequencer/Cargo.toml @@ -19,6 +19,7 @@ starknet_api = { workspace = true } starknet = { workspace = true } # Other +eyre = { workspace = true } tracing = { workspace = true } rustc-hash = "1.1.0" diff --git a/crates/sequencer/src/lib.rs b/crates/sequencer/src/lib.rs index a82f65f7..ebd30d80 100644 --- a/crates/sequencer/src/lib.rs +++ b/crates/sequencer/src/lib.rs @@ -3,3 +3,4 @@ pub mod constants; pub mod execution; pub mod sequencer; pub mod state; +pub mod transaction; diff --git a/crates/sequencer/src/transaction.rs b/crates/sequencer/src/transaction.rs new file mode 100644 index 00000000..fcfa5c82 --- /dev/null +++ b/crates/sequencer/src/transaction.rs @@ -0,0 +1,61 @@ +use std::sync::Arc; + +use blockifier::transaction::{ + account_transaction::AccountTransaction, + transaction_execution::Transaction as ExecutionTransaction, +}; +use starknet::core::types::{BroadcastedTransaction, FieldElement}; +use starknet_api::core::{ContractAddress, Nonce, PatriciaKey}; +use starknet_api::hash::{StarkFelt, StarkHash}; +use starknet_api::transaction::InvokeTransaction; +use starknet_api::transaction::{ + Calldata, Fee, InvokeTransactionV1, TransactionHash, TransactionSignature, +}; + +#[derive(Debug)] +pub struct StarknetTransaction(BroadcastedTransaction); + +impl StarknetTransaction { + pub fn new(transaction: BroadcastedTransaction) -> Self { + Self(transaction) + } +} + +impl TryFrom for ExecutionTransaction { + type Error = eyre::Error; + + fn try_from(transaction: StarknetTransaction) -> Result { + match transaction.0 { + BroadcastedTransaction::Invoke(invoke) => Ok(ExecutionTransaction::AccountTransaction( + AccountTransaction::Invoke(InvokeTransaction::V1(InvokeTransactionV1 { + transaction_hash: TransactionHash(Into::::into( + Into::::into(FieldElement::ONE), // TODO: Replace with actual computed hash. + )), + max_fee: Fee(invoke.max_fee.try_into()?), + signature: TransactionSignature( + invoke + .signature + .into_iter() + .map(Into::::into) + .collect(), + ), + nonce: Nonce(invoke.nonce.try_into()?), + sender_address: ContractAddress(TryInto::::try_into(Into::< + StarkHash, + >::into( + Into::::into(invoke.sender_address), + ))?), + calldata: Calldata(Arc::new( + invoke + .calldata + .into_iter() + .map(Into::::into) + .collect(), + )), + })), + )), + // TODO: Add support for other transaction types. + _ => Err(eyre::eyre!("Unsupported transaction type")), + } + } +} From 98c374d3e561ca1f1f9d9469de87c92ea058b1ee Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 28 Sep 2023 11:49:47 +0200 Subject: [PATCH 10/24] add test --- crates/ef-testing/src/sequencer/setup.rs | 77 ++++++++++++++++++++++++ crates/ef-testing/src/sequencer/utils.rs | 53 +++++++++++++++- crates/sequencer/src/sequencer.rs | 11 ++-- 3 files changed, 136 insertions(+), 5 deletions(-) diff --git a/crates/ef-testing/src/sequencer/setup.rs b/crates/ef-testing/src/sequencer/setup.rs index 22183e24..02c20f97 100644 --- a/crates/ef-testing/src/sequencer/setup.rs +++ b/crates/ef-testing/src/sequencer/setup.rs @@ -184,3 +184,80 @@ impl InitializeEvmState for KakarotSequencer { Ok(()) } } + +#[cfg(test)] +mod tests { + use crate::sequencer::{ + constants::{ + tests::{PRIVATE_KEY, PUBLIC_KEY, SELECTOR, TEST_CONTRACT_ADDRESS}, + CHAIN_ID, + }, + utils::to_broadcasted_starknet_transaction, + }; + + use super::*; + use blockifier::state::state_api::StateReader; + use bytes::BytesMut; + use reth_primitives::{sign_message, AccessList, Signature, TransactionSigned, TxEip1559}; + use revm_primitives::B256; + use sequencer::{ + execution::Execution, state::State as SequencerState, transaction::StarknetTransaction, + }; + use starknet::core::types::BroadcastedTransaction; + + #[test] + fn test_execute_contract_address() { + // Given + let sequencer = KakarotSequencer::new(SequencerState::default()); + let mut sequencer = sequencer.initialize().unwrap(); + + let transaction = TransactionSigned { + hash: B256::default(), + signature: Signature::default(), + transaction: reth_primitives::Transaction::Eip1559(TxEip1559 { + chain_id: *CHAIN_ID, + nonce: 0, + gas_limit: 0, + max_fee_per_gas: 0, + max_priority_fee_per_gas: 0, + to: reth_primitives::TransactionKind::Call(*TEST_CONTRACT_ADDRESS), + value: 0, + access_list: AccessList::default(), + input: SELECTOR.clone(), + }), + }; + let signature = + sign_message(*PRIVATE_KEY, transaction.transaction.signature_hash()).unwrap(); + let mut output = BytesMut::new(); + transaction.encode_with_signature(&signature, &mut output, false); + let transaction = BroadcastedTransaction::Invoke( + to_broadcasted_starknet_transaction(&sequencer, &output.to_vec().into()).unwrap(), + ); + let transaction = StarknetTransaction::new(transaction).try_into().unwrap(); + + // When + let bytecode = Bytes::from(vec![96, 1, 96, 0, 85]); // PUSH 01 PUSH 00 SSTORE + let nonce = U256::from(0); + sequencer + .initialize_contract(&TEST_CONTRACT_ADDRESS, &bytecode, nonce, vec![]) + .unwrap(); + sequencer + .initialize_contract(&PUBLIC_KEY, &Bytes::default(), U256::from(0), vec![]) + .unwrap(); + sequencer.0.execute(transaction).unwrap(); + + // Then + let contract_starknet_address = sequencer + .compute_starknet_address(&TEST_CONTRACT_ADDRESS) + .try_into() + .unwrap(); + let storage = (&mut sequencer.0.state) + .get_storage_at( + contract_starknet_address, + get_storage_var_address("storage_", &[StarkFelt::from(0u8), StarkFelt::from(0u8)]) + .unwrap(), + ) + .unwrap(); + assert_eq!(storage, StarkFelt::from(1u8)); + } +} diff --git a/crates/ef-testing/src/sequencer/utils.rs b/crates/ef-testing/src/sequencer/utils.rs index cdc885fd..7025ab5b 100644 --- a/crates/ef-testing/src/sequencer/utils.rs +++ b/crates/ef-testing/src/sequencer/utils.rs @@ -1,12 +1,19 @@ use blockifier::abi::abi_utils::get_storage_var_address as blockifier_get_storage_var_address; -use reth_primitives::Bytes; +use reth_primitives::{Bytes, TransactionSigned}; +use reth_rlp::Decodable; use revm_primitives::U256; +use starknet::{ + core::types::{BroadcastedInvokeTransaction, FieldElement}, + macros::selector, +}; use starknet_api::{ core::{ClassHash, ContractAddress}, hash::StarkFelt, state::StorageKey, }; +use super::{constants::KAKAROT_ADDRESS, KakarotSequencer}; + pub(crate) fn get_storage_var_address( storage_var: &str, keys: &[StarkFelt], @@ -39,3 +46,47 @@ pub(crate) fn contract_address_to_starkfelt(contract_address: &ContractAddress) pub(crate) fn class_hash_to_starkfelt(class_hash: &ClassHash) -> StarkFelt { class_hash.0 } + +pub fn bytes_to_felt_vec(bytes: &Bytes) -> Vec { + bytes.to_vec().into_iter().map(FieldElement::from).collect() +} + +#[allow(dead_code)] +pub(crate) fn to_broadcasted_starknet_transaction( + sequencer: &KakarotSequencer, + bytes: &Bytes, +) -> Result { + let transaction = TransactionSigned::decode(&mut bytes.as_ref())?; + + let evm_address = transaction + .recover_signer() + .ok_or_else(|| eyre::eyre!("Missing signer in signed transaction"))?; + + let nonce = FieldElement::from(transaction.nonce()); + let starknet_address = sequencer.compute_starknet_address(&evm_address); + + let mut calldata = bytes_to_felt_vec(bytes); + + let mut execute_calldata: Vec = vec![ + FieldElement::ONE, // call array length + contract_address_to_starkfelt(&KAKAROT_ADDRESS).into(), // contract address + selector!("eth_send_transaction"), // selector + FieldElement::ZERO, // data offset + FieldElement::from(calldata.len()), // data length + FieldElement::from(calldata.len()), // calldata length + ]; + execute_calldata.append(&mut calldata); + + let signature = vec![]; + + let request = BroadcastedInvokeTransaction { + max_fee: FieldElement::from(0u8), + signature, + nonce, + sender_address: starknet_address.into(), + calldata: execute_calldata, + is_query: false, + }; + + Ok(request) +} diff --git a/crates/sequencer/src/sequencer.rs b/crates/sequencer/src/sequencer.rs index a6f6b58e..6fa25a26 100644 --- a/crates/sequencer/src/sequencer.rs +++ b/crates/sequencer/src/sequencer.rs @@ -23,7 +23,7 @@ pub struct Sequencer where for<'a> &'a mut S: State + StateReader, { - pub context: BlockContext, + pub block_context: BlockContext, pub state: S, } @@ -32,8 +32,11 @@ where for<'a> &'a mut S: State + StateReader, { /// Creates a new Sequencer instance. - pub fn new(context: BlockContext, state: S) -> Self { - Self { context, state } + pub fn new(block_context: BlockContext, state: S) -> Self { + Self { + block_context, + state, + } } } @@ -44,7 +47,7 @@ where fn execute(&mut self, transaction: Transaction) -> Result<(), TransactionExecutionError> { let mut cached_state = CachedState::new(&mut self.state); let charge_fee = false; - let res = transaction.execute(&mut cached_state, &self.context, charge_fee); + let res = transaction.execute(&mut cached_state, &self.block_context, charge_fee); match res { Err(err) => { From 0f816e3934d0096eefb1617590240f0c44398ef5 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 28 Sep 2023 12:00:41 +0200 Subject: [PATCH 11/24] correct make file --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f9561e3b..e77b6764 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ KAKAROT_COMMIT := .katana/remote_kakarot_sha setup: $(EF_TESTS_DIR) setup-kakarot setup-kakarot: - git submodules update --init --recursive + git submodule update --init --recursive fetch-dump: fetch-kakarot-submodule-commit cargo run --features dump --bin fetch-dump-katana From 0b2800b46a36ad55794adb9eb12da8f02c5df793 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 28 Sep 2023 16:05:42 +0200 Subject: [PATCH 12/24] update ci to pull submodules --- .github/workflows/ci.yml | 23 +++++++++++++++++++++++ .github/workflows/kakarot.yml | 29 +++++++++++++++++++++++++++++ .github/workflows/test.yml | 11 +++++++---- Makefile | 5 ++++- 4 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/kakarot.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..aee5c36b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +--- +name: Workflow - CI + +on: + push: + branches: [main] + pull_request: + +jobs: + linters: + name: Linters + uses: ./.github/workflows/linters.yml + + submodules: + name: Compile Kakarot contracts + uses: ./.github/workflows/kakarot.yml + + tests: + name: Rust tests + uses: ./.github/workflows/test.yml + needs: submodules + + diff --git a/.github/workflows/kakarot.yml b/.github/workflows/kakarot.yml new file mode 100644 index 00000000..09e17b31 --- /dev/null +++ b/.github/workflows/kakarot.yml @@ -0,0 +1,29 @@ +name: Kakarot compilation caching + +on: + workflow_call: + +jobs: + submodules: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 + - name: Set up Python 3.9 + uses: actions/setup-python@v4 + with: + python-version: 3.9 + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + - name: pull kakarot submodule and setup + run: make setup-kakarot + - name: Save compiled kakarot contracts + id: cached-contracts + uses: actions/cache/save@v3 + with: + path: ./lib/kakarot/build + key: ${{ runner.os }}-contracts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1da5e17f..8b49e8b8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,10 +1,7 @@ name: test on: - push: - branches: [main] - pull_request: - branches: [main] + workflow_call: permissions: read-all @@ -17,6 +14,12 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 120 steps: + - name: Load compiled kakarot contracts + id: cached-contracts + uses: actions/cache/restore@v3 + with: + path: ./lib/kakarot/build + key: ${{ runner.os }}-contracts - uses: actions/checkout@v3 - name: Setup rust env uses: actions-rs/toolchain@v1 diff --git a/Makefile b/Makefile index e77b6764..d127baad 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,10 @@ KAKAROT_COMMIT := .katana/remote_kakarot_sha .PHONY: $(EF_TESTS_DIR) setup: $(EF_TESTS_DIR) setup-kakarot -setup-kakarot: +setup-kakarot: pull-kakarot + cd lib/kakarot && make setup && make build + +pull-kakarot: git submodule update --init --recursive fetch-dump: fetch-kakarot-submodule-commit From 923cd1777d952da9e402160f1427983bec576e23 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 28 Sep 2023 16:12:43 +0200 Subject: [PATCH 13/24] remove setup kakarot from setup --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d127baad..60bb6b6f 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ KAKAROT_COMMIT := .katana/remote_kakarot_sha # Ensures the commands for $(EF_TESTS_DIR) always run on `make setup`, regardless if the directory exists .PHONY: $(EF_TESTS_DIR) -setup: $(EF_TESTS_DIR) setup-kakarot +setup: $(EF_TESTS_DIR) setup-kakarot: pull-kakarot cd lib/kakarot && make setup && make build From 8cf0fd61ed04157e7c30307e930f723b7f88ec3c Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 28 Sep 2023 16:42:00 +0200 Subject: [PATCH 14/24] fixing checkout --- .github/workflows/test.yml | 2 +- crates/ef-testing/src/sequencer/setup.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8b49e8b8..4c59d52e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,13 +14,13 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 120 steps: + - uses: actions/checkout@v3 - name: Load compiled kakarot contracts id: cached-contracts uses: actions/cache/restore@v3 with: path: ./lib/kakarot/build key: ${{ runner.os }}-contracts - - uses: actions/checkout@v3 - name: Setup rust env uses: actions-rs/toolchain@v1 with: diff --git a/crates/ef-testing/src/sequencer/setup.rs b/crates/ef-testing/src/sequencer/setup.rs index 02c20f97..a878f675 100644 --- a/crates/ef-testing/src/sequencer/setup.rs +++ b/crates/ef-testing/src/sequencer/setup.rs @@ -206,7 +206,7 @@ mod tests { use starknet::core::types::BroadcastedTransaction; #[test] - fn test_execute_contract_address() { + fn test_execute_simple_contract() { // Given let sequencer = KakarotSequencer::new(SequencerState::default()); let mut sequencer = sequencer.initialize().unwrap(); From a2771ac0f55f0514d25bfd61cd454b0acc3928ea Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Mon, 2 Oct 2023 16:55:49 +0200 Subject: [PATCH 15/24] answer comments --- .github/workflows/test.yml | 3 - .../{sequencer => evm_sequencer}/constants.rs | 37 +++-- .../src/{sequencer => evm_sequencer}/mod.rs | 47 ++----- .../src/{sequencer => evm_sequencer}/setup.rs | 133 ++++++++---------- .../src/{sequencer => evm_sequencer}/types.rs | 0 .../src/{sequencer => evm_sequencer}/utils.rs | 32 +++-- crates/ef-testing/src/lib.rs | 2 +- crates/sequencer/src/transaction.rs | 46 +++++- 8 files changed, 146 insertions(+), 154 deletions(-) rename crates/ef-testing/src/{sequencer => evm_sequencer}/constants.rs (80%) rename crates/ef-testing/src/{sequencer => evm_sequencer}/mod.rs (71%) rename crates/ef-testing/src/{sequencer => evm_sequencer}/setup.rs (68%) rename crates/ef-testing/src/{sequencer => evm_sequencer}/types.rs (100%) rename crates/ef-testing/src/{sequencer => evm_sequencer}/utils.rs (78%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4c59d52e..8a78ba9d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,13 +29,10 @@ jobs: override: true - name: Retrieve cached dependencies uses: Swatinem/rust-cache@v2 - # fetch ef tests - name: fetch ef tests run: make setup - # fetch dump - name: fetch dump run: GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} make fetch-dump - uses: taiki-e/install-action@nextest - # run tests - name: run tests run: make ef-tests diff --git a/crates/ef-testing/src/sequencer/constants.rs b/crates/ef-testing/src/evm_sequencer/constants.rs similarity index 80% rename from crates/ef-testing/src/sequencer/constants.rs rename to crates/ef-testing/src/evm_sequencer/constants.rs index fb4b0dbd..d720d36d 100644 --- a/crates/ef-testing/src/sequencer/constants.rs +++ b/crates/ef-testing/src/evm_sequencer/constants.rs @@ -11,35 +11,35 @@ use starknet_api::{ lazy_static! { // Chain params - pub static ref CHAIN_ID: u64 = 1_263_227_476; + pub static ref CHAIN_ID: u64 = 0x4b4b5254; - // Vm resources + // Vm resources: maps resource name to fee cost. pub static ref VM_RESOURCES: HashMap = [ - (String::from("n_steps"), 1f64), - ("pedersen_builtin".to_string(), 1f64), - ("range_check_builtin".to_string(), 1f64), - ("ecdsa_builtin".to_string(), 1f64), - ("bitwise_builtin".to_string(), 1f64), - ("poseidon_builtin".to_string(), 1f64), - ("output_builtin".to_string(), 1f64), - ("ec_op_builtin".to_string(), 1f64), - ("keccak_builtin".to_string(), 1f64), - ("segment_arena_builtin".to_string(), 1f64), + (String::from("n_steps"), 1_f64), + ("pedersen_builtin".to_string(), 1_f64), + ("range_check_builtin".to_string(), 1_f64), + ("ecdsa_builtin".to_string(), 1_f64), + ("bitwise_builtin".to_string(), 1_f64), + ("poseidon_builtin".to_string(), 1_f64), + ("output_builtin".to_string(), 1_f64), + ("ec_op_builtin".to_string(), 1_f64), + ("keccak_builtin".to_string(), 1_f64), + ("segment_arena_builtin".to_string(), 1_f64), ] .into_iter() .collect(); // Block context pub static ref BLOCK_CONTEXT: BlockContext = BlockContext { - chain_id: ChainId("KKRT".into()), + chain_id: ChainId(String::from_utf8(CHAIN_ID.to_be_bytes().to_vec()).unwrap()), block_number: BlockNumber(0), block_timestamp: BlockTimestamp(0), sequencer_address: *SEQUENCER_ADDRESS, fee_token_address: *FEE_TOKEN_ADDRESS, vm_resource_fee_cost: Arc::new(VM_RESOURCES.clone()), gas_price: 1, - invoke_tx_max_n_steps: 2u32.pow(24), - validate_max_n_steps: 2u32.pow(24), + invoke_tx_max_n_steps: 2_u32.pow(24), + validate_max_n_steps: 2_u32.pow(24), max_recursion_depth: 1024, }; @@ -63,9 +63,9 @@ lazy_static! { .unwrap() ); pub static ref KAKAROT_ADDRESS: ContractAddress = - ContractAddress(TryInto::::try_into(StarkFelt::from(1u8)).unwrap()); + ContractAddress(TryInto::::try_into(StarkFelt::from(1_u8)).unwrap()); pub static ref KAKAROT_OWNER_ADDRESS: ContractAddress = - ContractAddress(TryInto::::try_into(StarkFelt::from(2u8)).unwrap()); + ContractAddress(TryInto::::try_into(StarkFelt::from(2_u8)).unwrap()); // Main contract classes pub static ref KAKAROT_CLASS: LegacyContractClass = serde_json::from_reader::<_, LegacyContractClass>(std::fs::File::open("../../lib/kakarot/build/kakarot.json").unwrap()).unwrap(); @@ -86,7 +86,7 @@ pub mod tests { use std::str::FromStr; use lazy_static::lazy_static; - use reth_primitives::{Address, Bytes}; + use reth_primitives::Address; use revm_primitives::B256; lazy_static! { @@ -96,6 +96,5 @@ pub mod tests { pub static ref PUBLIC_KEY: Address = Address::from_str("0x7513A12F74fFF533ee12F20EE524e4883CBd1945").unwrap(); pub static ref TEST_CONTRACT_ADDRESS: Address = Address::from_low_u64_be(10); - pub static ref SELECTOR: Bytes = Bytes::from_str("0x693c6139").unwrap(); } } diff --git a/crates/ef-testing/src/sequencer/mod.rs b/crates/ef-testing/src/evm_sequencer/mod.rs similarity index 71% rename from crates/ef-testing/src/sequencer/mod.rs rename to crates/ef-testing/src/evm_sequencer/mod.rs index 7931c5e5..99c01ba4 100644 --- a/crates/ef-testing/src/sequencer/mod.rs +++ b/crates/ef-testing/src/evm_sequencer/mod.rs @@ -3,24 +3,20 @@ pub mod setup; pub mod types; pub mod utils; +use blockifier::abi::abi_utils::get_storage_var_address; use blockifier::execution::contract_class::{ContractClass, ContractClassV0}; use blockifier::state::errors::StateError; use blockifier::state::state_api::{State as BlockifierState, StateResult}; use cairo_vm::types::errors::program_errors::ProgramError; -use reth_primitives::Address; use sequencer::sequencer::Sequencer; use sequencer::state::State; -use starknet::core::utils::get_contract_address; use self::constants::{ BLOCK_CONTEXT, CONTRACT_ACCOUNT_CLASS, CONTRACT_ACCOUNT_CLASS_HASH, EOA_CLASS, EOA_CLASS_HASH, FEE_TOKEN_ADDRESS, KAKAROT_ADDRESS, KAKAROT_CLASS, KAKAROT_CLASS_HASH, KAKAROT_OWNER_ADDRESS, PROXY_CLASS, PROXY_CLASS_HASH, }; -use self::types::FeltSequencer; -use self::utils::{ - class_hash_to_starkfelt, contract_address_to_starkfelt, get_storage_var_address, -}; +use self::utils::{class_hash_to_starkfelt, contract_address_to_starkfelt}; pub(crate) struct KakarotSequencer(Sequencer); @@ -32,24 +28,15 @@ impl KakarotSequencer { } pub fn initialize(mut self) -> StateResult { - let mut storage = vec![]; - - // Initialize the kakarot owner. - let kakarot_owner_storage = ( - get_storage_var_address("Ownable_owner", &[]).unwrap(), // safe unwrap: var is ASCII - contract_address_to_starkfelt(&KAKAROT_OWNER_ADDRESS), - ); - storage.push(kakarot_owner_storage); - - // Initialize the kakarot fee token address. - let kakarot_fee_token_storage = ( - get_storage_var_address("native_token_address", &[]).unwrap(), // safe unwrap: var is ASCII - contract_address_to_starkfelt(&FEE_TOKEN_ADDRESS), - ); - storage.push(kakarot_fee_token_storage); - - // Initialize the kakarot various class hashes. - let kakarot_class_hashes = &mut vec![ + let storage = vec![ + ( + get_storage_var_address("Ownable_owner", &[]).unwrap(), // safe unwrap: var is ASCII + contract_address_to_starkfelt(&KAKAROT_OWNER_ADDRESS), + ), + ( + get_storage_var_address("native_token_address", &[]).unwrap(), // safe unwrap: var is ASCII + contract_address_to_starkfelt(&FEE_TOKEN_ADDRESS), + ), ( get_storage_var_address("contract_account_class_hash", &[]).unwrap(), class_hash_to_starkfelt(&CONTRACT_ACCOUNT_CLASS_HASH), @@ -63,7 +50,6 @@ impl KakarotSequencer { class_hash_to_starkfelt(&PROXY_CLASS_HASH), ), ]; - storage.append(kakarot_class_hashes); // Write all the storage vars to the sequencer state. for (k, v) in storage { @@ -105,17 +91,6 @@ impl KakarotSequencer { Ok(self) } - - pub fn compute_starknet_address(&self, evm_address: &Address) -> FeltSequencer { - let evm_address: FeltSequencer = (*evm_address).into(); - let starknet_address = get_contract_address( - evm_address.into(), - PROXY_CLASS_HASH.0.into(), - &[], - (*KAKAROT_ADDRESS.0.key()).into(), - ); - starknet_address.into() - } } #[cfg(test)] diff --git a/crates/ef-testing/src/sequencer/setup.rs b/crates/ef-testing/src/evm_sequencer/setup.rs similarity index 68% rename from crates/ef-testing/src/sequencer/setup.rs rename to crates/ef-testing/src/evm_sequencer/setup.rs index a878f675..765cc95a 100644 --- a/crates/ef-testing/src/sequencer/setup.rs +++ b/crates/ef-testing/src/evm_sequencer/setup.rs @@ -1,5 +1,5 @@ use blockifier::abi::abi_utils::{ - get_erc20_balance_var_addresses, get_uint256_storage_var_addresses, + get_erc20_balance_var_addresses, get_storage_var_address, get_uint256_storage_var_addresses, }; use blockifier::state::state_api::{State, StateResult}; use reth_primitives::{Address, Bytes}; @@ -14,7 +14,7 @@ use super::constants::{ }; use super::types::FeltSequencer; use super::utils::{ - class_hash_to_starkfelt, contract_address_to_starkfelt, get_storage_var_address, + class_hash_to_starkfelt, compute_starknet_address, contract_address_to_starkfelt, split_bytecode_to_starkfelt, split_u256, }; use super::KakarotSequencer; @@ -39,30 +39,48 @@ impl InitializeEvmState for KakarotSequencer { nonce: U256, evm_storage: Vec<(U256, U256)>, ) -> StateResult<()> { - let starknet_address = self.compute_starknet_address(evm_address); - let mut storage = vec![]; - - // Initialize the contract evm_address. - let evm_address: FeltSequencer = (*evm_address).into(); - let evm_address_storage = ( - get_storage_var_address("evm_address", &[]).unwrap(), // safe unwrap: var is ASCII - evm_address.into(), - ); - storage.push(evm_address_storage); - - // Initialize the is_initialized_ storage var. - let is_initialize_storage = ( - get_storage_var_address("is_initialized_", &[]).unwrap(), // safe unwrap: var is ASCII - StarkFelt::from(1u8), - ); - storage.push(is_initialize_storage); - - // Initialize the contract owner - let owner_storage = ( - get_storage_var_address("Ownable_owner", &[]).unwrap(), // safe unwrap: var is ASCII - contract_address_to_starkfelt(&KAKAROT_ADDRESS), - ); - storage.push(owner_storage); + let nonce = StarkFelt::from(TryInto::::try_into(nonce).map_err(|err| { + StarknetApiError::OutOfRange { + string: err.to_string(), + } + })?); + let starknet_address = compute_starknet_address(evm_address); + let evm_address = Into::::into(*evm_address).into(); + + let mut storage = vec![ + ( + get_storage_var_address("evm_address", &[]).unwrap(), // safe unwrap: var is ASCII + evm_address, + ), + ( + get_storage_var_address("is_initialized_", &[]).unwrap(), // safe unwrap: var is ASCII + StarkFelt::from(1u8), + ), + ( + get_storage_var_address("Ownable_owner", &[]).unwrap(), // safe unwrap: var is ASCII + contract_address_to_starkfelt(&KAKAROT_ADDRESS), + ), + ( + get_storage_var_address("bytecode_len_", &[]).unwrap(), // safe unwrap: var is ASCII + StarkFelt::from(bytecode.len() as u32), + ), + ( + get_storage_var_address("kakarot_address", &[]).unwrap(), // safe unwrap: var is ASCII + contract_address_to_starkfelt(&KAKAROT_ADDRESS), + ), + ( + get_storage_var_address("nonce", &[]).unwrap(), // safe unwrap: var is ASCII + nonce, + ), + ( + get_storage_var_address("_implementation", &[]).unwrap(), // safe unwrap: var is ASCII + if bytecode.is_empty() && evm_storage.is_empty() { + class_hash_to_starkfelt(&EOA_CLASS_HASH) + } else { + class_hash_to_starkfelt(&CONTRACT_ACCOUNT_CLASS_HASH) + }, + ), + ]; // Initialize the bytecode storage var. let bytecode_storage = &mut split_bytecode_to_starkfelt(bytecode) @@ -75,57 +93,21 @@ impl InitializeEvmState for KakarotSequencer { ) }) .collect(); - let bytecode_len_storage = ( - get_storage_var_address("bytecode_len_", &[]).unwrap(), // safe unwrap: var is ASCII - StarkFelt::from(bytecode.len() as u32), - ); storage.append(bytecode_storage); - storage.push(bytecode_len_storage); - - // Initialize the kakarot address. - let kakarot_address_storage = ( - get_storage_var_address("kakarot_address", &[]).unwrap(), // safe unwrap: var is ASCII - contract_address_to_starkfelt(&KAKAROT_ADDRESS), - ); - storage.push(kakarot_address_storage); - - // Initialize the nonce storage var. - let nonce = StarkFelt::from(TryInto::::try_into(nonce).map_err(|err| { - StarknetApiError::OutOfRange { - string: err.to_string(), - } - })?); - let nonce_storage = ( - get_storage_var_address("nonce", &[]).unwrap(), // safe unwrap: var is ASCII - nonce, - ); - storage.push(nonce_storage); // Initialize the storage vars. - let is_evm_storage_empty = evm_storage.is_empty(); let evm_storage_storage = &mut evm_storage - .into_iter() + .iter() .flat_map(|(k, v)| { let keys = - get_uint256_storage_var_addresses("storage_", &split_u256(k).map(Into::into)) + get_uint256_storage_var_addresses("storage_", &split_u256(*k).map(Into::into)) .unwrap(); - let values = split_u256(v).map(Into::into); + let values = split_u256(*v).map(Into::into); vec![(keys.0, values[0]), (keys.1, values[1])] }) .collect(); storage.append(evm_storage_storage); - // Initialize the implementation. - let implementation_storage = ( - get_storage_var_address("_implementation", &[]).unwrap(), // safe unwrap: var is ASCII - if bytecode.is_empty() && is_evm_storage_empty { - class_hash_to_starkfelt(&EOA_CLASS_HASH) - } else { - class_hash_to_starkfelt(&CONTRACT_ACCOUNT_CLASS_HASH) - }, - ); - storage.push(implementation_storage); - // Write all the storage vars to the sequencer state. let starknet_address = starknet_address.try_into()?; for (k, v) in storage { @@ -138,7 +120,7 @@ impl InitializeEvmState for KakarotSequencer { // Add the address to the Kakarot evm to starknet mapping let evm_starknet_address_mapping_storage = ( - get_storage_var_address("evm_to_starknet_address", &[evm_address.into()]).unwrap(), // safe unwrap: var is ASCII + get_storage_var_address("evm_to_starknet_address", &[evm_address]).unwrap(), // safe unwrap: var is ASCII contract_address_to_starkfelt(&starknet_address), ); (&mut self.0.state).set_storage_at( @@ -150,7 +132,7 @@ impl InitializeEvmState for KakarotSequencer { } fn fund(&mut self, evm_address: &Address, balance: U256) -> StateResult<()> { - let starknet_address = self.compute_starknet_address(evm_address); + let starknet_address = compute_starknet_address(evm_address); let balance_values = split_u256(balance); let mut storage = vec![]; @@ -187,9 +169,9 @@ impl InitializeEvmState for KakarotSequencer { #[cfg(test)] mod tests { - use crate::sequencer::{ + use crate::evm_sequencer::{ constants::{ - tests::{PRIVATE_KEY, PUBLIC_KEY, SELECTOR, TEST_CONTRACT_ADDRESS}, + tests::{PRIVATE_KEY, PUBLIC_KEY, TEST_CONTRACT_ADDRESS}, CHAIN_ID, }, utils::to_broadcasted_starknet_transaction, @@ -203,7 +185,7 @@ mod tests { use sequencer::{ execution::Execution, state::State as SequencerState, transaction::StarknetTransaction, }; - use starknet::core::types::BroadcastedTransaction; + use starknet::core::types::{BroadcastedTransaction, FieldElement}; #[test] fn test_execute_simple_contract() { @@ -223,7 +205,7 @@ mod tests { to: reth_primitives::TransactionKind::Call(*TEST_CONTRACT_ADDRESS), value: 0, access_list: AccessList::default(), - input: SELECTOR.clone(), + input: Bytes::default(), }), }; let signature = @@ -231,9 +213,11 @@ mod tests { let mut output = BytesMut::new(); transaction.encode_with_signature(&signature, &mut output, false); let transaction = BroadcastedTransaction::Invoke( - to_broadcasted_starknet_transaction(&sequencer, &output.to_vec().into()).unwrap(), + to_broadcasted_starknet_transaction(&output.to_vec().into()).unwrap(), ); - let transaction = StarknetTransaction::new(transaction).try_into().unwrap(); + let transaction = StarknetTransaction::new(transaction) + .try_into_execution_transaction(FieldElement::from(*CHAIN_ID)) + .unwrap(); // When let bytecode = Bytes::from(vec![96, 1, 96, 0, 85]); // PUSH 01 PUSH 00 SSTORE @@ -247,8 +231,7 @@ mod tests { sequencer.0.execute(transaction).unwrap(); // Then - let contract_starknet_address = sequencer - .compute_starknet_address(&TEST_CONTRACT_ADDRESS) + let contract_starknet_address = compute_starknet_address(&TEST_CONTRACT_ADDRESS) .try_into() .unwrap(); let storage = (&mut sequencer.0.state) diff --git a/crates/ef-testing/src/sequencer/types.rs b/crates/ef-testing/src/evm_sequencer/types.rs similarity index 100% rename from crates/ef-testing/src/sequencer/types.rs rename to crates/ef-testing/src/evm_sequencer/types.rs diff --git a/crates/ef-testing/src/sequencer/utils.rs b/crates/ef-testing/src/evm_sequencer/utils.rs similarity index 78% rename from crates/ef-testing/src/sequencer/utils.rs rename to crates/ef-testing/src/evm_sequencer/utils.rs index 7025ab5b..e86e6b3d 100644 --- a/crates/ef-testing/src/sequencer/utils.rs +++ b/crates/ef-testing/src/evm_sequencer/utils.rs @@ -1,24 +1,31 @@ -use blockifier::abi::abi_utils::get_storage_var_address as blockifier_get_storage_var_address; -use reth_primitives::{Bytes, TransactionSigned}; +use super::{ + constants::{KAKAROT_ADDRESS, PROXY_CLASS_HASH}, + types::FeltSequencer, +}; +use reth_primitives::{Address, Bytes, TransactionSigned}; use reth_rlp::Decodable; use revm_primitives::U256; use starknet::{ - core::types::{BroadcastedInvokeTransaction, FieldElement}, + core::{ + types::{BroadcastedInvokeTransaction, FieldElement}, + utils::get_contract_address, + }, macros::selector, }; use starknet_api::{ core::{ClassHash, ContractAddress}, hash::StarkFelt, - state::StorageKey, }; -use super::{constants::KAKAROT_ADDRESS, KakarotSequencer}; - -pub(crate) fn get_storage_var_address( - storage_var: &str, - keys: &[StarkFelt], -) -> Result { - Ok(blockifier_get_storage_var_address(storage_var, keys)?) +pub fn compute_starknet_address(evm_address: &Address) -> FeltSequencer { + let evm_address: FeltSequencer = (*evm_address).into(); + let starknet_address = get_contract_address( + evm_address.into(), + PROXY_CLASS_HASH.0.into(), + &[], + (*KAKAROT_ADDRESS.0.key()).into(), + ); + starknet_address.into() } pub(crate) fn split_bytecode_to_starkfelt(bytecode: &Bytes) -> Vec { @@ -53,7 +60,6 @@ pub fn bytes_to_felt_vec(bytes: &Bytes) -> Vec { #[allow(dead_code)] pub(crate) fn to_broadcasted_starknet_transaction( - sequencer: &KakarotSequencer, bytes: &Bytes, ) -> Result { let transaction = TransactionSigned::decode(&mut bytes.as_ref())?; @@ -63,7 +69,7 @@ pub(crate) fn to_broadcasted_starknet_transaction( .ok_or_else(|| eyre::eyre!("Missing signer in signed transaction"))?; let nonce = FieldElement::from(transaction.nonce()); - let starknet_address = sequencer.compute_starknet_address(&evm_address); + let starknet_address = compute_starknet_address(&evm_address); let mut calldata = bytes_to_felt_vec(bytes); diff --git a/crates/ef-testing/src/lib.rs b/crates/ef-testing/src/lib.rs index abc3987e..d5949b34 100644 --- a/crates/ef-testing/src/lib.rs +++ b/crates/ef-testing/src/lib.rs @@ -1,5 +1,5 @@ +pub mod evm_sequencer; pub mod models; -pub mod sequencer; pub mod storage; pub mod traits; pub mod utils; diff --git a/crates/sequencer/src/transaction.rs b/crates/sequencer/src/transaction.rs index fcfa5c82..f39a6aba 100644 --- a/crates/sequencer/src/transaction.rs +++ b/crates/sequencer/src/transaction.rs @@ -4,6 +4,7 @@ use blockifier::transaction::{ account_transaction::AccountTransaction, transaction_execution::Transaction as ExecutionTransaction, }; +use starknet::core::crypto::compute_hash_on_elements; use starknet::core::types::{BroadcastedTransaction, FieldElement}; use starknet_api::core::{ContractAddress, Nonce, PatriciaKey}; use starknet_api::hash::{StarkFelt, StarkHash}; @@ -19,17 +20,22 @@ impl StarknetTransaction { pub fn new(transaction: BroadcastedTransaction) -> Self { Self(transaction) } -} - -impl TryFrom for ExecutionTransaction { - type Error = eyre::Error; - fn try_from(transaction: StarknetTransaction) -> Result { - match transaction.0 { + pub fn try_into_execution_transaction( + self, + chain_id: FieldElement, + ) -> Result { + match self.0 { BroadcastedTransaction::Invoke(invoke) => Ok(ExecutionTransaction::AccountTransaction( AccountTransaction::Invoke(InvokeTransaction::V1(InvokeTransactionV1 { transaction_hash: TransactionHash(Into::::into( - Into::::into(FieldElement::ONE), // TODO: Replace with actual computed hash. + Into::::into(compute_transaction_hash( + invoke.sender_address, + &invoke.calldata, + invoke.max_fee, + chain_id, + invoke.nonce, + )), )), max_fee: Fee(invoke.max_fee.try_into()?), signature: TransactionSignature( @@ -59,3 +65,29 @@ impl TryFrom for ExecutionTransaction { } } } + +const PREFIX_INVOKE: FieldElement = FieldElement::from_mont([ + 18443034532770911073, + 18446744073709551615, + 18446744073709551615, + 513398556346534256, +]); + +fn compute_transaction_hash( + sender_address: FieldElement, + calldata: &[FieldElement], + max_fee: FieldElement, + chain_id: FieldElement, + nonce: FieldElement, +) -> FieldElement { + compute_hash_on_elements(&[ + PREFIX_INVOKE, + FieldElement::ONE, + sender_address, + FieldElement::ZERO, // entry_point_selector + compute_hash_on_elements(calldata), + max_fee, + chain_id, + nonce, + ]) +} From b0f27c9e33d3e85a0f0066ae6cb1f49648ea5578 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Tue, 3 Oct 2023 12:42:08 +0200 Subject: [PATCH 16/24] update based on comments --- crates/ef-testing/src/evm_sequencer/mod.rs | 32 +++---- crates/ef-testing/src/evm_sequencer/setup.rs | 93 ++++++++------------ crates/ef-testing/src/evm_sequencer/utils.rs | 25 ++---- crates/sequencer/src/transaction.rs | 9 +- 4 files changed, 56 insertions(+), 103 deletions(-) diff --git a/crates/ef-testing/src/evm_sequencer/mod.rs b/crates/ef-testing/src/evm_sequencer/mod.rs index 99c01ba4..afd75410 100644 --- a/crates/ef-testing/src/evm_sequencer/mod.rs +++ b/crates/ef-testing/src/evm_sequencer/mod.rs @@ -16,7 +16,6 @@ use self::constants::{ FEE_TOKEN_ADDRESS, KAKAROT_ADDRESS, KAKAROT_CLASS, KAKAROT_CLASS_HASH, KAKAROT_OWNER_ADDRESS, PROXY_CLASS, PROXY_CLASS_HASH, }; -use self::utils::{class_hash_to_starkfelt, contract_address_to_starkfelt}; pub(crate) struct KakarotSequencer(Sequencer); @@ -29,31 +28,20 @@ impl KakarotSequencer { pub fn initialize(mut self) -> StateResult { let storage = vec![ - ( - get_storage_var_address("Ownable_owner", &[]).unwrap(), // safe unwrap: var is ASCII - contract_address_to_starkfelt(&KAKAROT_OWNER_ADDRESS), - ), - ( - get_storage_var_address("native_token_address", &[]).unwrap(), // safe unwrap: var is ASCII - contract_address_to_starkfelt(&FEE_TOKEN_ADDRESS), - ), - ( - get_storage_var_address("contract_account_class_hash", &[]).unwrap(), - class_hash_to_starkfelt(&CONTRACT_ACCOUNT_CLASS_HASH), - ), - ( - get_storage_var_address("externally_owned_account_class_hash", &[]).unwrap(), - class_hash_to_starkfelt(&EOA_CLASS_HASH), - ), - ( - get_storage_var_address("account_proxy_class_hash", &[]).unwrap(), - class_hash_to_starkfelt(&PROXY_CLASS_HASH), - ), + ("Ownable_owner", *KAKAROT_OWNER_ADDRESS.0.key()), + ("native_token_address", *FEE_TOKEN_ADDRESS.0.key()), + ("contract_account_class_hash", CONTRACT_ACCOUNT_CLASS_HASH.0), + ("externally_owned_account_class_hash", EOA_CLASS_HASH.0), + ("account_proxy_class_hash", PROXY_CLASS_HASH.0), ]; // Write all the storage vars to the sequencer state. for (k, v) in storage { - (&mut self.0.state).set_storage_at(*KAKAROT_ADDRESS, k, v); + (&mut self.0.state).set_storage_at( + *KAKAROT_ADDRESS, + get_storage_var_address(k, &[]).unwrap(), // safe unwrap: all vars are ASCII + v, + ); } // Write the kakarot class and class hash. diff --git a/crates/ef-testing/src/evm_sequencer/setup.rs b/crates/ef-testing/src/evm_sequencer/setup.rs index 765cc95a..e93f1d66 100644 --- a/crates/ef-testing/src/evm_sequencer/setup.rs +++ b/crates/ef-testing/src/evm_sequencer/setup.rs @@ -13,14 +13,11 @@ use super::constants::{ PROXY_CLASS_HASH, }; use super::types::FeltSequencer; -use super::utils::{ - class_hash_to_starkfelt, compute_starknet_address, contract_address_to_starkfelt, - split_bytecode_to_starkfelt, split_u256, -}; +use super::utils::{compute_starknet_address, split_bytecode_to_starkfelt, split_u256}; use super::KakarotSequencer; -pub trait InitializeEvmState { - fn initialize_contract( +pub trait EvmState { + fn setup_account( &mut self, evm_address: &Address, bytecode: &Bytes, @@ -31,8 +28,8 @@ pub trait InitializeEvmState { fn fund(&mut self, evm_address: &Address, balance: U256) -> StateResult<()>; } -impl InitializeEvmState for KakarotSequencer { - fn initialize_contract( +impl EvmState for KakarotSequencer { + fn setup_account( &mut self, evm_address: &Address, bytecode: &Bytes, @@ -48,50 +45,33 @@ impl InitializeEvmState for KakarotSequencer { let evm_address = Into::::into(*evm_address).into(); let mut storage = vec![ + (("evm_address", vec![]), evm_address), + (("is_initialized_", vec![]), StarkFelt::from(1u8)), + (("Ownable_owner", vec![]), *KAKAROT_ADDRESS.0.key()), ( - get_storage_var_address("evm_address", &[]).unwrap(), // safe unwrap: var is ASCII - evm_address, - ), - ( - get_storage_var_address("is_initialized_", &[]).unwrap(), // safe unwrap: var is ASCII - StarkFelt::from(1u8), - ), - ( - get_storage_var_address("Ownable_owner", &[]).unwrap(), // safe unwrap: var is ASCII - contract_address_to_starkfelt(&KAKAROT_ADDRESS), - ), - ( - get_storage_var_address("bytecode_len_", &[]).unwrap(), // safe unwrap: var is ASCII + ("bytecode_len_", vec![]), StarkFelt::from(bytecode.len() as u32), ), - ( - get_storage_var_address("kakarot_address", &[]).unwrap(), // safe unwrap: var is ASCII - contract_address_to_starkfelt(&KAKAROT_ADDRESS), - ), - ( - get_storage_var_address("nonce", &[]).unwrap(), // safe unwrap: var is ASCII - nonce, - ), - ( - get_storage_var_address("_implementation", &[]).unwrap(), // safe unwrap: var is ASCII - if bytecode.is_empty() && evm_storage.is_empty() { - class_hash_to_starkfelt(&EOA_CLASS_HASH) - } else { - class_hash_to_starkfelt(&CONTRACT_ACCOUNT_CLASS_HASH) - }, - ), + (("kakarot_address", vec![]), *KAKAROT_ADDRESS.0.key()), ]; + let starknet_address = starknet_address.try_into()?; + // Initialize the implementation and nonce based on account type. + if bytecode.is_empty() && evm_storage.is_empty() { + storage.push((("_implementation", vec![]), EOA_CLASS_HASH.0)); + self.0.state.set_nonce(starknet_address, Nonce(nonce)); + } else { + storage.append(&mut vec![ + (("nonce", vec![]), nonce), + (("_implementation", vec![]), CONTRACT_ACCOUNT_CLASS_HASH.0), + ]); + } + // Initialize the bytecode storage var. let bytecode_storage = &mut split_bytecode_to_starkfelt(bytecode) .into_iter() .enumerate() - .map(|(i, bytes)| { - ( - get_storage_var_address("bytecode_", &[StarkFelt::from(i as u32)]).unwrap(), // safe unwrap: var is ASCII - bytes, - ) - }) + .map(|(i, bytes)| (("bytecode_", vec![StarkFelt::from(i as u32)]), bytes)) .collect(); storage.append(bytecode_storage); @@ -99,29 +79,32 @@ impl InitializeEvmState for KakarotSequencer { let evm_storage_storage = &mut evm_storage .iter() .flat_map(|(k, v)| { - let keys = - get_uint256_storage_var_addresses("storage_", &split_u256(*k).map(Into::into)) - .unwrap(); + let keys = split_u256(*k).map(Into::into); let values = split_u256(*v).map(Into::into); - vec![(keys.0, values[0]), (keys.1, values[1])] + vec![ + (("storage_", vec![keys[0]]), values[0]), + (("storage_", vec![keys[1]]), values[1]), + ] }) .collect(); storage.append(evm_storage_storage); // Write all the storage vars to the sequencer state. - let starknet_address = starknet_address.try_into()?; - for (k, v) in storage { - (&mut self.0.state).set_storage_at(starknet_address, k, v); + for ((var, keys), v) in storage { + (&mut self.0.state).set_storage_at( + starknet_address, + get_storage_var_address(var, &keys).unwrap(), // safe unwrap: all vars are ASCII + v, + ); } - // Set up the contract class hash and nonce. - self.0.state.set_nonce(starknet_address, Nonce(nonce)); + // Set up the contract class hash. (&mut self.0.state).set_class_hash_at(starknet_address, *PROXY_CLASS_HASH)?; // Add the address to the Kakarot evm to starknet mapping let evm_starknet_address_mapping_storage = ( get_storage_var_address("evm_to_starknet_address", &[evm_address]).unwrap(), // safe unwrap: var is ASCII - contract_address_to_starkfelt(&starknet_address), + *starknet_address.0.key(), ); (&mut self.0.state).set_storage_at( *KAKAROT_ADDRESS, @@ -223,10 +206,10 @@ mod tests { let bytecode = Bytes::from(vec![96, 1, 96, 0, 85]); // PUSH 01 PUSH 00 SSTORE let nonce = U256::from(0); sequencer - .initialize_contract(&TEST_CONTRACT_ADDRESS, &bytecode, nonce, vec![]) + .setup_account(&TEST_CONTRACT_ADDRESS, &bytecode, nonce, vec![]) .unwrap(); sequencer - .initialize_contract(&PUBLIC_KEY, &Bytes::default(), U256::from(0), vec![]) + .setup_account(&PUBLIC_KEY, &Bytes::default(), U256::from(0), vec![]) .unwrap(); sequencer.0.execute(transaction).unwrap(); diff --git a/crates/ef-testing/src/evm_sequencer/utils.rs b/crates/ef-testing/src/evm_sequencer/utils.rs index e86e6b3d..193e6121 100644 --- a/crates/ef-testing/src/evm_sequencer/utils.rs +++ b/crates/ef-testing/src/evm_sequencer/utils.rs @@ -12,10 +12,7 @@ use starknet::{ }, macros::selector, }; -use starknet_api::{ - core::{ClassHash, ContractAddress}, - hash::StarkFelt, -}; +use starknet_api::hash::StarkFelt; pub fn compute_starknet_address(evm_address: &Address) -> FeltSequencer { let evm_address: FeltSequencer = (*evm_address).into(); @@ -46,14 +43,6 @@ pub(crate) fn split_u256(value: U256) -> [u128; 2] { ] } -pub(crate) fn contract_address_to_starkfelt(contract_address: &ContractAddress) -> StarkFelt { - *contract_address.0.key() -} - -pub(crate) fn class_hash_to_starkfelt(class_hash: &ClassHash) -> StarkFelt { - class_hash.0 -} - pub fn bytes_to_felt_vec(bytes: &Bytes) -> Vec { bytes.to_vec().into_iter().map(FieldElement::from).collect() } @@ -74,12 +63,12 @@ pub(crate) fn to_broadcasted_starknet_transaction( let mut calldata = bytes_to_felt_vec(bytes); let mut execute_calldata: Vec = vec![ - FieldElement::ONE, // call array length - contract_address_to_starkfelt(&KAKAROT_ADDRESS).into(), // contract address - selector!("eth_send_transaction"), // selector - FieldElement::ZERO, // data offset - FieldElement::from(calldata.len()), // data length - FieldElement::from(calldata.len()), // calldata length + FieldElement::ONE, // call array length + (*KAKAROT_ADDRESS.0.key()).into(), // contract address + selector!("eth_send_transaction"), // selector + FieldElement::ZERO, // data offset + FieldElement::from(calldata.len()), // data length + FieldElement::from(calldata.len()), // calldata length ]; execute_calldata.append(&mut calldata); diff --git a/crates/sequencer/src/transaction.rs b/crates/sequencer/src/transaction.rs index f39a6aba..316d0aad 100644 --- a/crates/sequencer/src/transaction.rs +++ b/crates/sequencer/src/transaction.rs @@ -66,13 +66,6 @@ impl StarknetTransaction { } } -const PREFIX_INVOKE: FieldElement = FieldElement::from_mont([ - 18443034532770911073, - 18446744073709551615, - 18446744073709551615, - 513398556346534256, -]); - fn compute_transaction_hash( sender_address: FieldElement, calldata: &[FieldElement], @@ -81,7 +74,7 @@ fn compute_transaction_hash( nonce: FieldElement, ) -> FieldElement { compute_hash_on_elements(&[ - PREFIX_INVOKE, + FieldElement::from_byte_slice_be(b"invoke").unwrap(), FieldElement::ONE, sender_address, FieldElement::ZERO, // entry_point_selector From 6e3b4f51e2d50945563b8e53d2e5a9b36cc9c4f7 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Tue, 3 Oct 2023 12:48:14 +0200 Subject: [PATCH 17/24] fix ci rebase --- .github/workflows/ci.yml | 6 +++--- .github/workflows/kakarot.yml | 6 ++++++ .github/workflows/trunk-check.yaml | 5 +---- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aee5c36b..f1a463dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,9 +7,9 @@ on: pull_request: jobs: - linters: - name: Linters - uses: ./.github/workflows/linters.yml + trunk: + name: Trunk + uses: ./.github/workflows/trunk-check.yml submodules: name: Compile Kakarot contracts diff --git a/.github/workflows/kakarot.yml b/.github/workflows/kakarot.yml index 09e17b31..f78b45f1 100644 --- a/.github/workflows/kakarot.yml +++ b/.github/workflows/kakarot.yml @@ -3,6 +3,12 @@ name: Kakarot compilation caching on: workflow_call: +permissions: read-all + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: submodules: runs-on: ubuntu-latest diff --git a/.github/workflows/trunk-check.yaml b/.github/workflows/trunk-check.yaml index 327024da..4a3233d7 100644 --- a/.github/workflows/trunk-check.yaml +++ b/.github/workflows/trunk-check.yaml @@ -1,10 +1,7 @@ name: Trunk on: - push: - branches: [main] - pull_request: - branches: [main] + workflow_call: concurrency: group: ${{ github.workflow }}-${{ github.ref }} From ba61750690a998a7ab5f17d730618f00d7e7be1a Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Tue, 3 Oct 2023 12:50:17 +0200 Subject: [PATCH 18/24] update extension --- .github/workflows/{trunk-check.yaml => trunk-check.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{trunk-check.yaml => trunk-check.yml} (100%) diff --git a/.github/workflows/trunk-check.yaml b/.github/workflows/trunk-check.yml similarity index 100% rename from .github/workflows/trunk-check.yaml rename to .github/workflows/trunk-check.yml From 8d49f9baec249804651832c65d447928c5c9d7d2 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Tue, 3 Oct 2023 12:53:28 +0200 Subject: [PATCH 19/24] update ci --- .github/workflows/kakarot.yml | 2 +- .github/workflows/test.yml | 2 +- .github/workflows/trunk-check.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/kakarot.yml b/.github/workflows/kakarot.yml index f78b45f1..01670c45 100644 --- a/.github/workflows/kakarot.yml +++ b/.github/workflows/kakarot.yml @@ -6,7 +6,7 @@ on: permissions: read-all concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.ref }}-submodules cancel-in-progress: true jobs: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8a78ba9d..7a0db599 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,7 @@ on: permissions: read-all concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.ref }}-test cancel-in-progress: true jobs: diff --git a/.github/workflows/trunk-check.yml b/.github/workflows/trunk-check.yml index 4a3233d7..4daffb63 100644 --- a/.github/workflows/trunk-check.yml +++ b/.github/workflows/trunk-check.yml @@ -4,7 +4,7 @@ on: workflow_call: concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.ref }}-trunk cancel-in-progress: true permissions: read-all From 7e14e69c877b4131912aee946121c17d44905206 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Tue, 3 Oct 2023 14:20:07 +0200 Subject: [PATCH 20/24] try CI with more cores --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7a0db599..cac380f5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ concurrency: jobs: test: - runs-on: ubuntu-latest + runs-on: ubuntu-latest-16-cores timeout-minutes: 120 steps: - uses: actions/checkout@v3 From 68deaef9a5d32b033f0c3083c59d9c743e7f5b57 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Tue, 3 Oct 2023 14:35:50 +0200 Subject: [PATCH 21/24] fix trunk --- .github/workflows/ci.yml | 7 ++++--- .github/workflows/kakarot.yml | 1 + .github/workflows/test.yml | 2 ++ .github/workflows/trunk-check.yml | 1 + Cargo.lock | 4 ++-- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1a463dd..f662a5f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,10 +1,13 @@ --- +permissions: read-all name: Workflow - CI on: push: branches: [main] pull_request: + branches: + - main jobs: trunk: @@ -15,9 +18,7 @@ jobs: name: Compile Kakarot contracts uses: ./.github/workflows/kakarot.yml - tests: + tests: name: Rust tests uses: ./.github/workflows/test.yml needs: submodules - - diff --git a/.github/workflows/kakarot.yml b/.github/workflows/kakarot.yml index 01670c45..1b2365d5 100644 --- a/.github/workflows/kakarot.yml +++ b/.github/workflows/kakarot.yml @@ -1,6 +1,7 @@ name: Kakarot compilation caching on: + # trunk-ignore(yamllint/empty-values) workflow_call: permissions: read-all diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cac380f5..49151c58 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,7 @@ name: test on: + # trunk-ignore(yamllint/empty-values) workflow_call: permissions: read-all @@ -11,6 +12,7 @@ concurrency: jobs: test: + # trunk-ignore(actionlint/runner-label) runs-on: ubuntu-latest-16-cores timeout-minutes: 120 steps: diff --git a/.github/workflows/trunk-check.yml b/.github/workflows/trunk-check.yml index 4daffb63..2d71764b 100644 --- a/.github/workflows/trunk-check.yml +++ b/.github/workflows/trunk-check.yml @@ -1,6 +1,7 @@ name: Trunk on: + # trunk-ignore(yamllint/empty-values) workflow_call: concurrency: diff --git a/Cargo.lock b/Cargo.lock index e6d0845c..2e4d0a4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9135,9 +9135,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tungstenite" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e862a1c4128df0112ab625f55cd5c934bcb4312ba80b39ae4b4835a3fd58e649" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" dependencies = [ "byteorder", "bytes", From 3eb1927268d59a8f32f234288a4eba3532f9f0e5 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Tue, 3 Oct 2023 14:42:15 +0200 Subject: [PATCH 22/24] fix CI permissions --- .github/workflows/ci.yml | 6 +++++- .github/workflows/kakarot.yml | 3 +-- .github/workflows/test.yml | 3 +-- .github/workflows/trunk-check.yml | 6 ++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f662a5f2..538d0813 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,4 @@ --- -permissions: read-all name: Workflow - CI on: @@ -9,10 +8,15 @@ on: branches: - main +permissions: read-all + jobs: trunk: name: Trunk uses: ./.github/workflows/trunk-check.yml + permissions: + checks: write + contents: read submodules: name: Compile Kakarot contracts diff --git a/.github/workflows/kakarot.yml b/.github/workflows/kakarot.yml index 1b2365d5..16198ddb 100644 --- a/.github/workflows/kakarot.yml +++ b/.github/workflows/kakarot.yml @@ -1,8 +1,7 @@ name: Kakarot compilation caching on: - # trunk-ignore(yamllint/empty-values) - workflow_call: + workflow_call: {} permissions: read-all diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 49151c58..c92582cb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,8 +1,7 @@ name: test on: - # trunk-ignore(yamllint/empty-values) - workflow_call: + workflow_call: {} permissions: read-all diff --git a/.github/workflows/trunk-check.yml b/.github/workflows/trunk-check.yml index 2d71764b..556d70e3 100644 --- a/.github/workflows/trunk-check.yml +++ b/.github/workflows/trunk-check.yml @@ -1,19 +1,17 @@ name: Trunk on: - # trunk-ignore(yamllint/empty-values) - workflow_call: + workflow_call: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }}-trunk cancel-in-progress: true -permissions: read-all - jobs: trunk_check: name: Trunk Check Runner runs-on: ubuntu-latest + # trunk-ignore(checkov/CKV2_GHA_1) permissions: checks: write # For trunk to post annotations contents: read # For repo checkout From 873d1129860f167c618540859a535f5e9e51e784 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Tue, 3 Oct 2023 16:23:13 +0200 Subject: [PATCH 23/24] update trunk timeout --- .trunk/trunk.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 5ab7ff9b..7f19224c 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -20,6 +20,7 @@ lint: cargo clippy --message-format json --locked --workspace --all-features --all-targets -- --cap-lints=warn --no-deps -D warnings + run_timeout: 20m enabled: - actionlint@1.6.26 - checkov@2.4.9 From 178bdd36b07501340fecd650ab0873968e87fb30 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Tue, 3 Oct 2023 16:57:03 +0200 Subject: [PATCH 24/24] fix clippy --- crates/ef-testing/src/evm_sequencer/setup.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ef-testing/src/evm_sequencer/setup.rs b/crates/ef-testing/src/evm_sequencer/setup.rs index e93f1d66..b85d261e 100644 --- a/crates/ef-testing/src/evm_sequencer/setup.rs +++ b/crates/ef-testing/src/evm_sequencer/setup.rs @@ -124,7 +124,7 @@ impl EvmState for KakarotSequencer { let balance_keys = [balance_keys.0, balance_keys.1]; let balance_storage = &mut balance_keys .into_iter() - .zip(balance_values.into_iter()) + .zip(balance_values) .map(|(k, v)| (k, StarkFelt::from(v))) .collect(); storage.append(balance_storage);