re-integrated handlers with op codes 0xf2/return ..0xff/selfdestruct
This commit is contained in:
parent
7436e516fd
commit
1bb6ef43a1
|
@ -51,7 +51,9 @@ proc mkOpTable(select: Fork): array[Op,Vm2OpExec] {.compileTime.} =
|
|||
result.importList(select, vm2OpExecDup, "Dup")
|
||||
result.importList(select, vm2OpExecSwap, "Swap")
|
||||
result.importList(select, vm2OpExecLog, "Log")
|
||||
result.importList(select, vm2OpExecSysOP, "SysOp")
|
||||
#result.importList(select, vm2OpExecCreate, "Create")
|
||||
#result.importList(select, vm2OpExecCall, "Call")
|
||||
result.importList(select, vm2OpExecSysOp, "SysOp")
|
||||
|
||||
for op in Op:
|
||||
if select notin result[op].forks:
|
||||
|
|
|
@ -59,6 +59,7 @@ else:
|
|||
|
||||
Computation* = ref object
|
||||
returnStack*: seq[int]
|
||||
output*: seq[byte]
|
||||
vmState*: BaseVMState
|
||||
gasMeter*: GasMeter
|
||||
stack*: Stack
|
||||
|
|
|
@ -47,7 +47,6 @@ else:
|
|||
emvcStatic = 1
|
||||
ColdAccountAccessCost = 2
|
||||
WarmStorageReadCost = 3
|
||||
|
||||
type
|
||||
GasInt = int
|
||||
|
||||
|
|
|
@ -47,8 +47,8 @@ else:
|
|||
const
|
||||
ColdSloadCost = 42
|
||||
WarmStorageReadCost = 43
|
||||
|
||||
var blindGasCosts: array[Op,int]
|
||||
var
|
||||
blindGasCosts: array[Op,int]
|
||||
|
||||
# copied from stack.nim
|
||||
macro genTupleType(len: static[int], elemType: untyped): untyped =
|
||||
|
|
|
@ -12,32 +12,260 @@
|
|||
## ======================================
|
||||
##
|
||||
|
||||
const
|
||||
kludge {.intdefine.}: int = 0
|
||||
breakCircularDependency {.used.} = kludge > 0
|
||||
|
||||
import
|
||||
../op_codes, ./oph_defs, ../../../errors.nim
|
||||
../../../errors,
|
||||
./oph_defs,
|
||||
./oph_helpers,
|
||||
stint
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kludge BEGIN
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
when not breakCircularDependency:
|
||||
import
|
||||
../../../db/accounts_cache,
|
||||
../../stack,
|
||||
../../v2computation,
|
||||
../../v2memory,
|
||||
../../v2state,
|
||||
../../v2types,
|
||||
../gas_meter,
|
||||
../utils/v2utils_numeric,
|
||||
../v2gas_costs,
|
||||
eth/common
|
||||
|
||||
else:
|
||||
import macros
|
||||
|
||||
type
|
||||
GasInt = int
|
||||
GasResult = tuple[gasCost, gasRefund: GasInt]
|
||||
const
|
||||
ColdAccountAccessCost = 42
|
||||
var
|
||||
blindGasCosts: array[Op,int]
|
||||
blindAddress: EthAddress
|
||||
blindGasResult: GasResult
|
||||
|
||||
# copied from stack.nim
|
||||
macro genTupleType(len: static[int], elemType: untyped): untyped =
|
||||
result = nnkTupleConstr.newNimNode()
|
||||
for i in 0 ..< len: result.add(elemType)
|
||||
|
||||
# function stubs from stack.nim (to satisfy compiler logic)
|
||||
proc popAddress(x: var Stack): EthAddress = blindAddress
|
||||
proc popInt(x: var Stack, n: static[int]): auto =
|
||||
var rc: genTupleType(n, UInt256)
|
||||
return rc
|
||||
|
||||
# function stubs from v2computation.nim (to satisfy compiler logic)
|
||||
proc gasCosts(c: Computation): array[Op,int] = blindGasCosts
|
||||
proc setError(c: Computation, msg: string, burnsGas = false) = discard
|
||||
proc selfDestruct(c: Computation, address: EthAddress) = discard
|
||||
proc accountExists(c: Computation, address: EthAddress): bool = false
|
||||
proc getBalance[T](c: Computation, address: T): Uint256 = 0.u256
|
||||
|
||||
# function stubs from v2utils_numeric.nim
|
||||
func cleanMemRef(x: UInt256): int = 0
|
||||
|
||||
# function stubs from v2memory.nim
|
||||
proc len(mem: Memory): int = 0
|
||||
proc extend(mem: var Memory; startPos: Natural; size: Natural) = discard
|
||||
proc read(mem: var Memory, startPos: Natural, size: Natural): seq[byte] = @[]
|
||||
|
||||
# function stubs from v2state.nim
|
||||
template mutateStateDB(vmState: BaseVMState, body: untyped) =
|
||||
block:
|
||||
var db {.inject.} = vmState.accountDb
|
||||
body
|
||||
|
||||
# function stubs from gas_meter.nim
|
||||
proc consumeGas(gasMeter: var GasMeter; amount: int; reason: string) = discard
|
||||
|
||||
# stubs from v2gas_costs.nim
|
||||
type GasParams = object
|
||||
case kind*: Op
|
||||
of SelfDestruct:
|
||||
sd_condition: bool
|
||||
else:
|
||||
discard
|
||||
proc c_handler(x: int; y: Uint256, z: GasParams): GasResult = blindGasResult
|
||||
proc m_handler(x: int; curMemSize, memOffset, memLen: int64): int = 0
|
||||
|
||||
# function stubs from accounts_cache.nim:
|
||||
func inAccessList[A,B](ac: A; address: B): bool = false
|
||||
proc accessList[A,B](ac: var A; address: B) = discard
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kludge END
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
invalidOp: Vm2OpFn =
|
||||
proc(k: Vm2Ctx) {.gcsafe.} =
|
||||
raise newException(InvalidInstruction,
|
||||
"Invalid instruction, received an opcode " &
|
||||
"not implemented in the current fork.")
|
||||
returnOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
## 0xf3, Halt execution returning output data.
|
||||
let (startPos, size) = k.cpt.stack.popInt(2)
|
||||
|
||||
let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef)
|
||||
k.cpt.gasMeter.consumeGas(
|
||||
k.cpt.gasCosts[Return].m_handler(k.cpt.memory.len, pos, len),
|
||||
reason = "RETURN")
|
||||
k.cpt.memory.extend(pos, len)
|
||||
k.cpt.output = k.cpt.memory.read(pos, len)
|
||||
|
||||
|
||||
revertOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
## 0xfd, Halt execution reverting state changes but returning data
|
||||
## and remaining gas.
|
||||
let (startPos, size) = k.cpt.stack.popInt(2)
|
||||
|
||||
let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef)
|
||||
k.cpt.gasMeter.consumeGas(
|
||||
k.cpt.gasCosts[Revert].m_handler(k.cpt.memory.len, pos, len),
|
||||
reason = "REVERT")
|
||||
|
||||
k.cpt.memory.extend(pos, len)
|
||||
k.cpt.output = k.cpt.memory.read(pos, len)
|
||||
# setError(msg, false) will signal cheap revert
|
||||
k.cpt.setError("REVERT opcode executed", false)
|
||||
|
||||
|
||||
invalidOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
raise newException(InvalidInstruction,
|
||||
"Invalid instruction, received an opcode " &
|
||||
"not implemented in the current fork.")
|
||||
|
||||
# -----------
|
||||
|
||||
selfDestructOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
## 0xff, Halt execution and register account for later deletion.
|
||||
let beneficiary = k.cpt.stack.popAddress()
|
||||
k.cpt.selfDestruct(beneficiary)
|
||||
|
||||
|
||||
selfDestructEIP150Op: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
## selfDestructEip150 (auto generated comment)
|
||||
let beneficiary = k.cpt.stack.popAddress()
|
||||
|
||||
let gasParams = GasParams(
|
||||
kind: SelfDestruct,
|
||||
sd_condition: not k.cpt.accountExists(beneficiary))
|
||||
|
||||
let gasCost =
|
||||
k.cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost
|
||||
k.cpt.gasMeter.consumeGas(
|
||||
gasCost, reason = "SELFDESTRUCT EIP150")
|
||||
k.cpt.selfDestruct(beneficiary)
|
||||
|
||||
|
||||
selfDestructEip161Op: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
## selfDestructEip161 (auto generated comment)
|
||||
checkInStaticContext(k.cpt)
|
||||
|
||||
let
|
||||
beneficiary = k.cpt.stack.popAddress()
|
||||
isDead = not k.cpt.accountExists(beneficiary)
|
||||
balance = k.cpt.getBalance(k.cpt.msg.contractAddress)
|
||||
|
||||
let gasParams = GasParams(
|
||||
kind: SelfDestruct,
|
||||
sd_condition: isDead and not balance.isZero)
|
||||
|
||||
let gasCost =
|
||||
k.cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost
|
||||
k.cpt.gasMeter.consumeGas(
|
||||
gasCost, reason = "SELFDESTRUCT EIP161")
|
||||
k.cpt.selfDestruct(beneficiary)
|
||||
|
||||
|
||||
selfDestructEIP2929Op: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
## selfDestructEIP2929 (auto generated comment)
|
||||
checkInStaticContext(k.cpt)
|
||||
|
||||
let
|
||||
beneficiary = k.cpt.stack.popAddress()
|
||||
isDead = not k.cpt.accountExists(beneficiary)
|
||||
balance = k.cpt.getBalance(k.cpt.msg.contractAddress)
|
||||
|
||||
let gasParams = GasParams(
|
||||
kind: SelfDestruct,
|
||||
sd_condition: isDead and not balance.isZero)
|
||||
|
||||
var gasCost =
|
||||
k.cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost
|
||||
|
||||
k.cpt.vmState.mutateStateDB:
|
||||
if not db.inAccessList(beneficiary):
|
||||
db.accessList(beneficiary)
|
||||
gasCost = gasCost + ColdAccountAccessCost
|
||||
|
||||
k.cpt.gasMeter.consumeGas(
|
||||
gasCost, reason = "SELFDESTRUCT EIP161")
|
||||
k.cpt.selfDestruct(beneficiary)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public, op exec table entries
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
vm2OpExecSysOP*: seq[Vm2OpExec] = @[
|
||||
vm2OpExecSysOp*: seq[Vm2OpExec] = @[
|
||||
|
||||
(opCode: Invalid, ## 0xfe, invalid instruction.
|
||||
(opCode: Return, ## 0xf3, Halt execution returning output data.
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Halt execution returning output data",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: returnOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Revert, ## 0xfd, Halt and revert state changes
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Halt execution reverting state changes but returning data " &
|
||||
"and remaining gas",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: revertOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Invalid, ## 0xfe, invalid instruction.
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Designated invalid instruction",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: invalidOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: SelfDestruct, ## 0xff, Halt execution, prep for later deletion
|
||||
forks: Vm2OpAllForks - Vm2OpTangerineAndLater,
|
||||
info: "Halt execution and register account for later deletion",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: selfDestructOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: SelfDestruct, ## 0xff, EIP150: self destruct, Tangerine
|
||||
forks: Vm2OpTangerineAndLater - Vm2OpSpuriousAndLater,
|
||||
info: "EIP150: Halt execution and register account for later deletion",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: selfDestructEIP150Op,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: SelfDestruct, ## 0xff, EIP161: self destruct, Spurious and later
|
||||
forks: Vm2OpSpuriousAndLater - Vm2OpBerlinAndLater,
|
||||
info: "EIP161: Halt execution and register account for later deletion",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: selfDestructEIP161Op,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: SelfDestruct, ## 0xff, EIP2929: self destruct, Berlin and later
|
||||
forks: Vm2OpBerlinAndLater,
|
||||
info: "EIP2929: Halt execution and register account for later deletion",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: selfDestructEIP2929Op,
|
||||
post: vm2OpIgnore))]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
strformat, times, sets, sequtils, options,
|
||||
strformat, times, sets, options,
|
||||
chronicles, stint, nimcrypto, eth/common,
|
||||
./utils/[macros_procs_opcodes, v2utils_numeric],
|
||||
./gas_meter, ./v2gas_costs, ./v2opcode_values, ./v2forks,
|
||||
|
@ -24,56 +24,10 @@ logScope:
|
|||
# ##################################
|
||||
# Syntactic sugar
|
||||
|
||||
proc gasEip2929AccountCheck(c: Computation, address: EthAddress, prevCost = 0.GasInt) =
|
||||
c.vmState.mutateStateDB:
|
||||
let gasCost = if not db.inAccessList(address):
|
||||
db.accessList(address)
|
||||
ColdAccountAccessCost
|
||||
else:
|
||||
WarmStorageReadCost
|
||||
|
||||
c.gasMeter.consumeGas(gasCost - prevCost, reason = "gasEIP2929AccountCheck")
|
||||
|
||||
template push(x: typed) {.dirty.} =
|
||||
## Push an expression on the computation stack
|
||||
c.stack.push x
|
||||
|
||||
proc writePaddedResult(mem: var Memory,
|
||||
data: openarray[byte],
|
||||
memPos, dataPos, len: Natural,
|
||||
paddingValue = 0.byte) =
|
||||
|
||||
mem.extend(memPos, len)
|
||||
let dataEndPosition = dataPos.int64 + len - 1
|
||||
let sourceBytes = data[min(dataPos, data.len) .. min(data.len - 1, dataEndPosition)]
|
||||
mem.write(memPos, sourceBytes)
|
||||
|
||||
# Don't duplicate zero-padding of mem.extend
|
||||
let paddingOffset = min(memPos + sourceBytes.len, mem.len)
|
||||
let numPaddingBytes = min(mem.len - paddingOffset, len - sourceBytes.len)
|
||||
if numPaddingBytes > 0:
|
||||
# TODO: avoid unnecessary memory allocation
|
||||
mem.write(paddingOffset, repeat(paddingValue, numPaddingBytes))
|
||||
|
||||
template sstoreNetGasMeteringImpl(c: Computation, slot, newValue: Uint256) =
|
||||
let stateDB = c.vmState.readOnlyStateDB
|
||||
let currentValue {.inject.} = c.getStorage(slot)
|
||||
|
||||
let
|
||||
gasParam = GasParams(
|
||||
kind: Op.Sstore,
|
||||
s_currentValue: currentValue,
|
||||
s_originalValue: stateDB.getCommittedStorage(c.msg.contractAddress, slot))
|
||||
(gasCost, gasRefund) = c.gasCosts[Sstore].c_handler(newValue, gasParam)
|
||||
|
||||
c.gasMeter.consumeGas(gasCost, &"SSTORE EIP2200: {c.msg.contractAddress}[{slot}] -> {newValue} ({currentValue})")
|
||||
|
||||
if gasRefund != 0:
|
||||
c.gasMeter.refundGas(gasRefund)
|
||||
|
||||
c.vmState.mutateStateDB:
|
||||
db.setStorage(c.msg.contractAddress, slot, newValue)
|
||||
|
||||
# ##################################
|
||||
# re-implemented OP handlers
|
||||
|
||||
|
@ -248,6 +202,14 @@ opHandler log1, Op.Log1
|
|||
opHandler log2, Op.Log2
|
||||
opHandler log3, Op.Log3
|
||||
opHandler log4, Op.Log4
|
||||
opHandler returnOp, Op.Return
|
||||
opHandler revert, Op.Revert
|
||||
opHandler invalidOp, Op.Invalid
|
||||
|
||||
opHandler selfDestruct, Op.SelfDestruct, FkFrontier
|
||||
opHandler selfDestructEIP150, Op.SelfDestruct, FkTangerine
|
||||
opHandler selfDestructEIP161, Op.SelfDestruct, FkSpurious
|
||||
opHandler selfDestructEIP2929, Op.SelfDestruct
|
||||
|
||||
# ##########################################
|
||||
# f0s: System operations.
|
||||
|
@ -490,84 +452,3 @@ genCall(call, Call)
|
|||
genCall(callCode, CallCode)
|
||||
genCall(delegateCall, DelegateCall)
|
||||
genCall(staticCall, StaticCall)
|
||||
|
||||
op returnOp, inline = false, startPos, size:
|
||||
## 0xf3, Halt execution returning output data.
|
||||
let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef)
|
||||
|
||||
c.gasMeter.consumeGas(
|
||||
c.gasCosts[Return].m_handler(c.memory.len, pos, len),
|
||||
reason = "RETURN"
|
||||
)
|
||||
|
||||
c.memory.extend(pos, len)
|
||||
c.output = c.memory.read(pos, len)
|
||||
|
||||
op revert, inline = false, startPos, size:
|
||||
## 0xfd, Halt execution reverting state changes but returning data and remaining gas.
|
||||
let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef)
|
||||
c.gasMeter.consumeGas(
|
||||
c.gasCosts[Revert].m_handler(c.memory.len, pos, len),
|
||||
reason = "REVERT"
|
||||
)
|
||||
|
||||
c.memory.extend(pos, len)
|
||||
c.output = c.memory.read(pos, len)
|
||||
# setError(msg, false) will signal cheap revert
|
||||
c.setError("REVERT opcode executed", false)
|
||||
|
||||
op selfDestruct, inline = false:
|
||||
## 0xff Halt execution and register account for later deletion.
|
||||
let beneficiary = c.stack.popAddress()
|
||||
c.selfDestruct(beneficiary)
|
||||
|
||||
op selfDestructEip150, inline = false:
|
||||
let beneficiary = c.stack.popAddress()
|
||||
|
||||
let gasParams = GasParams(kind: SelfDestruct,
|
||||
sd_condition: not c.accountExists(beneficiary)
|
||||
)
|
||||
|
||||
let gasCost = c.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost
|
||||
c.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP150")
|
||||
c.selfDestruct(beneficiary)
|
||||
|
||||
op selfDestructEip161, inline = false:
|
||||
checkInStaticContext(c)
|
||||
|
||||
let
|
||||
beneficiary = c.stack.popAddress()
|
||||
isDead = not c.accountExists(beneficiary)
|
||||
balance = c.getBalance(c.msg.contractAddress)
|
||||
|
||||
let gasParams = GasParams(kind: SelfDestruct,
|
||||
sd_condition: isDead and not balance.isZero
|
||||
)
|
||||
|
||||
let gasCost = c.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost
|
||||
c.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP161")
|
||||
c.selfDestruct(beneficiary)
|
||||
|
||||
# Constantinople's new opcodes
|
||||
|
||||
op selfDestructEIP2929, inline = false:
|
||||
checkInStaticContext(c)
|
||||
|
||||
let
|
||||
beneficiary = c.stack.popAddress()
|
||||
isDead = not c.accountExists(beneficiary)
|
||||
balance = c.getBalance(c.msg.contractAddress)
|
||||
|
||||
let gasParams = GasParams(kind: SelfDestruct,
|
||||
sd_condition: isDead and not balance.isZero
|
||||
)
|
||||
|
||||
var gasCost = c.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost
|
||||
|
||||
c.vmState.mutateStateDB:
|
||||
if not db.inAccessList(beneficiary):
|
||||
db.accessList(beneficiary)
|
||||
gasCost = gasCost + ColdAccountAccessCost
|
||||
|
||||
c.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP161")
|
||||
c.selfDestruct(beneficiary)
|
||||
|
|
Loading…
Reference in New Issue