1mod types;
5use futures::stream::FuturesOrdered;
6pub use types::*;
7
8use super::chain::ChainGetTipSetV2;
9use crate::blocks::{Tipset, TipsetKey};
10use crate::chain::index::ResolveNullTipset;
11use crate::cid_collections::CidHashSet;
12use crate::eth::EthChainId;
13use crate::interpreter::{MessageCallbackCtx, VMTrace};
14use crate::libp2p::NetworkMessage;
15use crate::lotus_json::{LotusJson, lotus_json_with_self};
16use crate::networks::ChainConfig;
17use crate::rpc::registry::actors_reg::load_and_serialize_actor_state;
18use crate::shim::actors::market::DealState;
19use crate::shim::actors::market::ext::MarketStateExt as _;
20use crate::shim::actors::miner::ext::DeadlineExt;
21use crate::shim::actors::state_load::*;
22use crate::shim::actors::verifreg::ext::VerifiedRegistryStateExt as _;
23use crate::shim::actors::verifreg::{Allocation, AllocationID, Claim};
24use crate::shim::actors::{init, system};
25use crate::shim::actors::{
26 market, miner,
27 miner::{MinerInfo, MinerPower},
28 power, reward, verifreg,
29};
30use crate::shim::actors::{
31 market::ext::BalanceTableExt as _, miner::ext::MinerStateExt as _,
32 power::ext::PowerStateExt as _,
33};
34use crate::shim::address::Payload;
35use crate::shim::machine::BuiltinActorManifest;
36use crate::shim::message::{Message, MethodNum};
37use crate::shim::sector::{SectorNumber, SectorSize};
38use crate::shim::state_tree::{ActorID, StateTree};
39use crate::shim::{
40 address::Address, clock::ChainEpoch, deal::DealID, econ::TokenAmount, executor::Receipt,
41 state_tree::ActorState, version::NetworkVersion,
42};
43use crate::state_manager::{
44 MarketBalance, StateManager, StateOutput, circulating_supply::GenesisInfo, utils::structured,
45};
46use crate::utils::db::car_stream::{CarBlock, CarWriter};
47use crate::{
48 beacon::BeaconEntry,
49 rpc::{ApiPaths, Ctx, Permission, RpcMethod, ServerError, types::*},
50};
51use ahash::{HashMap, HashMapExt, HashSet};
52use anyhow::Context;
53use anyhow::Result;
54use cid::Cid;
55use enumflags2::{BitFlags, make_bitflags};
56use fil_actor_miner_state::v10::{qa_power_for_weight, qa_power_max};
57use fil_actor_verifreg_state::v13::ClaimID;
58use fil_actors_shared::fvm_ipld_amt::Amt;
59use fil_actors_shared::fvm_ipld_bitfield::BitField;
60use futures::{StreamExt as _, TryStreamExt as _};
61use fvm_ipld_blockstore::Blockstore;
62use fvm_ipld_encoding::{CborStore, DAG_CBOR};
63pub use fvm_shared3::sector::StoragePower;
64use ipld_core::ipld::Ipld;
65use jsonrpsee::types::error::ErrorObject;
66use num_bigint::BigInt;
67use num_traits::Euclid;
68use nunny::vec as nonempty;
69use parking_lot::Mutex;
70use schemars::JsonSchema;
71use serde::{Deserialize, Serialize};
72use std::num::NonZeroUsize;
73use std::ops::Mul;
74use std::path::PathBuf;
75use std::{sync::Arc, time::Duration};
76use tokio::task::JoinSet;
77
78const INITIAL_PLEDGE_NUM: u64 = 110;
79const INITIAL_PLEDGE_DEN: u64 = 100;
80
81pub enum StateCall {}
82
83impl StateCall {
84 pub fn run<DB: Blockstore + Send + Sync + 'static>(
85 state_manager: &StateManager<DB>,
86 message: &Message,
87 tsk: Option<TipsetKey>,
88 ) -> anyhow::Result<ApiInvocResult> {
89 let tipset = state_manager
90 .chain_store()
91 .load_required_tipset_or_heaviest(&tsk)?;
92 Ok(state_manager.call(message, Some(tipset))?)
93 }
94}
95
96impl RpcMethod<2> for StateCall {
97 const NAME: &'static str = "Filecoin.StateCall";
98 const PARAM_NAMES: [&'static str; 2] = ["message", "tipsetKey"];
99 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
100 const PERMISSION: Permission = Permission::Read;
101 const DESCRIPTION: Option<&'static str> = Some(
102 "Runs the given message and returns its result without persisting changes. The message is applied to the tipset's parent state.",
103 );
104
105 type Params = (Message, ApiTipsetKey);
106 type Ok = ApiInvocResult;
107
108 async fn handle(
109 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
110 (message, ApiTipsetKey(tsk)): Self::Params,
111 ) -> Result<Self::Ok, ServerError> {
112 Ok(Self::run(&ctx.state_manager, &message, tsk)?)
113 }
114}
115
116pub enum StateReplay {}
117impl RpcMethod<2> for StateReplay {
118 const NAME: &'static str = "Filecoin.StateReplay";
119 const PARAM_NAMES: [&'static str; 2] = ["tipsetKey", "messageCid"];
120 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
121 const PERMISSION: Permission = Permission::Read;
122 const DESCRIPTION: Option<&'static str> = Some(
123 "Replays a given message, assuming it was included in a block in the specified tipset.",
124 );
125
126 type Params = (ApiTipsetKey, Cid);
127 type Ok = ApiInvocResult;
128
129 async fn handle(
132 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
133 (ApiTipsetKey(tsk), message_cid): Self::Params,
134 ) -> Result<Self::Ok, ServerError> {
135 let tipset = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
136 Ok(ctx.state_manager.replay(tipset, message_cid).await?)
137 }
138}
139
140pub enum StateNetworkName {}
141impl RpcMethod<0> for StateNetworkName {
142 const NAME: &'static str = "Filecoin.StateNetworkName";
143 const PARAM_NAMES: [&'static str; 0] = [];
144 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
145 const PERMISSION: Permission = Permission::Read;
146
147 type Params = ();
148 type Ok = String;
149
150 async fn handle(ctx: Ctx<impl Blockstore>, (): Self::Params) -> Result<Self::Ok, ServerError> {
151 let heaviest_tipset = ctx.chain_store().heaviest_tipset();
152 Ok(ctx
153 .state_manager
154 .get_network_state_name(*heaviest_tipset.parent_state())?
155 .into())
156 }
157}
158
159pub enum StateNetworkVersion {}
160impl RpcMethod<1> for StateNetworkVersion {
161 const NAME: &'static str = "Filecoin.StateNetworkVersion";
162 const PARAM_NAMES: [&'static str; 1] = ["tipsetKey"];
163 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
164 const PERMISSION: Permission = Permission::Read;
165 const DESCRIPTION: Option<&'static str> =
166 Some("Returns the network version at the given tipset.");
167
168 type Params = (ApiTipsetKey,);
169 type Ok = NetworkVersion;
170
171 async fn handle(
172 ctx: Ctx<impl Blockstore>,
173 (ApiTipsetKey(tsk),): Self::Params,
174 ) -> Result<Self::Ok, ServerError> {
175 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
176 Ok(ctx.state_manager.get_network_version(ts.epoch()))
177 }
178}
179
180pub enum StateAccountKey {}
183
184impl RpcMethod<2> for StateAccountKey {
185 const NAME: &'static str = "Filecoin.StateAccountKey";
186 const PARAM_NAMES: [&'static str; 2] = ["address", "tipsetKey"];
187 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
188 const PERMISSION: Permission = Permission::Read;
189 const DESCRIPTION: Option<&'static str> =
190 Some("Returns the public key address for the given ID address (secp and bls accounts).");
191
192 type Params = (Address, ApiTipsetKey);
193 type Ok = Address;
194
195 async fn handle(
196 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
197 (address, ApiTipsetKey(tsk)): Self::Params,
198 ) -> Result<Self::Ok, ServerError> {
199 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
200 Ok(ctx
201 .state_manager
202 .resolve_to_deterministic_address(address, &ts)
203 .await?)
204 }
205}
206
207pub enum StateLookupID {}
210
211impl RpcMethod<2> for StateLookupID {
212 const NAME: &'static str = "Filecoin.StateLookupID";
213 const PARAM_NAMES: [&'static str; 2] = ["address", "tipsetKey"];
214 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
215 const PERMISSION: Permission = Permission::Read;
216 const DESCRIPTION: Option<&'static str> =
217 Some("Retrieves the ID address of the given address.");
218
219 type Params = (Address, ApiTipsetKey);
220 type Ok = Address;
221
222 async fn handle(
223 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
224 (address, ApiTipsetKey(tsk)): Self::Params,
225 ) -> Result<Self::Ok, ServerError> {
226 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
227 Ok(ctx.state_manager.lookup_required_id(&address, &ts)?)
228 }
229}
230
231pub enum StateVerifiedRegistryRootKey {}
233
234impl RpcMethod<1> for StateVerifiedRegistryRootKey {
235 const NAME: &'static str = "Filecoin.StateVerifiedRegistryRootKey";
236 const PARAM_NAMES: [&'static str; 1] = ["tipsetKey"];
237 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
238 const PERMISSION: Permission = Permission::Read;
239 const DESCRIPTION: Option<&'static str> =
240 Some("Returns the address of the Verified Registry's root key.");
241
242 type Params = (ApiTipsetKey,);
243 type Ok = Address;
244
245 async fn handle(
246 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
247 (ApiTipsetKey(tsk),): Self::Params,
248 ) -> Result<Self::Ok, ServerError> {
249 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
250 let state: verifreg::State = ctx.state_manager.get_actor_state(&ts)?;
251 Ok(state.root_key())
252 }
253}
254
255pub enum StateVerifierStatus {}
258
259impl RpcMethod<2> for StateVerifierStatus {
260 const NAME: &'static str = "Filecoin.StateVerifierStatus";
261 const PARAM_NAMES: [&'static str; 2] = ["address", "tipsetKey"];
262 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
263 const PERMISSION: Permission = Permission::Read;
264 const DESCRIPTION: Option<&'static str> = Some("Returns the data cap for the given address.");
265
266 type Params = (Address, ApiTipsetKey);
267 type Ok = Option<StoragePower>;
268
269 async fn handle(
270 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
271 (address, ApiTipsetKey(tsk)): Self::Params,
272 ) -> Result<Self::Ok, ServerError> {
273 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
274 let aid = ctx.state_manager.lookup_required_id(&address, &ts)?;
275 let verifreg_state: verifreg::State = ctx.state_manager.get_actor_state(&ts)?;
276 Ok(verifreg_state.verifier_data_cap(ctx.store(), aid)?)
277 }
278}
279
280pub enum StateGetActor {}
281
282impl RpcMethod<2> for StateGetActor {
283 const NAME: &'static str = "Filecoin.StateGetActor";
284 const PARAM_NAMES: [&'static str; 2] = ["address", "tipsetKey"];
285 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
286 const PERMISSION: Permission = Permission::Read;
287 const DESCRIPTION: Option<&'static str> =
288 Some("Returns the nonce and balance for the specified actor.");
289
290 type Params = (Address, ApiTipsetKey);
291 type Ok = Option<ActorState>;
292
293 async fn handle(
294 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
295 (address, ApiTipsetKey(tsk)): Self::Params,
296 ) -> Result<Self::Ok, ServerError> {
297 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
298 let state = ctx.state_manager.get_actor(&address, *ts.parent_state())?;
299 Ok(state)
300 }
301}
302
303pub enum StateGetActorV2 {}
304
305impl RpcMethod<2> for StateGetActorV2 {
306 const NAME: &'static str = "Filecoin.StateGetActor";
307 const PARAM_NAMES: [&'static str; 2] = ["address", "tipsetSelector"];
308 const API_PATHS: BitFlags<ApiPaths> = make_bitflags!(ApiPaths::{ V2 });
309 const PERMISSION: Permission = Permission::Read;
310 const DESCRIPTION: Option<&'static str> =
311 Some("Returns the nonce and balance for the specified actor.");
312
313 type Params = (Address, TipsetSelector);
314 type Ok = Option<ActorState>;
315
316 async fn handle(
317 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
318 (address, selector): Self::Params,
319 ) -> Result<Self::Ok, ServerError> {
320 let ts = ChainGetTipSetV2::get_required_tipset(&ctx, &selector).await?;
321 Ok(ctx.state_manager.get_actor(&address, *ts.parent_state())?)
322 }
323}
324
325pub enum StateGetID {}
326
327impl RpcMethod<2> for StateGetID {
328 const NAME: &'static str = "Filecoin.StateGetID";
329 const PARAM_NAMES: [&'static str; 2] = ["address", "tipsetSelector"];
330 const API_PATHS: BitFlags<ApiPaths> = make_bitflags!(ApiPaths::{ V2 });
331 const PERMISSION: Permission = Permission::Read;
332 const DESCRIPTION: Option<&'static str> =
333 Some("Retrieves the ID address for the specified address at the selected tipset.");
334
335 type Params = (Address, TipsetSelector);
336 type Ok = Address;
337
338 async fn handle(
339 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
340 (address, selector): Self::Params,
341 ) -> Result<Self::Ok, ServerError> {
342 let ts = ChainGetTipSetV2::get_required_tipset(&ctx, &selector).await?;
343 Ok(ctx.state_manager.lookup_required_id(&address, &ts)?)
344 }
345}
346
347pub enum StateLookupRobustAddress {}
348
349macro_rules! get_robust_address {
350 ($store:expr, $id_addr_decoded:expr, $state:expr, $make_map_with_root:path, $robust_addr:expr) => {{
351 let map = $make_map_with_root(&$state.address_map, &$store)?;
352 map.for_each(|addr, v| {
353 if *v == $id_addr_decoded {
354 $robust_addr = Address::from_bytes(addr)?;
355 return Ok(());
356 }
357 Ok(())
358 })?;
359 Ok($robust_addr)
360 }};
361}
362
363impl RpcMethod<2> for StateLookupRobustAddress {
364 const NAME: &'static str = "Filecoin.StateLookupRobustAddress";
365 const PARAM_NAMES: [&'static str; 2] = ["address", "tipsetKey"];
366 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
367 const PERMISSION: Permission = Permission::Read;
368 const DESCRIPTION: Option<&'static str> =
369 Some("Returns the public key address for non-account addresses (e.g., multisig, miners).");
370
371 type Params = (Address, ApiTipsetKey);
372 type Ok = Address;
373
374 async fn handle(
375 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
376 (addr, ApiTipsetKey(tsk)): Self::Params,
377 ) -> Result<Self::Ok, ServerError> {
378 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
379 let store = ctx.store();
380 let state_tree = StateTree::new_from_root(ctx.store_owned(), ts.parent_state())?;
381 if let &Payload::ID(id_addr_decoded) = addr.payload() {
382 let init_state: init::State = state_tree.get_actor_state()?;
383 let mut robust_addr = Address::default();
384 match init_state {
385 init::State::V0(_) => Err(ServerError::internal_error(
386 "StateLookupRobustAddress is not implemented for init state v0",
387 None,
388 )),
389 init::State::V8(state) => get_robust_address!(
390 store,
391 id_addr_decoded,
392 state,
393 fil_actors_shared::v8::make_map_with_root::<_, ActorID>,
394 robust_addr
395 ),
396 init::State::V9(state) => get_robust_address!(
397 store,
398 id_addr_decoded,
399 state,
400 fil_actors_shared::v9::make_map_with_root::<_, ActorID>,
401 robust_addr
402 ),
403 init::State::V10(state) => get_robust_address!(
404 store,
405 id_addr_decoded,
406 state,
407 fil_actors_shared::v10::make_map_with_root::<_, ActorID>,
408 robust_addr
409 ),
410 init::State::V11(state) => get_robust_address!(
411 store,
412 id_addr_decoded,
413 state,
414 fil_actors_shared::v11::make_map_with_root::<_, ActorID>,
415 robust_addr
416 ),
417 init::State::V12(state) => get_robust_address!(
418 store,
419 id_addr_decoded,
420 state,
421 fil_actors_shared::v12::make_map_with_root::<_, ActorID>,
422 robust_addr
423 ),
424 init::State::V13(state) => get_robust_address!(
425 store,
426 id_addr_decoded,
427 state,
428 fil_actors_shared::v13::make_map_with_root::<_, ActorID>,
429 robust_addr
430 ),
431 init::State::V14(state) => {
432 let map = fil_actor_init_state::v14::AddressMap::load(
433 &store,
434 &state.address_map,
435 fil_actors_shared::v14::DEFAULT_HAMT_CONFIG,
436 "address_map",
437 )
438 .context("Failed to load address map")?;
439 map.for_each(|addr, v| {
440 if *v == id_addr_decoded {
441 robust_addr = addr.into();
442 return Ok(());
443 }
444 Ok(())
445 })
446 .context("Robust address not found")?;
447 Ok(robust_addr)
448 }
449 init::State::V15(state) => {
450 let map = fil_actor_init_state::v15::AddressMap::load(
451 &store,
452 &state.address_map,
453 fil_actors_shared::v15::DEFAULT_HAMT_CONFIG,
454 "address_map",
455 )
456 .context("Failed to load address map")?;
457 map.for_each(|addr, v| {
458 if *v == id_addr_decoded {
459 robust_addr = addr.into();
460 return Ok(());
461 }
462 Ok(())
463 })
464 .context("Robust address not found")?;
465 Ok(robust_addr)
466 }
467 init::State::V16(state) => {
468 let map = fil_actor_init_state::v16::AddressMap::load(
469 &store,
470 &state.address_map,
471 fil_actors_shared::v16::DEFAULT_HAMT_CONFIG,
472 "address_map",
473 )
474 .context("Failed to load address map")?;
475 map.for_each(|addr, v| {
476 if *v == id_addr_decoded {
477 robust_addr = addr.into();
478 return Ok(());
479 }
480 Ok(())
481 })
482 .context("Robust address not found")?;
483 Ok(robust_addr)
484 }
485 init::State::V17(state) => {
486 let map = fil_actor_init_state::v17::AddressMap::load(
487 &store,
488 &state.address_map,
489 fil_actors_shared::v17::DEFAULT_HAMT_CONFIG,
490 "address_map",
491 )
492 .context("Failed to load address map")?;
493 map.for_each(|addr, v| {
494 if *v == id_addr_decoded {
495 robust_addr = addr.into();
496 return Ok(());
497 }
498 Ok(())
499 })
500 .context("Robust address not found")?;
501 Ok(robust_addr)
502 }
503 }
504 } else {
505 Ok(Address::default())
506 }
507 }
508}
509
510pub enum StateMarketBalance {}
513
514impl RpcMethod<2> for StateMarketBalance {
515 const NAME: &'static str = "Filecoin.StateMarketBalance";
516 const PARAM_NAMES: [&'static str; 2] = ["address", "tipsetKey"];
517 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
518 const PERMISSION: Permission = Permission::Read;
519 const DESCRIPTION: Option<&'static str> = Some(
520 "Returns the Escrow and Locked balances of the specified address in the Storage Market.",
521 );
522
523 type Params = (Address, ApiTipsetKey);
524 type Ok = MarketBalance;
525
526 async fn handle(
527 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
528 (address, ApiTipsetKey(tsk)): Self::Params,
529 ) -> Result<Self::Ok, ServerError> {
530 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
531 ctx.state_manager
532 .market_balance(&address, &ts)
533 .map_err(From::from)
534 }
535}
536
537pub enum StateMarketDeals {}
538
539impl RpcMethod<1> for StateMarketDeals {
540 const NAME: &'static str = "Filecoin.StateMarketDeals";
541 const PARAM_NAMES: [&'static str; 1] = ["tipsetKey"];
542 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
543 const PERMISSION: Permission = Permission::Read;
544 const DESCRIPTION: Option<&'static str> =
545 Some("Returns information about every deal in the Storage Market.");
546
547 type Params = (ApiTipsetKey,);
548 type Ok = HashMap<String, ApiMarketDeal>;
549
550 async fn handle(
551 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
552 (ApiTipsetKey(tsk),): Self::Params,
553 ) -> Result<Self::Ok, ServerError> {
554 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
555 let market_state: market::State = ctx.state_manager.get_actor_state(&ts)?;
556
557 let da = market_state.proposals(ctx.store())?;
558 let sa = market_state.states(ctx.store())?;
559
560 let mut out = HashMap::new();
561 da.for_each(|deal_id, d| {
562 let s = sa.get(deal_id)?.unwrap_or(market::DealState {
563 sector_start_epoch: -1,
564 last_updated_epoch: -1,
565 slash_epoch: -1,
566 verified_claim: 0,
567 sector_number: 0,
568 });
569 out.insert(
570 deal_id.to_string(),
571 MarketDeal {
572 proposal: d?,
573 state: s,
574 }
575 .into(),
576 );
577 Ok(())
578 })?;
579 Ok(out)
580 }
581}
582
583pub enum StateMinerInfo {}
585
586impl RpcMethod<2> for StateMinerInfo {
587 const NAME: &'static str = "Filecoin.StateMinerInfo";
588 const PARAM_NAMES: [&'static str; 2] = ["minerAddress", "tipsetKey"];
589 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
590 const PERMISSION: Permission = Permission::Read;
591 const DESCRIPTION: Option<&'static str> =
592 Some("Returns information about the specified miner.");
593
594 type Params = (Address, ApiTipsetKey);
595 type Ok = MinerInfo;
596
597 async fn handle(
598 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
599 (address, ApiTipsetKey(tsk)): Self::Params,
600 ) -> Result<Self::Ok, ServerError> {
601 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
602 Ok(ctx.state_manager.miner_info(&address, &ts)?)
603 }
604}
605
606pub enum StateMinerActiveSectors {}
607
608impl RpcMethod<2> for StateMinerActiveSectors {
609 const NAME: &'static str = "Filecoin.StateMinerActiveSectors";
610 const PARAM_NAMES: [&'static str; 2] = ["minerAddress", "tipsetKey"];
611 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
612 const PERMISSION: Permission = Permission::Read;
613 const DESCRIPTION: Option<&'static str> =
614 Some("Returns information about sectors actively proven by a given miner.");
615
616 type Params = (Address, ApiTipsetKey);
617 type Ok = Vec<SectorOnChainInfo>;
618
619 async fn handle(
620 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
621 (address, ApiTipsetKey(tsk)): Self::Params,
622 ) -> Result<Self::Ok, ServerError> {
623 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
624 let policy = &ctx.chain_config().policy;
625 let miner_state: miner::State = ctx
626 .state_manager
627 .get_actor_state_from_address(&ts, &address)?;
628 let mut active_sectors = vec![];
630 miner_state.for_each_deadline(policy, ctx.store(), |_dlidx, deadline| {
631 deadline.for_each(ctx.store(), |_partidx, partition| {
632 active_sectors.push(partition.active_sectors());
633 Ok(())
634 })
635 })?;
636 let sectors =
637 miner_state.load_sectors_ext(ctx.store(), Some(&BitField::union(&active_sectors)))?;
638 Ok(sectors)
639 }
640}
641
642pub enum StateMinerAllocated {}
644
645impl RpcMethod<2> for StateMinerAllocated {
646 const NAME: &'static str = "Filecoin.StateMinerAllocated";
647 const PARAM_NAMES: [&'static str; 2] = ["minerAddress", "tipsetKey"];
648 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
649 const PERMISSION: Permission = Permission::Read;
650 const DESCRIPTION: Option<&'static str> = Some(
651 "Returns a bitfield containing all sector numbers marked as allocated to the provided miner ID.",
652 );
653
654 type Params = (Address, ApiTipsetKey);
655 type Ok = BitField;
656
657 async fn handle(
658 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
659 (address, ApiTipsetKey(tsk)): Self::Params,
660 ) -> Result<Self::Ok, ServerError> {
661 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
662 let miner_state: miner::State = ctx
663 .state_manager
664 .get_actor_state_from_address(&ts, &address)?;
665 Ok(miner_state.load_allocated_sector_numbers(ctx.store())?)
666 }
667}
668
669pub enum StateMinerPartitions {}
671
672impl RpcMethod<3> for StateMinerPartitions {
673 const NAME: &'static str = "Filecoin.StateMinerPartitions";
674 const PARAM_NAMES: [&'static str; 3] = ["minerAddress", "deadlineIndex", "tipsetKey"];
675 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
676 const PERMISSION: Permission = Permission::Read;
677 const DESCRIPTION: Option<&'static str> =
678 Some("Returns all partitions in the specified deadline.");
679
680 type Params = (Address, u64, ApiTipsetKey);
681 type Ok = Vec<MinerPartitions>;
682
683 async fn handle(
684 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
685 (address, dl_idx, ApiTipsetKey(tsk)): Self::Params,
686 ) -> Result<Self::Ok, ServerError> {
687 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
688 let policy = &ctx.chain_config().policy;
689 let miner_state: miner::State = ctx
690 .state_manager
691 .get_actor_state_from_address(&ts, &address)?;
692 let deadline = miner_state.load_deadline(policy, ctx.store(), dl_idx)?;
693 let mut all_partitions = Vec::new();
694 deadline.for_each(ctx.store(), |_partidx, partition| {
695 all_partitions.push(MinerPartitions::new(
696 partition.all_sectors(),
697 partition.faulty_sectors(),
698 partition.recovering_sectors(),
699 partition.live_sectors(),
700 partition.active_sectors(),
701 ));
702 Ok(())
703 })?;
704 Ok(all_partitions)
705 }
706}
707
708pub enum StateMinerSectors {}
709
710impl RpcMethod<3> for StateMinerSectors {
711 const NAME: &'static str = "Filecoin.StateMinerSectors";
712 const PARAM_NAMES: [&'static str; 3] = ["minerAddress", "sectors", "tipsetKey"];
713 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
714 const PERMISSION: Permission = Permission::Read;
715 const DESCRIPTION: Option<&'static str> = Some(
716 "Returns information about the given miner's sectors. If no filter is provided, all sectors are included.",
717 );
718
719 type Params = (Address, Option<BitField>, ApiTipsetKey);
720 type Ok = Vec<SectorOnChainInfo>;
721
722 async fn handle(
723 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
724 (address, sectors, ApiTipsetKey(tsk)): Self::Params,
725 ) -> Result<Self::Ok, ServerError> {
726 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
727 let miner_state: miner::State = ctx
728 .state_manager
729 .get_actor_state_from_address(&ts, &address)?;
730 Ok(miner_state.load_sectors_ext(ctx.store(), sectors.as_ref())?)
731 }
732}
733
734pub enum StateMinerSectorCount {}
736
737impl RpcMethod<2> for StateMinerSectorCount {
738 const NAME: &'static str = "Filecoin.StateMinerSectorCount";
739 const PARAM_NAMES: [&'static str; 2] = ["minerAddress", "tipsetKey"];
740 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
741 const PERMISSION: Permission = Permission::Read;
742 const DESCRIPTION: Option<&'static str> =
743 Some("Returns the number of sectors in a miner's sector and proving sets.");
744
745 type Params = (Address, ApiTipsetKey);
746 type Ok = MinerSectors;
747
748 async fn handle(
749 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
750 (address, ApiTipsetKey(tsk)): Self::Params,
751 ) -> Result<Self::Ok, ServerError> {
752 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
753 let policy = &ctx.chain_config().policy;
754 let miner_state: miner::State = ctx
755 .state_manager
756 .get_actor_state_from_address(&ts, &address)?;
757 let mut live_count = 0;
759 let mut active_count = 0;
760 let mut faulty_count = 0;
761 miner_state.for_each_deadline(policy, ctx.store(), |_dlidx, deadline| {
762 deadline.for_each(ctx.store(), |_partidx, partition| {
763 live_count += partition.live_sectors().len();
764 active_count += partition.active_sectors().len();
765 faulty_count += partition.faulty_sectors().len();
766 Ok(())
767 })
768 })?;
769 Ok(MinerSectors::new(live_count, active_count, faulty_count))
770 }
771}
772
773pub enum StateMinerSectorAllocated {}
775
776impl RpcMethod<3> for StateMinerSectorAllocated {
777 const NAME: &'static str = "Filecoin.StateMinerSectorAllocated";
778 const PARAM_NAMES: [&'static str; 3] = ["minerAddress", "sectorNumber", "tipsetKey"];
779 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
780 const PERMISSION: Permission = Permission::Read;
781 const DESCRIPTION: Option<&'static str> =
782 Some("Checks if a sector number is marked as allocated.");
783
784 type Params = (Address, SectorNumber, ApiTipsetKey);
785 type Ok = bool;
786
787 async fn handle(
788 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
789 (miner_address, sector_number, ApiTipsetKey(tsk)): Self::Params,
790 ) -> Result<Self::Ok, ServerError> {
791 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
792 let miner_state: miner::State = ctx
793 .state_manager
794 .get_actor_state_from_address(&ts, &miner_address)?;
795 let allocated_sector_numbers: BitField =
796 miner_state.load_allocated_sector_numbers(ctx.store())?;
797 Ok(allocated_sector_numbers.get(sector_number))
798 }
799}
800
801pub enum StateMinerPower {}
803
804impl RpcMethod<2> for StateMinerPower {
805 const NAME: &'static str = "Filecoin.StateMinerPower";
806 const PARAM_NAMES: [&'static str; 2] = ["minerAddress", "tipsetKey"];
807 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
808 const PERMISSION: Permission = Permission::Read;
809 const DESCRIPTION: Option<&'static str> = Some("Returns the power of the specified miner.");
810
811 type Params = (Address, ApiTipsetKey);
812 type Ok = MinerPower;
813
814 async fn handle(
815 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
816 (address, ApiTipsetKey(tsk)): Self::Params,
817 ) -> Result<Self::Ok, ServerError> {
818 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
819 ctx.state_manager
820 .miner_power(&address, &ts)
821 .map_err(From::from)
822 }
823}
824
825pub enum StateMinerDeadlines {}
826
827impl RpcMethod<2> for StateMinerDeadlines {
828 const NAME: &'static str = "Filecoin.StateMinerDeadlines";
829 const PARAM_NAMES: [&'static str; 2] = ["minerAddress", "tipsetKey"];
830 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
831 const PERMISSION: Permission = Permission::Read;
832 const DESCRIPTION: Option<&'static str> =
833 Some("Returns all proving deadlines for the given miner.");
834
835 type Params = (Address, ApiTipsetKey);
836 type Ok = Vec<ApiDeadline>;
837
838 async fn handle(
839 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
840 (address, ApiTipsetKey(tsk)): Self::Params,
841 ) -> Result<Self::Ok, ServerError> {
842 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
843 let policy = &ctx.chain_config().policy;
844 let state: miner::State = ctx
845 .state_manager
846 .get_actor_state_from_address(&ts, &address)?;
847 let mut res = Vec::new();
848 state.for_each_deadline(policy, ctx.store(), |_idx, deadline| {
849 res.push(ApiDeadline {
850 post_submissions: deadline.partitions_posted(),
851 disputable_proof_count: deadline.disputable_proof_count(ctx.store())?,
852 daily_fee: deadline.daily_fee(),
853 });
854 Ok(())
855 })?;
856 Ok(res)
857 }
858}
859
860pub enum StateMinerProvingDeadline {}
861
862impl RpcMethod<2> for StateMinerProvingDeadline {
863 const NAME: &'static str = "Filecoin.StateMinerProvingDeadline";
864 const PARAM_NAMES: [&'static str; 2] = ["minerAddress", "tipsetKey"];
865 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
866 const PERMISSION: Permission = Permission::Read;
867 const DESCRIPTION: Option<&'static str> = Some(
868 "Calculates the deadline and related details for a given epoch during a proving period.",
869 );
870
871 type Params = (Address, ApiTipsetKey);
872 type Ok = ApiDeadlineInfo;
873
874 async fn handle(
875 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
876 (address, ApiTipsetKey(tsk)): Self::Params,
877 ) -> Result<Self::Ok, ServerError> {
878 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
879 let policy = &ctx.chain_config().policy;
880 let state: miner::State = ctx
881 .state_manager
882 .get_actor_state_from_address(&ts, &address)?;
883 Ok(ApiDeadlineInfo(
884 state
885 .recorded_deadline_info(policy, ts.epoch())
886 .next_not_elapsed(),
887 ))
888 }
889}
890
891pub enum StateMinerFaults {}
893
894impl RpcMethod<2> for StateMinerFaults {
895 const NAME: &'static str = "Filecoin.StateMinerFaults";
896 const PARAM_NAMES: [&'static str; 2] = ["minerAddress", "tipsetKey"];
897 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
898 const PERMISSION: Permission = Permission::Read;
899 const DESCRIPTION: Option<&'static str> =
900 Some("Returns a bitfield of the faulty sectors for the given miner.");
901
902 type Params = (Address, ApiTipsetKey);
903 type Ok = BitField;
904
905 async fn handle(
906 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
907 (address, ApiTipsetKey(tsk)): Self::Params,
908 ) -> Result<Self::Ok, ServerError> {
909 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
910 ctx.state_manager
911 .miner_faults(&address, &ts)
912 .map_err(From::from)
913 }
914}
915
916pub enum StateMinerRecoveries {}
917
918impl RpcMethod<2> for StateMinerRecoveries {
919 const NAME: &'static str = "Filecoin.StateMinerRecoveries";
920 const PARAM_NAMES: [&'static str; 2] = ["minerAddress", "tipsetKey"];
921 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
922 const PERMISSION: Permission = Permission::Read;
923 const DESCRIPTION: Option<&'static str> =
924 Some("Returns a bitfield of recovering sectors for the given miner.");
925
926 type Params = (Address, ApiTipsetKey);
927 type Ok = BitField;
928
929 async fn handle(
930 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
931 (address, ApiTipsetKey(tsk)): Self::Params,
932 ) -> Result<Self::Ok, ServerError> {
933 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
934 ctx.state_manager
935 .miner_recoveries(&address, &ts)
936 .map_err(From::from)
937 }
938}
939
940pub enum StateMinerAvailableBalance {}
941
942impl RpcMethod<2> for StateMinerAvailableBalance {
943 const NAME: &'static str = "Filecoin.StateMinerAvailableBalance";
944 const PARAM_NAMES: [&'static str; 2] = ["minerAddress", "tipsetKey"];
945 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
946 const PERMISSION: Permission = Permission::Read;
947 const DESCRIPTION: Option<&'static str> =
948 Some("Returns the portion of a miner's balance available for withdrawal or spending.");
949
950 type Params = (Address, ApiTipsetKey);
951 type Ok = TokenAmount;
952
953 async fn handle(
954 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
955 (address, ApiTipsetKey(tsk)): Self::Params,
956 ) -> Result<Self::Ok, ServerError> {
957 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
958 let actor = ctx
959 .state_manager
960 .get_required_actor(&address, *ts.parent_state())?;
961 let state = miner::State::load(ctx.store(), actor.code, actor.state)?;
962 let actor_balance: TokenAmount = actor.balance.clone().into();
963 let (vested, available): (TokenAmount, TokenAmount) = match &state {
964 miner::State::V17(s) => (
965 s.check_vested_funds(ctx.store(), ts.epoch())?.into(),
966 s.get_available_balance(&actor_balance.into())?.into(),
967 ),
968 miner::State::V16(s) => (
969 s.check_vested_funds(ctx.store(), ts.epoch())?.into(),
970 s.get_available_balance(&actor_balance.into())?.into(),
971 ),
972 miner::State::V15(s) => (
973 s.check_vested_funds(ctx.store(), ts.epoch())?.into(),
974 s.get_available_balance(&actor_balance.into())?.into(),
975 ),
976 miner::State::V14(s) => (
977 s.check_vested_funds(ctx.store(), ts.epoch())?.into(),
978 s.get_available_balance(&actor_balance.into())?.into(),
979 ),
980 miner::State::V13(s) => (
981 s.check_vested_funds(ctx.store(), ts.epoch())?.into(),
982 s.get_available_balance(&actor_balance.into())?.into(),
983 ),
984 miner::State::V12(s) => (
985 s.check_vested_funds(ctx.store(), ts.epoch())?.into(),
986 s.get_available_balance(&actor_balance.into())?.into(),
987 ),
988 miner::State::V11(s) => (
989 s.check_vested_funds(ctx.store(), ts.epoch())?.into(),
990 s.get_available_balance(&actor_balance.into())?.into(),
991 ),
992 miner::State::V10(s) => (
993 s.check_vested_funds(ctx.store(), ts.epoch())?.into(),
994 s.get_available_balance(&actor_balance.into())?.into(),
995 ),
996 miner::State::V9(s) => (
997 s.check_vested_funds(ctx.store(), ts.epoch())?.into(),
998 s.get_available_balance(&actor_balance.into())?.into(),
999 ),
1000 miner::State::V8(s) => (
1001 s.check_vested_funds(ctx.store(), ts.epoch())?.into(),
1002 s.get_available_balance(&actor_balance.into())?.into(),
1003 ),
1004 };
1005
1006 Ok(vested + available)
1007 }
1008}
1009
1010pub enum StateMinerInitialPledgeCollateral {}
1011
1012impl RpcMethod<3> for StateMinerInitialPledgeCollateral {
1013 const NAME: &'static str = "Filecoin.StateMinerInitialPledgeCollateral";
1014 const PARAM_NAMES: [&'static str; 3] = ["minerAddress", "sectorPreCommitInfo", "tipsetKey"];
1015 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1016 const PERMISSION: Permission = Permission::Read;
1017 const DESCRIPTION: Option<&'static str> =
1018 Some("Returns the initial pledge collateral for the specified miner's sector.");
1019
1020 type Params = (Address, SectorPreCommitInfo, ApiTipsetKey);
1021 type Ok = TokenAmount;
1022
1023 async fn handle(
1024 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1025 (address, pci, ApiTipsetKey(tsk)): Self::Params,
1026 ) -> Result<Self::Ok, ServerError> {
1027 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1028
1029 let sector_size = pci
1030 .seal_proof
1031 .sector_size()
1032 .map_err(|e| anyhow::anyhow!("failed to get resolve size: {e}"))?;
1033
1034 let market_state: market::State = ctx.state_manager.get_actor_state(&ts)?;
1035 let (w, vw) = market_state.verify_deals_for_activation(
1036 ctx.store(),
1037 address,
1038 pci.deal_ids,
1039 ts.epoch(),
1040 pci.expiration,
1041 )?;
1042 let duration = pci.expiration - ts.epoch();
1043 let sector_weight =
1044 qa_power_for_weight(SectorSize::from(sector_size).into(), duration, &w, &vw);
1045
1046 let power_state: power::State = ctx.state_manager.get_actor_state(&ts)?;
1047 let power_smoothed = power_state.total_power_smoothed();
1048 let pledge_collateral = power_state.total_locked();
1049
1050 let reward_state: reward::State = ctx.state_manager.get_actor_state(&ts)?;
1051 let genesis_info = GenesisInfo::from_chain_config(ctx.chain_config().clone());
1052 let circ_supply = genesis_info.get_vm_circulating_supply_detailed(
1053 ts.epoch(),
1054 &Arc::new(ctx.store()),
1055 ts.parent_state(),
1056 )?;
1057 let initial_pledge = reward_state.initial_pledge_for_power(
1058 §or_weight,
1059 pledge_collateral,
1060 power_smoothed,
1061 &circ_supply.fil_circulating,
1062 power_state.ramp_start_epoch(),
1063 power_state.ramp_duration_epochs(),
1064 )?;
1065
1066 let (q, _) = (initial_pledge * INITIAL_PLEDGE_NUM).div_rem(INITIAL_PLEDGE_DEN);
1067 Ok(q)
1068 }
1069}
1070
1071pub enum StateMinerPreCommitDepositForPower {}
1072
1073impl RpcMethod<3> for StateMinerPreCommitDepositForPower {
1074 const NAME: &'static str = "Filecoin.StateMinerPreCommitDepositForPower";
1075 const PARAM_NAMES: [&'static str; 3] = ["minerAddress", "sectorPreCommitInfo", "tipsetKey"];
1076 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1077 const PERMISSION: Permission = Permission::Read;
1078 const DESCRIPTION: Option<&'static str> =
1079 Some("Returns the sector precommit deposit for the specified miner.");
1080
1081 type Params = (Address, SectorPreCommitInfo, ApiTipsetKey);
1082 type Ok = TokenAmount;
1083
1084 async fn handle(
1085 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1086 (address, pci, ApiTipsetKey(tsk)): Self::Params,
1087 ) -> Result<Self::Ok, ServerError> {
1088 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1089
1090 let sector_size = pci
1091 .seal_proof
1092 .sector_size()
1093 .map_err(|e| anyhow::anyhow!("failed to get resolve size: {e}"))?;
1094
1095 let market_state: market::State = ctx.state_manager.get_actor_state(&ts)?;
1096 let (w, vw) = market_state.verify_deals_for_activation(
1097 ctx.store(),
1098 address,
1099 pci.deal_ids,
1100 ts.epoch(),
1101 pci.expiration,
1102 )?;
1103 let duration = pci.expiration - ts.epoch();
1104 let sector_size = SectorSize::from(sector_size).into();
1105 let sector_weight =
1106 if ctx.state_manager.get_network_version(ts.epoch()) < NetworkVersion::V16 {
1107 qa_power_for_weight(sector_size, duration, &w, &vw)
1108 } else {
1109 qa_power_max(sector_size)
1110 };
1111
1112 let power_state: power::State = ctx.state_manager.get_actor_state(&ts)?;
1113 let power_smoothed = power_state.total_power_smoothed();
1114
1115 let reward_state: reward::State = ctx.state_manager.get_actor_state(&ts)?;
1116 let deposit: TokenAmount =
1117 reward_state.pre_commit_deposit_for_power(power_smoothed, sector_weight)?;
1118 let (value, _) = (deposit * INITIAL_PLEDGE_NUM).div_rem(INITIAL_PLEDGE_DEN);
1119 Ok(value)
1120 }
1121}
1122
1123pub enum StateGetReceipt {}
1125
1126impl RpcMethod<2> for StateGetReceipt {
1127 const NAME: &'static str = "Filecoin.StateGetReceipt";
1128 const PARAM_NAMES: [&'static str; 2] = ["cid", "tipset_key"];
1129 const API_PATHS: BitFlags<ApiPaths> = make_bitflags!(ApiPaths::V0); const PERMISSION: Permission = Permission::Read;
1131
1132 type Params = (Cid, ApiTipsetKey);
1133 type Ok = Receipt;
1134
1135 async fn handle(
1136 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1137 (cid, ApiTipsetKey(tsk)): Self::Params,
1138 ) -> Result<Self::Ok, ServerError> {
1139 let tipset = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1140 ctx.state_manager
1141 .get_receipt(tipset, cid)
1142 .map_err(From::from)
1143 }
1144}
1145
1146pub enum StateWaitMsgV0 {}
1149
1150impl RpcMethod<2> for StateWaitMsgV0 {
1151 const NAME: &'static str = "Filecoin.StateWaitMsg";
1152 const PARAM_NAMES: [&'static str; 2] = ["messageCid", "confidence"];
1153 const API_PATHS: BitFlags<ApiPaths> = make_bitflags!(ApiPaths::V0); const PERMISSION: Permission = Permission::Read;
1155
1156 type Params = (Cid, i64);
1157 type Ok = MessageLookup;
1158
1159 async fn handle(
1160 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1161 (message_cid, confidence): Self::Params,
1162 ) -> Result<Self::Ok, ServerError> {
1163 let (tipset, receipt) = ctx
1164 .state_manager
1165 .wait_for_message(message_cid, confidence, None, None)
1166 .await?;
1167 let tipset = tipset.context("wait for msg returned empty tuple")?;
1168 let receipt = receipt.context("wait for msg returned empty receipt")?;
1169 let ipld = receipt.return_data().deserialize().unwrap_or(Ipld::Null);
1170 Ok(MessageLookup {
1171 receipt,
1172 tipset: tipset.key().clone(),
1173 height: tipset.epoch(),
1174 message: message_cid,
1175 return_dec: ipld,
1176 })
1177 }
1178}
1179
1180pub enum StateWaitMsg {}
1183
1184impl RpcMethod<4> for StateWaitMsg {
1185 const NAME: &'static str = "Filecoin.StateWaitMsg";
1186 const PARAM_NAMES: [&'static str; 4] =
1187 ["messageCid", "confidence", "lookbackLimit", "allowReplaced"];
1188 const API_PATHS: BitFlags<ApiPaths> = make_bitflags!(ApiPaths::V1); const PERMISSION: Permission = Permission::Read;
1190 const DESCRIPTION: Option<&'static str> = Some(
1191 "StateWaitMsg searches up to limit epochs for a message in the chain. If not found, it blocks until the message appears on-chain and reaches the required confidence depth.",
1192 );
1193
1194 type Params = (Cid, i64, ChainEpoch, bool);
1195 type Ok = MessageLookup;
1196
1197 async fn handle(
1198 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1199 (message_cid, confidence, look_back_limit, allow_replaced): Self::Params,
1200 ) -> Result<Self::Ok, ServerError> {
1201 let (tipset, receipt) = ctx
1202 .state_manager
1203 .wait_for_message(
1204 message_cid,
1205 confidence,
1206 Some(look_back_limit),
1207 Some(allow_replaced),
1208 )
1209 .await?;
1210 let tipset = tipset.context("wait for msg returned empty tuple")?;
1211 let receipt = receipt.context("wait for msg returned empty receipt")?;
1212 let ipld = receipt.return_data().deserialize().unwrap_or(Ipld::Null);
1213 Ok(MessageLookup {
1214 receipt,
1215 tipset: tipset.key().clone(),
1216 height: tipset.epoch(),
1217 message: message_cid,
1218 return_dec: ipld,
1219 })
1220 }
1221}
1222
1223pub enum StateSearchMsg {}
1226
1227impl RpcMethod<4> for StateSearchMsg {
1228 const NAME: &'static str = "Filecoin.StateSearchMsg";
1229 const PARAM_NAMES: [&'static str; 4] =
1230 ["tipsetKey", "messageCid", "lookBackLimit", "allowReplaced"];
1231 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1232 const PERMISSION: Permission = Permission::Read;
1233 const DESCRIPTION: Option<&'static str> =
1234 Some("Returns the receipt and tipset the specified message was included in.");
1235
1236 type Params = (ApiTipsetKey, Cid, i64, bool);
1237 type Ok = MessageLookup;
1238
1239 async fn handle(
1240 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1241 (ApiTipsetKey(tsk), message_cid, look_back_limit, allow_replaced): Self::Params,
1242 ) -> Result<Self::Ok, ServerError> {
1243 let from = tsk
1244 .map(|k| ctx.chain_index().load_required_tipset(&k))
1245 .transpose()?;
1246 let (tipset, receipt) = ctx
1247 .state_manager
1248 .search_for_message(
1249 from,
1250 message_cid,
1251 Some(look_back_limit),
1252 Some(allow_replaced),
1253 )
1254 .await?
1255 .with_context(|| format!("message {message_cid} not found."))?;
1256 let ipld = receipt.return_data().deserialize().unwrap_or(Ipld::Null);
1257 Ok(MessageLookup {
1258 receipt,
1259 tipset: tipset.key().clone(),
1260 height: tipset.epoch(),
1261 message: message_cid,
1262 return_dec: ipld,
1263 })
1264 }
1265}
1266
1267pub enum StateSearchMsgLimited {}
1269
1270impl RpcMethod<2> for StateSearchMsgLimited {
1271 const NAME: &'static str = "Filecoin.StateSearchMsgLimited";
1272 const PARAM_NAMES: [&'static str; 2] = ["message_cid", "look_back_limit"];
1273 const API_PATHS: BitFlags<ApiPaths> = make_bitflags!(ApiPaths::V0); const PERMISSION: Permission = Permission::Read;
1275 const DESCRIPTION: Option<&'static str> = Some(
1276 "Looks back up to limit epochs in the chain for a message, and returns its receipt and the tipset where it was executed.",
1277 );
1278 type Params = (Cid, i64);
1279 type Ok = MessageLookup;
1280
1281 async fn handle(
1282 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1283 (message_cid, look_back_limit): Self::Params,
1284 ) -> Result<Self::Ok, ServerError> {
1285 let (tipset, receipt) = ctx
1286 .state_manager
1287 .search_for_message(None, message_cid, Some(look_back_limit), None)
1288 .await?
1289 .with_context(|| {
1290 format!("message {message_cid} not found within the last {look_back_limit} epochs")
1291 })?;
1292 let ipld = receipt.return_data().deserialize().unwrap_or(Ipld::Null);
1293 Ok(MessageLookup {
1294 receipt,
1295 tipset: tipset.key().clone(),
1296 height: tipset.epoch(),
1297 message: message_cid,
1298 return_dec: ipld,
1299 })
1300 }
1301}
1302
1303pub enum StateFetchRoot {}
1318
1319impl RpcMethod<2> for StateFetchRoot {
1320 const NAME: &'static str = "Forest.StateFetchRoot";
1321 const PARAM_NAMES: [&'static str; 2] = ["root_cid", "save_to_file"];
1322 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1323 const PERMISSION: Permission = Permission::Read;
1324
1325 type Params = (Cid, Option<PathBuf>);
1326 type Ok = String;
1327
1328 async fn handle(
1329 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1330 (root_cid, save_to_file): Self::Params,
1331 ) -> Result<Self::Ok, ServerError> {
1332 let network_send = ctx.network_send().clone();
1333 let db = ctx.store_owned();
1334
1335 let (car_tx, car_handle) = if let Some(save_to_file) = save_to_file {
1336 let (car_tx, car_rx) = flume::bounded(100);
1337 let roots = nonempty![root_cid];
1338 let file = tokio::fs::File::create(save_to_file).await?;
1339
1340 let car_handle = tokio::spawn(async move {
1341 car_rx
1342 .stream()
1343 .map(Ok)
1344 .forward(CarWriter::new_carv1(roots, file)?)
1345 .await
1346 });
1347
1348 (Some(car_tx), Some(car_handle))
1349 } else {
1350 (None, None)
1351 };
1352
1353 const MAX_CONCURRENT_REQUESTS: usize = 64;
1354 const REQUEST_TIMEOUT: Duration = Duration::from_secs(10);
1355
1356 let mut seen: CidHashSet = CidHashSet::default();
1357 let mut counter: usize = 0;
1358 let mut fetched: usize = 0;
1359 let mut failures: usize = 0;
1360 let mut task_set = JoinSet::new();
1361
1362 fn handle_worker(fetched: &mut usize, failures: &mut usize, ret: anyhow::Result<()>) {
1363 match ret {
1364 Ok(()) => *fetched += 1,
1365 Err(msg) => {
1366 *failures += 1;
1367 tracing::debug!("Request failed: {msg}");
1368 }
1369 }
1370 }
1371
1372 let mut get_ipld_link = |ipld: &Ipld| match ipld {
1374 &Ipld::Link(cid) if cid.codec() == DAG_CBOR && seen.insert(cid) => Some(cid),
1375 _ => None,
1376 };
1377
1378 let dfs = Arc::new(Mutex::new(vec![Ipld::Link(root_cid)]));
1384 let mut to_be_fetched = vec![];
1385
1386 loop {
1388 while let Some(ipld) = lock_pop(&dfs) {
1389 {
1390 let mut dfs_guard = dfs.lock();
1391 for new_cid in ipld.iter().filter_map(&mut get_ipld_link) {
1394 counter += 1;
1395 if counter.is_multiple_of(1_000) {
1396 tracing::debug!(
1398 "Graph walk: CIDs: {counter}, Fetched: {fetched}, Failures: {failures}, dfs: {}, Concurrent: {}",
1399 dfs_guard.len(),
1400 task_set.len()
1401 );
1402 }
1403
1404 if let Some(next_ipld) = db.get_cbor(&new_cid)? {
1405 dfs_guard.push(next_ipld);
1406 if let Some(car_tx) = &car_tx {
1407 car_tx.send(CarBlock {
1408 cid: new_cid,
1409 data: db.get(&new_cid)?.with_context(|| {
1410 format!("Failed to get cid {new_cid} from block store")
1411 })?,
1412 })?;
1413 }
1414 } else {
1415 to_be_fetched.push(new_cid);
1416 }
1417 }
1418 }
1419
1420 while let Some(cid) = to_be_fetched.pop() {
1421 if task_set.len() == MAX_CONCURRENT_REQUESTS
1422 && let Some(ret) = task_set.join_next().await
1423 {
1424 handle_worker(&mut fetched, &mut failures, ret?)
1425 }
1426 task_set.spawn_blocking({
1427 let network_send = network_send.clone();
1428 let db = db.clone();
1429 let dfs_vec = Arc::clone(&dfs);
1430 let car_tx = car_tx.clone();
1431 move || {
1432 let (tx, rx) = flume::bounded(1);
1433 network_send.send(NetworkMessage::BitswapRequest {
1434 cid,
1435 response_channel: tx,
1436 })?;
1437 let _ignore = rx.recv_timeout(REQUEST_TIMEOUT);
1441
1442 let new_ipld = db
1443 .get_cbor::<Ipld>(&cid)?
1444 .with_context(|| format!("Request failed: {cid}"))?;
1445 dfs_vec.lock().push(new_ipld);
1446 if let Some(car_tx) = &car_tx {
1447 car_tx.send(CarBlock {
1448 cid,
1449 data: db.get(&cid)?.with_context(|| {
1450 format!("Failed to get cid {cid} from block store")
1451 })?,
1452 })?;
1453 }
1454
1455 Ok(())
1456 }
1457 });
1458 }
1459 tokio::task::yield_now().await;
1460 }
1461 if let Some(ret) = task_set.join_next().await {
1462 handle_worker(&mut fetched, &mut failures, ret?)
1463 } else {
1464 break;
1467 }
1468 }
1469
1470 drop(car_tx);
1471 if let Some(car_handle) = car_handle {
1472 car_handle.await??;
1473 }
1474
1475 Ok(format!(
1476 "IPLD graph traversed! CIDs: {counter}, fetched: {fetched}, failures: {failures}."
1477 ))
1478 }
1479}
1480
1481pub enum ForestStateCompute {}
1482
1483impl RpcMethod<2> for ForestStateCompute {
1484 const NAME: &'static str = "Forest.StateCompute";
1485 const N_REQUIRED_PARAMS: usize = 1;
1486 const PARAM_NAMES: [&'static str; 2] = ["epoch", "n_epochs"];
1487 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1488 const PERMISSION: Permission = Permission::Read;
1489
1490 type Params = (ChainEpoch, Option<NonZeroUsize>);
1491 type Ok = Vec<ForestComputeStateOutput>;
1492
1493 async fn handle(
1494 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1495 (from_epoch, n_epochs): Self::Params,
1496 ) -> Result<Self::Ok, ServerError> {
1497 let n_epochs = n_epochs.map(|n| n.get()).unwrap_or(1) as ChainEpoch;
1498 let to_epoch = from_epoch + n_epochs - 1;
1499 let to_ts = ctx.chain_index().tipset_by_height(
1500 to_epoch,
1501 ctx.chain_store().heaviest_tipset(),
1502 ResolveNullTipset::TakeOlder,
1503 )?;
1504 let from_ts = if from_epoch >= to_ts.epoch() {
1505 to_ts.clone()
1508 } else {
1509 ctx.chain_index().tipset_by_height(
1510 from_epoch,
1511 to_ts.clone(),
1512 ResolveNullTipset::TakeOlder,
1513 )?
1514 };
1515
1516 let mut futures = FuturesOrdered::new();
1517 for ts in to_ts
1518 .chain(ctx.store())
1519 .take_while(|ts| ts.epoch() >= from_ts.epoch())
1520 {
1521 let chain_store = ctx.chain_store().clone();
1522 let network_context = ctx.sync_network_context.clone();
1523 futures.push_front(async move {
1524 if crate::chain_sync::load_full_tipset(&chain_store, ts.key()).is_err() {
1525 const MAX_RETRIES: usize = 5;
1527 let fts = 'retry_loop: {
1528 for i in 1..=MAX_RETRIES {
1529 match network_context.chain_exchange_messages(None, &ts).await {
1530 Ok(fts) => break 'retry_loop Ok(fts),
1531 Err(e) if i >= MAX_RETRIES => break 'retry_loop Err(e),
1532 Err(_) => continue,
1533 }
1534 }
1535 Err("unreachable chain exchange error in ForestStateCompute".into())
1536 }
1537 .map_err(|e| {
1538 anyhow::anyhow!("failed to download messages@{}: {e}", ts.epoch())
1539 })?;
1540 fts.persist(chain_store.blockstore())?;
1541 }
1542 anyhow::Ok(ts)
1543 });
1544 }
1545
1546 let mut results = Vec::with_capacity(n_epochs as _);
1547 while let Some(ts) = futures.try_next().await? {
1548 let epoch = ts.epoch();
1549 let tipset_key = ts.key().clone();
1550 let StateOutput { state_root, .. } = ctx
1551 .state_manager
1552 .compute_tipset_state(ts, crate::state_manager::NO_CALLBACK, VMTrace::NotTraced)
1553 .await?;
1554 results.push(ForestComputeStateOutput {
1555 state_root,
1556 epoch,
1557 tipset_key,
1558 });
1559 }
1560 Ok(results)
1561 }
1562}
1563
1564pub enum StateCompute {}
1565
1566impl RpcMethod<3> for StateCompute {
1567 const NAME: &'static str = "Filecoin.StateCompute";
1568 const PARAM_NAMES: [&'static str; 3] = ["height", "messages", "tipsetKey"];
1569 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1570 const PERMISSION: Permission = Permission::Read;
1571 const DESCRIPTION: Option<&'static str> =
1572 Some("Applies the given messages on the given tipset");
1573
1574 type Params = (ChainEpoch, Vec<Message>, ApiTipsetKey);
1575 type Ok = ComputeStateOutput;
1576
1577 async fn handle(
1578 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1579 (height, messages, ApiTipsetKey(tsk)): Self::Params,
1580 ) -> Result<Self::Ok, ServerError> {
1581 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1582 let (tx, rx) = flume::unbounded();
1583 let callback = move |ctx: MessageCallbackCtx<'_>| {
1584 tx.send(ApiInvocResult {
1585 msg_cid: ctx.message.cid(),
1586 msg: ctx.message.message().clone(),
1587 msg_rct: Some(ctx.apply_ret.msg_receipt()),
1588 error: ctx.apply_ret.failure_info().unwrap_or_default(),
1589 duration: ctx.duration.as_nanos().clamp(0, u64::MAX as u128) as u64,
1590 gas_cost: MessageGasCost::new(ctx.message.message(), ctx.apply_ret)?,
1591 execution_trace: structured::parse_events(ctx.apply_ret.exec_trace())
1592 .unwrap_or_default(),
1593 })?;
1594 Ok(())
1595 };
1596 let StateOutput { state_root, .. } = ctx
1597 .state_manager
1598 .compute_state(height, messages, ts, Some(callback), VMTrace::Traced)
1599 .await?;
1600 let mut trace = vec![];
1601 while let Ok(v) = rx.try_recv() {
1602 trace.push(v);
1603 }
1604 Ok(ComputeStateOutput {
1605 root: state_root,
1606 trace,
1607 })
1608 }
1609}
1610
1611fn lock_pop<T>(mutex: &Mutex<Vec<T>>) -> Option<T> {
1614 mutex.lock().pop()
1615}
1616
1617pub enum StateGetRandomnessFromTickets {}
1619
1620impl RpcMethod<4> for StateGetRandomnessFromTickets {
1621 const NAME: &'static str = "Filecoin.StateGetRandomnessFromTickets";
1622 const PARAM_NAMES: [&'static str; 4] = ["personalization", "randEpoch", "entropy", "tipsetKey"];
1623 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1624 const PERMISSION: Permission = Permission::Read;
1625 const DESCRIPTION: Option<&'static str> = Some("Samples the chain for randomness.");
1626
1627 type Params = (i64, ChainEpoch, Vec<u8>, ApiTipsetKey);
1628 type Ok = Vec<u8>;
1629
1630 async fn handle(
1631 ctx: Ctx<impl Blockstore>,
1632 (personalization, rand_epoch, entropy, ApiTipsetKey(tsk)): Self::Params,
1633 ) -> Result<Self::Ok, ServerError> {
1634 let tipset = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1635 let chain_rand = ctx.state_manager.chain_rand(tipset);
1636 let digest = chain_rand.get_chain_randomness(rand_epoch, false)?;
1637 let value = crate::state_manager::chain_rand::draw_randomness_from_digest(
1638 &digest,
1639 personalization,
1640 rand_epoch,
1641 &entropy,
1642 )?;
1643 Ok(value.to_vec())
1644 }
1645}
1646
1647pub enum StateGetRandomnessDigestFromTickets {}
1648
1649impl RpcMethod<2> for StateGetRandomnessDigestFromTickets {
1650 const NAME: &'static str = "Filecoin.StateGetRandomnessDigestFromTickets";
1651 const PARAM_NAMES: [&'static str; 2] = ["randEpoch", "tipsetKey"];
1652 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1653 const PERMISSION: Permission = Permission::Read;
1654 const DESCRIPTION: Option<&'static str> = Some("Samples the chain for randomness.");
1655
1656 type Params = (ChainEpoch, ApiTipsetKey);
1657 type Ok = Vec<u8>;
1658
1659 async fn handle(
1660 ctx: Ctx<impl Blockstore>,
1661 (rand_epoch, ApiTipsetKey(tsk)): Self::Params,
1662 ) -> Result<Self::Ok, ServerError> {
1663 let tipset = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1664 let chain_rand = ctx.state_manager.chain_rand(tipset);
1665 let digest = chain_rand.get_chain_randomness(rand_epoch, false)?;
1666 Ok(digest.to_vec())
1667 }
1668}
1669
1670pub enum StateGetRandomnessFromBeacon {}
1672
1673impl RpcMethod<4> for StateGetRandomnessFromBeacon {
1674 const NAME: &'static str = "Filecoin.StateGetRandomnessFromBeacon";
1675 const PARAM_NAMES: [&'static str; 4] = ["personalization", "randEpoch", "entropy", "tipsetKey"];
1676 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1677 const PERMISSION: Permission = Permission::Read;
1678 const DESCRIPTION: Option<&'static str> = Some(
1679 "Returns the beacon entry for the specified Filecoin epoch. If unavailable, the call blocks until it becomes available.",
1680 );
1681
1682 type Params = (i64, ChainEpoch, Vec<u8>, ApiTipsetKey);
1683 type Ok = Vec<u8>;
1684
1685 async fn handle(
1686 ctx: Ctx<impl Blockstore>,
1687 (personalization, rand_epoch, entropy, ApiTipsetKey(tsk)): Self::Params,
1688 ) -> Result<Self::Ok, ServerError> {
1689 let tipset = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1690 let chain_rand = ctx.state_manager.chain_rand(tipset);
1691 let digest = chain_rand.get_beacon_randomness_v3(rand_epoch)?;
1692 let value = crate::state_manager::chain_rand::draw_randomness_from_digest(
1693 &digest,
1694 personalization,
1695 rand_epoch,
1696 &entropy,
1697 )?;
1698 Ok(value.to_vec())
1699 }
1700}
1701
1702pub enum StateGetRandomnessDigestFromBeacon {}
1703
1704impl RpcMethod<2> for StateGetRandomnessDigestFromBeacon {
1705 const NAME: &'static str = "Filecoin.StateGetRandomnessDigestFromBeacon";
1706 const PARAM_NAMES: [&'static str; 2] = ["randEpoch", "tipsetKey"];
1707 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1708 const PERMISSION: Permission = Permission::Read;
1709 const DESCRIPTION: Option<&'static str> = Some("Samples the beacon for randomness.");
1710
1711 type Params = (ChainEpoch, ApiTipsetKey);
1712 type Ok = Vec<u8>;
1713
1714 async fn handle(
1715 ctx: Ctx<impl Blockstore>,
1716 (rand_epoch, ApiTipsetKey(tsk)): Self::Params,
1717 ) -> Result<Self::Ok, ServerError> {
1718 let tipset = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1719 let chain_rand = ctx.state_manager.chain_rand(tipset);
1720 let digest = chain_rand.get_beacon_randomness_v3(rand_epoch)?;
1721 Ok(digest.to_vec())
1722 }
1723}
1724
1725pub enum StateReadState {}
1727
1728impl RpcMethod<2> for StateReadState {
1729 const NAME: &'static str = "Filecoin.StateReadState";
1730 const PARAM_NAMES: [&'static str; 2] = ["address", "tipsetKey"];
1731 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1732 const PERMISSION: Permission = Permission::Read;
1733 const DESCRIPTION: Option<&'static str> = Some("Returns the state of the specified actor.");
1734
1735 type Params = (Address, ApiTipsetKey);
1736 type Ok = ApiActorState;
1737
1738 async fn handle(
1739 ctx: Ctx<impl Blockstore>,
1740 (address, ApiTipsetKey(tsk)): Self::Params,
1741 ) -> Result<Self::Ok, ServerError> {
1742 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1743 let actor = ctx
1744 .state_manager
1745 .get_required_actor(&address, *ts.parent_state())?;
1746 let state_json = load_and_serialize_actor_state(ctx.store(), &actor.code, &actor.state)
1747 .map_err(|e| anyhow::anyhow!("Failed to load actor state: {}", e))?;
1748 Ok(ApiActorState {
1749 balance: actor.balance.clone().into(),
1750 code: actor.code,
1751 state: state_json,
1752 })
1753 }
1754}
1755
1756pub enum StateDecodeParams {}
1757impl RpcMethod<4> for StateDecodeParams {
1758 const NAME: &'static str = "Filecoin.StateDecodeParams";
1759 const PARAM_NAMES: [&'static str; 4] = ["address", "method", "params", "tipsetKey"];
1760 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1761 const PERMISSION: Permission = Permission::Read;
1762 const DESCRIPTION: Option<&'static str> = Some("Decode the provided method params.");
1763
1764 type Params = (Address, MethodNum, Vec<u8>, ApiTipsetKey);
1765 type Ok = serde_json::Value;
1766
1767 async fn handle(
1768 ctx: Ctx<impl Blockstore>,
1769 (address, method, params, ApiTipsetKey(tsk)): Self::Params,
1770 ) -> Result<Self::Ok, ServerError> {
1771 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1772 let actor = ctx
1773 .state_manager
1774 .get_required_actor(&address, *ts.parent_state())?;
1775
1776 let res = crate::rpc::registry::methods_reg::deserialize_params(
1777 &actor.code,
1778 method,
1779 params.as_slice(),
1780 )?;
1781 Ok(res.into())
1782 }
1783}
1784
1785pub enum StateCirculatingSupply {}
1786
1787impl RpcMethod<1> for StateCirculatingSupply {
1788 const NAME: &'static str = "Filecoin.StateCirculatingSupply";
1789 const PARAM_NAMES: [&'static str; 1] = ["tipsetKey"];
1790 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1791 const PERMISSION: Permission = Permission::Read;
1792 const DESCRIPTION: Option<&'static str> =
1793 Some("Returns the exact circulating supply of Filecoin at the given tipset.");
1794
1795 type Params = (ApiTipsetKey,);
1796 type Ok = TokenAmount;
1797
1798 async fn handle(
1799 ctx: Ctx<impl Blockstore>,
1800 (ApiTipsetKey(tsk),): Self::Params,
1801 ) -> Result<Self::Ok, ServerError> {
1802 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1803 let height = ts.epoch();
1804 let root = ts.parent_state();
1805 let genesis_info = GenesisInfo::from_chain_config(ctx.chain_config().clone());
1806 let supply =
1807 genesis_info.get_state_circulating_supply(height - 1, &ctx.store_owned(), root)?;
1808 Ok(supply)
1809 }
1810}
1811
1812pub enum StateVerifiedClientStatus {}
1813
1814impl RpcMethod<2> for StateVerifiedClientStatus {
1815 const NAME: &'static str = "Filecoin.StateVerifiedClientStatus";
1816 const PARAM_NAMES: [&'static str; 2] = ["address", "tipsetKey"];
1817 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1818 const PERMISSION: Permission = Permission::Read;
1819 const DESCRIPTION: Option<&'static str> = Some(
1820 "Returns the data cap for the given address. Returns null if no entry exists in the data cap table.",
1821 );
1822
1823 type Params = (Address, ApiTipsetKey);
1824 type Ok = Option<BigInt>;
1825
1826 async fn handle(
1827 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1828 (address, ApiTipsetKey(tsk)): Self::Params,
1829 ) -> Result<Self::Ok, ServerError> {
1830 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1831 let status = ctx.state_manager.verified_client_status(&address, &ts)?;
1832 Ok(status)
1833 }
1834}
1835
1836pub enum StateVMCirculatingSupplyInternal {}
1837
1838impl RpcMethod<1> for StateVMCirculatingSupplyInternal {
1839 const NAME: &'static str = "Filecoin.StateVMCirculatingSupplyInternal";
1840 const PARAM_NAMES: [&'static str; 1] = ["tipsetKey"];
1841 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1842 const PERMISSION: Permission = Permission::Read;
1843 const DESCRIPTION: Option<&'static str> =
1844 Some("Returns an approximation of Filecoin's circulating supply at the given tipset.");
1845
1846 type Params = (ApiTipsetKey,);
1847 type Ok = CirculatingSupply;
1848
1849 async fn handle(
1850 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1851 (ApiTipsetKey(tsk),): Self::Params,
1852 ) -> Result<Self::Ok, ServerError> {
1853 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1854 let genesis_info = GenesisInfo::from_chain_config(ctx.chain_config().clone());
1855 Ok(genesis_info.get_vm_circulating_supply_detailed(
1856 ts.epoch(),
1857 &ctx.store_owned(),
1858 ts.parent_state(),
1859 )?)
1860 }
1861}
1862
1863pub enum StateListMiners {}
1864
1865impl RpcMethod<1> for StateListMiners {
1866 const NAME: &'static str = "Filecoin.StateListMiners";
1867 const PARAM_NAMES: [&'static str; 1] = ["tipsetKey"];
1868 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1869 const PERMISSION: Permission = Permission::Read;
1870 const DESCRIPTION: Option<&'static str> =
1871 Some("Returns the addresses of every miner with claimed power in the Power Actor.");
1872
1873 type Params = (ApiTipsetKey,);
1874 type Ok = Vec<Address>;
1875
1876 async fn handle(
1877 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1878 (ApiTipsetKey(tsk),): Self::Params,
1879 ) -> Result<Self::Ok, ServerError> {
1880 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1881 let state: power::State = ctx.state_manager.get_actor_state(&ts)?;
1882 let miners = state.list_all_miners(ctx.store())?;
1883 Ok(miners)
1884 }
1885}
1886
1887pub enum StateListActors {}
1888
1889impl RpcMethod<1> for StateListActors {
1890 const NAME: &'static str = "Filecoin.StateListActors";
1891 const PARAM_NAMES: [&'static str; 1] = ["tipsetKey"];
1892 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1893 const PERMISSION: Permission = Permission::Read;
1894 const DESCRIPTION: Option<&'static str> =
1895 Some("Returns the addresses of every actor in the state.");
1896
1897 type Params = (ApiTipsetKey,);
1898 type Ok = Vec<Address>;
1899
1900 async fn handle(
1901 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1902 (ApiTipsetKey(tsk),): Self::Params,
1903 ) -> Result<Self::Ok, ServerError> {
1904 let mut actors = vec![];
1905 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1906 let state_tree = ctx.state_manager.get_state_tree(ts.parent_state())?;
1907 state_tree.for_each(|addr, _state| {
1908 actors.push(addr);
1909 Ok(())
1910 })?;
1911 Ok(actors)
1912 }
1913}
1914
1915pub enum StateMarketStorageDeal {}
1916
1917impl RpcMethod<2> for StateMarketStorageDeal {
1918 const NAME: &'static str = "Filecoin.StateMarketStorageDeal";
1919 const PARAM_NAMES: [&'static str; 2] = ["dealId", "tipsetKey"];
1920 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1921 const PERMISSION: Permission = Permission::Read;
1922 const DESCRIPTION: Option<&'static str> = Some("Returns information about the specified deal.");
1923
1924 type Params = (DealID, ApiTipsetKey);
1925 type Ok = ApiMarketDeal;
1926
1927 async fn handle(
1928 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1929 (deal_id, ApiTipsetKey(tsk)): Self::Params,
1930 ) -> Result<Self::Ok, ServerError> {
1931 let store = ctx.store();
1932 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1933 let market_state: market::State = ctx.state_manager.get_actor_state(&ts)?;
1934 let proposals = market_state.proposals(store)?;
1935 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"))?;
1936
1937 let states = market_state.states(store)?;
1938 let state = states.get(deal_id)?.unwrap_or_else(DealState::empty);
1939
1940 Ok(MarketDeal { proposal, state }.into())
1941 }
1942}
1943
1944pub enum StateMarketParticipants {}
1945
1946impl RpcMethod<1> for StateMarketParticipants {
1947 const NAME: &'static str = "Filecoin.StateMarketParticipants";
1948 const PARAM_NAMES: [&'static str; 1] = ["tipsetKey"];
1949 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1950 const PERMISSION: Permission = Permission::Read;
1951 const DESCRIPTION: Option<&'static str> =
1952 Some("Returns the Escrow and Locked balances of all participants in the Storage Market.");
1953
1954 type Params = (ApiTipsetKey,);
1955 type Ok = HashMap<String, MarketBalance>;
1956
1957 async fn handle(
1958 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1959 (ApiTipsetKey(tsk),): Self::Params,
1960 ) -> Result<Self::Ok, ServerError> {
1961 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
1962 let market_state = ctx.state_manager.market_state(&ts)?;
1963 let escrow_table = market_state.escrow_table(ctx.store())?;
1964 let locked_table = market_state.locked_table(ctx.store())?;
1965 let mut result = HashMap::new();
1966 escrow_table.for_each(|address, escrow| {
1967 let locked = locked_table.get(address)?;
1968 result.insert(
1969 address.to_string(),
1970 MarketBalance {
1971 escrow: escrow.clone(),
1972 locked,
1973 },
1974 );
1975 Ok(())
1976 })?;
1977 Ok(result)
1978 }
1979}
1980
1981pub enum StateDealProviderCollateralBounds {}
1982
1983impl RpcMethod<3> for StateDealProviderCollateralBounds {
1984 const NAME: &'static str = "Filecoin.StateDealProviderCollateralBounds";
1985 const PARAM_NAMES: [&'static str; 3] = ["size", "verified", "tipsetKey"];
1986 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
1987 const PERMISSION: Permission = Permission::Read;
1988 const DESCRIPTION: Option<&'static str> = Some(
1989 "Returns the minimum and maximum collateral a storage provider can issue, based on deal size and verified status.",
1990 );
1991
1992 type Params = (u64, bool, ApiTipsetKey);
1993 type Ok = DealCollateralBounds;
1994
1995 async fn handle(
1996 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
1997 (size, verified, ApiTipsetKey(tsk)): Self::Params,
1998 ) -> Result<Self::Ok, ServerError> {
1999 let deal_provider_collateral_num = BigInt::from(110);
2000 let deal_provider_collateral_denom = BigInt::from(100);
2001
2002 let _: bool = verified;
2004
2005 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2006
2007 let power_state: power::State = ctx.state_manager.get_actor_state(&ts)?;
2008 let reward_state: reward::State = ctx.state_manager.get_actor_state(&ts)?;
2009
2010 let genesis_info = GenesisInfo::from_chain_config(ctx.chain_config().clone());
2011
2012 let supply = genesis_info.get_vm_circulating_supply(
2013 ts.epoch(),
2014 &ctx.store_owned(),
2015 ts.parent_state(),
2016 )?;
2017
2018 let power_claim = power_state.total_power();
2019
2020 let policy = &ctx.chain_config().policy;
2021
2022 let baseline_power = reward_state.this_epoch_baseline_power();
2023
2024 let (min, max) = reward_state.deal_provider_collateral_bounds(
2025 policy,
2026 size.into(),
2027 &power_claim.raw_byte_power,
2028 baseline_power,
2029 &supply,
2030 );
2031
2032 let min = min
2033 .atto()
2034 .mul(deal_provider_collateral_num)
2035 .div_euclid(&deal_provider_collateral_denom);
2036
2037 Ok(DealCollateralBounds {
2038 max,
2039 min: TokenAmount::from_atto(min),
2040 })
2041 }
2042}
2043
2044pub enum StateGetBeaconEntry {}
2045
2046impl RpcMethod<1> for StateGetBeaconEntry {
2047 const NAME: &'static str = "Filecoin.StateGetBeaconEntry";
2048 const PARAM_NAMES: [&'static str; 1] = ["epoch"];
2049 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2050 const PERMISSION: Permission = Permission::Read;
2051 const DESCRIPTION: Option<&'static str> =
2052 Some("Returns the beacon entries for the specified epoch.");
2053
2054 type Params = (ChainEpoch,);
2055 type Ok = BeaconEntry;
2056
2057 async fn handle(
2058 ctx: Ctx<impl Blockstore>,
2059 (epoch,): Self::Params,
2060 ) -> Result<Self::Ok, ServerError> {
2061 {
2062 let genesis_timestamp = ctx.chain_store().genesis_block_header().timestamp as i64;
2063 let block_delay = ctx.chain_config().block_delay_secs as i64;
2064 let epoch_timestamp = genesis_timestamp + block_delay * epoch + 1;
2066 let now_timestamp = chrono::Utc::now().timestamp();
2067 match epoch_timestamp.saturating_sub(now_timestamp) {
2068 diff if diff > 0 => {
2069 tokio::time::sleep(Duration::from_secs(diff as u64)).await;
2070 }
2071 _ => {}
2072 };
2073 }
2074
2075 let (_, beacon) = ctx.beacon().beacon_for_epoch(epoch)?;
2076 let network_version = ctx.state_manager.get_network_version(epoch);
2077 let round = beacon.max_beacon_round_for_epoch(network_version, epoch);
2078 let entry = beacon.entry(round).await?;
2079 Ok(entry)
2080 }
2081}
2082
2083pub enum StateSectorPreCommitInfoV0 {}
2084
2085impl RpcMethod<3> for StateSectorPreCommitInfoV0 {
2086 const NAME: &'static str = "Filecoin.StateSectorPreCommitInfo";
2087 const PARAM_NAMES: [&'static str; 3] = ["minerAddress", "sectorNumber", "tipsetKey"];
2088 const API_PATHS: BitFlags<ApiPaths> = make_bitflags!(ApiPaths::V0); const PERMISSION: Permission = Permission::Read;
2090
2091 type Params = (Address, u64, ApiTipsetKey);
2092 type Ok = SectorPreCommitOnChainInfo;
2093
2094 async fn handle(
2095 ctx: Ctx<impl Blockstore>,
2096 (miner_address, sector_number, ApiTipsetKey(tsk)): Self::Params,
2097 ) -> Result<Self::Ok, ServerError> {
2098 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2099 let state: miner::State = ctx
2100 .state_manager
2101 .get_actor_state_from_address(&ts, &miner_address)?;
2102 Ok(state
2103 .load_precommit_on_chain_info(ctx.store(), sector_number)?
2104 .context("precommit info does not exist")?)
2105 }
2106}
2107
2108pub enum StateSectorPreCommitInfo {}
2109
2110impl RpcMethod<3> for StateSectorPreCommitInfo {
2111 const NAME: &'static str = "Filecoin.StateSectorPreCommitInfo";
2112 const PARAM_NAMES: [&'static str; 3] = ["minerAddress", "sectorNumber", "tipsetKey"];
2113 const API_PATHS: BitFlags<ApiPaths> = make_bitflags!(ApiPaths::V1); const PERMISSION: Permission = Permission::Read;
2115 const DESCRIPTION: Option<&'static str> = Some(
2116 "Returns the PreCommit information for the specified miner's sector. Returns null if not precommitted.",
2117 );
2118
2119 type Params = (Address, u64, ApiTipsetKey);
2120 type Ok = Option<SectorPreCommitOnChainInfo>;
2121
2122 async fn handle(
2123 ctx: Ctx<impl Blockstore>,
2124 (miner_address, sector_number, ApiTipsetKey(tsk)): Self::Params,
2125 ) -> Result<Self::Ok, ServerError> {
2126 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2127 let state: miner::State = ctx
2128 .state_manager
2129 .get_actor_state_from_address(&ts, &miner_address)?;
2130 Ok(state.load_precommit_on_chain_info(ctx.store(), sector_number)?)
2131 }
2132}
2133
2134impl StateSectorPreCommitInfo {
2135 pub fn get_sectors(
2136 store: &Arc<impl Blockstore>,
2137 miner_address: &Address,
2138 tipset: &Tipset,
2139 ) -> anyhow::Result<Vec<u64>> {
2140 let mut sectors = vec![];
2141 let state_tree = StateTree::new_from_root(store.clone(), tipset.parent_state())?;
2142 let state: miner::State = state_tree.get_actor_state_from_address(miner_address)?;
2143 match &state {
2144 miner::State::V8(s) => {
2145 let precommitted = fil_actors_shared::v8::make_map_with_root::<
2146 _,
2147 fil_actor_miner_state::v8::SectorPreCommitOnChainInfo,
2148 >(&s.pre_committed_sectors, store)?;
2149 precommitted
2150 .for_each(|_k, v| {
2151 sectors.push(v.info.sector_number);
2152 Ok(())
2153 })
2154 .context("failed to iterate over precommitted sectors")
2155 }
2156 miner::State::V9(s) => {
2157 let precommitted = fil_actors_shared::v9::make_map_with_root::<
2158 _,
2159 fil_actor_miner_state::v9::SectorPreCommitOnChainInfo,
2160 >(&s.pre_committed_sectors, store)?;
2161 precommitted
2162 .for_each(|_k, v| {
2163 sectors.push(v.info.sector_number);
2164 Ok(())
2165 })
2166 .context("failed to iterate over precommitted sectors")
2167 }
2168 miner::State::V10(s) => {
2169 let precommitted = fil_actors_shared::v10::make_map_with_root::<
2170 _,
2171 fil_actor_miner_state::v10::SectorPreCommitOnChainInfo,
2172 >(&s.pre_committed_sectors, store)?;
2173 precommitted
2174 .for_each(|_k, v| {
2175 sectors.push(v.info.sector_number);
2176 Ok(())
2177 })
2178 .context("failed to iterate over precommitted sectors")
2179 }
2180 miner::State::V11(s) => {
2181 let precommitted = fil_actors_shared::v11::make_map_with_root::<
2182 _,
2183 fil_actor_miner_state::v11::SectorPreCommitOnChainInfo,
2184 >(&s.pre_committed_sectors, store)?;
2185 precommitted
2186 .for_each(|_k, v| {
2187 sectors.push(v.info.sector_number);
2188 Ok(())
2189 })
2190 .context("failed to iterate over precommitted sectors")
2191 }
2192 miner::State::V12(s) => {
2193 let precommitted = fil_actors_shared::v12::make_map_with_root::<
2194 _,
2195 fil_actor_miner_state::v12::SectorPreCommitOnChainInfo,
2196 >(&s.pre_committed_sectors, store)?;
2197 precommitted
2198 .for_each(|_k, v| {
2199 sectors.push(v.info.sector_number);
2200 Ok(())
2201 })
2202 .context("failed to iterate over precommitted sectors")
2203 }
2204 miner::State::V13(s) => {
2205 let precommitted = fil_actors_shared::v13::make_map_with_root::<
2206 _,
2207 fil_actor_miner_state::v13::SectorPreCommitOnChainInfo,
2208 >(&s.pre_committed_sectors, store)?;
2209 precommitted
2210 .for_each(|_k, v| {
2211 sectors.push(v.info.sector_number);
2212 Ok(())
2213 })
2214 .context("failed to iterate over precommitted sectors")
2215 }
2216 miner::State::V14(s) => {
2217 let precommitted = fil_actor_miner_state::v14::PreCommitMap::load(
2218 store,
2219 &s.pre_committed_sectors,
2220 fil_actor_miner_state::v14::PRECOMMIT_CONFIG,
2221 "precommits",
2222 )?;
2223 precommitted
2224 .for_each(|_k, v| {
2225 sectors.push(v.info.sector_number);
2226 Ok(())
2227 })
2228 .context("failed to iterate over precommitted sectors")
2229 }
2230 miner::State::V15(s) => {
2231 let precommitted = fil_actor_miner_state::v15::PreCommitMap::load(
2232 store,
2233 &s.pre_committed_sectors,
2234 fil_actor_miner_state::v15::PRECOMMIT_CONFIG,
2235 "precommits",
2236 )?;
2237 precommitted
2238 .for_each(|_k, v| {
2239 sectors.push(v.info.sector_number);
2240 Ok(())
2241 })
2242 .context("failed to iterate over precommitted sectors")
2243 }
2244 miner::State::V16(s) => {
2245 let precommitted = fil_actor_miner_state::v16::PreCommitMap::load(
2246 store,
2247 &s.pre_committed_sectors,
2248 fil_actor_miner_state::v16::PRECOMMIT_CONFIG,
2249 "precommits",
2250 )?;
2251 precommitted
2252 .for_each(|_k, v| {
2253 sectors.push(v.info.sector_number);
2254 Ok(())
2255 })
2256 .context("failed to iterate over precommitted sectors")
2257 }
2258 miner::State::V17(s) => {
2259 let precommitted = fil_actor_miner_state::v17::PreCommitMap::load(
2260 store,
2261 &s.pre_committed_sectors,
2262 fil_actor_miner_state::v17::PRECOMMIT_CONFIG,
2263 "precommits",
2264 )?;
2265 precommitted
2266 .for_each(|_k, v| {
2267 sectors.push(v.info.sector_number);
2268 Ok(())
2269 })
2270 .context("failed to iterate over precommitted sectors")
2271 }
2272 }?;
2273
2274 Ok(sectors)
2275 }
2276
2277 pub fn get_sector_pre_commit_infos(
2278 store: &Arc<impl Blockstore>,
2279 miner_address: &Address,
2280 tipset: &Tipset,
2281 ) -> anyhow::Result<Vec<SectorPreCommitInfo>> {
2282 let mut infos = vec![];
2283 let state_tree = StateTree::new_from_root(store.clone(), tipset.parent_state())?;
2284 let state: miner::State = state_tree.get_actor_state_from_address(miner_address)?;
2285 match &state {
2286 miner::State::V8(s) => {
2287 let precommitted = fil_actors_shared::v8::make_map_with_root::<
2288 _,
2289 fil_actor_miner_state::v8::SectorPreCommitOnChainInfo,
2290 >(&s.pre_committed_sectors, store)?;
2291 precommitted
2292 .for_each(|_k, v| {
2293 infos.push(v.info.clone().into());
2294 Ok(())
2295 })
2296 .context("failed to iterate over precommitted sectors")
2297 }
2298 miner::State::V9(s) => {
2299 let precommitted = fil_actors_shared::v9::make_map_with_root::<
2300 _,
2301 fil_actor_miner_state::v9::SectorPreCommitOnChainInfo,
2302 >(&s.pre_committed_sectors, store)?;
2303 precommitted
2304 .for_each(|_k, v| {
2305 infos.push(v.info.clone().into());
2306 Ok(())
2307 })
2308 .context("failed to iterate over precommitted sectors")
2309 }
2310 miner::State::V10(s) => {
2311 let precommitted = fil_actors_shared::v10::make_map_with_root::<
2312 _,
2313 fil_actor_miner_state::v10::SectorPreCommitOnChainInfo,
2314 >(&s.pre_committed_sectors, store)?;
2315 precommitted
2316 .for_each(|_k, v| {
2317 infos.push(v.info.clone().into());
2318 Ok(())
2319 })
2320 .context("failed to iterate over precommitted sectors")
2321 }
2322 miner::State::V11(s) => {
2323 let precommitted = fil_actors_shared::v11::make_map_with_root::<
2324 _,
2325 fil_actor_miner_state::v11::SectorPreCommitOnChainInfo,
2326 >(&s.pre_committed_sectors, store)?;
2327 precommitted
2328 .for_each(|_k, v| {
2329 infos.push(v.info.clone().into());
2330 Ok(())
2331 })
2332 .context("failed to iterate over precommitted sectors")
2333 }
2334 miner::State::V12(s) => {
2335 let precommitted = fil_actors_shared::v12::make_map_with_root::<
2336 _,
2337 fil_actor_miner_state::v12::SectorPreCommitOnChainInfo,
2338 >(&s.pre_committed_sectors, store)?;
2339 precommitted
2340 .for_each(|_k, v| {
2341 infos.push(v.info.clone().into());
2342 Ok(())
2343 })
2344 .context("failed to iterate over precommitted sectors")
2345 }
2346 miner::State::V13(s) => {
2347 let precommitted = fil_actors_shared::v13::make_map_with_root::<
2348 _,
2349 fil_actor_miner_state::v13::SectorPreCommitOnChainInfo,
2350 >(&s.pre_committed_sectors, store)?;
2351 precommitted
2352 .for_each(|_k, v| {
2353 infos.push(v.info.clone().into());
2354 Ok(())
2355 })
2356 .context("failed to iterate over precommitted sectors")
2357 }
2358 miner::State::V14(s) => {
2359 let precommitted = fil_actor_miner_state::v14::PreCommitMap::load(
2360 store,
2361 &s.pre_committed_sectors,
2362 fil_actor_miner_state::v14::PRECOMMIT_CONFIG,
2363 "precommits",
2364 )?;
2365 precommitted
2366 .for_each(|_k, v| {
2367 infos.push(v.info.clone().into());
2368 Ok(())
2369 })
2370 .context("failed to iterate over precommitted sectors")
2371 }
2372 miner::State::V15(s) => {
2373 let precommitted = fil_actor_miner_state::v15::PreCommitMap::load(
2374 store,
2375 &s.pre_committed_sectors,
2376 fil_actor_miner_state::v15::PRECOMMIT_CONFIG,
2377 "precommits",
2378 )?;
2379 precommitted
2380 .for_each(|_k, v| {
2381 infos.push(v.info.clone().into());
2382 Ok(())
2383 })
2384 .context("failed to iterate over precommitted sectors")
2385 }
2386 miner::State::V16(s) => {
2387 let precommitted = fil_actor_miner_state::v16::PreCommitMap::load(
2388 store,
2389 &s.pre_committed_sectors,
2390 fil_actor_miner_state::v16::PRECOMMIT_CONFIG,
2391 "precommits",
2392 )?;
2393 precommitted
2394 .for_each(|_k, v| {
2395 infos.push(v.info.clone().into());
2396 Ok(())
2397 })
2398 .context("failed to iterate over precommitted sectors")
2399 }
2400 miner::State::V17(s) => {
2401 let precommitted = fil_actor_miner_state::v17::PreCommitMap::load(
2402 store,
2403 &s.pre_committed_sectors,
2404 fil_actor_miner_state::v17::PRECOMMIT_CONFIG,
2405 "precommits",
2406 )?;
2407 precommitted
2408 .for_each(|_k, v| {
2409 infos.push(v.info.clone().into());
2410 Ok(())
2411 })
2412 .context("failed to iterate over precommitted sectors")
2413 }
2414 }?;
2415
2416 Ok(infos)
2417 }
2418}
2419
2420pub enum StateSectorGetInfo {}
2421
2422impl RpcMethod<3> for StateSectorGetInfo {
2423 const NAME: &'static str = "Filecoin.StateSectorGetInfo";
2424 const PARAM_NAMES: [&'static str; 3] = ["minerAddress", "sectorNumber", "tipsetKey"];
2425 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2426 const PERMISSION: Permission = Permission::Read;
2427 const DESCRIPTION: Option<&'static str> = Some(
2428 "Returns on-chain information for the specified miner's sector. Returns null if not found. Use StateSectorExpiration for accurate expiration epochs.",
2429 );
2430
2431 type Params = (Address, u64, ApiTipsetKey);
2432 type Ok = Option<SectorOnChainInfo>;
2433
2434 async fn handle(
2435 ctx: Ctx<impl Blockstore>,
2436 (miner_address, sector_number, ApiTipsetKey(tsk)): Self::Params,
2437 ) -> Result<Self::Ok, ServerError> {
2438 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2439 Ok(ctx
2440 .state_manager
2441 .get_all_sectors(&miner_address, &ts)?
2442 .into_iter()
2443 .find(|info| info.sector_number == sector_number))
2444 }
2445}
2446
2447impl StateSectorGetInfo {
2448 pub fn get_sectors(
2449 store: &Arc<impl Blockstore>,
2450 miner_address: &Address,
2451 tipset: &Tipset,
2452 ) -> anyhow::Result<Vec<u64>> {
2453 let state_tree = StateTree::new_from_root(store.clone(), tipset.parent_state())?;
2454 let state: miner::State = state_tree.get_actor_state_from_address(miner_address)?;
2455 Ok(state
2456 .load_sectors(store, None)?
2457 .into_iter()
2458 .map(|s| s.sector_number)
2459 .collect())
2460 }
2461}
2462
2463pub enum StateSectorExpiration {}
2464
2465impl RpcMethod<3> for StateSectorExpiration {
2466 const NAME: &'static str = "Filecoin.StateSectorExpiration";
2467 const PARAM_NAMES: [&'static str; 3] = ["minerAddress", "sectorNumber", "tipsetKey"];
2468 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2469 const PERMISSION: Permission = Permission::Read;
2470 const DESCRIPTION: Option<&'static str> =
2471 Some("Returns the epoch at which the specified sector will expire.");
2472
2473 type Params = (Address, u64, ApiTipsetKey);
2474 type Ok = SectorExpiration;
2475
2476 async fn handle(
2477 ctx: Ctx<impl Blockstore>,
2478 (miner_address, sector_number, ApiTipsetKey(tsk)): Self::Params,
2479 ) -> Result<Self::Ok, ServerError> {
2480 let store = ctx.store();
2481 let policy = &ctx.chain_config().policy;
2482 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2483 let state: miner::State = ctx
2484 .state_manager
2485 .get_actor_state_from_address(&ts, &miner_address)?;
2486 let mut early = 0;
2487 let mut on_time = 0;
2488 let mut terminated = false;
2489 state.for_each_deadline(policy, store, |_deadline_index, deadline| {
2490 deadline.for_each(store, |_partition_index, partition| {
2491 if !terminated && partition.all_sectors().get(sector_number) {
2492 if partition.terminated().get(sector_number) {
2493 terminated = true;
2494 early = 0;
2495 on_time = 0;
2496 return Ok(());
2497 }
2498 let expirations: Amt<fil_actor_miner_state::v16::ExpirationSet, _> =
2499 Amt::load(&partition.expirations_epochs(), store)?;
2500 expirations.for_each(|epoch, expiration| {
2501 if expiration.early_sectors.get(sector_number) {
2502 early = epoch as _;
2503 }
2504 if expiration.on_time_sectors.get(sector_number) {
2505 on_time = epoch as _;
2506 }
2507 Ok(())
2508 })?;
2509 }
2510
2511 Ok(())
2512 })?;
2513 Ok(())
2514 })?;
2515 if early == 0 && on_time == 0 {
2516 Err(anyhow::anyhow!("failed to find sector {sector_number}").into())
2517 } else {
2518 Ok(SectorExpiration { early, on_time })
2519 }
2520 }
2521}
2522
2523pub enum StateSectorPartition {}
2524
2525impl RpcMethod<3> for StateSectorPartition {
2526 const NAME: &'static str = "Filecoin.StateSectorPartition";
2527 const PARAM_NAMES: [&'static str; 3] = ["minerAddress", "sectorNumber", "tipsetKey"];
2528 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2529 const PERMISSION: Permission = Permission::Read;
2530 const DESCRIPTION: Option<&'static str> =
2531 Some("Finds the deadline/partition for the specified sector.");
2532
2533 type Params = (Address, u64, ApiTipsetKey);
2534 type Ok = SectorLocation;
2535
2536 async fn handle(
2537 ctx: Ctx<impl Blockstore>,
2538 (miner_address, sector_number, ApiTipsetKey(tsk)): Self::Params,
2539 ) -> Result<Self::Ok, ServerError> {
2540 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2541 let state: miner::State = ctx
2542 .state_manager
2543 .get_actor_state_from_address(&ts, &miner_address)?;
2544 let (deadline, partition) =
2545 state.find_sector(ctx.store(), sector_number, &ctx.chain_config().policy)?;
2546 Ok(SectorLocation {
2547 deadline,
2548 partition,
2549 })
2550 }
2551}
2552
2553pub enum StateListMessages {}
2555
2556impl RpcMethod<3> for StateListMessages {
2557 const NAME: &'static str = "Filecoin.StateListMessages";
2558 const PARAM_NAMES: [&'static str; 3] = ["messageFilter", "tipsetKey", "maxHeight"];
2559 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2560 const PERMISSION: Permission = Permission::Read;
2561 const DESCRIPTION: Option<&'static str> =
2562 Some("Returns all messages with a matching to or from address up to the given height.");
2563
2564 type Params = (MessageFilter, ApiTipsetKey, i64);
2565 type Ok = Vec<Cid>;
2566
2567 async fn handle(
2568 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
2569 (from_to, ApiTipsetKey(tsk), max_height): Self::Params,
2570 ) -> Result<Self::Ok, ServerError> {
2571 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2572 if from_to.is_empty() {
2573 return Err(ErrorObject::owned(
2574 1,
2575 "must specify at least To or From in message filter",
2576 Some(from_to),
2577 )
2578 .into());
2579 } else if let Some(to) = from_to.to {
2580 if ctx.state_manager.lookup_id(&to, &ts)?.is_none() {
2583 return Ok(vec![]);
2584 }
2585 } else if let Some(from) = from_to.from
2586 && ctx.state_manager.lookup_id(&from, &ts)?.is_none()
2587 {
2588 return Ok(vec![]);
2589 }
2590
2591 let mut out = Vec::new();
2592 let mut cur_ts = ts.clone();
2593
2594 while cur_ts.epoch() >= max_height {
2595 let msgs = ctx.chain_store().messages_for_tipset(&cur_ts)?;
2596
2597 for msg in msgs {
2598 if from_to.matches(msg.message()) {
2599 out.push(msg.cid());
2600 }
2601 }
2602
2603 if cur_ts.epoch() == 0 {
2604 break;
2605 }
2606
2607 let next = ctx.chain_index().load_required_tipset(cur_ts.parents())?;
2608 cur_ts = next;
2609 }
2610
2611 Ok(out)
2612 }
2613}
2614
2615pub enum StateGetClaim {}
2616
2617impl RpcMethod<3> for StateGetClaim {
2618 const NAME: &'static str = "Filecoin.StateGetClaim";
2619 const PARAM_NAMES: [&'static str; 3] = ["address", "claimId", "tipsetKey"];
2620 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2621 const PERMISSION: Permission = Permission::Read;
2622 const DESCRIPTION: Option<&'static str> =
2623 Some("Returns the claim for a given address and claim ID.");
2624
2625 type Params = (Address, ClaimID, ApiTipsetKey);
2626 type Ok = Option<Claim>;
2627
2628 async fn handle(
2629 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
2630 (address, claim_id, ApiTipsetKey(tsk)): Self::Params,
2631 ) -> Result<Self::Ok, ServerError> {
2632 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2633 Ok(ctx.state_manager.get_claim(&address, &ts, claim_id)?)
2634 }
2635}
2636
2637pub enum StateGetClaims {}
2638
2639impl RpcMethod<2> for StateGetClaims {
2640 const NAME: &'static str = "Filecoin.StateGetClaims";
2641 const PARAM_NAMES: [&'static str; 2] = ["address", "tipsetKey"];
2642 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2643 const PERMISSION: Permission = Permission::Read;
2644 const DESCRIPTION: Option<&'static str> = Some("Returns all claims for a given provider.");
2645
2646 type Params = (Address, ApiTipsetKey);
2647 type Ok = HashMap<ClaimID, Claim>;
2648
2649 async fn handle(
2650 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
2651 (address, ApiTipsetKey(tsk)): Self::Params,
2652 ) -> Result<Self::Ok, ServerError> {
2653 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2654 Ok(Self::get_claims(&ctx.store_owned(), &address, &ts)?)
2655 }
2656}
2657
2658impl StateGetClaims {
2659 pub fn get_claims(
2660 store: &Arc<impl Blockstore>,
2661 address: &Address,
2662 tipset: &Tipset,
2663 ) -> anyhow::Result<HashMap<ClaimID, Claim>> {
2664 let state_tree = StateTree::new_from_tipset(store.clone(), tipset)?;
2665 let state: verifreg::State = state_tree.get_actor_state()?;
2666 let actor_id = state_tree.lookup_required_id(address)?;
2667 let actor_id_address = Address::new_id(actor_id);
2668 state.get_claims(store, &actor_id_address)
2669 }
2670}
2671
2672pub enum StateGetAllClaims {}
2673
2674impl RpcMethod<1> for StateGetAllClaims {
2675 const NAME: &'static str = "Filecoin.StateGetAllClaims";
2676 const PARAM_NAMES: [&'static str; 1] = ["tipsetKey"];
2677 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2678 const PERMISSION: Permission = Permission::Read;
2679 const DESCRIPTION: Option<&'static str> =
2680 Some("Returns all claims available in the verified registry actor.");
2681
2682 type Params = (ApiTipsetKey,);
2683 type Ok = HashMap<ClaimID, Claim>;
2684
2685 async fn handle(
2686 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
2687 (ApiTipsetKey(tsk),): Self::Params,
2688 ) -> Result<Self::Ok, ServerError> {
2689 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2690 Ok(ctx.state_manager.get_all_claims(&ts)?)
2691 }
2692}
2693
2694pub enum StateGetAllocation {}
2695
2696impl RpcMethod<3> for StateGetAllocation {
2697 const NAME: &'static str = "Filecoin.StateGetAllocation";
2698 const PARAM_NAMES: [&'static str; 3] = ["address", "allocationId", "tipsetKey"];
2699 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2700 const PERMISSION: Permission = Permission::Read;
2701 const DESCRIPTION: Option<&'static str> =
2702 Some("Returns the allocation for a given address and allocation ID.");
2703
2704 type Params = (Address, AllocationID, ApiTipsetKey);
2705 type Ok = Option<Allocation>;
2706
2707 async fn handle(
2708 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
2709 (address, allocation_id, ApiTipsetKey(tsk)): Self::Params,
2710 ) -> Result<Self::Ok, ServerError> {
2711 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2712 Ok(ctx
2713 .state_manager
2714 .get_allocation(&address, &ts, allocation_id)?)
2715 }
2716}
2717
2718pub enum StateGetAllocations {}
2719
2720impl RpcMethod<2> for StateGetAllocations {
2721 const NAME: &'static str = "Filecoin.StateGetAllocations";
2722 const PARAM_NAMES: [&'static str; 2] = ["address", "tipsetKey"];
2723 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2724 const PERMISSION: Permission = Permission::Read;
2725 const DESCRIPTION: Option<&'static str> = Some("Returns all allocations for a given client.");
2726
2727 type Params = (Address, ApiTipsetKey);
2728 type Ok = HashMap<AllocationID, Allocation>;
2729
2730 async fn handle(
2731 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
2732 (address, ApiTipsetKey(tsk)): Self::Params,
2733 ) -> Result<Self::Ok, ServerError> {
2734 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2735 Ok(Self::get_allocations(&ctx.store_owned(), &address, &ts)?)
2736 }
2737}
2738
2739impl StateGetAllocations {
2740 pub fn get_valid_actor_addresses<'a>(
2742 store: &'a Arc<impl Blockstore>,
2743 tipset: &'a Tipset,
2744 ) -> anyhow::Result<impl Iterator<Item = Address> + 'a> {
2745 let mut addresses = HashSet::default();
2746 let state_tree = StateTree::new_from_tipset(store.clone(), tipset)?;
2747 let verifreg_state: verifreg::State = state_tree.get_actor_state()?;
2748 match verifreg_state {
2749 verifreg::State::V13(s) => {
2750 let map = s.load_allocs(store)?;
2751 map.for_each(|k, _| {
2752 let actor_id = fil_actors_shared::v13::parse_uint_key(k)?;
2753 addresses.insert(Address::new_id(actor_id));
2754 Ok(())
2755 })?;
2756 }
2757 verifreg::State::V12(s) => {
2758 let map = s.load_allocs(store)?;
2759 map.for_each(|k, _| {
2760 let actor_id = fil_actors_shared::v12::parse_uint_key(k)?;
2761 addresses.insert(Address::new_id(actor_id));
2762 Ok(())
2763 })?;
2764 }
2765 _ => (),
2766 };
2767
2768 if addresses.is_empty() {
2769 let init_state: init::State = state_tree.get_actor_state()?;
2770 match init_state {
2771 init::State::V0(_) => {
2772 anyhow::bail!("StateGetAllocations is not implemented for init state v0");
2773 }
2774 init::State::V8(s) => {
2775 let map =
2776 fil_actors_shared::v8::make_map_with_root::<_, u64>(&s.address_map, store)?;
2777 map.for_each(|_k, v| {
2778 addresses.insert(Address::new_id(*v));
2779 Ok(())
2780 })?;
2781 }
2782 init::State::V9(s) => {
2783 let map =
2784 fil_actors_shared::v9::make_map_with_root::<_, u64>(&s.address_map, store)?;
2785 map.for_each(|_k, v| {
2786 addresses.insert(Address::new_id(*v));
2787 Ok(())
2788 })?;
2789 }
2790 init::State::V10(s) => {
2791 let map = fil_actors_shared::v10::make_map_with_root::<_, u64>(
2792 &s.address_map,
2793 store,
2794 )?;
2795 map.for_each(|_k, v| {
2796 addresses.insert(Address::new_id(*v));
2797 Ok(())
2798 })?;
2799 }
2800 init::State::V11(s) => {
2801 let map = fil_actors_shared::v11::make_map_with_root::<_, u64>(
2802 &s.address_map,
2803 store,
2804 )?;
2805 map.for_each(|_k, v| {
2806 addresses.insert(Address::new_id(*v));
2807 Ok(())
2808 })?;
2809 }
2810 init::State::V12(s) => {
2811 let map = fil_actors_shared::v12::make_map_with_root::<_, u64>(
2812 &s.address_map,
2813 store,
2814 )?;
2815 map.for_each(|_k, v| {
2816 addresses.insert(Address::new_id(*v));
2817 Ok(())
2818 })?;
2819 }
2820 init::State::V13(s) => {
2821 let map = fil_actors_shared::v13::make_map_with_root::<_, u64>(
2822 &s.address_map,
2823 store,
2824 )?;
2825 map.for_each(|_k, v| {
2826 addresses.insert(Address::new_id(*v));
2827 Ok(())
2828 })?;
2829 }
2830 init::State::V14(s) => {
2831 let map = fil_actor_init_state::v14::AddressMap::load(
2832 store,
2833 &s.address_map,
2834 fil_actors_shared::v14::DEFAULT_HAMT_CONFIG,
2835 "address_map",
2836 )?;
2837 map.for_each(|_k, v| {
2838 addresses.insert(Address::new_id(*v));
2839 Ok(())
2840 })?;
2841 }
2842 init::State::V15(s) => {
2843 let map = fil_actor_init_state::v15::AddressMap::load(
2844 store,
2845 &s.address_map,
2846 fil_actors_shared::v15::DEFAULT_HAMT_CONFIG,
2847 "address_map",
2848 )?;
2849 map.for_each(|_k, v| {
2850 addresses.insert(Address::new_id(*v));
2851 Ok(())
2852 })?;
2853 }
2854 init::State::V16(s) => {
2855 let map = fil_actor_init_state::v16::AddressMap::load(
2856 store,
2857 &s.address_map,
2858 fil_actors_shared::v16::DEFAULT_HAMT_CONFIG,
2859 "address_map",
2860 )?;
2861 map.for_each(|_k, v| {
2862 addresses.insert(Address::new_id(*v));
2863 Ok(())
2864 })?;
2865 }
2866 init::State::V17(s) => {
2867 let map = fil_actor_init_state::v17::AddressMap::load(
2868 store,
2869 &s.address_map,
2870 fil_actors_shared::v17::DEFAULT_HAMT_CONFIG,
2871 "address_map",
2872 )?;
2873 map.for_each(|_k, v| {
2874 addresses.insert(Address::new_id(*v));
2875 Ok(())
2876 })?;
2877 }
2878 };
2879 }
2880
2881 Ok(addresses
2882 .into_iter()
2883 .filter(|addr| match Self::get_allocations(store, addr, tipset) {
2884 Ok(r) => !r.is_empty(),
2885 _ => false,
2886 }))
2887 }
2888
2889 pub fn get_allocations(
2890 store: &Arc<impl Blockstore>,
2891 address: &Address,
2892 tipset: &Tipset,
2893 ) -> anyhow::Result<HashMap<AllocationID, Allocation>> {
2894 let state_tree = StateTree::new_from_tipset(store.clone(), tipset)?;
2895 let state: verifreg::State = state_tree.get_actor_state()?;
2896 state.get_allocations(store, address)
2897 }
2898}
2899
2900pub enum StateGetAllAllocations {}
2901
2902impl RpcMethod<1> for crate::rpc::prelude::StateGetAllAllocations {
2903 const NAME: &'static str = "Filecoin.StateGetAllAllocations";
2904 const PARAM_NAMES: [&'static str; 1] = ["tipsetKey"];
2905 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2906 const PERMISSION: Permission = Permission::Read;
2907 const DESCRIPTION: Option<&'static str> =
2908 Some("Returns all allocations available in the verified registry actor.");
2909
2910 type Params = (ApiTipsetKey,);
2911 type Ok = HashMap<AllocationID, Allocation>;
2912
2913 async fn handle(
2914 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
2915 (ApiTipsetKey(tsk),): Self::Params,
2916 ) -> Result<Self::Ok, ServerError> {
2917 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2918 Ok(ctx.state_manager.get_all_allocations(&ts)?)
2919 }
2920}
2921
2922pub enum StateGetAllocationIdForPendingDeal {}
2923
2924impl RpcMethod<2> for StateGetAllocationIdForPendingDeal {
2925 const NAME: &'static str = "Filecoin.StateGetAllocationIdForPendingDeal";
2926 const PARAM_NAMES: [&'static str; 2] = ["dealId", "tipsetKey"];
2927 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2928 const PERMISSION: Permission = Permission::Read;
2929 const DESCRIPTION: Option<&'static str> =
2930 Some("Returns the allocation ID for the specified pending deal.");
2931
2932 type Params = (DealID, ApiTipsetKey);
2933 type Ok = AllocationID;
2934
2935 async fn handle(
2936 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
2937 (deal_id, ApiTipsetKey(tsk)): Self::Params,
2938 ) -> Result<Self::Ok, ServerError> {
2939 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
2940 let state_tree = StateTree::new_from_tipset(ctx.store_owned(), &ts)?;
2941 let market_state: market::State = state_tree.get_actor_state()?;
2942 Ok(market_state.get_allocation_id_for_pending_deal(ctx.store(), &deal_id)?)
2943 }
2944}
2945
2946impl StateGetAllocationIdForPendingDeal {
2947 pub fn get_allocations_for_pending_deals(
2948 store: &Arc<impl Blockstore>,
2949 tipset: &Tipset,
2950 ) -> anyhow::Result<HashMap<DealID, AllocationID>> {
2951 let state_tree = StateTree::new_from_tipset(store.clone(), tipset)?;
2952 let state: market::State = state_tree.get_actor_state()?;
2953 state.get_allocations_for_pending_deals(store)
2954 }
2955}
2956
2957pub enum StateGetAllocationForPendingDeal {}
2958
2959impl RpcMethod<2> for StateGetAllocationForPendingDeal {
2960 const NAME: &'static str = "Filecoin.StateGetAllocationForPendingDeal";
2961 const PARAM_NAMES: [&'static str; 2] = ["dealId", "tipsetKey"];
2962 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2963 const PERMISSION: Permission = Permission::Read;
2964 const DESCRIPTION: Option<&'static str> = Some(
2965 "Returns the allocation for the specified pending deal. Returns null if no pending allocation is found.",
2966 );
2967
2968 type Params = (DealID, ApiTipsetKey);
2969 type Ok = Option<Allocation>;
2970
2971 async fn handle(
2972 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
2973 (deal_id, tsk): Self::Params,
2974 ) -> Result<Self::Ok, ServerError> {
2975 let allocation_id =
2976 StateGetAllocationIdForPendingDeal::handle(ctx.clone(), (deal_id, tsk.clone())).await?;
2977 if allocation_id == fil_actor_market_state::v14::NO_ALLOCATION_ID {
2978 return Ok(None);
2979 }
2980 let deal = StateMarketStorageDeal::handle(ctx.clone(), (deal_id, tsk.clone())).await?;
2981 StateGetAllocation::handle(ctx.clone(), (deal.proposal.client, allocation_id, tsk)).await
2982 }
2983}
2984
2985pub enum StateGetNetworkParams {}
2986
2987impl RpcMethod<0> for StateGetNetworkParams {
2988 const NAME: &'static str = "Filecoin.StateGetNetworkParams";
2989 const PARAM_NAMES: [&'static str; 0] = [];
2990 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
2991 const PERMISSION: Permission = Permission::Read;
2992 const DESCRIPTION: Option<&'static str> = Some("Returns current network parameters.");
2993
2994 type Params = ();
2995 type Ok = NetworkParams;
2996
2997 async fn handle(
2998 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
2999 (): Self::Params,
3000 ) -> Result<Self::Ok, ServerError> {
3001 let config = ctx.chain_config().as_ref();
3002 let heaviest_tipset = ctx.chain_store().heaviest_tipset();
3003 let network_name = ctx
3004 .state_manager
3005 .get_network_state_name(*heaviest_tipset.parent_state())?
3006 .into();
3007 let policy = &config.policy;
3008
3009 let params = NetworkParams {
3010 network_name,
3011 block_delay_secs: config.block_delay_secs as u64,
3012 consensus_miner_min_power: policy.minimum_consensus_power.clone(),
3013 pre_commit_challenge_delay: policy.pre_commit_challenge_delay,
3014 fork_upgrade_params: ForkUpgradeParams::try_from(config)
3015 .context("Failed to get fork upgrade params")?,
3016 eip155_chain_id: config.eth_chain_id,
3017 };
3018
3019 Ok(params)
3020 }
3021}
3022
3023#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
3024#[serde(rename_all = "PascalCase")]
3025pub struct NetworkParams {
3026 network_name: String,
3027 block_delay_secs: u64,
3028 #[schemars(with = "crate::lotus_json::LotusJson<BigInt>")]
3029 #[serde(with = "crate::lotus_json")]
3030 consensus_miner_min_power: BigInt,
3031 pre_commit_challenge_delay: ChainEpoch,
3032 fork_upgrade_params: ForkUpgradeParams,
3033 #[serde(rename = "Eip155ChainID")]
3034 eip155_chain_id: EthChainId,
3035}
3036
3037lotus_json_with_self!(NetworkParams);
3038
3039#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
3040#[serde(rename_all = "PascalCase")]
3041pub struct ForkUpgradeParams {
3042 upgrade_smoke_height: ChainEpoch,
3043 upgrade_breeze_height: ChainEpoch,
3044 upgrade_ignition_height: ChainEpoch,
3045 upgrade_liftoff_height: ChainEpoch,
3046 upgrade_assembly_height: ChainEpoch,
3047 upgrade_refuel_height: ChainEpoch,
3048 upgrade_tape_height: ChainEpoch,
3049 upgrade_kumquat_height: ChainEpoch,
3050 breeze_gas_tamping_duration: ChainEpoch,
3051 upgrade_calico_height: ChainEpoch,
3052 upgrade_persian_height: ChainEpoch,
3053 upgrade_orange_height: ChainEpoch,
3054 upgrade_claus_height: ChainEpoch,
3055 upgrade_trust_height: ChainEpoch,
3056 upgrade_norwegian_height: ChainEpoch,
3057 upgrade_turbo_height: ChainEpoch,
3058 upgrade_hyperdrive_height: ChainEpoch,
3059 upgrade_chocolate_height: ChainEpoch,
3060 upgrade_oh_snap_height: ChainEpoch,
3061 upgrade_skyr_height: ChainEpoch,
3062 upgrade_shark_height: ChainEpoch,
3063 upgrade_hygge_height: ChainEpoch,
3064 upgrade_lightning_height: ChainEpoch,
3065 upgrade_thunder_height: ChainEpoch,
3066 upgrade_watermelon_height: ChainEpoch,
3067 upgrade_dragon_height: ChainEpoch,
3068 upgrade_phoenix_height: ChainEpoch,
3069 upgrade_waffle_height: ChainEpoch,
3070 upgrade_tuktuk_height: ChainEpoch,
3071 upgrade_teep_height: ChainEpoch,
3072 upgrade_tock_height: ChainEpoch,
3073 }
3075
3076impl TryFrom<&ChainConfig> for ForkUpgradeParams {
3077 type Error = anyhow::Error;
3078 fn try_from(config: &ChainConfig) -> anyhow::Result<Self> {
3079 let height_infos = &config.height_infos;
3080 let get_height = |height| -> anyhow::Result<ChainEpoch> {
3081 let height = height_infos
3082 .get(&height)
3083 .context(format!("Height info for {height} not found"))?
3084 .epoch;
3085 Ok(height)
3086 };
3087
3088 use crate::networks::Height::*;
3089 Ok(ForkUpgradeParams {
3090 upgrade_smoke_height: get_height(Smoke)?,
3091 upgrade_breeze_height: get_height(Breeze)?,
3092 upgrade_ignition_height: get_height(Ignition)?,
3093 upgrade_liftoff_height: get_height(Liftoff)?,
3094 upgrade_assembly_height: get_height(Assembly)?,
3095 upgrade_refuel_height: get_height(Refuel)?,
3096 upgrade_tape_height: get_height(Tape)?,
3097 upgrade_kumquat_height: get_height(Kumquat)?,
3098 breeze_gas_tamping_duration: config.breeze_gas_tamping_duration,
3099 upgrade_calico_height: get_height(Calico)?,
3100 upgrade_persian_height: get_height(Persian)?,
3101 upgrade_orange_height: get_height(Orange)?,
3102 upgrade_claus_height: get_height(Claus)?,
3103 upgrade_trust_height: get_height(Trust)?,
3104 upgrade_norwegian_height: get_height(Norwegian)?,
3105 upgrade_turbo_height: get_height(Turbo)?,
3106 upgrade_hyperdrive_height: get_height(Hyperdrive)?,
3107 upgrade_chocolate_height: get_height(Chocolate)?,
3108 upgrade_oh_snap_height: get_height(OhSnap)?,
3109 upgrade_skyr_height: get_height(Skyr)?,
3110 upgrade_shark_height: get_height(Shark)?,
3111 upgrade_hygge_height: get_height(Hygge)?,
3112 upgrade_lightning_height: get_height(Lightning)?,
3113 upgrade_thunder_height: get_height(Thunder)?,
3114 upgrade_watermelon_height: get_height(Watermelon)?,
3115 upgrade_dragon_height: get_height(Dragon)?,
3116 upgrade_phoenix_height: get_height(Phoenix)?,
3117 upgrade_waffle_height: get_height(Waffle)?,
3118 upgrade_tuktuk_height: get_height(TukTuk)?,
3119 upgrade_teep_height: get_height(Teep)?,
3120 upgrade_tock_height: get_height(Tock)?,
3121 })
3123 }
3124}
3125
3126pub enum StateMinerInitialPledgeForSector {}
3127impl RpcMethod<4> for StateMinerInitialPledgeForSector {
3128 const NAME: &'static str = "Filecoin.StateMinerInitialPledgeForSector";
3129 const PARAM_NAMES: [&'static str; 4] = [
3130 "sector_duration",
3131 "sector_size",
3132 "verified_size",
3133 "tipset_key",
3134 ];
3135 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
3136 const PERMISSION: Permission = Permission::Read;
3137
3138 type Params = (ChainEpoch, SectorSize, u64, ApiTipsetKey);
3139 type Ok = TokenAmount;
3140
3141 async fn handle(
3142 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
3143 (sector_duration, sector_size, verified_size, ApiTipsetKey(tsk)): Self::Params,
3144 ) -> Result<Self::Ok, ServerError> {
3145 if sector_duration <= 0 {
3146 return Err(anyhow::anyhow!("sector duration must be greater than 0").into());
3147 }
3148 if verified_size > sector_size as u64 {
3149 return Err(
3150 anyhow::anyhow!("verified deal size cannot be larger than sector size").into(),
3151 );
3152 }
3153
3154 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
3155
3156 let power_state: power::State = ctx.state_manager.get_actor_state(&ts)?;
3157 let power_smoothed = power_state.total_power_smoothed();
3158 let pledge_collateral = power_state.total_locked();
3159
3160 let reward_state: reward::State = ctx.state_manager.get_actor_state(&ts)?;
3161
3162 let genesis_info = GenesisInfo::from_chain_config(ctx.chain_config().clone());
3163 let circ_supply = genesis_info.get_vm_circulating_supply_detailed(
3164 ts.epoch(),
3165 &ctx.store_owned(),
3166 ts.parent_state(),
3167 )?;
3168
3169 let deal_weight = BigInt::from(0);
3170 let verified_deal_weight = BigInt::from(verified_size) * sector_duration;
3171 let sector_weight = qa_power_for_weight(
3172 sector_size.into(),
3173 sector_duration,
3174 &deal_weight,
3175 &verified_deal_weight,
3176 );
3177
3178 let (epochs_since_start, duration) = get_pledge_ramp_params(&ctx, ts.epoch(), &ts)?;
3179
3180 let initial_pledge = reward_state.initial_pledge_for_power(
3181 §or_weight,
3182 pledge_collateral,
3183 power_smoothed,
3184 &circ_supply.fil_circulating,
3185 epochs_since_start,
3186 duration,
3187 )?;
3188
3189 let (value, _) = (initial_pledge * INITIAL_PLEDGE_NUM).div_rem(INITIAL_PLEDGE_DEN);
3190 Ok(value)
3191 }
3192}
3193
3194fn get_pledge_ramp_params(
3195 ctx: &Ctx<impl Blockstore + Send + Sync + 'static>,
3196 height: ChainEpoch,
3197 ts: &Tipset,
3198) -> Result<(ChainEpoch, u64), anyhow::Error> {
3199 let state_tree = ctx.state_manager.get_state_tree(ts.parent_state())?;
3200
3201 let power_state: power::State = state_tree
3202 .get_actor_state()
3203 .context("loading power actor state")?;
3204
3205 if power_state.ramp_start_epoch() > 0 {
3206 Ok((
3207 height - power_state.ramp_start_epoch(),
3208 power_state.ramp_duration_epochs(),
3209 ))
3210 } else {
3211 Ok((0, 0))
3212 }
3213}
3214
3215#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
3216#[serde(rename_all = "PascalCase")]
3217pub struct StateActorCodeCidsOutput {
3218 pub network_version: NetworkVersion,
3219 pub network_version_revision: i64,
3220 pub actor_version: String,
3221 #[serde(with = "crate::lotus_json")]
3222 #[schemars(with = "LotusJson<Cid>")]
3223 pub manifest: Cid,
3224 #[serde(with = "crate::lotus_json")]
3225 #[schemars(with = "LotusJson<Cid>")]
3226 pub bundle: Cid,
3227 #[serde(with = "crate::lotus_json")]
3228 #[schemars(with = "LotusJson<HashMap<String, Cid>>")]
3229 pub actor_cids: HashMap<String, Cid>,
3230}
3231lotus_json_with_self!(StateActorCodeCidsOutput);
3232
3233impl std::fmt::Display for StateActorCodeCidsOutput {
3234 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3235 writeln!(f, "Network Version: {}", self.network_version)?;
3236 writeln!(
3237 f,
3238 "Network Version Revision: {}",
3239 self.network_version_revision
3240 )?;
3241 writeln!(f, "Actor Version: {}", self.actor_version)?;
3242 writeln!(f, "Manifest CID: {}", self.manifest)?;
3243 writeln!(f, "Bundle CID: {}", self.bundle)?;
3244 writeln!(f, "Actor CIDs:")?;
3245 let longest_name = self
3246 .actor_cids
3247 .keys()
3248 .map(|name| name.len())
3249 .max()
3250 .unwrap_or(0);
3251 for (name, cid) in &self.actor_cids {
3252 writeln!(f, " {:width$} : {}", name, cid, width = longest_name)?;
3253 }
3254 Ok(())
3255 }
3256}
3257
3258pub enum StateActorInfo {}
3259
3260impl RpcMethod<0> for StateActorInfo {
3261 const NAME: &'static str = "Forest.StateActorInfo";
3262 const PARAM_NAMES: [&'static str; 0] = [];
3263 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
3264 const PERMISSION: Permission = Permission::Read;
3265 const DESCRIPTION: Option<&'static str> =
3266 Some("Returns the builtin actor information for the current network.");
3267
3268 type Params = ();
3269 type Ok = StateActorCodeCidsOutput;
3270
3271 async fn handle(
3272 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
3273 (): Self::Params,
3274 ) -> Result<Self::Ok, ServerError> {
3275 let ts = ctx.chain_store().load_required_tipset_or_heaviest(None)?;
3276 let state_tree = StateTree::new_from_tipset(ctx.store_owned(), &ts)?;
3277 let bundle = state_tree.get_actor_bundle_metadata()?;
3278 let system_state: system::State = state_tree.get_actor_state()?;
3279 let actors = system_state.builtin_actors_cid();
3280
3281 let current_manifest = BuiltinActorManifest::load_v1_actor_list(ctx.store(), actors)?;
3282
3283 if current_manifest != bundle.manifest {
3286 return Err(anyhow::anyhow!("Actor bundle manifest does not match the manifest in the state tree. This indicates that the node is misconfigured or is running an unsupported network.")
3287 .into());
3288 }
3289
3290 let network_version = ctx.chain_config().network_version(ts.epoch() - 1);
3291 let network_version_revision = ctx.chain_config().network_version_revision(ts.epoch() - 1);
3292 let result = StateActorCodeCidsOutput {
3293 network_version,
3294 network_version_revision,
3295 actor_version: bundle.version.to_owned(),
3296 manifest: current_manifest.actor_list_cid,
3297 bundle: bundle.bundle_cid,
3298 actor_cids: current_manifest
3299 .builtin_actors()
3300 .map(|(a, c)| (a.name().to_string(), c))
3301 .collect(),
3302 };
3303
3304 Ok(result)
3305 }
3306}