Skip to content

Commit

Permalink
rpcdaemon: add ExecutionResult methods to retrieve success and error_…
Browse files Browse the repository at this point in the history
…message (#1294)
  • Loading branch information
lupin012 committed Jun 28, 2023
1 parent 5ed320e commit b2d9bd4
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 65 deletions.
16 changes: 6 additions & 10 deletions silkworm/silkrpc/commands/eth_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1118,12 +1118,10 @@ awaitable<void> EthereumRpcApi::handle_eth_call(const nlohmann::json& request, s
return tx->create_state(io_executor, db_reader, block_num);
});

if (execution_result.pre_check_error) {
make_glaze_json_error(reply, request["id"], -32000, execution_result.pre_check_error.value());
} else if (execution_result.error_code == evmc_status_code::EVMC_SUCCESS) {
if (execution_result.success()) {
make_glaze_json_content(reply, request["id"], execution_result.data);
} else {
const auto error_message = EVMExecutor::get_error_message(execution_result.error_code, execution_result.data);
const auto error_message = execution_result.error_message();
if (execution_result.data.empty()) {
make_glaze_json_error(reply, request["id"], -32000, error_message);
} else {
Expand Down Expand Up @@ -1313,9 +1311,8 @@ awaitable<void> EthereumRpcApi::handle_eth_create_access_list(const nlohmann::js
AccessListResult access_list_result;
access_list_result.access_list = current_access_list;
access_list_result.gas_used = txn.gas_limit - execution_result.gas_left;
if (execution_result.error_code != evmc_status_code::EVMC_SUCCESS) {
const auto error_message = EVMExecutor::get_error_message(execution_result.error_code, execution_result.data, false /* full_error */);
access_list_result.error = error_message;
if (execution_result.success() == false) {
access_list_result.error = execution_result.error_message(false /* full_error */);
}
reply = make_json_content(request["id"], access_list_result);
break;
Expand Down Expand Up @@ -1408,9 +1405,8 @@ awaitable<void> EthereumRpcApi::handle_eth_call_bundle(const nlohmann::json& req
tx_info.gas_used = tx_with_block->transaction.gas_limit - execution_result.gas_left;
tx_info.hash = hash_of_transaction(tx_with_block->transaction);

if (execution_result.error_code != evmc_status_code::EVMC_SUCCESS) {
const auto error_message = EVMExecutor::get_error_message(execution_result.error_code, execution_result.data, false /* full_error */);
tx_info.error_message = error_message;
if (execution_result.success() == false) {
tx_info.error_message = execution_result.error_message(false /* full_error */);
} else {
tx_info.value = silkworm::to_bytes32(execution_result.data);
}
Expand Down
2 changes: 1 addition & 1 deletion silkworm/silkrpc/core/call_many.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ CallManyResult CallExecutor::executes_all_bundles(const silkworm::ChainConfig* c
if (call_execution_result.error_code == evmc_status_code::EVMC_SUCCESS) {
reply["value"] = "0x" + silkworm::to_hex(call_execution_result.data);
} else {
const auto error_message = EVMExecutor::get_error_message(call_execution_result.error_code, call_execution_result.data);
const auto error_message = call_execution_result.error_message();
if (call_execution_result.data.empty()) {
reply["error"] = error_message;
} else {
Expand Down
10 changes: 5 additions & 5 deletions silkworm/silkrpc/core/estimate_gas_oracle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ boost::asio::awaitable<intx::uint256> EstimateGasOracle::estimate_gas(const Call
transaction.gas_limit = mid;

result = try_execution(executor, block, transaction);
if (result.error_code == evmc_status_code::EVMC_SUCCESS) {
if (result.success()) {
hi = mid;
} else {
lo = mid;
Expand All @@ -105,7 +105,7 @@ boost::asio::awaitable<intx::uint256> EstimateGasOracle::estimate_gas(const Call
transaction.gas_limit = hi;
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) {
} else if (result.error_code == std::nullopt) {
result.pre_check_error = std::nullopt;
result.error_code = evmc_status_code::EVMC_SUCCESS;
}
Expand All @@ -119,7 +119,7 @@ boost::asio::awaitable<intx::uint256> EstimateGasOracle::estimate_gas(const Call
},
boost::asio::use_awaitable);

if (exec_result.error_code != evmc_status_code::EVMC_SUCCESS || exec_result.pre_check_error) {
if (exec_result.success() == false) {
throw_exception(exec_result, cap);
}
co_return hi;
Expand All @@ -134,8 +134,8 @@ void EstimateGasOracle::throw_exception(ExecutionResult& result, uint64_t cap) {
SILK_DEBUG << "result error " << result.pre_check_error.value();
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;
auto error_message = result.error_message();
SILK_DEBUG << "result message: " << error_message << ", code " << *result.error_code;
if (result.data.empty()) {
throw EstimateGasException{-32000, error_message};
} else {
Expand Down
1 change: 0 additions & 1 deletion silkworm/silkrpc/core/estimate_gas_oracle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ 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
46 changes: 23 additions & 23 deletions silkworm/silkrpc/core/estimate_gas_oracle_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ TEST_CASE("estimate gas") {
MockEstimateGasOracle estimate_gas_oracle{block_header_provider, account_reader, config, workers, *tx, tx_database};

SECTION("Call empty, always fails but success in last step") {
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS, .pre_check_error = std::nullopt};
ExecutionResult expect_result_fail{.error_code = pre_check_error, .pre_check_error = "intrisic gas"};
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS};
ExecutionResult expect_result_fail{.pre_check_error = "intrisic gas"};
EXPECT_CALL(estimate_gas_oracle, try_execution(_, _, _))
.Times(16)
.WillOnce(Return(expect_result_fail))
Expand All @@ -128,16 +128,16 @@ TEST_CASE("estimate gas") {
}

SECTION("Call empty, always succeeds") {
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS, .pre_check_error = std::nullopt};
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS};
EXPECT_CALL(estimate_gas_oracle, try_execution(_, _, _)).Times(14).WillRepeatedly(Return(expect_result_ok));
auto result = boost::asio::co_spawn(pool, estimate_gas_oracle.estimate_gas(call, block), boost::asio::use_future);
const intx::uint256& estimate_gas = result.get();
CHECK(estimate_gas == kTxGas);
}

SECTION("Call empty, alternatively fails and succeeds") {
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS, .pre_check_error = std::nullopt};
ExecutionResult expect_result_fail{.error_code = pre_check_error, .pre_check_error = "intrisic gas"};
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS};
ExecutionResult expect_result_fail{.pre_check_error = "intrisic gas"};
EXPECT_CALL(estimate_gas_oracle, try_execution(_, _, _))
.Times(14)
.WillOnce(Return(expect_result_fail))
Expand All @@ -161,8 +161,8 @@ TEST_CASE("estimate gas") {
}

SECTION("Call empty, alternatively succeeds and fails") {
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS, .pre_check_error = std::nullopt};
ExecutionResult expect_result_fail{.error_code = pre_check_error, .pre_check_error = "intrisic gas"};
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS};
ExecutionResult expect_result_fail{.pre_check_error = "intrisic gas"};
EXPECT_CALL(estimate_gas_oracle, try_execution(_, _, _))
.Times(14)
.WillOnce(Return(expect_result_ok))
Expand All @@ -187,8 +187,8 @@ TEST_CASE("estimate gas") {

SECTION("Call with gas, always fails but succes last step") {
call.gas = kTxGas * 4;
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS, .pre_check_error = std::nullopt};
ExecutionResult expect_result_fail{.error_code = pre_check_error, .pre_check_error = "intrisic gas"};
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS};
ExecutionResult expect_result_fail{.pre_check_error = "intrisic gas"};
EXPECT_CALL(estimate_gas_oracle, try_execution(_, _, _))
.Times(17)
.WillOnce(Return(expect_result_fail))
Expand Down Expand Up @@ -216,7 +216,7 @@ TEST_CASE("estimate gas") {

SECTION("Call with gas, always succeeds") {
call.gas = kTxGas * 4;
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS, .pre_check_error = std::nullopt};
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS};
EXPECT_CALL(estimate_gas_oracle, try_execution(_, _, _))
.Times(15)
.WillRepeatedly(Return(expect_result_ok));
Expand All @@ -227,8 +227,8 @@ TEST_CASE("estimate gas") {
}

SECTION("Call with gas_price, gas not capped") {
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS, .pre_check_error = std::nullopt};
ExecutionResult expect_result_fail{.error_code = pre_check_error, .pre_check_error = "intrisic gas"};
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS};
ExecutionResult expect_result_fail{.pre_check_error = "intrisic gas"};
call.gas = kTxGas * 2;
call.gas_price = intx::uint256{10'000};

Expand Down Expand Up @@ -257,8 +257,8 @@ TEST_CASE("estimate gas") {
}

SECTION("Call with gas_price, gas capped") {
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS, .pre_check_error = std::nullopt};
ExecutionResult expect_result_fail{.error_code = pre_check_error, .pre_check_error = "intrisic gas"};
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS};
ExecutionResult expect_result_fail{.pre_check_error = "intrisic gas"};
call.gas = kTxGas * 2;
call.gas_price = intx::uint256{40'000};

Expand All @@ -284,8 +284,8 @@ TEST_CASE("estimate gas") {
}

SECTION("Call with gas_price and value, gas not capped") {
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS, .pre_check_error = std::nullopt};
ExecutionResult expect_result_fail{.error_code = pre_check_error, .pre_check_error = "intrisic gas"};
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS};
ExecutionResult expect_result_fail{.pre_check_error = "intrisic gas"};
call.gas = kTxGas * 2;
call.gas_price = intx::uint256{10'000};
call.value = intx::uint256{500'000'000};
Expand Down Expand Up @@ -315,8 +315,8 @@ TEST_CASE("estimate gas") {
}

SECTION("Call with gas_price and value, gas capped") {
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS, .pre_check_error = std::nullopt};
ExecutionResult expect_result_fail{.error_code = pre_check_error, .pre_check_error = "intrisic gas"};
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS};
ExecutionResult expect_result_fail{.pre_check_error = "intrisic gas"};
call.gas = kTxGas * 2;
call.gas_price = intx::uint256{20'000};
call.value = intx::uint256{500'000'000};
Expand All @@ -343,7 +343,7 @@ TEST_CASE("estimate gas") {
}

SECTION("Call gas above allowance, always succeeds, gas capped") {
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS, .pre_check_error = std::nullopt};
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS};
call.gas = kGasCap * 2;
EXPECT_CALL(estimate_gas_oracle, try_execution(_, _, _)).Times(24).WillRepeatedly(Return(expect_result_ok));
auto result = boost::asio::co_spawn(pool, estimate_gas_oracle.estimate_gas(call, block), boost::asio::use_future);
Expand All @@ -353,7 +353,7 @@ TEST_CASE("estimate gas") {
}

SECTION("Call gas below minimum, always succeeds") {
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS, .pre_check_error = std::nullopt};
ExecutionResult expect_result_ok{.error_code = evmc_status_code::EVMC_SUCCESS};
call.gas = kTxGas / 2;

EXPECT_CALL(estimate_gas_oracle, try_execution(_, _, _)).Times(14).WillRepeatedly(Return(expect_result_ok));
Expand All @@ -364,7 +364,7 @@ TEST_CASE("estimate gas") {
}

SECTION("Call with too high value, exception") {
ExecutionResult expect_result_fail{.error_code = pre_check_error, .pre_check_error = "intrisic gas"};
ExecutionResult expect_result_fail{.pre_check_error = "intrisic gas"};
call.value = intx::uint256{2'000'000'000};

try {
Expand All @@ -383,7 +383,7 @@ TEST_CASE("estimate gas") {

SECTION("Call fail, try exception") {
ExecutionResult expect_result_fail_pre_check{.error_code = 4, .pre_check_error = "intrinsic gas"};
ExecutionResult expect_result_fail{.error_code = 4, .pre_check_error = std::nullopt};
ExecutionResult expect_result_fail{.error_code = 4};
call.gas = kTxGas * 2;
call.gas_price = intx::uint256{20'000};
call.value = intx::uint256{500'000'000};
Expand All @@ -408,7 +408,7 @@ TEST_CASE("estimate gas") {
SECTION("Call fail, try exception with data") {
ExecutionResult expect_result_fail_pre_check{.error_code = 4, .pre_check_error = "intrinsic gas"};
auto data = *silkworm::from_hex("2ac3c1d3e24b45c6c310534bc2dd84b5ed576335");
ExecutionResult expect_result_fail{.error_code = 4, .data = data, .pre_check_error = std::nullopt};
ExecutionResult expect_result_fail{.error_code = 4, .data = data};
call.gas = kTxGas * 2;
call.gas_price = intx::uint256{20'000};
call.value = intx::uint256{500'000'000};
Expand Down
26 changes: 10 additions & 16 deletions silkworm/silkrpc/core/evm_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,15 +376,12 @@ awaitable<void> DebugExecutor::execute(json::Stream& stream, const silkworm::Blo
debug_tracer->flush_logs();
stream.close_array();

if (execution_result.pre_check_error) {
SILK_DEBUG << "debug failed: " << execution_result.pre_check_error.value();

stream.write_field("failed", true);
} else {
stream.write_field("failed", execution_result.error_code != evmc_status_code::EVMC_SUCCESS);
stream.write_field("failed", !execution_result.success());
if (!execution_result.pre_check_error) {
stream.write_field("gas", txn.gas_limit - execution_result.gas_left);
stream.write_field("returnValue", silkworm::to_hex(execution_result.data));
}

stream.close_object();
stream.close_object();
}
Expand Down Expand Up @@ -442,12 +439,11 @@ awaitable<void> DebugExecutor::execute(json::Stream& stream, uint64_t block_numb

debug_tracer->flush_logs();
stream.close_array();
if (execution_result.pre_check_error) {
SILK_DEBUG << "debug failed: " << execution_result.pre_check_error.value();

stream.write_field("failed", true);
} else {
stream.write_field("failed", execution_result.error_code != evmc_status_code::EVMC_SUCCESS);
SILK_DEBUG << "debug return: " << execution_result.error_message();

stream.write_field("failed", !execution_result.success());
if (!execution_result.pre_check_error) {
stream.write_field("gas", transaction.gas_limit - execution_result.gas_left);
stream.write_field("returnValue", silkworm::to_hex(execution_result.data));
}
Expand Down Expand Up @@ -536,12 +532,10 @@ awaitable<void> DebugExecutor::execute(json::Stream& stream,
debug_tracer->flush_logs();
stream.close_array();

if (execution_result.pre_check_error) {
SILK_DEBUG << "debug failed: " << execution_result.pre_check_error.value();
SILK_DEBUG << "debug return: " << execution_result.error_message();

stream.write_field("failed", true);
} else {
stream.write_field("failed", execution_result.error_code != evmc_status_code::EVMC_SUCCESS);
stream.write_field("failed", !execution_result.success());
if (!execution_result.pre_check_error) {
stream.write_field("gas", txn.gas_limit - execution_result.gas_left);
stream.write_field("returnValue", silkworm::to_hex(execution_result.data));
}
Expand Down
16 changes: 13 additions & 3 deletions silkworm/silkrpc/core/evm_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@

namespace silkworm::rpc {

std::string ExecutionResult::error_message(bool full_error) const {
if (pre_check_error) {
return *pre_check_error;
}
if (error_code) {
return silkworm::rpc::EVMExecutor::get_error_message(*error_code, data, full_error);
}
return "";
}

static Bytes build_abi_selector(const std::string& signature) {
const auto signature_hash = hash_of(byte_view_of_string(signature));
return {std::begin(signature_hash.bytes), std::begin(signature_hash.bytes) + 4};
Expand Down Expand Up @@ -231,7 +241,7 @@ ExecutionResult EVMExecutor::call(
const auto error = pre_check(evm, txn, base_fee_per_gas, g0);
if (error) {
Bytes data{};
return {1000, txn.gas_limit, data, *error};
return {std::nullopt, txn.gas_limit, data, *error};
}

intx::uint256 want;
Expand All @@ -248,7 +258,7 @@ ExecutionResult EVMExecutor::call(
Bytes data{};
std::string from = to_hex(*txn.from);
std::string msg = "insufficient funds for gas * price + value: address 0x" + from + " have " + intx::to_string(have) + " want " + intx::to_string(want + txn.value);
return {1000, txn.gas_limit, data, msg};
return {std::nullopt, txn.gas_limit, data, msg};
}
} else {
ibs_state_.subtract_from_balance(*txn.from, want);
Expand Down Expand Up @@ -289,7 +299,7 @@ ExecutionResult EVMExecutor::call(

ExecutionResult exec_result{result.status, gas_left, result.data};

SILK_DEBUG << "EVMExecutor::call call_result: " << exec_result.error_code << " #data: " << exec_result.data.size() << " end";
SILK_DEBUG << "EVMExecutor::call call_result: " << exec_result.error_message() << " #data: " << exec_result.data.size() << " end";

return exec_result;
}
Expand Down
10 changes: 8 additions & 2 deletions silkworm/silkrpc/core/evm_executor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,16 @@
namespace silkworm::rpc {

struct ExecutionResult {
int64_t error_code;
std::optional<int64_t> error_code;
uint64_t gas_left;
Bytes data;
std::optional<std::string> pre_check_error{std::nullopt};
std::optional<std::string> pre_check_error;

bool success() const {
return ((error_code == std::nullopt || *error_code == evmc_status_code::EVMC_SUCCESS) && pre_check_error == std::nullopt);
}

std::string error_message(bool full_error = true) const;
};

constexpr int kCacheSize = 32000;
Expand Down
Loading

0 comments on commit b2d9bd4

Please sign in to comment.