From 6b77f3dda5ef92a6ac9399b4b164f035f0239086 Mon Sep 17 00:00:00 2001 From: tersec Date: Wed, 22 Jul 2020 08:04:21 +0000 Subject: [PATCH] update compute_subnet_for_attestation() to use https://github.com/ethereum/eth2.0-specs/pull/1876 signature, which isn't in v0.12.1, which works with lookahead (#1346) --- beacon_chain/attestation_aggregation.nim | 4 ++- beacon_chain/spec/network.nim | 21 +++++++----- beacon_chain/spec/validator.nim | 33 +++++++++++++++---- beacon_chain/validator_api.nim | 5 ++- beacon_chain/validator_duties.nim | 2 +- ncli/ncli_db.nim | 3 +- research/state_sim.nim | 2 +- .../justification_finalization_helpers.nim | 2 +- 8 files changed, 47 insertions(+), 25 deletions(-) diff --git a/beacon_chain/attestation_aggregation.nim b/beacon_chain/attestation_aggregation.nim index d7742b94e..75691b50f 100644 --- a/beacon_chain/attestation_aggregation.nim +++ b/beacon_chain/attestation_aggregation.nim @@ -171,7 +171,9 @@ proc isValidAttestation*( epochInfo = blck.getEpochInfo(state) requiredSubnetIndex = compute_subnet_for_attestation( - epochInfo.shuffled_active_validator_indices.len.uint64, attestation) + get_committee_count_at_slot( + epochInfo.shuffled_active_validator_indices.len.uint64), + attestation.data.slot, attestation.data.index.CommitteeIndex) if requiredSubnetIndex != topicCommitteeIndex: debug "isValidAttestation: attestation's committee index not for the correct subnet", diff --git a/beacon_chain/spec/network.nim b/beacon_chain/spec/network.nim index 302194e54..bb25d7268 100644 --- a/beacon_chain/spec/network.nim +++ b/beacon_chain/spec/network.nim @@ -58,26 +58,27 @@ func getAggregateAndProofsTopic*(forkDigest: ForkDigest): string = raiseAssert e.msg # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/validator.md#broadcast-attestation +# https://github.com/ethereum/eth2.0-specs/pull/1876 func compute_subnet_for_attestation*( - num_active_validators: uint64, attestation: Attestation): uint64 = + committees_per_slot: uint64, slot: Slot, committee_index: CommitteeIndex): + uint64 = # Compute the correct subnet for an attestation for Phase 0. # Note, this mimics expected Phase 1 behavior where attestations will be # mapped to their shard subnet. - # - # The spec version has params (state: BeaconState, attestation: Attestation), - # but it's only to call get_committee_count_at_slot(), which needs only epoch - # and the number of active validators. let - slots_since_epoch_start = attestation.data.slot mod SLOTS_PER_EPOCH + slots_since_epoch_start = slot mod SLOTS_PER_EPOCH committees_since_epoch_start = - get_committee_count_at_slot(num_active_validators) * slots_since_epoch_start + committees_per_slot * slots_since_epoch_start - (committees_since_epoch_start + attestation.data.index) mod ATTESTATION_SUBNET_COUNT + (committees_since_epoch_start + committee_index.uint64) mod + ATTESTATION_SUBNET_COUNT # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/validator.md#broadcast-attestation func getAttestationTopic*(forkDigest: ForkDigest, subnetIndex: uint64): string = # This is for subscribing or broadcasting manually to a known index. + doAssert subnetIndex < ATTESTATION_SUBNET_COUNT + try: &"/eth2/{$forkDigest}/beacon_attestation_{subnetIndex}/ssz" except ValueError as e: @@ -86,4 +87,6 @@ func getAttestationTopic*(forkDigest: ForkDigest, subnetIndex: uint64): func getAttestationTopic*(forkDigest: ForkDigest, attestation: Attestation, num_active_validators: uint64): string = getAttestationTopic( forkDigest, - compute_subnet_for_attestation(num_active_validators, attestation)) + compute_subnet_for_attestation( + get_committee_count_at_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 12a0ecd35..054baa551 100644 --- a/beacon_chain/spec/validator.nim +++ b/beacon_chain/spec/validator.nim @@ -10,7 +10,7 @@ import algorithm, options, sequtils, math, tables, sets, - ./datatypes, ./digest, ./helpers + ./datatypes, ./digest, ./helpers, ./network # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#compute_shuffled_index # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#compute_committee @@ -274,17 +274,14 @@ func get_beacon_proposer_index*(state: BeaconState, cache: var StateCache): # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/validator.md#validator-assignments func get_committee_assignment*( state: BeaconState, epoch: Epoch, - validator_indices: HashSet[ValidatorIndex]): - Option[tuple[a: seq[ValidatorIndex], b: CommitteeIndex, c: Slot]] {.used.} = + validator_index: ValidatorIndex): + Option[tuple[a: seq[ValidatorIndex], b: CommitteeIndex, c: Slot]] = # Return the committee assignment in the ``epoch`` for ``validator_index``. # ``assignment`` returned is a tuple of the following form: # * ``assignment[0]`` is the list of validators in the committee # * ``assignment[1]`` is the index to which the committee is assigned # * ``assignment[2]`` is the slot at which the committee is assigned # Return None if no assignment. - # - # Slightly adapted from spec version to support multiple validator indices, - # since each beacon_node supports many validators. let next_epoch = get_current_epoch(state) + 1 doAssert epoch <= next_epoch @@ -295,10 +292,32 @@ func get_committee_assignment*( for index in 0 ..< get_committee_count_at_slot(state, slot): let idx = index.CommitteeIndex let committee = get_beacon_committee(state, slot, idx, cache) - if not disjoint(validator_indices, toHashSet(committee)): + if validator_index in committee: return some((committee, idx, slot)) none(tuple[a: seq[ValidatorIndex], b: CommitteeIndex, c: Slot]) +func get_committee_assignments*( + state: BeaconState, epoch: Epoch, + validator_indices: HashSet[ValidatorIndex]): + seq[tuple[subnetIndex: uint64, slot: Slot]] = + let next_epoch = get_current_epoch(state) + 1 + doAssert epoch <= next_epoch + + 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) + + for slot in start_slot ..< start_slot + SLOTS_PER_EPOCH: + for index in 0 ..< committee_count_at_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), + slot)) + # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/validator.md#validator-assignments func is_proposer( state: BeaconState, validator_index: ValidatorIndex): bool {.used.} = diff --git a/beacon_chain/validator_api.nim b/beacon_chain/validator_api.nim index 24c8de387..826b41b60 100644 --- a/beacon_chain/validator_api.nim +++ b/beacon_chain/validator_api.nim @@ -7,7 +7,7 @@ import # Standard library - tables, strutils, parseutils, sequtils, sets, + tables, strutils, parseutils, sequtils, # Nimble packages stew/[byteutils, objects], @@ -356,8 +356,7 @@ proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) = let idx = state.validators.asSeq.findIt(it.pubKey == pubkey) if idx == -1: continue - let ca = state.get_committee_assignment( - epoch, toHashSet([idx.ValidatorIndex])) + let ca = state.get_committee_assignment(epoch, idx.ValidatorIndex) if ca.isSome: result.add((public_key: pubkey, committee_index: ca.get.b, diff --git a/beacon_chain/validator_duties.nim b/beacon_chain/validator_duties.nim index 7d5e4979f..e54ea77db 100644 --- a/beacon_chain/validator_duties.nim +++ b/beacon_chain/validator_duties.nim @@ -425,7 +425,7 @@ proc broadcastAggregatedAttestations( proc handleValidatorDuties*( node: BeaconNode, lastSlot, slot: Slot) {.async.} = - ## Perform validator duties - create blocks, vote and aggreagte existing votes + ## Perform validator duties - create blocks, vote and aggregate existing votes var head = node.updateHead() if node.attachedValidators.count == 0: # Nothing to do because we have no validator attached diff --git a/ncli/ncli_db.nim b/ncli/ncli_db.nim index 9f41cb78c..62d414c96 100644 --- a/ncli/ncli_db.nim +++ b/ncli/ncli_db.nim @@ -4,8 +4,7 @@ ../beacon_chain/[beacon_chain_db, block_pool, extras], ../beacon_chain/spec/[crypto, datatypes, digest, helpers, state_transition, validator, presets], - ../beacon_chain/sszdump, ../beacon_chain/ssz/merkleization, - ../research/simutils, + ../beacon_chain/sszdump, ../research/simutils, eth/db/[kvstore, kvstore_sqlite3] type Timers = enum diff --git a/research/state_sim.nim b/research/state_sim.nim index 237521764..0bc1f999f 100644 --- a/research/state_sim.nim +++ b/research/state_sim.nim @@ -151,7 +151,7 @@ cli do(slots = SLOTS_PER_EPOCH * 6, flushFile(stdout) - if (state[].data.slot) mod SLOTS_PER_EPOCH == 0: + if (state[].data.slot).isEpoch: echo &" slot: {shortLog(state[].data.slot)} ", &"epoch: {shortLog(state[].data.slot.compute_epoch_at_slot)}" diff --git a/tests/spec_epoch_processing/justification_finalization_helpers.nim b/tests/spec_epoch_processing/justification_finalization_helpers.nim index 93a0c9d69..45142f710 100644 --- a/tests/spec_epoch_processing/justification_finalization_helpers.nim +++ b/tests/spec_epoch_processing/justification_finalization_helpers.nim @@ -22,7 +22,7 @@ proc addMockAttestations*( sufficient_support = false ) = # We must be at the end of the epoch - doAssert (state.slot + 1) mod SLOTS_PER_EPOCH == 0 + doAssert (state.slot + 1).isEpoch # Alias the attestations container var attestations: ptr seq[PendingAttestation]