re-integrated/added EIP2929 handlers

This commit is contained in:
Jordan Hrycaj 2021-04-15 17:42:19 +01:00 committed by zah
parent 716bd64419
commit 7436e516fd
6 changed files with 230 additions and 88 deletions

View File

@ -66,6 +66,7 @@ else:
msg*: Message
code*: CodeStream
returnData*: seq[byte]
fork*: Fork
# ------------------------------------------------------------------------------
# Kludge END

View File

@ -19,6 +19,7 @@ const
import
../../../errors,
./oph_defs,
./oph_helpers,
sequtils,
strformat,
stint
@ -35,13 +36,20 @@ when not breakCircularDependency:
../../v2memory,
../../v2state,
../gas_meter,
../v2gas_costs,
../utils/v2utils_numeric,
eth/common
else:
import macros
var blindGasCosts: array[Op,int]
var
GasBalance = 0
GasExtCode = 42
GasExtCodeHash = 7
blindGasCosts: array[Op,int]
blindAddress: EthAddress
gasFees: array[Fork,array[0..123,int]]
# copied from stack.nim
macro genTupleType(len: static[int], elemType: untyped): untyped =
@ -50,7 +58,7 @@ else:
# function stubs from stack.nim (to satisfy compiler logic)
proc push[T](x: Stack; n: T) = discard
proc popAddress(x: var Stack): UInt256 = 0.u256
proc popAddress(x: var Stack): EthAddress = blindAddress
proc popInt(x: var Stack, n: static[int]): auto =
var rc: genTupleType(n, UInt256)
return rc
@ -62,6 +70,7 @@ else:
proc getCode[T](c: Computation, address: T): seq[byte] = @[]
proc getGasPrice(c: Computation): Uint256 = 0.u256
proc getOrigin(c: Computation): Uint256 = 0.u256
proc getCodeHash[T](c: Computation, address: T): Uint256 = 0.u256
# function stubs from v2utils_numeric.nim
func cleanMemRef(x: UInt256): int = 0
@ -117,12 +126,25 @@ const
k.cpt.stack.push:
k.cpt.msg.contractAddress
# ------------------
balanceOp: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x31, Get balance of the given account.
let address = k.cpt.stack.popAddress
k.cpt.stack.push:
k.cpt.getBalance(address)
balanceEIP2929Op: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x31, EIP292: Get balance of the given account for Berlin and later
let address = k.cpt.stack.popAddress()
k.cpt.gasEip2929AccountCheck(
address, gasFees[k.cpt.fork][GasBalance])
k.cpt.stack.push:
k.cpt.getBalance(address)
# ------------------
originOp: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x32, Get execution origination address.
k.cpt.stack.push:
@ -204,7 +226,9 @@ const
gasPriceOp: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x3A, Get price of gas in current environment.
k.cpt.stack.push:
k.cpt.getGasPrice
k.cpt.getGasPrice()
# -----------
extCodeSizeOp: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x3b, Get size of an account's code
@ -212,6 +236,16 @@ const
k.cpt.stack.push:
k.cpt.getCodeSize(address)
extCodeSizeEIP2929Op: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x3b, Get size of an account's code
let address = k.cpt.stack.popAddress()
k.cpt.gasEip2929AccountCheck(
address, gasFees[k.cpt.fork][GasExtCode])
k.cpt.stack.push:
k.cpt.getCodeSize(address)
# -----------
extCodeCopyOp: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x3c, Copy an account's code to memory.
@ -229,6 +263,25 @@ const
k.cpt.memory.writePaddedResult(codeBytes, memPos, codePos, len)
extCodeCopyEIP2929Op: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x3c, Copy an account's code to memory.
let address = k.cpt.stack.popAddress()
let (memStartPos, codeStartPos, size) = k.cpt.stack.popInt(3)
let (memPos, codePos, len) = (memStartPos.cleanMemRef,
codeStartPos.cleanMemRef, size.cleanMemRef)
k.cpt.gasMeter.consumeGas(
k.cpt.gasCosts[ExtCodeCopy].m_handler(k.cpt.memory.len, memPos, len),
reason = "ExtCodeCopy fee")
k.cpt.gasEip2929AccountCheck(
address, gasFees[k.cpt.fork][GasExtCode])
let codeBytes = k.cpt.getCode(address)
k.cpt.memory.writePaddedResult(codeBytes, memPos, codePos, len)
# -----------
returnDataSizeOp: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x3d, Get size of output data from the previous call from the
## current environment.
@ -256,6 +309,24 @@ const
"length")
k.cpt.memory.writePaddedResult(k.cpt.returnData, memPos, copyPos, len)
# ---------------
extCodeHashOp: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x3f, Returns the keccak256 hash of a contracts code
let address = k.cpt.stack.popAddress()
k.cpt.stack.push:
k.cpt.getCodeHash(address)
extCodeHashEIP2929Op: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x3f, EIP2929: Returns the keccak256 hash of a contracts code
let address = k.cpt.stack.popAddress()
k.cpt.gasEip2929AccountCheck(
address, gasFees[k.cpt.fork][GasExtCodeHash])
k.cpt.stack.push:
k.cpt.getCodeHash(address)
# ------------------------------------------------------------------------------
# Public, op exec table entries
# ------------------------------------------------------------------------------
@ -271,12 +342,19 @@ const
post: vm2OpIgnore)),
(opCode: Balance, ## 0x31, Balance
forks: Vm2OpAllForks,
forks: Vm2OpAllForks - Vm2OpBerlinAndLater,
info: "Get balance of the given account",
exec: (prep: vm2OpIgnore,
run: balanceOp,
post: vm2OpIgnore)),
(opCode: Balance, ## 0x31, Balance for Berlin and later
forks: Vm2OpBerlinAndLater,
info: "EIP2929: Get balance of the given account",
exec: (prep: vm2OpIgnore,
run: balanceEIP2929Op,
post: vm2OpIgnore)),
(opCode: Origin, ## 0x32, Origination address
forks: Vm2OpAllForks,
info: "Get execution origination address",
@ -342,19 +420,33 @@ const
post: vm2OpIgnore)),
(opCode: ExtCodeSize, ## 0x3b, Account code size
forks: Vm2OpAllForks,
forks: Vm2OpAllForks - Vm2OpBerlinAndLater,
info: "Get size of an account's code",
exec: (prep: vm2OpIgnore,
run: extCodeSizeOp,
post: vm2OpIgnore)),
(opCode: ExtCodeSize, ## 0x3b, Account code size for Berlin and later
forks: Vm2OpBerlinAndLater,
info: "EIP2929: Get size of an account's code",
exec: (prep: vm2OpIgnore,
run: extCodeSizeEIP2929Op,
post: vm2OpIgnore)),
(opCode: ExtCodeCopy, ## 0x3c, Account code copy to memory.
forks: Vm2OpAllForks,
forks: Vm2OpAllForks - Vm2OpBerlinAndLater,
info: "Copy an account's code to memory",
exec: (prep: vm2OpIgnore,
run: extCodeCopyOp,
post: vm2OpIgnore)),
(opCode: ExtCodeCopy, ## 0x3c, Account Code-copy for Berlin and later
forks: Vm2OpBerlinAndLater,
info: "EIP2929: Copy an account's code to memory",
exec: (prep: vm2OpIgnore,
run: extCodeCopyEIP2929Op,
post: vm2OpIgnore)),
(opCode: ReturnDataSize, ## 0x3d, Previous call output data size
forks: Vm2OpAllForks,
info: "Get size of output data from the previous call " &
@ -368,6 +460,20 @@ const
info: "Copy output data from the previous call to memory",
exec: (prep: vm2OpIgnore,
run: returnDataCopyOp,
post: vm2OpIgnore)),
(opCode: ExtCodeHash, ## 0x3f, Contract hash
forks: Vm2OpAllForks - Vm2OpBerlinAndLater,
info: "Returns the keccak256 hash of a contracts code",
exec: (prep: vm2OpIgnore,
run: extCodeHashOp,
post: vm2OpIgnore)),
(opCode: ExtCodeHash, ## 0x3f, Contract hash for berlin and later
forks: Vm2OpBerlinAndLater,
info: "EIP2929: Returns the keccak256 hash of a contracts code",
exec: (prep: vm2OpIgnore,
run: extCodeHashEIP2929Op,
post: vm2OpIgnore))]
# ------------------------------------------------------------------------------

View File

@ -35,11 +35,34 @@ const
when not breakCircularDependency:
import
../../v2types
../../../db/accounts_cache,
../../v2state,
../../v2types,
../gas_meter,
../v2gas_costs,
eth/common
else:
const
emvcStatic = 1
ColdAccountAccessCost = 2
WarmStorageReadCost = 3
type
GasInt = int
# function stubs from v2state.nim
template mutateStateDB(vmState: BaseVMState, body: untyped) =
block:
var db {.inject.} = vmState.accountDb
body
# 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
# function stubs from gas_meter.nim
proc consumeGas(gasMeter: var GasMeter; amount: int; reason: string) = discard
# ------------------------------------------------------------------------------
# Kludge END
@ -63,6 +86,20 @@ proc asText(id, name: string): NimNode {.compileTime.} =
# Public
# ------------------------------------------------------------------------------
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 checkInStaticContext*(c: Computation) =
## Verify static context in handler function, raise an error otherwise
if emvcStatic == c.msg.flags:

View File

@ -36,7 +36,6 @@ when not breakCircularDependency:
../../stack,
../../v2computation,
../../v2memory,
../../v2state,
../../v2types,
../gas_meter,
../utils/v2utils_numeric,

View File

@ -39,12 +39,15 @@ when not breakCircularDependency:
../gas_meter,
../utils/v2utils_numeric,
../v2gas_costs,
eth/common,
times
eth/common
else:
import macros
const
ColdSloadCost = 42
WarmStorageReadCost = 43
var blindGasCosts: array[Op,int]
# copied from stack.nim
@ -79,7 +82,10 @@ else:
# function stubs from v2state.nim
proc readOnlyStateDB(x: BaseVMState): ReadOnlyStateDB = x.accountDb
template mutateStateDB(vmState: BaseVMState, body: untyped) = discard
template mutateStateDB(vmState: BaseVMState, body: untyped) =
block:
var db {.inject.} = vmState.accountDb
body
# function stubs from gas_meter.nim
proc refundGas(gasMeter: var GasMeter; amount: int) = discard
@ -99,6 +105,11 @@ else:
# function stubs from state_db.nim
proc getCommittedStorage[A,B](x: A; y: B; z: Uint256): Uint256 = 0.u256
# function stubs from accounts_cache.nim:
func inAccessList[A,B](ac: A; address: B; slot: UInt256): bool = false
proc accessList[A,B](ac: var A; address: B; slot: UInt256) = discard
proc setStorage[A,B](ac: var A; address: B, slot, value: UInt256) = discard
# ------------------------------------------------------------------------------
# Kludge END
# ------------------------------------------------------------------------------
@ -195,6 +206,7 @@ const
k.cpt.memory.extend(memPos, 1)
k.cpt.memory.write(memPos, [value.toByteArrayBE[31]])
# -------
sloadOp: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x54, Load word from storage.
@ -202,6 +214,22 @@ const
k.cpt.stack.push:
k.cpt.getStorage(slot)
sloadEIP2929Op: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x54, EIP2929: Load word from storage for Berlin and later
let (slot) = k.cpt.stack.popInt(1)
k.cpt.vmState.mutateStateDB:
let gasCost = if not db.inAccessList(k.cpt.msg.contractAddress, slot):
db.accessList(k.cpt.msg.contractAddress, slot)
ColdSloadCost
else:
WarmStorageReadCost
k.cpt.gasMeter.consumeGas(gasCost, reason = "sloadEIP2929")
k.cpt.stack.push:
k.cpt.getStorage(slot)
# -------
sstoreOp: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x55, Save word to storage.
let (slot, newValue) = k.cpt.stack.popInt(2)
@ -251,6 +279,26 @@ const
sstoreNetGasMeteringImpl(k.cpt, slot, newValue)
sstoreEIP2929Op: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x55, EIP2929: sstore for Berlin and later
let (slot, newValue) = k.cpt.stack.popInt(2)
checkInStaticContext(k.cpt)
# Minimum gas required to be present for an SSTORE call, not consumed
const SentryGasEIP2200 = 2300
if k.cpt.gasMeter.gasRemaining <= SentryGasEIP2200:
raise newException(OutOfGas, "Gas not enough to perform EIP2200 SSTORE")
k.cpt.vmState.mutateStateDB:
if not db.inAccessList(k.cpt.msg.contractAddress, slot):
db.accessList(k.cpt.msg.contractAddress, slot)
k.cpt.gasMeter.consumeGas(ColdSloadCost, reason = "sstoreEIP2929")
sstoreNetGasMeteringImpl(k.cpt, slot, newValue)
# -------
jumpOp: Vm2OpFn = proc (k: Vm2Ctx) =
## 0x56, Alter the program counter
let (jumpTarget) = k.cpt.stack.popInt(1)
@ -360,12 +408,19 @@ const
post: vm2OpIgnore)),
(opCode: Sload, ## 0x54, Load word from storage
forks: Vm2OpAllForks,
forks: Vm2OpAllForks - Vm2OpBerlinAndLater,
info: "Load word from storage",
exec: (prep: vm2OpIgnore,
run: sloadOp,
post: vm2OpIgnore)),
(opCode: Sload, ## 0x54, sload for Berlin and later
forks: Vm2OpBerlinAndLater,
info: "EIP2929: sload for Berlin and later",
exec: (prep: vm2OpIgnore,
run: sloadEIP2929Op,
post: vm2OpIgnore)),
(opCode: Sstore, ## 0x55, Save word
forks: Vm2OpAllForks - Vm2OpConstantinopleAndLater,
info: "Save word to storage",
@ -381,12 +436,19 @@ const
post: vm2OpIgnore)),
(opCode: Sstore, ## 0x55, sstore for Istanbul and later
forks: Vm2OpIstanbulAndLater,
forks: Vm2OpIstanbulAndLater - Vm2OpBerlinAndLater,
info: "EIP2200: sstore for Istanbul and later",
exec: (prep: vm2OpIgnore,
run: sstoreEIP2200Op,
post: vm2OpIgnore)),
(opCode: Sstore, ## 0x55, sstore for Berlin and later
forks: Vm2OpBerlinAndLater,
info: "EIP2929: sstore for Istanbul and later",
exec: (prep: vm2OpIgnore,
run: sstoreEIP2929Op,
post: vm2OpIgnore)),
(opCode: Jump, ## 0x56, Jump
forks: Vm2OpIstanbulAndLater,
info: "Alter the program counter",

View File

@ -124,8 +124,8 @@ opHandler sarOp, Op.Sar
opHandler sha3, Op.Sha3
opHandler address, Op.Address
opHandler balance, Op.Balance, FkFrontier
opHandler balanceEIP2929, Op.Balance
opHandler balance, Op.Balance, FkFrontier
opHandler balanceEIP2929, Op.Balance
opHandler origin, Op.Origin
opHandler caller, Op.Caller
@ -145,6 +145,10 @@ opHandler extCodeCopyEIP2929, Op.ExtCodeCopy
opHandler returnDataSize, Op.ReturnDataSize
opHandler returnDataCopy, Op.ReturnDataCopy
opHandler extCodeHash, Op.ExtCodeHash, FkFrontier
opHandler extCodeHashEIP2929, Op.ExtCodeHash
opHandler blockhash, Op.Blockhash
opHandler coinbase, Op.Coinbase
opHandler timestamp, Op.Timestamp
@ -158,13 +162,13 @@ opHandler mload, Op.Mload
opHandler mstore, Op.Mstore
opHandler mstore8, Op.Mstore8
opHandler sload, Op.Sload, FkFrontier
opHandler sloadEIP2929, Op.Sload
opHandler sload, Op.Sload, FkFrontier
opHandler sloadEIP2929, Op.Sload
opHandler sstore, Op.Sstore, FkFrontier
opHandler sstoreEIP1283, Op.Sstore, FkConstantinople
opHandler sstoreEIP2200, Op.Sstore, FkIstanbul
opHandler sstoreEIP2929, Op.Sstore
opHandler sstore, Op.Sstore, FkFrontier
opHandler sstoreEIP1283, Op.Sstore, FkConstantinople
opHandler sstoreEIP2200, Op.Sstore, FkIstanbul
opHandler sstoreEIP2929, Op.Sstore
opHandler jump, Op.Jump
opHandler jumpI, Op.JumpI
@ -545,16 +549,6 @@ op selfDestructEip161, inline = false:
c.selfDestruct(beneficiary)
# Constantinople's new opcodes
#################################
op extCodeHash, inline = true:
let address = c.stack.popAddress()
push: c.getCodeHash(address)
op extCodeHashEIP2929, inline = true:
let address = c.stack.popAddress()
c.gasEip2929AccountCheck(address, gasFees[c.fork][GasExtCodeHash])
push: c.getCodeHash(address)
op selfDestructEIP2929, inline = false:
checkInStaticContext(c)
@ -577,60 +571,3 @@ op selfDestructEIP2929, inline = false:
c.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP161")
c.selfDestruct(beneficiary)
# ---------------------------------------------------
op balanceEIP2929x, inline = true:
## 0x31, Get balance of the given account.
let address = c.stack.popAddress()
c.gasEip2929AccountCheck(address, gasFees[c.fork][GasBalance])
push: c.getBalance(address)
op extCodeSizeEIP2929x, inline = true:
## 0x3b, Get size of an account's code
let address = c.stack.popAddress()
c.gasEip2929AccountCheck(address, gasFees[c.fork][GasExtCode])
push: c.getCodeSize(address)
op extCodeCopyEIP2929x, inline = true:
## 0x3c, Copy an account's code to memory.
let address = c.stack.popAddress()
let (memStartPos, codeStartPos, size) = c.stack.popInt(3)
let (memPos, codePos, len) = (memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef)
c.gasMeter.consumeGas(
c.gasCosts[ExtCodeCopy].m_handler(c.memory.len, memPos, len),
reason="ExtCodeCopy fee")
c.gasEip2929AccountCheck(address, gasFees[c.fork][GasExtCode])
let codeBytes = c.getCode(address)
c.memory.writePaddedResult(codeBytes, memPos, codePos, len)
op sloadEIP2929x, inline = true, slot:
## 0x54, Load word from storage.
c.vmState.mutateStateDB:
let gasCost = if not db.inAccessList(c.msg.contractAddress, slot):
db.accessList(c.msg.contractAddress, slot)
ColdSloadCost
else:
WarmStorageReadCost
c.gasMeter.consumeGas(gasCost, reason = "sloadEIP2929")
push: c.getStorage(slot)
op sstoreEIP2929x, inline = false, slot, newValue:
checkInStaticContext(c)
const SentryGasEIP2200 = 2300 # Minimum gas required to be present for an SSTORE call, not consumed
if c.gasMeter.gasRemaining <= SentryGasEIP2200:
raise newException(OutOfGas, "Gas not enough to perform EIP2200 SSTORE")
c.vmState.mutateStateDB:
if not db.inAccessList(c.msg.contractAddress, slot):
db.accessList(c.msg.contractAddress, slot)
c.gasMeter.consumeGas(ColdSloadCost, reason = "sstoreEIP2929")
block:
sstoreNetGasMeteringImpl(c, slot, newValue)