diff --git a/nimbus/evm/interpreter/op_handlers/oph_arithmetic.nim b/nimbus/evm/interpreter/op_handlers/oph_arithmetic.nim index b56b71e60..4e9dcf94f 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_arithmetic.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_arithmetic.nim @@ -37,248 +37,247 @@ func slt(x, y: UInt256): bool = # Private, op handlers implementation # ------------------------------------------------------------------------------ -const - addOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x01, Addition - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - k.cpt.stack.push(lhs + rhs) +proc addOp (k: var VmCtx): EvmResultVoid = + ## 0x01, Addition + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + k.cpt.stack.push(lhs + rhs) - mulOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x02, Multiplication - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - k.cpt.stack.push(lhs * rhs) +proc mulOp(k: var VmCtx): EvmResultVoid = + ## 0x02, Multiplication + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + k.cpt.stack.push(lhs * rhs) - subOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x03, Substraction - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - k.cpt.stack.push(lhs - rhs) +proc subOp(k: var VmCtx): EvmResultVoid = + ## 0x03, Substraction + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + k.cpt.stack.push(lhs - rhs) - divideOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x04, Division - let - (lhs, rhs) = ? k.cpt.stack.popInt(2) - value = if rhs.isZero: - # EVM special casing of div by 0 - zero(UInt256) - else: - lhs div rhs - - k.cpt.stack.push value - - - sdivOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x05, Signed division - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - - var r: UInt256 - if rhs.isZero.not: - var a = lhs - var b = rhs - var signA, signB: bool - extractSign(a, signA) - extractSign(b, signB) - r = a div b - setSign(r, signA xor signB) - k.cpt.stack.push(r) - - - moduloOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x06, Modulo - let - (lhs, rhs) = ? k.cpt.stack.popInt(2) - value = if rhs.isZero: - zero(UInt256) - else: - lhs mod rhs - - k.cpt.stack.push value - - - smodOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x07, Signed modulo - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - - var r: UInt256 - if rhs.isZero.not: - var sign: bool - var v = lhs - var m = rhs - extractSign(m, sign) - extractSign(v, sign) - r = v mod m - setSign(r, sign) - k.cpt.stack.push(r) - - - addmodOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x08, Modulo addition - ## Intermediate computations do not roll over at 2^256 - let - (lhs, rhs, modulus) = ? k.cpt.stack.popInt(3) - value = if modulus.isZero: - zero(UInt256) - else: - addmod(lhs, rhs, modulus) - - k.cpt.stack.push value - - - mulmodOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x09, Modulo multiplication - ## Intermediate computations do not roll over at 2^256 - let - (lhs, rhs, modulus) = ? k.cpt.stack.popInt(3) - value = if modulus.isZero: - zero(UInt256) - else: - mulmod(lhs, rhs, modulus) - - k.cpt.stack.push value - - - expOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x0A, Exponentiation - let (base, exponent) = ? k.cpt.stack.popInt(2) - - ? k.cpt.opcodeGastCost(Exp, - k.cpt.gasCosts[Exp].d_handler(exponent), - reason = "EXP: exponent bytes") - - let value = if not base.isZero: - base.pow(exponent) - elif exponent.isZero: - # https://github.com/ethereum/yellowpaper/issues/257 - # https://github.com/ethereum/tests/pull/460 - # https://github.com/ewasm/evm2wasm/issues/137 - 1.u256 - else: - zero(UInt256) - - k.cpt.stack.push value - - - signExtendOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x0B, Sign extend - ## Extend length of two’s complement signed integer. - let (bits, value) = ? k.cpt.stack.popInt(2) - - var res: UInt256 - if bits <= 31.u256: - let - one = 1.u256 - testBit = bits.truncate(int) * 8 + 7 - bitPos = one shl testBit - mask = bitPos - one - if not isZero(value and bitPos): - res = value or (not mask) - else: - res = value and mask - else: - res = value - k.cpt.stack.push res - - - ltOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x10, Less-than comparison - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - k.cpt.stack.push((lhs < rhs).uint.u256) - - gtOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x11, Greater-than comparison - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - k.cpt.stack.push((lhs > rhs).uint.u256) - - sltOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x12, Signed less-than comparison - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - k.cpt.stack.push(slt(lhs, rhs).uint.u256) - - sgtOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x13, Signed greater-than comparison - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - # Arguments are swapped and SLT is used. - k.cpt.stack.push(slt(rhs, lhs).uint.u256) - - eqOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x14, Equality comparison - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - k.cpt.stack.push((lhs == rhs).uint.u256) - - isZeroOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x15, Check if zero - let value = ? k.cpt.stack.popInt() - k.cpt.stack.push(value.isZero.uint.u256) - - andOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x16, Bitwise AND - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - k.cpt.stack.push(lhs and rhs) - - orOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x17, Bitwise OR - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - k.cpt.stack.push(lhs or rhs) - - xorOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x18, Bitwise XOR - let (lhs, rhs) = ? k.cpt.stack.popInt(2) - k.cpt.stack.push(lhs xor rhs) - - notOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x19, Check if zero - let value = ? k.cpt.stack.popInt() - k.cpt.stack.push(value.not) - - byteOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0x20, Retrieve single byte from word. - let - (position, value) = ? k.cpt.stack.popInt(2) - val = if position >= 32.u256: +proc divideOp(k: var VmCtx): EvmResultVoid = + ## 0x04, Division + let + (lhs, rhs) = ? k.cpt.stack.popInt(2) + value = if rhs.isZero: + # EVM special casing of div by 0 zero(UInt256) else: - let pos = position.truncate(int) - when system.cpuEndian == bigEndian: - cast[array[32, byte]](value)[pos].u256 + lhs div rhs + + k.cpt.stack.push value + + +proc sdivOp(k: var VmCtx): EvmResultVoid = + ## 0x05, Signed division + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + + var r: UInt256 + if rhs.isZero.not: + var a = lhs + var b = rhs + var signA, signB: bool + extractSign(a, signA) + extractSign(b, signB) + r = a div b + setSign(r, signA xor signB) + k.cpt.stack.push(r) + + +proc moduloOp(k: var VmCtx): EvmResultVoid = + ## 0x06, Modulo + let + (lhs, rhs) = ? k.cpt.stack.popInt(2) + value = if rhs.isZero: + zero(UInt256) + else: + lhs mod rhs + + k.cpt.stack.push value + + +proc smodOp(k: var VmCtx): EvmResultVoid = + ## 0x07, Signed modulo + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + + var r: UInt256 + if rhs.isZero.not: + var sign: bool + var v = lhs + var m = rhs + extractSign(m, sign) + extractSign(v, sign) + r = v mod m + setSign(r, sign) + k.cpt.stack.push(r) + + +proc addmodOp(k: var VmCtx): EvmResultVoid = + ## 0x08, Modulo addition + ## Intermediate computations do not roll over at 2^256 + let + (lhs, rhs, modulus) = ? k.cpt.stack.popInt(3) + value = if modulus.isZero: + zero(UInt256) + else: + addmod(lhs, rhs, modulus) + + k.cpt.stack.push value + + +proc mulmodOp(k: var VmCtx): EvmResultVoid = + ## 0x09, Modulo multiplication + ## Intermediate computations do not roll over at 2^256 + let + (lhs, rhs, modulus) = ? k.cpt.stack.popInt(3) + value = if modulus.isZero: + zero(UInt256) + else: + mulmod(lhs, rhs, modulus) + + k.cpt.stack.push value + + +proc expOp(k: var VmCtx): EvmResultVoid = + ## 0x0A, Exponentiation + let (base, exponent) = ? k.cpt.stack.popInt(2) + + ? k.cpt.opcodeGastCost(Exp, + k.cpt.gasCosts[Exp].d_handler(exponent), + reason = "EXP: exponent bytes") + + let value = if not base.isZero: + base.pow(exponent) + elif exponent.isZero: + # https://github.com/ethereum/yellowpaper/issues/257 + # https://github.com/ethereum/tests/pull/460 + # https://github.com/ewasm/evm2wasm/issues/137 + 1.u256 else: - cast[array[32, byte]](value)[31 - pos].u256 + zero(UInt256) - k.cpt.stack.push val + k.cpt.stack.push value - # Constantinople's new opcodes +proc signExtendOp(k: var VmCtx): EvmResultVoid = + ## 0x0B, Sign extend + ## Extend length of two’s complement signed integer. + let (bits, value) = ? k.cpt.stack.popInt(2) - shlOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - let (shift, num) = ? k.cpt.stack.popInt(2) - let shiftLen = shift.safeInt - if shiftLen >= 256: - k.cpt.stack.push 0 - else: - k.cpt.stack.push(num shl shiftLen) - - shrOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - let (shift, num) = ? k.cpt.stack.popInt(2) - let shiftLen = shift.safeInt - if shiftLen >= 256: - k.cpt.stack.push 0 - else: - # uint version of `shr` - k.cpt.stack.push(num shr shiftLen) - - sarOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = + var res: UInt256 + if bits <= 31.u256: let - shiftLen = ? k.cpt.stack.popSafeInt() - num256 = ? k.cpt.stack.popInt() - num = cast[Int256](num256) - - if shiftLen >= 256: - if num.isNegative: - k.cpt.stack.push(cast[UInt256]((-1).i256)) - else: - k.cpt.stack. push 0 + one = 1.u256 + testBit = bits.truncate(int) * 8 + 7 + bitPos = one shl testBit + mask = bitPos - one + if not isZero(value and bitPos): + res = value or (not mask) else: - # int version of `shr` then force the result - # into uint256 - k.cpt.stack.push(cast[UInt256](num shr shiftLen)) + res = value and mask + else: + res = value + k.cpt.stack.push res + + +proc ltOp(k: var VmCtx): EvmResultVoid = + ## 0x10, Less-than comparison + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + k.cpt.stack.push((lhs < rhs).uint.u256) + +proc gtOp(k: var VmCtx): EvmResultVoid = + ## 0x11, Greater-than comparison + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + k.cpt.stack.push((lhs > rhs).uint.u256) + +proc sltOp(k: var VmCtx): EvmResultVoid = + ## 0x12, Signed less-than comparison + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + k.cpt.stack.push(slt(lhs, rhs).uint.u256) + +proc sgtOp(k: var VmCtx): EvmResultVoid = + ## 0x13, Signed greater-than comparison + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + # Arguments are swapped and SLT is used. + k.cpt.stack.push(slt(rhs, lhs).uint.u256) + +proc eqOp(k: var VmCtx): EvmResultVoid = + ## 0x14, Equality comparison + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + k.cpt.stack.push((lhs == rhs).uint.u256) + +proc isZeroOp(k: var VmCtx): EvmResultVoid = + ## 0x15, Check if zero + let value = ? k.cpt.stack.popInt() + k.cpt.stack.push(value.isZero.uint.u256) + +proc andOp(k: var VmCtx): EvmResultVoid = + ## 0x16, Bitwise AND + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + k.cpt.stack.push(lhs and rhs) + +proc orOp(k: var VmCtx): EvmResultVoid = + ## 0x17, Bitwise OR + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + k.cpt.stack.push(lhs or rhs) + +proc xorOp(k: var VmCtx): EvmResultVoid = + ## 0x18, Bitwise XOR + let (lhs, rhs) = ? k.cpt.stack.popInt(2) + k.cpt.stack.push(lhs xor rhs) + +proc notOp(k: var VmCtx): EvmResultVoid = + ## 0x19, Check if zero + let value = ? k.cpt.stack.popInt() + k.cpt.stack.push(value.not) + +proc byteOp(k: var VmCtx): EvmResultVoid = + ## 0x20, Retrieve single byte from word. + let + (position, value) = ? k.cpt.stack.popInt(2) + val = if position >= 32.u256: + zero(UInt256) + else: + let pos = position.truncate(int) + when system.cpuEndian == bigEndian: + cast[array[32, byte]](value)[pos].u256 + else: + cast[array[32, byte]](value)[31 - pos].u256 + + k.cpt.stack.push val + + +# Constantinople's new opcodes + +proc shlOp(k: var VmCtx): EvmResultVoid = + let (shift, num) = ? k.cpt.stack.popInt(2) + let shiftLen = shift.safeInt + if shiftLen >= 256: + k.cpt.stack.push 0 + else: + k.cpt.stack.push(num shl shiftLen) + +proc shrOp(k: var VmCtx): EvmResultVoid = + let (shift, num) = ? k.cpt.stack.popInt(2) + let shiftLen = shift.safeInt + if shiftLen >= 256: + k.cpt.stack.push 0 + else: + # uint version of `shr` + k.cpt.stack.push(num shr shiftLen) + +proc sarOp(k: var VmCtx): EvmResultVoid = + let + shiftLen = ? k.cpt.stack.popSafeInt() + num256 = ? k.cpt.stack.popInt() + num = cast[Int256](num256) + + if shiftLen >= 256: + if num.isNegative: + k.cpt.stack.push(cast[UInt256]((-1).i256)) + else: + k.cpt.stack. push 0 + else: + # int version of `shr` then force the result + # into uint256 + k.cpt.stack.push(cast[UInt256](num shr shiftLen)) # ------------------------------------------------------------------------------ # Public, op exec table entries @@ -292,7 +291,7 @@ const name: "add", info: "Addition operation", exec: (prep: VmOpIgnore, - run: addOp, + run: VmOpFn addOp, post: VmOpIgnore)), (opCode: Mul, ## 0x02, Multiplication diff --git a/nimbus/evm/interpreter/op_handlers/oph_blockdata.nim b/nimbus/evm/interpreter/op_handlers/oph_blockdata.nim index ccb6a43ba..0abf3cb6f 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_blockdata.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_blockdata.nim @@ -29,63 +29,62 @@ when not defined(evmc_enabled): # Private, op handlers implementation # ------------------------------------------------------------------------------ -const - blockhashOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x40, Get the hash of one of the 256 most recent complete blocks. - let - cpt = k.cpt - blockNumber = ? cpt.stack.popInt() - blockHash = cpt.getBlockHash(blockNumber.truncate(BlockNumber)) +proc blockhashOp (k: var VmCtx): EvmResultVoid = + ## 0x40, Get the hash of one of the 256 most recent complete blocks. + let + cpt = k.cpt + blockNumber = ? cpt.stack.popInt() + blockHash = cpt.getBlockHash(blockNumber.truncate(BlockNumber)) - cpt.stack.push blockHash + cpt.stack.push blockHash - coinBaseOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x41, Get the block's beneficiary address. - k.cpt.stack.push k.cpt.getCoinbase +proc coinBaseOp (k: var VmCtx): EvmResultVoid = + ## 0x41, Get the block's beneficiary address. + k.cpt.stack.push k.cpt.getCoinbase - timestampOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x42, Get the block's timestamp. - k.cpt.stack.push k.cpt.getTimestamp +proc timestampOp (k: var VmCtx): EvmResultVoid = + ## 0x42, Get the block's timestamp. + k.cpt.stack.push k.cpt.getTimestamp - blocknumberOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x43, Get the block's number. - k.cpt.stack.push k.cpt.getBlockNumber +proc blocknumberOp (k: var VmCtx): EvmResultVoid = + ## 0x43, Get the block's number. + k.cpt.stack.push k.cpt.getBlockNumber - difficultyOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x44, Get the block's difficulty - k.cpt.stack.push k.cpt.getDifficulty +proc difficultyOp (k: var VmCtx): EvmResultVoid = + ## 0x44, Get the block's difficulty + k.cpt.stack.push k.cpt.getDifficulty - gasLimitOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x45, Get the block's gas limit - k.cpt.stack.push k.cpt.getGasLimit +proc gasLimitOp (k: var VmCtx): EvmResultVoid = + ## 0x45, Get the block's gas limit + k.cpt.stack.push k.cpt.getGasLimit - chainIdOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x46, Get current chain’s EIP-155 unique identifier. - k.cpt.stack.push k.cpt.getChainId +proc chainIdOp (k: var VmCtx): EvmResultVoid = + ## 0x46, Get current chain’s EIP-155 unique identifier. + k.cpt.stack.push k.cpt.getChainId - selfBalanceOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x47, Get current contract's balance. - let cpt = k.cpt - cpt.stack.push cpt.getBalance(cpt.msg.contractAddress) +proc selfBalanceOp (k: var VmCtx): EvmResultVoid = + ## 0x47, Get current contract's balance. + let cpt = k.cpt + cpt.stack.push cpt.getBalance(cpt.msg.contractAddress) - baseFeeOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x48, Get the block's base fee. - k.cpt.stack.push k.cpt.getBaseFee +proc baseFeeOp (k: var VmCtx): EvmResultVoid = + ## 0x48, Get the block's base fee. + k.cpt.stack.push k.cpt.getBaseFee - blobHashOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x49, Get current transaction's EIP-4844 versioned hash. - let - index = ? k.cpt.stack.popSafeInt() - len = k.cpt.getVersionedHashesLen +proc blobHashOp (k: var VmCtx): EvmResultVoid = + ## 0x49, Get current transaction's EIP-4844 versioned hash. + let + index = ? k.cpt.stack.popSafeInt() + len = k.cpt.getVersionedHashesLen - if index < len: - k.cpt.stack.push k.cpt.getVersionedHash(index) - else: - k.cpt.stack.push 0 + if index < len: + k.cpt.stack.push k.cpt.getVersionedHash(index) + else: + k.cpt.stack.push 0 - blobBaseFeeOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x4a, Get the block's base fee. - k.cpt.stack.push k.cpt.getBlobBaseFee +proc blobBaseFeeOp (k: var VmCtx): EvmResultVoid = + ## 0x4a, Get the block's base fee. + k.cpt.stack.push k.cpt.getBlobBaseFee # ------------------------------------------------------------------------------ diff --git a/nimbus/evm/interpreter/op_handlers/oph_call.nim b/nimbus/evm/interpreter/op_handlers/oph_call.nim index 00d8aa79f..6de699a92 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_call.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_call.nim @@ -198,310 +198,309 @@ else: # Private, op handlers implementation # ------------------------------------------------------------------------------ -const - callOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0xf1, Message-Call into an account - let cpt = k.cpt +proc callOp(k: var VmCtx): EvmResultVoid = + ## 0xf1, Message-Call into an account + let cpt = k.cpt - if EVMC_STATIC in cpt.msg.flags: - let val = ? cpt.stack[^3, UInt256] - if val > 0.u256: - return err(opErr(StaticContext)) + if EVMC_STATIC in cpt.msg.flags: + let val = ? cpt.stack[^3, UInt256] + if val > 0.u256: + return err(opErr(StaticContext)) + let + p = ? cpt.callParams + res = ? cpt.gasCosts[Call].c_handler( + p.value, + GasParams( + kind: Call, + c_isNewAccount: not cpt.accountExists(p.contractAddress), + c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, + c_contractGas: p.gas, + c_currentMemSize: cpt.memory.len, + c_memOffset: p.memOffset, + c_memLength: p.memLength)) + + var (gasCost, childGasLimit) = res + + gasCost += p.gasCallEIP2929 + if gasCost >= 0: + ? cpt.opcodeGastCost(Call, gasCost, reason = $Call) + + cpt.returnData.setLen(0) + + if cpt.msg.depth >= MaxCallDepth: + debug "Computation Failure", + reason = "Stack too deep", + maximumDepth = MaxCallDepth, + depth = cpt.msg.depth + cpt.gasMeter.returnGas(childGasLimit) + return ok() + + if gasCost < 0 and childGasLimit <= 0: + return err(opErr(OutOfGas)) + + cpt.memory.extend(p.memInPos, p.memInLen) + cpt.memory.extend(p.memOutPos, p.memOutLen) + + let senderBalance = cpt.getBalance(p.sender) + if senderBalance < p.value: + cpt.gasMeter.returnGas(childGasLimit) + return ok() + + when evmc_enabled: let - p = ? cpt.callParams - res = ? cpt.gasCosts[Call].c_handler( - p.value, - GasParams( - kind: Call, - c_isNewAccount: not cpt.accountExists(p.contractAddress), - c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, - c_contractGas: p.gas, - c_currentMemSize: cpt.memory.len, - c_memOffset: p.memOffset, - c_memLength: p.memLength)) + msg = new(nimbus_message) + c = cpt + msg[] = nimbus_message( + kind : EVMC_CALL, + depth : (cpt.msg.depth + 1).int32, + gas : childGasLimit, + sender : p.sender, + recipient : p.contractAddress, + code_address: p.codeAddress, + input_data : cpt.memory.readPtr(p.memInPos), + input_size : p.memInLen.uint, + value : toEvmc(p.value), + flags : p.flags + ) + c.execSubCall(msg, p) + else: + cpt.execSubCall( + memPos = p.memOutPos, + memLen = p.memOutLen, + childMsg = Message( + kind: EVMC_CALL, + depth: cpt.msg.depth + 1, + gas: childGasLimit, + sender: p.sender, + contractAddress: p.contractAddress, + codeAddress: p.codeAddress, + value: p.value, + data: cpt.memory.read(p.memInPos, p.memInLen), + flags: p.flags)) + ok() - var (gasCost, childGasLimit) = res +# --------------------- - gasCost += p.gasCallEIP2929 - if gasCost >= 0: - ? cpt.opcodeGastCost(Call, gasCost, reason = $Call) +proc callCodeOp(k: var VmCtx): EvmResultVoid = + ## 0xf2, Message-call into this account with an alternative account's code. + let + cpt = k.cpt + p = ? cpt.callCodeParams + res = ? cpt.gasCosts[CallCode].c_handler( + p.value, + GasParams( + kind: CallCode, + c_isNewAccount: not cpt.accountExists(p.contractAddress), + c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, + c_contractGas: p.gas, + c_currentMemSize: cpt.memory.len, + c_memOffset: p.memOffset, + c_memLength: p.memLength)) - cpt.returnData.setLen(0) + var (gasCost, childGasLimit) = res + gasCost += p.gasCallEIP2929 + if gasCost >= 0: + ? cpt.opcodeGastCost(CallCode, gasCost, reason = $CallCode) - if cpt.msg.depth >= MaxCallDepth: - debug "Computation Failure", - reason = "Stack too deep", - maximumDepth = MaxCallDepth, - depth = cpt.msg.depth - cpt.gasMeter.returnGas(childGasLimit) - return ok() + cpt.returnData.setLen(0) - if gasCost < 0 and childGasLimit <= 0: - return err(opErr(OutOfGas)) + if cpt.msg.depth >= MaxCallDepth: + debug "Computation Failure", + reason = "Stack too deep", + maximumDepth = MaxCallDepth, + depth = cpt.msg.depth + cpt.gasMeter.returnGas(childGasLimit) + return ok() - cpt.memory.extend(p.memInPos, p.memInLen) - cpt.memory.extend(p.memOutPos, p.memOutLen) + if gasCost < 0 and childGasLimit <= 0: + return err(opErr(OutOfGas)) - let senderBalance = cpt.getBalance(p.sender) - if senderBalance < p.value: - cpt.gasMeter.returnGas(childGasLimit) - return ok() + cpt.memory.extend(p.memInPos, p.memInLen) + cpt.memory.extend(p.memOutPos, p.memOutLen) - when evmc_enabled: - let - msg = new(nimbus_message) - c = cpt - msg[] = nimbus_message( - kind : EVMC_CALL, - depth : (cpt.msg.depth + 1).int32, - gas : childGasLimit, - sender : p.sender, - recipient : p.contractAddress, - code_address: p.codeAddress, - input_data : cpt.memory.readPtr(p.memInPos), - input_size : p.memInLen.uint, - value : toEvmc(p.value), - flags : p.flags - ) - c.execSubCall(msg, p) - else: - cpt.execSubCall( - memPos = p.memOutPos, - memLen = p.memOutLen, - childMsg = Message( - kind: EVMC_CALL, - depth: cpt.msg.depth + 1, - gas: childGasLimit, - sender: p.sender, - contractAddress: p.contractAddress, - codeAddress: p.codeAddress, - value: p.value, - data: cpt.memory.read(p.memInPos, p.memInLen), - flags: p.flags)) - ok() + let senderBalance = cpt.getBalance(p.sender) + if senderBalance < p.value: + cpt.gasMeter.returnGas(childGasLimit) + return ok() - # --------------------- - - callCodeOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0xf2, Message-call into this account with an alternative account's code. + when evmc_enabled: let - cpt = k.cpt - p = ? cpt.callCodeParams - res = ? cpt.gasCosts[CallCode].c_handler( - p.value, - GasParams( - kind: CallCode, - c_isNewAccount: not cpt.accountExists(p.contractAddress), - c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, - c_contractGas: p.gas, - c_currentMemSize: cpt.memory.len, - c_memOffset: p.memOffset, - c_memLength: p.memLength)) + msg = new(nimbus_message) + c = cpt + msg[] = nimbus_message( + kind : EVMC_CALLCODE, + depth : (cpt.msg.depth + 1).int32, + gas : childGasLimit, + sender : p.sender, + recipient : p.contractAddress, + code_address: p.codeAddress, + input_data : cpt.memory.readPtr(p.memInPos), + input_size : p.memInLen.uint, + value : toEvmc(p.value), + flags : p.flags + ) + c.execSubCall(msg, p) + else: + cpt.execSubCall( + memPos = p.memOutPos, + memLen = p.memOutLen, + childMsg = Message( + kind: EVMC_CALLCODE, + depth: cpt.msg.depth + 1, + gas: childGasLimit, + sender: p.sender, + contractAddress: p.contractAddress, + codeAddress: p.codeAddress, + value: p.value, + data: cpt.memory.read(p.memInPos, p.memInLen), + flags: p.flags)) + ok() - var (gasCost, childGasLimit) = res - gasCost += p.gasCallEIP2929 - if gasCost >= 0: - ? cpt.opcodeGastCost(CallCode, gasCost, reason = $CallCode) +# --------------------- - cpt.returnData.setLen(0) +proc delegateCallOp(k: var VmCtx): EvmResultVoid = + ## 0xf4, Message-call into this account with an alternative account's + ## code, but persisting the current values for sender and value. + let + cpt = k.cpt + p = ? cpt.delegateCallParams + res = ? cpt.gasCosts[DelegateCall].c_handler( + p.value, + GasParams( + kind: DelegateCall, + c_isNewAccount: not cpt.accountExists(p.contractAddress), + c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, + c_contractGas: p.gas, + c_currentMemSize: cpt.memory.len, + c_memOffset: p.memOffset, + c_memLength: p.memLength)) - if cpt.msg.depth >= MaxCallDepth: - debug "Computation Failure", - reason = "Stack too deep", - maximumDepth = MaxCallDepth, - depth = cpt.msg.depth - cpt.gasMeter.returnGas(childGasLimit) - return ok() + var (gasCost, childGasLimit) = res + gasCost += p.gasCallEIP2929 + if gasCost >= 0: + ? cpt.opcodeGastCost(DelegateCall, gasCost, reason = $DelegateCall) - if gasCost < 0 and childGasLimit <= 0: - return err(opErr(OutOfGas)) + cpt.returnData.setLen(0) + if cpt.msg.depth >= MaxCallDepth: + debug "Computation Failure", + reason = "Stack too deep", + maximumDepth = MaxCallDepth, + depth = cpt.msg.depth + cpt.gasMeter.returnGas(childGasLimit) + return ok() - cpt.memory.extend(p.memInPos, p.memInLen) - cpt.memory.extend(p.memOutPos, p.memOutLen) + if gasCost < 0 and childGasLimit <= 0: + return err(opErr(OutOfGas)) - let senderBalance = cpt.getBalance(p.sender) - if senderBalance < p.value: - cpt.gasMeter.returnGas(childGasLimit) - return ok() + cpt.memory.extend(p.memInPos, p.memInLen) + cpt.memory.extend(p.memOutPos, p.memOutLen) - when evmc_enabled: - let - msg = new(nimbus_message) - c = cpt - msg[] = nimbus_message( - kind : EVMC_CALLCODE, - depth : (cpt.msg.depth + 1).int32, - gas : childGasLimit, - sender : p.sender, - recipient : p.contractAddress, - code_address: p.codeAddress, - input_data : cpt.memory.readPtr(p.memInPos), - input_size : p.memInLen.uint, - value : toEvmc(p.value), - flags : p.flags - ) - c.execSubCall(msg, p) - else: - cpt.execSubCall( - memPos = p.memOutPos, - memLen = p.memOutLen, - childMsg = Message( - kind: EVMC_CALLCODE, - depth: cpt.msg.depth + 1, - gas: childGasLimit, - sender: p.sender, - contractAddress: p.contractAddress, - codeAddress: p.codeAddress, - value: p.value, - data: cpt.memory.read(p.memInPos, p.memInLen), - flags: p.flags)) - ok() - - # --------------------- - - delegateCallOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0xf4, Message-call into this account with an alternative account's - ## code, but persisting the current values for sender and value. + when evmc_enabled: let - cpt = k.cpt - p = ? cpt.delegateCallParams - res = ? cpt.gasCosts[DelegateCall].c_handler( - p.value, - GasParams( - kind: DelegateCall, - c_isNewAccount: not cpt.accountExists(p.contractAddress), - c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, - c_contractGas: p.gas, - c_currentMemSize: cpt.memory.len, - c_memOffset: p.memOffset, - c_memLength: p.memLength)) + msg = new(nimbus_message) + c = cpt + msg[] = nimbus_message( + kind : EVMC_DELEGATECALL, + depth : (cpt.msg.depth + 1).int32, + gas : childGasLimit, + sender : p.sender, + recipient : p.contractAddress, + code_address: p.codeAddress, + input_data : cpt.memory.readPtr(p.memInPos), + input_size : p.memInLen.uint, + value : toEvmc(p.value), + flags : p.flags + ) + c.execSubCall(msg, p) + else: + cpt.execSubCall( + memPos = p.memOutPos, + memLen = p.memOutLen, + childMsg = Message( + kind: EVMC_DELEGATECALL, + depth: cpt.msg.depth + 1, + gas: childGasLimit, + sender: p.sender, + contractAddress: p.contractAddress, + codeAddress: p.codeAddress, + value: p.value, + data: cpt.memory.read(p.memInPos, p.memInLen), + flags: p.flags)) + ok() - var (gasCost, childGasLimit) = res - gasCost += p.gasCallEIP2929 - if gasCost >= 0: - ? cpt.opcodeGastCost(DelegateCall, gasCost, reason = $DelegateCall) +# --------------------- - cpt.returnData.setLen(0) - if cpt.msg.depth >= MaxCallDepth: - debug "Computation Failure", - reason = "Stack too deep", - maximumDepth = MaxCallDepth, - depth = cpt.msg.depth - cpt.gasMeter.returnGas(childGasLimit) - return ok() +proc staticCallOp(k: var VmCtx): EvmResultVoid = + ## 0xfa, Static message-call into an account. - if gasCost < 0 and childGasLimit <= 0: - return err(opErr(OutOfGas)) + let + cpt = k.cpt + p = ? cpt.staticCallParams + res = ? cpt.gasCosts[StaticCall].c_handler( + p.value, + GasParams( + kind: StaticCall, + c_isNewAccount: not cpt.accountExists(p.contractAddress), + c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, + c_contractGas: p.gas, + c_currentMemSize: cpt.memory.len, + c_memOffset: p.memOffset, + c_memLength: p.memLength)) - cpt.memory.extend(p.memInPos, p.memInLen) - cpt.memory.extend(p.memOutPos, p.memOutLen) + var (gasCost, childGasLimit) = res + gasCost += p.gasCallEIP2929 + if gasCost >= 0: + ? cpt.opcodeGastCost(StaticCall, gasCost, reason = $StaticCall) - when evmc_enabled: - let - msg = new(nimbus_message) - c = cpt - msg[] = nimbus_message( - kind : EVMC_DELEGATECALL, - depth : (cpt.msg.depth + 1).int32, - gas : childGasLimit, - sender : p.sender, - recipient : p.contractAddress, - code_address: p.codeAddress, - input_data : cpt.memory.readPtr(p.memInPos), - input_size : p.memInLen.uint, - value : toEvmc(p.value), - flags : p.flags - ) - c.execSubCall(msg, p) - else: - cpt.execSubCall( - memPos = p.memOutPos, - memLen = p.memOutLen, - childMsg = Message( - kind: EVMC_DELEGATECALL, - depth: cpt.msg.depth + 1, - gas: childGasLimit, - sender: p.sender, - contractAddress: p.contractAddress, - codeAddress: p.codeAddress, - value: p.value, - data: cpt.memory.read(p.memInPos, p.memInLen), - flags: p.flags)) - ok() + cpt.returnData.setLen(0) - # --------------------- + if cpt.msg.depth >= MaxCallDepth: + debug "Computation Failure", + reason = "Stack too deep", + maximumDepth = MaxCallDepth, + depth = cpt.msg.depth + cpt.gasMeter.returnGas(childGasLimit) + return ok() - staticCallOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0xfa, Static message-call into an account. + if gasCost < 0 and childGasLimit <= 0: + return err(opErr(OutOfGas)) + cpt.memory.extend(p.memInPos, p.memInLen) + cpt.memory.extend(p.memOutPos, p.memOutLen) + + when evmc_enabled: let - cpt = k.cpt - p = ? cpt.staticCallParams - res = ? cpt.gasCosts[StaticCall].c_handler( - p.value, - GasParams( - kind: StaticCall, - c_isNewAccount: not cpt.accountExists(p.contractAddress), - c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, - c_contractGas: p.gas, - c_currentMemSize: cpt.memory.len, - c_memOffset: p.memOffset, - c_memLength: p.memLength)) - - var (gasCost, childGasLimit) = res - gasCost += p.gasCallEIP2929 - if gasCost >= 0: - ? cpt.opcodeGastCost(StaticCall, gasCost, reason = $StaticCall) - - cpt.returnData.setLen(0) - - if cpt.msg.depth >= MaxCallDepth: - debug "Computation Failure", - reason = "Stack too deep", - maximumDepth = MaxCallDepth, - depth = cpt.msg.depth - cpt.gasMeter.returnGas(childGasLimit) - return ok() - - if gasCost < 0 and childGasLimit <= 0: - return err(opErr(OutOfGas)) - - cpt.memory.extend(p.memInPos, p.memInLen) - cpt.memory.extend(p.memOutPos, p.memOutLen) - - when evmc_enabled: - let - msg = new(nimbus_message) - c = cpt - msg[] = nimbus_message( - kind : EVMC_CALL, - depth : (cpt.msg.depth + 1).int32, - gas : childGasLimit, - sender : p.sender, - recipient : p.contractAddress, - code_address: p.codeAddress, - input_data : cpt.memory.readPtr(p.memInPos), - input_size : p.memInLen.uint, - value : toEvmc(p.value), - flags : p.flags - ) - c.execSubCall(msg, p) - else: - cpt.execSubCall( - memPos = p.memOutPos, - memLen = p.memOutLen, - childMsg = Message( - kind: EVMC_CALL, - depth: cpt.msg.depth + 1, - gas: childGasLimit, - sender: p.sender, - contractAddress: p.contractAddress, - codeAddress: p.codeAddress, - value: p.value, - data: cpt.memory.read(p.memInPos, p.memInLen), - flags: p.flags)) - ok() + msg = new(nimbus_message) + c = cpt + msg[] = nimbus_message( + kind : EVMC_CALL, + depth : (cpt.msg.depth + 1).int32, + gas : childGasLimit, + sender : p.sender, + recipient : p.contractAddress, + code_address: p.codeAddress, + input_data : cpt.memory.readPtr(p.memInPos), + input_size : p.memInLen.uint, + value : toEvmc(p.value), + flags : p.flags + ) + c.execSubCall(msg, p) + else: + cpt.execSubCall( + memPos = p.memOutPos, + memLen = p.memOutLen, + childMsg = Message( + kind: EVMC_CALL, + depth: cpt.msg.depth + 1, + gas: childGasLimit, + sender: p.sender, + contractAddress: p.contractAddress, + codeAddress: p.codeAddress, + value: p.value, + data: cpt.memory.read(p.memInPos, p.memInLen), + flags: p.flags)) + ok() # ------------------------------------------------------------------------------ # Public, op exec table entries diff --git a/nimbus/evm/interpreter/op_handlers/oph_create.nim b/nimbus/evm/interpreter/op_handlers/oph_create.nim index 4ac2603a6..07ae4eb75 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_create.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_create.nim @@ -81,167 +81,167 @@ else: # Private, op handlers implementation # ------------------------------------------------------------------------------ -const - createOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0xf0, Create a new account with associated code - ? checkInStaticContext(k.cpt) - let - cpt = k.cpt - endowment = ? cpt.stack.popInt() - memPos = ? cpt.stack.popSafeInt() - memLen = ? cpt.stack.peekSafeInt() +proc createOp(k: var VmCtx): EvmResultVoid = + ## 0xf0, Create a new account with associated code + ? checkInStaticContext(k.cpt) - ? cpt.stack.top(0) + let + cpt = k.cpt + endowment = ? cpt.stack.popInt() + memPos = ? cpt.stack.popSafeInt() + memLen = ? cpt.stack.peekSafeInt() - # EIP-3860 - if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: - trace "Initcode size exceeds maximum", initcodeSize = memLen - return err(opErr(InvalidInitCode)) + ? cpt.stack.top(0) - let - gasParams = GasParams( - kind: Create, - cr_currentMemSize: cpt.memory.len, - cr_memOffset: memPos, - cr_memLength: memLen) - res = cpt.gasCosts[Create].cr_handler(1.u256, gasParams) + # EIP-3860 + if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: + trace "Initcode size exceeds maximum", initcodeSize = memLen + return err(opErr(InvalidInitCode)) - ? cpt.opcodeGastCost(Create, - res.gasCost, reason = "CREATE: GasCreate + memLen * memory expansion") - cpt.memory.extend(memPos, memLen) - cpt.returnData.setLen(0) + let + gasParams = GasParams( + kind: Create, + cr_currentMemSize: cpt.memory.len, + cr_memOffset: memPos, + cr_memLength: memLen) + res = cpt.gasCosts[Create].cr_handler(1.u256, gasParams) - if cpt.msg.depth >= MaxCallDepth: + ? cpt.opcodeGastCost(Create, + res.gasCost, reason = "CREATE: GasCreate + memLen * memory expansion") + cpt.memory.extend(memPos, memLen) + cpt.returnData.setLen(0) + + if cpt.msg.depth >= MaxCallDepth: + debug "Computation Failure", + reason = "Stack too deep", + maxDepth = MaxCallDepth, + depth = cpt.msg.depth + return ok() + + if endowment != 0: + let senderBalance = cpt.getBalance(cpt.msg.contractAddress) + if senderBalance < endowment: debug "Computation Failure", - reason = "Stack too deep", - maxDepth = MaxCallDepth, - depth = cpt.msg.depth + reason = "Insufficient funds available to transfer", + required = endowment, + balance = senderBalance return ok() - if endowment != 0: - let senderBalance = cpt.getBalance(cpt.msg.contractAddress) - if senderBalance < endowment: - debug "Computation Failure", - reason = "Insufficient funds available to transfer", - required = endowment, - balance = senderBalance - return ok() + var createMsgGas = cpt.gasMeter.gasRemaining + if cpt.fork >= FkTangerine: + createMsgGas -= createMsgGas div 64 + ? cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE msg gas") - var createMsgGas = cpt.gasMeter.gasRemaining - if cpt.fork >= FkTangerine: - createMsgGas -= createMsgGas div 64 - ? cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE msg gas") - - when evmc_enabled: - let - msg = new(nimbus_message) - c = cpt - msg[] = nimbus_message( - kind: EVMC_CREATE, - depth: (cpt.msg.depth + 1).int32, - gas: createMsgGas, + when evmc_enabled: + let + msg = new(nimbus_message) + c = cpt + msg[] = nimbus_message( + kind: EVMC_CREATE, + depth: (cpt.msg.depth + 1).int32, + gas: createMsgGas, + sender: cpt.msg.contractAddress, + input_data: cpt.memory.readPtr(memPos), + input_size: memLen.uint, + value: toEvmc(endowment), + create2_salt: toEvmc(ZERO_CONTRACTSALT), + ) + c.execSubCreate(msg) + else: + cpt.execSubCreate( + childMsg = Message( + kind: EVMC_CREATE, + depth: cpt.msg.depth + 1, + gas: createMsgGas, sender: cpt.msg.contractAddress, - input_data: cpt.memory.readPtr(memPos), - input_size: memLen.uint, - value: toEvmc(endowment), - create2_salt: toEvmc(ZERO_CONTRACTSALT), - ) - c.execSubCreate(msg) - else: - cpt.execSubCreate( - childMsg = Message( - kind: EVMC_CREATE, - depth: cpt.msg.depth + 1, - gas: createMsgGas, - sender: cpt.msg.contractAddress, - value: endowment, - data: cpt.memory.read(memPos, memLen))) - ok() + value: endowment, + data: cpt.memory.read(memPos, memLen))) + ok() - # --------------------- +# --------------------- - create2Op: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0xf5, Behaves identically to CREATE, except using keccak256 - ? checkInStaticContext(k.cpt) +proc create2Op(k: var VmCtx): EvmResultVoid = + ## 0xf5, Behaves identically to CREATE, except using keccak256 + ? checkInStaticContext(k.cpt) - let - cpt = k.cpt - endowment = ? cpt.stack.popInt() - memPos = ? cpt.stack.popSafeInt() - memLen = ? cpt.stack.popSafeInt() - salt256 = ? cpt.stack.peekInt() - salt = ContractSalt(bytes: salt256.toBytesBE) + let + cpt = k.cpt + endowment = ? cpt.stack.popInt() + memPos = ? cpt.stack.popSafeInt() + memLen = ? cpt.stack.popSafeInt() + salt256 = ? cpt.stack.peekInt() + salt = ContractSalt(bytes: salt256.toBytesBE) - ? cpt.stack.top(0) + ? cpt.stack.top(0) - # EIP-3860 - if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: - trace "Initcode size exceeds maximum", initcodeSize = memLen - return err(opErr(InvalidInitCode)) + # EIP-3860 + if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: + trace "Initcode size exceeds maximum", initcodeSize = memLen + return err(opErr(InvalidInitCode)) - let - gasParams = GasParams( - kind: Create, - cr_currentMemSize: cpt.memory.len, - cr_memOffset: memPos, - cr_memLength: memLen) - res = cpt.gasCosts[Create].cr_handler(1.u256, gasParams) + let + gasParams = GasParams( + kind: Create, + cr_currentMemSize: cpt.memory.len, + cr_memOffset: memPos, + cr_memLength: memLen) + res = cpt.gasCosts[Create].cr_handler(1.u256, gasParams) - let gasCost = res.gasCost + cpt.gasCosts[Create2].m_handler(0, 0, memLen) + let gasCost = res.gasCost + cpt.gasCosts[Create2].m_handler(0, 0, memLen) - ? cpt.opcodeGastCost(Create2, - gasCost, reason = "CREATE2: GasCreate + memLen * memory expansion") - cpt.memory.extend(memPos, memLen) - cpt.returnData.setLen(0) + ? cpt.opcodeGastCost(Create2, + gasCost, reason = "CREATE2: GasCreate + memLen * memory expansion") + cpt.memory.extend(memPos, memLen) + cpt.returnData.setLen(0) - if cpt.msg.depth >= MaxCallDepth: + if cpt.msg.depth >= MaxCallDepth: + debug "Computation Failure", + reason = "Stack too deep", + maxDepth = MaxCallDepth, + depth = cpt.msg.depth + return ok() + + if endowment != 0: + let senderBalance = cpt.getBalance(cpt.msg.contractAddress) + if senderBalance < endowment: debug "Computation Failure", - reason = "Stack too deep", - maxDepth = MaxCallDepth, - depth = cpt.msg.depth + reason = "Insufficient funds available to transfer", + required = endowment, + balance = senderBalance return ok() - if endowment != 0: - let senderBalance = cpt.getBalance(cpt.msg.contractAddress) - if senderBalance < endowment: - debug "Computation Failure", - reason = "Insufficient funds available to transfer", - required = endowment, - balance = senderBalance - return ok() + var createMsgGas = cpt.gasMeter.gasRemaining + if cpt.fork >= FkTangerine: + createMsgGas -= createMsgGas div 64 + ? cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE2 msg gas") - var createMsgGas = cpt.gasMeter.gasRemaining - if cpt.fork >= FkTangerine: - createMsgGas -= createMsgGas div 64 - ? cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE2 msg gas") - - when evmc_enabled: - let - msg = new(nimbus_message) - c = cpt - msg[] = nimbus_message( - kind: EVMC_CREATE2, - depth: (cpt.msg.depth + 1).int32, - gas: createMsgGas, + when evmc_enabled: + let + msg = new(nimbus_message) + c = cpt + msg[] = nimbus_message( + kind: EVMC_CREATE2, + depth: (cpt.msg.depth + 1).int32, + gas: createMsgGas, + sender: cpt.msg.contractAddress, + input_data: cpt.memory.readPtr(memPos), + input_size: memLen.uint, + value: toEvmc(endowment), + create2_salt: toEvmc(salt), + ) + c.execSubCreate(msg) + else: + cpt.execSubCreate( + salt = salt, + childMsg = Message( + kind: EVMC_CREATE2, + depth: cpt.msg.depth + 1, + gas: createMsgGas, sender: cpt.msg.contractAddress, - input_data: cpt.memory.readPtr(memPos), - input_size: memLen.uint, - value: toEvmc(endowment), - create2_salt: toEvmc(salt), - ) - c.execSubCreate(msg) - else: - cpt.execSubCreate( - salt = salt, - childMsg = Message( - kind: EVMC_CREATE2, - depth: cpt.msg.depth + 1, - gas: createMsgGas, - sender: cpt.msg.contractAddress, - value: endowment, - data: cpt.memory.read(memPos, memLen))) - ok() + value: endowment, + data: cpt.memory.read(memPos, memLen))) + ok() # ------------------------------------------------------------------------------ # Public, op exec table entries diff --git a/nimbus/evm/interpreter/op_handlers/oph_envinfo.nim b/nimbus/evm/interpreter/op_handlers/oph_envinfo.nim index ef856843f..03aeda9b9 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_envinfo.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_envinfo.nim @@ -35,213 +35,212 @@ when not defined(evmc_enabled): # Private, op handlers implementation # ------------------------------------------------------------------------------ -const - addressOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x30, Get address of currently executing account. - k.cpt.stack.push k.cpt.msg.contractAddress +proc addressOp (k: var VmCtx): EvmResultVoid = + ## 0x30, Get address of currently executing account. + k.cpt.stack.push k.cpt.msg.contractAddress - # ------------------ +# ------------------ - balanceOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x31, Get balance of the given account. - let - cpt = k.cpt - address = ? cpt.stack.popAddress - cpt.stack.push cpt.getBalance(address) +proc balanceOp (k: var VmCtx): EvmResultVoid = + ## 0x31, Get balance of the given account. + let + cpt = k.cpt + address = ? cpt.stack.popAddress + cpt.stack.push cpt.getBalance(address) - balanceEIP2929Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x31, EIP292: Get balance of the given account for Berlin and later - let - cpt = k.cpt - address = ? cpt.stack.popAddress() - gasCost = cpt.gasEip2929AccountCheck(address) +proc balanceEIP2929Op (k: var VmCtx): EvmResultVoid = + ## 0x31, EIP292: Get balance of the given account for Berlin and later + let + cpt = k.cpt + address = ? cpt.stack.popAddress() + gasCost = cpt.gasEip2929AccountCheck(address) - ? cpt.opcodeGastCost(Balance, gasCost, reason = "Balance EIP2929") - cpt.stack.push cpt.getBalance(address) + ? cpt.opcodeGastCost(Balance, gasCost, reason = "Balance EIP2929") + cpt.stack.push cpt.getBalance(address) - # ------------------ +# ------------------ - originOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x32, Get execution origination address. - k.cpt.stack.push k.cpt.getOrigin() +proc originOp (k: var VmCtx): EvmResultVoid = + ## 0x32, Get execution origination address. + k.cpt.stack.push k.cpt.getOrigin() - callerOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x33, Get caller address. - k.cpt.stack.push k.cpt.msg.sender +proc callerOp (k: var VmCtx): EvmResultVoid = + ## 0x33, Get caller address. + k.cpt.stack.push k.cpt.msg.sender - callValueOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x34, Get deposited value by the instruction/transaction - ## responsible for this execution - k.cpt.stack.push k.cpt.msg.value +proc callValueOp (k: var VmCtx): EvmResultVoid = + ## 0x34, Get deposited value by the instruction/transaction + ## responsible for this execution + k.cpt.stack.push k.cpt.msg.value - callDataLoadOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x35, Get input data of current environment - let - startPos = ? k.cpt.stack.popInt() - start = startPos.cleanMemRef +proc callDataLoadOp (k: var VmCtx): EvmResultVoid = + ## 0x35, Get input data of current environment + let + startPos = ? k.cpt.stack.popInt() + start = startPos.cleanMemRef - if start >= k.cpt.msg.data.len: - return k.cpt.stack.push 0 + if start >= k.cpt.msg.data.len: + return k.cpt.stack.push 0 - # If the data does not take 32 bytes, pad with zeros - let - endRange = min(k.cpt.msg.data.len - 1, start + 31) - presentBytes = endRange - start + # If the data does not take 32 bytes, pad with zeros + let + endRange = min(k.cpt.msg.data.len - 1, start + 31) + presentBytes = endRange - start - # We rely on value being initialized with 0 by default - var value: array[32, byte] - value[0 .. presentBytes] = k.cpt.msg.data.toOpenArray(start, endRange) - k.cpt.stack.push value + # We rely on value being initialized with 0 by default + var value: array[32, byte] + value[0 .. presentBytes] = k.cpt.msg.data.toOpenArray(start, endRange) + k.cpt.stack.push value - callDataSizeOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x36, Get size of input data in current environment. - k.cpt.stack.push k.cpt.msg.data.len.u256 +proc callDataSizeOp (k: var VmCtx): EvmResultVoid = + ## 0x36, Get size of input data in current environment. + k.cpt.stack.push k.cpt.msg.data.len.u256 - callDataCopyOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x37, Copy input data in current environment to memory. - let (memStartPos, copyStartPos, size) = ? k.cpt.stack.popInt(3) +proc callDataCopyOp (k: var VmCtx): EvmResultVoid = + ## 0x37, Copy input data in current environment to memory. + let (memStartPos, copyStartPos, size) = ? k.cpt.stack.popInt(3) - # TODO tests: https://github.com/status-im/nimbus/issues/67 - let (memPos, copyPos, len) = + # TODO tests: https://github.com/status-im/nimbus/issues/67 + let (memPos, copyPos, len) = + (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef) + + ? k.cpt.opcodeGastCost(CallDataCopy, + k.cpt.gasCosts[CallDataCopy].m_handler(k.cpt.memory.len, memPos, len), + reason = "CallDataCopy fee") + + k.cpt.memory.writePadded(k.cpt.msg.data, memPos, copyPos, len) + ok() + + +proc codeSizeOp (k: var VmCtx): EvmResultVoid = + ## 0x38, Get size of code running in current environment. + let cpt = k.cpt + cpt.stack.push cpt.code.len + + +proc codeCopyOp (k: var VmCtx): EvmResultVoid = + ## 0x39, Copy code running in current environment to memory. + let + cpt = k.cpt + (memStartPos, copyStartPos, size) = ? cpt.stack.popInt(3) + + # TODO tests: https://github.com/status-im/nimbus/issues/67 + let (memPos, copyPos, len) = + (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef) + + ? cpt.opcodeGastCost(CodeCopy, + cpt.gasCosts[CodeCopy].m_handler(cpt.memory.len, memPos, len), + reason = "CodeCopy fee") + + cpt.memory.writePadded(cpt.code.bytes, memPos, copyPos, len) + ok() + +proc gasPriceOp (k: var VmCtx): EvmResultVoid = + ## 0x3A, Get price of gas in current environment. + k.cpt.stack.push k.cpt.getGasPrice() + +# ----------- + +proc extCodeSizeOp (k: var VmCtx): EvmResultVoid = + ## 0x3b, Get size of an account's code + let + cpt = k.cpt + address = ? k.cpt.stack.popAddress() + + cpt.stack.push cpt.getCodeSize(address) + +proc extCodeSizeEIP2929Op (k: var VmCtx): EvmResultVoid = + ## 0x3b, Get size of an account's code + let + cpt = k.cpt + address = ? cpt.stack.popAddress() + gasCost = cpt.gasEip2929AccountCheck(address) + + ? cpt.opcodeGastCost(ExtCodeSize, gasCost, reason = "ExtCodeSize EIP2929") + cpt.stack.push cpt.getCodeSize(address) + +# ----------- + +proc extCodeCopyOp (k: var VmCtx): EvmResultVoid = + ## 0x3c, Copy an account's code to memory. + let + cpt = k.cpt + address = ? cpt.stack.popAddress() + (memStartPos, codeStartPos, size) = ? cpt.stack.popInt(3) + (memPos, codePos, len) = + (memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef) + + ? cpt.opcodeGastCost(ExtCodeCopy, + cpt.gasCosts[ExtCodeCopy].m_handler(cpt.memory.len, memPos, len), + reason = "ExtCodeCopy fee") + + let codeBytes = cpt.getCode(address) + cpt.memory.writePadded(codeBytes, memPos, codePos, len) + ok() + + +proc extCodeCopyEIP2929Op (k: var VmCtx): EvmResultVoid = + ## 0x3c, Copy an account's code to memory. + let + cpt = k.cpt + address = ? cpt.stack.popAddress() + (memStartPos, codeStartPos, size) = ? cpt.stack.popInt(3) + (memPos, codePos, len) = (memStartPos.cleanMemRef, + codeStartPos.cleanMemRef, size.cleanMemRef) + + gasCost = cpt.gasCosts[ExtCodeCopy].m_handler(cpt.memory.len, memPos, len) + + cpt.gasEip2929AccountCheck(address) + ? cpt.opcodeGastCost(ExtCodeCopy, gasCost, reason = "ExtCodeCopy EIP2929") + + let codeBytes = cpt.getCode(address) + cpt.memory.writePadded(codeBytes, memPos, codePos, len) + ok() + +# ----------- + +proc returnDataSizeOp (k: var VmCtx): EvmResultVoid = + ## 0x3d, Get size of output data from the previous call from the + ## current environment. + k.cpt.stack.push k.cpt.returnData.len + + +proc returnDataCopyOp (k: var VmCtx): EvmResultVoid = + ## 0x3e, Copy output data from the previous call to memory. + let + (memStartPos, copyStartPos, size) = ? k.cpt.stack.popInt(3) + (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef) + gasCost = k.cpt.gasCosts[ReturnDataCopy].m_handler( + k.cpt.memory.len, memPos, len) - ? k.cpt.opcodeGastCost(CallDataCopy, - k.cpt.gasCosts[CallDataCopy].m_handler(k.cpt.memory.len, memPos, len), - reason = "CallDataCopy fee") + ? k.cpt.opcodeGastCost(ReturnDataCopy, gasCost, reason = "returnDataCopy fee") - k.cpt.memory.writePadded(k.cpt.msg.data, memPos, copyPos, len) - ok() + if copyPos + len > k.cpt.returnData.len: + return err(opErr(OutOfBounds)) + k.cpt.memory.writePadded(k.cpt.returnData, memPos, copyPos, len) + ok() +# --------------- - codeSizeOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x38, Get size of code running in current environment. - let cpt = k.cpt - cpt.stack.push cpt.code.len +proc extCodeHashOp (k: var VmCtx): EvmResultVoid = + ## 0x3f, Returns the keccak256 hash of a contract’s code + let + cpt = k.cpt + address = ? k.cpt.stack.popAddress() + cpt.stack.push cpt.getCodeHash(address) - codeCopyOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x39, Copy code running in current environment to memory. - let - cpt = k.cpt - (memStartPos, copyStartPos, size) = ? cpt.stack.popInt(3) +proc extCodeHashEIP2929Op (k: var VmCtx): EvmResultVoid = + ## 0x3f, EIP2929: Returns the keccak256 hash of a contract’s code + let + cpt = k.cpt + address = ? k.cpt.stack.popAddress() + gasCost = cpt.gasEip2929AccountCheck(address) - # TODO tests: https://github.com/status-im/nimbus/issues/67 - let (memPos, copyPos, len) = - (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef) - - ? cpt.opcodeGastCost(CodeCopy, - cpt.gasCosts[CodeCopy].m_handler(cpt.memory.len, memPos, len), - reason = "CodeCopy fee") - - cpt.memory.writePadded(cpt.code.bytes, memPos, copyPos, len) - ok() - - gasPriceOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x3A, Get price of gas in current environment. - k.cpt.stack.push k.cpt.getGasPrice() - - # ----------- - - extCodeSizeOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x3b, Get size of an account's code - let - cpt = k.cpt - address = ? k.cpt.stack.popAddress() - - cpt.stack.push cpt.getCodeSize(address) - - extCodeSizeEIP2929Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x3b, Get size of an account's code - let - cpt = k.cpt - address = ? cpt.stack.popAddress() - gasCost = cpt.gasEip2929AccountCheck(address) - - ? cpt.opcodeGastCost(ExtCodeSize, gasCost, reason = "ExtCodeSize EIP2929") - cpt.stack.push cpt.getCodeSize(address) - - # ----------- - - extCodeCopyOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x3c, Copy an account's code to memory. - let - cpt = k.cpt - address = ? cpt.stack.popAddress() - (memStartPos, codeStartPos, size) = ? cpt.stack.popInt(3) - (memPos, codePos, len) = - (memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef) - - ? cpt.opcodeGastCost(ExtCodeCopy, - cpt.gasCosts[ExtCodeCopy].m_handler(cpt.memory.len, memPos, len), - reason = "ExtCodeCopy fee") - - let codeBytes = cpt.getCode(address) - cpt.memory.writePadded(codeBytes, memPos, codePos, len) - ok() - - - extCodeCopyEIP2929Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x3c, Copy an account's code to memory. - let - cpt = k.cpt - address = ? cpt.stack.popAddress() - (memStartPos, codeStartPos, size) = ? cpt.stack.popInt(3) - (memPos, codePos, len) = (memStartPos.cleanMemRef, - codeStartPos.cleanMemRef, size.cleanMemRef) - - gasCost = cpt.gasCosts[ExtCodeCopy].m_handler(cpt.memory.len, memPos, len) + - cpt.gasEip2929AccountCheck(address) - ? cpt.opcodeGastCost(ExtCodeCopy, gasCost, reason = "ExtCodeCopy EIP2929") - - let codeBytes = cpt.getCode(address) - cpt.memory.writePadded(codeBytes, memPos, codePos, len) - ok() - - # ----------- - - returnDataSizeOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x3d, Get size of output data from the previous call from the - ## current environment. - k.cpt.stack.push k.cpt.returnData.len - - - returnDataCopyOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x3e, Copy output data from the previous call to memory. - let - (memStartPos, copyStartPos, size) = ? k.cpt.stack.popInt(3) - (memPos, copyPos, len) = - (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef) - gasCost = k.cpt.gasCosts[ReturnDataCopy].m_handler( - k.cpt.memory.len, memPos, len) - - ? k.cpt.opcodeGastCost(ReturnDataCopy, gasCost, reason = "returnDataCopy fee") - - if copyPos + len > k.cpt.returnData.len: - return err(opErr(OutOfBounds)) - k.cpt.memory.writePadded(k.cpt.returnData, memPos, copyPos, len) - ok() - - # --------------- - - extCodeHashOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x3f, Returns the keccak256 hash of a contract’s code - let - cpt = k.cpt - address = ? k.cpt.stack.popAddress() - - cpt.stack.push cpt.getCodeHash(address) - - extCodeHashEIP2929Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x3f, EIP2929: Returns the keccak256 hash of a contract’s code - let - cpt = k.cpt - address = ? k.cpt.stack.popAddress() - gasCost = cpt.gasEip2929AccountCheck(address) - - ? cpt.opcodeGastCost(ExtCodeHash, gasCost, reason = "ExtCodeHash EIP2929") - cpt.stack.push cpt.getCodeHash(address) + ? cpt.opcodeGastCost(ExtCodeHash, gasCost, reason = "ExtCodeHash EIP2929") + cpt.stack.push cpt.getCodeHash(address) # ------------------------------------------------------------------------------ # Public, op exec table entries @@ -255,7 +254,7 @@ const name: "address", info: "Get address of currently executing account", exec: (prep: VmOpIgnore, - run: addressOp, + run: VmOpFn addressOp, post: VmOpIgnore)), (opCode: Balance, ## 0x31, Balance diff --git a/nimbus/evm/interpreter/op_handlers/oph_hash.nim b/nimbus/evm/interpreter/op_handlers/oph_hash.nim index 1e1a4f7f6..595fd8eb1 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_hash.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_hash.nim @@ -30,27 +30,26 @@ import # Private, op handlers implementation # ------------------------------------------------------------------------------ -const - sha3Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x20, Compute Keccak-256 hash. - let - (startPos, length) = ? k.cpt.stack.popInt(2) - (pos, len) = (startPos.safeInt, length.safeInt) +proc sha3Op(k: var VmCtx): EvmResultVoid = + ## 0x20, Compute Keccak-256 hash. + let + (startPos, length) = ? k.cpt.stack.popInt(2) + (pos, len) = (startPos.safeInt, length.safeInt) - if pos < 0 or len < 0 or pos > 2147483648'i64: - return err(opErr(OutOfBounds)) + if pos < 0 or len < 0 or pos > 2147483648'i64: + return err(opErr(OutOfBounds)) - ? k.cpt.opcodeGastCost(Op.Sha3, - k.cpt.gasCosts[Op.Sha3].m_handler(k.cpt.memory.len, pos, len), - reason = "SHA3: word gas cost") + ? k.cpt.opcodeGastCost(Op.Sha3, + k.cpt.gasCosts[Op.Sha3].m_handler(k.cpt.memory.len, pos, len), + reason = "SHA3: word gas cost") - k.cpt.memory.extend(pos, len) + k.cpt.memory.extend(pos, len) - let endRange = min(pos + len, k.cpt.memory.len) - 1 - if endRange == -1 or pos >= k.cpt.memory.len: - k.cpt.stack.push(EMPTY_SHA3) - else: - k.cpt.stack.push keccakHash k.cpt.memory.bytes.toOpenArray(pos, endRange) + let endRange = min(pos + len, k.cpt.memory.len) - 1 + if endRange == -1 or pos >= k.cpt.memory.len: + k.cpt.stack.push(EMPTY_SHA3) + else: + k.cpt.stack.push keccakHash k.cpt.memory.bytes.toOpenArray(pos, endRange) # ------------------------------------------------------------------------------ # Public, op exec table entries diff --git a/nimbus/evm/interpreter/op_handlers/oph_memory.nim b/nimbus/evm/interpreter/op_handlers/oph_memory.nim index 3743dfb41..8e8732c32 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_memory.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_memory.nim @@ -122,197 +122,196 @@ func jumpImpl(c: Computation; jumpTarget: UInt256): EvmResultVoid = # Private, op handlers implementation # ------------------------------------------------------------------------------ -const - popOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = - ## 0x50, Remove item from stack. - k.cpt.stack.popInt.isOkOr: - return err(error) - ok() +proc popOp(k: var VmCtx): EvmResultVoid = + ## 0x50, Remove item from stack. + k.cpt.stack.popInt.isOkOr: + return err(error) + ok() - mloadOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x51, Load word from memory - let memStartPos = ? k.cpt.stack.popInt() +proc mloadOp (k: var VmCtx): EvmResultVoid = + ## 0x51, Load word from memory + let memStartPos = ? k.cpt.stack.popInt() - let memPos = memStartPos.cleanMemRef - ? k.cpt.opcodeGastCost(Mload, - k.cpt.gasCosts[Mload].m_handler(k.cpt.memory.len, memPos, 32), - reason = "MLOAD: GasVeryLow + memory expansion") + let memPos = memStartPos.cleanMemRef + ? k.cpt.opcodeGastCost(Mload, + k.cpt.gasCosts[Mload].m_handler(k.cpt.memory.len, memPos, 32), + reason = "MLOAD: GasVeryLow + memory expansion") - k.cpt.memory.extend(memPos, 32) - k.cpt.stack.push k.cpt.memory.read32Bytes(memPos) + k.cpt.memory.extend(memPos, 32) + k.cpt.stack.push k.cpt.memory.read32Bytes(memPos) - mstoreOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x52, Save word to memory - let (memStartPos, value) = ? k.cpt.stack.popInt(2) +proc mstoreOp (k: var VmCtx): EvmResultVoid = + ## 0x52, Save word to memory + let (memStartPos, value) = ? k.cpt.stack.popInt(2) - let memPos = memStartPos.cleanMemRef - ? k.cpt.opcodeGastCost(Mstore, - k.cpt.gasCosts[Mstore].m_handler(k.cpt.memory.len, memPos, 32), - reason = "MSTORE: GasVeryLow + memory expansion") + let memPos = memStartPos.cleanMemRef + ? k.cpt.opcodeGastCost(Mstore, + k.cpt.gasCosts[Mstore].m_handler(k.cpt.memory.len, memPos, 32), + reason = "MSTORE: GasVeryLow + memory expansion") - k.cpt.memory.extend(memPos, 32) - k.cpt.memory.write(memPos, value.toBytesBE) + k.cpt.memory.extend(memPos, 32) + k.cpt.memory.write(memPos, value.toBytesBE) - mstore8Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x53, Save byte to memory - let (memStartPos, value) = ? k.cpt.stack.popInt(2) +proc mstore8Op (k: var VmCtx): EvmResultVoid = + ## 0x53, Save byte to memory + let (memStartPos, value) = ? k.cpt.stack.popInt(2) - let memPos = memStartPos.cleanMemRef - ? k.cpt.opcodeGastCost(Mstore8, - k.cpt.gasCosts[Mstore8].m_handler(k.cpt.memory.len, memPos, 1), - reason = "MSTORE8: GasVeryLow + memory expansion") + let memPos = memStartPos.cleanMemRef + ? k.cpt.opcodeGastCost(Mstore8, + k.cpt.gasCosts[Mstore8].m_handler(k.cpt.memory.len, memPos, 1), + reason = "MSTORE8: GasVeryLow + memory expansion") - k.cpt.memory.extend(memPos, 1) - k.cpt.memory.write(memPos, value.toByteArrayBE[31]) + k.cpt.memory.extend(memPos, 1) + k.cpt.memory.write(memPos, value.toByteArrayBE[31]) - # ------- +# ------- - sloadOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x54, Load word from storage. - let - cpt = k.cpt - slot = ? cpt.stack.popInt() - cpt.stack.push cpt.getStorage(slot) +proc sloadOp (k: var VmCtx): EvmResultVoid = + ## 0x54, Load word from storage. + let + cpt = k.cpt + slot = ? cpt.stack.popInt() + cpt.stack.push cpt.getStorage(slot) - sloadEIP2929Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x54, EIP2929: Load word from storage for Berlin and later - let - cpt = k.cpt - slot = ? cpt.stack.popInt() - gasCost = cpt.gasEip2929AccountCheck(cpt.msg.contractAddress, slot) - ? cpt.opcodeGastCost(Sload, gasCost, reason = "sloadEIP2929") - cpt.stack.push cpt.getStorage(slot) +proc sloadEIP2929Op (k: var VmCtx): EvmResultVoid = + ## 0x54, EIP2929: Load word from storage for Berlin and later + let + cpt = k.cpt + slot = ? cpt.stack.popInt() + gasCost = cpt.gasEip2929AccountCheck(cpt.msg.contractAddress, slot) + ? cpt.opcodeGastCost(Sload, gasCost, reason = "sloadEIP2929") + cpt.stack.push cpt.getStorage(slot) - # ------- +# ------- - sstoreOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x55, Save word to storage. - let - cpt = k.cpt - (slot, newValue) = ? cpt.stack.popInt(2) +proc sstoreOp (k: var VmCtx): EvmResultVoid = + ## 0x55, Save word to storage. + let + cpt = k.cpt + (slot, newValue) = ? cpt.stack.popInt(2) - ? checkInStaticContext(cpt) - sstoreEvmcOrSstore(cpt, slot, newValue) + ? checkInStaticContext(cpt) + sstoreEvmcOrSstore(cpt, slot, newValue) - sstoreEIP1283Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x55, EIP1283: sstore for Constantinople and later - let - cpt = k.cpt - (slot, newValue) = ? cpt.stack.popInt(2) +proc sstoreEIP1283Op (k: var VmCtx): EvmResultVoid = + ## 0x55, EIP1283: sstore for Constantinople and later + let + cpt = k.cpt + (slot, newValue) = ? cpt.stack.popInt(2) - ? checkInStaticContext(cpt) - sstoreEvmcOrNetGasMetering(cpt, slot, newValue) + ? checkInStaticContext(cpt) + sstoreEvmcOrNetGasMetering(cpt, slot, newValue) - sstoreEIP2200Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x55, EIP2200: sstore for Istanbul and later - let - cpt = k.cpt - (slot, newValue) = ? cpt.stack.popInt(2) +proc sstoreEIP2200Op (k: var VmCtx): EvmResultVoid = + ## 0x55, EIP2200: sstore for Istanbul and later + let + cpt = k.cpt + (slot, newValue) = ? cpt.stack.popInt(2) - ? checkInStaticContext(cpt) - const SentryGasEIP2200 = 2300 + ? checkInStaticContext(cpt) + const SentryGasEIP2200 = 2300 - if cpt.gasMeter.gasRemaining <= SentryGasEIP2200: - return err(opErr(OutOfGas)) + if cpt.gasMeter.gasRemaining <= SentryGasEIP2200: + return err(opErr(OutOfGas)) - sstoreEvmcOrNetGasMetering(cpt, slot, newValue) + sstoreEvmcOrNetGasMetering(cpt, slot, newValue) - sstoreEIP2929Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x55, EIP2929: sstore for Berlin and later - let - cpt = k.cpt - (slot, newValue) = ? cpt.stack.popInt(2) +proc sstoreEIP2929Op (k: var VmCtx): EvmResultVoid = + ## 0x55, EIP2929: sstore for Berlin and later + let + cpt = k.cpt + (slot, newValue) = ? cpt.stack.popInt(2) - ? checkInStaticContext(cpt) + ? checkInStaticContext(cpt) - # Minimum gas required to be present for an SSTORE call, not consumed - const SentryGasEIP2200 = 2300 + # Minimum gas required to be present for an SSTORE call, not consumed + const SentryGasEIP2200 = 2300 - if cpt.gasMeter.gasRemaining <= SentryGasEIP2200: - return err(opErr(OutOfGas)) + if cpt.gasMeter.gasRemaining <= SentryGasEIP2200: + return err(opErr(OutOfGas)) - var coldAccessGas = 0.GasInt - when evmc_enabled: - if cpt.host.accessStorage(cpt.msg.contractAddress, slot) == EVMC_ACCESS_COLD: + var coldAccessGas = 0.GasInt + when evmc_enabled: + if cpt.host.accessStorage(cpt.msg.contractAddress, slot) == EVMC_ACCESS_COLD: + coldAccessGas = ColdSloadCost + else: + cpt.vmState.mutateStateDB: + if not db.inAccessList(cpt.msg.contractAddress, slot): + db.accessList(cpt.msg.contractAddress, slot) coldAccessGas = ColdSloadCost - else: - cpt.vmState.mutateStateDB: - if not db.inAccessList(cpt.msg.contractAddress, slot): - db.accessList(cpt.msg.contractAddress, slot) - coldAccessGas = ColdSloadCost - sstoreEvmcOrNetGasMetering(cpt, slot, newValue, coldAccessGas) + sstoreEvmcOrNetGasMetering(cpt, slot, newValue, coldAccessGas) - # ------- +# ------- - jumpOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = - ## 0x56, Alter the program counter - let jumpTarget = ? k.cpt.stack.popInt() - jumpImpl(k.cpt, jumpTarget) +proc jumpOp (k: var VmCtx): EvmResultVoid = + ## 0x56, Alter the program counter + let jumpTarget = ? k.cpt.stack.popInt() + jumpImpl(k.cpt, jumpTarget) - jumpIOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = - ## 0x57, Conditionally alter the program counter. - let (jumpTarget, testedValue) = ? k.cpt.stack.popInt(2) - if testedValue.isZero: - return ok() - jumpImpl(k.cpt, jumpTarget) +proc jumpIOp (k: var VmCtx): EvmResultVoid = + ## 0x57, Conditionally alter the program counter. + let (jumpTarget, testedValue) = ? k.cpt.stack.popInt(2) + if testedValue.isZero: + return ok() + jumpImpl(k.cpt, jumpTarget) - pcOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = - ## 0x58, Get the value of the program counter prior to the increment - ## corresponding to this instruction. - k.cpt.stack.push max(k.cpt.code.pc - 1, 0) +proc pcOp (k: var VmCtx): EvmResultVoid = + ## 0x58, Get the value of the program counter prior to the increment + ## corresponding to this instruction. + k.cpt.stack.push max(k.cpt.code.pc - 1, 0) - msizeOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = - ## 0x59, Get the size of active memory in bytes. - k.cpt.stack.push k.cpt.memory.len +proc msizeOp (k: var VmCtx): EvmResultVoid = + ## 0x59, Get the size of active memory in bytes. + k.cpt.stack.push k.cpt.memory.len - gasOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = - ## 0x5a, Get the amount of available gas, including the corresponding - ## reduction for the cost of this instruction. - k.cpt.stack.push k.cpt.gasMeter.gasRemaining +proc gasOp (k: var VmCtx): EvmResultVoid = + ## 0x5a, Get the amount of available gas, including the corresponding + ## reduction for the cost of this instruction. + k.cpt.stack.push k.cpt.gasMeter.gasRemaining - jumpDestOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = - ## 0x5b, Mark a valid destination for jumps. This operation has no effect - ## on machine state during execution. - ok() +proc jumpDestOp (k: var VmCtx): EvmResultVoid = + ## 0x5b, Mark a valid destination for jumps. This operation has no effect + ## on machine state during execution. + ok() - tloadOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x5c, Load word from transient storage. - let - slot = ? k.cpt.stack.popInt() - val = k.cpt.getTransientStorage(slot) - k.cpt.stack.push val +proc tloadOp (k: var VmCtx): EvmResultVoid = + ## 0x5c, Load word from transient storage. + let + slot = ? k.cpt.stack.popInt() + val = k.cpt.getTransientStorage(slot) + k.cpt.stack.push val - tstoreOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x5d, Save word to transient storage. - ? checkInStaticContext(k.cpt) +proc tstoreOp (k: var VmCtx): EvmResultVoid = + ## 0x5d, Save word to transient storage. + ? checkInStaticContext(k.cpt) - let - slot = ? k.cpt.stack.popInt() - val = ? k.cpt.stack.popInt() - k.cpt.setTransientStorage(slot, val) - ok() + let + slot = ? k.cpt.stack.popInt() + val = ? k.cpt.stack.popInt() + k.cpt.setTransientStorage(slot, val) + ok() - mCopyOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x5e, Copy memory - let (dst, src, size) = ? k.cpt.stack.popInt(3) +proc mCopyOp (k: var VmCtx): EvmResultVoid = + ## 0x5e, Copy memory + let (dst, src, size) = ? k.cpt.stack.popInt(3) - let (dstPos, srcPos, len) = - (dst.cleanMemRef, src.cleanMemRef, size.cleanMemRef) + let (dstPos, srcPos, len) = + (dst.cleanMemRef, src.cleanMemRef, size.cleanMemRef) - ? k.cpt.opcodeGastCost(Mcopy, - k.cpt.gasCosts[Mcopy].m_handler(k.cpt.memory.len, max(dstPos, srcPos), len), - reason = "Mcopy fee") + ? k.cpt.opcodeGastCost(Mcopy, + k.cpt.gasCosts[Mcopy].m_handler(k.cpt.memory.len, max(dstPos, srcPos), len), + reason = "Mcopy fee") - k.cpt.memory.copy(dstPos, srcPos, len) - ok() + k.cpt.memory.copy(dstPos, srcPos, len) + ok() # ------------------------------------------------------------------------------ # Public, op exec table entries @@ -326,7 +325,7 @@ const name: "pop", info: "Remove item from stack", exec: (prep: VmOpIgnore, - run: popOp, + run: VmOpFn popOp, post: VmOpIgnore)), (opCode: Mload, ## 0x51, Load word from memory diff --git a/nimbus/evm/interpreter/op_handlers/oph_push.nim b/nimbus/evm/interpreter/op_handlers/oph_push.nim index 2aad8435c..da025418a 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_push.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_push.nim @@ -65,11 +65,11 @@ genOphList fnName, fnInfo, inxRange, "VmOpExecPush", opName # about which opcodes are for which forks, but that seems uglier than # just adding Push0 here as a special case.) -const - push0Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = - ## 0x5f, push 0 onto the stack - k.cpt.stack.push(0) +proc push0Op(k: var VmCtx): EvmResultVoid = + ## 0x5f, push 0 onto the stack + k.cpt.stack.push(0) +const VmOpExecPushZero*: seq[VmOpExec] = @[ (opCode: Push0, ## 0x5f, push 0 onto the stack diff --git a/nimbus/evm/interpreter/op_handlers/oph_sysops.nim b/nimbus/evm/interpreter/op_handlers/oph_sysops.nim index 8884fd607..706ecfe25 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_sysops.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_sysops.nim @@ -37,121 +37,120 @@ when not defined(evmc_enabled): # Private # ------------------------------------------------------------------------------ -const - returnOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0xf3, Halt execution returning output data. - let (startPos, size) = ? k.cpt.stack.popInt(2) +proc returnOp(k: var VmCtx): EvmResultVoid = + ## 0xf3, Halt execution returning output data. + let (startPos, size) = ? k.cpt.stack.popInt(2) - let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef) - ? k.cpt.opcodeGastCost(Return, - k.cpt.gasCosts[Return].m_handler(k.cpt.memory.len, pos, len), - reason = "RETURN") - k.cpt.memory.extend(pos, len) - k.cpt.output = k.cpt.memory.read(pos, len) - ok() + let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef) + ? k.cpt.opcodeGastCost(Return, + k.cpt.gasCosts[Return].m_handler(k.cpt.memory.len, pos, len), + reason = "RETURN") + k.cpt.memory.extend(pos, len) + k.cpt.output = k.cpt.memory.read(pos, len) + ok() - revertOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0xfd, Halt execution reverting state changes but returning data - ## and remaining gas. - let (startPos, size) = ? k.cpt.stack.popInt(2) +proc revertOp(k: var VmCtx): EvmResultVoid = + ## 0xfd, Halt execution reverting state changes but returning data + ## and remaining gas. + let (startPos, size) = ? k.cpt.stack.popInt(2) - let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef) - ? k.cpt.opcodeGastCost(Revert, - k.cpt.gasCosts[Revert].m_handler(k.cpt.memory.len, pos, len), - reason = "REVERT") + let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef) + ? k.cpt.opcodeGastCost(Revert, + k.cpt.gasCosts[Revert].m_handler(k.cpt.memory.len, pos, len), + reason = "REVERT") - k.cpt.memory.extend(pos, len) - k.cpt.output = k.cpt.memory.read(pos, len) - # setError(msg, false) will signal cheap revert - k.cpt.setError(EVMC_REVERT, "REVERT opcode executed", false) - ok() + k.cpt.memory.extend(pos, len) + k.cpt.output = k.cpt.memory.read(pos, len) + # setError(msg, false) will signal cheap revert + k.cpt.setError(EVMC_REVERT, "REVERT opcode executed", false) + ok() - invalidOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - err(opErr(InvalidInstruction)) +proc invalidOp(k: var VmCtx): EvmResultVoid = + err(opErr(InvalidInstruction)) - # ----------- +# ----------- - selfDestructOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## 0xff, Halt execution and register account for later deletion. - let cpt = k.cpt - let beneficiary = ? cpt.stack.popAddress() - when defined(evmc_enabled): - block: - cpt.selfDestruct(beneficiary) - else: - block: - cpt.selfDestruct(beneficiary) - ok() - - selfDestructEIP150Op: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## selfDestructEip150 (auto generated comment) - let cpt = k.cpt - let beneficiary = ? cpt.stack.popAddress() +proc selfDestructOp(k: var VmCtx): EvmResultVoid = + ## 0xff, Halt execution and register account for later deletion. + let cpt = k.cpt + let beneficiary = ? cpt.stack.popAddress() + when defined(evmc_enabled): block: - let gasParams = GasParams( - kind: SelfDestruct, - sd_condition: not cpt.accountExists(beneficiary)) - - let res = ? cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams) - ? cpt.opcodeGastCost(SelfDestruct, - res.gasCost, reason = "SELFDESTRUCT EIP150") cpt.selfDestruct(beneficiary) - ok() - - selfDestructEIP161Op: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## selfDestructEip161 (auto generated comment) - let cpt = k.cpt - ? checkInStaticContext(cpt) - - let beneficiary = ? cpt.stack.popAddress() + else: block: - let - isDead = not cpt.accountExists(beneficiary) - balance = cpt.getBalance(cpt.msg.contractAddress) + cpt.selfDestruct(beneficiary) + ok() - let gasParams = GasParams( +proc selfDestructEIP150Op(k: var VmCtx): EvmResultVoid = + ## selfDestructEip150 (auto generated comment) + let cpt = k.cpt + let beneficiary = ? cpt.stack.popAddress() + block: + let gasParams = GasParams( + kind: SelfDestruct, + sd_condition: not cpt.accountExists(beneficiary)) + + let res = ? cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams) + ? cpt.opcodeGastCost(SelfDestruct, + res.gasCost, reason = "SELFDESTRUCT EIP150") + cpt.selfDestruct(beneficiary) + ok() + +proc selfDestructEIP161Op(k: var VmCtx): EvmResultVoid = + ## selfDestructEip161 (auto generated comment) + let cpt = k.cpt + ? checkInStaticContext(cpt) + + let beneficiary = ? cpt.stack.popAddress() + block: + let + isDead = not cpt.accountExists(beneficiary) + balance = cpt.getBalance(cpt.msg.contractAddress) + + let gasParams = GasParams( + kind: SelfDestruct, + sd_condition: isDead and not balance.isZero) + + let res = ? cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams) + ? cpt.opcodeGastCost(SelfDestruct, + res.gasCost, reason = "SELFDESTRUCT EIP161") + cpt.selfDestruct(beneficiary) + ok() + +proc selfDestructEIP2929Op(k: var VmCtx): EvmResultVoid = + ## selfDestructEIP2929 (auto generated comment) + let cpt = k.cpt + ? checkInStaticContext(cpt) + + let beneficiary = ? cpt.stack.popAddress() + block: + let + isDead = not cpt.accountExists(beneficiary) + balance = cpt.getBalance(cpt.msg.contractAddress) + + let + gasParams = GasParams( kind: SelfDestruct, sd_condition: isDead and not balance.isZero) + res = ? cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams) - let res = ? cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams) - ? cpt.opcodeGastCost(SelfDestruct, - res.gasCost, reason = "SELFDESTRUCT EIP161") - cpt.selfDestruct(beneficiary) - ok() + var gasCost = res.gasCost - selfDestructEIP2929Op: VmOpFn = proc(k: var VmCtx): EvmResultVoid = - ## selfDestructEIP2929 (auto generated comment) - let cpt = k.cpt - ? checkInStaticContext(cpt) - - let beneficiary = ? cpt.stack.popAddress() - block: - let - isDead = not cpt.accountExists(beneficiary) - balance = cpt.getBalance(cpt.msg.contractAddress) - - let - gasParams = GasParams( - kind: SelfDestruct, - sd_condition: isDead and not balance.isZero) - res = ? cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams) - - var gasCost = res.gasCost - - when evmc_enabled: - if cpt.host.accessAccount(beneficiary) == EVMC_ACCESS_COLD: + when evmc_enabled: + if cpt.host.accessAccount(beneficiary) == EVMC_ACCESS_COLD: + gasCost = gasCost + ColdAccountAccessCost + else: + cpt.vmState.mutateStateDB: + if not db.inAccessList(beneficiary): + db.accessList(beneficiary) gasCost = gasCost + ColdAccountAccessCost - else: - cpt.vmState.mutateStateDB: - if not db.inAccessList(beneficiary): - db.accessList(beneficiary) - gasCost = gasCost + ColdAccountAccessCost - ? cpt.opcodeGastCost(SelfDestruct, - gasCost, reason = "SELFDESTRUCT EIP2929") - cpt.selfDestruct(beneficiary) - ok() + ? cpt.opcodeGastCost(SelfDestruct, + gasCost, reason = "SELFDESTRUCT EIP2929") + cpt.selfDestruct(beneficiary) + ok() # ------------------------------------------------------------------------------ # Public, op exec table entries