From ed0a6422616856d7f77f6bcb83c333fe6e5bb4d1 Mon Sep 17 00:00:00 2001 From: harry Date: Fri, 16 Jun 2023 08:38:02 +0800 Subject: [PATCH] fix gas calc, sync with upstream crates --- Cargo.toml | 2 +- crates/api/src/adapter.rs | 2 +- crates/api/src/jsonrpc/impls/web3.rs | 86 +++++++++++++++++++++++++--- crates/api/src/jsonrpc/mod.rs | 3 + crates/executor/src/adapter/mod.rs | 25 +++----- crates/executor/src/lib.rs | 14 +---- 6 files changed, 96 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c37bd0b..6ec4063 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ ripemd = "0.1" ruc = { version = "5.0.10", features = ["crypto"] } vsdb = { version = "0.60.0", default-features = false, features = ["extra_types"] } -vsdb_trie_db = "0.14.0" +vsdb_trie_db = "0.15.0" #################################################################### #################################################################### diff --git a/crates/api/src/adapter.rs b/crates/api/src/adapter.rs index a10fcd2..eb3033c 100644 --- a/crates/api/src/adapter.rs +++ b/crates/api/src/adapter.rs @@ -154,7 +154,7 @@ impl APIAdapter for DefaultAPIAdapter { .map(|gas| gas.as_u64()) .unwrap_or(MAX_BLOCK_GAS_LIMIT); - Ok(RTEvmExecutor::default().call(&backend, gas_limit, from, to, value, data)) + Ok(RTEvmExecutor.call(&backend, gas_limit, from, to, value, data)) } async fn get_code_by_hash(&self, hash: &Hash) -> Result>> { diff --git a/crates/api/src/jsonrpc/impls/web3.rs b/crates/api/src/jsonrpc/impls/web3.rs index 56d109c..ab1df9f 100644 --- a/crates/api/src/jsonrpc/impls/web3.rs +++ b/crates/api/src/jsonrpc/impls/web3.rs @@ -13,8 +13,9 @@ use rt_evm_model::{ lazy::PROTOCOL_VERSION, traits::APIAdapter, types::{ - Block, BlockNumber, Bytes, Hash, Header, Hex, Receipt, SignedTransaction, - TxResp, UnverifiedTransaction, H160, H256, H64, MAX_BLOCK_GAS_LIMIT, U256, + Block, BlockNumber, Bytes, ExitError, ExitReason, Hash, Header, Hex, Receipt, + SignedTransaction, TxResp, UnverifiedTransaction, H160, H256, H64, + MAX_BLOCK_GAS_LIMIT, MAX_PRIORITY_FEE_PER_GAS, U256, }, }; use ruc::*; @@ -303,11 +304,49 @@ impl RTEvmWeb3RpcServer for Web3RpcImpl .map(|hex| hex.as_bytes()) .unwrap_or_default(); let resp = self - .call_evm(req, data_bytes, num) + .call_evm(req.clone(), data_bytes.clone(), num) .await .map_err(|e| Error::Custom(e.to_string()))?; if resp.exit_reason.is_succeed() { + // This parameter is used as the divisor and cannot be 0 + let gas_limit = if let Some(gas) = req.gas.as_ref() { + alt!(*gas > U256::from(u32::MAX), u32::MAX, gas.as_u32()) as u64 + } else { + u32::MAX as u64 + }; + + let mut highest = U256::from(gas_limit); + let mut lowest = U256::from(21_000); + let mut mid = + (U256::from(resp.gas_used) * U256::from(3)).min((highest + lowest) / 2); + let mut previous_highest = highest; + + while (highest - lowest) > U256::one() { + let mut req2 = req.clone(); + req2.gas = Some(mid); + let resp2 = self + .call_evm(req2, data_bytes.clone(), num) + .await + .map_err(|e| Error::Custom(e.to_string()))?; + match resp2.exit_reason { + ExitReason::Succeed(_) => { + highest = mid; + if (previous_highest - highest) * 10 / previous_highest + < U256::one() + { + return Ok(highest); + } + previous_highest = highest; + } + ExitReason::Revert(_) | ExitReason::Error(ExitError::OutOfGas) => { + lowest = mid; + } + other => error_on_execution_failure(&other, &resp2.ret)?, + } + mid = (highest + lowest) / 2; + } + return Ok(resp.gas_used.into()); } @@ -380,6 +419,10 @@ impl RTEvmWeb3RpcServer for Web3RpcImpl Ok(U256::from(8u64)) } + async fn get_max_priority_fee_per_gas(&self) -> RpcResult { + Ok(U256::from(MAX_PRIORITY_FEE_PER_GAS)) + } + async fn get_logs(&self, filter: Web3Filter) -> RpcResult> { let topics: Vec>>> = filter .topics @@ -508,10 +551,11 @@ impl RTEvmWeb3RpcServer for Web3RpcImpl ( filter.from_block.map(convert).unwrap_or(latest_number), - std::cmp::min( - filter.to_block.map(convert).unwrap_or(latest_number), - latest_number, - ), + filter + .to_block + .map(convert) + .unwrap_or(latest_number) + .min(latest_number), ) }; @@ -776,3 +820,31 @@ pub fn from_receipt_to_web3_log( } } } + +pub fn error_on_execution_failure(reason: &ExitReason, data: &[u8]) -> RpcResult<()> { + match reason { + ExitReason::Succeed(_) => Ok(()), + ExitReason::Error(e) => { + if *e == ExitError::OutOfGas { + // `ServerError(0)` will be useful in estimate gas + return Err(Error::Custom("out of gas".to_string())); + } + Err(Error::Custom("Internal".to_string())) + } + ExitReason::Revert(_) => { + let mut message = + "VM Exception while processing transaction: revert".to_string(); + // A minimum size of error function selector (4) + offset (32) + string length (32) + // should contain a utf-8 encoded revert reason. + if data.len() > 68 { + let message_len = data[36..68].iter().sum::(); + let body: &[u8] = &data[68..68 + message_len as usize]; + if let Ok(reason) = std::str::from_utf8(body) { + message = format!("{message} {reason}"); + } + } + Err(Error::Custom(message)) + } + ExitReason::Fatal(e) => Err(Error::Custom(format!("evm fatal: {e:?}"))), + } +} diff --git a/crates/api/src/jsonrpc/mod.rs b/crates/api/src/jsonrpc/mod.rs index 092d723..c60c56c 100644 --- a/crates/api/src/jsonrpc/mod.rs +++ b/crates/api/src/jsonrpc/mod.rs @@ -86,6 +86,9 @@ pub trait RTEvmWeb3Rpc { #[method(name = "eth_gasPrice")] async fn gas_price(&self) -> RpcResult; + #[method(name = "eth_maxPriorityFeePerGas")] + async fn get_max_priority_fee_per_gas(&self) -> RpcResult; + #[method(name = "eth_getLogs")] async fn get_logs(&self, filter: Web3Filter) -> RpcResult>; diff --git a/crates/executor/src/adapter/mod.rs b/crates/executor/src/adapter/mod.rs index 8b10a58..f0bb783 100644 --- a/crates/executor/src/adapter/mod.rs +++ b/crates/executor/src/adapter/mod.rs @@ -119,21 +119,11 @@ impl<'a> Backend for RTEvmExecutorAdapter<'a> { } fn basic(&self, address: H160) -> Basic { - self.state - .get(address.as_bytes()) - .map(|raw| { - if raw.is_none() { - return Basic::default(); - } - Account::decode(raw.unwrap()).map_or_else( - |_| Default::default(), - |account| Basic { - balance: account.balance, - nonce: account.nonce, - }, - ) - }) - .unwrap_or_default() + let account = self.get_account(address); + Basic { + balance: account.balance, + nonce: account.nonce, + } } fn code(&self, address: H160) -> Vec { @@ -259,7 +249,7 @@ impl<'a> RTEvmExecutorAdapter<'a> { storage: I, reset_storage: bool, ) -> bool { - let (old_account, existing) = match self.state.get(address.as_bytes()) { + let (old_account, mut existing) = match self.state.get(address.as_bytes()) { Ok(Some(raw)) => (pnk!(Account::decode(raw)), true), _ => ( Account { @@ -271,6 +261,9 @@ impl<'a> RTEvmExecutorAdapter<'a> { false, ), }; + if old_account.storage_root == NIL_HASH { + existing = false; + } let storage_trie = if reset_storage { self.trie_db.trie_create(address.as_bytes(), true).c(d!()) diff --git a/crates/executor/src/lib.rs b/crates/executor/src/lib.rs index 0ef83e1..7f1aaac 100644 --- a/crates/executor/src/lib.rs +++ b/crates/executor/src/lib.rs @@ -20,12 +20,11 @@ use evm::{ CreateScheme, }; use rt_evm_model::{ - codec::ProtocolCodec, traits::{ApplyBackend, Backend, Executor, ExecutorAdapter as Adapter}, types::{ data_gas_cost, Account, Config, ExecResp, Hasher, SignedTransaction, TransactionAction, TxResp, GAS_CALL_TRANSACTION, GAS_CREATE_TRANSACTION, H160, - MIN_TRANSACTION_GAS_LIMIT, NIL_HASH, U256, + MIN_TRANSACTION_GAS_LIMIT, U256, }, }; use std::collections::BTreeMap; @@ -154,15 +153,7 @@ impl Executor for RTEvmExecutor { } fn get_account(&self, backend: &B, address: &H160) -> Account { - match backend.get(address.as_bytes()) { - Some(bytes) => Account::decode(bytes).unwrap(), - None => Account { - nonce: Default::default(), - balance: Default::default(), - storage_root: NIL_HASH, - code_hash: NIL_HASH, - }, - } + backend.get_account(*address) } } @@ -196,6 +187,7 @@ impl RTEvmExecutor { backend.save_account(sender, &account); let metadata = StackSubstateMetadata::new(gas_limit.as_u64(), config); + let mut executor = StackExecutor::new_with_precompiles( MemoryStackState::new(metadata, backend), config,