4
4
use cid:: Cid ;
5
5
use fvm_ipld_blockstore:: Blockstore ;
6
6
use fvm_ipld_encoding:: tuple:: * ;
7
+ use fvm_ipld_encoding:: RawBytes ;
7
8
use fvm_shared:: address:: Address ;
8
9
use fvm_shared:: bigint:: bigint_ser:: BigIntDe ;
9
10
use fvm_shared:: clock:: ChainEpoch ;
@@ -13,10 +14,11 @@ use fvm_shared::sector::SectorNumber;
13
14
use fvm_shared:: { ActorID , HAMT_BIT_WIDTH } ;
14
15
15
16
use fil_actors_runtime:: {
16
- actor_error, ActorError , AsActorError , Config , Map2 , MapMap , DEFAULT_HAMT_CONFIG ,
17
+ actor_error, parse_uint_key, ActorError , AsActorError , Config , Map2 , MapMap ,
18
+ DEFAULT_HAMT_CONFIG ,
17
19
} ;
18
20
19
- use crate :: { AddrPairKey , AllocationID , ClaimID } ;
21
+ use crate :: { AddrPairKey , AllocationID , AllocationKey , ClaimID , ClaimKey } ;
20
22
use crate :: { DataCap , RemoveDataCapProposalID } ;
21
23
22
24
pub type DataCapMap < BS > = Map2 < BS , Address , BigIntDe > ;
@@ -156,6 +158,34 @@ impl State {
156
158
Ok ( allocated_ids)
157
159
}
158
160
161
+ // Lists all allocation clients and IDs, paginated with a cursor.
162
+ // Returns a new cursor from which to continue listing, if any items remain.
163
+ pub fn list_allocations < BS : Blockstore > (
164
+ & self ,
165
+ store : & BS ,
166
+ cursor : Option < Cursor > ,
167
+ limit : Option < u64 > ,
168
+ ) -> Result < ( Vec < AllocationKey > , Option < Cursor > ) , ActorError > {
169
+ let ( start_outer, start_inner) = verify_cursor ( & cursor, self . allocations ) ?;
170
+ let mut allocs = self . load_allocs ( store) ?;
171
+ let mut found = vec ! [ ] ;
172
+ let next = allocs
173
+ . for_each_each ( start_outer, start_inner, limit, |k1, k2, _v| {
174
+ let client = parse_uint_key ( k1) ?;
175
+ let id = parse_uint_key ( k2) ?;
176
+ found. push ( AllocationKey { client, id } ) ;
177
+ Ok ( ( ) )
178
+ } )
179
+ . context_code ( ExitCode :: USR_ILLEGAL_STATE , "listing allocations" ) ?;
180
+ let next_cursor = match next {
181
+ Some ( ( k1, k2) ) => {
182
+ Some ( Cursor :: new ( self . allocations , parse_uint_key ( & k1) ?, parse_uint_key ( & k2) ?) )
183
+ }
184
+ None => None ,
185
+ } ;
186
+ Ok ( ( found, next_cursor) )
187
+ }
188
+
159
189
pub fn load_claims < ' a , BS : Blockstore > (
160
190
& self ,
161
191
store : & ' a BS ,
@@ -196,7 +226,36 @@ impl State {
196
226
self . save_claims ( & mut st_claims) ?;
197
227
Ok ( ( ) )
198
228
}
229
+
230
+ // Lists all claim providers and IDs, paginated with a cursor.
231
+ // Returns a new cursor from which to continue listing, if any items remain.
232
+ pub fn list_claims < BS : Blockstore > (
233
+ & self ,
234
+ store : & BS ,
235
+ cursor : Option < Cursor > ,
236
+ limit : Option < u64 > ,
237
+ ) -> Result < ( Vec < ClaimKey > , Option < Cursor > ) , ActorError > {
238
+ let ( start_outer, start_inner) = verify_cursor ( & cursor, self . claims ) ?;
239
+ let mut claims = self . load_claims ( store) ?;
240
+ let mut found = vec ! [ ] ;
241
+ let next = claims
242
+ . for_each_each ( start_outer, start_inner, limit, |k1, k2, _v| {
243
+ let provider = parse_uint_key ( k1) ?;
244
+ let id = parse_uint_key ( k2) ?;
245
+ found. push ( ClaimKey { provider, id } ) ;
246
+ Ok ( ( ) )
247
+ } )
248
+ . context_code ( ExitCode :: USR_ILLEGAL_STATE , "listing claims" ) ?;
249
+ let next_cursor = match next {
250
+ Some ( ( k1, k2) ) => {
251
+ Some ( Cursor :: new ( self . claims , parse_uint_key ( & k1) ?, parse_uint_key ( & k2) ?) )
252
+ }
253
+ None => None ,
254
+ } ;
255
+ Ok ( ( found, next_cursor) )
256
+ }
199
257
}
258
+
200
259
#[ derive( Serialize_tuple , Deserialize_tuple , Clone , Debug , PartialEq , Eq ) ]
201
260
pub struct Claim {
202
261
// The provider storing the data (from allocation).
@@ -262,3 +321,44 @@ where
262
321
. get ( provider, id)
263
322
. context_code ( ExitCode :: USR_ILLEGAL_STATE , "HAMT lookup failure getting claim" )
264
323
}
324
+
325
+ /// Opaque cursor to iterate over allocations/claims data structures
326
+ #[ derive( Serialize_tuple , Deserialize_tuple , Clone , Debug ) ]
327
+ pub struct Cursor {
328
+ pub root : Cid ,
329
+ pub outer_key : ActorID ,
330
+ pub inner_key : u64 ,
331
+ }
332
+
333
+ impl Cursor {
334
+ pub fn new ( cid : Cid , outer_key : ActorID , inner_key : u64 ) -> Self {
335
+ Self { root : cid, inner_key, outer_key }
336
+ }
337
+
338
+ /// Generates a cursor from an opaque representation
339
+ pub fn from_bytes ( bytes : RawBytes ) -> Result < Option < Cursor > , ActorError > {
340
+ if bytes. is_empty ( ) {
341
+ Ok ( None )
342
+ } else {
343
+ Ok ( Some ( fvm_ipld_encoding:: from_slice ( & bytes) ?) )
344
+ }
345
+ }
346
+
347
+ /// Generates an opaque representation of the cursor that can be used to resume enumeration
348
+ pub fn to_bytes ( & self ) -> Result < RawBytes , ActorError > {
349
+ Ok ( RawBytes :: from ( fvm_ipld_encoding:: to_vec ( self ) ?) )
350
+ }
351
+ }
352
+
353
+ fn verify_cursor (
354
+ cursor : & Option < Cursor > ,
355
+ expected_root : Cid ,
356
+ ) -> Result < ( Option < & ActorID > , Option < & u64 > ) , ActorError > {
357
+ if let Some ( cursor) = cursor {
358
+ if cursor. root != expected_root {
359
+ return Err ( ActorError :: illegal_argument ( "invalid cursor" . to_string ( ) ) ) ;
360
+ }
361
+ return Ok ( ( Some ( & cursor. outer_key ) , Some ( & cursor. inner_key ) ) ) ;
362
+ }
363
+ Ok ( ( None , None ) )
364
+ }
0 commit comments