Skip to content

Commit

Permalink
rpcdaemon: estimate gas oracle rework (#1274)
Browse files Browse the repository at this point in the history
  • Loading branch information
lupin012 authored Jun 24, 2023
1 parent b1ace7b commit f866de6
Show file tree
Hide file tree
Showing 8 changed files with 346 additions and 177 deletions.
42 changes: 21 additions & 21 deletions silkworm/silkrpc/core/estimate_gas_oracle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,58 +78,61 @@ boost::asio::awaitable<intx::uint256> EstimateGasOracle::estimate_gas(const Call
SILK_DEBUG << "hi: " << hi << ", lo: " << lo << ", cap: " << cap;

auto this_executor = co_await boost::asio::this_coro::executor;
auto ret_success = co_await boost::asio::async_compose<decltype(boost::asio::use_awaitable), void(bool)>(
auto exec_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 = transaction_.create_state(this_executor, tx_database_, block_number);
EVMExecutor executor{config_, workers_, state};

ExecutionResult result{evmc_status_code::EVMC_SUCCESS};
silkworm::Transaction transaction{call.to_transaction()};
while (lo + 1 < hi) {
auto mid = (hi + lo) / 2;
transaction.gas_limit = mid;

auto success = try_execution(executor, block, transaction);
if (success) {
result = try_execution(executor, block, transaction);
if (result.error_code == evmc_status_code::EVMC_SUCCESS) {
hi = mid;
} else {
lo = mid;
if (result.pre_check_error == std::nullopt) {
break;
}
}
}

auto last_success = true;
if (hi == cap) {
transaction.gas_limit = hi;
last_success = try_execution(executor, block, transaction);
SILK_DEBUG << "HI == cap tested again with " << (last_success ? "succeed" : "failed");
result = try_execution(executor, block, transaction);
SILK_DEBUG << "HI == cap tested again with " << (result.error_code == evmc_status_code::EVMC_SUCCESS ? "succeed" : "failed");
} else if (result.error_code == pre_check_error) {
result.pre_check_error = std::nullopt;
result.error_code = evmc_status_code::EVMC_SUCCESS;
}

SILK_DEBUG << "EstimateGasOracle::estimate_gas returns " << hi;

boost::asio::post(this_executor, [last_success, self = std::move(self)]() mutable {
self.complete(last_success);
boost::asio::post(this_executor, [result, self = std::move(self)]() mutable {
self.complete(result);
});
});
},
boost::asio::use_awaitable);

if (!ret_success) {
throw EstimateGasException{-1, "gas required exceeds allowance (" + std::to_string(cap) + ")"};
if (exec_result.error_code != evmc_status_code::EVMC_SUCCESS || exec_result.pre_check_error) {
throw_exception(exec_result, cap);
}
co_return hi;
}

bool EstimateGasOracle::try_execution(EVMExecutor& executor, const silkworm::Block& block, const silkworm::Transaction& transaction) {
auto result = executor.call_sync(block, transaction);
ExecutionResult EstimateGasOracle::try_execution(EVMExecutor& executor, const silkworm::Block& block, const silkworm::Transaction& transaction) {
return executor.call_sync(block, transaction);
}

bool success = false;
void EstimateGasOracle::throw_exception(ExecutionResult& result, uint64_t cap) {
if (result.pre_check_error) {
SILK_DEBUG << "result error " << result.pre_check_error.value();
} else if (result.error_code == evmc_status_code::EVMC_SUCCESS) {
SILK_DEBUG << "result SUCCESS";
success = true;
} else if (result.error_code == evmc_status_code::EVMC_INSUFFICIENT_BALANCE) {
SILK_DEBUG << "result INSUFFICIENT BALANCE";
throw EstimateGasException{-1, "gas required exceeds allowance (" + std::to_string(cap) + ")"};
} else {
const auto error_message = EVMExecutor::get_error_message(result.error_code, result.data);
SILK_DEBUG << "result message " << error_message << ", code " << result.error_code;
Expand All @@ -139,8 +142,5 @@ bool EstimateGasOracle::try_execution(EVMExecutor& executor, const silkworm::Blo
throw EstimateGasException{3, error_message, result.data};
}
}

return success;
}

} // namespace silkworm::rpc
5 changes: 4 additions & 1 deletion silkworm/silkrpc/core/estimate_gas_oracle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace silkworm::rpc {

const std::uint64_t kTxGas = 21'000;
const std::uint64_t kGasCap = 25'000'000;
const std::uint64_t pre_check_error = 1000;

using BlockHeaderProvider = std::function<boost::asio::awaitable<silkworm::BlockHeader>(uint64_t)>;
using AccountReader = std::function<boost::asio::awaitable<std::optional<silkworm::Account>>(const evmc::address&, uint64_t)>;
Expand Down Expand Up @@ -89,9 +90,11 @@ class EstimateGasOracle {
boost::asio::awaitable<intx::uint256> estimate_gas(const Call& call, const silkworm::Block& latest_block);

protected:
virtual bool try_execution(EVMExecutor& executor, const silkworm::Block& _block, const silkworm::Transaction& transaction);
virtual ExecutionResult try_execution(EVMExecutor& executor, const silkworm::Block& _block, const silkworm::Transaction& transaction);

private:
void throw_exception(ExecutionResult& result, uint64_t cap);

const BlockHeaderProvider& block_header_provider_;
const AccountReader& account_reader_;
const silkworm::ChainConfig& config_;
Expand Down
Loading

0 comments on commit f866de6

Please sign in to comment.