Merge fork gossip support (#3213)
* Merge fork gossip support * index directly by BeaconStateFork and remove debugging log statement
This commit is contained in:
parent
0304d28c9e
commit
0d4e49f946
|
@ -187,6 +187,11 @@ OK: 3/3 Fail: 0/3 Skip: 0/3
|
||||||
+ should raise on unknown data OK
|
+ should raise on unknown data OK
|
||||||
```
|
```
|
||||||
OK: 7/7 Fail: 0/7 Skip: 0/7
|
OK: 7/7 Fail: 0/7 Skip: 0/7
|
||||||
|
## Gossip fork transition
|
||||||
|
```diff
|
||||||
|
+ Gossip fork transition OK
|
||||||
|
```
|
||||||
|
OK: 1/1 Fail: 0/1 Skip: 0/1
|
||||||
## Gossip validation [Preset: mainnet]
|
## Gossip validation [Preset: mainnet]
|
||||||
```diff
|
```diff
|
||||||
+ Any committee index is valid OK
|
+ Any committee index is valid OK
|
||||||
|
|
|
@ -35,11 +35,7 @@ export
|
||||||
type
|
type
|
||||||
RpcServer* = RpcHttpServer
|
RpcServer* = RpcHttpServer
|
||||||
|
|
||||||
GossipState* = enum
|
GossipState* = set[BeaconStateFork]
|
||||||
Disconnected
|
|
||||||
ConnectedToPhase0
|
|
||||||
InTransitionToAltair
|
|
||||||
ConnectedToAltair
|
|
||||||
|
|
||||||
BeaconNode* = ref object
|
BeaconNode* = ref object
|
||||||
nickname*: string
|
nickname*: string
|
||||||
|
|
|
@ -509,10 +509,14 @@ proc init*(T: type ChainDAGRef, cfg: RuntimeConfig, db: BeaconChainDB,
|
||||||
onFinHappened: onFinCb
|
onFinHappened: onFinCb
|
||||||
)
|
)
|
||||||
|
|
||||||
doAssert cfg.GENESIS_FORK_VERSION != cfg.ALTAIR_FORK_VERSION
|
let forkVersions =
|
||||||
doAssert cfg.GENESIS_FORK_VERSION != cfg.MERGE_FORK_VERSION
|
[cfg.GENESIS_FORK_VERSION, cfg.ALTAIR_FORK_VERSION, cfg.MERGE_FORK_VERSION,
|
||||||
doAssert cfg.ALTAIR_FORK_VERSION != cfg.MERGE_FORK_VERSION
|
cfg.SHARDING_FORK_VERSION]
|
||||||
|
for i in 0 ..< forkVersions.len:
|
||||||
|
for j in i+1 ..< forkVersions.len:
|
||||||
|
doAssert forkVersions[i] != forkVersions[j]
|
||||||
doAssert cfg.ALTAIR_FORK_EPOCH <= cfg.MERGE_FORK_EPOCH
|
doAssert cfg.ALTAIR_FORK_EPOCH <= cfg.MERGE_FORK_EPOCH
|
||||||
|
doAssert cfg.MERGE_FORK_EPOCH <= cfg.SHARDING_FORK_EPOCH
|
||||||
doAssert dag.updateFlags in [{}, {verifyFinalization}]
|
doAssert dag.updateFlags in [{}, {verifyFinalization}]
|
||||||
|
|
||||||
var cache: StateCache
|
var cache: StateCache
|
||||||
|
|
|
@ -459,7 +459,7 @@ proc init(T: type BeaconNode,
|
||||||
processor: processor,
|
processor: processor,
|
||||||
blockProcessor: blockProcessor,
|
blockProcessor: blockProcessor,
|
||||||
consensusManager: consensusManager,
|
consensusManager: consensusManager,
|
||||||
gossipState: GossipState.Disconnected,
|
gossipState: {},
|
||||||
beaconClock: beaconClock,
|
beaconClock: beaconClock,
|
||||||
onAttestationSent: onAttestationSent,
|
onAttestationSent: onAttestationSent,
|
||||||
validatorMonitor: validatorMonitor
|
validatorMonitor: validatorMonitor
|
||||||
|
@ -512,9 +512,9 @@ func verifyFinalization(node: BeaconNode, slot: Slot) =
|
||||||
func subnetLog(v: BitArray): string =
|
func subnetLog(v: BitArray): string =
|
||||||
$toSeq(v.oneIndices())
|
$toSeq(v.oneIndices())
|
||||||
|
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.2/specs/phase0/validator.md#phase-0-attestation-subnet-stability
|
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/phase0/validator.md#phase-0-attestation-subnet-stability
|
||||||
proc updateAttestationSubnetHandlers(node: BeaconNode, slot: Slot) =
|
proc updateAttestationSubnetHandlers(node: BeaconNode, slot: Slot) =
|
||||||
if node.gossipState == GossipState.Disconnected:
|
if node.gossipState.card == 0:
|
||||||
# When disconnected, updateGossipState is responsible for all things
|
# When disconnected, updateGossipState is responsible for all things
|
||||||
# subnets - in particular, it will remove subscriptions on the edge where
|
# subnets - in particular, it will remove subscriptions on the edge where
|
||||||
# we enter the disconnected state.
|
# we enter the disconnected state.
|
||||||
|
@ -536,20 +536,16 @@ proc updateAttestationSubnetHandlers(node: BeaconNode, slot: Slot) =
|
||||||
# Remember what we subscribed to, so we can unsubscribe later
|
# Remember what we subscribed to, so we can unsubscribe later
|
||||||
node.actionTracker.subscribedSubnets = subnets
|
node.actionTracker.subscribedSubnets = subnets
|
||||||
|
|
||||||
case node.gossipState
|
let forkDigests: array[BeaconStateFork, auto] = [
|
||||||
of GossipState.Disconnected:
|
node.dag.forkDigests.phase0,
|
||||||
raiseAssert "Checked above"
|
node.dag.forkDigests.altair,
|
||||||
of GossipState.ConnectedToPhase0:
|
node.dag.forkDigests.merge
|
||||||
node.network.unsubscribeAttestationSubnets(unsubscribeSubnets, node.dag.forkDigests.phase0)
|
]
|
||||||
node.network.subscribeAttestationSubnets(subscribeSubnets, node.dag.forkDigests.phase0)
|
|
||||||
of GossipState.InTransitionToAltair:
|
for gossipFork in node.gossipState:
|
||||||
node.network.unsubscribeAttestationSubnets(unsubscribeSubnets, node.dag.forkDigests.phase0)
|
let forkDigest = forkDigests[gossipFork]
|
||||||
node.network.unsubscribeAttestationSubnets(unsubscribeSubnets, node.dag.forkDigests.altair)
|
node.network.unsubscribeAttestationSubnets(unsubscribeSubnets, forkDigest)
|
||||||
node.network.subscribeAttestationSubnets(subscribeSubnets, node.dag.forkDigests.phase0)
|
node.network.subscribeAttestationSubnets(subscribeSubnets, forkDigest)
|
||||||
node.network.subscribeAttestationSubnets(subscribeSubnets, node.dag.forkDigests.altair)
|
|
||||||
of GossipState.ConnectedToAltair:
|
|
||||||
node.network.unsubscribeAttestationSubnets(unsubscribeSubnets, node.dag.forkDigests.altair)
|
|
||||||
node.network.subscribeAttestationSubnets(subscribeSubnets, node.dag.forkDigests.altair)
|
|
||||||
|
|
||||||
debug "Attestation subnets",
|
debug "Attestation subnets",
|
||||||
slot, epoch = slot.epoch, gossipState = node.gossipState,
|
slot, epoch = slot.epoch, gossipState = node.gossipState,
|
||||||
|
@ -557,7 +553,8 @@ proc updateAttestationSubnetHandlers(node: BeaconNode, slot: Slot) =
|
||||||
aggregateSubnets = subnetLog(aggregateSubnets),
|
aggregateSubnets = subnetLog(aggregateSubnets),
|
||||||
prevSubnets = subnetLog(prevSubnets),
|
prevSubnets = subnetLog(prevSubnets),
|
||||||
subscribeSubnets = subnetLog(subscribeSubnets),
|
subscribeSubnets = subnetLog(subscribeSubnets),
|
||||||
unsubscribeSubnets = subnetLog(unsubscribeSubnets)
|
unsubscribeSubnets = subnetLog(unsubscribeSubnets),
|
||||||
|
gossipState = node.gossipState
|
||||||
|
|
||||||
# inspired by lighthouse research here
|
# inspired by lighthouse research here
|
||||||
# https://gist.github.com/blacktemplar/5c1862cb3f0e32a1a7fb0b25e79e6e2c#file-generate-scoring-params-py
|
# https://gist.github.com/blacktemplar/5c1862cb3f0e32a1a7fb0b25e79e6e2c#file-generate-scoring-params-py
|
||||||
|
@ -608,18 +605,20 @@ static:
|
||||||
aggregateTopicParams.validateParameters().tryGet()
|
aggregateTopicParams.validateParameters().tryGet()
|
||||||
basicParams.validateParameters.tryGet()
|
basicParams.validateParameters.tryGet()
|
||||||
|
|
||||||
proc addPhase0MessageHandlers(node: BeaconNode, forkDigest: ForkDigest, slot: Slot) =
|
proc addPhase0MessageHandlers(
|
||||||
node.network.subscribe(getBeaconBlocksTopic(forkDigest), blocksTopicParams, enableTopicMetrics = true)
|
node: BeaconNode, forkDigest: ForkDigest, slot: Slot) =
|
||||||
|
node.network.subscribe(
|
||||||
|
getBeaconBlocksTopic(forkDigest), blocksTopicParams,
|
||||||
|
enableTopicMetrics = true)
|
||||||
node.network.subscribe(getAttesterSlashingsTopic(forkDigest), basicParams)
|
node.network.subscribe(getAttesterSlashingsTopic(forkDigest), basicParams)
|
||||||
node.network.subscribe(getProposerSlashingsTopic(forkDigest), basicParams)
|
node.network.subscribe(getProposerSlashingsTopic(forkDigest), basicParams)
|
||||||
node.network.subscribe(getVoluntaryExitsTopic(forkDigest), basicParams)
|
node.network.subscribe(getVoluntaryExitsTopic(forkDigest), basicParams)
|
||||||
node.network.subscribe(getAggregateAndProofsTopic(forkDigest), aggregateTopicParams, enableTopicMetrics = true)
|
node.network.subscribe(
|
||||||
|
getAggregateAndProofsTopic(forkDigest), aggregateTopicParams,
|
||||||
|
enableTopicMetrics = true)
|
||||||
|
|
||||||
# updateAttestationSubnetHandlers subscribes attestation subnets
|
# updateAttestationSubnetHandlers subscribes attestation subnets
|
||||||
|
|
||||||
proc addPhase0MessageHandlers(node: BeaconNode, slot: Slot) =
|
|
||||||
addPhase0MessageHandlers(node, node.dag.forkDigests.phase0, slot)
|
|
||||||
|
|
||||||
proc removePhase0MessageHandlers(node: BeaconNode, forkDigest: ForkDigest) =
|
proc removePhase0MessageHandlers(node: BeaconNode, forkDigest: ForkDigest) =
|
||||||
node.network.unsubscribe(getBeaconBlocksTopic(forkDigest))
|
node.network.unsubscribe(getBeaconBlocksTopic(forkDigest))
|
||||||
node.network.unsubscribe(getVoluntaryExitsTopic(forkDigest))
|
node.network.unsubscribe(getVoluntaryExitsTopic(forkDigest))
|
||||||
|
@ -633,9 +632,6 @@ proc removePhase0MessageHandlers(node: BeaconNode, forkDigest: ForkDigest) =
|
||||||
|
|
||||||
node.actionTracker.subscribedSubnets = default(AttnetBits)
|
node.actionTracker.subscribedSubnets = default(AttnetBits)
|
||||||
|
|
||||||
proc removePhase0MessageHandlers(node: BeaconNode) =
|
|
||||||
removePhase0MessageHandlers(node, node.dag.forkDigests.phase0)
|
|
||||||
|
|
||||||
proc addAltairMessageHandlers(node: BeaconNode, forkDigest: ForkDigest, slot: Slot) =
|
proc addAltairMessageHandlers(node: BeaconNode, forkDigest: ForkDigest, slot: Slot) =
|
||||||
node.addPhase0MessageHandlers(forkDigest, slot)
|
node.addPhase0MessageHandlers(forkDigest, slot)
|
||||||
|
|
||||||
|
@ -653,9 +649,6 @@ proc addAltairMessageHandlers(node: BeaconNode, forkDigest: ForkDigest, slot: Sl
|
||||||
getSyncCommitteeContributionAndProofTopic(forkDigest), basicParams)
|
getSyncCommitteeContributionAndProofTopic(forkDigest), basicParams)
|
||||||
node.network.updateSyncnetsMetadata(syncnets)
|
node.network.updateSyncnetsMetadata(syncnets)
|
||||||
|
|
||||||
proc addAltairMessageHandlers(node: BeaconNode, slot: Slot) =
|
|
||||||
addAltairMessageHandlers(node, node.dag.forkDigests.altair, slot)
|
|
||||||
|
|
||||||
proc removeAltairMessageHandlers(node: BeaconNode, forkDigest: ForkDigest) =
|
proc removeAltairMessageHandlers(node: BeaconNode, forkDigest: ForkDigest) =
|
||||||
node.removePhase0MessageHandlers(forkDigest)
|
node.removePhase0MessageHandlers(forkDigest)
|
||||||
|
|
||||||
|
@ -668,20 +661,6 @@ proc removeAltairMessageHandlers(node: BeaconNode, forkDigest: ForkDigest) =
|
||||||
node.network.unsubscribe(
|
node.network.unsubscribe(
|
||||||
getSyncCommitteeContributionAndProofTopic(forkDigest))
|
getSyncCommitteeContributionAndProofTopic(forkDigest))
|
||||||
|
|
||||||
proc removeAltairMessageHandlers(node: BeaconNode) =
|
|
||||||
removeAltairMessageHandlers(node, node.dag.forkDigests.altair)
|
|
||||||
|
|
||||||
proc addMergeMessageHandlers(node: BeaconNode, slot: Slot) =
|
|
||||||
addAltairMessageHandlers(node, node.dag.forkDigests.merge, slot)
|
|
||||||
|
|
||||||
proc removeMergeMessageHandlers(node: BeaconNode) =
|
|
||||||
removeAltairMessageHandlers(node, node.dag.forkDigests.merge)
|
|
||||||
|
|
||||||
proc removeAllMessageHandlers(node: BeaconNode) =
|
|
||||||
node.removePhase0MessageHandlers()
|
|
||||||
node.removeAltairMessageHandlers()
|
|
||||||
node.removeMergeMessageHandlers()
|
|
||||||
|
|
||||||
proc setupDoppelgangerDetection(node: BeaconNode, slot: Slot) =
|
proc setupDoppelgangerDetection(node: BeaconNode, slot: Slot) =
|
||||||
# When another client's already running, this is very likely to detect
|
# When another client's already running, this is very likely to detect
|
||||||
# potential duplicate validators, which can trigger slashing.
|
# potential duplicate validators, which can trigger slashing.
|
||||||
|
@ -726,17 +705,34 @@ proc updateGossipStatus(node: BeaconNode, slot: Slot) {.async.} =
|
||||||
if slot > head.slot: (slot - head.slot).uint64
|
if slot > head.slot: (slot - head.slot).uint64
|
||||||
else: 0'u64
|
else: 0'u64
|
||||||
targetGossipState =
|
targetGossipState =
|
||||||
if headDistance > TOPIC_SUBSCRIBE_THRESHOLD_SLOTS + HYSTERESIS_BUFFER:
|
getTargetGossipState(
|
||||||
GossipState.Disconnected
|
slot.epoch,
|
||||||
elif slot.epoch + 1 < node.dag.cfg.ALTAIR_FORK_EPOCH:
|
node.dag.cfg.ALTAIR_FORK_EPOCH,
|
||||||
GossipState.ConnectedToPhase0
|
node.dag.cfg.MERGE_FORK_EPOCH,
|
||||||
elif slot.epoch >= node.dag.cfg.ALTAIR_FORK_EPOCH:
|
headDistance > TOPIC_SUBSCRIBE_THRESHOLD_SLOTS + HYSTERESIS_BUFFER)
|
||||||
GossipState.ConnectedToAltair
|
|
||||||
else:
|
|
||||||
GossipState.InTransitionToAltair
|
|
||||||
|
|
||||||
if node.gossipState == GossipState.Disconnected and
|
doAssert targetGossipState.card <= 2
|
||||||
targetGossipState != GossipState.Disconnected:
|
|
||||||
|
let
|
||||||
|
newGossipForks = targetGossipState - node.gossipState
|
||||||
|
oldGossipForks = node.gossipState - targetGossipState
|
||||||
|
|
||||||
|
doAssert newGossipForks.card <= 2
|
||||||
|
doAssert oldGossipForks.card <= 2
|
||||||
|
|
||||||
|
func maxGossipFork(gossipState: GossipState): int =
|
||||||
|
var res = -1
|
||||||
|
for gossipFork in gossipState:
|
||||||
|
res = max(res, gossipFork.int)
|
||||||
|
res
|
||||||
|
|
||||||
|
if maxGossipFork(targetGossipState) < maxGossipFork(node.gossipState) and
|
||||||
|
targetGossipState != {}:
|
||||||
|
warn "Unexpected clock regression during transition",
|
||||||
|
targetGossipState,
|
||||||
|
gossipState = node.gossipState
|
||||||
|
|
||||||
|
if node.gossipState.card == 0 and targetGossipState.card > 0:
|
||||||
# We are synced, so we will connect
|
# We are synced, so we will connect
|
||||||
debug "Enabling topic subscriptions",
|
debug "Enabling topic subscriptions",
|
||||||
wallSlot = slot,
|
wallSlot = slot,
|
||||||
|
@ -755,53 +751,36 @@ proc updateGossipStatus(node: BeaconNode, slot: Slot) {.async.} =
|
||||||
node.actionTracker.updateActions(
|
node.actionTracker.updateActions(
|
||||||
node.dag.getEpochRef(head, slot.epoch + 1))
|
node.dag.getEpochRef(head, slot.epoch + 1))
|
||||||
|
|
||||||
case targetGossipState
|
if node.gossipState.card > 0 and targetGossipState.card == 0:
|
||||||
of GossipState.Disconnected:
|
debug "Disabling topic subscriptions",
|
||||||
case node.gossipState:
|
wallSlot = slot,
|
||||||
of GossipState.Disconnected: discard
|
headSlot = head.slot,
|
||||||
else:
|
headDistance
|
||||||
debug "Disabling topic subscriptions",
|
|
||||||
wallSlot = slot,
|
|
||||||
headSlot = head.slot,
|
|
||||||
headDistance
|
|
||||||
node.removeAllMessageHandlers()
|
|
||||||
node.gossipState = GossipState.Disconnected
|
|
||||||
|
|
||||||
of GossipState.ConnectedToPhase0:
|
# These depend on forks.BeaconStateFork being properly ordered
|
||||||
case node.gossipState:
|
let forkDigests: array[BeaconStateFork, auto] = [
|
||||||
of GossipState.ConnectedToPhase0: discard
|
node.dag.forkDigests.phase0,
|
||||||
of GossipState.Disconnected:
|
node.dag.forkDigests.altair,
|
||||||
node.addPhase0MessageHandlers(slot)
|
node.dag.forkDigests.merge
|
||||||
of GossipState.InTransitionToAltair:
|
]
|
||||||
warn "Unexpected clock regression during altair transition"
|
|
||||||
node.removeAltairMessageHandlers()
|
|
||||||
of GossipState.ConnectedToAltair:
|
|
||||||
warn "Unexpected clock regression during altair transition"
|
|
||||||
node.removeAltairMessageHandlers()
|
|
||||||
node.addPhase0MessageHandlers(slot)
|
|
||||||
|
|
||||||
of GossipState.InTransitionToAltair:
|
const removeMessageHandlers: array[BeaconStateFork, auto] = [
|
||||||
case node.gossipState:
|
removePhase0MessageHandlers,
|
||||||
of GossipState.InTransitionToAltair: discard
|
removeAltairMessageHandlers,
|
||||||
of GossipState.Disconnected:
|
removeAltairMessageHandlers # with different forkDigest
|
||||||
node.addPhase0MessageHandlers(slot)
|
]
|
||||||
node.addAltairMessageHandlers(slot)
|
|
||||||
of GossipState.ConnectedToPhase0:
|
|
||||||
node.addAltairMessageHandlers(slot)
|
|
||||||
of GossipState.ConnectedToAltair:
|
|
||||||
warn "Unexpected clock regression during altair transition"
|
|
||||||
node.addPhase0MessageHandlers(slot)
|
|
||||||
|
|
||||||
of GossipState.ConnectedToAltair:
|
for gossipFork in oldGossipForks:
|
||||||
case node.gossipState:
|
removeMessageHandlers[gossipFork](node, forkDigests[gossipFork])
|
||||||
of GossipState.ConnectedToAltair: discard
|
|
||||||
of GossipState.Disconnected:
|
const addMessageHandlers: array[BeaconStateFork, auto] = [
|
||||||
node.addAltairMessageHandlers(slot)
|
addPhase0MessageHandlers,
|
||||||
of GossipState.ConnectedToPhase0:
|
addAltairMessageHandlers,
|
||||||
node.removePhase0MessageHandlers()
|
addAltairMessageHandlers # with different forkDigest
|
||||||
node.addAltairMessageHandlers(slot)
|
]
|
||||||
of GossipState.InTransitionToAltair:
|
|
||||||
node.removePhase0MessageHandlers()
|
for gossipFork in newGossipForks:
|
||||||
|
addMessageHandlers[gossipFork](node, forkDigests[gossipFork], slot)
|
||||||
|
|
||||||
node.gossipState = targetGossipState
|
node.gossipState = targetGossipState
|
||||||
node.updateAttestationSubnetHandlers(slot)
|
node.updateAttestationSubnetHandlers(slot)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import validator_client/[common, fallback_service, duties_service,
|
import validator_client/[common, fallback_service, duties_service,
|
||||||
attestation_service, fork_service]
|
attestation_service, fork_service]
|
||||||
|
|
||||||
proc initGenesis*(vc: ValidatorClientRef): Future[RestGenesis] {.async.} =
|
proc initGenesis(vc: ValidatorClientRef): Future[RestGenesis] {.async.} =
|
||||||
info "Initializing genesis", nodes_count = len(vc.beaconNodes)
|
info "Initializing genesis", nodes_count = len(vc.beaconNodes)
|
||||||
var nodes = vc.beaconNodes
|
var nodes = vc.beaconNodes
|
||||||
while true:
|
while true:
|
||||||
|
@ -73,7 +73,7 @@ proc initGenesis*(vc: ValidatorClientRef): Future[RestGenesis] {.async.} =
|
||||||
dec(counter)
|
dec(counter)
|
||||||
return melem
|
return melem
|
||||||
|
|
||||||
proc initValidators*(vc: ValidatorClientRef): Future[bool] {.async.} =
|
proc initValidators(vc: ValidatorClientRef): Future[bool] {.async.} =
|
||||||
info "Initializaing validators", path = vc.config.validatorsDir()
|
info "Initializaing validators", path = vc.config.validatorsDir()
|
||||||
var duplicates: seq[ValidatorPubKey]
|
var duplicates: seq[ValidatorPubKey]
|
||||||
for item in vc.config.validatorItems():
|
for item in vc.config.validatorItems():
|
||||||
|
@ -86,7 +86,7 @@ proc initValidators*(vc: ValidatorClientRef): Future[bool] {.async.} =
|
||||||
vc.attachedValidators.addLocalValidator(item)
|
vc.attachedValidators.addLocalValidator(item)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc initClock*(vc: ValidatorClientRef): Future[BeaconClock] {.async.} =
|
proc initClock(vc: ValidatorClientRef): Future[BeaconClock] {.async.} =
|
||||||
# This procedure performs initialization of BeaconClock using current genesis
|
# This procedure performs initialization of BeaconClock using current genesis
|
||||||
# information. It also performs waiting for genesis.
|
# information. It also performs waiting for genesis.
|
||||||
let res = BeaconClock.init(vc.beaconGenesis.genesis_time)
|
let res = BeaconClock.init(vc.beaconGenesis.genesis_time)
|
||||||
|
@ -101,7 +101,7 @@ proc initClock*(vc: ValidatorClientRef): Future[BeaconClock] {.async.} =
|
||||||
await sleepAsync(genesisTime.offset)
|
await sleepAsync(genesisTime.offset)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
proc asyncInit*(vc: ValidatorClientRef) {.async.} =
|
proc asyncInit(vc: ValidatorClientRef) {.async.} =
|
||||||
vc.beaconGenesis = await vc.initGenesis()
|
vc.beaconGenesis = await vc.initGenesis()
|
||||||
info "Genesis information", genesis_time = vc.beaconGenesis.genesis_time,
|
info "Genesis information", genesis_time = vc.beaconGenesis.genesis_time,
|
||||||
genesis_fork_version = vc.beaconGenesis.genesis_fork_version,
|
genesis_fork_version = vc.beaconGenesis.genesis_fork_version,
|
||||||
|
@ -151,7 +151,7 @@ proc onSlotStart(vc: ValidatorClientRef, wallTime: BeaconTime,
|
||||||
blockIn = vc.getDurationToNextBlock(wallSlot.slot),
|
blockIn = vc.getDurationToNextBlock(wallSlot.slot),
|
||||||
delay = shortLog(delay)
|
delay = shortLog(delay)
|
||||||
|
|
||||||
proc asyncRun*(vc: ValidatorClientRef) {.async.} =
|
proc asyncRun(vc: ValidatorClientRef) {.async.} =
|
||||||
vc.fallbackService.start()
|
vc.fallbackService.start()
|
||||||
vc.forkService.start()
|
vc.forkService.start()
|
||||||
vc.dutiesService.start()
|
vc.dutiesService.start()
|
||||||
|
|
|
@ -404,13 +404,13 @@ proc nextForkEpochAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Epoch =
|
||||||
of BeaconStateFork.Altair: cfg.MERGE_FORK_EPOCH
|
of BeaconStateFork.Altair: cfg.MERGE_FORK_EPOCH
|
||||||
of BeaconStateFork.Phase0: cfg.ALTAIR_FORK_EPOCH
|
of BeaconStateFork.Phase0: cfg.ALTAIR_FORK_EPOCH
|
||||||
|
|
||||||
func getForkSchedule*(cfg: RuntimeConfig): array[2, Fork] =
|
func getForkSchedule*(cfg: RuntimeConfig): array[3, Fork] =
|
||||||
## This procedure returns list of known and/or scheduled forks.
|
## This procedure returns list of known and/or scheduled forks.
|
||||||
##
|
##
|
||||||
## This procedure is used by HTTP REST framework and validator client.
|
## This procedure is used by HTTP REST framework and validator client.
|
||||||
##
|
##
|
||||||
## NOTE: Update this procedure when new fork will be scheduled.
|
## NOTE: Update this procedure when new fork will be scheduled.
|
||||||
[cfg.genesisFork(), cfg.altairFork()]
|
[cfg.genesisFork(), cfg.altairFork(), cfg.mergeFork()]
|
||||||
|
|
||||||
type
|
type
|
||||||
# The first few fields of a state, shared across all forks
|
# The first few fields of a state, shared across all forks
|
||||||
|
|
|
@ -125,3 +125,44 @@ func getDiscoveryForkID*(cfg: RuntimeConfig,
|
||||||
fork_digest: fork_digest,
|
fork_digest: fork_digest,
|
||||||
next_fork_version: current_fork_version,
|
next_fork_version: current_fork_version,
|
||||||
next_fork_epoch: FAR_FUTURE_EPOCH)
|
next_fork_epoch: FAR_FUTURE_EPOCH)
|
||||||
|
|
||||||
|
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/altair/p2p-interface.md#transitioning-the-gossip
|
||||||
|
func getTargetGossipState*(
|
||||||
|
epoch, ALTAIR_FORK_EPOCH, MERGE_FORK_EPOCH: Epoch, isBehind: bool):
|
||||||
|
set[BeaconStateFork] =
|
||||||
|
if isBehind:
|
||||||
|
{}
|
||||||
|
|
||||||
|
# The order of these checks doesn't matter.
|
||||||
|
elif epoch >= MERGE_FORK_EPOCH:
|
||||||
|
{BeaconStateFork.Merge}
|
||||||
|
elif epoch + 1 < ALTAIR_FORK_EPOCH:
|
||||||
|
{BeaconStateFork.Phase0}
|
||||||
|
|
||||||
|
# Order remaining checks so ALTAIR_FORK_EPOCH == MERGE_FORK_EPOCH works
|
||||||
|
# and when the transition zones align contiguously, or are separated by
|
||||||
|
# intermediate pure-Altair epochs.
|
||||||
|
#
|
||||||
|
# In the first case, should never enable Altair, and there's also never
|
||||||
|
# any Phase -> Altair or Altair -> Merge gossip transition epoch. Given
|
||||||
|
# contiguous Phase0 -> Altair and Altair -> Merge gossip transitions, a
|
||||||
|
# pure Altair state gossip state never occurs, but it works without any
|
||||||
|
# special cases so long as one checks for transition-to-fork+1 before a
|
||||||
|
# pure fork gossip state.
|
||||||
|
#
|
||||||
|
# Therefore, check for transition-to-merge before pure-Altair.
|
||||||
|
elif epoch + 1 >= MERGE_FORK_EPOCH:
|
||||||
|
# As there are only two fork epochs and there's no transition to phase0
|
||||||
|
{if ALTAIR_FORK_EPOCH == MERGE_FORK_EPOCH:
|
||||||
|
BeaconStateFork.Phase0
|
||||||
|
else:
|
||||||
|
BeaconStateFork.Altair,
|
||||||
|
BeaconStateFork.Merge}
|
||||||
|
elif epoch >= ALTAIR_FORK_EPOCH:
|
||||||
|
{BeaconStateFork.Altair}
|
||||||
|
|
||||||
|
# Must be after the case which catches phase0 => merge
|
||||||
|
elif epoch + 1 >= ALTAIR_FORK_EPOCH:
|
||||||
|
{BeaconStateFork.Phase0, BeaconStateFork.Altair}
|
||||||
|
else:
|
||||||
|
raiseAssert "Unknown target gossip state"
|
||||||
|
|
|
@ -23,6 +23,7 @@ import # Unit test
|
||||||
./test_eth2_ssz_serialization,
|
./test_eth2_ssz_serialization,
|
||||||
./test_exit_pool,
|
./test_exit_pool,
|
||||||
./test_forks,
|
./test_forks,
|
||||||
|
./test_gossip_transition,
|
||||||
./test_gossip_validation,
|
./test_gossip_validation,
|
||||||
./test_helpers,
|
./test_helpers,
|
||||||
./test_honest_validator,
|
./test_honest_validator,
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
{.used.}
|
||||||
|
|
||||||
|
import
|
||||||
|
unittest2,
|
||||||
|
./testutil,
|
||||||
|
../beacon_chain/spec/[forks, network]
|
||||||
|
|
||||||
|
template getTargetGossipState(a, b, c: int, isBehind: bool): auto =
|
||||||
|
getTargetGossipState(a.Epoch, b.Epoch, c.Epoch, isBehind)
|
||||||
|
|
||||||
|
suite "Gossip fork transition":
|
||||||
|
test "Gossip fork transition":
|
||||||
|
check:
|
||||||
|
getTargetGossipState(0, 0, 0, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(0, 0, 2, false) == {BeaconStateFork.Altair}
|
||||||
|
getTargetGossipState(0, 1, 2, false) == {BeaconStateFork.Phase0, BeaconStateFork.Altair}
|
||||||
|
getTargetGossipState(0, 2, 3, false) == {BeaconStateFork.Phase0}
|
||||||
|
getTargetGossipState(0, 2, 5, false) == {BeaconStateFork.Phase0}
|
||||||
|
getTargetGossipState(0, 3, 4, false) == {BeaconStateFork.Phase0}
|
||||||
|
getTargetGossipState(0, 3, 5, false) == {BeaconStateFork.Phase0}
|
||||||
|
getTargetGossipState(0, 4, 4, false) == {BeaconStateFork.Phase0}
|
||||||
|
getTargetGossipState(0, 4, 5, false) == {BeaconStateFork.Phase0}
|
||||||
|
getTargetGossipState(1, 0, 1, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(1, 0, 5, false) == {BeaconStateFork.Altair}
|
||||||
|
getTargetGossipState(1, 1, 4, false) == {BeaconStateFork.Altair}
|
||||||
|
getTargetGossipState(2, 0, 2, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(2, 2, 3, false) == {BeaconStateFork.Altair, BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(2, 2, 4, false) == {BeaconStateFork.Altair}
|
||||||
|
getTargetGossipState(2, 3, 4, false) == {BeaconStateFork.Phase0, BeaconStateFork.Altair}
|
||||||
|
getTargetGossipState(2, 3, 5, true) == {}
|
||||||
|
getTargetGossipState(2, 5, 5, false) == {BeaconStateFork.Phase0}
|
||||||
|
getTargetGossipState(3, 0, 2, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(3, 0, 3, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(3, 0, 5, false) == {BeaconStateFork.Altair}
|
||||||
|
getTargetGossipState(3, 1, 2, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(3, 1, 1, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(3, 1, 3, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(3, 1, 5, true) == {}
|
||||||
|
getTargetGossipState(3, 1, 4, false) == {BeaconStateFork.Altair, BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(3, 2, 3, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(3, 3, 4, false) == {BeaconStateFork.Altair, BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(3, 3, 4, true) == {}
|
||||||
|
getTargetGossipState(3, 4, 4, false) == {BeaconStateFork.Phase0, BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(4, 0, 0, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(4, 0, 1, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(4, 1, 1, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(4, 1, 3, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(4, 2, 4, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(4, 3, 4, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(4, 4, 4, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(4, 5, 5, false) == {BeaconStateFork.Phase0, BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(5, 0, 0, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(5, 0, 2, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(5, 0, 4, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(5, 0, 5, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(5, 0, 5, true) == {}
|
||||||
|
getTargetGossipState(5, 1, 5, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(5, 2, 2, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(5, 2, 4, true) == {}
|
||||||
|
getTargetGossipState(5, 3, 4, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(5, 3, 5, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(5, 5, 5, false) == {BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(2, 0, 3, false) == {BeaconStateFork.Altair, BeaconStateFork.Merge}
|
||||||
|
getTargetGossipState(4, 1, 2, false) == {BeaconStateFork.Merge}
|
Loading…
Reference in New Issue