diff --git a/src/compiler/evm_frontend/evm_imported.cpp b/src/compiler/evm_frontend/evm_imported.cpp index 7ba2a9f0..895a3ea6 100644 --- a/src/compiler/evm_frontend/evm_imported.cpp +++ b/src/compiler/evm_frontend/evm_imported.cpp @@ -216,6 +216,7 @@ const RuntimeFunctions &getRuntimeFunctionTable() { .GetTLoad = &evmGetTLoad, .SetTStore = &evmSetTStore, .SetCallDataCopy = &evmSetCallDataCopy, + .TouchExtCodeCopyAccount = &evmTouchExtCodeCopyAccount, .SetExtCodeCopy = &evmSetExtCodeCopy, .SetReturnDataCopy = &evmSetReturnDataCopy, .ExpandMemoryNoGas = &evmExpandMemoryNoGas, @@ -674,6 +675,21 @@ void evmSetCallDataCopy(zen::runtime::EVMInstance *Instance, } } +void evmTouchExtCodeCopyAccount(zen::runtime::EVMInstance *Instance, + const uint8_t *Address) { + const zen::runtime::EVMModule *Module = Instance->getModule(); + ZEN_ASSERT(Module && Module->Host); + evmc::address Addr = loadAddressFromLE(Address); + + evmc_revision Rev = Instance->getRevision(); + if (Rev >= EVMC_BERLIN && + Module->Host->access_account(Addr) == EVMC_ACCESS_COLD) { + if (!Instance->chargeGas(zen::evm::ADDITIONAL_COLD_ACCOUNT_ACCESS_COST)) { + return; + } + } +} + void evmSetExtCodeCopy(zen::runtime::EVMInstance *Instance, const uint8_t *Address, uint64_t DestOffset, uint64_t Offset, uint64_t Size) { diff --git a/src/compiler/evm_frontend/evm_imported.h b/src/compiler/evm_frontend/evm_imported.h index be297904..717166d5 100644 --- a/src/compiler/evm_frontend/evm_imported.h +++ b/src/compiler/evm_frontend/evm_imported.h @@ -127,6 +127,7 @@ struct RuntimeFunctions { U256WithU256Fn GetTLoad; VoidWithU256U256Fn SetTStore; VoidWithUInt64UInt64UInt64Fn SetCallDataCopy; + VoidWithBytes32Fn TouchExtCodeCopyAccount; VoidWithBytes32UInt64UInt64UInt64Fn SetExtCodeCopy; UInt64WithUInt64UInt64UInt64Fn SetReturnDataCopy; VoidWithUInt64Fn ExpandMemoryNoGas; @@ -218,6 +219,8 @@ const uint8_t *evmGetBlobHash(zen::runtime::EVMInstance *Instance, const intx::uint256 *evmGetBlobBaseFee(zen::runtime::EVMInstance *Instance); void evmSetCallDataCopy(zen::runtime::EVMInstance *Instance, uint64_t DestOffset, uint64_t Offset, uint64_t Size); +void evmTouchExtCodeCopyAccount(zen::runtime::EVMInstance *Instance, + const uint8_t *Address); void evmSetExtCodeCopy(zen::runtime::EVMInstance *Instance, const uint8_t *Address, uint64_t DestOffset, uint64_t Offset, uint64_t Size); diff --git a/src/compiler/evm_frontend/evm_mir_compiler.cpp b/src/compiler/evm_frontend/evm_mir_compiler.cpp index 660b8b87..a1c44d17 100644 --- a/src/compiler/evm_frontend/evm_mir_compiler.cpp +++ b/src/compiler/evm_frontend/evm_mir_compiler.cpp @@ -5035,6 +5035,11 @@ void EVMMirBuilder::handleMStore8(Operand AddrComponents, void EVMMirBuilder::handleMCopy(Operand DestAddrComponents, Operand SrcAddrComponents, Operand LengthComponents) { + if (LengthComponents.isConstU64() && + LengthComponents.getConstValue()[0] == 0) { + return; + } + MType *I64Type = &Ctx.I64Type; MInstruction *Zero = createIntConstInstruction(I64Type, 0); @@ -6737,6 +6742,18 @@ void EVMMirBuilder::handleExtCodeCopy(Operand AddressComponents, Operand OffsetComponents, Operand SizeComponents) { const auto &RuntimeFunctions = getRuntimeFunctionTable(); + if (SizeComponents.isConstU64() && SizeComponents.getConstValue()[0] == 0) { +#ifdef ZEN_ENABLE_EVM_GAS_REGISTER + syncGasToMemory(); +#endif + callRuntimeForWithErrorCheck( + RuntimeFunctions.TouchExtCodeCopyAccount, AddressComponents); +#ifdef ZEN_ENABLE_EVM_GAS_REGISTER + reloadGasFromMemory(); +#endif + return; + } + // Use max uint64_t value if the offset/size is not 64-bit, because the // extcodecopy will fill zeros when offset is beyond code size or handle large // size properly. diff --git a/tests/evm_asm/extcodecopy_zero_size.easm b/tests/evm_asm/extcodecopy_zero_size.easm new file mode 100644 index 00000000..5d3f3a4d --- /dev/null +++ b/tests/evm_asm/extcodecopy_zero_size.easm @@ -0,0 +1,12 @@ +// EXTCODECOPY with zero size keeps existing memory and skips code copy work +PUSH1 0x2C +PUSH1 0x00 +MSTORE +PUSH1 0x00 +PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +PUSH1 0x00 +EXTCODECOPY +PUSH1 0x20 +PUSH1 0x00 +RETURN diff --git a/tests/evm_asm/extcodecopy_zero_size.evm.hex b/tests/evm_asm/extcodecopy_zero_size.evm.hex new file mode 100644 index 00000000..7d1821da --- /dev/null +++ b/tests/evm_asm/extcodecopy_zero_size.evm.hex @@ -0,0 +1 @@ +602C60005260007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60003C60206000F3 diff --git a/tests/evm_asm/extcodecopy_zero_size.expected b/tests/evm_asm/extcodecopy_zero_size.expected new file mode 100644 index 00000000..4769e7f1 --- /dev/null +++ b/tests/evm_asm/extcodecopy_zero_size.expected @@ -0,0 +1,8 @@ +status: success +error_code: 0 +stack: [] +memory: '000000000000000000000000000000000000000000000000000000000000002C' +storage: {} +transient_storage: {} +return: '000000000000000000000000000000000000000000000000000000000000002C' +events: [] diff --git a/tests/evm_asm/mcopy_zero_size.easm b/tests/evm_asm/mcopy_zero_size.easm new file mode 100644 index 00000000..3a8cce70 --- /dev/null +++ b/tests/evm_asm/mcopy_zero_size.easm @@ -0,0 +1,11 @@ +// MCOPY with zero size keeps existing memory and skips source/destination access +PUSH1 0x2D +PUSH1 0x00 +MSTORE +PUSH1 0x00 +PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +MCOPY +PUSH1 0x20 +PUSH1 0x00 +RETURN diff --git a/tests/evm_asm/mcopy_zero_size.evm.hex b/tests/evm_asm/mcopy_zero_size.evm.hex new file mode 100644 index 00000000..525e0e1c --- /dev/null +++ b/tests/evm_asm/mcopy_zero_size.evm.hex @@ -0,0 +1 @@ +602D60005260007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E60206000F3 diff --git a/tests/evm_asm/mcopy_zero_size.expected b/tests/evm_asm/mcopy_zero_size.expected new file mode 100644 index 00000000..fda71026 --- /dev/null +++ b/tests/evm_asm/mcopy_zero_size.expected @@ -0,0 +1,8 @@ +status: success +error_code: 0 +stack: [] +memory: '000000000000000000000000000000000000000000000000000000000000002D' +storage: {} +transient_storage: {} +return: '000000000000000000000000000000000000000000000000000000000000002D' +events: []