Skip to content

Commit ad4f69b

Browse files
authored
Built-in market API for deal proposal metadata (#818)
1 parent 245de89 commit ad4f69b

File tree

4 files changed

+307
-0
lines changed

4 files changed

+307
-0
lines changed

actors/market/src/lib.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,15 @@ pub enum Method {
7777
AddBalanceExported = frc42_dispatch::method_hash!("AddBalance"),
7878
WithdrawBalanceExported = frc42_dispatch::method_hash!("WithdrawBalance"),
7979
GetBalanceExported = frc42_dispatch::method_hash!("GetBalance"),
80+
GetDealDataCommitmentExported = frc42_dispatch::method_hash!("GetDealDataCommitment"),
81+
GetDealClientExported = frc42_dispatch::method_hash!("GetDealClient"),
82+
GetDealProviderExported = frc42_dispatch::method_hash!("GetDealProvider"),
83+
GetDealLabelExported = frc42_dispatch::method_hash!("GetDealLabel"),
84+
GetDealTermExported = frc42_dispatch::method_hash!("GetDealTerm"),
85+
GetDealEpochPriceExported = frc42_dispatch::method_hash!("GetDealEpochPrice"),
86+
GetDealClientCollateralExported = frc42_dispatch::method_hash!("GetDealClientCollateral"),
87+
GetDealProviderCollateralExported = frc42_dispatch::method_hash!("GetDealProviderCollateral"),
88+
GetDealVerifiedExported = frc42_dispatch::method_hash!("GetDealVerified"),
8089
}
8190

8291
/// Market Actor
@@ -1049,6 +1058,101 @@ impl Actor {
10491058
}
10501059
Ok(())
10511060
}
1061+
1062+
/// Returns the data commitment and size of a deal proposal.
1063+
/// This will be available after the deal is published (whether or not is is activated)
1064+
/// and up until some undefined period after it is terminated.
1065+
fn get_deal_data_commitment(
1066+
rt: &mut impl Runtime,
1067+
params: GetDealDataCommitmentParams,
1068+
) -> Result<GetDealDataCommitmentReturn, ActorError> {
1069+
rt.validate_immediate_caller_accept_any()?;
1070+
let found = rt.state::<State>()?.get_proposal(rt.store(), params.id)?;
1071+
Ok(GetDealDataCommitmentReturn { data: found.piece_cid, size: found.piece_size })
1072+
}
1073+
1074+
/// Returns the client of a deal proposal.
1075+
fn get_deal_client(
1076+
rt: &mut impl Runtime,
1077+
params: GetDealClientParams,
1078+
) -> Result<GetDealClientReturn, ActorError> {
1079+
rt.validate_immediate_caller_accept_any()?;
1080+
let found = rt.state::<State>()?.get_proposal(rt.store(), params.id)?;
1081+
Ok(GetDealClientReturn { client: found.client.id().unwrap() })
1082+
}
1083+
1084+
/// Returns the provider of a deal proposal.
1085+
fn get_deal_provider(
1086+
rt: &mut impl Runtime,
1087+
params: GetDealProviderParams,
1088+
) -> Result<GetDealProviderReturn, ActorError> {
1089+
rt.validate_immediate_caller_accept_any()?;
1090+
let found = rt.state::<State>()?.get_proposal(rt.store(), params.id)?;
1091+
Ok(GetDealProviderReturn { provider: found.provider.id().unwrap() })
1092+
}
1093+
1094+
/// Returns the label of a deal proposal.
1095+
fn get_deal_label(
1096+
rt: &mut impl Runtime,
1097+
params: GetDealLabelParams,
1098+
) -> Result<GetDealLabelReturn, ActorError> {
1099+
rt.validate_immediate_caller_accept_any()?;
1100+
let found = rt.state::<State>()?.get_proposal(rt.store(), params.id)?;
1101+
Ok(GetDealLabelReturn { label: found.label })
1102+
}
1103+
1104+
/// Returns the start and end epochs of a deal proposal.
1105+
/// The deal term is a half-open range, exclusive of the end epoch.
1106+
fn get_deal_term(
1107+
rt: &mut impl Runtime,
1108+
params: GetDealTermParams,
1109+
) -> Result<GetDealTermReturn, ActorError> {
1110+
rt.validate_immediate_caller_accept_any()?;
1111+
let found = rt.state::<State>()?.get_proposal(rt.store(), params.id)?;
1112+
Ok(GetDealTermReturn { start: found.start_epoch, end: found.end_epoch })
1113+
}
1114+
1115+
/// Returns the per-epoch price of a deal proposal.
1116+
fn get_deal_epoch_price(
1117+
rt: &mut impl Runtime,
1118+
params: GetDealEpochPriceParams,
1119+
) -> Result<GetDealEpochPriceReturn, ActorError> {
1120+
rt.validate_immediate_caller_accept_any()?;
1121+
let found = rt.state::<State>()?.get_proposal(rt.store(), params.id)?;
1122+
Ok(GetDealEpochPriceReturn { price_per_epoch: found.storage_price_per_epoch })
1123+
}
1124+
1125+
/// Returns the client collateral requirement for a deal proposal.
1126+
fn get_deal_client_collateral(
1127+
rt: &mut impl Runtime,
1128+
params: GetDealClientCollateralParams,
1129+
) -> Result<GetDealClientCollateralReturn, ActorError> {
1130+
rt.validate_immediate_caller_accept_any()?;
1131+
let found = rt.state::<State>()?.get_proposal(rt.store(), params.id)?;
1132+
Ok(GetDealClientCollateralReturn { collateral: found.client_collateral })
1133+
}
1134+
1135+
/// Returns the provider collateral requirement for a deal proposal.
1136+
fn get_deal_provider_collateral(
1137+
rt: &mut impl Runtime,
1138+
params: GetDealProviderCollateralParams,
1139+
) -> Result<GetDealProviderCollateralReturn, ActorError> {
1140+
rt.validate_immediate_caller_accept_any()?;
1141+
let found = rt.state::<State>()?.get_proposal(rt.store(), params.id)?;
1142+
Ok(GetDealProviderCollateralReturn { collateral: found.provider_collateral })
1143+
}
1144+
1145+
/// Returns the verified flag for a deal proposal.
1146+
/// Note that the source of truth for verified allocations and claims is
1147+
/// the verified registry actor.
1148+
fn get_deal_verified(
1149+
rt: &mut impl Runtime,
1150+
params: GetDealVerifiedParams,
1151+
) -> Result<GetDealVerifiedReturn, ActorError> {
1152+
rt.validate_immediate_caller_accept_any()?;
1153+
let found = rt.state::<State>()?.get_proposal(rt.store(), params.id)?;
1154+
Ok(GetDealVerifiedReturn { verified: found.verified_deal })
1155+
}
10521156
}
10531157

10541158
fn compute_data_commitment<BS: Blockstore>(
@@ -1464,6 +1568,43 @@ impl ActorCode for Actor {
14641568
let res = Self::get_balance(rt, cbor::deserialize_params(params)?)?;
14651569
Ok(RawBytes::serialize(res)?)
14661570
}
1571+
Some(Method::GetDealDataCommitmentExported) => {
1572+
let res = Self::get_deal_data_commitment(rt, cbor::deserialize_params(params)?)?;
1573+
Ok(RawBytes::serialize(res)?)
1574+
}
1575+
Some(Method::GetDealClientExported) => {
1576+
let res = Self::get_deal_client(rt, cbor::deserialize_params(params)?)?;
1577+
Ok(RawBytes::serialize(res)?)
1578+
}
1579+
Some(Method::GetDealProviderExported) => {
1580+
let res = Self::get_deal_provider(rt, cbor::deserialize_params(params)?)?;
1581+
Ok(RawBytes::serialize(res)?)
1582+
}
1583+
Some(Method::GetDealLabelExported) => {
1584+
let res = Self::get_deal_label(rt, cbor::deserialize_params(params)?)?;
1585+
Ok(RawBytes::serialize(res)?)
1586+
}
1587+
Some(Method::GetDealTermExported) => {
1588+
let res = Self::get_deal_term(rt, cbor::deserialize_params(params)?)?;
1589+
Ok(RawBytes::serialize(res)?)
1590+
}
1591+
Some(Method::GetDealEpochPriceExported) => {
1592+
let res = Self::get_deal_epoch_price(rt, cbor::deserialize_params(params)?)?;
1593+
Ok(RawBytes::serialize(res)?)
1594+
}
1595+
Some(Method::GetDealClientCollateralExported) => {
1596+
let res = Self::get_deal_client_collateral(rt, cbor::deserialize_params(params)?)?;
1597+
Ok(RawBytes::serialize(res)?)
1598+
}
1599+
Some(Method::GetDealProviderCollateralExported) => {
1600+
let res =
1601+
Self::get_deal_provider_collateral(rt, cbor::deserialize_params(params)?)?;
1602+
Ok(RawBytes::serialize(res)?)
1603+
}
1604+
Some(Method::GetDealVerifiedExported) => {
1605+
let res = Self::get_deal_verified(rt, cbor::deserialize_params(params)?)?;
1606+
Ok(RawBytes::serialize(res)?)
1607+
}
14671608
None => Err(actor_error!(unhandled_message, "Invalid method")),
14681609
}
14691610
}

actors/market/src/state.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,22 @@ impl State {
115115
+ &self.total_client_storage_fee
116116
}
117117

118+
pub fn get_proposal<BS: Blockstore>(
119+
&self,
120+
store: &BS,
121+
id: DealID,
122+
) -> Result<DealProposal, ActorError> {
123+
let proposals = DealArray::load(&self.proposals, store)
124+
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load deal proposals")?;
125+
let found = proposals
126+
.get(id)
127+
.with_context_code(ExitCode::USR_ILLEGAL_STATE, || {
128+
format!("failed to load deal proposal {}", id)
129+
})?
130+
.with_context_code(ExitCode::USR_NOT_FOUND, || format!("no such deal {}", id))?;
131+
Ok(found.clone())
132+
}
133+
118134
pub(super) fn mutator<'bs, BS: Blockstore>(
119135
&mut self,
120136
store: &'bs BS,

actors/market/src/types.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use fvm_shared::econ::TokenAmount;
1515
use fvm_shared::piece::PaddedPieceSize;
1616
use fvm_shared::ActorID;
1717

18+
use crate::Label;
1819
use fvm_shared::sector::RegisteredSealProof;
1920

2021
use super::deal::{ClientDealProposal, DealProposal, DealState};
@@ -136,3 +137,71 @@ pub struct SectorDataSpec {
136137
pub deal_ids: Vec<DealID>,
137138
pub sector_type: RegisteredSealProof,
138139
}
140+
141+
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
142+
#[serde(transparent)]
143+
pub struct DealQueryParams {
144+
pub id: DealID,
145+
}
146+
147+
pub type GetDealDataCommitmentParams = DealQueryParams;
148+
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
149+
pub struct GetDealDataCommitmentReturn {
150+
pub data: Cid,
151+
pub size: PaddedPieceSize,
152+
}
153+
154+
pub type GetDealClientParams = DealQueryParams;
155+
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
156+
#[serde(transparent)]
157+
pub struct GetDealClientReturn {
158+
pub client: ActorID,
159+
}
160+
161+
pub type GetDealProviderParams = DealQueryParams;
162+
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
163+
#[serde(transparent)]
164+
pub struct GetDealProviderReturn {
165+
pub provider: ActorID,
166+
}
167+
168+
pub type GetDealLabelParams = DealQueryParams;
169+
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
170+
#[serde(transparent)]
171+
pub struct GetDealLabelReturn {
172+
pub label: Label,
173+
}
174+
175+
pub type GetDealTermParams = DealQueryParams;
176+
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
177+
pub struct GetDealTermReturn {
178+
pub start: ChainEpoch, // First epoch for the deal (inclusive)
179+
pub end: ChainEpoch, // Epoch at which the deal expires (i.e. exclusive).
180+
}
181+
182+
pub type GetDealEpochPriceParams = DealQueryParams;
183+
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
184+
pub struct GetDealEpochPriceReturn {
185+
pub price_per_epoch: TokenAmount,
186+
}
187+
188+
pub type GetDealClientCollateralParams = DealQueryParams;
189+
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
190+
#[serde(transparent)]
191+
pub struct GetDealClientCollateralReturn {
192+
pub collateral: TokenAmount,
193+
}
194+
195+
pub type GetDealProviderCollateralParams = DealQueryParams;
196+
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
197+
#[serde(transparent)]
198+
pub struct GetDealProviderCollateralReturn {
199+
pub collateral: TokenAmount,
200+
}
201+
202+
pub type GetDealVerifiedParams = DealQueryParams;
203+
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
204+
#[serde(transparent)]
205+
pub struct GetDealVerifiedReturn {
206+
pub verified: bool,
207+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use fvm_ipld_encoding::RawBytes;
2+
use fvm_shared::clock::ChainEpoch;
3+
use serde::de::DeserializeOwned;
4+
5+
use fil_actor_market::{
6+
Actor as MarketActor, DealQueryParams, GetDealClientCollateralReturn, GetDealClientReturn,
7+
GetDealDataCommitmentReturn, GetDealEpochPriceReturn, GetDealLabelReturn,
8+
GetDealProviderCollateralReturn, GetDealProviderReturn, GetDealTermReturn,
9+
GetDealVerifiedReturn, Method,
10+
};
11+
use fil_actors_runtime::network::EPOCHS_IN_DAY;
12+
use fil_actors_runtime::test_utils::{MockRuntime, ACCOUNT_ACTOR_CODE_ID};
13+
use harness::*;
14+
15+
mod harness;
16+
17+
#[test]
18+
fn proposal_data() {
19+
let start_epoch = 1000;
20+
let end_epoch = start_epoch + 200 * EPOCHS_IN_DAY;
21+
let publish_epoch = ChainEpoch::from(1);
22+
23+
let mut rt = setup();
24+
rt.set_epoch(publish_epoch);
25+
let next_allocation_id = 1;
26+
27+
let proposal = generate_deal_and_add_funds(
28+
&mut rt,
29+
CLIENT_ADDR,
30+
&MinerAddresses::default(),
31+
start_epoch,
32+
end_epoch,
33+
);
34+
rt.set_caller(*ACCOUNT_ACTOR_CODE_ID, WORKER_ADDR);
35+
let id =
36+
publish_deals(&mut rt, &MinerAddresses::default(), &[proposal.clone()], next_allocation_id)
37+
[0];
38+
39+
let data: GetDealDataCommitmentReturn =
40+
query_deal(&mut rt, Method::GetDealDataCommitmentExported, id);
41+
assert_eq!(proposal.piece_cid, data.data);
42+
assert_eq!(proposal.piece_size, data.size);
43+
44+
let client: GetDealClientReturn = query_deal(&mut rt, Method::GetDealClientExported, id);
45+
assert_eq!(proposal.client.id().unwrap(), client.client);
46+
47+
let provider: GetDealProviderReturn = query_deal(&mut rt, Method::GetDealProviderExported, id);
48+
assert_eq!(proposal.provider.id().unwrap(), provider.provider);
49+
50+
let label: GetDealLabelReturn = query_deal(&mut rt, Method::GetDealLabelExported, id);
51+
assert_eq!(proposal.label, label.label);
52+
53+
let term: GetDealTermReturn = query_deal(&mut rt, Method::GetDealTermExported, id);
54+
assert_eq!(proposal.start_epoch, term.start);
55+
assert_eq!(proposal.end_epoch, term.end);
56+
57+
let price: GetDealEpochPriceReturn = query_deal(&mut rt, Method::GetDealEpochPriceExported, id);
58+
assert_eq!(proposal.storage_price_per_epoch, price.price_per_epoch);
59+
60+
let client_collateral: GetDealClientCollateralReturn =
61+
query_deal(&mut rt, Method::GetDealClientCollateralExported, id);
62+
assert_eq!(proposal.client_collateral, client_collateral.collateral);
63+
64+
let provider_collateral: GetDealProviderCollateralReturn =
65+
query_deal(&mut rt, Method::GetDealProviderCollateralExported, id);
66+
assert_eq!(proposal.provider_collateral, provider_collateral.collateral);
67+
68+
let verified: GetDealVerifiedReturn = query_deal(&mut rt, Method::GetDealVerifiedExported, id);
69+
assert_eq!(proposal.verified_deal, verified.verified);
70+
71+
check_state(&rt);
72+
}
73+
74+
fn query_deal<T: DeserializeOwned>(rt: &mut MockRuntime, method: Method, id: u64) -> T {
75+
let params = DealQueryParams { id };
76+
rt.expect_validate_caller_any();
77+
rt.call::<MarketActor>(method as u64, &RawBytes::serialize(params).unwrap())
78+
.unwrap()
79+
.deserialize()
80+
.unwrap()
81+
}

0 commit comments

Comments
 (0)