Skip to content
Draft
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
26 changes: 13 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src/rpc/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub struct Client {
v0: tokio::sync::OnceCell<UrlClient>,
v1: tokio::sync::OnceCell<UrlClient>,
v2: tokio::sync::OnceCell<UrlClient>,
experimental: tokio::sync::OnceCell<UrlClient>,
}

impl Client {
Expand Down Expand Up @@ -84,6 +85,7 @@ impl Client {
v0: Default::default(),
v1: Default::default(),
v2: Default::default(),
experimental: Default::default(),
}
}
pub fn base_url(&self) -> &Url {
Expand Down Expand Up @@ -162,6 +164,7 @@ impl Client {
ApiPaths::V0 => &self.v0,
ApiPaths::V1 => &self.v1,
ApiPaths::V2 => &self.v2,
ApiPaths::Experimental => &self.experimental,
}
.get_or_try_init(|| async {
let url = self
Expand All @@ -170,6 +173,7 @@ impl Client {
ApiPaths::V0 => "rpc/v0",
ApiPaths::V1 => "rpc/v1",
ApiPaths::V2 => "rpc/v2",
ApiPaths::Experimental => "rpc/experimental",
})
.map_err(|it| {
ClientError::Custom(format!("creating url for endpoint failed: {it}"))
Expand Down
124 changes: 122 additions & 2 deletions src/rpc/methods/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::cid_collections::CidHashSet;
use crate::eth::EthChainId;
use crate::interpreter::{MessageCallbackCtx, VMTrace};
use crate::libp2p::NetworkMessage;
use crate::lotus_json::lotus_json_with_self;
use crate::lotus_json::{LotusJson, lotus_json_with_self};
use crate::networks::ChainConfig;
use crate::rpc::registry::actors_reg::load_and_serialize_actor_state;
use crate::shim::actors::init;
Expand Down Expand Up @@ -68,6 +68,7 @@ use nunny::vec as nonempty;
use parking_lot::Mutex;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::io::Write;
use std::ops::Mul;
use std::path::PathBuf;
use std::{sync::Arc, time::Duration};
Expand Down Expand Up @@ -497,7 +498,7 @@ impl RpcMethod<1> for StateMarketDeals {
let sa = market_state.states(ctx.store())?;

let mut out = HashMap::new();
da.for_each(|deal_id, d| {
da.for_each_cacheless(|deal_id, d| {
let s = sa.get(deal_id)?.unwrap_or(market::DealState {
sector_start_epoch: -1,
last_updated_epoch: -1,
Expand All @@ -519,6 +520,125 @@ impl RpcMethod<1> for StateMarketDeals {
}
}

pub enum StateMarketDealsDump {}

impl RpcMethod<2> for StateMarketDealsDump {
const NAME: &'static str = "Forest.StateMarketDealsDump";
const PARAM_NAMES: [&'static str; 2] = ["tipsetKey", "outputFile"];
const API_PATHS: BitFlags<ApiPaths> = make_bitflags!(ApiPaths::Experimental);
const PERMISSION: Permission = Permission::Read;
const DESCRIPTION: Option<&'static str> =
Some("Dumps information about every deal in the Storage Market to a NDJSON file.");

type Params = (ApiTipsetKey, String);
type Ok = ();

async fn handle(
ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
(ApiTipsetKey(tsk), output_file): Self::Params,
) -> Result<Self::Ok, ServerError> {
let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
let market_state: market::State = ctx.state_manager.get_actor_state(&ts)?;

let da = market_state.proposals(ctx.store())?;
let sa = market_state.states(ctx.store())?;

let output_path = PathBuf::from(&output_file);
if let Some(parent) = output_path.parent() {
std::fs::create_dir_all(parent)
.context("Failed to create output directory for market deals")?;
}
let file = std::fs::File::create(&output_path)
.context("Failed to create market deals output file")?;
let mut writer = std::io::BufWriter::new(file);

da.for_each_cacheless(|deal_id, d| {
let s = sa.get(deal_id)?.unwrap_or_else(DealState::empty);
let market_deal = ApiMarketDeal {
proposal: d?.into(),
state: s.into(),
};
writeln!(
writer,
"{}",
crate::lotus_json::HasLotusJson::into_lotus_json_string(market_deal)?
)?;
Ok(())
})?;
Ok(())
}
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
#[serde(rename_all = "PascalCase")]
pub struct StateMarketDealsFilter {
#[schemars(with = "LotusJson<Option<Address>>")]
#[serde(with = "crate::lotus_json")]
pub allowed_clients: Option<Vec<Address>>,
#[schemars(with = "LotusJson<Option<Address>>")]
#[serde(with = "crate::lotus_json")]
pub allowed_providers: Option<Vec<Address>>,
}

lotus_json_with_self!(StateMarketDealsFilter);

pub enum StateMarketDealsFiltered {}

impl RpcMethod<2> for StateMarketDealsFiltered {
const NAME: &'static str = "Forest.StateMarketDealsFiltered";
const PARAM_NAMES: [&'static str; 2] = ["tipsetKey", "filter"];
const API_PATHS: BitFlags<ApiPaths> = make_bitflags!(ApiPaths::Experimental);
const PERMISSION: Permission = Permission::Read;
const DESCRIPTION: Option<&'static str> = Some(
"Returns information about every deal in the Storage Market, optionally filtered by client and provider addresses.",
);

type Params = (ApiTipsetKey, StateMarketDealsFilter);
type Ok = HashMap<u64, ApiMarketDeal>;

async fn handle(
ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
(
ApiTipsetKey(tsk),
StateMarketDealsFilter {
allowed_clients,
allowed_providers,
},
): Self::Params,
) -> Result<Self::Ok, ServerError> {
let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
let market_state: market::State = ctx.state_manager.get_actor_state(&ts)?;

let da = market_state.proposals(ctx.store())?;
let sa = market_state.states(ctx.store())?;

let mut out = HashMap::default();

let allowed_clients = allowed_clients
.into_iter()
.flatten()
.collect::<HashSet<_>>();
let allowed_providers = allowed_providers
.into_iter()
.flatten()
.collect::<HashSet<_>>();
da.for_each_cacheless(|deal_id, d| {
let state = sa.get(deal_id)?.unwrap_or_else(DealState::empty);

let proposal = d?;
if !allowed_clients.contains(&proposal.client.into())
&& !allowed_providers.contains(&proposal.provider.into())
{
return Ok(());
}

out.insert(deal_id, MarketDeal { proposal, state }.into());
Ok(())
})?;
Ok(out)
}
}

/// looks up the miner info of the given address.
pub enum StateMinerInfo {}

Expand Down
2 changes: 2 additions & 0 deletions src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ macro_rules! for_each_rpc_method {
$callback!($crate::rpc::state::StateLookupRobustAddress);
$callback!($crate::rpc::state::StateMarketBalance);
$callback!($crate::rpc::state::StateMarketDeals);
$callback!($crate::rpc::state::StateMarketDealsFiltered);
$callback!($crate::rpc::state::StateMarketDealsDump);
$callback!($crate::rpc::state::StateMarketParticipants);
$callback!($crate::rpc::state::StateMarketStorageDeal);
$callback!($crate::rpc::state::StateMinerActiveSectors);
Expand Down
6 changes: 6 additions & 0 deletions src/rpc/reflect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ pub enum ApiPaths {
/// Only expose this method on `/rpc/v2`
#[strum(ascii_case_insensitive)]
V2 = 0b00000100,
/// Experimental methods, subject to change
#[strum(ascii_case_insensitive)]
Experimental = 0b10000000,
}

impl ApiPaths {
Expand Down Expand Up @@ -436,6 +439,9 @@ mod tests {
assert_eq!(v1, ApiPaths::V1);
let v2 = ApiPaths::from_uri(&"http://127.0.0.1:2345/rpc/v2".parse().unwrap()).unwrap();
assert_eq!(v2, ApiPaths::V2);
let experimental =
ApiPaths::from_uri(&"http://127.0.0.1:2345/rpc/experimental".parse().unwrap()).unwrap();
assert_eq!(experimental, ApiPaths::Experimental);

ApiPaths::from_uri(&"http://127.0.0.1:2345/rpc/v3".parse().unwrap()).unwrap_err();
}
Expand Down
7 changes: 6 additions & 1 deletion src/rpc/segregation_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ use tower::Layer;
static VERSION_METHODS_MAPPINGS: LazyLock<HashMap<ApiPaths, HashSet<&'static str>>> =
LazyLock::new(|| {
let mut map = HashMap::default();
for version in [ApiPaths::V0, ApiPaths::V1, ApiPaths::V2] {
for version in [
ApiPaths::V0,
ApiPaths::V1,
ApiPaths::V2,
ApiPaths::Experimental,
] {
let mut supported = HashSet::default();

macro_rules! insert {
Expand Down
Loading
Loading