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
doAssert(false, "unreachable code")
func forkDeterminationInfoForHeader*(header: BlockHeader): ForkDeterminationInfo =
# FIXME-Adam-mightAlsoNeedTTD?
forkDeterminationInfo(header.blockNumber, header.timestamp)
proc validateChainConfig*(conf: ChainConfig): bool =
result = true
@ -448,6 +444,7 @@ proc chainConfigForNetwork*(id: NetworkId): ChainConfig =
muirGlacierBlock: some(0.toBlockNumber),
berlinBlock: some(0.toBlockNumber),
londonBlock: some(0.toBlockNumber),
mergeForkBlock: some(1735371.toBlockNumber),
terminalTotalDifficulty: some(sepoliaTTD),
shanghaiTime: some(1_677_557_088.EthTime)
)

View File

@ -58,7 +58,7 @@ type
forkTransitionTable: ForkTransitionTable
# Eth wire protocol need this
forkIds: array[HardFork, ForkID]
forkIdCalculator: ForkIdCalculator
networkId: NetworkId
# synchronizer need this
@ -117,10 +117,13 @@ proc consensusTransition(com: CommonRef, fork: HardFork) =
# this could happen during reorg
com.consensusType = com.config.consensusType
proc setForkId(com: CommonRef, blockZero: BlockHeader) =
com.genesisHash = blockZero.blockHash
proc setForkId(com: CommonRef, genesis: BlockHeader) =
com.genesisHash = genesis.blockHash
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) =
if not conf.daoForkSupport or conf.daoForkBlock.isNone:
@ -160,7 +163,7 @@ proc init(com : CommonRef,
# already at the MergeFork
const TimeZero = EthTime(0)
# com.forkIds and com.blockZeroHash is set
# com.forkIdCalculator and com.genesisHash are set
# by setForkId
if genesis.isNil.not:
com.hardForkTransition(ForkDeterminationInfo(
@ -246,7 +249,7 @@ proc clone*(com: CommonRef, db: CoreDbRef): CommonRef =
pruneTrie : com.pruneTrie,
config : com.config,
forkTransitionTable: com.forkTransitionTable,
forkIds : com.forkIds,
forkIdCalculator: com.forkIdCalculator,
genesisHash : com.genesisHash,
genesisHeader: com.genesisHeader,
syncProgress : com.syncProgress,
@ -315,7 +318,7 @@ func toEVMFork*(com: CommonRef): EVMFork =
func isLondon*(com: CommonRef, number: BlockNumber): bool =
# 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 =
# TODO: Fixme, use only London comparator
@ -339,10 +342,13 @@ proc minerAddress*(com: CommonRef; header: BlockHeader): EthAddress
account.value
func forkId*(com: CommonRef, forkDeterminer: ForkDeterminationInfo): ForkID {.gcsafe.} =
func forkId*(com: CommonRef, head, time: uint64): ForkID {.gcsafe.} =
## EIP 2364/2124
let fork = com.toHardFork(forkDeterminer)
com.forkIds[fork]
com.forkIdCalculator.newID(head, time)
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 =
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
# set, to not bother with TTD anymore. But I'm not sure
# it makes sense to allow time to be optional. See the
# comment below on blockNumberToForkDeterminationInfo.
# comment below on forkDeterminationInfo.
ForkDeterminationInfo* = object
blockNumber*: BlockNumber
time*: Option[EthTime]
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
# 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
@ -104,6 +104,10 @@ func forkDeterminationInfo*(n: BlockNumber, t: EthTime): ForkDeterminationInfo =
func forkDeterminationInfoIncludingTd*(n: BlockNumber, t: EthTime, td: DifficultyInt): ForkDeterminationInfo =
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 =
n + 1
@ -343,72 +347,74 @@ const
# ------------------------------------------------------------------------------
# Fork ID helpers
# ------------------------------------------------------------------------------
type
ForkIdCalculator* = object
byBlock: seq[uint64]
byTime: seq[uint64]
genesisCRC: uint32
func toNextFork(n: Option[BlockNumber]): uint64 =
if n.isSome:
n.get.truncate(uint64)
else:
0'u64
func newID*(calc: ForkIdCalculator, head, time: uint64): ForkID =
var hash = calc.genesisCRC
for fork in calc.byBlock:
if fork <= head:
# 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.
func toNextFork(t: Option[EthTime]): uint64 =
if t.isSome:
t.get.uint64
else:
0'u64
for fork in calc.byTime:
if fork <= time:
# Fork already passed, checksum the previous hash and fork timestamp
hash = crc32(hash, fork.toBytesBE)
continue
return (hash, fork)
func arrayMappingHardForkToNextFork(c: ChainConfig): array[HardFork, uint64] =
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),
]
(hash, 0'u64)
func getNextFork(next: array[HardFork, uint64], fork: HardFork): uint64 =
if fork == high(HardFork):
result = 0
return
func initForkIdCalculator*(map: ForkTransitionTable,
genesisCRC: uint32,
genesisTime: uint64): ForkIdCalculator =
result = next[fork]
for x in fork..high(HardFork):
if result != next[x]:
result = next[x]
break
# Extract the fork rule block number aggregate it
var forksByBlock: seq[uint64]
for fork, val in map.blockNumberThresholds:
if val.isNone: continue
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,
prevCRC: uint32, prevFork: uint64): ForkID =
result.nextFork = getNextFork(next, fork)
if map.mergeForkTransitionThreshold.blockNumber.isSome:
let val64 = map.mergeForkTransitionThreshold.blockNumber.get.truncate(uint64)
if forksByBlock.len == 0:
forksByBlock.add val64
elif forksByBlock[^1] != val64:
# Deduplicate fork identifiers applying multiple forks
forksByBlock.add val64
if result.nextFork != prevFork:
result.crc = crc32(prevCRC, toBytesBE(prevFork))
else:
result.crc = prevCRC
# Skip any forks in block 0, that's the genesis ruleset
if forksByBlock.len > 0 and forksByBlock[0] == 0:
forksByBlock.delete(0)
func calculateForkIds*(c: ChainConfig,
genesisCRC: uint32): array[HardFork, ForkID] =
let next = arrayMappingHardForkToNextFork(c)
# Extract the fork rule timestamp number aggregate it
var forksByTime: seq[uint64]
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
var prevFork = getNextFork(next, Frontier)
# Skip any forks before genesis.
while forksByTime.len > 0 and forksByTime[0] <= genesisTime:
forksByTime.delete(0)
for fork in HardFork:
result[fork] = calculateForkId(next, fork, prevCRC, prevFork)
prevFork = result[fork].nextFork
prevCRC = result[fork].crc
result.genesisCRC = genesisCRC
result.byBlock = system.move(forksByBlock)
result.byTime = system.move(forksByTime)
# ------------------------------------------------------------------------------
# End

View File

@ -182,7 +182,7 @@ proc asyncProcessTransaction*(
{.async, gcsafe.} =
## Variant of `asyncProcessTransaction()` with `*fork* derived
## 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)
proc processTransaction*(

View File

@ -171,7 +171,7 @@ template calcDifficultyGrayGlacier*(timeStamp: EthTime, parent: BlockHeader): Di
makeDifficultyCalculator(11_400_000, timeStamp, parent)
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:
result = calcDifficultyGrayGlacier(timeStamp, parent)
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
let
forkDeterminer = forkDeterminationInfoForHeader(parent)
forkDeterminer = forkDeterminationInfo(parent)
parentFork = com.toEVMFork(forkDeterminer)
nextFork = com.toEVMFork(forkDeterminer.adjustForNextBlock)

View File

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

View File

@ -25,7 +25,7 @@ type
ChainForkId* = object
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

View File

@ -212,7 +212,7 @@ proc genesisLoadRunner(noisy = true;
params = params)
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}":
# Before allocating the database, the data directory needs to be
@ -229,7 +229,7 @@ proc genesisLoadRunner(noisy = true;
params = params)
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":
mcom.initializeEmptyDb

View File

@ -1,47 +1,60 @@
import
unittest2,
../nimbus/common/common
../nimbus/common/common,
../nimbus/utils/utils
const
MainNetIDs = [
(blockNumber: 0'u64, id: (crc: 0xfc64ec04'u32, nextFork: 1150000'u64)), # Unsynced
(blockNumber: 1149999'u64, id: (crc: 0xfc64ec04'u32, nextFork: 1150000'u64)), # Last Frontier block
(blockNumber: 1150000'u64, id: (crc: 0x97c2c34c'u32, nextFork: 1920000'u64)), # First Homestead block
(blockNumber: 1919999'u64, id: (crc: 0x97c2c34c'u32, nextFork: 1920000'u64)), # Last Homestead block
(blockNumber: 1920000'u64, id: (crc: 0x91d1f948'u32, nextFork: 2463000'u64)), # First DAO block
(blockNumber: 2462999'u64, id: (crc: 0x91d1f948'u32, nextFork: 2463000'u64)), # Last DAO block
(blockNumber: 2463000'u64, id: (crc: 0x7a64da13'u32, nextFork: 2675000'u64)), # First Tangerine block
(blockNumber: 2674999'u64, id: (crc: 0x7a64da13'u32, nextFork: 2675000'u64)), # Last Tangerine block
(blockNumber: 2675000'u64, id: (crc: 0x3edd5b10'u32, nextFork: 4370000'u64)), # First Spurious block
(blockNumber: 4369999'u64, id: (crc: 0x3edd5b10'u32, nextFork: 4370000'u64)), # Last Spurious block
(blockNumber: 4370000'u64, id: (crc: 0xa00bc324'u32, nextFork: 7280000'u64)), # First Byzantium block
(blockNumber: 7279999'u64, id: (crc: 0xa00bc324'u32, nextFork: 7280000'u64)), # Last Byzantium block
(blockNumber: 7280000'u64, id: (crc: 0x668db0af'u32, nextFork: 9069000'u64)), # First and last Constantinople, first Petersburg block
(blockNumber: 7987396'u64, id: (crc: 0x668db0af'u32, nextFork: 9069000'u64)), # Past Petersburg block
(blockNumber: 9068999'u64, id: (crc: 0x668db0af'u32, nextFork: 9069000'u64)), # Last Petersburg block
(blockNumber: 9069000'u64, id: (crc: 0x879D6E30'u32, nextFork: 9200000'u64)), # First Istanbul block
(blockNumber: 9199999'u64, id: (crc: 0x879D6E30'u32, nextFork: 9200000'u64)), # Last Istanbul block
(blockNumber: 9200000'u64, id: (crc: 0xE029E991'u32, nextFork: 12244000'u64)), # First MuirGlacier block
(blockNumber: 12243999'u64, id: (crc: 0xE029E991'u32, nextFork: 12244000'u64)), # Last MuirGlacier block
(blockNumber: 12244000'u64, id: (crc: 0x0eb440f6'u32, nextFork: 12965000'u64)), # First Berlin block
(blockNumber: 12964999'u64, id: (crc: 0x0eb440f6'u32, nextFork: 12965000'u64)), # Last Berlin block
(blockNumber: 12965000'u64, id: (crc: 0xb715077d'u32, nextFork: 13773000'u64)), # First London block
(blockNumber: 13772999'u64, id: (crc: 0xb715077d'u32, nextFork: 13773000'u64)), # Last London block
(blockNumber: 13773000'u64, id: (crc: 0x20c327fc'u32, nextFork: 15050000'u64)), # First Arrow Glacier block
(blockNumber: 15049999'u64, id: (crc: 0x20c327fc'u32, nextFork: 15050000'u64)), # Last Arrow Glacier block
(blockNumber: 15050000'u64, id: (crc: 0xf0afd0e3'u32, nextFork: 0'u64)), # First Gray Glacier block
(blockNumber: 20000000'u64, id: (crc: 0xf0afd0e3'u32, nextFork: 0'u64)), # Future Gray Glacier block
(number: 0'u64 , time: 0'u64, id: (crc: 0xfc64ec04'u32, next: 1150000'u64)), # Unsynced
(number: 1149999'u64 , time: 0'u64, id: (crc: 0xfc64ec04'u32, next: 1150000'u64)), # Last Frontier block
(number: 1150000'u64 , time: 0'u64, id: (crc: 0x97c2c34c'u32, next: 1920000'u64)), # First Homestead block
(number: 1919999'u64 , time: 0'u64, id: (crc: 0x97c2c34c'u32, next: 1920000'u64)), # Last Homestead block
(number: 1920000'u64 , time: 0'u64, id: (crc: 0x91d1f948'u32, next: 2463000'u64)), # First DAO block
(number: 2462999'u64 , time: 0'u64, id: (crc: 0x91d1f948'u32, next: 2463000'u64)), # Last DAO block
(number: 2463000'u64 , time: 0'u64, id: (crc: 0x7a64da13'u32, next: 2675000'u64)), # First Tangerine block
(number: 2674999'u64 , time: 0'u64, id: (crc: 0x7a64da13'u32, next: 2675000'u64)), # Last Tangerine block
(number: 2675000'u64 , time: 0'u64, id: (crc: 0x3edd5b10'u32, next: 4370000'u64)), # First Spurious block
(number: 4369999'u64 , time: 0'u64, id: (crc: 0x3edd5b10'u32, next: 4370000'u64)), # Last Spurious block
(number: 4370000'u64 , time: 0'u64, id: (crc: 0xa00bc324'u32, next: 7280000'u64)), # First Byzantium block
(number: 7279999'u64 , time: 0'u64, id: (crc: 0xa00bc324'u32, next: 7280000'u64)), # Last Byzantium block
(number: 7280000'u64 , time: 0'u64, id: (crc: 0x668db0af'u32, next: 9069000'u64)), # First and last Constantinople, first Petersburg block
(number: 7987396'u64 , time: 0'u64, id: (crc: 0x668db0af'u32, next: 9069000'u64)), # Past Petersburg block
(number: 9068999'u64 , time: 0'u64, id: (crc: 0x668db0af'u32, next: 9069000'u64)), # Last Petersburg block
(number: 9069000'u64 , time: 0'u64, id: (crc: 0x879D6E30'u32, next: 9200000'u64)), # First Istanbul block
(number: 9199999'u64 , time: 0'u64, id: (crc: 0x879D6E30'u32, next: 9200000'u64)), # Last Istanbul block
(number: 9200000'u64 , time: 0'u64, id: (crc: 0xE029E991'u32, next: 12244000'u64)), # First MuirGlacier block
(number: 12243999'u64, time: 0'u64, id: (crc: 0xE029E991'u32, next: 12244000'u64)), # Last MuirGlacier block
(number: 12244000'u64, time: 0'u64, id: (crc: 0x0eb440f6'u32, next: 12965000'u64)), # First Berlin block
(number: 12964999'u64, time: 0'u64, id: (crc: 0x0eb440f6'u32, next: 12965000'u64)), # Last Berlin block
(number: 12965000'u64, time: 0'u64, id: (crc: 0xb715077d'u32, next: 13773000'u64)), # First London block
(number: 13772999'u64, time: 0'u64, id: (crc: 0xb715077d'u32, next: 13773000'u64)), # Last London block
(number: 13773000'u64, time: 0'u64, id: (crc: 0x20c327fc'u32, next: 15050000'u64)), # First Arrow Glacier block
(number: 15049999'u64, time: 0'u64, id: (crc: 0x20c327fc'u32, next: 15050000'u64)), # Last Arrow Glacier block
(number: 15050000'u64, time: 0'u64, id: (crc: 0xf0afd0e3'u32, next: 1681338455'u64)), # First 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 = [
(blockNumber: 0'u64, id: (crc: 0xa3f5ab08'u32, nextFork: 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
(blockNumber: 1561651'u64, id: (crc: 0xc25efa5c'u32, nextFork: 4460644'u64)), # First Istanbul block
(blockNumber: 4460643'u64, id: (crc: 0xc25efa5c'u32, nextFork: 4460644'u64)), # Future Istanbul block
(blockNumber: 4460644'u64, id: (crc: 0x757a1c47'u32, nextFork: 5062605'u64)), # First Berlin block
(blockNumber: 5062604'u64, id: (crc: 0x757a1c47'u32, nextFork: 5062605'u64)), # Last Berlin block
(blockNumber: 5062605'u64, id: (crc: 0xb8c6299d'u32, nextFork: 0'u64)), # First London block
(blockNumber: 10000000'u64, id: (crc: 0xb8c6299d'u32, nextFork: 0'u64)), # Future London 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
(number: 1561650'u64, time: 0'u64, id: (crc: 0xa3f5ab08'u32, next: 1561651'u64)), # Last Petersburg block
(number: 1561651'u64, time: 0'u64, id: (crc: 0xc25efa5c'u32, next: 4460644'u64)), # First Istanbul block
(number: 4460643'u64, time: 0'u64, id: (crc: 0xc25efa5c'u32, next: 4460644'u64)), # Future Istanbul block
(number: 4460644'u64, time: 0'u64, id: (crc: 0x757a1c47'u32, next: 5062605'u64)), # First Berlin block
(number: 5062604'u64, time: 0'u64, id: (crc: 0x757a1c47'u32, next: 5062605'u64)), # Last Berlin block
(number: 5062605'u64, time: 0'u64, id: (crc: 0xb8c6299d'u32, next: 1678832736'u64)), # First 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) =
@ -50,15 +63,67 @@ template runTest(network: untyped, name: string) =
params = networkParams(network)
com = CommonRef.new(newCoreDbRef LegacyDbMemory, true, network, params)
for x in `network IDs`:
let id = com.forkId(x.blockNumber.toBlockNumber.blockNumberToForkDeterminationInfo)
for i, x in `network IDs`:
let id = com.forkId(x.number, x.time)
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*() =
suite "Fork ID tests":
runTest(MainNet, "MainNet")
runTest(GoerliNet, "GoerliNet")
runTest(SepoliaNet, "SepoliaNet")
test "Genesis Time Fork ID":
runGenesisTimeIdTests()
when isMainModule:
forkIdMain()

View File

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

View File

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