Skip to content

Commit

Permalink
Claim verifreg allocations from miner actor (filecoin-project#715)
Browse files Browse the repository at this point in the history
Integrate FIL+ and miner actor
* Add FIL+ allocation claim to sector activation
* Match deal activation error semantics on alloc claim
* can_claim_allocation allows claiming on the epoch of expiration

Co-authored-by: zenground0 <[email protected]>
  • Loading branch information
2 people authored and shamb0 committed Jan 31, 2023
1 parent 9ae2008 commit 07c522f
Show file tree
Hide file tree
Showing 14 changed files with 379 additions and 136 deletions.
23 changes: 15 additions & 8 deletions actors/market/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,9 +534,7 @@ impl Actor {

Ok(VerifyDealsForActivationReturn { sectors: sectors_data })
}
/// Activate a set of deals, returning the combined deal weights.
/// The weight is defined as the sum, over all deals in the set, of the product of deal size
/// and duration.
/// Activate a set of deals, returning the combined deal space and extra info for verified deals.
fn activate_deals<BS, RT>(
rt: &mut RT,
params: ActivateDealsParams,
Expand Down Expand Up @@ -567,6 +565,7 @@ impl Actor {
};

// Update deal states
let mut verified_infos = Vec::new();
rt.transaction(|st: &mut State, rt| {
let mut msm = st.mutator(rt.store());
msm.with_deal_states(Permission::Write)
Expand Down Expand Up @@ -635,7 +634,17 @@ impl Actor {
.delete(&deal_id_key(deal_id))
.with_context_code(ExitCode::USR_ILLEGAL_STATE, || {
format!("failed to remove allocation id for deal {}", deal_id)
})?;
})?
.unwrap_or((BytesKey(vec![]), NO_ALLOCATION_ID))
.1;
if allocation != NO_ALLOCATION_ID {
verified_infos.push(VerifiedDealInfo {
client: proposal.client.id().unwrap(),
allocation_id: allocation,
data: proposal.piece_cid,
size: proposal.piece_size,
})
}
msm.deal_states
.as_mut()
.unwrap()
Expand All @@ -645,9 +654,7 @@ impl Actor {
sector_start_epoch: curr_epoch,
last_updated_epoch: EPOCH_UNDEFINED,
slash_epoch: EPOCH_UNDEFINED,
verified_claim: allocation
.unwrap_or((BytesKey(vec![]), NO_ALLOCATION_ID))
.1,
verified_claim: allocation,
},
)
.with_context_code(ExitCode::USR_ILLEGAL_STATE, || {
Expand All @@ -659,7 +666,7 @@ impl Actor {
Ok(())
})?;

Ok(ActivateDealsResult { spaces: deal_spaces })
Ok(ActivateDealsResult { nonverified_deal_space: deal_spaces.deal_space, verified_infos })
}

/// Terminate a set of deals in response to their containing sector being terminated.
Expand Down
17 changes: 15 additions & 2 deletions actors/market/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2019-2022 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

use super::ext::verifreg::AllocationID;
use cid::Cid;
use fil_actors_runtime::Array;
use fvm_ipld_bitfield::BitField;
Expand All @@ -11,6 +12,9 @@ use fvm_shared::bigint::{bigint_ser, BigInt};
use fvm_shared::clock::ChainEpoch;
use fvm_shared::deal::DealID;
use fvm_shared::econ::TokenAmount;
use fvm_shared::piece::PaddedPieceSize;
use fvm_shared::ActorID;

use fvm_shared::sector::RegisteredSealProof;

use super::deal::{ClientDealProposal, DealProposal, DealState};
Expand Down Expand Up @@ -95,11 +99,20 @@ pub struct ActivateDealsParams {
pub sector_expiry: ChainEpoch,
}

#[derive(Serialize_tuple, Deserialize_tuple, Clone)]
pub struct VerifiedDealInfo {
pub client: ActorID,
pub allocation_id: AllocationID,
pub data: Cid,
pub size: PaddedPieceSize,
}

#[derive(Serialize_tuple, Deserialize_tuple)]
pub struct ActivateDealsResult {
pub spaces: DealSpaces,
#[serde(with = "bigint_ser")]
pub nonverified_deal_space: BigInt,
pub verified_infos: Vec<VerifiedDealInfo>,
}

#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Default)]
pub struct DealSpaces {
#[serde(with = "bigint_ser")]
Expand Down
22 changes: 15 additions & 7 deletions actors/market/tests/verify_deals_for_activation_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,23 @@ fn verify_deal_and_activate_to_get_deal_space_for_unverified_deal_proposal() {
let a_response = activate_deals(&mut rt, SECTOR_EXPIRY, PROVIDER_ADDR, CURR_EPOCH, &[deal_id]);
assert_eq!(1, v_response.sectors.len());
assert_eq!(Some(make_piece_cid("1".as_bytes())), v_response.sectors[0].commd);
assert_eq!(BigInt::zero(), a_response.spaces.verified_deal_space);
assert_eq!(BigInt::from(deal_proposal.piece_size.0), a_response.spaces.deal_space);
assert!(a_response.verified_infos.is_empty());
assert_eq!(BigInt::from(deal_proposal.piece_size.0), a_response.nonverified_deal_space);

check_state(&rt);
}

#[test]
fn verify_deal_and_activate_to_get_deal_space_for_verified_deal_proposal() {
let mut rt = setup();
let next_allocation_id = 1;
let deal_id = generate_and_publish_verified_deal(
&mut rt,
CLIENT_ADDR,
&MINER_ADDRESSES,
START_EPOCH,
END_EPOCH,
1,
next_allocation_id,
);
let deal_proposal = get_deal_proposal(&mut rt, deal_id);

Expand All @@ -85,8 +86,13 @@ fn verify_deal_and_activate_to_get_deal_space_for_verified_deal_proposal() {

assert_eq!(1, response.sectors.len());
assert_eq!(Some(make_piece_cid("1".as_bytes())), response.sectors[0].commd);
assert_eq!(BigInt::from(deal_proposal.piece_size.0), a_response.spaces.verified_deal_space);
assert_eq!(BigInt::zero(), a_response.spaces.deal_space);
assert_eq!(1, a_response.verified_infos.len());
assert_eq!(deal_proposal.piece_size, a_response.verified_infos[0].size);
assert_eq!(deal_proposal.client.id().unwrap(), a_response.verified_infos[0].client);
assert_eq!(deal_proposal.piece_cid, a_response.verified_infos[0].data);
assert_eq!(next_allocation_id, a_response.verified_infos[0].allocation_id);

assert_eq!(BigInt::zero(), a_response.nonverified_deal_space);

check_state(&rt);
}
Expand Down Expand Up @@ -145,8 +151,10 @@ fn verification_and_weights_for_verified_and_unverified_deals() {
let a_response = activate_deals(&mut rt, SECTOR_EXPIRY, PROVIDER_ADDR, CURR_EPOCH, &deal_ids);

assert_eq!(1, response.sectors.len());
assert_eq!(verified_space, a_response.spaces.verified_deal_space);
assert_eq!(unverified_space, a_response.spaces.deal_space);
let returned_verified_space: BigInt =
a_response.verified_infos.iter().map(|info| BigInt::from(info.size.0)).sum();
assert_eq!(verified_space, returned_verified_space);
assert_eq!(unverified_space, a_response.nonverified_deal_space);

check_state(&rt);
}
Expand Down
48 changes: 47 additions & 1 deletion actors/miner/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,30 @@ pub mod market {
pub sector_expiry: ChainEpoch,
}

#[derive(Serialize_tuple, Deserialize_tuple, Clone)]
pub struct VerifiedDealInfo {
pub client: ActorID,
pub allocation_id: u64,
pub data: Cid,
pub size: PaddedPieceSize,
}

impl Default for VerifiedDealInfo {
fn default() -> VerifiedDealInfo {
VerifiedDealInfo {
size: PaddedPieceSize(0),
client: 0,
allocation_id: 0,
data: Default::default(),
}
}
}

#[derive(Serialize_tuple, Deserialize_tuple)]
pub struct ActivateDealsResult {
pub spaces: DealSpaces,
#[serde(with = "bigint_ser")]
pub nonverified_deal_space: BigInt,
pub verified_infos: Vec<VerifiedDealInfo>,
}

#[derive(Serialize_tuple, Deserialize_tuple, Clone, Default)]
Expand Down Expand Up @@ -138,8 +159,11 @@ pub mod verifreg {
use super::*;

pub const GET_CLAIMS_METHOD: u64 = 10;
pub const CLAIM_ALLOCATIONS_METHOD: u64 = 9;

pub type ClaimID = u64;
pub type AllocationID = u64;

#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug, PartialEq, Eq)]
pub struct Claim {
// The provider storing the data (from allocation).
Expand Down Expand Up @@ -170,4 +194,26 @@ pub mod verifreg {
pub batch_info: BatchReturn,
pub claims: Vec<Claim>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)]
pub struct SectorAllocationClaim {
pub client: ActorID,
pub allocation_id: AllocationID,
pub data: Cid,
pub size: PaddedPieceSize,
pub sector: SectorNumber,
pub sector_expiry: ChainEpoch,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)]
pub struct ClaimAllocationsParams {
pub sectors: Vec<SectorAllocationClaim>,
pub all_or_nothing: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)]
pub struct ClaimAllocationsReturn {
pub batch_info: BatchReturn,
#[serde(with = "bigint_ser")]
pub claimed_space: BigInt,
}
}
146 changes: 100 additions & 46 deletions actors/miner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1052,25 +1052,20 @@ impl Actor {
continue;
}

let res = rt.send(
&STORAGE_MARKET_ACTOR_ADDR,
ext::market::ACTIVATE_DEALS_METHOD,
RawBytes::serialize(ext::market::ActivateDealsParams {
deal_ids: update.deals.clone(),
sector_expiry: sector_info.expiration,
})?,
TokenAmount::zero(),
);
let deal_spaces = if let Ok(res) = res {
// Erroring in this case as it means something went really wrong
let activate_ret: ext::market::ActivateDealsResult = res.deserialize()?;
activate_ret.spaces
} else {
info!(
"failed to activate deals on sector {0}, skipping sector {0}",
update.sector_number,
);
continue;
let deal_spaces = match activate_deals_and_claim_allocations(
rt,
update.deals.clone(),
sector_info.expiration,
sector_info.sector_number,
)? {
Some(deal_spaces) => deal_spaces,
None => {
info!(
"failed to activate deals on sector {}, skipping from replica update set",
update.sector_number
);
continue;
}
};

let expiration = sector_info.expiration;
Expand Down Expand Up @@ -4834,35 +4829,21 @@ where
let mut valid_pre_commits = Vec::default();

for pre_commit in pre_commits {
let deal_spaces = if !pre_commit.info.deal_ids.is_empty() {
// Check (and activate) storage deals associated to sector. Abort if checks failed.
let res = rt.send(
&STORAGE_MARKET_ACTOR_ADDR,
ext::market::ACTIVATE_DEALS_METHOD,
RawBytes::serialize(ext::market::ActivateDealsParams {
deal_ids: pre_commit.info.deal_ids.clone(),
sector_expiry: pre_commit.info.expiration,
})?,
TokenAmount::zero(),
);
match res {
Ok(res) => {
let activate_res: ext::market::ActivateDealsResult = res.deserialize()?;
activate_res.spaces
}
Err(e) => {
info!(
"failed to activate deals on sector {}, dropping from prove commit set: {}",
pre_commit.info.sector_number,
e.msg()
);
continue;
}
match activate_deals_and_claim_allocations(
rt,
pre_commit.clone().info.deal_ids,
pre_commit.info.expiration,
pre_commit.info.sector_number,
)? {
None => {
info!(
"failed to activate deals on sector {}, dropping from prove commit set",
pre_commit.info.sector_number,
);
continue;
}
} else {
ext::market::DealSpaces::default()
Some(deal_spaces) => valid_pre_commits.push((pre_commit, deal_spaces)),
};
valid_pre_commits.push((pre_commit, deal_spaces));
}

// When all prove commits have failed abort early
Expand Down Expand Up @@ -5011,6 +4992,79 @@ where
Ok(())
}

// activate deals with builtin market and claim allocations with verified registry actor
// returns an error in case of a fatal programmer error
// returns Ok(None) in case deal activation or verified allocation claim fails
fn activate_deals_and_claim_allocations<RT, BS>(
rt: &mut RT,
deal_ids: Vec<DealID>,
sector_expiry: ChainEpoch,
sector_number: SectorNumber,
) -> Result<Option<crate::ext::market::DealSpaces>, ActorError>
where
BS: Blockstore,
RT: Runtime<BS>,
{
if deal_ids.is_empty() {
return Ok(Some(ext::market::DealSpaces::default()));
}
// Check (and activate) storage deals associated to sector. Abort if checks failed.
let activate_raw = rt.send(
&STORAGE_MARKET_ACTOR_ADDR,
ext::market::ACTIVATE_DEALS_METHOD,
RawBytes::serialize(ext::market::ActivateDealsParams { deal_ids, sector_expiry })?,
TokenAmount::zero(),
);
let activate_res: ext::market::ActivateDealsResult = match activate_raw {
Ok(res) => res.deserialize()?,
Err(e) => {
info!("error activating deals on sector {}: {}", sector_number, e.msg());
return Ok(None);
}
};

// If deal activation includes verified deals claim allocations
if activate_res.verified_infos.is_empty() {
return Ok(Some(ext::market::DealSpaces {
deal_space: activate_res.nonverified_deal_space,
..Default::default()
}));
}
let sector_claims = activate_res
.verified_infos
.iter()
.map(|info| ext::verifreg::SectorAllocationClaim {
client: info.client,
allocation_id: info.allocation_id,
data: info.data,
size: info.size,
sector: sector_number,
sector_expiry,
})
.collect();

let claim_raw = rt.send(
&VERIFIED_REGISTRY_ACTOR_ADDR,
ext::verifreg::CLAIM_ALLOCATIONS_METHOD,
RawBytes::serialize(ext::verifreg::ClaimAllocationsParams {
sectors: sector_claims,
all_or_nothing: true,
})?,
TokenAmount::zero(),
);
let claim_res: ext::verifreg::ClaimAllocationsReturn = match claim_raw {
Ok(res) => res.deserialize()?,
Err(e) => {
info!("error claiming allocation on sector {}: {}", sector_number, e.msg());
return Ok(None);
}
};
Ok(Some(ext::market::DealSpaces {
deal_space: activate_res.nonverified_deal_space,
verified_deal_space: claim_res.claimed_space,
}))
}

// XXX: probably better to push this one level down into state
fn balance_invariants_broken(e: Error) -> ActorError {
ActorError::unchecked(
Expand Down
Loading

0 comments on commit 07c522f

Please sign in to comment.