@@ -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}
0 commit comments