Skip to content

Commit

Permalink
rpcdaemon: fix trace_* API family gas cost (#2187)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sixtysixter authored Aug 2, 2024
1 parent 8f1e05a commit 33875b4
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rpc-integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: Checkout RPC Tests Repository & Install Requirements
run: |
rm -rf ${{runner.workspace}}/rpc-tests
git -c advice.detachedHead=false clone --depth 1 --branch v0.33.0 https://github.com/erigontech/rpc-tests ${{runner.workspace}}/rpc-tests
git -c advice.detachedHead=false clone --depth 1 --branch v0.34.0 https://github.com/erigontech/rpc-tests ${{runner.workspace}}/rpc-tests
cd ${{runner.workspace}}/rpc-tests
pip3 install -r requirements.txt
Expand Down
2 changes: 1 addition & 1 deletion silkworm/rpc/core/evm_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ void DebugTracer::fill_call_gas_info(unsigned char opcode, const evmone::Executi
const auto dst = intx::be::trunc<evmc::address>(stack_top[-1]); // dst

if ((value != 0 || execution_state.rev < EVMC_SPURIOUS_DRAGON) && !intra_block_state.exists(dst)) {
fix_call_gas_info_->gas_cost += 25000;
fix_call_gas_info_->gas_cost += 25000; // add ACCOUNT_CREATION_COST as in instructions_calls.cpp:105
}
SILK_DEBUG << "DebugTracer::evaluate_call_fixes:"
<< " call_gas: " << call_gas
Expand Down
81 changes: 70 additions & 11 deletions silkworm/rpc/core/evm_trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

#include <boost/asio/use_awaitable.hpp>
#include <evmc/hex.hpp>
#include <evmc/instructions.h>
#include <evmone/execution_state.hpp>
#include <evmone/instructions_traits.hpp>
#include <intx/intx.hpp>
Expand Down Expand Up @@ -576,10 +575,6 @@ void VmTraceTracer::on_execution_start(evmc_revision rev, const evmc_message& ms
opcode_names_ = evmc_get_instruction_names_table(rev);
metrics_ = evmc_get_instruction_metrics_table(rev);
}
if (precompile::is_precompile(msg.code_address, rev)) {
is_precompile_ = true;
return;
}

start_gas_.push(msg.gas);

Expand Down Expand Up @@ -622,11 +617,24 @@ void VmTraceTracer::on_execution_start(evmc_revision rev, const evmc_message& ms
<< ", index_prefix: " << index_prefix;
}

void VmTraceTracer::on_instruction_start(uint32_t pc, const intx::uint256* stack_top, const int /*stack_height*/, const int64_t gas,
const evmone::ExecutionState& execution_state, const silkworm::IntraBlockState& /*intra_block_state*/) noexcept {
void VmTraceTracer::on_instruction_start(uint32_t pc, const intx::uint256* stack_top, const int stack_height, const int64_t gas,
const evmone::ExecutionState& execution_state, const silkworm::IntraBlockState& intra_block_state) noexcept {
const auto op_code = execution_state.original_code[pc];
auto op_name = get_opcode_name(opcode_names_, op_code);

if (fix_call_gas_info_) { // previous opcode was a CALL
auto& trace_op = fix_call_gas_info_->trace_op_;
if (execution_state.msg->depth == fix_call_gas_info_->depth) {
if (fix_call_gas_info_->gas_cost) {
trace_op.gas_cost = fix_call_gas_info_->gas_cost + fix_call_gas_info_->code_cost;
}
} else {
trace_op.gas_cost = gas + fix_call_gas_info_->stipend + fix_call_gas_info_->code_cost;
}

fix_call_gas_info_.reset();
}

auto& vm_trace = traces_stack_.top().get();
if (!vm_trace.ops.empty()) {
auto& op = vm_trace.ops[vm_trace.ops.size() - 1];
Expand Down Expand Up @@ -655,6 +663,9 @@ void VmTraceTracer::on_instruction_start(uint32_t pc, const intx::uint256* stack
copy_store(op_code, stack_top, trace_op.trace_ex.storage);

vm_trace.ops.push_back(trace_op);

fill_call_gas_info(vm_trace.ops.back(), execution_state, stack_top, stack_height, intra_block_state);

SILK_DEBUG << "VmTraceTracer::on_instruction_start:"
<< " pc: " << std::dec << pc
<< ", opcode: 0x" << std::hex << evmc::hex(op_code)
Expand All @@ -680,13 +691,14 @@ void VmTraceTracer::on_precompiled_run(const evmc_result& result, int64_t gas, c
op.sub->code = "0x";
}
}
if (fix_call_gas_info_) {
fix_call_gas_info_->gas_cost += gas + fix_call_gas_info_->code_cost;
fix_call_gas_info_->code_cost = 0;
fix_call_gas_info_->precompiled = true;
}
}

void VmTraceTracer::on_execution_end(const evmc_result& result, const silkworm::IntraBlockState& /*intra_block_state*/) noexcept {
if (is_precompile_) {
is_precompile_ = false;
return;
}
auto& vm_trace = traces_stack_.top().get();
traces_stack_.pop();

Expand Down Expand Up @@ -736,9 +748,27 @@ void VmTraceTracer::on_execution_end(const evmc_result& result, const silkworm::
break;

case evmc_status_code::EVMC_REVERT:
op.gas_cost = op.gas_cost - result.gas_left;
op.trace_ex.used = result.gas_left;
break;

default:
op.gas_cost = op.gas_cost - result.gas_left;
op.trace_ex.used = result.gas_left;
if (fix_call_gas_info_) {
auto& trace_op = fix_call_gas_info_->trace_op_;
if (result.gas_left == 0 && !fix_call_gas_info_->precompiled) {
trace_op.gas_cost = fix_call_gas_info_->stipend + fix_call_gas_info_->gas_cost;
} else if (!fix_call_gas_info_->precompiled) {
trace_op.gas_cost = result.gas_left + fix_call_gas_info_->gas_cost + fix_call_gas_info_->code_cost;
fix_call_gas_info_->gas_cost = 0;
} else if (fix_call_gas_info_->precompiled) {
trace_op.gas_cost = fix_call_gas_info_->gas_cost;
fix_call_gas_info_->gas_cost = 0;
} else {
fix_call_gas_info_->gas_cost = 0;
}
}
break;
}
}
Expand All @@ -747,6 +777,35 @@ void VmTraceTracer::on_pre_check_failed(const evmc_result& /*result*/, const evm
vm_trace_.code = "0x" + silkworm::to_hex(ByteView{msg.input_data, msg.input_size});
}

void VmTraceTracer::fill_call_gas_info(TraceOp& trace_op, const evmone::ExecutionState& execution_state, const intx::uint256* stack_top, const int stack_height, const silkworm::IntraBlockState& intra_block_state) {
auto op_code = trace_op.op_code;
if (op_code == evmc_opcode::OP_CALL || op_code == evmc_opcode::OP_CALLCODE || op_code == evmc_opcode::OP_STATICCALL || op_code == evmc_opcode::OP_DELEGATECALL || op_code == evmc_opcode::OP_CREATE || op_code == evmc_opcode::OP_CREATE2) {
fix_call_gas_info_.emplace(FixCallGasInfo{execution_state.msg->depth, 0, metrics_[op_code].gas_cost, trace_op});

const auto value = stack_top[-2]; // value
if (value != 0) {
fix_call_gas_info_->gas_cost += 9000;
}
if (op_code == OP_CALL) {
if (op_code == OP_CALL && stack_height >= 7 && value != 0) {
fix_call_gas_info_->stipend = 2300; // for CALLs with value, include stipend
}
const auto call_gas = stack_top[0]; // gas
const auto dst = intx::be::trunc<evmc::address>(stack_top[-1]); // dst

if ((value != 0 || execution_state.rev < EVMC_SPURIOUS_DRAGON) && !intra_block_state.exists(dst)) {
fix_call_gas_info_->gas_cost += 25000; // add ACCOUNT_CREATION_COST as in instructions_calls.cpp:105
}
SILK_DEBUG << "DebugTracer::evaluate_call_fixes:"
<< " call_gas: " << call_gas
<< " dst: " << dst
<< " value: " << value
<< " gas_cost: " << fix_call_gas_info_->gas_cost
<< " stipend: " << fix_call_gas_info_->stipend;
}
}
}

void TraceTracer::on_execution_start(evmc_revision rev, const evmc_message& msg, evmone::bytes_view code) noexcept {
if (opcode_names_ == nullptr) {
opcode_names_ = evmc_get_instruction_names_table(rev);
Expand Down
19 changes: 17 additions & 2 deletions silkworm/rpc/core/evm_trace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ void copy_store(std::uint8_t op_code, const evmone::uint256* stack, std::optiona
void copy_memory_offset_len(std::uint8_t op_code, const evmone::uint256* stack, std::optional<TraceMemory>& trace_memory);
void push_memory_offset_len(std::uint8_t op_code, const evmone::uint256* stack, std::stack<TraceMemory>& tms);

struct FixCallGasInfo {
int32_t depth{0};
int64_t stipend{0};
int16_t code_cost{0};
TraceOp& trace_op_;
int64_t gas_cost{0};
bool precompiled{false};
};

class VmTraceTracer : public silkworm::EvmTracer {
public:
explicit VmTraceTracer(VmTrace& vm_trace, std::int32_t index = -1) : vm_trace_(vm_trace), transaction_index_{index} {}
Expand All @@ -144,15 +153,21 @@ class VmTraceTracer : public silkworm::EvmTracer {
void on_precompiled_run(const evmc_result& result, int64_t gas, const silkworm::IntraBlockState& intra_block_state) noexcept override;

private:
bool is_precompile_{false};
void fill_call_gas_info(TraceOp& trace_op,
const evmone::ExecutionState& execution_state,
const intx::uint256* stack_top,
int stack_height,
const silkworm::IntraBlockState& intra_block_state);

VmTrace& vm_trace_;
std::int32_t transaction_index_;
std::stack<std::string> index_prefix_;
std::stack<std::reference_wrapper<VmTrace>> traces_stack_;
const char* const* opcode_names_ = nullptr;
const evmc_instruction_metrics* metrics_ = nullptr;
std::stack<int64_t> start_gas_;
std::stack<TraceMemory> trace_memory_stack_;
const evmc_instruction_metrics* metrics_ = nullptr;
std::optional<FixCallGasInfo> fix_call_gas_info_;
};

struct TraceAction {
Expand Down

0 comments on commit 33875b4

Please sign in to comment.