From 7de05efaaf3c1bc537aea46481d4b839375882eb Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Wed, 19 Aug 2020 10:03:50 +0200 Subject: [PATCH] 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 --- beacon_chain/block_pools/chain_dag.nim | 3 +- beacon_chain/spec/state_transition_epoch.nim | 67 +++++++++++--------- beacon_chain/spec/validator.nim | 22 +++++-- 3 files changed, 53 insertions(+), 39 deletions(-) diff --git a/beacon_chain/block_pools/chain_dag.nim b/beacon_chain/block_pools/chain_dag.nim index 49a9d8518..02d8a5a26 100644 --- a/beacon_chain/block_pools/chain_dag.nim +++ b/beacon_chain/block_pools/chain_dag.nim @@ -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 = diff --git a/beacon_chain/spec/state_transition_epoch.nim b/beacon_chain/spec/state_transition_epoch.nim index 203c1b19c..a05e27009 100644 --- a/beacon_chain/spec/state_transition_epoch.nim +++ b/beacon_chain/spec/state_transition_epoch.nim @@ -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) diff --git a/beacon_chain/spec/validator.nim b/beacon_chain/spec/validator.nim index 642e1fff0..874cd80af 100644 --- a/beacon_chain/spec/validator.nim +++ b/beacon_chain/spec/validator.nim @@ -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..