use cid::Cid;
use fvm_ipld_blockstore::Blockstore;
use fvm_ipld_encoding::tuple::*;
use fvm_shared3::address::Address;
use fvm_shared3::bigint::bigint_ser::BigIntDe;
use fvm_shared3::clock::ChainEpoch;
use fvm_shared3::error::ExitCode;
use fvm_shared3::piece::PaddedPieceSize;
use fvm_shared3::sector::SectorNumber;
use fvm_shared3::{ActorID, HAMT_BIT_WIDTH};
use super::DataCap;
use super::{AllocationID, ClaimID};
use fil_actors_shared::actor_error_v10;
use fil_actors_shared::v10::{
make_empty_map, make_map_with_root_and_bitwidth, ActorError, AsActorError, Map, MapMap,
};
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone)]
pub struct State {
pub root_key: Address,
pub verifiers: Cid, pub remove_data_cap_proposal_ids: Cid,
pub allocations: Cid, pub next_allocation_id: u64,
pub claims: Cid, }
impl State {
pub fn new<BS: Blockstore>(store: &BS, root_key: Address) -> Result<State, ActorError> {
let empty_map = make_empty_map::<_, ()>(store, HAMT_BIT_WIDTH)
.flush()
.map_err(|e| actor_error_v10!(illegal_state, "failed to create empty map: {}", e))?;
let empty_mapmap =
MapMap::<_, (), ActorID, u64>::new(store, HAMT_BIT_WIDTH, HAMT_BIT_WIDTH)
.flush()
.map_err(|e| {
actor_error_v10!(illegal_state, "failed to create empty multi map: {}", e)
})?;
Ok(State {
root_key,
verifiers: empty_map,
remove_data_cap_proposal_ids: empty_map,
allocations: empty_mapmap,
next_allocation_id: 1,
claims: empty_mapmap,
})
}
pub fn put_verifier(
&mut self,
store: &impl Blockstore,
verifier: &Address,
cap: &DataCap,
) -> Result<(), ActorError> {
let mut verifiers =
make_map_with_root_and_bitwidth::<_, BigIntDe>(&self.verifiers, store, HAMT_BIT_WIDTH)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load verifiers")?;
verifiers
.set(verifier.to_bytes().into(), BigIntDe(cap.clone()))
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to set verifier")?;
self.verifiers = verifiers
.flush()
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to flush verifiers")?;
Ok(())
}
pub fn remove_verifier(
&mut self,
store: &impl Blockstore,
verifier: &Address,
) -> Result<(), ActorError> {
let mut verifiers =
make_map_with_root_and_bitwidth::<_, BigIntDe>(&self.verifiers, store, HAMT_BIT_WIDTH)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load verifiers")?;
verifiers
.delete(&verifier.to_bytes())
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to remove verifier")?
.context_code(ExitCode::USR_ILLEGAL_ARGUMENT, "verifier not found")?;
self.verifiers = verifiers
.flush()
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to flush verifiers")?;
Ok(())
}
pub fn get_verifier_cap(
&self,
store: &impl Blockstore,
verifier: &Address,
) -> Result<Option<DataCap>, ActorError> {
let verifiers =
make_map_with_root_and_bitwidth::<_, BigIntDe>(&self.verifiers, store, HAMT_BIT_WIDTH)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load verifiers")?;
let allowance = verifiers
.get(&verifier.to_bytes())
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to get verifier")?;
Ok(allowance.map(|a| a.0.clone() as DataCap))
}
pub fn load_verifiers<'a, BS: Blockstore>(
&self,
store: &'a BS,
) -> Result<Map<'a, BS, BigIntDe>, ActorError> {
make_map_with_root_and_bitwidth::<_, BigIntDe>(&self.verifiers, store, HAMT_BIT_WIDTH)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load verifiers")
}
pub fn load_allocs<'a, BS: Blockstore>(
&self,
store: &'a BS,
) -> Result<MapMap<'a, BS, Allocation, ActorID, AllocationID>, ActorError> {
MapMap::<BS, Allocation, ActorID, AllocationID>::from_root(
store,
&self.allocations,
HAMT_BIT_WIDTH,
HAMT_BIT_WIDTH,
)
.context_code(
ExitCode::USR_ILLEGAL_STATE,
"failed to load allocations table",
)
}
pub fn save_allocs<BS: Blockstore>(
&mut self,
allocs: &mut MapMap<'_, BS, Allocation, ActorID, AllocationID>,
) -> Result<(), ActorError> {
self.allocations = allocs.flush().context_code(
ExitCode::USR_ILLEGAL_STATE,
"failed to flush allocations table",
)?;
Ok(())
}
pub fn insert_allocations<BS: Blockstore>(
&mut self,
store: &BS,
client: ActorID,
new_allocs: Vec<Allocation>,
) -> Result<Vec<AllocationID>, ActorError> {
if new_allocs.is_empty() {
return Ok(vec![]);
}
let mut allocs = self.load_allocs(store)?;
let first_id = self.next_allocation_id;
let mut count = 0;
let count_ref = &mut count;
allocs
.put_many(
client,
new_allocs.into_iter().map(move |a| {
let id = first_id + *count_ref;
*count_ref += 1;
(id, a)
}),
)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to put allocations")?;
self.save_allocs(&mut allocs)?;
self.next_allocation_id += count;
let allocated_ids = (first_id..first_id + count).collect();
Ok(allocated_ids)
}
pub fn load_claims<'a, BS: Blockstore>(
&self,
store: &'a BS,
) -> Result<MapMap<'a, BS, Claim, ActorID, ClaimID>, ActorError> {
MapMap::<BS, Claim, ActorID, ClaimID>::from_root(
store,
&self.claims,
HAMT_BIT_WIDTH,
HAMT_BIT_WIDTH,
)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load claims table")
}
pub fn save_claims<BS: Blockstore>(
&mut self,
claims: &mut MapMap<'_, BS, Claim, ActorID, ClaimID>,
) -> Result<(), ActorError> {
self.claims = claims
.flush()
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to flush claims table")?;
Ok(())
}
pub fn put_claims<BS: Blockstore>(
&mut self,
store: &BS,
claims: Vec<(ClaimID, Claim)>,
) -> Result<(), ActorError> {
if claims.is_empty() {
return Ok(());
}
let mut st_claims = self.load_claims(store)?;
for (id, claim) in claims.into_iter() {
st_claims
.put(claim.provider, id, claim)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to put claim")?;
}
self.save_claims(&mut st_claims)?;
Ok(())
}
}
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug, PartialEq, Eq)]
pub struct Claim {
pub provider: ActorID,
pub client: ActorID,
pub data: Cid,
pub size: PaddedPieceSize,
pub term_min: ChainEpoch,
pub term_max: ChainEpoch,
pub term_start: ChainEpoch,
pub sector: SectorNumber,
}
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug, PartialEq, Eq)]
pub struct Allocation {
pub client: ActorID,
pub provider: ActorID,
pub data: Cid,
pub size: PaddedPieceSize,
pub term_min: ChainEpoch,
pub term_max: ChainEpoch,
pub expiration: ChainEpoch,
}
pub fn get_allocation<'a, BS>(
allocations: &'a mut MapMap<BS, Allocation, ActorID, AllocationID>,
client: ActorID,
id: AllocationID,
) -> Result<Option<&'a Allocation>, ActorError>
where
BS: Blockstore,
{
allocations.get(client, id).context_code(
ExitCode::USR_ILLEGAL_STATE,
"HAMT lookup failure getting allocation",
)
}
pub fn get_claim<'a, BS>(
claims: &'a mut MapMap<BS, Claim, ActorID, ClaimID>,
provider: ActorID,
id: ClaimID,
) -> Result<Option<&'a Claim>, ActorError>
where
BS: Blockstore,
{
claims.get(provider, id).context_code(
ExitCode::USR_ILLEGAL_STATE,
"HAMT lookup failure getting claim",
)
}