small perf fixes

* don't sort shuffled_validator_indices, just get them directly with
iteration
* grab full epoch of proposer indices while we have the data available -
they'll get cached and reused
* avoid computing active validator set when not used for logging
This commit is contained in:
Jacek Sieka 2020-08-19 10:03:50 +02:00 committed by zah
parent 2c19e3f8cd
commit 7de05efaaf
3 changed files with 53 additions and 39 deletions

View File

@ -658,7 +658,8 @@ proc updateStateData*(
slots = state.data.data.slot - startSlot,
stateRoot = shortLog(state.data.root),
stateSlot = state.data.data.slot,
stateRoot = shortLog(startRoot),
startRoot = shortLog(startRoot),
startSlot,
blck = shortLog(bs)
proc loadTailState*(dag: ChainDAGRef): StateData =

View File

@ -101,7 +101,7 @@ func get_attesting_balance(
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#justification-and-finalization
proc process_justification_and_finalization*(state: var BeaconState,
stateCache: var StateCache, updateFlags: UpdateFlags = {}) {.nbench.} =
cache: var StateCache, updateFlags: UpdateFlags = {}) {.nbench.} =
logScope: pcs = "process_justification_and_finalization"
@ -126,20 +126,19 @@ proc process_justification_and_finalization*(state: var BeaconState,
state.justification_bits = (state.justification_bits shl 1) and
cast[uint8]((2^JUSTIFICATION_BITS_LENGTH) - 1)
# This is a somewhat expensive approach
let active_validator_indices {.used.} =
toHashSet(mapIt(
get_active_validator_indices(state, get_current_epoch(state)), it.uint32))
let matching_target_attestations_previous =
get_matching_target_attestations(state, previous_epoch) # Previous epoch
if verifyFinalization in updateFlags:
let active_validator_indices =
toHashSet(cache.get_shuffled_active_validator_indices(
state, get_current_epoch(state)))
# Non-attesting indices in previous epoch
let missing_all_validators =
difference(active_validator_indices,
toHashSet(mapIt(get_attesting_indices(state,
matching_target_attestations_previous, stateCache), it.uint32)))
get_attesting_indices(
state, matching_target_attestations_previous, cache))
# testnet0 and testnet1 have 8 non-attesting validators each, by default
if missing_all_validators.len > 15:
@ -157,42 +156,48 @@ proc process_justification_and_finalization*(state: var BeaconState,
# and
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#final-updates
# after which the state.previous_epoch_attestations is replaced.
let total_active_balance = get_total_active_balance(state, stateCache)
trace "Non-attesting indices in previous epoch",
missing_all_validators=
difference(active_validator_indices,
toHashSet(mapIt(get_attesting_indices(state,
matching_target_attestations_previous, stateCache), it.uint32))),
missing_unslashed_validators=
difference(active_validator_indices,
toHashSet(mapIt(get_unslashed_attesting_indices(state,
matching_target_attestations_previous, stateCache), it.uint32))),
prev_attestations_len=len(state.previous_epoch_attestations),
cur_attestations_len=len(state.current_epoch_attestations),
num_active_validators=len(active_validator_indices),
required_balance = total_active_balance * 2,
attesting_balance_prev = get_attesting_balance(state, matching_target_attestations_previous, stateCache)
let total_active_balance = get_total_active_balance(state, cache)
when chronicles.enabledLogLevel == LogLevel.TRACE:
let active_validator_indices =
toHashSet(cache.get_shuffled_active_validator_indices(
state, get_current_epoch(state)))
trace "Non-attesting indices in previous epoch",
missing_all_validators =
difference(active_validator_indices, get_attesting_indices(
state, matching_target_attestations_previous, cache)),
missing_unslashed_validators =
difference(active_validator_indices,
get_unslashed_attesting_indices(
state, matching_target_attestations_previous, cache)),
prev_attestations_len = len(state.previous_epoch_attestations),
cur_attestations_len = len(state.current_epoch_attestations),
num_active_validators = len(active_validator_indices),
total_active_balance,
attesting_balance_prev = get_attesting_balance(
state, matching_target_attestations_previous, cache)
if get_attesting_balance(state, matching_target_attestations_previous,
stateCache) * 3 >= total_active_balance * 2:
cache) * 3 >= total_active_balance * 2:
state.current_justified_checkpoint =
Checkpoint(epoch: previous_epoch,
root: get_block_root(state, previous_epoch))
state.justification_bits.setBit 1
debug "Justified with previous epoch",
trace "Justified with previous epoch",
current_epoch = current_epoch,
checkpoint = shortLog(state.current_justified_checkpoint)
let matching_target_attestations_current =
get_matching_target_attestations(state, current_epoch) # Current epoch
if get_attesting_balance(state, matching_target_attestations_current,
stateCache) * 3 >= total_active_balance * 2:
cache) * 3 >= total_active_balance * 2:
state.current_justified_checkpoint =
Checkpoint(epoch: current_epoch,
root: get_block_root(state, current_epoch))
state.justification_bits.setBit 0
debug "Justified with current epoch",
trace "Justified with current epoch",
current_epoch = current_epoch,
checkpoint = shortLog(state.current_justified_checkpoint)
@ -205,7 +210,7 @@ proc process_justification_and_finalization*(state: var BeaconState,
old_previous_justified_checkpoint.epoch + 3 == current_epoch:
state.finalized_checkpoint = old_previous_justified_checkpoint
debug "Finalized with rule 234",
trace "Finalized with rule 234",
current_epoch = current_epoch,
checkpoint = shortLog(state.finalized_checkpoint)
@ -215,7 +220,7 @@ proc process_justification_and_finalization*(state: var BeaconState,
old_previous_justified_checkpoint.epoch + 2 == current_epoch:
state.finalized_checkpoint = old_previous_justified_checkpoint
debug "Finalized with rule 23",
trace "Finalized with rule 23",
current_epoch = current_epoch,
checkpoint = shortLog(state.finalized_checkpoint)
@ -225,7 +230,7 @@ proc process_justification_and_finalization*(state: var BeaconState,
old_current_justified_checkpoint.epoch + 2 == current_epoch:
state.finalized_checkpoint = old_current_justified_checkpoint
debug "Finalized with rule 123",
trace "Finalized with rule 123",
current_epoch = current_epoch,
checkpoint = shortLog(state.finalized_checkpoint)
@ -235,7 +240,7 @@ proc process_justification_and_finalization*(state: var BeaconState,
old_current_justified_checkpoint.epoch + 1 == current_epoch:
state.finalized_checkpoint = old_current_justified_checkpoint
debug "Finalized with rule 12",
trace "Finalized with rule 12",
current_epoch = current_epoch,
checkpoint = shortLog(state.finalized_checkpoint)

View File

@ -9,7 +9,7 @@
{.push raises: [Defect].}
import
algorithm, options, sequtils, math, tables,
options, sequtils, math, tables,
./datatypes, ./digest, ./helpers
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#compute_shuffled_index
@ -296,17 +296,25 @@ func get_beacon_proposer_index*(state: BeaconState, cache: var StateCache, slot:
var buffer: array[32 + 8, byte]
buffer[0..31] = get_seed(state, epoch, DOMAIN_BEACON_PROPOSER).data
buffer[32..39] = uint_to_bytes8(slot.uint64)
# There's exactly one beacon proposer per slot.
let
seed = eth2digest(buffer)
indices =
sorted(cache.get_shuffled_active_validator_indices(state, epoch), system.cmp)
# active validator indices are kept in cache but sorting them takes
# quite a while
indices = get_active_validator_indices(state, epoch)
start = slot.epoch().compute_start_slot_at_epoch()
return cache.beacon_proposer_indices.mgetOrPut(
slot, compute_proposer_index(state, indices, seed))
var res: Option[ValidatorIndex]
for i in 0..<SLOTS_PER_EPOCH:
buffer[32..39] = uint_to_bytes8((start + i).uint64)
let seed = eth2digest(buffer)
let pi = compute_proposer_index(state, indices, seed)
if start + i == slot:
res = pi
cache.beacon_proposer_indices[start + i] = pi
return res
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#get_beacon_proposer_index
func get_beacon_proposer_index*(state: BeaconState, cache: var StateCache):