Skip to content

Commit 1a08293

Browse files
MathieuDutSikma2bd
authored andcommitted
Change the shuffling to take into account the weight. (linera-io#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 linera-io#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 87a5fca commit 1a08293

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
@@ -56,7 +56,11 @@ use linera_execution::{
5656
};
5757
use linera_storage::{Clock as _, ResultReadCertificates, Storage as _};
5858
use linera_views::ViewError;
59-
use rand::prelude::SliceRandom as _;
59+
use rand::{
60+
distributions::{Distribution, WeightedIndex},
61+
rngs::StdRng,
62+
SeedableRng,
63+
};
6064
use serde::{Deserialize, Serialize};
6165
use thiserror::Error;
6266
use tokio::sync::{mpsc, OwnedRwLockReadGuard};
@@ -263,18 +267,45 @@ impl<Env: Environment> Client<Env> {
263267
}
264268
}
265269

270+
fn weighted_select(
271+
remaining_validators: &mut Vec<RemoteNode<Env::ValidatorNode>>,
272+
remaining_weights: &mut Vec<u64>,
273+
rng: &mut StdRng,
274+
) -> Option<RemoteNode<Env::ValidatorNode>> {
275+
if remaining_weights.is_empty() {
276+
return None;
277+
}
278+
let dist = WeightedIndex::new(remaining_weights.clone()).unwrap();
279+
let idx = dist.sample(rng);
280+
remaining_weights.remove(idx);
281+
Some(remaining_validators.remove(idx))
282+
}
283+
266284
/// Downloads and processes all certificates up to (excluding) the specified height.
267285
#[instrument(level = "trace", skip(self))]
268286
async fn download_certificates(
269287
&self,
270288
chain_id: ChainId,
271289
target_next_block_height: BlockHeight,
272290
) -> Result<Box<ChainInfo>, ChainClientError> {
273-
let mut validators = self.validator_nodes().await?;
274-
// Sequentially try each validator in random order.
275-
validators.shuffle(&mut rand::thread_rng());
276-
let mut info = self.fetch_chain_info(chain_id, &validators).await?;
277-
for remote_node in validators {
291+
let (_, committee) = self.admin_committee().await?;
292+
let mut remaining_validators = self.make_nodes(&committee)?;
293+
let mut info = self
294+
.fetch_chain_info(chain_id, &remaining_validators)
295+
.await?;
296+
// Determining the weights of the validators
297+
let mut remaining_weights = remaining_validators
298+
.iter()
299+
.map(|validator| {
300+
let validator_state = committee.validators.get(&validator.public_key).unwrap();
301+
validator_state.votes
302+
})
303+
.collect::<Vec<_>>();
304+
let mut rng: StdRng = StdRng::from_entropy();
305+
306+
while let Some(remote_node) =
307+
Self::weighted_select(&mut remaining_validators, &mut remaining_weights, &mut rng)
308+
{
278309
if target_next_block_height <= info.next_block_height {
279310
return Ok(info);
280311
}

0 commit comments

Comments
 (0)