Fix race condition in VC block proposal service (#1282)

Closes #918
Closes #923
This commit is contained in:
Michael Sproul
2020-07-07 14:03:21 +10:00
committed by GitHub
parent 5bc8fea2e0
commit 20a48df80a
12 changed files with 329 additions and 179 deletions

View File

@@ -10,9 +10,10 @@ pub type ValidatorDutyBytes = ValidatorDutyBase<PublicKeyBytes>;
/// A validator duty with the pubkey represented as a `PublicKey`.
pub type ValidatorDuty = ValidatorDutyBase<PublicKey>;
// NOTE: if you add or remove fields, please adjust `eq_ignoring_proposal_slots`
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
pub struct ValidatorDutyBase<T> {
/// The validator's BLS public key, uniquely identifying them. _48-bytes, hex encoded with 0x prefix, case insensitive._
/// The validator's BLS public key, uniquely identifying them.
pub validator_pubkey: T,
/// The validator's index in `state.validators`
pub validator_index: Option<u64>,
@@ -25,7 +26,9 @@ pub struct ValidatorDutyBase<T> {
/// The committee count at `attestation_slot`.
pub committee_count_at_slot: Option<u64>,
/// The slots in which a validator must propose a block (can be empty).
pub block_proposal_slots: Vec<Slot>,
///
/// Should be set to `None` when duties are not yet known (before the current epoch).
pub block_proposal_slots: Option<Vec<Slot>>,
/// This provides the modulo: `max(1, len(committee) // TARGET_AGGREGATORS_PER_COMMITTEE)`
/// which allows the validator client to determine if this duty requires the validator to be
/// aggregate attestations.
@@ -49,6 +52,20 @@ impl<T> ValidatorDutyBase<T> {
false
}
}
/// Return `true` if these validator duties are equal, ignoring their `block_proposal_slots`.
pub fn eq_ignoring_proposal_slots(&self, other: &Self) -> bool
where
T: PartialEq,
{
self.validator_pubkey == other.validator_pubkey
&& self.validator_index == other.validator_index
&& self.attestation_slot == other.attestation_slot
&& self.attestation_committee_index == other.attestation_committee_index
&& self.attestation_committee_position == other.attestation_committee_position
&& self.committee_count_at_slot == other.committee_count_at_slot
&& self.aggregator_modulo == other.aggregator_modulo
}
}
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Encode, Decode)]
@@ -74,3 +91,29 @@ pub struct ValidatorSubscription {
/// for this slot.
pub is_aggregator: bool,
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn eq_ignoring_proposal_slots() {
let duty1 = ValidatorDuty {
validator_pubkey: PublicKey::default(),
validator_index: Some(10),
attestation_slot: Some(Slot::new(50)),
attestation_committee_index: Some(2),
attestation_committee_position: Some(6),
committee_count_at_slot: Some(4),
block_proposal_slots: None,
aggregator_modulo: Some(99),
};
let duty2 = ValidatorDuty {
block_proposal_slots: Some(vec![Slot::new(42), Slot::new(45)]),
..duty1.clone()
};
assert_ne!(duty1, duty2);
assert!(duty1.eq_ignoring_proposal_slots(&duty2));
assert!(duty2.eq_ignoring_proposal_slots(&duty1));
}
}