Skip to content

Commit fc32fb2

Browse files
Change the shuffling to take into account the weight. (#4505)
## Motivation Not all validators are equal. Taking into account their weight during the shuffling makes the validators with more weight more responsible for accessing the Fixes #2616 ## Proposal We simply count the weights when doing the random shuffling. ## Test Plan The CI. ## Release Plan - Nothing to do / These changes follow the usual release cycle. ## Links None.
1 parent 77b7715 commit fc32fb2

File tree

1 file changed

+37
-6
lines changed

1 file changed

+37
-6
lines changed

linera-core/src/client/mod.rs

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ use linera_execution::{
5757
};
5858
use linera_storage::{Clock as _, ResultReadCertificates, Storage as _};
5959
use linera_views::ViewError;
60-
use rand::prelude::SliceRandom as _;
60+
use rand::{
61+
distributions::{Distribution, WeightedIndex},
62+
rngs::StdRng,
63+
SeedableRng,
64+
};
6165
use serde::{Deserialize, Serialize};
6266
use thiserror::Error;
6367
use tokio::sync::{mpsc, OwnedRwLockReadGuard};
@@ -312,18 +316,45 @@ impl<Env: Environment> Client<Env> {
312316
}
313317
}
314318

319+
fn weighted_select(
320+
remaining_validators: &mut Vec<RemoteNode<Env::ValidatorNode>>,
321+
remaining_weights: &mut Vec<u64>,
322+
rng: &mut StdRng,
323+
) -> Option<RemoteNode<Env::ValidatorNode>> {
324+
if remaining_weights.is_empty() {
325+
return None;
326+
}
327+
let dist = WeightedIndex::new(remaining_weights.clone()).unwrap();
328+
let idx = dist.sample(rng);
329+
remaining_weights.remove(idx);
330+
Some(remaining_validators.remove(idx))
331+
}
332+
315333
/// Downloads and processes all certificates up to (excluding) the specified height.
316334
#[instrument(level = "trace", skip(self))]
317335
async fn download_certificates(
318336
&self,
319337
chain_id: ChainId,
320338
target_next_block_height: BlockHeight,
321339
) -> Result<Box<ChainInfo>, ChainClientError> {
322-
let mut validators = self.validator_nodes().await?;
323-
// Sequentially try each validator in random order.
324-
validators.shuffle(&mut rand::thread_rng());
325-
let mut info = self.fetch_chain_info(chain_id, &validators).await?;
326-
for remote_node in validators {
340+
let (_, committee) = self.admin_committee().await?;
341+
let mut remaining_validators = self.make_nodes(&committee)?;
342+
let mut info = self
343+
.fetch_chain_info(chain_id, &remaining_validators)
344+
.await?;
345+
// Determining the weights of the validators
346+
let mut remaining_weights = remaining_validators
347+
.iter()
348+
.map(|validator| {
349+
let validator_state = committee.validators.get(&validator.public_key).unwrap();
350+
validator_state.votes
351+
})
352+
.collect::<Vec<_>>();
353+
let mut rng: StdRng = StdRng::from_entropy();
354+
355+
while let Some(remote_node) =
356+
Self::weighted_select(&mut remaining_validators, &mut remaining_weights, &mut rng)
357+
{
327358
if target_next_block_height <= info.next_block_height {
328359
return Ok(info);
329360
}

0 commit comments

Comments
 (0)