EIP-4399 implementation of nim-vm
what's new: - `RANDOM` OPCODE - `random` field of BlockHeader(previously `mixDigest`) - `PostMerge` temporary name
This commit is contained in:
parent
77c9b8c2f0
commit
71aa7e4b5c
|
@ -18,3 +18,6 @@ type
|
|||
FkIstanbul = "Istanbul"
|
||||
FkBerlin = "Berlin"
|
||||
FkLondon = "London"
|
||||
# TODO: PostMerge is a temporary name
|
||||
# until we have an official name
|
||||
FkPostMerge = "PostMerge"
|
||||
|
|
|
@ -24,6 +24,7 @@ const
|
|||
eth5 = 5.eth
|
||||
eth3 = 3.eth
|
||||
eth2 = 2.eth
|
||||
eth0 = 0.u256
|
||||
|
||||
# Note than the `blockRewards` were previously exported but nowhere
|
||||
# used otherwise.
|
||||
|
@ -37,7 +38,8 @@ const
|
|||
eth2, # FkPetersburg
|
||||
eth2, # FkIstanbul
|
||||
eth2, # FkBerlin
|
||||
eth2 # FkLondon
|
||||
eth2, # FkLondon
|
||||
eth0 # FkPostMerge
|
||||
]
|
||||
|
||||
{.push raises: [Defect].}
|
||||
|
|
|
@ -61,17 +61,24 @@ proc setupTxContext(host: TransactionHost) =
|
|||
# vmState.gasLimit now unused
|
||||
host.txContext.block_gas_limit = vmState.gasLimit
|
||||
# vmState.difficulty now unused
|
||||
host.txContext.block_difficulty = vmState.difficulty.toEvmc
|
||||
host.txContext.chain_id = vmState.chaindb.config.chainId.uint.u256.toEvmc
|
||||
host.txContext.block_base_fee = vmState.baseFee.toEvmc
|
||||
|
||||
# Most host functions do `flip256` in `evmc_host_glue`, but due to this
|
||||
# result being cached, it's better to do `flip256` when filling the cache.
|
||||
host.txContext.tx_gas_price = flip256(host.txContext.tx_gas_price)
|
||||
host.txContext.block_difficulty = flip256(host.txContext.block_difficulty)
|
||||
host.txContext.chain_id = flip256(host.txContext.chain_id)
|
||||
host.txContext.block_base_fee = flip256(host.txContext.block_base_fee)
|
||||
|
||||
# EIP-4399
|
||||
# Transfer block randomness to difficulty OPCODE
|
||||
let difficulty = vmState.difficulty.toEvmc
|
||||
if difficulty.isZero:
|
||||
# no flipping, because hash is a 32 bytes array
|
||||
host.txContext.block_difficulty = vmState.random.toEvmc
|
||||
else:
|
||||
host.txContext.block_difficulty = flip256(difficulty)
|
||||
|
||||
host.cachedTxContext = true
|
||||
|
||||
const use_evmc_glue = defined(evmc_enabled)
|
||||
|
|
|
@ -94,6 +94,9 @@ template isCreate*(kind: EvmcCallKind): bool =
|
|||
template isStatic*(msg: EvmcMessage): bool =
|
||||
EVMC_STATIC in msg.flags
|
||||
|
||||
template isZero*(n: evmc_bytes32): bool =
|
||||
n == default(evmc_bytes32)
|
||||
|
||||
# Nim quirks: Exporting `evmc_status_code` (etc) are needed to access the enum
|
||||
# values, even though alias `EnumStatusCode` is already exported. Exporting
|
||||
# `evmc_flags` won't export the flags, `evmc_flag_bit_shifts` must be used.
|
||||
|
|
|
@ -78,7 +78,11 @@ proc resetTxEnv(dh: TxChainRef; parent: BlockHeader; fee: Option[UInt256])
|
|||
parent = parent,
|
||||
timestamp = getTime().utc.toTime,
|
||||
gasLimit = (if dh.maxMode: dh.limits.maxLimit else: dh.limits.trgLimit),
|
||||
fee = fee,
|
||||
fee = fee,
|
||||
# EIP-4399 extra complexity
|
||||
# TODO: make sure from where or what value
|
||||
# this `random` param should be
|
||||
random = Hash256(),
|
||||
miner = dh.miner,
|
||||
chainDB = dh.db)
|
||||
|
||||
|
|
|
@ -51,6 +51,15 @@ template getDifficulty*(c: Computation): DifficultyInt =
|
|||
else:
|
||||
c.vmState.difficulty
|
||||
|
||||
template getRandom*(c: Computation): Hash256 =
|
||||
when evmc_enabled:
|
||||
# EIP-4399
|
||||
# no flipping because `block_difficulty` in this context
|
||||
# is a 32 bytes array
|
||||
Hash256.fromEvmc c.host.getTxContext().block_difficulty
|
||||
else:
|
||||
c.vmState.random
|
||||
|
||||
template getGasLimit*(c: Computation): GasInt =
|
||||
when evmc_enabled:
|
||||
c.host.getTxContext().block_gas_limit.GasInt
|
||||
|
|
|
@ -16,7 +16,15 @@ proc hostGetTxContextImpl(ctx: Computation): nimbus_tx_context {.cdecl.} =
|
|||
result.block_number = vmstate.blockNumber.truncate(int64)
|
||||
result.block_timestamp = vmstate.timestamp.toUnix()
|
||||
result.block_gas_limit = int64(vmstate.gasLimit)
|
||||
result.block_difficulty = toEvmc(vmstate.difficulty)
|
||||
|
||||
# EIP-4399
|
||||
# Transfer block randomness to difficulty OPCODE
|
||||
let difficulty = toEvmc(vmstate.difficulty)
|
||||
if difficulty == default(evmc_bytes32): # or difficulty.isZero
|
||||
result.block_difficulty = vmState.random.toEvmc
|
||||
else:
|
||||
result.block_difficulty = difficulty
|
||||
|
||||
result.chain_id = toEvmc(vmstate.chaindb.config.chainId.uint.u256)
|
||||
result.block_base_fee = toEvmc(vmstate.baseFee)
|
||||
|
||||
|
|
|
@ -761,7 +761,8 @@ const
|
|||
FkPetersburg: SpuriousGasFees,
|
||||
FkIstanbul: IstanbulGasFees,
|
||||
FkBerlin: BerlinGasFees,
|
||||
FkLondon: LondonGasFees
|
||||
FkLondon: LondonGasFees,
|
||||
FkPostMerge: LondonGasFees
|
||||
]
|
||||
|
||||
|
||||
|
@ -773,6 +774,7 @@ gasCosts(FkConstantinople, constantinople, ConstantinopleGasCosts)
|
|||
gasCosts(FkIstanbul, istanbul, IstanbulGasCosts)
|
||||
gasCosts(FkBerlin, berlin, BerlinGasCosts)
|
||||
gasCosts(FkLondon, london, LondonGasCosts)
|
||||
gasCosts(FkPostMerge, postMerge, PostMergeGasCosts)
|
||||
|
||||
proc forkToSchedule*(fork: Fork): GasCosts =
|
||||
if fork < FkHomestead:
|
||||
|
@ -789,8 +791,10 @@ proc forkToSchedule*(fork: Fork): GasCosts =
|
|||
IstanbulGasCosts
|
||||
elif fork < FkLondon:
|
||||
BerlinGasCosts
|
||||
else:
|
||||
elif fork < FkPostMerge:
|
||||
LondonGasCosts
|
||||
else:
|
||||
PostMergeGasCosts
|
||||
|
||||
const
|
||||
## Precompile costs
|
||||
|
|
|
@ -188,3 +188,7 @@ fill_enum_holes:
|
|||
Revert = 0xfd, # Halt execution reverting state changes but returning data and remaining gas.
|
||||
Invalid = 0xfe, # Designated invalid instruction.
|
||||
SelfDestruct = 0xff # Halt execution and register account for later deletion.
|
||||
|
||||
const
|
||||
# EIP-4399 new opcode
|
||||
Random* = Difficulty
|
||||
|
|
|
@ -412,6 +412,11 @@ op difficulty, inline = true:
|
|||
## 0x44, Get the block's difficulty
|
||||
push: c.getDifficulty()
|
||||
|
||||
op randomEIP4399, inline = true:
|
||||
## since EIP-4399 0x44 renamed from `DIFFICULTY` to `RANDOM`
|
||||
## 0x44, Get the block's randomness
|
||||
push: c.getRandom()
|
||||
|
||||
op gasLimit, inline = true:
|
||||
## 0x45, Get the block's gas limit
|
||||
push: c.getGasLimit()
|
||||
|
|
|
@ -249,11 +249,18 @@ let BerlinOpDispatch {.compileTime.}: array[Op, NimNode] = genBerlinJumpTable(Is
|
|||
|
||||
proc genLondonJumpTable(ops: array[Op, NimNode]): array[Op, NimNode] {.compileTime.} =
|
||||
result = ops
|
||||
# incoming EIP-3198 and EIP-3529
|
||||
# EIP-3198 and EIP-3529
|
||||
result[BaseFee] = newIdentNode "baseFee"
|
||||
|
||||
let LondonOpDispatch {.compileTime.}: array[Op, NimNode] = genLondonJumpTable(BerlinOpDispatch)
|
||||
|
||||
proc genPostMergeJumpTable(ops: array[Op, NimNode]): array[Op, NimNode] {.compileTime.} =
|
||||
result = ops
|
||||
# EIP-4399
|
||||
result[Random] = newIdentNode "randomEIP4399"
|
||||
|
||||
let PostMergeOpDispatch {.compileTime.}: array[Op, NimNode] = genPostMergeJumpTable(LondonOpDispatch)
|
||||
|
||||
proc opTableToCaseStmt(opTable: array[Op, NimNode], c: NimNode): NimNode =
|
||||
|
||||
let instr = quote do: `c`.instr
|
||||
|
@ -345,6 +352,9 @@ macro genBerlinDispatch(c: Computation): untyped =
|
|||
macro genLondonDispatch(c: Computation): untyped =
|
||||
result = opTableToCaseStmt(LondonOpDispatch, c)
|
||||
|
||||
macro genPostMergeDispatch(c: Computation): untyped =
|
||||
result = opTableToCaseStmt(PostMergeOpDispatch, c)
|
||||
|
||||
proc frontierVM(c: Computation) =
|
||||
genFrontierDispatch(c)
|
||||
|
||||
|
@ -375,6 +385,9 @@ proc berlinVM(c: Computation) {.gcsafe.} =
|
|||
proc londonVM(c: Computation) {.gcsafe.} =
|
||||
genLondonDispatch(c)
|
||||
|
||||
proc postMergeVM(c: Computation) {.gcsafe.} =
|
||||
genPostMergeDispatch(c)
|
||||
|
||||
proc selectVM(c: Computation, fork: Fork) {.gcsafe.} =
|
||||
# TODO: Optimise getting fork and updating opCodeExec only when necessary
|
||||
case fork
|
||||
|
@ -396,8 +409,10 @@ proc selectVM(c: Computation, fork: Fork) {.gcsafe.} =
|
|||
c.istanbulVM()
|
||||
of FkBerlin:
|
||||
c.berlinVM()
|
||||
else:
|
||||
of FkLondon:
|
||||
c.londonVM()
|
||||
else:
|
||||
c.postMergeVM()
|
||||
|
||||
proc executeOpcodes(c: Computation) =
|
||||
let fork = c.fork
|
||||
|
|
|
@ -59,6 +59,7 @@ proc init(
|
|||
timestamp: EthTime;
|
||||
gasLimit: GasInt;
|
||||
fee: Option[Uint256];
|
||||
random: Hash256;
|
||||
miner: EthAddress;
|
||||
chainDB: BaseChainDB;
|
||||
tracer: TransactionTracer)
|
||||
|
@ -70,6 +71,7 @@ proc init(
|
|||
self.timestamp = timestamp
|
||||
self.gasLimit = gasLimit
|
||||
self.fee = fee
|
||||
self.random = random
|
||||
self.chaindb = chainDB
|
||||
self.tracer = tracer
|
||||
self.logEntries = @[]
|
||||
|
@ -84,6 +86,7 @@ proc init(
|
|||
timestamp: EthTime;
|
||||
gasLimit: GasInt;
|
||||
fee: Option[Uint256];
|
||||
random: Hash256;
|
||||
miner: EthAddress;
|
||||
chainDB: BaseChainDB;
|
||||
tracerFlags: set[TracerFlags])
|
||||
|
@ -96,6 +99,7 @@ proc init(
|
|||
timestamp = timestamp,
|
||||
gasLimit = gasLimit,
|
||||
fee = fee,
|
||||
random = random,
|
||||
miner = miner,
|
||||
chainDB = chainDB,
|
||||
tracer = tracer)
|
||||
|
@ -117,6 +121,7 @@ proc new*(
|
|||
timestamp: EthTime; ## tx env: time stamp
|
||||
gasLimit: GasInt; ## tx env: gas limit
|
||||
fee: Option[Uint256]; ## tx env: optional base fee
|
||||
random: Hash256; ## tx env: POS block randomness
|
||||
miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA)
|
||||
chainDB: BaseChainDB; ## block chain database
|
||||
tracerFlags: set[TracerFlags] = {};
|
||||
|
@ -136,6 +141,7 @@ proc new*(
|
|||
timestamp = timestamp,
|
||||
gasLimit = gasLimit,
|
||||
fee = fee,
|
||||
random = random,
|
||||
miner = miner,
|
||||
chainDB = chainDB,
|
||||
tracerFlags = tracerFlags)
|
||||
|
@ -145,6 +151,7 @@ proc reinit*(self: BaseVMState; ## Object descriptor
|
|||
timestamp: EthTime; ## tx env: time stamp
|
||||
gasLimit: GasInt; ## tx env: gas limit
|
||||
fee: Option[Uint256]; ## tx env: optional base fee
|
||||
random: Hash256; ## tx env: POS block randomness
|
||||
miner: EthAddress; ## tx env: coinbase(PoW) or signer(PoA)
|
||||
pruneTrie: bool = true): bool
|
||||
{.gcsafe, raises: [Defect,CatchableError].} =
|
||||
|
@ -169,6 +176,7 @@ proc reinit*(self: BaseVMState; ## Object descriptor
|
|||
timestamp = timestamp,
|
||||
gasLimit = gasLimit,
|
||||
fee = fee,
|
||||
random = random,
|
||||
miner = miner,
|
||||
chainDB = db,
|
||||
tracer = tracer)
|
||||
|
@ -191,6 +199,7 @@ proc reinit*(self: BaseVMState; ## Object descriptor
|
|||
timestamp = header.timestamp,
|
||||
gasLimit = header.gasLimit,
|
||||
fee = header.fee,
|
||||
random = header.random,
|
||||
miner = self.chainDB.getMinerAddress(header),
|
||||
pruneTrie = pruneTrie)
|
||||
|
||||
|
@ -227,6 +236,7 @@ proc init*(
|
|||
header.timestamp,
|
||||
header.gasLimit,
|
||||
header.fee,
|
||||
header.random,
|
||||
chainDB.getMinerAddress(header),
|
||||
chainDB,
|
||||
tracerFlags)
|
||||
|
|
|
@ -38,6 +38,7 @@ type
|
|||
timestamp* : EthTime
|
||||
gasLimit* : GasInt
|
||||
fee* : Option[Uint256]
|
||||
random* : Hash256
|
||||
name* : string
|
||||
flags* : set[VMFlag]
|
||||
tracer* : TransactionTracer
|
||||
|
|
Loading…
Reference in New Issue