use std::fmt;
use zebra_chain::{block::Height, chain_tip::ChainTip, parameters::Network};
use crate::protocol::external::types::Version;
#[cfg(any(test, feature = "proptest-impl"))]
mod tests;
pub struct MinimumPeerVersion<C> {
network: Network,
chain_tip: C,
current_minimum: Version,
has_changed: bool,
}
impl<C> fmt::Debug for MinimumPeerVersion<C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(std::any::type_name::<MinimumPeerVersion<C>>())
.field("network", &self.network)
.field("current_minimum", &self.current_minimum)
.field("has_changed", &self.has_changed)
.finish()
}
}
impl<C> MinimumPeerVersion<C>
where
C: ChainTip,
{
pub fn new(chain_tip: C, network: &Network) -> Self {
MinimumPeerVersion {
network: network.clone(),
chain_tip,
current_minimum: Version::min_remote_for_height(network, None),
has_changed: true,
}
}
pub fn changed(&mut self) -> Option<Version> {
self.update();
if self.has_changed {
self.has_changed = false;
Some(self.current_minimum)
} else {
None
}
}
pub fn current(&mut self) -> Version {
self.update();
self.current_minimum
}
fn update(&mut self) {
let height = self.chain_tip.best_tip_height();
let new_minimum = Version::min_remote_for_height(&self.network, height);
if self.current_minimum != new_minimum {
self.current_minimum = new_minimum;
self.has_changed = true;
}
}
pub fn chain_tip_height(&self) -> Height {
match self.chain_tip.best_tip_height() {
Some(height) => height,
None => Height(0),
}
}
}
impl<C> Clone for MinimumPeerVersion<C>
where
C: Clone,
{
fn clone(&self) -> Self {
MinimumPeerVersion {
network: self.network.clone(),
chain_tip: self.chain_tip.clone(),
current_minimum: self.current_minimum,
has_changed: true,
}
}
}