diff --git a/system-contracts/contracts/EvmInterpreter.template.yul b/system-contracts/contracts/EvmInterpreter.template.yul index 615c5d1c8..32ca6ed92 100644 --- a/system-contracts/contracts/EvmInterpreter.template.yul +++ b/system-contracts/contracts/EvmInterpreter.template.yul @@ -21,10 +21,7 @@ object "EVMInterpreter" { // This error should never be triggered // require(offset > 100, "Offset too small"); - mstore8(sub(offset, 100), 0xd9) - mstore8(sub(offset, 99), 0xeb) - mstore8(sub(offset, 98), 0x76) - mstore8(sub(offset, 97), 0xb2) + mstore(sub(offset, 100), 0xD9EB76B200000000000000000000000000000000000000000000000000000000) mstore(sub(offset, 96), gasLeft) mstore(sub(offset, 64), 0x40) mstore(sub(offset, 32), len) @@ -60,8 +57,6 @@ object "EVMInterpreter" { function validateCorrectBytecode(offset, len, gasToReturn) -> returnGas { if len { - // let firstByte := shr(mload(offset), 248) - // FIXME: Check this. let firstByte := shr(248, mload(offset)) if eq(firstByte, 0xEF) { revert(0, 0) diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index 16394c340..c93e7f1ce 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -76,7 +76,6 @@ function MAX_UINT() -> max_uint { // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 function readIP(ip,maxAcceptablePos) -> opcode { - // TODO: Why not do this at the beginning once instead of every time? if gt(ip, maxAcceptablePos) { revert(0, 0) } @@ -164,11 +163,8 @@ function popStackCheck(sp, evmGasLeft, numInputs) { } } -function popPushStackCheck(sp, evmGasLeft, numInputs) { - let popCheck := lt(sub(sp, mul(0x20, sub(numInputs, 1))), STACK_OFFSET()) - let pushOffset := sub(sp, mul(0x20, numInputs)) - let pushCheck := or(gt(pushOffset, BYTECODE_OFFSET()), eq(pushOffset, BYTECODE_OFFSET())) - if or(popCheck, pushCheck) { +function pushStackCheck(sp, evmGasLeft, numInputs) { + if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_OFFSET())) { revertWithGas(evmGasLeft) } } @@ -202,11 +198,7 @@ function ptrShrinkIntoActive(_dest) { } function _getRawCodeHash(account) -> hash { - // TODO: Unhardcode this selector - mstore8(0, 0x4d) - mstore8(1, 0xe2) - mstore8(2, 0xe4) - mstore8(3, 0x68) + mstore(0, 0x4DE2E46800000000000000000000000000000000000000000000000000000000) mstore(4, account) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -221,12 +213,7 @@ function _getRawCodeHash(account) -> hash { function _getCodeHash(account) -> hash { // function getCodeHash(uint256 _input) external view override returns (bytes32) - // 0xe03fe177 - // TODO: Unhardcode this selector - mstore8(0, 0xe0) - mstore8(1, 0x3f) - mstore8(2, 0xe1) - mstore8(3, 0x77) + mstore(0, 0xE03FE17700000000000000000000000000000000000000000000000000000000) mstore(4, account) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -241,7 +228,6 @@ function _getCodeHash(account) -> hash { function getIsStaticFromCallFlags() -> isStatic { isStatic := verbatim_0i_1o("get_global::call_flags") - // TODO: make it a constnat isStatic := iszero(iszero(and(isStatic, 0x04))) } @@ -310,11 +296,7 @@ function getDeployedBytecode() { function consumeEvmFrame() -> passGas, isStatic, callerEVM { // function consumeEvmFrame() external returns (uint256 passGas, bool isStatic) - // TODO: Unhardcode selector - mstore8(0, 0x04) - mstore8(1, 0xc1) - mstore8(2, 0x4e) - mstore8(3, 0x9e) + mstore(0, 0x04C14E9E00000000000000000000000000000000000000000000000000000000) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 64) @@ -494,6 +476,13 @@ function getGasForPrecompiles(addr, argsOffset, argsSize) -> gasToCharge { } } +function checkMemOverflowByOffset(offset, evmGasLeft) { + if gt(offset, MAX_POSSIBLE_MEM()) { + mstore(0, evmGasLeft) + revert(0, 32) + } +} + function checkMemOverflow(location, evmGasLeft) { if gt(location, MAX_MEMORY_FRAME()) { mstore(0, evmGasLeft) @@ -559,11 +548,7 @@ function printString(value) { } function isSlotWarm(key) -> isWarm { - // TODO: Unhardcode this selector 0x482d2e74 - mstore8(0, 0x48) - mstore8(1, 0x2d) - mstore8(2, 0x2e) - mstore8(3, 0x74) + mstore(0, 0x482D2E7400000000000000000000000000000000000000000000000000000000) mstore(4, key) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) @@ -577,11 +562,7 @@ function isSlotWarm(key) -> isWarm { } function warmSlot(key,currentValue) -> isWarm, originalValue { - // TODO: Unhardcode this selector 0xbdf78160 - mstore8(0, 0xbd) - mstore8(1, 0xf7) - mstore8(2, 0x81) - mstore8(3, 0x60) + mstore(0, 0xBDF7816000000000000000000000000000000000000000000000000000000000) mstore(4, key) mstore(36,currentValue) @@ -624,29 +605,34 @@ function getNewAddress(addr) -> newAddr { if iszero(nonce) { nonceEncoded := 128 } - // The nonce has 4 bytes - if gt(nonce, 0xFFFFFF) { - nonceEncoded := shl(32, 0x84) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 5 - } - // The nonce has 3 bytes - if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { - nonceEncoded := shl(24, 0x83) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 4 - } - // The nonce has 2 bytes - if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { - nonceEncoded := shl(16, 0x82) + switch gt(nonce, 0xFFFF) + case 1 { + switch gt(nonce, 0xFFFFFF) + case 1 { + // The nonce has 4 bytes + nonceEncoded := shl(32, 0x84) + nonceEncodedLength := 5 + } + default { + // The nonce has 3 bytes + nonceEncoded := shl(24, 0x83) + nonceEncodedLength := 4 + } nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 3 } - // The nonce has 1 byte and it's in [0x80, 0xFF] - if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { - nonceEncoded := shl(8, 0x81) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 2 + default { + // The nonce has 2 bytes + if gt(nonce, 0xFF) { + nonceEncoded := shl(16, 0x82) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 3 + } + // The nonce has 1 byte and it's in [0x80, 0xFF] + if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { + nonceEncoded := shl(8, 0x81) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 2 + } } listLength := add(21, nonceEncodedLength) @@ -674,10 +660,7 @@ function getNewAddress(addr) -> newAddr { } function incrementNonce(addr) { - mstore8(0, 0x30) - mstore8(1, 0x63) - mstore8(2, 0x95) - mstore8(3, 0xc6) + mstore(0, 0x306395C600000000000000000000000000000000000000000000000000000000) mstore(4, addr) let farCallAbi := getFarCallABI( @@ -761,11 +744,7 @@ function addGasIfEvmRevert(isCallerEVM,offset,size,evmGasLeft) -> newOffset,newS } function $llvm_AlwaysInline_llvm$_warmAddress(addr) -> isWarm { - // TODO: Unhardcode this selector 0x8db2ba78 - mstore8(0, 0x8d) - mstore8(1, 0xb2) - mstore8(2, 0xba) - mstore8(3, 0x78) + mstore(0, 0x8DB2BA7800000000000000000000000000000000000000000000000000000000) mstore(4, addr) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) @@ -779,10 +758,7 @@ function $llvm_AlwaysInline_llvm$_warmAddress(addr) -> isWarm { } function getNonce(addr) -> nonce { - mstore8(0, 0xfb) - mstore8(1, 0x1a) - mstore8(2, 0x9a) - mstore8(3, 0x57) + mstore(0, 0xFB1A9A5700000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -795,10 +771,7 @@ function getNonce(addr) -> nonce { } function getRawNonce(addr) -> nonce { - mstore8(0, 0x5a) - mstore8(1, 0xa9) - mstore8(2, 0xb6) - mstore8(3, 0xb5) + mstore(0, 0x5AA9B6B500000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -817,10 +790,7 @@ function _isEVM(_addr) -> isEVM { // address(SYSTEM_CONTRACTS_OFFSET + 0x02) // ); - mstore8(0, 0x8c) - mstore8(1, 0x04) - mstore8(2, 0x04) - mstore8(3, 0x77) + mstore(0, 0x8C04047700000000000000000000000000000000000000000000000000000000) mstore(4, _addr) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -835,12 +805,8 @@ function _isEVM(_addr) -> isEVM { function _pushEVMFrame(_passGas, _isStatic) { // function pushEVMFrame(uint256 _passGas, bool _isStatic) external - let selector := 0xead77156 - mstore8(0, 0xea) - mstore8(1, 0xd7) - mstore8(2, 0x71) - mstore8(3, 0x56) + mstore(0, 0xEAD7715600000000000000000000000000000000000000000000000000000000) mstore(4, _passGas) mstore(36, _isStatic) @@ -853,13 +819,8 @@ function _pushEVMFrame(_passGas, _isStatic) { function _popEVMFrame() { // function popEVMFrame() external - // 0xe467d2f0 - let selector := 0xe467d2f0 - mstore8(0, 0xe4) - mstore8(1, 0x67) - mstore8(2, 0xd2) - mstore8(3, 0xf0) + mstore(0, 0xE467D2F000000000000000000000000000000000000000000000000000000000) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 0) if iszero(success) { @@ -869,7 +830,6 @@ function _popEVMFrame() { } // Each evm gas is 5 zkEVM one -// FIXME: change this variable to reflect real ergs : gas ratio function GAS_DIVISOR() -> gas_div { gas_div := 5 } function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30 function OVERHEAD() -> overhead { overhead := 2000 } @@ -967,11 +927,11 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp { addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff) - checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft) - checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft) + checkOverflow(argsOffset,argsSize, evmGasLeft) + checkOverflow(retOffset, retSize, evmGasLeft) - checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft) - checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft) + checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft) extraCost := 0 if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) { @@ -989,18 +949,9 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp { let frameGasLeft let success - if _isEVM(addr) { - _pushEVMFrame(gasToPass, true) - // TODO Check the following comment from zkSync .sol. - // We can not just pass all gas here to prevert overflow of zkEVM gas counter - success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) - - frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) - _popEVMFrame() - } - - // zkEVM native - if iszero(_isEVM(addr)) { + switch _isEVM(addr) + case 0 { + // zkEVM native gasToPass := _getZkEVMGas(gasToPass, addr) let zkevmGasBefore := gas() success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, add(MEM_OFFSET_INNER(), retOffset), retSize) @@ -1013,9 +964,23 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp { frameGasLeft := sub(gasToPass, gasUsed) } } + default { + _pushEVMFrame(gasToPass, true) + success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) + + frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) + _popEVMFrame() + } + + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) sp := pushStackItem(sp, success, evmGasLeft) } function capGas(evmGasLeft,oldGasToPass) -> gasToPass { @@ -1040,7 +1005,31 @@ function getMaxExpansionMemory(retOffset,retSize,argsOffset,argsSize) -> maxExpa function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize,isStatic) -> success, frameGasLeft, gasToPassNew{ gasToPassNew := gasToPass let is_evm := _isEVM(addr) - if isStatic { + + switch isStatic + case 0 { + switch is_evm + case 0 { + // zkEVM native + gasToPassNew := _getZkEVMGas(gasToPassNew, addr) + let zkevmGasBefore := gas() + success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize) + _saveReturndataAfterZkEVMCall() + let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) + + frameGasLeft := 0 + if gt(gasToPassNew, gasUsed) { + frameGasLeft := sub(gasToPassNew, gasUsed) + } + } + default { + _pushEVMFrame(gasToPassNew, isStatic) + success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0) + frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + _popEVMFrame() + } + } + default { if value { revertWithGas(gasToPassNew) } @@ -1054,27 +1043,6 @@ function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize retSize ) } - - if and(is_evm, iszero(isStatic)) { - _pushEVMFrame(gasToPassNew, isStatic) - success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0) - frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) - _popEVMFrame() - } - - // zkEVM native - if and(iszero(is_evm), iszero(isStatic)) { - gasToPassNew := _getZkEVMGas(gasToPassNew, addr) - let zkevmGasBefore := gas() - success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize) - _saveReturndataAfterZkEVMCall() - let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) - - frameGasLeft := 0 - if gt(gasToPassNew, gasUsed) { - frameGasLeft := sub(gasToPassNew, gasUsed) - } - } } function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp { @@ -1138,8 +1106,14 @@ function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp { isStatic ) - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } sp := pushStackItem(sp,success, evmGasLeft) } @@ -1159,11 +1133,11 @@ function delegateCall(oldSp, oldIsStatic, evmGasLeft) -> sp, isStatic, extraCost // addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff) - checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft) - checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft) + checkOverflow(argsOffset, argsSize, evmGasLeft) + checkOverflow(retOffset, retSize, evmGasLeft) - checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft) - checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft) + checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft) if iszero(_isEVM(addr)) { revertWithGas(evmGasLeft) @@ -1180,13 +1154,6 @@ function delegateCall(oldSp, oldIsStatic, evmGasLeft) -> sp, isStatic, extraCost } gasToPass := capGas(evmGasLeft,gasToPass) - // TODO: Do this - // if warmAccount(addr) { - // extraCost = GAS_WARM_ACCESS; - // } else { - // extraCost = GAS_COLD_ACCOUNT_ACCESS; - // } - _pushEVMFrame(gasToPass, isStatic) let success := delegatecall( // We can not just pass all gas here to prevert overflow of zkEVM gas counter @@ -1202,8 +1169,14 @@ function delegateCall(oldSp, oldIsStatic, evmGasLeft) -> sp, isStatic, extraCost _popEVMFrame() - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } sp := pushStackItem(sp, success, evmGasLeft) } @@ -1248,18 +1221,9 @@ function _performStaticCall( _outputOffset, _outputLen ) -> success, _gasLeft { - if _calleeIsEVM { - _pushEVMFrame(_calleeGas, true) - // TODO Check the following comment from zkSync .sol. - // We can not just pass all gas here to prevert overflow of zkEVM gas counter - success := staticcall(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) - - _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) - _popEVMFrame() - } - - // zkEVM native - if iszero(_calleeIsEVM) { + switch _calleeIsEVM + case 0 { + // zkEVM native _calleeGas := _getZkEVMGas(_calleeGas, _callee) let zkevmGasBefore := gas() success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, _outputOffset, _outputLen) @@ -1273,6 +1237,13 @@ function _performStaticCall( _gasLeft := sub(_calleeGas, gasUsed) } } + default { + _pushEVMFrame(_calleeGas, true) + success := staticcall(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) + + _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) + _popEVMFrame() + } } function isAddrEmpty(addr) -> isEmpty { @@ -1287,12 +1258,7 @@ function isAddrEmpty(addr) -> isEmpty { } function _fetchConstructorReturnGas() -> gasLeft { - //selector is 0x24e5ab4a - - mstore8(0, 0x24) - mstore8(1, 0xe5) - mstore8(2, 0xab) - mstore8(3, 0x4a) + mstore(0, 0x24E5AB4A00000000000000000000000000000000000000000000000000000000) let success := staticcall(gas(), DEPLOYER_SYSTEM_CONTRACT(), 0, 4, 0, 32) @@ -1317,10 +1283,11 @@ function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGa offset := add(MEM_OFFSET_INNER(), offset) - sp := pushStackItem(sp, mload(sub(offset, 0x80)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x60)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x40)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x20)), evmGasLeftOld) + pushStackCheck(sp, evmGasLeftOld, 4) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x80))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x60))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x40))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x20))) // Selector mstore(sub(offset, 0x80), 0x5b16a23c) @@ -1364,7 +1331,7 @@ function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGa let back - popStackCheck(sp, evmGasLeft, 4) + // skipping check since we pushed exactly 4 items earlier back, sp := popStackItemWithoutCheck(sp) mstore(sub(offset, 0x20), back) back, sp := popStackItemWithoutCheck(sp) @@ -1375,6 +1342,45 @@ function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGa mstore(sub(offset, 0x80), back) } +function $llvm_AlwaysInline_llvm$_copyRest(dest, val, len) { + let rest_bits := shl(3, len) + let upper_bits := sub(256, rest_bits) + let val_mask := shl(upper_bits, MAX_UINT()) + let val_masked := and(val, val_mask) + let dst_val := mload(dest) + let dst_mask := shr(rest_bits, MAX_UINT()) + let dst_masked := and(dst_val, dst_mask) + mstore(dest, or(val_masked, dst_masked)) +} + +function $llvm_AlwaysInline_llvm$_memcpy(dest, src, len) { + let dest_addr := dest + let src_addr := src + let dest_end := add(dest, and(len, sub(0, 32))) + for { } lt(dest_addr, dest_end) {} { + mstore(dest_addr, mload(src_addr)) + dest_addr := add(dest_addr, 32) + src_addr := add(src_addr, 32) + } + + let rest_len := and(len, 31) + if rest_len { + $llvm_AlwaysInline_llvm$_copyRest(dest_addr, mload(src_addr), rest_len) + } +} + +function $llvm_AlwaysInline_llvm$_memsetToZero(dest,len) { + let dest_end := add(dest, and(len, sub(0, 32))) + for {let i := dest} lt(i, dest_end) { i := add(i, 32) } { + mstore(i, 0) + } + + let rest_len := and(len, 31) + if rest_len { + $llvm_AlwaysInline_llvm$_copyRest(dest_end, 0, rest_len) + } +} + function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { evmGasLeft := chargeGas(evmGas, 100) @@ -1397,21 +1403,12 @@ function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { } evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - let len_32 := shr(5, len) - for {let i := 0} lt(i, len_32) { i := add(i, 1) } { - mstore(add(dest,shl(5,i)),0) - } - let size_32 := shl(5,len_32) - let rest_32 := sub(len, size_32) - for {let i := 0} lt(i, rest_32) { i := add(i, 1) } { - mstore8(add(dest,add(size_32,i)),0) - } + $llvm_AlwaysInline_llvm$_memsetToZero(dest, len) // Gets the code from the addr - if iszero(iszero(_getRawCodeHash(addr))) { + if and(iszero(iszero(_getRawCodeHash(addr))),gt(len,0)) { pop(_fetchDeployedCodeWithDest(addr, offset, len,add(dest,MEM_OFFSET_INNER()))) } - } function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp { @@ -1428,9 +1425,8 @@ function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { revertWithGas(evmGasLeft) @@ -1475,9 +1471,8 @@ function performCreate2(evmGas, oldSp, isStatic) -> evmGasLeft, sp, result, addr size, sp := popStackItemWithoutCheck(sp) salt, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { revertWithGas(evmGasLeft) @@ -1499,7 +1494,7 @@ function performCreate2(evmGas, oldSp, isStatic) -> evmGasLeft, sp, result, addr { let hashedBytecode := keccak256(add(MEM_OFFSET_INNER(), offset), size) - mstore8(0, 0xFF) + mstore(0, 0xFF00000000000000000000000000000000000000000000000000000000000000) mstore(0x01, shl(0x60, address())) mstore(0x15, salt) mstore(0x35, hashedBytecode) diff --git a/system-contracts/contracts/EvmInterpreterLoop.template.yul b/system-contracts/contracts/EvmInterpreterLoop.template.yul index 931ede4c5..dc3346988 100644 --- a/system-contracts/contracts/EvmInterpreterLoop.template.yul +++ b/system-contracts/contracts/EvmInterpreterLoop.template.yul @@ -19,7 +19,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -31,7 +31,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -43,7 +43,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -55,7 +55,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -67,7 +67,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -79,7 +79,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -91,7 +91,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -103,7 +103,7 @@ for { } true { } { let a, b, N - popPushStackCheck(sp, evmGasLeft, 3) + popStackCheck(sp, evmGasLeft, 3) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) N, sp := popStackItemWithoutCheck(sp) @@ -129,7 +129,7 @@ for { } true { } { let a, exponent - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) exponent, sp := popStackItemWithoutCheck(sp) @@ -148,7 +148,7 @@ for { } true { } { let b, x - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) b, sp := popStackItemWithoutCheck(sp) x, sp := popStackItemWithoutCheck(sp) @@ -160,7 +160,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -172,7 +172,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -184,7 +184,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -196,7 +196,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -208,7 +208,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -220,7 +220,7 @@ for { } true { } { let a - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) a, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, iszero(a)) @@ -231,7 +231,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -243,7 +243,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -255,7 +255,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -267,7 +267,7 @@ for { } true { } { let a - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) a, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, not(a)) @@ -278,7 +278,7 @@ for { } true { } { let i, x - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) i, sp := popStackItemWithoutCheck(sp) x, sp := popStackItemWithoutCheck(sp) @@ -290,7 +290,7 @@ for { } true { } { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -302,7 +302,7 @@ for { } true { } { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -314,7 +314,7 @@ for { } true { } { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -330,8 +330,8 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) let keccak := keccak256(add(MEM_OFFSET_INNER(), offset), size) // When an offset is first accessed (either read or write), memory may trigger @@ -362,7 +362,7 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, 2500) } - sp := pushStackItem(sp, balance(addr), evmGasLeft) + sp := pushStackItemWithoutCheck(sp, balance(addr)) ip := add(ip, 1) } case 0x32 { // OP_ORIGIN @@ -388,7 +388,7 @@ for { } true { } { let i - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) i, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, calldataload(i)) @@ -413,13 +413,9 @@ for { } true { } { checkMultipleOverflow(offset,size,MEM_OFFSET_INNER(), evmGasLeft) checkMultipleOverflow(destOffset,size,MEM_OFFSET_INNER(), evmGasLeft) + // TODO invalid? if or(gt(add(add(offset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM()), gt(add(add(destOffset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM())) { - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(destOffset, MEM_OFFSET_INNER()), i), - 0 - ) - } + $llvm_AlwaysInline_llvm$_memsetToZero(add(destOffset, MEM_OFFSET_INNER()), size) } // dynamicGas = 3 * minimum_word_size + memory_expansion_cost @@ -464,12 +460,7 @@ for { } true { } { revertWithGas(evmGasLeft) } - for { let i := 0 } lt(i, len) { i := add(i, 1) } { - mstore8( - add(dst, i), - shr(248, mload(add(offset, i))) - ) - } + $llvm_AlwaysInline_llvm$_memcpy(dst, offset, len) ip := add(ip, 1) } case 0x3A { // OP_GASPRICE @@ -489,14 +480,9 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, 2500) } - // TODO: check, the .sol uses extcodesize directly, but it doesnt seem to work - // if a contract is created it works, but if the address is a zkSync's contract - // what happens? - // sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) - switch _isEVM(addr) - case 0 { sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) } - default { sp := pushStackItem(sp, _fetchDeployedCodeLen(addr), evmGasLeft) } + case 0 { sp := pushStackItemWithoutCheck(sp, extcodesize(addr)) } + default { sp := pushStackItemWithoutCheck(sp, _fetchDeployedCodeLen(addr)) } ip := add(ip, 1) } case 0x3C { // OP_EXTCODECOPY @@ -519,9 +505,6 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) len, sp := popStackItemWithoutCheck(sp) - // TODO: check if these conditions are met - // The addition offset + size overflows. - // offset + size is larger than RETURNDATASIZE. checkOverflow(offset,len, evmGasLeft) if gt(add(offset, len), mload(LAST_RETURNDATA_SIZE_OFFSET())) { revertWithGas(evmGasLeft) @@ -529,7 +512,7 @@ for { } true { } { // minimum_word_size = (size + 31) / 32 // dynamicGas = 3 * minimum_word_size + memory_expansion_cost - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(add(dest, len))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) @@ -549,16 +532,16 @@ for { } true { } { ip := add(ip, 1) if iszero(addr) { - sp := pushStackItem(sp, 0, evmGasLeft) + sp := pushStackItemWithoutCheck(sp, 0) continue } - sp := pushStackItem(sp, extcodehash(addr), evmGasLeft) + sp := pushStackItemWithoutCheck(sp, extcodehash(addr)) } case 0x40 { // OP_BLOCKHASH evmGasLeft := chargeGas(evmGasLeft, 20) let blockNumber - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) blockNumber, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, blockhash(blockNumber)) @@ -619,13 +602,12 @@ for { } true { } { offset, sp := popStackItem(sp, evmGasLeft) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) let memValue := mload(add(MEM_OFFSET_INNER(), offset)) - sp := pushStackItem(sp, memValue, evmGasLeft) + sp := pushStackItemWithoutCheck(sp, memValue) ip := add(ip, 1) } case 0x52 { // OP_MSTORE @@ -637,11 +619,10 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) mstore(add(MEM_OFFSET_INNER(), offset), value) ip := add(ip, 1) } @@ -654,11 +635,10 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 1)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) mstore8(add(MEM_OFFSET_INNER(), offset), value) ip := add(ip, 1) } @@ -682,7 +662,7 @@ for { } true { } { let _wasW, _orgV := warmSlot(key, value) } - sp := pushStackItem(sp,value, evmGasLeft) + sp := pushStackItemWithoutCheck(sp,value) ip := add(ip, 1) } case 0x55 { // OP_SSTORE @@ -742,6 +722,10 @@ for { } true { } { if iszero(eq(nextOpcode, 0x5B)) { revertWithGas(evmGasLeft) } + + // execute JUMPDEST immediately + evmGasLeft := chargeGas(evmGasLeft, 1) + ip := add(ip, 1) } case 0x57 { // OP_JUMPI evmGasLeft := chargeGas(evmGasLeft, 10) @@ -764,6 +748,10 @@ for { } true { } { if iszero(eq(nextOpcode, 0x5B)) { revertWithGas(evmGasLeft) } + + // execute JUMPDEST immediately + evmGasLeft := chargeGas(evmGasLeft, 1) + ip := add(ip, 1) } case 0x58 { // OP_PC evmGasLeft := chargeGas(evmGasLeft, 2) @@ -796,7 +784,7 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, 100) let key - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) key, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, tload(key)) @@ -824,26 +812,14 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) + // TODO overflow checks + checkMemOverflowByOffset(add(offset, size), evmGasLeft) + checkMemOverflowByOffset(add(destOffset, size), evmGasLeft) + expandMemory(add(destOffset, size)) expandMemory(add(offset, size)) - let oldSize := mul(mload(MEM_OFFSET()),32) - if gt(add(oldSize,size),MAX_POSSIBLE_MEM()) { - revertWithGas(evmGasLeft) - } - - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(oldSize,MEM_OFFSET_INNER()), i), - shr(248,mload(add(add(offset,MEM_OFFSET_INNER()), i))) - ) - } - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(destOffset,MEM_OFFSET_INNER()), i), - shr(248,mload(add(add(oldSize,MEM_OFFSET_INNER()), i))) - ) - } + mcopy(add(destOffset, MEM_OFFSET_INNER()), add(offset, MEM_OFFSET_INNER()), size) ip := add(ip, 1) } case 0x5F { // OP_PUSH0 @@ -1282,8 +1258,8 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -1305,8 +1281,8 @@ for { } true { } { size, sp := popStackItemWithoutCheck(sp) topic1, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -1327,8 +1303,8 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -1356,9 +1332,8 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -1387,8 +1362,8 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -1469,6 +1444,7 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) + // TODO invalid? ensureAcceptableMemLocation(offset) ensureAcceptableMemLocation(size) evmGasLeft := chargeGas(evmGasLeft,expandMemory(add(offset,size))) diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 3507b5f1f..772dac808 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -21,10 +21,7 @@ object "EVMInterpreter" { // This error should never be triggered // require(offset > 100, "Offset too small"); - mstore8(sub(offset, 100), 0xd9) - mstore8(sub(offset, 99), 0xeb) - mstore8(sub(offset, 98), 0x76) - mstore8(sub(offset, 97), 0xb2) + mstore(sub(offset, 100), 0xD9EB76B200000000000000000000000000000000000000000000000000000000) mstore(sub(offset, 96), gasLeft) mstore(sub(offset, 64), 0x40) mstore(sub(offset, 32), len) @@ -60,8 +57,6 @@ object "EVMInterpreter" { function validateCorrectBytecode(offset, len, gasToReturn) -> returnGas { if len { - // let firstByte := shr(mload(offset), 248) - // FIXME: Check this. let firstByte := shr(248, mload(offset)) if eq(firstByte, 0xEF) { revert(0, 0) @@ -150,7 +145,6 @@ object "EVMInterpreter" { // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 function readIP(ip,maxAcceptablePos) -> opcode { - // TODO: Why not do this at the beginning once instead of every time? if gt(ip, maxAcceptablePos) { revert(0, 0) } @@ -238,11 +232,8 @@ object "EVMInterpreter" { } } - function popPushStackCheck(sp, evmGasLeft, numInputs) { - let popCheck := lt(sub(sp, mul(0x20, sub(numInputs, 1))), STACK_OFFSET()) - let pushOffset := sub(sp, mul(0x20, numInputs)) - let pushCheck := or(gt(pushOffset, BYTECODE_OFFSET()), eq(pushOffset, BYTECODE_OFFSET())) - if or(popCheck, pushCheck) { + function pushStackCheck(sp, evmGasLeft, numInputs) { + if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_OFFSET())) { revertWithGas(evmGasLeft) } } @@ -276,11 +267,7 @@ object "EVMInterpreter" { } function _getRawCodeHash(account) -> hash { - // TODO: Unhardcode this selector - mstore8(0, 0x4d) - mstore8(1, 0xe2) - mstore8(2, 0xe4) - mstore8(3, 0x68) + mstore(0, 0x4DE2E46800000000000000000000000000000000000000000000000000000000) mstore(4, account) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -295,12 +282,7 @@ object "EVMInterpreter" { function _getCodeHash(account) -> hash { // function getCodeHash(uint256 _input) external view override returns (bytes32) - // 0xe03fe177 - // TODO: Unhardcode this selector - mstore8(0, 0xe0) - mstore8(1, 0x3f) - mstore8(2, 0xe1) - mstore8(3, 0x77) + mstore(0, 0xE03FE17700000000000000000000000000000000000000000000000000000000) mstore(4, account) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -315,7 +297,6 @@ object "EVMInterpreter" { function getIsStaticFromCallFlags() -> isStatic { isStatic := verbatim_0i_1o("get_global::call_flags") - // TODO: make it a constnat isStatic := iszero(iszero(and(isStatic, 0x04))) } @@ -384,11 +365,7 @@ object "EVMInterpreter" { function consumeEvmFrame() -> passGas, isStatic, callerEVM { // function consumeEvmFrame() external returns (uint256 passGas, bool isStatic) - // TODO: Unhardcode selector - mstore8(0, 0x04) - mstore8(1, 0xc1) - mstore8(2, 0x4e) - mstore8(3, 0x9e) + mstore(0, 0x04C14E9E00000000000000000000000000000000000000000000000000000000) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 64) @@ -568,6 +545,13 @@ object "EVMInterpreter" { } } + function checkMemOverflowByOffset(offset, evmGasLeft) { + if gt(offset, MAX_POSSIBLE_MEM()) { + mstore(0, evmGasLeft) + revert(0, 32) + } + } + function checkMemOverflow(location, evmGasLeft) { if gt(location, MAX_MEMORY_FRAME()) { mstore(0, evmGasLeft) @@ -633,11 +617,7 @@ object "EVMInterpreter" { } function isSlotWarm(key) -> isWarm { - // TODO: Unhardcode this selector 0x482d2e74 - mstore8(0, 0x48) - mstore8(1, 0x2d) - mstore8(2, 0x2e) - mstore8(3, 0x74) + mstore(0, 0x482D2E7400000000000000000000000000000000000000000000000000000000) mstore(4, key) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) @@ -651,11 +631,7 @@ object "EVMInterpreter" { } function warmSlot(key,currentValue) -> isWarm, originalValue { - // TODO: Unhardcode this selector 0xbdf78160 - mstore8(0, 0xbd) - mstore8(1, 0xf7) - mstore8(2, 0x81) - mstore8(3, 0x60) + mstore(0, 0xBDF7816000000000000000000000000000000000000000000000000000000000) mstore(4, key) mstore(36,currentValue) @@ -698,29 +674,34 @@ object "EVMInterpreter" { if iszero(nonce) { nonceEncoded := 128 } - // The nonce has 4 bytes - if gt(nonce, 0xFFFFFF) { - nonceEncoded := shl(32, 0x84) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 5 - } - // The nonce has 3 bytes - if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { - nonceEncoded := shl(24, 0x83) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 4 - } - // The nonce has 2 bytes - if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { - nonceEncoded := shl(16, 0x82) + switch gt(nonce, 0xFFFF) + case 1 { + switch gt(nonce, 0xFFFFFF) + case 1 { + // The nonce has 4 bytes + nonceEncoded := shl(32, 0x84) + nonceEncodedLength := 5 + } + default { + // The nonce has 3 bytes + nonceEncoded := shl(24, 0x83) + nonceEncodedLength := 4 + } nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 3 } - // The nonce has 1 byte and it's in [0x80, 0xFF] - if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { - nonceEncoded := shl(8, 0x81) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 2 + default { + // The nonce has 2 bytes + if gt(nonce, 0xFF) { + nonceEncoded := shl(16, 0x82) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 3 + } + // The nonce has 1 byte and it's in [0x80, 0xFF] + if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { + nonceEncoded := shl(8, 0x81) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 2 + } } listLength := add(21, nonceEncodedLength) @@ -748,10 +729,7 @@ object "EVMInterpreter" { } function incrementNonce(addr) { - mstore8(0, 0x30) - mstore8(1, 0x63) - mstore8(2, 0x95) - mstore8(3, 0xc6) + mstore(0, 0x306395C600000000000000000000000000000000000000000000000000000000) mstore(4, addr) let farCallAbi := getFarCallABI( @@ -835,11 +813,7 @@ object "EVMInterpreter" { } function $llvm_AlwaysInline_llvm$_warmAddress(addr) -> isWarm { - // TODO: Unhardcode this selector 0x8db2ba78 - mstore8(0, 0x8d) - mstore8(1, 0xb2) - mstore8(2, 0xba) - mstore8(3, 0x78) + mstore(0, 0x8DB2BA7800000000000000000000000000000000000000000000000000000000) mstore(4, addr) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) @@ -853,10 +827,7 @@ object "EVMInterpreter" { } function getNonce(addr) -> nonce { - mstore8(0, 0xfb) - mstore8(1, 0x1a) - mstore8(2, 0x9a) - mstore8(3, 0x57) + mstore(0, 0xFB1A9A5700000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -869,10 +840,7 @@ object "EVMInterpreter" { } function getRawNonce(addr) -> nonce { - mstore8(0, 0x5a) - mstore8(1, 0xa9) - mstore8(2, 0xb6) - mstore8(3, 0xb5) + mstore(0, 0x5AA9B6B500000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -891,10 +859,7 @@ object "EVMInterpreter" { // address(SYSTEM_CONTRACTS_OFFSET + 0x02) // ); - mstore8(0, 0x8c) - mstore8(1, 0x04) - mstore8(2, 0x04) - mstore8(3, 0x77) + mstore(0, 0x8C04047700000000000000000000000000000000000000000000000000000000) mstore(4, _addr) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -909,12 +874,8 @@ object "EVMInterpreter" { function _pushEVMFrame(_passGas, _isStatic) { // function pushEVMFrame(uint256 _passGas, bool _isStatic) external - let selector := 0xead77156 - mstore8(0, 0xea) - mstore8(1, 0xd7) - mstore8(2, 0x71) - mstore8(3, 0x56) + mstore(0, 0xEAD7715600000000000000000000000000000000000000000000000000000000) mstore(4, _passGas) mstore(36, _isStatic) @@ -927,13 +888,8 @@ object "EVMInterpreter" { function _popEVMFrame() { // function popEVMFrame() external - // 0xe467d2f0 - let selector := 0xe467d2f0 - mstore8(0, 0xe4) - mstore8(1, 0x67) - mstore8(2, 0xd2) - mstore8(3, 0xf0) + mstore(0, 0xE467D2F000000000000000000000000000000000000000000000000000000000) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 0) if iszero(success) { @@ -943,7 +899,6 @@ object "EVMInterpreter" { } // Each evm gas is 5 zkEVM one - // FIXME: change this variable to reflect real ergs : gas ratio function GAS_DIVISOR() -> gas_div { gas_div := 5 } function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30 function OVERHEAD() -> overhead { overhead := 2000 } @@ -1041,11 +996,11 @@ object "EVMInterpreter" { addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff) - checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft) - checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft) + checkOverflow(argsOffset,argsSize, evmGasLeft) + checkOverflow(retOffset, retSize, evmGasLeft) - checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft) - checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft) + checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft) extraCost := 0 if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) { @@ -1063,18 +1018,9 @@ object "EVMInterpreter" { let frameGasLeft let success - if _isEVM(addr) { - _pushEVMFrame(gasToPass, true) - // TODO Check the following comment from zkSync .sol. - // We can not just pass all gas here to prevert overflow of zkEVM gas counter - success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) - - frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) - _popEVMFrame() - } - - // zkEVM native - if iszero(_isEVM(addr)) { + switch _isEVM(addr) + case 0 { + // zkEVM native gasToPass := _getZkEVMGas(gasToPass, addr) let zkevmGasBefore := gas() success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, add(MEM_OFFSET_INNER(), retOffset), retSize) @@ -1087,9 +1033,23 @@ object "EVMInterpreter" { frameGasLeft := sub(gasToPass, gasUsed) } } + default { + _pushEVMFrame(gasToPass, true) + success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) + + frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) + _popEVMFrame() + } + + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) sp := pushStackItem(sp, success, evmGasLeft) } function capGas(evmGasLeft,oldGasToPass) -> gasToPass { @@ -1114,7 +1074,31 @@ object "EVMInterpreter" { function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize,isStatic) -> success, frameGasLeft, gasToPassNew{ gasToPassNew := gasToPass let is_evm := _isEVM(addr) - if isStatic { + + switch isStatic + case 0 { + switch is_evm + case 0 { + // zkEVM native + gasToPassNew := _getZkEVMGas(gasToPassNew, addr) + let zkevmGasBefore := gas() + success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize) + _saveReturndataAfterZkEVMCall() + let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) + + frameGasLeft := 0 + if gt(gasToPassNew, gasUsed) { + frameGasLeft := sub(gasToPassNew, gasUsed) + } + } + default { + _pushEVMFrame(gasToPassNew, isStatic) + success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0) + frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + _popEVMFrame() + } + } + default { if value { revertWithGas(gasToPassNew) } @@ -1128,27 +1112,6 @@ object "EVMInterpreter" { retSize ) } - - if and(is_evm, iszero(isStatic)) { - _pushEVMFrame(gasToPassNew, isStatic) - success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0) - frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) - _popEVMFrame() - } - - // zkEVM native - if and(iszero(is_evm), iszero(isStatic)) { - gasToPassNew := _getZkEVMGas(gasToPassNew, addr) - let zkevmGasBefore := gas() - success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize) - _saveReturndataAfterZkEVMCall() - let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) - - frameGasLeft := 0 - if gt(gasToPassNew, gasUsed) { - frameGasLeft := sub(gasToPassNew, gasUsed) - } - } } function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp { @@ -1212,8 +1175,14 @@ object "EVMInterpreter" { isStatic ) - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } sp := pushStackItem(sp,success, evmGasLeft) } @@ -1233,11 +1202,11 @@ object "EVMInterpreter" { // addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff) - checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft) - checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft) + checkOverflow(argsOffset, argsSize, evmGasLeft) + checkOverflow(retOffset, retSize, evmGasLeft) - checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft) - checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft) + checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft) if iszero(_isEVM(addr)) { revertWithGas(evmGasLeft) @@ -1254,13 +1223,6 @@ object "EVMInterpreter" { } gasToPass := capGas(evmGasLeft,gasToPass) - // TODO: Do this - // if warmAccount(addr) { - // extraCost = GAS_WARM_ACCESS; - // } else { - // extraCost = GAS_COLD_ACCOUNT_ACCESS; - // } - _pushEVMFrame(gasToPass, isStatic) let success := delegatecall( // We can not just pass all gas here to prevert overflow of zkEVM gas counter @@ -1276,8 +1238,14 @@ object "EVMInterpreter" { _popEVMFrame() - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } sp := pushStackItem(sp, success, evmGasLeft) } @@ -1322,18 +1290,9 @@ object "EVMInterpreter" { _outputOffset, _outputLen ) -> success, _gasLeft { - if _calleeIsEVM { - _pushEVMFrame(_calleeGas, true) - // TODO Check the following comment from zkSync .sol. - // We can not just pass all gas here to prevert overflow of zkEVM gas counter - success := staticcall(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) - - _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) - _popEVMFrame() - } - - // zkEVM native - if iszero(_calleeIsEVM) { + switch _calleeIsEVM + case 0 { + // zkEVM native _calleeGas := _getZkEVMGas(_calleeGas, _callee) let zkevmGasBefore := gas() success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, _outputOffset, _outputLen) @@ -1347,6 +1306,13 @@ object "EVMInterpreter" { _gasLeft := sub(_calleeGas, gasUsed) } } + default { + _pushEVMFrame(_calleeGas, true) + success := staticcall(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) + + _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) + _popEVMFrame() + } } function isAddrEmpty(addr) -> isEmpty { @@ -1361,12 +1327,7 @@ object "EVMInterpreter" { } function _fetchConstructorReturnGas() -> gasLeft { - //selector is 0x24e5ab4a - - mstore8(0, 0x24) - mstore8(1, 0xe5) - mstore8(2, 0xab) - mstore8(3, 0x4a) + mstore(0, 0x24E5AB4A00000000000000000000000000000000000000000000000000000000) let success := staticcall(gas(), DEPLOYER_SYSTEM_CONTRACT(), 0, 4, 0, 32) @@ -1391,10 +1352,11 @@ object "EVMInterpreter" { offset := add(MEM_OFFSET_INNER(), offset) - sp := pushStackItem(sp, mload(sub(offset, 0x80)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x60)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x40)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x20)), evmGasLeftOld) + pushStackCheck(sp, evmGasLeftOld, 4) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x80))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x60))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x40))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x20))) // Selector mstore(sub(offset, 0x80), 0x5b16a23c) @@ -1438,7 +1400,7 @@ object "EVMInterpreter" { let back - popStackCheck(sp, evmGasLeft, 4) + // skipping check since we pushed exactly 4 items earlier back, sp := popStackItemWithoutCheck(sp) mstore(sub(offset, 0x20), back) back, sp := popStackItemWithoutCheck(sp) @@ -1449,6 +1411,45 @@ object "EVMInterpreter" { mstore(sub(offset, 0x80), back) } + function $llvm_AlwaysInline_llvm$_copyRest(dest, val, len) { + let rest_bits := shl(3, len) + let upper_bits := sub(256, rest_bits) + let val_mask := shl(upper_bits, MAX_UINT()) + let val_masked := and(val, val_mask) + let dst_val := mload(dest) + let dst_mask := shr(rest_bits, MAX_UINT()) + let dst_masked := and(dst_val, dst_mask) + mstore(dest, or(val_masked, dst_masked)) + } + + function $llvm_AlwaysInline_llvm$_memcpy(dest, src, len) { + let dest_addr := dest + let src_addr := src + let dest_end := add(dest, and(len, sub(0, 32))) + for { } lt(dest_addr, dest_end) {} { + mstore(dest_addr, mload(src_addr)) + dest_addr := add(dest_addr, 32) + src_addr := add(src_addr, 32) + } + + let rest_len := and(len, 31) + if rest_len { + $llvm_AlwaysInline_llvm$_copyRest(dest_addr, mload(src_addr), rest_len) + } + } + + function $llvm_AlwaysInline_llvm$_memsetToZero(dest,len) { + let dest_end := add(dest, and(len, sub(0, 32))) + for {let i := dest} lt(i, dest_end) { i := add(i, 32) } { + mstore(i, 0) + } + + let rest_len := and(len, 31) + if rest_len { + $llvm_AlwaysInline_llvm$_copyRest(dest_end, 0, rest_len) + } + } + function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { evmGasLeft := chargeGas(evmGas, 100) @@ -1471,21 +1472,12 @@ object "EVMInterpreter" { } evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - let len_32 := shr(5, len) - for {let i := 0} lt(i, len_32) { i := add(i, 1) } { - mstore(add(dest,shl(5,i)),0) - } - let size_32 := shl(5,len_32) - let rest_32 := sub(len, size_32) - for {let i := 0} lt(i, rest_32) { i := add(i, 1) } { - mstore8(add(dest,add(size_32,i)),0) - } + $llvm_AlwaysInline_llvm$_memsetToZero(dest, len) // Gets the code from the addr - if iszero(iszero(_getRawCodeHash(addr))) { + if and(iszero(iszero(_getRawCodeHash(addr))),gt(len,0)) { pop(_fetchDeployedCodeWithDest(addr, offset, len,add(dest,MEM_OFFSET_INNER()))) } - } function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp { @@ -1502,9 +1494,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { revertWithGas(evmGasLeft) @@ -1549,9 +1540,8 @@ object "EVMInterpreter" { size, sp := popStackItemWithoutCheck(sp) salt, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { revertWithGas(evmGasLeft) @@ -1573,7 +1563,7 @@ object "EVMInterpreter" { { let hashedBytecode := keccak256(add(MEM_OFFSET_INNER(), offset), size) - mstore8(0, 0xFF) + mstore(0, 0xFF00000000000000000000000000000000000000000000000000000000000000) mstore(0x01, shl(0x60, address())) mstore(0x15, salt) mstore(0x35, hashedBytecode) @@ -1618,7 +1608,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1630,7 +1620,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1642,7 +1632,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1654,7 +1644,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1666,7 +1656,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1678,7 +1668,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1690,7 +1680,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1702,7 +1692,7 @@ object "EVMInterpreter" { let a, b, N - popPushStackCheck(sp, evmGasLeft, 3) + popStackCheck(sp, evmGasLeft, 3) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) N, sp := popStackItemWithoutCheck(sp) @@ -1728,7 +1718,7 @@ object "EVMInterpreter" { let a, exponent - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) exponent, sp := popStackItemWithoutCheck(sp) @@ -1747,7 +1737,7 @@ object "EVMInterpreter" { let b, x - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) b, sp := popStackItemWithoutCheck(sp) x, sp := popStackItemWithoutCheck(sp) @@ -1759,7 +1749,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1771,7 +1761,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1783,7 +1773,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1795,7 +1785,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1807,7 +1797,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1819,7 +1809,7 @@ object "EVMInterpreter" { let a - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) a, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, iszero(a)) @@ -1830,7 +1820,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1842,7 +1832,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1854,7 +1844,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1866,7 +1856,7 @@ object "EVMInterpreter" { let a - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) a, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, not(a)) @@ -1877,7 +1867,7 @@ object "EVMInterpreter" { let i, x - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) i, sp := popStackItemWithoutCheck(sp) x, sp := popStackItemWithoutCheck(sp) @@ -1889,7 +1879,7 @@ object "EVMInterpreter" { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -1901,7 +1891,7 @@ object "EVMInterpreter" { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -1913,7 +1903,7 @@ object "EVMInterpreter" { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -1929,8 +1919,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) let keccak := keccak256(add(MEM_OFFSET_INNER(), offset), size) // When an offset is first accessed (either read or write), memory may trigger @@ -1961,7 +1951,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 2500) } - sp := pushStackItem(sp, balance(addr), evmGasLeft) + sp := pushStackItemWithoutCheck(sp, balance(addr)) ip := add(ip, 1) } case 0x32 { // OP_ORIGIN @@ -1987,7 +1977,7 @@ object "EVMInterpreter" { let i - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) i, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, calldataload(i)) @@ -2012,13 +2002,9 @@ object "EVMInterpreter" { checkMultipleOverflow(offset,size,MEM_OFFSET_INNER(), evmGasLeft) checkMultipleOverflow(destOffset,size,MEM_OFFSET_INNER(), evmGasLeft) + // TODO invalid? if or(gt(add(add(offset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM()), gt(add(add(destOffset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM())) { - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(destOffset, MEM_OFFSET_INNER()), i), - 0 - ) - } + $llvm_AlwaysInline_llvm$_memsetToZero(add(destOffset, MEM_OFFSET_INNER()), size) } // dynamicGas = 3 * minimum_word_size + memory_expansion_cost @@ -2063,12 +2049,7 @@ object "EVMInterpreter" { revertWithGas(evmGasLeft) } - for { let i := 0 } lt(i, len) { i := add(i, 1) } { - mstore8( - add(dst, i), - shr(248, mload(add(offset, i))) - ) - } + $llvm_AlwaysInline_llvm$_memcpy(dst, offset, len) ip := add(ip, 1) } case 0x3A { // OP_GASPRICE @@ -2088,14 +2069,9 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 2500) } - // TODO: check, the .sol uses extcodesize directly, but it doesnt seem to work - // if a contract is created it works, but if the address is a zkSync's contract - // what happens? - // sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) - switch _isEVM(addr) - case 0 { sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) } - default { sp := pushStackItem(sp, _fetchDeployedCodeLen(addr), evmGasLeft) } + case 0 { sp := pushStackItemWithoutCheck(sp, extcodesize(addr)) } + default { sp := pushStackItemWithoutCheck(sp, _fetchDeployedCodeLen(addr)) } ip := add(ip, 1) } case 0x3C { // OP_EXTCODECOPY @@ -2118,9 +2094,6 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) len, sp := popStackItemWithoutCheck(sp) - // TODO: check if these conditions are met - // The addition offset + size overflows. - // offset + size is larger than RETURNDATASIZE. checkOverflow(offset,len, evmGasLeft) if gt(add(offset, len), mload(LAST_RETURNDATA_SIZE_OFFSET())) { revertWithGas(evmGasLeft) @@ -2128,7 +2101,7 @@ object "EVMInterpreter" { // minimum_word_size = (size + 31) / 32 // dynamicGas = 3 * minimum_word_size + memory_expansion_cost - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(add(dest, len))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) @@ -2148,16 +2121,16 @@ object "EVMInterpreter" { ip := add(ip, 1) if iszero(addr) { - sp := pushStackItem(sp, 0, evmGasLeft) + sp := pushStackItemWithoutCheck(sp, 0) continue } - sp := pushStackItem(sp, extcodehash(addr), evmGasLeft) + sp := pushStackItemWithoutCheck(sp, extcodehash(addr)) } case 0x40 { // OP_BLOCKHASH evmGasLeft := chargeGas(evmGasLeft, 20) let blockNumber - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) blockNumber, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, blockhash(blockNumber)) @@ -2218,13 +2191,12 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp, evmGasLeft) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) let memValue := mload(add(MEM_OFFSET_INNER(), offset)) - sp := pushStackItem(sp, memValue, evmGasLeft) + sp := pushStackItemWithoutCheck(sp, memValue) ip := add(ip, 1) } case 0x52 { // OP_MSTORE @@ -2236,11 +2208,10 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) mstore(add(MEM_OFFSET_INNER(), offset), value) ip := add(ip, 1) } @@ -2253,11 +2224,10 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 1)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) mstore8(add(MEM_OFFSET_INNER(), offset), value) ip := add(ip, 1) } @@ -2281,7 +2251,7 @@ object "EVMInterpreter" { let _wasW, _orgV := warmSlot(key, value) } - sp := pushStackItem(sp,value, evmGasLeft) + sp := pushStackItemWithoutCheck(sp,value) ip := add(ip, 1) } case 0x55 { // OP_SSTORE @@ -2341,6 +2311,10 @@ object "EVMInterpreter" { if iszero(eq(nextOpcode, 0x5B)) { revertWithGas(evmGasLeft) } + + // execute JUMPDEST immediately + evmGasLeft := chargeGas(evmGasLeft, 1) + ip := add(ip, 1) } case 0x57 { // OP_JUMPI evmGasLeft := chargeGas(evmGasLeft, 10) @@ -2363,6 +2337,10 @@ object "EVMInterpreter" { if iszero(eq(nextOpcode, 0x5B)) { revertWithGas(evmGasLeft) } + + // execute JUMPDEST immediately + evmGasLeft := chargeGas(evmGasLeft, 1) + ip := add(ip, 1) } case 0x58 { // OP_PC evmGasLeft := chargeGas(evmGasLeft, 2) @@ -2395,7 +2373,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 100) let key - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) key, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, tload(key)) @@ -2423,26 +2401,14 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) + // TODO overflow checks + checkMemOverflowByOffset(add(offset, size), evmGasLeft) + checkMemOverflowByOffset(add(destOffset, size), evmGasLeft) + expandMemory(add(destOffset, size)) expandMemory(add(offset, size)) - let oldSize := mul(mload(MEM_OFFSET()),32) - if gt(add(oldSize,size),MAX_POSSIBLE_MEM()) { - revertWithGas(evmGasLeft) - } - - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(oldSize,MEM_OFFSET_INNER()), i), - shr(248,mload(add(add(offset,MEM_OFFSET_INNER()), i))) - ) - } - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(destOffset,MEM_OFFSET_INNER()), i), - shr(248,mload(add(add(oldSize,MEM_OFFSET_INNER()), i))) - ) - } + mcopy(add(destOffset, MEM_OFFSET_INNER()), add(offset, MEM_OFFSET_INNER()), size) ip := add(ip, 1) } case 0x5F { // OP_PUSH0 @@ -2881,8 +2847,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -2904,8 +2870,8 @@ object "EVMInterpreter" { size, sp := popStackItemWithoutCheck(sp) topic1, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -2926,8 +2892,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -2955,9 +2921,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -2986,8 +2951,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -3068,6 +3033,7 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) + // TODO invalid? ensureAcceptableMemLocation(offset) ensureAcceptableMemLocation(size) evmGasLeft := chargeGas(evmGasLeft,expandMemory(add(offset,size))) @@ -3197,7 +3163,6 @@ object "EVMInterpreter" { // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 function readIP(ip,maxAcceptablePos) -> opcode { - // TODO: Why not do this at the beginning once instead of every time? if gt(ip, maxAcceptablePos) { revert(0, 0) } @@ -3285,11 +3250,8 @@ object "EVMInterpreter" { } } - function popPushStackCheck(sp, evmGasLeft, numInputs) { - let popCheck := lt(sub(sp, mul(0x20, sub(numInputs, 1))), STACK_OFFSET()) - let pushOffset := sub(sp, mul(0x20, numInputs)) - let pushCheck := or(gt(pushOffset, BYTECODE_OFFSET()), eq(pushOffset, BYTECODE_OFFSET())) - if or(popCheck, pushCheck) { + function pushStackCheck(sp, evmGasLeft, numInputs) { + if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_OFFSET())) { revertWithGas(evmGasLeft) } } @@ -3323,11 +3285,7 @@ object "EVMInterpreter" { } function _getRawCodeHash(account) -> hash { - // TODO: Unhardcode this selector - mstore8(0, 0x4d) - mstore8(1, 0xe2) - mstore8(2, 0xe4) - mstore8(3, 0x68) + mstore(0, 0x4DE2E46800000000000000000000000000000000000000000000000000000000) mstore(4, account) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -3342,12 +3300,7 @@ object "EVMInterpreter" { function _getCodeHash(account) -> hash { // function getCodeHash(uint256 _input) external view override returns (bytes32) - // 0xe03fe177 - // TODO: Unhardcode this selector - mstore8(0, 0xe0) - mstore8(1, 0x3f) - mstore8(2, 0xe1) - mstore8(3, 0x77) + mstore(0, 0xE03FE17700000000000000000000000000000000000000000000000000000000) mstore(4, account) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -3362,7 +3315,6 @@ object "EVMInterpreter" { function getIsStaticFromCallFlags() -> isStatic { isStatic := verbatim_0i_1o("get_global::call_flags") - // TODO: make it a constnat isStatic := iszero(iszero(and(isStatic, 0x04))) } @@ -3431,11 +3383,7 @@ object "EVMInterpreter" { function consumeEvmFrame() -> passGas, isStatic, callerEVM { // function consumeEvmFrame() external returns (uint256 passGas, bool isStatic) - // TODO: Unhardcode selector - mstore8(0, 0x04) - mstore8(1, 0xc1) - mstore8(2, 0x4e) - mstore8(3, 0x9e) + mstore(0, 0x04C14E9E00000000000000000000000000000000000000000000000000000000) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 64) @@ -3615,6 +3563,13 @@ object "EVMInterpreter" { } } + function checkMemOverflowByOffset(offset, evmGasLeft) { + if gt(offset, MAX_POSSIBLE_MEM()) { + mstore(0, evmGasLeft) + revert(0, 32) + } + } + function checkMemOverflow(location, evmGasLeft) { if gt(location, MAX_MEMORY_FRAME()) { mstore(0, evmGasLeft) @@ -3680,11 +3635,7 @@ object "EVMInterpreter" { } function isSlotWarm(key) -> isWarm { - // TODO: Unhardcode this selector 0x482d2e74 - mstore8(0, 0x48) - mstore8(1, 0x2d) - mstore8(2, 0x2e) - mstore8(3, 0x74) + mstore(0, 0x482D2E7400000000000000000000000000000000000000000000000000000000) mstore(4, key) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) @@ -3698,11 +3649,7 @@ object "EVMInterpreter" { } function warmSlot(key,currentValue) -> isWarm, originalValue { - // TODO: Unhardcode this selector 0xbdf78160 - mstore8(0, 0xbd) - mstore8(1, 0xf7) - mstore8(2, 0x81) - mstore8(3, 0x60) + mstore(0, 0xBDF7816000000000000000000000000000000000000000000000000000000000) mstore(4, key) mstore(36,currentValue) @@ -3745,29 +3692,34 @@ object "EVMInterpreter" { if iszero(nonce) { nonceEncoded := 128 } - // The nonce has 4 bytes - if gt(nonce, 0xFFFFFF) { - nonceEncoded := shl(32, 0x84) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 5 - } - // The nonce has 3 bytes - if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { - nonceEncoded := shl(24, 0x83) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 4 - } - // The nonce has 2 bytes - if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { - nonceEncoded := shl(16, 0x82) + switch gt(nonce, 0xFFFF) + case 1 { + switch gt(nonce, 0xFFFFFF) + case 1 { + // The nonce has 4 bytes + nonceEncoded := shl(32, 0x84) + nonceEncodedLength := 5 + } + default { + // The nonce has 3 bytes + nonceEncoded := shl(24, 0x83) + nonceEncodedLength := 4 + } nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 3 } - // The nonce has 1 byte and it's in [0x80, 0xFF] - if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { - nonceEncoded := shl(8, 0x81) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 2 + default { + // The nonce has 2 bytes + if gt(nonce, 0xFF) { + nonceEncoded := shl(16, 0x82) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 3 + } + // The nonce has 1 byte and it's in [0x80, 0xFF] + if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { + nonceEncoded := shl(8, 0x81) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 2 + } } listLength := add(21, nonceEncodedLength) @@ -3795,10 +3747,7 @@ object "EVMInterpreter" { } function incrementNonce(addr) { - mstore8(0, 0x30) - mstore8(1, 0x63) - mstore8(2, 0x95) - mstore8(3, 0xc6) + mstore(0, 0x306395C600000000000000000000000000000000000000000000000000000000) mstore(4, addr) let farCallAbi := getFarCallABI( @@ -3882,11 +3831,7 @@ object "EVMInterpreter" { } function $llvm_AlwaysInline_llvm$_warmAddress(addr) -> isWarm { - // TODO: Unhardcode this selector 0x8db2ba78 - mstore8(0, 0x8d) - mstore8(1, 0xb2) - mstore8(2, 0xba) - mstore8(3, 0x78) + mstore(0, 0x8DB2BA7800000000000000000000000000000000000000000000000000000000) mstore(4, addr) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) @@ -3900,10 +3845,7 @@ object "EVMInterpreter" { } function getNonce(addr) -> nonce { - mstore8(0, 0xfb) - mstore8(1, 0x1a) - mstore8(2, 0x9a) - mstore8(3, 0x57) + mstore(0, 0xFB1A9A5700000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -3916,10 +3858,7 @@ object "EVMInterpreter" { } function getRawNonce(addr) -> nonce { - mstore8(0, 0x5a) - mstore8(1, 0xa9) - mstore8(2, 0xb6) - mstore8(3, 0xb5) + mstore(0, 0x5AA9B6B500000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -3938,10 +3877,7 @@ object "EVMInterpreter" { // address(SYSTEM_CONTRACTS_OFFSET + 0x02) // ); - mstore8(0, 0x8c) - mstore8(1, 0x04) - mstore8(2, 0x04) - mstore8(3, 0x77) + mstore(0, 0x8C04047700000000000000000000000000000000000000000000000000000000) mstore(4, _addr) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -3956,12 +3892,8 @@ object "EVMInterpreter" { function _pushEVMFrame(_passGas, _isStatic) { // function pushEVMFrame(uint256 _passGas, bool _isStatic) external - let selector := 0xead77156 - mstore8(0, 0xea) - mstore8(1, 0xd7) - mstore8(2, 0x71) - mstore8(3, 0x56) + mstore(0, 0xEAD7715600000000000000000000000000000000000000000000000000000000) mstore(4, _passGas) mstore(36, _isStatic) @@ -3974,13 +3906,8 @@ object "EVMInterpreter" { function _popEVMFrame() { // function popEVMFrame() external - // 0xe467d2f0 - let selector := 0xe467d2f0 - mstore8(0, 0xe4) - mstore8(1, 0x67) - mstore8(2, 0xd2) - mstore8(3, 0xf0) + mstore(0, 0xE467D2F000000000000000000000000000000000000000000000000000000000) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 0) if iszero(success) { @@ -3990,7 +3917,6 @@ object "EVMInterpreter" { } // Each evm gas is 5 zkEVM one - // FIXME: change this variable to reflect real ergs : gas ratio function GAS_DIVISOR() -> gas_div { gas_div := 5 } function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30 function OVERHEAD() -> overhead { overhead := 2000 } @@ -4088,11 +4014,11 @@ object "EVMInterpreter" { addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff) - checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft) - checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft) + checkOverflow(argsOffset,argsSize, evmGasLeft) + checkOverflow(retOffset, retSize, evmGasLeft) - checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft) - checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft) + checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft) extraCost := 0 if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) { @@ -4110,18 +4036,9 @@ object "EVMInterpreter" { let frameGasLeft let success - if _isEVM(addr) { - _pushEVMFrame(gasToPass, true) - // TODO Check the following comment from zkSync .sol. - // We can not just pass all gas here to prevert overflow of zkEVM gas counter - success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) - - frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) - _popEVMFrame() - } - - // zkEVM native - if iszero(_isEVM(addr)) { + switch _isEVM(addr) + case 0 { + // zkEVM native gasToPass := _getZkEVMGas(gasToPass, addr) let zkevmGasBefore := gas() success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, add(MEM_OFFSET_INNER(), retOffset), retSize) @@ -4134,9 +4051,23 @@ object "EVMInterpreter" { frameGasLeft := sub(gasToPass, gasUsed) } } + default { + _pushEVMFrame(gasToPass, true) + success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) + + frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) + _popEVMFrame() + } + + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) sp := pushStackItem(sp, success, evmGasLeft) } function capGas(evmGasLeft,oldGasToPass) -> gasToPass { @@ -4161,7 +4092,31 @@ object "EVMInterpreter" { function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize,isStatic) -> success, frameGasLeft, gasToPassNew{ gasToPassNew := gasToPass let is_evm := _isEVM(addr) - if isStatic { + + switch isStatic + case 0 { + switch is_evm + case 0 { + // zkEVM native + gasToPassNew := _getZkEVMGas(gasToPassNew, addr) + let zkevmGasBefore := gas() + success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize) + _saveReturndataAfterZkEVMCall() + let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) + + frameGasLeft := 0 + if gt(gasToPassNew, gasUsed) { + frameGasLeft := sub(gasToPassNew, gasUsed) + } + } + default { + _pushEVMFrame(gasToPassNew, isStatic) + success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0) + frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + _popEVMFrame() + } + } + default { if value { revertWithGas(gasToPassNew) } @@ -4175,27 +4130,6 @@ object "EVMInterpreter" { retSize ) } - - if and(is_evm, iszero(isStatic)) { - _pushEVMFrame(gasToPassNew, isStatic) - success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0) - frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) - _popEVMFrame() - } - - // zkEVM native - if and(iszero(is_evm), iszero(isStatic)) { - gasToPassNew := _getZkEVMGas(gasToPassNew, addr) - let zkevmGasBefore := gas() - success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize) - _saveReturndataAfterZkEVMCall() - let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) - - frameGasLeft := 0 - if gt(gasToPassNew, gasUsed) { - frameGasLeft := sub(gasToPassNew, gasUsed) - } - } } function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp { @@ -4259,8 +4193,14 @@ object "EVMInterpreter" { isStatic ) - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } sp := pushStackItem(sp,success, evmGasLeft) } @@ -4280,11 +4220,11 @@ object "EVMInterpreter" { // addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff) - checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft) - checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft) + checkOverflow(argsOffset, argsSize, evmGasLeft) + checkOverflow(retOffset, retSize, evmGasLeft) - checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft) - checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft) + checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft) if iszero(_isEVM(addr)) { revertWithGas(evmGasLeft) @@ -4301,13 +4241,6 @@ object "EVMInterpreter" { } gasToPass := capGas(evmGasLeft,gasToPass) - // TODO: Do this - // if warmAccount(addr) { - // extraCost = GAS_WARM_ACCESS; - // } else { - // extraCost = GAS_COLD_ACCOUNT_ACCESS; - // } - _pushEVMFrame(gasToPass, isStatic) let success := delegatecall( // We can not just pass all gas here to prevert overflow of zkEVM gas counter @@ -4323,8 +4256,14 @@ object "EVMInterpreter" { _popEVMFrame() - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } sp := pushStackItem(sp, success, evmGasLeft) } @@ -4369,18 +4308,9 @@ object "EVMInterpreter" { _outputOffset, _outputLen ) -> success, _gasLeft { - if _calleeIsEVM { - _pushEVMFrame(_calleeGas, true) - // TODO Check the following comment from zkSync .sol. - // We can not just pass all gas here to prevert overflow of zkEVM gas counter - success := staticcall(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) - - _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) - _popEVMFrame() - } - - // zkEVM native - if iszero(_calleeIsEVM) { + switch _calleeIsEVM + case 0 { + // zkEVM native _calleeGas := _getZkEVMGas(_calleeGas, _callee) let zkevmGasBefore := gas() success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, _outputOffset, _outputLen) @@ -4394,6 +4324,13 @@ object "EVMInterpreter" { _gasLeft := sub(_calleeGas, gasUsed) } } + default { + _pushEVMFrame(_calleeGas, true) + success := staticcall(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) + + _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) + _popEVMFrame() + } } function isAddrEmpty(addr) -> isEmpty { @@ -4408,12 +4345,7 @@ object "EVMInterpreter" { } function _fetchConstructorReturnGas() -> gasLeft { - //selector is 0x24e5ab4a - - mstore8(0, 0x24) - mstore8(1, 0xe5) - mstore8(2, 0xab) - mstore8(3, 0x4a) + mstore(0, 0x24E5AB4A00000000000000000000000000000000000000000000000000000000) let success := staticcall(gas(), DEPLOYER_SYSTEM_CONTRACT(), 0, 4, 0, 32) @@ -4438,10 +4370,11 @@ object "EVMInterpreter" { offset := add(MEM_OFFSET_INNER(), offset) - sp := pushStackItem(sp, mload(sub(offset, 0x80)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x60)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x40)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x20)), evmGasLeftOld) + pushStackCheck(sp, evmGasLeftOld, 4) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x80))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x60))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x40))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x20))) // Selector mstore(sub(offset, 0x80), 0x5b16a23c) @@ -4485,7 +4418,7 @@ object "EVMInterpreter" { let back - popStackCheck(sp, evmGasLeft, 4) + // skipping check since we pushed exactly 4 items earlier back, sp := popStackItemWithoutCheck(sp) mstore(sub(offset, 0x20), back) back, sp := popStackItemWithoutCheck(sp) @@ -4496,6 +4429,45 @@ object "EVMInterpreter" { mstore(sub(offset, 0x80), back) } + function $llvm_AlwaysInline_llvm$_copyRest(dest, val, len) { + let rest_bits := shl(3, len) + let upper_bits := sub(256, rest_bits) + let val_mask := shl(upper_bits, MAX_UINT()) + let val_masked := and(val, val_mask) + let dst_val := mload(dest) + let dst_mask := shr(rest_bits, MAX_UINT()) + let dst_masked := and(dst_val, dst_mask) + mstore(dest, or(val_masked, dst_masked)) + } + + function $llvm_AlwaysInline_llvm$_memcpy(dest, src, len) { + let dest_addr := dest + let src_addr := src + let dest_end := add(dest, and(len, sub(0, 32))) + for { } lt(dest_addr, dest_end) {} { + mstore(dest_addr, mload(src_addr)) + dest_addr := add(dest_addr, 32) + src_addr := add(src_addr, 32) + } + + let rest_len := and(len, 31) + if rest_len { + $llvm_AlwaysInline_llvm$_copyRest(dest_addr, mload(src_addr), rest_len) + } + } + + function $llvm_AlwaysInline_llvm$_memsetToZero(dest,len) { + let dest_end := add(dest, and(len, sub(0, 32))) + for {let i := dest} lt(i, dest_end) { i := add(i, 32) } { + mstore(i, 0) + } + + let rest_len := and(len, 31) + if rest_len { + $llvm_AlwaysInline_llvm$_copyRest(dest_end, 0, rest_len) + } + } + function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { evmGasLeft := chargeGas(evmGas, 100) @@ -4518,21 +4490,12 @@ object "EVMInterpreter" { } evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - let len_32 := shr(5, len) - for {let i := 0} lt(i, len_32) { i := add(i, 1) } { - mstore(add(dest,shl(5,i)),0) - } - let size_32 := shl(5,len_32) - let rest_32 := sub(len, size_32) - for {let i := 0} lt(i, rest_32) { i := add(i, 1) } { - mstore8(add(dest,add(size_32,i)),0) - } + $llvm_AlwaysInline_llvm$_memsetToZero(dest, len) // Gets the code from the addr - if iszero(iszero(_getRawCodeHash(addr))) { + if and(iszero(iszero(_getRawCodeHash(addr))),gt(len,0)) { pop(_fetchDeployedCodeWithDest(addr, offset, len,add(dest,MEM_OFFSET_INNER()))) } - } function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp { @@ -4549,9 +4512,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { revertWithGas(evmGasLeft) @@ -4596,9 +4558,8 @@ object "EVMInterpreter" { size, sp := popStackItemWithoutCheck(sp) salt, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { revertWithGas(evmGasLeft) @@ -4620,7 +4581,7 @@ object "EVMInterpreter" { { let hashedBytecode := keccak256(add(MEM_OFFSET_INNER(), offset), size) - mstore8(0, 0xFF) + mstore(0, 0xFF00000000000000000000000000000000000000000000000000000000000000) mstore(0x01, shl(0x60, address())) mstore(0x15, salt) mstore(0x35, hashedBytecode) @@ -4665,7 +4626,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4677,7 +4638,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4689,7 +4650,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4701,7 +4662,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4713,7 +4674,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4725,7 +4686,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4737,7 +4698,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4749,7 +4710,7 @@ object "EVMInterpreter" { let a, b, N - popPushStackCheck(sp, evmGasLeft, 3) + popStackCheck(sp, evmGasLeft, 3) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) N, sp := popStackItemWithoutCheck(sp) @@ -4775,7 +4736,7 @@ object "EVMInterpreter" { let a, exponent - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) exponent, sp := popStackItemWithoutCheck(sp) @@ -4794,7 +4755,7 @@ object "EVMInterpreter" { let b, x - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) b, sp := popStackItemWithoutCheck(sp) x, sp := popStackItemWithoutCheck(sp) @@ -4806,7 +4767,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4818,7 +4779,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4830,7 +4791,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4842,7 +4803,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4854,7 +4815,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4866,7 +4827,7 @@ object "EVMInterpreter" { let a - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) a, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, iszero(a)) @@ -4877,7 +4838,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4889,7 +4850,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4901,7 +4862,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4913,7 +4874,7 @@ object "EVMInterpreter" { let a - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) a, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, not(a)) @@ -4924,7 +4885,7 @@ object "EVMInterpreter" { let i, x - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) i, sp := popStackItemWithoutCheck(sp) x, sp := popStackItemWithoutCheck(sp) @@ -4936,7 +4897,7 @@ object "EVMInterpreter" { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -4948,7 +4909,7 @@ object "EVMInterpreter" { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -4960,7 +4921,7 @@ object "EVMInterpreter" { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -4976,8 +4937,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) let keccak := keccak256(add(MEM_OFFSET_INNER(), offset), size) // When an offset is first accessed (either read or write), memory may trigger @@ -5008,7 +4969,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 2500) } - sp := pushStackItem(sp, balance(addr), evmGasLeft) + sp := pushStackItemWithoutCheck(sp, balance(addr)) ip := add(ip, 1) } case 0x32 { // OP_ORIGIN @@ -5034,7 +4995,7 @@ object "EVMInterpreter" { let i - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) i, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, calldataload(i)) @@ -5059,13 +5020,9 @@ object "EVMInterpreter" { checkMultipleOverflow(offset,size,MEM_OFFSET_INNER(), evmGasLeft) checkMultipleOverflow(destOffset,size,MEM_OFFSET_INNER(), evmGasLeft) + // TODO invalid? if or(gt(add(add(offset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM()), gt(add(add(destOffset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM())) { - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(destOffset, MEM_OFFSET_INNER()), i), - 0 - ) - } + $llvm_AlwaysInline_llvm$_memsetToZero(add(destOffset, MEM_OFFSET_INNER()), size) } // dynamicGas = 3 * minimum_word_size + memory_expansion_cost @@ -5110,12 +5067,7 @@ object "EVMInterpreter" { revertWithGas(evmGasLeft) } - for { let i := 0 } lt(i, len) { i := add(i, 1) } { - mstore8( - add(dst, i), - shr(248, mload(add(offset, i))) - ) - } + $llvm_AlwaysInline_llvm$_memcpy(dst, offset, len) ip := add(ip, 1) } case 0x3A { // OP_GASPRICE @@ -5135,14 +5087,9 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 2500) } - // TODO: check, the .sol uses extcodesize directly, but it doesnt seem to work - // if a contract is created it works, but if the address is a zkSync's contract - // what happens? - // sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) - switch _isEVM(addr) - case 0 { sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) } - default { sp := pushStackItem(sp, _fetchDeployedCodeLen(addr), evmGasLeft) } + case 0 { sp := pushStackItemWithoutCheck(sp, extcodesize(addr)) } + default { sp := pushStackItemWithoutCheck(sp, _fetchDeployedCodeLen(addr)) } ip := add(ip, 1) } case 0x3C { // OP_EXTCODECOPY @@ -5165,9 +5112,6 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) len, sp := popStackItemWithoutCheck(sp) - // TODO: check if these conditions are met - // The addition offset + size overflows. - // offset + size is larger than RETURNDATASIZE. checkOverflow(offset,len, evmGasLeft) if gt(add(offset, len), mload(LAST_RETURNDATA_SIZE_OFFSET())) { revertWithGas(evmGasLeft) @@ -5175,7 +5119,7 @@ object "EVMInterpreter" { // minimum_word_size = (size + 31) / 32 // dynamicGas = 3 * minimum_word_size + memory_expansion_cost - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(add(dest, len))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) @@ -5195,16 +5139,16 @@ object "EVMInterpreter" { ip := add(ip, 1) if iszero(addr) { - sp := pushStackItem(sp, 0, evmGasLeft) + sp := pushStackItemWithoutCheck(sp, 0) continue } - sp := pushStackItem(sp, extcodehash(addr), evmGasLeft) + sp := pushStackItemWithoutCheck(sp, extcodehash(addr)) } case 0x40 { // OP_BLOCKHASH evmGasLeft := chargeGas(evmGasLeft, 20) let blockNumber - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) blockNumber, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, blockhash(blockNumber)) @@ -5265,13 +5209,12 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp, evmGasLeft) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) let memValue := mload(add(MEM_OFFSET_INNER(), offset)) - sp := pushStackItem(sp, memValue, evmGasLeft) + sp := pushStackItemWithoutCheck(sp, memValue) ip := add(ip, 1) } case 0x52 { // OP_MSTORE @@ -5283,11 +5226,10 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) mstore(add(MEM_OFFSET_INNER(), offset), value) ip := add(ip, 1) } @@ -5300,11 +5242,10 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 1)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) mstore8(add(MEM_OFFSET_INNER(), offset), value) ip := add(ip, 1) } @@ -5328,7 +5269,7 @@ object "EVMInterpreter" { let _wasW, _orgV := warmSlot(key, value) } - sp := pushStackItem(sp,value, evmGasLeft) + sp := pushStackItemWithoutCheck(sp,value) ip := add(ip, 1) } case 0x55 { // OP_SSTORE @@ -5388,6 +5329,10 @@ object "EVMInterpreter" { if iszero(eq(nextOpcode, 0x5B)) { revertWithGas(evmGasLeft) } + + // execute JUMPDEST immediately + evmGasLeft := chargeGas(evmGasLeft, 1) + ip := add(ip, 1) } case 0x57 { // OP_JUMPI evmGasLeft := chargeGas(evmGasLeft, 10) @@ -5410,6 +5355,10 @@ object "EVMInterpreter" { if iszero(eq(nextOpcode, 0x5B)) { revertWithGas(evmGasLeft) } + + // execute JUMPDEST immediately + evmGasLeft := chargeGas(evmGasLeft, 1) + ip := add(ip, 1) } case 0x58 { // OP_PC evmGasLeft := chargeGas(evmGasLeft, 2) @@ -5442,7 +5391,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 100) let key - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) key, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, tload(key)) @@ -5470,26 +5419,14 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) + // TODO overflow checks + checkMemOverflowByOffset(add(offset, size), evmGasLeft) + checkMemOverflowByOffset(add(destOffset, size), evmGasLeft) + expandMemory(add(destOffset, size)) expandMemory(add(offset, size)) - let oldSize := mul(mload(MEM_OFFSET()),32) - if gt(add(oldSize,size),MAX_POSSIBLE_MEM()) { - revertWithGas(evmGasLeft) - } - - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(oldSize,MEM_OFFSET_INNER()), i), - shr(248,mload(add(add(offset,MEM_OFFSET_INNER()), i))) - ) - } - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(destOffset,MEM_OFFSET_INNER()), i), - shr(248,mload(add(add(oldSize,MEM_OFFSET_INNER()), i))) - ) - } + mcopy(add(destOffset, MEM_OFFSET_INNER()), add(offset, MEM_OFFSET_INNER()), size) ip := add(ip, 1) } case 0x5F { // OP_PUSH0 @@ -5928,8 +5865,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -5951,8 +5888,8 @@ object "EVMInterpreter" { size, sp := popStackItemWithoutCheck(sp) topic1, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -5973,8 +5910,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -6002,9 +5939,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -6033,8 +5969,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -6115,6 +6051,7 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) + // TODO invalid? ensureAcceptableMemLocation(offset) ensureAcceptableMemLocation(size) evmGasLeft := chargeGas(evmGasLeft,expandMemory(add(offset,size)))