@@ -298,7 +298,16 @@ void to_json(nlohmann::json& json, const TraceEntry& trace_entry) {
298
298
} else {
299
299
json[" value" ] = trace_entry.value ;
300
300
}
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
+ }
302
311
}
303
312
304
313
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
471
480
tm.data = " 0x" ;
472
481
const auto data = memory.data ();
473
482
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++) {
475
484
std::string entry{evmc::hex ({data + start + idx, 1 })};
476
485
tm.data .append (entry);
477
486
}
@@ -1154,7 +1163,7 @@ Task<std::vector<Trace>> TraceCallExecutor::trace_block(const BlockWithHash& blo
1154
1163
.state_diff = false ,
1155
1164
};
1156
1165
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++) {
1158
1167
rpc::Transaction transaction{block_with_hash.block .transactions [pos]};
1159
1168
const auto tnx_hash = transaction.hash ();
1160
1169
@@ -1282,7 +1291,7 @@ Task<std::vector<TraceCallResult>> TraceCallExecutor::trace_block_transactions(c
1282
1291
EVMExecutor executor{*chain_config_ptr, workers_, curr_state};
1283
1292
1284
1293
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++) {
1286
1295
const silkworm::Transaction& transaction{block.transactions [index]};
1287
1296
1288
1297
auto & result = trace_call_result.at (index);
@@ -1349,7 +1358,7 @@ Task<TraceManyCallResult> TraceCallExecutor::trace_calls(const silkworm::Block&
1349
1358
std::shared_ptr<silkworm::EvmTracer> ibs_tracer = std::make_shared<trace::IntraBlockStateTracer>(state_addresses);
1350
1359
1351
1360
TraceManyCallResult result;
1352
- for (std:: size_t index{0 }; index < calls.size (); index++) {
1361
+ for (size_t index{0 }; index < calls.size (); index++) {
1353
1362
const auto & config = calls[index].trace_config ;
1354
1363
1355
1364
silkworm::Transaction transaction{calls[index].call .to_transaction ()};
@@ -1412,7 +1421,7 @@ Task<TraceDeployResult> TraceCallExecutor::trace_deploy_transaction(const silkwo
1412
1421
1413
1422
auto create_tracer = std::make_shared<trace::CreateTracer>(contract_address, initial_ibs);
1414
1423
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++) {
1416
1425
const silkworm::Transaction& transaction{block.transactions [index]};
1417
1426
executor.call (block, transaction, tracers, /* refund=*/ true , /* gas_bailout=*/ true );
1418
1427
executor.reset ();
@@ -1451,8 +1460,24 @@ Task<std::vector<Trace>> TraceCallExecutor::trace_transaction(const BlockWithHas
1451
1460
co_return traces;
1452
1461
}
1453
1462
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
+
1454
1478
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 ;
1456
1481
1457
1482
const auto chain_config_ptr = co_await chain_storage_.read_chain_config ();
1458
1483
ensure (chain_config_ptr.has_value (), " cannot read chain config" );
@@ -1464,10 +1489,16 @@ Task<TraceEntriesResult> TraceCallExecutor::trace_transaction_entries(const Tran
1464
1489
auto curr_state = tx_.create_state (current_executor, database_reader_, chain_storage_, block_number - 1 );
1465
1490
EVMExecutor executor{*chain_config_ptr, workers_, curr_state};
1466
1491
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);
1468
1498
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 );
1469
1501
1470
- executor.call (transaction_with_block.block_with_hash ->block , transaction_with_block.transaction , tracers, /* refund=*/ true , /* gas_bailout=*/ true );
1471
1502
return entry_tracer->result ();
1472
1503
});
1473
1504
@@ -1488,26 +1519,18 @@ Task<std::string> TraceCallExecutor::trace_transaction_error(const TransactionWi
1488
1519
1489
1520
auto curr_state = tx_.create_state (current_executor, database_reader_, chain_storage_, block_number - 1 );
1490
1521
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 {};
1502
1526
}
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
+
1503
1531
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 );
1511
1534
}
1512
1535
return result;
1513
1536
});
@@ -1529,28 +1552,17 @@ Task<TraceOperationsResult> TraceCallExecutor::trace_operations(const Transactio
1529
1552
1530
1553
auto curr_state = tx_.create_state (current_executor, database_reader_, chain_storage_, block_number - 1 );
1531
1554
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);
1537
1555
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 )) {
1551
1557
SILK_ERROR << " trace_operations: transaction idx: " << transaction_with_block.transaction .transaction_index << " not found" ;
1552
1558
return {};
1553
1559
}
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 ();
1554
1566
});
1555
1567
1556
1568
co_return trace_op_result;
@@ -1747,31 +1759,47 @@ void CreateTracer::on_execution_start(evmc_revision, const evmc_message& msg, ev
1747
1759
<< " , code: " << silkworm::to_hex (code);
1748
1760
}
1749
1761
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 () ;
1756
1768
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 ));
1758
1786
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 ;
1761
1793
}
1762
1794
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});
1773
1801
} 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 ;
1775
1803
switch (msg.kind ) {
1776
1804
case evmc_call_kind::EVMC_CALL:
1777
1805
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
1782
1810
case evmc_call_kind::EVMC_CALLCODE:
1783
1811
result_.push_back (TraceEntry{" CALLCODE" , msg.depth , sender, recipient, str_value, str_input});
1784
1812
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});
1787
1816
break ;
1788
1817
}
1789
1818
}
1819
+ traces_stack_idx_.emplace (result_.size () - 1 );
1820
+ current_depth_ = msg.depth ;
1790
1821
1791
1822
SILK_DEBUG << " EntryTracer::on_execution_start: gas: " << std::dec << msg.gas
1792
- << " create: " << create
1793
1823
<< " , msg.depth: " << msg.depth
1794
1824
<< " , msg.kind: " << msg.kind
1795
1825
<< " , sender: " << sender
1796
- << " , recipient: " << recipient << " (created: " << create << " ) "
1826
+ << " , recipient: " << recipient
1797
1827
<< " , code_address: " << code_address
1798
1828
<< " , msg.value: " << intx::hex (intx::be::load<intx::uint256>(msg.value ))
1799
1829
<< " , code: " << silkworm::to_hex (code)
0 commit comments