mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-11 21:04:11 +00:00
Some of Shanghai: EIP-3651, EIP-3855, EIP-3860 (#1406)
* EIP-3651: Warm COINBASE * EIP-3855: PUSH0 instruction * EIP-3860: Limit and meter initcode
This commit is contained in:
parent
63c6000bad
commit
4bf4aeba94
@ -56,6 +56,10 @@ const
|
||||
# contract is not subject to this limit.
|
||||
EIP170_MAX_CODE_SIZE* = 0x6000
|
||||
|
||||
# See EIP-3860 (https://eips.ethereum.org/EIPS/eip-3860). Maximum initcode
|
||||
# size when creating a new contract.
|
||||
EIP3860_MAX_INITCODE_SIZE* = 2 * EIP170_MAX_CODE_SIZE
|
||||
|
||||
# EIP
|
||||
MaxPrecompilesAddr* = 0xFFFF
|
||||
|
||||
|
@ -259,6 +259,10 @@ proc validateTransaction*(
|
||||
debug "invalid tx: Eip1559 Tx type detected before London"
|
||||
return false
|
||||
|
||||
if fork >= FkShanghai and tx.contractCreation and tx.payload.len >= EIP3860_MAX_INITCODE_SIZE:
|
||||
debug "invalid tx: initcode size exceeds maximum"
|
||||
return false
|
||||
|
||||
# Note that the following check bears some plausibility but is _not_
|
||||
# covered by the eip-1559 reference (sort of) pseudo code, for details
|
||||
# see `https://eips.ethereum.org/EIPS/eip-1559#specification`_
|
||||
|
@ -52,7 +52,8 @@ type
|
||||
GasSha3Word, # Paid for each word (rounded up) for input data to a SHA3 operation.
|
||||
GasCopy, # Partial payment for COPY operations, multiplied by words copied, rounded up.
|
||||
GasBlockhash, # Payment for BLOCKHASH operation.
|
||||
GasExtCodeHash # Payment for contract's code hashing
|
||||
GasExtCodeHash, # Payment for contract's code hashing
|
||||
GasInitcodeWord # Payment for each word (rounded up) for initcode
|
||||
|
||||
GasFeeSchedule = array[GasFeeKind, GasInt]
|
||||
|
||||
@ -278,6 +279,7 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
||||
result.gasCost = static(FeeSchedule[GasCodeDeposit]) * gasParams.cr_memLength
|
||||
else:
|
||||
result.gasCost = static(FeeSchedule[GasCreate]) +
|
||||
(static(FeeSchedule[GasInitcodeWord]) * gasParams.cr_memLength.wordCount) +
|
||||
`prefix gasMemoryExpansion`(
|
||||
gasParams.cr_currentMemSize,
|
||||
gasParams.cr_memOffset,
|
||||
@ -620,7 +622,8 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
||||
ReturnSub: fixed GasLow,
|
||||
JumpSub: fixed GasHigh,
|
||||
|
||||
# 60s & 70s: Push Operations
|
||||
# 5f, 60s & 70s: Push Operations
|
||||
Push0: fixed GasBase,
|
||||
Push1: fixed GasVeryLow,
|
||||
Push2: fixed GasVeryLow,
|
||||
Push3: fixed GasVeryLow,
|
||||
@ -749,7 +752,8 @@ const
|
||||
GasSha3Word: 6,
|
||||
GasCopy: 3,
|
||||
GasBlockhash: 20,
|
||||
GasExtCodeHash: 400
|
||||
GasExtCodeHash: 400,
|
||||
GasInitcodeWord: 0 # Changed to 2 in EIP-3860
|
||||
]
|
||||
|
||||
# Create the schedule for each forks
|
||||
@ -802,6 +806,10 @@ func londonGasFees(previousFees: GasFeeSchedule): GasFeeSchedule =
|
||||
5000 - ColdSloadCost +
|
||||
ACCESS_LIST_STORAGE_KEY_COST
|
||||
|
||||
func shanghaiGasFees(previousFees: GasFeeSchedule): GasFeeSchedule =
|
||||
result = previousFees
|
||||
result[GasInitcodeWord] = 2.GasInt # INITCODE_WORD_COST from EIP-3860
|
||||
|
||||
const
|
||||
HomesteadGasFees = BaseGasFees.homesteadGasFees
|
||||
TangerineGasFees = HomesteadGasFees.tangerineGasFees
|
||||
@ -809,6 +817,7 @@ const
|
||||
IstanbulGasFees = SpuriousGasFees.istanbulGasFees
|
||||
BerlinGasFees = IstanbulGasFees.berlinGasFees
|
||||
LondonGasFees = BerlinGasFees.londonGasFees
|
||||
ShanghaiGasFees = LondonGasFees.shanghaiGasFees
|
||||
|
||||
gasFees*: array[EVMFork, GasFeeSchedule] = [
|
||||
FkFrontier: BaseGasFees,
|
||||
@ -822,8 +831,8 @@ const
|
||||
FkBerlin: BerlinGasFees,
|
||||
FkLondon: LondonGasFees,
|
||||
FkParis: LondonGasFees,
|
||||
FkShanghai: LondonGasFees,
|
||||
FkCancun: LondonGasFees,
|
||||
FkShanghai: ShanghaiGasFees,
|
||||
FkCancun: ShanghaiGasFees,
|
||||
]
|
||||
|
||||
gasCosts(FkFrontier, base, BaseGasCosts)
|
||||
@ -834,6 +843,7 @@ gasCosts(FkConstantinople, constantinople, ConstantinopleGasCosts)
|
||||
gasCosts(FkIstanbul, istanbul, IstanbulGasCosts)
|
||||
gasCosts(FkBerlin, berlin, BerlinGasCosts)
|
||||
gasCosts(FkLondon, london, LondonGasCosts)
|
||||
gasCosts(FkShanghai, shanghai, ShanghaiGasCosts)
|
||||
|
||||
proc forkToSchedule*(fork: EVMFork): GasCosts =
|
||||
if fork < FkHomestead:
|
||||
@ -850,8 +860,10 @@ proc forkToSchedule*(fork: EVMFork): GasCosts =
|
||||
IstanbulGasCosts
|
||||
elif fork < FkLondon:
|
||||
BerlinGasCosts
|
||||
else:
|
||||
elif fork < FkShanghai:
|
||||
LondonGasCosts
|
||||
else:
|
||||
ShanghaiGasCosts
|
||||
|
||||
const
|
||||
## Precompile costs
|
||||
|
@ -129,9 +129,9 @@ type
|
||||
BeginSub = 0x5c, ## Marks the entry point to a subroutine
|
||||
ReturnSub = 0x5d, ## Returns control to the caller of a subroutine.
|
||||
JumpSub = 0x5e, ## Transfers control to a subroutine.
|
||||
Nop0x5F = 0x5f, ## ..
|
||||
|
||||
# 60s & 70s: Push Operations.
|
||||
# 5f, 60s & 70s: Push Operations.
|
||||
Push0 = 0x5f, ## Place 0 on stack. EIP-3855
|
||||
Push1 = 0x60, ## Place 1-byte item on stack.
|
||||
Push2 = 0x61, ## Place 2-byte item on stack.
|
||||
|
||||
|
@ -34,6 +34,7 @@ const
|
||||
(vm2OpExecBlockData, "BlockData"),
|
||||
(vm2OpExecMemory, "Memory"),
|
||||
(vm2OpExecPush, "Push"),
|
||||
(vm2OpExecPushZero, "PushZero"),
|
||||
(vm2OpExecDup, "Dup"),
|
||||
(vm2OpExecSwap, "Swap"),
|
||||
(vm2OpExecLog, "Log"),
|
||||
|
@ -91,6 +91,11 @@ const
|
||||
|
||||
k.cpt.stack.top(0)
|
||||
|
||||
# EIP-3860
|
||||
if k.cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE:
|
||||
trace "Initcode size exceeds maximum", initcodeSize = memLen
|
||||
return
|
||||
|
||||
let gasParams = GasParams(
|
||||
kind: Create,
|
||||
cr_currentMemSize: k.cpt.memory.len,
|
||||
@ -163,6 +168,11 @@ const
|
||||
|
||||
k.cpt.stack.top(0)
|
||||
|
||||
# EIP-3860
|
||||
if k.cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE:
|
||||
trace "Initcode size exceeds maximum", initcodeSize = memLen
|
||||
return
|
||||
|
||||
let gasParams = GasParams(
|
||||
kind: Create,
|
||||
cr_currentMemSize: k.cpt.memory.len,
|
||||
|
@ -81,6 +81,12 @@ const
|
||||
Vm2OpLondonAndLater* =
|
||||
Vm2OpBerlinAndLater - {FkBerlin}
|
||||
|
||||
Vm2OpParisAndLater* =
|
||||
Vm2OpLondonAndLater - {FkLondon}
|
||||
|
||||
Vm2OpShanghaiAndLater* =
|
||||
Vm2OpParisAndLater - {FkParis}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -58,6 +58,28 @@ genOphHandlers fnName, fnInfo, inxRange, pushImpl
|
||||
|
||||
genOphList fnName, fnInfo, inxRange, "vm2OpExecPush", opName
|
||||
|
||||
|
||||
# Push0 needs to be slightly different because it's only available after
|
||||
# Shanghai (EIP-3855). But it still seems like it belongs in this file.
|
||||
# (Alternatively, we could make genOphList accept some more information
|
||||
# about which opcodes are for which forks, but that seems uglier than
|
||||
# just adding Push0 here as a special case.)
|
||||
|
||||
const
|
||||
push0Op: Vm2OpFn = proc (k: var Vm2Ctx) =
|
||||
## 0x5f, push 0 onto the stack
|
||||
k.cpt.stack.push(0)
|
||||
|
||||
vm2OpExecPushZero*: seq[Vm2OpExec] = @[
|
||||
|
||||
(opCode: Push0, ## 0x5f, push 0 onto the stack
|
||||
forks: Vm2OpShanghaiAndLater,
|
||||
name: "Push0",
|
||||
info: "Push 0 on the stack",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: push0Op,
|
||||
post: vm2OpIgnore))]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -28,6 +28,8 @@ proc intrinsicGas*(tx: Transaction, fork: EVMFork): GasInt =
|
||||
|
||||
if tx.contractCreation:
|
||||
result = result + gasFees[fork][GasTXCreate]
|
||||
if fork >= FkShanghai:
|
||||
result = result + (gasFees[fork][GasInitcodeWord] * tx.payload.len)
|
||||
|
||||
if tx.txType > TxLegacy:
|
||||
result = result + tx.accessList.len * ACCESS_LIST_ADDRESS_COST
|
||||
@ -121,6 +123,9 @@ proc validate*(tx: Transaction, fork: EVMFork) =
|
||||
if tx.intrinsicGas(fork) > tx.gasLimit:
|
||||
raise newException(ValidationError, "Insufficient gas")
|
||||
|
||||
if fork >= FkShanghai and tx.contractCreation and tx.payload.len >= EIP3860_MAX_INITCODE_SIZE:
|
||||
raise newException(ValidationError, "Initcode size exceeds max")
|
||||
|
||||
# check signature validity
|
||||
var sender: EthAddress
|
||||
if not tx.getSender(sender):
|
||||
|
@ -73,6 +73,8 @@ func intrinsicGas*(call: CallParams, fork: EVMFork): GasInt {.inline.} =
|
||||
# EIP-2 (Homestead) extra intrinsic gas for contract creations.
|
||||
if call.isCreate:
|
||||
gas += gasFees[fork][GasTXCreate]
|
||||
if fork >= FkShanghai:
|
||||
gas += (gasFees[fork][GasInitcodeWord] * call.input.len.wordCount)
|
||||
|
||||
# Input data cost, reduced in EIP-2028 (Istanbul).
|
||||
let gasZero = gasFees[fork][GasTXDataZero]
|
||||
@ -99,6 +101,11 @@ proc initialAccessListEIP2929(call: CallParams) =
|
||||
# access list itself, after calculating the new contract address.
|
||||
if not call.isCreate:
|
||||
db.accessList(call.to)
|
||||
|
||||
# EIP3651 adds coinbase to the list of addresses that should start warm.
|
||||
if vmState.fork >= FkShanghai:
|
||||
db.accessList(vmState.coinbase)
|
||||
|
||||
# TODO: Check this only adds the correct subset of precompiles.
|
||||
for c in activePrecompiles():
|
||||
db.accessList(c)
|
||||
|
Loading…
x
Reference in New Issue
Block a user