Skip to content

Commit 03eff49

Browse files
committed
Add ListAllocations/Claims methods for verified registry actor.
1 parent 73376df commit 03eff49

File tree

11 files changed

+490
-28
lines changed

11 files changed

+490
-28
lines changed

Cargo.lock

Lines changed: 33 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ fvm_sdk = "~4.0"
118118
fvm_shared = "~4.0"
119119
fvm_ipld_encoding = "0.4.0"
120120
fvm_ipld_blockstore = "0.2.0"
121-
fvm_ipld_hamt = "0.8.0"
121+
fvm_ipld_hamt = "0.9.0"
122122
fvm_ipld_kamt = "0.3.0"
123123
fvm_ipld_amt = { version = "0.6.2" }
124124
fvm_ipld_bitfield = "0.6.0"

actors/verifreg/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ cid = { workspace = true }
2121
frc42_dispatch = { workspace = true }
2222
frc46_token = { workspace = true }
2323
fvm_actor_utils = { workspace = true }
24+
fvm_ipld_bitfield = { workspace = true }
2425
fvm_ipld_blockstore = { workspace = true }
2526
fvm_ipld_encoding = { workspace = true }
2627
fvm_ipld_hamt = { workspace = true }

actors/verifreg/src/expiration.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ where
4242
collection
4343
.for_each_in(owner, |key, record| {
4444
if curr_epoch >= record.expiration() {
45-
let id = parse_uint_key(key)
46-
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to parse uint key")?;
45+
let id = parse_uint_key(key)?;
4746
found_ids.push(id);
4847
}
4948
Ok(())

actors/verifreg/src/lib.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ use fil_actors_runtime::{ActorContext, AsActorError, BatchReturnGen};
3131

3232
use crate::ext::datacap::{DestroyParams, MintParams};
3333
use crate::state::{
34-
DataCapMap, RemoveDataCapProposalMap, DATACAP_MAP_CONFIG, REMOVE_DATACAP_PROPOSALS_CONFIG,
34+
Cursor, DataCapMap, RemoveDataCapProposalMap, DATACAP_MAP_CONFIG,
35+
REMOVE_DATACAP_PROPOSALS_CONFIG,
3536
};
3637

3738
pub use self::state::Allocation;
@@ -70,6 +71,8 @@ pub enum Method {
7071
GetClaimsExported = frc42_dispatch::method_hash!("GetClaims"),
7172
ExtendClaimTermsExported = frc42_dispatch::method_hash!("ExtendClaimTerms"),
7273
RemoveExpiredClaimsExported = frc42_dispatch::method_hash!("RemoveExpiredClaims"),
74+
ListAllocationsExported = frc42_dispatch::method_hash!("ListAllocations"),
75+
ListClaimsExported = frc42_dispatch::method_hash!("ListClaims"),
7376
UniversalReceiverHook = frc42_dispatch::method_hash!("Receive"),
7477
}
7578

@@ -604,6 +607,29 @@ impl Actor {
604607
Ok(RemoveExpiredClaimsReturn { considered, results: batch_ret })
605608
}
606609

610+
pub fn list_allocations(
611+
rt: &impl Runtime,
612+
params: ListAllocationsParams,
613+
) -> Result<ListAllocationsResponse, ActorError> {
614+
let cursor = Cursor::from_bytes(params.cursor)?;
615+
let st: State = rt.state()?;
616+
let (allocations, next_cursor) =
617+
st.list_allocations(rt.store(), cursor, Some(params.limit))?;
618+
let next_cursor = next_cursor.map(|c| c.to_bytes()).transpose()?;
619+
Ok(ListAllocationsResponse { allocations, next_cursor })
620+
}
621+
622+
pub fn list_claims(
623+
rt: &impl Runtime,
624+
params: ListClaimsParams,
625+
) -> Result<ListClaimsResponse, ActorError> {
626+
let cursor = Cursor::from_bytes(params.cursor)?;
627+
let st: State = rt.state()?;
628+
let (claims, next_cursor) = st.list_claims(rt.store(), cursor, Some(params.limit))?;
629+
let next_cursor = next_cursor.map(|c| c.to_bytes()).transpose()?;
630+
Ok(ListClaimsResponse { claims, next_cursor })
631+
}
632+
607633
// Receives data cap tokens (only) and creates allocations according to one or more
608634
// allocation requests specified in the transfer's operator data.
609635
// The token amount received must exactly correspond to the sum of the requested allocation sizes.
@@ -1069,6 +1095,8 @@ impl ActorCode for Actor {
10691095
GetClaims|GetClaimsExported => get_claims,
10701096
ExtendClaimTerms|ExtendClaimTermsExported => extend_claim_terms,
10711097
RemoveExpiredClaims|RemoveExpiredClaimsExported => remove_expired_claims,
1098+
ListAllocationsExported => list_allocations,
1099+
ListClaimsExported => list_claims,
10721100
UniversalReceiverHook => universal_receiver_hook,
10731101
}
10741102
}

actors/verifreg/src/state.rs

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use cid::Cid;
55
use fvm_ipld_blockstore::Blockstore;
66
use fvm_ipld_encoding::tuple::*;
7+
use fvm_ipld_encoding::RawBytes;
78
use fvm_shared::address::Address;
89
use fvm_shared::bigint::bigint_ser::BigIntDe;
910
use fvm_shared::clock::ChainEpoch;
@@ -13,10 +14,11 @@ use fvm_shared::sector::SectorNumber;
1314
use fvm_shared::{ActorID, HAMT_BIT_WIDTH};
1415

1516
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,
1719
};
1820

19-
use crate::{AddrPairKey, AllocationID, ClaimID};
21+
use crate::{AddrPairKey, AllocationID, AllocationKey, ClaimID, ClaimKey};
2022
use crate::{DataCap, RemoveDataCapProposalID};
2123

2224
pub 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)]
201260
pub struct Claim {
202261
// The provider storing the data (from allocation).
@@ -262,3 +321,44 @@ 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, 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

Comments
 (0)