Fix ForkID calculation

This commit is contained in:
jangko 2023-10-24 17:39:19 +07:00
parent 6e59cccc5b
commit 0ee448c1eb
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
12 changed files with 195 additions and 121 deletions

View File

@ -262,10 +262,6 @@ proc toHardFork*(map: ForkTransitionTable, forkDeterminer: ForkDeterminationInfo
# should always have a match # should always have a match
doAssert(false, "unreachable code") doAssert(false, "unreachable code")
func forkDeterminationInfoForHeader*(header: BlockHeader): ForkDeterminationInfo =
# FIXME-Adam-mightAlsoNeedTTD?
forkDeterminationInfo(header.blockNumber, header.timestamp)
proc validateChainConfig*(conf: ChainConfig): bool = proc validateChainConfig*(conf: ChainConfig): bool =
result = true result = true
@ -448,6 +444,7 @@ proc chainConfigForNetwork*(id: NetworkId): ChainConfig =
muirGlacierBlock: some(0.toBlockNumber), muirGlacierBlock: some(0.toBlockNumber),
berlinBlock: some(0.toBlockNumber), berlinBlock: some(0.toBlockNumber),
londonBlock: some(0.toBlockNumber), londonBlock: some(0.toBlockNumber),
mergeForkBlock: some(1735371.toBlockNumber),
terminalTotalDifficulty: some(sepoliaTTD), terminalTotalDifficulty: some(sepoliaTTD),
shanghaiTime: some(1_677_557_088.EthTime) shanghaiTime: some(1_677_557_088.EthTime)
) )

View File

@ -58,7 +58,7 @@ type
forkTransitionTable: ForkTransitionTable forkTransitionTable: ForkTransitionTable
# Eth wire protocol need this # Eth wire protocol need this
forkIds: array[HardFork, ForkID] forkIdCalculator: ForkIdCalculator
networkId: NetworkId networkId: NetworkId
# synchronizer need this # synchronizer need this
@ -117,10 +117,13 @@ proc consensusTransition(com: CommonRef, fork: HardFork) =
# this could happen during reorg # this could happen during reorg
com.consensusType = com.config.consensusType com.consensusType = com.config.consensusType
proc setForkId(com: CommonRef, blockZero: BlockHeader) = proc setForkId(com: CommonRef, genesis: BlockHeader) =
com.genesisHash = blockZero.blockHash com.genesisHash = genesis.blockHash
let genesisCRC = crc32(0, com.genesisHash.data) let genesisCRC = crc32(0, com.genesisHash.data)
com.forkIds = calculateForkIds(com.config, genesisCRC) com.forkIdCalculator = initForkIdCalculator(
com.forkTransitionTable,
genesisCRC,
genesis.timestamp.uint64)
proc daoCheck(conf: ChainConfig) = proc daoCheck(conf: ChainConfig) =
if not conf.daoForkSupport or conf.daoForkBlock.isNone: if not conf.daoForkSupport or conf.daoForkBlock.isNone:
@ -160,7 +163,7 @@ proc init(com : CommonRef,
# already at the MergeFork # already at the MergeFork
const TimeZero = EthTime(0) const TimeZero = EthTime(0)
# com.forkIds and com.blockZeroHash is set # com.forkIdCalculator and com.genesisHash are set
# by setForkId # by setForkId
if genesis.isNil.not: if genesis.isNil.not:
com.hardForkTransition(ForkDeterminationInfo( com.hardForkTransition(ForkDeterminationInfo(
@ -246,7 +249,7 @@ proc clone*(com: CommonRef, db: CoreDbRef): CommonRef =
pruneTrie : com.pruneTrie, pruneTrie : com.pruneTrie,
config : com.config, config : com.config,
forkTransitionTable: com.forkTransitionTable, forkTransitionTable: com.forkTransitionTable,
forkIds : com.forkIds, forkIdCalculator: com.forkIdCalculator,
genesisHash : com.genesisHash, genesisHash : com.genesisHash,
genesisHeader: com.genesisHeader, genesisHeader: com.genesisHeader,
syncProgress : com.syncProgress, syncProgress : com.syncProgress,
@ -315,7 +318,7 @@ func toEVMFork*(com: CommonRef): EVMFork =
func isLondon*(com: CommonRef, number: BlockNumber): bool = func isLondon*(com: CommonRef, number: BlockNumber): bool =
# TODO: Fixme, use only London comparator # TODO: Fixme, use only London comparator
com.toHardFork(number.blockNumberToForkDeterminationInfo) >= London com.toHardFork(number.forkDeterminationInfo) >= London
func isLondon*(com: CommonRef, number: BlockNumber, timestamp: EthTime): bool = func isLondon*(com: CommonRef, number: BlockNumber, timestamp: EthTime): bool =
# TODO: Fixme, use only London comparator # TODO: Fixme, use only London comparator
@ -339,10 +342,13 @@ proc minerAddress*(com: CommonRef; header: BlockHeader): EthAddress
account.value account.value
func forkId*(com: CommonRef, forkDeterminer: ForkDeterminationInfo): ForkID {.gcsafe.} = func forkId*(com: CommonRef, head, time: uint64): ForkID {.gcsafe.} =
## EIP 2364/2124 ## EIP 2364/2124
let fork = com.toHardFork(forkDeterminer) com.forkIdCalculator.newID(head, time)
com.forkIds[fork]
func forkId*(com: CommonRef, head: BlockNumber, time: EthTime): ForkID {.gcsafe.} =
## EIP 2364/2124
com.forkIdCalculator.newID(head.truncate(uint64), time.uint64)
func isEIP155*(com: CommonRef, number: BlockNumber): bool = func isEIP155*(com: CommonRef, number: BlockNumber): bool =
com.config.eip155Block.isSome and number >= com.config.eip155Block.get com.config.eip155Block.isSome and number >= com.config.eip155Block.get

View File

@ -84,13 +84,13 @@ type
# is because it's perfectly fine, if mergeForkBlock is # is because it's perfectly fine, if mergeForkBlock is
# set, to not bother with TTD anymore. But I'm not sure # set, to not bother with TTD anymore. But I'm not sure
# it makes sense to allow time to be optional. See the # it makes sense to allow time to be optional. See the
# comment below on blockNumberToForkDeterminationInfo. # comment below on forkDeterminationInfo.
ForkDeterminationInfo* = object ForkDeterminationInfo* = object
blockNumber*: BlockNumber blockNumber*: BlockNumber
time*: Option[EthTime] time*: Option[EthTime]
td*: Option[DifficultyInt] td*: Option[DifficultyInt]
func blockNumberToForkDeterminationInfo*(n: BlockNumber): ForkDeterminationInfo = func forkDeterminationInfo*(n: BlockNumber): ForkDeterminationInfo =
# FIXME: All callers of this function are suspect; I'm guess we should # FIXME: All callers of this function are suspect; I'm guess we should
# always be using both block number and time. But we have a few places, # always be using both block number and time. But we have a few places,
# like various tests, where we only have block number and the tests are # like various tests, where we only have block number and the tests are
@ -104,6 +104,10 @@ func forkDeterminationInfo*(n: BlockNumber, t: EthTime): ForkDeterminationInfo =
func forkDeterminationInfoIncludingTd*(n: BlockNumber, t: EthTime, td: DifficultyInt): ForkDeterminationInfo = func forkDeterminationInfoIncludingTd*(n: BlockNumber, t: EthTime, td: DifficultyInt): ForkDeterminationInfo =
ForkDeterminationInfo(blockNumber: n, time: some(t), td: some(td)) ForkDeterminationInfo(blockNumber: n, time: some(t), td: some(td))
func forkDeterminationInfo*(header: BlockHeader): ForkDeterminationInfo =
# FIXME-Adam-mightAlsoNeedTTD?
forkDeterminationInfo(header.blockNumber, header.timestamp)
proc adjustForNextBlock*(n: BlockNumber): BlockNumber = proc adjustForNextBlock*(n: BlockNumber): BlockNumber =
n + 1 n + 1
@ -343,72 +347,74 @@ const
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Fork ID helpers # Fork ID helpers
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
type
ForkIdCalculator* = object
byBlock: seq[uint64]
byTime: seq[uint64]
genesisCRC: uint32
func toNextFork(n: Option[BlockNumber]): uint64 = func newID*(calc: ForkIdCalculator, head, time: uint64): ForkID =
if n.isSome: var hash = calc.genesisCRC
n.get.truncate(uint64) for fork in calc.byBlock:
else: if fork <= head:
0'u64 # Fork already passed, checksum the previous hash and the fork number
hash = crc32(hash, fork.toBytesBE)
continue
return (hash, fork)
# EIP-6122: ForkID now works with timestamps too. for fork in calc.byTime:
func toNextFork(t: Option[EthTime]): uint64 = if fork <= time:
if t.isSome: # Fork already passed, checksum the previous hash and fork timestamp
t.get.uint64 hash = crc32(hash, fork.toBytesBE)
else: continue
0'u64 return (hash, fork)
func arrayMappingHardForkToNextFork(c: ChainConfig): array[HardFork, uint64] = (hash, 0'u64)
return [
0'u64,
toNextFork(c.homesteadBlock),
toNextFork(c.daoForkBlock),
toNextFork(c.eip150Block),
toNextFork(c.eip158Block),
toNextFork(c.byzantiumBlock),
toNextFork(c.constantinopleBlock),
toNextFork(c.petersburgBlock),
toNextFork(c.istanbulBlock),
toNextFork(c.muirGlacierBlock),
toNextFork(c.berlinBlock),
toNextFork(c.londonBlock),
toNextFork(c.arrowGlacierBlock),
toNextFork(c.grayGlacierBlock),
toNextFork(c.mergeForkBlock),
toNextFork(c.shanghaiTime),
toNextFork(c.cancunTime),
]
func getNextFork(next: array[HardFork, uint64], fork: HardFork): uint64 = func initForkIdCalculator*(map: ForkTransitionTable,
if fork == high(HardFork): genesisCRC: uint32,
result = 0 genesisTime: uint64): ForkIdCalculator =
return
result = next[fork] # Extract the fork rule block number aggregate it
for x in fork..high(HardFork): var forksByBlock: seq[uint64]
if result != next[x]: for fork, val in map.blockNumberThresholds:
result = next[x] if val.isNone: continue
break let val64 = val.get.truncate(uint64)
if forksByBlock.len == 0:
forksByBlock.add val64
elif forksByBlock[^1] != val64:
# Deduplicate fork identifiers applying multiple forks
forksByBlock.add val64
func calculateForkId(next: array[HardFork, uint64], fork: HardFork, if map.mergeForkTransitionThreshold.blockNumber.isSome:
prevCRC: uint32, prevFork: uint64): ForkID = let val64 = map.mergeForkTransitionThreshold.blockNumber.get.truncate(uint64)
result.nextFork = getNextFork(next, fork) if forksByBlock.len == 0:
forksByBlock.add val64
elif forksByBlock[^1] != val64:
# Deduplicate fork identifiers applying multiple forks
forksByBlock.add val64
if result.nextFork != prevFork: # Skip any forks in block 0, that's the genesis ruleset
result.crc = crc32(prevCRC, toBytesBE(prevFork)) if forksByBlock.len > 0 and forksByBlock[0] == 0:
else: forksByBlock.delete(0)
result.crc = prevCRC
func calculateForkIds*(c: ChainConfig, # Extract the fork rule timestamp number aggregate it
genesisCRC: uint32): array[HardFork, ForkID] = var forksByTime: seq[uint64]
let next = arrayMappingHardForkToNextFork(c) for fork, val in map.timeThresholds:
if val.isNone: continue
let val64 = val.get.uint64
if forksByTime.len == 0:
forksByTime.add val64
elif forksByTime[^1] != val64:
forksByTime.add val64
var prevCRC = genesisCRC # Skip any forks before genesis.
var prevFork = getNextFork(next, Frontier) while forksByTime.len > 0 and forksByTime[0] <= genesisTime:
forksByTime.delete(0)
for fork in HardFork: result.genesisCRC = genesisCRC
result[fork] = calculateForkId(next, fork, prevCRC, prevFork) result.byBlock = system.move(forksByBlock)
prevFork = result[fork].nextFork result.byTime = system.move(forksByTime)
prevCRC = result[fork].crc
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# End # End

View File

@ -182,7 +182,7 @@ proc asyncProcessTransaction*(
{.async, gcsafe.} = {.async, gcsafe.} =
## Variant of `asyncProcessTransaction()` with `*fork* derived ## Variant of `asyncProcessTransaction()` with `*fork* derived
## from the `vmState` argument. ## from the `vmState` argument.
let fork = vmState.com.toEVMFork(header.forkDeterminationInfoForHeader) let fork = vmState.com.toEVMFork(header.forkDeterminationInfo)
return await vmState.asyncProcessTransaction(tx, sender, header, fork) return await vmState.asyncProcessTransaction(tx, sender, header, fork)
proc processTransaction*( proc processTransaction*(

View File

@ -171,7 +171,7 @@ template calcDifficultyGrayGlacier*(timeStamp: EthTime, parent: BlockHeader): Di
makeDifficultyCalculator(11_400_000, timeStamp, parent) makeDifficultyCalculator(11_400_000, timeStamp, parent)
func calcDifficulty*(com: CommonRef, timeStamp: EthTime, parent: BlockHeader): DifficultyInt = func calcDifficulty*(com: CommonRef, timeStamp: EthTime, parent: BlockHeader): DifficultyInt =
let next = com.toHardFork(parent.forkDeterminationInfoForHeader.adjustForNextBlock) let next = com.toHardFork(parent.forkDeterminationInfo.adjustForNextBlock)
if next >= GrayGlacier: if next >= GrayGlacier:
result = calcDifficultyGrayGlacier(timeStamp, parent) result = calcDifficultyGrayGlacier(timeStamp, parent)
elif next >= ArrowGlacier: elif next >= ArrowGlacier:

View File

@ -35,7 +35,7 @@ proc baseFeeGet*(com: CommonRef; parent: BlockHeader): GasPrice =
# Note that the baseFee is calculated for the next header # Note that the baseFee is calculated for the next header
let let
forkDeterminer = forkDeterminationInfoForHeader(parent) forkDeterminer = forkDeterminationInfo(parent)
parentFork = com.toEVMFork(forkDeterminer) parentFork = com.toEVMFork(forkDeterminer)
nextFork = com.toEVMFork(forkDeterminer.adjustForNextBlock) nextFork = com.toEVMFork(forkDeterminer.adjustForNextBlock)

View File

@ -392,7 +392,7 @@ method getStatus*(ctx: EthWireRef): EthState
db = ctx.db db = ctx.db
com = ctx.chain.com com = ctx.chain.com
bestBlock = db.getCanonicalHead() bestBlock = db.getCanonicalHead()
forkId = com.forkId(bestBlock.forkDeterminationInfoForHeader) forkId = com.forkId(bestBlock.blockNumber, bestBlock.timestamp)
EthState( EthState(
totalDifficulty: db.headTotalDifficulty, totalDifficulty: db.headTotalDifficulty,
@ -400,7 +400,7 @@ method getStatus*(ctx: EthWireRef): EthState
bestBlockHash: bestBlock.blockHash, bestBlockHash: bestBlock.blockHash,
forkId: ChainForkId( forkId: ChainForkId(
forkHash: forkId.crc.toBytesBE, forkHash: forkId.crc.toBytesBE,
forkNext: forkId.nextFork.toBlockNumber forkNext: forkId.nextFork
) )
) )

View File

@ -25,7 +25,7 @@ type
ChainForkId* = object ChainForkId* = object
forkHash*: array[4, byte] # The RLP encoding must be exactly 4 bytes. forkHash*: array[4, byte] # The RLP encoding must be exactly 4 bytes.
forkNext*: BlockNumber # The RLP encoding must be variable-length forkNext*: uint64 # The RLP encoding must be variable-length
EthWireBase* = ref object of RootRef EthWireBase* = ref object of RootRef

View File

@ -212,7 +212,7 @@ proc genesisLoadRunner(noisy = true;
params = params) params = params)
check mcom.ttd.get == sSpcs.termTotalDff check mcom.ttd.get == sSpcs.termTotalDff
check mcom.toHardFork(sSpcs.mergeFork.toBlockNumber.blockNumberToForkDeterminationInfo) == MergeFork check mcom.toHardFork(sSpcs.mergeFork.toBlockNumber.forkDeterminationInfo) == MergeFork
test &"Construct persistent ChainDBRef on {tmpDir}, {persistPruneInfo}": test &"Construct persistent ChainDBRef on {tmpDir}, {persistPruneInfo}":
# Before allocating the database, the data directory needs to be # Before allocating the database, the data directory needs to be
@ -229,7 +229,7 @@ proc genesisLoadRunner(noisy = true;
params = params) params = params)
check dcom.ttd.get == sSpcs.termTotalDff check dcom.ttd.get == sSpcs.termTotalDff
check dcom.toHardFork(sSpcs.mergeFork.toBlockNumber.blockNumberToForkDeterminationInfo) == MergeFork check dcom.toHardFork(sSpcs.mergeFork.toBlockNumber.forkDeterminationInfo) == MergeFork
test "Initialise in-memory Genesis": test "Initialise in-memory Genesis":
mcom.initializeEmptyDb mcom.initializeEmptyDb

View File

@ -1,47 +1,60 @@
import import
unittest2, unittest2,
../nimbus/common/common ../nimbus/common/common,
../nimbus/utils/utils
const const
MainNetIDs = [ MainNetIDs = [
(blockNumber: 0'u64, id: (crc: 0xfc64ec04'u32, nextFork: 1150000'u64)), # Unsynced (number: 0'u64 , time: 0'u64, id: (crc: 0xfc64ec04'u32, next: 1150000'u64)), # Unsynced
(blockNumber: 1149999'u64, id: (crc: 0xfc64ec04'u32, nextFork: 1150000'u64)), # Last Frontier block (number: 1149999'u64 , time: 0'u64, id: (crc: 0xfc64ec04'u32, next: 1150000'u64)), # Last Frontier block
(blockNumber: 1150000'u64, id: (crc: 0x97c2c34c'u32, nextFork: 1920000'u64)), # First Homestead block (number: 1150000'u64 , time: 0'u64, id: (crc: 0x97c2c34c'u32, next: 1920000'u64)), # First Homestead block
(blockNumber: 1919999'u64, id: (crc: 0x97c2c34c'u32, nextFork: 1920000'u64)), # Last Homestead block (number: 1919999'u64 , time: 0'u64, id: (crc: 0x97c2c34c'u32, next: 1920000'u64)), # Last Homestead block
(blockNumber: 1920000'u64, id: (crc: 0x91d1f948'u32, nextFork: 2463000'u64)), # First DAO block (number: 1920000'u64 , time: 0'u64, id: (crc: 0x91d1f948'u32, next: 2463000'u64)), # First DAO block
(blockNumber: 2462999'u64, id: (crc: 0x91d1f948'u32, nextFork: 2463000'u64)), # Last DAO block (number: 2462999'u64 , time: 0'u64, id: (crc: 0x91d1f948'u32, next: 2463000'u64)), # Last DAO block
(blockNumber: 2463000'u64, id: (crc: 0x7a64da13'u32, nextFork: 2675000'u64)), # First Tangerine block (number: 2463000'u64 , time: 0'u64, id: (crc: 0x7a64da13'u32, next: 2675000'u64)), # First Tangerine block
(blockNumber: 2674999'u64, id: (crc: 0x7a64da13'u32, nextFork: 2675000'u64)), # Last Tangerine block (number: 2674999'u64 , time: 0'u64, id: (crc: 0x7a64da13'u32, next: 2675000'u64)), # Last Tangerine block
(blockNumber: 2675000'u64, id: (crc: 0x3edd5b10'u32, nextFork: 4370000'u64)), # First Spurious block (number: 2675000'u64 , time: 0'u64, id: (crc: 0x3edd5b10'u32, next: 4370000'u64)), # First Spurious block
(blockNumber: 4369999'u64, id: (crc: 0x3edd5b10'u32, nextFork: 4370000'u64)), # Last Spurious block (number: 4369999'u64 , time: 0'u64, id: (crc: 0x3edd5b10'u32, next: 4370000'u64)), # Last Spurious block
(blockNumber: 4370000'u64, id: (crc: 0xa00bc324'u32, nextFork: 7280000'u64)), # First Byzantium block (number: 4370000'u64 , time: 0'u64, id: (crc: 0xa00bc324'u32, next: 7280000'u64)), # First Byzantium block
(blockNumber: 7279999'u64, id: (crc: 0xa00bc324'u32, nextFork: 7280000'u64)), # Last Byzantium block (number: 7279999'u64 , time: 0'u64, id: (crc: 0xa00bc324'u32, next: 7280000'u64)), # Last Byzantium block
(blockNumber: 7280000'u64, id: (crc: 0x668db0af'u32, nextFork: 9069000'u64)), # First and last Constantinople, first Petersburg block (number: 7280000'u64 , time: 0'u64, id: (crc: 0x668db0af'u32, next: 9069000'u64)), # First and last Constantinople, first Petersburg block
(blockNumber: 7987396'u64, id: (crc: 0x668db0af'u32, nextFork: 9069000'u64)), # Past Petersburg block (number: 7987396'u64 , time: 0'u64, id: (crc: 0x668db0af'u32, next: 9069000'u64)), # Past Petersburg block
(blockNumber: 9068999'u64, id: (crc: 0x668db0af'u32, nextFork: 9069000'u64)), # Last Petersburg block (number: 9068999'u64 , time: 0'u64, id: (crc: 0x668db0af'u32, next: 9069000'u64)), # Last Petersburg block
(blockNumber: 9069000'u64, id: (crc: 0x879D6E30'u32, nextFork: 9200000'u64)), # First Istanbul block (number: 9069000'u64 , time: 0'u64, id: (crc: 0x879D6E30'u32, next: 9200000'u64)), # First Istanbul block
(blockNumber: 9199999'u64, id: (crc: 0x879D6E30'u32, nextFork: 9200000'u64)), # Last Istanbul block (number: 9199999'u64 , time: 0'u64, id: (crc: 0x879D6E30'u32, next: 9200000'u64)), # Last Istanbul block
(blockNumber: 9200000'u64, id: (crc: 0xE029E991'u32, nextFork: 12244000'u64)), # First MuirGlacier block (number: 9200000'u64 , time: 0'u64, id: (crc: 0xE029E991'u32, next: 12244000'u64)), # First MuirGlacier block
(blockNumber: 12243999'u64, id: (crc: 0xE029E991'u32, nextFork: 12244000'u64)), # Last MuirGlacier block (number: 12243999'u64, time: 0'u64, id: (crc: 0xE029E991'u32, next: 12244000'u64)), # Last MuirGlacier block
(blockNumber: 12244000'u64, id: (crc: 0x0eb440f6'u32, nextFork: 12965000'u64)), # First Berlin block (number: 12244000'u64, time: 0'u64, id: (crc: 0x0eb440f6'u32, next: 12965000'u64)), # First Berlin block
(blockNumber: 12964999'u64, id: (crc: 0x0eb440f6'u32, nextFork: 12965000'u64)), # Last Berlin block (number: 12964999'u64, time: 0'u64, id: (crc: 0x0eb440f6'u32, next: 12965000'u64)), # Last Berlin block
(blockNumber: 12965000'u64, id: (crc: 0xb715077d'u32, nextFork: 13773000'u64)), # First London block (number: 12965000'u64, time: 0'u64, id: (crc: 0xb715077d'u32, next: 13773000'u64)), # First London block
(blockNumber: 13772999'u64, id: (crc: 0xb715077d'u32, nextFork: 13773000'u64)), # Last London block (number: 13772999'u64, time: 0'u64, id: (crc: 0xb715077d'u32, next: 13773000'u64)), # Last London block
(blockNumber: 13773000'u64, id: (crc: 0x20c327fc'u32, nextFork: 15050000'u64)), # First Arrow Glacier block (number: 13773000'u64, time: 0'u64, id: (crc: 0x20c327fc'u32, next: 15050000'u64)), # First Arrow Glacier block
(blockNumber: 15049999'u64, id: (crc: 0x20c327fc'u32, nextFork: 15050000'u64)), # Last Arrow Glacier block (number: 15049999'u64, time: 0'u64, id: (crc: 0x20c327fc'u32, next: 15050000'u64)), # Last Arrow Glacier block
(blockNumber: 15050000'u64, id: (crc: 0xf0afd0e3'u32, nextFork: 0'u64)), # First Gray Glacier block (number: 15050000'u64, time: 0'u64, id: (crc: 0xf0afd0e3'u32, next: 1681338455'u64)), # First Gray Glacier block
(blockNumber: 20000000'u64, id: (crc: 0xf0afd0e3'u32, nextFork: 0'u64)), # Future Gray Glacier block (number: 20000000'u64, time: 1681338454'u64, id: (crc: 0xf0afd0e3'u32, next: 1681338455'u64)), # Last Gray Glacier block
(number: 20000000'u64, time: 1681338455'u64, id: (crc: 0xdce96c2d'u32, next: 0'u64)), # First Shanghai block
(number: 30000000'u64, time: 2000000000'u64, id: (crc: 0xdce96c2d'u32, next: 0'u64)), # Future Shanghai block
] ]
GoerliNetIDs = [ GoerliNetIDs = [
(blockNumber: 0'u64, id: (crc: 0xa3f5ab08'u32, nextFork: 1561651'u64)), # Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block (number: 0'u64 , time: 0'u64, id: (crc: 0xa3f5ab08'u32, next: 1561651'u64)), # Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
(blockNumber: 1561650'u64, id: (crc: 0xa3f5ab08'u32, nextFork: 1561651'u64)), # Last Petersburg block (number: 1561650'u64, time: 0'u64, id: (crc: 0xa3f5ab08'u32, next: 1561651'u64)), # Last Petersburg block
(blockNumber: 1561651'u64, id: (crc: 0xc25efa5c'u32, nextFork: 4460644'u64)), # First Istanbul block (number: 1561651'u64, time: 0'u64, id: (crc: 0xc25efa5c'u32, next: 4460644'u64)), # First Istanbul block
(blockNumber: 4460643'u64, id: (crc: 0xc25efa5c'u32, nextFork: 4460644'u64)), # Future Istanbul block (number: 4460643'u64, time: 0'u64, id: (crc: 0xc25efa5c'u32, next: 4460644'u64)), # Future Istanbul block
(blockNumber: 4460644'u64, id: (crc: 0x757a1c47'u32, nextFork: 5062605'u64)), # First Berlin block (number: 4460644'u64, time: 0'u64, id: (crc: 0x757a1c47'u32, next: 5062605'u64)), # First Berlin block
(blockNumber: 5062604'u64, id: (crc: 0x757a1c47'u32, nextFork: 5062605'u64)), # Last Berlin block (number: 5062604'u64, time: 0'u64, id: (crc: 0x757a1c47'u32, next: 5062605'u64)), # Last Berlin block
(blockNumber: 5062605'u64, id: (crc: 0xb8c6299d'u32, nextFork: 0'u64)), # First London block (number: 5062605'u64, time: 0'u64, id: (crc: 0xb8c6299d'u32, next: 1678832736'u64)), # First London block
(blockNumber: 10000000'u64, id: (crc: 0xb8c6299d'u32, nextFork: 0'u64)), # Future London block (number: 6000000'u64, time: 1678832735'u64, id: (crc: 0xB8C6299D'u32, next: 1678832736'u64)), # Last London block
(number: 6000001'u64, time: 1678832736'u64, id: (crc: 0xf9843abf'u32, next: 0'u64)), # First Shanghai block
(number: 6500000'u64, time: 2678832736'u64, id: (crc: 0xf9843abf'u32, next: 0'u64)), # Future Shanghai block
]
SepoliaNetIDs = [
(number: 0'u64, time: 0'u64, id: (crc: 0xfe3366e7'u32, next: 1735371'u64)), # Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople, Petersburg, Istanbul, Berlin and first London block
(number: 1735370'u64, time: 0'u64, id: (crc: 0xfe3366e7'u32, next: 1735371'u64)), # Last London block
(number: 1735371'u64, time: 0'u64, id: (crc: 0xb96cbd13'u32, next: 1677557088'u64)), # First MergeNetsplit block
(number: 1735372'u64, time: 1677557087'u64, id: (crc: 0xb96cbd13'u32, next: 1677557088'u64)), # Last MergeNetsplit block
(number: 1735372'u64, time: 1677557088'u64, id: (crc: 0xf7f9bc08'u32, next: 0'u64)), # First Shanghai block
] ]
template runTest(network: untyped, name: string) = template runTest(network: untyped, name: string) =
@ -50,15 +63,67 @@ template runTest(network: untyped, name: string) =
params = networkParams(network) params = networkParams(network)
com = CommonRef.new(newCoreDbRef LegacyDbMemory, true, network, params) com = CommonRef.new(newCoreDbRef LegacyDbMemory, true, network, params)
for x in `network IDs`: for i, x in `network IDs`:
let id = com.forkId(x.blockNumber.toBlockNumber.blockNumberToForkDeterminationInfo) let id = com.forkId(x.number, x.time)
check id.crc == x.id.crc check id.crc == x.id.crc
check id.nextFork == x.id.nextFork check id.nextFork == x.id.next
func config(shanghai, cancun: uint64): ChainConfig =
ChainConfig(
chainID: ChainId(1337),
homesteadBlock: some(0.u256),
dAOForkBlock: none(BlockNumber),
dAOForkSupport: true,
eIP150Block: some(0.u256),
eIP155Block: some(0.u256),
eIP158Block: some(0.u256),
byzantiumBlock: some(0.u256),
constantinopleBlock: some(0.u256),
petersburgBlock: some(0.u256),
istanbulBlock: some(0.u256),
muirGlacierBlock: some(0.u256),
berlinBlock: some(0.u256),
londonBlock: some(0.u256),
terminalTotalDifficulty: some(0.u256),
terminalTotalDifficultyPassed: some(true),
mergeForkBlock: some(0.u256),
shanghaiTime: some(shanghai.EthTime),
cancunTime: some(cancun.EthTime),
)
func calcID(conf: ChainConfig, crc: uint32, time: uint64): ForkID =
let map = conf.toForkTransitionTable
let calc = map.initForkIdCalculator(crc, time)
calc.newID(0, time)
template runGenesisTimeIdTests() =
let
time = 1690475657'u64
genesis = common.BlockHeader(timestamp: time.EthTime)
genesisCRC = crc32(0, genesis.blockHash.data)
cases = [
# Shanghai active before genesis, skip
(c: config(time-1, time+1), want: (crc: genesisCRC, next: time + 1)),
# Shanghai active at genesis, skip
(c: config(time, time+1), want: (crc: genesisCRC, next: time + 1)),
# Shanghai not active, skip
(c: config(time+1, time+2), want: (crc: genesisCRC, next: time + 1)),
]
for i, x in cases:
let get = calcID(x.c, genesisCRC, time)
check get.crc == x.want.crc
check get.nextFork == x.want.next
proc forkIdMain*() = proc forkIdMain*() =
suite "Fork ID tests": suite "Fork ID tests":
runTest(MainNet, "MainNet") runTest(MainNet, "MainNet")
runTest(GoerliNet, "GoerliNet") runTest(GoerliNet, "GoerliNet")
runTest(SepoliaNet, "SepoliaNet")
test "Genesis Time Fork ID":
runGenesisTimeIdTests()
when isMainModule: when isMainModule:
forkIdMain() forkIdMain()

View File

@ -92,7 +92,7 @@ proc testFixtureIndexes(ctx: var TestCtx, testStatusIMPL: var TestStatus) =
var gasUsed: GasInt var gasUsed: GasInt
let sender = ctx.tx.getSender() let sender = ctx.tx.getSender()
let fork = com.toEVMFork(ctx.header.forkDeterminationInfoForHeader) let fork = com.toEVMFork(ctx.header.forkDeterminationInfo)
vmState.mutateStateDB: vmState.mutateStateDB:
setupStateDB(ctx.pre, db) setupStateDB(ctx.pre, db)

View File

@ -107,7 +107,7 @@ proc writeRootHashToStderr(vmState: BaseVMState) =
proc runExecution(ctx: var StateContext, conf: StateConf, pre: JsonNode): StateResult = proc runExecution(ctx: var StateContext, conf: StateConf, pre: JsonNode): StateResult =
let let
com = CommonRef.new(newCoreDbRef LegacyDbMemory, ctx.chainConfig, pruneTrie = false) com = CommonRef.new(newCoreDbRef LegacyDbMemory, ctx.chainConfig, pruneTrie = false)
fork = com.toEVMFork(ctx.header.forkDeterminationInfoForHeader) fork = com.toEVMFork(ctx.header.forkDeterminationInfo)
stream = newFileStream(stderr) stream = newFileStream(stderr)
tracer = if conf.jsonEnabled: tracer = if conf.jsonEnabled:
newJSonTracer(stream, ctx.tracerFlags, conf.pretty) newJSonTracer(stream, ctx.tracerFlags, conf.pretty)