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(
26 ctx: Ctx<impl Blockstore>,
27 (): Self::Params,
28 _: &http::Extensions,
29 ) -> Result<Self::Ok, ServerError> {
30 let mut node_status = NodeStatusResult::default();
31
32 let head = ctx.chain_store().heaviest_tipset();
33 let cur_duration: Duration = SystemTime::now().duration_since(UNIX_EPOCH)?;
34
35 let ts = head.min_timestamp();
36 let cur_duration_secs = cur_duration.as_secs();
37 let behind = if ts <= cur_duration_secs + 1 {
38 cur_duration_secs.saturating_sub(ts)
39 } else {
40 return Err(anyhow::anyhow!(
41 "System time should not be behind tipset timestamp, please sync the system clock."
42 )
43 .into());
44 };
45
46 let chain_finality = ctx.chain_config().policy.chain_finality;
47
48 node_status.sync_status.epoch = head.epoch() as u64;
49 node_status.sync_status.behind = behind;
50
51 if head.epoch() > chain_finality {
52 let mut block_count = 0;
53 let mut ts = head;
54
55 for _ in 0..100 {
56 block_count += ts.block_headers().len();
57 let tsk = ts.parents();
58 ts = ctx.chain_index().load_required_tipset(tsk)?;
59 }
60
61 node_status.chain_status.blocks_per_tipset_last_100 = block_count as f64 / 100.;
62
63 for _ in 100..chain_finality {
64 block_count += ts.block_headers().len();
65 let tsk = ts.parents();
66 ts = ctx.chain_index().load_required_tipset(tsk)?;
67 }
68
69 node_status.chain_status.blocks_per_tipset_last_finality =
70 block_count as f64 / chain_finality as f64;
71 }
72
73 Ok(node_status)
74 }
75}
76
77#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, Clone, JsonSchema)]
78pub struct NodeSyncStatus {
79 pub epoch: u64,
80 pub behind: u64,
81}
82lotus_json_with_self!(NodeSyncStatus);
83
84#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default, Clone, JsonSchema)]
85pub struct NodePeerStatus {
86 pub peers_to_publish_msgs: u32,
87 pub peers_to_publish_blocks: u32,
88}
89lotus_json_with_self!(NodePeerStatus);
90
91#[derive(Debug, PartialEq, Serialize, Deserialize, Default, Clone, JsonSchema)]
92pub struct NodeChainStatus {
93 pub blocks_per_tipset_last_100: f64,
94 pub blocks_per_tipset_last_finality: f64,
95}
96lotus_json_with_self!(NodeChainStatus);
97
98#[derive(Debug, Deserialize, Default, Serialize, Clone, JsonSchema, PartialEq)]
99pub struct NodeStatusResult {
100 pub sync_status: NodeSyncStatus,
101 pub peer_status: NodePeerStatus,
102 pub chain_status: NodeChainStatus,
103}
104lotus_json_with_self!(NodeStatusResult);