optimize epoch registry processing (#5412)

This commit is contained in:
tersec 2023-09-11 09:21:50 +00:00 committed by GitHub
parent cc13e0b7e0
commit 10ec7be686
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 19 deletions

View File

@ -669,12 +669,14 @@ template `[]`*[T](a: seq[T], b: ValidatorIndex): auto = # Also var seq (!)
iterator vindices*( iterator vindices*(
a: HashList[Validator, Limit VALIDATOR_REGISTRY_LIMIT]): ValidatorIndex = a: HashList[Validator, Limit VALIDATOR_REGISTRY_LIMIT]): ValidatorIndex =
for i in 0..<a.len(): static: doAssert distinctBase(ValidatorIndex) is uint32
for i in 0..<a.len.uint32:
yield i.ValidatorIndex yield i.ValidatorIndex
iterator vindices*( iterator vindices*(
a: List[Validator, Limit VALIDATOR_REGISTRY_LIMIT]): ValidatorIndex = a: List[Validator, Limit VALIDATOR_REGISTRY_LIMIT]): ValidatorIndex =
for i in 0..<a.len(): static: doAssert distinctBase(ValidatorIndex) is uint32
for i in 0..<a.len.uint32:
yield i.ValidatorIndex yield i.ValidatorIndex
template `==`*(x, y: JustificationBits): bool = template `==`*(x, y: JustificationBits): bool =

View File

@ -27,7 +27,6 @@ import
../extras, ../extras,
"."/[beaconstate, eth2_merkleization, validator] "."/[beaconstate, eth2_merkleization, validator]
from std/algorithm import sort
from std/math import sum, `^` from std/math import sum, `^`
from ./datatypes/capella import from ./datatypes/capella import
BeaconState, HistoricalSummary, Withdrawal, WithdrawalIndex BeaconState, HistoricalSummary, Withdrawal, WithdrawalIndex
@ -811,7 +810,9 @@ func process_rewards_and_penalties*(
decrease_balance(balance, info.validators[vidx].delta.penalties) decrease_balance(balance, info.validators[vidx].delta.penalties)
state.balances.asSeq()[vidx] = balance state.balances.asSeq()[vidx] = balance
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/beacon-chain.md#registry-updates from std/heapqueue import HeapQueue, `[]`, len, push, replace
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/phase0/beacon-chain.md#registry-updates
func process_registry_updates*( func process_registry_updates*(
cfg: RuntimeConfig, state: var ForkyBeaconState, cache: var StateCache): cfg: RuntimeConfig, state: var ForkyBeaconState, cache: var StateCache):
Result[void, cstring] = Result[void, cstring] =
@ -832,6 +833,13 @@ func process_registry_updates*(
# the current epoch, 1 + MAX_SEED_LOOKAHEAD epochs ahead. Thus caches # the current epoch, 1 + MAX_SEED_LOOKAHEAD epochs ahead. Thus caches
# remain valid for this epoch through though this function along with # remain valid for this epoch through though this function along with
# the rest of the epoch transition. # the rest of the epoch transition.
#
# This implementation fuses the two loops over all validators in the
# spec code.
## Queue validators eligible for activation and not dequeued for activation
var activation_queue: HeapQueue[(uint64, uint32)]
let churn_limit = get_validator_churn_limit(cfg, state, cache)
for vidx in state.validators.vindices: for vidx in state.validators.vindices:
if is_eligible_for_activation_queue(state.validators.item(vidx)): if is_eligible_for_activation_queue(state.validators.item(vidx)):
state.validators.mitem(vidx).activation_eligibility_epoch = state.validators.mitem(vidx).activation_eligibility_epoch =
@ -841,25 +849,23 @@ func process_registry_updates*(
state.validators.item(vidx).effective_balance <= cfg.EJECTION_BALANCE: state.validators.item(vidx).effective_balance <= cfg.EJECTION_BALANCE:
? initiate_validator_exit(cfg, state, vidx, cache) ? initiate_validator_exit(cfg, state, vidx, cache)
## Queue validators eligible for activation and not dequeued for activation
var activation_queue : seq[tuple[a: Epoch, b: ValidatorIndex]] = @[]
for vidx in state.validators.vindices:
let validator = unsafeAddr state.validators.item(vidx) let validator = unsafeAddr state.validators.item(vidx)
if is_eligible_for_activation(state, validator[]): if is_eligible_for_activation(state, validator[]):
activation_queue.add ( let val_key =
validator[].activation_eligibility_epoch, vidx) (FAR_FUTURE_EPOCH - validator[].activation_eligibility_epoch,
high(distinctBase(ValidatorIndex)) - distinctBase(vidx))
activation_queue.sort(system.cmp) if activation_queue.len.uint64 < churn_limit:
activation_queue.push val_key
elif val_key > activation_queue[0]:
discard activation_queue.replace val_key
## Dequeued validators for activation up to churn limit (without resetting ## Dequeued validators for activation up to churn limit (without resetting
## activation epoch) ## activation epoch)
let churn_limit = get_validator_churn_limit(cfg, state, cache) doAssert activation_queue.len.uint64 <= churn_limit
for i, epoch_and_index in activation_queue: for i in 0 ..< activation_queue.len:
if i.uint64 >= churn_limit: let (_, vidx_complement) = activation_queue[i]
break state.validators.mitem(
let high(distinctBase(ValidatorIndex)) - vidx_complement).activation_epoch =
(_, vidx) = epoch_and_index
state.validators.mitem(vidx).activation_epoch =
compute_activation_exit_epoch(get_current_epoch(state)) compute_activation_exit_epoch(get_current_epoch(state))
ok() ok()