ghost-telemetry-backend/telemetry-core/src/state/node.rs
Uncle Stinky 51e78f29e7
initial commit, building blocks for the later usage
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2024-11-18 16:58:38 +03:00

225 lines
5.7 KiB
Rust

use crate::find_location;
use common::node_message::SystemInterval;
use common::node_types::{
Block, BlockDetails, NodeDetails, NodeHardware, NodeHwBench, NodeIO, NodeLocation, NodeStats,
Timestamp,
};
use common::time;
/// Minimum time between block below broadcasting updates to the browser gets throttled, in ms.
const THROTTLE_THRESHOLD: u64 = 100;
/// Minimum time of intervals for block updates sent to the browser when throttled, in ms.
const THROTTLE_INTERVAL: u64 = 1000;
pub struct Node {
/// Static details
details: NodeDetails,
/// Basic stats
stats: NodeStats,
/// Node IO stats
io: NodeIO,
/// Best block
best: BlockDetails,
/// Finalized block
finalized: Block,
/// Timer for throttling block updates
throttle: u64,
/// Hardware stats over time
hardware: NodeHardware,
/// Physical location details
location: find_location::Location,
/// Flag marking if the node is stale (not syncing or producing blocks)
stale: bool,
/// Unix timestamp for when node started up (falls back to connection time)
startup_time: Option<Timestamp>,
/// Hardware benchmark results for the node
hwbench: Option<NodeHwBench>,
}
impl Node {
pub fn new(mut details: NodeDetails) -> Self {
let startup_time = details
.startup_time
.take()
.and_then(|time| time.parse().ok());
Node {
details,
stats: NodeStats::default(),
io: NodeIO::default(),
best: BlockDetails::default(),
finalized: Block::zero(),
throttle: 0,
hardware: NodeHardware::default(),
location: None,
stale: false,
startup_time,
hwbench: None,
}
}
pub fn details(&self) -> &NodeDetails {
&self.details
}
pub fn stats(&self) -> &NodeStats {
&self.stats
}
pub fn io(&self) -> &NodeIO {
&self.io
}
pub fn best(&self) -> &Block {
&self.best.block
}
pub fn best_timestamp(&self) -> u64 {
self.best.block_timestamp
}
pub fn finalized(&self) -> &Block {
&self.finalized
}
pub fn hardware(&self) -> &NodeHardware {
&self.hardware
}
pub fn location(&self) -> Option<&NodeLocation> {
self.location.as_deref()
}
pub fn update_location(&mut self, location: find_location::Location) {
self.location = location;
}
pub fn block_details(&self) -> &BlockDetails {
&self.best
}
pub fn hwbench(&self) -> Option<&NodeHwBench> {
self.hwbench.as_ref()
}
pub fn update_hwbench(&mut self, hwbench: NodeHwBench) -> Option<NodeHwBench> {
self.hwbench.replace(hwbench)
}
pub fn update_block(&mut self, block: Block) -> bool {
if block.height > self.best.block.height {
self.stale = false;
self.best.block = block;
true
} else {
false
}
}
pub fn update_details(
&mut self,
timestamp: u64,
propagation_time: Option<u64>,
) -> Option<&BlockDetails> {
self.best.block_time = timestamp - self.best.block_timestamp;
self.best.block_timestamp = timestamp;
self.best.propagation_time = propagation_time;
if self.throttle < timestamp {
if self.best.block_time <= THROTTLE_THRESHOLD {
self.throttle = timestamp + THROTTLE_INTERVAL;
}
Some(&self.best)
} else {
None
}
}
pub fn update_hardware(&mut self, interval: &SystemInterval) -> bool {
let mut changed = false;
if let Some(upload) = interval.bandwidth_upload {
changed |= self.hardware.upload.push(upload);
}
if let Some(download) = interval.bandwidth_download {
changed |= self.hardware.download.push(download);
}
self.hardware.chart_stamps.push(time::now() as f64);
changed
}
pub fn update_stats(&mut self, interval: &SystemInterval) -> Option<&NodeStats> {
let mut changed = false;
if let Some(peers) = interval.peers {
if peers != self.stats.peers {
self.stats.peers = peers;
changed = true;
}
}
if let Some(txcount) = interval.txcount {
if txcount != self.stats.txcount {
self.stats.txcount = txcount;
changed = true;
}
}
if changed {
Some(&self.stats)
} else {
None
}
}
pub fn update_io(&mut self, interval: &SystemInterval) -> Option<&NodeIO> {
let mut changed = false;
if let Some(size) = interval.used_state_cache_size {
changed |= self.io.used_state_cache_size.push(size);
}
if changed {
Some(&self.io)
} else {
None
}
}
pub fn update_finalized(&mut self, block: Block) -> Option<&Block> {
if block.height > self.finalized.height {
self.finalized = block;
Some(self.finalized())
} else {
None
}
}
pub fn update_stale(&mut self, threshold: u64) -> bool {
if self.best.block_timestamp < threshold {
self.stale = true;
}
self.stale
}
pub fn stale(&self) -> bool {
self.stale
}
pub fn set_validator_address(&mut self, addr: Box<str>) -> bool {
if self.details.validator.as_ref() == Some(&addr) {
false
} else {
self.details.validator = Some(addr);
true
}
}
pub fn startup_time(&self) -> Option<Timestamp> {
self.startup_time
}
}