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

fix(market-pallet): deal settling #149

Merged
Show file tree
Hide file tree
Changes from 4 commits
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
25 changes: 18 additions & 7 deletions pallets/market/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -834,18 +834,25 @@ pub mod pallet {
sector_expiry: BlockNumberFor<T>,
sector_activation: BlockNumberFor<T>,
) -> Result<(), DealActivationError> {
log::trace!(target: LOG_TARGET, "validate_deal_can_activate: {provider:?} == {:?}", deal.provider);
ensure!(
*provider == deal.provider,
DealActivationError::InvalidProvider
);

log::trace!(target: LOG_TARGET, "validate_deal_can_activate: {:?} == DealState::Published", deal.state);
ensure!(
deal.state == DealState::Published,
DealActivationError::InvalidDealState
);

log::trace!(target: LOG_TARGET, "validate_deal_can_activate: {sector_activation:?} <= {:?}", deal.start_block);
ensure!(
sector_activation <= deal.start_block,
DealActivationError::StartBlockElapsed
);

log::trace!(target: LOG_TARGET, "validate_deal_can_activate: {sector_expiry:?} >= {:?}", deal.end_block);
ensure!(
sector_expiry >= deal.end_block,
DealActivationError::SectorExpiresBeforeDeal
Expand Down Expand Up @@ -923,32 +930,35 @@ pub mod pallet {
>,
provider: &T::AccountId,
) -> Result<(), ProposalError> {
Self::validate_signature(
&Encode::encode(&deal.proposal),
&deal.client_signature,
&deal.proposal.client,
)?;
log::trace!(target: LOG_TARGET, "validating signature... {:?}", deal.client_signature);
let encoded = Encode::encode(&deal.proposal);
Self::validate_signature(&encoded, &deal.client_signature, &deal.proposal.client)?;

// Ensure the Piece's Cid is parsable and valid
log::trace!(target: LOG_TARGET, "validating cid...");
let _ = deal.proposal.cid()?;

log::trace!(target: LOG_TARGET, "checking if provider is the same across deals");
ensure!(
deal.proposal.provider == *provider,
ProposalError::DifferentProvider
);

log::trace!(target: LOG_TARGET, "check if deal.start_block < deal.end_block");
ensure!(
deal.proposal.start_block < deal.proposal.end_block,
ProposalError::DealEndBeforeStart
);

log::trace!(target: LOG_TARGET, "check if deal.state == PUBLISHED");
ensure!(
deal.proposal.state == DealState::Published,
ProposalError::DealNotPublished
);

let min_dur = T::BlocksPerDay::get() * T::MinDealDuration::get();
let max_dur = T::BlocksPerDay::get() * T::MaxDealDuration::get();
log::trace!(target: LOG_TARGET, "checking if deal.duration() {:?} <= {:?} <= {:?}", min_dur, deal.proposal.duration(), max_dur);
ensure!(
deal.proposal.duration() >= min_dur && deal.proposal.duration() <= max_dur,
ProposalError::DealDurationOutOfBounds
Expand Down Expand Up @@ -1400,6 +1410,9 @@ pub mod pallet {
log::error!(target: LOG_TARGET, "on_finalize: invariant violated, cannot slash the deal {}", deal_id);
continue;
};

// Deal has been processed, no need to process it twice.
Proposals::<T>::remove(&deal_id);
}
DealState::Active(_) => {
log::info!(
Expand All @@ -1409,8 +1422,6 @@ pub mod pallet {
}
}

// Deal has been processed, no need to process it twice.
Proposals::<T>::remove(&deal_id);
// PRE-COND: all deals in DealsPerBlock are published.
// All Published deals are hashed and added to [`PendingProposals`].
let _ = pending_proposals.remove(&Self::hash_proposal(&proposal));
Expand Down
76 changes: 60 additions & 16 deletions pallets/storage-provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,29 +221,42 @@ pub mod pallet {
.map_err(|_| Error::<T>::StorageProviderNotFound)?;
let sector_number = sector.sector_number;
let current_block = <frame_system::Pallet<T>>::block_number();

log::trace!(
target: LOG_TARGET,
"checking sector number {sector_number} <= {SECTORS_MAX}",
);
ensure!(
sector_number <= SECTORS_MAX.into(),
Error::<T>::InvalidSector
);
log::trace!(target: LOG_TARGET, "checking proof type");
ensure!(
sp.info.window_post_proof_type == sector.seal_proof.registered_window_post_proof(),
Error::<T>::InvalidProofType
);
log::trace!(target: LOG_TARGET, "checking sector number not used");
ensure!(
!sp.pre_committed_sectors.contains_key(&sector_number)
&& !sp.sectors.contains_key(&sector_number),
Error::<T>::SectorNumberAlreadyUsed
);
validate_cid::<T>(&sector.unsealed_cid[..])?;
let balance = T::Currency::total_balance(&owner);
let deposit = calculate_pre_commit_deposit::<T>();

Self::validate_expiration(
current_block,
current_block + T::MaxProveCommitDuration::get(),
sector.expiration,
)?;

let balance = T::Currency::total_balance(&owner);
let deposit = calculate_pre_commit_deposit::<T>();
log::trace!(target: LOG_TARGET, "checking balance {balance:?} >= {deposit:?}");
ensure!(balance >= deposit, Error::<T>::NotEnoughFunds);

// Reserve deposit from storage provider
T::Currency::reserve(&owner, deposit)?;

StorageProviders::<T>::try_mutate(&owner, |maybe_sp| -> DispatchResult {
let sp = maybe_sp
.as_mut()
Expand All @@ -257,7 +270,10 @@ pub mod pallet {
.map_err(|_| Error::<T>::MaxPreCommittedSectorExceeded)?;
Ok(())
})?;

// Notify that the sector has been pre-committed
Self::deposit_event(Event::SectorPreCommitted { owner, sector });

Ok(())
}

Expand All @@ -268,18 +284,24 @@ pub mod pallet {
origin: OriginFor<T>,
sector: ProveCommitSector,
) -> DispatchResult {
log::trace!(target: LOG_TARGET, "prove_commit_sector: {:?}", sector);

let owner = ensure_signed(origin)?;
let sp = StorageProviders::<T>::try_get(&owner)
.map_err(|_| Error::<T>::StorageProviderNotFound)?;
let sector_number = sector.sector_number;
let sp = StorageProviders::<T>::try_get(&owner).map_err(|_| {
log::error!(target: LOG_TARGET, "storage provider {owner:?} not found ");
Error::<T>::StorageProviderNotFound
})?;

let precommit = sp
.get_pre_committed_sector(sector_number)
.map_err(|_| Error::<T>::InvalidSector)?;
let sector_number = sector.sector_number;
let precommit = sp.get_pre_committed_sector(sector_number).map_err(|_| {
log::error!(target: LOG_TARGET, "precommitted sector {sector_number} not found ");
Error::<T>::InvalidSector
})?;
let current_block = <frame_system::Pallet<T>>::block_number();
let prove_commit_due =
precommit.pre_commit_block_number + T::MaxProveCommitDuration::get();

log::trace!(target: LOG_TARGET, "prove_commit_sector: {current_block:?} < {prove_commit_due:?}");
ensure!(
current_block < prove_commit_due,
Error::<T>::ProveCommitAfterDeadline
Expand Down Expand Up @@ -311,6 +333,7 @@ pub mod pallet {
let deal_amount = sector_deals.len();
T::Market::activate_deals(&owner, sector_deals, deal_amount > 0)?;

// Notify that the sector has been proven
Self::deposit_event(Event::SectorProven {
owner,
sector_number,
Expand All @@ -327,42 +350,62 @@ pub mod pallet {
expiration: BlockNumberFor<T>,
) -> Result<(), Error<T>> {
// Expiration must be after activation. Check this explicitly to avoid an underflow below.
log::trace!(target: LOG_TARGET, "validate_expiration: {expiration:?} >= {activation:?}");
ensure!(
expiration >= activation,
Error::<T>::ExpirationBeforeActivation
);

// expiration cannot be less than minimum after activation
let min_sector_expiration = T::MinSectorExpiration::get();
log::trace!(target: LOG_TARGET, "validate_expiration: {expiration:?} - {activation:?} > {min_sector_expiration:?}");
ensure!(
expiration - activation > T::MinSectorExpiration::get(),
expiration - activation > min_sector_expiration,
Error::<T>::ExpirationTooSoon
);

// expiration cannot exceed MaxSectorExpirationExtension from now
let max_sector_expiration_extension = T::MaxSectorExpirationExtension::get();
log::trace!(target: LOG_TARGET, "validate_expiration: {expiration:?} < {curr_block:?} + {max_sector_expiration_extension:?}");
ensure!(
expiration < curr_block + T::MaxSectorExpirationExtension::get(),
expiration < curr_block + max_sector_expiration_extension,
Error::<T>::ExpirationTooLong,
);

// total sector lifetime cannot exceed SectorMaximumLifetime for the sector's seal proof
let sector_maximum_lifetime = T::SectorMaximumLifetime::get();
log::trace!(target: LOG_TARGET, "validate_expiration: {expiration:?} - {activation:?} < {sector_maximum_lifetime:?}");
ensure!(
expiration - activation < T::SectorMaximumLifetime::get(),
expiration - activation < sector_maximum_lifetime,
Error::<T>::MaxSectorLifetimeExceeded
);

Ok(())
}
}

// Adapted from filecoin reference here: https://github.com/filecoin-project/builtin-actors/blob/54236ae89880bf4aa89b0dba6d9060c3fd2aacee/actors/miner/src/commd.rs#L51-L56
fn validate_cid<T: Config>(bytes: &[u8]) -> Result<(), Error<T>> {
log::trace!(target: LOG_TARGET, "validating cid: {bytes:?}");

let c = Cid::try_from(bytes).map_err(|e| {
log::error!(target: LOG_TARGET, "failed to validate cid: {:?}", e);
Error::<T>::InvalidCid
})?;

let version = c.version();
let codec = c.codec();
let hash = c.hash();

log::trace!(target: LOG_TARGET, "cid: version {version:?} codec {codec} hash {hash:?}");

// these values should be consistent with the cid's created by the SP.
// They could change in the future when we make a definitive decision on what hashing algorithm to use and such
ensure!(
c.version() == Version::V1
&& c.codec() == CID_CODEC // The codec should align with our CID_CODEC value.
&& c.hash().code() == BLAKE2B_MULTIHASH_CODE // The CID should be hashed using blake2b
&& c.hash().size() == 32,
version == Version::V1
&& codec == CID_CODEC // The codec should align with our CID_CODEC value.
&& hash.code() == BLAKE2B_MULTIHASH_CODE // The CID should be hashed using blake2b
&& hash.size() == 32,
Error::<T>::InvalidCid
);
Ok(())
Expand All @@ -374,9 +417,10 @@ pub mod pallet {
}

fn validate_seal_proof(
_seal_proof_type: &RegisteredSealProof,
seal_proof_type: &RegisteredSealProof,
proofs: BoundedVec<u8, ConstU32<256>>,
) -> bool {
log::trace!(target: LOG_TARGET, "validate_seal_proof: {seal_proof_type:?} {proofs:?}");
proofs.len() != 0 // TODO(@aidan46, no-ref, 2024-06-24): Actually check proof
}
}