diff --git a/beacon_chain/attestation_aggregation.nim b/beacon_chain/attestation_aggregation.nim index 75691b50f4..5ca38cee8f 100644 --- a/beacon_chain/attestation_aggregation.nim +++ b/beacon_chain/attestation_aggregation.nim @@ -42,13 +42,13 @@ proc aggregate_attestations*( doAssert slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= state.slot doAssert state.slot >= slot + var cache = StateCache() # TODO performance issue for future, via get_active_validator_indices(...) - doAssert index.uint64 < get_committee_count_at_slot(state, slot) + doAssert index.uint64 < get_committee_count_per_slot(state, slot, cache) # TODO for testing purposes, refactor this into the condition check # and just calculation # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/validator.md#aggregation-selection - var cache = StateCache() if not is_aggregator(state, slot, index, slot_signature, cache): return none(AggregateAndProof) @@ -171,8 +171,7 @@ proc isValidAttestation*( epochInfo = blck.getEpochInfo(state) requiredSubnetIndex = compute_subnet_for_attestation( - get_committee_count_at_slot( - epochInfo.shuffled_active_validator_indices.len.uint64), + get_committee_count_per_slot(epochInfo), attestation.data.slot, attestation.data.index.CommitteeIndex) if requiredSubnetIndex != topicCommitteeIndex: diff --git a/beacon_chain/block_pool.nim b/beacon_chain/block_pool.nim index 7477bb3e25..09a5fa6703 100644 --- a/beacon_chain/block_pool.nim +++ b/beacon_chain/block_pool.nim @@ -8,7 +8,7 @@ import extras, beacon_chain_db, stew/results, - spec/[crypto, datatypes, digest, presets] + spec/[crypto, datatypes, digest, helpers, presets] import @@ -212,3 +212,9 @@ proc isValidBeaconBlock*( current_slot: Slot, flags: UpdateFlags): Result[void, BlockError] = isValidBeaconBlock( pool.dag, pool.quarantine, signed_beacon_block, current_slot, flags) + +func count_active_validators*(epochInfo: EpochRef): uint64 = + epochInfo.shuffled_active_validator_indices.len.uint64 + +func get_committee_count_per_slot*(epochInfo: EpochRef): uint64 = + get_committee_count_per_slot(count_active_validators(epochInfo)) diff --git a/beacon_chain/mainchain_monitor.nim b/beacon_chain/mainchain_monitor.nim index dcc65670dd..d382f316eb 100644 --- a/beacon_chain/mainchain_monitor.nim +++ b/beacon_chain/mainchain_monitor.nim @@ -506,8 +506,8 @@ proc createBeaconStateAux(preset: RuntimePreset, eth1Block.voteData.block_hash, eth1Block.timestamp.uint64, deposits, {}) - let activeValidators = count_active_validator_indices(result[], GENESIS_EPOCH) - eth1Block.knownGoodDepositsCount = some activeValidators.uint64 + let activeValidators = count_active_validators(result[], GENESIS_EPOCH, StateCache()) + eth1Block.knownGoodDepositsCount = some activeValidators proc createBeaconState(m: MainchainMonitor, eth1Block: Eth1Block): BeaconStateRef = createBeaconStateAux( diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index eb0c80c6a6..58c07218de 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -115,8 +115,10 @@ func compute_activation_exit_epoch*(epoch: Epoch): Epoch = # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#get_validator_churn_limit func get_validator_churn_limit(state: BeaconState, cache: var StateCache): uint64 = # Return the validator churn limit for the current epoch. - max(MIN_PER_EPOCH_CHURN_LIMIT, - len(cache.shuffled_active_validator_indices).uint64 div CHURN_LIMIT_QUOTIENT) + max( + MIN_PER_EPOCH_CHURN_LIMIT, + count_active_validators( + state, state.get_current_epoch(), cache) div CHURN_LIMIT_QUOTIENT) # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#initiate_validator_exit func initiate_validator_exit*(state: var BeaconState, @@ -588,12 +590,11 @@ proc check_attestation*( attestation = shortLog(attestation) trace "process_attestation: beginning" - let committee_count_at_slot = - get_committee_count_at_slot(get_shuffled_active_validator_indices( - state, state.get_current_epoch(), stateCache).len.uint64).uint64 - if not (data.index < committee_count_at_slot): + let committees_per_slot = + get_committee_count_per_slot(state, data.slot, stateCache) + if not (data.index < committees_per_slot): warn "Data index exceeds committee count", - committee_count = committee_count_at_slot + committee_count = committees_per_slot return if not isValidAttestationTargetEpoch(state.get_current_epoch(), data): diff --git a/beacon_chain/spec/helpers.nim b/beacon_chain/spec/helpers.nim index 7b849e3ad0..9fa8d59ee5 100644 --- a/beacon_chain/spec/helpers.nim +++ b/beacon_chain/spec/helpers.nim @@ -11,7 +11,7 @@ import # Standard lib - math, + std/[math, sequtils, tables], # Third-party stew/endians2, # Internal @@ -57,10 +57,16 @@ func is_active_validator*(validator: Validator, epoch: Epoch): bool = validator.activation_epoch <= epoch and epoch < validator.exit_epoch # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#get_active_validator_indices -func count_active_validator_indices*(state: BeaconState, epoch: Epoch): int = - for val in state.validators: - if is_active_validator(val, epoch): - result += 1 +func count_active_validators*(state: BeaconState, + epoch: Epoch, + cache: StateCache): uint64 = + if epoch in cache.shuffled_active_validator_indices: + try: + cache.shuffled_active_validator_indices[epoch].len.uint64 + except KeyError: + raiseAssert "just checked" + else: + countIt(state.validators, is_active_validator(it, epoch)).uint64 # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#get_active_validator_indices func get_active_validator_indices*(state: BeaconState, epoch: Epoch): @@ -70,13 +76,15 @@ func get_active_validator_indices*(state: BeaconState, epoch: Epoch): if is_active_validator(val, epoch): result.add idx.ValidatorIndex -# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#get_committee_count_at_slot -func get_committee_count_at_slot*(num_active_validators: uint64): uint64 = +# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#get_committee_count_per_slot +func get_committee_count_per_slot*(num_active_validators: uint64): uint64 = clamp( num_active_validators div SLOTS_PER_EPOCH div TARGET_COMMITTEE_SIZE, - 1, MAX_COMMITTEES_PER_SLOT).uint64 + 1'u64, MAX_COMMITTEES_PER_SLOT) -func get_committee_count_at_slot*(state: BeaconState, slot: Slot): uint64 = +func get_committee_count_per_slot*(state: BeaconState, + epoch: Epoch, + cache: StateCache): uint64 = # Return the number of committees at ``slot``. # TODO this is mostly used in for loops which have indexes which then need to @@ -84,12 +92,16 @@ func get_committee_count_at_slot*(state: BeaconState, slot: Slot): uint64 = # with better and more type-safe use pattern, probably beginning with using a # CommitteeIndex return type here. let - epoch = compute_epoch_at_slot(slot) - active_validator_count = count_active_validator_indices(state, epoch) - result = get_committee_count_at_slot(active_validator_count.uint64) + active_validator_count = count_active_validators(state, epoch, cache) + result = get_committee_count_per_slot(active_validator_count) # Otherwise, get_beacon_committee(...) cannot access some committees. - doAssert (SLOTS_PER_EPOCH * MAX_COMMITTEES_PER_SLOT).uint64 >= result + doAssert (SLOTS_PER_EPOCH * MAX_COMMITTEES_PER_SLOT) >= uint64(result) + +func get_committee_count_per_slot*(state: BeaconState, + slot: Slot, + cache: StateCache): uint64 = + get_committee_count_per_slot(state, slot.compute_epoch_at_slot, cache) # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#get_current_epoch func get_current_epoch*(state: BeaconState): Epoch = diff --git a/beacon_chain/spec/network.nim b/beacon_chain/spec/network.nim index bb25d72686..9c14f01916 100644 --- a/beacon_chain/spec/network.nim +++ b/beacon_chain/spec/network.nim @@ -84,9 +84,11 @@ func getAttestationTopic*(forkDigest: ForkDigest, subnetIndex: uint64): except ValueError as e: raiseAssert e.msg -func getAttestationTopic*(forkDigest: ForkDigest, attestation: Attestation, num_active_validators: uint64): string = +func getAttestationTopic*(forkDigest: ForkDigest, + attestation: Attestation, + num_active_validators: uint64): string = getAttestationTopic( forkDigest, compute_subnet_for_attestation( - get_committee_count_at_slot(num_active_validators), + get_committee_count_per_slot(num_active_validators), attestation.data.slot, attestation.data.index.CommitteeIndex)) diff --git a/beacon_chain/spec/validator.nim b/beacon_chain/spec/validator.nim index 054baa5514..099fde8c88 100644 --- a/beacon_chain/spec/validator.nim +++ b/beacon_chain/spec/validator.nim @@ -154,14 +154,14 @@ func get_beacon_committee*( get_shuffled_active_validator_indices(state, epoch) try: - let committee_count = get_committee_count_at_slot( + let committees_per_slot = get_committee_count_per_slot( cache.shuffled_active_validator_indices[epoch].len.uint64) compute_committee( cache.shuffled_active_validator_indices[epoch], get_seed(state, epoch, DOMAIN_BEACON_ATTESTER), - (slot mod SLOTS_PER_EPOCH) * committee_count + + (slot mod SLOTS_PER_EPOCH) * committees_per_slot + index.uint64, - committee_count * SLOTS_PER_EPOCH + committees_per_slot * SLOTS_PER_EPOCH ) except KeyError: raiseAssert "values are added to cache before using them" @@ -289,7 +289,7 @@ func get_committee_assignment*( let start_slot = compute_start_slot_at_epoch(epoch) for slot in start_slot ..< start_slot + SLOTS_PER_EPOCH: - for index in 0 ..< get_committee_count_at_slot(state, slot): + for index in 0'u64 ..< get_committee_count_per_slot(state, slot, cache): let idx = index.CommitteeIndex let committee = get_beacon_committee(state, slot, idx, cache) if validator_index in committee: @@ -306,16 +306,17 @@ func get_committee_assignments*( var cache = StateCache() let start_slot = compute_start_slot_at_epoch(epoch) - # get_committee_count_at_slot is constant throughout an epoch - let committee_count_at_slot = get_committee_count_at_slot(state, start_slot) + # get_committee_count_per_slot is constant throughout an epoch + let committees_per_slot = + get_committee_count_per_slot(state, start_slot, cache) for slot in start_slot ..< start_slot + SLOTS_PER_EPOCH: - for index in 0 ..< committee_count_at_slot: + for index in 0'u64 ..< committees_per_slot: let idx = index.CommitteeIndex if not disjoint(validator_indices, get_beacon_committee(state, slot, idx, cache).toHashSet): result.add( - (compute_subnet_for_attestation(committee_count_at_slot, slot, idx), + (compute_subnet_for_attestation(committees_per_slot, slot, idx), slot)) # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/validator.md#validator-assignments diff --git a/beacon_chain/validator_api.nim b/beacon_chain/validator_api.nim index 12e8b0a73e..468b58a2f6 100644 --- a/beacon_chain/validator_api.nim +++ b/beacon_chain/validator_api.nim @@ -237,7 +237,7 @@ proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) = proc forSlot(slot: Slot, res: var seq[BeaconStatesCommitteesTuple]) = if index == 0: # TODO this means if the parameter is missing (its optional) - let committees_per_slot = get_committee_count_at_slot(state, slot) + let committees_per_slot = get_committee_count_per_slot(state, slot, cache) for committee_index in 0'u64..