Skip to content

Commit

Permalink
debugging handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
zobront committed Dec 6, 2024
1 parent 44bdb14 commit 0579210
Show file tree
Hide file tree
Showing 18 changed files with 841 additions and 567 deletions.
594 changes: 220 additions & 374 deletions Cargo.lock

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ op-alloy-consensus = { version = "0.7.2", default-features = false }
op-alloy-rpc-types-engine = { version = "0.7.2", default-features = false }

# Reth
reth-evm = { git = "https://github.com/paradigmxyz/reth.git", rev = "8e4a917" }
reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth.git", rev = "8e4a917" }
reth-primitives = { git = "https://github.com/paradigmxyz/reth.git", rev = "8e4a917" }
reth-optimism-chainspec = { git = "https://github.com/paradigmxyz/reth.git", rev = "8e4a917" }
reth-optimism-forks = { git = "https://github.com/paradigmxyz/reth.git", rev = "8e4a917" }
reth-evm = { git = "https://github.com/zobront/reth.git", branch = "fill-env-opt-deposit", default-features = false }
reth-primitives-traits = { git = "https://github.com/zobront/reth.git", branch = "fill-env-opt-deposit", default-features = false }
reth-primitives = { git = "https://github.com/zobront/reth.git", branch = "fill-env-opt-deposit", default-features = false, features = ["optimism"] }
reth-optimism-chainspec = { git = "https://github.com/zobront/reth.git", branch = "fill-env-opt-deposit", default-features = false }
reth-optimism-forks = { git = "https://github.com/zobront/reth.git", branch = "fill-env-opt-deposit", default-features = false }

# General
lru = "0.12.4"
Expand Down
6 changes: 6 additions & 0 deletions bin/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ op-alloy-rpc-types-engine = { workspace = true, features = ["serde"] }

# Revm
revm.workspace = true

# Reth
reth-evm.workspace = true
reth-primitives-traits.workspace = true
reth-primitives.workspace = true
reth-optimism-chainspec.workspace = true
reth-optimism-forks.workspace = true

# General
lru.workspace = true
Expand Down
299 changes: 299 additions & 0 deletions bin/client/src/evm_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
use alloc::{sync::Arc, vec::Vec};
use alloy_consensus::Header;
use alloy_rlp::Encodable;
use alloy_primitives::{Address, Bytes, TxKind, U256};
use op_alloy_consensus::OpTxEnvelope;
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes};
use reth_optimism_chainspec::{DecodeError, OpChainSpec};
use reth_optimism_forks::OpHardfork;
use revm::{
Database, Evm, EvmBuilder,
primitives::{
Env, OptimismFields, BlobExcessGasAndPrice, BlockEnv, CfgEnv,
CfgEnvWithHandlerCfg, SpecId, TransactTo, TxEnv, HandlerCfg, AnalysisKind
},
};

use crate::fpvm_handle_register;

/// A default implementation of the EVM Config.
#[derive(Clone, Debug)]
pub struct KonaEvmConfig {
chain_spec: Arc<OpChainSpec>,
}

impl KonaEvmConfig {
/// Create a new instance of the default EVM config from a chain spec.
pub const fn new(chain_spec: Arc<OpChainSpec>) -> Self {
Self { chain_spec }
}
}

impl ConfigureEvmEnv for KonaEvmConfig {
type Header = Header;
type Transaction = OpTxEnvelope;
type Error = DecodeError;

/// Fill transaction environment from a [`OpTxEnvelope`] and the given sender address.
fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &OpTxEnvelope, sender: Address) {
match transaction {
OpTxEnvelope::Legacy(signed_tx) => {
let tx = signed_tx.tx();
tx_env.caller = sender;
tx_env.gas_limit = tx.gas_limit;
tx_env.gas_price = U256::from(tx.gas_price);
tx_env.gas_priority_fee = None;
tx_env.transact_to = match tx.to {
TxKind::Call(to) => TransactTo::Call(to),
TxKind::Create => TransactTo::Create,
};
tx_env.value = tx.value;
tx_env.data = tx.input.clone();
tx_env.chain_id = tx.chain_id;
tx_env.nonce = Some(tx.nonce);
tx_env.access_list.clear();
tx_env.blob_hashes.clear();
tx_env.max_fee_per_blob_gas.take();
tx_env.optimism = OptimismFields {
source_hash: None,
mint: None,
is_system_transaction: Some(false),
enveloped_tx: {
let mut buf = Vec::new();
transaction.encode(&mut buf);
Some(buf.into())
},
};
}
OpTxEnvelope::Eip2930(signed_tx) => {
let tx = signed_tx.tx();
tx_env.caller = sender;
tx_env.gas_limit = tx.gas_limit;
tx_env.gas_price = U256::from(tx.gas_price);
tx_env.gas_priority_fee = None;
tx_env.transact_to = match tx.to {
TxKind::Call(to) => TransactTo::Call(to),
TxKind::Create => TransactTo::Create,
};
tx_env.value = tx.value;
tx_env.data = tx.input.clone();
tx_env.chain_id = Some(tx.chain_id);
tx_env.nonce = Some(tx.nonce);
tx_env.access_list = tx.access_list.to_vec();
tx_env.blob_hashes.clear();
tx_env.max_fee_per_blob_gas.take();
tx_env.optimism = OptimismFields {
source_hash: None,
mint: None,
is_system_transaction: Some(false),
enveloped_tx: {
let mut buf = Vec::new();
transaction.encode(&mut buf);
Some(buf.into())
},
};
}
OpTxEnvelope::Eip1559(signed_tx) => {
let tx = signed_tx.tx();
tx_env.caller = sender;
tx_env.gas_limit = tx.gas_limit;
tx_env.gas_price = U256::from(tx.max_fee_per_gas);
tx_env.gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas));
tx_env.transact_to = match tx.to {
TxKind::Call(to) => TransactTo::Call(to),
TxKind::Create => TransactTo::Create,
};
tx_env.value = tx.value;
tx_env.data = tx.input.clone();
tx_env.chain_id = Some(tx.chain_id);
tx_env.nonce = Some(tx.nonce);
tx_env.access_list = tx.access_list.to_vec();
tx_env.blob_hashes.clear();
tx_env.max_fee_per_blob_gas.take();
tx_env.optimism = OptimismFields {
source_hash: None,
mint: None,
is_system_transaction: Some(false),
enveloped_tx: {
let mut buf = Vec::new();
transaction.encode(&mut buf);
Some(buf.into())
},
};
}
OpTxEnvelope::Deposit(tx) => {
tx_env.caller = tx.from;
tx_env.access_list.clear();
tx_env.gas_limit = tx.gas_limit;
tx_env.gas_price = U256::ZERO;
tx_env.gas_priority_fee = None;
match tx.to {
TxKind::Call(to) => tx_env.transact_to = TransactTo::Call(to),
TxKind::Create => tx_env.transact_to = TransactTo::Create,
}
tx_env.value = tx.value;
tx_env.data = tx.input.clone();
tx_env.chain_id = None;
tx_env.nonce = None;
tx_env.optimism = OptimismFields {
source_hash: Some(tx.source_hash),
mint: tx.mint,
is_system_transaction: Some(tx.is_system_transaction),
enveloped_tx: {
let mut buf = Vec::new();
transaction.encode(&mut buf);
Some(buf.into())
},
};
}
_ => {
// ZTODO: no return, how to better handle errors?
panic!("Unsupported transaction type");
}
}
}

/// Fill transaction environment with a system contract call.
fn fill_tx_env_system_contract_call(
&self,
env: &mut Env,
caller: Address,
contract: Address,
data: Bytes,
) {
env.tx = TxEnv {
caller,
transact_to: TxKind::Call(contract),
// Explicitly set nonce to None so revm does not do any nonce checks
nonce: None,
gas_limit: 30_000_000,
value: U256::ZERO,
data,
// Setting the gas price to zero enforces that no value is transferred as part of the
// call, and that the call will not count against the block's gas limit
gas_price: U256::ZERO,
// The chain ID check is not relevant here and is disabled if set to None
chain_id: None,
// Setting the gas priority fee to None ensures the effective gas price is derived from
// the `gas_price` field, which we need to be zero
gas_priority_fee: None,
access_list: Vec::new(),
// blob fields can be None for this tx
blob_hashes: Vec::new(),
max_fee_per_blob_gas: None,
authorization_list: None,
optimism: OptimismFields {
source_hash: None,
mint: None,
is_system_transaction: Some(false),
// The L1 fee is not charged for the EIP-4788 transaction, submit zero bytes for the
// enveloped tx size.
enveloped_tx: Some(Bytes::default()),
},
};

// ensure the block gas limit is >= the tx
env.block.gas_limit = U256::from(env.tx.gas_limit);

// disable the base fee check for this call by setting the base fee to zero
env.block.basefee = U256::ZERO;
}

/// Fill [`CfgEnvWithHandlerCfg`] fields according to the chain spec and given header.
///
/// This must set the corresponding spec id in the handler cfg, based on timestamp or total
/// difficulty
fn fill_cfg_env(
&self,
cfg_env: &mut CfgEnvWithHandlerCfg,
header: &Self::Header,
_total_difficulty: U256,
) {
let spec_id = revm_spec_by_timestamp_after_bedrock(&self.chain_spec, header.timestamp);

cfg_env.chain_id = self.chain_spec.chain().id();
cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse;

cfg_env.handler_cfg.spec_id = spec_id;
cfg_env.handler_cfg.is_optimism = true;
}

/// Returns the configured [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for `parent + 1` block.
///
/// This is intended for usage in block building after the merge and requires additional
/// attributes that can't be derived from the parent block: attributes that are determined by
/// the CL, such as the timestamp, suggested fee recipient, and randomness value.
fn next_cfg_and_block_env(
&self,
parent: &Self::Header,
attributes: NextBlockEnvAttributes,
) -> Result<(CfgEnvWithHandlerCfg, BlockEnv), Self::Error> {
// configure evm env based on parent block
let cfg = CfgEnv::default().with_chain_id(self.chain_spec.chain().id());

// ensure we're not missing any timestamp based hardforks
let spec_id = revm_spec_by_timestamp_after_bedrock(&self.chain_spec, attributes.timestamp);

// if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is
// cancun now, we need to set the excess blob gas to the default value(0)
let blob_excess_gas_and_price = parent
.next_block_excess_blob_gas()
.or_else(|| (spec_id.is_enabled_in(SpecId::CANCUN)).then_some(0))
.map(BlobExcessGasAndPrice::new);

let block_env = BlockEnv {
number: U256::from(parent.number + 1),
coinbase: attributes.suggested_fee_recipient,
timestamp: U256::from(attributes.timestamp),
difficulty: U256::ZERO,
prevrandao: Some(attributes.prev_randao),
gas_limit: U256::from(parent.gas_limit),
// calculate basefee based on parent block's gas usage
basefee: self.chain_spec.next_block_base_fee(parent, attributes.timestamp)?,
// calculate excess gas based on parent block's blob gas usage
blob_excess_gas_and_price,
};

let cfg_with_handler_cfg;
{
cfg_with_handler_cfg = CfgEnvWithHandlerCfg {
cfg_env: cfg,
handler_cfg: HandlerCfg { spec_id, is_optimism: true },
};
}

Ok((cfg_with_handler_cfg, block_env))
}
}

impl ConfigureEvm for KonaEvmConfig {
type DefaultExternalContext<'a> = ();

fn evm<DB: Database>(&self, db: DB) -> Evm<'_, Self::DefaultExternalContext<'_>, DB> {
EvmBuilder::default()
.with_db(db)
.optimism()
.append_handler_register(fpvm_handle_register)
.build()
}

fn default_external_context<'a>(&self) -> Self::DefaultExternalContext<'a> {}
}

fn revm_spec_by_timestamp_after_bedrock(chain_spec: &OpChainSpec, timestamp: u64) -> SpecId {
if chain_spec.fork(OpHardfork::Holocene).active_at_timestamp(timestamp) {
revm::primitives::HOLOCENE
} else if chain_spec.fork(OpHardfork::Granite).active_at_timestamp(timestamp) {
revm::primitives::GRANITE
} else if chain_spec.fork(OpHardfork::Fjord).active_at_timestamp(timestamp) {
revm::primitives::FJORD
} else if chain_spec.fork(OpHardfork::Ecotone).active_at_timestamp(timestamp) {
revm::primitives::ECOTONE
} else if chain_spec.fork(OpHardfork::Canyon).active_at_timestamp(timestamp) {
revm::primitives::CANYON
} else if chain_spec.fork(OpHardfork::Regolith).active_at_timestamp(timestamp) {
revm::primitives::REGOLITH
} else {
revm::primitives::BEDROCK
}
}
10 changes: 4 additions & 6 deletions bin/client/src/kona.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ use alloc::string::String;
use kona_preimage::{HintWriter, OracleReader};
use kona_std_fpvm::{FileChannel, FileDescriptor};
use kona_std_fpvm_proc::client_entry;

mod precompiles;
use crate::{run, fpvm_handle_register};

/// The global preimage oracle reader pipe.
static ORACLE_READER_PIPE: FileChannel =
Expand All @@ -23,10 +22,10 @@ static HINT_WRITER_PIPE: FileChannel =
FileChannel::new(FileDescriptor::HintRead, FileDescriptor::HintWrite);

/// The global preimage oracle reader.
static ORACLE_READER: OracleReader<FileChannel> = OracleReader::new(ORACLE_READER_PIPE);
pub static ORACLE_READER: OracleReader<FileChannel> = OracleReader::new(ORACLE_READER_PIPE);

/// The global hint writer.
static HINT_WRITER: HintWriter<FileChannel> = HintWriter::new(HINT_WRITER_PIPE);
pub static HINT_WRITER: HintWriter<FileChannel> = HintWriter::new(HINT_WRITER_PIPE);

#[client_entry(100_000_000)]
fn main() -> Result<(), String> {
Expand All @@ -39,9 +38,8 @@ fn main() -> Result<(), String> {
.expect("Failed to set tracing subscriber");
}

kona_proof::block_on(kona_client::run(
kona_proof::block_on(run(
ORACLE_READER,
HINT_WRITER,
Some(precompiles::fpvm_handle_register),
))
}
Loading

0 comments on commit 0579210

Please sign in to comment.