Skip to content

Commit

Permalink
fix gas calc, sync with upstream crates
Browse files Browse the repository at this point in the history
  • Loading branch information
harryliisme3 authored and ktmlm committed Jul 21, 2023
1 parent 4a3b0f8 commit ed0a642
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 36 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"

####################################################################
####################################################################
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Option<Vec<u8>>> {
Expand Down
86 changes: 79 additions & 7 deletions crates/api/src/jsonrpc/impls/web3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down Expand Up @@ -303,11 +304,49 @@ impl<Adapter: APIAdapter + 'static> RTEvmWeb3RpcServer for Web3RpcImpl<Adapter>
.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());
}

Expand Down Expand Up @@ -380,6 +419,10 @@ impl<Adapter: APIAdapter + 'static> RTEvmWeb3RpcServer for Web3RpcImpl<Adapter>
Ok(U256::from(8u64))
}

async fn get_max_priority_fee_per_gas(&self) -> RpcResult<U256> {
Ok(U256::from(MAX_PRIORITY_FEE_PER_GAS))
}

async fn get_logs(&self, filter: Web3Filter) -> RpcResult<Vec<Web3Log>> {
let topics: Vec<Option<Vec<Option<H256>>>> = filter
.topics
Expand Down Expand Up @@ -508,10 +551,11 @@ impl<Adapter: APIAdapter + 'static> RTEvmWeb3RpcServer for Web3RpcImpl<Adapter>

(
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),
)
};

Expand Down Expand Up @@ -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::<u8>();
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:?}"))),
}
}
3 changes: 3 additions & 0 deletions crates/api/src/jsonrpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ pub trait RTEvmWeb3Rpc {
#[method(name = "eth_gasPrice")]
async fn gas_price(&self) -> RpcResult<U256>;

#[method(name = "eth_maxPriorityFeePerGas")]
async fn get_max_priority_fee_per_gas(&self) -> RpcResult<U256>;

#[method(name = "eth_getLogs")]
async fn get_logs(&self, filter: Web3Filter) -> RpcResult<Vec<Web3Log>>;

Expand Down
25 changes: 9 additions & 16 deletions crates/executor/src/adapter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8> {
Expand Down Expand Up @@ -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 {
Expand All @@ -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!())
Expand Down
14 changes: 3 additions & 11 deletions crates/executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -154,15 +153,7 @@ impl Executor for RTEvmExecutor {
}

fn get_account<B: Backend + Adapter>(&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)
}
}

Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit ed0a642

Please sign in to comment.