diff --git a/examples/demo-rollup/tests/evm/mod.rs b/examples/demo-rollup/tests/evm/mod.rs index c164942f0..8141c4ddd 100644 --- a/examples/demo-rollup/tests/evm/mod.rs +++ b/examples/demo-rollup/tests/evm/mod.rs @@ -12,7 +12,7 @@ use ethers_signers::{LocalWallet, Signer, Wallet}; use jsonrpsee::core::client::ClientT; use jsonrpsee::http_client::{HttpClient, HttpClientBuilder}; use jsonrpsee::rpc_params; -use sov_evm::smart_contracts::SimpleStorageContract; +use sov_evm::SimpleStorageContract; use sov_risc0_adapter::host::Risc0Host; use super::test_helpers::start_rollup; diff --git a/examples/demo-stf/src/hooks_impl.rs b/examples/demo-stf/src/hooks_impl.rs index 156566a73..c3f55d754 100644 --- a/examples/demo-stf/src/hooks_impl.rs +++ b/examples/demo-stf/src/hooks_impl.rs @@ -104,13 +104,12 @@ impl SlotHooks for Runtime { impl FinalizeHook for Runtime { type Context = C; - fn finalize_slot_hook( + fn finalize_hook( &self, #[allow(unused_variables)] root_hash: &<::Storage as Storage>::Root, #[allow(unused_variables)] accessory_working_set: &mut AccessoryWorkingSet, ) { #[cfg(feature = "experimental")] - self.evm - .finalize_slot_hook(root_hash, accessory_working_set); + self.evm.finalize_hook(root_hash, accessory_working_set); } } diff --git a/full-node/sov-ethereum/src/lib.rs b/full-node/sov-ethereum/src/lib.rs index 53e26c90a..21b460e04 100644 --- a/full-node/sov-ethereum/src/lib.rs +++ b/full-node/sov-ethereum/src/lib.rs @@ -3,7 +3,7 @@ mod batch_builder; #[cfg(feature = "experimental")] pub use experimental::{get_ethereum_rpc, Ethereum}; #[cfg(feature = "experimental")] -pub use sov_evm::signer::DevSigner; +pub use sov_evm::DevSigner; #[cfg(feature = "experimental")] pub mod experimental { @@ -21,9 +21,7 @@ pub mod experimental { Address as RethAddress, TransactionSignedNoHash as RethTransactionSignedNoHash, }; use reth_rpc_types::{TransactionRequest, TypedTransactionRequest}; - use sov_evm::call::CallMessage; - use sov_evm::evm::RlpEvmTransaction; - use sov_evm::Evm; + use sov_evm::{CallMessage, Evm, RlpEvmTransaction}; use sov_modules_api::transaction::Transaction; use sov_modules_api::utils::to_jsonrpsee_error_object; use sov_modules_api::{EncodeCall, WorkingSet}; @@ -93,9 +91,9 @@ pub mod experimental { let signed_transaction: RethTransactionSignedNoHash = raw_tx.clone().try_into()?; let tx_hash = signed_transaction.hash(); - let sender = signed_transaction.recover_signer().ok_or( - sov_evm::evm::primitive_types::RawEvmTxConversionError::FailedToRecoverSigner, - )?; + let sender = signed_transaction + .recover_signer() + .ok_or(sov_evm::RawEvmTxConversionError::FailedToRecoverSigner)?; let mut nonces = self.nonces.lock().unwrap(); let nonce = *nonces.entry(sender).and_modify(|n| *n += 1).or_insert(0); diff --git a/module-system/module-implementations/integration-tests/src/chain_state/helpers.rs b/module-system/module-implementations/integration-tests/src/chain_state/helpers.rs index 0e0ac03c4..8405b2568 100644 --- a/module-system/module-implementations/integration-tests/src/chain_state/helpers.rs +++ b/module-system/module-implementations/integration-tests/src/chain_state/helpers.rs @@ -85,7 +85,7 @@ impl SlotHooks for TestRuntime { impl FinalizeHook for TestRuntime { type Context = C; - fn finalize_slot_hook( + fn finalize_hook( &self, _root_hash: &<::Storage as Storage>::Root, _accesorry_working_set: &mut AccessoryWorkingSet, diff --git a/module-system/module-implementations/sov-chain-state/src/hooks.rs b/module-system/module-implementations/sov-chain-state/src/hooks.rs index 07d99231a..f94110662 100644 --- a/module-system/module-implementations/sov-chain-state/src/hooks.rs +++ b/module-system/module-implementations/sov-chain-state/src/hooks.rs @@ -64,7 +64,7 @@ impl SlotHooks for ChainState FinalizeHook for ChainState { type Context = C; - fn finalize_slot_hook( + fn finalize_hook( &self, _root_hash: &::Root, _accesorry_working_set: &mut AccessoryWorkingSet, diff --git a/module-system/module-implementations/sov-evm/README.md b/module-system/module-implementations/sov-evm/README.md new file mode 100644 index 000000000..8c29e3b27 --- /dev/null +++ b/module-system/module-implementations/sov-evm/README.md @@ -0,0 +1,5 @@ +# `sov-evm` module + +The sov-evm module provides compatibility with the EVM. + +The module `CallMessage` contains `rlp` encoded Ethereum transaction, which is validated & executed immediately after being dispatched from the DA. Once all transactions from the DA slot have been processed, they are grouped into an `Ethereum` block. Users can access information such as receipts, blocks, transactions, and more through standard Ethereum endpoints. diff --git a/module-system/module-implementations/sov-evm/src/call.rs b/module-system/module-implementations/sov-evm/src/call.rs index da89f0f1d..09bbf879b 100644 --- a/module-system/module-implementations/sov-evm/src/call.rs +++ b/module-system/module-implementations/sov-evm/src/call.rs @@ -16,8 +16,11 @@ use crate::Evm; derive(serde::Serialize), derive(serde::Deserialize) )] + +/// EVM call message. #[derive(borsh::BorshDeserialize, borsh::BorshSerialize, Debug, PartialEq, Clone)] pub struct CallMessage { + /// RLP encoded transaction. pub tx: RlpEvmTransaction, } @@ -30,7 +33,7 @@ impl Evm { ) -> Result { let evm_tx_recovered: TransactionSignedEcRecovered = tx.try_into()?; let block_env = self - .pending_block + .block_env .get(working_set) .expect("Pending block must be set"); diff --git a/module-system/module-implementations/sov-evm/src/evm/conversions.rs b/module-system/module-implementations/sov-evm/src/evm/conversions.rs index bdc40594a..d63fb4adf 100644 --- a/module-system/module-implementations/sov-evm/src/evm/conversions.rs +++ b/module-system/module-implementations/sov-evm/src/evm/conversions.rs @@ -117,7 +117,7 @@ impl From for TransactionSignedEcRecovered { // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/576 // https://github.com/paradigmxyz/reth/blob/d8677b4146f77c7c82d659c59b79b38caca78778/crates/rpc/rpc/src/eth/revm_utils.rs#L201 -pub fn prepare_call_env(request: CallRequest) -> TxEnv { +pub(crate) fn prepare_call_env(request: CallRequest) -> TxEnv { TxEnv { caller: request.from.unwrap(), gas_limit: request.gas.map(|p| p.try_into().unwrap()).unwrap(), diff --git a/module-system/module-implementations/sov-evm/src/evm/mod.rs b/module-system/module-implementations/sov-evm/src/evm/mod.rs index 0d28d5e40..e8db4432e 100644 --- a/module-system/module-implementations/sov-evm/src/evm/mod.rs +++ b/module-system/module-implementations/sov-evm/src/evm/mod.rs @@ -9,11 +9,11 @@ pub(crate) mod db; mod db_commit; pub(crate) mod db_init; pub(crate) mod executor; -pub mod primitive_types; +pub(crate) mod primitive_types; #[cfg(test)] mod tests; -pub use conversions::prepare_call_env; +pub(crate) use conversions::prepare_call_env; pub use primitive_types::RlpEvmTransaction; use sov_state::codec::BcsCodec; @@ -83,6 +83,7 @@ pub struct EvmChainConfig { /// Delta to add to parent block timestamp pub block_timestamp_delta: u64, + /// Base fee params. pub base_fee_params: BaseFeeParams, } diff --git a/module-system/module-implementations/sov-evm/src/evm/primitive_types.rs b/module-system/module-implementations/sov-evm/src/evm/primitive_types.rs index 232773151..4dcb6427b 100644 --- a/module-system/module-implementations/sov-evm/src/evm/primitive_types.rs +++ b/module-system/module-implementations/sov-evm/src/evm/primitive_types.rs @@ -107,12 +107,16 @@ pub(crate) struct Receipt { pub(crate) error: Option>, } +/// Tx conversion error. #[derive(Error, Debug)] pub enum RawEvmTxConversionError { + /// Transaction is empty, #[error("Empty raw transaction data")] EmptyRawTransactionData, + /// Decoding error. #[error("Failed to decode signed transaction")] FailedToDecodeSignedTransaction, + /// Unable to recover signer. #[error("Failed to recover signer")] FailedToRecoverSigner, } diff --git a/module-system/module-implementations/sov-evm/src/genesis.rs b/module-system/module-implementations/sov-evm/src/genesis.rs index bc74a8267..bebd4c6ae 100644 --- a/module-system/module-implementations/sov-evm/src/genesis.rs +++ b/module-system/module-implementations/sov-evm/src/genesis.rs @@ -69,7 +69,7 @@ impl Evm { parent_hash: H256::default(), ommers_hash: EMPTY_OMMER_ROOT, beneficiary: config.coinbase, - // This will be set in finalize_slot_hook or in the next begin_slot_hook + // This will be set in finalize_hook or in the next begin_slot_hook state_root: KECCAK_EMPTY, transactions_root: EMPTY_TRANSACTIONS, receipts_root: EMPTY_RECEIPTS, diff --git a/module-system/module-implementations/sov-evm/src/hooks.rs b/module-system/module-implementations/sov-evm/src/hooks.rs index 4add37213..ad0c28427 100644 --- a/module-system/module-implementations/sov-evm/src/hooks.rs +++ b/module-system/module-implementations/sov-evm/src/hooks.rs @@ -10,17 +10,19 @@ impl Evm where ::Root: Into<[u8; 32]>, { + /// Logic executed at the beginning of the slot. Here we set the root hash of the previous head. pub fn begin_slot_hook(&self, da_root_hash: [u8; 32], working_set: &mut WorkingSet) { let parent_block = self .head .get(working_set) .expect("Head block should always be set"); + // TODO // parent_block.header.state_root = root_hash.into(); // self.head.set(&parent_block, working_set); let cfg = self.cfg.get(working_set).unwrap_or_default(); - let new_pending_block = BlockEnv { + let new_pending_env = BlockEnv { number: parent_block.header.number + 1, coinbase: cfg.coinbase, timestamp: parent_block.header.timestamp + cfg.block_timestamp_delta, @@ -31,14 +33,16 @@ where .unwrap(), gas_limit: cfg.block_gas_limit, }; - self.pending_block.set(&new_pending_block, working_set); + self.block_env.set(&new_pending_env, working_set); } + /// Logic executed at the end of the slot. Here, we generate an authenticated block and set it as the new head of the chain. + /// It's important to note that the state root hash is not known at this moment, so we postpone setting this field until the begin_slot_hook of the next slot. pub fn end_slot_hook(&self, working_set: &mut WorkingSet) { let cfg = self.cfg.get(working_set).unwrap_or_default(); - let pending_block = self - .pending_block + let block_env = self + .block_env .get(working_set) .expect("Pending block should always be set"); @@ -50,9 +54,9 @@ where let expected_block_number = parent_block.header.number + 1; assert_eq!( - pending_block.number, expected_block_number, + block_env.number, expected_block_number, "Pending head must be set to block {}, but found block {}", - expected_block_number, pending_block.number + expected_block_number, block_env.number ); let pending_transactions: Vec = @@ -78,11 +82,11 @@ where let header = reth_primitives::Header { parent_hash: parent_block.header.hash, - timestamp: pending_block.timestamp, - number: pending_block.number, + timestamp: block_env.timestamp, + number: block_env.number, ommers_hash: reth_primitives::constants::EMPTY_OMMER_ROOT, beneficiary: parent_block.header.beneficiary, - // This will be set in finalize_slot_hook or in the next begin_slot_hook + // This will be set in finalize_hook or in the next begin_slot_hook state_root: reth_primitives::constants::KECCAK_EMPTY, transactions_root: reth_primitives::proofs::calculate_transaction_root( transactions.as_slice(), @@ -93,9 +97,9 @@ where .iter() .fold(Bloom::zero(), |bloom, r| bloom | r.bloom), difficulty: U256::ZERO, - gas_limit: pending_block.gas_limit, + gas_limit: block_env.gas_limit, gas_used, - mix_hash: pending_block.prevrandao, + mix_hash: block_env.prevrandao, nonce: 0, base_fee_per_gas: parent_block.header.next_block_base_fee(cfg.base_fee_params), extra_data: Bytes::default(), @@ -139,7 +143,12 @@ where self.pending_transactions.clear(working_set); } - pub fn finalize_slot_hook( + /// This logic is executed after calculating the root hash. + /// At this point, it is impossible to alter state variables because the state root is fixed. + /// However, non-state data can be modified. + /// This function's purpose is to add the block to the (non-authenticated) blocks structure, + /// enabling block-related RPC queries. + pub fn finalize_hook( &self, root_hash: &<::Storage as Storage>::Root, accesorry_working_set: &mut AccessoryWorkingSet, diff --git a/module-system/module-implementations/sov-evm/src/lib.rs b/module-system/module-implementations/sov-evm/src/lib.rs index 72d53d582..44b70d2b8 100644 --- a/module-system/module-implementations/sov-evm/src/lib.rs +++ b/module-system/module-implementations/sov-evm/src/lib.rs @@ -1,11 +1,15 @@ +#![deny(missing_docs)] +#![doc = include_str!("../README.md")] #[cfg(feature = "experimental")] -pub mod call; +mod call; #[cfg(feature = "experimental")] -pub mod evm; +mod evm; #[cfg(feature = "experimental")] -pub mod genesis; +mod genesis; #[cfg(feature = "experimental")] -pub mod hooks; +mod hooks; +#[cfg(feature = "experimental")] +pub use {call::*, evm::*, genesis::*, hooks::*, primitive_types::RawEvmTxConversionError}; #[cfg(feature = "native")] #[cfg(feature = "experimental")] mod query; @@ -13,9 +17,13 @@ mod query; #[cfg(feature = "experimental")] pub use query::*; #[cfg(feature = "experimental")] -pub mod signer; +mod signer; +#[cfg(feature = "experimental")] +pub use signer::DevSigner; #[cfg(feature = "smart_contracts")] -pub mod smart_contracts; +mod smart_contracts; +#[cfg(feature = "smart_contracts")] +pub use smart_contracts::SimpleStorageContract; #[cfg(feature = "experimental")] #[cfg(test)] mod tests; @@ -38,36 +46,56 @@ mod experimental { use crate::evm::primitive_types::{ Block, BlockEnv, Receipt, SealedBlock, TransactionSignedAndRecovered, }; + + /// Evm account. #[derive(Clone, Debug)] pub struct AccountData { + /// Account address. pub address: Address, + /// Account balance. pub balance: U256, + /// Code hash. pub code_hash: H256, + /// Smart contract code. pub code: Bytes, + /// Account nonce. pub nonce: u64, } impl AccountData { + /// Empty code hash. pub fn empty_code() -> H256 { KECCAK_EMPTY } + /// Account balance. pub fn balance(balance: u64) -> U256 { U256::from(balance) } } + /// Genesis configuration. #[derive(Clone, Debug)] pub struct EvmConfig { + /// Genesis accounts. pub data: Vec, + /// Chain id. pub chain_id: u64, + /// Limits size of contract code size. pub limit_contract_code_size: Option, + /// List of EVM hardforks by block number pub spec: HashMap, + /// Coinbase where all the fees go pub coinbase: Address, + /// Starting base fee. pub starting_base_fee: u64, + /// Gas limit for single block pub block_gas_limit: u64, + /// Genesis timestamp. pub genesis_timestamp: u64, + /// Delta to add to parent block timestamp, pub block_timestamp_delta: u64, + /// Base fee params. pub base_fee_params: reth_primitives::BaseFeeParams, } @@ -94,50 +122,69 @@ mod experimental { } } + /// The sov-evm module provides compatibility with the EVM. #[allow(dead_code)] // #[cfg_attr(feature = "native", derive(sov_modules_api::ModuleCallJsonSchema))] #[derive(ModuleInfo, Clone)] pub struct Evm { + /// The address of the evm module. #[address] pub(crate) address: C::Address, + /// Mapping from account address to account state. #[state] pub(crate) accounts: sov_modules_api::StateMap, + /// Mapping from code hash to code. Used for lazy-loading code into a contract account. #[state] pub(crate) code: sov_modules_api::StateMap, + /// Chain configuration. This field is set in genesis. #[state] pub(crate) cfg: sov_modules_api::StateValue, + /// Block environment used by the evm. This field is set in `begin_slot_hook`. #[state] - pub(crate) pending_block: sov_modules_api::StateValue, + pub(crate) block_env: sov_modules_api::StateValue, + /// Transactions that will be added to the current block. + /// A valid transaction is added to the vec on every call message. #[state] pub(crate) pending_transactions: sov_modules_api::StateVec, + /// Head of the chain. The new head is set in `end_slot_hook` but without the inclusion of the `state_root` field. + /// The `state_root` is added in `begin_slot_hook` of the next block because its calculation occurs after the `end_slot_hook`. #[state] pub(crate) head: sov_modules_api::StateValue, + /// Used only by the RPC: This represents the head of the chain and is set in two distinct stages: + /// 1. `end_slot_hook`: the pending head is populated with data from pending_transactions. + /// 2. `finalize_hook` the `root_hash` is populated. + /// Since this value is not authenticated, it can be modified in the `finalize_hook` with the correct `state_root`. #[state] pub(crate) pending_head: sov_modules_api::AccessoryStateValue, + /// Used only by the RPC: The vec is extended with `pending_head` in `finalize_hook`. #[state] pub(crate) blocks: sov_modules_api::AccessoryStateVec, + /// Used only by the RPC: block_hash => block_number mapping, #[state] pub(crate) block_hashes: sov_modules_api::AccessoryStateMap, + /// Used only by the RPC: List of processed transactions. #[state] pub(crate) transactions: sov_modules_api::AccessoryStateVec, + /// Used only by the RPC: transaction_hash => transaction_index mapping. #[state] pub(crate) transaction_hashes: sov_modules_api::AccessoryStateMap, + /// Used only by the RPC: Receipts. #[state] pub(crate) receipts: sov_modules_api::AccessoryStateVec, } diff --git a/module-system/module-implementations/sov-evm/src/query.rs b/module-system/module-implementations/sov-evm/src/query.rs index 5df95006f..65b02711a 100644 --- a/module-system/module-implementations/sov-evm/src/query.rs +++ b/module-system/module-implementations/sov-evm/src/query.rs @@ -15,51 +15,7 @@ use crate::Evm; #[rpc_gen(client, server, namespace = "eth")] impl Evm { - fn get_cfg_env_template(&self) -> revm::primitives::CfgEnv { - let mut cfg_env = revm::primitives::CfgEnv::default(); - // Reth sets this to true and uses only timeout, but other clients use this as a part of DOS attacks protection, with 100mln gas limit - // https://github.com/paradigmxyz/reth/blob/62f39a5a151c5f4ddc9bf0851725923989df0412/crates/rpc/rpc/src/eth/revm_utils.rs#L215 - cfg_env.disable_block_gas_limit = false; - cfg_env.disable_eip3607 = true; - cfg_env.disable_base_fee = true; - cfg_env.chain_id = 0; - // https://github.com/Sovereign-Labs/sovereign-sdk/issues/912 - cfg_env.spec_id = revm::primitives::SpecId::SHANGHAI; - cfg_env.perf_analyse_created_bytecodes = revm::primitives::AnalysisKind::Analyse; - cfg_env.limit_contract_code_size = None; - cfg_env - } - - fn get_sealed_block_by_number( - &self, - block_number: Option, - working_set: &mut WorkingSet, - ) -> SealedBlock { - // safe, finalized, and pending are not supported - match block_number { - Some(ref block_number) if block_number == "earliest" => self - .blocks - .get(0, &mut working_set.accessory_state()) - .expect("Genesis block must be set"), - Some(ref block_number) if block_number == "latest" => self - .blocks - .last(&mut working_set.accessory_state()) - .expect("Head block must be set"), - Some(ref block_number) => { - let block_number = block_number.strip_prefix("0x").unwrap_or(block_number); - let block_number = - usize::from_str_radix(block_number, 16).expect("Block number must be hex"); - self.blocks - .get(block_number, &mut working_set.accessory_state()) - .expect("Block must be set") - } - None => self - .blocks - .last(&mut working_set.accessory_state()) - .expect("Head block must be set"), - } - } - + /// Handler for: `eth_chainId` #[rpc_method(name = "chainId")] pub fn chain_id( &self, @@ -77,6 +33,7 @@ impl Evm { Ok(Some(chain_id)) } + /// Handler for: `eth_getBlockByNumber` #[rpc_method(name = "getBlockByNumber")] pub fn get_block_by_number( &self, @@ -136,6 +93,7 @@ impl Evm { Ok(Some(block.into())) } + /// Handler for: `eth_getTransactionCount` #[rpc_method(name = "getTransactionCount")] pub fn get_transaction_count( &self, @@ -157,6 +115,7 @@ impl Evm { Ok(nonce.into()) } + /// Handler for: `eth_feeHistory` // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/502 #[rpc_method(name = "feeHistory")] pub fn fee_history( @@ -172,6 +131,7 @@ impl Evm { }) } + /// Handler for: `eth_getTransactionByHash` // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/502 #[rpc_method(name = "getTransactionByHash")] pub fn get_transaction_by_hash( @@ -212,6 +172,7 @@ impl Evm { Ok(transaction) } + /// Handler for: `eth_getTransactionReceipt` // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/502 #[rpc_method(name = "getTransactionReceipt")] pub fn get_transaction_receipt( @@ -246,9 +207,9 @@ impl Evm { Ok(receipt) } - //https://github.com/paradigmxyz/reth/blob/f577e147807a783438a3f16aad968b4396274483/crates/rpc/rpc/src/eth/api/transactions.rs#L502 - //https://github.com/paradigmxyz/reth/blob/main/crates/rpc/rpc-types/src/eth/call.rs#L7 - + /// Handler for: `eth_call` + // https://github.com/paradigmxyz/reth/blob/f577e147807a783438a3f16aad968b4396274483/crates/rpc/rpc/src/eth/api/transactions.rs#L502 + // https://github.com/paradigmxyz/reth/blob/main/crates/rpc/rpc-types/src/eth/call.rs#L7 // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/502 #[rpc_method(name = "call")] pub fn get_call( @@ -262,9 +223,9 @@ impl Evm { info!("evm module: eth_call"); let tx_env = prepare_call_env(request); - let block_env = self.pending_block.get(working_set).unwrap_or_default(); + let block_env = self.block_env.get(working_set).unwrap_or_default(); let cfg = self.cfg.get(working_set).unwrap_or_default(); - let cfg_env = get_cfg_env(&block_env, cfg, Some(self.get_cfg_env_template())); + let cfg_env = get_cfg_env(&block_env, cfg, Some(get_cfg_env_template())); let evm_db: EvmDb<'_, C> = self.get_db(working_set); @@ -277,6 +238,7 @@ impl Evm { Ok(output.into_data().into()) } + /// Handler for: `eth_blockNumber` #[rpc_method(name = "blockNumber")] pub fn block_number( &self, @@ -292,6 +254,7 @@ impl Evm { Ok(block_number) } + /// Handler for: `eth_estimateGas` // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/502 #[rpc_method(name = "estimateGas")] pub fn eth_estimate_gas( @@ -300,16 +263,61 @@ impl Evm { _block_number: Option, _working_set: &mut WorkingSet, ) -> RpcResult { - unimplemented!("eth_sendTransaction not implemented") + unimplemented!("eth_estimateGas not implemented") } + /// Handler for: `eth_gasPrice` // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/502 #[rpc_method(name = "gasPrice")] - pub fn gas_price(&self) -> RpcResult { - unimplemented!("eth_sendTransaction not implemented") + pub fn gas_price(&self, _working_set: &mut WorkingSet) -> RpcResult { + unimplemented!("eth_gasPrice not implemented") + } + + fn get_sealed_block_by_number( + &self, + block_number: Option, + working_set: &mut WorkingSet, + ) -> SealedBlock { + // safe, finalized, and pending are not supported + match block_number { + Some(ref block_number) if block_number == "earliest" => self + .blocks + .get(0, &mut working_set.accessory_state()) + .expect("Genesis block must be set"), + Some(ref block_number) if block_number == "latest" => self + .blocks + .last(&mut working_set.accessory_state()) + .expect("Head block must be set"), + Some(ref block_number) => { + let block_number = + usize::from_str_radix(block_number, 16).expect("Block number must be hex"); + self.blocks + .get(block_number, &mut working_set.accessory_state()) + .expect("Block must be set") + } + None => self + .blocks + .last(&mut working_set.accessory_state()) + .expect("Head block must be set"), + } } } +fn get_cfg_env_template() -> revm::primitives::CfgEnv { + let mut cfg_env = revm::primitives::CfgEnv::default(); + // Reth sets this to true and uses only timeout, but other clients use this as a part of DOS attacks protection, with 100mln gas limit + // https://github.com/paradigmxyz/reth/blob/62f39a5a151c5f4ddc9bf0851725923989df0412/crates/rpc/rpc/src/eth/revm_utils.rs#L215 + cfg_env.disable_block_gas_limit = false; + cfg_env.disable_eip3607 = true; + cfg_env.disable_base_fee = true; + cfg_env.chain_id = 0; + // https://github.com/Sovereign-Labs/sovereign-sdk/issues/912 + cfg_env.spec_id = revm::primitives::SpecId::SHANGHAI; + cfg_env.perf_analyse_created_bytecodes = revm::primitives::AnalysisKind::Analyse; + cfg_env.limit_contract_code_size = None; + cfg_env +} + // modified from: https://github.com/paradigmxyz/reth/blob/cc576bc8690a3e16e6e5bf1cbbbfdd029e85e3d4/crates/rpc/rpc/src/eth/api/transactions.rs#L849 pub(crate) fn build_rpc_receipt( block: SealedBlock, diff --git a/module-system/module-implementations/sov-evm/src/signer/mod.rs b/module-system/module-implementations/sov-evm/src/signer/mod.rs index c98fde337..66f177f7e 100644 --- a/module-system/module-implementations/sov-evm/src/signer/mod.rs +++ b/module-system/module-implementations/sov-evm/src/signer/mod.rs @@ -57,6 +57,7 @@ impl DevSigner { )) } + /// List of signers. pub fn signers(&self) -> Vec
{ self.signers.keys().copied().collect() } diff --git a/module-system/module-implementations/sov-evm/src/tests/genesis_tests.rs b/module-system/module-implementations/sov-evm/src/tests/genesis_tests.rs index 87ab67230..669c5e86f 100644 --- a/module-system/module-implementations/sov-evm/src/tests/genesis_tests.rs +++ b/module-system/module-implementations/sov-evm/src/tests/genesis_tests.rs @@ -219,7 +219,7 @@ pub(crate) fn get_evm(config: &EvmConfig) -> (Evm, WorkingSet let mut working_set = WorkingSet::new(ProverStorage::with_path(tmpdir.path()).unwrap()); let evm = Evm::::default(); evm.genesis(config, &mut working_set).unwrap(); - evm.finalize_slot_hook(&[10u8; 32].into(), &mut working_set.accessory_state()); + evm.finalize_hook(&[10u8; 32].into(), &mut working_set.accessory_state()); (evm, working_set) } diff --git a/module-system/module-implementations/sov-evm/src/tests/hooks_tests.rs b/module-system/module-implementations/sov-evm/src/tests/hooks_tests.rs index c27bb87c0..35174c414 100644 --- a/module-system/module-implementations/sov-evm/src/tests/hooks_tests.rs +++ b/module-system/module-implementations/sov-evm/src/tests/hooks_tests.rs @@ -20,7 +20,7 @@ lazy_static! { fn begin_slot_hook_creates_pending_block() { let (evm, mut working_set) = get_evm(&TEST_CONFIG); evm.begin_slot_hook(DA_ROOT_HASH.0, &mut working_set); - let pending_block = evm.pending_block.get(&mut working_set).unwrap(); + let pending_block = evm.block_env.get(&mut working_set).unwrap(); assert_eq!( pending_block, BlockEnv { @@ -193,7 +193,7 @@ fn finalize_hook_creates_final_block() { let mut accessory_state = working_set.accessory_state(); let root_hash = [99u8; 32].into(); - evm.finalize_slot_hook(&root_hash, &mut accessory_state); + evm.finalize_hook(&root_hash, &mut accessory_state); assert_eq!(evm.blocks.len(&mut accessory_state), 2); diff --git a/module-system/sov-modules-api/src/hooks.rs b/module-system/sov-modules-api/src/hooks.rs index ac6bf6325..bbb08bdc9 100644 --- a/module-system/sov-modules-api/src/hooks.rs +++ b/module-system/sov-modules-api/src/hooks.rs @@ -69,7 +69,7 @@ pub trait SlotHooks { pub trait FinalizeHook { type Context: Context; - fn finalize_slot_hook( + fn finalize_hook( &self, root_hash: &<::Storage as Storage>::Root, accesorry_working_set: &mut AccessoryWorkingSet, diff --git a/module-system/sov-modules-stf-template/src/lib.rs b/module-system/sov-modules-stf-template/src/lib.rs index efb25dfe7..f50825d76 100644 --- a/module-system/sov-modules-stf-template/src/lib.rs +++ b/module-system/sov-modules-stf-template/src/lib.rs @@ -126,7 +126,7 @@ where let mut working_set = checkpoint.to_revertable(); self.runtime - .finalize_slot_hook(&root_hash, &mut working_set.accessory_state()); + .finalize_hook(&root_hash, &mut working_set.accessory_state()); let accessory_log = working_set.checkpoint().freeze_non_provable(); @@ -174,7 +174,7 @@ where let mut working_set = checkpoint.to_revertable(); self.runtime - .finalize_slot_hook(&genesis_hash, &mut working_set.accessory_state()); + .finalize_hook(&genesis_hash, &mut working_set.accessory_state()); let accessory_log = working_set.checkpoint().freeze_non_provable();