Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion config/stratus.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,14 @@ chain_id = 2008
# inspector_evms = 50
# Should reject contract transactions and calls to accounts that are not contracts?
# reject_not_contract = true

[executor.evm]
# EVM hardfork spec, e.g. Prague, Cancun, Shanghai.
# evm_spec = "Prague"
# spec = "Prague"
# Maximum gas limit applied when executing a transaction.
# transaction_max_gas_limit = 100000000
# Maximum gas limit applied when executing a call (eth_call and eth_estimateGas).
# call_max_gas_limit = 100000000

[miner]
# Target block time: `automine`, `external`, or a duration like `1s`.
Expand Down
6 changes: 5 additions & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,11 @@ e2e-stratus block-mode="automine" test="":
fi

just _log "Starting Stratus"
just stratus-test -a 0.0.0.0:3000 --block-mode {{block-mode}}
if [[ {{block-mode}} =~ ^[0-9]+(ms|s)$ ]]; then
just stratus-test -a 0.0.0.0:3000 --block-mode {{block-mode}} --executor-transaction-max-gas-limit 1000000000 --executor-call-max-gas-limit 1000000000
else
just stratus-test -a 0.0.0.0:3000 --block-mode {{block-mode}}
fi

just _log "Running E2E tests"
if [[ {{block-mode}} =~ ^[0-9]+(ms|s)$ ]]; then
Expand Down
14 changes: 11 additions & 3 deletions src/config/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,11 @@ mod tests {
call_past_evms = 2
inspector_evms = 3
reject_not_contract = false
evm_spec = "Cancun"

[executor.evm]
spec = "Cancun"
transaction_max_gas_limit = 100000000
call_max_gas_limit = 100000000

[miner]
block_mode = "1s"
Expand Down Expand Up @@ -576,7 +580,11 @@ mod tests {
call_past_evms = 2
inspector_evms = 3
reject_not_contract = false
evm_spec = "Cancun"

[executor.evm]
spec = "Cancun"
transaction_max_gas_limit = 100000000
call_max_gas_limit = 100000000

[miner]
block_mode = "1s"
Expand Down Expand Up @@ -673,7 +681,7 @@ mod tests {
assert_eq!(config.rpc_server.rpc_address.to_string(), "0.0.0.0:3001");
assert_eq!(config.rpc_server.rpc_max_response_size_bytes, 20971520);
assert_eq!(config.executor.executor_chain_id, 100);
assert_eq!(config.executor.executor_evm_spec.to_string(), "Cancun");
assert_eq!(config.executor.evm.spec.to_string(), "Cancun");
assert_eq!(config.miner.block_mode, MinerMode::Interval(std::time::Duration::from_secs(1)));
assert_eq!(config.exporter.async_threads, 2);
assert_eq!(config.exporter.blocking_threads, 32);
Expand Down
32 changes: 27 additions & 5 deletions src/eth/executor/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,27 @@ pub struct ExecutorConfig {
#[serde(rename = "reject_not_contract")]
pub executor_reject_not_contract: bool,

#[arg(id = "executor.evm_spec", long = "executor-evm-spec", default_value = "Prague", value_parser = parse_evm_spec)]
#[serde(rename = "evm_spec", with = "spec_id_serde")]
pub executor_evm_spec: SpecId,
#[clap(flatten)]
pub evm: EvmConfig,
}

#[derive(Parser, DebugAsJson, Clone, Copy, serde::Serialize)]
pub struct EvmConfig {
#[arg(id = "executor.evm.spec", long = "executor-evm-spec", default_value = "Prague", value_parser = parse_spec)]
Comment thread
carneiro-cw marked this conversation as resolved.
#[serde(with = "spec_id_serde")]
pub spec: SpecId,

/// Maximum gas limit applied when executing a transaction.
#[arg(
id = "executor.evm.transaction_max_gas_limit",
long = "executor-transaction-max-gas-limit",
default_value = "100000000"
Comment thread
carneiro-cw marked this conversation as resolved.
)]
pub transaction_max_gas_limit: u64,

/// Maximum gas limit applied when executing a call (eth_call and eth_estimateGas).
#[arg(id = "executor.evm.call_max_gas_limit", long = "executor-call-max-gas-limit", default_value = "100000000")]
pub call_max_gas_limit: u64,
}

#[cfg(test)]
Expand All @@ -52,7 +70,11 @@ impl Default for ExecutorConfig {
call_past_evms: 50,
inspector_evms: 50,
executor_reject_not_contract: true,
executor_evm_spec: SpecId::PRAGUE,
evm: EvmConfig {
spec: SpecId::PRAGUE,
transaction_max_gas_limit: 100_000_000,
call_max_gas_limit: 100_000_000,
},
}
}
}
Expand All @@ -76,7 +98,7 @@ fn parse_chain_id(input: &str) -> anyhow::Result<u64> {
Ok(chain_id)
}

fn parse_evm_spec(input: &str) -> anyhow::Result<SpecId> {
fn parse_spec(input: &str) -> anyhow::Result<SpecId> {
SpecId::from_str(input).map_err(|err| anyhow::anyhow!("unknown hard fork: {err:?}"))
}

Expand Down
26 changes: 17 additions & 9 deletions src/eth/executor/evm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub type RevmResultAndState = ExecResultAndState<RevmExecResult>;
pub struct Evm<Input: EvmInput> {
evm: GeneralRevm<RevmSession>,
kind: EvmKind,
max_gas_limit: u64,
_input_type: PhantomData<Input>,
}

Expand All @@ -62,9 +63,16 @@ impl<Input: EvmInput> Evm<Input> {
// configure revm
let chain_id = config.executor_chain_id;

// the inspector reexecutes and traces mined transactions, so it follows the transaction limit
let max_gas_limit = match kind {
EvmKind::Transaction | EvmKind::Inspect => config.evm.transaction_max_gas_limit,
EvmKind::CallPast | EvmKind::CallPresent => config.evm.call_max_gas_limit,
};

Self {
evm: create_evm(chain_id, config.executor_evm_spec, RevmSession::new(storage), kind),
evm: create_evm(chain_id, config.evm.spec, RevmSession::new(storage), kind),
kind,
max_gas_limit,
_input_type: PhantomData,
}
}
Expand All @@ -75,7 +83,7 @@ impl<Input: EvmInput> Evm<Input> {

// configure session
self.evm.journaled_state.database.reset(input.kind());
input.fill_env(&mut self.evm);
input.fill_env(&mut self.evm, self.max_gas_limit);

let tx = std::mem::take(&mut self.evm.tx);
let evm_result = self.evm.transact(tx);
Expand Down Expand Up @@ -159,7 +167,7 @@ impl Evm<TransactionExecutionInput> {
let tx_input: TransactionExecutionInput = tx.execution.input;

// Configure EVM state
evm.fill_env(tx_input);
evm.fill_env(tx_input, self.max_gas_limit);
let tx = std::mem::take(&mut evm.tx);
evm.transact_commit(tx)?;
}
Expand All @@ -168,7 +176,7 @@ impl Evm<TransactionExecutionInput> {
GethDebugTracerType::BuiltInTracer(GethDebugBuiltInTracerType::FourByteTracer) => {
let mut inspector = FourByteInspector::default();
let mut evm_with_inspector = evm.with_inspector(&mut inspector);
evm_with_inspector.fill_env(inspect_input);
evm_with_inspector.fill_env(inspect_input, self.max_gas_limit);
let tx = std::mem::take(&mut evm_with_inspector.tx);
evm_with_inspector.inspect_tx(tx)?;
FourByteFrame::from(&inspector).into()
Expand All @@ -177,7 +185,7 @@ impl Evm<TransactionExecutionInput> {
let call_config = opts.tracer_config.into_call_config()?;
let mut inspector = TracingInspector::new(TracingInspectorConfig::from_geth_call_config(&call_config));
let mut evm_with_inspector = evm.with_inspector(&mut inspector);
evm_with_inspector.fill_env(inspect_input);
evm_with_inspector.fill_env(inspect_input, self.max_gas_limit);
let tx = std::mem::take(&mut evm_with_inspector.tx);
let res = evm_with_inspector.inspect_tx(tx)?;
let mut trace = inspector.geth_builder().geth_call_traces(call_config, res.result.tx_gas_used()).into();
Expand All @@ -188,7 +196,7 @@ impl Evm<TransactionExecutionInput> {
let prestate_config = opts.tracer_config.into_pre_state_config()?;
let mut inspector = TracingInspector::new(TracingInspectorConfig::from_geth_prestate_config(&prestate_config));
let mut evm_with_inspector = evm.with_inspector(&mut inspector);
evm_with_inspector.fill_env(inspect_input);
evm_with_inspector.fill_env(inspect_input, self.max_gas_limit);
let tx = std::mem::take(&mut evm_with_inspector.tx);
let res = evm_with_inspector.inspect_tx(tx)?;

Expand All @@ -199,7 +207,7 @@ impl Evm<TransactionExecutionInput> {
let mux_config = opts.tracer_config.into_mux_config()?;
let mut inspector = MuxInspector::try_from_config(mux_config).map_err(|e| anyhow!(e))?;
let mut evm_with_inspector = evm.with_inspector(&mut inspector);
evm_with_inspector.fill_env(inspect_input);
evm_with_inspector.fill_env(inspect_input, self.max_gas_limit);
let tx = std::mem::take(&mut evm_with_inspector.tx);
let res = evm_with_inspector.inspect_tx(tx)?;
inspector.try_into_mux_frame(&res, &cache_db, tx_info)?.into()
Expand All @@ -208,7 +216,7 @@ impl Evm<TransactionExecutionInput> {
let flat_call_config = opts.tracer_config.into_flat_call_config()?;
let mut inspector = TracingInspector::new(TracingInspectorConfig::from_flat_call_config(&flat_call_config));
let mut evm_with_inspector = evm.with_inspector(&mut inspector);
evm_with_inspector.fill_env(inspect_input);
evm_with_inspector.fill_env(inspect_input, self.max_gas_limit);
let tx = std::mem::take(&mut evm_with_inspector.tx);
let res = evm_with_inspector.inspect_tx(tx)?;
inspector
Expand All @@ -220,7 +228,7 @@ impl Evm<TransactionExecutionInput> {
GethDebugTracerType::JsTracer(code) => {
let mut inspector = JsInspector::new(code, opts.tracer_config.into_json()).map_err(|e| anyhow!(e.to_string()))?;
let mut evm_with_inspector = evm.with_inspector(&mut inspector);
evm_with_inspector.fill_env(inspect_input);
evm_with_inspector.fill_env(inspect_input, self.max_gas_limit);
let tx = std::mem::take(&mut evm_with_inspector.tx);
let block = std::mem::take(&mut evm_with_inspector.block);
let res = evm_with_inspector.inspect_tx(tx.clone())?;
Expand Down
5 changes: 2 additions & 3 deletions src/eth/executor/evm/types/input/call_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use revm::context::TransactTo;

use crate::eth::executor::evm::types::EvmInput;
use crate::eth::executor::evm::types::ExecutionMetricsContext;
use crate::eth::executor::evm::types::GAS_MAX_LIMIT;
use crate::eth::executor::evm::types::GeneralRevm;
use crate::eth::storage::ExecutionKind;
use crate::eth::types::Address;
Expand Down Expand Up @@ -80,13 +79,13 @@ impl EvmInput for CallExecutionInput {
evm.block.basefee = 0;
}

fn fill_tx_env<DB: Database, I>(self, evm: &mut GeneralRevm<DB, I>) {
fn fill_tx_env<DB: Database, I>(self, evm: &mut GeneralRevm<DB, I>, gas_limit: u64) {
evm.tx.caller = self.from.into();
evm.tx.kind = match self.to {
Some(contract) => TransactTo::Call(contract.into()),
None => TransactTo::Create,
};
evm.tx.gas_limit = GAS_MAX_LIMIT;
evm.tx.gas_limit = gas_limit;
evm.tx.gas_price = 0;
evm.tx.chain_id = None;
evm.tx.nonce = 0;
Expand Down
6 changes: 3 additions & 3 deletions src/eth/executor/evm/types/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ pub trait EvmInput: Default + Clone {

fn metrics_context(&self) -> ExecutionMetricsContext;

fn fill_tx_env<DB: Database, I>(self, evm: &mut GeneralRevm<DB, I>);
fn fill_tx_env<DB: Database, I>(self, evm: &mut GeneralRevm<DB, I>, gas_limit: u64);

fn fill_block_env<DB: Database, I>(&self, evm: &mut GeneralRevm<DB, I>);

fn fill_env<DB: Database, I>(self, evm: &mut GeneralRevm<DB, I>) {
fn fill_env<DB: Database, I>(self, evm: &mut GeneralRevm<DB, I>, gas_limit: u64) {
self.fill_block_env(evm);
self.fill_tx_env(evm);
self.fill_tx_env(evm, gas_limit);
}
}
5 changes: 2 additions & 3 deletions src/eth/executor/evm/types/input/transaction_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use revm::context::TransactTo;

use crate::eth::executor::evm::types::EvmInput;
use crate::eth::executor::evm::types::ExecutionMetricsContext;
use crate::eth::executor::evm::types::GAS_MAX_LIMIT;
use crate::eth::executor::evm::types::GeneralRevm;
use crate::eth::storage::ExecutionKind;
use crate::eth::types::Address;
Expand Down Expand Up @@ -112,13 +111,13 @@ impl EvmInput for TransactionExecutionInput {
evm.block.basefee = 0;
}

fn fill_tx_env<DB: Database, I>(self, evm: &mut GeneralRevm<DB, I>) {
fn fill_tx_env<DB: Database, I>(self, evm: &mut GeneralRevm<DB, I>, gas_limit: u64) {
evm.tx.caller = self.from.into();
evm.tx.kind = match self.to {
Some(contract) => TransactTo::Call(contract.into()),
None => TransactTo::Create,
};
evm.tx.gas_limit = GAS_MAX_LIMIT;
evm.tx.gas_limit = gas_limit;
evm.tx.gas_price = 0;
evm.tx.chain_id = self.chain_id.map_into();
evm.tx.nonce = self.nonce.into();
Expand Down
6 changes: 0 additions & 6 deletions src/eth/executor/evm/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ pub use output::call_execution::CallExecutionOutput;
pub use output::transaction_execution::TransactionExecutionOutput;
pub use output::transaction_execution::TransactionExecutionResult;

/// Maximum gas limit allowed for a transaction. Prevents a transaction from consuming too many resources.
#[cfg(feature = "dev")]
pub const GAS_MAX_LIMIT: u64 = 1_000_000_000;
#[cfg(not(feature = "dev"))]
pub const GAS_MAX_LIMIT: u64 = 100_000_000;

pub type ContextWithDB<DB> = Context<BlockEnv, TxEnv, CfgEnv, DB, Journal<DB>>;
pub type GeneralRevm<DB, I = ()> = RevmEvm<ContextWithDB<DB>, I, EthInstructions<EthInterpreter, ContextWithDB<DB>>, EthPrecompiles, EthFrame>;

Expand Down
13 changes: 6 additions & 7 deletions src/eth/executor/evm/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ use crate::eth::executor::EvmKind;
use crate::eth::executor::TransactionExecution;
use crate::eth::executor::TransactionExecutionInput;
use crate::eth::executor::evm::GeneralRevm;
use crate::eth::executor::evm::types::GAS_MAX_LIMIT;
use crate::eth::types::Address;
use crate::ext::OptionExt;

Expand Down Expand Up @@ -76,28 +75,28 @@ fn enhance_call_frame_errors(frame: &mut CallFrame) {
}

pub trait TxEnvExt {
fn fill_env(&mut self, input: TransactionExecutionInput);
fn fill_env(&mut self, input: TransactionExecutionInput, gas_limit: u64);
}

pub trait EvmExt {
fn fill_env(&mut self, input: TransactionExecutionInput);
fn fill_env(&mut self, input: TransactionExecutionInput, gas_limit: u64);
}

impl<DB: Database, I> EvmExt for GeneralRevm<DB, I> {
fn fill_env(&mut self, input: TransactionExecutionInput) {
fn fill_env(&mut self, input: TransactionExecutionInput, gas_limit: u64) {
self.block.fill_env(&input);
self.tx.fill_env(input);
self.tx.fill_env(input, gas_limit);
}
}

impl TxEnvExt for TxEnv {
fn fill_env(&mut self, input: TransactionExecutionInput) {
fn fill_env(&mut self, input: TransactionExecutionInput, gas_limit: u64) {
self.caller = input.from.into();
self.kind = match input.to {
Some(contract) => TransactTo::Call(contract.into()),
None => TransactTo::Create,
};
self.gas_limit = GAS_MAX_LIMIT;
self.gas_limit = gas_limit;
self.gas_price = 0;
self.chain_id = input.chain_id.map_into();
self.nonce = input.nonce.into();
Expand Down
Loading