Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exported methods for iteration of verified allocations and claims #1468

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 33 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ fvm_sdk = "~4.0"
fvm_shared = "~4.0"
fvm_ipld_encoding = "0.4.0"
fvm_ipld_blockstore = "0.2.0"
fvm_ipld_hamt = "0.8.0"
fvm_ipld_hamt = "0.9.0"
fvm_ipld_kamt = "0.3.0"
fvm_ipld_amt = { version = "0.6.2" }
fvm_ipld_bitfield = "0.6.0"
Expand Down
1 change: 1 addition & 0 deletions actors/verifreg/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ cid = { workspace = true }
frc42_dispatch = { workspace = true }
frc46_token = { workspace = true }
fvm_actor_utils = { workspace = true }
fvm_ipld_bitfield = { workspace = true }
anorth marked this conversation as resolved.
Show resolved Hide resolved
fvm_ipld_blockstore = { workspace = true }
fvm_ipld_encoding = { workspace = true }
fvm_ipld_hamt = { workspace = true }
Expand Down
3 changes: 1 addition & 2 deletions actors/verifreg/src/expiration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ where
collection
.for_each_in(owner, |key, record| {
if curr_epoch >= record.expiration() {
let id = parse_uint_key(key)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to parse uint key")?;
let id = parse_uint_key(key)?;
found_ids.push(id);
}
Ok(())
Expand Down
30 changes: 29 additions & 1 deletion actors/verifreg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ use fil_actors_runtime::{ActorContext, AsActorError, BatchReturnGen};

use crate::ext::datacap::{DestroyParams, MintParams};
use crate::state::{
DataCapMap, RemoveDataCapProposalMap, DATACAP_MAP_CONFIG, REMOVE_DATACAP_PROPOSALS_CONFIG,
Cursor, DataCapMap, RemoveDataCapProposalMap, DATACAP_MAP_CONFIG,
REMOVE_DATACAP_PROPOSALS_CONFIG,
};

pub use self::state::Allocation;
Expand Down Expand Up @@ -70,6 +71,8 @@ pub enum Method {
GetClaimsExported = frc42_dispatch::method_hash!("GetClaims"),
ExtendClaimTermsExported = frc42_dispatch::method_hash!("ExtendClaimTerms"),
RemoveExpiredClaimsExported = frc42_dispatch::method_hash!("RemoveExpiredClaims"),
ListAllocationsExported = frc42_dispatch::method_hash!("ListAllocations"),
ListClaimsExported = frc42_dispatch::method_hash!("ListClaims"),
UniversalReceiverHook = frc42_dispatch::method_hash!("Receive"),
}

Expand Down Expand Up @@ -604,6 +607,29 @@ impl Actor {
Ok(RemoveExpiredClaimsReturn { considered, results: batch_ret })
}

pub fn list_allocations(
rt: &impl Runtime,
params: ListAllocationsParams,
) -> Result<ListAllocationsResponse, ActorError> {
let cursor = Cursor::from_bytes(params.cursor)?;
let st: State = rt.state()?;
let (allocations, next_cursor) =
st.list_allocations(rt.store(), cursor, Some(params.limit))?;
let next_cursor = next_cursor.map(|c| c.to_bytes()).transpose()?;
Ok(ListAllocationsResponse { allocations, next_cursor })
}

pub fn list_claims(
rt: &impl Runtime,
params: ListClaimsParams,
) -> Result<ListClaimsResponse, ActorError> {
let cursor = Cursor::from_bytes(params.cursor)?;
let st: State = rt.state()?;
let (claims, next_cursor) = st.list_claims(rt.store(), cursor, Some(params.limit))?;
let next_cursor = next_cursor.map(|c| c.to_bytes()).transpose()?;
Ok(ListClaimsResponse { claims, next_cursor })
}

// Receives data cap tokens (only) and creates allocations according to one or more
// allocation requests specified in the transfer's operator data.
// The token amount received must exactly correspond to the sum of the requested allocation sizes.
Expand Down Expand Up @@ -1069,6 +1095,8 @@ impl ActorCode for Actor {
GetClaims|GetClaimsExported => get_claims,
ExtendClaimTerms|ExtendClaimTermsExported => extend_claim_terms,
RemoveExpiredClaims|RemoveExpiredClaimsExported => remove_expired_claims,
ListAllocationsExported => list_allocations,
ListClaimsExported => list_claims,
UniversalReceiverHook => universal_receiver_hook,
}
}
104 changes: 102 additions & 2 deletions actors/verifreg/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use cid::Cid;
use fvm_ipld_blockstore::Blockstore;
use fvm_ipld_encoding::tuple::*;
use fvm_ipld_encoding::RawBytes;
use fvm_shared::address::Address;
use fvm_shared::bigint::bigint_ser::BigIntDe;
use fvm_shared::clock::ChainEpoch;
Expand All @@ -13,10 +14,11 @@ use fvm_shared::sector::SectorNumber;
use fvm_shared::{ActorID, HAMT_BIT_WIDTH};

use fil_actors_runtime::{
actor_error, ActorError, AsActorError, Config, Map2, MapMap, DEFAULT_HAMT_CONFIG,
actor_error, parse_uint_key, ActorError, AsActorError, Config, Map2, MapMap,
DEFAULT_HAMT_CONFIG,
};

use crate::{AddrPairKey, AllocationID, ClaimID};
use crate::{AddrPairKey, AllocationID, AllocationKey, ClaimID, ClaimKey};
use crate::{DataCap, RemoveDataCapProposalID};

pub type DataCapMap<BS> = Map2<BS, Address, BigIntDe>;
Expand Down Expand Up @@ -156,6 +158,34 @@ impl State {
Ok(allocated_ids)
}

// Lists all allocation clients and IDs, paginated with a cursor.
// Returns a new cursor from which to continue listing, if any items remain.
pub fn list_allocations<BS: Blockstore>(
&self,
store: &BS,
cursor: Option<Cursor>,
limit: Option<u64>,
) -> Result<(Vec<AllocationKey>, Option<Cursor>), ActorError> {
let (start_outer, start_inner) = verify_cursor(&cursor, self.allocations)?;
let mut allocs = self.load_allocs(store)?;
let mut found = vec![];
let next = allocs
.for_each_each(start_outer, start_inner, limit, |k1, k2, _v| {
let client = parse_uint_key(k1)?;
let id = parse_uint_key(k2)?;
found.push(AllocationKey { client, id });
Ok(())
})
.context_code(ExitCode::USR_ILLEGAL_STATE, "listing allocations")?;
let next_cursor = match next {
Some((k1, k2)) => {
Some(Cursor::new(self.allocations, parse_uint_key(&k1)?, parse_uint_key(&k2)?))
}
None => None,
};
Ok((found, next_cursor))
}

pub fn load_claims<'a, BS: Blockstore>(
&self,
store: &'a BS,
Expand Down Expand Up @@ -196,7 +226,36 @@ impl State {
self.save_claims(&mut st_claims)?;
Ok(())
}

// Lists all claim providers and IDs, paginated with a cursor.
// Returns a new cursor from which to continue listing, if any items remain.
pub fn list_claims<BS: Blockstore>(
&self,
store: &BS,
cursor: Option<Cursor>,
limit: Option<u64>,
) -> Result<(Vec<ClaimKey>, Option<Cursor>), ActorError> {
let (start_outer, start_inner) = verify_cursor(&cursor, self.claims)?;
let mut claims = self.load_claims(store)?;
let mut found = vec![];
let next = claims
.for_each_each(start_outer, start_inner, limit, |k1, k2, _v| {
let provider = parse_uint_key(k1)?;
let id = parse_uint_key(k2)?;
found.push(ClaimKey { provider, id });
Ok(())
})
.context_code(ExitCode::USR_ILLEGAL_STATE, "listing claims")?;
let next_cursor = match next {
Some((k1, k2)) => {
Some(Cursor::new(self.claims, parse_uint_key(&k1)?, parse_uint_key(&k2)?))
}
None => None,
};
Ok((found, next_cursor))
}
}

#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug, PartialEq, Eq)]
pub struct Claim {
// The provider storing the data (from allocation).
Expand Down Expand Up @@ -262,3 +321,44 @@ where
.get(provider, id)
.context_code(ExitCode::USR_ILLEGAL_STATE, "HAMT lookup failure getting claim")
}

/// Opaque cursor to iterate over allocations/claims data structures
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct Cursor {
pub root: Cid,
pub outer_key: ActorID,
pub inner_key: u64,
}

impl Cursor {
pub fn new(cid: Cid, outer_key: ActorID, inner_key: u64) -> Self {
Self { root: cid, inner_key, outer_key }
}

/// Generates a cursor from an opaque representation
pub fn from_bytes(bytes: RawBytes) -> Result<Option<Cursor>, ActorError> {
if bytes.is_empty() {
Ok(None)
} else {
Ok(Some(fvm_ipld_encoding::from_slice(&bytes)?))
}
}

/// Generates an opaque representation of the cursor that can be used to resume enumeration
pub fn to_bytes(&self) -> Result<RawBytes, ActorError> {
Ok(RawBytes::from(fvm_ipld_encoding::to_vec(self)?))
}
}

fn verify_cursor(
cursor: &Option<Cursor>,
expected_root: Cid,
) -> Result<(Option<&ActorID>, Option<&u64>), ActorError> {
if let Some(cursor) = cursor {
if cursor.root != expected_root {
return Err(ActorError::illegal_argument("invalid cursor".to_string()));
}
return Ok((Some(&cursor.outer_key), Some(&cursor.inner_key)));
}
Ok((None, None))
}
Loading
Loading