Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core] Fix proposals shuffling implementation #7921

Merged
merged 1 commit into from Oct 26, 2022

Conversation

robin-near
Copy link
Contributor

The SliceRandom::shuffle implementation changed from rand 0.6.5 to 0.7.0 in a subtle way: rust-random/rand#809 because the underlying gen_index implementation changed. (It appears that @matklad 's concern on #7717 turns out to be quite real!)

In order to reproduce the old behavior and to make sure this never changes again, this PR replicates the gen_index implementation (it's pretty straight-forward) from 0.6.5. The test case is updated (the old test case was unfortunately incorrect from #7717). Also, @mm-near 's #7909 now passes with this change.

Comment on lines 271 to 289
let mut rng: Hc128Rng = SeedableRng::from_seed(rng_seed);
dup_proposals.shuffle(&mut rng);
for i in (1..dup_proposals.len()).rev() {
dup_proposals.swap(i, gen_index_old(&mut rng, (i + 1) as u64) as usize);
}
}

fn gen_index_old(rng: &mut Hc128Rng, bound: u64) -> u64 {
// This is a simplified copy of the rand gen_index implementation to ensure that
// upgrades to the rand library will not cause a change in the shuffling behavior.
let zone = u64::MAX - (u64::MAX - bound + 1) % (bound);
loop {
let v = rng.next_u64();
let mul = (v as u128) * (bound as u128);
let (hi, lo) = ((mul >> 64) as u64, mul as u64);
if lo < zone {
return hi;
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are feeling enterpisey, I'd probably extracted this code into a separate module/type EpochManagerRng to make sure its public API doesn't expose rand. Right now this code has an implicit invariant of "don't use any rand methods besides from_seed and next_u64", and I'd love for that invariant to have teeth.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry not exactly sure what you mean - the module is already named old_* and these two functions are not public.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, sorry, I missed two points:

  • that this is already a separate module
  • that we no longer relying on randomness here for the latest protocol

I was fearing that we still use rand, and need to guard aginst future code changes.

chain/epoch-manager/src/proposals.rs Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants