33
44use cid:: Cid ;
55use fvm_ipld_blockstore:: Blockstore ;
6+ use fvm_ipld_encoding:: RawBytes ;
67use fvm_ipld_encoding:: tuple:: * ;
78use fvm_shared:: address:: Address ;
89use fvm_shared:: bigint:: bigint_ser:: BigIntDe ;
@@ -13,10 +14,11 @@ use fvm_shared::sector::SectorNumber;
1314use fvm_shared:: { ActorID , HAMT_BIT_WIDTH } ;
1415
1516use 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 ,
1719} ;
1820
19- use crate :: { AddrPairKey , AllocationID , ClaimID } ;
21+ use crate :: { AddrPairKey , AllocationID , AllocationKey , ClaimID , ClaimKey } ;
2022use crate :: { DataCap , RemoveDataCapProposalID } ;
2123
2224pub type DataCapMap < BS > = Map2 < BS , Address , BigIntDe > ;
@@ -156,6 +158,34 @@ impl State {
156158 Ok ( allocated_ids)
157159 }
158160
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+
159189 pub fn load_claims < ' a , BS : Blockstore > (
160190 & self ,
161191 store : & ' a BS ,
@@ -196,7 +226,36 @@ impl State {
196226 self . save_claims ( & mut st_claims) ?;
197227 Ok ( ( ) )
198228 }
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+ }
199257}
258+
200259#[ derive( Serialize_tuple , Deserialize_tuple , Clone , Debug , PartialEq , Eq ) ]
201260pub struct Claim {
202261 // The provider storing the data (from allocation).
@@ -262,3 +321,45 @@ where
262321 . get ( provider, id)
263322 . context_code ( ExitCode :: USR_ILLEGAL_STATE , "HAMT lookup failure getting claim" )
264323}
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 , inner_key : ActorID , outer_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+ // FIXME new error type
361+ }
362+ return Ok ( ( Some ( & cursor. outer_key ) , Some ( & cursor. inner_key ) ) )
363+ }
364+ Ok ( ( None , None ) )
365+ }
0 commit comments