use std::time::Duration;
use crate::error::ConsensusError;
use crate::utils::{validate_threshold, validate_timeout};
pub(crate) const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NetworkType {
Gossipsub,
P2P,
}
#[derive(Debug, Clone)]
pub struct ScopeConfig {
pub network_type: NetworkType,
pub default_consensus_threshold: f64,
pub default_timeout: Duration,
pub default_liveness_criteria_yes: bool,
pub max_rounds_override: Option<u32>,
}
impl Default for ScopeConfig {
fn default() -> Self {
Self {
network_type: NetworkType::Gossipsub,
default_consensus_threshold: 2.0 / 3.0,
default_timeout: DEFAULT_TIMEOUT,
default_liveness_criteria_yes: true,
max_rounds_override: None,
}
}
}
impl ScopeConfig {
pub fn validate(&self) -> Result<(), ConsensusError> {
validate_threshold(self.default_consensus_threshold)?;
validate_timeout(self.default_timeout)?;
if let Some(max_rounds) = self.max_rounds_override
&& max_rounds == 0
&& self.network_type == NetworkType::Gossipsub
{
return Err(ConsensusError::InvalidMaxRounds);
}
Ok(())
}
}
impl From<NetworkType> for ScopeConfig {
fn from(network_type: NetworkType) -> Self {
match network_type {
NetworkType::Gossipsub => Self {
network_type: NetworkType::Gossipsub,
default_consensus_threshold: 2.0 / 3.0,
default_timeout: DEFAULT_TIMEOUT,
default_liveness_criteria_yes: true,
max_rounds_override: None,
},
NetworkType::P2P => Self {
network_type: NetworkType::P2P,
default_consensus_threshold: 2.0 / 3.0,
default_timeout: DEFAULT_TIMEOUT,
default_liveness_criteria_yes: true,
max_rounds_override: None,
},
}
}
}
pub(crate) struct ScopeConfigBuilder {
config: ScopeConfig,
}
impl ScopeConfigBuilder {
pub(crate) fn new() -> Self {
Self {
config: ScopeConfig::default(),
}
}
pub fn with_network_type(mut self, network_type: NetworkType) -> Self {
self.config.network_type = network_type;
self
}
pub fn with_threshold(mut self, threshold: f64) -> Self {
self.config.default_consensus_threshold = threshold;
self
}
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.config.default_timeout = timeout;
self
}
pub fn with_liveness_criteria(mut self, liveness_criteria_yes: bool) -> Self {
self.config.default_liveness_criteria_yes = liveness_criteria_yes;
self
}
pub fn with_max_rounds(mut self, max_rounds: Option<u32>) -> Self {
self.config.max_rounds_override = max_rounds;
self
}
pub fn from_existing(config: ScopeConfig) -> Self {
Self { config }
}
pub fn p2p_preset(mut self) -> Self {
self.config.network_type = NetworkType::P2P;
self.config.default_consensus_threshold = 2.0 / 3.0;
self.config.default_timeout = DEFAULT_TIMEOUT;
self.config.default_liveness_criteria_yes = true;
self.config.max_rounds_override = None;
self
}
pub fn gossipsub_preset(mut self) -> Self {
self.config.network_type = NetworkType::Gossipsub;
self.config.default_consensus_threshold = 2.0 / 3.0;
self.config.default_timeout = DEFAULT_TIMEOUT;
self.config.default_liveness_criteria_yes = true;
self.config.max_rounds_override = None;
self
}
pub fn strict_consensus(mut self) -> Self {
self.config.default_consensus_threshold = 0.9;
self
}
pub fn fast_consensus(mut self) -> Self {
self.config.default_consensus_threshold = 0.6;
self.config.default_timeout = Duration::from_secs(30);
self
}
pub fn with_network_defaults(mut self, network_type: NetworkType) -> Self {
match network_type {
NetworkType::P2P => {
self.config.network_type = NetworkType::P2P;
self.config.default_consensus_threshold = 2.0 / 3.0;
self.config.default_timeout = DEFAULT_TIMEOUT;
}
NetworkType::Gossipsub => {
self.config.network_type = NetworkType::Gossipsub;
self.config.default_consensus_threshold = 2.0 / 3.0;
self.config.default_timeout = DEFAULT_TIMEOUT;
}
}
self
}
pub fn validate(&self) -> Result<(), ConsensusError> {
self.config.validate()
}
pub fn build(self) -> Result<ScopeConfig, ConsensusError> {
self.validate()?;
Ok(self.config)
}
pub fn get_config(&self) -> ScopeConfig {
self.config.clone()
}
}
impl Default for ScopeConfigBuilder {
fn default() -> Self {
Self::new()
}
}