Skip to content

Commit

Permalink
add infrastructure to select fork choice version
Browse files Browse the repository at this point in the history
To allow testing ethereum/consensus-specs#3466
add support for selecting fork choice version at launch. This means we
can deploy a different logic when `DENEB_FORK_EPOCH != FAR_FUTURE_EPOCH`
that won't be used on Mainnet.
  • Loading branch information
etan-status committed Sep 4, 2023
1 parent be9ecfa commit 576a9a6
Show file tree
Hide file tree
Showing 10 changed files with 42 additions and 14 deletions.
8 changes: 8 additions & 0 deletions beacon_chain/conf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import
./el/el_conf,
./filepath

from fork_choice/fork_choice_types
import ForkChoiceVersion
from consensus_object_pools/block_pools_types_light_client
import LightClientDataImportMode

Expand Down Expand Up @@ -632,6 +634,12 @@ type
desc: "Bandwidth estimate for the node (bits per second)"
name: "debug-bandwidth-estimate" .}: Option[Natural]

forkChoiceVersion* {.
hidden
desc: "Forkchoice version to use. " &
"Must be one of: stable"
name: "debug-forkchoice-version" .}: Option[ForkChoiceVersion]

of BNStartUpCmd.wallets:
case walletsCmd* {.command.}: WalletsCmd
of WalletsCmd.create:
Expand Down
3 changes: 2 additions & 1 deletion beacon_chain/consensus_object_pools/attestation_pool.nim
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,15 @@ declareGauge attestation_pool_block_attestation_packing_time,

proc init*(T: type AttestationPool, dag: ChainDAGRef,
quarantine: ref Quarantine,
forkChoiceVersion = ForkChoiceVersion.Stable,
onAttestation: OnAttestationCallback = nil): T =
## Initialize an AttestationPool from the dag `headState`
## The `finalized_root` works around the finalized_checkpoint of the genesis block
## holding a zero_root.
let finalizedEpochRef = dag.getFinalizedEpochRef()

var forkChoice = ForkChoice.init(
finalizedEpochRef, dag.finalizedHead.blck)
finalizedEpochRef, dag.finalizedHead.blck, forkChoiceVersion)

# Feed fork choice with unfinalized history - during startup, block pool only
# keeps track of a single history so we just need to follow it
Expand Down
12 changes: 8 additions & 4 deletions beacon_chain/fork_choice/fork_choice.nim
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,13 @@ func compute_deltas(
logScope: topics = "fork_choice"

func init*(
T: type ForkChoiceBackend, checkpoints: FinalityCheckpoints): T =
T(proto_array: ProtoArray.init(checkpoints))
T: type ForkChoiceBackend, checkpoints: FinalityCheckpoints,
version: ForkChoiceVersion): T =
T(proto_array: ProtoArray.init(checkpoints, version))

proc init*(
T: type ForkChoice, epochRef: EpochRef, blck: BlockRef): T =
T: type ForkChoice, epochRef: EpochRef, blck: BlockRef,
version: ForkChoiceVersion): T =
## Initialize a fork choice context for a finalized state - in the finalized
## state, the justified and finalized checkpoints are the same, so only one
## is used here
Expand All @@ -65,8 +67,10 @@ proc init*(
backend: ForkChoiceBackend.init(
FinalityCheckpoints(
justified: checkpoint,
finalized: checkpoint)),
finalized: checkpoint),
version),
checkpoints: Checkpoints(
version: version,
justified: BalanceCheckpoint(
checkpoint: checkpoint,
balances: epochRef.effective_balances),
Expand Down
7 changes: 7 additions & 0 deletions beacon_chain/fork_choice/fork_choice_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ import
# ----------------------------------------------------------------------

type
ForkChoiceVersion* {.pure.} = enum
## Controls which version of fork choice to run.
Stable = "stable"
## Use current version from stable Ethereum consensus specifications

fcKind* = enum
## Fork Choice Error Kinds
fcFinalizedNodeUnknown
Expand Down Expand Up @@ -88,6 +93,7 @@ type
## Subtracted from logical index to get the physical index

ProtoArray* = object
version*: ForkChoiceVersion
currentEpoch*: Epoch
checkpoints*: FinalityCheckpoints
nodes*: ProtoNodes
Expand All @@ -110,6 +116,7 @@ type
balances*: seq[Gwei]

Checkpoints* = object
version*: ForkChoiceVersion
time*: BeaconTime
justified*: BalanceCheckpoint
finalized*: Checkpoint
Expand Down
8 changes: 5 additions & 3 deletions beacon_chain/fork_choice/proto_array.nim
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ func nodeLeadsToViableHead(
# ----------------------------------------------------------------------

func init*(
T: type ProtoArray, checkpoints: FinalityCheckpoints): T =
T: type ProtoArray, checkpoints: FinalityCheckpoints,
version: ForkChoiceVersion): T =
let node = ProtoNode(
bid: BlockId(
slot: checkpoints.finalized.epoch.start_slot,
Expand All @@ -102,7 +103,8 @@ func init*(
bestChild: none(int),
bestDescendant: none(int))

T(checkpoints: checkpoints,
T(version: version,
checkpoints: checkpoints,
nodes: ProtoNodes(buf: @[node], offset: 0),
indices: {node.bid.root: 0}.toTable())

Expand Down Expand Up @@ -541,7 +543,7 @@ func nodeIsViableForHead(
correctJustified =
unrealized.justified.epoch >= self.checkpoints.justified.epoch and
node.checkpoints.justified.epoch + 2 >= self.currentEpoch

return
if not correctJustified:
false
Expand Down
6 changes: 4 additions & 2 deletions beacon_chain/nimbus_beacon_node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,8 @@ proc initFullNode(
let
quarantine = newClone(
Quarantine.init())
attestationPool = newClone(
AttestationPool.init(dag, quarantine, onAttestationReceived))
attestationPool = newClone(AttestationPool.init(
dag, quarantine, config.forkChoiceVersion.get, onAttestationReceived))
syncCommitteeMsgPool = newClone(
SyncCommitteeMsgPool.init(rng, dag.cfg, onSyncContribution))
lightClientPool = newClone(
Expand Down Expand Up @@ -1860,6 +1860,8 @@ proc doRunBeaconNode(config: var BeaconNodeConf, rng: ref HmacDrbgContext) {.rai
# works
for node in metadata.bootstrapNodes:
config.bootstrapNodes.add node
if config.forkChoiceVersion.isNone:
config.forkChoiceVersion = some(ForkChoiceVersion.Stable)

## Ctrl+C handling
proc controlCHandler() {.noconv.} =
Expand Down
4 changes: 3 additions & 1 deletion beacon_chain/rpc/rest_debug_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ proc installDebugApiHandlers*(router: var RestRouter, node: BeaconNode) =

var response = GetForkChoiceResponse(
justified_checkpoint: forkChoice.checkpoints.justified.checkpoint,
finalized_checkpoint: forkChoice.checkpoints.finalized)
finalized_checkpoint: forkChoice.checkpoints.finalized,
extra_data: RestExtraData(
version: some($forkChoice.backend.proto_array.version)))

for item in forkChoice.backend.proto_array:
let
Expand Down
2 changes: 1 addition & 1 deletion beacon_chain/spec/eth2_apis/rest_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ type
extra_data*: Option[RestNodeExtraData]

RestExtraData* = object
discard
version*: Option[string]

GetForkChoiceResponse* = object
justified_checkpoint*: Checkpoint
Expand Down
3 changes: 2 additions & 1 deletion tests/consensus_spec/test_fixture_fork_choice.nim
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ proc initialLoad(
dag = ChainDAGRef.init(
forkedState[].kind.genesisTestRuntimeConfig, db, validatorMonitor, {})
fkChoice = newClone(ForkChoice.init(
dag.getFinalizedEpochRef(), dag.finalizedHead.blck))
dag.getFinalizedEpochRef(), dag.finalizedHead.blck,
ForkChoiceVersion.Stable))

(dag, fkChoice)

Expand Down
3 changes: 2 additions & 1 deletion tests/test_keymanager_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,8 @@ proc startBeaconNode(basePort: int) {.raises: [CatchableError].} =
"--keymanager-port=" & $(basePort + PortKind.KeymanagerBN.ord),
"--keymanager-token-file=" & tokenFilePath,
"--suggested-fee-recipient=" & $defaultFeeRecipient,
"--doppelganger-detection=off"], it))
"--doppelganger-detection=off",
"--debug-forkchoice-version=stable"], it))
except Exception as exc: # TODO fix confutils exceptions
raiseAssert exc.msg

Expand Down

0 comments on commit 576a9a6

Please sign in to comment.