1use std::{
2 collections::BTreeMap,
3 net::{IpAddr, Ipv4Addr, SocketAddr},
4 time::Duration,
5};
6
7use once_cell::sync::Lazy;
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10
11use casper_binary_port::ConsensusStatus;
12use casper_types::{
13 ActivationPoint, AvailableBlockRange, Block, BlockHash, BlockSynchronizerStatus, Digest, EraId,
14 NextUpgrade, Peers, ProtocolVersion, PublicKey, TimeDiff, Timestamp,
15};
16
17use crate::{
18 components::rest_server::{DocExample, DOCS_EXAMPLE_PROTOCOL_VERSION},
19 reactor::main_reactor::ReactorState,
20 types::NodeId,
21};
22
23static CHAINSPEC_INFO: Lazy<ChainspecInfo> = Lazy::new(|| {
24 let next_upgrade = NextUpgrade::new(
25 ActivationPoint::EraId(EraId::from(42)),
26 ProtocolVersion::from_parts(2, 0, 1),
27 );
28 ChainspecInfo {
29 name: String::from("casper-example"),
30 next_upgrade: Some(next_upgrade),
31 }
32});
33
34static GET_STATUS_RESULT: Lazy<GetStatusResult> = Lazy::new(|| {
35 let node_id = NodeId::doc_example();
36 let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 54321);
37 let mut peers = BTreeMap::new();
38 peers.insert(*node_id, socket_addr.to_string());
39 let status_feed = StatusFeed {
40 last_added_block: Some(Block::example().clone()),
41 peers,
42 chainspec_info: ChainspecInfo::doc_example().clone(),
43 our_public_signing_key: Some(PublicKey::example().clone()),
44 round_length: Some(TimeDiff::from_millis(1 << 16)),
45 version: crate::VERSION_STRING.as_str(),
46 node_uptime: Duration::from_secs(13),
47 reactor_state: ReactorState::Initialize,
48 last_progress: Timestamp::from(0),
49 available_block_range: AvailableBlockRange::RANGE_0_0,
50 block_sync: BlockSynchronizerStatus::example().clone(),
51 starting_state_root_hash: Digest::default(),
52 latest_switch_block_hash: Some(BlockHash::default()),
53 };
54 GetStatusResult::new(status_feed, DOCS_EXAMPLE_PROTOCOL_VERSION)
55});
56
57#[derive(Debug, Serialize, Deserialize, Clone)]
59pub struct ChainspecInfo {
60 name: String,
62 next_upgrade: Option<NextUpgrade>,
63}
64
65impl DocExample for ChainspecInfo {
66 fn doc_example() -> &'static Self {
67 &CHAINSPEC_INFO
68 }
69}
70
71impl ChainspecInfo {
72 pub(crate) fn new(chainspec_network_name: String, next_upgrade: Option<NextUpgrade>) -> Self {
73 ChainspecInfo {
74 name: chainspec_network_name,
75 next_upgrade,
76 }
77 }
78}
79
80#[derive(Debug, Serialize)]
82pub struct StatusFeed {
83 pub last_added_block: Option<Block>,
85 pub peers: BTreeMap<NodeId, String>,
87 pub chainspec_info: ChainspecInfo,
89 pub our_public_signing_key: Option<PublicKey>,
91 pub round_length: Option<TimeDiff>,
93 pub version: &'static str,
95 pub node_uptime: Duration,
97 pub reactor_state: ReactorState,
99 pub last_progress: Timestamp,
101 pub available_block_range: AvailableBlockRange,
103 pub block_sync: BlockSynchronizerStatus,
105 pub starting_state_root_hash: Digest,
107 pub latest_switch_block_hash: Option<BlockHash>,
109}
110
111impl StatusFeed {
112 #[allow(clippy::too_many_arguments)]
113 pub(crate) fn new(
114 last_added_block: Option<Block>,
115 peers: BTreeMap<NodeId, String>,
116 chainspec_info: ChainspecInfo,
117 consensus_status: Option<ConsensusStatus>,
118 node_uptime: Duration,
119 reactor_state: ReactorState,
120 last_progress: Timestamp,
121 available_block_range: AvailableBlockRange,
122 block_sync: BlockSynchronizerStatus,
123 starting_state_root_hash: Digest,
124 latest_switch_block_hash: Option<BlockHash>,
125 ) -> Self {
126 let (our_public_signing_key, round_length) =
127 consensus_status.map_or((None, None), |consensus_status| {
128 (
129 Some(consensus_status.validator_public_key().clone()),
130 consensus_status.round_length(),
131 )
132 });
133 StatusFeed {
134 last_added_block,
135 peers,
136 chainspec_info,
137 our_public_signing_key,
138 round_length,
139 version: crate::VERSION_STRING.as_str(),
140 node_uptime,
141 reactor_state,
142 last_progress,
143 available_block_range,
144 block_sync,
145 starting_state_root_hash,
146 latest_switch_block_hash,
147 }
148 }
149}
150
151#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, JsonSchema)]
153#[serde(deny_unknown_fields)]
154pub struct MinimalBlockInfo {
155 hash: BlockHash,
156 timestamp: Timestamp,
157 era_id: EraId,
158 height: u64,
159 state_root_hash: Digest,
160 creator: PublicKey,
161}
162
163impl From<Block> for MinimalBlockInfo {
164 fn from(block: Block) -> Self {
165 let proposer = match &block {
166 Block::V1(v1) => v1.proposer().clone(),
167 Block::V2(v2) => v2.proposer().clone(),
168 };
169
170 MinimalBlockInfo {
171 hash: *block.hash(),
172 timestamp: block.timestamp(),
173 era_id: block.era_id(),
174 height: block.height(),
175 state_root_hash: *block.state_root_hash(),
176 creator: proposer,
177 }
178 }
179}
180
181#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, JsonSchema)]
183#[serde(deny_unknown_fields)]
184pub struct GetStatusResult {
185 pub peers: Peers,
187 #[schemars(with = "String")]
189 pub api_version: ProtocolVersion,
190 pub build_version: String,
192 pub chainspec_name: String,
194 pub starting_state_root_hash: Digest,
196 pub last_added_block_info: Option<MinimalBlockInfo>,
198 pub our_public_signing_key: Option<PublicKey>,
200 pub round_length: Option<TimeDiff>,
202 pub next_upgrade: Option<NextUpgrade>,
204 pub uptime: TimeDiff,
206 pub reactor_state: ReactorState,
208 pub last_progress: Timestamp,
210 pub available_block_range: AvailableBlockRange,
212 pub block_sync: BlockSynchronizerStatus,
214 pub latest_switch_block_hash: Option<BlockHash>,
216}
217
218impl GetStatusResult {
219 #[allow(deprecated)]
220 pub(crate) fn new(status_feed: StatusFeed, api_version: ProtocolVersion) -> Self {
221 GetStatusResult {
222 peers: Peers::from(status_feed.peers),
223 api_version,
224 chainspec_name: status_feed.chainspec_info.name,
225 starting_state_root_hash: status_feed.starting_state_root_hash,
226 last_added_block_info: status_feed.last_added_block.map(Into::into),
227 our_public_signing_key: status_feed.our_public_signing_key,
228 round_length: status_feed.round_length,
229 next_upgrade: status_feed.chainspec_info.next_upgrade,
230 uptime: status_feed.node_uptime.into(),
231 reactor_state: status_feed.reactor_state,
232 last_progress: status_feed.last_progress,
233 available_block_range: status_feed.available_block_range,
234 block_sync: status_feed.block_sync,
235 latest_switch_block_hash: status_feed.latest_switch_block_hash,
236 #[cfg(not(test))]
237 build_version: crate::VERSION_STRING.clone(),
238
239 #[cfg(test)]
241 build_version: String::from("1.0.0-xxxxxxxxx@DEBUG"),
242 }
243 }
244}
245
246impl DocExample for GetStatusResult {
247 fn doc_example() -> &'static Self {
248 &GET_STATUS_RESULT
249 }
250}