-
-
Save erwanor/23a73454f1ee6f703af90d6c778ad1d2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Materializes the entire current validator set as a Tendermint update. | |
/// | |
/// This re-defines all validators every time, to simplify the code compared to | |
/// trying to track delta updates. | |
#[instrument(skip(self))] | |
async fn build_tendermint_validator_updates(&mut self) -> Result<()> { | |
let current_consensus_keys: CurrentConsensusKeys = self | |
.get(state_key::current_consensus_keys()) | |
.await? | |
.expect("current consensus keys must be present"); | |
let current_consensus_keys = current_consensus_keys | |
.consensus_keys | |
.into_iter() | |
.collect::<BTreeSet<_>>(); | |
let mut voting_power_by_consensus_key = BTreeMap::<PublicKey, u64>::new(); | |
// First, build a mapping of consensus key to voting power for all known validators. | |
// Using a JoinSet, run each validator's state queries concurrently. | |
let mut js = JoinSet::new(); | |
for v in self.validator_identity_list().await?.iter() { | |
let state = self.validator_state(v); | |
let power = self.validator_power(v); | |
let consensus_key = self.validator_consensus_key(v); | |
js.spawn(async move { | |
let state = state | |
.await? | |
.expect("every known validator must have a recorded state"); | |
// Compute the effective power of this validator; this is the | |
// validator power, clamped to zero for all non-Active validators. | |
let effective_power = if state == validator::State::Active { | |
power | |
.await? | |
.expect("every known validator must have a recorded power") | |
} else { | |
0 | |
}; | |
let consensus_key = consensus_key | |
.await? | |
.expect("every known validator must have a recorded consensus key"); | |
anyhow::Ok((consensus_key, effective_power)) | |
}); | |
} | |
// Now collect the computed results into the lookup table. | |
while let Some(pair) = js.join_next().await.transpose()? { | |
let (consensus_key, effective_power) = pair?; | |
voting_power_by_consensus_key.insert(consensus_key, effective_power); | |
} | |
// Next, filter that mapping to exclude any zero-power validators, UNLESS they | |
// were already known to Tendermint. | |
voting_power_by_consensus_key.retain(|consensus_key, voting_power| { | |
*voting_power > 0 || current_consensus_keys.contains(consensus_key) | |
}); | |
// Finally, tell tendermint to delete any known consensus keys not otherwise updated | |
for ck in current_consensus_keys.iter() { | |
voting_power_by_consensus_key.entry(*ck).or_insert(0); | |
} | |
// Save the validator updates to send to Tendermint. | |
let tendermint_validator_updates = voting_power_by_consensus_key | |
.iter() | |
.map(|(ck, power)| { | |
Ok(Update { | |
pub_key: *ck, | |
power: (*power) | |
.try_into() | |
.context("should be able to convert u64 into validator Power")?, | |
}) | |
}) | |
.collect::<Result<Vec<_>>>()?; | |
self.put_tendermint_validator_updates(tendermint_validator_updates); | |
// Record the new consensus keys we will have told tendermint about. | |
let updated_consensus_keys = CurrentConsensusKeys { | |
consensus_keys: voting_power_by_consensus_key | |
.iter() | |
.filter_map(|(ck, power)| if *power != 0 { Some(*ck) } else { None }) | |
.collect(), | |
}; | |
tracing::debug!(?updated_consensus_keys); | |
self.put( | |
state_key::current_consensus_keys().to_owned(), | |
updated_consensus_keys, | |
); | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment