parent
a0549e3842
commit
5e8f958977
@ -28,8 +28,8 @@ pub struct ValidatorDuty {
|
|||||||
pub attestation_committee_index: Option<CommitteeIndex>,
|
pub attestation_committee_index: Option<CommitteeIndex>,
|
||||||
/// The position of the validator in the committee.
|
/// The position of the validator in the committee.
|
||||||
pub attestation_committee_position: Option<usize>,
|
pub attestation_committee_position: Option<usize>,
|
||||||
/// The slot in which a validator must propose a block, or `null` if block production is not required.
|
/// The slots in which a validator must propose a block (can be empty).
|
||||||
pub block_proposal_slot: Option<Slot>,
|
pub block_proposal_slots: Vec<Slot>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Encode, Decode)]
|
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Encode, Decode)]
|
||||||
@ -161,17 +161,18 @@ fn return_validator_duties<T: BeaconChainTypes>(
|
|||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let block_proposal_slot = validator_proposers
|
let block_proposal_slots = validator_proposers
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(i, _slot)| validator_index == *i)
|
.filter(|(i, _slot)| validator_index == *i)
|
||||||
.map(|(_i, slot)| *slot);
|
.map(|(_i, slot)| *slot)
|
||||||
|
.collect();
|
||||||
|
|
||||||
Ok(ValidatorDuty {
|
Ok(ValidatorDuty {
|
||||||
validator_pubkey,
|
validator_pubkey,
|
||||||
attestation_slot: duties.map(|d| d.slot),
|
attestation_slot: duties.map(|d| d.slot),
|
||||||
attestation_committee_index: duties.map(|d| d.index),
|
attestation_committee_index: duties.map(|d| d.index),
|
||||||
attestation_committee_position: duties.map(|d| d.committee_position),
|
attestation_committee_position: duties.map(|d| d.committee_position),
|
||||||
block_proposal_slot,
|
block_proposal_slots,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Ok(ValidatorDuty {
|
Ok(ValidatorDuty {
|
||||||
@ -179,7 +180,7 @@ fn return_validator_duties<T: BeaconChainTypes>(
|
|||||||
attestation_slot: None,
|
attestation_slot: None,
|
||||||
attestation_committee_index: None,
|
attestation_committee_index: None,
|
||||||
attestation_committee_position: None,
|
attestation_committee_position: None,
|
||||||
block_proposal_slot: None,
|
block_proposal_slots: vec![],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -294,14 +294,16 @@ fn check_duties<T: BeaconChainTypes>(
|
|||||||
"attestation index should match"
|
"attestation index should match"
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(slot) = duty.block_proposal_slot {
|
if !duty.block_proposal_slots.is_empty() {
|
||||||
let expected_proposer = state
|
for slot in &duty.block_proposal_slots {
|
||||||
.get_beacon_proposer_index(slot, spec)
|
let expected_proposer = state
|
||||||
.expect("should know proposer");
|
.get_beacon_proposer_index(*slot, spec)
|
||||||
assert_eq!(
|
.expect("should know proposer");
|
||||||
expected_proposer, validator_index,
|
assert_eq!(
|
||||||
"should get correct proposal slot"
|
expected_proposer, validator_index,
|
||||||
);
|
"should get correct proposal slot"
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
epoch.slot_iter(E::slots_per_epoch()).for_each(|slot| {
|
epoch.slot_iter(E::slots_per_epoch()).for_each(|slot| {
|
||||||
let slot_proposer = state
|
let slot_proposer = state
|
||||||
@ -314,6 +316,16 @@ fn check_duties<T: BeaconChainTypes>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Validator duties should include a proposer for every slot of the epoch.
|
||||||
|
let mut all_proposer_slots: Vec<Slot> = duties
|
||||||
|
.iter()
|
||||||
|
.flat_map(|duty| duty.block_proposal_slots.clone())
|
||||||
|
.collect();
|
||||||
|
all_proposer_slots.sort();
|
||||||
|
|
||||||
|
let all_slots: Vec<Slot> = epoch.slot_iter(E::slots_per_epoch()).collect();
|
||||||
|
assert_eq!(all_proposer_slots, all_slots);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -52,7 +52,7 @@ impl DutiesStore {
|
|||||||
let epoch = slot.epoch(slots_per_epoch);
|
let epoch = slot.epoch(slots_per_epoch);
|
||||||
|
|
||||||
validator_map.get(&epoch).and_then(|duties| {
|
validator_map.get(&epoch).and_then(|duties| {
|
||||||
if duties.block_proposal_slot == Some(slot) {
|
if duties.block_proposal_slots.contains(&slot) {
|
||||||
Some(duties.validator_pubkey.clone())
|
Some(duties.validator_pubkey.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -363,7 +363,7 @@ impl<T: SlotClock + 'static, E: EthSpec> DutiesService<T, E> {
|
|||||||
info!(
|
info!(
|
||||||
log,
|
log,
|
||||||
"First duty assignment for validator";
|
"First duty assignment for validator";
|
||||||
"proposal_slot" => format!("{:?}", &duties.block_proposal_slot),
|
"proposal_slots" => format!("{:?}", &duties.block_proposal_slots),
|
||||||
"attestation_slot" => format!("{:?}", &duties.attestation_slot),
|
"attestation_slot" => format!("{:?}", &duties.attestation_slot),
|
||||||
"validator" => format!("{:?}", &duties.validator_pubkey)
|
"validator" => format!("{:?}", &duties.validator_pubkey)
|
||||||
);
|
);
|
||||||
@ -408,17 +408,11 @@ impl<T: SlotClock + 'static, E: EthSpec> DutiesService<T, E> {
|
|||||||
|
|
||||||
/// Returns `true` if the slots in the `duties` are from the given `epoch`
|
/// Returns `true` if the slots in the `duties` are from the given `epoch`
|
||||||
fn duties_match_epoch(duties: &ValidatorDuty, epoch: Epoch, slots_per_epoch: u64) -> bool {
|
fn duties_match_epoch(duties: &ValidatorDuty, epoch: Epoch, slots_per_epoch: u64) -> bool {
|
||||||
if let Some(attestation_slot) = duties.attestation_slot {
|
duties
|
||||||
if attestation_slot.epoch(slots_per_epoch) != epoch {
|
.attestation_slot
|
||||||
return false;
|
.map_or(true, |slot| slot.epoch(slots_per_epoch) == epoch)
|
||||||
}
|
&& duties
|
||||||
}
|
.block_proposal_slots
|
||||||
|
.iter()
|
||||||
if let Some(block_proposal_slot) = duties.block_proposal_slot {
|
.all(|slot| slot.epoch(slots_per_epoch) == epoch)
|
||||||
if block_proposal_slot.epoch(slots_per_epoch) != epoch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user