Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evaluate rules on insert #15

Merged
merged 2 commits into from
Apr 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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?
ligustah marked this conversation as resolved.
Show resolved Hide resolved
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
Loading