use std::{cmp::Ordering, fmt::Debug};
use tari_node_components::blocks::ChainHeader;
pub trait ChainStrengthComparer: Debug {
fn compare(&self, a: &ChainHeader, b: &ChainHeader) -> Ordering;
}
#[derive(Default, Debug)]
pub struct AccumulatedDifficultySquaredComparer {}
impl ChainStrengthComparer for AccumulatedDifficultySquaredComparer {
fn compare(&self, a: &ChainHeader, b: &ChainHeader) -> Ordering {
let a_val = a.accumulated_data().total_accumulated_difficulty;
let b_val = b.accumulated_data().total_accumulated_difficulty;
a_val.cmp(&b_val)
}
}
#[derive(Debug)]
pub struct ThenComparer {
before: Box<dyn ChainStrengthComparer + Send + Sync>,
after: Box<dyn ChainStrengthComparer + Send + Sync>,
}
impl ThenComparer {
pub fn new(
before: Box<dyn ChainStrengthComparer + Send + Sync>,
after: Box<dyn ChainStrengthComparer + Send + Sync>,
) -> Self {
ThenComparer { before, after }
}
}
impl ChainStrengthComparer for ThenComparer {
fn compare(&self, a: &ChainHeader, b: &ChainHeader) -> Ordering {
match self.before.compare(a, b) {
Ordering::Equal => self.after.compare(a, b),
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
}
}
}
#[derive(Default, Debug)]
pub struct MoneroRandomxDifficultyComparer {}
impl ChainStrengthComparer for MoneroRandomxDifficultyComparer {
fn compare(&self, a: &ChainHeader, b: &ChainHeader) -> Ordering {
a.accumulated_data()
.accumulated_monero_randomx_difficulty()
.cmp(&b.accumulated_data().accumulated_monero_randomx_difficulty())
}
}
#[derive(Default, Debug)]
pub struct TariRandomxDifficultyComparer {}
impl ChainStrengthComparer for TariRandomxDifficultyComparer {
fn compare(&self, a: &ChainHeader, b: &ChainHeader) -> Ordering {
a.accumulated_data()
.accumulated_tari_randomx_difficulty()
.cmp(&b.accumulated_data().accumulated_tari_randomx_difficulty())
}
}
#[derive(Default, Debug)]
pub struct Sha3xDifficultyComparer {}
impl ChainStrengthComparer for Sha3xDifficultyComparer {
fn compare(&self, a: &ChainHeader, b: &ChainHeader) -> Ordering {
a.accumulated_data()
.accumulated_sha3x_difficulty()
.cmp(&b.accumulated_data().accumulated_sha3x_difficulty())
}
}
#[derive(Default, Debug)]
pub struct CuckarooCycleDifficultyComparer {}
impl ChainStrengthComparer for CuckarooCycleDifficultyComparer {
fn compare(&self, a: &ChainHeader, b: &ChainHeader) -> Ordering {
a.accumulated_data()
.accumulated_cuckaroo_difficulty()
.cmp(&b.accumulated_data().accumulated_cuckaroo_difficulty())
}
}
#[derive(Default, Debug)]
pub struct HeightComparer {}
impl ChainStrengthComparer for HeightComparer {
fn compare(&self, a: &ChainHeader, b: &ChainHeader) -> Ordering {
a.height().cmp(&b.height())
}
}
pub struct ChainStrengthComparerBuilder {
target: Option<Box<dyn ChainStrengthComparer + Send + Sync>>,
}
impl ChainStrengthComparerBuilder {
pub fn new() -> ChainStrengthComparerBuilder {
ChainStrengthComparerBuilder { target: None }
}
fn add_comparer_as_then(mut self, inner: Box<dyn ChainStrengthComparer + Send + Sync>) -> Self {
self.target = match self.target {
Some(t) => Some(Box::new(ThenComparer::new(t, inner))),
None => Some(inner),
};
self
}
pub fn by_accumulated_difficulty(self) -> Self {
self.add_comparer_as_then(Box::<AccumulatedDifficultySquaredComparer>::default())
}
pub fn by_monero_randomx_difficulty(self) -> Self {
self.add_comparer_as_then(Box::<MoneroRandomxDifficultyComparer>::default())
}
pub fn by_tari_randomx_difficulty(self) -> Self {
self.add_comparer_as_then(Box::<TariRandomxDifficultyComparer>::default())
}
pub fn by_sha3x_difficulty(self) -> Self {
self.add_comparer_as_then(Box::<Sha3xDifficultyComparer>::default())
}
pub fn by_cuckaroo_cycle_difficulty(self) -> Self {
self.add_comparer_as_then(Box::<CuckarooCycleDifficultyComparer>::default())
}
pub fn by_height(self) -> Self {
self.add_comparer_as_then(Box::<HeightComparer>::default())
}
pub fn then(self) -> Self {
self
}
pub fn build(self) -> Box<dyn ChainStrengthComparer + Send + Sync> {
self.target.unwrap()
}
}
pub fn strongest_chain() -> ChainStrengthComparerBuilder {
ChainStrengthComparerBuilder::new()
}