1
- use anyhow:: anyhow;
2
- use anyhow:: bail;
3
- use anyhow:: Result ;
4
1
use cid:: multihash:: Code ;
5
2
use cid:: Cid ;
6
-
7
3
use fvm_ipld_blockstore:: Block ;
8
4
use fvm_ipld_blockstore:: Blockstore as IpldStore ;
9
5
use fvm_ipld_encoding:: tuple:: * ;
10
6
use fvm_ipld_encoding:: Cbor ;
11
7
use fvm_ipld_encoding:: CborStore ;
12
8
use fvm_ipld_encoding:: DAG_CBOR ;
9
+ use fvm_ipld_hamt:: Error as HamtError ;
13
10
use fvm_ipld_hamt:: Hamt ;
14
11
use fvm_shared:: bigint:: bigint_ser;
15
12
use fvm_shared:: bigint:: bigint_ser:: BigIntDe ;
16
13
use fvm_shared:: bigint:: Zero ;
17
14
use fvm_shared:: econ:: TokenAmount ;
18
15
use fvm_shared:: ActorID ;
19
16
use num_traits:: Signed ;
17
+ use thiserror:: Error ;
20
18
21
19
const HAMT_BIT_WIDTH : u32 = 5 ;
22
20
21
+ #[ derive( Error , Debug ) ]
22
+ pub enum StateError {
23
+ #[ error( "ipld hamt error: {0}" ) ]
24
+ IpldHamt ( #[ from] HamtError ) ,
25
+ #[ error( "missing state at cid: {0}" ) ]
26
+ MissingState ( Cid ) ,
27
+ #[ error( "underlying serialization error: {0}" ) ]
28
+ Serialization ( String ) ,
29
+ #[ error(
30
+ "negative balance caused by subtracting {delta:?} from {owner:?}'s balance of {balance:?}"
31
+ ) ]
32
+ NegativeBalance {
33
+ owner : ActorID ,
34
+ balance : TokenAmount ,
35
+ delta : TokenAmount ,
36
+ } ,
37
+ #[ error(
38
+ "{spender:?} attempted to utilise {delta:?} of allowance {allowance:?} set by {owner:?}"
39
+ ) ]
40
+ InsufficentAllowance {
41
+ owner : ActorID ,
42
+ spender : ActorID ,
43
+ allowance : TokenAmount ,
44
+ delta : TokenAmount ,
45
+ } ,
46
+ }
47
+
48
+ type Result < T > = std:: result:: Result < T , StateError > ;
49
+
23
50
/// Token state IPLD structure
24
51
#[ derive( Serialize_tuple , Deserialize_tuple , PartialEq , Clone , Debug ) ]
25
52
pub struct TokenState {
@@ -63,24 +90,24 @@ impl TokenState {
63
90
// Load the actor state from the state tree.
64
91
match bs. get_cbor :: < Self > ( cid) {
65
92
Ok ( Some ( state) ) => Ok ( state) ,
66
- Ok ( None ) => Err ( anyhow ! ( "no state at this cid {:?}" , cid ) ) ,
67
- Err ( err) => Err ( anyhow ! ( "failed to get state: {}" , err) ) ,
93
+ Ok ( None ) => Err ( StateError :: MissingState ( cid. clone ( ) ) ) ,
94
+ Err ( err) => Err ( StateError :: Serialization ( err. to_string ( ) ) ) ,
68
95
}
69
96
}
70
97
71
98
/// Saves the current state to the blockstore, returning the cid
72
99
pub fn save < BS : IpldStore > ( & self , bs : & BS ) -> Result < Cid > {
73
100
let serialized = match fvm_ipld_encoding:: to_vec ( self ) {
74
101
Ok ( s) => s,
75
- Err ( err) => return Err ( anyhow ! ( "failed to serialize state: {:?}" , err) ) ,
102
+ Err ( err) => return Err ( StateError :: Serialization ( err. to_string ( ) ) ) ,
76
103
} ;
77
104
let block = Block {
78
105
codec : DAG_CBOR ,
79
106
data : serialized,
80
107
} ;
81
108
let cid = match bs. put ( Code :: Blake2b256 , & block) {
82
109
Ok ( cid) => cid,
83
- Err ( err) => return Err ( anyhow ! ( "failed to store initial state: {:}" , err) ) ,
110
+ Err ( err) => return Err ( StateError :: Serialization ( err. to_string ( ) ) ) ,
84
111
} ;
85
112
Ok ( cid)
86
113
}
@@ -126,11 +153,11 @@ impl TokenState {
126
153
127
154
// if the new_balance is negative, return an error
128
155
if new_balance. is_negative ( ) {
129
- bail ! (
130
- "resulting balance was negative adding {:?} to {:?}" ,
131
- delta,
132
- balance . unwrap_or ( & BigIntDe ( TokenAmount :: zero ( ) ) ) . 0
133
- ) ;
156
+ return Err ( StateError :: NegativeBalance {
157
+ balance : new_balance ,
158
+ delta : delta . clone ( ) ,
159
+ owner ,
160
+ } ) ;
134
161
}
135
162
136
163
balance_map. set ( owner, BigIntDe ( new_balance. clone ( ) ) ) ?;
@@ -144,30 +171,19 @@ impl TokenState {
144
171
& self ,
145
172
bs : & BS ,
146
173
) -> Result < Hamt < BS , BigIntDe , ActorID > > {
147
- match Hamt :: < BS , BigIntDe , ActorID > :: load_with_bit_width (
174
+ Ok ( Hamt :: < BS , BigIntDe , ActorID > :: load_with_bit_width (
148
175
& self . balances ,
149
176
( * bs) . clone ( ) ,
150
177
HAMT_BIT_WIDTH ,
151
- ) {
152
- Ok ( map) => Ok ( map) ,
153
- Err ( err) => return Err ( anyhow ! ( "failed to load balances hamt: {:?}" , err) ) ,
154
- }
178
+ ) ?)
155
179
}
156
180
157
181
/// Increase the total supply by the specified value
158
182
///
159
- /// The requested amount must be non-negative.
160
- /// Returns an error if the total supply overflows, else returns the new total supply
161
- pub fn increase_supply ( & mut self , value : & TokenAmount ) -> Result < TokenAmount > {
162
- let new_supply = self . supply . checked_add ( value) . ok_or_else ( || {
163
- anyhow ! (
164
- "Overflow when adding {} to the total_supply of {}" ,
165
- value,
166
- self . supply
167
- )
168
- } ) ?;
169
- self . supply = new_supply. clone ( ) ;
170
- Ok ( new_supply)
183
+ /// The requested amount must be non-negative. Returns the new total supply
184
+ pub fn increase_supply ( & mut self , value : & TokenAmount ) -> Result < & TokenAmount > {
185
+ self . supply += value;
186
+ Ok ( & self . supply )
171
187
}
172
188
173
189
/// Get the allowance that an owner has approved for a spender
@@ -296,25 +312,17 @@ impl TokenState {
296
312
return Ok ( current_allowance) ;
297
313
}
298
314
299
- let new_allowance = current_allowance. checked_sub ( value) . ok_or_else ( || {
300
- anyhow ! (
301
- "Overflow when subtracting {} from {}'s allowance of {}" ,
302
- value,
303
- owner,
304
- current_allowance
305
- )
306
- } ) ?;
307
-
308
- if new_allowance. is_negative ( ) {
309
- return Err ( anyhow ! (
310
- "Attempted to use {} of {}'s tokens from {}'s allowance of {}" ,
311
- value,
315
+ if current_allowance. lt ( value) {
316
+ return Err ( StateError :: InsufficentAllowance {
312
317
owner,
313
318
spender,
314
- current_allowance
315
- ) ) ;
319
+ allowance : current_allowance,
320
+ delta : value. clone ( ) ,
321
+ } ) ;
316
322
}
317
323
324
+ let new_allowance = current_allowance - value;
325
+
318
326
// TODO: helper function to set a new allowance and flush hamts
319
327
let owner_allowances = self . get_owner_allowance_map ( bs, owner) ?;
320
328
// to reach here, allowance must have been previously non zero; so safe to assume the map exists
@@ -353,12 +361,11 @@ impl TokenState {
353
361
///
354
362
/// Gets a HAMT with CIDs linking to other HAMTs
355
363
fn get_allowances_map < BS : IpldStore + Clone > ( & self , bs : & BS ) -> Result < Hamt < BS , Cid , ActorID > > {
356
- Hamt :: < BS , Cid , ActorID > :: load_with_bit_width (
364
+ Ok ( Hamt :: < BS , Cid , ActorID > :: load_with_bit_width (
357
365
& self . allowances ,
358
366
( * bs) . clone ( ) ,
359
367
HAMT_BIT_WIDTH ,
360
- )
361
- . map_err ( |e| anyhow ! ( "failed to load base allowances map {}" , e) )
368
+ ) ?)
362
369
}
363
370
}
364
371
0 commit comments