diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index 4a1b2307d..1a1395895 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -75,11 +75,8 @@ function MAX_UINT() -> max_uint { } // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 -function readIP(ip) -> opcode { +function readIP(ip,maxAcceptablePos) -> opcode { // TODO: Why not do this at the beginning once instead of every time? - let bytecodeLen := mload(BYTECODE_OFFSET()) - - let maxAcceptablePos := add(add(BYTECODE_OFFSET(), bytecodeLen), 31) if gt(ip, maxAcceptablePos) { revert(0, 0) } @@ -87,13 +84,11 @@ function readIP(ip) -> opcode { opcode := and(mload(sub(ip, 31)), 0xff) } -function readBytes(start, length) -> value { - let max := add(start, length) - for {} lt(start, max) { start := add(start, 1) } { - let next_byte := readIP(start) - - value := or(shl(8, value), next_byte) +function readBytes(start, maxAcceptablePos,length) -> value { + if gt(add(start,sub(length,1)), maxAcceptablePos) { + revert(0, 0) } + value := shr(mul(8,sub(32,length)),mload(start)) } function dupStackItem(sp, evmGas, position) -> newSp, evmGasLeft { @@ -469,12 +464,6 @@ function checkMemOverflow(location) { } } -// Note, that this function can overflow. It's up to the caller to ensure that it does not. -function memCost(memSizeWords) -> gasCost { - // The first term of the sum is the quadratic cost, the second one the linear one. - gasCost := add(div(mul(memSizeWords, memSizeWords), 512), mul(3, memSizeWords)) -} - // This function can overflow, it is the job of the caller to ensure that it does not. // The argument to this function is the offset into the memory region IN BYTES. function expandMemory(newSize) -> gasCost { @@ -488,12 +477,9 @@ function expandMemory(newSize) -> gasCost { let newSizeInWords := div(add(newSize, 31), 32) if gt(newSizeInWords, oldSizeInWords) { - // TODO: Check this, it feels like there might be a more optimized way - // of doing this cost calculation. - let oldCost := memCost(oldSizeInWords) - let newCost := memCost(newSizeInWords) + let new_minus_old := sub(newSizeInWords, oldSizeInWords) + gasCost := add(mul(3,new_minus_old), div(mul(new_minus_old,add(newSizeInWords,oldSizeInWords)),512)) - gasCost := sub(newCost, oldCost) mstore(MEM_OFFSET(), newSizeInWords) } } @@ -688,6 +674,22 @@ function getNonce(addr) -> nonce { nonce := mload(0) } +function getRawNonce(addr) -> nonce { + mstore8(0, 0x5a) + mstore8(1, 0xa9) + mstore8(2, 0xb6) + mstore8(3, 0xb5) + mstore(4, addr) + + let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) + + if iszero(result) { + revert(0, 0) + } + + nonce := mload(0) +} + function _isEVM(_addr) -> isEVM { // bytes4 selector = ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT.isAccountEVM.selector; (0x8c040477) // function isAccountEVM(address _addr) external view returns (bool); @@ -897,6 +899,46 @@ 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 { + if value { + revert(0, 0) + } + success, frameGasLeft:= _performStaticCall( + is_evm, + gasToPassNew, + addr, + argsOffset, + argsSize, + retOffset, + retSize + ) + } + + if and(is_evm, iszero(isStatic)) { + _pushEVMFrame(gasToPassNew, isStatic) + success := call(gasToPassNew, addr, value, argsOffset, argsSize, 0, 0) + frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + _popEVMFrame() + } + + // zkEVM native + if and(iszero(is_evm), iszero(isStatic)) { + gasToPassNew := _getZkEVMGas(gasToPassNew) + 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 { let gasToPass,addr,value,argsOffset,argsSize,retOffset,retSize @@ -940,44 +982,17 @@ function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp { checkMemOverflow(add(argsOffset, argsSize)) checkMemOverflow(add(retOffset, retSize)) - let frameGasLeft - let success - - if isStatic { - if value { - revert(0, 0) - } - success, frameGasLeft:= _performStaticCall( - _isEVM(addr), - gasToPass, - addr, - argsOffset, - argsSize, - retOffset, - retSize - ) - } - - if and(_isEVM(addr), iszero(isStatic)) { - _pushEVMFrame(gasToPass, isStatic) - success := call(gasToPass, addr, value, argsOffset, argsSize, 0, 0) - frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) - _popEVMFrame() - } - - // zkEVM native - if and(iszero(_isEVM(addr)), iszero(isStatic)) { - gasToPass := _getZkEVMGas(gasToPass) - let zkevmGasBefore := gas() - success := call(gasToPass, addr, value, argsOffset, argsSize, retOffset, retSize) - _saveReturndataAfterZkEVMCall() - let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) - - frameGasLeft := 0 - if gt(gasToPass, gasUsed) { - frameGasLeft := sub(gasToPass, gasUsed) - } - } + let success, frameGasLeft + success, frameGasLeft, gasToPass:= _performCall( + addr, + gasToPass, + value, + argsOffset, + argsSize, + retOffset, + retSize, + isStatic + ) extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) @@ -1112,12 +1127,12 @@ function _performStaticCall( function isAddrEmpty(addr) -> isEmpty { isEmpty := 0 - if and( and( - iszero(balance(addr)), - iszero(extcodesize(addr)) ), - iszero(getNonce(addr)) - ) { - isEmpty := 1 + if iszero(extcodesize(addr)) { // YUL doesn't have short-circuit evaluation + if iszero(balance(addr)) { + if iszero(getRawNonce(addr)) { + isEmpty := 1 + } + } } } @@ -1205,3 +1220,130 @@ function genericCreate(addr, offset, size, sp, value, evmGasLeftOld) -> result, back, sp := popStackItem(sp) mstore(sub(offset, 0x80), back) } + +function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { + evmGasLeft := chargeGas(evmGas, 100) + + let addr, dest, offset, len + addr, sp := popStackItem(oldSp) + dest, sp := popStackItem(sp) + offset, sp := popStackItem(sp) + len, sp := popStackItem(sp) + + // dynamicGas = 3 * minimum_word_size + memory_expansion_cost + address_access_cost + // minimum_word_size = (size + 31) / 32 + + let dynamicGas := add( + mul(3, shr(5, add(len, 31))), + expandMemory(add(dest, len)) + ) + if iszero(warmAddress(addr)) { + dynamicGas := add(dynamicGas, 2500) + } + evmGasLeft := chargeGas(evmGasLeft, dynamicGas) + + let len_32 := shr(5, len) + for {let i := 0} lt(i, len_32) { i := add(i, 1) } { + mstore(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(size_32,i),0) + } + // Gets the code from the addr + pop(_fetchDeployedCode(addr, add(offset, MEM_OFFSET_INNER()), len)) +} + +function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp { + evmGasLeft := chargeGas(evmGas, 32000) + + if isStatic { + revert(0, 0) + } + + let value, offset, size + + value, sp := popStackItem(oldSp) + offset, sp := popStackItem(sp) + size, sp := popStackItem(sp) + + checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size))) + + if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { + revert(0, 0) + } + + if gt(value, balance(address())) { + revert(0, 0) + } + + // dynamicGas = init_code_cost + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost + // minimum_word_size = (size + 31) / 32 + // init_code_cost = 2 * minimum_word_size + // code_deposit_cost = 200 * deployed_code_size + let dynamicGas := add( + shr(4, add(size, 31)), + expandMemory(add(offset, size)) + ) + evmGasLeft := chargeGas(evmGasLeft, dynamicGas) + + let addr := getNewAddress(address()) + + let result + result, evmGasLeft := genericCreate(addr, offset, size, sp, value, evmGasLeft) + + switch result + case 0 { sp := pushStackItem(sp, 0) } + default { sp := pushStackItem(sp, addr) } +} + +function performCreate2(evmGas, oldSp, isStatic) -> evmGasLeft, sp, result, addr{ + evmGasLeft := chargeGas(evmGas, 32000) + + if isStatic { + revert(0, 0) + } + + let value, offset, size, salt + + value, sp := popStackItem(oldSp) + offset, sp := popStackItem(sp) + size, sp := popStackItem(sp) + salt, sp := popStackItem(sp) + + checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size))) + + if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { + revert(0, 0) + } + + if gt(value, balance(address())) { + revert(0, 0) + } + + // dynamicGas = init_code_cost + hash_cost + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost + // minimum_word_size = (size + 31) / 32 + // init_code_cost = 2 * minimum_word_size + // hash_cost = 6 * minimum_word_size + // code_deposit_cost = 200 * deployed_code_size + evmGasLeft := chargeGas(evmGasLeft, add( + expandMemory(add(offset, size)), + shr(2, add(size, 31)) + )) + + { + let hashedBytecode := keccak256(add(MEM_OFFSET_INNER(), offset), size) + mstore8(0, 0xFF) + mstore(0x01, shl(0x60, address())) + mstore(0x15, salt) + mstore(0x35, hashedBytecode) + } + + addr := and( + keccak256(0, 0x55), + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + ) + + result, evmGasLeft := genericCreate(addr, offset, size, sp, value, evmGasLeft) +} diff --git a/system-contracts/contracts/EvmInterpreterLoop.template.yul b/system-contracts/contracts/EvmInterpreterLoop.template.yul index e3fd86274..7bbca259f 100644 --- a/system-contracts/contracts/EvmInterpreterLoop.template.yul +++ b/system-contracts/contracts/EvmInterpreterLoop.template.yul @@ -5,8 +5,10 @@ let sp := sub(STACK_OFFSET(), 32) let ip := add(BYTECODE_OFFSET(), 32) let opcode +let maxAcceptablePos := add(add(BYTECODE_OFFSET(), mload(BYTECODE_OFFSET())), 31) + for { } true { } { - opcode := readIP(ip) + opcode := readIP(ip,maxAcceptablePos) ip := add(ip, 1) @@ -272,6 +274,7 @@ for { } true { } { sp := pushStackItem(sp, sar(shift, value)) } case 0x20 { // OP_KECCAK256 + evmGasLeft := chargeGas(evmGasLeft, 30) let offset, size @@ -285,11 +288,11 @@ for { } true { } { // an expansion, which costs gas. // dynamicGas = 6 * minimum_word_size + memory_expansion_cost // minimum_word_size = (size + 31) / 32 - let minWordSize := shr(5, add(size, 31)) - let dynamicGas := add(mul(6, minWordSize), expandMemory(add(offset, size))) + let dynamicGas := add(mul(6, shr(5, add(size, 31))), expandMemory(add(offset, size))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) sp := pushStackItem(sp, keccak) + } case 0x30 { // OP_ADDRESS evmGasLeft := chargeGas(evmGasLeft, 2) @@ -339,6 +342,7 @@ for { } true { } { sp := pushStackItem(sp, calldatasize()) } case 0x37 { // OP_CALLDATACOPY + evmGasLeft := chargeGas(evmGasLeft, 3) let destOffset, offset, size @@ -352,11 +356,11 @@ for { } true { } { // dynamicGas = 3 * minimum_word_size + memory_expansion_cost // minimum_word_size = (size + 31) / 32 - let minWordSize := shr(5, add(size, 31)) - let dynamicGas := add(mul(3, minWordSize), expandMemory(add(destOffset, size))) + let dynamicGas := add(mul(3, shr(5, add(size, 31))), expandMemory(add(destOffset, size))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) calldatacopy(add(destOffset, MEM_OFFSET_INNER()), offset, size) + } case 0x38 { // OP_CODESIZE evmGasLeft := chargeGas(evmGasLeft, 2) @@ -365,6 +369,7 @@ for { } true { } { sp := pushStackItem(sp, bytecodeLen) } case 0x39 { // OP_CODECOPY + evmGasLeft := chargeGas(evmGasLeft, 3) let dst, offset, len @@ -375,8 +380,7 @@ for { } true { } { // dynamicGas = 3 * minimum_word_size + memory_expansion_cost // minimum_word_size = (size + 31) / 32 - let minWordSize := shr(5, add(len, 31)) - let dynamicGas := add(mul(3, minWordSize), expandMemory(add(dst, len))) + let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(add(dst, len))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) dst := add(dst, MEM_OFFSET_INNER()) @@ -394,6 +398,7 @@ for { } true { } { shr(248, mload(add(offset, i))) ) } + } case 0x3A { // OP_GASPRICE evmGasLeft := chargeGas(evmGasLeft, 2) @@ -418,32 +423,7 @@ for { } true { } { default { sp := pushStackItem(sp, _fetchDeployedCodeLen(addr)) } } case 0x3C { // OP_EXTCODECOPY - evmGasLeft := chargeGas(evmGasLeft, 100) - - let addr, dest, offset, len - addr, sp := popStackItem(sp) - dest, sp := popStackItem(sp) - offset, sp := popStackItem(sp) - len, sp := popStackItem(sp) - - // dynamicGas = 3 * minimum_word_size + memory_expansion_cost + address_access_cost - // minimum_word_size = (size + 31) / 32 - let dynamicGas := add( - mul(3, shr(5, add(len, 31))), - expandMemory(add(dest, len)) - ) - if iszero(warmAddress(addr)) { - dynamicGas := add(dynamicGas, 2500) - } - evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - - // TODO: Check if Zeroing out the memory is necessary - let _lastByte := add(dest, len) - for {let i := dest} lt(i, _lastByte) { i := add(i, 1) } { - mstore8(i, 0) - } - // Gets the code from the addr - pop(_fetchDeployedCode(addr, add(offset, MEM_OFFSET_INNER()), len)) + evmGasLeft, sp := performExtCodeCopy(evmGasLeft, sp) } case 0x3D { // OP_RETURNDATASIZE evmGasLeft := chargeGas(evmGasLeft, 2) @@ -452,6 +432,7 @@ for { } true { } { sp := pushStackItem(sp, rdz) } case 0x3E { // OP_RETURNDATACOPY + evmGasLeft := chargeGas(evmGasLeft, 3) let dest, offset, len @@ -469,11 +450,11 @@ for { } true { } { // minimum_word_size = (size + 31) / 32 // dynamicGas = 3 * minimum_word_size + memory_expansion_cost - let minWordSize := shr(5, add(len, 31)) - let dynamicGas := add(mul(3, minWordSize), expandMemory(add(dest, len))) + let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(add(dest, len))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) copyActivePtrData(add(MEM_OFFSET_INNER(), dest), offset, len) + } case 0x3F { // OP_EXTCODEHASH evmGasLeft := chargeGas(evmGasLeft, 100) @@ -574,6 +555,7 @@ for { } true { } { mstore8(add(MEM_OFFSET_INNER(), offset), value) } case 0x54 { // OP_SLOAD + evmGasLeft := chargeGas(evmGasLeft, 100) let key, value, isWarm @@ -593,8 +575,10 @@ for { } true { } { } sp := pushStackItem(sp,value) + } case 0x55 { // OP_SSTORE + evmGasLeft := chargeGas(evmGasLeft, 100) if isStatic { @@ -631,6 +615,7 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, gasSpent) sstore(key, value) + } // NOTE: We don't currently do full jumpdest validation // (i.e. validating a jumpdest isn't in PUSH data) @@ -644,7 +629,7 @@ for { } true { } { ip := add(add(BYTECODE_OFFSET(), 32), counter) // Check next opcode is JUMPDEST - let nextOpcode := readIP(ip) + let nextOpcode := readIP(ip,maxAcceptablePos) if iszero(eq(nextOpcode, 0x5B)) { revert(0, 0) } @@ -664,7 +649,7 @@ for { } true { } { ip := add(add(BYTECODE_OFFSET(), 32), counter) // Check next opcode is JUMPDEST - let nextOpcode := readIP(ip) + let nextOpcode := readIP(ip,maxAcceptablePos) if iszero(eq(nextOpcode, 0x5B)) { revert(0, 0) } @@ -703,7 +688,7 @@ for { } true { } { case 0x60 { // OP_PUSH1 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,1) + let value := readBytes(ip,maxAcceptablePos,1) sp := pushStackItem(sp, value) ip := add(ip, 1) @@ -711,7 +696,7 @@ for { } true { } { case 0x61 { // OP_PUSH2 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,2) + let value := readBytes(ip,maxAcceptablePos,2) sp := pushStackItem(sp, value) ip := add(ip, 2) @@ -719,7 +704,7 @@ for { } true { } { case 0x62 { // OP_PUSH3 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,3) + let value := readBytes(ip,maxAcceptablePos,3) sp := pushStackItem(sp, value) ip := add(ip, 3) @@ -727,7 +712,7 @@ for { } true { } { case 0x63 { // OP_PUSH4 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,4) + let value := readBytes(ip,maxAcceptablePos,4) sp := pushStackItem(sp, value) ip := add(ip, 4) @@ -735,7 +720,7 @@ for { } true { } { case 0x64 { // OP_PUSH5 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,5) + let value := readBytes(ip,maxAcceptablePos,5) sp := pushStackItem(sp, value) ip := add(ip, 5) @@ -743,7 +728,7 @@ for { } true { } { case 0x65 { // OP_PUSH6 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,6) + let value := readBytes(ip,maxAcceptablePos,6) sp := pushStackItem(sp, value) ip := add(ip, 6) @@ -751,7 +736,7 @@ for { } true { } { case 0x66 { // OP_PUSH7 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,7) + let value := readBytes(ip,maxAcceptablePos,7) sp := pushStackItem(sp, value) ip := add(ip, 7) @@ -759,7 +744,7 @@ for { } true { } { case 0x67 { // OP_PUSH8 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,8) + let value := readBytes(ip,maxAcceptablePos,8) sp := pushStackItem(sp, value) ip := add(ip, 8) @@ -767,7 +752,7 @@ for { } true { } { case 0x68 { // OP_PUSH9 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,9) + let value := readBytes(ip,maxAcceptablePos,9) sp := pushStackItem(sp, value) ip := add(ip, 9) @@ -775,7 +760,7 @@ for { } true { } { case 0x69 { // OP_PUSH10 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,10) + let value := readBytes(ip,maxAcceptablePos,10) sp := pushStackItem(sp, value) ip := add(ip, 10) @@ -783,7 +768,7 @@ for { } true { } { case 0x6A { // OP_PUSH11 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,11) + let value := readBytes(ip,maxAcceptablePos,11) sp := pushStackItem(sp, value) ip := add(ip, 11) @@ -791,7 +776,7 @@ for { } true { } { case 0x6B { // OP_PUSH12 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,12) + let value := readBytes(ip,maxAcceptablePos,12) sp := pushStackItem(sp, value) ip := add(ip, 12) @@ -799,7 +784,7 @@ for { } true { } { case 0x6C { // OP_PUSH13 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,13) + let value := readBytes(ip,maxAcceptablePos,13) sp := pushStackItem(sp, value) ip := add(ip, 13) @@ -807,7 +792,7 @@ for { } true { } { case 0x6D { // OP_PUSH14 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,14) + let value := readBytes(ip,maxAcceptablePos,14) sp := pushStackItem(sp, value) ip := add(ip, 14) @@ -815,7 +800,7 @@ for { } true { } { case 0x6E { // OP_PUSH15 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,15) + let value := readBytes(ip,maxAcceptablePos,15) sp := pushStackItem(sp, value) ip := add(ip, 15) @@ -823,7 +808,7 @@ for { } true { } { case 0x6F { // OP_PUSH16 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,16) + let value := readBytes(ip,maxAcceptablePos,16) sp := pushStackItem(sp, value) ip := add(ip, 16) @@ -831,7 +816,7 @@ for { } true { } { case 0x70 { // OP_PUSH17 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,17) + let value := readBytes(ip,maxAcceptablePos,17) sp := pushStackItem(sp, value) ip := add(ip, 17) @@ -839,7 +824,7 @@ for { } true { } { case 0x71 { // OP_PUSH18 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,18) + let value := readBytes(ip,maxAcceptablePos,18) sp := pushStackItem(sp, value) ip := add(ip, 18) @@ -847,7 +832,7 @@ for { } true { } { case 0x72 { // OP_PUSH19 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,19) + let value := readBytes(ip,maxAcceptablePos,19) sp := pushStackItem(sp, value) ip := add(ip, 19) @@ -855,7 +840,7 @@ for { } true { } { case 0x73 { // OP_PUSH20 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,20) + let value := readBytes(ip,maxAcceptablePos,20) sp := pushStackItem(sp, value) ip := add(ip, 20) @@ -863,7 +848,7 @@ for { } true { } { case 0x74 { // OP_PUSH21 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,21) + let value := readBytes(ip,maxAcceptablePos,21) sp := pushStackItem(sp, value) ip := add(ip, 21) @@ -871,7 +856,7 @@ for { } true { } { case 0x75 { // OP_PUSH22 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,22) + let value := readBytes(ip,maxAcceptablePos,22) sp := pushStackItem(sp, value) ip := add(ip, 22) @@ -879,7 +864,7 @@ for { } true { } { case 0x76 { // OP_PUSH23 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,23) + let value := readBytes(ip,maxAcceptablePos,23) sp := pushStackItem(sp, value) ip := add(ip, 23) @@ -887,7 +872,7 @@ for { } true { } { case 0x77 { // OP_PUSH24 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,24) + let value := readBytes(ip,maxAcceptablePos,24) sp := pushStackItem(sp, value) ip := add(ip, 24) @@ -895,7 +880,7 @@ for { } true { } { case 0x78 { // OP_PUSH25 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,25) + let value := readBytes(ip,maxAcceptablePos,25) sp := pushStackItem(sp, value) ip := add(ip, 25) @@ -903,7 +888,7 @@ for { } true { } { case 0x79 { // OP_PUSH26 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,26) + let value := readBytes(ip,maxAcceptablePos,26) sp := pushStackItem(sp, value) ip := add(ip, 26) @@ -911,7 +896,7 @@ for { } true { } { case 0x7A { // OP_PUSH27 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,27) + let value := readBytes(ip,maxAcceptablePos,27) sp := pushStackItem(sp, value) ip := add(ip, 27) @@ -919,7 +904,7 @@ for { } true { } { case 0x7B { // OP_PUSH28 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,28) + let value := readBytes(ip,maxAcceptablePos,28) sp := pushStackItem(sp, value) ip := add(ip, 28) @@ -927,7 +912,7 @@ for { } true { } { case 0x7C { // OP_PUSH29 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,29) + let value := readBytes(ip,maxAcceptablePos,29) sp := pushStackItem(sp, value) ip := add(ip, 29) @@ -935,7 +920,7 @@ for { } true { } { case 0x7D { // OP_PUSH30 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,30) + let value := readBytes(ip,maxAcceptablePos,30) sp := pushStackItem(sp, value) ip := add(ip, 30) @@ -943,7 +928,7 @@ for { } true { } { case 0x7E { // OP_PUSH31 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,31) + let value := readBytes(ip,maxAcceptablePos,31) sp := pushStackItem(sp, value) ip := add(ip, 31) @@ -951,7 +936,7 @@ for { } true { } { case 0x7F { // OP_PUSH32 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,32) + let value := readBytes(ip,maxAcceptablePos,32) sp := pushStackItem(sp, value) ip := add(ip, 32) @@ -1098,11 +1083,9 @@ for { } true { } { revert(0, 0) } - let offset, size, topic1, topic2 + let offset, size offset, sp := popStackItem(sp) size, sp := popStackItem(sp) - topic1, sp := popStackItem(sp) - topic2, sp := popStackItem(sp) checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size)) @@ -1111,7 +1094,12 @@ for { } true { } { dynamicGas := add(dynamicGas, 750) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - log2(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2) + { + let topic1, topic2 + topic1, sp := popStackItem(sp) + topic2, sp := popStackItem(sp) + log2(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2) + } } case 0xA3 { // OP_LOG3 evmGasLeft := chargeGas(evmGasLeft, 375) @@ -1137,7 +1125,7 @@ for { } true { } { topic2, sp := popStackItem(sp) topic3, sp := popStackItem(sp) log3(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2, topic3) - } + } } case 0xA4 { // OP_LOG4 evmGasLeft := chargeGas(evmGasLeft, 375) @@ -1164,50 +1152,10 @@ for { } true { } { topic3, sp := popStackItem(sp) topic4, sp := popStackItem(sp) log4(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2, topic3, topic4) - } - + } } case 0xF0 { // OP_CREATE - evmGasLeft := chargeGas(evmGasLeft, 32000) - - if isStatic { - revert(0, 0) - } - - let value, offset, size - - value, sp := popStackItem(sp) - offset, sp := popStackItem(sp) - size, sp := popStackItem(sp) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size))) - - if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { - revert(0, 0) - } - - if gt(value, balance(address())) { - revert(0, 0) - } - - // dynamicGas = init_code_cost + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost - // minimum_word_size = (size + 31) / 32 - // init_code_cost = 2 * minimum_word_size - // code_deposit_cost = 200 * deployed_code_size - let dynamicGas := add( - shr(4, add(size, 31)), - expandMemory(add(offset, size)) - ) - evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - - let addr := getNewAddress(address()) - - let result - result, evmGasLeft := genericCreate(addr, offset, size, sp, value, evmGasLeft) //code_deposit_cost missing - - switch result - case 0 { sp := pushStackItem(sp, 0) } - default { sp := pushStackItem(sp, addr) } + evmGasLeft, sp := performCreate(evmGasLeft, sp, isStatic) } case 0xF1 { // OP_CALL evmGasLeft := chargeGas(evmGasLeft, 100) @@ -1243,58 +1191,11 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, gasUsed) } case 0xF5 { // OP_CREATE2 - evmGasLeft := chargeGas(evmGasLeft, 32000) - - if isStatic { - revert(0, 0) - } - - let value, offset, size, salt - - value, sp := popStackItem(sp) - offset, sp := popStackItem(sp) - size, sp := popStackItem(sp) - salt, sp := popStackItem(sp) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size))) - - if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { - revert(0, 0) - } - - if gt(value, balance(address())) { - revert(0, 0) - } - - // dynamicGas = init_code_cost + hash_cost + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost - // minimum_word_size = (size + 31) / 32 - // init_code_cost = 2 * minimum_word_size - // hash_cost = 6 * minimum_word_size - // code_deposit_cost = 200 * deployed_code_size - evmGasLeft := chargeGas(evmGasLeft, add( - expandMemory(add(offset, size)), - shr(2, add(size, 31)) - )) - - { - let hashedBytecode := keccak256(add(MEM_OFFSET_INNER(), offset), size) - mstore8(0, 0xFF) - mstore(0x01, shl(0x60, address())) - mstore(0x15, salt) - mstore(0x35, hashedBytecode) - } - - let addr := and( - keccak256(0, 0x55), - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - ) - - let result - result, evmGasLeft := genericCreate(addr, offset, size, sp, value, evmGasLeft) //code_deposit_cost missing - + let result, addr + evmGasLeft, sp, result, addr := performCreate2(evmGasLeft, sp, isStatic) switch result - case 0 { sp := pushStackItem(sp, 0) } - default { sp := pushStackItem(sp, addr) } + case 0 { sp := pushStackItem(sp, 0) } + default { sp := pushStackItem(sp, addr) } } case 0xFA { // OP_STATICCALL evmGasLeft := chargeGas(evmGasLeft, 100) diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index eadbd8aca..28b920add 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -149,11 +149,8 @@ object "EVMInterpreter" { } // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 - function readIP(ip) -> opcode { + function readIP(ip,maxAcceptablePos) -> opcode { // TODO: Why not do this at the beginning once instead of every time? - let bytecodeLen := mload(BYTECODE_OFFSET()) - - let maxAcceptablePos := add(add(BYTECODE_OFFSET(), bytecodeLen), 31) if gt(ip, maxAcceptablePos) { revert(0, 0) } @@ -161,13 +158,11 @@ object "EVMInterpreter" { opcode := and(mload(sub(ip, 31)), 0xff) } - function readBytes(start, length) -> value { - let max := add(start, length) - for {} lt(start, max) { start := add(start, 1) } { - let next_byte := readIP(start) - - value := or(shl(8, value), next_byte) + function readBytes(start, maxAcceptablePos,length) -> value { + if gt(add(start,sub(length,1)), maxAcceptablePos) { + revert(0, 0) } + value := shr(mul(8,sub(32,length)),mload(start)) } function dupStackItem(sp, evmGas, position) -> newSp, evmGasLeft { @@ -543,12 +538,6 @@ object "EVMInterpreter" { } } - // Note, that this function can overflow. It's up to the caller to ensure that it does not. - function memCost(memSizeWords) -> gasCost { - // The first term of the sum is the quadratic cost, the second one the linear one. - gasCost := add(div(mul(memSizeWords, memSizeWords), 512), mul(3, memSizeWords)) - } - // This function can overflow, it is the job of the caller to ensure that it does not. // The argument to this function is the offset into the memory region IN BYTES. function expandMemory(newSize) -> gasCost { @@ -562,12 +551,9 @@ object "EVMInterpreter" { let newSizeInWords := div(add(newSize, 31), 32) if gt(newSizeInWords, oldSizeInWords) { - // TODO: Check this, it feels like there might be a more optimized way - // of doing this cost calculation. - let oldCost := memCost(oldSizeInWords) - let newCost := memCost(newSizeInWords) + let new_minus_old := sub(newSizeInWords, oldSizeInWords) + gasCost := add(mul(3,new_minus_old), div(mul(new_minus_old,add(newSizeInWords,oldSizeInWords)),512)) - gasCost := sub(newCost, oldCost) mstore(MEM_OFFSET(), newSizeInWords) } } @@ -762,6 +748,22 @@ object "EVMInterpreter" { nonce := mload(0) } + function getRawNonce(addr) -> nonce { + mstore8(0, 0x5a) + mstore8(1, 0xa9) + mstore8(2, 0xb6) + mstore8(3, 0xb5) + mstore(4, addr) + + let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) + + if iszero(result) { + revert(0, 0) + } + + nonce := mload(0) + } + function _isEVM(_addr) -> isEVM { // bytes4 selector = ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT.isAccountEVM.selector; (0x8c040477) // function isAccountEVM(address _addr) external view returns (bool); @@ -971,6 +973,46 @@ object "EVMInterpreter" { } } + function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize,isStatic) -> success, frameGasLeft, gasToPassNew{ + gasToPassNew := gasToPass + let is_evm := _isEVM(addr) + if isStatic { + if value { + revert(0, 0) + } + success, frameGasLeft:= _performStaticCall( + is_evm, + gasToPassNew, + addr, + argsOffset, + argsSize, + retOffset, + retSize + ) + } + + if and(is_evm, iszero(isStatic)) { + _pushEVMFrame(gasToPassNew, isStatic) + success := call(gasToPassNew, addr, value, argsOffset, argsSize, 0, 0) + frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + _popEVMFrame() + } + + // zkEVM native + if and(iszero(is_evm), iszero(isStatic)) { + gasToPassNew := _getZkEVMGas(gasToPassNew) + 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 { let gasToPass,addr,value,argsOffset,argsSize,retOffset,retSize @@ -1014,44 +1056,17 @@ object "EVMInterpreter" { checkMemOverflow(add(argsOffset, argsSize)) checkMemOverflow(add(retOffset, retSize)) - let frameGasLeft - let success - - if isStatic { - if value { - revert(0, 0) - } - success, frameGasLeft:= _performStaticCall( - _isEVM(addr), - gasToPass, - addr, - argsOffset, - argsSize, - retOffset, - retSize - ) - } - - if and(_isEVM(addr), iszero(isStatic)) { - _pushEVMFrame(gasToPass, isStatic) - success := call(gasToPass, addr, value, argsOffset, argsSize, 0, 0) - frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) - _popEVMFrame() - } - - // zkEVM native - if and(iszero(_isEVM(addr)), iszero(isStatic)) { - gasToPass := _getZkEVMGas(gasToPass) - let zkevmGasBefore := gas() - success := call(gasToPass, addr, value, argsOffset, argsSize, retOffset, retSize) - _saveReturndataAfterZkEVMCall() - let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) - - frameGasLeft := 0 - if gt(gasToPass, gasUsed) { - frameGasLeft := sub(gasToPass, gasUsed) - } - } + let success, frameGasLeft + success, frameGasLeft, gasToPass:= _performCall( + addr, + gasToPass, + value, + argsOffset, + argsSize, + retOffset, + retSize, + isStatic + ) extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) @@ -1186,12 +1201,12 @@ object "EVMInterpreter" { function isAddrEmpty(addr) -> isEmpty { isEmpty := 0 - if and( and( - iszero(balance(addr)), - iszero(extcodesize(addr)) ), - iszero(getNonce(addr)) - ) { - isEmpty := 1 + if iszero(extcodesize(addr)) { // YUL doesn't have short-circuit evaluation + if iszero(balance(addr)) { + if iszero(getRawNonce(addr)) { + isEmpty := 1 + } + } } } @@ -1280,6 +1295,133 @@ object "EVMInterpreter" { mstore(sub(offset, 0x80), back) } + function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { + evmGasLeft := chargeGas(evmGas, 100) + + let addr, dest, offset, len + addr, sp := popStackItem(oldSp) + dest, sp := popStackItem(sp) + offset, sp := popStackItem(sp) + len, sp := popStackItem(sp) + + // dynamicGas = 3 * minimum_word_size + memory_expansion_cost + address_access_cost + // minimum_word_size = (size + 31) / 32 + + let dynamicGas := add( + mul(3, shr(5, add(len, 31))), + expandMemory(add(dest, len)) + ) + if iszero(warmAddress(addr)) { + dynamicGas := add(dynamicGas, 2500) + } + evmGasLeft := chargeGas(evmGasLeft, dynamicGas) + + let len_32 := shr(5, len) + for {let i := 0} lt(i, len_32) { i := add(i, 1) } { + mstore(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(size_32,i),0) + } + // Gets the code from the addr + pop(_fetchDeployedCode(addr, add(offset, MEM_OFFSET_INNER()), len)) + } + + function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp { + evmGasLeft := chargeGas(evmGas, 32000) + + if isStatic { + revert(0, 0) + } + + let value, offset, size + + value, sp := popStackItem(oldSp) + offset, sp := popStackItem(sp) + size, sp := popStackItem(sp) + + checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size))) + + if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { + revert(0, 0) + } + + if gt(value, balance(address())) { + revert(0, 0) + } + + // dynamicGas = init_code_cost + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost + // minimum_word_size = (size + 31) / 32 + // init_code_cost = 2 * minimum_word_size + // code_deposit_cost = 200 * deployed_code_size + let dynamicGas := add( + shr(4, add(size, 31)), + expandMemory(add(offset, size)) + ) + evmGasLeft := chargeGas(evmGasLeft, dynamicGas) + + let addr := getNewAddress(address()) + + let result + result, evmGasLeft := genericCreate(addr, offset, size, sp, value, evmGasLeft) + + switch result + case 0 { sp := pushStackItem(sp, 0) } + default { sp := pushStackItem(sp, addr) } + } + + function performCreate2(evmGas, oldSp, isStatic) -> evmGasLeft, sp, result, addr{ + evmGasLeft := chargeGas(evmGas, 32000) + + if isStatic { + revert(0, 0) + } + + let value, offset, size, salt + + value, sp := popStackItem(oldSp) + offset, sp := popStackItem(sp) + size, sp := popStackItem(sp) + salt, sp := popStackItem(sp) + + checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size))) + + if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { + revert(0, 0) + } + + if gt(value, balance(address())) { + revert(0, 0) + } + + // dynamicGas = init_code_cost + hash_cost + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost + // minimum_word_size = (size + 31) / 32 + // init_code_cost = 2 * minimum_word_size + // hash_cost = 6 * minimum_word_size + // code_deposit_cost = 200 * deployed_code_size + evmGasLeft := chargeGas(evmGasLeft, add( + expandMemory(add(offset, size)), + shr(2, add(size, 31)) + )) + + { + let hashedBytecode := keccak256(add(MEM_OFFSET_INNER(), offset), size) + mstore8(0, 0xFF) + mstore(0x01, shl(0x60, address())) + mstore(0x15, salt) + mstore(0x35, hashedBytecode) + } + + addr := and( + keccak256(0, 0x55), + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + ) + + result, evmGasLeft := genericCreate(addr, offset, size, sp, value, evmGasLeft) + } + function simulate( isCallerEVM, @@ -1297,8 +1439,10 @@ object "EVMInterpreter" { let ip := add(BYTECODE_OFFSET(), 32) let opcode + let maxAcceptablePos := add(add(BYTECODE_OFFSET(), mload(BYTECODE_OFFSET())), 31) + for { } true { } { - opcode := readIP(ip) + opcode := readIP(ip,maxAcceptablePos) ip := add(ip, 1) @@ -1564,6 +1708,7 @@ object "EVMInterpreter" { sp := pushStackItem(sp, sar(shift, value)) } case 0x20 { // OP_KECCAK256 + evmGasLeft := chargeGas(evmGasLeft, 30) let offset, size @@ -1577,11 +1722,11 @@ object "EVMInterpreter" { // an expansion, which costs gas. // dynamicGas = 6 * minimum_word_size + memory_expansion_cost // minimum_word_size = (size + 31) / 32 - let minWordSize := shr(5, add(size, 31)) - let dynamicGas := add(mul(6, minWordSize), expandMemory(add(offset, size))) + let dynamicGas := add(mul(6, shr(5, add(size, 31))), expandMemory(add(offset, size))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) sp := pushStackItem(sp, keccak) + } case 0x30 { // OP_ADDRESS evmGasLeft := chargeGas(evmGasLeft, 2) @@ -1631,6 +1776,7 @@ object "EVMInterpreter" { sp := pushStackItem(sp, calldatasize()) } case 0x37 { // OP_CALLDATACOPY + evmGasLeft := chargeGas(evmGasLeft, 3) let destOffset, offset, size @@ -1644,11 +1790,11 @@ object "EVMInterpreter" { // dynamicGas = 3 * minimum_word_size + memory_expansion_cost // minimum_word_size = (size + 31) / 32 - let minWordSize := shr(5, add(size, 31)) - let dynamicGas := add(mul(3, minWordSize), expandMemory(add(destOffset, size))) + let dynamicGas := add(mul(3, shr(5, add(size, 31))), expandMemory(add(destOffset, size))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) calldatacopy(add(destOffset, MEM_OFFSET_INNER()), offset, size) + } case 0x38 { // OP_CODESIZE evmGasLeft := chargeGas(evmGasLeft, 2) @@ -1657,6 +1803,7 @@ object "EVMInterpreter" { sp := pushStackItem(sp, bytecodeLen) } case 0x39 { // OP_CODECOPY + evmGasLeft := chargeGas(evmGasLeft, 3) let dst, offset, len @@ -1667,8 +1814,7 @@ object "EVMInterpreter" { // dynamicGas = 3 * minimum_word_size + memory_expansion_cost // minimum_word_size = (size + 31) / 32 - let minWordSize := shr(5, add(len, 31)) - let dynamicGas := add(mul(3, minWordSize), expandMemory(add(dst, len))) + let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(add(dst, len))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) dst := add(dst, MEM_OFFSET_INNER()) @@ -1686,6 +1832,7 @@ object "EVMInterpreter" { shr(248, mload(add(offset, i))) ) } + } case 0x3A { // OP_GASPRICE evmGasLeft := chargeGas(evmGasLeft, 2) @@ -1710,32 +1857,7 @@ object "EVMInterpreter" { default { sp := pushStackItem(sp, _fetchDeployedCodeLen(addr)) } } case 0x3C { // OP_EXTCODECOPY - evmGasLeft := chargeGas(evmGasLeft, 100) - - let addr, dest, offset, len - addr, sp := popStackItem(sp) - dest, sp := popStackItem(sp) - offset, sp := popStackItem(sp) - len, sp := popStackItem(sp) - - // dynamicGas = 3 * minimum_word_size + memory_expansion_cost + address_access_cost - // minimum_word_size = (size + 31) / 32 - let dynamicGas := add( - mul(3, shr(5, add(len, 31))), - expandMemory(add(dest, len)) - ) - if iszero(warmAddress(addr)) { - dynamicGas := add(dynamicGas, 2500) - } - evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - - // TODO: Check if Zeroing out the memory is necessary - let _lastByte := add(dest, len) - for {let i := dest} lt(i, _lastByte) { i := add(i, 1) } { - mstore8(i, 0) - } - // Gets the code from the addr - pop(_fetchDeployedCode(addr, add(offset, MEM_OFFSET_INNER()), len)) + evmGasLeft, sp := performExtCodeCopy(evmGasLeft, sp) } case 0x3D { // OP_RETURNDATASIZE evmGasLeft := chargeGas(evmGasLeft, 2) @@ -1744,6 +1866,7 @@ object "EVMInterpreter" { sp := pushStackItem(sp, rdz) } case 0x3E { // OP_RETURNDATACOPY + evmGasLeft := chargeGas(evmGasLeft, 3) let dest, offset, len @@ -1761,11 +1884,11 @@ object "EVMInterpreter" { // minimum_word_size = (size + 31) / 32 // dynamicGas = 3 * minimum_word_size + memory_expansion_cost - let minWordSize := shr(5, add(len, 31)) - let dynamicGas := add(mul(3, minWordSize), expandMemory(add(dest, len))) + let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(add(dest, len))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) copyActivePtrData(add(MEM_OFFSET_INNER(), dest), offset, len) + } case 0x3F { // OP_EXTCODEHASH evmGasLeft := chargeGas(evmGasLeft, 100) @@ -1866,6 +1989,7 @@ object "EVMInterpreter" { mstore8(add(MEM_OFFSET_INNER(), offset), value) } case 0x54 { // OP_SLOAD + evmGasLeft := chargeGas(evmGasLeft, 100) let key, value, isWarm @@ -1885,8 +2009,10 @@ object "EVMInterpreter" { } sp := pushStackItem(sp,value) + } case 0x55 { // OP_SSTORE + evmGasLeft := chargeGas(evmGasLeft, 100) if isStatic { @@ -1923,6 +2049,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, gasSpent) sstore(key, value) + } // NOTE: We don't currently do full jumpdest validation // (i.e. validating a jumpdest isn't in PUSH data) @@ -1936,7 +2063,7 @@ object "EVMInterpreter" { ip := add(add(BYTECODE_OFFSET(), 32), counter) // Check next opcode is JUMPDEST - let nextOpcode := readIP(ip) + let nextOpcode := readIP(ip,maxAcceptablePos) if iszero(eq(nextOpcode, 0x5B)) { revert(0, 0) } @@ -1956,7 +2083,7 @@ object "EVMInterpreter" { ip := add(add(BYTECODE_OFFSET(), 32), counter) // Check next opcode is JUMPDEST - let nextOpcode := readIP(ip) + let nextOpcode := readIP(ip,maxAcceptablePos) if iszero(eq(nextOpcode, 0x5B)) { revert(0, 0) } @@ -1995,7 +2122,7 @@ object "EVMInterpreter" { case 0x60 { // OP_PUSH1 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,1) + let value := readBytes(ip,maxAcceptablePos,1) sp := pushStackItem(sp, value) ip := add(ip, 1) @@ -2003,7 +2130,7 @@ object "EVMInterpreter" { case 0x61 { // OP_PUSH2 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,2) + let value := readBytes(ip,maxAcceptablePos,2) sp := pushStackItem(sp, value) ip := add(ip, 2) @@ -2011,7 +2138,7 @@ object "EVMInterpreter" { case 0x62 { // OP_PUSH3 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,3) + let value := readBytes(ip,maxAcceptablePos,3) sp := pushStackItem(sp, value) ip := add(ip, 3) @@ -2019,7 +2146,7 @@ object "EVMInterpreter" { case 0x63 { // OP_PUSH4 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,4) + let value := readBytes(ip,maxAcceptablePos,4) sp := pushStackItem(sp, value) ip := add(ip, 4) @@ -2027,7 +2154,7 @@ object "EVMInterpreter" { case 0x64 { // OP_PUSH5 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,5) + let value := readBytes(ip,maxAcceptablePos,5) sp := pushStackItem(sp, value) ip := add(ip, 5) @@ -2035,7 +2162,7 @@ object "EVMInterpreter" { case 0x65 { // OP_PUSH6 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,6) + let value := readBytes(ip,maxAcceptablePos,6) sp := pushStackItem(sp, value) ip := add(ip, 6) @@ -2043,7 +2170,7 @@ object "EVMInterpreter" { case 0x66 { // OP_PUSH7 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,7) + let value := readBytes(ip,maxAcceptablePos,7) sp := pushStackItem(sp, value) ip := add(ip, 7) @@ -2051,7 +2178,7 @@ object "EVMInterpreter" { case 0x67 { // OP_PUSH8 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,8) + let value := readBytes(ip,maxAcceptablePos,8) sp := pushStackItem(sp, value) ip := add(ip, 8) @@ -2059,7 +2186,7 @@ object "EVMInterpreter" { case 0x68 { // OP_PUSH9 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,9) + let value := readBytes(ip,maxAcceptablePos,9) sp := pushStackItem(sp, value) ip := add(ip, 9) @@ -2067,7 +2194,7 @@ object "EVMInterpreter" { case 0x69 { // OP_PUSH10 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,10) + let value := readBytes(ip,maxAcceptablePos,10) sp := pushStackItem(sp, value) ip := add(ip, 10) @@ -2075,7 +2202,7 @@ object "EVMInterpreter" { case 0x6A { // OP_PUSH11 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,11) + let value := readBytes(ip,maxAcceptablePos,11) sp := pushStackItem(sp, value) ip := add(ip, 11) @@ -2083,7 +2210,7 @@ object "EVMInterpreter" { case 0x6B { // OP_PUSH12 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,12) + let value := readBytes(ip,maxAcceptablePos,12) sp := pushStackItem(sp, value) ip := add(ip, 12) @@ -2091,7 +2218,7 @@ object "EVMInterpreter" { case 0x6C { // OP_PUSH13 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,13) + let value := readBytes(ip,maxAcceptablePos,13) sp := pushStackItem(sp, value) ip := add(ip, 13) @@ -2099,7 +2226,7 @@ object "EVMInterpreter" { case 0x6D { // OP_PUSH14 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,14) + let value := readBytes(ip,maxAcceptablePos,14) sp := pushStackItem(sp, value) ip := add(ip, 14) @@ -2107,7 +2234,7 @@ object "EVMInterpreter" { case 0x6E { // OP_PUSH15 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,15) + let value := readBytes(ip,maxAcceptablePos,15) sp := pushStackItem(sp, value) ip := add(ip, 15) @@ -2115,7 +2242,7 @@ object "EVMInterpreter" { case 0x6F { // OP_PUSH16 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,16) + let value := readBytes(ip,maxAcceptablePos,16) sp := pushStackItem(sp, value) ip := add(ip, 16) @@ -2123,7 +2250,7 @@ object "EVMInterpreter" { case 0x70 { // OP_PUSH17 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,17) + let value := readBytes(ip,maxAcceptablePos,17) sp := pushStackItem(sp, value) ip := add(ip, 17) @@ -2131,7 +2258,7 @@ object "EVMInterpreter" { case 0x71 { // OP_PUSH18 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,18) + let value := readBytes(ip,maxAcceptablePos,18) sp := pushStackItem(sp, value) ip := add(ip, 18) @@ -2139,7 +2266,7 @@ object "EVMInterpreter" { case 0x72 { // OP_PUSH19 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,19) + let value := readBytes(ip,maxAcceptablePos,19) sp := pushStackItem(sp, value) ip := add(ip, 19) @@ -2147,7 +2274,7 @@ object "EVMInterpreter" { case 0x73 { // OP_PUSH20 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,20) + let value := readBytes(ip,maxAcceptablePos,20) sp := pushStackItem(sp, value) ip := add(ip, 20) @@ -2155,7 +2282,7 @@ object "EVMInterpreter" { case 0x74 { // OP_PUSH21 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,21) + let value := readBytes(ip,maxAcceptablePos,21) sp := pushStackItem(sp, value) ip := add(ip, 21) @@ -2163,7 +2290,7 @@ object "EVMInterpreter" { case 0x75 { // OP_PUSH22 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,22) + let value := readBytes(ip,maxAcceptablePos,22) sp := pushStackItem(sp, value) ip := add(ip, 22) @@ -2171,7 +2298,7 @@ object "EVMInterpreter" { case 0x76 { // OP_PUSH23 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,23) + let value := readBytes(ip,maxAcceptablePos,23) sp := pushStackItem(sp, value) ip := add(ip, 23) @@ -2179,7 +2306,7 @@ object "EVMInterpreter" { case 0x77 { // OP_PUSH24 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,24) + let value := readBytes(ip,maxAcceptablePos,24) sp := pushStackItem(sp, value) ip := add(ip, 24) @@ -2187,7 +2314,7 @@ object "EVMInterpreter" { case 0x78 { // OP_PUSH25 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,25) + let value := readBytes(ip,maxAcceptablePos,25) sp := pushStackItem(sp, value) ip := add(ip, 25) @@ -2195,7 +2322,7 @@ object "EVMInterpreter" { case 0x79 { // OP_PUSH26 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,26) + let value := readBytes(ip,maxAcceptablePos,26) sp := pushStackItem(sp, value) ip := add(ip, 26) @@ -2203,7 +2330,7 @@ object "EVMInterpreter" { case 0x7A { // OP_PUSH27 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,27) + let value := readBytes(ip,maxAcceptablePos,27) sp := pushStackItem(sp, value) ip := add(ip, 27) @@ -2211,7 +2338,7 @@ object "EVMInterpreter" { case 0x7B { // OP_PUSH28 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,28) + let value := readBytes(ip,maxAcceptablePos,28) sp := pushStackItem(sp, value) ip := add(ip, 28) @@ -2219,7 +2346,7 @@ object "EVMInterpreter" { case 0x7C { // OP_PUSH29 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,29) + let value := readBytes(ip,maxAcceptablePos,29) sp := pushStackItem(sp, value) ip := add(ip, 29) @@ -2227,7 +2354,7 @@ object "EVMInterpreter" { case 0x7D { // OP_PUSH30 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,30) + let value := readBytes(ip,maxAcceptablePos,30) sp := pushStackItem(sp, value) ip := add(ip, 30) @@ -2235,7 +2362,7 @@ object "EVMInterpreter" { case 0x7E { // OP_PUSH31 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,31) + let value := readBytes(ip,maxAcceptablePos,31) sp := pushStackItem(sp, value) ip := add(ip, 31) @@ -2243,7 +2370,7 @@ object "EVMInterpreter" { case 0x7F { // OP_PUSH32 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,32) + let value := readBytes(ip,maxAcceptablePos,32) sp := pushStackItem(sp, value) ip := add(ip, 32) @@ -2390,11 +2517,9 @@ object "EVMInterpreter" { revert(0, 0) } - let offset, size, topic1, topic2 + let offset, size offset, sp := popStackItem(sp) size, sp := popStackItem(sp) - topic1, sp := popStackItem(sp) - topic2, sp := popStackItem(sp) checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size)) @@ -2403,7 +2528,12 @@ object "EVMInterpreter" { dynamicGas := add(dynamicGas, 750) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - log2(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2) + { + let topic1, topic2 + topic1, sp := popStackItem(sp) + topic2, sp := popStackItem(sp) + log2(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2) + } } case 0xA3 { // OP_LOG3 evmGasLeft := chargeGas(evmGasLeft, 375) @@ -2429,7 +2559,7 @@ object "EVMInterpreter" { topic2, sp := popStackItem(sp) topic3, sp := popStackItem(sp) log3(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2, topic3) - } + } } case 0xA4 { // OP_LOG4 evmGasLeft := chargeGas(evmGasLeft, 375) @@ -2456,50 +2586,10 @@ object "EVMInterpreter" { topic3, sp := popStackItem(sp) topic4, sp := popStackItem(sp) log4(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2, topic3, topic4) - } - + } } case 0xF0 { // OP_CREATE - evmGasLeft := chargeGas(evmGasLeft, 32000) - - if isStatic { - revert(0, 0) - } - - let value, offset, size - - value, sp := popStackItem(sp) - offset, sp := popStackItem(sp) - size, sp := popStackItem(sp) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size))) - - if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { - revert(0, 0) - } - - if gt(value, balance(address())) { - revert(0, 0) - } - - // dynamicGas = init_code_cost + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost - // minimum_word_size = (size + 31) / 32 - // init_code_cost = 2 * minimum_word_size - // code_deposit_cost = 200 * deployed_code_size - let dynamicGas := add( - shr(4, add(size, 31)), - expandMemory(add(offset, size)) - ) - evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - - let addr := getNewAddress(address()) - - let result - result, evmGasLeft := genericCreate(addr, offset, size, sp, value, evmGasLeft) //code_deposit_cost missing - - switch result - case 0 { sp := pushStackItem(sp, 0) } - default { sp := pushStackItem(sp, addr) } + evmGasLeft, sp := performCreate(evmGasLeft, sp, isStatic) } case 0xF1 { // OP_CALL evmGasLeft := chargeGas(evmGasLeft, 100) @@ -2535,58 +2625,11 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, gasUsed) } case 0xF5 { // OP_CREATE2 - evmGasLeft := chargeGas(evmGasLeft, 32000) - - if isStatic { - revert(0, 0) - } - - let value, offset, size, salt - - value, sp := popStackItem(sp) - offset, sp := popStackItem(sp) - size, sp := popStackItem(sp) - salt, sp := popStackItem(sp) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size))) - - if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { - revert(0, 0) - } - - if gt(value, balance(address())) { - revert(0, 0) - } - - // dynamicGas = init_code_cost + hash_cost + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost - // minimum_word_size = (size + 31) / 32 - // init_code_cost = 2 * minimum_word_size - // hash_cost = 6 * minimum_word_size - // code_deposit_cost = 200 * deployed_code_size - evmGasLeft := chargeGas(evmGasLeft, add( - expandMemory(add(offset, size)), - shr(2, add(size, 31)) - )) - - { - let hashedBytecode := keccak256(add(MEM_OFFSET_INNER(), offset), size) - mstore8(0, 0xFF) - mstore(0x01, shl(0x60, address())) - mstore(0x15, salt) - mstore(0x35, hashedBytecode) - } - - let addr := and( - keccak256(0, 0x55), - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - ) - - let result - result, evmGasLeft := genericCreate(addr, offset, size, sp, value, evmGasLeft) //code_deposit_cost missing - + let result, addr + evmGasLeft, sp, result, addr := performCreate2(evmGasLeft, sp, isStatic) switch result - case 0 { sp := pushStackItem(sp, 0) } - default { sp := pushStackItem(sp, addr) } + case 0 { sp := pushStackItem(sp, 0) } + default { sp := pushStackItem(sp, addr) } } case 0xFA { // OP_STATICCALL evmGasLeft := chargeGas(evmGasLeft, 100) @@ -2729,11 +2772,8 @@ object "EVMInterpreter" { } // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 - function readIP(ip) -> opcode { + function readIP(ip,maxAcceptablePos) -> opcode { // TODO: Why not do this at the beginning once instead of every time? - let bytecodeLen := mload(BYTECODE_OFFSET()) - - let maxAcceptablePos := add(add(BYTECODE_OFFSET(), bytecodeLen), 31) if gt(ip, maxAcceptablePos) { revert(0, 0) } @@ -2741,13 +2781,11 @@ object "EVMInterpreter" { opcode := and(mload(sub(ip, 31)), 0xff) } - function readBytes(start, length) -> value { - let max := add(start, length) - for {} lt(start, max) { start := add(start, 1) } { - let next_byte := readIP(start) - - value := or(shl(8, value), next_byte) + function readBytes(start, maxAcceptablePos,length) -> value { + if gt(add(start,sub(length,1)), maxAcceptablePos) { + revert(0, 0) } + value := shr(mul(8,sub(32,length)),mload(start)) } function dupStackItem(sp, evmGas, position) -> newSp, evmGasLeft { @@ -3123,12 +3161,6 @@ object "EVMInterpreter" { } } - // Note, that this function can overflow. It's up to the caller to ensure that it does not. - function memCost(memSizeWords) -> gasCost { - // The first term of the sum is the quadratic cost, the second one the linear one. - gasCost := add(div(mul(memSizeWords, memSizeWords), 512), mul(3, memSizeWords)) - } - // This function can overflow, it is the job of the caller to ensure that it does not. // The argument to this function is the offset into the memory region IN BYTES. function expandMemory(newSize) -> gasCost { @@ -3142,12 +3174,9 @@ object "EVMInterpreter" { let newSizeInWords := div(add(newSize, 31), 32) if gt(newSizeInWords, oldSizeInWords) { - // TODO: Check this, it feels like there might be a more optimized way - // of doing this cost calculation. - let oldCost := memCost(oldSizeInWords) - let newCost := memCost(newSizeInWords) + let new_minus_old := sub(newSizeInWords, oldSizeInWords) + gasCost := add(mul(3,new_minus_old), div(mul(new_minus_old,add(newSizeInWords,oldSizeInWords)),512)) - gasCost := sub(newCost, oldCost) mstore(MEM_OFFSET(), newSizeInWords) } } @@ -3342,6 +3371,22 @@ object "EVMInterpreter" { nonce := mload(0) } + function getRawNonce(addr) -> nonce { + mstore8(0, 0x5a) + mstore8(1, 0xa9) + mstore8(2, 0xb6) + mstore8(3, 0xb5) + mstore(4, addr) + + let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) + + if iszero(result) { + revert(0, 0) + } + + nonce := mload(0) + } + function _isEVM(_addr) -> isEVM { // bytes4 selector = ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT.isAccountEVM.selector; (0x8c040477) // function isAccountEVM(address _addr) external view returns (bool); @@ -3551,6 +3596,46 @@ object "EVMInterpreter" { } } + function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize,isStatic) -> success, frameGasLeft, gasToPassNew{ + gasToPassNew := gasToPass + let is_evm := _isEVM(addr) + if isStatic { + if value { + revert(0, 0) + } + success, frameGasLeft:= _performStaticCall( + is_evm, + gasToPassNew, + addr, + argsOffset, + argsSize, + retOffset, + retSize + ) + } + + if and(is_evm, iszero(isStatic)) { + _pushEVMFrame(gasToPassNew, isStatic) + success := call(gasToPassNew, addr, value, argsOffset, argsSize, 0, 0) + frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + _popEVMFrame() + } + + // zkEVM native + if and(iszero(is_evm), iszero(isStatic)) { + gasToPassNew := _getZkEVMGas(gasToPassNew) + 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 { let gasToPass,addr,value,argsOffset,argsSize,retOffset,retSize @@ -3594,44 +3679,17 @@ object "EVMInterpreter" { checkMemOverflow(add(argsOffset, argsSize)) checkMemOverflow(add(retOffset, retSize)) - let frameGasLeft - let success - - if isStatic { - if value { - revert(0, 0) - } - success, frameGasLeft:= _performStaticCall( - _isEVM(addr), - gasToPass, - addr, - argsOffset, - argsSize, - retOffset, - retSize - ) - } - - if and(_isEVM(addr), iszero(isStatic)) { - _pushEVMFrame(gasToPass, isStatic) - success := call(gasToPass, addr, value, argsOffset, argsSize, 0, 0) - frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) - _popEVMFrame() - } - - // zkEVM native - if and(iszero(_isEVM(addr)), iszero(isStatic)) { - gasToPass := _getZkEVMGas(gasToPass) - let zkevmGasBefore := gas() - success := call(gasToPass, addr, value, argsOffset, argsSize, retOffset, retSize) - _saveReturndataAfterZkEVMCall() - let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) - - frameGasLeft := 0 - if gt(gasToPass, gasUsed) { - frameGasLeft := sub(gasToPass, gasUsed) - } - } + let success, frameGasLeft + success, frameGasLeft, gasToPass:= _performCall( + addr, + gasToPass, + value, + argsOffset, + argsSize, + retOffset, + retSize, + isStatic + ) extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) @@ -3766,12 +3824,12 @@ object "EVMInterpreter" { function isAddrEmpty(addr) -> isEmpty { isEmpty := 0 - if and( and( - iszero(balance(addr)), - iszero(extcodesize(addr)) ), - iszero(getNonce(addr)) - ) { - isEmpty := 1 + if iszero(extcodesize(addr)) { // YUL doesn't have short-circuit evaluation + if iszero(balance(addr)) { + if iszero(getRawNonce(addr)) { + isEmpty := 1 + } + } } } @@ -3860,6 +3918,133 @@ object "EVMInterpreter" { mstore(sub(offset, 0x80), back) } + function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { + evmGasLeft := chargeGas(evmGas, 100) + + let addr, dest, offset, len + addr, sp := popStackItem(oldSp) + dest, sp := popStackItem(sp) + offset, sp := popStackItem(sp) + len, sp := popStackItem(sp) + + // dynamicGas = 3 * minimum_word_size + memory_expansion_cost + address_access_cost + // minimum_word_size = (size + 31) / 32 + + let dynamicGas := add( + mul(3, shr(5, add(len, 31))), + expandMemory(add(dest, len)) + ) + if iszero(warmAddress(addr)) { + dynamicGas := add(dynamicGas, 2500) + } + evmGasLeft := chargeGas(evmGasLeft, dynamicGas) + + let len_32 := shr(5, len) + for {let i := 0} lt(i, len_32) { i := add(i, 1) } { + mstore(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(size_32,i),0) + } + // Gets the code from the addr + pop(_fetchDeployedCode(addr, add(offset, MEM_OFFSET_INNER()), len)) + } + + function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp { + evmGasLeft := chargeGas(evmGas, 32000) + + if isStatic { + revert(0, 0) + } + + let value, offset, size + + value, sp := popStackItem(oldSp) + offset, sp := popStackItem(sp) + size, sp := popStackItem(sp) + + checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size))) + + if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { + revert(0, 0) + } + + if gt(value, balance(address())) { + revert(0, 0) + } + + // dynamicGas = init_code_cost + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost + // minimum_word_size = (size + 31) / 32 + // init_code_cost = 2 * minimum_word_size + // code_deposit_cost = 200 * deployed_code_size + let dynamicGas := add( + shr(4, add(size, 31)), + expandMemory(add(offset, size)) + ) + evmGasLeft := chargeGas(evmGasLeft, dynamicGas) + + let addr := getNewAddress(address()) + + let result + result, evmGasLeft := genericCreate(addr, offset, size, sp, value, evmGasLeft) + + switch result + case 0 { sp := pushStackItem(sp, 0) } + default { sp := pushStackItem(sp, addr) } + } + + function performCreate2(evmGas, oldSp, isStatic) -> evmGasLeft, sp, result, addr{ + evmGasLeft := chargeGas(evmGas, 32000) + + if isStatic { + revert(0, 0) + } + + let value, offset, size, salt + + value, sp := popStackItem(oldSp) + offset, sp := popStackItem(sp) + size, sp := popStackItem(sp) + salt, sp := popStackItem(sp) + + checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size))) + + if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { + revert(0, 0) + } + + if gt(value, balance(address())) { + revert(0, 0) + } + + // dynamicGas = init_code_cost + hash_cost + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost + // minimum_word_size = (size + 31) / 32 + // init_code_cost = 2 * minimum_word_size + // hash_cost = 6 * minimum_word_size + // code_deposit_cost = 200 * deployed_code_size + evmGasLeft := chargeGas(evmGasLeft, add( + expandMemory(add(offset, size)), + shr(2, add(size, 31)) + )) + + { + let hashedBytecode := keccak256(add(MEM_OFFSET_INNER(), offset), size) + mstore8(0, 0xFF) + mstore(0x01, shl(0x60, address())) + mstore(0x15, salt) + mstore(0x35, hashedBytecode) + } + + addr := and( + keccak256(0, 0x55), + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + ) + + result, evmGasLeft := genericCreate(addr, offset, size, sp, value, evmGasLeft) + } + //////////////////////////////////////////////////////////////// // FALLBACK @@ -3888,8 +4073,10 @@ object "EVMInterpreter" { let ip := add(BYTECODE_OFFSET(), 32) let opcode + let maxAcceptablePos := add(add(BYTECODE_OFFSET(), mload(BYTECODE_OFFSET())), 31) + for { } true { } { - opcode := readIP(ip) + opcode := readIP(ip,maxAcceptablePos) ip := add(ip, 1) @@ -4155,6 +4342,7 @@ object "EVMInterpreter" { sp := pushStackItem(sp, sar(shift, value)) } case 0x20 { // OP_KECCAK256 + evmGasLeft := chargeGas(evmGasLeft, 30) let offset, size @@ -4168,11 +4356,11 @@ object "EVMInterpreter" { // an expansion, which costs gas. // dynamicGas = 6 * minimum_word_size + memory_expansion_cost // minimum_word_size = (size + 31) / 32 - let minWordSize := shr(5, add(size, 31)) - let dynamicGas := add(mul(6, minWordSize), expandMemory(add(offset, size))) + let dynamicGas := add(mul(6, shr(5, add(size, 31))), expandMemory(add(offset, size))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) sp := pushStackItem(sp, keccak) + } case 0x30 { // OP_ADDRESS evmGasLeft := chargeGas(evmGasLeft, 2) @@ -4222,6 +4410,7 @@ object "EVMInterpreter" { sp := pushStackItem(sp, calldatasize()) } case 0x37 { // OP_CALLDATACOPY + evmGasLeft := chargeGas(evmGasLeft, 3) let destOffset, offset, size @@ -4235,11 +4424,11 @@ object "EVMInterpreter" { // dynamicGas = 3 * minimum_word_size + memory_expansion_cost // minimum_word_size = (size + 31) / 32 - let minWordSize := shr(5, add(size, 31)) - let dynamicGas := add(mul(3, minWordSize), expandMemory(add(destOffset, size))) + let dynamicGas := add(mul(3, shr(5, add(size, 31))), expandMemory(add(destOffset, size))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) calldatacopy(add(destOffset, MEM_OFFSET_INNER()), offset, size) + } case 0x38 { // OP_CODESIZE evmGasLeft := chargeGas(evmGasLeft, 2) @@ -4248,6 +4437,7 @@ object "EVMInterpreter" { sp := pushStackItem(sp, bytecodeLen) } case 0x39 { // OP_CODECOPY + evmGasLeft := chargeGas(evmGasLeft, 3) let dst, offset, len @@ -4258,8 +4448,7 @@ object "EVMInterpreter" { // dynamicGas = 3 * minimum_word_size + memory_expansion_cost // minimum_word_size = (size + 31) / 32 - let minWordSize := shr(5, add(len, 31)) - let dynamicGas := add(mul(3, minWordSize), expandMemory(add(dst, len))) + let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(add(dst, len))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) dst := add(dst, MEM_OFFSET_INNER()) @@ -4277,6 +4466,7 @@ object "EVMInterpreter" { shr(248, mload(add(offset, i))) ) } + } case 0x3A { // OP_GASPRICE evmGasLeft := chargeGas(evmGasLeft, 2) @@ -4301,32 +4491,7 @@ object "EVMInterpreter" { default { sp := pushStackItem(sp, _fetchDeployedCodeLen(addr)) } } case 0x3C { // OP_EXTCODECOPY - evmGasLeft := chargeGas(evmGasLeft, 100) - - let addr, dest, offset, len - addr, sp := popStackItem(sp) - dest, sp := popStackItem(sp) - offset, sp := popStackItem(sp) - len, sp := popStackItem(sp) - - // dynamicGas = 3 * minimum_word_size + memory_expansion_cost + address_access_cost - // minimum_word_size = (size + 31) / 32 - let dynamicGas := add( - mul(3, shr(5, add(len, 31))), - expandMemory(add(dest, len)) - ) - if iszero(warmAddress(addr)) { - dynamicGas := add(dynamicGas, 2500) - } - evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - - // TODO: Check if Zeroing out the memory is necessary - let _lastByte := add(dest, len) - for {let i := dest} lt(i, _lastByte) { i := add(i, 1) } { - mstore8(i, 0) - } - // Gets the code from the addr - pop(_fetchDeployedCode(addr, add(offset, MEM_OFFSET_INNER()), len)) + evmGasLeft, sp := performExtCodeCopy(evmGasLeft, sp) } case 0x3D { // OP_RETURNDATASIZE evmGasLeft := chargeGas(evmGasLeft, 2) @@ -4335,6 +4500,7 @@ object "EVMInterpreter" { sp := pushStackItem(sp, rdz) } case 0x3E { // OP_RETURNDATACOPY + evmGasLeft := chargeGas(evmGasLeft, 3) let dest, offset, len @@ -4352,11 +4518,11 @@ object "EVMInterpreter" { // minimum_word_size = (size + 31) / 32 // dynamicGas = 3 * minimum_word_size + memory_expansion_cost - let minWordSize := shr(5, add(len, 31)) - let dynamicGas := add(mul(3, minWordSize), expandMemory(add(dest, len))) + let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(add(dest, len))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) copyActivePtrData(add(MEM_OFFSET_INNER(), dest), offset, len) + } case 0x3F { // OP_EXTCODEHASH evmGasLeft := chargeGas(evmGasLeft, 100) @@ -4457,6 +4623,7 @@ object "EVMInterpreter" { mstore8(add(MEM_OFFSET_INNER(), offset), value) } case 0x54 { // OP_SLOAD + evmGasLeft := chargeGas(evmGasLeft, 100) let key, value, isWarm @@ -4476,8 +4643,10 @@ object "EVMInterpreter" { } sp := pushStackItem(sp,value) + } case 0x55 { // OP_SSTORE + evmGasLeft := chargeGas(evmGasLeft, 100) if isStatic { @@ -4514,6 +4683,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, gasSpent) sstore(key, value) + } // NOTE: We don't currently do full jumpdest validation // (i.e. validating a jumpdest isn't in PUSH data) @@ -4527,7 +4697,7 @@ object "EVMInterpreter" { ip := add(add(BYTECODE_OFFSET(), 32), counter) // Check next opcode is JUMPDEST - let nextOpcode := readIP(ip) + let nextOpcode := readIP(ip,maxAcceptablePos) if iszero(eq(nextOpcode, 0x5B)) { revert(0, 0) } @@ -4547,7 +4717,7 @@ object "EVMInterpreter" { ip := add(add(BYTECODE_OFFSET(), 32), counter) // Check next opcode is JUMPDEST - let nextOpcode := readIP(ip) + let nextOpcode := readIP(ip,maxAcceptablePos) if iszero(eq(nextOpcode, 0x5B)) { revert(0, 0) } @@ -4586,7 +4756,7 @@ object "EVMInterpreter" { case 0x60 { // OP_PUSH1 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,1) + let value := readBytes(ip,maxAcceptablePos,1) sp := pushStackItem(sp, value) ip := add(ip, 1) @@ -4594,7 +4764,7 @@ object "EVMInterpreter" { case 0x61 { // OP_PUSH2 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,2) + let value := readBytes(ip,maxAcceptablePos,2) sp := pushStackItem(sp, value) ip := add(ip, 2) @@ -4602,7 +4772,7 @@ object "EVMInterpreter" { case 0x62 { // OP_PUSH3 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,3) + let value := readBytes(ip,maxAcceptablePos,3) sp := pushStackItem(sp, value) ip := add(ip, 3) @@ -4610,7 +4780,7 @@ object "EVMInterpreter" { case 0x63 { // OP_PUSH4 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,4) + let value := readBytes(ip,maxAcceptablePos,4) sp := pushStackItem(sp, value) ip := add(ip, 4) @@ -4618,7 +4788,7 @@ object "EVMInterpreter" { case 0x64 { // OP_PUSH5 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,5) + let value := readBytes(ip,maxAcceptablePos,5) sp := pushStackItem(sp, value) ip := add(ip, 5) @@ -4626,7 +4796,7 @@ object "EVMInterpreter" { case 0x65 { // OP_PUSH6 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,6) + let value := readBytes(ip,maxAcceptablePos,6) sp := pushStackItem(sp, value) ip := add(ip, 6) @@ -4634,7 +4804,7 @@ object "EVMInterpreter" { case 0x66 { // OP_PUSH7 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,7) + let value := readBytes(ip,maxAcceptablePos,7) sp := pushStackItem(sp, value) ip := add(ip, 7) @@ -4642,7 +4812,7 @@ object "EVMInterpreter" { case 0x67 { // OP_PUSH8 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,8) + let value := readBytes(ip,maxAcceptablePos,8) sp := pushStackItem(sp, value) ip := add(ip, 8) @@ -4650,7 +4820,7 @@ object "EVMInterpreter" { case 0x68 { // OP_PUSH9 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,9) + let value := readBytes(ip,maxAcceptablePos,9) sp := pushStackItem(sp, value) ip := add(ip, 9) @@ -4658,7 +4828,7 @@ object "EVMInterpreter" { case 0x69 { // OP_PUSH10 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,10) + let value := readBytes(ip,maxAcceptablePos,10) sp := pushStackItem(sp, value) ip := add(ip, 10) @@ -4666,7 +4836,7 @@ object "EVMInterpreter" { case 0x6A { // OP_PUSH11 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,11) + let value := readBytes(ip,maxAcceptablePos,11) sp := pushStackItem(sp, value) ip := add(ip, 11) @@ -4674,7 +4844,7 @@ object "EVMInterpreter" { case 0x6B { // OP_PUSH12 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,12) + let value := readBytes(ip,maxAcceptablePos,12) sp := pushStackItem(sp, value) ip := add(ip, 12) @@ -4682,7 +4852,7 @@ object "EVMInterpreter" { case 0x6C { // OP_PUSH13 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,13) + let value := readBytes(ip,maxAcceptablePos,13) sp := pushStackItem(sp, value) ip := add(ip, 13) @@ -4690,7 +4860,7 @@ object "EVMInterpreter" { case 0x6D { // OP_PUSH14 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,14) + let value := readBytes(ip,maxAcceptablePos,14) sp := pushStackItem(sp, value) ip := add(ip, 14) @@ -4698,7 +4868,7 @@ object "EVMInterpreter" { case 0x6E { // OP_PUSH15 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,15) + let value := readBytes(ip,maxAcceptablePos,15) sp := pushStackItem(sp, value) ip := add(ip, 15) @@ -4706,7 +4876,7 @@ object "EVMInterpreter" { case 0x6F { // OP_PUSH16 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,16) + let value := readBytes(ip,maxAcceptablePos,16) sp := pushStackItem(sp, value) ip := add(ip, 16) @@ -4714,7 +4884,7 @@ object "EVMInterpreter" { case 0x70 { // OP_PUSH17 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,17) + let value := readBytes(ip,maxAcceptablePos,17) sp := pushStackItem(sp, value) ip := add(ip, 17) @@ -4722,7 +4892,7 @@ object "EVMInterpreter" { case 0x71 { // OP_PUSH18 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,18) + let value := readBytes(ip,maxAcceptablePos,18) sp := pushStackItem(sp, value) ip := add(ip, 18) @@ -4730,7 +4900,7 @@ object "EVMInterpreter" { case 0x72 { // OP_PUSH19 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,19) + let value := readBytes(ip,maxAcceptablePos,19) sp := pushStackItem(sp, value) ip := add(ip, 19) @@ -4738,7 +4908,7 @@ object "EVMInterpreter" { case 0x73 { // OP_PUSH20 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,20) + let value := readBytes(ip,maxAcceptablePos,20) sp := pushStackItem(sp, value) ip := add(ip, 20) @@ -4746,7 +4916,7 @@ object "EVMInterpreter" { case 0x74 { // OP_PUSH21 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,21) + let value := readBytes(ip,maxAcceptablePos,21) sp := pushStackItem(sp, value) ip := add(ip, 21) @@ -4754,7 +4924,7 @@ object "EVMInterpreter" { case 0x75 { // OP_PUSH22 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,22) + let value := readBytes(ip,maxAcceptablePos,22) sp := pushStackItem(sp, value) ip := add(ip, 22) @@ -4762,7 +4932,7 @@ object "EVMInterpreter" { case 0x76 { // OP_PUSH23 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,23) + let value := readBytes(ip,maxAcceptablePos,23) sp := pushStackItem(sp, value) ip := add(ip, 23) @@ -4770,7 +4940,7 @@ object "EVMInterpreter" { case 0x77 { // OP_PUSH24 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,24) + let value := readBytes(ip,maxAcceptablePos,24) sp := pushStackItem(sp, value) ip := add(ip, 24) @@ -4778,7 +4948,7 @@ object "EVMInterpreter" { case 0x78 { // OP_PUSH25 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,25) + let value := readBytes(ip,maxAcceptablePos,25) sp := pushStackItem(sp, value) ip := add(ip, 25) @@ -4786,7 +4956,7 @@ object "EVMInterpreter" { case 0x79 { // OP_PUSH26 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,26) + let value := readBytes(ip,maxAcceptablePos,26) sp := pushStackItem(sp, value) ip := add(ip, 26) @@ -4794,7 +4964,7 @@ object "EVMInterpreter" { case 0x7A { // OP_PUSH27 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,27) + let value := readBytes(ip,maxAcceptablePos,27) sp := pushStackItem(sp, value) ip := add(ip, 27) @@ -4802,7 +4972,7 @@ object "EVMInterpreter" { case 0x7B { // OP_PUSH28 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,28) + let value := readBytes(ip,maxAcceptablePos,28) sp := pushStackItem(sp, value) ip := add(ip, 28) @@ -4810,7 +4980,7 @@ object "EVMInterpreter" { case 0x7C { // OP_PUSH29 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,29) + let value := readBytes(ip,maxAcceptablePos,29) sp := pushStackItem(sp, value) ip := add(ip, 29) @@ -4818,7 +4988,7 @@ object "EVMInterpreter" { case 0x7D { // OP_PUSH30 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,30) + let value := readBytes(ip,maxAcceptablePos,30) sp := pushStackItem(sp, value) ip := add(ip, 30) @@ -4826,7 +4996,7 @@ object "EVMInterpreter" { case 0x7E { // OP_PUSH31 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,31) + let value := readBytes(ip,maxAcceptablePos,31) sp := pushStackItem(sp, value) ip := add(ip, 31) @@ -4834,7 +5004,7 @@ object "EVMInterpreter" { case 0x7F { // OP_PUSH32 evmGasLeft := chargeGas(evmGasLeft, 3) - let value := readBytes(ip,32) + let value := readBytes(ip,maxAcceptablePos,32) sp := pushStackItem(sp, value) ip := add(ip, 32) @@ -4981,11 +5151,9 @@ object "EVMInterpreter" { revert(0, 0) } - let offset, size, topic1, topic2 + let offset, size offset, sp := popStackItem(sp) size, sp := popStackItem(sp) - topic1, sp := popStackItem(sp) - topic2, sp := popStackItem(sp) checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size)) @@ -4994,7 +5162,12 @@ object "EVMInterpreter" { dynamicGas := add(dynamicGas, 750) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - log2(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2) + { + let topic1, topic2 + topic1, sp := popStackItem(sp) + topic2, sp := popStackItem(sp) + log2(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2) + } } case 0xA3 { // OP_LOG3 evmGasLeft := chargeGas(evmGasLeft, 375) @@ -5020,7 +5193,7 @@ object "EVMInterpreter" { topic2, sp := popStackItem(sp) topic3, sp := popStackItem(sp) log3(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2, topic3) - } + } } case 0xA4 { // OP_LOG4 evmGasLeft := chargeGas(evmGasLeft, 375) @@ -5047,50 +5220,10 @@ object "EVMInterpreter" { topic3, sp := popStackItem(sp) topic4, sp := popStackItem(sp) log4(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2, topic3, topic4) - } - + } } case 0xF0 { // OP_CREATE - evmGasLeft := chargeGas(evmGasLeft, 32000) - - if isStatic { - revert(0, 0) - } - - let value, offset, size - - value, sp := popStackItem(sp) - offset, sp := popStackItem(sp) - size, sp := popStackItem(sp) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size))) - - if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { - revert(0, 0) - } - - if gt(value, balance(address())) { - revert(0, 0) - } - - // dynamicGas = init_code_cost + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost - // minimum_word_size = (size + 31) / 32 - // init_code_cost = 2 * minimum_word_size - // code_deposit_cost = 200 * deployed_code_size - let dynamicGas := add( - shr(4, add(size, 31)), - expandMemory(add(offset, size)) - ) - evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - - let addr := getNewAddress(address()) - - let result - result, evmGasLeft := genericCreate(addr, offset, size, sp, value, evmGasLeft) //code_deposit_cost missing - - switch result - case 0 { sp := pushStackItem(sp, 0) } - default { sp := pushStackItem(sp, addr) } + evmGasLeft, sp := performCreate(evmGasLeft, sp, isStatic) } case 0xF1 { // OP_CALL evmGasLeft := chargeGas(evmGasLeft, 100) @@ -5126,58 +5259,11 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, gasUsed) } case 0xF5 { // OP_CREATE2 - evmGasLeft := chargeGas(evmGasLeft, 32000) - - if isStatic { - revert(0, 0) - } - - let value, offset, size, salt - - value, sp := popStackItem(sp) - offset, sp := popStackItem(sp) - size, sp := popStackItem(sp) - salt, sp := popStackItem(sp) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size))) - - if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { - revert(0, 0) - } - - if gt(value, balance(address())) { - revert(0, 0) - } - - // dynamicGas = init_code_cost + hash_cost + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost - // minimum_word_size = (size + 31) / 32 - // init_code_cost = 2 * minimum_word_size - // hash_cost = 6 * minimum_word_size - // code_deposit_cost = 200 * deployed_code_size - evmGasLeft := chargeGas(evmGasLeft, add( - expandMemory(add(offset, size)), - shr(2, add(size, 31)) - )) - - { - let hashedBytecode := keccak256(add(MEM_OFFSET_INNER(), offset), size) - mstore8(0, 0xFF) - mstore(0x01, shl(0x60, address())) - mstore(0x15, salt) - mstore(0x35, hashedBytecode) - } - - let addr := and( - keccak256(0, 0x55), - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - ) - - let result - result, evmGasLeft := genericCreate(addr, offset, size, sp, value, evmGasLeft) //code_deposit_cost missing - + let result, addr + evmGasLeft, sp, result, addr := performCreate2(evmGasLeft, sp, isStatic) switch result - case 0 { sp := pushStackItem(sp, 0) } - default { sp := pushStackItem(sp, addr) } + case 0 { sp := pushStackItem(sp, 0) } + default { sp := pushStackItem(sp, addr) } } case 0xFA { // OP_STATICCALL evmGasLeft := chargeGas(evmGasLeft, 100)