Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EVM: Add missing docs #914

Merged
merged 13 commits into from
Sep 25, 2023
2 changes: 1 addition & 1 deletion examples/demo-rollup/tests/evm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 2 additions & 3 deletions examples/demo-stf/src/hooks_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,12 @@ impl<C: Context, Da: DaSpec> SlotHooks<Da> for Runtime<C, Da> {
impl<C: Context, Da: sov_modules_api::DaSpec> FinalizeHook<Da> for Runtime<C, Da> {
type Context = C;

fn finalize_slot_hook(
fn finalize_hook(
&self,
#[allow(unused_variables)] root_hash: &<<Self::Context as Spec>::Storage as Storage>::Root,
#[allow(unused_variables)] accessory_working_set: &mut AccessoryWorkingSet<C>,
) {
#[cfg(feature = "experimental")]
self.evm
.finalize_slot_hook(root_hash, accessory_working_set);
self.evm.finalize_hook(root_hash, accessory_working_set);
}
}
12 changes: 5 additions & 7 deletions full-node/sov-ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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};
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl<C: Context, Da: DaSpec> SlotHooks<Da> for TestRuntime<C, Da> {
impl<C: Context, Da: sov_modules_api::DaSpec> FinalizeHook<Da> for TestRuntime<C, Da> {
type Context = C;

fn finalize_slot_hook(
fn finalize_hook(
&self,
_root_hash: &<<Self::Context as Spec>::Storage as Storage>::Root,
_accesorry_working_set: &mut AccessoryWorkingSet<C>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<C: Context, Da: sov_modules_api::DaSpec> SlotHooks<Da> for ChainState<C, Da
impl<C: Context, Da: sov_modules_api::DaSpec> FinalizeHook<Da> for ChainState<C, Da> {
type Context = C;

fn finalize_slot_hook(
fn finalize_hook(
&self,
_root_hash: &<C::Storage as Storage>::Root,
_accesorry_working_set: &mut AccessoryWorkingSet<C>,
Expand Down
5 changes: 5 additions & 0 deletions module-system/module-implementations/sov-evm/README.md
Original file line number Diff line number Diff line change
@@ -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.
5 changes: 4 additions & 1 deletion module-system/module-implementations/sov-evm/src/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand All @@ -30,7 +33,7 @@ impl<C: sov_modules_api::Context> Evm<C> {
) -> Result<CallResponse> {
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");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl From<TransactionSignedAndRecovered> 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(),
Expand Down
5 changes: 3 additions & 2 deletions module-system/module-implementations/sov-evm/src/evm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,16 @@ pub(crate) struct Receipt {
pub(crate) error: Option<EVMError<u8>>,
}

/// 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,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl<C: sov_modules_api::Context> Evm<C> {
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,
Expand Down
33 changes: 21 additions & 12 deletions module-system/module-implementations/sov-evm/src/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@ impl<C: sov_modules_api::Context> Evm<C>
where
<C::Storage as Storage>::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<C>) {
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,
Expand All @@ -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<C>) {
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");

Expand All @@ -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<PendingTransaction> =
Expand All @@ -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(),
Expand All @@ -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(),
Expand Down Expand Up @@ -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: &<<C as Spec>::Storage as Storage>::Root,
accesorry_working_set: &mut AccessoryWorkingSet<C>,
Expand Down
Loading