forest/rpc/methods/
node.rs1use std::time::{Duration, SystemTime, UNIX_EPOCH};
5
6use crate::{
7 lotus_json::lotus_json_with_self,
8 rpc::{ApiPaths, Ctx, Permission, RpcMethod, ServerError},
9};
10use enumflags2::BitFlags;
11use fvm_ipld_blockstore::Blockstore;
12use schemars::JsonSchema;
13use serde::{Deserialize, Serialize};
14
15pub enum NodeStatus {}
16impl RpcMethod<0> for NodeStatus {
17 const NAME: &'static str = "Filecoin.NodeStatus";
18 const PARAM_NAMES: [&'static str; 0] = [];
19 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
20 const PERMISSION: Permission = Permission::Read;
21
22 type Params = ();
23 type Ok = NodeStatusResult;
24
25 async fn handle(ctx: Ctx<impl Blockstore>, (): Self::Params) -> Result<Self::Ok, ServerError> {
26 let mut node_status = NodeStatusResult::default();
27
28 let head = ctx.chain_store().heaviest_tipset();
29 let cur_duration: Duration = SystemTime::now().duration_since(UNIX_EPOCH)?;
30
31 let ts = head.min_timestamp();
32 let cur_duration_secs = cur_duration.as_secs();
33 let behind = if ts <= cur_duration_secs + 1 {
34 cur_duration_secs.saturating_sub(ts)
35 } else {
36 return Err(anyhow::anyhow!(
37 "System time should not be behind tipset timestamp, please sync the system clock."
38 )
39 .into());
40 };
41
42 let chain_finality = ctx.chain_config().policy.chain_finality;
43
44 node_status.sync_status.epoch = head.epoch() as u64;
45 node_status.sync_status.behind = behind;
46
47 if head.epoch() > chain_finality {
48 let mut block_count = 0;
49 let mut ts = head;
50
51 for _ in 0..100 {
52 block_count += ts.block_headers().len();
53 let tsk = ts.parents();
54 ts = ctx.chain_index().load_required_tipset(tsk)?;
55 }
56
57 node_status.chain_status.blocks_per_tipset_last_100 = block_count as f64 / 100.;
58
59 for _ in 100..chain_finality {
60 block_count += ts.block_headers().len();
61 let tsk = ts.parents();
62 ts = ctx.chain_index().load_required_tipset(tsk)?;
63 }
64
65 node_status.chain_status.blocks_per_tipset_last_finality =
66 block_count as f64 / chain_finality as f64;
67 }
68
69 Ok(node_status)
70 }
71}
72
73#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, Clone, JsonSchema)]
74pub struct NodeSyncStatus {
75 pub epoch: u64,
76 pub behind: u64,
77}
78lotus_json_with_self!(NodeSyncStatus);
79
80#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, Clone, JsonSchema)]
81pub struct NodePeerStatus {
82 pub peers_to_publish_msgs: u32,
83 pub peers_to_publish_blocks: u32,
84}
85lotus_json_with_self!(NodePeerStatus);
86
87#[derive(Debug, PartialEq, Serialize, Deserialize, Default, Clone, JsonSchema)]
88pub struct NodeChainStatus {
89 pub blocks_per_tipset_last_100: f64,
90 pub blocks_per_tipset_last_finality: f64,
91}
92lotus_json_with_self!(NodeChainStatus);
93
94#[derive(Debug, Deserialize, Default, Serialize, Clone, JsonSchema, PartialEq)]
95pub struct NodeStatusResult {
96 pub sync_status: NodeSyncStatus,
97 pub peer_status: NodePeerStatus,
98 pub chain_status: NodeChainStatus,
99}
100lotus_json_with_self!(NodeStatusResult);