Skip to content

Commit

Permalink
EVM: Add missing docs (#914)
Browse files Browse the repository at this point in the history
* rename pending_block to block_env

* make evm internals private

* refactor query.rs

* AccountData doc

* query.rs docs

* fix exports

* add missing docs

* cargo fmt

* Add readme

* Update README.md

* Update README.md

* better docs
  • Loading branch information
bkolad authored Sep 25, 2023
1 parent 3cebfd8 commit c24fc2f
Show file tree
Hide file tree
Showing 19 changed files with 171 additions and 96 deletions.
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

0 comments on commit c24fc2f

Please sign in to comment.