seed sync committee state cache (#4592)
By pre-seeding the sync committee cache when applying blocks, we avoid a significantly expensive validator set traversal / sync committee index construction during sync / block application - 20-30% sync speedup post-altair. * also cache/reload total active balance for another cool 10%
This commit is contained in:
parent
171a185e4d
commit
98db005c70
|
@ -271,6 +271,8 @@ type
|
|||
|
||||
shufflingRef*: ShufflingRef
|
||||
|
||||
total_active_balance*: Gwei
|
||||
|
||||
# balances, as used in fork choice
|
||||
effective_balances_bytes*: seq[byte]
|
||||
|
||||
|
|
|
@ -534,6 +534,8 @@ func init*(
|
|||
|
||||
attester_dependent_root = withState(state):
|
||||
forkyState.attester_dependent_root
|
||||
total_active_balance = withState(state):
|
||||
get_total_active_balance(forkyState.data, cache)
|
||||
epochRef = EpochRef(
|
||||
key: dag.epochKey(state.latest_block_id, epoch).expect(
|
||||
"Valid epoch ancestor when processing state"),
|
||||
|
@ -551,7 +553,8 @@ func init*(
|
|||
# beacon_proposers: Separately filled below
|
||||
proposer_dependent_root: proposer_dependent_root,
|
||||
|
||||
shufflingRef: shufflingRef
|
||||
shufflingRef: shufflingRef,
|
||||
total_active_balance: total_active_balance
|
||||
)
|
||||
epochStart = epoch.start_slot()
|
||||
|
||||
|
@ -597,12 +600,28 @@ func loadStateCache(
|
|||
let start_slot = epoch.start_slot()
|
||||
for i, idx in epochRef[][].beacon_proposers:
|
||||
cache.beacon_proposer_indices[start_slot + i] = idx
|
||||
cache.total_active_balance[epoch] = epochRef[][].total_active_balance
|
||||
|
||||
load(epoch)
|
||||
|
||||
if epoch > 0:
|
||||
load(epoch - 1)
|
||||
|
||||
if dag.head != nil: # nil during init.. sigh
|
||||
let period = dag.head.slot.sync_committee_period
|
||||
if period == epoch.sync_committee_period and
|
||||
period notin cache.sync_committees and
|
||||
period > dag.cfg.ALTAIR_FORK_EPOCH.sync_committee_period():
|
||||
# If the block we're aiming for shares ancestry with head, we can reuse
|
||||
# the cached head committee - this accounts for most "live" cases like
|
||||
# syncing and checking blocks since the committees rarely change
|
||||
let periodBsi = dag.atSlot(bid, period.start_slot)
|
||||
if periodBsi.isSome and periodBsi ==
|
||||
dag.atSlot(dag.head.bid, period.start_slot):
|
||||
# We often end up sharing sync committees with head during sync / gossip
|
||||
# validation / head updates
|
||||
cache.sync_committees[period] = dag.headSyncCommittees
|
||||
|
||||
func containsForkBlock*(dag: ChainDAGRef, root: Eth2Digest): bool =
|
||||
## Checks for blocks at the finalized checkpoint or newer
|
||||
KeyedBlockRef.asLookupKey(root) in dag.forkBlocks
|
||||
|
@ -1014,6 +1033,10 @@ proc init*(T: type ChainDAGRef, cfg: RuntimeConfig, db: BeaconChainDB,
|
|||
head = shortLog(head), tail = shortLog(dag.tail)
|
||||
quit 1
|
||||
|
||||
withState(dag.headState):
|
||||
when stateFork >= ConsensusFork.Altair:
|
||||
dag.headSyncCommittees = forkyState.data.get_sync_committee_cache(cache)
|
||||
|
||||
block:
|
||||
# EpochRef needs an epoch boundary state
|
||||
assign(dag.epochRefState, dag.headState)
|
||||
|
@ -1170,10 +1193,6 @@ proc init*(T: type ChainDAGRef, cfg: RuntimeConfig, db: BeaconChainDB,
|
|||
# have a cache
|
||||
dag.updateValidatorKeys(getStateField(dag.headState, validators).asSeq())
|
||||
|
||||
withState(dag.headState):
|
||||
when stateFork >= ConsensusFork.Altair:
|
||||
dag.headSyncCommittees = forkyState.data.get_sync_committee_cache(cache)
|
||||
|
||||
info "Block DAG initialized",
|
||||
head = shortLog(dag.head),
|
||||
finalizedHead = shortLog(dag.finalizedHead),
|
||||
|
|
Loading…
Reference in New Issue