11use std:: {
22 cmp:: Ordering ,
3- collections:: { btree_map:: Entry , BTreeMap , BTreeSet } ,
3+ collections:: { btree_map:: Entry , BTreeMap } ,
44 convert:: TryFrom ,
55} ;
66
77use rand:: Rng ;
88
99use casper_types:: {
1010 account:: { Account , AccountHash } ,
11- system:: auction:: { Bid , Bids , SeigniorageRecipientsSnapshot , UnbondingPurse } ,
11+ system:: auction:: {
12+ Bid , Bids , SeigniorageRecipientsSnapshot , UnbondingPurse , UnbondingPurses , WithdrawPurse ,
13+ WithdrawPurses ,
14+ } ,
1215 AccessRights , CLValue , Key , PublicKey , StoredValue , URef , U512 ,
1316} ;
1417
@@ -21,6 +24,7 @@ pub struct StateTracker<T> {
2124 total_supply : U512 ,
2225 total_supply_key : Key ,
2326 accounts_cache : BTreeMap < AccountHash , Account > ,
27+ withdraws_cache : BTreeMap < AccountHash , Vec < WithdrawPurse > > ,
2428 unbonds_cache : BTreeMap < AccountHash , Vec < UnbondingPurse > > ,
2529 purses_cache : BTreeMap < URef , U512 > ,
2630 bids_cache : Option < Bids > ,
@@ -46,6 +50,7 @@ impl<T: StateReader> StateTracker<T> {
4650 total_supply_key,
4751 total_supply : total_supply. into_t ( ) . expect ( "should be U512" ) ,
4852 accounts_cache : BTreeMap :: new ( ) ,
53+ withdraws_cache : BTreeMap :: new ( ) ,
4954 unbonds_cache : BTreeMap :: new ( ) ,
5055 purses_cache : BTreeMap :: new ( ) ,
5156 bids_cache : None ,
@@ -222,7 +227,12 @@ impl<T: StateReader> StateTracker<T> {
222227 pub fn set_bid ( & mut self , public_key : PublicKey , bid : Bid , slash : bool ) {
223228 let maybe_current_bid = self . get_bids ( ) . get ( & public_key) . cloned ( ) ;
224229
225- let new_amount = * bid. staked_amount ( ) ;
230+ let account_hash = public_key. to_account_hash ( ) ;
231+ let already_unbonded = self . already_unbonding_amount ( & account_hash, & public_key) ;
232+
233+ // we need to put enough funds in the bonding purse to cover the staked amount and the
234+ // amount that will be getting unbonded in the future
235+ let new_amount = * bid. staked_amount ( ) + already_unbonded;
226236 let old_amount = maybe_current_bid
227237 . as_ref ( )
228238 . map ( |bid| self . get_purse_balance ( * bid. bonding_purse ( ) ) )
@@ -234,8 +244,6 @@ impl<T: StateReader> StateTracker<T> {
234244 . unwrap ( )
235245 . insert ( public_key. clone ( ) , bid. clone ( ) ) ;
236246
237- let account_hash = public_key. to_account_hash ( ) ;
238-
239247 // Replace the bid (overwrite the previous bid, if any):
240248 self . write_entry ( Key :: Bid ( account_hash) , bid. clone ( ) . into ( ) ) ;
241249
@@ -246,6 +254,8 @@ impl<T: StateReader> StateTracker<T> {
246254 if old_bid. bonding_purse ( ) != bid. bonding_purse ( ) {
247255 self . set_purse_balance ( * old_bid. bonding_purse ( ) , U512 :: zero ( ) ) ;
248256 self . set_purse_balance ( * bid. bonding_purse ( ) , old_amount) ;
257+ // the old bonding purse gets zeroed - the unbonds will get invalid, anyway
258+ self . remove_withdraws_and_unbonds_with_bonding_purse ( old_bid. bonding_purse ( ) ) ;
249259 }
250260
251261 for ( delegator_pub_key, delegator) in old_bid
@@ -271,6 +281,8 @@ impl<T: StateReader> StateTracker<T> {
271281 self . set_purse_balance ( * new_delegator. bonding_purse ( ) , old_amount) ;
272282 }
273283 self . set_purse_balance ( * delegator. bonding_purse ( ) , U512 :: zero ( ) ) ;
284+ // the old bonding purse gets zeroed - remove the delegator's unbonds
285+ self . remove_withdraws_and_unbonds_with_bonding_purse ( delegator. bonding_purse ( ) ) ;
274286 } else {
275287 let amount = self . get_purse_balance ( * delegator. bonding_purse ( ) ) ;
276288 let already_unbonding =
@@ -288,48 +300,78 @@ impl<T: StateReader> StateTracker<T> {
288300 if ( slash && new_amount != old_amount) || new_amount > old_amount {
289301 self . set_purse_balance ( * bid. bonding_purse ( ) , new_amount) ;
290302 } else if new_amount < old_amount {
291- let already_unbonded = self . already_unbonding_amount ( & account_hash, & public_key) ;
292303 self . create_unbonding_purse (
293304 * bid. bonding_purse ( ) ,
294305 & public_key,
295306 & public_key,
296- old_amount - new_amount - already_unbonded ,
307+ old_amount - new_amount,
297308 ) ;
298309 }
299310
300311 for ( delegator_public_key, delegator) in bid. delegators ( ) {
301312 let old_amount = self . get_purse_balance ( * delegator. bonding_purse ( ) ) ;
302- let new_amount = * delegator. staked_amount ( ) ;
313+ let already_unbonded =
314+ self . already_unbonding_amount ( & account_hash, delegator_public_key) ;
315+ let new_amount = * delegator. staked_amount ( ) + already_unbonded;
303316 if ( slash && new_amount != old_amount) || new_amount > old_amount {
304- self . set_purse_balance ( * delegator. bonding_purse ( ) , * delegator . staked_amount ( ) ) ;
317+ self . set_purse_balance ( * delegator. bonding_purse ( ) , new_amount ) ;
305318 } else if new_amount < old_amount {
306- let already_unbonded = self . already_unbonding_amount ( & account_hash, & public_key) ;
307319 self . create_unbonding_purse (
308320 * delegator. bonding_purse ( ) ,
309321 & public_key,
310322 delegator_public_key,
311- old_amount - new_amount - already_unbonded ,
323+ old_amount - new_amount,
312324 ) ;
313325 }
314326 }
315327 }
316328
329+ fn get_withdraws ( & mut self ) -> WithdrawPurses {
330+ let mut result = self . reader . get_withdraws ( ) ;
331+ for ( acc, purses) in & self . withdraws_cache {
332+ result. insert ( * acc, purses. clone ( ) ) ;
333+ }
334+ result
335+ }
336+
337+ fn get_unbonds ( & mut self ) -> UnbondingPurses {
338+ let mut result = self . reader . get_unbonds ( ) ;
339+ for ( acc, purses) in & self . unbonds_cache {
340+ result. insert ( * acc, purses. clone ( ) ) ;
341+ }
342+ result
343+ }
344+
345+ fn write_withdraw ( & mut self , account_hash : AccountHash , withdraws : Vec < WithdrawPurse > ) {
346+ self . withdraws_cache . insert ( account_hash, withdraws. clone ( ) ) ;
347+ self . write_entry (
348+ Key :: Withdraw ( account_hash) ,
349+ StoredValue :: Withdraw ( withdraws) ,
350+ ) ;
351+ }
352+
353+ fn write_unbond ( & mut self , account_hash : AccountHash , unbonds : Vec < UnbondingPurse > ) {
354+ self . unbonds_cache . insert ( account_hash, unbonds. clone ( ) ) ;
355+ self . write_entry ( Key :: Unbond ( account_hash) , StoredValue :: Unbonding ( unbonds) ) ;
356+ }
357+
317358 /// Returns the sum of already unbonding purses for the given validator account & unbonder.
318359 fn already_unbonding_amount ( & mut self , account : & AccountHash , unbonder : & PublicKey ) -> U512 {
319- let existing_purses = self
320- . reader
321- . get_unbonds ( )
322- . get ( account)
323- . cloned ( )
324- . unwrap_or_default ( ) ;
360+ let current_era = * self . read_snapshot ( ) . 1 . keys ( ) . next ( ) . unwrap ( ) ;
361+ let unbonding_delay = self . reader . get_unbonding_delay ( ) ;
362+ let limit_era = current_era. saturating_sub ( unbonding_delay) ;
363+
364+ let existing_purses = self . get_unbonds ( ) . get ( account) . cloned ( ) . unwrap_or_default ( ) ;
325365 let existing_purses_legacy = self
326- . reader
327366 . get_withdraws ( )
328367 . get ( account)
329368 . cloned ( )
330369 . unwrap_or_default ( )
331370 . into_iter ( )
332- . map ( UnbondingPurse :: from) ;
371+ . map ( UnbondingPurse :: from)
372+ // There may be some leftover old legacy purses that haven't been purged - this is to
373+ // make sure that we don't accidentally take them into account.
374+ . filter ( |purse| purse. era_of_creation ( ) >= limit_era) ;
333375
334376 existing_purses_legacy
335377 . chain ( existing_purses)
@@ -338,26 +380,23 @@ impl<T: StateReader> StateTracker<T> {
338380 . sum ( )
339381 }
340382
341- /// Generates the writes to the global state that will remove the pending withdraws and unbonds
342- /// of all the old validators that will cease to be validators, and slashes their unbonding
343- /// purses.
344- pub fn remove_withdraws_and_unbonds ( & mut self , removed : & BTreeSet < PublicKey > ) {
345- let withdraws = self . reader . get_withdraws ( ) ;
346- let unbonds = self . reader . get_unbonds ( ) ;
347- for removed_validator in removed {
348- let acc = removed_validator. to_account_hash ( ) ;
349- if let Some ( withdraw_set) = withdraws. get ( & acc) {
350- for withdraw in withdraw_set {
351- self . set_purse_balance ( * withdraw. bonding_purse ( ) , U512 :: zero ( ) ) ;
352- }
353- self . write_entry ( Key :: Withdraw ( acc) , StoredValue :: Withdraw ( vec ! [ ] ) ) ;
383+ pub fn remove_withdraws_and_unbonds_with_bonding_purse ( & mut self , affected_purse : & URef ) {
384+ let withdraws = self . get_withdraws ( ) ;
385+ let unbonds = self . get_unbonds ( ) ;
386+
387+ for ( acc, mut purses) in withdraws {
388+ let old_len = purses. len ( ) ;
389+ purses. retain ( |purse| purse. bonding_purse ( ) . addr ( ) != affected_purse. addr ( ) ) ;
390+ if purses. len ( ) != old_len {
391+ self . write_withdraw ( acc, purses) ;
354392 }
393+ }
355394
356- if let Some ( unbond_set ) = unbonds. get ( & acc ) {
357- for unbond in unbond_set {
358- self . set_purse_balance ( * unbond . bonding_purse ( ) , U512 :: zero ( ) ) ;
359- }
360- self . write_entry ( Key :: Unbond ( acc) , StoredValue :: Unbonding ( vec ! [ ] ) ) ;
395+ for ( acc , mut purses ) in unbonds {
396+ let old_len = purses . len ( ) ;
397+ purses . retain ( |purse| purse . bonding_purse ( ) . addr ( ) != affected_purse . addr ( ) ) ;
398+ if purses . len ( ) != old_len {
399+ self . write_unbond ( acc, purses ) ;
361400 }
362401 }
363402 }
0 commit comments