From 30ad238e75e58ce00359566a58c789f370361072 Mon Sep 17 00:00:00 2001 From: cl507523 Date: Mon, 25 May 2026 08:05:26 +0000 Subject: [PATCH] fix(evm): preserve return data after successful CREATE/CREATE2 The interpreter's CreateHandler cleared the return data buffer on CREATE success (`setReturnData({})`), violating EIP-211 which requires RETURNDATA to always reflect the output of the most recent sub-call. The CALL handler already preserved return data unconditionally; this commit aligns CREATE/CREATE2 with the same pattern: always assign return data from the host result before checking the status code. Without this fix, any RETURNDATASIZE / RETURNDATACOPY executed after a successful CREATE would observe an empty buffer, causing cascading mismatches (gas_left, status, value, create2_salt, recorded_calls count, and recorded_logs) against the evmone reference VM. Co-Authored-By: Claude Opus 4.6 --- src/evm/opcode_handlers.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/evm/opcode_handlers.cpp b/src/evm/opcode_handlers.cpp index 7a9b9aed2..1b088d1c8 100644 --- a/src/evm/opcode_handlers.cpp +++ b/src/evm/opcode_handlers.cpp @@ -1239,13 +1239,13 @@ void CreateHandler::doExecute() { } Context->getInstance()->addGasRefund(Result.gas_refund); + // Always set return data from the host result, matching CALL handler + // behavior and EVM spec (EIP-211: RETURNDATA should reflect last sub-call). + Context->setReturnData(std::vector( + Result.output_data, Result.output_data + Result.output_size)); if (Result.status_code == EVMC_SUCCESS) { - Context->setReturnData(std::vector()); Frame->pop(); // pop the assume value Frame->push(intx::be::load(Result.create_address)); - } else { - Context->setReturnData(std::vector( - Result.output_data, Result.output_data + Result.output_size)); } Context->setStatus(EVMC_SUCCESS); }