77# This file may not be copied, modified, or distributed except according to
88# those terms.
99
10+ {.push raises : [].}
11+
1012import
1113 std/ [strutils],
1214 eth/ common/ [headers],
1517 ../ utils/ utils,
1618 ./ evmforks
1719
18- {.push raises : [].}
19-
2020type
2121 HardFork * = enum
2222 Frontier
@@ -348,10 +348,10 @@ type
348348 byBlock: seq [uint64 ]
349349 byTime: seq [uint64 ]
350350 genesisCRC: uint32
351- cache : seq [ForkID ]
351+ forkHistory : seq [ForkID ]
352352
353353func newID * (calc: ForkIdCalculator , head, time: uint64 ): ForkID =
354- # Create a fork ID for a specific block height and timestamp:
354+ # # Create a fork ID for a specific block height and timestamp
355355 var crc = calc.genesisCRC
356356 for fork in calc.byBlock:
357357 if fork <= head:
@@ -369,39 +369,76 @@ 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 )
375- var crc = calc.genesisCRC
376-
377- # Build cache of all valid ForkIds
378- # Each entry is (crc before fork, fork number)
379- for fork in calc.byBlock:
380- calc.cache.add ( (crc, fork) )
381- crc = crc32 (crc, fork.toBytesBE)
382-
383- for fork in calc.byTime:
384- calc.cache.add ( (crc, fork) )
385- crc = crc32 (crc, fork.toBytesBE)
386-
387- # Add last fork ID (after all forks, next=0)
388- calc.cache.add ( (crc, 0 'u64 ) )
372+ func compatible * (calc: ForkIdCalculator , forkId: ForkID , number: uint64 , time: uint64 ): bool =
373+ # # Check forkId compatibility at a specific head position according to EIP-2124 / EIP-6122.
374+ # # The number and time represent the local chain state at which compatibility needs to be checked
375+ # # In regular use this should be the current header block number and timestamp, but for testing
376+ # # arbitrary points in history can be used.
377+
378+ # Calculate our current local fork ID at the given head position (= block and/or time)
379+ let localId = calc.newID (number, time)
380+
381+ # Calculate position of local fork ID in history
382+ var localForkPos = - 1
383+ for i, historicalId in calc.forkHistory:
384+ if localId.crc == historicalId.crc:
385+ localForkPos = i
386+ break
387+
388+ # Based on position of local fork ID, determine if the head is block or time based
389+ let head =
390+ if localForkPos >= calc.byBlock.len ():
391+ time
392+ else :
393+ number
394+
395+ # 1: local and remote FORK_HASH matches
396+ if forkId.crc == localId.crc:
397+ if forkId.nextFork != 0 : # announced fork
398+ if head >= forkId.nextFork:
399+ # 1a - next fork already passed locally
400+ return false
401+ else :
402+ # 1b - next fork not yet passed locally
403+ return true
389404
390- for id in calc.cache :
391- if id == forkId:
405+ else :
406+ # 1b - no next fork announced
392407 return true
393408
409+ # 2 + 3: FORK_HASH is subset or superset of local past forks
410+ for i, historicalId in calc.forkHistory:
411+ if forkId.crc == historicalId.crc:
412+ # Need to know if remote (=forkId) is ahead or behind localId
413+ if i > localForkPos:
414+ # 3: Remote is at a future fork we also know about
415+ # (local is syncing)
416+ return true
417+ # TODO : Should we still check its next fork?
418+ if forkId.nextFork == historicalId.nextFork:
419+ # 2: Remote is at a past fork we also know about and its nextFork matches the one for that past fork
420+ # (remote is syncing)
421+ return true
422+ else :
423+ # 4: Remote is at a past fork we also know about but its nextFork doesn't match
424+ return false
425+
426+ # 4: incompatible
394427 false
395428
396- func initForkIdCalculator * (map: ForkTransitionTable ,
397- genesisCRC: uint32 ,
398- genesisTime: uint64 ): ForkIdCalculator =
399- # Build ForkIdCalculator from the chain's fork configuration
429+ func init * (
430+ _: type ForkIdCalculator ,
431+ map: ForkTransitionTable ,
432+ genesisCRC: uint32 ,
433+ genesisTime: uint64 ,
434+ ): ForkIdCalculator =
435+ # # Build ForkIdCalculator from the chain's fork configuration
400436
401437 # Extract the fork rule block number aggregate it
402438 var forksByBlock: seq [uint64 ]
403439 for fork, val in map.blockNumberThresholds:
404- if val.isNone: continue
440+ if val.isNone:
441+ continue
405442 let val64 = val.get
406443 if forksByBlock.len == 0 :
407444 forksByBlock.add val64
@@ -424,7 +461,8 @@ func initForkIdCalculator*(map: ForkTransitionTable,
424461 # Extract the fork rule timestamp number aggregate it
425462 var forksByTime: seq [uint64 ]
426463 for fork, val in map.timeThresholds:
427- if val.isNone: continue
464+ if val.isNone:
465+ continue
428466 let val64 = val.get.uint64
429467 if forksByTime.len == 0 :
430468 forksByTime.add val64
@@ -435,9 +473,28 @@ func initForkIdCalculator*(map: ForkTransitionTable,
435473 while forksByTime.len > 0 and forksByTime[0 ] <= genesisTime:
436474 forksByTime.delete (0 )
437475
438- result .genesisCRC = genesisCRC
439- result .byBlock = system.move (forksByBlock)
440- result .byTime = system.move (forksByTime)
476+ # Calculate the fork ids for the full fork history
477+ var forkHistory = newSeqOfCap [ForkID ](forksByBlock.len + forksByTime.len + 1 )
478+ var crc = genesisCRC
479+
480+ # Each entry is (crc before fork, fork number)
481+ for fork in forksByBlock:
482+ forkHistory.add ((crc, fork))
483+ crc = crc32 (crc, fork.toBytesBE)
484+
485+ for fork in forksByTime:
486+ forkHistory.add ((crc, fork))
487+ crc = crc32 (crc, fork.toBytesBE)
488+
489+ # Add last fork ID (after all forks, next=0)
490+ forkHistory.add ((crc, 0 'u64 ))
491+
492+ ForkIdCalculator (
493+ genesisCRC: genesisCRC,
494+ byBlock: system.move (forksByBlock),
495+ byTime: system.move (forksByTime),
496+ forkHistory: system.move (forkHistory),
497+ )
441498
442499# ------------------------------------------------------------------------------
443500# End
0 commit comments