mod config;
mod meta_level;
mod optimizer_level;
mod transaction_level;
pub use config::NestedConfig;
pub use meta_level::MetaLevel;
pub use optimizer_level::{OptimizerLevel, ValidationPlan, ValidationStrategy};
pub use transaction_level::{ProcessedTransaction, TransactionLevel};
use crate::error::AiResult;
use crate::types::AiTransaction;
use parking_lot::RwLock;
use std::sync::Arc;
use tracing::{debug, trace};
pub struct NestedLearning {
pub meta_level: Arc<RwLock<MetaLevel>>,
pub optimizer_level: Arc<RwLock<OptimizerLevel>>,
pub transaction_level: Arc<RwLock<TransactionLevel>>,
config: NestedConfig,
block_count: u64,
tx_count: u64,
}
impl NestedLearning {
pub fn new(config: NestedConfig) -> Self {
Self {
meta_level: Arc::new(RwLock::new(MetaLevel::new(&config))),
optimizer_level: Arc::new(RwLock::new(OptimizerLevel::new(&config))),
transaction_level: Arc::new(RwLock::new(TransactionLevel::new(&config))),
config,
block_count: 0,
tx_count: 0,
}
}
pub fn process(&mut self, tx: &AiTransaction) -> AiResult<NestedResult> {
trace!(hash = ?tx.hash, "Processing transaction through nested learning");
let processed = {
let mut tl = self.transaction_level.write();
tl.process(tx.clone())
};
let strategy = {
let ol = self.optimizer_level.read();
ol.get_strategy(&processed)
};
self.tx_count += 1;
if self.tx_count % self.config.optimizer_update_interval == 0 {
debug!(
tx_count = self.tx_count,
"Triggering optimizer-level update"
);
let mut ol = self.optimizer_level.write();
ol.periodic_update();
}
Ok(NestedResult {
processed,
strategy,
meta_params: self.get_meta_params(),
})
}
pub fn on_new_block(&mut self, block_stats: &BlockStats) {
self.block_count += 1;
if self.block_count % self.config.meta_update_interval == 0 {
debug!(
block_count = self.block_count,
"Triggering meta-level update"
);
let mut ml = self.meta_level.write();
ml.update(block_stats);
}
}
pub fn learn(&mut self, tx: &AiTransaction, outcome: &ValidationOutcome) {
let mut ol = self.optimizer_level.write();
ol.learn(tx, outcome);
let mut tl = self.transaction_level.write();
tl.update_features(tx, outcome);
}
pub fn get_meta_params(&self) -> MetaParams {
let ml = self.meta_level.read();
ml.get_params()
}
pub fn get_validation_plan(&self, batch: &[AiTransaction]) -> ValidationPlan {
let ol = self.optimizer_level.read();
ol.create_plan(batch)
}
pub fn stats(&self) -> NestedStats {
NestedStats {
block_count: self.block_count,
tx_count: self.tx_count,
meta_update_count: self.block_count / self.config.meta_update_interval,
optimizer_update_count: self.tx_count / self.config.optimizer_update_interval,
}
}
}
#[derive(Debug, Clone)]
pub struct NestedResult {
pub processed: ProcessedTransaction,
pub strategy: ValidationStrategy,
pub meta_params: MetaParams,
}
#[derive(Debug, Clone, Default)]
pub struct BlockStats {
pub tx_count: usize,
pub processing_time_ms: u64,
pub failures: usize,
pub latency_p50: u64,
pub latency_p90: u64,
pub latency_p99: u64,
pub peer_count: usize,
}
#[derive(Debug, Clone)]
pub struct ValidationOutcome {
pub valid: bool,
pub time_ms: u64,
pub error: Option<String>,
}
#[derive(Debug, Clone)]
pub struct MetaParams {
pub target_throughput: f64,
pub target_latency: u64,
pub validation_strictness: f32,
pub gossip_multiplier: f32,
}
impl Default for MetaParams {
fn default() -> Self {
Self {
target_throughput: 1000.0,
target_latency: 500,
validation_strictness: 0.8,
gossip_multiplier: 1.0,
}
}
}
#[derive(Debug, Clone)]
pub struct NestedStats {
pub block_count: u64,
pub tx_count: u64,
pub meta_update_count: u64,
pub optimizer_update_count: u64,
}
#[cfg(test)]
mod tests {
use super::*;
fn make_test_tx(id: u8) -> AiTransaction {
AiTransaction {
hash: [id; 32],
timestamp: 1702656000000 + (id as u64 * 1000),
agent: [1u8; 32],
entry_type: "test".to_string(),
data: vec![id; 10],
size: 10,
}
}
#[test]
fn test_nested_learning_basic() {
let config = NestedConfig::default();
let mut nested = NestedLearning::new(config);
let tx = make_test_tx(1);
let result = nested.process(&tx).unwrap();
assert!(result.processed.features.len() > 0);
}
#[test]
fn test_nested_learning_batch() {
let config = NestedConfig::default();
let nested = NestedLearning::new(config);
let batch: Vec<_> = (0..10).map(|i| make_test_tx(i)).collect();
let plan = nested.get_validation_plan(&batch);
assert_eq!(plan.order.len(), 10);
}
#[test]
fn test_meta_level_update() {
let mut config = NestedConfig::default();
config.meta_update_interval = 5; let mut nested = NestedLearning::new(config);
let stats = BlockStats::default();
for _ in 0..10 {
nested.on_new_block(&stats);
}
assert!(nested.stats().meta_update_count >= 2);
}
}