@@ -80,6 +80,9 @@ pub enum StateInvariantError {
80
80
type Result < T > = std:: result:: Result < T , StateError > ;
81
81
82
82
type Map < ' bs , BS , K , V > = Hamt < & ' bs BS , V , K > ;
83
+ type BalanceMap < ' bs , BS > = Map < ' bs , BS , BytesKey , TokenAmount > ;
84
+ type AllowanceMap < ' bs , BS > = Map < ' bs , BS , BytesKey , Cid > ;
85
+ type OwnerAllowanceMap < ' bs , BS > = Map < ' bs , BS , BytesKey , TokenAmount > ;
83
86
84
87
/// Token state IPLD structure
85
88
#[ derive( Serialize_tuple , Deserialize_tuple , PartialEq , Eq , Clone , Debug ) ]
@@ -112,9 +115,9 @@ impl TokenState {
112
115
/// 1 <= hamt_bit_width <= 8.
113
116
pub fn new_with_bit_width < BS : Blockstore > ( store : & BS , hamt_bit_width : u32 ) -> Result < Self > {
114
117
// Blockstore is still needed to create valid Cids for the Hamts
115
- let empty_balance_map = Hamt :: < _ , ( ) > :: new_with_bit_width ( store, hamt_bit_width) . flush ( ) ?;
118
+ let empty_balance_map = BalanceMap :: new_with_bit_width ( store, hamt_bit_width) . flush ( ) ?;
116
119
let empty_allowances_map =
117
- Hamt :: < _ , ( ) > :: new_with_bit_width ( store, hamt_bit_width) . flush ( ) ?;
120
+ AllowanceMap :: new_with_bit_width ( store, hamt_bit_width) . flush ( ) ?;
118
121
119
122
Ok ( Self {
120
123
supply : Default :: default ( ) ,
@@ -236,11 +239,8 @@ impl TokenState {
236
239
}
237
240
238
241
/// Retrieve the balance map as a HAMT
239
- pub fn get_balance_map < ' bs , BS : Blockstore > (
240
- & self ,
241
- bs : & ' bs BS ,
242
- ) -> Result < Map < ' bs , BS , BytesKey , TokenAmount > > {
243
- Ok ( Hamt :: load_with_bit_width ( & self . balances , bs, self . hamt_bit_width ) ?)
242
+ pub fn get_balance_map < ' bs , BS : Blockstore > ( & self , bs : & ' bs BS ) -> Result < BalanceMap < ' bs , BS > > {
243
+ Ok ( BalanceMap :: load_with_bit_width ( & self . balances , bs, self . hamt_bit_width ) ?)
244
244
}
245
245
246
246
/// Retrieve the number of token holders
@@ -278,8 +278,8 @@ impl TokenState {
278
278
) -> Result < TokenAmount > {
279
279
let owner_allowances = self . get_owner_allowance_map ( bs, owner) ?;
280
280
match owner_allowances {
281
- Some ( hamt ) => {
282
- let maybe_allowance = hamt . get ( & operator) ?;
281
+ Some ( map ) => {
282
+ let maybe_allowance = map . get ( & actor_id_key ( operator) ) ?;
283
283
if let Some ( allowance) = maybe_allowance {
284
284
return Ok ( allowance. clone ( ) ) ;
285
285
}
@@ -305,39 +305,41 @@ impl TokenState {
305
305
let mut global_allowances_map = self . get_allowances_map ( bs) ?;
306
306
307
307
// get or create the owner's allowance map
308
- let mut allowance_map = match global_allowances_map. get ( & owner) ? {
309
- Some ( hamt) => Hamt :: load_with_bit_width ( hamt, bs, self . hamt_bit_width ) ?,
308
+ let owner_key = actor_id_key ( owner) ;
309
+ let mut allowance_map = match global_allowances_map. get ( & owner_key) ? {
310
+ Some ( cid) => OwnerAllowanceMap :: load_with_bit_width ( cid, bs, self . hamt_bit_width ) ?,
310
311
None => {
311
312
// the owner doesn't have any allowances, and the delta is negative, this is a no-op
312
313
if delta. is_negative ( ) {
313
314
return Ok ( TokenAmount :: zero ( ) ) ;
314
315
}
315
316
316
317
// else create a new map for the owner
317
- Hamt :: < & BS , TokenAmount , ActorID > :: new_with_bit_width ( bs, self . hamt_bit_width )
318
+ OwnerAllowanceMap :: new_with_bit_width ( bs, self . hamt_bit_width )
318
319
}
319
320
} ;
320
321
321
322
// calculate new allowance (max with zero)
322
- let new_allowance = match allowance_map. get ( & operator) ? {
323
+ let operator_key = actor_id_key ( operator) ;
324
+ let new_allowance = match allowance_map. get ( & operator_key) ? {
323
325
Some ( existing_allowance) => existing_allowance + delta,
324
326
None => ( * delta) . clone ( ) ,
325
327
}
326
328
. max ( TokenAmount :: zero ( ) ) ;
327
329
328
330
// if the new allowance is zero, we can remove the entry from the state tree
329
331
if new_allowance. is_zero ( ) {
330
- allowance_map. delete ( & operator ) ?;
332
+ allowance_map. delete ( & operator_key ) ?;
331
333
} else {
332
- allowance_map. set ( operator , new_allowance. clone ( ) ) ?;
334
+ allowance_map. set ( operator_key , new_allowance. clone ( ) ) ?;
333
335
}
334
336
335
337
// if the owner-allowance map is empty, remove it from the global allowances map
336
338
if allowance_map. is_empty ( ) {
337
- global_allowances_map. delete ( & owner ) ?;
339
+ global_allowances_map. delete ( & owner_key ) ?;
338
340
} else {
339
341
// else update the global-allowance map
340
- global_allowances_map. set ( owner , allowance_map. flush ( ) ?) ?;
342
+ global_allowances_map. set ( owner_key , allowance_map. flush ( ) ?) ?;
341
343
}
342
344
343
345
// update the state with the updated global map
@@ -358,20 +360,22 @@ impl TokenState {
358
360
let allowance_map = self . get_owner_allowance_map ( bs, owner) ?;
359
361
if let Some ( mut map) = allowance_map {
360
362
// revoke the allowance
361
- let old_allowance = match map. delete ( & operator) ? {
363
+ let operator_key = actor_id_key ( operator) ;
364
+ let old_allowance = match map. delete ( & operator_key) ? {
362
365
Some ( ( _, amount) ) => amount,
363
366
None => TokenAmount :: zero ( ) ,
364
367
} ;
365
368
366
369
// if the allowance map has become empty it can be dropped entirely
370
+ let owner_key = actor_id_key ( owner) ;
367
371
if map. is_empty ( ) {
368
372
let mut root_allowance_map = self . get_allowances_map ( bs) ?;
369
- root_allowance_map. delete ( & owner ) ?;
373
+ root_allowance_map. delete ( & owner_key ) ?;
370
374
self . allowances = root_allowance_map. flush ( ) ?;
371
375
} else {
372
376
let new_cid = map. flush ( ) ?;
373
377
let mut root_allowance_map = self . get_allowances_map ( bs) ?;
374
- root_allowance_map. set ( owner , new_cid) ?;
378
+ root_allowance_map. set ( owner_key , new_cid) ?;
375
379
self . allowances = root_allowance_map. flush ( ) ?;
376
380
}
377
381
@@ -397,13 +401,15 @@ impl TokenState {
397
401
let mut root_allowances_map = self . get_allowances_map ( bs) ?;
398
402
399
403
// get or create the owner's allowance map
400
- let mut allowance_map = match root_allowances_map. get ( & owner) ? {
401
- Some ( hamt) => Hamt :: load_with_bit_width ( hamt, bs, self . hamt_bit_width ) ?,
402
- None => Hamt :: < & BS , TokenAmount , ActorID > :: new_with_bit_width ( bs, self . hamt_bit_width ) ,
404
+ let owner_key = actor_id_key ( owner) ;
405
+ let mut allowance_map = match root_allowances_map. get ( & owner_key) ? {
406
+ Some ( cid) => OwnerAllowanceMap :: load_with_bit_width ( cid, bs, self . hamt_bit_width ) ?,
407
+ None => OwnerAllowanceMap :: new_with_bit_width ( bs, self . hamt_bit_width ) ,
403
408
} ;
404
409
405
410
// determine the existing allowance
406
- let old_allowance = match allowance_map. get ( & operator) ? {
411
+ let operator_key = actor_id_key ( operator) ;
412
+ let old_allowance = match allowance_map. get ( & operator_key) ? {
407
413
Some ( a) => a. clone ( ) ,
408
414
None => TokenAmount :: zero ( ) ,
409
415
} ;
@@ -415,9 +421,9 @@ impl TokenState {
415
421
}
416
422
417
423
// set the new allowance
418
- allowance_map. set ( operator , amount. clone ( ) ) ?;
424
+ allowance_map. set ( operator_key , amount. clone ( ) ) ?;
419
425
// update the root map
420
- root_allowances_map. set ( owner , allowance_map. flush ( ) ?) ?;
426
+ root_allowances_map. set ( owner_key , allowance_map. flush ( ) ?) ?;
421
427
// update the state with the updated global map
422
428
self . allowances = root_allowances_map. flush ( ) ?;
423
429
@@ -474,10 +480,12 @@ impl TokenState {
474
480
& self ,
475
481
bs : & ' bs BS ,
476
482
owner : ActorID ,
477
- ) -> Result < Option < Map < ' bs , BS , ActorID , TokenAmount > > > {
483
+ ) -> Result < Option < OwnerAllowanceMap < ' bs , BS > > > {
478
484
let allowances_map = self . get_allowances_map ( bs) ?;
479
- let owner_allowances = match allowances_map. get ( & owner) ? {
480
- Some ( cid) => Some ( Hamt :: load_with_bit_width ( cid, bs, self . hamt_bit_width ) ?) ,
485
+ let owner_allowances = match allowances_map. get ( & actor_id_key ( owner) ) ? {
486
+ Some ( cid) => {
487
+ Some ( OwnerAllowanceMap :: load_with_bit_width ( cid, bs, self . hamt_bit_width ) ?)
488
+ }
481
489
None => None ,
482
490
} ;
483
491
Ok ( owner_allowances)
@@ -489,8 +497,8 @@ impl TokenState {
489
497
pub fn get_allowances_map < ' bs , BS : Blockstore > (
490
498
& self ,
491
499
bs : & ' bs BS ,
492
- ) -> Result < Map < ' bs , BS , ActorID , Cid > > {
493
- Ok ( Hamt :: load_with_bit_width ( & self . allowances , bs, self . hamt_bit_width ) ?)
500
+ ) -> Result < AllowanceMap < ' bs , BS > > {
501
+ Ok ( AllowanceMap :: load_with_bit_width ( & self . allowances , bs, self . hamt_bit_width ) ?)
494
502
}
495
503
496
504
/// Checks that the current state obeys all system invariants
@@ -551,38 +559,49 @@ impl TokenState {
551
559
// check allowances are all non-negative
552
560
let allowances_map = self . get_allowances_map ( bs) ?;
553
561
let res = allowances_map. for_each ( |owner, _| {
554
- let allowance_map = self . get_owner_allowance_map ( bs, * owner) ?;
562
+ let owner = match decode_actor_id ( owner) {
563
+ None => {
564
+ bail ! ( "invalid owner key in allowances map" )
565
+ }
566
+ Some ( a) => a,
567
+ } ;
568
+ let allowance_map = self . get_owner_allowance_map ( bs, owner) ?;
555
569
// check that the allowance map isn't empty
556
570
if allowance_map. is_none ( ) {
557
- maybe_err = Some ( StateInvariantError :: ExplicitEmptyAllowance ( * owner) ) ;
571
+ maybe_err = Some ( StateInvariantError :: ExplicitEmptyAllowance ( owner) ) ;
558
572
bail ! ( "invariant failed" )
559
573
}
560
574
561
575
let allowance_map = allowance_map. unwrap ( ) ;
562
576
allowance_map. for_each ( |operator, allowance| {
577
+ let operator = match decode_actor_id ( operator) {
578
+ None => {
579
+ bail ! ( "invalid operator key in allowances map" )
580
+ }
581
+ Some ( a) => a,
582
+ } ;
583
+
563
584
// check there's no stored self-stored allowance
564
- if * owner == * operator {
585
+ if owner == operator {
565
586
maybe_err = Some ( StateInvariantError :: ExplicitSelfAllowance {
566
- account : * owner,
587
+ account : owner,
567
588
allowance : allowance. clone ( ) ,
568
589
} ) ;
569
590
bail ! ( "invariant failed" )
570
591
}
571
592
// check the allowance isn't negative
572
593
if allowance. is_negative ( ) {
573
594
maybe_err = Some ( StateInvariantError :: NegativeAllowance {
574
- owner : * owner ,
575
- operator : * operator ,
595
+ owner,
596
+ operator,
576
597
allowance : allowance. clone ( ) ,
577
598
} ) ;
578
599
bail ! ( "invariant failed" )
579
600
}
580
601
// check there's no explicit zero allowance
581
602
if allowance. is_zero ( ) {
582
- maybe_err = Some ( StateInvariantError :: ExplicitZeroAllowance {
583
- owner : * owner,
584
- operator : * operator,
585
- } ) ;
603
+ maybe_err =
604
+ Some ( StateInvariantError :: ExplicitZeroAllowance { owner, operator } ) ;
586
605
bail ! ( "invariant failed" )
587
606
}
588
607
Ok ( ( ) )
@@ -615,7 +634,7 @@ mod test {
615
634
use fvm_shared:: { bigint:: Zero , ActorID } ;
616
635
617
636
use super :: TokenState ;
618
- use crate :: token:: state:: StateError ;
637
+ use crate :: token:: state:: { actor_id_key , StateError } ;
619
638
620
639
#[ test]
621
640
fn it_instantiates ( ) {
@@ -750,7 +769,8 @@ mod test {
750
769
assert_eq ! ( returned_allowance, allowance) ;
751
770
// the map entry is cleaned-up
752
771
let root_map = state. get_allowances_map ( bs) . unwrap ( ) ;
753
- assert ! ( !root_map. contains_key( & owner) . unwrap( ) ) ;
772
+ let owner_key = actor_id_key ( owner) ;
773
+ assert ! ( !root_map. contains_key( & owner_key) . unwrap( ) ) ;
754
774
755
775
// can't set negative allowance
756
776
let allowance = TokenAmount :: from_atto ( -50 ) ;
0 commit comments