avoid intermediate const in opcodes (#2381)

The extra layer of `const` makes the function name harder to see a
debugger / profiler
This commit is contained in:
Jacek Sieka 2024-06-17 18:13:38 +02:00 committed by GitHub
parent 2aaab1cb4a
commit 135ef222a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 1123 additions and 1130 deletions

View File

@ -37,248 +37,247 @@ func slt(x, y: UInt256): bool =
# Private, op handlers implementation # Private, op handlers implementation
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
const proc addOp (k: var VmCtx): EvmResultVoid =
addOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = ## 0x01, Addition
## 0x01, Addition let (lhs, rhs) = ? k.cpt.stack.popInt(2)
let (lhs, rhs) = ? k.cpt.stack.popInt(2) k.cpt.stack.push(lhs + rhs)
k.cpt.stack.push(lhs + rhs)
mulOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = proc mulOp(k: var VmCtx): EvmResultVoid =
## 0x02, Multiplication ## 0x02, Multiplication
let (lhs, rhs) = ? k.cpt.stack.popInt(2) let (lhs, rhs) = ? k.cpt.stack.popInt(2)
k.cpt.stack.push(lhs * rhs) k.cpt.stack.push(lhs * rhs)
subOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = proc subOp(k: var VmCtx): EvmResultVoid =
## 0x03, Substraction ## 0x03, Substraction
let (lhs, rhs) = ? k.cpt.stack.popInt(2) let (lhs, rhs) = ? k.cpt.stack.popInt(2)
k.cpt.stack.push(lhs - rhs) k.cpt.stack.push(lhs - rhs)
divideOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = proc divideOp(k: var VmCtx): EvmResultVoid =
## 0x04, Division ## 0x04, Division
let let
(lhs, rhs) = ? k.cpt.stack.popInt(2) (lhs, rhs) = ? k.cpt.stack.popInt(2)
value = if rhs.isZero: value = if rhs.isZero:
# EVM special casing of div by 0 # 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 twos 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:
zero(UInt256) zero(UInt256)
else: else:
let pos = position.truncate(int) lhs div rhs
when system.cpuEndian == bigEndian:
cast[array[32, byte]](value)[pos].u256 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: 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 twos complement signed integer.
let (bits, value) = ? k.cpt.stack.popInt(2)
shlOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = var res: UInt256
let (shift, num) = ? k.cpt.stack.popInt(2) if bits <= 31.u256:
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 =
let let
shiftLen = ? k.cpt.stack.popSafeInt() one = 1.u256
num256 = ? k.cpt.stack.popInt() testBit = bits.truncate(int) * 8 + 7
num = cast[Int256](num256) bitPos = one shl testBit
mask = bitPos - one
if shiftLen >= 256: if not isZero(value and bitPos):
if num.isNegative: res = value or (not mask)
k.cpt.stack.push(cast[UInt256]((-1).i256))
else:
k.cpt.stack. push 0
else: else:
# int version of `shr` then force the result res = value and mask
# into uint256 else:
k.cpt.stack.push(cast[UInt256](num shr shiftLen)) 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 # Public, op exec table entries
@ -292,7 +291,7 @@ const
name: "add", name: "add",
info: "Addition operation", info: "Addition operation",
exec: (prep: VmOpIgnore, exec: (prep: VmOpIgnore,
run: addOp, run: VmOpFn addOp,
post: VmOpIgnore)), post: VmOpIgnore)),
(opCode: Mul, ## 0x02, Multiplication (opCode: Mul, ## 0x02, Multiplication

View File

@ -29,63 +29,62 @@ when not defined(evmc_enabled):
# Private, op handlers implementation # Private, op handlers implementation
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
const proc blockhashOp (k: var VmCtx): EvmResultVoid =
blockhashOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = ## 0x40, Get the hash of one of the 256 most recent complete blocks.
## 0x40, Get the hash of one of the 256 most recent complete blocks. let
let cpt = k.cpt
cpt = k.cpt blockNumber = ? cpt.stack.popInt()
blockNumber = ? cpt.stack.popInt() blockHash = cpt.getBlockHash(blockNumber.truncate(BlockNumber))
blockHash = cpt.getBlockHash(blockNumber.truncate(BlockNumber))
cpt.stack.push blockHash cpt.stack.push blockHash
coinBaseOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc coinBaseOp (k: var VmCtx): EvmResultVoid =
## 0x41, Get the block's beneficiary address. ## 0x41, Get the block's beneficiary address.
k.cpt.stack.push k.cpt.getCoinbase k.cpt.stack.push k.cpt.getCoinbase
timestampOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc timestampOp (k: var VmCtx): EvmResultVoid =
## 0x42, Get the block's timestamp. ## 0x42, Get the block's timestamp.
k.cpt.stack.push k.cpt.getTimestamp k.cpt.stack.push k.cpt.getTimestamp
blocknumberOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc blocknumberOp (k: var VmCtx): EvmResultVoid =
## 0x43, Get the block's number. ## 0x43, Get the block's number.
k.cpt.stack.push k.cpt.getBlockNumber k.cpt.stack.push k.cpt.getBlockNumber
difficultyOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc difficultyOp (k: var VmCtx): EvmResultVoid =
## 0x44, Get the block's difficulty ## 0x44, Get the block's difficulty
k.cpt.stack.push k.cpt.getDifficulty k.cpt.stack.push k.cpt.getDifficulty
gasLimitOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc gasLimitOp (k: var VmCtx): EvmResultVoid =
## 0x45, Get the block's gas limit ## 0x45, Get the block's gas limit
k.cpt.stack.push k.cpt.getGasLimit k.cpt.stack.push k.cpt.getGasLimit
chainIdOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc chainIdOp (k: var VmCtx): EvmResultVoid =
## 0x46, Get current chains EIP-155 unique identifier. ## 0x46, Get current chains EIP-155 unique identifier.
k.cpt.stack.push k.cpt.getChainId k.cpt.stack.push k.cpt.getChainId
selfBalanceOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc selfBalanceOp (k: var VmCtx): EvmResultVoid =
## 0x47, Get current contract's balance. ## 0x47, Get current contract's balance.
let cpt = k.cpt let cpt = k.cpt
cpt.stack.push cpt.getBalance(cpt.msg.contractAddress) cpt.stack.push cpt.getBalance(cpt.msg.contractAddress)
baseFeeOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc baseFeeOp (k: var VmCtx): EvmResultVoid =
## 0x48, Get the block's base fee. ## 0x48, Get the block's base fee.
k.cpt.stack.push k.cpt.getBaseFee k.cpt.stack.push k.cpt.getBaseFee
blobHashOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc blobHashOp (k: var VmCtx): EvmResultVoid =
## 0x49, Get current transaction's EIP-4844 versioned hash. ## 0x49, Get current transaction's EIP-4844 versioned hash.
let let
index = ? k.cpt.stack.popSafeInt() index = ? k.cpt.stack.popSafeInt()
len = k.cpt.getVersionedHashesLen len = k.cpt.getVersionedHashesLen
if index < len: if index < len:
k.cpt.stack.push k.cpt.getVersionedHash(index) k.cpt.stack.push k.cpt.getVersionedHash(index)
else: else:
k.cpt.stack.push 0 k.cpt.stack.push 0
blobBaseFeeOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc blobBaseFeeOp (k: var VmCtx): EvmResultVoid =
## 0x4a, Get the block's base fee. ## 0x4a, Get the block's base fee.
k.cpt.stack.push k.cpt.getBlobBaseFee k.cpt.stack.push k.cpt.getBlobBaseFee
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -198,310 +198,309 @@ else:
# Private, op handlers implementation # Private, op handlers implementation
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
const proc callOp(k: var VmCtx): EvmResultVoid =
callOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = ## 0xf1, Message-Call into an account
## 0xf1, Message-Call into an account let cpt = k.cpt
let cpt = k.cpt
if EVMC_STATIC in cpt.msg.flags: if EVMC_STATIC in cpt.msg.flags:
let val = ? cpt.stack[^3, UInt256] let val = ? cpt.stack[^3, UInt256]
if val > 0.u256: if val > 0.u256:
return err(opErr(StaticContext)) 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 let
p = ? cpt.callParams msg = new(nimbus_message)
res = ? cpt.gasCosts[Call].c_handler( c = cpt
p.value, msg[] = nimbus_message(
GasParams( kind : EVMC_CALL,
kind: Call, depth : (cpt.msg.depth + 1).int32,
c_isNewAccount: not cpt.accountExists(p.contractAddress), gas : childGasLimit,
c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, sender : p.sender,
c_contractGas: p.gas, recipient : p.contractAddress,
c_currentMemSize: cpt.memory.len, code_address: p.codeAddress,
c_memOffset: p.memOffset, input_data : cpt.memory.readPtr(p.memInPos),
c_memLength: p.memLength)) 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 proc callCodeOp(k: var VmCtx): EvmResultVoid =
if gasCost >= 0: ## 0xf2, Message-call into this account with an alternative account's code.
? cpt.opcodeGastCost(Call, gasCost, reason = $Call) 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: cpt.returnData.setLen(0)
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: if cpt.msg.depth >= MaxCallDepth:
return err(opErr(OutOfGas)) 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) if gasCost < 0 and childGasLimit <= 0:
cpt.memory.extend(p.memOutPos, p.memOutLen) return err(opErr(OutOfGas))
let senderBalance = cpt.getBalance(p.sender) cpt.memory.extend(p.memInPos, p.memInLen)
if senderBalance < p.value: cpt.memory.extend(p.memOutPos, p.memOutLen)
cpt.gasMeter.returnGas(childGasLimit)
return ok()
when evmc_enabled: let senderBalance = cpt.getBalance(p.sender)
let if senderBalance < p.value:
msg = new(nimbus_message) cpt.gasMeter.returnGas(childGasLimit)
c = cpt return ok()
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()
# --------------------- when evmc_enabled:
callCodeOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid =
## 0xf2, Message-call into this account with an alternative account's code.
let let
cpt = k.cpt msg = new(nimbus_message)
p = ? cpt.callCodeParams c = cpt
res = ? cpt.gasCosts[CallCode].c_handler( msg[] = nimbus_message(
p.value, kind : EVMC_CALLCODE,
GasParams( depth : (cpt.msg.depth + 1).int32,
kind: CallCode, gas : childGasLimit,
c_isNewAccount: not cpt.accountExists(p.contractAddress), sender : p.sender,
c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, recipient : p.contractAddress,
c_contractGas: p.gas, code_address: p.codeAddress,
c_currentMemSize: cpt.memory.len, input_data : cpt.memory.readPtr(p.memInPos),
c_memOffset: p.memOffset, input_size : p.memInLen.uint,
c_memLength: p.memLength)) 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: var (gasCost, childGasLimit) = res
debug "Computation Failure", gasCost += p.gasCallEIP2929
reason = "Stack too deep", if gasCost >= 0:
maximumDepth = MaxCallDepth, ? cpt.opcodeGastCost(DelegateCall, gasCost, reason = $DelegateCall)
depth = cpt.msg.depth
cpt.gasMeter.returnGas(childGasLimit)
return ok()
if gasCost < 0 and childGasLimit <= 0: cpt.returnData.setLen(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) if gasCost < 0 and childGasLimit <= 0:
cpt.memory.extend(p.memOutPos, p.memOutLen) return err(opErr(OutOfGas))
let senderBalance = cpt.getBalance(p.sender) cpt.memory.extend(p.memInPos, p.memInLen)
if senderBalance < p.value: cpt.memory.extend(p.memOutPos, p.memOutLen)
cpt.gasMeter.returnGas(childGasLimit)
return ok()
when evmc_enabled: 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.
let let
cpt = k.cpt msg = new(nimbus_message)
p = ? cpt.delegateCallParams c = cpt
res = ? cpt.gasCosts[DelegateCall].c_handler( msg[] = nimbus_message(
p.value, kind : EVMC_DELEGATECALL,
GasParams( depth : (cpt.msg.depth + 1).int32,
kind: DelegateCall, gas : childGasLimit,
c_isNewAccount: not cpt.accountExists(p.contractAddress), sender : p.sender,
c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, recipient : p.contractAddress,
c_contractGas: p.gas, code_address: p.codeAddress,
c_currentMemSize: cpt.memory.len, input_data : cpt.memory.readPtr(p.memInPos),
c_memOffset: p.memOffset, input_size : p.memInLen.uint,
c_memLength: p.memLength)) 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) proc staticCallOp(k: var VmCtx): EvmResultVoid =
if cpt.msg.depth >= MaxCallDepth: ## 0xfa, Static message-call into an account.
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: let
return err(opErr(OutOfGas)) 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) var (gasCost, childGasLimit) = res
cpt.memory.extend(p.memOutPos, p.memOutLen) gasCost += p.gasCallEIP2929
if gasCost >= 0:
? cpt.opcodeGastCost(StaticCall, gasCost, reason = $StaticCall)
when evmc_enabled: cpt.returnData.setLen(0)
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()
# --------------------- 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 = if gasCost < 0 and childGasLimit <= 0:
## 0xfa, Static message-call into an account. return err(opErr(OutOfGas))
cpt.memory.extend(p.memInPos, p.memInLen)
cpt.memory.extend(p.memOutPos, p.memOutLen)
when evmc_enabled:
let let
cpt = k.cpt msg = new(nimbus_message)
p = ? cpt.staticCallParams c = cpt
res = ? cpt.gasCosts[StaticCall].c_handler( msg[] = nimbus_message(
p.value, kind : EVMC_CALL,
GasParams( depth : (cpt.msg.depth + 1).int32,
kind: StaticCall, gas : childGasLimit,
c_isNewAccount: not cpt.accountExists(p.contractAddress), sender : p.sender,
c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, recipient : p.contractAddress,
c_contractGas: p.gas, code_address: p.codeAddress,
c_currentMemSize: cpt.memory.len, input_data : cpt.memory.readPtr(p.memInPos),
c_memOffset: p.memOffset, input_size : p.memInLen.uint,
c_memLength: p.memLength)) value : toEvmc(p.value),
flags : p.flags
var (gasCost, childGasLimit) = res )
gasCost += p.gasCallEIP2929 c.execSubCall(msg, p)
if gasCost >= 0: else:
? cpt.opcodeGastCost(StaticCall, gasCost, reason = $StaticCall) cpt.execSubCall(
memPos = p.memOutPos,
cpt.returnData.setLen(0) memLen = p.memOutLen,
childMsg = Message(
if cpt.msg.depth >= MaxCallDepth: kind: EVMC_CALL,
debug "Computation Failure", depth: cpt.msg.depth + 1,
reason = "Stack too deep", gas: childGasLimit,
maximumDepth = MaxCallDepth, sender: p.sender,
depth = cpt.msg.depth contractAddress: p.contractAddress,
cpt.gasMeter.returnGas(childGasLimit) codeAddress: p.codeAddress,
return ok() value: p.value,
data: cpt.memory.read(p.memInPos, p.memInLen),
if gasCost < 0 and childGasLimit <= 0: flags: p.flags))
return err(opErr(OutOfGas)) 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()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public, op exec table entries # Public, op exec table entries

View File

@ -81,167 +81,167 @@ else:
# Private, op handlers implementation # Private, op handlers implementation
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
const
createOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid =
## 0xf0, Create a new account with associated code
? checkInStaticContext(k.cpt)
let proc createOp(k: var VmCtx): EvmResultVoid =
cpt = k.cpt ## 0xf0, Create a new account with associated code
endowment = ? cpt.stack.popInt() ? checkInStaticContext(k.cpt)
memPos = ? cpt.stack.popSafeInt()
memLen = ? cpt.stack.peekSafeInt()
? cpt.stack.top(0) let
cpt = k.cpt
endowment = ? cpt.stack.popInt()
memPos = ? cpt.stack.popSafeInt()
memLen = ? cpt.stack.peekSafeInt()
# EIP-3860 ? cpt.stack.top(0)
if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE:
trace "Initcode size exceeds maximum", initcodeSize = memLen
return err(opErr(InvalidInitCode))
let # EIP-3860
gasParams = GasParams( if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE:
kind: Create, trace "Initcode size exceeds maximum", initcodeSize = memLen
cr_currentMemSize: cpt.memory.len, return err(opErr(InvalidInitCode))
cr_memOffset: memPos,
cr_memLength: memLen)
res = cpt.gasCosts[Create].cr_handler(1.u256, gasParams)
? cpt.opcodeGastCost(Create, let
res.gasCost, reason = "CREATE: GasCreate + memLen * memory expansion") gasParams = GasParams(
cpt.memory.extend(memPos, memLen) kind: Create,
cpt.returnData.setLen(0) 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", debug "Computation Failure",
reason = "Stack too deep", reason = "Insufficient funds available to transfer",
maxDepth = MaxCallDepth, required = endowment,
depth = cpt.msg.depth balance = senderBalance
return ok() return ok()
if endowment != 0: var createMsgGas = cpt.gasMeter.gasRemaining
let senderBalance = cpt.getBalance(cpt.msg.contractAddress) if cpt.fork >= FkTangerine:
if senderBalance < endowment: createMsgGas -= createMsgGas div 64
debug "Computation Failure", ? cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE msg gas")
reason = "Insufficient funds available to transfer",
required = endowment,
balance = senderBalance
return ok()
var createMsgGas = cpt.gasMeter.gasRemaining when evmc_enabled:
if cpt.fork >= FkTangerine: let
createMsgGas -= createMsgGas div 64 msg = new(nimbus_message)
? cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE msg gas") c = cpt
msg[] = nimbus_message(
when evmc_enabled: kind: EVMC_CREATE,
let depth: (cpt.msg.depth + 1).int32,
msg = new(nimbus_message) gas: createMsgGas,
c = cpt sender: cpt.msg.contractAddress,
msg[] = nimbus_message( input_data: cpt.memory.readPtr(memPos),
kind: EVMC_CREATE, input_size: memLen.uint,
depth: (cpt.msg.depth + 1).int32, value: toEvmc(endowment),
gas: createMsgGas, 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, sender: cpt.msg.contractAddress,
input_data: cpt.memory.readPtr(memPos), value: endowment,
input_size: memLen.uint, data: cpt.memory.read(memPos, memLen)))
value: toEvmc(endowment), ok()
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()
# --------------------- # ---------------------
create2Op: VmOpFn = proc(k: var VmCtx): EvmResultVoid = proc create2Op(k: var VmCtx): EvmResultVoid =
## 0xf5, Behaves identically to CREATE, except using keccak256 ## 0xf5, Behaves identically to CREATE, except using keccak256
? checkInStaticContext(k.cpt) ? checkInStaticContext(k.cpt)
let let
cpt = k.cpt cpt = k.cpt
endowment = ? cpt.stack.popInt() endowment = ? cpt.stack.popInt()
memPos = ? cpt.stack.popSafeInt() memPos = ? cpt.stack.popSafeInt()
memLen = ? cpt.stack.popSafeInt() memLen = ? cpt.stack.popSafeInt()
salt256 = ? cpt.stack.peekInt() salt256 = ? cpt.stack.peekInt()
salt = ContractSalt(bytes: salt256.toBytesBE) salt = ContractSalt(bytes: salt256.toBytesBE)
? cpt.stack.top(0) ? cpt.stack.top(0)
# EIP-3860 # EIP-3860
if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE:
trace "Initcode size exceeds maximum", initcodeSize = memLen trace "Initcode size exceeds maximum", initcodeSize = memLen
return err(opErr(InvalidInitCode)) return err(opErr(InvalidInitCode))
let let
gasParams = GasParams( gasParams = GasParams(
kind: Create, kind: Create,
cr_currentMemSize: cpt.memory.len, cr_currentMemSize: cpt.memory.len,
cr_memOffset: memPos, cr_memOffset: memPos,
cr_memLength: memLen) cr_memLength: memLen)
res = cpt.gasCosts[Create].cr_handler(1.u256, gasParams) 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, ? cpt.opcodeGastCost(Create2,
gasCost, reason = "CREATE2: GasCreate + memLen * memory expansion") gasCost, reason = "CREATE2: GasCreate + memLen * memory expansion")
cpt.memory.extend(memPos, memLen) cpt.memory.extend(memPos, memLen)
cpt.returnData.setLen(0) 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", debug "Computation Failure",
reason = "Stack too deep", reason = "Insufficient funds available to transfer",
maxDepth = MaxCallDepth, required = endowment,
depth = cpt.msg.depth balance = senderBalance
return ok() return ok()
if endowment != 0: var createMsgGas = cpt.gasMeter.gasRemaining
let senderBalance = cpt.getBalance(cpt.msg.contractAddress) if cpt.fork >= FkTangerine:
if senderBalance < endowment: createMsgGas -= createMsgGas div 64
debug "Computation Failure", ? cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE2 msg gas")
reason = "Insufficient funds available to transfer",
required = endowment,
balance = senderBalance
return ok()
var createMsgGas = cpt.gasMeter.gasRemaining when evmc_enabled:
if cpt.fork >= FkTangerine: let
createMsgGas -= createMsgGas div 64 msg = new(nimbus_message)
? cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE2 msg gas") c = cpt
msg[] = nimbus_message(
when evmc_enabled: kind: EVMC_CREATE2,
let depth: (cpt.msg.depth + 1).int32,
msg = new(nimbus_message) gas: createMsgGas,
c = cpt sender: cpt.msg.contractAddress,
msg[] = nimbus_message( input_data: cpt.memory.readPtr(memPos),
kind: EVMC_CREATE2, input_size: memLen.uint,
depth: (cpt.msg.depth + 1).int32, value: toEvmc(endowment),
gas: createMsgGas, 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, sender: cpt.msg.contractAddress,
input_data: cpt.memory.readPtr(memPos), value: endowment,
input_size: memLen.uint, data: cpt.memory.read(memPos, memLen)))
value: toEvmc(endowment), ok()
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()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public, op exec table entries # Public, op exec table entries

View File

@ -35,213 +35,212 @@ when not defined(evmc_enabled):
# Private, op handlers implementation # Private, op handlers implementation
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
const proc addressOp (k: var VmCtx): EvmResultVoid =
addressOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = ## 0x30, Get address of currently executing account.
## 0x30, Get address of currently executing account. k.cpt.stack.push k.cpt.msg.contractAddress
k.cpt.stack.push k.cpt.msg.contractAddress
# ------------------ # ------------------
balanceOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc balanceOp (k: var VmCtx): EvmResultVoid =
## 0x31, Get balance of the given account. ## 0x31, Get balance of the given account.
let let
cpt = k.cpt cpt = k.cpt
address = ? cpt.stack.popAddress address = ? cpt.stack.popAddress
cpt.stack.push cpt.getBalance(address) cpt.stack.push cpt.getBalance(address)
balanceEIP2929Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc balanceEIP2929Op (k: var VmCtx): EvmResultVoid =
## 0x31, EIP292: Get balance of the given account for Berlin and later ## 0x31, EIP292: Get balance of the given account for Berlin and later
let let
cpt = k.cpt cpt = k.cpt
address = ? cpt.stack.popAddress() address = ? cpt.stack.popAddress()
gasCost = cpt.gasEip2929AccountCheck(address) gasCost = cpt.gasEip2929AccountCheck(address)
? cpt.opcodeGastCost(Balance, gasCost, reason = "Balance EIP2929") ? cpt.opcodeGastCost(Balance, gasCost, reason = "Balance EIP2929")
cpt.stack.push cpt.getBalance(address) cpt.stack.push cpt.getBalance(address)
# ------------------ # ------------------
originOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc originOp (k: var VmCtx): EvmResultVoid =
## 0x32, Get execution origination address. ## 0x32, Get execution origination address.
k.cpt.stack.push k.cpt.getOrigin() k.cpt.stack.push k.cpt.getOrigin()
callerOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc callerOp (k: var VmCtx): EvmResultVoid =
## 0x33, Get caller address. ## 0x33, Get caller address.
k.cpt.stack.push k.cpt.msg.sender k.cpt.stack.push k.cpt.msg.sender
callValueOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc callValueOp (k: var VmCtx): EvmResultVoid =
## 0x34, Get deposited value by the instruction/transaction ## 0x34, Get deposited value by the instruction/transaction
## responsible for this execution ## responsible for this execution
k.cpt.stack.push k.cpt.msg.value k.cpt.stack.push k.cpt.msg.value
callDataLoadOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc callDataLoadOp (k: var VmCtx): EvmResultVoid =
## 0x35, Get input data of current environment ## 0x35, Get input data of current environment
let let
startPos = ? k.cpt.stack.popInt() startPos = ? k.cpt.stack.popInt()
start = startPos.cleanMemRef start = startPos.cleanMemRef
if start >= k.cpt.msg.data.len: if start >= k.cpt.msg.data.len:
return k.cpt.stack.push 0 return k.cpt.stack.push 0
# If the data does not take 32 bytes, pad with zeros # If the data does not take 32 bytes, pad with zeros
let let
endRange = min(k.cpt.msg.data.len - 1, start + 31) endRange = min(k.cpt.msg.data.len - 1, start + 31)
presentBytes = endRange - start presentBytes = endRange - start
# We rely on value being initialized with 0 by default # We rely on value being initialized with 0 by default
var value: array[32, byte] var value: array[32, byte]
value[0 .. presentBytes] = k.cpt.msg.data.toOpenArray(start, endRange) value[0 .. presentBytes] = k.cpt.msg.data.toOpenArray(start, endRange)
k.cpt.stack.push value k.cpt.stack.push value
callDataSizeOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc callDataSizeOp (k: var VmCtx): EvmResultVoid =
## 0x36, Get size of input data in current environment. ## 0x36, Get size of input data in current environment.
k.cpt.stack.push k.cpt.msg.data.len.u256 k.cpt.stack.push k.cpt.msg.data.len.u256
callDataCopyOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc callDataCopyOp (k: var VmCtx): EvmResultVoid =
## 0x37, Copy input data in current environment to memory. ## 0x37, Copy input data in current environment to memory.
let (memStartPos, copyStartPos, size) = ? k.cpt.stack.popInt(3) let (memStartPos, copyStartPos, size) = ? k.cpt.stack.popInt(3)
# TODO tests: https://github.com/status-im/nimbus/issues/67 # TODO tests: https://github.com/status-im/nimbus/issues/67
let (memPos, copyPos, len) = 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) (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.opcodeGastCost(ReturnDataCopy, gasCost, reason = "returnDataCopy fee")
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) if copyPos + len > k.cpt.returnData.len:
ok() return err(opErr(OutOfBounds))
k.cpt.memory.writePadded(k.cpt.returnData, memPos, copyPos, len)
ok()
# ---------------
codeSizeOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc extCodeHashOp (k: var VmCtx): EvmResultVoid =
## 0x38, Get size of code running in current environment. ## 0x3f, Returns the keccak256 hash of a contracts code
let cpt = k.cpt let
cpt.stack.push cpt.code.len cpt = k.cpt
address = ? k.cpt.stack.popAddress()
cpt.stack.push cpt.getCodeHash(address)
codeCopyOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc extCodeHashEIP2929Op (k: var VmCtx): EvmResultVoid =
## 0x39, Copy code running in current environment to memory. ## 0x3f, EIP2929: Returns the keccak256 hash of a contracts code
let let
cpt = k.cpt cpt = k.cpt
(memStartPos, copyStartPos, size) = ? cpt.stack.popInt(3) address = ? k.cpt.stack.popAddress()
gasCost = cpt.gasEip2929AccountCheck(address)
# TODO tests: https://github.com/status-im/nimbus/issues/67 ? cpt.opcodeGastCost(ExtCodeHash, gasCost, reason = "ExtCodeHash EIP2929")
let (memPos, copyPos, len) = cpt.stack.push cpt.getCodeHash(address)
(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 contracts 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 contracts 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)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public, op exec table entries # Public, op exec table entries
@ -255,7 +254,7 @@ const
name: "address", name: "address",
info: "Get address of currently executing account", info: "Get address of currently executing account",
exec: (prep: VmOpIgnore, exec: (prep: VmOpIgnore,
run: addressOp, run: VmOpFn addressOp,
post: VmOpIgnore)), post: VmOpIgnore)),
(opCode: Balance, ## 0x31, Balance (opCode: Balance, ## 0x31, Balance

View File

@ -30,27 +30,26 @@ import
# Private, op handlers implementation # Private, op handlers implementation
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
const proc sha3Op(k: var VmCtx): EvmResultVoid =
sha3Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = ## 0x20, Compute Keccak-256 hash.
## 0x20, Compute Keccak-256 hash. let
let (startPos, length) = ? k.cpt.stack.popInt(2)
(startPos, length) = ? k.cpt.stack.popInt(2) (pos, len) = (startPos.safeInt, length.safeInt)
(pos, len) = (startPos.safeInt, length.safeInt)
if pos < 0 or len < 0 or pos > 2147483648'i64: if pos < 0 or len < 0 or pos > 2147483648'i64:
return err(opErr(OutOfBounds)) return err(opErr(OutOfBounds))
? k.cpt.opcodeGastCost(Op.Sha3, ? k.cpt.opcodeGastCost(Op.Sha3,
k.cpt.gasCosts[Op.Sha3].m_handler(k.cpt.memory.len, pos, len), k.cpt.gasCosts[Op.Sha3].m_handler(k.cpt.memory.len, pos, len),
reason = "SHA3: word gas cost") 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 let endRange = min(pos + len, k.cpt.memory.len) - 1
if endRange == -1 or pos >= k.cpt.memory.len: if endRange == -1 or pos >= k.cpt.memory.len:
k.cpt.stack.push(EMPTY_SHA3) k.cpt.stack.push(EMPTY_SHA3)
else: else:
k.cpt.stack.push keccakHash k.cpt.memory.bytes.toOpenArray(pos, endRange) k.cpt.stack.push keccakHash k.cpt.memory.bytes.toOpenArray(pos, endRange)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public, op exec table entries # Public, op exec table entries

View File

@ -122,197 +122,196 @@ func jumpImpl(c: Computation; jumpTarget: UInt256): EvmResultVoid =
# Private, op handlers implementation # Private, op handlers implementation
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
const proc popOp(k: var VmCtx): EvmResultVoid =
popOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = ## 0x50, Remove item from stack.
## 0x50, Remove item from stack. k.cpt.stack.popInt.isOkOr:
k.cpt.stack.popInt.isOkOr: return err(error)
return err(error) ok()
ok()
mloadOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc mloadOp (k: var VmCtx): EvmResultVoid =
## 0x51, Load word from memory ## 0x51, Load word from memory
let memStartPos = ? k.cpt.stack.popInt() let memStartPos = ? k.cpt.stack.popInt()
let memPos = memStartPos.cleanMemRef let memPos = memStartPos.cleanMemRef
? k.cpt.opcodeGastCost(Mload, ? k.cpt.opcodeGastCost(Mload,
k.cpt.gasCosts[Mload].m_handler(k.cpt.memory.len, memPos, 32), k.cpt.gasCosts[Mload].m_handler(k.cpt.memory.len, memPos, 32),
reason = "MLOAD: GasVeryLow + memory expansion") reason = "MLOAD: GasVeryLow + memory expansion")
k.cpt.memory.extend(memPos, 32) k.cpt.memory.extend(memPos, 32)
k.cpt.stack.push k.cpt.memory.read32Bytes(memPos) k.cpt.stack.push k.cpt.memory.read32Bytes(memPos)
mstoreOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc mstoreOp (k: var VmCtx): EvmResultVoid =
## 0x52, Save word to memory ## 0x52, Save word to memory
let (memStartPos, value) = ? k.cpt.stack.popInt(2) let (memStartPos, value) = ? k.cpt.stack.popInt(2)
let memPos = memStartPos.cleanMemRef let memPos = memStartPos.cleanMemRef
? k.cpt.opcodeGastCost(Mstore, ? k.cpt.opcodeGastCost(Mstore,
k.cpt.gasCosts[Mstore].m_handler(k.cpt.memory.len, memPos, 32), k.cpt.gasCosts[Mstore].m_handler(k.cpt.memory.len, memPos, 32),
reason = "MSTORE: GasVeryLow + memory expansion") reason = "MSTORE: GasVeryLow + memory expansion")
k.cpt.memory.extend(memPos, 32) k.cpt.memory.extend(memPos, 32)
k.cpt.memory.write(memPos, value.toBytesBE) k.cpt.memory.write(memPos, value.toBytesBE)
mstore8Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc mstore8Op (k: var VmCtx): EvmResultVoid =
## 0x53, Save byte to memory ## 0x53, Save byte to memory
let (memStartPos, value) = ? k.cpt.stack.popInt(2) let (memStartPos, value) = ? k.cpt.stack.popInt(2)
let memPos = memStartPos.cleanMemRef let memPos = memStartPos.cleanMemRef
? k.cpt.opcodeGastCost(Mstore8, ? k.cpt.opcodeGastCost(Mstore8,
k.cpt.gasCosts[Mstore8].m_handler(k.cpt.memory.len, memPos, 1), k.cpt.gasCosts[Mstore8].m_handler(k.cpt.memory.len, memPos, 1),
reason = "MSTORE8: GasVeryLow + memory expansion") reason = "MSTORE8: GasVeryLow + memory expansion")
k.cpt.memory.extend(memPos, 1) k.cpt.memory.extend(memPos, 1)
k.cpt.memory.write(memPos, value.toByteArrayBE[31]) k.cpt.memory.write(memPos, value.toByteArrayBE[31])
# ------- # -------
sloadOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc sloadOp (k: var VmCtx): EvmResultVoid =
## 0x54, Load word from storage. ## 0x54, Load word from storage.
let let
cpt = k.cpt cpt = k.cpt
slot = ? cpt.stack.popInt() slot = ? cpt.stack.popInt()
cpt.stack.push cpt.getStorage(slot) cpt.stack.push cpt.getStorage(slot)
sloadEIP2929Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc sloadEIP2929Op (k: var VmCtx): EvmResultVoid =
## 0x54, EIP2929: Load word from storage for Berlin and later ## 0x54, EIP2929: Load word from storage for Berlin and later
let let
cpt = k.cpt cpt = k.cpt
slot = ? cpt.stack.popInt() slot = ? cpt.stack.popInt()
gasCost = cpt.gasEip2929AccountCheck(cpt.msg.contractAddress, slot) gasCost = cpt.gasEip2929AccountCheck(cpt.msg.contractAddress, slot)
? cpt.opcodeGastCost(Sload, gasCost, reason = "sloadEIP2929") ? cpt.opcodeGastCost(Sload, gasCost, reason = "sloadEIP2929")
cpt.stack.push cpt.getStorage(slot) cpt.stack.push cpt.getStorage(slot)
# ------- # -------
sstoreOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc sstoreOp (k: var VmCtx): EvmResultVoid =
## 0x55, Save word to storage. ## 0x55, Save word to storage.
let let
cpt = k.cpt cpt = k.cpt
(slot, newValue) = ? cpt.stack.popInt(2) (slot, newValue) = ? cpt.stack.popInt(2)
? checkInStaticContext(cpt) ? checkInStaticContext(cpt)
sstoreEvmcOrSstore(cpt, slot, newValue) sstoreEvmcOrSstore(cpt, slot, newValue)
sstoreEIP1283Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc sstoreEIP1283Op (k: var VmCtx): EvmResultVoid =
## 0x55, EIP1283: sstore for Constantinople and later ## 0x55, EIP1283: sstore for Constantinople and later
let let
cpt = k.cpt cpt = k.cpt
(slot, newValue) = ? cpt.stack.popInt(2) (slot, newValue) = ? cpt.stack.popInt(2)
? checkInStaticContext(cpt) ? checkInStaticContext(cpt)
sstoreEvmcOrNetGasMetering(cpt, slot, newValue) sstoreEvmcOrNetGasMetering(cpt, slot, newValue)
sstoreEIP2200Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc sstoreEIP2200Op (k: var VmCtx): EvmResultVoid =
## 0x55, EIP2200: sstore for Istanbul and later ## 0x55, EIP2200: sstore for Istanbul and later
let let
cpt = k.cpt cpt = k.cpt
(slot, newValue) = ? cpt.stack.popInt(2) (slot, newValue) = ? cpt.stack.popInt(2)
? checkInStaticContext(cpt) ? checkInStaticContext(cpt)
const SentryGasEIP2200 = 2300 const SentryGasEIP2200 = 2300
if cpt.gasMeter.gasRemaining <= SentryGasEIP2200: if cpt.gasMeter.gasRemaining <= SentryGasEIP2200:
return err(opErr(OutOfGas)) return err(opErr(OutOfGas))
sstoreEvmcOrNetGasMetering(cpt, slot, newValue) sstoreEvmcOrNetGasMetering(cpt, slot, newValue)
sstoreEIP2929Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc sstoreEIP2929Op (k: var VmCtx): EvmResultVoid =
## 0x55, EIP2929: sstore for Berlin and later ## 0x55, EIP2929: sstore for Berlin and later
let let
cpt = k.cpt cpt = k.cpt
(slot, newValue) = ? cpt.stack.popInt(2) (slot, newValue) = ? cpt.stack.popInt(2)
? checkInStaticContext(cpt) ? checkInStaticContext(cpt)
# Minimum gas required to be present for an SSTORE call, not consumed # Minimum gas required to be present for an SSTORE call, not consumed
const SentryGasEIP2200 = 2300 const SentryGasEIP2200 = 2300
if cpt.gasMeter.gasRemaining <= SentryGasEIP2200: if cpt.gasMeter.gasRemaining <= SentryGasEIP2200:
return err(opErr(OutOfGas)) return err(opErr(OutOfGas))
var coldAccessGas = 0.GasInt var coldAccessGas = 0.GasInt
when evmc_enabled: when evmc_enabled:
if cpt.host.accessStorage(cpt.msg.contractAddress, slot) == EVMC_ACCESS_COLD: 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 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 = proc jumpOp (k: var VmCtx): EvmResultVoid =
## 0x56, Alter the program counter ## 0x56, Alter the program counter
let jumpTarget = ? k.cpt.stack.popInt() let jumpTarget = ? k.cpt.stack.popInt()
jumpImpl(k.cpt, jumpTarget) jumpImpl(k.cpt, jumpTarget)
jumpIOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = proc jumpIOp (k: var VmCtx): EvmResultVoid =
## 0x57, Conditionally alter the program counter. ## 0x57, Conditionally alter the program counter.
let (jumpTarget, testedValue) = ? k.cpt.stack.popInt(2) let (jumpTarget, testedValue) = ? k.cpt.stack.popInt(2)
if testedValue.isZero: if testedValue.isZero:
return ok() return ok()
jumpImpl(k.cpt, jumpTarget) jumpImpl(k.cpt, jumpTarget)
pcOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = proc pcOp (k: var VmCtx): EvmResultVoid =
## 0x58, Get the value of the program counter prior to the increment ## 0x58, Get the value of the program counter prior to the increment
## corresponding to this instruction. ## corresponding to this instruction.
k.cpt.stack.push max(k.cpt.code.pc - 1, 0) k.cpt.stack.push max(k.cpt.code.pc - 1, 0)
msizeOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = proc msizeOp (k: var VmCtx): EvmResultVoid =
## 0x59, Get the size of active memory in bytes. ## 0x59, Get the size of active memory in bytes.
k.cpt.stack.push k.cpt.memory.len k.cpt.stack.push k.cpt.memory.len
gasOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = proc gasOp (k: var VmCtx): EvmResultVoid =
## 0x5a, Get the amount of available gas, including the corresponding ## 0x5a, Get the amount of available gas, including the corresponding
## reduction for the cost of this instruction. ## reduction for the cost of this instruction.
k.cpt.stack.push k.cpt.gasMeter.gasRemaining k.cpt.stack.push k.cpt.gasMeter.gasRemaining
jumpDestOp: VmOpFn = func (k: var VmCtx): EvmResultVoid = proc jumpDestOp (k: var VmCtx): EvmResultVoid =
## 0x5b, Mark a valid destination for jumps. This operation has no effect ## 0x5b, Mark a valid destination for jumps. This operation has no effect
## on machine state during execution. ## on machine state during execution.
ok() ok()
tloadOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc tloadOp (k: var VmCtx): EvmResultVoid =
## 0x5c, Load word from transient storage. ## 0x5c, Load word from transient storage.
let let
slot = ? k.cpt.stack.popInt() slot = ? k.cpt.stack.popInt()
val = k.cpt.getTransientStorage(slot) val = k.cpt.getTransientStorage(slot)
k.cpt.stack.push val k.cpt.stack.push val
tstoreOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc tstoreOp (k: var VmCtx): EvmResultVoid =
## 0x5d, Save word to transient storage. ## 0x5d, Save word to transient storage.
? checkInStaticContext(k.cpt) ? checkInStaticContext(k.cpt)
let let
slot = ? k.cpt.stack.popInt() slot = ? k.cpt.stack.popInt()
val = ? k.cpt.stack.popInt() val = ? k.cpt.stack.popInt()
k.cpt.setTransientStorage(slot, val) k.cpt.setTransientStorage(slot, val)
ok() ok()
mCopyOp: VmOpFn = proc (k: var VmCtx): EvmResultVoid = proc mCopyOp (k: var VmCtx): EvmResultVoid =
## 0x5e, Copy memory ## 0x5e, Copy memory
let (dst, src, size) = ? k.cpt.stack.popInt(3) let (dst, src, size) = ? k.cpt.stack.popInt(3)
let (dstPos, srcPos, len) = let (dstPos, srcPos, len) =
(dst.cleanMemRef, src.cleanMemRef, size.cleanMemRef) (dst.cleanMemRef, src.cleanMemRef, size.cleanMemRef)
? k.cpt.opcodeGastCost(Mcopy, ? k.cpt.opcodeGastCost(Mcopy,
k.cpt.gasCosts[Mcopy].m_handler(k.cpt.memory.len, max(dstPos, srcPos), len), k.cpt.gasCosts[Mcopy].m_handler(k.cpt.memory.len, max(dstPos, srcPos), len),
reason = "Mcopy fee") reason = "Mcopy fee")
k.cpt.memory.copy(dstPos, srcPos, len) k.cpt.memory.copy(dstPos, srcPos, len)
ok() ok()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public, op exec table entries # Public, op exec table entries
@ -326,7 +325,7 @@ const
name: "pop", name: "pop",
info: "Remove item from stack", info: "Remove item from stack",
exec: (prep: VmOpIgnore, exec: (prep: VmOpIgnore,
run: popOp, run: VmOpFn popOp,
post: VmOpIgnore)), post: VmOpIgnore)),
(opCode: Mload, ## 0x51, Load word from memory (opCode: Mload, ## 0x51, Load word from memory

View File

@ -65,11 +65,11 @@ genOphList fnName, fnInfo, inxRange, "VmOpExecPush", opName
# about which opcodes are for which forks, but that seems uglier than # about which opcodes are for which forks, but that seems uglier than
# just adding Push0 here as a special case.) # just adding Push0 here as a special case.)
const proc push0Op(k: var VmCtx): EvmResultVoid =
push0Op: VmOpFn = proc (k: var VmCtx): EvmResultVoid = ## 0x5f, push 0 onto the stack
## 0x5f, push 0 onto the stack k.cpt.stack.push(0)
k.cpt.stack.push(0)
const
VmOpExecPushZero*: seq[VmOpExec] = @[ VmOpExecPushZero*: seq[VmOpExec] = @[
(opCode: Push0, ## 0x5f, push 0 onto the stack (opCode: Push0, ## 0x5f, push 0 onto the stack

View File

@ -37,121 +37,120 @@ when not defined(evmc_enabled):
# Private # Private
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
const proc returnOp(k: var VmCtx): EvmResultVoid =
returnOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = ## 0xf3, Halt execution returning output data.
## 0xf3, Halt execution returning output data. let (startPos, size) = ? k.cpt.stack.popInt(2)
let (startPos, size) = ? k.cpt.stack.popInt(2)
let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef) let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef)
? k.cpt.opcodeGastCost(Return, ? k.cpt.opcodeGastCost(Return,
k.cpt.gasCosts[Return].m_handler(k.cpt.memory.len, pos, len), k.cpt.gasCosts[Return].m_handler(k.cpt.memory.len, pos, len),
reason = "RETURN") reason = "RETURN")
k.cpt.memory.extend(pos, len) k.cpt.memory.extend(pos, len)
k.cpt.output = k.cpt.memory.read(pos, len) k.cpt.output = k.cpt.memory.read(pos, len)
ok() ok()
revertOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = proc revertOp(k: var VmCtx): EvmResultVoid =
## 0xfd, Halt execution reverting state changes but returning data ## 0xfd, Halt execution reverting state changes but returning data
## and remaining gas. ## and remaining gas.
let (startPos, size) = ? k.cpt.stack.popInt(2) let (startPos, size) = ? k.cpt.stack.popInt(2)
let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef) let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef)
? k.cpt.opcodeGastCost(Revert, ? k.cpt.opcodeGastCost(Revert,
k.cpt.gasCosts[Revert].m_handler(k.cpt.memory.len, pos, len), k.cpt.gasCosts[Revert].m_handler(k.cpt.memory.len, pos, len),
reason = "REVERT") reason = "REVERT")
k.cpt.memory.extend(pos, len) k.cpt.memory.extend(pos, len)
k.cpt.output = k.cpt.memory.read(pos, len) k.cpt.output = k.cpt.memory.read(pos, len)
# setError(msg, false) will signal cheap revert # setError(msg, false) will signal cheap revert
k.cpt.setError(EVMC_REVERT, "REVERT opcode executed", false) k.cpt.setError(EVMC_REVERT, "REVERT opcode executed", false)
ok() ok()
invalidOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = proc invalidOp(k: var VmCtx): EvmResultVoid =
err(opErr(InvalidInstruction)) err(opErr(InvalidInstruction))
# ----------- # -----------
selfDestructOp: VmOpFn = proc(k: var VmCtx): EvmResultVoid = proc selfDestructOp(k: var VmCtx): EvmResultVoid =
## 0xff, Halt execution and register account for later deletion. ## 0xff, Halt execution and register account for later deletion.
let cpt = k.cpt let cpt = k.cpt
let beneficiary = ? cpt.stack.popAddress() let beneficiary = ? cpt.stack.popAddress()
when defined(evmc_enabled): 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()
block: 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) cpt.selfDestruct(beneficiary)
ok() else:
selfDestructEIP161Op: VmOpFn = proc(k: var VmCtx): EvmResultVoid =
## selfDestructEip161 (auto generated comment)
let cpt = k.cpt
? checkInStaticContext(cpt)
let beneficiary = ? cpt.stack.popAddress()
block: block:
let cpt.selfDestruct(beneficiary)
isDead = not cpt.accountExists(beneficiary) ok()
balance = cpt.getBalance(cpt.msg.contractAddress)
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, kind: SelfDestruct,
sd_condition: isDead and not balance.isZero) 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) var gasCost = res.gasCost
? cpt.opcodeGastCost(SelfDestruct,
res.gasCost, reason = "SELFDESTRUCT EIP161")
cpt.selfDestruct(beneficiary)
ok()
selfDestructEIP2929Op: VmOpFn = proc(k: var VmCtx): EvmResultVoid = when evmc_enabled:
## selfDestructEIP2929 (auto generated comment) if cpt.host.accessAccount(beneficiary) == EVMC_ACCESS_COLD:
let cpt = k.cpt gasCost = gasCost + ColdAccountAccessCost
? checkInStaticContext(cpt) else:
cpt.vmState.mutateStateDB:
let beneficiary = ? cpt.stack.popAddress() if not db.inAccessList(beneficiary):
block: db.accessList(beneficiary)
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:
gasCost = gasCost + ColdAccountAccessCost gasCost = gasCost + ColdAccountAccessCost
else:
cpt.vmState.mutateStateDB:
if not db.inAccessList(beneficiary):
db.accessList(beneficiary)
gasCost = gasCost + ColdAccountAccessCost
? cpt.opcodeGastCost(SelfDestruct, ? cpt.opcodeGastCost(SelfDestruct,
gasCost, reason = "SELFDESTRUCT EIP2929") gasCost, reason = "SELFDESTRUCT EIP2929")
cpt.selfDestruct(beneficiary) cpt.selfDestruct(beneficiary)
ok() ok()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public, op exec table entries # Public, op exec table entries