Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rpcdaemon: fix memory gas cost in call #2211

Merged
merged 5 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.34.0 https://github.com/erigontech/rpc-tests ${{runner.workspace}}/rpc-tests
git -c advice.detachedHead=false clone --depth 1 --branch v0.35.0 https://github.com/erigontech/rpc-tests ${{runner.workspace}}/rpc-tests
cd ${{runner.workspace}}/rpc-tests
pip3 install -r requirements.txt

Expand Down
99 changes: 71 additions & 28 deletions silkworm/rpc/core/evm_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <evmc/instructions.h>
#include <evmone/execution_state.hpp>
#include <evmone/instructions.hpp>
#include <intx/intx.hpp>

#include <silkworm/core/common/util.hpp>
Expand Down Expand Up @@ -163,11 +164,13 @@ void DebugTracer::on_instruction_start(uint32_t pc, const intx::uint256* stack_t
if (execution_state.msg->depth == fix_call_gas_info_->depth) {
if (fix_call_gas_info_->gas_cost) {
log.gas_cost = fix_call_gas_info_->gas_cost + fix_call_gas_info_->code_cost;
} else if (!fix_call_gas_info_->precompiled) {
log.gas_cost = log.gas - gas + fix_call_gas_info_->stipend;
}
} else {
log.gas_cost = gas + fix_call_gas_info_->stipend + fix_call_gas_info_->code_cost;
if (fix_call_gas_info_->opcode == OP_CALLCODE) {
log.gas_cost += fix_call_gas_info_->stipend + fix_call_gas_info_->gas_cost + fix_call_gas_info_->call_gas;
} else {
log.gas_cost = gas + fix_call_gas_info_->stipend + fix_call_gas_info_->code_cost;
}
}

fix_call_gas_info_.reset();
Expand Down Expand Up @@ -242,7 +245,11 @@ void DebugTracer::on_execution_end(const evmc_result& result, const silkworm::In

case evmc_status_code::EVMC_OUT_OF_GAS:
if (fix_call_gas_info_) {
log.gas_cost += fix_call_gas_info_->gas_cost;
if (fix_call_gas_info_->opcode == OP_CALLCODE) {
log.gas_cost = fix_call_gas_info_->code_cost;
} else {
log.gas_cost += fix_call_gas_info_->gas_cost;
}
}
break;

Expand All @@ -251,13 +258,11 @@ void DebugTracer::on_execution_end(const evmc_result& result, const silkworm::In
if (result.gas_left == 0 && !fix_call_gas_info_->precompiled) {
log.gas_cost = fix_call_gas_info_->stipend + fix_call_gas_info_->gas_cost;
} else if (!fix_call_gas_info_->precompiled) {
log.gas_cost = result.gas_left + fix_call_gas_info_->gas_cost + fix_call_gas_info_->code_cost;
log.gas_cost = result.gas_left + fix_call_gas_info_->gas_cost + fix_call_gas_info_->code_cost - fix_call_gas_info_->stipend;
fix_call_gas_info_->gas_cost = 0;
} else if (fix_call_gas_info_->precompiled) {
log.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 @@ -282,30 +287,68 @@ void DebugTracer::flush_logs() {
}
}

int64_t memory_cost(const evmone::Memory& memory, std::uint64_t offset, std::uint64_t size) noexcept {
if (size == 0) {
return 0;
}
const auto new_size = offset + size;
if (new_size <= memory.size()) {
return 0;
}

const auto new_words = evmone::num_words(new_size);
const auto current_words = static_cast<int64_t>(memory.size() / evmone::word_size);
const auto new_cost = 3 * new_words + new_words * new_words / 512;
const auto current_cost = 3 * current_words + current_words * current_words / 512;
const auto cost = new_cost - current_cost;

return cost;
}

void DebugTracer::fill_call_gas_info(unsigned char opcode, const evmone::ExecutionState& execution_state, const intx::uint256* stack_top, const int stack_height, const silkworm::IntraBlockState& intra_block_state) {
if (opcode == OP_CALL || opcode == OP_CALLCODE || opcode == OP_STATICCALL || opcode == OP_DELEGATECALL || opcode == OP_CREATE || opcode == OP_CREATE2) {
fix_call_gas_info_ = FixCallGasInfo{execution_state.msg->depth, 0, metrics_[opcode].gas_cost};
const auto value = stack_top[-2]; // value
if (value != 0) {
fix_call_gas_info_->gas_cost += 9000;
}
if (opcode == OP_CALL) {
if (opcode == 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 (opcode != OP_CALL && opcode != OP_CALLCODE && opcode != OP_STATICCALL && opcode != OP_DELEGATECALL && opcode != OP_CREATE && opcode != OP_CREATE2) {
return;
}
fix_call_gas_info_.emplace(FixCallGasInfo{opcode, execution_state.msg->depth, 0, metrics_[opcode].gas_cost});

auto idx = 0;
const auto call_gas = stack_top[idx--]; // gas
const auto dst = intx::be::trunc<evmc::address>(stack_top[idx--]);
const auto value = (opcode == OP_STATICCALL || opcode == OP_DELEGATECALL) ? 0 : stack_top[idx--];
const auto input_offset = static_cast<std::uint64_t>(stack_top[idx--]);
const auto input_size = static_cast<std::uint64_t>(stack_top[idx--]);
const auto output_offset = static_cast<std::uint64_t>(stack_top[idx--]);
const auto output_size = static_cast<std::uint64_t>(stack_top[idx--]);

SILK_DEBUG << "DebugTracer::evaluate_call_fixes:"
<< " gas: " << std::dec << call_gas
<< ", input_offset: " << std::dec << input_offset
<< ", input_size: " << std::dec << input_size
<< ", output_offset: " << std::dec << output_offset
<< ", output_size: " << std::dec << output_size;

if (call_gas < std::numeric_limits<int64_t>::max()) {
fix_call_gas_info_->call_gas = static_cast<std::int64_t>(call_gas);
}
fix_call_gas_info_->gas_cost += memory_cost(execution_state.memory, input_offset, input_size);
fix_call_gas_info_->gas_cost += memory_cost(execution_state.memory, output_offset, output_size);

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;
if (value != 0) {
fix_call_gas_info_->gas_cost += 9000;
}
if (opcode == OP_CALL) {
if (opcode == OP_CALL && stack_height >= 7 && value != 0) {
fix_call_gas_info_->stipend = 2300; // for CALLs with value, include stipend
}
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;
}
}

Expand Down
2 changes: 2 additions & 0 deletions silkworm/rpc/core/evm_debug.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,11 @@ struct DebugLog {
};

struct FixCallGasInfo {
unsigned char opcode;
int32_t depth{0};
int64_t stipend{0};
int16_t code_cost{0};
int64_t call_gas{0};
int64_t gas_cost{0};
bool precompiled{false};
};
Expand Down
Loading