distribution_bucket_picker.rs 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. #![warn(missing_docs)]
  2. use frame_support::traits::Randomness;
  3. use sp_arithmetic::traits::Zero;
  4. use sp_runtime::SaturatedConversion;
  5. use sp_std::cell::RefCell;
  6. use sp_std::collections::btree_set::BTreeSet;
  7. use sp_std::marker::PhantomData;
  8. use sp_std::rc::Rc;
  9. use sp_std::vec::Vec;
  10. use crate::{DynamicBagType, Module, Trait};
  11. // Generates distribution bucket IDs to assign to a new dynamic bag.
  12. pub(crate) struct DistributionBucketPicker<T> {
  13. trait_marker: PhantomData<T>,
  14. }
  15. impl<T: Trait> DistributionBucketPicker<T> {
  16. // Get random distribution buckets from distribution bucket families using the dynamic bag
  17. // creation policy.
  18. pub(crate) fn pick_distribution_buckets(
  19. bag_type: DynamicBagType,
  20. ) -> BTreeSet<T::DistributionBucketId> {
  21. let creation_policy = Module::<T>::get_dynamic_bag_creation_policy(bag_type);
  22. if creation_policy.no_distribution_buckets_required() {
  23. return BTreeSet::new();
  24. }
  25. // Randomness for all bucket family.
  26. // let random_seed = RefCell::new(Module::<T>::get_initial_random_seed());
  27. let random_seed = Rc::new(RefCell::new(Module::<T>::get_initial_random_seed()));
  28. creation_policy
  29. .families
  30. .iter()
  31. .filter_map(|(family_id, bucket_num)| {
  32. Module::<T>::ensure_distribution_bucket_family_exists(family_id)
  33. .ok()
  34. .map(|fam| (fam, bucket_num))
  35. })
  36. .map(|(family, bucket_num)| {
  37. let filtered_ids = family
  38. .distribution_buckets
  39. .iter()
  40. .filter_map(|(id, bucket)| bucket.accepting_new_bags.then(|| *id))
  41. .collect::<Vec<_>>();
  42. (filtered_ids, bucket_num)
  43. })
  44. .map(|(bucket_ids, bucket_num)| {
  45. Self::get_random_distribution_buckets(bucket_ids, *bucket_num, random_seed.clone())
  46. })
  47. .flatten()
  48. .collect::<BTreeSet<_>>()
  49. }
  50. // Get random bucket IDs from the ID collection.
  51. pub fn get_random_distribution_buckets(
  52. ids: Vec<T::DistributionBucketId>,
  53. bucket_number: u32,
  54. seed: Rc<RefCell<T::Hash>>, // seed: RefCell<T::Hash>
  55. ) -> BTreeSet<T::DistributionBucketId> {
  56. let mut working_ids = ids;
  57. let mut result_ids = BTreeSet::default();
  58. for _ in 0..bucket_number {
  59. if working_ids.is_empty() {
  60. break;
  61. }
  62. let current_seed = Self::advance_random_seed(seed.clone());
  63. let upper_bound = working_ids.len() as u64 - 1;
  64. let index =
  65. Module::<T>::random_index(current_seed.as_ref(), upper_bound).saturated_into();
  66. result_ids.insert(working_ids.remove(index));
  67. }
  68. result_ids
  69. }
  70. // Changes the internal seed value of the container and returns new random seed.
  71. fn advance_random_seed(seed: Rc<RefCell<T::Hash>>) -> T::Hash {
  72. // Cannot create randomness in the initial block (Substrate error).
  73. if <frame_system::Module<T>>::block_number() == Zero::zero() {
  74. return Module::<T>::get_initial_random_seed();
  75. }
  76. let current_seed = *seed.borrow();
  77. seed.replace(T::Randomness::random(current_seed.as_ref()))
  78. }
  79. }