From bfbbb0d5c9388f0187f8347169ba81079ab2071f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bierlein?= Date: Thu, 18 Apr 2024 16:51:28 +0200 Subject: [PATCH] Improve rule evaluation errors --- src/controller.rs | 20 ++++++----- src/rules.rs | 90 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 84 insertions(+), 26 deletions(-) diff --git a/src/controller.rs b/src/controller.rs index 8aa1d66..141a97b 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -1,9 +1,10 @@ +use eyre::WrapErr; use sqlx::SqlitePool; use tokio::select; use tokio::sync::{mpsc, oneshot}; use crate::p2p::NetworkState; -use crate::rules::{RuleContext, RulesEngine}; +use crate::rules::{Evaluation, Results, RuleContext, RulesEngine}; use crate::storage::{PremintStorage, Reader, Writer}; use crate::types::{InclusionClaim, MintpoolNodeInfo, PremintTypes}; @@ -171,18 +172,19 @@ impl Controller { Ok(()) } - async fn validate_and_insert(&self, premint: PremintTypes) -> eyre::Result<()> { + async fn validate_and_insert(&self, premint: PremintTypes) -> eyre::Result { let evaluation = self.rules.evaluate(&premint, self.store.clone()).await?; if evaluation.is_accept() { - self.store.store(premint).await + self.store + .store(premint) + .await + .map(|_r| evaluation) + .wrap_err("Failed to store premint") } else { - tracing::warn!( - "Premint failed validation: {:?}, evaluation: {:?}", - premint, - evaluation.summary() - ); - Err(eyre::eyre!(evaluation.summary())) + tracing::info!("Premint failed validation: {:?}", premint); + + Err(evaluation).wrap_err("Premint failed validation") } } } diff --git a/src/rules.rs b/src/rules.rs index 87c2c25..97472b5 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -1,8 +1,12 @@ +use std::error::Error; +use std::fmt::{Display, Formatter}; use std::sync::Arc; use alloy::network::Ethereum; use async_trait::async_trait; use futures::future::join_all; +use serde::ser::SerializeStruct; +use serde::{Serialize, Serializer}; use crate::chain_list::{ChainListProvider, CHAINS}; use crate::config::Config; @@ -16,6 +20,33 @@ pub enum Evaluation { Reject(String), } +impl Display for Evaluation { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Evaluation::Accept => f.write_str("Accept"), + Evaluation::Ignore(reason) => write!(f, "Ignore ({})", reason), + Evaluation::Reject(reason) => write!(f, "Reject ({})", reason), + } + } +} + +impl Evaluation { + fn variant(&self) -> &'static str { + match self { + Evaluation::Accept => "accept", + Evaluation::Ignore(_) => "ignore", + Evaluation::Reject(_) => "reject", + } + } + + fn reason(&self) -> Option<&str> { + match self { + Evaluation::Ignore(reason) | Evaluation::Reject(reason) => Some(reason), + _ => None, + } + } +} + #[macro_export] macro_rules! reject { ($($arg:tt)*) => {{ @@ -36,7 +67,31 @@ pub struct RuleResult { pub result: eyre::Result, } -#[derive(Debug)] +impl Serialize for RuleResult { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer + .serialize_struct("RuleResult", 3) + .and_then(|mut s| { + match self.result { + Ok(ref result) => { + s.serialize_field("result", result.variant())?; + s.serialize_field("reason", &result.reason())?; + } + Err(ref e) => { + s.serialize_field("result", "error")?; + s.serialize_field("reason", &e.to_string())?; + } + } + s.serialize_field("rule_name", &self.rule_name)?; + s.end() + }) + } +} + +#[derive(Debug, Serialize)] pub struct Results(Vec); impl Results { @@ -55,22 +110,23 @@ impl Results { pub fn is_err(&self) -> bool { self.0.iter().any(|r| r.result.is_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(ref reason)) => { - format!("{}: Ignore ({})", r.rule_name, reason) - } - Ok(Evaluation::Reject(ref reason)) => { - format!("{}: Reject ({})", r.rule_name, reason) - } - Err(ref e) => format!("{}: Error ({})", r.rule_name, e), - }) - .collect::>() - .join("\n") +impl Error for Results {} + +impl Display for Results { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str( + self.0 + .iter() + .map(|r| match r.result { + Ok(ref e) => format!("{}: {}", r.rule_name, e), + Err(ref e) => format!("{}: Error ({})", r.rule_name, e), + }) + .collect::>() + .join("\n") + .as_str(), + ) } } @@ -276,7 +332,7 @@ impl RulesEngine { } mod general { - use crate::rules::Evaluation::{Accept, Ignore, Reject}; + use crate::rules::Evaluation::Accept; use crate::rules::{Evaluation, Rule, RuleContext}; use crate::storage::Reader; use crate::types::PremintMetadata;