Skip to content

Commit

Permalink
reduce LC optsync latency (#4002)
Browse files Browse the repository at this point in the history
The optimistic sync spec was updated since the LC based optsync module
was introduced. It is no longer necessary to wait for the justified
checkpoint to have execution enabled; instead, any block is okay to be
optimistically imported to the EL client, as long as its parent block
has execution enabled. Complex syncing logic has been removed, and the
LC optsync module will now follow gossip directly, reducing the latency
when using this module. Note that because this is now based on gossip
instead of using sync manager / request manager, that individual blocks
may be missed. However, EL clients should recover from this by fetching
missing blocks themselves.
  • Loading branch information
etan-status committed Aug 25, 2022
1 parent b6488d5 commit 9180f09
Show file tree
Hide file tree
Showing 16 changed files with 553 additions and 1,401 deletions.
13 changes: 1 addition & 12 deletions AllTests-mainnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,6 @@ OK: 6/6 Fail: 0/6 Skip: 0/6
+ basics OK
```
OK: 1/1 Fail: 0/1 Skip: 0/1
## Block clearance (light client) [Preset: mainnet]
```diff
+ Delayed finality update OK
+ Error conditions OK
+ Incremental sync OK
+ Initial sync OK
+ Low slot numbers OK
+ Reorg OK
+ Reverse incremental sync OK
```
OK: 7/7 Fail: 0/7 Skip: 0/7
## Block pool altair processing [Preset: mainnet]
```diff
+ Invalid signatures [Preset: mainnet] OK
Expand Down Expand Up @@ -596,4 +585,4 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
OK: 9/9 Fail: 0/9 Skip: 0/9

---TOTAL---
OK: 333/338 Fail: 0/338 Skip: 5/338
OK: 326/331 Fail: 0/331 Skip: 5/331
13 changes: 7 additions & 6 deletions beacon_chain/beacon_node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ import

# Local modules
"."/[beacon_clock, beacon_chain_db, conf, light_client],
./gossip_processing/[eth2_processor, block_processor],
./gossip_processing/[eth2_processor, block_processor, optimistic_processor],
./networking/eth2_network,
./eth1/eth1_monitor,
./consensus_object_pools/[
blockchain_dag, block_quarantine, consensus_manager, exit_pool,
attestation_pool, sync_committee_msg_pool],
./spec/datatypes/[base, altair],
./spec/eth2_apis/dynamic_fee_recipients,
./sync/[optimistic_sync_light_client, sync_manager, request_manager],
./sync/[sync_manager, request_manager],
./validators/[
action_tracker, message_router, validator_monitor, validator_pool,
keystore_management],
Expand All @@ -33,9 +33,9 @@ export
osproc, chronos, httpserver, presto, action_tracker,
beacon_clock, beacon_chain_db, conf, light_client,
attestation_pool, sync_committee_msg_pool, validator_pool,
eth2_network, eth1_monitor, optimistic_sync_light_client,
request_manager, sync_manager, eth2_processor, blockchain_dag,
block_quarantine, base, exit_pool, message_router, validator_monitor,
eth2_network, eth1_monitor, request_manager, sync_manager,
eth2_processor, optimistic_processor, blockchain_dag, block_quarantine,
base, exit_pool, message_router, validator_monitor,
consensus_manager, dynamic_fee_recipients

type
Expand All @@ -58,7 +58,7 @@ type
db*: BeaconChainDB
config*: BeaconNodeConf
attachedValidators*: ref ValidatorPool
lcOptSync*: LCOptimisticSync
optimisticProcessor*: OptimisticProcessor
lightClient*: LightClient
dag*: ChainDAGRef
quarantine*: ref Quarantine
Expand All @@ -83,6 +83,7 @@ type
consensusManager*: ref ConsensusManager
attachedValidatorBalanceTotal*: uint64
gossipState*: GossipState
blocksGossipState*: GossipState
beaconClock*: BeaconClock
restKeysCache*: Table[ValidatorPubKey, ValidatorIndex]
validatorMonitor*: ref ValidatorMonitor
Expand Down
63 changes: 28 additions & 35 deletions beacon_chain/beacon_node_light_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,24 @@ import

logScope: topics = "beacnde"

func shouldSyncOptimistically*(node: BeaconNode, wallSlot: Slot): bool =
# Check whether light client is used for syncing
let optimisticHeader = node.lightClient.optimisticHeader.valueOr:
return false

# Check whether light client is sufficiently ahead of DAG
const minProgress = 8 * SLOTS_PER_EPOCH # Set arbitrarily
let dagSlot = getStateField(node.dag.headState, slot)
if dagSlot + minProgress > optimisticHeader.slot:
return false

# Check whether light client has synced sufficiently close to wall slot
const maxAge = 2 * SLOTS_PER_EPOCH
if optimisticHeader.slot < max(wallSlot, maxAge.Slot) - maxAge:
return false

true

proc initLightClient*(
node: BeaconNode,
rng: ref HmacDrbgContext,
Expand All @@ -30,52 +48,28 @@ proc initLightClient*(
# for broadcasting light client data as a server.

let
optimisticProcessor = proc(signedBlock: ForkedMsgTrustedSignedBeaconBlock):
optimisticHandler = proc(signedBlock: ForkedMsgTrustedSignedBeaconBlock):
Future[void] {.async.} =
debug "New LC optimistic block",
opt = signedBlock.toBlockId(),
dag = node.dag.head.bid,
wallSlot = node.currentSlot
return
optSync = initLCOptimisticSync(
node.network, getBeaconTime, optimisticProcessor,
config.safeSlotsToImportOptimistically)
optimisticProcessor = initOptimisticProcessor(
getBeaconTime, optimisticHandler)

lightClient = createLightClient(
node.network, rng, config, cfg, forkDigests, getBeaconTime,
genesis_validators_root, LightClientFinalizationMode.Strict)

if config.lightClientEnable:
proc shouldSyncOptimistically(slot: Slot): bool =
const
# Minimum number of slots to be ahead of DAG to use optimistic sync
minProgress = 8 * SLOTS_PER_EPOCH
# Maximum age of light client optimistic header to use optimistic sync
maxAge = 2 * SLOTS_PER_EPOCH

if slot < getStateField(node.dag.headState, slot) + minProgress:
false
elif getBeaconTime().slotOrZero > slot + maxAge:
false
else:
true

proc onFinalizedHeader(lightClient: LightClient) =
let optimisticHeader = lightClient.optimisticHeader.valueOr:
return
if not shouldSyncOptimistically(optimisticHeader.slot):
return
let finalizedHeader = lightClient.finalizedHeader.valueOr:
return
optSync.setOptimisticHeader(optimisticHeader)
optSync.setFinalizedHeader(finalizedHeader)
proc onFinalizedHeader(
lightClient: LightClient, finalizedHeader: BeaconBlockHeader) =
optimisticProcessor.setFinalizedHeader(finalizedHeader)

proc onOptimisticHeader(lightClient: LightClient) =
let optimisticHeader = lightClient.optimisticHeader.valueOr:
return
if not shouldSyncOptimistically(optimisticHeader.slot):
return
optSync.setOptimisticHeader(optimisticHeader)
proc onOptimisticHeader(
lightClient: LightClient, optimisticHeader: BeaconBlockHeader) =
optimisticProcessor.setOptimisticHeader(optimisticHeader)

lightClient.onFinalizedHeader = onFinalizedHeader
lightClient.onOptimisticHeader = onOptimisticHeader
Expand All @@ -86,14 +80,13 @@ proc initLightClient*(
lightClientEnable = config.lightClientEnable,
lightClientTrustedBlockRoot = config.lightClientTrustedBlockRoot

node.lcOptSync = optSync
node.optimisticProcessor = optimisticProcessor
node.lightClient = lightClient

proc startLightClient*(node: BeaconNode) =
if not node.config.lightClientEnable:
return

node.lcOptSync.start()
node.lightClient.start()

proc installLightClientMessageValidators*(node: BeaconNode) =
Expand Down
6 changes: 0 additions & 6 deletions beacon_chain/conf_light_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,6 @@ type LightClientConf* = object
desc: "A file containing the hex-encoded 256 bit secret key to be used for verifying/generating JWT tokens"
name: "jwt-secret" .}: Option[string]

safeSlotsToImportOptimistically* {.
hidden
desc: "Modify SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY"
defaultValue: 128
name: "safe-slots-to-import-optimistically" .}: uint16

# Testing
stopAtEpoch* {.
hidden
Expand Down
Loading

0 comments on commit 9180f09

Please sign in to comment.