Skip to content

Commit f1ca632

Browse files
Baltolijhunsaker
authored andcommitted
Set std::nullopt as call frame to-address when creation fails
1 parent c3376f3 commit f1ca632

File tree

3 files changed

+101
-1
lines changed

3 files changed

+101
-1
lines changed

category/execution/ethereum/core/address.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <evmc/evmc.hpp>
2121

22+
#include <algorithm>
2223
#include <cstddef>
2324
#include <functional>
2425

@@ -29,6 +30,11 @@ using Address = ::evmc::address;
2930
static_assert(sizeof(Address) == 20);
3031
static_assert(alignof(Address) == 1);
3132

33+
constexpr bool is_zero(evmc_address const &addr)
34+
{
35+
return std::ranges::all_of(addr.bytes, [](auto const b) { return b == 0; });
36+
}
37+
3238
MONAD_NAMESPACE_END
3339

3440
namespace boost

category/execution/ethereum/test/test_call_trace.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// You should have received a copy of the GNU General Public License
1414
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1515

16+
#include <category/core/byte_string.hpp>
1617
#include <category/core/int.hpp>
1718
#include <category/execution/ethereum/block_hash_buffer.hpp>
1819
#include <category/execution/ethereum/chain/ethereum_mainnet.hpp>
@@ -40,6 +41,7 @@
4041
#include <optional>
4142

4243
using namespace monad;
44+
using namespace monad::literals;
4345
using namespace monad::test;
4446

4547
namespace
@@ -255,3 +257,93 @@ TYPED_TEST(TraitsTest, execute_reverted_insufficient_balance)
255257

256258
EXPECT_EQ(call_frames[0], expected);
257259
}
260+
261+
TYPED_TEST(TraitsTest, create_call_trace)
262+
{
263+
InMemoryMachine machine;
264+
mpt::Db db{machine};
265+
TrieDb tdb{db};
266+
vm::VM vm;
267+
268+
// Try to deploy a contract with reverting initcode
269+
auto const code = 0x60fe6000526001601f6000f0_bytes;
270+
auto const icode = vm::make_shared_intercode(code);
271+
auto const code_hash = to_bytes(keccak256(code));
272+
273+
commit_sequential(
274+
tdb,
275+
StateDeltas{
276+
{ADDR_A,
277+
StateDelta{
278+
.account =
279+
{std::nullopt,
280+
Account{
281+
.balance = std::numeric_limits<uint256_t>::max()}}}},
282+
{ADDR_B,
283+
StateDelta{
284+
.account =
285+
{std::nullopt,
286+
Account{.balance = 0, .code_hash = code_hash}}}}},
287+
Code{
288+
{code_hash, icode},
289+
},
290+
BlockHeader{});
291+
292+
BlockState bs{tdb, vm};
293+
Incarnation const incarnation{0, 0};
294+
State s{bs, incarnation};
295+
296+
Transaction const tx{
297+
.max_fee_per_gas = 1,
298+
.gas_limit = 1'000'000,
299+
.value = 0,
300+
.to = ADDR_B,
301+
};
302+
303+
auto const &sender = ADDR_A;
304+
auto const &beneficiary = ADDR_A;
305+
306+
evmc_tx_context const tx_context{};
307+
BlockHashBufferFinalized buffer{};
308+
std::vector<CallFrame> call_frames;
309+
CallTracer call_tracer{tx, call_frames};
310+
EvmcHost<typename TestFixture::Trait> host{
311+
call_tracer, tx_context, buffer, s};
312+
313+
auto const result =
314+
ExecuteTransactionNoValidation<typename TestFixture::Trait>(
315+
EthereumMainnet{},
316+
tx,
317+
sender,
318+
authorities_empty,
319+
BlockHeader{.beneficiary = beneficiary},
320+
0)(s, host);
321+
EXPECT_TRUE(result.status_code == EVMC_SUCCESS);
322+
ASSERT_TRUE(call_frames.size() == 2);
323+
324+
// We don't care about the specific revision-dependent gas used in each call
325+
// frame, only that the outer frame succeeds while the inner one fails to
326+
// create and has a `std::nullopt` to address.
327+
328+
EXPECT_EQ(call_frames[0].type, CallType::CALL);
329+
EXPECT_EQ(call_frames[0].flags, 0u);
330+
EXPECT_EQ(call_frames[0].from, sender);
331+
EXPECT_EQ(call_frames[0].to, ADDR_B);
332+
EXPECT_EQ(call_frames[0].value, 0u);
333+
EXPECT_EQ(call_frames[0].input, byte_string{});
334+
EXPECT_EQ(call_frames[0].output, byte_string{});
335+
EXPECT_EQ(call_frames[0].status, EVMC_SUCCESS);
336+
EXPECT_EQ(call_frames[0].depth, 0u);
337+
EXPECT_EQ(call_frames[0].logs, std::vector<CallFrame::Log>{});
338+
339+
EXPECT_EQ(call_frames[1].type, CallType::CREATE);
340+
EXPECT_EQ(call_frames[1].flags, 0u);
341+
EXPECT_EQ(call_frames[1].from, ADDR_B);
342+
EXPECT_EQ(call_frames[1].to, std::nullopt);
343+
EXPECT_EQ(call_frames[1].value, 0u);
344+
EXPECT_EQ(call_frames[1].input, 0xFE_bytes);
345+
EXPECT_EQ(call_frames[1].output, byte_string{});
346+
EXPECT_EQ(call_frames[1].status, EVMC_FAILURE);
347+
EXPECT_EQ(call_frames[1].depth, 1u);
348+
EXPECT_EQ(call_frames[1].logs, std::vector<CallFrame::Log>{});
349+
}

category/execution/ethereum/trace/call_tracer.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ void CallTracer::on_exit(evmc::Result const &res)
169169
frame.status = res.status_code;
170170

171171
if (frame.type == CallType::CREATE || frame.type == CallType::CREATE2) {
172-
frame.to = res.create_address;
172+
frame.to = is_zero(res.create_address)
173+
? std::nullopt
174+
: std::optional{res.create_address};
173175
}
174176

175177
last_.pop();

0 commit comments

Comments
 (0)