use crate::types::{AiTransaction, ConsensusLevel, ValidationPrediction};
pub struct AdaptiveConsensus {
importance_model: ImportanceModel,
override_rules: Vec<OverrideRule>,
}
impl AdaptiveConsensus {
pub fn new() -> Self {
Self {
importance_model: ImportanceModel::new(),
override_rules: vec![
OverrideRule {
condition: OverrideCondition::SizeAbove(1024 * 1024), level: ConsensusLevel::Full,
},
OverrideRule {
condition: OverrideCondition::SizeBelow(100),
level: ConsensusLevel::Local,
},
],
}
}
pub fn determine_level(
&self,
tx: &AiTransaction,
prediction: &ValidationPrediction,
) -> ConsensusLevel {
for rule in &self.override_rules {
if rule.matches(tx, prediction) {
return rule.level;
}
}
let importance = self.importance_model.evaluate(tx, prediction);
match importance {
Importance::Critical => ConsensusLevel::Full, Importance::High => ConsensusLevel::Majority, Importance::Normal => ConsensusLevel::Quorum, Importance::Low => ConsensusLevel::Local, }
}
pub fn add_override(&mut self, rule: OverrideRule) {
self.override_rules.push(rule);
}
pub fn get_overrides(&self) -> &[OverrideRule] {
&self.override_rules
}
}
impl Default for AdaptiveConsensus {
fn default() -> Self {
Self::new()
}
}
struct ImportanceModel {
size_weight: f32,
confidence_weight: f32,
type_weight: f32,
}
impl ImportanceModel {
fn new() -> Self {
Self {
size_weight: 0.3,
confidence_weight: 0.4,
type_weight: 0.3,
}
}
fn evaluate(&self, tx: &AiTransaction, prediction: &ValidationPrediction) -> Importance {
let size_score = (tx.size as f32).ln().max(0.0) / 20.0;
let confidence_score = 1.0 - prediction.confidence;
let type_score = match tx.entry_type.as_str() {
"agent_validation" => 1.0, "link" => 0.3, "cap_grant" => 0.8, _ => 0.5, };
let importance_score = size_score * self.size_weight
+ confidence_score * self.confidence_weight
+ type_score * self.type_weight;
if importance_score > 0.8 {
Importance::Critical
} else if importance_score > 0.6 {
Importance::High
} else if importance_score > 0.3 {
Importance::Normal
} else {
Importance::Low
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Importance {
Critical,
High,
Normal,
Low,
}
#[derive(Debug, Clone)]
pub struct OverrideRule {
pub condition: OverrideCondition,
pub level: ConsensusLevel,
}
impl OverrideRule {
fn matches(&self, tx: &AiTransaction, prediction: &ValidationPrediction) -> bool {
match &self.condition {
OverrideCondition::SizeAbove(threshold) => tx.size > *threshold,
OverrideCondition::SizeBelow(threshold) => tx.size < *threshold,
OverrideCondition::ConfidenceAbove(threshold) => prediction.confidence > *threshold,
OverrideCondition::ConfidenceBelow(threshold) => prediction.confidence < *threshold,
OverrideCondition::EntryType(entry_type) => &tx.entry_type == entry_type,
}
}
}
#[derive(Debug, Clone)]
pub enum OverrideCondition {
SizeAbove(usize),
SizeBelow(usize),
ConfidenceAbove(f32),
ConfidenceBelow(f32),
EntryType(String),
}
#[cfg(test)]
mod tests {
use super::*;
fn make_test_tx(id: u8, size: usize) -> AiTransaction {
AiTransaction {
hash: [id; 32],
timestamp: 1702656000000,
agent: [1u8; 32],
entry_type: "test".to_string(),
data: vec![0; size],
size,
}
}
fn make_prediction(confidence: f32) -> ValidationPrediction {
ValidationPrediction {
likely_valid: true,
confidence,
estimated_time_ms: 50,
}
}
#[test]
fn test_adaptive_consensus() {
let consensus = AdaptiveConsensus::new();
let small_tx = make_test_tx(1, 50);
let high_conf = make_prediction(0.95);
let level = consensus.determine_level(&small_tx, &high_conf);
assert_eq!(level, ConsensusLevel::Local);
let large_tx = make_test_tx(2, 2 * 1024 * 1024);
let level = consensus.determine_level(&large_tx, &high_conf);
assert_eq!(level, ConsensusLevel::Full);
}
#[test]
fn test_importance_model() {
let consensus = AdaptiveConsensus::new();
let tx = make_test_tx(1, 500);
let low_conf = make_prediction(0.3);
let level = consensus.determine_level(&tx, &low_conf);
assert!(matches!(
level,
ConsensusLevel::Quorum | ConsensusLevel::Majority | ConsensusLevel::Full
));
}
#[test]
fn test_override_rules() {
let mut consensus = AdaptiveConsensus::new();
consensus.override_rules.insert(
0,
OverrideRule {
condition: OverrideCondition::EntryType("critical_entry".to_string()),
level: ConsensusLevel::Full,
},
);
let tx = AiTransaction {
hash: [1u8; 32],
timestamp: 1702656000000,
agent: [1u8; 32],
entry_type: "critical_entry".to_string(),
data: vec![0; 200],
size: 200,
};
let prediction = make_prediction(0.99);
let level = consensus.determine_level(&tx, &prediction);
assert_eq!(level, ConsensusLevel::Full);
}
}