Skip to content

Commit 513a1b1

Browse files
committed
Fix forkId compatibility according to EIP-2124 and EIP-6122
1 parent da507bd commit 513a1b1

File tree

4 files changed

+305
-22
lines changed

4 files changed

+305
-22
lines changed

execution_chain/common/common.nim

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -351,19 +351,21 @@ func isLondonOrLater*(com: CommonRef, number: BlockNumber): bool =
351351
com.toHardFork(number.forkDeterminationInfo) >= London
352352

353353
func forkId*(com: CommonRef, head, time: uint64): ForkID {.gcsafe.} =
354-
## EIP 2364/2124
354+
## Get ForkId for given block number / timestamp (EIP 2364/2124)
355355
com.forkIdCalculator.newID(head, time)
356356

357357
func forkId*(com: CommonRef, forkActivationTime: EthTime): ForkID {.gcsafe.} =
358-
# Only works for timestamp based forks
358+
## Get ForkId for given timestamp (EIP 2364/2124)
359+
## Only works for timestamp based forks
359360
com.forkIdCalculator.newID(0'u64, forkActivationTime.uint64)
360361

361362
func forkId*(com: CommonRef, head: BlockNumber, time: EthTime): ForkID {.gcsafe.} =
362-
## EIP 2364/2124
363+
## Get ForkId for given block number / timestamp (EIP-2124 + EIP-6122)
363364
com.forkIdCalculator.newID(head, time.uint64)
364365

365-
func compatibleForkId*(com: CommonRef, id: ForkID): bool =
366-
com.forkIdCalculator.compatible(id)
366+
func compatibleForkId*(com: CommonRef, forkId: ForkID, blockNumber: BlockNumber, time: EthTime): bool =
367+
## Check if a fork ID is compatible at a specific head position
368+
com.forkIdCalculator.compatible(forkId, blockNumber, time.uint64)
367369

368370
func isEIP155*(com: CommonRef, number: BlockNumber): bool =
369371
com.config.eip155Block.isSome and number >= com.config.eip155Block.value

execution_chain/common/hardforks.nim

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ type
348348
byBlock: seq[uint64]
349349
byTime: seq[uint64]
350350
genesisCRC: uint32
351-
cache: seq[ForkID]
351+
forkHistory: seq[ForkID]
352352

353353
func newID*(calc: ForkIdCalculator, head, time: uint64): ForkID =
354354
# Create a fork ID for a specific block height and timestamp:
@@ -369,28 +369,82 @@ func newID*(calc: ForkIdCalculator, head, time: uint64): ForkID =
369369

370370
(crc, 0'u64)
371371

372-
func compatible*(calc: var ForkIdCalculator, forkId: ForkID): bool =
373-
if calc.cache.len == 0:
374-
calc.cache = newSeqOfCap[ForkID](calc.byBlock.len + calc.byTime.len + 1)
372+
func calculateForkHistory(calc: var ForkIdCalculator) =
373+
if calc.forkHistory.len == 0:
374+
calc.forkHistory = newSeqOfCap[ForkID](calc.byBlock.len + calc.byTime.len + 1)
375375
var crc = calc.genesisCRC
376376

377377
# Build cache of all valid ForkIds
378378
# Each entry is (crc before fork, fork number)
379379
for fork in calc.byBlock:
380-
calc.cache.add( (crc, fork) )
380+
calc.forkHistory.add( (crc, fork) )
381381
crc = crc32(crc, fork.toBytesBE)
382382

383383
for fork in calc.byTime:
384-
calc.cache.add( (crc, fork) )
384+
calc.forkHistory.add( (crc, fork) )
385385
crc = crc32(crc, fork.toBytesBE)
386386

387387
# Add last fork ID (after all forks, next=0)
388-
calc.cache.add( (crc, 0'u64) )
388+
calc.forkHistory.add( (crc, 0'u64) )
389+
390+
func compatible*(calc: var ForkIdCalculator, forkId: ForkID, number: uint64, time: uint64): bool =
391+
# Check forkId compatibility at a specific head position according to EIP-2124 / EIP-6122.
392+
# The number and time represent the local chain state at which compatibility needs to be checked
393+
# In regular use this should be the current header block number and timestamp, but for testing
394+
# arbitrary points in history can be used.
395+
calc.calculateForkHistory()
396+
397+
# Calculate our current local fork ID at the given head position (= block and/or time)
398+
let localId = calc.newID(number, time)
399+
400+
# Calculate position of local fork ID in history
401+
var localForkPos = -1
402+
for i, historicalId in calc.forkHistory:
403+
if localId.crc == historicalId.crc:
404+
localForkPos = i
405+
break
406+
407+
# Based on position of local fork ID, determine if the head is block or time based
408+
let head =
409+
if localForkPos >= calc.byBlock.len():
410+
time
411+
else:
412+
number
413+
414+
# 1: local and remote FORK_HASH matches
415+
if forkId.crc == localId.crc:
416+
if forkId.nextFork != 0: # announced fork
417+
if head >= forkId.nextFork:
418+
# 1a - next fork already passed locally
419+
return false
420+
else:
421+
# 1b - next fork not yet passed locally
422+
return true
389423

390-
for id in calc.cache:
391-
if id == forkId:
424+
else:
425+
# 1b - no next fork announced
392426
return true
393-
427+
# TODO: should we have a condition here about our nextFork already beeing passed based on actual time?
428+
# return localId.nextFork == 0 or localId.nextFork > "current time"
429+
430+
# 2 + 3: FORK_HASH is subset or superset of local past forks
431+
for i, historicalId in calc.forkHistory:
432+
if forkId.crc == historicalId.crc:
433+
# Need to know if remote (=forkId) is ahead or behind localId
434+
if i > localForkPos:
435+
# 3: Remote is at a future fork we also know about
436+
# (local is syncing)
437+
return true
438+
# TODO: Should we still check its next fork?
439+
if forkId.nextFork == historicalId.nextFork:
440+
# 2: Remote is at a past fork we also know about and its nextFork matches the one for that past fork
441+
# (remote is syncing)
442+
return true
443+
else:
444+
# 4: Remote is at a past fork we also know about but its nextFork doesn't match
445+
return false
446+
447+
# 4: incompatible
394448
false
395449

396450
func initForkIdCalculator*(map: ForkTransitionTable,

execution_chain/nimbus_execution_client.nim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ proc setupP2P(nimbus: NimbusNode, config: ExecutionClientConf, com: CommonRef) =
109109
com.forkId(header.number, header.timestamp)
110110

111111
func compatibleForkIdProc(id: ForkID): bool =
112-
com.compatibleForkId(id)
112+
let header = fc.latestHeader()
113+
com.compatibleForkId(id, header.number, header.timestamp)
113114

114115
let forkIdProcs = ForkIdProcs(
115116
forkId: forkIdProc,

0 commit comments

Comments
 (0)