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:
parent
2aaab1cb4a
commit
135ef222a2
|
@ -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 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:
|
|
||||||
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 two’s 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
|
||||||
|
|
|
@ -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 chain’s EIP-155 unique identifier.
|
## 0x46, Get current chain’s 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
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 contract’s 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 contract’s 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 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)
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# 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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue