Skip to content

Commit 5a17bc2

Browse files
committed
Enable native transfer logs
1 parent 7f8a3ce commit 5a17bc2

File tree

4 files changed

+144
-17
lines changed

4 files changed

+144
-17
lines changed

category/execution/ethereum/evm.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,6 @@ bool sender_has_balance(State &state, evmc_message const &msg) noexcept
5050
return state.record_balance_constraint_for_debit(msg.sender, value);
5151
}
5252

53-
void transfer_balances(State &state, evmc_message const &msg, Address const &to)
54-
{
55-
uint256_t const value = intx::be::load<uint256_t>(msg.value);
56-
state.subtract_from_balance(msg.sender, value);
57-
state.add_to_balance(to, value);
58-
}
59-
6053
MONAD_ANONYMOUS_NAMESPACE_END
6154

6255
MONAD_NAMESPACE_BEGIN
@@ -110,7 +103,8 @@ evmc::Result deploy_contract_code(
110103
EXPLICIT_TRAITS(deploy_contract_code);
111104

112105
template <Traits traits>
113-
std::optional<evmc::Result> pre_call(evmc_message const &msg, State &state)
106+
std::optional<evmc::Result>
107+
pre_call(EvmcHost<traits> &host, evmc_message const &msg, State &state)
114108
{
115109
state.push();
116110

@@ -122,7 +116,7 @@ std::optional<evmc::Result> pre_call(evmc_message const &msg, State &state)
122116
return evmc::Result{EVMC_INSUFFICIENT_BALANCE, msg.gas};
123117
}
124118
else if (!static_call) {
125-
transfer_balances(state, msg, msg.recipient);
119+
host.transfer_balances(msg, msg.recipient);
126120
}
127121
}
128122

@@ -232,7 +226,7 @@ evmc::Result create(
232226
constexpr auto starting_nonce =
233227
traits::evm_rev() >= EVMC_SPURIOUS_DRAGON ? 1 : 0;
234228
state.set_nonce(contract_address, starting_nonce);
235-
transfer_balances(state, msg, contract_address);
229+
host->transfer_balances(msg, contract_address);
236230

237231
evmc_message const m_call{
238232
.kind = EVMC_CALL,
@@ -297,7 +291,7 @@ evmc::Result call(
297291
auto &call_tracer = host->get_call_tracer();
298292
call_tracer.on_enter(msg);
299293

300-
if (auto result = pre_call<traits>(msg, state); result.has_value()) {
294+
if (auto result = pre_call<traits>(*host, msg, state); result.has_value()) {
301295
call_tracer.on_exit(result.value());
302296
return std::move(result.value());
303297
}

category/execution/ethereum/evmc_host.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@ MONAD_NAMESPACE_BEGIN
3636
EvmcHostBase::EvmcHostBase(
3737
CallTracerBase &call_tracer, evmc_tx_context const &tx_context,
3838
BlockHashBuffer const &block_hash_buffer, State &state,
39-
std::function<bool()> const &revert_transaction) noexcept
39+
std::function<bool()> const &revert_transaction,
40+
bool const simulate_v1_enabled) noexcept
4041
: block_hash_buffer_{block_hash_buffer}
4142
, tx_context_{tx_context}
4243
, state_{state}
4344
, call_tracer_{call_tracer}
4445
, revert_transaction_{revert_transaction}
46+
, simulate_v1_enabled_{simulate_v1_enabled}
4547
{
4648
}
4749

category/execution/ethereum/evmc_host.hpp

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
#include <category/core/config.hpp>
2020
#include <category/execution/ethereum/chain/chain.hpp>
2121
#include <category/execution/ethereum/core/address.hpp>
22+
#include <category/execution/ethereum/core/contract/abi_encode.hpp>
23+
#include <category/execution/ethereum/core/contract/abi_signatures.hpp>
24+
#include <category/execution/ethereum/core/contract/events.hpp>
2225
#include <category/execution/ethereum/evm.hpp>
2326
#include <category/execution/ethereum/precompiles.hpp>
2427
#include <category/execution/ethereum/state3/state.hpp>
@@ -53,13 +56,14 @@ class EvmcHostBase : public vm::Host
5356
State &state_;
5457
CallTracerBase &call_tracer_;
5558
std::function<bool()> revert_transaction_;
59+
bool simulate_v1_enabled_;
5660

5761
public:
5862
EvmcHostBase(
5963
CallTracerBase &, evmc_tx_context const &, BlockHashBuffer const &,
60-
State &, std::function<bool()> const &revert_transaction = [] {
61-
return false;
62-
}) noexcept;
64+
State &,
65+
std::function<bool()> const &revert_transaction = [] { return false; },
66+
bool simulate_v1_enabled = false) noexcept;
6367

6468
virtual ~EvmcHostBase() noexcept = default;
6569

@@ -100,7 +104,7 @@ class EvmcHostBase : public vm::Host
100104
bytes32_t const &value) noexcept override;
101105
};
102106

103-
static_assert(sizeof(EvmcHostBase) == 88);
107+
static_assert(sizeof(EvmcHostBase) == 96);
104108
static_assert(alignof(EvmcHostBase) == 8);
105109

106110
template <Traits traits>
@@ -126,6 +130,12 @@ struct EvmcHost final : public EvmcHostBase
126130
Address const &address, Address const &beneficiary) noexcept override
127131
{
128132
try {
133+
emit_native_transfer_event(
134+
address,
135+
beneficiary,
136+
intx::be::load<uint256_t>(
137+
state_.get_current_balance_pessimistic(address)));
138+
129139
call_tracer_.on_self_destruct(address, beneficiary);
130140
return state_.selfdestruct<traits>(address, beneficiary);
131141
}
@@ -176,13 +186,45 @@ struct EvmcHost final : public EvmcHostBase
176186
stack_unwind();
177187
}
178188

189+
void transfer_balances(evmc_message const &msg, Address const &to)
190+
{
191+
uint256_t const value = intx::be::load<uint256_t>(msg.value);
192+
state_.subtract_from_balance(msg.sender, value);
193+
state_.add_to_balance(to, value);
194+
emit_native_transfer_event(msg.sender, to, value);
195+
}
196+
179197
CallTracerBase &get_call_tracer() noexcept
180198
{
181199
return call_tracer_;
182200
}
201+
202+
private:
203+
void emit_native_transfer_event(
204+
Address const &from, Address const &to, uint256_t const &value)
205+
{
206+
if (simulate_v1_enabled_) {
207+
constexpr auto sender =
208+
0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_address;
209+
constexpr auto signature =
210+
abi_encode_event_signature("Transfer(address,address,uint256)");
211+
static_assert(
212+
signature ==
213+
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef_bytes32);
214+
215+
auto const event = EventBuilder(sender, signature)
216+
.add_topic(abi_encode_address(from))
217+
.add_topic(abi_encode_address(to))
218+
.add_data(abi_encode_uint(u256_be{value}))
219+
.build();
220+
221+
state_.store_log(event);
222+
call_tracer_.on_log(event);
223+
}
224+
}
183225
};
184226

185-
static_assert(sizeof(EvmcHost<EvmTraits<EVMC_LATEST_STABLE_REVISION>>) == 88);
227+
static_assert(sizeof(EvmcHost<EvmTraits<EVMC_LATEST_STABLE_REVISION>>) == 96);
186228
static_assert(alignof(EvmcHost<EvmTraits<EVMC_LATEST_STABLE_REVISION>>) == 8);
187229

188230
MONAD_NAMESPACE_END

category/execution/ethereum/test/test_call_trace.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,3 +443,92 @@ TYPED_TEST(TraitsTest, selfdestruct_logs)
443443
EXPECT_TRUE(frame.logs.has_value());
444444
}
445445
}
446+
447+
TYPED_TEST(TraitsTest, simulate_v1_trace)
448+
{
449+
InMemoryMachine machine;
450+
mpt::Db db{machine};
451+
TrieDb tdb{db};
452+
vm::VM vm;
453+
454+
commit_sequential(
455+
tdb,
456+
StateDeltas{
457+
{ADDR_A,
458+
StateDelta{
459+
.account =
460+
{std::nullopt,
461+
Account{
462+
.balance = std::numeric_limits<uint256_t>::max()}}}},
463+
{ADDR_B,
464+
StateDelta{.account = {std::nullopt, Account{.balance = 0}}}}},
465+
Code{},
466+
BlockHeader{});
467+
468+
BlockState bs{tdb, vm};
469+
Incarnation const incarnation{0, 0};
470+
State s{bs, incarnation};
471+
472+
Transaction const tx{
473+
.max_fee_per_gas = 1,
474+
.gas_limit = 1'000'000,
475+
.value = 1'000'000,
476+
.to = ADDR_B,
477+
};
478+
479+
auto const &sender = ADDR_A;
480+
auto const &beneficiary = ADDR_A;
481+
482+
evmc_tx_context const tx_context{};
483+
BlockHashBufferFinalized buffer{};
484+
std::vector<CallFrame> call_frames;
485+
CallTracer call_tracer{tx, call_frames};
486+
EvmcHost<typename TestFixture::Trait> host{
487+
call_tracer,
488+
tx_context,
489+
buffer,
490+
s,
491+
[](auto &&...) { return false; },
492+
true, // enable simulate_v1 tracing
493+
};
494+
495+
auto const result =
496+
ExecuteTransactionNoValidation<typename TestFixture::Trait>(
497+
EthereumMainnet{},
498+
tx,
499+
sender,
500+
authorities_empty,
501+
BlockHeader{.beneficiary = beneficiary},
502+
0)(s, host);
503+
504+
EXPECT_TRUE(result.status_code == EVMC_SUCCESS);
505+
EXPECT_EQ(call_frames.size(), 1);
506+
507+
CallFrame const expected{
508+
.type = CallType::CALL,
509+
.flags = 0,
510+
.from = sender,
511+
.to = ADDR_B,
512+
.value = 1'000'000,
513+
.gas = 1'000'000,
514+
.gas_used = 21'000,
515+
.status = EVMC_SUCCESS,
516+
.depth = 0,
517+
.logs = std::vector<CallFrame::Log>{{
518+
{
519+
.data = byte_string{intx::be::store<bytes32_t, uint256_t>(
520+
1'000'000)},
521+
.topics =
522+
std::vector{
523+
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef_bytes32,
524+
0x0000000000000000000000000000000000000000000000000000000000000100_bytes32,
525+
0x0000000000000000000000000000000000000000000000000000000000000101_bytes32,
526+
},
527+
.address = 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_address,
528+
},
529+
0,
530+
}},
531+
};
532+
533+
EXPECT_EQ(call_frames[0], expected);
534+
}

0 commit comments

Comments
 (0)