Skip to content

Commit

Permalink
Evaluate rules on insert (#15)
Browse files Browse the repository at this point in the history
Check incoming premints against the rules engine.
  • Loading branch information
ligustah authored Apr 6, 2024
1 parent cd5423f commit cc1bbcc
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 8 deletions.
28 changes: 25 additions & 3 deletions src/controller.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::p2p::NetworkState;
use crate::rules::{RuleContext, RulesEngine};
use crate::storage::PremintStorage;
use crate::types::{InclusionClaim, MintpoolNodeInfo, PremintTypes};
use sqlx::SqlitePool;
Expand Down Expand Up @@ -55,6 +56,7 @@ pub struct Controller {
swarm_event_receiver: mpsc::Receiver<P2PEvent>,
external_commands: mpsc::Receiver<ControllerCommands>,
store: PremintStorage,
rules: RulesEngine,
}

impl Controller {
Expand All @@ -63,12 +65,14 @@ impl Controller {
swarm_event_receiver: mpsc::Receiver<P2PEvent>,
external_commands: mpsc::Receiver<ControllerCommands>,
store: PremintStorage,
rules: RulesEngine,
) -> Self {
Self {
swarm_command_sender,
swarm_event_receiver,
external_commands,
store,
rules,
}
}

Expand All @@ -95,6 +99,7 @@ impl Controller {
P2PEvent::PremintReceived(premint) => {
tracing::debug!(premint = premint.to_json().ok(), "Received premint");

// TODO: handle error? respond with error summary?
let _ = self.validate_and_insert(premint).await;
}
}
Expand Down Expand Up @@ -155,9 +160,26 @@ impl Controller {
}

async fn validate_and_insert(&self, premint: PremintTypes) -> eyre::Result<()> {
// TODO: insert rules check here

self.store.store(premint).await
let evaluation = self
.rules
.evaluate(
premint.clone(),
RuleContext {
store: self.store.clone(),
},
)
.await;

if evaluation.is_accept() {
self.store.store(premint).await
} else {
tracing::warn!(
"Premint failed validation: {:?}, evaluation: {:?}",
premint,
evaluation
);
Err(eyre::eyre!(evaluation.summary()))
}
}
}

Expand Down
26 changes: 23 additions & 3 deletions src/rules.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use async_trait::async_trait;
use futures::future::join_all;

use crate::storage::PremintStorage;
use crate::types::{Premint, PremintTypes};

#[derive(Debug)]
Expand Down Expand Up @@ -35,10 +36,27 @@ impl Results {
pub fn is_err(&self) -> bool {
self.0.iter().any(|r| matches!(r.result, Err(_)))
}

pub fn summary(&self) -> String {
self.0
.iter()
.map(|r| match r.result {
Ok(Evaluation::Accept) => format!("{}: Accept", r.rule_name),
Ok(Evaluation::Ignore) => format!("{}: Ignore", r.rule_name),
Ok(Evaluation::Reject(ref reason)) => {
format!("{}: Reject ({})", r.rule_name, reason)
}
Err(ref e) => format!("{}: Error ({})", r.rule_name, e),
})
.collect::<Vec<_>>()
.join("\n")
}
}

#[derive(Clone)]
pub struct RuleContext {}
pub struct RuleContext {
pub store: PremintStorage,
}

#[async_trait]
pub trait Rule: Send + Sync {
Expand Down Expand Up @@ -125,7 +143,7 @@ pub struct RulesEngine {
rules: Vec<Box<dyn Rule>>,
}

fn all_rules() -> Vec<Box<dyn Rule>> {
pub fn all_rules() -> Vec<Box<dyn Rule>> {
let mut rules: Vec<Box<dyn Rule>> = Vec::new();

rules.append(&mut general::all_rules());
Expand All @@ -141,7 +159,9 @@ impl RulesEngine {
pub fn add_rule(&mut self, rule: impl Rule + 'static) {
self.rules.push(Box::new(rule));
}

pub fn add_default_rules(&mut self) {
self.rules.extend(all_rules());
}
pub async fn evaluate(&self, item: PremintTypes, context: RuleContext) -> Results {
let results: Vec<_> = self
.rules
Expand Down
10 changes: 8 additions & 2 deletions src/run.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use libp2p::identity;

use crate::config::{ChainInclusionMode, Config};
use crate::controller::{Controller, ControllerInterface};
use crate::p2p::SwarmController;
use crate::rules::RulesEngine;
use crate::storage::PremintStorage;
use libp2p::identity;

/// Starts the libp2p swarm, the controller, and the checkers if applicable.
/// Returns an interface for interacting with the controller.
Expand All @@ -19,8 +21,12 @@ pub async fn start_services(config: &Config) -> eyre::Result<ControllerInterface

let store = PremintStorage::new(config).await;

// configure rules
let mut rules = RulesEngine::new();
rules.add_default_rules();

let mut swarm_controller = SwarmController::new(id_keys, config, swrm_recv, event_send);
let mut controller = Controller::new(swrm_cmd_send, event_recv, ext_cmd_recv, store);
let mut controller = Controller::new(swrm_cmd_send, event_recv, ext_cmd_recv, store, rules);
let controller_interface = ControllerInterface::new(ext_cmd_send);

let port = config.peer_port;
Expand Down
11 changes: 11 additions & 0 deletions src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ pub struct PremintStorage {
prune_minted_premints: bool,
}

impl Clone for PremintStorage {
fn clone(&self) -> Self {
Self {
db: self.db.clone(),
// we want at most one instance to prune premints,
// so we'll always set it to false when cloning
prune_minted_premints: false,
}
}
}

impl PremintStorage {
pub async fn new(config: &Config) -> Self {
let db = init_db(config).await;
Expand Down

0 comments on commit cc1bbcc

Please sign in to comment.