Skip to content

Commit

Permalink
feat(rpc): implement Filecoin.StateMarketStorageDeal
Browse files Browse the repository at this point in the history
  • Loading branch information
hanabi1224 committed Mar 19, 2024
1 parent 95090c0 commit a0b3b33
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 11 deletions.
1 change: 1 addition & 0 deletions src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ where
STATE_VM_CIRCULATING_SUPPLY_INTERNAL,
state_vm_circulating_supply_internal::<DB>,
)?;
module.register_async_method(STATE_MARKET_STORAGE_DEAL, state_market_storage_deal::<DB>)?;
module.register_async_method(MSIG_GET_AVAILABLE_BALANCE, msig_get_available_balance::<DB>)?;
module.register_async_method(MSIG_GET_PENDING, msig_get_pending::<DB>)?;
// Gas API
Expand Down
52 changes: 45 additions & 7 deletions src/rpc/state_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,9 @@ use crate::cid_collections::CidHashSet;
use crate::libp2p::NetworkMessage;
use crate::lotus_json::LotusJson;
use crate::rpc::error::JsonRpcError;
use crate::rpc_api::data_types::{
ApiActorState, ApiDeadline, ApiInvocResult, ApiTipsetKey, CirculatingSupply, Data, MarketDeal,
MessageFilter, MessageLookup, MinerSectors, MiningBaseInfo, RPCState, SectorOnChainInfo,
Transaction,
};
use crate::rpc_api::data_types::*;
use crate::shim::{
address::Address, clock::ChainEpoch, econ::TokenAmount, executor::Receipt,
address::Address, clock::ChainEpoch, deal::DealID, econ::TokenAmount, executor::Receipt,
state_tree::ActorState, version::NetworkVersion,
};
use crate::state_manager::chain_rand::ChainRand;
Expand All @@ -24,6 +20,7 @@ use ahash::{HashMap, HashMapExt};
use anyhow::Context as _;
use anyhow::Result;
use cid::Cid;
use fil_actor_interface::market::{DealProposal, DealProposals, DealState};
use fil_actor_interface::miner::DeadlineInfo;
use fil_actor_interface::{
market, miner,
Expand Down Expand Up @@ -1009,7 +1006,7 @@ pub async fn state_list_miners<DB: Blockstore + Send + Sync + 'static>(
let actor = data
.state_manager
.get_actor(&Address::POWER_ACTOR, *ts.parent_state())?
.context("Power actor not found".to_string())?;
.context("Power actor not found")?;

let state = power::State::load(store, actor.code, actor.state)?;
let miners = state
Expand All @@ -1020,3 +1017,44 @@ pub async fn state_list_miners<DB: Blockstore + Send + Sync + 'static>(

Ok(LotusJson(miners))
}

pub async fn state_market_storage_deal<DB: Blockstore + Send + Sync + 'static>(
params: Params<'_>,
data: Data<RPCState<DB>>,
) -> Result<ApiMarketDeal, JsonRpcError> {
let LotusJson((deal_id, ApiTipsetKey(tsk))): LotusJson<(DealID, ApiTipsetKey)> =
params.parse()?;

let ts = data
.state_manager
.chain_store()
.load_required_tipset_or_heaviest(&tsk)?;
let store = data.state_manager.blockstore();
let actor = data
.state_manager
.get_actor(&Address::MARKET_ACTOR, *ts.parent_state())?
.context("Market actor not found")?;
let market_state = market::State::load(store, actor.code, actor.state)?;
let proposals = market_state.proposals(store)?;
let proposal: DealProposal = match proposals {
DealProposals::V9(deal_array) => deal_array.get(deal_id)?.map(TryFrom::try_from),
DealProposals::V10(deal_array) => deal_array.get(deal_id)?.map(TryFrom::try_from),
DealProposals::V11(deal_array) => deal_array.get(deal_id)?.map(TryFrom::try_from),
DealProposals::V12(deal_array) => deal_array.get(deal_id)?.map(TryFrom::try_from),
DealProposals::V13(deal_array) => deal_array.get(deal_id)?.map(TryFrom::try_from),
}
.ok_or_else(|| anyhow::anyhow!("deal {deal_id} not found - deal may not have completed sealing before deal proposal start epoch, or deal may have been slashed"))??;

let states = market_state.states(store)?;

const EMPTY_DEAL_STATE: DealState = DealState {
sector_start_epoch: -1,
last_updated_epoch: -1,
slash_epoch: -1,
verified_claim: 0,
};

let state = states.get(deal_id)?.unwrap_or(EMPTY_DEAL_STATE);

Ok(MarketDeal { proposal, state }.into())
}
105 changes: 105 additions & 0 deletions src/rpc_api/data_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use crate::state_manager::StateManager;
use ahash::HashSet;
use chrono::Utc;
use cid::Cid;
use fil_actor_interface::market::AllocationID;
use fil_actor_interface::miner::MinerInfo;
use fil_actor_interface::{
market::{DealProposal, DealState},
Expand Down Expand Up @@ -103,6 +104,110 @@ pub struct MessageSendSpec {

lotus_json_with_self!(MessageSendSpec);

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "PascalCase")]
pub struct ApiDealState {
pub sector_start_epoch: ChainEpoch,
pub last_updated_epoch: ChainEpoch,
pub slash_epoch: ChainEpoch,
#[serde(skip)]
pub verified_claim: AllocationID,
}

lotus_json_with_self!(ApiDealState);

impl From<DealState> for ApiDealState {
fn from(s: DealState) -> Self {
let DealState {
sector_start_epoch,
last_updated_epoch,
slash_epoch,
verified_claim,
} = s;
Self {
sector_start_epoch,
last_updated_epoch,
slash_epoch,
verified_claim,
}
}
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "PascalCase")]
pub struct ApiDealProposal {
#[serde(rename = "PieceCID", with = "crate::lotus_json")]
pub piece_cid: Cid,
pub piece_size: u64,
pub verified_deal: bool,
#[serde(with = "crate::lotus_json")]
pub client: Address,
#[serde(with = "crate::lotus_json")]
pub provider: Address,
pub label: String,
pub start_epoch: ChainEpoch,
pub end_epoch: ChainEpoch,
#[serde(with = "crate::lotus_json")]
pub storage_price_per_epoch: TokenAmount,
#[serde(with = "crate::lotus_json")]
pub provider_collateral: TokenAmount,
#[serde(with = "crate::lotus_json")]
pub client_collateral: TokenAmount,
}

lotus_json_with_self!(ApiDealProposal);

impl From<DealProposal> for ApiDealProposal {
fn from(p: DealProposal) -> Self {
let DealProposal {
piece_cid,
piece_size,
verified_deal,
client,
provider,
label,
start_epoch,
end_epoch,
storage_price_per_epoch,
provider_collateral,
client_collateral,
} = p;
Self {
piece_cid,
piece_size: piece_size.0,
verified_deal,
client: client.into(),
provider: provider.into(),
label,
start_epoch,
end_epoch,
storage_price_per_epoch: storage_price_per_epoch.into(),
provider_collateral: provider_collateral.into(),
client_collateral: client_collateral.into(),
}
}
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "PascalCase")]
pub struct ApiMarketDeal {
#[serde(with = "crate::lotus_json")]
pub proposal: ApiDealProposal,
#[serde(with = "crate::lotus_json")]
pub state: ApiDealState,
}

lotus_json_with_self!(ApiMarketDeal);

impl From<MarketDeal> for ApiMarketDeal {
fn from(d: MarketDeal) -> Self {
Self {
proposal: d.proposal.into(),
state: d.state.into(),
}
}
}

#[derive(Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct MarketDeal {
Expand Down
2 changes: 2 additions & 0 deletions src/rpc_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ pub static ACCESS_MAP: Lazy<HashMap<&str, Access>> = Lazy::new(|| {
access.insert(state_api::STATE_LIST_MINERS, Access::Read);
access.insert(state_api::STATE_MINER_SECTOR_COUNT, Access::Read);
access.insert(state_api::STATE_VERIFIED_CLIENT_STATUS, Access::Read);
access.insert(state_api::STATE_MARKET_STORAGE_DEAL, Access::Read);
access.insert(
state_api::STATE_VM_CIRCULATING_SUPPLY_INTERNAL,
Access::Read,
Expand Down Expand Up @@ -400,6 +401,7 @@ pub mod state_api {
pub const STATE_VERIFIED_CLIENT_STATUS: &str = "Filecoin.StateVerifiedClientStatus";
pub const STATE_VM_CIRCULATING_SUPPLY_INTERNAL: &str =
"Filecoin.StateVMCirculatingSupplyInternal";
pub const STATE_MARKET_STORAGE_DEAL: &str = "Filecoin.StateMarketStorageDeal";
pub const MSIG_GET_AVAILABLE_BALANCE: &str = "Filecoin.MsigGetAvailableBalance";
pub const MSIG_GET_PENDING: &str = "Filecoin.MsigGetPending";
}
Expand Down
9 changes: 8 additions & 1 deletion src/rpc_client/state_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
blocks::TipsetKey,
rpc_api::{data_types::*, state_api::*},
shim::{
address::Address, clock::ChainEpoch, econ::TokenAmount, message::Message,
address::Address, clock::ChainEpoch, deal::DealID, econ::TokenAmount, message::Message,
message::MethodNum, state_tree::ActorState, version::NetworkVersion,
},
};
Expand Down Expand Up @@ -222,6 +222,13 @@ impl ApiInfo {
RpcRequest::new(STATE_LIST_MESSAGES, (from_to, tsk, max_height))
}

pub fn state_market_storage_deal_req(
deal_id: DealID,
tsk: ApiTipsetKey,
) -> RpcRequest<ApiMarketDeal> {
RpcRequest::new(STATE_MARKET_STORAGE_DEAL, (deal_id, tsk))
}

pub fn msig_get_available_balance_req(
addr: Address,
tsk: ApiTipsetKey,
Expand Down
31 changes: 28 additions & 3 deletions src/tool/subcommands/api_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ use crate::rpc_api::{data_types::RPCState, eth_api::*};
use crate::rpc_client::{ApiInfo, JsonRpcError, RpcRequest, DEFAULT_PORT};
use crate::shim::address::{Address, Protocol};
use crate::shim::crypto::Signature;
use crate::shim::state_tree::StateTree;
use crate::state_manager::StateManager;
use crate::utils::version::FOREST_VERSION_STRING;
use crate::Client;
use ahash::HashMap;
use anyhow::Context as _;
use clap::{Subcommand, ValueEnum};
use fil_actor_interface::market;
use fil_actors_shared::v10::runtime::DomainSeparationTag;
use futures::stream::FuturesUnordered;
use futures::StreamExt;
Expand Down Expand Up @@ -551,7 +553,7 @@ fn eth_tests_with_tipset(shared_tipset: &Tipset) -> Vec<RpcTest> {

// Extract tests that use chain-specific data such as block CIDs or message
// CIDs. Right now, only the last `n_tipsets` tipsets are used.
fn snapshot_tests(store: &ManyCar, n_tipsets: usize) -> anyhow::Result<Vec<RpcTest>> {
fn snapshot_tests(store: Arc<ManyCar>, n_tipsets: usize) -> anyhow::Result<Vec<RpcTest>> {
let mut tests = vec![];
let shared_tipset = store.heaviest_tipset()?;
let root_tsk = shared_tipset.key();
Expand Down Expand Up @@ -764,6 +766,29 @@ fn snapshot_tests(store: &ManyCar, n_tipsets: usize) -> anyhow::Result<Vec<RpcTe
)));
}
}

// Get deals
let deals = {
let state = StateTree::new_from_root(store.clone(), tipset.parent_state())?;
let actor = state
.get_actor(&Address::MARKET_ACTOR)?
.context("Market actor not found")?;
let market_state = market::State::load(&store, actor.code, actor.state)?;
let proposals = market_state.proposals(&store)?;
let mut deals = vec![];
proposals.for_each(|deal_id, _| {
deals.push(deal_id);
Ok(())
})?;
deals
};

for deal in deals {
tests.push(RpcTest::identity(ApiInfo::state_market_storage_deal_req(
deal,
tipset.key().into(),
)));
}
}
Ok(tests)
}
Expand Down Expand Up @@ -810,8 +835,8 @@ async fn compare_apis(
tests.extend(eth_tests());

if !snapshot_files.is_empty() {
let store = ManyCar::try_from(snapshot_files)?;
tests.extend(snapshot_tests(&store, config.n_tipsets)?);
let store = Arc::new(ManyCar::try_from(snapshot_files)?);
tests.extend(snapshot_tests(store, config.n_tipsets)?);
}

if config.use_websocket {
Expand Down

0 comments on commit a0b3b33

Please sign in to comment.