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, slots = state.data.data.slot - startSlot,
stateRoot = shortLog(state.data.root), stateRoot = shortLog(state.data.root),
stateSlot = state.data.data.slot, stateSlot = state.data.data.slot,
stateRoot = shortLog(startRoot), startRoot = shortLog(startRoot),
startSlot,
blck = shortLog(bs) blck = shortLog(bs)
proc loadTailState*(dag: ChainDAGRef): StateData = 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 # 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, 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" 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 state.justification_bits = (state.justification_bits shl 1) and
cast[uint8]((2^JUSTIFICATION_BITS_LENGTH) - 1) 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 = let matching_target_attestations_previous =
get_matching_target_attestations(state, previous_epoch) # Previous epoch get_matching_target_attestations(state, previous_epoch) # Previous epoch
if verifyFinalization in updateFlags: 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 # Non-attesting indices in previous epoch
let missing_all_validators = let missing_all_validators =
difference(active_validator_indices, difference(active_validator_indices,
toHashSet(mapIt(get_attesting_indices(state, get_attesting_indices(
matching_target_attestations_previous, stateCache), it.uint32))) state, matching_target_attestations_previous, cache))
# testnet0 and testnet1 have 8 non-attesting validators each, by default # testnet0 and testnet1 have 8 non-attesting validators each, by default
if missing_all_validators.len > 15: if missing_all_validators.len > 15:
@ -157,42 +156,48 @@ proc process_justification_and_finalization*(state: var BeaconState,
# and # and
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#final-updates # 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. # after which the state.previous_epoch_attestations is replaced.
let total_active_balance = get_total_active_balance(state, 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", trace "Non-attesting indices in previous epoch",
missing_all_validators= missing_all_validators =
difference(active_validator_indices, get_attesting_indices(
state, matching_target_attestations_previous, cache)),
missing_unslashed_validators =
difference(active_validator_indices, difference(active_validator_indices,
toHashSet(mapIt(get_attesting_indices(state, get_unslashed_attesting_indices(
matching_target_attestations_previous, stateCache), it.uint32))), state, matching_target_attestations_previous, cache)),
missing_unslashed_validators= prev_attestations_len = len(state.previous_epoch_attestations),
difference(active_validator_indices, cur_attestations_len = len(state.current_epoch_attestations),
toHashSet(mapIt(get_unslashed_attesting_indices(state, num_active_validators = len(active_validator_indices),
matching_target_attestations_previous, stateCache), it.uint32))), total_active_balance,
prev_attestations_len=len(state.previous_epoch_attestations), attesting_balance_prev = get_attesting_balance(
cur_attestations_len=len(state.current_epoch_attestations), state, matching_target_attestations_previous, cache)
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)
if get_attesting_balance(state, matching_target_attestations_previous, 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 = state.current_justified_checkpoint =
Checkpoint(epoch: previous_epoch, Checkpoint(epoch: previous_epoch,
root: get_block_root(state, previous_epoch)) root: get_block_root(state, previous_epoch))
state.justification_bits.setBit 1 state.justification_bits.setBit 1
debug "Justified with previous epoch", trace "Justified with previous epoch",
current_epoch = current_epoch, current_epoch = current_epoch,
checkpoint = shortLog(state.current_justified_checkpoint) checkpoint = shortLog(state.current_justified_checkpoint)
let matching_target_attestations_current = let matching_target_attestations_current =
get_matching_target_attestations(state, current_epoch) # Current epoch get_matching_target_attestations(state, current_epoch) # Current epoch
if get_attesting_balance(state, matching_target_attestations_current, 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 = state.current_justified_checkpoint =
Checkpoint(epoch: current_epoch, Checkpoint(epoch: current_epoch,
root: get_block_root(state, current_epoch)) root: get_block_root(state, current_epoch))
state.justification_bits.setBit 0 state.justification_bits.setBit 0
debug "Justified with current epoch", trace "Justified with current epoch",
current_epoch = current_epoch, current_epoch = current_epoch,
checkpoint = shortLog(state.current_justified_checkpoint) 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: old_previous_justified_checkpoint.epoch + 3 == current_epoch:
state.finalized_checkpoint = old_previous_justified_checkpoint state.finalized_checkpoint = old_previous_justified_checkpoint
debug "Finalized with rule 234", trace "Finalized with rule 234",
current_epoch = current_epoch, current_epoch = current_epoch,
checkpoint = shortLog(state.finalized_checkpoint) 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: old_previous_justified_checkpoint.epoch + 2 == current_epoch:
state.finalized_checkpoint = old_previous_justified_checkpoint state.finalized_checkpoint = old_previous_justified_checkpoint
debug "Finalized with rule 23", trace "Finalized with rule 23",
current_epoch = current_epoch, current_epoch = current_epoch,
checkpoint = shortLog(state.finalized_checkpoint) 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: old_current_justified_checkpoint.epoch + 2 == current_epoch:
state.finalized_checkpoint = old_current_justified_checkpoint state.finalized_checkpoint = old_current_justified_checkpoint
debug "Finalized with rule 123", trace "Finalized with rule 123",
current_epoch = current_epoch, current_epoch = current_epoch,
checkpoint = shortLog(state.finalized_checkpoint) 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: old_current_justified_checkpoint.epoch + 1 == current_epoch:
state.finalized_checkpoint = old_current_justified_checkpoint state.finalized_checkpoint = old_current_justified_checkpoint
debug "Finalized with rule 12", trace "Finalized with rule 12",
current_epoch = current_epoch, current_epoch = current_epoch,
checkpoint = shortLog(state.finalized_checkpoint) checkpoint = shortLog(state.finalized_checkpoint)

View File

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