Skip to content
This repository was archived by the owner on Sep 28, 2023. It is now read-only.

Commit 7b9d613

Browse files
committed
Types UTs
1 parent 6a1b9fa commit 7b9d613

3 files changed

Lines changed: 178 additions & 5 deletions

File tree

frame/dapp-staking-v3/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ pub mod pallet {
434434
/// Only the amount that isn't actively used for staking can be unlocked.
435435
/// If the amount is greater than the available amount for unlocking, everything is unlocked.
436436
/// If the remaining locked amount would take the account below the minimum locked amount, everything is unlocked.
437-
#[pallet::call_index(5)]
437+
#[pallet::call_index(6)]
438438
#[pallet::weight(Weight::zero())]
439439
pub fn unlock(
440440
origin: OriginFor<T>,

frame/dapp-staking-v3/src/test/tests_types.rs

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,18 @@ fn account_ledger_add_lock_amount_works() {
6464
// First step, sanity checks
6565
let first_era = 1;
6666
assert!(acc_ledger.active_locked_amount().is_zero());
67+
assert!(acc_ledger.total_locked_amount().is_zero());
6768
assert!(acc_ledger.add_lock_amount(0, first_era).is_ok());
6869
assert!(acc_ledger.active_locked_amount().is_zero());
6970

7071
// Adding lock value works as expected
7172
let init_amount = 20;
7273
assert!(acc_ledger.add_lock_amount(init_amount, first_era).is_ok());
7374
assert_eq!(acc_ledger.active_locked_amount(), init_amount);
75+
assert_eq!(acc_ledger.total_locked_amount(), init_amount);
7476
assert_eq!(acc_ledger.lock_era(), first_era);
7577
assert!(!acc_ledger.is_empty());
78+
assert_eq!(acc_ledger.locked.len(), 1);
7679
assert_eq!(
7780
acc_ledger.latest_locked_chunk(),
7881
Some(&LockedChunk::<Balance> {
@@ -85,7 +88,9 @@ fn account_ledger_add_lock_amount_works() {
8588
let addition = 7;
8689
assert!(acc_ledger.add_lock_amount(addition, first_era).is_ok());
8790
assert_eq!(acc_ledger.active_locked_amount(), init_amount + addition);
91+
assert_eq!(acc_ledger.total_locked_amount(), init_amount + addition);
8892
assert_eq!(acc_ledger.lock_era(), first_era);
93+
assert_eq!(acc_ledger.locked.len(), 1);
8994

9095
// Add up to storage limit
9196
for i in 2..=LockedDummy::get() {
@@ -95,11 +100,178 @@ fn account_ledger_add_lock_amount_works() {
95100
init_amount + addition * i as u128
96101
);
97102
assert_eq!(acc_ledger.lock_era(), first_era + i);
103+
assert_eq!(acc_ledger.locked.len(), i as usize);
98104
}
99105

100106
// Any further additions should fail due to exhausting bounded storage capacity
101107
assert!(acc_ledger
102108
.add_lock_amount(addition, acc_ledger.lock_era() + 1)
103109
.is_err());
104110
assert!(!acc_ledger.is_empty());
111+
assert_eq!(acc_ledger.locked.len(), LockedDummy::get() as usize);
112+
}
113+
114+
#[test]
115+
fn account_ledger_subtract_lock_amount_basic_usage_works() {
116+
get_u32_type!(LockedDummy, 5);
117+
get_u32_type!(UnlockingDummy, 5);
118+
let mut acc_ledger =
119+
AccountLedger::<Balance, BlockNumber, LockedDummy, UnlockingDummy>::default();
120+
121+
// Sanity check scenario
122+
// Cannot reduce if there is nothing locked, should be a noop
123+
assert!(acc_ledger.subtract_lock_amount(0, 1).is_ok());
124+
assert!(acc_ledger.subtract_lock_amount(10, 1).is_ok());
125+
assert!(acc_ledger.locked.len().is_zero());
126+
assert!(acc_ledger.is_empty());
127+
128+
// First basic scenario
129+
// Add some lock amount, then reduce it for the same era
130+
let first_era = 1;
131+
let first_lock_amount = 19;
132+
let unlock_amount = 7;
133+
assert!(acc_ledger
134+
.add_lock_amount(first_lock_amount, first_era)
135+
.is_ok());
136+
assert!(acc_ledger
137+
.subtract_lock_amount(unlock_amount, first_era)
138+
.is_ok());
139+
assert_eq!(acc_ledger.locked.len(), 1);
140+
assert_eq!(
141+
acc_ledger.total_locked_amount(),
142+
first_lock_amount - unlock_amount
143+
);
144+
assert_eq!(
145+
acc_ledger.active_locked_amount(),
146+
first_lock_amount - unlock_amount
147+
);
148+
assert_eq!(acc_ledger.unlocking_amount(), 0);
149+
150+
// Second basic scenario
151+
// Reduce the lock from the era which isn't latest in the vector
152+
let first_lock_amount = first_lock_amount - unlock_amount;
153+
let second_lock_amount = 31;
154+
let second_era = 2;
155+
assert!(acc_ledger
156+
.add_lock_amount(second_lock_amount - first_lock_amount, second_era)
157+
.is_ok());
158+
assert_eq!(acc_ledger.active_locked_amount(), second_lock_amount);
159+
assert_eq!(acc_ledger.locked.len(), 2);
160+
161+
// Subtract from the first era and verify state is as expected
162+
assert!(acc_ledger
163+
.subtract_lock_amount(unlock_amount, first_era)
164+
.is_ok());
165+
assert_eq!(acc_ledger.locked.len(), 2);
166+
assert_eq!(
167+
acc_ledger.active_locked_amount(),
168+
second_lock_amount - unlock_amount
169+
);
170+
assert_eq!(
171+
acc_ledger.locked[0].amount,
172+
first_lock_amount - unlock_amount
173+
);
174+
assert_eq!(
175+
acc_ledger.locked[1].amount,
176+
second_lock_amount - unlock_amount
177+
);
178+
179+
// Third basic scenario
180+
// Reduce the the latest era, don't expect the first one to change
181+
assert!(acc_ledger
182+
.subtract_lock_amount(unlock_amount, second_era)
183+
.is_ok());
184+
assert_eq!(acc_ledger.locked.len(), 2);
185+
assert_eq!(
186+
acc_ledger.active_locked_amount(),
187+
second_lock_amount - unlock_amount * 2
188+
);
189+
assert_eq!(
190+
acc_ledger.locked[0].amount,
191+
first_lock_amount - unlock_amount
192+
);
193+
assert_eq!(
194+
acc_ledger.locked[1].amount,
195+
second_lock_amount - unlock_amount * 2
196+
);
197+
}
198+
199+
#[test]
200+
fn account_ledger_subtract_lock_amount_overflow_fails() {
201+
get_u32_type!(LockedDummy, 5);
202+
get_u32_type!(UnlockingDummy, 5);
203+
let mut acc_ledger =
204+
AccountLedger::<Balance, BlockNumber, LockedDummy, UnlockingDummy>::default();
205+
206+
let first_lock_amount = 17 * 19;
207+
let era = 1;
208+
let unlock_amount = 5;
209+
assert!(acc_ledger.add_lock_amount(first_lock_amount, era).is_ok());
210+
for idx in 1..=LockedDummy::get() {
211+
assert!(acc_ledger.subtract_lock_amount(unlock_amount, idx).is_ok());
212+
assert_eq!(acc_ledger.locked.len(), idx as usize);
213+
assert_eq!(
214+
acc_ledger.active_locked_amount(),
215+
first_lock_amount - unlock_amount * idx as u128
216+
);
217+
}
218+
219+
// Updating existing lock should still work
220+
for _ in 1..10 {
221+
assert!(acc_ledger
222+
.subtract_lock_amount(unlock_amount, LockedDummy::get())
223+
.is_ok());
224+
}
225+
226+
// Attempt to add additional chunks should fail.
227+
assert!(acc_ledger
228+
.subtract_lock_amount(unlock_amount, LockedDummy::get() + 1)
229+
.is_err());
230+
}
231+
232+
#[test]
233+
fn account_ledger_subtract_lock_amount_advanced_example_works() {
234+
get_u32_type!(LockedDummy, 5);
235+
get_u32_type!(UnlockingDummy, 5);
236+
let mut acc_ledger =
237+
AccountLedger::<Balance, BlockNumber, LockedDummy, UnlockingDummy>::default();
238+
239+
// Prepare an example where we have two non-consecutive entries, and we unlock in the era right before the second entry.
240+
// This covers a scenario where user has locked in the current era,
241+
// creating an entry for the next era, and then decides to immediately unlock.
242+
let first_lock_amount = 17;
243+
let second_lock_amount = 23;
244+
let first_era = 1;
245+
let second_era = 5;
246+
let unlock_era = second_era - 1;
247+
let unlock_amount = 5;
248+
assert!(acc_ledger
249+
.add_lock_amount(first_lock_amount, first_era)
250+
.is_ok());
251+
assert!(acc_ledger
252+
.add_lock_amount(second_lock_amount, second_era)
253+
.is_ok());
254+
assert_eq!(acc_ledger.locked.len(), 2);
255+
256+
assert!(acc_ledger
257+
.subtract_lock_amount(unlock_amount, unlock_era)
258+
.is_ok());
259+
assert_eq!(
260+
acc_ledger.active_locked_amount(),
261+
first_lock_amount + second_lock_amount - unlock_amount
262+
);
263+
264+
// Check entries in more detail
265+
assert_eq!(acc_ledger.locked.len(), 3);
266+
assert_eq!(acc_ledger.locked[0].amount, first_lock_amount,);
267+
assert_eq!(
268+
acc_ledger.locked[2].amount,
269+
first_lock_amount + second_lock_amount - unlock_amount
270+
);
271+
// Verify the new entry
272+
assert_eq!(
273+
acc_ledger.locked[1].amount,
274+
first_lock_amount - unlock_amount
275+
);
276+
assert_eq!(acc_ledger.locked[1].era, unlock_era);
105277
}

frame/dapp-staking-v3/src/types.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ where
144144
}
145145
}
146146

147-
// TODO: would users get better UX if we kept using eras? Using blocks is more precise though.
148147
/// How much was unlocked in some block.
149148
#[derive(Encode, Decode, MaxEncodedLen, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)]
150149
pub struct UnlockingChunk<
@@ -337,18 +336,20 @@ where
337336

338337
// Update existing or insert a new chunk
339338
let mut inner = self.locked.clone().into_inner();
340-
if inner[index].era == era {
339+
let relevant_chunk_index = if inner[index].era == era {
341340
inner[index].amount.saturating_reduce(amount);
341+
index
342342
} else {
343343
let mut chunk = inner[index];
344344
chunk.amount.saturating_reduce(amount);
345345
chunk.era = era;
346346

347347
inner.insert(index + 1, chunk);
348-
}
348+
index + 1
349+
};
349350

350351
// Update all chunks after the relevant one, and remove zero chunks
351-
inner[index + 1..]
352+
inner[relevant_chunk_index + 1..]
352353
.iter_mut()
353354
.for_each(|chunk| chunk.amount.saturating_reduce(amount));
354355
inner.retain(|chunk| !chunk.amount.is_zero());

0 commit comments

Comments
 (0)