Skip to content

Commit

Permalink
Basic tests
Browse files Browse the repository at this point in the history
  • Loading branch information
anorth committed Aug 9, 2023
1 parent 1c09ff7 commit 887b7a9
Show file tree
Hide file tree
Showing 12 changed files with 600 additions and 189 deletions.
18 changes: 8 additions & 10 deletions actors/market/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,35 +56,33 @@ pub mod miner {
// Notification of change committed to one or more sectors.
// The relevant state must be already committed so the receiver can observe any impacts
// at the sending miner actor.
#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)]
// TODO REVIEW: #[serde(transparent)]?
pub struct SectorContentChangedParams {
// Distinct sectors with changed content.
pub sectors: Vec<SectorChanges>,
}

// Description of changes to one sector's content.
#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)]
pub struct SectorChanges {
// Identifier of sector being updated.
pub sector: SectorNumber,
// Minimum epoch until which the data is committed to the sector.
// Note the sector may later be extended without necessarily another notification.
pub commitment_epoch: ChainEpoch,
pub minimum_commitment_epoch: ChainEpoch,
// Information about some pieces added to (or retained in) the sector.
// This may be only a subset of sector content.
// Inclusion here does not mean the piece was definitely absent previously.
// Exclusion here does not mean a piece has been removed since a prior notification.
pub added: Vec<PieceInfo>,
}

// Description of a peice of data committed to a sector.
#[derive(Serialize_tuple, Deserialize_tuple)]
// Description of a piece of data committed to a sector.
#[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)]
pub struct PieceInfo {
pub data: Cid,
pub size: PaddedPieceSize,
// TODO: should the offset within the sector be included to allow complete addressing?
pub offset: u64,
// A receiver-specific identifier.
// E.g. an encoded deal ID which the provider claims this piece satisfies.
pub payload: Vec<u8>,
Expand All @@ -93,19 +91,19 @@ pub mod miner {
// For each piece in each sector, the notifee returns an exit code and
// (possibly-empty) result data.
// The miner actor will pass through results to its caller.
#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)]
// TODO REVIEW: #[serde(transparent)]?
pub struct SectorContentChangedReturn {
// A result for each sector that was notified, in the same order.
pub sectors: Vec<SectorReturn>,
}
#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)]
// TODO REVIEW: #[serde(transparent)]?
pub struct SectorReturn {
// A result for each piece for the sector that was notified, in the same order.
pub added: Vec<PieceReturn>,
}
#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)]
pub struct PieceReturn {
// Indicates whether the receiver accepted the notification.
// The caller is free to ignore this, but may chose to abort and roll back.
Expand Down
114 changes: 80 additions & 34 deletions actors/market/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use fil_actors_runtime::runtime::builtins::Type;
use fil_actors_runtime::runtime::{ActorCode, Policy, Runtime};
use fil_actors_runtime::{
actor_dispatch, actor_error, deserialize_block, ActorContext, ActorDowncast, ActorError,
AsActorError, Map, Set, BURNT_FUNDS_ACTOR_ADDR, CRON_ACTOR_ADDR, DATACAP_TOKEN_ACTOR_ADDR,
AsActorError, Set, BURNT_FUNDS_ACTOR_ADDR, CRON_ACTOR_ADDR, DATACAP_TOKEN_ACTOR_ADDR,
REWARD_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, SYSTEM_ACTOR_ADDR, VERIFIED_REGISTRY_ACTOR_ADDR,
};
use fil_actors_runtime::{extract_send_result, BatchReturnGen, FIRST_ACTOR_SPECIFIC_EXIT_CODE};
Expand Down Expand Up @@ -572,17 +572,13 @@ impl Actor {
batch_gen.add_fail(ExitCode::USR_ILLEGAL_ARGUMENT);
continue 'sector;
}
// The deal might fail activation later, but ignoring that for duplicate-checking
// is not worth the complexity.
activated_deals.insert(*deal_id);

let (proposal, alloc_id) = match preactivate_deal(
let proposal = match preactivate_deal(
rt,
*deal_id,
&proposals,
&states,
&pending_deals,
&mut pending_deal_allocation_ids,
&miner_addr,
p.sector_expiry,
curr_epoch,
Expand All @@ -597,6 +593,15 @@ impl Actor {
};

// No continue below here, to ensure state changes are consistent.
// Any error is an abort.
// Extract and remove any verified allocation ID for the pending deal.
let alloc_id = remove_pending_deal_allocation_id(
// FIXME move outside inner loop
&mut pending_deal_allocation_ids,
*deal_id,
)?
.unwrap_or(NO_ALLOCATION_ID);

if alloc_id != NO_ALLOCATION_ID {
verified_infos.push(VerifiedDealInfo {
client: proposal.client.id().unwrap(),
Expand All @@ -619,6 +624,9 @@ impl Actor {
},
));
}
for id in &p.deal_ids {
activated_deals.insert(*id);
}

sectors_deals.push((p.sector_number, SectorDealIDs { deals: p.deal_ids.clone() }));
activations.push(SectorDealActivation { nonverified_deal_space, verified_infos });
Expand Down Expand Up @@ -670,17 +678,15 @@ impl Actor {
});
continue;
}
activated_deals.insert(deal_id);

let (_proposal, alloc_id) = match preactivate_deal(
let proposal = match preactivate_deal(
rt,
deal_id,
&proposals,
&states,
&pending_deals,
&mut pending_deal_allocation_ids,
&miner_addr,
sector.commitment_epoch,
sector.minimum_commitment_epoch,
curr_epoch,
st.next_id,
)? {
Expand All @@ -692,6 +698,43 @@ impl Actor {
}
};

if piece.data != proposal.piece_cid {
log::warn!(
"failed to activate: piece CID {} doesn't match deal {} with {}",
piece.data,
deal_id,
proposal.piece_cid
);
pieces_ret.push(PieceReturn {
code: ExitCode::USR_ILLEGAL_ARGUMENT,
data: vec![],
});
continue;
}
if piece.size != proposal.piece_size {
log::warn!(
"failed to activate: piece size {} doesn't match deal {} with {}",
piece.size.0,
deal_id,
proposal.piece_size.0
);
pieces_ret.push(PieceReturn {
code: ExitCode::USR_ILLEGAL_ARGUMENT,
data: vec![],
});
continue;
}

// No continue below here, to ensure state changes are consistent.
activated_deals.insert(deal_id);

// Extract and remove any verified allocation ID for the pending deal.
let alloc_id = remove_pending_deal_allocation_id(
&mut pending_deal_allocation_ids,
deal_id,
)?
.unwrap_or(NO_ALLOCATION_ID);

deal_states.push((
deal_id,
DealState {
Expand All @@ -711,6 +754,7 @@ impl Actor {
},
));
sector_deal_ids.push(deal_id);
pieces_ret.push(PieceReturn { code: ExitCode::OK, data: vec![] });
}

sectors_deals.push((sector.sector, SectorDealIDs { deals: sector_deal_ids }));
Expand All @@ -719,6 +763,7 @@ impl Actor {
}
st.put_deal_states(rt.store(), &deal_states)?;
st.put_sector_deal_ids(rt.store(), &miner_addr, &sectors_deals)?;
st.save_pending_deal_allocation_ids(&mut pending_deal_allocation_ids)?;

assert_eq!(sectors_ret.len(), params.sectors.len(), "mismatched sector returns");
Ok(sectors_ret)
Expand Down Expand Up @@ -1191,7 +1236,7 @@ pub fn validate_deals_for_sector(
Ok(())
}

// Validates a deal can activate and updates state in preparation for its activation.
// Validates a deal is ready to activate now.
// There are two types of error possible here:
// - An Err in the outer result indicates something broken that should be propagated
// and abort the current message.
Expand All @@ -1204,13 +1249,20 @@ fn preactivate_deal<BS: Blockstore>(
proposals: &DealArray<BS>,
states: &DealMetaArray<BS>,
pending_proposals: &Set<BS>,
pending_deal_allocation_ids: &mut Map<BS, AllocationID>,
provider: &Address,
sector_commitment: ChainEpoch,
curr_epoch: ChainEpoch,
next_id: DealID,
) -> Result<Result<(DealProposal, AllocationID), ActorError>, ActorError> {
let proposal = get_proposal(proposals, deal_id, next_id)?;
) -> Result<Result<DealProposal, ActorError>, ActorError> {
let proposal = match get_proposal(proposals, deal_id, next_id) {
Ok(p) => p,
Err(e) => {
return match e.exit_code() {
ExitCode::USR_NOT_FOUND | EX_DEAL_EXPIRED => Ok(Err(e)), // Fail this deal only.
_ => Err(e), // Abort.
};
}
};

let ok = validate_deal_can_activate(&proposal, provider, sector_commitment, curr_epoch);
if let Err(e) = ok {
Expand All @@ -1229,11 +1281,7 @@ fn preactivate_deal<BS: Blockstore>(
return Ok(Err(actor_error!(illegal_argument, "deal {} is not in pending set", deal_cid)));
}

// Extract and remove any verified allocation ID for the pending deal.
let alloc_id = remove_pending_deal_allocation_id(pending_deal_allocation_ids, deal_id)?
.unwrap_or(NO_ALLOCATION_ID);

Ok(Ok((proposal, alloc_id)))
Ok(Ok(proposal))
}

fn alloc_request_for_deal(
Expand Down Expand Up @@ -1329,30 +1377,28 @@ fn validate_deal_can_activate(
curr_epoch: ChainEpoch,
) -> Result<(), ActorError> {
if &proposal.provider != miner_addr {
return Err(actor_error!(
forbidden,
return Err(ActorError::forbidden(format!(
"proposal has provider {}, must be {}",
proposal.provider,
miner_addr
));
proposal.provider, miner_addr
)));
};

if curr_epoch > proposal.start_epoch {
return Err(actor_error!(
illegal_argument,
"proposal start epoch {} has already elapsed at {}",
proposal.start_epoch,
curr_epoch
return Err(ActorError::unchecked(
// Use the same code as if the proposal had already been cleaned up from state.
EX_DEAL_EXPIRED,
format!(
"proposal start epoch {} has already elapsed at {}",
proposal.start_epoch, curr_epoch
),
));
};

if proposal.end_epoch > sector_expiration {
return Err(actor_error!(
illegal_argument,
return Err(ActorError::illegal_argument(format!(
"proposal expiration {} exceeds sector expiration {}",
proposal.end_epoch,
sector_expiration
));
proposal.end_epoch, sector_expiration
)));
};

Ok(())
Expand Down
Loading

0 comments on commit 887b7a9

Please sign in to comment.