Skip to content

Commit

Permalink
Merge pull request #202 from eosnetworkfoundation/elmato/use-gas-para…
Browse files Browse the repository at this point in the history
…meters-trace-executor

[1.0.5] Refactor EVMExecutor::call
  • Loading branch information
elmato committed Sep 13, 2024
2 parents db4ab66 + aeaac37 commit 944f319
Show file tree
Hide file tree
Showing 13 changed files with 95 additions and 59 deletions.
8 changes: 4 additions & 4 deletions silkworm/silkrpc/commands/eth_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1160,7 +1160,7 @@ awaitable<void> EthereumRpcApi::handle_eth_call(const nlohmann::json& request, s
const auto execution_result = co_await EVMExecutor::call(
*chain_config_ptr, workers_, block_with_hash->block, txn, [&](auto& io_executor, auto block_num) {
return tx->create_state(io_executor, db_reader, block_num);
}, {}, true, false, eos_evm_version, gas_params);
}, gas_params, eos_evm_version, {}, true, txn.from == evmc::address{0});

if (execution_result.success()) {
make_glaze_json_content(reply, request["id"], execution_result.data);
Expand Down Expand Up @@ -1343,8 +1343,8 @@ awaitable<void> EthereumRpcApi::handle_eth_create_access_list(const nlohmann::js
const auto execution_result = co_await EVMExecutor::call(
*chain_config_ptr, workers_, block_with_hash->block, txn, [&](auto& io_executor, auto block_num) {
return tx->create_state(io_executor, db_reader, block_num);
},
std::move(tracers), /* refund */ true, /* gasBailout */ false, eos_evm_version, gas_params);
}, gas_params, eos_evm_version,
std::move(tracers), /* refund */ true, /* gasBailout */ false);

if (execution_result.pre_check_error) {
reply = make_json_error(request["id"], -32000, execution_result.pre_check_error.value());
Expand Down Expand Up @@ -1434,7 +1434,7 @@ awaitable<void> EthereumRpcApi::handle_eth_call_bundle(const nlohmann::json& req
const auto execution_result = co_await EVMExecutor::call(
*chain_config_ptr, workers_, block_with_hash->block, tx_with_block->transaction, [&](auto& io_executor, auto block_num) {
return tx->create_state(io_executor, db_reader, block_num);
}, {}, true, false, eos_evm_version, gas_params);
}, gas_params, eos_evm_version, {}, true, false);
if (execution_result.pre_check_error) {
reply = make_json_error(request["id"], -32000, execution_result.pre_check_error.value());
error = true;
Expand Down
3 changes: 2 additions & 1 deletion silkworm/silkrpc/commands/trace_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
#include <silkworm/silkrpc/json/types.hpp>
#include <silkworm/silkrpc/types/call.hpp>
#include <silkworm/silkrpc/commands/rpc_api_quirk.hpp>

#include <silkworm/silkrpc/core/rawdb/chain.hpp>
#include <silkworm/silkrpc/core/gas_parameters.hpp>
namespace silkworm::rpc::commands {

// https://eth.wiki/json-rpc/API#trace_call
Expand Down
13 changes: 8 additions & 5 deletions silkworm/silkrpc/core/call_many.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
#include <silkworm/silkrpc/core/remote_state.hpp>
#include <silkworm/silkrpc/ethdb/kv/cached_database.hpp>
#include <silkworm/silkrpc/json/types.hpp>

#include <silkworm/silkrpc/core/gas_parameters.hpp>
namespace silkworm::rpc::call {

using boost::asio::awaitable;
Expand All @@ -53,7 +53,9 @@ CallManyResult CallExecutor::executes_all_bundles(const silkworm::ChainConfig* c
std::optional<std::uint64_t> opt_timeout,
const AccountsOverrides& accounts_overrides,
int32_t transaction_index,
boost::asio::any_io_executor& this_executor) {
boost::asio::any_io_executor& this_executor,
const evmone::gas_parameters& gas_params,
uint64_t eos_evm_version) {
CallManyResult result;
const auto& block = block_with_hash.block;
const auto& block_transactions = block.transactions;
Expand All @@ -70,7 +72,7 @@ CallManyResult CallExecutor::executes_all_bundles(const silkworm::ChainConfig* c
txn.recover_sender();
}

auto exec_result = executor.call(block, txn);
auto exec_result = executor.call(block, txn, gas_params, eos_evm_version);

if ((clock_time::since(start_time) / 1000000) > timeout) {
std::ostringstream oss;
Expand Down Expand Up @@ -110,7 +112,7 @@ CallManyResult CallExecutor::executes_all_bundles(const silkworm::ChainConfig* c
for (const auto& call : bundle.transactions) {
silkworm::Transaction txn{call.to_transaction()};

auto call_execution_result = executor.call(blockContext.block, txn);
auto call_execution_result = executor.call(blockContext.block, txn, gas_params, eos_evm_version);

if (call_execution_result.pre_check_error) {
result.error = call_execution_result.pre_check_error;
Expand Down Expand Up @@ -171,12 +173,13 @@ boost::asio::awaitable<CallManyResult> CallExecutor::execute(const Bundles& bund
if (transaction_index == -1) {
transaction_index = static_cast<std::int32_t>(block_with_hash->block.transactions.size());
}
const auto [eos_evm_version, gas_params] = co_await load_gas_parameters(tx_database, chain_config_ptr, block_with_hash->block);

auto this_executor = co_await boost::asio::this_coro::executor;
result = co_await boost::asio::async_compose<decltype(boost::asio::use_awaitable), void(CallManyResult)>(
[&](auto&& self) {
boost::asio::post(workers_, [&, self = std::move(self)]() mutable {
result = executes_all_bundles(chain_config_ptr, *block_with_hash, tx_database, bundles, opt_timeout, accounts_overrides, transaction_index, this_executor);
result = executes_all_bundles(chain_config_ptr, *block_with_hash, tx_database, bundles, opt_timeout, accounts_overrides, transaction_index, this_executor, gas_params, eos_evm_version);
boost::asio::post(this_executor, [result, self = std::move(self)]() mutable {
self.complete(result);
});
Expand Down
5 changes: 4 additions & 1 deletion silkworm/silkrpc/core/call_many.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <silkworm/silkrpc/types/block.hpp>
#include <silkworm/silkrpc/types/call.hpp>
#include <silkworm/silkrpc/types/transaction.hpp>
#include <silkworm/silkrpc/core/gas_parameters.hpp>

namespace silkworm::rpc::call {

Expand Down Expand Up @@ -68,7 +69,9 @@ class CallExecutor {
std::optional<std::uint64_t> opt_timeout,
const AccountsOverrides& accounts_overrides,
int32_t transaction_index,
boost::asio::any_io_executor& executor);
boost::asio::any_io_executor& executor,
const evmone::gas_parameters& gas_params,
uint64_t eos_evm_version);

private:
ethdb::Transaction& transaction_;
Expand Down
2 changes: 1 addition & 1 deletion silkworm/silkrpc/core/estimate_gas_oracle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ boost::asio::awaitable<intx::uint256> EstimateGasOracle::estimate_gas(const Call

ExecutionResult EstimateGasOracle::try_execution(EVMExecutor& executor, const silkworm::Block& block, const silkworm::Transaction& transaction, uint64_t eos_evm_version, const evmone::gas_parameters& gas_params) {
executor.reset_all();
return executor.call(block, transaction, {}, true, false, eos_evm_version, gas_params);
return executor.call(block, transaction, gas_params, eos_evm_version, {}, true, false);
}

void EstimateGasOracle::throw_exception(ExecutionResult& result, uint64_t cap) {
Expand Down
15 changes: 9 additions & 6 deletions silkworm/silkrpc/core/evm_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
#include <silkworm/silkrpc/core/rawdb/chain.hpp>
#include <silkworm/silkrpc/ethdb/transaction_database.hpp>
#include <silkworm/silkrpc/json/types.hpp>

#include <silkworm/silkrpc/core/gas_parameters.hpp>
namespace silkworm::rpc::debug {

using boost::asio::awaitable;
Expand Down Expand Up @@ -347,6 +347,7 @@ awaitable<void> DebugExecutor::execute(json::Stream& stream, const silkworm::Blo

const auto chain_id = co_await core::rawdb::read_chain_id(database_reader_);
const auto chain_config_ptr = lookup_chain_config(chain_id);
const auto [eos_evm_version, gas_params] = co_await load_gas_parameters(database_reader_, chain_config_ptr, block);
auto current_executor = co_await boost::asio::this_coro::executor;

co_await boost::asio::async_compose<decltype(boost::asio::use_awaitable), void(void)>(
Expand All @@ -371,7 +372,7 @@ awaitable<void> DebugExecutor::execute(json::Stream& stream, const silkworm::Blo
stream.open_array();

Tracers tracers{debug_tracer};
const auto execution_result = executor.call(block, txn, std::move(tracers), /* refund */ false, /* gasBailout */ false);
const auto execution_result = executor.call(block, txn, gas_params, eos_evm_version, std::move(tracers), /* refund */ false, /* gasBailout */ false);

debug_tracer->flush_logs();
stream.close_array();
Expand Down Expand Up @@ -411,6 +412,7 @@ awaitable<void> DebugExecutor::execute(json::Stream& stream, uint64_t block_numb

const auto chain_id = co_await core::rawdb::read_chain_id(database_reader_);
const auto chain_config_ptr = lookup_chain_config(chain_id);
const auto [eos_evm_version, gas_params] = co_await load_gas_parameters(database_reader_, chain_config_ptr, block);
auto current_executor = co_await boost::asio::this_coro::executor;

co_await boost::asio::async_compose<decltype(boost::asio::use_awaitable), void(void)>(
Expand All @@ -425,7 +427,7 @@ awaitable<void> DebugExecutor::execute(json::Stream& stream, uint64_t block_numb
if (!txn.from) {
txn.recover_sender();
}
executor.call(block, txn);
executor.call(block, txn, gas_params, eos_evm_version);
}
executor.reset();

Expand All @@ -435,7 +437,7 @@ awaitable<void> DebugExecutor::execute(json::Stream& stream, uint64_t block_numb
stream.open_array();

Tracers tracers{debug_tracer};
const auto execution_result = executor.call(block, transaction, std::move(tracers));
const auto execution_result = executor.call(block, transaction, gas_params, eos_evm_version, std::move(tracers));

debug_tracer->flush_logs();
stream.close_array();
Expand Down Expand Up @@ -473,6 +475,7 @@ awaitable<void> DebugExecutor::execute(json::Stream& stream,

const auto chain_id = co_await core::rawdb::read_chain_id(database_reader_);
const auto chain_config_ptr = lookup_chain_config(chain_id);
const auto [eos_evm_version, gas_params] = co_await load_gas_parameters(database_reader_, chain_config_ptr, block);

auto current_executor = co_await boost::asio::this_coro::executor;
co_await boost::asio::async_compose<decltype(boost::asio::use_awaitable), void(void)>(
Expand All @@ -488,7 +491,7 @@ awaitable<void> DebugExecutor::execute(json::Stream& stream,
txn.recover_sender();
}

executor.call(block, txn);
executor.call(block, txn, gas_params, eos_evm_version);
}
executor.reset();

Expand Down Expand Up @@ -527,7 +530,7 @@ awaitable<void> DebugExecutor::execute(json::Stream& stream,
auto debug_tracer = std::make_shared<debug::DebugTracer>(stream, config_);
Tracers tracers{debug_tracer};

const auto execution_result = executor.call(blockContext.block, txn, std::move(tracers), /* refund */ false, /* gasBailout */ false);
const auto execution_result = executor.call(blockContext.block, txn, gas_params, eos_evm_version, std::move(tracers), /* refund */ false, /* gasBailout */ false);

debug_tracer->flush_logs();
stream.close_array();
Expand Down
55 changes: 36 additions & 19 deletions silkworm/silkrpc/core/evm_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,17 +166,23 @@ std::string EVMExecutor::get_error_message(int64_t error_code, const Bytes& erro

uint64_t EVMExecutor::refund_gas(const EVM& evm, const silkworm::Transaction& txn, uint64_t gas_left, uint64_t gas_refund) {
const evmc_revision rev{evm.revision()};
const uint64_t max_refund_quotient{rev >= EVMC_LONDON ? protocol::kMaxRefundQuotientLondon
: protocol::kMaxRefundQuotientFrontier};
const uint64_t max_refund{(txn.gas_limit - gas_left) / max_refund_quotient};
uint64_t refund = gas_refund < max_refund ? gas_refund : max_refund; // min
gas_left += refund;
if( evm.get_eos_evm_version() < 2 ) {
const uint64_t max_refund_quotient{rev >= EVMC_LONDON ? protocol::kMaxRefundQuotientLondon
: protocol::kMaxRefundQuotientFrontier};
const uint64_t max_refund{(txn.gas_limit - gas_left) / max_refund_quotient};
uint64_t refund = gas_refund < max_refund ? gas_refund : max_refund; // min
gas_left += refund;
} else {
gas_left += gas_refund;
if( gas_left > txn.gas_limit - silkworm::protocol::fee::kGTransaction ) {
gas_left = txn.gas_limit - silkworm::protocol::fee::kGTransaction;
}
}

const intx::uint256 base_fee_per_gas{evm.block().header.base_fee_per_gas.value_or(0)};
SILK_DEBUG << "EVMExecutor::refund_gas txn.max_fee_per_gas: " << txn.max_fee_per_gas << " base_fee_per_gas: " << base_fee_per_gas;
const intx::uint256 effective_gas_price{txn.max_fee_per_gas >= base_fee_per_gas ? txn.effective_gas_price(base_fee_per_gas)
: txn.max_priority_fee_per_gas};
SILK_DEBUG << "EVMExecutor::refund_gas effective_gas_price: " << effective_gas_price;
SILK_DEBUG << "EVMExecutor::refund_gas effective_gas_price: " << effective_gas_price << ", txn.max_fee_per_gas: " << txn.max_fee_per_gas << ", base_fee_per_gas: " << base_fee_per_gas;
ibs_state_.add_to_balance(*txn.from, gas_left * effective_gas_price);
return gas_left;
}
Expand Down Expand Up @@ -220,11 +226,11 @@ std::optional<std::string> EVMExecutor::pre_check(const EVM& evm, const silkworm
ExecutionResult EVMExecutor::call(
const silkworm::Block& block,
const silkworm::Transaction& txn,
const evmone::gas_parameters& gas_params,
uint64_t eos_evm_version,
Tracers tracers,
bool refund,
bool gas_bailout,
uint64_t eos_evm_version,
const evmone::gas_parameters& gas_params) {
bool gas_bailout) {
SILK_DEBUG << "EVMExecutor::call: " << block.header.number << " gasLimit: " << txn.gas_limit << " refund: " << refund << " gasBailout: " << gas_bailout;
SILK_DEBUG << "EVMExecutor::call: transaction: " << &txn;

Expand Down Expand Up @@ -260,13 +266,19 @@ ExecutionResult EVMExecutor::call(
}

intx::uint256 want;
const intx::uint256 effective_gas_price{txn.max_fee_per_gas >= base_fee_per_gas ? txn.effective_gas_price(base_fee_per_gas)
: txn.max_priority_fee_per_gas};
if (txn.max_fee_per_gas > 0 || txn.max_priority_fee_per_gas > 0) {
// This method should be called after check (max_fee and base_fee) present in pre_check() method
const intx::uint256 effective_gas_price{txn.effective_gas_price(base_fee_per_gas)};
want = txn.gas_limit * effective_gas_price;
} else {
want = 0;
}

// EIP-4844 data gas cost (calc_data_fee)
const intx::uint256 data_gas_price{evm.block().header.data_gas_price().value_or(0)};
want += txn.total_data_gas() * data_gas_price;

const auto have = ibs_state_.get_balance(*txn.from);
if (have < want + txn.value) {
if (!gas_bailout) {
Expand All @@ -290,6 +302,12 @@ ExecutionResult EVMExecutor::call(
ibs_state_.access_storage(ae.account, key);
}
}

if (rev >= EVMC_SHANGHAI) {
// EIP-3651: Warm COINBASE
ibs_state_.access_account(evm.beneficiary);
}

silkworm::CallResult result;
try {
SILK_DEBUG << "EVMExecutor::call execute on EVM txn: " << &txn << " g0: " << static_cast<uint64_t>(g0) << " start";
Expand All @@ -312,10 +330,9 @@ ExecutionResult EVMExecutor::call(
}

// Reward the fee recipient
const intx::uint256 priority_fee_per_gas{txn.max_fee_per_gas >= base_fee_per_gas ? txn.priority_fee_per_gas(base_fee_per_gas)
: txn.max_priority_fee_per_gas};
SILK_DEBUG << "EVMExecutor::call evm.beneficiary: " << evm.beneficiary << " balance: " << priority_fee_per_gas * gas_used;
ibs_state_.add_to_balance(evm.beneficiary, priority_fee_per_gas * gas_used);
const intx::uint256 price{evm.config().protocol_rule_set == protocol::RuleSetType::kTrust ? effective_gas_price : txn.priority_fee_per_gas(base_fee_per_gas)};
ibs_state_.add_to_balance(evm.beneficiary, price * gas_used);
SILK_DEBUG << "EVMExecutor::call evm.beneficiary: " << evm.beneficiary << " balance: " << price * gas_used;

for (auto tracer : evm.tracers()) {
tracer.get().on_reward_granted(result, evm.state());
Expand All @@ -334,18 +351,18 @@ awaitable<ExecutionResult> EVMExecutor::call(const silkworm::ChainConfig& config
const silkworm::Block& block,
const silkworm::Transaction& txn,
StateFactory state_factory,
const evmone::gas_parameters& gas_params,
uint64_t eos_evm_version,
Tracers tracers,
bool refund,
bool gas_bailout,
uint64_t eos_evm_version,
const evmone::gas_parameters& gas_params) {
bool gas_bailout) {
auto this_executor = co_await boost::asio::this_coro::executor;
const auto execution_result = co_await boost::asio::async_compose<decltype(boost::asio::use_awaitable), void(ExecutionResult)>(
[&](auto&& self) {
boost::asio::post(workers, [&, self = std::move(self)]() mutable {
auto state = state_factory(this_executor, block.header.number);
EVMExecutor executor{config, workers, state};
auto exec_result = executor.call(block, txn, tracers, refund, gas_bailout, eos_evm_version, gas_params);
auto exec_result = executor.call(block, txn, gas_params, eos_evm_version, tracers, refund, gas_bailout);
boost::asio::post(this_executor, [exec_result, self = std::move(self)]() mutable {
self.complete(exec_result);
});
Expand Down
Loading

0 comments on commit 944f319

Please sign in to comment.