use epochcache for attesting (#1478)

This commit is contained in:
Jacek Sieka 2020-08-10 15:21:31 +02:00 committed by GitHub
parent 280e72f3c9
commit 2a36949913
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 30 deletions

View File

@ -12,7 +12,7 @@ import
beaconstate, crypto, datatypes, digest, helpers, presets, signatures,
validator],
../extras,
./block_pools_types
./block_pools_types, ./chain_dag
# Spec functions implemented based on cached values instead of the full state
func count_active_validators*(epochInfo: EpochRef): uint64 =
@ -122,3 +122,31 @@ proc is_valid_indexed_attestation*(
return false
true
func makeAttestationData*(
epochRef: EpochRef, bs: BlockSlot,
committee_index: uint64): AttestationData =
## Create an attestation / vote for the block `bs` using the
## data in `epochRef` to fill in the rest of the fields.
## `epochRef` is the epoch information corresponding to the `bs` advanced to
## the slot we're attesting to.
let
slot = bs.slot
current_epoch = slot.compute_epoch_at_slot()
epoch_boundary_slot = compute_start_slot_at_epoch(current_epoch)
epoch_boundary_block = bs.blck.atSlot(epoch_boundary_slot)
doAssert current_epoch == epochRef.epoch
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/validator.md#attestation-data
AttestationData(
slot: slot,
index: committee_index,
beacon_block_root: bs.blck.root,
source: epochRef.current_justified_checkpoint,
target: Checkpoint(
epoch: current_epoch,
root: epoch_boundary_block.blck.root
)
)

View File

@ -18,7 +18,7 @@ import
eth/[keys, async_utils], eth/p2p/discoveryv5/[protocol, enr],
# Local modules
spec/[datatypes, digest, crypto, beaconstate, helpers, validator, network],
spec/[datatypes, digest, crypto, helpers, validator, network],
spec/state_transition,
conf, time, validator_pool,
attestation_pool, block_pools/[spec_cache, chain_dag, clearance],
@ -60,11 +60,29 @@ proc addLocalValidators*(node: BeaconNode) =
info "Local validators attached ", count = node.attachedValidators.count
proc getAttachedValidator*(node: BeaconNode,
pubkey: ValidatorPubKey): AttachedValidator =
node.attachedValidators.getValidator(pubkey)
proc getAttachedValidator*(node: BeaconNode,
state: BeaconState,
idx: ValidatorIndex): AttachedValidator =
let validatorKey = state.validators[idx].pubkey.initPubKey
node.attachedValidators.getValidator(validatorKey)
if idx < state.validators.len.ValidatorIndex:
node.getAttachedValidator(state.validators[idx].pubkey)
else:
warn "Validator index out of bounds",
idx, stateSlot = state.slot, validators = state.validators.len
nil
proc getAttachedValidator*(node: BeaconNode,
epochRef: EpochRef,
idx: ValidatorIndex): AttachedValidator =
if idx < epochRef.validator_keys.len.ValidatorIndex:
node.getAttachedValidator(epochRef.validator_keys[idx])
else:
warn "Validator index out of bounds",
idx, epoch = epochRef.epoch, validators = epochRef.validator_keys.len
nil
proc isSynced*(node: BeaconNode, head: BlockRef): bool =
## TODO This function is here as a placeholder for some better heurestics to
@ -318,31 +336,29 @@ proc handleAttestations(node: BeaconNode, head: BlockRef, slot: Slot) =
# In case blocks went missing, this means advancing past the latest block
# using empty slots as fillers.
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/validator.md#validator-assignments
# TODO we could cache the validator assignment since it's valid for the entire
# epoch since it doesn't change, but that has to be weighed against
# the complexity of handling forks correctly - instead, we use an adapted
# version here that calculates the committee for a single slot only
node.chainDag.withState(node.chainDag.tmpState, attestationHead):
var cache = getEpochCache(attestationHead.blck, state)
let
epochRef = node.chainDag.getEpochRef(
attestationHead.blck, slot.compute_epoch_at_slot())
committees_per_slot =
get_committee_count_per_slot(state, slot.epoch, cache)
num_active_validators =
count_active_validators(state, slot.compute_epoch_at_slot, cache)
get_committee_count_per_slot(epochRef)
num_active_validators = count_active_validators(epochRef)
fork = node.chainDag.headState.data.data.fork
genesis_validators_root =
node.chainDag.headState.data.data.genesis_validators_root
for committee_index in 0'u64..<committees_per_slot:
let committee = get_beacon_committee(
state, slot, committee_index.CommitteeIndex, cache)
epochRef, slot, committee_index.CommitteeIndex)
for index_in_committee, validatorIdx in committee:
let validator = node.getAttachedValidator(state, validatorIdx)
let validator = node.getAttachedValidator(epochRef, validatorIdx)
if validator != nil:
let ad = makeAttestationData(state, slot, committee_index, blck.root)
let ad = makeAttestationData(epochRef, attestationHead, committee_index)
attestations.add((ad, committee.len, index_in_committee, validator))
for a in attestations:
traceAsyncErrors createAndSendAttestation(
node, state.fork, state.genesis_validators_root, a.validator, a.data,
node, fork, genesis_validators_root, a.validator, a.data,
a.committeeLen, a.indexInCommittee, num_active_validators)
proc handleProposal(node: BeaconNode, head: BlockRef, slot: Slot):
@ -359,7 +375,7 @@ proc handleProposal(node: BeaconNode, head: BlockRef, slot: Slot):
return head
let validator =
node.attachedValidators.getValidator(proposer.get()[1].initPubKey())
node.attachedValidators.getValidator(proposer.get()[1])
if validator != nil:
return await proposeBlock(node, validator, proposer.get()[0], head, slot)

View File

@ -20,9 +20,9 @@ proc addLocalValidator*(pool: var ValidatorPool,
info "Local validator attached", pubKey, validator = shortLog(v)
func getValidator*(pool: ValidatorPool,
proc getValidator*(pool: ValidatorPool,
validatorKey: ValidatorPubKey): AttachedValidator =
pool.validators.getOrDefault(validatorKey)
pool.validators.getOrDefault(validatorKey.initPubKey)
# TODO: Honest validator - https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/validator.md
proc signBlockProposal*(v: AttachedValidator, fork: Fork,