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

Add GetDealSector exported API method to market actor #1443

Merged
merged 1 commit into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
74 changes: 53 additions & 21 deletions actors/market/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ fil_actors_runtime::wasm_trampoline!(Actor);

pub const NO_ALLOCATION_ID: u64 = 0;

// An exit code indicating that information about a past deal is no longer available.
// Indicates that information about a past deal is no longer available.
pub const EX_DEAL_EXPIRED: ExitCode = ExitCode::new(FIRST_ACTOR_SPECIFIC_EXIT_CODE);
// Indicates that information about a deal's activation is not yet available.
pub const EX_DEAL_NOT_ACTIVATED: ExitCode = ExitCode::new(FIRST_ACTOR_SPECIFIC_EXIT_CODE + 1);

/// Market actor methods available
#[derive(FromPrimitive)]
Expand Down Expand Up @@ -93,6 +95,7 @@ pub enum Method {
GetDealProviderCollateralExported = frc42_dispatch::method_hash!("GetDealProviderCollateral"),
GetDealVerifiedExported = frc42_dispatch::method_hash!("GetDealVerified"),
GetDealActivationExported = frc42_dispatch::method_hash!("GetDealActivation"),
GetDealSectorExported = frc42_dispatch::method_hash!("GetDealSector"),
SectorContentChangedExported = ext::miner::SECTOR_CONTENT_CHANGED,
}

Expand Down Expand Up @@ -1116,28 +1119,56 @@ impl Actor {
terminated: state.slash_epoch,
}),
None => {
let maybe_proposal = st.find_proposal(rt.store(), params.id)?;
match maybe_proposal {
Some(_) => Ok(GetDealActivationReturn {
// The proposal has been published, but not activated.
activated: EPOCH_UNDEFINED,
terminated: EPOCH_UNDEFINED,
}),
None => {
if params.id < st.next_id {
// If the deal ID has been used, it must have been cleaned up.
Err(ActorError::unchecked(
EX_DEAL_EXPIRED,
format!("deal {} expired", params.id),
))
} else {
// We can't distinguish between failing to activate, or having been
// cleaned up after completion/termination.
Err(ActorError::not_found(format!("no such deal {}", params.id)))
}
}
// Pass through exit codes if proposal doesn't exist.
let _ = st.get_proposal(rt.store(), params.id)?;
// Proposal was published but never activated.
Ok(GetDealActivationReturn {
activated: EPOCH_UNDEFINED,
terminated: EPOCH_UNDEFINED,
})
}
}
}

/// Fetches the sector in which a deal is stored.
/// This is available from after a deal is activated until it is finally settled
/// (either normally or by termination).
/// Fails with USR_NOT_FOUND if the deal doesn't exist (yet),
/// EX_DEAL_NOT_ACTIVATED if the deal is published but has not been activated,
/// or EX_DEAL_EXPIRED if the deal has been removed from state.
fn get_deal_sector(
rt: &impl Runtime,
params: GetDealSectorParams,
) -> Result<GetDealSectorReturn, ActorError> {
rt.validate_immediate_caller_accept_any()?;
let st = rt.state::<State>()?;
let found = st.find_deal_state(rt.store(), params.id)?;
match found {
Some(state) => {
// The deal has been activated and not yet finally settled.
if state.slash_epoch != EPOCH_UNDEFINED {
// The deal has been terminated but not cleaned up.
// Hide this internal state from caller and fail as if it had been cleaned up.
// This will become an impossible state when deal termination is
// processed immediately.
anorth marked this conversation as resolved.
Show resolved Hide resolved
// Remove with https://github.com/filecoin-project/builtin-actors/issues/1388.
Err(ActorError::unchecked(
EX_DEAL_EXPIRED,
format!("deal {} expired", params.id),
))
} else {
Ok(GetDealSectorReturn { sector: state.sector_number })
}
}
None => {
// Pass through exit codes if proposal doesn't exist.
let _ = st.get_proposal(rt.store(), params.id)?;
// Proposal was published but never activated.
Err(ActorError::unchecked(
EX_DEAL_NOT_ACTIVATED,
format!("deal {} not yet activated", params.id),
))
}
}
}
}
Expand Down Expand Up @@ -1603,6 +1634,7 @@ impl ActorCode for Actor {
GetDealProviderCollateralExported => get_deal_provider_collateral,
GetDealVerifiedExported => get_deal_verified,
GetDealActivationExported => get_deal_activation,
GetDealSectorExported => get_deal_sector,
SectorContentChangedExported => sector_content_changed,
}
}
1 change: 1 addition & 0 deletions actors/market/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,7 @@ pub fn get_proposal<BS: Blockstore>(
// If the deal ID has been used, it must have been cleaned up.
ActorError::unchecked(EX_DEAL_EXPIRED, format!("deal {} expired", id))
} else {
// Never been published.
ActorError::not_found(format!("no such deal {}", id))
}
})?;
Expand Down
9 changes: 9 additions & 0 deletions actors/market/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,15 @@ pub struct GetDealActivationReturn {
pub terminated: ChainEpoch,
}

pub type GetDealSectorParams = DealQueryParams;

#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
#[serde(transparent)]
pub struct GetDealSectorReturn {
anorth marked this conversation as resolved.
Show resolved Hide resolved
/// Sector number with the provider that has committed the deal.
pub sector: SectorNumber,
}

// Interface market clients can implement to receive notifications from builtin market
pub const MARKET_NOTIFY_DEAL_METHOD: u64 = frc42_dispatch::method_hash!("MarketNotifyDeal");

Expand Down
34 changes: 18 additions & 16 deletions actors/market/tests/deal_api_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ use serde::de::DeserializeOwned;
use fil_actor_market::{
Actor as MarketActor, DealQueryParams, GetDealActivationReturn, GetDealClientCollateralReturn,
GetDealClientReturn, GetDealDataCommitmentReturn, GetDealLabelReturn,
GetDealProviderCollateralReturn, GetDealProviderReturn, GetDealTermReturn,
GetDealTotalPriceReturn, GetDealVerifiedReturn, Method, EX_DEAL_EXPIRED,
GetDealProviderCollateralReturn, GetDealProviderReturn, GetDealSectorReturn, GetDealTermReturn,
GetDealTotalPriceReturn, GetDealVerifiedReturn, Method, EX_DEAL_EXPIRED, EX_DEAL_NOT_ACTIVATED,
};
use fil_actors_runtime::network::EPOCHS_IN_DAY;
use fil_actors_runtime::runtime::policy_constants::DEAL_UPDATES_INTERVAL;
use fil_actors_runtime::test_utils::{
expect_abort_contains_message, MockRuntime, ACCOUNT_ACTOR_CODE_ID,
};
use fil_actors_runtime::test_utils::{expect_abort, MockRuntime, ACCOUNT_ACTOR_CODE_ID};
use fil_actors_runtime::ActorError;
use fil_actors_runtime::BURNT_FUNDS_ACTOR_ADDR;
use harness::*;
Expand Down Expand Up @@ -114,6 +112,7 @@ fn activation() {
query_deal(&rt, Method::GetDealActivationExported, id);
assert_eq!(EPOCH_UNDEFINED, activation.activated);
assert_eq!(EPOCH_UNDEFINED, activation.terminated);
query_deal_fails(&rt, Method::GetDealSectorExported, id, EX_DEAL_NOT_ACTIVATED);

// activate the deal
let activate_epoch = start_epoch - 2;
Expand All @@ -124,6 +123,10 @@ fn activation() {
query_deal(&rt, Method::GetDealActivationExported, id);
assert_eq!(activate_epoch, activation.activated);
assert_eq!(EPOCH_UNDEFINED, activation.terminated);
assert_eq!(
GetDealSectorReturn { sector: sector_number },
query_deal(&rt, Method::GetDealSectorExported, id)
);

// terminate early
let terminate_epoch = activate_epoch + 100;
Expand All @@ -133,6 +136,7 @@ fn activation() {
query_deal(&rt, Method::GetDealActivationExported, id);
assert_eq!(activate_epoch, activation.activated);
assert_eq!(terminate_epoch, activation.terminated);
query_deal_fails(&rt, Method::GetDealSectorExported, id, EX_DEAL_EXPIRED);

// Clean up state
let clean_epoch = terminate_epoch + DEAL_UPDATES_INTERVAL;
Expand All @@ -146,24 +150,22 @@ fn activation() {
ExitCode::OK,
);
cron_tick(&rt);
expect_abort_contains_message(
EX_DEAL_EXPIRED,
"expired",
query_deal_raw(&rt, Method::GetDealActivationExported, id),
);
query_deal_fails(&rt, Method::GetDealActivationExported, id, EX_DEAL_EXPIRED);
query_deal_fails(&rt, Method::GetDealSectorExported, id, EX_DEAL_EXPIRED);

// Non-existent deal is NOT FOUND
expect_abort_contains_message(
ExitCode::USR_NOT_FOUND,
"no such deal",
query_deal_raw(&rt, Method::GetDealActivationExported, id + 1),
);
// Non-existent deal is USR_NOT_FOUND
query_deal_fails(&rt, Method::GetDealActivationExported, id + 1, ExitCode::USR_NOT_FOUND);
query_deal_fails(&rt, Method::GetDealSectorExported, id + 1, ExitCode::USR_NOT_FOUND);
}

fn query_deal<T: DeserializeOwned>(rt: &MockRuntime, method: Method, id: u64) -> T {
query_deal_raw(rt, method, id).unwrap().unwrap().deserialize().unwrap()
}

fn query_deal_fails(rt: &MockRuntime, method: Method, id: u64, expected: ExitCode) {
expect_abort(expected, query_deal_raw(rt, method, id));
}

fn query_deal_raw(
rt: &MockRuntime,
method: Method,
Expand Down
Loading