diff --git a/Cargo.lock b/Cargo.lock index 85935370a1ca..0ebfb1f96110 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2727,9 +2727,9 @@ checksum = "1676f435fc1dadde4d03e43f5d62b259e1ce5f40bd4ffb21db2b42ebe59c1382" [[package]] name = "fil_actor_account_state" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c94732b4360fa5796fe0f0524b62d4b7f9081c0001e45e44e1969511ad237a68" +checksum = "67883dea647b9f019d7e2fb026189a4e4b773fdd3532b0e5ceaaca820e2db51b" dependencies = [ "frc42_macros", "fvm_ipld_encoding", @@ -2743,9 +2743,9 @@ dependencies = [ [[package]] name = "fil_actor_cron_state" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29941aeb04a17810b8d2104e0f0e4fa10001393e7a1d3523631196d7922fbc2f" +checksum = "3b780f5e7b95fc7b2db4b0e0206c65c539eb97816d452913126356bf82d0beca" dependencies = [ "fvm_ipld_encoding", "fvm_shared 2.6.0", @@ -2758,9 +2758,9 @@ dependencies = [ [[package]] name = "fil_actor_datacap_state" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091aa98dfbb933274389c5be9348590e168548b15b886bd2eafbff7c13ecef23" +checksum = "3a057ba9ec0a412c6848965971705b88182c9d40395c3c7354ae965e7eac136f" dependencies = [ "fil_actors_shared", "frc42_macros", @@ -2778,9 +2778,9 @@ dependencies = [ [[package]] name = "fil_actor_evm_state" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539689549dd7c11fa9139a8adce2568fcbcab1383edf152e5cba45061df6d3d2" +checksum = "90f4bb3f4eec705d3cf572287ec3dece15f075a5d71547835756a432715fec50" dependencies = [ "cid", "fil_actors_shared", @@ -2798,9 +2798,9 @@ dependencies = [ [[package]] name = "fil_actor_init_state" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed980044e180910897862014dc237448f44c7f7600470a9357458b8c7d1ea0bc" +checksum = "60c2ebcac63b2dc64b5d2712478607e49af1e0d023c3895181d6716770802a72" dependencies = [ "anyhow", "cid", @@ -2819,9 +2819,9 @@ dependencies = [ [[package]] name = "fil_actor_interface" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab089bd0e43f98c8bdccdec814e14c74c631b73ee832f16d313bbb8ba9cecc1e" +checksum = "1d3a84774e9fd1556006fe089830b8567653d9510e1f15c3940390c2bc380d7c" dependencies = [ "anyhow", "cid", @@ -2857,9 +2857,9 @@ dependencies = [ [[package]] name = "fil_actor_market_state" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c76cad842778e6aa42e9defdcdea0553072ff6f0c0aa41242fd00f265b8d9d" +checksum = "b605d354a19ea3fd50fae38978f51ca480249a352ebb437c141f329dace53030" dependencies = [ "anyhow", "cid", @@ -2882,9 +2882,9 @@ dependencies = [ [[package]] name = "fil_actor_miner_state" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7022542811937e9b5d722586f0b17037561ef7cd3f0c35ce4c849a20da7c744d" +checksum = "b122406387087c7b039314e3b9a58b5572e83706d8a30bda34e48bb288bd7584" dependencies = [ "anyhow", "bitflags 2.5.0", @@ -2900,7 +2900,7 @@ dependencies = [ "fvm_shared 2.6.0", "fvm_shared 3.6.0", "fvm_shared 4.1.2", - "itertools 0.11.0", + "itertools 0.12.1", "lazy_static", "multihash 0.18.1", "num-bigint", @@ -2912,9 +2912,9 @@ dependencies = [ [[package]] name = "fil_actor_multisig_state" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8738df800e7cb4d350717ebc20d74fffaf26c9298108e03e5458a4690760797" +checksum = "a89c9fb31047555d59a14afa50afab4e51d20cd8563215edd9f1a7af3df7e742" dependencies = [ "anyhow", "cid", @@ -2935,9 +2935,9 @@ dependencies = [ [[package]] name = "fil_actor_power_state" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a1996681dae26388ae9a30fb9fcefebda66e56b470b78a887b9b995cbb9a8f7" +checksum = "13fbfa3d2d269e86ae0f6b60f49595e4d6e0a5636ed35b72858ebbb9c7111598" dependencies = [ "anyhow", "cid", @@ -2958,9 +2958,9 @@ dependencies = [ [[package]] name = "fil_actor_reward_state" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dc9c0958524a3413cf72974b715fbae5bf57407f914ef1ca129624b4fcd7a58" +checksum = "111335c876bc5a82f92448afa182d37abd2a250bc64743a97f04bb3019b7de8a" dependencies = [ "fvm_ipld_encoding", "fvm_shared 2.6.0", @@ -2974,9 +2974,9 @@ dependencies = [ [[package]] name = "fil_actor_system_state" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6cdcc5a6a21fb639853cb828fe2625aa1e792439db1161681f866ecbbc594e" +checksum = "b0e71183137503e5167e7492c668860f7df040211f3aef60ab3a2ea2fccad1cf" dependencies = [ "cid", "fil_actors_shared", @@ -2991,9 +2991,9 @@ dependencies = [ [[package]] name = "fil_actor_verifreg_state" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e9394839dd721f7cdbbafd82747ec9daa4b6229e1bc1c7f014366216fc3a60" +checksum = "28cc536630e4f981dc291fd4fc455abb2475c54d2b018019db3385e7d1a38cfb" dependencies = [ "anyhow", "cid", @@ -3011,9 +3011,9 @@ dependencies = [ [[package]] name = "fil_actors_shared" -version = "10.0.0-dev.4" +version = "10.0.0-dev.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa8b5e64f9b025625f7f667dc90e729d350fddae0f464c119b2d7436a79800f2" +checksum = "78c2d2bf3e828be88945b795dcbd0fbefd3ad77b1c0f30ab8e4faf00e6aa6c7f" dependencies = [ "anyhow", "cid", @@ -3028,7 +3028,7 @@ dependencies = [ "fvm_shared 3.6.0", "fvm_shared 4.1.2", "integer-encoding", - "itertools 0.11.0", + "itertools 0.12.1", "multihash 0.18.1", "num", "num-bigint", diff --git a/Cargo.toml b/Cargo.toml index 082e9ccc8fd3..3df6579bd00e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,18 +52,18 @@ dialoguer = "0.11" digest = "0.10.5" directories = "5" ethereum-types = "0.14.1" -fil_actor_account_state = { version = "10.0.0-dev.4" } -fil_actor_cron_state = { version = "10.0.0-dev.4" } -fil_actor_datacap_state = { version = "10.0.0-dev.4" } -fil_actor_init_state = { version = "10.0.0-dev.4" } -fil_actor_interface = { version = "10.0.0-dev.4" } -fil_actor_market_state = { version = "10.0.0-dev.4" } -fil_actor_miner_state = { version = "10.0.0-dev.4" } -fil_actor_power_state = { version = "10.0.0-dev.4" } -fil_actor_reward_state = { version = "10.0.0-dev.4" } -fil_actor_system_state = { version = "10.0.0-dev.4" } -fil_actor_verifreg_state = { version = "10.0.0-dev.4" } -fil_actors_shared = { version = "10.0.0-dev.4", features = ["json"] } +fil_actor_account_state = { version = "10.0.0-dev.5" } +fil_actor_cron_state = { version = "10.0.0-dev.5" } +fil_actor_datacap_state = { version = "10.0.0-dev.5" } +fil_actor_init_state = { version = "10.0.0-dev.5" } +fil_actor_interface = { version = "10.0.0-dev.5" } +fil_actor_market_state = { version = "10.0.0-dev.5" } +fil_actor_miner_state = { version = "10.0.0-dev.5" } +fil_actor_power_state = { version = "10.0.0-dev.5" } +fil_actor_reward_state = { version = "10.0.0-dev.5" } +fil_actor_system_state = { version = "10.0.0-dev.5" } +fil_actor_verifreg_state = { version = "10.0.0-dev.5" } +fil_actors_shared = { version = "10.0.0-dev.5", features = ["json"] } filecoin-proofs-api = { version = "16.0", default-features = false } flume = "0.11" frc46_token = "10.0.0" diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index f17eb10230dd..bd6faa809fa8 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -289,6 +289,7 @@ where STATE_VM_CIRCULATING_SUPPLY_INTERNAL, state_vm_circulating_supply_internal::, )?; + module.register_async_method(STATE_MARKET_STORAGE_DEAL, state_market_storage_deal::)?; module.register_async_method(MSIG_GET_AVAILABLE_BALANCE, msig_get_available_balance::)?; module.register_async_method(MSIG_GET_PENDING, msig_get_pending::)?; // Gas API diff --git a/src/rpc/state_api.rs b/src/rpc/state_api.rs index 9fc4f049aaec..7d89589616e3 100644 --- a/src/rpc/state_api.rs +++ b/src/rpc/state_api.rs @@ -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; @@ -24,6 +20,7 @@ use ahash::{HashMap, HashMapExt}; use anyhow::Context as _; use anyhow::Result; use cid::Cid; +use fil_actor_interface::market::DealState; use fil_actor_interface::miner::DeadlineInfo; use fil_actor_interface::{ market, miner, @@ -1009,7 +1006,7 @@ pub async fn state_list_miners( 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 @@ -1020,3 +1017,29 @@ pub async fn state_list_miners( Ok(LotusJson(miners)) } + +pub async fn state_market_storage_deal( + params: Params<'_>, + data: Data>, +) -> Result { + 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 = proposals.get(deal_id)?.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)?; + let state = states.get(deal_id)?.unwrap_or_else(DealState::empty); + + Ok(MarketDeal { proposal, state }.into()) +} diff --git a/src/rpc_api/data_types.rs b/src/rpc_api/data_types.rs index 9b6d9d03f995..4075bdc0a701 100644 --- a/src/rpc_api/data_types.rs +++ b/src/rpc_api/data_types.rs @@ -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}, @@ -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 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 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 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 { diff --git a/src/rpc_api/mod.rs b/src/rpc_api/mod.rs index b8111843646d..ba7de7a8f7c9 100644 --- a/src/rpc_api/mod.rs +++ b/src/rpc_api/mod.rs @@ -115,6 +115,7 @@ pub static ACCESS_MAP: Lazy> = 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, @@ -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"; } diff --git a/src/rpc_client/state_ops.rs b/src/rpc_client/state_ops.rs index 663c670ab8dd..2d304afca6e7 100644 --- a/src/rpc_client/state_ops.rs +++ b/src/rpc_client/state_ops.rs @@ -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, }, }; @@ -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 { + RpcRequest::new(STATE_MARKET_STORAGE_DEAL, (deal_id, tsk)) + } + pub fn msig_get_available_balance_req( addr: Address, tsk: ApiTipsetKey, diff --git a/src/tool/subcommands/api_cmd.rs b/src/tool/subcommands/api_cmd.rs index 4574f9f9fbb6..25cc97fd90e7 100644 --- a/src/tool/subcommands/api_cmd.rs +++ b/src/tool/subcommands/api_cmd.rs @@ -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; @@ -551,7 +553,7 @@ fn eth_tests_with_tipset(shared_tipset: &Tipset) -> Vec { // 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> { +fn snapshot_tests(store: Arc, n_tipsets: usize) -> anyhow::Result> { let mut tests = vec![]; let shared_tipset = store.heaviest_tipset()?; let root_tsk = shared_tipset.key(); @@ -764,6 +766,30 @@ fn snapshot_tests(store: &ManyCar, n_tipsets: usize) -> anyhow::Result