2019-03-06 07:57:41 +00:00
|
|
|
use super::errors::WinningRootError;
|
|
|
|
use std::collections::HashMap;
|
2019-03-06 06:14:54 +00:00
|
|
|
use types::*;
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct WinningRoot {
|
2019-03-06 07:57:41 +00:00
|
|
|
pub crosslink_data_root: Hash256,
|
2019-03-06 06:14:54 +00:00
|
|
|
pub attesting_validator_indices: Vec<usize>,
|
|
|
|
pub total_balance: u64,
|
|
|
|
pub total_attesting_balance: u64,
|
|
|
|
}
|
|
|
|
|
2019-03-06 07:57:41 +00:00
|
|
|
pub fn winning_root(
|
2019-03-06 06:14:54 +00:00
|
|
|
state: &BeaconState,
|
|
|
|
shard: u64,
|
|
|
|
current_epoch_attestations: &[&PendingAttestation],
|
|
|
|
previous_epoch_attestations: &[&PendingAttestation],
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<WinningRoot, WinningRootError> {
|
|
|
|
let mut attestations = current_epoch_attestations.to_vec();
|
|
|
|
attestations.append(&mut previous_epoch_attestations.to_vec());
|
|
|
|
|
|
|
|
let mut candidates: HashMap<Hash256, WinningRoot> = HashMap::new();
|
|
|
|
|
|
|
|
let mut highest_seen_balance = 0;
|
|
|
|
|
|
|
|
for a in &attestations {
|
|
|
|
if a.data.shard != shard {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-03-06 07:57:41 +00:00
|
|
|
let crosslink_data_root = &a.data.crosslink_data_root;
|
2019-03-06 06:14:54 +00:00
|
|
|
|
2019-03-06 07:57:41 +00:00
|
|
|
if candidates.contains_key(crosslink_data_root) {
|
2019-03-06 06:14:54 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let attesting_validator_indices = attestations
|
|
|
|
.iter()
|
|
|
|
.try_fold::<_, _, Result<_, BeaconStateError>>(vec![], |mut acc, a| {
|
2019-03-06 07:57:41 +00:00
|
|
|
if (a.data.shard == shard) && (a.data.crosslink_data_root == *crosslink_data_root) {
|
2019-03-06 06:14:54 +00:00
|
|
|
acc.append(&mut state.get_attestation_participants(
|
|
|
|
&a.data,
|
|
|
|
&a.aggregation_bitfield,
|
|
|
|
spec,
|
|
|
|
)?);
|
|
|
|
}
|
|
|
|
Ok(acc)
|
|
|
|
})?;
|
|
|
|
|
|
|
|
let total_balance: u64 = attesting_validator_indices
|
|
|
|
.iter()
|
|
|
|
.fold(0, |acc, i| acc + state.get_effective_balance(*i, spec));
|
|
|
|
|
|
|
|
let total_attesting_balance: u64 = attesting_validator_indices
|
|
|
|
.iter()
|
|
|
|
.fold(0, |acc, i| acc + state.get_effective_balance(*i, spec));
|
|
|
|
|
|
|
|
if total_attesting_balance > highest_seen_balance {
|
|
|
|
highest_seen_balance = total_attesting_balance;
|
|
|
|
}
|
|
|
|
|
|
|
|
let candidate_root = WinningRoot {
|
2019-03-06 07:57:41 +00:00
|
|
|
crosslink_data_root: *crosslink_data_root,
|
2019-03-06 06:14:54 +00:00
|
|
|
attesting_validator_indices,
|
|
|
|
total_attesting_balance,
|
|
|
|
total_balance,
|
|
|
|
};
|
|
|
|
|
2019-03-06 07:57:41 +00:00
|
|
|
candidates.insert(*crosslink_data_root, candidate_root);
|
2019-03-06 06:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(candidates
|
|
|
|
.iter()
|
|
|
|
.filter_map(|(_hash, candidate)| {
|
|
|
|
if candidate.total_attesting_balance == highest_seen_balance {
|
|
|
|
Some(candidate)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
2019-03-06 07:57:41 +00:00
|
|
|
.min_by_key(|candidate| candidate.crosslink_data_root)
|
2019-03-06 06:14:54 +00:00
|
|
|
.ok_or_else(|| WinningRootError::NoWinningRoot)?
|
|
|
|
// TODO: avoid clone.
|
|
|
|
.clone())
|
|
|
|
}
|