#[cfg(not(feature = "std"))]
extern crate alloc;
use crate::DOMAIN_EXTRINSICS_SHUFFLING_SEED_SUBJECT;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use domain_runtime_primitives::opaque::AccountId;
use hash_db::Hasher;
use rand::seq::SliceRandom;
use rand::SeedableRng;
use rand_chacha::ChaCha8Rng;
use sp_state_machine::trace;
use sp_std::collections::btree_map::BTreeMap;
use sp_std::collections::vec_deque::VecDeque;
use sp_std::fmt::Debug;
use subspace_core_primitives::Randomness;
pub fn extrinsics_shuffling_seed<Hashing>(block_randomness: Randomness) -> Hashing::Out
where
Hashing: Hasher,
{
let mut subject = DOMAIN_EXTRINSICS_SHUFFLING_SEED_SUBJECT.to_vec();
subject.extend_from_slice(block_randomness.as_ref());
Hashing::hash(&subject)
}
pub fn deduplicate_and_shuffle_extrinsics<Extrinsic>(
mut extrinsics: Vec<(Option<AccountId>, Extrinsic)>,
shuffling_seed: Randomness,
) -> VecDeque<Extrinsic>
where
Extrinsic: Debug + PartialEq + Clone,
{
let mut seen = Vec::new();
extrinsics.retain(|(_, uxt)| match seen.contains(uxt) {
true => {
trace!(extrinsic = ?uxt, "Duplicated extrinsic");
false
}
false => {
seen.push(uxt.clone());
true
}
});
drop(seen);
trace!(?extrinsics, "Origin deduplicated extrinsics");
shuffle_extrinsics::<Extrinsic, AccountId>(extrinsics, shuffling_seed)
}
pub fn shuffle_extrinsics<Extrinsic: Debug, AccountId: Ord + Clone>(
extrinsics: Vec<(Option<AccountId>, Extrinsic)>,
shuffling_seed: Randomness,
) -> VecDeque<Extrinsic> {
let mut rng = ChaCha8Rng::from_seed(*shuffling_seed);
let mut positions = extrinsics
.iter()
.map(|(maybe_signer, _)| maybe_signer)
.cloned()
.collect::<Vec<_>>();
positions.shuffle(&mut rng);
let mut grouped_extrinsics: BTreeMap<Option<AccountId>, VecDeque<_>> = extrinsics
.into_iter()
.fold(BTreeMap::new(), |mut groups, (maybe_signer, tx)| {
groups.entry(maybe_signer).or_default().push_back(tx);
groups
});
let shuffled_extrinsics = positions
.into_iter()
.map(|maybe_signer| {
grouped_extrinsics
.get_mut(&maybe_signer)
.expect("Extrinsics are grouped correctly; qed")
.pop_front()
.expect("Extrinsic definitely exists as it's correctly grouped above; qed")
})
.collect::<VecDeque<_>>();
trace!(?shuffled_extrinsics, "Shuffled extrinsics");
shuffled_extrinsics
}