diff --git a/Cargo.toml b/Cargo.toml index 95efc1c1..20cae321 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,9 +35,16 @@ alloy = { version = "0.2.1", features = [ "rlp", "k256", "provider-http", - "sol-types" + "sol-types", + "network", +]} +revm = { version = "12.1.0", default-features = false, features = [ + "std", + "serde", + "optional_block_gas_limit", + "optional_eip3607", + "optional_no_base_fee", ]} -revm = { version = "12.1.0", default-features = false, features = ["std", "serde"] } triehash-ethereum = { git = "https://github.com/openethereum/parity-ethereum", rev = "55c90d4016505317034e3e98f699af07f5404b63" } # async/futures diff --git a/client/src/client.rs b/client/src/client.rs index 833bc79b..4c67fd4a 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -4,7 +4,9 @@ use std::sync::Arc; use std::time::Duration; use alloy::primitives::{Address, B256, U256}; -use alloy::rpc::types::{Filter, Log, SyncStatus, Transaction, TransactionReceipt}; +use alloy::rpc::types::{ + Filter, Log, SyncStatus, Transaction, TransactionReceipt, TransactionRequest, +}; use eyre::{eyre, Result}; use tracing::{info, warn}; use zduny_wasm_timer::Delay; @@ -13,7 +15,6 @@ use common::types::{Block, BlockTag}; use config::networks::Network; use config::Config; use consensus::database::Database; -use execution::types::CallOpts; use crate::node::Node; @@ -267,12 +268,12 @@ impl Client { } } - pub async fn call(&self, opts: &CallOpts, block: BlockTag) -> Result> { - self.node.call(opts, block).await.map_err(|err| err.into()) + pub async fn call(&self, tx: &TransactionRequest, block: BlockTag) -> Result> { + self.node.call(tx, block).await.map_err(|err| err.into()) } - pub async fn estimate_gas(&self, opts: &CallOpts) -> Result { - self.node.estimate_gas(opts).await.map_err(|err| err.into()) + pub async fn estimate_gas(&self, tx: &TransactionRequest) -> Result { + self.node.estimate_gas(tx).await.map_err(|err| err.into()) } pub async fn get_balance(&self, address: &Address, block: BlockTag) -> Result { diff --git a/client/src/node.rs b/client/src/node.rs index 547ba671..f65eaa58 100644 --- a/client/src/node.rs +++ b/client/src/node.rs @@ -1,7 +1,9 @@ use std::sync::Arc; use alloy::primitives::{Address, B256, U256}; -use alloy::rpc::types::{Filter, Log, SyncInfo, SyncStatus, Transaction, TransactionReceipt}; +use alloy::rpc::types::{ + Filter, Log, SyncInfo, SyncStatus, Transaction, TransactionReceipt, TransactionRequest, +}; use eyre::{eyre, Result}; use zduny_wasm_timer::{SystemTime, UNIX_EPOCH}; @@ -13,7 +15,6 @@ use consensus::ConsensusClient; use execution::evm::Evm; use execution::rpc::http_rpc::HttpRpc; use execution::state::State; -use execution::types::CallOpts; use execution::ExecutionClient; use crate::errors::NodeError; @@ -50,20 +51,23 @@ impl Node { }) } - pub async fn call(&self, opts: &CallOpts, block: BlockTag) -> Result, NodeError> { + pub async fn call( + &self, + tx: &TransactionRequest, + block: BlockTag, + ) -> Result, NodeError> { self.check_blocktag_age(&block).await?; let mut evm = Evm::new(self.execution.clone(), self.chain_id(), block); - - evm.call(opts).await.map_err(NodeError::ExecutionEvmError) + evm.call(tx).await.map_err(NodeError::ExecutionEvmError) } - pub async fn estimate_gas(&self, opts: &CallOpts) -> Result { + pub async fn estimate_gas(&self, tx: &TransactionRequest) -> Result { self.check_head_age().await?; let mut evm = Evm::new(self.execution.clone(), self.chain_id(), BlockTag::Latest); - evm.estimate_gas(opts) + evm.estimate_gas(tx) .await .map_err(NodeError::ExecutionEvmError) } diff --git a/client/src/rpc.rs b/client/src/rpc.rs index 814421aa..5e4de6ab 100644 --- a/client/src/rpc.rs +++ b/client/src/rpc.rs @@ -2,7 +2,9 @@ use std::net::{IpAddr, Ipv4Addr}; use std::{fmt::Display, net::SocketAddr, str::FromStr, sync::Arc}; use alloy::primitives::{Address, B256, U256}; -use alloy::rpc::types::{Filter, Log, SyncStatus, Transaction, TransactionReceipt}; +use alloy::rpc::types::{ + Filter, Log, SyncStatus, Transaction, TransactionReceipt, TransactionRequest, +}; use eyre::Result; use jsonrpsee::{ core::{async_trait, server::Methods, Error}, @@ -16,7 +18,6 @@ use common::{ utils::{hex_str_to_bytes, u64_to_hex_string}, }; use consensus::database::Database; -use execution::types::CallOpts; use crate::{errors::NodeError, node::Node}; @@ -68,9 +69,9 @@ trait EthRpc { #[method(name = "getCode")] async fn get_code(&self, address: &str, block: BlockTag) -> Result; #[method(name = "call")] - async fn call(&self, opts: CallOpts, block: BlockTag) -> Result; + async fn call(&self, tx: TransactionRequest, block: BlockTag) -> Result; #[method(name = "estimateGas")] - async fn estimate_gas(&self, opts: CallOpts) -> Result; + async fn estimate_gas(&self, tx: TransactionRequest) -> Result; #[method(name = "chainId")] async fn chain_id(&self) -> Result; #[method(name = "gasPrice")] @@ -177,20 +178,20 @@ impl EthRpcServer for RpcInner { Ok(format!("0x{:}", hex::encode(code))) } - async fn call(&self, opts: CallOpts, block: BlockTag) -> Result { + async fn call(&self, tx: TransactionRequest, block: BlockTag) -> Result { let res = self .node - .call(&opts, block) + .call(&tx, block) .await .map_err(NodeError::to_json_rpsee_error)?; Ok(format!("0x{}", hex::encode(res))) } - async fn estimate_gas(&self, opts: CallOpts) -> Result { + async fn estimate_gas(&self, tx: TransactionRequest) -> Result { let gas = self .node - .estimate_gas(&opts) + .estimate_gas(&tx) .await .map_err(NodeError::to_json_rpsee_error)?; diff --git a/common/src/types.rs b/common/src/types.rs index e456743d..cd349f61 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -28,6 +28,8 @@ pub struct Block { pub transactions: Transactions, pub transactions_root: B256, pub uncles: Vec, + pub blob_gas_used: Option, + pub excess_blob_gas: Option, } #[derive(Deserialize, Debug, Clone)] diff --git a/consensus-core/src/types/utils.rs b/consensus-core/src/types/utils.rs index c9fabca6..f42c3833 100644 --- a/consensus-core/src/types/utils.rs +++ b/consensus-core/src/types/utils.rs @@ -212,6 +212,8 @@ impl From for Block { size: U64::ZERO, transactions_root: B256::default(), uncles: vec![], + blob_gas_used: value.blob_gas_used().map(|v| U64::from(v.as_u64())).ok(), + excess_blob_gas: value.excess_blob_gas().map(|v| U64::from(v.as_u64())).ok(), } } } diff --git a/examples/call.rs b/examples/call.rs index 74612109..9e0023b7 100644 --- a/examples/call.rs +++ b/examples/call.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; use alloy::primitives::{Address, Bytes}; +use alloy::rpc::types::TransactionRequest; use dotenv::dotenv; use tracing::info; use tracing_subscriber::filter::{EnvFilter, LevelFilter}; @@ -11,7 +12,7 @@ use tracing_subscriber::FmtSubscriber; use helios::{ client::{Client, ClientBuilder, FileDB}, config::networks::Network, - types::{BlockTag, CallOpts}, + types::BlockTag, }; #[tokio::main] @@ -53,16 +54,21 @@ async fn main() -> eyre::Result<()> { client.wait_synced().await; // Call on helios client - let call_opts = CallOpts { + let tx = TransactionRequest { from: None, - to: Some("0x6B175474E89094C44Da98b954EedeAC495271d0F".parse::
()?), + to: Some( + "0x6B175474E89094C44Da98b954EedeAC495271d0F" + .parse::
()? + .into(), + ), gas: None, gas_price: None, value: None, - data: Some("0x18160ddd".parse::()?), + input: "0x18160ddd".parse::()?.into(), + ..Default::default() }; - let result = client.call(&call_opts, BlockTag::Latest).await?; + let result = client.call(&tx, BlockTag::Latest).await?; info!("[HELIOS] DAI total supply: {:?}", result); Ok(()) diff --git a/execution/src/evm.rs b/execution/src/evm.rs index e9c1de55..d4dd810f 100644 --- a/execution/src/evm.rs +++ b/execution/src/evm.rs @@ -1,19 +1,19 @@ use std::{borrow::BorrowMut, collections::HashMap, sync::Arc}; +use alloy::{network::TransactionBuilder, rpc::types::TransactionRequest}; use eyre::{Report, Result}; use futures::future::join_all; use revm::{ primitives::{ - address, AccessListItem, AccountInfo, Address, Bytecode, Env, ExecutionResult, - ResultAndState, TransactTo, B256, U256, + address, AccessListItem, AccountInfo, Address, BlobExcessGasAndPrice, Bytecode, Env, + ExecutionResult, ResultAndState, B256, U256, }, Database, Evm as Revm, }; use tracing::trace; use crate::{ - constants::PARALLEL_QUERY_BATCH_SIZE, errors::EvmError, rpc::ExecutionRpc, types::CallOpts, - ExecutionClient, + constants::PARALLEL_QUERY_BATCH_SIZE, errors::EvmError, rpc::ExecutionRpc, ExecutionClient, }; use common::types::BlockTag; @@ -32,8 +32,8 @@ impl Evm { } } - pub async fn call(&mut self, opts: &CallOpts) -> Result, EvmError> { - let tx = self.call_inner(opts).await?; + pub async fn call(&mut self, tx: &TransactionRequest) -> Result, EvmError> { + let tx = self.call_inner(tx).await?; match tx.result { ExecutionResult::Success { output, .. } => Ok(output.into_data().to_vec()), @@ -44,8 +44,8 @@ impl Evm { } } - pub async fn estimate_gas(&mut self, opts: &CallOpts) -> Result { - let tx = self.call_inner(opts).await?; + pub async fn estimate_gas(&mut self, tx: &TransactionRequest) -> Result { + let tx = self.call_inner(tx).await?; match tx.result { ExecutionResult::Success { gas_used, .. } => Ok(gas_used), @@ -54,11 +54,11 @@ impl Evm { } } - async fn call_inner(&mut self, opts: &CallOpts) -> Result { + async fn call_inner(&mut self, tx: &TransactionRequest) -> Result { let mut db = ProofDB::new(self.tag, self.execution.clone()); - _ = db.state.prefetch_state(opts).await; + _ = db.state.prefetch_state(tx).await; - let env = Box::new(self.get_env(opts, self.tag).await); + let env = Box::new(self.get_env(tx, self.tag).await); let evm = Revm::builder().with_db(db).with_env(env).build(); let mut ctx = evm.into_context_with_handler_cfg(); @@ -70,10 +70,12 @@ impl Evm { let mut evm = Revm::builder().with_context_with_handler_cfg(ctx).build(); let res = evm.transact(); - ctx = evm.into_context_with_handler_cfg(); - if res.is_ok() { + let db = ctx.context.evm.db.borrow_mut(); + let needs_update = db.state.needs_update(); + + if res.is_ok() || !needs_update { break res; } }; @@ -81,25 +83,43 @@ impl Evm { tx_res.map_err(|_| EvmError::Generic("evm error".to_string())) } - async fn get_env(&self, opts: &CallOpts, tag: BlockTag) -> Env { + async fn get_env(&self, tx: &TransactionRequest, tag: BlockTag) -> Env { let mut env = Env::default(); - let to = &opts.to.unwrap_or_default(); - let from = &opts.from.unwrap_or_default(); - env.tx.transact_to = TransactTo::Call(*to); - env.tx.caller = *from; - env.tx.value = opts.value.unwrap_or_default(); - env.tx.data = opts.data.clone().unwrap_or_default(); - env.tx.gas_limit = opts.gas.map(|v| v.to()).unwrap_or(u64::MAX); - env.tx.gas_price = opts.gas_price.unwrap_or_default(); + env.tx.caller = tx.from.unwrap_or_default(); + env.tx.gas_limit = tx.gas_limit().map(|v| v as u64).unwrap_or(u64::MAX); + env.tx.gas_price = tx.gas_price().map(U256::from).unwrap_or_default(); + env.tx.transact_to = tx.to.unwrap_or_default(); + env.tx.value = tx.value.unwrap_or_default(); + env.tx.data = tx.input().unwrap_or_default().clone(); + env.tx.nonce = tx.nonce(); + env.tx.chain_id = tx.chain_id(); + env.tx.access_list = tx.access_list().map(|v| v.to_vec()).unwrap_or_default(); + env.tx.gas_priority_fee = tx.max_priority_fee_per_gas().map(U256::from); + env.tx.max_fee_per_blob_gas = tx.max_fee_per_gas().map(U256::from); + env.tx.blob_hashes = tx + .blob_versioned_hashes + .as_ref() + .map(|v| v.to_vec()) + .unwrap_or_default(); let block = self.execution.get_block(tag, false).await.unwrap(); env.block.number = block.number.to(); env.block.coinbase = block.miner; env.block.timestamp = block.timestamp.to(); + env.block.gas_limit = block.gas_limit.to(); + env.block.basefee = block.base_fee_per_gas; env.block.difficulty = block.difficulty; + env.block.prevrandao = Some(block.mix_hash); + env.block.blob_excess_gas_and_price = block + .excess_blob_gas + .map(|v| BlobExcessGasAndPrice::new(v.to())); + env.cfg.chain_id = self.chain_id; + env.cfg.disable_block_gas_limit = true; + env.cfg.disable_eip3607 = true; + env.cfg.disable_base_fee = true; env } @@ -219,22 +239,22 @@ impl EvmState { } } - pub async fn prefetch_state(&mut self, opts: &CallOpts) -> Result<()> { + pub async fn prefetch_state(&mut self, tx: &TransactionRequest) -> Result<()> { let mut list = self .execution .rpc - .create_access_list(opts, self.block) + .create_access_list(tx, self.block) .await .map_err(EvmError::RpcError)? .0; let from_access_entry = AccessListItem { - address: opts.from.unwrap_or_default(), + address: tx.from.unwrap_or_default(), storage_keys: Vec::default(), }; let to_access_entry = AccessListItem { - address: opts.to.unwrap_or_default(), + address: tx.to().unwrap_or_default(), storage_keys: Vec::default(), }; diff --git a/execution/src/rpc/http_rpc.rs b/execution/src/rpc/http_rpc.rs index 0bc0f352..9804fc78 100644 --- a/execution/src/rpc/http_rpc.rs +++ b/execution/src/rpc/http_rpc.rs @@ -12,7 +12,6 @@ use eyre::Result; use reqwest::Client; use revm::primitives::AccessList; -use crate::types::CallOpts; use common::errors::RpcError; use common::types::BlockTag; @@ -61,27 +60,20 @@ impl ExecutionRpc for HttpRpc { Ok(proof_response) } - async fn create_access_list(&self, opts: &CallOpts, block: BlockTag) -> Result { + async fn create_access_list( + &self, + tx: &TransactionRequest, + block: BlockTag, + ) -> Result { let block = match block { BlockTag::Latest => BlockId::latest(), BlockTag::Finalized => BlockId::finalized(), BlockTag::Number(num) => BlockId::number(num), }; - let tx = TransactionRequest { - to: Some(opts.to.unwrap_or_default().into()), - from: opts.from, - value: opts.value, - gas: Some(opts.gas.unwrap_or(U256::from(100_000_000)).to()), - max_fee_per_gas: Some(0), - max_priority_fee_per_gas: Some(0), - input: opts.data.as_ref().map(|data| data.to_owned()).into(), - ..Default::default() - }; - let list = self .provider - .create_access_list(&tx) + .create_access_list(tx) .block_id(block) .await .map_err(|e| RpcError::new("create_access_list", e))?; diff --git a/execution/src/rpc/mock_rpc.rs b/execution/src/rpc/mock_rpc.rs index 89bf1301..f883ad95 100644 --- a/execution/src/rpc/mock_rpc.rs +++ b/execution/src/rpc/mock_rpc.rs @@ -3,13 +3,12 @@ use std::{fs::read_to_string, path::PathBuf}; use alloy::primitives::{Address, B256, U256}; use alloy::rpc::types::{ AccessList, EIP1186AccountProofResponse, FeeHistory, Filter, Log, Transaction, - TransactionReceipt, + TransactionReceipt, TransactionRequest, }; use async_trait::async_trait; use eyre::{eyre, Result}; use super::ExecutionRpc; -use crate::types::CallOpts; use common::{types::BlockTag, utils::hex_str_to_bytes}; #[derive(Clone)] @@ -35,7 +34,11 @@ impl ExecutionRpc for MockRpc { Ok(serde_json::from_str(&proof)?) } - async fn create_access_list(&self, _opts: &CallOpts, _block: BlockTag) -> Result { + async fn create_access_list( + &self, + _opts: &TransactionRequest, + _block: BlockTag, + ) -> Result { Err(eyre!("not implemented")) } diff --git a/execution/src/rpc/mod.rs b/execution/src/rpc/mod.rs index f97dbe09..9d04e89f 100644 --- a/execution/src/rpc/mod.rs +++ b/execution/src/rpc/mod.rs @@ -3,11 +3,10 @@ use async_trait::async_trait; use alloy::primitives::{Address, B256, U256}; use alloy::rpc::types::{ AccessList, EIP1186AccountProofResponse, FeeHistory, Filter, Log, Transaction, - TransactionReceipt, + TransactionReceipt, TransactionRequest, }; use eyre::Result; -use crate::types::CallOpts; use common::types::BlockTag; pub mod http_rpc; @@ -27,7 +26,11 @@ pub trait ExecutionRpc: Send + Clone + Sync + 'static { block: u64, ) -> Result; - async fn create_access_list(&self, opts: &CallOpts, block: BlockTag) -> Result; + async fn create_access_list( + &self, + opts: &TransactionRequest, + block: BlockTag, + ) -> Result; async fn get_code(&self, address: &Address, block: u64) -> Result>; async fn send_raw_transaction(&self, bytes: &[u8]) -> Result; async fn get_transaction_receipt(&self, tx_hash: &B256) -> Result>; diff --git a/execution/src/types.rs b/execution/src/types.rs index 3b4c097b..308dd4eb 100644 --- a/execution/src/types.rs +++ b/execution/src/types.rs @@ -1,7 +1,6 @@ -use std::{collections::HashMap, fmt}; +use std::collections::HashMap; -use alloy::primitives::{Address, Bytes, B256, U256}; -use serde::{Deserialize, Serialize}; +use alloy::primitives::{B256, U256}; #[derive(Default, Debug, Clone)] pub struct Account { @@ -12,26 +11,3 @@ pub struct Account { pub storage_hash: B256, pub slots: HashMap, } - -#[derive(Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct CallOpts { - pub from: Option
, - pub to: Option
, - pub gas: Option, - pub gas_price: Option, - pub value: Option, - #[serde(alias = "input")] - pub data: Option, -} - -impl fmt::Debug for CallOpts { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("CallOpts") - .field("from", &self.from) - .field("to", &self.to) - .field("value", &self.value) - .field("data", &hex::encode(self.data.clone().unwrap_or_default())) - .finish() - } -} diff --git a/helios-ts/src/lib.rs b/helios-ts/src/lib.rs index 5e2a5bf3..ab17c653 100644 --- a/helios-ts/src/lib.rs +++ b/helios-ts/src/lib.rs @@ -4,14 +4,13 @@ extern crate web_sys; use std::str::FromStr; use alloy::primitives::{Address, B256}; -use alloy::rpc::types::Filter; +use alloy::rpc::types::{Filter, TransactionRequest}; use eyre::Result; use wasm_bindgen::prelude::*; use common::types::BlockTag; use config::{networks, Config}; use consensus::database::{ConfigDB, Database}; -use execution::types::CallOpts; use crate::storage::LocalStorageDB; @@ -194,7 +193,7 @@ impl Client { #[wasm_bindgen] pub async fn call(&self, opts: JsValue, block: JsValue) -> String { - let opts: CallOpts = serde_wasm_bindgen::from_value(opts).unwrap(); + let opts: TransactionRequest = serde_wasm_bindgen::from_value(opts).unwrap(); let block: BlockTag = serde_wasm_bindgen::from_value(block).unwrap(); let res = self.inner.call(&opts, block).await.unwrap(); format!("0x{}", hex::encode(res)) @@ -202,7 +201,7 @@ impl Client { #[wasm_bindgen] pub async fn estimate_gas(&self, opts: JsValue) -> u32 { - let opts: CallOpts = serde_wasm_bindgen::from_value(opts).unwrap(); + let opts: TransactionRequest = serde_wasm_bindgen::from_value(opts).unwrap(); self.inner.estimate_gas(&opts).await.unwrap() as u32 } diff --git a/src/lib.rs b/src/lib.rs index 22129ccd..ff15c4f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,7 +67,7 @@ pub mod types { pub use common::config::types::*; pub use common::types::{Block, BlockTag, Transactions}; pub use consensus_core::types::*; - pub use execution::types::{Account, CallOpts}; + pub use execution::types::Account; } pub mod errors {