1use crate::{balance::ProductType, Config, Error};
51
52use core::{fmt::Debug, marker::PhantomData};
54
55use codec::DecodeWithMemTracking;
57use scale_info::{prelude::vec, TypeInfo};
58
59use derive_more::Constructor;
61
62use frame_suite::{assets::*, misc::PositionIndex, plugins::ModelContext};
64
65use frame_support::{
67 dispatch::DispatchResult,
68 ensure,
69 traits::{
70 fungible::{Inspect, InspectFreeze},
71 tokens::Precision,
72 VariantCountOf,
73 },
74};
75
76use frame_system::pallet;
78
79use sp_core::{Decode, Encode, Get, MaxEncodedLen};
81use sp_runtime::{
82 traits::{CheckedAdd, Zero},
83 BoundedVec, DispatchError, RuntimeDebug, Vec, WeakBoundedVec,
84};
85use sp_std::collections::btree_set::BTreeSet;
86
87pub type Digest<T> = <T as pallet::Config>::AccountId;
95
96pub type DirectDigest<T> = Digest<T>;
100
101pub type IndexDigest<T> = Digest<T>;
103
104pub type PoolDigest<T> = Digest<T>;
106
107pub type EntryDigest<T> = Digest<T>;
109
110pub type SlotDigest<T> = Digest<T>;
112
113pub type DigestSource<T> = <T as pallet::Config>::AccountId;
116
117pub type Proprietor<T> = <T as pallet::Config>::AccountId;
119
120pub type AssetOf<T, I = ()> = <<T as Config<I>>::Asset as Inspect<Proprietor<T>>>::Balance;
124
125pub type LazyBalanceOf<T, I = ()> = VirtualBalance<T, I>;
130
131pub type CommitInstance<T, I = ()> = VirtualReceipt<T, I>;
141
142pub type CommitReason<T, I = ()> = <<T as Config<I>>::Asset as InspectFreeze<Proprietor<T>>>::Id;
149
150pub type BalanceContext<T, I = ()> = <T as Config<I>>::BalanceContext;
156
157pub type BalanceModelContext<T, I = ()> = <BalanceContext<T, I> as ModelContext>::Context;
163
164pub type LazyVirtual<T, A, R, Ti, Ad, I = ()> =
167 ProductType<T, I, BalanceModelContext<T, I>, A, R, Ti, Ad>;
168
169pub type VirtualBalance<T, I = ()> =
174 LazyVirtual<T, BalanceAsset, BalanceRational, BalanceTime, BalanceAddon, I>;
175
176pub type VirtualSnapShot<T, I = ()> =
181 LazyVirtual<T, SnapShotAsset, SnapShotRational, SnapShotTime, SnapShotAddon, I>;
182
183pub type VirtualReceipt<T, I = ()> =
191 LazyVirtual<T, ReceiptAsset, ReceiptRational, ReceiptTime, ReceiptAddon, I>;
192
193#[derive(
217 Encode,
218 Decode,
219 Clone,
220 RuntimeDebug,
221 PartialEq,
222 Eq,
223 MaxEncodedLen,
224 TypeInfo,
225 DecodeWithMemTracking,
226)]
227#[scale_info(skip_type_params(T, I))]
228pub struct DigestInfo<T: Config<I>, I: 'static = ()>(
229 BoundedVec<LazyBalanceOf<T, I>, VariantCountOf<T::Position>>,
230);
231
232impl<T: Config<I>, I: 'static> DigestInfo<T, I> {
237 pub fn balances(&self) -> Result<Vec<(T::Position, LazyBalanceOf<T, I>)>, DispatchError> {
242 let bound = &self.0;
243 let mut collect = Vec::new();
244 for (i, balance) in bound.iter().enumerate() {
245 if *balance == Default::default() {
246 continue;
247 }
248 let position = <T::Position as PositionIndex>::position_of(i);
249 debug_assert!(
250 position.is_some(),
251 "commit-variant invalid position found for index {:?},
252 an example default of the position type for debugging is {:?}",
253 i,
254 T::Position::default()
255 );
256 let position = position.ok_or(Error::<T, I>::InvalidCommitVariantIndex)?;
257 collect.push((position, balance.clone()));
258 }
259 Ok(collect)
260 }
261
262 pub(crate) fn mut_balance(
263 &mut self,
264 variant: &T::Position,
265 ) -> Option<&mut LazyBalanceOf<T, I>> {
266 let idx = variant.index();
269 self.0.get_mut(idx)
270 }
271
272 pub fn get_balance(&self, variant: &T::Position) -> Option<&LazyBalanceOf<T, I>> {
273 let idx = variant.index();
274 self.0.get(idx)
275 }
276
277 pub fn reveal(&self) -> BoundedVec<LazyBalanceOf<T, I>, VariantCountOf<T::Position>> {
278 self.0.clone()
279 }
280
281 pub(crate) fn init_balance(&mut self, variant: &T::Position) -> Result<(), DispatchError> {
282 let idx = variant.index();
283 let vec = &mut self.0;
285 for i in 0..=idx {
286 if let None = vec.get(i) {
287 let result = vec.try_push(Default::default());
289 debug_assert!(
290 result.is_ok(),
291 "default commit-variants push results bad, where pushed
292 index {:?} is lesser than or equal to expected variant (position)
293 {:?} whoose index is {:?}",
294 i,
295 variant,
296 idx
297 );
298 result.map_err(|_| Error::<T, I>::VariantsExhausted)?;
299 }
300 }
301 return Ok(());
302 }
303}
304
305#[derive(Encode, Decode, Clone, RuntimeDebug, MaxEncodedLen, TypeInfo, DecodeWithMemTracking)]
320#[scale_info(skip_type_params(T, I))]
321pub struct Commits<T: Config<I>, I: 'static = ()>(
322 WeakBoundedVec<CommitInstance<T, I>, T::MaxCommits>,
323);
324
325impl<T: Config<I>, I: 'static> Commits<T, I> {
330 pub(crate) fn new(instance: CommitInstance<T, I>) -> Result<Self, DispatchError> {
336 let max = T::MaxCommits::get();
337 ensure!(!max.is_zero(), Error::<T, I>::ZeroMaxCommits);
338 let vec = vec![instance];
339 let commits = WeakBoundedVec::<CommitInstance<T, I>, T::MaxCommits>::try_from(vec);
340 debug_assert!(
341 commits.is_ok(),
342 "single commit-instance vec to weak-vec of
343 max-commit {} is non-zero failed but shouldn't be",
344 T::MaxCommits::get()
345 );
346 let commits = commits.map_err(|_| Error::<T, I>::CommitConstructionFailed)?;
347 return Ok(Commits(commits));
348 }
349
350 pub(crate) fn add_commit(
356 &mut self,
357 instance: CommitInstance<T, I>,
358 ) -> Result<(), DispatchError> {
359 debug_assert!(
360 !self.0.is_empty(),
361 "empty commits constructed without a single
362 commit-instance, attempting to add a new-instance {:?}",
363 instance
364 );
365 ensure!(!self.0.is_empty(), Error::<T, I>::EmptyCommitsNotAllowed);
366 let vec = &mut self.0;
367 vec.try_push(instance)
368 .map_err(|_| Error::<T, I>::MaxCommitsReached)?;
369 Ok(())
370 }
371
372 pub fn commits(&self) -> WeakBoundedVec<CommitInstance<T, I>, T::MaxCommits> {
373 debug_assert!(
374 !self.0.is_empty(),
375 "empty commits constructed without
376 a single commit-instance"
377 );
378 self.0.clone()
382 }
383}
384
385#[derive(
400 Encode,
401 Decode,
402 Clone,
403 RuntimeDebug,
404 MaxEncodedLen,
405 TypeInfo,
406 PartialEq,
407 Eq,
408 DecodeWithMemTracking,
409)]
410#[scale_info(skip_type_params(T, I))]
411pub struct CommitInfo<T: Config<I>, I: 'static = ()> {
412 digest: Digest<T>,
417
418 commits: Commits<T, I>,
424
425 variant: T::Position,
433}
434
435impl<T: Config<I>, I: 'static> CommitInfo<T, I> {
440 pub(crate) fn new(
446 digest: Digest<T>,
447 instance: CommitInstance<T, I>,
448 variant: T::Position,
449 ) -> Result<Self, DispatchError> {
450 let commits = Commits::<T, I>::new(instance)?;
451 let try_position = <T::Position as PositionIndex>::position_of(
452 <T::Position as PositionIndex>::index(&variant),
453 );
454 debug_assert!(
455 try_position.is_some(),
456 "cannot equalize new-commit's given variant {:?} and its derived
457 positional index (not consistent) when creating new commit-info for
458 proprietor towards non-classified-digest {:?}",
459 variant,
460 digest
461 );
462 let position = try_position.ok_or(Error::<T, I>::InvalidCommitVariantIndex)?;
463 debug_assert!(
464 position == variant,
465 "new-commit's given variant {:?} and its derived
466 positional index (not consistent) variant is not same,
467 found {:?} when creating new commit-info for
468 proprietor towards non-classified-digest {:?}",
469 variant,
470 position,
471 digest
472 );
473 ensure!(
474 position == variant,
475 Error::<T, I>::InvalidCommitVariantIndex
476 );
477 Ok(Self {
478 digest,
479 commits,
480 variant,
481 })
482 }
483
484 #[inline]
486 pub fn commits(&self) -> WeakBoundedVec<CommitInstance<T, I>, T::MaxCommits> {
487 Commits::<T, I>::commits(&self.commits)
488 }
489
490 pub fn digest(&self) -> Digest<T> {
492 self.digest.clone()
493 }
494
495 pub fn variant(&self) -> T::Position {
497 self.variant.clone()
498 }
499
500 #[inline]
506 pub(crate) fn add_commit(
507 &mut self,
508 instance: CommitInstance<T, I>,
509 ) -> Result<(), DispatchError> {
510 self.commits.add_commit(instance)
511 }
512}
513
514#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, DecodeWithMemTracking)]
524#[scale_info(skip_type_params(T, I))]
525pub struct EntryInfo<T: Config<I>, I: 'static = ()> {
526 digest: EntryDigest<T>,
528
529 shares: T::Shares,
531
532 variant: T::Position,
537}
538
539impl<T: Config<I>, I: 'static> EntryInfo<T, I> {
544 pub fn new(
551 digest: EntryDigest<T>,
552 shares: T::Shares,
553 variant: T::Position,
554 ) -> Result<Self, DispatchError> {
555 ensure!(!shares.is_zero(), Error::<T, I>::ShareCannotBeZero);
556 let try_position = <T::Position as PositionIndex>::position_of(
557 <T::Position as PositionIndex>::index(&variant),
558 );
559 debug_assert!(
560 try_position.is_some(),
561 "cannot equalize new-commit's given variant {:?} and its derived
562 positional index (not consistent) when creating new entry-info for
563 entry-digest {:?} of shares {:?}",
564 variant,
565 digest,
566 shares
567 );
568 let position = try_position.ok_or(Error::<T, I>::InvalidCommitVariantIndex)?;
569 debug_assert!(
570 position == variant,
571 "new-commit's given variant {:?} and its derived
572 positional index (not consistent) variant is not same,
573 found {:?} when creating new entry-info for entry-digest
574 {:?} of shares {:?}",
575 variant,
576 position,
577 digest,
578 shares
579 );
580 ensure!(
581 position == variant,
582 Error::<T, I>::InvalidCommitVariantIndex
583 );
584 Ok(Self {
585 digest,
586 shares,
587 variant,
588 })
589 }
590
591 pub fn shares(&self) -> T::Shares {
595 self.shares
596 }
597
598 pub fn digest(&self) -> Digest<T> {
600 self.digest.clone()
601 }
602
603 pub fn variant(&self) -> T::Position {
605 self.variant.clone()
606 }
607}
608
609impl<T: Config<I>, I: 'static> Clone for EntryInfo<T, I> {
610 fn clone(&self) -> Self {
611 Self {
612 digest: self.digest.clone(),
613 shares: self.shares,
614 variant: self.variant.clone(),
615 }
616 }
617}
618
619#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, DecodeWithMemTracking)]
632#[scale_info(skip_type_params(T, I))]
633pub struct Entries<T: Config<I>, I: 'static = ()>(
634 WeakBoundedVec<EntryInfo<T, I>, T::MaxIndexEntries>,
635);
636
637impl<T: Config<I>, I: 'static> Entries<T, I> {
642 pub fn new(entries: Vec<EntryInfo<T, I>>) -> Result<Self, DispatchError> {
647 let max = T::MaxIndexEntries::get();
648 ensure!(!max.is_zero(), Error::<T, I>::TriedCreatingHaltedIndexes);
649 ensure!(!entries.is_empty(), Error::<T, I>::EmptyEntriesNotAllowed);
650 let mut seen = BTreeSet::new();
651 for entry in &entries {
652 ensure!(
653 seen.insert(entry.digest.clone()),
654 Error::<T, I>::DuplicateEntry
655 );
656 }
657 let entries = WeakBoundedVec::<EntryInfo<T, I>, T::MaxIndexEntries>::try_from(entries)
658 .map_err(|_| Error::<T, I>::MaxEntriesReached)?;
659 return Ok(Entries(entries));
660 }
661
662 pub fn entries(&self) -> Vec<EntryInfo<T, I>> {
664 let bounded = &self.0;
665 let mut collect = Vec::new();
666 for entry in bounded {
667 collect.push(entry.clone())
668 }
669 debug_assert!(
670 !collect.is_empty(),
671 "empty entries-list initiated which
672 should not be for indexes"
673 );
674 collect
675 }
676
677 pub fn add_entry(&mut self, entry: EntryInfo<T, I>) -> Result<(), DispatchError> {
682 debug_assert!(
683 !self.0.is_empty(),
684 "empty entries constructed without a single
685 commit-instance, attempting to add a new-entry",
686 );
687 ensure!(!self.0.is_empty(), Error::<T, I>::EmptyEntriesNotAllowed);
688 let vec = &mut self.0;
689 vec.try_push(entry)
690 .map_err(|_| Error::<T, I>::MaxEntriesReached)?;
691 let mut seen = BTreeSet::new();
692 for entry in vec {
693 ensure!(
694 seen.insert(entry.digest.clone()),
695 Error::<T, I>::DuplicateEntry
696 );
697 }
698 Ok(())
699 }
700
701 pub fn remove_entry(&mut self, entry: &EntryDigest<T>) -> Result<(), DispatchError> {
705 debug_assert!(
706 !self.0.is_empty(),
707 "empty entries constructed without a single
708 commit-instance, attempting to remove an existing-entry {:?}",
709 entry
710 );
711 ensure!(
712 (!self.0.is_empty() && self.0.len() > 1),
713 Error::<T, I>::EmptyEntriesNotAllowed
714 );
715 debug_assert!(
716 self.0.len() > 1,
717 "attempting to remove an existing-entry {:?}, which
718 will result in zero-length entries",
719 entry
720 );
721 let mut entry_idx = None;
722 for (i, entry_of) in self.0.iter().enumerate() {
723 if entry_of.digest == *entry {
724 entry_idx = Some(i);
725 break;
726 }
727 }
728
729 match entry_idx {
730 Some(idx) => {
731 self.0.remove(idx);
732 }
733 None => {
734 return Err(Error::<T, I>::EntryOfIndexNotFound)?;
735 }
736 }
737 Ok(())
738 }
739}
740
741#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, DecodeWithMemTracking)]
750#[scale_info(skip_type_params(T, I))]
751pub struct IndexInfo<T: Config<I>, I: 'static = ()> {
752 principal: AssetOf<T, I>,
758
759 capital: T::Shares,
761
762 entries: Entries<T, I>,
764}
765
766impl<T: Config<I>, I: 'static> IndexInfo<T, I> {
771 pub(crate) fn new(entries: &mut Entries<T, I>) -> Result<Self, DispatchError> {
780 debug_assert!(!entries.0.is_empty(), "entries is constructed empty");
781 ensure!(!entries.0.is_empty(), Error::<T, I>::EmptyEntriesNotAllowed);
782 let mut total_capital = T::Shares::zero();
783 for entry in &entries.0 {
784 let shares = entry.shares;
785 debug_assert!(
786 !shares.is_zero(),
787 "entry for digest {:?} of variant {:?} share is constructed zero",
788 entry.digest,
789 entry.variant
790 );
791 ensure!(!shares.is_zero(), Error::<T, I>::ShareCannotBeZero);
792 total_capital = total_capital
793 .checked_add(&shares)
794 .ok_or(Error::<T, I>::CapitalOverflowed)?;
795 }
796 debug_assert!(
797 !total_capital.is_zero(),
798 "total capital is zero while its entry shares isn't"
799 );
800 ensure!(!total_capital.is_zero(), Error::<T, I>::CapitalCannotBeZero);
801 Ok(Self {
802 principal: AssetOf::<T, I>::zero(),
803 capital: total_capital,
804 entries: entries.clone(),
805 })
806 }
807
808 pub fn capital(&self) -> T::Shares {
810 let value = self.capital;
811 debug_assert!(!value.is_zero(), "index capital is constructed zero");
812 value
813 }
814
815 pub fn principal(&self) -> AssetOf<T, I> {
818 self.principal
819 }
820
821 #[inline]
823 pub fn entries(&self) -> Vec<EntryInfo<T, I>> {
824 Entries::<T, I>::entries(&self.entries)
825 }
826
827 pub fn reveal_entries(&self) -> Entries<T, I> {
829 self.entries.clone()
830 }
831
832 pub fn entry_exists(&self, entry: &EntryDigest<T>) -> DispatchResult {
834 let entries = &self.entries;
835 debug_assert!(!entries.0.is_empty(), "entries is constructed empty");
836 ensure!(!entries.0.is_empty(), Error::<T, I>::EmptyEntriesNotAllowed);
837 let mut idx = None;
838 for (i, entry_of) in entries.0.iter().enumerate() {
840 if entry_of.digest == *entry {
841 idx = Some(i);
842 }
843 }
844
845 if let Some(_) = idx {
847 return Ok(());
848 };
849
850 Err(Error::<T, I>::EntryOfIndexNotFound.into())
851 }
852
853 pub(crate) fn set_balance(&mut self, principal: AssetOf<T, I>) {
855 self.principal = principal
856 }
857}
858
859#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, DecodeWithMemTracking)]
870#[scale_info(skip_type_params(T, I))]
871pub struct SlotInfo<T: Config<I>, I: 'static = ()> {
872 digest: SlotDigest<T>,
874
875 shares: T::Shares,
877
878 commit: CommitInstance<T, I>,
884
885 variant: T::Position,
887}
888
889impl<T: Config<I>, I: 'static> SlotInfo<T, I> {
894 pub fn shares(&self) -> T::Shares {
896 self.shares
897 }
898
899 pub fn commit(&self) -> CommitInstance<T, I> {
902 self.commit.clone()
903 }
904
905 pub fn digest(&self) -> SlotDigest<T> {
907 self.digest.clone()
908 }
909
910 pub fn variant(&self) -> T::Position {
912 self.variant.clone()
913 }
914
915 fn set_slot_commit(&mut self, commit: CommitInstance<T, I>) {
933 self.commit = commit
934 }
935}
936
937impl<T: Config<I>, I: 'static> From<EntryInfo<T, I>> for SlotInfo<T, I> {
942 fn from(entry: EntryInfo<T, I>) -> Self {
951 Self {
952 digest: entry.digest,
953 shares: entry.shares,
954 commit: Default::default(),
955 variant: entry.variant,
956 }
957 }
958}
959
960#[derive(Encode, Decode, MaxEncodedLen, TypeInfo)]
972#[scale_info(skip_type_params(T, I))]
973pub struct Slots<T: Config<I>, I: 'static = ()>(WeakBoundedVec<SlotInfo<T, I>, T::MaxIndexEntries>);
974
975impl<T: Config<I>, I: 'static> Slots<T, I> {
980 pub fn slots(&self) -> Vec<SlotInfo<T, I>> {
982 let bounded = &self.0;
983 let mut collect = Vec::new();
984 for slot in bounded {
985 collect.push(slot.clone())
986 }
987 debug_assert!(
988 !collect.is_empty(),
989 "empty slots initiated which should not be for pools"
990 );
991 collect
992 }
993
994 fn add_slot(&mut self, entry: EntryInfo<T, I>) -> Result<(), DispatchError> {
999 debug_assert!(
1000 !self.0.is_empty(),
1001 "empty slots constructed without a single
1002 slot, attempting to add a new-slot via entry",
1003 );
1004 ensure!(!self.0.is_empty(), Error::<T, I>::EmptySlotsNotAllowed);
1005 let vec = &mut self.0;
1006 vec.try_push(entry.into())
1007 .map_err(|_| Error::<T, I>::MaxSlotsReached)?;
1008 let mut seen = BTreeSet::new();
1009 for slot in vec {
1010 ensure!(
1011 seen.insert(slot.digest.clone()),
1012 Error::<T, I>::DuplicateSlot,
1013 );
1014 }
1015 Ok(())
1016 }
1017
1018 fn remove_slot(&mut self, slot: &SlotDigest<T>) -> Result<(), DispatchError> {
1022 debug_assert!(
1023 !self.0.is_empty(),
1024 "empty slots constructed without a single
1025 slot, attempting to remove an existing-slot {:?}",
1026 slot,
1027 );
1028 ensure!(
1029 (!self.0.is_empty() && self.0.len() > 1),
1030 Error::<T, I>::EmptySlotsNotAllowed
1031 );
1032 debug_assert!(
1033 self.0.len() > 1,
1034 "attempting to remove an existing-slot {:?}, which
1035 will result in zero-length slots",
1036 slot
1037 );
1038 let mut slot_idx = None;
1039 for (i, slot_of) in self.0.iter().enumerate() {
1040 if slot_of.digest == *slot {
1041 slot_idx = Some(i);
1042 break;
1043 }
1044 }
1045
1046 match slot_idx {
1047 Some(idx) => {
1048 self.0.remove(idx);
1049 }
1050 None => {
1051 return Err(Error::<T, I>::SlotOfPoolNotFound)?;
1052 }
1053 }
1054 Ok(())
1055 }
1056
1057 fn set_slot_commit(
1067 &mut self,
1068 digest: &SlotDigest<T>,
1069 commit: CommitInstance<T, I>,
1070 ) -> Result<(), DispatchError> {
1071 debug_assert!(
1072 !self.0.is_empty(),
1073 "empty slots constructed without a single
1074 slot {:?}",
1075 self,
1076 );
1077
1078 let mut slot_idx = None;
1079 for (i, slot_of) in self.0.iter().enumerate() {
1080 if slot_of.digest == *digest {
1081 slot_idx = Some(i);
1082 break;
1083 }
1084 }
1085
1086 match slot_idx {
1087 Some(idx) => {
1088 let slot_of = self
1089 .0
1090 .get_mut(idx)
1091 .ok_or(Error::<T, I>::SlotOfPoolNotFound)?;
1092 slot_of.set_slot_commit(commit);
1093 }
1094 None => {
1095 return Err(Error::<T, I>::SlotOfPoolNotFound)?;
1096 }
1097 }
1098 Ok(())
1099 }
1100}
1101
1102impl<T: Config<I>, I: 'static> TryFrom<Entries<T, I>> for Slots<T, I> {
1107 type Error = DispatchError;
1108
1109 fn try_from(entries: Entries<T, I>) -> Result<Self, Self::Error> {
1117 let raw_vec: Vec<SlotInfo<T, I>> =
1118 entries.0.into_iter().map(|entry| entry.into()).collect();
1119
1120 let entries = WeakBoundedVec::try_from(raw_vec)
1121 .map(Slots)
1122 .map_err(|_| Error::<T, I>::MaxSlotsReached.into());
1123 debug_assert!(
1124 entries.is_ok(),
1125 "both entries and slots have same upper weak-bound
1126 but slots cannot be tried from entries"
1127 );
1128 entries
1129 }
1130}
1131
1132#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, DecodeWithMemTracking)]
1149#[scale_info(skip_type_params(T, I))]
1150pub struct PoolInfo<T: Config<I>, I: 'static = ()> {
1151 balance_of: LazyBalanceOf<T, I>,
1156
1157 capital: T::Shares,
1162
1163 commission: T::Commission,
1168
1169 slots: Slots<T, I>,
1176}
1177
1178impl<T: Config<I>, I: 'static> PoolInfo<T, I> {
1183 pub(crate) fn new(
1193 index_entries: Entries<T, I>,
1194 commission: T::Commission,
1195 ) -> Result<Self, DispatchError> {
1196 let total_capital = index_entries
1197 .0
1198 .iter()
1199 .try_fold(T::Shares::zero(), |acc, slot| {
1200 acc.checked_add(&slot.shares)
1201 .ok_or(Error::<T, I>::CapitalOverflowed)
1202 })?;
1203
1204 let slots = index_entries.try_into()?;
1205
1206 Ok(Self {
1207 balance_of: Default::default(),
1208 capital: total_capital,
1209 commission,
1210 slots,
1211 })
1212 }
1213
1214 pub fn balance(&self) -> LazyBalanceOf<T, I> {
1216 self.balance_of.clone()
1217 }
1218
1219 pub(crate) fn set_balance(&mut self, balance: LazyBalanceOf<T, I>) {
1221 self.balance_of = balance;
1222 }
1223
1224 pub fn capital(&self) -> T::Shares {
1226 let value = self.capital;
1227 debug_assert!(!value.is_zero(), "index capital is constructed zero");
1228 value
1229 }
1230
1231 pub fn commission(&self) -> T::Commission {
1233 self.commission
1234 }
1235
1236 pub fn slots(&self) -> Vec<SlotInfo<T, I>> {
1238 self.slots.slots()
1239 }
1240
1241 pub(crate) fn balance_reset(&mut self) {
1246 self.balance_of = Default::default();
1247 for slot in &mut self.slots.0 {
1248 slot.commit = Default::default();
1249 }
1250 }
1251
1252 #[inline]
1255 pub(crate) fn set_slot_commit(
1256 &mut self,
1257 digest: &SlotDigest<T>,
1258 commit: CommitInstance<T, I>,
1259 ) -> Result<(), DispatchError> {
1260 self.slots.set_slot_commit(digest, commit)
1261 }
1262
1263 pub(crate) fn add_slot(&mut self, entry: EntryInfo<T, I>) -> DispatchResult {
1271 self.slots.add_slot(entry)?;
1272 let total_capital = self
1273 .slots
1274 .0
1275 .iter()
1276 .try_fold(T::Shares::zero(), |acc, slot| {
1277 acc.checked_add(&slot.shares)
1278 .ok_or(Error::<T, I>::CapitalOverflowed)
1279 })?;
1280 self.capital = total_capital;
1281 Ok(())
1282 }
1283
1284 pub(crate) fn remove_slot(&mut self, slot: &SlotDigest<T>) -> DispatchResult {
1291 self.slots.remove_slot(slot)?;
1292 ensure!(
1293 !self.slots.0.is_empty(),
1294 Error::<T, I>::EmptySlotsNotAllowed
1295 );
1296 let total_capital = self
1297 .slots
1298 .0
1299 .iter()
1300 .try_fold(T::Shares::zero(), |acc, slot| {
1301 acc.checked_add(&slot.shares)
1302 .ok_or(Error::<T, I>::CapitalOverflowed)
1303 })?;
1304 self.capital = total_capital;
1305 Ok(())
1306 }
1307
1308 pub fn slot_exists(&self, slot: &SlotDigest<T>) -> DispatchResult {
1310 let slots = &self.slots;
1311 debug_assert!(!slots.0.is_empty(), "slots are constructed empty");
1312 let mut idx = None;
1313 for (i, slot_of) in slots.0.iter().enumerate() {
1315 if slot_of.digest == *slot {
1316 idx = Some(i);
1317 }
1318 }
1319
1320 if let Some(_) = idx {
1322 return Ok(());
1323 };
1324
1325 Err(Error::<T, I>::SlotOfPoolNotFound.into())
1326 }
1327}
1328
1329#[derive(
1344 Encode,
1345 Decode,
1346 RuntimeDebug,
1347 MaxEncodedLen,
1348 TypeInfo,
1349 Constructor,
1350 PartialEq,
1351 Eq,
1352 DecodeWithMemTracking,
1353)]
1354#[scale_info(skip_type_params(T, I))]
1355pub struct IndexOfReason<T: Config<I>, I: 'static = ()> {
1356 pub reason: CommitReason<T, I>,
1358
1359 pub index: IndexInfo<T, I>,
1361}
1362
1363#[derive(
1373 Encode,
1374 Decode,
1375 RuntimeDebug,
1376 MaxEncodedLen,
1377 TypeInfo,
1378 Constructor,
1379 PartialEq,
1380 Eq,
1381 DecodeWithMemTracking,
1382)]
1383#[scale_info(skip_type_params(T, I))]
1384pub struct PoolOfReason<T: Config<I>, I: 'static = ()> {
1385 pub reason: CommitReason<T, I>,
1387
1388 pub pool: PoolInfo<T, I>,
1390}
1391
1392#[derive(
1412 Encode,
1413 Decode,
1414 MaxEncodedLen,
1415 RuntimeDebug,
1416 TypeInfo,
1417 PartialEq,
1418 Clone,
1419 Constructor,
1420 Eq,
1421 DecodeWithMemTracking,
1422 Copy,
1423)]
1424#[scale_info(skip_type_params(T, I))]
1425pub(crate) struct AssetDelta<T: Config<I>, I: 'static = ()> {
1426 pub deposit: AssetOf<T, I>,
1428 pub withdraw: AssetOf<T, I>,
1430}
1431
1432#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, DecodeWithMemTracking, Clone, Debug, Copy)]
1438pub enum ChooseDigest {
1439 Direct,
1440 Index,
1441 Pool,
1442}
1443
1444impl ChooseDigest {
1445 pub fn digest_model<T: Config<I>, I: 'static>(&self, digest: Digest<T>) -> DigestVariant<T, I> {
1446 match self {
1447 ChooseDigest::Direct => DigestVariant::Direct(digest),
1448 ChooseDigest::Index => DigestVariant::Index(digest),
1449 ChooseDigest::Pool => DigestVariant::Pool(digest),
1450 }
1451 }
1452}
1453
1454#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, DecodeWithMemTracking)]
1469#[scale_info(skip_type_params(T, I))]
1470pub enum DigestVariant<T: Config<I>, I: 'static = ()> {
1471 Direct(Digest<T>),
1473 Index(Digest<T>),
1475 Pool(Digest<T>),
1477 #[codec(skip)]
1480 __Ignore(PhantomData<I>),
1481}
1482
1483#[derive(
1500 Encode,
1501 Decode,
1502 DecodeWithMemTracking,
1503 RuntimeDebug,
1504 Clone,
1505 PartialEq,
1506 Eq,
1507 MaxEncodedLen,
1508 TypeInfo,
1509)]
1510pub enum PrecisionWrapper {
1511 Exact,
1512 BestEffort,
1513}
1514
1515impl From<PrecisionWrapper> for Precision {
1516 fn from(value: PrecisionWrapper) -> Self {
1517 match value {
1518 PrecisionWrapper::Exact => Precision::Exact,
1519 PrecisionWrapper::BestEffort => Precision::BestEffort,
1520 }
1521 }
1522}
1523
1524impl<T: Config<I>, I: 'static> Default for DigestInfo<T, I> {
1529 fn default() -> Self {
1532 Self(Default::default())
1533 }
1534}
1535
1536impl<T: Config<I>, I: 'static> PartialEq for Commits<T, I> {
1537 fn eq(&self, other: &Self) -> bool {
1538 self.0 == other.0
1539 }
1540}
1541
1542impl<T: Config<I>, I: 'static> Eq for Commits<T, I> {}
1543
1544impl<T: Config<I>, I: 'static> PartialEq for EntryInfo<T, I> {
1545 fn eq(&self, other: &Self) -> bool {
1546 self.digest == other.digest && self.shares == other.shares && self.variant == other.variant
1547 }
1548}
1549
1550impl<T: Config<I>, I: 'static> Eq for EntryInfo<T, I> {}
1551
1552impl<T: Config<I>, I: 'static> core::fmt::Debug for EntryInfo<T, I> {
1553 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1554 f.debug_struct("EntryInfo")
1555 .field("digest", &self.digest)
1556 .field("shares", &self.shares)
1557 .field("variant", &self.variant)
1558 .finish()
1559 }
1560}
1561
1562impl<T: Config<I>, I: 'static> PartialEq for Entries<T, I> {
1563 fn eq(&self, other: &Self) -> bool {
1564 self.0 == other.0
1565 }
1566}
1567
1568impl<T: Config<I>, I: 'static> Eq for Entries<T, I> {}
1569
1570impl<T: Config<I>, I: 'static> core::fmt::Debug for Entries<T, I> {
1571 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1572 f.debug_tuple("Entries").field(&self.0).finish()
1573 }
1574}
1575
1576impl<T: Config<I>, I: 'static> Clone for Entries<T, I> {
1577 fn clone(&self) -> Self {
1578 Self(self.0.clone())
1579 }
1580}
1581
1582impl<T: Config<I>, I: 'static> core::fmt::Debug for IndexInfo<T, I> {
1583 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1584 f.debug_struct("IndexInfo")
1585 .field("principal", &self.principal)
1586 .field("capital", &self.capital)
1587 .field("entries", &self.entries)
1588 .finish()
1589 }
1590}
1591
1592impl<T: Config<I>, I: 'static> PartialEq for IndexInfo<T, I> {
1593 fn eq(&self, other: &Self) -> bool {
1594 self.principal == other.principal
1595 && self.capital == other.capital
1596 && self.entries == other.entries
1597 }
1598}
1599
1600impl<T: Config<I>, I: 'static> Eq for IndexInfo<T, I> {}
1601
1602impl<T: Config<I>, I: 'static> Clone for IndexInfo<T, I> {
1603 fn clone(&self) -> Self {
1604 Self {
1605 principal: self.principal,
1606 capital: self.capital,
1607 entries: self.entries.clone(),
1608 }
1609 }
1610}
1611
1612impl<T: Config<I>, I: 'static> PartialEq for SlotInfo<T, I> {
1613 fn eq(&self, other: &Self) -> bool {
1614 self.digest == other.digest
1615 && self.shares == other.shares
1616 && self.commit == other.commit
1617 && self.variant == other.variant
1618 }
1619}
1620
1621impl<T: Config<I>, I: 'static> Eq for SlotInfo<T, I> {}
1622
1623impl<T: Config<I>, I: 'static> core::fmt::Debug for SlotInfo<T, I> {
1624 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1625 f.debug_struct("SlotInfo")
1626 .field("digest", &self.digest)
1627 .field("shares", &self.shares)
1628 .field("commit", &self.commit)
1629 .field("variant", &self.variant)
1630 .finish()
1631 }
1632}
1633
1634impl<T: Config<I>, I: 'static> Clone for SlotInfo<T, I> {
1635 fn clone(&self) -> Self {
1636 Self {
1637 digest: self.digest.clone(),
1638 shares: self.shares,
1639 commit: self.commit.clone(),
1640 variant: self.variant.clone(),
1641 }
1642 }
1643}
1644
1645impl<T: Config<I>, I: 'static> PartialEq for Slots<T, I> {
1646 fn eq(&self, other: &Self) -> bool {
1647 self.0 == other.0
1648 }
1649}
1650
1651impl<T: Config<I>, I: 'static> core::fmt::Debug for Slots<T, I> {
1652 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1653 f.debug_tuple("Slots").field(&self.0.as_slice()).finish()
1654 }
1655}
1656
1657impl<T: Config<I>, I: 'static> Eq for Slots<T, I> {}
1658
1659impl<T: Config<I>, I: 'static> Clone for Slots<T, I> {
1660 fn clone(&self) -> Self {
1661 Self(self.0.clone())
1662 }
1663}
1664
1665impl<T: Config<I>, I: 'static> PartialEq for PoolInfo<T, I> {
1666 fn eq(&self, other: &Self) -> bool {
1667 self.balance_of == other.balance_of
1668 && self.capital == other.capital
1669 && self.commission == other.commission
1670 && self.slots == other.slots
1671 }
1672}
1673
1674impl<T: Config<I>, I: 'static> Eq for PoolInfo<T, I> {}
1675
1676impl<T: Config<I>, I: 'static> Clone for PoolInfo<T, I> {
1677 fn clone(&self) -> Self {
1678 Self {
1679 balance_of: self.balance_of.clone(),
1680 capital: self.capital,
1681 commission: self.commission,
1682 slots: self.slots.clone(),
1683 }
1684 }
1685}
1686
1687impl<T: Config<I>, I: 'static> core::fmt::Debug for PoolInfo<T, I> {
1688 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1689 f.debug_struct("PoolInfo")
1690 .field("balance_of", &self.balance_of)
1691 .field("capital", &self.capital)
1692 .field("commission", &self.commission)
1693 .field("slots", &self.slots)
1694 .finish()
1695 }
1696}
1697
1698impl<T: Config<I>, I: 'static> Clone for IndexOfReason<T, I> {
1699 fn clone(&self) -> Self {
1700 Self {
1701 reason: self.reason,
1702 index: self.index.clone(),
1703 }
1704 }
1705}
1706
1707impl<T: Config<I>, I: 'static> Clone for PoolOfReason<T, I> {
1708 fn clone(&self) -> Self {
1709 Self {
1710 reason: self.reason,
1711 pool: self.pool.clone(),
1712 }
1713 }
1714}
1715
1716impl<T: Config<I>, I: 'static> Clone for DigestVariant<T, I> {
1717 fn clone(&self) -> Self {
1718 match self {
1719 DigestVariant::Direct(d) => DigestVariant::Direct(d.clone()),
1720 DigestVariant::Index(d) => DigestVariant::Index(d.clone()),
1721 DigestVariant::Pool(d) => DigestVariant::Pool(d.clone()),
1722 DigestVariant::__Ignore(_) => {
1723 debug_assert!(false, "digest variant phantom variant accessed");
1724 DigestVariant::__Ignore(PhantomData)
1725 }
1726 }
1727 }
1728}
1729
1730impl<T: Config<I>, I: 'static> PartialEq for DigestVariant<T, I> {
1731 fn eq(&self, other: &Self) -> bool {
1732 match (self, other) {
1733 (DigestVariant::Direct(a), DigestVariant::Direct(b)) => a == b,
1734 (DigestVariant::Index(a), DigestVariant::Index(b)) => a == b,
1735 (DigestVariant::Pool(a), DigestVariant::Pool(b)) => a == b,
1736 (DigestVariant::__Ignore(_), DigestVariant::__Ignore(_)) => {
1737 debug_assert!(false, "digest variant phantom variant accessed");
1738 true
1739 }
1740 (DigestVariant::__Ignore(_), _) => {
1741 debug_assert!(false, "digest variant phantom variant accessed");
1742 false
1743 }
1744 (_, DigestVariant::__Ignore(_)) => {
1745 debug_assert!(false, "digest variant phantom variant accessed");
1746 false
1747 }
1748 _ => false,
1749 }
1750 }
1751}
1752
1753impl<T: Config<I>, I: 'static> Eq for DigestVariant<T, I> {}
1754
1755impl<T: Config<I>, I: 'static> Debug for DigestVariant<T, I> {
1756 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1757 match self {
1758 DigestVariant::Direct(d) => write!(f, "Direct({:?})", d),
1759 DigestVariant::Index(d) => write!(f, "Index({:?})", d),
1760 DigestVariant::Pool(d) => write!(f, "Pool({:?})", d),
1761 DigestVariant::__Ignore(_) => {
1762 debug_assert!(false, "digest variant phantom variant accessed");
1763 write!(f, "Invalid Digest Variant")
1764 }
1765 }
1766 }
1767}
1768
1769#[cfg(test)]
1774mod tests {
1775
1776 use crate::{
1782 balance::{balance_total, mint},
1783 mock::*,
1784 };
1785
1786 use frame_suite::{
1788 commitment::*,
1789 misc::{Directive, PositionIndex},
1790 };
1791
1792 use frame_support::{
1794 assert_err, assert_ok,
1795 traits::tokens::{Fortitude, Precision},
1796 };
1797
1798 #[test]
1803 fn digest_info_balances() {
1804 commit_test_ext().execute_with(|| {
1805 set_default_user_balance_and_standard_hold(ALICE).unwrap();
1806 set_default_user_balance_and_standard_hold(ALAN).unwrap();
1807 set_default_user_balance_and_standard_hold(BOB).unwrap();
1808
1809 let alice_position = Position::default();
1810 Pallet::place_commit(
1811 &ALICE,
1812 &ESCROW,
1813 &CONTRACT_FREELANCE,
1814 STANDARD_COMMIT,
1815 &Directive::new(Precision::BestEffort, Fortitude::Force),
1816 )
1817 .unwrap();
1818
1819 let alan_position = Position::position_of(1).unwrap();
1820 Pallet::place_commit_of_variant(
1821 &ALAN,
1822 &ESCROW,
1823 &CONTRACT_FREELANCE,
1824 LARGE_COMMIT,
1825 &alan_position,
1826 &Directive::new(Precision::BestEffort, Fortitude::Force),
1827 )
1828 .unwrap();
1829
1830 let bob_position = Position::position_of(2).unwrap();
1831 Pallet::place_commit_of_variant(
1832 &BOB,
1833 &GOVERNANCE,
1834 &PROPOSAL_TREASURY_SPEND,
1835 LARGE_COMMIT,
1836 &bob_position,
1837 &Directive::new(Precision::BestEffort, Fortitude::Force),
1838 )
1839 .unwrap();
1840
1841 let digest_info = DigestMap::get((ESCROW, CONTRACT_FREELANCE)).unwrap();
1842 let balances = digest_info.balances().unwrap();
1843 let alice_balances = balances.get(0).unwrap();
1845 assert_eq!(alice_balances.0, alice_position);
1846 let alice_bal = digest_info.get_balance(&alice_position).unwrap();
1847 assert_eq!(alice_balances.1, *alice_bal);
1848 let alan_balances = balances.get(1).unwrap();
1850 assert_eq!(alan_balances.0, alan_position);
1851 let alan_bal = digest_info.get_balance(&alan_position).unwrap();
1852 assert_eq!(alan_balances.1, *alan_bal);
1853
1854 let digest_info = DigestMap::get((GOVERNANCE, PROPOSAL_TREASURY_SPEND)).unwrap();
1856 let balances = digest_info.balances().unwrap();
1857 let bob_balances = balances.get(0).unwrap();
1859 assert_eq!(bob_balances.0, bob_position);
1860 let bob_bal = digest_info.get_balance(&bob_position).unwrap();
1861 assert_eq!(bob_balances.1, *bob_bal);
1862 })
1863 }
1864
1865 #[test]
1866 fn digest_info_get_balance() {
1867 commit_test_ext().execute_with(|| {
1868 set_default_user_balance_and_standard_hold(ALICE).unwrap();
1869
1870 let alice_position = Position::default();
1871 Pallet::place_commit(
1872 &ALICE,
1873 &ESCROW,
1874 &CONTRACT_FREELANCE,
1875 STANDARD_COMMIT,
1876 &Directive::new(Precision::BestEffort, Fortitude::Force),
1877 )
1878 .unwrap();
1879
1880 let digest_info = DigestMap::get((ESCROW, CONTRACT_FREELANCE)).unwrap();
1881 let alice_balance = digest_info.get_balance(&alice_position).unwrap();
1882
1883 let alice_bal_total =
1884 balance_total(alice_balance, &alice_position, &CONTRACT_FREELANCE).unwrap();
1885 assert_eq!(alice_bal_total, STANDARD_COMMIT);
1886 })
1887 }
1888
1889 #[test]
1890 fn digest_info_mut_balance() {
1891 commit_test_ext().execute_with(|| {
1892 set_default_user_balance_and_standard_hold(ALICE).unwrap();
1893
1894 let alice_position = Position::default();
1895 Pallet::place_commit(
1896 &ALICE,
1897 &ESCROW,
1898 &CONTRACT_FREELANCE,
1899 STANDARD_COMMIT,
1900 &Directive::new(Precision::BestEffort, Fortitude::Force),
1901 )
1902 .unwrap();
1903
1904 let mut digest_info = DigestMap::get((ESCROW, CONTRACT_FREELANCE)).unwrap();
1905 let alice_mut_balance = digest_info.mut_balance(&alice_position).unwrap();
1906
1907 let mint_val = 125;
1908 mint(
1909 alice_mut_balance,
1910 &alice_position,
1911 &CONTRACT_FREELANCE,
1912 &mint_val,
1913 &Directive::new(Precision::Exact, Fortitude::Force),
1914 )
1915 .unwrap();
1916 let alice_bal_total =
1917 balance_total(alice_mut_balance, &alice_position, &CONTRACT_FREELANCE).unwrap();
1918 assert_ne!(alice_bal_total, STANDARD_COMMIT);
1919
1920 assert_eq!(alice_bal_total, STANDARD_COMMIT + mint_val);
1921 })
1922 }
1923
1924 #[test]
1925 fn digest_info_reveal() {
1926 commit_test_ext().execute_with(|| {
1927 set_default_user_balance_and_standard_hold(ALICE).unwrap();
1928 set_default_user_balance_and_standard_hold(ALAN).unwrap();
1929 set_default_user_balance_and_standard_hold(BOB).unwrap();
1930
1931 let alice_position = Position::default();
1932 Pallet::place_commit(
1933 &ALICE,
1934 &ESCROW,
1935 &CONTRACT_FREELANCE,
1936 STANDARD_COMMIT,
1937 &Directive::new(Precision::BestEffort, Fortitude::Force),
1938 )
1939 .unwrap();
1940
1941 let alan_position = Position::position_of(1).unwrap();
1942 Pallet::place_commit_of_variant(
1943 &ALAN,
1944 &ESCROW,
1945 &CONTRACT_FREELANCE,
1946 LARGE_COMMIT,
1947 &alan_position,
1948 &Directive::new(Precision::BestEffort, Fortitude::Force),
1949 )
1950 .unwrap();
1951
1952 let bob_position = Position::position_of(2).unwrap();
1953 Pallet::place_commit_of_variant(
1954 &BOB,
1955 &GOVERNANCE,
1956 &PROPOSAL_TREASURY_SPEND,
1957 LARGE_COMMIT,
1958 &bob_position,
1959 &Directive::new(Precision::BestEffort, Fortitude::Force),
1960 )
1961 .unwrap();
1962
1963 let digest_info = DigestMap::get((ESCROW, CONTRACT_FREELANCE)).unwrap();
1964 let reveal_balances = digest_info.reveal();
1965
1966 assert_eq!(reveal_balances.len(), 2);
1967
1968 let alice_total_bal =
1969 balance_total(&reveal_balances[0], &alice_position, &CONTRACT_FREELANCE).unwrap();
1970 assert_eq!(alice_total_bal, STANDARD_COMMIT,);
1971
1972 let alan_total_bal =
1973 balance_total(&reveal_balances[1], &alan_position, &CONTRACT_FREELANCE).unwrap();
1974 assert_eq!(alan_total_bal, LARGE_COMMIT,);
1975
1976 let digest_info = DigestMap::get((GOVERNANCE, PROPOSAL_TREASURY_SPEND)).unwrap();
1977 let reveal_balances = digest_info.reveal();
1978
1979 assert_eq!(reveal_balances.len(), 3);
1980 assert_eq!(
1981 balance_total(&reveal_balances[0], &bob_position, &PROPOSAL_TREASURY_SPEND),
1982 Ok(0)
1983 );
1984 assert_eq!(
1985 balance_total(&reveal_balances[1], &bob_position, &PROPOSAL_TREASURY_SPEND),
1986 Ok(0)
1987 );
1988
1989 let bob_total_bal =
1990 balance_total(&reveal_balances[2], &bob_position, &PROPOSAL_TREASURY_SPEND)
1991 .unwrap();
1992 assert_eq!(bob_total_bal, LARGE_COMMIT,);
1993 })
1994 }
1995
1996 #[test]
1997 fn digest_info_init_balance() {
1998 commit_test_ext().execute_with(|| {
1999 let mut digest_info = DigestInfo::default();
2000
2001 let pos0 = Position::position_of(0).unwrap();
2002 let pos1 = Position::position_of(1).unwrap();
2003 let pos2 = Position::position_of(2).unwrap();
2004
2005 assert!(digest_info.get_balance(&pos0).is_none());
2007 assert!(digest_info.get_balance(&pos1).is_none());
2008 assert!(digest_info.get_balance(&pos2).is_none());
2009
2010 assert_ok!(digest_info.init_balance(&pos1));
2011
2012 assert!(digest_info.get_balance(&pos0).is_some());
2014 assert!(digest_info.get_balance(&pos1).is_some());
2015 assert!(digest_info.get_balance(&pos2).is_none());
2016
2017 assert_eq!(digest_info.reveal().len(), 2);
2018
2019 assert_ok!(digest_info.init_balance(&pos2));
2020 assert!(digest_info.get_balance(&pos2).is_some());
2021
2022 assert_eq!(digest_info.reveal().len(), 3);
2023 })
2024 }
2025
2026 #[test]
2031 fn commits_new_success() {
2032 commit_test_ext().execute_with(|| {
2033 let commit_ins = CommitInstance::default();
2034
2035 let commits = Commits::new(commit_ins.clone()).unwrap();
2036 assert_eq!(commits.0.len(), 1);
2037
2038 let init_commit = commits.0.get(0).unwrap();
2039 assert_eq!(init_commit.clone(), commit_ins);
2040 })
2041 }
2042
2043 #[test]
2044 fn commits_success() {
2045 commit_test_ext().execute_with(|| {
2046 let derive_bal_a = CommitInstance::default();
2047 let mut commits = Commits::new(derive_bal_a.clone()).unwrap();
2048
2049 let commits_vec = commits.commits();
2050 assert_eq!(commits_vec, vec![derive_bal_a.clone()]);
2051
2052 let derive_bal_b = CommitInstance::default();
2053 let derive_bal_c = CommitInstance::default();
2054 commits.add_commit(derive_bal_b.clone()).unwrap();
2055 commits.add_commit(derive_bal_c.clone()).unwrap();
2056
2057 let commits_vec = commits.commits();
2058 assert_eq!(commits_vec, vec![derive_bal_a, derive_bal_b, derive_bal_c]);
2059 })
2060 }
2061
2062 #[test]
2063 fn add_commit_success() {
2064 commit_test_ext().execute_with(|| {
2065 let derive_bal_a = CommitInstance::default();
2066 let mut commits = Commits::new(derive_bal_a.clone()).unwrap();
2067
2068 let commits_vec = commits.commits();
2069 assert_eq!(commits_vec, vec![derive_bal_a.clone()]);
2070
2071 let derive_bal_b = CommitInstance::default();
2072 let derive_bal_c = CommitInstance::default();
2073 commits.add_commit(derive_bal_b.clone()).unwrap();
2074 commits.add_commit(derive_bal_c.clone()).unwrap();
2075
2076 let commits_vec = commits.commits();
2077 assert_eq!(commits_vec, vec![derive_bal_a, derive_bal_b, derive_bal_c]);
2078
2079 let derive_bal_d = CommitInstance::default();
2080 assert_err!(commits.add_commit(derive_bal_d), Error::MaxCommitsReached);
2081 })
2082 }
2083
2084 #[test]
2089 fn commit_info_new_success() {
2090 commit_test_ext().execute_with(|| {
2091 let instance = CommitInstance::default();
2092 let variant = Position::position_of(0).unwrap();
2093 let commit_info = CommitInfo::new(VALIDATOR_ALPHA, instance.clone(), variant).unwrap();
2094
2095 assert_eq!(commit_info.commits().len(), 1);
2096 assert_eq!(commit_info.commits(), vec![instance]);
2097 assert_eq!(commit_info.digest(), VALIDATOR_ALPHA);
2098 assert_eq!(commit_info.variant(), variant);
2099 })
2100 }
2101
2102 #[test]
2103 fn commit_info_add_commit_success() {
2104 commit_test_ext().execute_with(|| {
2105 let instance_a = CommitInstance::default();
2106 let variant = Position::position_of(0).unwrap();
2107 let mut commit_info =
2108 CommitInfo::new(VALIDATOR_ALPHA, instance_a.clone(), variant).unwrap();
2109
2110 assert_eq!(commit_info.commits().len(), 1);
2111 assert_eq!(commit_info.commits(), vec![instance_a.clone()]);
2112
2113 let instance_b = CommitInstance::default();
2114 let instance_c = CommitInstance::default();
2115 commit_info.add_commit(instance_b.clone()).unwrap();
2116 commit_info.add_commit(instance_c.clone()).unwrap();
2117
2118 assert_eq!(commit_info.commits().len(), 3);
2119 assert_eq!(
2120 commit_info.commits(),
2121 vec![instance_a, instance_b, instance_c]
2122 );
2123 })
2124 }
2125
2126 #[test]
2131 fn entry_info_eq_true() {
2132 commit_test_ext().execute_with(|| {
2133 let variant = Position::position_of(0).unwrap();
2134 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2135 let entry_info_b = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2136
2137 assert!(entry_info_a.eq(&entry_info_b));
2138 })
2139 }
2140
2141 #[test]
2142 fn entry_info_eq_false() {
2143 commit_test_ext().execute_with(|| {
2144 let variant = Position::position_of(0).unwrap();
2145 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2146 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 100, variant).unwrap();
2147
2148 assert!(!entry_info_a.eq(&entry_info_b));
2149 })
2150 }
2151
2152 #[test]
2153 fn entry_info_new_success() {
2154 commit_test_ext().execute_with(|| {
2155 let variant = Position::position_of(0).unwrap();
2156 let entry_info = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2157
2158 assert_eq!(entry_info.digest(), VALIDATOR_ALPHA);
2159 assert_eq!(entry_info.shares, 100);
2160 assert_eq!(entry_info.variant(), variant);
2161 })
2162 }
2163
2164 #[test]
2165 fn entry_info_new_err_share_cannot_be_zero() {
2166 let variant = Position::position_of(0).unwrap();
2167 assert_err!(
2168 EntryInfo::new(VALIDATOR_ALPHA, 0, variant),
2169 Error::ShareCannotBeZero
2170 );
2171 }
2172
2173 #[test]
2178 fn entries_eq_true() {
2179 let variant = Position::position_of(0).unwrap();
2180 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2181 let entry_info_b = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2182
2183 let entries_a = Entries::new(vec![entry_info_a]).unwrap();
2184 let entries_b = Entries::new(vec![entry_info_b]).unwrap();
2185
2186 assert!(entries_a.eq(&entries_b));
2187 }
2188
2189 #[test]
2190 fn entries_eq_false() {
2191 let variant = Position::position_of(0).unwrap();
2192 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2193 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2194
2195 let entries_a = Entries::new(vec![entry_info_a]).unwrap();
2196 let entries_b = Entries::new(vec![entry_info_b]).unwrap();
2197
2198 assert!(!entries_a.eq(&entries_b));
2199 }
2200
2201 #[test]
2202 fn entries_new_success() {
2203 let variant = Position::position_of(0).unwrap();
2204 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2205 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2206 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2207
2208 let entries = Entries::new(vec![
2209 entry_info_a.clone(),
2210 entry_info_b.clone(),
2211 entry_info_c.clone(),
2212 ])
2213 .unwrap();
2214
2215 assert_eq!(entries.0.get(0), Some(&entry_info_a));
2216 assert_eq!(entries.0.get(1), Some(&entry_info_b));
2217 assert_eq!(entries.0.get(2), Some(&entry_info_c));
2218 assert_eq!(entries.0.get(3), None);
2219 }
2220
2221 #[test]
2222 fn entries_new_err_duplicate_entry() {
2223 let variant = Position::position_of(0).unwrap();
2224 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2225 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2226 let _entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2227
2228 let entries = Entries::new(vec![
2229 entry_info_a.clone(),
2230 entry_info_b.clone(),
2231 entry_info_b.clone(),
2232 ]);
2233
2234 assert!(entries.is_err());
2235 assert_err!(entries, Error::DuplicateEntry);
2236 }
2237
2238 #[test]
2239 fn entries_new_err_max_entries_reached() {
2240 let variant = Position::position_of(0).unwrap();
2241 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2242 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2243 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2244 let entry_info_d = EntryInfo::new(VALIDATOR_DELTA, 125, variant).unwrap();
2245
2246 let entries = Entries::new(vec![
2247 entry_info_a.clone(),
2248 entry_info_b.clone(),
2249 entry_info_c.clone(),
2250 entry_info_d.clone(),
2251 ]);
2252
2253 assert!(entries.is_err());
2254 assert_err!(entries, Error::MaxEntriesReached);
2255 }
2256
2257 #[test]
2258 fn entries_success() {
2259 let variant = Position::position_of(0).unwrap();
2260 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2261 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2262 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2263
2264 let entries = Entries::new(vec![
2265 entry_info_a.clone(),
2266 entry_info_b.clone(),
2267 entry_info_c.clone(),
2268 ])
2269 .unwrap();
2270
2271 let actual_entries = entries.entries();
2272 let expected_entries = vec![entry_info_a, entry_info_b, entry_info_c];
2273 assert_eq!(actual_entries, expected_entries);
2274 }
2275
2276 #[test]
2277 fn add_entry_success() {
2278 let variant = Position::position_of(0).unwrap();
2279 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2280
2281 let mut entries = Entries::new(vec![entry_info_a.clone()]).unwrap();
2282
2283 let actual_entries = entries.entries();
2284 let expected_entries = vec![entry_info_a.clone()];
2285 assert_eq!(actual_entries, expected_entries);
2286
2287 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2288 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2289
2290 entries.add_entry(entry_info_b.clone()).unwrap();
2291
2292 let actual_entries = entries.entries();
2293 let expected_entries = vec![entry_info_a.clone(), entry_info_b.clone()];
2294 assert_eq!(actual_entries, expected_entries);
2295
2296 entries.add_entry(entry_info_c.clone()).unwrap();
2297
2298 let actual_entries = entries.entries();
2299 let expected_entries = vec![entry_info_a, entry_info_b, entry_info_c];
2300 assert_eq!(actual_entries, expected_entries);
2301 }
2302
2303 #[test]
2304 fn add_entry_err_duplicate_entry() {
2305 let variant = Position::position_of(0).unwrap();
2306 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2307
2308 let mut entries = Entries::new(vec![entry_info_a.clone()]).unwrap();
2309
2310 assert_err!(entries.add_entry(entry_info_a), Error::DuplicateEntry);
2311 }
2312
2313 #[test]
2314 fn add_entry_err_max_entries_reached() {
2315 let variant = Position::position_of(0).unwrap();
2316 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2317 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2318 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2319
2320 let mut entries = Entries::new(vec![
2321 entry_info_a.clone(),
2322 entry_info_b.clone(),
2323 entry_info_c.clone(),
2324 ])
2325 .unwrap();
2326
2327 let entry_info_d = EntryInfo::new(VALIDATOR_DELTA, 125, variant).unwrap();
2328
2329 assert_err!(entries.add_entry(entry_info_d), Error::MaxEntriesReached);
2330 }
2331
2332 #[test]
2333 fn remove_entry_success() {
2334 let variant = Position::position_of(0).unwrap();
2335 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2336 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2337 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2338
2339 let mut entries = Entries::new(vec![
2340 entry_info_a.clone(),
2341 entry_info_b.clone(),
2342 entry_info_c.clone(),
2343 ])
2344 .unwrap();
2345
2346 let actual_entries = entries.entries();
2347 let expected_entries = vec![
2348 entry_info_a.clone(),
2349 entry_info_b.clone(),
2350 entry_info_c.clone(),
2351 ];
2352 assert_eq!(actual_entries, expected_entries);
2353
2354 entries.remove_entry(&VALIDATOR_ALPHA).unwrap();
2355
2356 let actual_entries = entries.entries();
2357 let expected_entries = vec![entry_info_b.clone(), entry_info_c.clone()];
2358 assert_eq!(actual_entries, expected_entries);
2359
2360 entries.remove_entry(&VALIDATOR_GAMMA).unwrap();
2361
2362 let actual_entries = entries.entries();
2363 let expected_entries = vec![entry_info_b.clone()];
2364 assert_eq!(actual_entries, expected_entries);
2365 }
2366
2367 #[test]
2368 fn remove_entry_err_entry_of_index_not_found() {
2369 let variant = Position::position_of(0).unwrap();
2370 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2371 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2372
2373 let mut entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2374
2375 assert_err!(
2376 entries.remove_entry(&VALIDATOR_GAMMA),
2377 Error::EntryOfIndexNotFound
2378 );
2379 }
2380
2381 #[test]
2382 fn remove_entry_err_empty_entries_not_allowed() {
2383 let variant = Position::position_of(0).unwrap();
2384 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2385
2386 let mut entries = Entries::new(vec![entry_info_a.clone()]).unwrap();
2387
2388 assert_err!(
2389 entries.remove_entry(&VALIDATOR_ALPHA),
2390 Error::EmptyEntriesNotAllowed
2391 );
2392 }
2393
2394 #[test]
2399 fn index_info_eq_true() {
2400 let variant = Position::position_of(0).unwrap();
2401 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2402 let entry_info_b = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2403
2404 let mut entries_a = Entries::new(vec![entry_info_a]).unwrap();
2405 let mut entries_b = Entries::new(vec![entry_info_b]).unwrap();
2406
2407 let index_info_a = IndexInfo::new(&mut entries_a).unwrap();
2408 let index_info_b = IndexInfo::new(&mut entries_b).unwrap();
2409
2410 assert!(index_info_a.eq(&index_info_b));
2411 }
2412
2413 #[test]
2414 fn index_info_eq_false() {
2415 let variant = Position::position_of(0).unwrap();
2416 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2417 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2418
2419 let mut entries_a = Entries::new(vec![entry_info_a]).unwrap();
2420 let mut entries_b = Entries::new(vec![entry_info_b]).unwrap();
2421
2422 let index_info_a = IndexInfo::new(&mut entries_a).unwrap();
2423 let index_info_b = IndexInfo::new(&mut entries_b).unwrap();
2424
2425 assert!(!index_info_a.eq(&index_info_b));
2426 }
2427
2428 #[test]
2429 fn index_info_new_success() {
2430 let variant = Position::position_of(0).unwrap();
2431 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2432 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2433
2434 let mut entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2435 let index_info = IndexInfo::new(&mut entries).unwrap();
2436
2437 assert_eq!(index_info.capital(), 150);
2438 assert_eq!(index_info.principal(), 0);
2439 assert_eq!(index_info.entries(), vec![entry_info_a, entry_info_b]);
2440 }
2441
2442 #[test]
2443 fn index_info_new_err_capital_overflowed() {
2444 let variant = Position::position_of(0).unwrap();
2445 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, MAX_SHARES, variant).unwrap();
2446 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2447
2448 let mut entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2449 let index_info = IndexInfo::new(&mut entries);
2450 assert!(index_info.is_err());
2451 assert_err!(index_info, Error::CapitalOverflowed);
2452 }
2453
2454 #[test]
2455 fn index_info_reveal_entries() {
2456 let variant = Position::position_of(0).unwrap();
2457 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2458 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2459
2460 let mut entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2461 let index_info = IndexInfo::new(&mut entries).unwrap();
2462
2463 let reveal_entries = index_info.reveal_entries();
2464 assert_eq!(reveal_entries, entries);
2465 }
2466
2467 #[test]
2468 fn entry_exists_success() {
2469 let variant = Position::position_of(0).unwrap();
2470 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2471 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2472
2473 let mut entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2474 let index_info = IndexInfo::new(&mut entries).unwrap();
2475
2476 assert_ok!(index_info.entry_exists(&VALIDATOR_ALPHA));
2477 assert_ok!(index_info.entry_exists(&VALIDATOR_BETA));
2478 }
2479
2480 #[test]
2481 fn entry_exists_err_entry_index_not_found() {
2482 let variant = Position::position_of(0).unwrap();
2483 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2484 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2485
2486 let mut entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2487 let index_info = IndexInfo::new(&mut entries).unwrap();
2488
2489 assert_err!(
2490 index_info.entry_exists(&VALIDATOR_GAMMA),
2491 Error::EntryOfIndexNotFound
2492 );
2493 }
2494
2495 #[test]
2500 fn slot_info_eq_true() {
2501 let variant = Position::position_of(0).unwrap();
2502
2503 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2504 let entry_info_b = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2505
2506 let slot_info_a: SlotInfo = entry_info_a.into();
2507 let slot_info_b: SlotInfo = entry_info_b.into();
2508
2509 assert!(slot_info_a.eq(&slot_info_b));
2510 }
2511
2512 #[test]
2513 fn slot_info_eq_false() {
2514 let variant = Position::position_of(0).unwrap();
2515
2516 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2517 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2518
2519 let slot_info_a: SlotInfo = entry_info_a.into();
2520 let slot_info_b: SlotInfo = entry_info_b.into();
2521
2522 assert!(!slot_info_a.eq(&slot_info_b));
2523 }
2524
2525 #[test]
2526 fn slot_info_from_entry_success() {
2527 let variant = Position::position_of(0).unwrap();
2528
2529 let entry = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2530
2531 let slot_info: SlotInfo = entry.clone().into();
2532
2533 assert_eq!(slot_info.digest(), VALIDATOR_ALPHA);
2534 assert_eq!(slot_info.shares(), 100);
2535 assert_eq!(slot_info.variant(), variant);
2536
2537 let default_commit = CommitInstance::default();
2538 assert_eq!(slot_info.commit(), default_commit);
2539 }
2540
2541 #[test]
2542 fn slot_info_set_slot_commit() {
2543 commit_test_ext().execute_with(|| {
2544 set_default_user_balance_and_standard_hold(ALICE).unwrap();
2545 let variant = Position::position_of(0).unwrap();
2546 let entry = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2547 let mut slot_info: SlotInfo = entry.clone().into();
2548
2549 let default_commit = CommitInstance::default();
2550 assert_eq!(slot_info.commit(), default_commit);
2551
2552 let alice_position = Position::position_of(1).unwrap();
2553 Pallet::place_commit_of_variant(
2554 &ALICE,
2555 &GOVERNANCE,
2556 &PROPOSAL_TREASURY_SPEND,
2557 LARGE_COMMIT,
2558 &alice_position,
2559 &Directive::new(Precision::BestEffort, Fortitude::Force),
2560 )
2561 .unwrap();
2562
2563 let commit_info = CommitMap::get((ALICE, GOVERNANCE)).unwrap();
2564 let new_instance = commit_info.commits.0.get(0).unwrap();
2565
2566 slot_info.set_slot_commit(new_instance.clone());
2567 assert_ne!(slot_info.commit(), default_commit);
2568 assert_eq!(slot_info.commit(), new_instance.clone());
2569 })
2570 }
2571
2572 #[test]
2577 fn slots_eq_true() {
2578 let variant = Position::position_of(0).unwrap();
2579
2580 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2581 let entry_info_b = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2582
2583 let entries_a = Entries::new(vec![entry_info_a]).unwrap();
2584 let entries_b = Entries::new(vec![entry_info_b]).unwrap();
2585
2586 let slots_a = Slots::try_from(entries_a).unwrap();
2587 let slots_b = Slots::try_from(entries_b).unwrap();
2588
2589 assert!(slots_a.eq(&slots_b));
2590 }
2591
2592 #[test]
2593 fn slots_eq_false() {
2594 let variant = Position::position_of(0).unwrap();
2595
2596 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2597 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2598
2599 let entries_a = Entries::new(vec![entry_info_a]).unwrap();
2600 let entries_b = Entries::new(vec![entry_info_b]).unwrap();
2601
2602 let slots_a = Slots::try_from(entries_a).unwrap();
2603 let slots_b = Slots::try_from(entries_b).unwrap();
2604
2605 assert!(!slots_a.eq(&slots_b));
2606 }
2607
2608 #[test]
2609 fn slots_success() {
2610 let variant = Position::position_of(0).unwrap();
2611
2612 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2613 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2614 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2615
2616 let entries = Entries::new(vec![
2617 entry_info_a.clone(),
2618 entry_info_b.clone(),
2619 entry_info_c.clone(),
2620 ])
2621 .unwrap();
2622
2623 let slots = Slots::try_from(entries).unwrap();
2624 let slot_info_a: SlotInfo = entry_info_a.into();
2625 let slot_info_b: SlotInfo = entry_info_b.into();
2626 let slot_info_c: SlotInfo = entry_info_c.into();
2627
2628 let actual_slots = slots.slots();
2629 let expected_slots = vec![slot_info_a, slot_info_b, slot_info_c];
2630 assert_eq!(actual_slots, expected_slots);
2631 }
2632
2633 #[test]
2634 fn add_slot_success() {
2635 let variant = Position::position_of(0).unwrap();
2636
2637 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2638 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2639 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2640
2641 let entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2642
2643 let mut slots = Slots::try_from(entries).unwrap();
2644 let slot_info_a: SlotInfo = entry_info_a.into();
2645 let slot_info_b: SlotInfo = entry_info_b.into();
2646
2647 let actual_slots = slots.slots();
2648 let expected_slots = vec![slot_info_a.clone(), slot_info_b.clone()];
2649 assert_eq!(actual_slots, expected_slots);
2650
2651 slots.add_slot(entry_info_c.clone()).unwrap();
2652
2653 let slot_info_c: SlotInfo = entry_info_c.into();
2654
2655 let actual_slots = slots.slots();
2656 let expected_slots = vec![slot_info_a, slot_info_b, slot_info_c];
2657 assert_eq!(actual_slots, expected_slots);
2658 }
2659
2660 #[test]
2661 fn add_slot_err_max_slots_reached() {
2662 let variant = Position::position_of(0).unwrap();
2663
2664 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2665 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2666 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2667 let entry_info_d = EntryInfo::new(VALIDATOR_DELTA, 125, variant).unwrap();
2668
2669 let entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2670
2671 let mut slots = Slots::try_from(entries).unwrap();
2672
2673 slots.add_slot(entry_info_c.clone()).unwrap();
2674
2675 assert_err!(slots.add_slot(entry_info_d), Error::MaxSlotsReached);
2676 }
2677
2678 #[test]
2679 fn add_slot_err_duplicate_slot() {
2680 let variant = Position::position_of(0).unwrap();
2681
2682 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2683 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2684 let _entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2685
2686 let entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2687
2688 let mut slots = Slots::try_from(entries).unwrap();
2689
2690 assert_err!(slots.add_slot(entry_info_b), Error::DuplicateSlot);
2691 }
2692
2693 #[test]
2694 fn remove_slot_success() {
2695 let variant = Position::position_of(0).unwrap();
2696 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2697 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2698 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2699
2700 let entries = Entries::new(vec![
2701 entry_info_a.clone(),
2702 entry_info_b.clone(),
2703 entry_info_c.clone(),
2704 ])
2705 .unwrap();
2706 let mut slots = Slots::try_from(entries).unwrap();
2707 let slot_info_a: SlotInfo = entry_info_a.into();
2708 let slot_info_b: SlotInfo = entry_info_b.into();
2709 let slot_info_c: SlotInfo = entry_info_c.into();
2710
2711 let actual_slots = slots.slots();
2712 let expected_slots = vec![
2713 slot_info_a.clone(),
2714 slot_info_b.clone(),
2715 slot_info_c.clone(),
2716 ];
2717 assert_eq!(actual_slots, expected_slots);
2718
2719 slots.remove_slot(&VALIDATOR_ALPHA).unwrap();
2720
2721 let actual_slots = slots.slots();
2722 let expected_slots = vec![slot_info_b.clone(), slot_info_c.clone()];
2723 assert_eq!(actual_slots, expected_slots);
2724
2725 slots.remove_slot(&VALIDATOR_GAMMA).unwrap();
2726
2727 let actual_slots = slots.slots();
2728 let expected_slots = vec![slot_info_b.clone()];
2729 assert_eq!(actual_slots, expected_slots);
2730 }
2731
2732 #[test]
2733 fn remove_slot_err_slot_of_pool_not_found() {
2734 let variant = Position::position_of(0).unwrap();
2735 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2736 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2737
2738 let entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2739
2740 let mut slots = Slots::try_from(entries).unwrap();
2741
2742 assert_err!(
2743 slots.remove_slot(&VALIDATOR_GAMMA),
2744 Error::SlotOfPoolNotFound
2745 );
2746 }
2747
2748 #[test]
2749 fn remove_slot_err_empty_slots_not_allowed() {
2750 let variant = Position::position_of(0).unwrap();
2751 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2752
2753 let entries = Entries::new(vec![entry_info_a.clone()]).unwrap();
2754
2755 let mut slots = Slots::try_from(entries).unwrap();
2756
2757 assert_err!(
2758 slots.remove_slot(&VALIDATOR_ALPHA),
2759 Error::EmptySlotsNotAllowed
2760 );
2761 }
2762
2763 #[test]
2764 fn set_slot_commit_success() {
2765 commit_test_ext().execute_with(|| {
2766 set_default_user_balance_and_standard_hold(ALICE).unwrap();
2767 let alice_position = Position::position_of(1).unwrap();
2768 Pallet::place_commit_of_variant(
2769 &ALICE,
2770 &GOVERNANCE,
2771 &PROPOSAL_TREASURY_SPEND,
2772 LARGE_COMMIT,
2773 &alice_position,
2774 &Directive::new(Precision::BestEffort, Fortitude::Force),
2775 )
2776 .unwrap();
2777
2778 let commit_info = CommitMap::get((ALICE, GOVERNANCE)).unwrap();
2779 let new_instance = commit_info.commits.0.get(0).unwrap();
2780
2781 let variant = Position::position_of(0).unwrap();
2782
2783 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2784 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2785 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 75, variant).unwrap();
2786
2787 let entries = Entries::new(vec![
2788 entry_info_a.clone(),
2789 entry_info_b.clone(),
2790 entry_info_c.clone(),
2791 ])
2792 .unwrap();
2793
2794 let mut slots = Slots::try_from(entries).unwrap();
2795 let slot_info_a: SlotInfo = entry_info_a.into();
2796 let slot_info_b: SlotInfo = entry_info_b.into();
2797 let slot_info_c: SlotInfo = entry_info_c.into();
2798
2799 let actual_slots = slots.slots();
2800 let expected_slots = vec![
2801 slot_info_a.clone(),
2802 slot_info_b.clone(),
2803 slot_info_c.clone(),
2804 ];
2805 assert_eq!(actual_slots, expected_slots);
2806
2807 slots
2808 .set_slot_commit(&VALIDATOR_BETA, new_instance.clone())
2809 .unwrap();
2810
2811 let actual_slots = slots.slots();
2812 let new_slot_b = &actual_slots[1];
2813 assert_ne!(new_slot_b.clone(), slot_info_b.clone());
2814 let expected_slots = vec![slot_info_a.clone(), new_slot_b.clone(), slot_info_c.clone()];
2815 assert_eq!(actual_slots, expected_slots);
2816 })
2817 }
2818
2819 #[test]
2820 fn set_slot_commit_err_slot_of_pool_not_found() {
2821 commit_test_ext().execute_with(|| {
2822 set_default_user_balance_and_standard_hold(ALICE).unwrap();
2823 let alice_position = Position::position_of(1).unwrap();
2824 Pallet::place_commit_of_variant(
2825 &ALICE,
2826 &GOVERNANCE,
2827 &PROPOSAL_TREASURY_SPEND,
2828 LARGE_COMMIT,
2829 &alice_position,
2830 &Directive::new(Precision::BestEffort, Fortitude::Force),
2831 )
2832 .unwrap();
2833
2834 let commit_info = CommitMap::get((ALICE, GOVERNANCE)).unwrap();
2835 let new_instance = commit_info.commits.0.get(0).unwrap();
2836
2837 let variant = Position::position_of(0).unwrap();
2838
2839 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2840 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2841
2842 let entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2843
2844 let mut slots = Slots::try_from(entries).unwrap();
2845 let slot_info_a: SlotInfo = entry_info_a.into();
2846 let slot_info_b: SlotInfo = entry_info_b.into();
2847
2848 let actual_slots = slots.slots();
2849 let expected_slots = vec![slot_info_a.clone(), slot_info_b.clone()];
2850 assert_eq!(actual_slots, expected_slots);
2851
2852 let result = slots.set_slot_commit(&VALIDATOR_GAMMA, new_instance.clone());
2853 assert_err!(result, Error::SlotOfPoolNotFound);
2854 })
2855 }
2856
2857 #[test]
2862 fn pool_info_eq_true() {
2863 let variant = Position::position_of(0).unwrap();
2864
2865 let entry_info = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2866 let entries = Entries::new(vec![entry_info]).unwrap();
2867
2868 let pool_info_a = PoolInfo::new(entries.clone(), COMMISSION_ZERO).unwrap();
2869 let pool_info_b = PoolInfo::new(entries, COMMISSION_ZERO).unwrap();
2870
2871 assert!(pool_info_a.eq(&pool_info_b));
2872 }
2873
2874 #[test]
2875 fn pool_info_eq_false() {
2876 let variant = Position::position_of(0).unwrap();
2877 let entry_info = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2878 let entries = Entries::new(vec![entry_info]).unwrap();
2879
2880 let pool_info_a = PoolInfo::new(entries.clone(), COMMISSION_ZERO).unwrap();
2881 let pool_info_b = PoolInfo::new(entries, COMMISSION_STANDARD).unwrap();
2882
2883 assert!(!pool_info_a.eq(&pool_info_b));
2884 }
2885
2886 #[test]
2887 fn pool_info_new_success() {
2888 let variant = Position::position_of(0).unwrap();
2889
2890 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2891 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2892
2893 let entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2894
2895 let pool = PoolInfo::new(entries, COMMISSION_STANDARD).unwrap();
2896 let slot_info_a: SlotInfo = entry_info_a.into();
2897 let slot_info_b: SlotInfo = entry_info_b.into();
2898
2899 assert_eq!(pool.balance_of, LazyBalance::default());
2900 assert_eq!(pool.capital(), 150);
2901 assert_eq!(pool.commission, COMMISSION_STANDARD);
2902 assert_eq!(pool.slots().len(), 2);
2903 assert_eq!(pool.slots(), vec![slot_info_a, slot_info_b]);
2904 }
2905
2906 #[test]
2907 fn pool_info_new_err_capital_overflowed() {
2908 let variant = Position::position_of(0).unwrap();
2909
2910 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, MAX_SHARES, variant).unwrap();
2911 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2912
2913 let entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2914
2915 let pool = PoolInfo::new(entries, COMMISSION_STANDARD);
2916 assert!(pool.is_err());
2917 assert_err!(pool, Error::CapitalOverflowed);
2918 }
2919
2920 #[test]
2921 fn pool_info_slots_success() {
2922 let variant = Position::position_of(0).unwrap();
2923
2924 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2925 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 50, variant).unwrap();
2926 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 150, variant).unwrap();
2927
2928 let entries = Entries::new(vec![
2929 entry_info_a.clone(),
2930 entry_info_b.clone(),
2931 entry_info_c.clone(),
2932 ])
2933 .unwrap();
2934
2935 let pool = PoolInfo::new(entries, COMMISSION_STANDARD).unwrap();
2936 let slot_info_a: SlotInfo = entry_info_a.into();
2937 let slot_info_b: SlotInfo = entry_info_b.into();
2938 let slot_info_c: SlotInfo = entry_info_c.into();
2939
2940 let actual_slots = pool.slots();
2941 let expected_slots = vec![slot_info_a, slot_info_b, slot_info_c];
2942 assert_eq!(actual_slots, expected_slots);
2943 }
2944
2945 #[test]
2946 fn pool_info_balance_reset_success() {
2947 let variant = Position::position_of(0).unwrap();
2948 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2949 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 200, variant).unwrap();
2950
2951 let entries = Entries::new(vec![entry_info_a, entry_info_b]).unwrap();
2952 let mut pool = PoolInfo::new(entries, COMMISSION_ZERO).unwrap();
2953
2954 pool.balance_reset();
2955
2956 assert_eq!(pool.balance_of, Default::default());
2957
2958 for slot in pool.slots() {
2959 assert_eq!(slot.commit(), Default::default());
2960 }
2961 }
2962
2963 #[test]
2964 fn pool_info_add_slot_success() {
2965 let variant = Position::position_of(0).unwrap();
2966
2967 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2968 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 100, variant).unwrap();
2969
2970 let entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
2971
2972 let mut pool = PoolInfo::new(entries, COMMISSION_ZERO).unwrap();
2973 let slot_info_a: SlotInfo = entry_info_a.into();
2974 let slot_info_b: SlotInfo = entry_info_b.into();
2975
2976 assert_eq!(pool.capital(), 200);
2977 assert_eq!(pool.slots().len(), 2);
2978
2979 let actual_slots = pool.slots();
2980 let expected_slots = vec![slot_info_a.clone(), slot_info_b.clone()];
2981 assert_eq!(actual_slots, expected_slots);
2982
2983 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 50, variant).unwrap();
2984 assert_ok!(pool.add_slot(entry_info_c.clone()));
2985 let slot_info_c: SlotInfo = entry_info_c.into();
2986
2987 assert_eq!(pool.capital(), 250);
2988 assert_eq!(pool.slots().len(), 3);
2989 let actual_slots = pool.slots();
2990 let expected_slots = vec![slot_info_a.clone(), slot_info_b.clone(), slot_info_c];
2991 assert_eq!(actual_slots, expected_slots);
2992 }
2993
2994 #[test]
2995 fn pool_info_add_slot_err_capital_overflowed() {
2996 let variant = Position::position_of(0).unwrap();
2997
2998 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
2999 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 100, variant).unwrap();
3000
3001 let entries = Entries::new(vec![entry_info_a.clone(), entry_info_b.clone()]).unwrap();
3002
3003 let mut pool = PoolInfo::new(entries, COMMISSION_ZERO).unwrap();
3004 let slot_info_a: SlotInfo = entry_info_a.into();
3005 let slot_info_b: SlotInfo = entry_info_b.into();
3006
3007 assert_eq!(pool.capital(), 200);
3008 assert_eq!(pool.slots().len(), 2);
3009
3010 let actual_slots = pool.slots();
3011 let expected_slots = vec![slot_info_a.clone(), slot_info_b.clone()];
3012 assert_eq!(actual_slots, expected_slots);
3013
3014 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, MAX_SHARES, variant).unwrap();
3015 assert_err!(pool.add_slot(entry_info_c), Error::CapitalOverflowed);
3016 }
3017
3018 #[test]
3019 fn pool_info_remove_slot_success() {
3020 let variant = Position::position_of(0).unwrap();
3021
3022 let entry_info_a = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
3023 let entry_info_b = EntryInfo::new(VALIDATOR_BETA, 100, variant).unwrap();
3024 let entry_info_c = EntryInfo::new(VALIDATOR_GAMMA, 50, variant).unwrap();
3025
3026 let entries = Entries::new(vec![
3027 entry_info_a.clone(),
3028 entry_info_b.clone(),
3029 entry_info_c.clone(),
3030 ])
3031 .unwrap();
3032
3033 let mut pool = PoolInfo::new(entries, COMMISSION_ZERO).unwrap();
3034 let slot_info_a: SlotInfo = entry_info_a.into();
3035 let slot_info_b: SlotInfo = entry_info_b.into();
3036 let slot_info_c: SlotInfo = entry_info_c.into();
3037
3038 assert_eq!(pool.capital(), 250);
3039 assert_eq!(pool.slots().len(), 3);
3040
3041 let actual_slots = pool.slots();
3042 let expected_slots = vec![
3043 slot_info_a.clone(),
3044 slot_info_b.clone(),
3045 slot_info_c.clone(),
3046 ];
3047 assert_eq!(actual_slots, expected_slots);
3048
3049 pool.remove_slot(&VALIDATOR_ALPHA).unwrap();
3050 let actual_slots = pool.slots();
3051 let expected_slots = vec![slot_info_b.clone(), slot_info_c.clone()];
3052 assert_eq!(actual_slots, expected_slots);
3053
3054 assert_eq!(pool.capital(), 150);
3055 assert_eq!(pool.slots().len(), 2);
3056
3057 pool.remove_slot(&VALIDATOR_GAMMA).unwrap();
3058 let actual_slots = pool.slots();
3059 let expected_slots = vec![slot_info_b.clone()];
3060 assert_eq!(actual_slots, expected_slots);
3061
3062 assert_eq!(pool.capital(), 100);
3063 assert_eq!(pool.slots().len(), 1);
3064 }
3065
3066 #[test]
3067 fn pool_info_slot_exists_success() {
3068 let variant = Position::position_of(0).unwrap();
3069
3070 let entry_info = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
3071 let entries = Entries::new(vec![entry_info]).unwrap();
3072
3073 let pool = PoolInfo::new(entries, COMMISSION_ZERO).unwrap();
3074
3075 assert_ok!(pool.slot_exists(&VALIDATOR_ALPHA));
3076 }
3077
3078 #[test]
3079 fn pool_info_slot_exists_err_not_found() {
3080 let variant = Position::position_of(0).unwrap();
3081
3082 let entry_info = EntryInfo::new(VALIDATOR_ALPHA, 100, variant).unwrap();
3083 let entries = Entries::new(vec![entry_info]).unwrap();
3084
3085 let pool = PoolInfo::new(entries, COMMISSION_ZERO).unwrap();
3086
3087 assert_err!(pool.slot_exists(&VALIDATOR_BETA), Error::SlotOfPoolNotFound);
3088 }
3089}