Add minmax warding (#108)

* add minmax warding
This commit is contained in:
Al Liu 2023-03-28 00:20:01 +08:00 committed by GitHub
parent f4b94c8267
commit 61356f1116
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 28 deletions

View File

@ -124,3 +124,30 @@ pub trait Node {
fn state(&self) -> &Self::State;
fn step(&mut self);
}
#[cfg(test)]
impl Node for usize {
type Settings = ();
type State = Self;
fn new<R: rand::Rng>(_rng: &mut R, id: NodeId, _settings: Self::Settings) -> Self {
id.inner()
}
fn id(&self) -> NodeId {
(*self).into()
}
fn current_view(&self) -> usize {
*self
}
fn state(&self) -> &Self::State {
self
}
fn step(&mut self) {
use std::ops::AddAssign;
self.add_assign(1);
}
}

View File

@ -0,0 +1,50 @@
use crate::node::Node;
use crate::warding::{SimulationState, SimulationWard};
use serde::Deserialize;
/// MinMaxView. It monitors the gap between a min view and max view, triggers when surpassing
/// the max view - min view is larger than a gap.
#[derive(Debug, Deserialize, Copy, Clone)]
pub struct MinMaxViewWard {
max_gap: usize,
}
impl<N: Node> SimulationWard<N> for MinMaxViewWard {
type SimulationState = SimulationState<N>;
fn analyze(&mut self, state: &Self::SimulationState) -> bool {
let mut min = usize::MAX;
let mut max = 0;
let nodes = state
.nodes
.read()
.expect("simulations: MinMaxViewWard panic when requiring a read lock");
for node in nodes.iter() {
let view = node.current_view();
min = min.min(view);
max = max.max(view);
}
max - min >= self.max_gap
}
}
#[cfg(test)]
mod test {
use crate::warding::minmax::MinMaxViewWard;
use crate::warding::{SimulationState, SimulationWard};
use std::sync::{Arc, RwLock};
#[test]
fn rebase_threshold() {
let mut minmax = MinMaxViewWard { max_gap: 5 };
let state = SimulationState {
nodes: Arc::new(RwLock::new(vec![10])),
};
// we only have one node, so always false
assert!(!minmax.analyze(&state));
// push a new node with 10
state.nodes.write().unwrap().push(20);
// we now have two nodes and the max - min is 10 > max_gap 5, so true
assert!(minmax.analyze(&state));
}
}

View File

@ -5,6 +5,7 @@ use serde::Deserialize;
// internal
use crate::node::Node;
mod minmax;
mod ttf;
pub struct SimulationState<N> {
@ -21,9 +22,10 @@ pub trait SimulationWard<N> {
/// Ward dispatcher
/// Enum to avoid Boxing (Box<dyn SimulationWard>) wards.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Ward {
#[serde(rename = "time_to_finality")]
MaxView(ttf::MaxViewWard),
MinMaxView(minmax::MinMaxViewWard),
}
impl Ward {
@ -32,6 +34,7 @@ impl Ward {
) -> &mut dyn SimulationWard<N, SimulationState = SimulationState<N>> {
match self {
Ward::MaxView(ward) => ward,
Ward::MinMaxView(ward) => ward,
}
}
}

View File

@ -23,39 +23,12 @@ impl<N: Node> SimulationWard<N> for MaxViewWard {
#[cfg(test)]
mod test {
use crate::node::{Node, NodeId};
use crate::warding::ttf::MaxViewWard;
use crate::warding::{SimulationState, SimulationWard};
use rand::Rng;
use std::ops::AddAssign;
use std::sync::{Arc, RwLock};
#[test]
fn rebase_threshold() {
impl Node for usize {
type Settings = ();
type State = Self;
fn new<R: Rng>(_rng: &mut R, id: NodeId, _settings: Self::Settings) -> Self {
id.inner()
}
fn id(&self) -> NodeId {
(*self).into()
}
fn current_view(&self) -> usize {
*self
}
fn state(&self) -> &Self::State {
self
}
fn step(&mut self) {
self.add_assign(1);
}
}
let mut ttf = MaxViewWard { max_view: 10 };
let node = 11;