From fb6e17c89e064b1df103106e4e40c2b38b59aa7b Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Fri, 25 Oct 2024 23:03:29 +0200 Subject: [PATCH] Fix emulator memory layout --- system-contracts/SystemContractsHashes.json | 4 +- system-contracts/contracts/EvmEmulator.yul | 303 +++++++++--------- .../evm-emulator/EvmEmulator.template.yul | 15 +- .../EvmEmulatorFunctions.template.yul | 80 ++--- .../evm-emulator/EvmEmulatorLoop.template.yul | 64 ++-- 5 files changed, 230 insertions(+), 236 deletions(-) diff --git a/system-contracts/SystemContractsHashes.json b/system-contracts/SystemContractsHashes.json index bfc85b78ee..bb2a2908d3 100644 --- a/system-contracts/SystemContractsHashes.json +++ b/system-contracts/SystemContractsHashes.json @@ -122,8 +122,8 @@ "contractName": "EvmEmulator", "bytecodePath": "contracts-preprocessed/artifacts/EvmEmulator.yul/EvmEmulator.yul.zbin", "sourceCodePath": "contracts-preprocessed/EvmEmulator.yul", - "bytecodeHash": "0x01000d1d093f6a59a05b49ed5299ba34bb00dbac6f9bb3202f674dd73e3c8b47", - "sourceCodeHash": "0x1cf23b0864e4a958d66a7e2b74535478f866d61fd5af55651822d1565d5b5fb9" + "bytecodeHash": "0x01000cfbba1a8e74d49e2e72deceac517c07f8a95c27cf88d9c3696e8e383c7a", + "sourceCodeHash": "0x7d9ad6454772e2ff2b23e9ee77aca3174c9e4dd97957dca14051c5565cc47c72" }, { "contractName": "EvmGasManager", diff --git a/system-contracts/contracts/EvmEmulator.yul b/system-contracts/contracts/EvmEmulator.yul index 893e56f8a9..8b5842415a 100644 --- a/system-contracts/contracts/EvmEmulator.yul +++ b/system-contracts/contracts/EvmEmulator.yul @@ -4,19 +4,16 @@ object "EvmEmulator" { /// @dev It assumes that the initCode has been passed via the calldata and so we use the pointer /// to obtain the bytecode. function getConstructorBytecode() { - let bytecodeLengthOffset := BYTECODE_OFFSET() - let bytecodeOffset := add(BYTECODE_OFFSET(), 32) - loadCalldataIntoActivePtr() let size := getActivePtrDataSize() - if gt(size, MAX_POSSIBLE_INIT_BYTECODE()) { + if gt(size, MAX_POSSIBLE_INIT_BYTECODE_LEN()) { panic() } - mstore(bytecodeLengthOffset, size) - copyActivePtrData(bytecodeOffset, 0, size) + mstore(BYTECODE_LEN_OFFSET(), size) + copyActivePtrData(BYTECODE_OFFSET(), 0, size) } function padBytecode(offset, len) -> blobOffset, blobLen { @@ -43,7 +40,7 @@ object "EvmEmulator" { function validateBytecodeAndChargeGas(offset, deployedCodeLen, gasToReturn) -> returnGas { if deployedCodeLen { // EIP-3860 - if gt(deployedCodeLen, MAX_POSSIBLE_DEPLOYED_BYTECODE()) { + if gt(deployedCodeLen, MAX_POSSIBLE_DEPLOYED_BYTECODE_LEN()) { panic() } @@ -94,32 +91,37 @@ object "EvmEmulator" { offset := add(LAST_RETURNDATA_SIZE_OFFSET(), 64) } - function BYTECODE_OFFSET() -> offset { + function BYTECODE_LEN_OFFSET() -> offset { offset := add(STACK_OFFSET(), mul(1024, 32)) } - function MAX_POSSIBLE_DEPLOYED_BYTECODE() -> max { - max := 24576 + function BYTECODE_OFFSET() -> offset { + offset := add(BYTECODE_LEN_OFFSET(), 32) } - function MAX_POSSIBLE_INIT_BYTECODE() -> max { - max := mul(2, MAX_POSSIBLE_DEPLOYED_BYTECODE()) // EIP-3860 + function MAX_POSSIBLE_DEPLOYED_BYTECODE_LEN() -> max { + max := 24576 // EIP-170 } - function MEM_OFFSET() -> offset { - offset := add(BYTECODE_OFFSET(), MAX_POSSIBLE_INIT_BYTECODE()) + function MAX_POSSIBLE_INIT_BYTECODE_LEN() -> max { + max := mul(2, MAX_POSSIBLE_DEPLOYED_BYTECODE_LEN()) // EIP-3860 } - function MEM_OFFSET_INNER() -> offset { - offset := add(MEM_OFFSET(), 32) + function MEM_LEN_OFFSET() -> offset { + offset := add(BYTECODE_OFFSET(), MAX_POSSIBLE_INIT_BYTECODE_LEN()) + } + + function MEM_OFFSET() -> offset { + offset := add(MEM_LEN_OFFSET(), 32) } - function MAX_POSSIBLE_MEM() -> max { + // used to simplify gas calculations for memory expansion + function MAX_POSSIBLE_MEM_LEN() -> max { max := 0x100000 // 1MB } function MAX_MEMORY_FRAME() -> max { - max := add(MEM_OFFSET_INNER(), MAX_POSSIBLE_MEM()) + max := add(MEM_OFFSET(), MAX_POSSIBLE_MEM_LEN()) } function MAX_UINT() -> max_uint { @@ -194,7 +196,7 @@ object "EvmEmulator" { } // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 - function readIP(ip,maxAcceptablePos) -> opcode { + function readIP(ip, maxAcceptablePos) -> opcode { if gt(ip, maxAcceptablePos) { revert(0, 0) } @@ -283,14 +285,8 @@ object "EvmEmulator" { } // Basically performs an extcodecopy, while returning the length of the bytecode. - function _fetchDeployedCode(addr, _offset, _len) -> codeLen { - codeLen := _fetchDeployedCodeWithDest(addr, 0, _len, _offset) - } - - // Basically performs an extcodecopy, while returning the length of the bytecode. - function _fetchDeployedCodeWithDest(addr, _offset, _len, dest) -> codeLen { + function _fetchDeployedCodeWithDest(addr, dstOffset, srcOffset, len) -> codeLen { let codeHash := _getRawCodeHash(addr) - mstore(0, codeHash) let success := staticcall(gas(), CODE_ORACLE_SYSTEM_CONTRACT(), 0, 32, 0, 0) @@ -304,11 +300,11 @@ object "EvmEmulator" { returndatacopy(0, 0, 32) codeLen := mload(0) - if gt(_len, codeLen) { - _len := codeLen + if gt(len, codeLen) { + len := codeLen } - returndatacopy(dest, add(32, _offset), _len) + returndatacopy(dstOffset, add(32, srcOffset), len) } // Returns the length of the bytecode. @@ -335,13 +331,14 @@ object "EvmEmulator" { } function getDeployedBytecode() { - let codeLen := _fetchDeployedCode( - getCodeAddress(), - add(BYTECODE_OFFSET(), 32), - MAX_POSSIBLE_DEPLOYED_BYTECODE() + let codeLen := _fetchDeployedCodeWithDest( + getCodeAddress(), + BYTECODE_OFFSET(), // destination offset + 0, // source offset + MAX_POSSIBLE_DEPLOYED_BYTECODE_LEN() ) - mstore(BYTECODE_OFFSET(), codeLen) + mstore(BYTECODE_LEN_OFFSET(), codeLen) } function getMax(a, b) -> max { @@ -371,7 +368,7 @@ object "EvmEmulator" { function expandMemory(offset, size) -> gasCost { // memory expansion costs 0 if size is 0 if size { - let oldSizeInWords := mload(MEM_OFFSET()) + let oldSizeInWords := mload(MEM_LEN_OFFSET()) // div rounding up let newSizeInWords := div(add(add(offset, size), 31), 32) @@ -394,7 +391,7 @@ object "EvmEmulator" { gasCost := add(linearPart, quadraticPart) - mstore(MEM_OFFSET(), newSizeInWords) + mstore(MEM_LEN_OFFSET(), newSizeInWords) } } } @@ -501,7 +498,7 @@ object "EvmEmulator" { } function pushStackItem(sp, item, oldStackHead) -> newSp, stackHead { - if iszero(lt(sp, BYTECODE_OFFSET())) { + if iszero(lt(sp, BYTECODE_LEN_OFFSET())) { panic() } @@ -529,7 +526,7 @@ object "EvmEmulator" { } function pushStackCheck(sp, numInputs) { - if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_OFFSET())) { + if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_LEN_OFFSET())) { panic() } } @@ -680,9 +677,9 @@ object "EvmEmulator" { addr, gasToPass, value, - add(argsOffset, MEM_OFFSET_INNER()), + add(argsOffset, MEM_OFFSET()), argsSize, - add(retOffset, MEM_OFFSET_INNER()), + add(retOffset, MEM_OFFSET()), retSize ) @@ -743,9 +740,9 @@ object "EvmEmulator" { let success, frameGasLeft := _performStaticCall( addr, gasToPass, - add(MEM_OFFSET_INNER(), argsOffset), + add(MEM_OFFSET(), argsOffset), argsSize, - add(MEM_OFFSET_INNER(), retOffset), + add(MEM_OFFSET(), retOffset), retSize ) @@ -804,13 +801,13 @@ object "EvmEmulator" { let success := delegatecall( 0, // 0 gas since VM will add EVM_GAS_STIPEND() to gas addr, - add(MEM_OFFSET_INNER(), argsOffset), + add(MEM_OFFSET(), argsOffset), argsSize, 0, 0 ) - let frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) + let frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET(), retOffset), retSize) let gasUsed := sub(gasToPass, frameGasLeft) newEvmGasLeft := chargeGas(evmGasLeft, gasUsed) @@ -899,7 +896,7 @@ object "EvmEmulator" { // The gas cost mentioned here is purely the cost of the contract, // and does not consider the cost of the call itself nor the instructions // to put the parameters in memory. - // Take into account MEM_OFFSET_INNER() when passing the argsOffset + // Take into account MEM_OFFSET() when passing the argsOffset function getGasForPrecompiles(addr, argsOffset, argsSize) -> gasToCharge { switch addr case 0x01 { // ecRecover @@ -1124,7 +1121,7 @@ object "EvmEmulator" { checkMemIsAccessible(offset, size) // EIP-3860 - if gt(size, MAX_POSSIBLE_INIT_BYTECODE()) { + if gt(size, MAX_POSSIBLE_INIT_BYTECODE_LEN()) { panic() } @@ -1146,7 +1143,7 @@ object "EvmEmulator" { _eraseReturndataPointer() - offset := add(MEM_OFFSET_INNER(), offset) // caller must ensure that it doesn't overflow + offset := add(MEM_OFFSET(), offset) // caller must ensure that it doesn't overflow let gasForTheCall := capGasForCall(evmGasLeft, INF_PASS_GAS()) @@ -1292,21 +1289,21 @@ object "EvmEmulator" { isStatic, ) -> returnOffset, returnLen, retGasLeft { - returnOffset := MEM_OFFSET_INNER() + returnOffset := MEM_OFFSET() returnLen := 0 // stack pointer - index to first stack element; empty stack = -1 let sp := sub(STACK_OFFSET(), 32) // instruction pointer - index to next instruction. Not called pc because it's an // actual yul/evm instruction. - let ip := add(BYTECODE_OFFSET(), 32) + let ip := BYTECODE_OFFSET() let opcode let stackHead - let maxAcceptablePos := add(add(BYTECODE_OFFSET(), mload(BYTECODE_OFFSET())), 31) + let maxAcceptablePos := sub(add(BYTECODE_OFFSET(), mload(BYTECODE_LEN_OFFSET())), 1) for { } true { } { - opcode := readIP(ip,maxAcceptablePos) + opcode := readIP(ip, maxAcceptablePos) switch opcode case 0x00 { // OP_STOP @@ -1590,7 +1587,7 @@ object "EvmEmulator" { let dynamicGas := add(mul(6, shr(5, add(size, 31))), expandMemory(offset, size)) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - stackHead := keccak256(add(MEM_OFFSET_INNER(), offset), size) + stackHead := keccak256(add(MEM_OFFSET(), offset), size) ip := add(ip, 1) } @@ -1662,14 +1659,14 @@ object "EvmEmulator" { let dynamicGas := add(mul(3, shr(5, add(size, 31))), expandMemory(destOffset, size)) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - calldatacopy(add(destOffset, MEM_OFFSET_INNER()), offset, size) + calldatacopy(add(destOffset, MEM_OFFSET()), offset, size) ip := add(ip, 1) } case 0x38 { // OP_CODESIZE evmGasLeft := chargeGas(evmGasLeft, 2) - let bytecodeLen := mload(BYTECODE_OFFSET()) + let bytecodeLen := mload(BYTECODE_LEN_OFFSET()) sp, stackHead := pushStackItem(sp, bytecodeLen, stackHead) ip := add(ip, 1) } @@ -1691,12 +1688,12 @@ object "EvmEmulator" { let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(dstOffset, len)) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - dstOffset := add(dstOffset, MEM_OFFSET_INNER()) - sourceOffset := add(add(sourceOffset, BYTECODE_OFFSET()), 32) + dstOffset := add(dstOffset, MEM_OFFSET()) + sourceOffset := add(sourceOffset, BYTECODE_OFFSET()) checkOverflow(sourceOffset, len) // Check bytecode overflow - if gt(add(sourceOffset, len), sub(MEM_OFFSET(), 1)) { + if gt(add(sourceOffset, len), sub(MEM_LEN_OFFSET(), 1)) { panic() } @@ -1728,20 +1725,20 @@ object "EvmEmulator" { case 0x3C { // OP_EXTCODECOPY evmGasLeft := chargeGas(evmGasLeft, 100) - let addr, dest, offset, len + let addr, dstOffset, srcOffset, len popStackCheck(sp, 4) addr, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - dest, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - offset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) + dstOffset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) + srcOffset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) len, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - checkMemIsAccessible(dest, len) + checkMemIsAccessible(dstOffset, len) // dynamicGas = 3 * minimum_word_size + memory_expansion_cost + address_access_cost // minimum_word_size = (size + 31) / 32 let dynamicGas := add( mul(3, shr(5, add(len, 31))), - expandMemory(dest, len) + expandMemory(dstOffset, len) ) if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) { @@ -1750,11 +1747,11 @@ object "EvmEmulator" { evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - $llvm_AlwaysInline_llvm$_memsetToZero(dest, len) + $llvm_AlwaysInline_llvm$_memsetToZero(dstOffset, len) // Gets the code from the addr if and(iszero(iszero(_getRawCodeHash(addr))), gt(len, 0)) { - pop(_fetchDeployedCodeWithDest(addr, offset, len, add(dest, MEM_OFFSET_INNER()))) + pop(_fetchDeployedCodeWithDest(addr, add(dstOffset, MEM_OFFSET()), srcOffset, len)) } ip := add(ip, 1) @@ -1789,7 +1786,7 @@ object "EvmEmulator" { panic() } - copyActivePtrData(add(MEM_OFFSET_INNER(), dstOffset), sourceOffset, len) + copyActivePtrData(add(MEM_OFFSET(), dstOffset), sourceOffset, len) ip := add(ip, 1) } case 0x3F { // OP_EXTCODEHASH @@ -1873,7 +1870,7 @@ object "EvmEmulator" { let expansionGas := expandMemory(offset, 32) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - stackHead := mload(add(MEM_OFFSET_INNER(), offset)) + stackHead := mload(add(MEM_OFFSET(), offset)) ip := add(ip, 1) } @@ -1890,7 +1887,7 @@ object "EvmEmulator" { let expansionGas := expandMemory(offset, 32) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - mstore(add(MEM_OFFSET_INNER(), offset), value) + mstore(add(MEM_OFFSET(), offset), value) ip := add(ip, 1) } case 0x53 { // OP_MSTORE8 @@ -1906,7 +1903,7 @@ object "EvmEmulator" { let expansionGas := expandMemory(offset, 1) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - mstore8(add(MEM_OFFSET_INNER(), offset), value) + mstore8(add(MEM_OFFSET(), offset), value) ip := add(ip, 1) } case 0x54 { // OP_SLOAD @@ -1977,7 +1974,7 @@ object "EvmEmulator" { counter, sp, stackHead := popStackItem(sp, stackHead) - ip := add(add(BYTECODE_OFFSET(), 32), counter) + ip := add(BYTECODE_OFFSET(), counter) // Check next opcode is JUMPDEST let nextOpcode := readIP(ip,maxAcceptablePos) @@ -2003,7 +2000,7 @@ object "EvmEmulator" { continue } - ip := add(add(BYTECODE_OFFSET(), 32), counter) + ip := add(BYTECODE_OFFSET(), counter) // Check next opcode is JUMPDEST let nextOpcode := readIP(ip, maxAcceptablePos) @@ -2020,14 +2017,14 @@ object "EvmEmulator" { ip := add(ip, 1) // PC = ip - 32 (bytecode size) - 1 (current instruction) - sp, stackHead := pushStackItem(sp, sub(sub(ip, BYTECODE_OFFSET()), 33), stackHead) + sp, stackHead := pushStackItem(sp, sub(sub(ip, BYTECODE_LEN_OFFSET()), 33), stackHead) } case 0x59 { // OP_MSIZE evmGasLeft := chargeGas(evmGasLeft, 2) let size - size := mload(MEM_OFFSET()) + size := mload(MEM_LEN_OFFSET()) size := shl(5, size) sp, stackHead := pushStackItem(sp, size, stackHead) ip := add(ip, 1) @@ -2080,7 +2077,7 @@ object "EvmEmulator" { evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - mcopy(add(destOffset, MEM_OFFSET_INNER()), add(offset, MEM_OFFSET_INNER()), size) + mcopy(add(destOffset, MEM_OFFSET()), add(offset, MEM_OFFSET()), size) ip := add(ip, 1) } case 0x5F { // OP_PUSH0 @@ -2526,7 +2523,7 @@ object "EvmEmulator" { let dynamicGas := add(shl(3, size), expandMemory(offset, size)) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - log0(add(offset, MEM_OFFSET_INNER()), size) + log0(add(offset, MEM_OFFSET()), size) ip := add(ip, 1) } case 0xA1 { // OP_LOG1 @@ -2551,7 +2548,7 @@ object "EvmEmulator" { { let topic1 topic1, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - log1(add(offset, MEM_OFFSET_INNER()), size, topic1) + log1(add(offset, MEM_OFFSET()), size, topic1) } ip := add(ip, 1) } @@ -2578,7 +2575,7 @@ object "EvmEmulator" { let topic1, topic2 topic1, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic2, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - log2(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2) + log2(add(offset, MEM_OFFSET()), size, topic1, topic2) } ip := add(ip, 1) } @@ -2606,7 +2603,7 @@ object "EvmEmulator" { topic1, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic2, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic3, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - log3(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2, topic3) + log3(add(offset, MEM_OFFSET()), size, topic1, topic2, topic3) } ip := add(ip, 1) } @@ -2635,7 +2632,7 @@ object "EvmEmulator" { topic2, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic3, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic4, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - log4(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2, topic3, topic4) + log4(add(offset, MEM_OFFSET()), size, topic1, topic2, topic3, topic4) } ip := add(ip, 1) } @@ -2674,7 +2671,7 @@ object "EvmEmulator" { returnLen := size // Don't check overflow here since previous checks are enough to ensure this is safe - returnOffset := add(MEM_OFFSET_INNER(), offset) + returnOffset := add(MEM_OFFSET(), offset) break } case 0xF4 { // OP_DELEGATECALL @@ -2706,7 +2703,7 @@ object "EvmEmulator" { evmGasLeft := chargeGas(evmGasLeft, expandMemory(offset, size)) // Don't check overflow here since previous checks are enough to ensure this is safe - offset := add(offset, MEM_OFFSET_INNER()) + offset := add(offset, MEM_OFFSET()) if eq(isCallerEVM, 1) { offset := sub(offset, 32) @@ -3131,32 +3128,37 @@ object "EvmEmulator" { offset := add(LAST_RETURNDATA_SIZE_OFFSET(), 64) } - function BYTECODE_OFFSET() -> offset { + function BYTECODE_LEN_OFFSET() -> offset { offset := add(STACK_OFFSET(), mul(1024, 32)) } - function MAX_POSSIBLE_DEPLOYED_BYTECODE() -> max { - max := 24576 + function BYTECODE_OFFSET() -> offset { + offset := add(BYTECODE_LEN_OFFSET(), 32) } - function MAX_POSSIBLE_INIT_BYTECODE() -> max { - max := mul(2, MAX_POSSIBLE_DEPLOYED_BYTECODE()) // EIP-3860 + function MAX_POSSIBLE_DEPLOYED_BYTECODE_LEN() -> max { + max := 24576 // EIP-170 } - function MEM_OFFSET() -> offset { - offset := add(BYTECODE_OFFSET(), MAX_POSSIBLE_INIT_BYTECODE()) + function MAX_POSSIBLE_INIT_BYTECODE_LEN() -> max { + max := mul(2, MAX_POSSIBLE_DEPLOYED_BYTECODE_LEN()) // EIP-3860 } - function MEM_OFFSET_INNER() -> offset { - offset := add(MEM_OFFSET(), 32) + function MEM_LEN_OFFSET() -> offset { + offset := add(BYTECODE_OFFSET(), MAX_POSSIBLE_INIT_BYTECODE_LEN()) } - function MAX_POSSIBLE_MEM() -> max { + function MEM_OFFSET() -> offset { + offset := add(MEM_LEN_OFFSET(), 32) + } + + // used to simplify gas calculations for memory expansion + function MAX_POSSIBLE_MEM_LEN() -> max { max := 0x100000 // 1MB } function MAX_MEMORY_FRAME() -> max { - max := add(MEM_OFFSET_INNER(), MAX_POSSIBLE_MEM()) + max := add(MEM_OFFSET(), MAX_POSSIBLE_MEM_LEN()) } function MAX_UINT() -> max_uint { @@ -3231,7 +3233,7 @@ object "EvmEmulator" { } // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 - function readIP(ip,maxAcceptablePos) -> opcode { + function readIP(ip, maxAcceptablePos) -> opcode { if gt(ip, maxAcceptablePos) { revert(0, 0) } @@ -3320,14 +3322,8 @@ object "EvmEmulator" { } // Basically performs an extcodecopy, while returning the length of the bytecode. - function _fetchDeployedCode(addr, _offset, _len) -> codeLen { - codeLen := _fetchDeployedCodeWithDest(addr, 0, _len, _offset) - } - - // Basically performs an extcodecopy, while returning the length of the bytecode. - function _fetchDeployedCodeWithDest(addr, _offset, _len, dest) -> codeLen { + function _fetchDeployedCodeWithDest(addr, dstOffset, srcOffset, len) -> codeLen { let codeHash := _getRawCodeHash(addr) - mstore(0, codeHash) let success := staticcall(gas(), CODE_ORACLE_SYSTEM_CONTRACT(), 0, 32, 0, 0) @@ -3341,11 +3337,11 @@ object "EvmEmulator" { returndatacopy(0, 0, 32) codeLen := mload(0) - if gt(_len, codeLen) { - _len := codeLen + if gt(len, codeLen) { + len := codeLen } - returndatacopy(dest, add(32, _offset), _len) + returndatacopy(dstOffset, add(32, srcOffset), len) } // Returns the length of the bytecode. @@ -3372,13 +3368,14 @@ object "EvmEmulator" { } function getDeployedBytecode() { - let codeLen := _fetchDeployedCode( - getCodeAddress(), - add(BYTECODE_OFFSET(), 32), - MAX_POSSIBLE_DEPLOYED_BYTECODE() + let codeLen := _fetchDeployedCodeWithDest( + getCodeAddress(), + BYTECODE_OFFSET(), // destination offset + 0, // source offset + MAX_POSSIBLE_DEPLOYED_BYTECODE_LEN() ) - mstore(BYTECODE_OFFSET(), codeLen) + mstore(BYTECODE_LEN_OFFSET(), codeLen) } function getMax(a, b) -> max { @@ -3408,7 +3405,7 @@ object "EvmEmulator" { function expandMemory(offset, size) -> gasCost { // memory expansion costs 0 if size is 0 if size { - let oldSizeInWords := mload(MEM_OFFSET()) + let oldSizeInWords := mload(MEM_LEN_OFFSET()) // div rounding up let newSizeInWords := div(add(add(offset, size), 31), 32) @@ -3431,7 +3428,7 @@ object "EvmEmulator" { gasCost := add(linearPart, quadraticPart) - mstore(MEM_OFFSET(), newSizeInWords) + mstore(MEM_LEN_OFFSET(), newSizeInWords) } } } @@ -3538,7 +3535,7 @@ object "EvmEmulator" { } function pushStackItem(sp, item, oldStackHead) -> newSp, stackHead { - if iszero(lt(sp, BYTECODE_OFFSET())) { + if iszero(lt(sp, BYTECODE_LEN_OFFSET())) { panic() } @@ -3566,7 +3563,7 @@ object "EvmEmulator" { } function pushStackCheck(sp, numInputs) { - if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_OFFSET())) { + if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_LEN_OFFSET())) { panic() } } @@ -3717,9 +3714,9 @@ object "EvmEmulator" { addr, gasToPass, value, - add(argsOffset, MEM_OFFSET_INNER()), + add(argsOffset, MEM_OFFSET()), argsSize, - add(retOffset, MEM_OFFSET_INNER()), + add(retOffset, MEM_OFFSET()), retSize ) @@ -3780,9 +3777,9 @@ object "EvmEmulator" { let success, frameGasLeft := _performStaticCall( addr, gasToPass, - add(MEM_OFFSET_INNER(), argsOffset), + add(MEM_OFFSET(), argsOffset), argsSize, - add(MEM_OFFSET_INNER(), retOffset), + add(MEM_OFFSET(), retOffset), retSize ) @@ -3841,13 +3838,13 @@ object "EvmEmulator" { let success := delegatecall( 0, // 0 gas since VM will add EVM_GAS_STIPEND() to gas addr, - add(MEM_OFFSET_INNER(), argsOffset), + add(MEM_OFFSET(), argsOffset), argsSize, 0, 0 ) - let frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) + let frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET(), retOffset), retSize) let gasUsed := sub(gasToPass, frameGasLeft) newEvmGasLeft := chargeGas(evmGasLeft, gasUsed) @@ -3936,7 +3933,7 @@ object "EvmEmulator" { // The gas cost mentioned here is purely the cost of the contract, // and does not consider the cost of the call itself nor the instructions // to put the parameters in memory. - // Take into account MEM_OFFSET_INNER() when passing the argsOffset + // Take into account MEM_OFFSET() when passing the argsOffset function getGasForPrecompiles(addr, argsOffset, argsSize) -> gasToCharge { switch addr case 0x01 { // ecRecover @@ -4161,7 +4158,7 @@ object "EvmEmulator" { checkMemIsAccessible(offset, size) // EIP-3860 - if gt(size, MAX_POSSIBLE_INIT_BYTECODE()) { + if gt(size, MAX_POSSIBLE_INIT_BYTECODE_LEN()) { panic() } @@ -4183,7 +4180,7 @@ object "EvmEmulator" { _eraseReturndataPointer() - offset := add(MEM_OFFSET_INNER(), offset) // caller must ensure that it doesn't overflow + offset := add(MEM_OFFSET(), offset) // caller must ensure that it doesn't overflow let gasForTheCall := capGasForCall(evmGasLeft, INF_PASS_GAS()) @@ -4329,21 +4326,21 @@ object "EvmEmulator" { isStatic, ) -> returnOffset, returnLen { - returnOffset := MEM_OFFSET_INNER() + returnOffset := MEM_OFFSET() returnLen := 0 // stack pointer - index to first stack element; empty stack = -1 let sp := sub(STACK_OFFSET(), 32) // instruction pointer - index to next instruction. Not called pc because it's an // actual yul/evm instruction. - let ip := add(BYTECODE_OFFSET(), 32) + let ip := BYTECODE_OFFSET() let opcode let stackHead - let maxAcceptablePos := add(add(BYTECODE_OFFSET(), mload(BYTECODE_OFFSET())), 31) + let maxAcceptablePos := sub(add(BYTECODE_OFFSET(), mload(BYTECODE_LEN_OFFSET())), 1) for { } true { } { - opcode := readIP(ip,maxAcceptablePos) + opcode := readIP(ip, maxAcceptablePos) switch opcode case 0x00 { // OP_STOP @@ -4627,7 +4624,7 @@ object "EvmEmulator" { let dynamicGas := add(mul(6, shr(5, add(size, 31))), expandMemory(offset, size)) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - stackHead := keccak256(add(MEM_OFFSET_INNER(), offset), size) + stackHead := keccak256(add(MEM_OFFSET(), offset), size) ip := add(ip, 1) } @@ -4699,14 +4696,14 @@ object "EvmEmulator" { let dynamicGas := add(mul(3, shr(5, add(size, 31))), expandMemory(destOffset, size)) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - calldatacopy(add(destOffset, MEM_OFFSET_INNER()), offset, size) + calldatacopy(add(destOffset, MEM_OFFSET()), offset, size) ip := add(ip, 1) } case 0x38 { // OP_CODESIZE evmGasLeft := chargeGas(evmGasLeft, 2) - let bytecodeLen := mload(BYTECODE_OFFSET()) + let bytecodeLen := mload(BYTECODE_LEN_OFFSET()) sp, stackHead := pushStackItem(sp, bytecodeLen, stackHead) ip := add(ip, 1) } @@ -4728,12 +4725,12 @@ object "EvmEmulator" { let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(dstOffset, len)) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - dstOffset := add(dstOffset, MEM_OFFSET_INNER()) - sourceOffset := add(add(sourceOffset, BYTECODE_OFFSET()), 32) + dstOffset := add(dstOffset, MEM_OFFSET()) + sourceOffset := add(sourceOffset, BYTECODE_OFFSET()) checkOverflow(sourceOffset, len) // Check bytecode overflow - if gt(add(sourceOffset, len), sub(MEM_OFFSET(), 1)) { + if gt(add(sourceOffset, len), sub(MEM_LEN_OFFSET(), 1)) { panic() } @@ -4765,20 +4762,20 @@ object "EvmEmulator" { case 0x3C { // OP_EXTCODECOPY evmGasLeft := chargeGas(evmGasLeft, 100) - let addr, dest, offset, len + let addr, dstOffset, srcOffset, len popStackCheck(sp, 4) addr, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - dest, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - offset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) + dstOffset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) + srcOffset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) len, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - checkMemIsAccessible(dest, len) + checkMemIsAccessible(dstOffset, len) // dynamicGas = 3 * minimum_word_size + memory_expansion_cost + address_access_cost // minimum_word_size = (size + 31) / 32 let dynamicGas := add( mul(3, shr(5, add(len, 31))), - expandMemory(dest, len) + expandMemory(dstOffset, len) ) if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) { @@ -4787,11 +4784,11 @@ object "EvmEmulator" { evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - $llvm_AlwaysInline_llvm$_memsetToZero(dest, len) + $llvm_AlwaysInline_llvm$_memsetToZero(dstOffset, len) // Gets the code from the addr if and(iszero(iszero(_getRawCodeHash(addr))), gt(len, 0)) { - pop(_fetchDeployedCodeWithDest(addr, offset, len, add(dest, MEM_OFFSET_INNER()))) + pop(_fetchDeployedCodeWithDest(addr, add(dstOffset, MEM_OFFSET()), srcOffset, len)) } ip := add(ip, 1) @@ -4826,7 +4823,7 @@ object "EvmEmulator" { panic() } - copyActivePtrData(add(MEM_OFFSET_INNER(), dstOffset), sourceOffset, len) + copyActivePtrData(add(MEM_OFFSET(), dstOffset), sourceOffset, len) ip := add(ip, 1) } case 0x3F { // OP_EXTCODEHASH @@ -4910,7 +4907,7 @@ object "EvmEmulator" { let expansionGas := expandMemory(offset, 32) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - stackHead := mload(add(MEM_OFFSET_INNER(), offset)) + stackHead := mload(add(MEM_OFFSET(), offset)) ip := add(ip, 1) } @@ -4927,7 +4924,7 @@ object "EvmEmulator" { let expansionGas := expandMemory(offset, 32) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - mstore(add(MEM_OFFSET_INNER(), offset), value) + mstore(add(MEM_OFFSET(), offset), value) ip := add(ip, 1) } case 0x53 { // OP_MSTORE8 @@ -4943,7 +4940,7 @@ object "EvmEmulator" { let expansionGas := expandMemory(offset, 1) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - mstore8(add(MEM_OFFSET_INNER(), offset), value) + mstore8(add(MEM_OFFSET(), offset), value) ip := add(ip, 1) } case 0x54 { // OP_SLOAD @@ -5014,7 +5011,7 @@ object "EvmEmulator" { counter, sp, stackHead := popStackItem(sp, stackHead) - ip := add(add(BYTECODE_OFFSET(), 32), counter) + ip := add(BYTECODE_OFFSET(), counter) // Check next opcode is JUMPDEST let nextOpcode := readIP(ip,maxAcceptablePos) @@ -5040,7 +5037,7 @@ object "EvmEmulator" { continue } - ip := add(add(BYTECODE_OFFSET(), 32), counter) + ip := add(BYTECODE_OFFSET(), counter) // Check next opcode is JUMPDEST let nextOpcode := readIP(ip, maxAcceptablePos) @@ -5057,14 +5054,14 @@ object "EvmEmulator" { ip := add(ip, 1) // PC = ip - 32 (bytecode size) - 1 (current instruction) - sp, stackHead := pushStackItem(sp, sub(sub(ip, BYTECODE_OFFSET()), 33), stackHead) + sp, stackHead := pushStackItem(sp, sub(sub(ip, BYTECODE_LEN_OFFSET()), 33), stackHead) } case 0x59 { // OP_MSIZE evmGasLeft := chargeGas(evmGasLeft, 2) let size - size := mload(MEM_OFFSET()) + size := mload(MEM_LEN_OFFSET()) size := shl(5, size) sp, stackHead := pushStackItem(sp, size, stackHead) ip := add(ip, 1) @@ -5117,7 +5114,7 @@ object "EvmEmulator" { evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - mcopy(add(destOffset, MEM_OFFSET_INNER()), add(offset, MEM_OFFSET_INNER()), size) + mcopy(add(destOffset, MEM_OFFSET()), add(offset, MEM_OFFSET()), size) ip := add(ip, 1) } case 0x5F { // OP_PUSH0 @@ -5563,7 +5560,7 @@ object "EvmEmulator" { let dynamicGas := add(shl(3, size), expandMemory(offset, size)) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - log0(add(offset, MEM_OFFSET_INNER()), size) + log0(add(offset, MEM_OFFSET()), size) ip := add(ip, 1) } case 0xA1 { // OP_LOG1 @@ -5588,7 +5585,7 @@ object "EvmEmulator" { { let topic1 topic1, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - log1(add(offset, MEM_OFFSET_INNER()), size, topic1) + log1(add(offset, MEM_OFFSET()), size, topic1) } ip := add(ip, 1) } @@ -5615,7 +5612,7 @@ object "EvmEmulator" { let topic1, topic2 topic1, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic2, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - log2(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2) + log2(add(offset, MEM_OFFSET()), size, topic1, topic2) } ip := add(ip, 1) } @@ -5643,7 +5640,7 @@ object "EvmEmulator" { topic1, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic2, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic3, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - log3(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2, topic3) + log3(add(offset, MEM_OFFSET()), size, topic1, topic2, topic3) } ip := add(ip, 1) } @@ -5672,7 +5669,7 @@ object "EvmEmulator" { topic2, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic3, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic4, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - log4(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2, topic3, topic4) + log4(add(offset, MEM_OFFSET()), size, topic1, topic2, topic3, topic4) } ip := add(ip, 1) } @@ -5711,7 +5708,7 @@ object "EvmEmulator" { returnLen := size // Don't check overflow here since previous checks are enough to ensure this is safe - returnOffset := add(MEM_OFFSET_INNER(), offset) + returnOffset := add(MEM_OFFSET(), offset) break } case 0xF4 { // OP_DELEGATECALL @@ -5743,7 +5740,7 @@ object "EvmEmulator" { evmGasLeft := chargeGas(evmGasLeft, expandMemory(offset, size)) // Don't check overflow here since previous checks are enough to ensure this is safe - offset := add(offset, MEM_OFFSET_INNER()) + offset := add(offset, MEM_OFFSET()) if eq(isCallerEVM, 1) { offset := sub(offset, 32) diff --git a/system-contracts/evm-emulator/EvmEmulator.template.yul b/system-contracts/evm-emulator/EvmEmulator.template.yul index 1730a0b8ea..e42bb3826e 100644 --- a/system-contracts/evm-emulator/EvmEmulator.template.yul +++ b/system-contracts/evm-emulator/EvmEmulator.template.yul @@ -4,19 +4,16 @@ object "EvmEmulator" { /// @dev It assumes that the initCode has been passed via the calldata and so we use the pointer /// to obtain the bytecode. function getConstructorBytecode() { - let bytecodeLengthOffset := BYTECODE_OFFSET() - let bytecodeOffset := add(BYTECODE_OFFSET(), 32) - loadCalldataIntoActivePtr() let size := getActivePtrDataSize() - if gt(size, MAX_POSSIBLE_INIT_BYTECODE()) { + if gt(size, MAX_POSSIBLE_INIT_BYTECODE_LEN()) { panic() } - mstore(bytecodeLengthOffset, size) - copyActivePtrData(bytecodeOffset, 0, size) + mstore(BYTECODE_LEN_OFFSET(), size) + copyActivePtrData(BYTECODE_OFFSET(), 0, size) } function padBytecode(offset, len) -> blobOffset, blobLen { @@ -43,7 +40,7 @@ object "EvmEmulator" { function validateBytecodeAndChargeGas(offset, deployedCodeLen, gasToReturn) -> returnGas { if deployedCodeLen { // EIP-3860 - if gt(deployedCodeLen, MAX_POSSIBLE_DEPLOYED_BYTECODE()) { + if gt(deployedCodeLen, MAX_POSSIBLE_DEPLOYED_BYTECODE_LEN()) { panic() } @@ -66,7 +63,7 @@ object "EvmEmulator" { isStatic, ) -> returnOffset, returnLen, retGasLeft { - returnOffset := MEM_OFFSET_INNER() + returnOffset := MEM_OFFSET() returnLen := 0 @@ -112,7 +109,7 @@ object "EvmEmulator" { isStatic, ) -> returnOffset, returnLen { - returnOffset := MEM_OFFSET_INNER() + returnOffset := MEM_OFFSET() returnLen := 0 diff --git a/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul b/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul index 0a716511aa..d48c09afc5 100644 --- a/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul +++ b/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul @@ -34,32 +34,37 @@ function STACK_OFFSET() -> offset { offset := add(LAST_RETURNDATA_SIZE_OFFSET(), 64) } -function BYTECODE_OFFSET() -> offset { +function BYTECODE_LEN_OFFSET() -> offset { offset := add(STACK_OFFSET(), mul(1024, 32)) } -function MAX_POSSIBLE_DEPLOYED_BYTECODE() -> max { - max := 24576 +function BYTECODE_OFFSET() -> offset { + offset := add(BYTECODE_LEN_OFFSET(), 32) } -function MAX_POSSIBLE_INIT_BYTECODE() -> max { - max := mul(2, MAX_POSSIBLE_DEPLOYED_BYTECODE()) // EIP-3860 +function MAX_POSSIBLE_DEPLOYED_BYTECODE_LEN() -> max { + max := 24576 // EIP-170 } -function MEM_OFFSET() -> offset { - offset := add(BYTECODE_OFFSET(), MAX_POSSIBLE_INIT_BYTECODE()) +function MAX_POSSIBLE_INIT_BYTECODE_LEN() -> max { + max := mul(2, MAX_POSSIBLE_DEPLOYED_BYTECODE_LEN()) // EIP-3860 +} + +function MEM_LEN_OFFSET() -> offset { + offset := add(BYTECODE_OFFSET(), MAX_POSSIBLE_INIT_BYTECODE_LEN()) } -function MEM_OFFSET_INNER() -> offset { - offset := add(MEM_OFFSET(), 32) +function MEM_OFFSET() -> offset { + offset := add(MEM_LEN_OFFSET(), 32) } -function MAX_POSSIBLE_MEM() -> max { +// used to simplify gas calculations for memory expansion +function MAX_POSSIBLE_MEM_LEN() -> max { max := 0x100000 // 1MB } function MAX_MEMORY_FRAME() -> max { - max := add(MEM_OFFSET_INNER(), MAX_POSSIBLE_MEM()) + max := add(MEM_OFFSET(), MAX_POSSIBLE_MEM_LEN()) } function MAX_UINT() -> max_uint { @@ -134,7 +139,7 @@ function checkOverflow(data1, data2) { } // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 -function readIP(ip,maxAcceptablePos) -> opcode { +function readIP(ip, maxAcceptablePos) -> opcode { if gt(ip, maxAcceptablePos) { revert(0, 0) } @@ -223,14 +228,8 @@ function _getRawCodeHash(account) -> hash { } // Basically performs an extcodecopy, while returning the length of the bytecode. -function _fetchDeployedCode(addr, _offset, _len) -> codeLen { - codeLen := _fetchDeployedCodeWithDest(addr, 0, _len, _offset) -} - -// Basically performs an extcodecopy, while returning the length of the bytecode. -function _fetchDeployedCodeWithDest(addr, _offset, _len, dest) -> codeLen { +function _fetchDeployedCodeWithDest(addr, dstOffset, srcOffset, len) -> codeLen { let codeHash := _getRawCodeHash(addr) - mstore(0, codeHash) let success := staticcall(gas(), CODE_ORACLE_SYSTEM_CONTRACT(), 0, 32, 0, 0) @@ -244,11 +243,11 @@ function _fetchDeployedCodeWithDest(addr, _offset, _len, dest) -> codeLen { returndatacopy(0, 0, 32) codeLen := mload(0) - if gt(_len, codeLen) { - _len := codeLen + if gt(len, codeLen) { + len := codeLen } - returndatacopy(dest, add(32, _offset), _len) + returndatacopy(dstOffset, add(32, srcOffset), len) } // Returns the length of the bytecode. @@ -275,13 +274,14 @@ function _fetchDeployedCodeLen(addr) -> codeLen { } function getDeployedBytecode() { - let codeLen := _fetchDeployedCode( - getCodeAddress(), - add(BYTECODE_OFFSET(), 32), - MAX_POSSIBLE_DEPLOYED_BYTECODE() + let codeLen := _fetchDeployedCodeWithDest( + getCodeAddress(), + BYTECODE_OFFSET(), // destination offset + 0, // source offset + MAX_POSSIBLE_DEPLOYED_BYTECODE_LEN() ) - mstore(BYTECODE_OFFSET(), codeLen) + mstore(BYTECODE_LEN_OFFSET(), codeLen) } function getMax(a, b) -> max { @@ -311,7 +311,7 @@ function bitMaskFromBytes(nBytes) -> bitMask { function expandMemory(offset, size) -> gasCost { // memory expansion costs 0 if size is 0 if size { - let oldSizeInWords := mload(MEM_OFFSET()) + let oldSizeInWords := mload(MEM_LEN_OFFSET()) // div rounding up let newSizeInWords := div(add(add(offset, size), 31), 32) @@ -334,7 +334,7 @@ function expandMemory(offset, size) -> gasCost { gasCost := add(linearPart, quadraticPart) - mstore(MEM_OFFSET(), newSizeInWords) + mstore(MEM_LEN_OFFSET(), newSizeInWords) } } } @@ -441,7 +441,7 @@ function popStackItem(sp, oldStackHead) -> a, newSp, stackHead { } function pushStackItem(sp, item, oldStackHead) -> newSp, stackHead { - if iszero(lt(sp, BYTECODE_OFFSET())) { + if iszero(lt(sp, BYTECODE_LEN_OFFSET())) { panic() } @@ -469,7 +469,7 @@ function popStackCheck(sp, numInputs) { } function pushStackCheck(sp, numInputs) { - if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_OFFSET())) { + if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_LEN_OFFSET())) { panic() } } @@ -620,9 +620,9 @@ function performCall(oldSp, evmGasLeft, oldStackHead) -> newGasLeft, sp, stackHe addr, gasToPass, value, - add(argsOffset, MEM_OFFSET_INNER()), + add(argsOffset, MEM_OFFSET()), argsSize, - add(retOffset, MEM_OFFSET_INNER()), + add(retOffset, MEM_OFFSET()), retSize ) @@ -683,9 +683,9 @@ function performStaticCall(oldSp, evmGasLeft, oldStackHead) -> newGasLeft, sp, s let success, frameGasLeft := _performStaticCall( addr, gasToPass, - add(MEM_OFFSET_INNER(), argsOffset), + add(MEM_OFFSET(), argsOffset), argsSize, - add(MEM_OFFSET_INNER(), retOffset), + add(MEM_OFFSET(), retOffset), retSize ) @@ -744,13 +744,13 @@ function performDelegateCall(oldSp, evmGasLeft, isStatic, oldStackHead) -> newEv let success := delegatecall( 0, // 0 gas since VM will add EVM_GAS_STIPEND() to gas addr, - add(MEM_OFFSET_INNER(), argsOffset), + add(MEM_OFFSET(), argsOffset), argsSize, 0, 0 ) - let frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) + let frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET(), retOffset), retSize) let gasUsed := sub(gasToPass, frameGasLeft) newEvmGasLeft := chargeGas(evmGasLeft, gasUsed) @@ -839,7 +839,7 @@ function getMaxMemoryExpansionCost(retOffset, retSize, argsOffset, argsSize) -> // The gas cost mentioned here is purely the cost of the contract, // and does not consider the cost of the call itself nor the instructions // to put the parameters in memory. -// Take into account MEM_OFFSET_INNER() when passing the argsOffset +// Take into account MEM_OFFSET() when passing the argsOffset function getGasForPrecompiles(addr, argsOffset, argsSize) -> gasToCharge { switch addr case 0x01 { // ecRecover @@ -1064,7 +1064,7 @@ function $llvm_NoInline_llvm$_genericCreate(offset, size, value, evmGasLeftOld, checkMemIsAccessible(offset, size) // EIP-3860 - if gt(size, MAX_POSSIBLE_INIT_BYTECODE()) { + if gt(size, MAX_POSSIBLE_INIT_BYTECODE_LEN()) { panic() } @@ -1086,7 +1086,7 @@ function $llvm_NoInline_llvm$_genericCreate(offset, size, value, evmGasLeftOld, _eraseReturndataPointer() - offset := add(MEM_OFFSET_INNER(), offset) // caller must ensure that it doesn't overflow + offset := add(MEM_OFFSET(), offset) // caller must ensure that it doesn't overflow let gasForTheCall := capGasForCall(evmGasLeft, INF_PASS_GAS()) diff --git a/system-contracts/evm-emulator/EvmEmulatorLoop.template.yul b/system-contracts/evm-emulator/EvmEmulatorLoop.template.yul index c3bd57186d..0265cd443b 100644 --- a/system-contracts/evm-emulator/EvmEmulatorLoop.template.yul +++ b/system-contracts/evm-emulator/EvmEmulatorLoop.template.yul @@ -2,14 +2,14 @@ let sp := sub(STACK_OFFSET(), 32) // instruction pointer - index to next instruction. Not called pc because it's an // actual yul/evm instruction. -let ip := add(BYTECODE_OFFSET(), 32) +let ip := BYTECODE_OFFSET() let opcode let stackHead -let maxAcceptablePos := add(add(BYTECODE_OFFSET(), mload(BYTECODE_OFFSET())), 31) +let maxAcceptablePos := sub(add(BYTECODE_OFFSET(), mload(BYTECODE_LEN_OFFSET())), 1) for { } true { } { - opcode := readIP(ip,maxAcceptablePos) + opcode := readIP(ip, maxAcceptablePos) switch opcode case 0x00 { // OP_STOP @@ -293,7 +293,7 @@ for { } true { } { let dynamicGas := add(mul(6, shr(5, add(size, 31))), expandMemory(offset, size)) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - stackHead := keccak256(add(MEM_OFFSET_INNER(), offset), size) + stackHead := keccak256(add(MEM_OFFSET(), offset), size) ip := add(ip, 1) } @@ -365,14 +365,14 @@ for { } true { } { let dynamicGas := add(mul(3, shr(5, add(size, 31))), expandMemory(destOffset, size)) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - calldatacopy(add(destOffset, MEM_OFFSET_INNER()), offset, size) + calldatacopy(add(destOffset, MEM_OFFSET()), offset, size) ip := add(ip, 1) } case 0x38 { // OP_CODESIZE evmGasLeft := chargeGas(evmGasLeft, 2) - let bytecodeLen := mload(BYTECODE_OFFSET()) + let bytecodeLen := mload(BYTECODE_LEN_OFFSET()) sp, stackHead := pushStackItem(sp, bytecodeLen, stackHead) ip := add(ip, 1) } @@ -394,12 +394,12 @@ for { } true { } { let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(dstOffset, len)) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - dstOffset := add(dstOffset, MEM_OFFSET_INNER()) - sourceOffset := add(add(sourceOffset, BYTECODE_OFFSET()), 32) + dstOffset := add(dstOffset, MEM_OFFSET()) + sourceOffset := add(sourceOffset, BYTECODE_OFFSET()) checkOverflow(sourceOffset, len) // Check bytecode overflow - if gt(add(sourceOffset, len), sub(MEM_OFFSET(), 1)) { + if gt(add(sourceOffset, len), sub(MEM_LEN_OFFSET(), 1)) { panic() } @@ -431,20 +431,20 @@ for { } true { } { case 0x3C { // OP_EXTCODECOPY evmGasLeft := chargeGas(evmGasLeft, 100) - let addr, dest, offset, len + let addr, dstOffset, srcOffset, len popStackCheck(sp, 4) addr, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - dest, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - offset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) + dstOffset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) + srcOffset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) len, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - checkMemIsAccessible(dest, len) + checkMemIsAccessible(dstOffset, len) // dynamicGas = 3 * minimum_word_size + memory_expansion_cost + address_access_cost // minimum_word_size = (size + 31) / 32 let dynamicGas := add( mul(3, shr(5, add(len, 31))), - expandMemory(dest, len) + expandMemory(dstOffset, len) ) if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) { @@ -453,11 +453,11 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - $llvm_AlwaysInline_llvm$_memsetToZero(dest, len) + $llvm_AlwaysInline_llvm$_memsetToZero(dstOffset, len) // Gets the code from the addr if and(iszero(iszero(_getRawCodeHash(addr))), gt(len, 0)) { - pop(_fetchDeployedCodeWithDest(addr, offset, len, add(dest, MEM_OFFSET_INNER()))) + pop(_fetchDeployedCodeWithDest(addr, add(dstOffset, MEM_OFFSET()), srcOffset, len)) } ip := add(ip, 1) @@ -492,7 +492,7 @@ for { } true { } { panic() } - copyActivePtrData(add(MEM_OFFSET_INNER(), dstOffset), sourceOffset, len) + copyActivePtrData(add(MEM_OFFSET(), dstOffset), sourceOffset, len) ip := add(ip, 1) } case 0x3F { // OP_EXTCODEHASH @@ -576,7 +576,7 @@ for { } true { } { let expansionGas := expandMemory(offset, 32) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - stackHead := mload(add(MEM_OFFSET_INNER(), offset)) + stackHead := mload(add(MEM_OFFSET(), offset)) ip := add(ip, 1) } @@ -593,7 +593,7 @@ for { } true { } { let expansionGas := expandMemory(offset, 32) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - mstore(add(MEM_OFFSET_INNER(), offset), value) + mstore(add(MEM_OFFSET(), offset), value) ip := add(ip, 1) } case 0x53 { // OP_MSTORE8 @@ -609,7 +609,7 @@ for { } true { } { let expansionGas := expandMemory(offset, 1) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - mstore8(add(MEM_OFFSET_INNER(), offset), value) + mstore8(add(MEM_OFFSET(), offset), value) ip := add(ip, 1) } case 0x54 { // OP_SLOAD @@ -680,7 +680,7 @@ for { } true { } { counter, sp, stackHead := popStackItem(sp, stackHead) - ip := add(add(BYTECODE_OFFSET(), 32), counter) + ip := add(BYTECODE_OFFSET(), counter) // Check next opcode is JUMPDEST let nextOpcode := readIP(ip,maxAcceptablePos) @@ -706,7 +706,7 @@ for { } true { } { continue } - ip := add(add(BYTECODE_OFFSET(), 32), counter) + ip := add(BYTECODE_OFFSET(), counter) // Check next opcode is JUMPDEST let nextOpcode := readIP(ip, maxAcceptablePos) @@ -723,14 +723,14 @@ for { } true { } { ip := add(ip, 1) // PC = ip - 32 (bytecode size) - 1 (current instruction) - sp, stackHead := pushStackItem(sp, sub(sub(ip, BYTECODE_OFFSET()), 33), stackHead) + sp, stackHead := pushStackItem(sp, sub(sub(ip, BYTECODE_LEN_OFFSET()), 33), stackHead) } case 0x59 { // OP_MSIZE evmGasLeft := chargeGas(evmGasLeft, 2) let size - size := mload(MEM_OFFSET()) + size := mload(MEM_LEN_OFFSET()) size := shl(5, size) sp, stackHead := pushStackItem(sp, size, stackHead) ip := add(ip, 1) @@ -783,7 +783,7 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - mcopy(add(destOffset, MEM_OFFSET_INNER()), add(offset, MEM_OFFSET_INNER()), size) + mcopy(add(destOffset, MEM_OFFSET()), add(offset, MEM_OFFSET()), size) ip := add(ip, 1) } case 0x5F { // OP_PUSH0 @@ -1229,7 +1229,7 @@ for { } true { } { let dynamicGas := add(shl(3, size), expandMemory(offset, size)) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - log0(add(offset, MEM_OFFSET_INNER()), size) + log0(add(offset, MEM_OFFSET()), size) ip := add(ip, 1) } case 0xA1 { // OP_LOG1 @@ -1254,7 +1254,7 @@ for { } true { } { { let topic1 topic1, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - log1(add(offset, MEM_OFFSET_INNER()), size, topic1) + log1(add(offset, MEM_OFFSET()), size, topic1) } ip := add(ip, 1) } @@ -1281,7 +1281,7 @@ for { } true { } { let topic1, topic2 topic1, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic2, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - log2(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2) + log2(add(offset, MEM_OFFSET()), size, topic1, topic2) } ip := add(ip, 1) } @@ -1309,7 +1309,7 @@ for { } true { } { topic1, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic2, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic3, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - log3(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2, topic3) + log3(add(offset, MEM_OFFSET()), size, topic1, topic2, topic3) } ip := add(ip, 1) } @@ -1338,7 +1338,7 @@ for { } true { } { topic2, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic3, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) topic4, sp, stackHead := popStackItemWithoutCheck(sp, stackHead) - log4(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2, topic3, topic4) + log4(add(offset, MEM_OFFSET()), size, topic1, topic2, topic3, topic4) } ip := add(ip, 1) } @@ -1377,7 +1377,7 @@ for { } true { } { returnLen := size // Don't check overflow here since previous checks are enough to ensure this is safe - returnOffset := add(MEM_OFFSET_INNER(), offset) + returnOffset := add(MEM_OFFSET(), offset) break } case 0xF4 { // OP_DELEGATECALL @@ -1409,7 +1409,7 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, expandMemory(offset, size)) // Don't check overflow here since previous checks are enough to ensure this is safe - offset := add(offset, MEM_OFFSET_INNER()) + offset := add(offset, MEM_OFFSET()) if eq(isCallerEVM, 1) { offset := sub(offset, 32)