#![allow(clippy::field_reassign_with_default)]
use std::{
collections::BTreeMap,
hash::Hash,
net::{IpAddr, Ipv4Addr, SocketAddr},
time::Duration,
};
use once_cell::sync::Lazy;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use casper_hashing::Digest;
use casper_types::{EraId, ProtocolVersion, PublicKey};
use crate::{
components::{
chainspec_loader::NextUpgrade,
rpc_server::rpcs::docs::{DocExample, DOCS_EXAMPLE_PROTOCOL_VERSION},
},
crypto::AsymmetricKeyExt,
types::{ActivationPoint, Block, BlockHash, NodeId, PeersMap, TimeDiff, Timestamp},
};
static CHAINSPEC_INFO: Lazy<ChainspecInfo> = Lazy::new(|| {
let next_upgrade = NextUpgrade::new(
ActivationPoint::EraId(EraId::from(42)),
ProtocolVersion::from_parts(2, 0, 1),
);
ChainspecInfo {
name: String::from("casper-example"),
starting_state_root_hash: Digest::from([2u8; Digest::LENGTH]),
next_upgrade: Some(next_upgrade),
}
});
static GET_STATUS_RESULT: Lazy<GetStatusResult> = Lazy::new(|| {
let node_id = NodeId::doc_example();
let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 54321);
let mut peers = BTreeMap::new();
peers.insert(*node_id, socket_addr.to_string());
let status_feed = StatusFeed::<NodeId> {
last_added_block: Some(Block::doc_example().clone()),
peers,
chainspec_info: ChainspecInfo::doc_example().clone(),
our_public_signing_key: Some(PublicKey::doc_example().clone()),
round_length: Some(TimeDiff::from(1 << 16)),
version: crate::VERSION_STRING.as_str(),
node_uptime: Duration::from_secs(13),
};
GetStatusResult::new(status_feed, DOCS_EXAMPLE_PROTOCOL_VERSION)
});
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ChainspecInfo {
name: String,
starting_state_root_hash: Digest,
next_upgrade: Option<NextUpgrade>,
}
impl DocExample for ChainspecInfo {
fn doc_example() -> &'static Self {
&*CHAINSPEC_INFO
}
}
impl ChainspecInfo {
pub(crate) fn new(
chainspec_network_name: String,
starting_state_root_hash: Digest,
next_upgrade: Option<NextUpgrade>,
) -> Self {
ChainspecInfo {
name: chainspec_network_name,
starting_state_root_hash,
next_upgrade,
}
}
}
#[derive(Debug, Serialize)]
#[serde(bound = "I: Eq + Hash + Ord + Serialize")]
pub struct StatusFeed<I> {
pub last_added_block: Option<Block>,
pub peers: BTreeMap<I, String>,
pub chainspec_info: ChainspecInfo,
pub our_public_signing_key: Option<PublicKey>,
pub round_length: Option<TimeDiff>,
pub version: &'static str,
pub node_uptime: Duration,
}
impl<I> StatusFeed<I> {
pub(crate) fn new(
last_added_block: Option<Block>,
peers: BTreeMap<I, String>,
chainspec_info: ChainspecInfo,
consensus_status: Option<(PublicKey, Option<TimeDiff>)>,
node_uptime: Duration,
) -> Self {
let (our_public_signing_key, round_length) = match consensus_status {
Some((public_key, round_length)) => (Some(public_key), round_length),
None => (None, None),
};
StatusFeed {
last_added_block,
peers,
chainspec_info,
our_public_signing_key,
round_length,
version: crate::VERSION_STRING.as_str(),
node_uptime,
}
}
}
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct MinimalBlockInfo {
hash: BlockHash,
timestamp: Timestamp,
era_id: EraId,
height: u64,
state_root_hash: Digest,
creator: PublicKey,
}
impl From<Block> for MinimalBlockInfo {
fn from(block: Block) -> Self {
MinimalBlockInfo {
hash: *block.hash(),
timestamp: block.header().timestamp(),
era_id: block.header().era_id(),
height: block.header().height(),
state_root_hash: *block.header().state_root_hash(),
creator: block.body().proposer().clone(),
}
}
}
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct GetStatusResult {
#[schemars(with = "String")]
pub api_version: ProtocolVersion,
pub chainspec_name: String,
pub starting_state_root_hash: Digest,
pub peers: PeersMap,
pub last_added_block_info: Option<MinimalBlockInfo>,
pub our_public_signing_key: Option<PublicKey>,
pub round_length: Option<TimeDiff>,
pub next_upgrade: Option<NextUpgrade>,
pub build_version: String,
pub uptime: TimeDiff,
}
impl GetStatusResult {
pub(crate) fn new(status_feed: StatusFeed<NodeId>, api_version: ProtocolVersion) -> Self {
GetStatusResult {
api_version,
chainspec_name: status_feed.chainspec_info.name,
starting_state_root_hash: status_feed.chainspec_info.starting_state_root_hash,
peers: PeersMap::from(status_feed.peers),
last_added_block_info: status_feed.last_added_block.map(Into::into),
our_public_signing_key: status_feed.our_public_signing_key,
round_length: status_feed.round_length,
next_upgrade: status_feed.chainspec_info.next_upgrade,
uptime: status_feed.node_uptime.into(),
#[cfg(not(test))]
build_version: crate::VERSION_STRING.clone(),
#[cfg(test)]
build_version: String::from("1.0.0-xxxxxxxxx@DEBUG"),
}
}
}
impl DocExample for GetStatusResult {
fn doc_example() -> &'static Self {
&*GET_STATUS_RESULT
}
}