diff --git a/actors/market/src/lib.rs b/actors/market/src/lib.rs index 3bbbc0e19..8d8ebb591 100644 --- a/actors/market/src/lib.rs +++ b/actors/market/src/lib.rs @@ -77,6 +77,15 @@ pub enum Method { AddBalanceExported = frc42_dispatch::method_hash!("AddBalance"), WithdrawBalanceExported = frc42_dispatch::method_hash!("WithdrawBalance"), GetBalanceExported = frc42_dispatch::method_hash!("GetBalance"), + GetDealDataCommitmentExported = frc42_dispatch::method_hash!("GetDealDataCommitment"), + GetDealClientExported = frc42_dispatch::method_hash!("GetDealClient"), + GetDealProviderExported = frc42_dispatch::method_hash!("GetDealProvider"), + GetDealLabelExported = frc42_dispatch::method_hash!("GetDealLabel"), + GetDealTermExported = frc42_dispatch::method_hash!("GetDealTerm"), + GetDealEpochPriceExported = frc42_dispatch::method_hash!("GetDealEpochPrice"), + GetDealClientCollateralExported = frc42_dispatch::method_hash!("GetDealClientCollateral"), + GetDealProviderCollateralExported = frc42_dispatch::method_hash!("GetDealProviderCollateral"), + GetDealVerifiedExported = frc42_dispatch::method_hash!("GetDealVerified"), } /// Market Actor @@ -821,6 +830,101 @@ impl Actor { } Ok(()) } + + /// Returns the data commitment and size of a deal proposal. + /// This will be available after the deal is published (whether or not is is activated) + /// and up until some undefined period after it is terminated. + fn get_deal_data_commitment( + rt: &mut impl Runtime, + params: GetDealDataCommitmentParams, + ) -> Result { + rt.validate_immediate_caller_accept_any()?; + let found = rt.state::()?.get_proposal(rt.store(), params.id)?; + Ok(GetDealDataCommitmentReturn { data: found.piece_cid, size: found.piece_size }) + } + + /// Returns the client of a deal proposal. + fn get_deal_client( + rt: &mut impl Runtime, + params: GetDealClientParams, + ) -> Result { + rt.validate_immediate_caller_accept_any()?; + let found = rt.state::()?.get_proposal(rt.store(), params.id)?; + Ok(GetDealClientReturn { client: found.client.id().unwrap() }) + } + + /// Returns the provider of a deal proposal. + fn get_deal_provider( + rt: &mut impl Runtime, + params: GetDealProviderParams, + ) -> Result { + rt.validate_immediate_caller_accept_any()?; + let found = rt.state::()?.get_proposal(rt.store(), params.id)?; + Ok(GetDealProviderReturn { provider: found.provider.id().unwrap() }) + } + + /// Returns the label of a deal proposal. + fn get_deal_label( + rt: &mut impl Runtime, + params: GetDealLabelParams, + ) -> Result { + rt.validate_immediate_caller_accept_any()?; + let found = rt.state::()?.get_proposal(rt.store(), params.id)?; + Ok(GetDealLabelReturn { label: found.label }) + } + + /// Returns the start and end epochs of a deal proposal. + /// The deal term is a half-open range, exclusive of the end epoch. + fn get_deal_term( + rt: &mut impl Runtime, + params: GetDealTermParams, + ) -> Result { + rt.validate_immediate_caller_accept_any()?; + let found = rt.state::()?.get_proposal(rt.store(), params.id)?; + Ok(GetDealTermReturn { start: found.start_epoch, end: found.end_epoch }) + } + + /// Returns the per-epoch price of a deal proposal. + fn get_deal_epoch_price( + rt: &mut impl Runtime, + params: GetDealEpochPriceParams, + ) -> Result { + rt.validate_immediate_caller_accept_any()?; + let found = rt.state::()?.get_proposal(rt.store(), params.id)?; + Ok(GetDealEpochPriceReturn { price_per_epoch: found.storage_price_per_epoch }) + } + + /// Returns the client collateral requirement for a deal proposal. + fn get_deal_client_collateral( + rt: &mut impl Runtime, + params: GetDealClientCollateralParams, + ) -> Result { + rt.validate_immediate_caller_accept_any()?; + let found = rt.state::()?.get_proposal(rt.store(), params.id)?; + Ok(GetDealClientCollateralReturn { collateral: found.client_collateral }) + } + + /// Returns the provider collateral requirement for a deal proposal. + fn get_deal_provider_collateral( + rt: &mut impl Runtime, + params: GetDealProviderCollateralParams, + ) -> Result { + rt.validate_immediate_caller_accept_any()?; + let found = rt.state::()?.get_proposal(rt.store(), params.id)?; + Ok(GetDealProviderCollateralReturn { collateral: found.provider_collateral }) + } + + /// Returns the verified flag for a deal proposal. + /// Note that the source of truth for verified allocations and claims is + /// the verified registry actor. + fn get_deal_verified( + rt: &mut impl Runtime, + params: GetDealVerifiedParams, + ) -> Result { + rt.validate_immediate_caller_accept_any()?; + let found = rt.state::()?.get_proposal(rt.store(), params.id)?; + Ok(GetDealVerifiedReturn { verified: found.verified_deal }) + } } fn compute_data_commitment( @@ -1240,6 +1344,43 @@ impl ActorCode for Actor { let res = Self::get_balance(rt, cbor::deserialize_params(params)?)?; Ok(RawBytes::serialize(res)?) } + Some(Method::GetDealDataCommitmentExported) => { + let res = Self::get_deal_data_commitment(rt, cbor::deserialize_params(params)?)?; + Ok(RawBytes::serialize(res)?) + } + Some(Method::GetDealClientExported) => { + let res = Self::get_deal_client(rt, cbor::deserialize_params(params)?)?; + Ok(RawBytes::serialize(res)?) + } + Some(Method::GetDealProviderExported) => { + let res = Self::get_deal_provider(rt, cbor::deserialize_params(params)?)?; + Ok(RawBytes::serialize(res)?) + } + Some(Method::GetDealLabelExported) => { + let res = Self::get_deal_label(rt, cbor::deserialize_params(params)?)?; + Ok(RawBytes::serialize(res)?) + } + Some(Method::GetDealTermExported) => { + let res = Self::get_deal_term(rt, cbor::deserialize_params(params)?)?; + Ok(RawBytes::serialize(res)?) + } + Some(Method::GetDealEpochPriceExported) => { + let res = Self::get_deal_epoch_price(rt, cbor::deserialize_params(params)?)?; + Ok(RawBytes::serialize(res)?) + } + Some(Method::GetDealClientCollateralExported) => { + let res = Self::get_deal_client_collateral(rt, cbor::deserialize_params(params)?)?; + Ok(RawBytes::serialize(res)?) + } + Some(Method::GetDealProviderCollateralExported) => { + let res = + Self::get_deal_provider_collateral(rt, cbor::deserialize_params(params)?)?; + Ok(RawBytes::serialize(res)?) + } + Some(Method::GetDealVerifiedExported) => { + let res = Self::get_deal_verified(rt, cbor::deserialize_params(params)?)?; + Ok(RawBytes::serialize(res)?) + } None => Err(actor_error!(unhandled_message, "Invalid method")), } } diff --git a/actors/market/src/types.rs b/actors/market/src/types.rs index bac78d0df..afdfa2da4 100644 --- a/actors/market/src/types.rs +++ b/actors/market/src/types.rs @@ -15,6 +15,7 @@ use fvm_shared::econ::TokenAmount; use fvm_shared::piece::PaddedPieceSize; use fvm_shared::ActorID; +use crate::Label; use fvm_shared::sector::RegisteredSealProof; use super::deal::{ClientDealProposal, DealProposal, DealState}; @@ -136,3 +137,71 @@ pub struct SectorDataSpec { pub deal_ids: Vec, pub sector_type: RegisteredSealProof, } + +#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)] +#[serde(transparent)] +pub struct DealQueryParams { + pub id: DealID, +} + +pub type GetDealDataCommitmentParams = DealQueryParams; +#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)] +pub struct GetDealDataCommitmentReturn { + pub data: Cid, + pub size: PaddedPieceSize, +} + +pub type GetDealClientParams = DealQueryParams; +#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)] +#[serde(transparent)] +pub struct GetDealClientReturn { + pub client: ActorID, +} + +pub type GetDealProviderParams = DealQueryParams; +#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)] +#[serde(transparent)] +pub struct GetDealProviderReturn { + pub provider: ActorID, +} + +pub type GetDealLabelParams = DealQueryParams; +#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)] +#[serde(transparent)] +pub struct GetDealLabelReturn { + pub label: Label, +} + +pub type GetDealTermParams = DealQueryParams; +#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)] +pub struct GetDealTermReturn { + pub start: ChainEpoch, // First epoch for the deal (inclusive) + pub end: ChainEpoch, // Epoch at which the deal expires (i.e. exclusive). +} + +pub type GetDealEpochPriceParams = DealQueryParams; +#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)] +pub struct GetDealEpochPriceReturn { + pub price_per_epoch: TokenAmount, +} + +pub type GetDealClientCollateralParams = DealQueryParams; +#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)] +#[serde(transparent)] +pub struct GetDealClientCollateralReturn { + pub collateral: TokenAmount, +} + +pub type GetDealProviderCollateralParams = DealQueryParams; +#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)] +#[serde(transparent)] +pub struct GetDealProviderCollateralReturn { + pub collateral: TokenAmount, +} + +pub type GetDealVerifiedParams = DealQueryParams; +#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)] +#[serde(transparent)] +pub struct GetDealVerifiedReturn { + pub verified: bool, +} diff --git a/actors/market/tests/deal_api_test.rs b/actors/market/tests/deal_api_test.rs new file mode 100644 index 000000000..4471f0f43 --- /dev/null +++ b/actors/market/tests/deal_api_test.rs @@ -0,0 +1,81 @@ +use fvm_ipld_encoding::RawBytes; +use fvm_shared::clock::ChainEpoch; +use serde::de::DeserializeOwned; + +use fil_actor_market::{ + Actor as MarketActor, DealQueryParams, GetDealClientCollateralReturn, GetDealClientReturn, + GetDealDataCommitmentReturn, GetDealEpochPriceReturn, GetDealLabelReturn, + GetDealProviderCollateralReturn, GetDealProviderReturn, GetDealTermReturn, + GetDealVerifiedReturn, Method, +}; +use fil_actors_runtime::network::EPOCHS_IN_DAY; +use fil_actors_runtime::test_utils::{MockRuntime, ACCOUNT_ACTOR_CODE_ID}; +use harness::*; + +mod harness; + +#[test] +fn proposal_data() { + let start_epoch = 1000; + let end_epoch = start_epoch + 200 * EPOCHS_IN_DAY; + let publish_epoch = ChainEpoch::from(1); + + let mut rt = setup(); + rt.set_epoch(publish_epoch); + let next_allocation_id = 1; + + let proposal = generate_deal_and_add_funds( + &mut rt, + CLIENT_ADDR, + &MinerAddresses::default(), + start_epoch, + end_epoch, + ); + rt.set_caller(*ACCOUNT_ACTOR_CODE_ID, WORKER_ADDR); + let id = + publish_deals(&mut rt, &MinerAddresses::default(), &[proposal.clone()], next_allocation_id) + [0]; + + let data: GetDealDataCommitmentReturn = + query_deal(&mut rt, Method::GetDealDataCommitmentExported, id); + assert_eq!(proposal.piece_cid, data.data); + assert_eq!(proposal.piece_size, data.size); + + let client: GetDealClientReturn = query_deal(&mut rt, Method::GetDealClientExported, id); + assert_eq!(proposal.client.id().unwrap(), client.client); + + let provider: GetDealProviderReturn = query_deal(&mut rt, Method::GetDealProviderExported, id); + assert_eq!(proposal.provider.id().unwrap(), provider.provider); + + let label: GetDealLabelReturn = query_deal(&mut rt, Method::GetDealLabelExported, id); + assert_eq!(proposal.label, label.label); + + let term: GetDealTermReturn = query_deal(&mut rt, Method::GetDealTermExported, id); + assert_eq!(proposal.start_epoch, term.start); + assert_eq!(proposal.end_epoch, term.end); + + let price: GetDealEpochPriceReturn = query_deal(&mut rt, Method::GetDealEpochPriceExported, id); + assert_eq!(proposal.storage_price_per_epoch, price.price_per_epoch); + + let client_collateral: GetDealClientCollateralReturn = + query_deal(&mut rt, Method::GetDealClientCollateralExported, id); + assert_eq!(proposal.client_collateral, client_collateral.collateral); + + let provider_collateral: GetDealProviderCollateralReturn = + query_deal(&mut rt, Method::GetDealProviderCollateralExported, id); + assert_eq!(proposal.provider_collateral, provider_collateral.collateral); + + let verified: GetDealVerifiedReturn = query_deal(&mut rt, Method::GetDealVerifiedExported, id); + assert_eq!(proposal.verified_deal, verified.verified); + + check_state(&rt); +} + +fn query_deal(rt: &mut MockRuntime, method: Method, id: u64) -> T { + let params = DealQueryParams { id }; + rt.expect_validate_caller_any(); + rt.call::(method as u64, &RawBytes::serialize(params).unwrap()) + .unwrap() + .deserialize() + .unwrap() +}