Skip to content

Commit ce15ff0

Browse files
authored
rpcdaemon: fix ots_traceTransaction (#2043)
1 parent acc92fa commit ce15ff0

File tree

2 files changed

+107
-70
lines changed

2 files changed

+107
-70
lines changed

silkworm/rpc/core/evm_trace.cpp

Lines changed: 99 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,16 @@ void to_json(nlohmann::json& json, const TraceEntry& trace_entry) {
298298
} else {
299299
json["value"] = trace_entry.value;
300300
}
301-
json["input"] = trace_entry.input;
301+
if (!trace_entry.input) {
302+
json["input"] = nullptr;
303+
} else {
304+
json["input"] = *trace_entry.input;
305+
}
306+
if (!trace_entry.output) {
307+
json["output"] = nullptr;
308+
} else {
309+
json["output"] = *trace_entry.output;
310+
}
302311
}
303312

304313
void to_json(nlohmann::json& json, const InternalOperation& trace_operation) {
@@ -471,7 +480,7 @@ void copy_memory(const evmone::Memory& memory, std::optional<TraceMemory>& trace
471480
tm.data = "0x";
472481
const auto data = memory.data();
473482
const auto start = tm.offset;
474-
for (uint64_t idx{0}; idx < tm.len; idx++) {
483+
for (size_t idx{0}; idx < tm.len; idx++) {
475484
std::string entry{evmc::hex({data + start + idx, 1})};
476485
tm.data.append(entry);
477486
}
@@ -1154,7 +1163,7 @@ Task<std::vector<Trace>> TraceCallExecutor::trace_block(const BlockWithHash& blo
11541163
.state_diff = false,
11551164
};
11561165
const auto trace_call_results = co_await trace_block_transactions(block_with_hash.block, trace_block_config);
1157-
for (std::uint64_t pos = 0; pos < trace_call_results.size(); pos++) {
1166+
for (size_t pos = 0; pos < trace_call_results.size(); pos++) {
11581167
rpc::Transaction transaction{block_with_hash.block.transactions[pos]};
11591168
const auto tnx_hash = transaction.hash();
11601169

@@ -1282,7 +1291,7 @@ Task<std::vector<TraceCallResult>> TraceCallExecutor::trace_block_transactions(c
12821291
EVMExecutor executor{*chain_config_ptr, workers_, curr_state};
12831292

12841293
std::vector<TraceCallResult> trace_call_result(transactions.size());
1285-
for (std::uint64_t index = 0; index < transactions.size(); index++) {
1294+
for (size_t index = 0; index < transactions.size(); index++) {
12861295
const silkworm::Transaction& transaction{block.transactions[index]};
12871296

12881297
auto& result = trace_call_result.at(index);
@@ -1349,7 +1358,7 @@ Task<TraceManyCallResult> TraceCallExecutor::trace_calls(const silkworm::Block&
13491358
std::shared_ptr<silkworm::EvmTracer> ibs_tracer = std::make_shared<trace::IntraBlockStateTracer>(state_addresses);
13501359

13511360
TraceManyCallResult result;
1352-
for (std::size_t index{0}; index < calls.size(); index++) {
1361+
for (size_t index{0}; index < calls.size(); index++) {
13531362
const auto& config = calls[index].trace_config;
13541363

13551364
silkworm::Transaction transaction{calls[index].call.to_transaction()};
@@ -1412,7 +1421,7 @@ Task<TraceDeployResult> TraceCallExecutor::trace_deploy_transaction(const silkwo
14121421

14131422
auto create_tracer = std::make_shared<trace::CreateTracer>(contract_address, initial_ibs);
14141423
Tracers tracers{create_tracer};
1415-
for (std::uint64_t index = 0; index < transactions.size(); index++) {
1424+
for (size_t index = 0; index < transactions.size(); index++) {
14161425
const silkworm::Transaction& transaction{block.transactions[index]};
14171426
executor.call(block, transaction, tracers, /*refund=*/true, /*gas_bailout=*/true);
14181427
executor.reset();
@@ -1451,8 +1460,24 @@ Task<std::vector<Trace>> TraceCallExecutor::trace_transaction(const BlockWithHas
14511460
co_return traces;
14521461
}
14531462

1463+
bool TraceCallExecutor::run_previous_transactions(EVMExecutor& executor, const silkworm::Block& block, uint64_t tx_id) {
1464+
if (tx_id == 0) {
1465+
return true;
1466+
}
1467+
for (size_t idx = 0; idx < block.transactions.size(); idx++) {
1468+
const auto& txn = block.transactions.at(idx);
1469+
1470+
if (tx_id == idx) {
1471+
return true;
1472+
}
1473+
executor.call(block, txn, {}, /*refund=*/true, /*gas_bailout=*/false);
1474+
}
1475+
return false;
1476+
}
1477+
14541478
Task<TraceEntriesResult> TraceCallExecutor::trace_transaction_entries(const TransactionWithBlock& transaction_with_block) {
1455-
auto block_number = transaction_with_block.block_with_hash->block.header.number;
1479+
const auto& block = transaction_with_block.block_with_hash->block;
1480+
const auto block_number = block.header.number;
14561481

14571482
const auto chain_config_ptr = co_await chain_storage_.read_chain_config();
14581483
ensure(chain_config_ptr.has_value(), "cannot read chain config");
@@ -1464,10 +1489,16 @@ Task<TraceEntriesResult> TraceCallExecutor::trace_transaction_entries(const Tran
14641489
auto curr_state = tx_.create_state(current_executor, database_reader_, chain_storage_, block_number - 1);
14651490
EVMExecutor executor{*chain_config_ptr, workers_, curr_state};
14661491

1467-
auto entry_tracer = std::make_shared<trace::EntryTracer>(initial_ibs);
1492+
if (!run_previous_transactions(executor, block, transaction_with_block.transaction.transaction_index)) {
1493+
SILK_ERROR << "trace_operations: transaction idx: " << transaction_with_block.transaction.transaction_index << " not found";
1494+
return {};
1495+
}
1496+
1497+
const auto entry_tracer = std::make_shared<trace::EntryTracer>(initial_ibs);
14681498
Tracers tracers{entry_tracer};
1499+
const auto& txn = block.transactions.at(transaction_with_block.transaction.transaction_index);
1500+
executor.call(block, txn, tracers, /*refund=*/true, /*gas_bailout=*/false);
14691501

1470-
executor.call(transaction_with_block.block_with_hash->block, transaction_with_block.transaction, tracers, /*refund=*/true, /*gas_bailout=*/true);
14711502
return entry_tracer->result();
14721503
});
14731504

@@ -1488,26 +1519,18 @@ Task<std::string> TraceCallExecutor::trace_transaction_error(const TransactionWi
14881519

14891520
auto curr_state = tx_.create_state(current_executor, database_reader_, chain_storage_, block_number - 1);
14901521
EVMExecutor executor{*chain_config_ptr, workers_, curr_state};
1491-
Tracers tracers{};
1492-
bool found = false;
1493-
ExecutionResult execution_result{};
1494-
1495-
for (size_t idx = 0; idx < block.transactions.size(); idx++) {
1496-
const auto& txn = block.transactions.at(idx);
1497-
execution_result = executor.call(block, txn, tracers, /*refund=*/true, /*gas_bailout=*/false);
1498-
if (transaction_with_block.transaction.transaction_index == idx) {
1499-
found = true;
1500-
break;
1501-
}
1522+
1523+
if (!run_previous_transactions(executor, block, transaction_with_block.transaction.transaction_index)) {
1524+
SILK_ERROR << "trace_transaction_error: transaction idx: " << transaction_with_block.transaction.transaction_index << " not found";
1525+
return {};
15021526
}
1527+
1528+
const auto& txn = block.transactions.at(transaction_with_block.transaction.transaction_index);
1529+
auto execution_result = executor.call(block, txn, {}, /*refund=*/true, /*gas_bailout=*/false);
1530+
15031531
std::string result = "0x";
1504-
if (found) {
1505-
if (execution_result.error_code != evmc_status_code::EVMC_SUCCESS) {
1506-
result = "0x" + silkworm::to_hex(execution_result.data);
1507-
}
1508-
return result;
1509-
} else {
1510-
SILK_ERROR << "trace_transaction_error: transaction idx: " << transaction_with_block.transaction.transaction_index << " not found";
1532+
if (execution_result.error_code != evmc_status_code::EVMC_SUCCESS) {
1533+
result = "0x" + silkworm::to_hex(execution_result.data);
15111534
}
15121535
return result;
15131536
});
@@ -1529,28 +1552,17 @@ Task<TraceOperationsResult> TraceCallExecutor::trace_operations(const Transactio
15291552

15301553
auto curr_state = tx_.create_state(current_executor, database_reader_, chain_storage_, block_number - 1);
15311554
EVMExecutor executor{*chain_config_ptr, workers_, curr_state};
1532-
bool found = false;
1533-
1534-
std::shared_ptr<trace::OperationTracer> entry_tracer = nullptr;
1535-
for (size_t idx = 0; idx < block.transactions.size(); idx++) {
1536-
const auto& txn = block.transactions.at(idx);
15371555

1538-
if (transaction_with_block.transaction.transaction_index == idx) {
1539-
entry_tracer = std::make_shared<trace::OperationTracer>(initial_ibs);
1540-
Tracers tracers{entry_tracer};
1541-
executor.call(block, txn, tracers, /*refund=*/true, /*gas_bailout=*/false);
1542-
found = true;
1543-
break;
1544-
} else {
1545-
executor.call(block, txn, {}, /*refund=*/true, /*gas_bailout=*/false);
1546-
}
1547-
}
1548-
if (found) {
1549-
return entry_tracer->result();
1550-
} else {
1556+
if (!run_previous_transactions(executor, block, transaction_with_block.transaction.transaction_index)) {
15511557
SILK_ERROR << "trace_operations: transaction idx: " << transaction_with_block.transaction.transaction_index << " not found";
15521558
return {};
15531559
}
1560+
1561+
auto entry_tracer = std::make_shared<trace::OperationTracer>(initial_ibs);
1562+
Tracers tracers{entry_tracer};
1563+
const auto& txn = block.transactions.at(transaction_with_block.transaction.transaction_index);
1564+
executor.call(block, txn, tracers, /*refund=*/true, /*gas_bailout=*/false);
1565+
return entry_tracer->result();
15541566
});
15551567

15561568
co_return trace_op_result;
@@ -1747,31 +1759,47 @@ void CreateTracer::on_execution_start(evmc_revision, const evmc_message& msg, ev
17471759
<< ", code: " << silkworm::to_hex(code);
17481760
}
17491761

1750-
void EntryTracer::on_execution_start(evmc_revision, const evmc_message& msg, evmone::bytes_view code) noexcept {
1751-
auto sender = evmc::address{msg.sender};
1752-
auto recipient = evmc::address{msg.recipient};
1753-
auto code_address = evmc::address{msg.code_address};
1754-
bool create = (!initial_ibs_.exists(recipient) && recipient != code_address);
1755-
auto input = silkworm::ByteView{msg.input_data, msg.input_size};
1762+
void EntryTracer::on_execution_end(const evmc_result& result, const silkworm::IntraBlockState& /* intra_block_state */) noexcept {
1763+
current_depth_--;
1764+
if (traces_stack_idx_.empty())
1765+
return;
1766+
auto& trace_idx = traces_stack_idx_.top();
1767+
traces_stack_idx_.pop();
17561768

1757-
auto str_value = "0x" + intx::hex(intx::be::load<intx::uint256>(msg.value));
1769+
if (trace_idx != std::numeric_limits<uint64_t>::max()) {
1770+
result_[trace_idx].output = "0x" + silkworm::to_hex(silkworm::ByteView{result.output_data, result.output_size});
1771+
}
1772+
}
1773+
1774+
void EntryTracer::on_self_destruct(const evmc::address& address, const evmc::address& beneficiary) noexcept {
1775+
auto balance = initial_ibs_.get_balance(address);
1776+
result_.push_back(TraceEntry{"SELFDESTRUCT", current_depth_ + 1, address, beneficiary, "0x" + intx::to_string(balance, 16), "0x", "0x"});
1777+
}
1778+
1779+
void EntryTracer::on_execution_start(evmc_revision rev, const evmc_message& msg, evmone::bytes_view code) noexcept {
1780+
const auto& sender = evmc::address{msg.sender};
1781+
const auto& recipient = evmc::address{msg.recipient};
1782+
const auto& code_address = evmc::address{msg.code_address};
1783+
const auto& input = silkworm::ByteView{msg.input_data, msg.input_size};
1784+
1785+
const auto str_value = "0x" + intx::hex(intx::be::load<intx::uint256>(msg.value));
17581786
auto str_input = "0x" + silkworm::to_hex(input);
1759-
if (str_input == "0x") {
1760-
str_input = "0x" + silkworm::to_hex(code);
1787+
1788+
// Ignore precompiles in the returned trace (maybe we shouldn't?)
1789+
if (precompile::is_precompile(msg.code_address, rev)) {
1790+
// writes special value for index
1791+
traces_stack_idx_.emplace(std::numeric_limits<uint64_t>::max());
1792+
return;
17611793
}
17621794

1763-
if (create) {
1764-
if (msg.depth > 0) {
1765-
if (msg.kind == evmc_call_kind::EVMC_CREATE) {
1766-
result_.push_back(TraceEntry{"CREATE", msg.depth, sender, recipient, str_value, str_input});
1767-
} else if (msg.kind == evmc_call_kind::EVMC_CREATE2) {
1768-
result_.push_back(TraceEntry{"CREATE2", msg.depth, sender, recipient, str_value, str_input});
1769-
}
1770-
} else {
1771-
result_.push_back(TraceEntry{"CALL", msg.depth, sender, recipient, str_value, str_input});
1772-
}
1795+
if (msg.kind == evmc_call_kind::EVMC_CREATE) {
1796+
str_input = "0x" + silkworm::to_hex(code);
1797+
result_.push_back(TraceEntry{"CREATE", msg.depth, sender, recipient, str_value, str_input});
1798+
} else if (msg.kind == evmc_call_kind::EVMC_CREATE2) {
1799+
str_input = "0x" + silkworm::to_hex(code);
1800+
result_.push_back(TraceEntry{"CREATE2", msg.depth, sender, recipient, str_value, str_input});
17731801
} else {
1774-
bool in_static_mode = (msg.flags & evmc_flags::EVMC_STATIC) != 0;
1802+
const bool in_static_mode = (msg.flags & evmc_flags::EVMC_STATIC) != 0;
17751803
switch (msg.kind) {
17761804
case evmc_call_kind::EVMC_CALL:
17771805
in_static_mode ? result_.push_back(TraceEntry{"STATICCALL", msg.depth, sender, recipient, "", str_input}) : result_.push_back(TraceEntry{"CALL", msg.depth, sender, recipient, str_value, str_input});
@@ -1782,18 +1810,20 @@ void EntryTracer::on_execution_start(evmc_revision, const evmc_message& msg, evm
17821810
case evmc_call_kind::EVMC_CALLCODE:
17831811
result_.push_back(TraceEntry{"CALLCODE", msg.depth, sender, recipient, str_value, str_input});
17841812
break;
1785-
case evmc_call_kind::EVMC_CREATE:
1786-
case evmc_call_kind::EVMC_CREATE2:
1813+
default:
1814+
// safeguard in case new CALL-like opcodes are introduced but not handled,
1815+
result_.push_back(TraceEntry{"UNKNWON", msg.depth, sender, recipient, str_value, str_input});
17871816
break;
17881817
}
17891818
}
1819+
traces_stack_idx_.emplace(result_.size() - 1);
1820+
current_depth_ = msg.depth;
17901821

17911822
SILK_DEBUG << "EntryTracer::on_execution_start: gas: " << std::dec << msg.gas
1792-
<< " create: " << create
17931823
<< ", msg.depth: " << msg.depth
17941824
<< ", msg.kind: " << msg.kind
17951825
<< ", sender: " << sender
1796-
<< ", recipient: " << recipient << " (created: " << create << ")"
1826+
<< ", recipient: " << recipient
17971827
<< ", code_address: " << code_address
17981828
<< ", msg.value: " << intx::hex(intx::be::load<intx::uint256>(msg.value))
17991829
<< ", code: " << silkworm::to_hex(code)

silkworm/rpc/core/evm_trace.hpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,8 @@ struct TraceEntry {
334334
evmc::address from;
335335
evmc::address to;
336336
std::string value;
337-
std::string input;
337+
std::optional<std::string> input;
338+
std::optional<std::string> output;
338339
};
339340

340341
enum OperationType : int {
@@ -399,12 +400,16 @@ class EntryTracer : public silkworm::EvmTracer {
399400
EntryTracer& operator=(const EntryTracer&) = delete;
400401

401402
void on_execution_start(evmc_revision rev, const evmc_message& msg, evmone::bytes_view code) noexcept override;
403+
void on_execution_end(const evmc_result& result, const silkworm::IntraBlockState& intra_block_state) noexcept override;
404+
void on_self_destruct(const evmc::address& address, const evmc::address& beneficiary) noexcept override;
402405

403406
TraceEntriesResult result() const { return result_; }
404407

405408
private:
406409
const silkworm::IntraBlockState& initial_ibs_;
407410
TraceEntriesResult result_;
411+
std::stack<uint64_t> traces_stack_idx_;
412+
int32_t current_depth_{-1};
408413
};
409414

410415
class OperationTracer : public silkworm::EvmTracer {
@@ -489,6 +494,8 @@ class TraceCallExecutor {
489494
std::int32_t index,
490495
const TraceConfig& config);
491496

497+
bool run_previous_transactions(EVMExecutor& executor, const silkworm::Block& block, uint64_t tx_id);
498+
492499
silkworm::BlockCache& block_cache_;
493500
const core::rawdb::DatabaseReader& database_reader_;
494501
const ChainStorage& chain_storage_;

0 commit comments

Comments
 (0)