From 16222acd6a9d9913da62f88cd81b7162e08a6a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bierlein?= Date: Wed, 3 Apr 2024 21:07:50 +0200 Subject: [PATCH 1/8] Remove comments --- src/types.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/types.rs b/src/types.rs index c23bb18..b0b90e2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -7,8 +7,6 @@ use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use std::fmt::Debug; -// use crate::rules::RulesEngine; - #[derive(Debug)] pub struct PremintName(pub String); @@ -38,13 +36,7 @@ pub struct PremintMetadata { #[async_trait] pub trait Premint: Serialize + DeserializeOwned + Debug + Clone { fn metadata(&self) -> PremintMetadata; - fn guid(&self) -> String; - - // async fn validate(&self, engine: RulesEngine) -> bool { - // engine.validate(self).await - // } - fn check_filter(chain_id: u64) -> Option; fn map_claim(chain_id: u64, log: Log) -> eyre::Result; async fn verify_claim(chain_id: u64, tx: Transaction, log: Log, claim: InclusionClaim) -> bool; From 30d16317496c21872b5578764fc85b54606eb083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bierlein?= Date: Wed, 3 Apr 2024 21:08:51 +0200 Subject: [PATCH 2/8] Update rule trait to include a name --- src/rules.rs | 64 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/src/rules.rs b/src/rules.rs index 9f5f475..56215ae 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -9,44 +9,48 @@ pub struct RuleContext {} #[async_trait] trait Rule: Send + Sync { async fn check(&self, item: PremintTypes, context: RuleContext) -> eyre::Result; + fn rule_name(&self) -> &'static str; } -struct FnRule(pub T); +struct FnRule(pub &'static str, pub T); #[async_trait] impl Rule for FnRule -where - T: Fn(PremintTypes, RuleContext) -> Fut + Send + Sync + 'static, - Fut: std::future::Future> + Send, + where + T: Fn(PremintTypes, RuleContext) -> Fut + Send + Sync + 'static, + Fut: std::future::Future> + Send, { async fn check(&self, item: PremintTypes, context: RuleContext) -> eyre::Result { - self.0(item, context).await + self.1(item, context).await } + + fn rule_name(&self) -> &'static str { self.0 } } macro_rules! rule { ($fn:tt) => { - FnRule($fn) + FnRule(stringify!($fn), $fn) }; } macro_rules! typed_rule { - ($t:path, $fn:tt) => { - crate::rules::FnRule( - |item: crate::types::PremintTypes, - context: crate::rules::RuleContext| - -> std::pin::Pin< - std::boxed::Box> + Send + Sync>, - > { - std::boxed::Box::pin(async { - match item { - $t(premint) => $fn(premint, context).await, - _ => Ok(true), - } - }) - }, - ) - }; + ($t:path, $fn:tt) => {{ + struct TypedRule; + + #[async_trait] + impl crate::rules::Rule for TypedRule{ + async fn check(&self, item: crate::types::PremintTypes, context: crate::rules::RuleContext) -> eyre::Result { + match item { + $t(premint) => $fn(premint, context).await, + _ => Ok(true), + } + } + + fn rule_name(&self) -> &'static str { concat!(stringify!($t), "::", stringify!($fn)) } + } + + TypedRule{} + }}; } struct RulesEngine { @@ -78,10 +82,13 @@ impl RulesEngine { #[cfg(test)] mod test { - use super::*; - use crate::types::SimplePremint; use alloy_primitives::U256; + use crate::premints::zora_premint_v2::types::ZoraPremintV2; + use crate::types::SimplePremint; + + use super::*; + async fn simple_rule(item: PremintTypes, context: RuleContext) -> eyre::Result { Ok(true) } @@ -97,6 +104,10 @@ mod test { Ok(true) } + async fn simple_typed_zora_rule(item: ZoraPremintV2, context: RuleContext) -> eyre::Result { + Ok(true) + } + #[tokio::test] async fn test_simple_rule() { let context = RuleContext {}; @@ -128,8 +139,13 @@ mod test { let context = RuleContext {}; let rule = typed_rule!(PremintTypes::Simple, simple_typed_rule); + let rule2 = typed_rule!(PremintTypes::ZoraV2, simple_typed_zora_rule); + + assert_eq!(rule.rule_name(), "PremintTypes::Simple::simple_typed_rule"); + assert_eq!(rule2.rule_name(), "PremintTypes::ZoraV2::simple_typed_zora_rule"); re.add_rule(rule); + re.add_rule(rule2); let result = re .evaluate(PremintTypes::Simple(Default::default()), context) From 9f8738ede099afb94e95dce7f709f8cb9ae89a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bierlein?= Date: Wed, 3 Apr 2024 22:20:57 +0200 Subject: [PATCH 3/8] Handle errors in evaluate --- src/rules.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/rules.rs b/src/rules.rs index 56215ae..f46f3e1 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -65,7 +65,7 @@ impl RulesEngine { self.rules.push(Box::new(rule)); } - pub async fn evaluate(&self, item: PremintTypes, context: RuleContext) -> bool { + pub async fn evaluate(&self, item: PremintTypes, context: RuleContext) -> eyre::Result { let results: Vec<_> = self .rules .iter() @@ -73,10 +73,22 @@ impl RulesEngine { .collect(); let all_checks = join_all(results).await; - // TODO: handle errors - all_checks - .iter() - .all(|check| check.is_ok() && check.as_ref().unwrap().clone()) + // TODO: ideally we'd want to return a list of all errors + // so that a caller could determine which rules failed and why + for error in all_checks.into_iter() { + match error { + Err(e) => { + return Err(e); + } + Ok(pass) => { + if !pass { + return Ok(false) + } + } + } + } + + Ok(true) } } @@ -130,7 +142,7 @@ mod test { .evaluate(PremintTypes::Simple(Default::default()), context) .await; - assert!(result); + assert!(result.unwrap()); } #[tokio::test] @@ -151,6 +163,6 @@ mod test { .evaluate(PremintTypes::Simple(Default::default()), context) .await; - assert!(result); + assert!(result.unwrap()); } } From cac8f5565916f34891a8a21e746141ee23afec1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bierlein?= Date: Wed, 3 Apr 2024 22:22:52 +0200 Subject: [PATCH 4/8] fmt --- src/rules.rs | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/rules.rs b/src/rules.rs index f46f3e1..7f3ce08 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -16,15 +16,17 @@ struct FnRule(pub &'static str, pub T); #[async_trait] impl Rule for FnRule - where - T: Fn(PremintTypes, RuleContext) -> Fut + Send + Sync + 'static, - Fut: std::future::Future> + Send, +where + T: Fn(PremintTypes, RuleContext) -> Fut + Send + Sync + 'static, + Fut: std::future::Future> + Send, { async fn check(&self, item: PremintTypes, context: RuleContext) -> eyre::Result { self.1(item, context).await } - fn rule_name(&self) -> &'static str { self.0 } + fn rule_name(&self) -> &'static str { + self.0 + } } macro_rules! rule { @@ -38,18 +40,24 @@ macro_rules! typed_rule { struct TypedRule; #[async_trait] - impl crate::rules::Rule for TypedRule{ - async fn check(&self, item: crate::types::PremintTypes, context: crate::rules::RuleContext) -> eyre::Result { + impl crate::rules::Rule for TypedRule { + async fn check( + &self, + item: crate::types::PremintTypes, + context: crate::rules::RuleContext, + ) -> eyre::Result { match item { $t(premint) => $fn(premint, context).await, _ => Ok(true), } } - fn rule_name(&self) -> &'static str { concat!(stringify!($t), "::", stringify!($fn)) } + fn rule_name(&self) -> &'static str { + concat!(stringify!($t), "::", stringify!($fn)) + } } - TypedRule{} + TypedRule {} }}; } @@ -82,7 +90,7 @@ impl RulesEngine { } Ok(pass) => { if !pass { - return Ok(false) + return Ok(false); } } } @@ -116,7 +124,10 @@ mod test { Ok(true) } - async fn simple_typed_zora_rule(item: ZoraPremintV2, context: RuleContext) -> eyre::Result { + async fn simple_typed_zora_rule( + item: ZoraPremintV2, + context: RuleContext, + ) -> eyre::Result { Ok(true) } @@ -154,7 +165,10 @@ mod test { let rule2 = typed_rule!(PremintTypes::ZoraV2, simple_typed_zora_rule); assert_eq!(rule.rule_name(), "PremintTypes::Simple::simple_typed_rule"); - assert_eq!(rule2.rule_name(), "PremintTypes::ZoraV2::simple_typed_zora_rule"); + assert_eq!( + rule2.rule_name(), + "PremintTypes::ZoraV2::simple_typed_zora_rule" + ); re.add_rule(rule); re.add_rule(rule2); From 1a49c4d0a4d092f503e6c61ef6f5b71e674f01ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bierlein?= Date: Thu, 4 Apr 2024 13:00:16 +0200 Subject: [PATCH 5/8] Move tests --- src/rules.rs | 101 +++++------------------------------------- tests/rules_engine.rs | 77 ++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 90 deletions(-) create mode 100644 tests/rules_engine.rs diff --git a/src/rules.rs b/src/rules.rs index 7f3ce08..e9c1307 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -7,12 +7,12 @@ use crate::types::{Premint, PremintTypes}; pub struct RuleContext {} #[async_trait] -trait Rule: Send + Sync { +pub trait Rule: Send + Sync { async fn check(&self, item: PremintTypes, context: RuleContext) -> eyre::Result; fn rule_name(&self) -> &'static str; } -struct FnRule(pub &'static str, pub T); +pub struct FnRule(pub &'static str, pub T); #[async_trait] impl Rule for FnRule @@ -29,22 +29,24 @@ where } } +#[macro_export] macro_rules! rule { ($fn:tt) => { - FnRule(stringify!($fn), $fn) + mintpool::rules::FnRule(stringify!($fn), $fn) }; } +#[macro_export] macro_rules! typed_rule { ($t:path, $fn:tt) => {{ struct TypedRule; - #[async_trait] - impl crate::rules::Rule for TypedRule { + #[async_trait::async_trait] + impl mintpool::rules::Rule for TypedRule { async fn check( &self, - item: crate::types::PremintTypes, - context: crate::rules::RuleContext, + item: mintpool::types::PremintTypes, + context: mintpool::rules::RuleContext, ) -> eyre::Result { match item { $t(premint) => $fn(premint, context).await, @@ -61,7 +63,7 @@ macro_rules! typed_rule { }}; } -struct RulesEngine { +pub struct RulesEngine { rules: Vec>, } @@ -98,85 +100,4 @@ impl RulesEngine { Ok(true) } -} - -#[cfg(test)] -mod test { - use alloy_primitives::U256; - - use crate::premints::zora_premint_v2::types::ZoraPremintV2; - use crate::types::SimplePremint; - - use super::*; - - async fn simple_rule(item: PremintTypes, context: RuleContext) -> eyre::Result { - Ok(true) - } - - async fn conditional_rule(item: PremintTypes, context: RuleContext) -> eyre::Result { - match item { - PremintTypes::Simple(s) => Ok(s.metadata().chain_id == U256::default()), - _ => Ok(true), - } - } - - async fn simple_typed_rule(item: SimplePremint, context: RuleContext) -> eyre::Result { - Ok(true) - } - - async fn simple_typed_zora_rule( - item: ZoraPremintV2, - context: RuleContext, - ) -> eyre::Result { - Ok(true) - } - - #[tokio::test] - async fn test_simple_rule() { - let context = RuleContext {}; - let rule = rule!(simple_rule); - let result = rule - .check(PremintTypes::Simple(Default::default()), context) - .await - .unwrap(); - assert!(result); - } - - #[tokio::test] - async fn test_simple_rules_engine() { - let mut re = RulesEngine::new(); - let context = RuleContext {}; - re.add_rule(rule!(simple_rule)); - re.add_rule(rule!(conditional_rule)); - - let result = re - .evaluate(PremintTypes::Simple(Default::default()), context) - .await; - - assert!(result.unwrap()); - } - - #[tokio::test] - async fn test_typed_rules_engine() { - let mut re = RulesEngine::new(); - let context = RuleContext {}; - - let rule = typed_rule!(PremintTypes::Simple, simple_typed_rule); - let rule2 = typed_rule!(PremintTypes::ZoraV2, simple_typed_zora_rule); - - assert_eq!(rule.rule_name(), "PremintTypes::Simple::simple_typed_rule"); - assert_eq!( - rule2.rule_name(), - "PremintTypes::ZoraV2::simple_typed_zora_rule" - ); - - re.add_rule(rule); - re.add_rule(rule2); - - let result = re - .evaluate(PremintTypes::Simple(Default::default()), context) - .await; - - assert!(result.unwrap()); - } -} +} \ No newline at end of file diff --git a/tests/rules_engine.rs b/tests/rules_engine.rs new file mode 100644 index 0000000..4d33996 --- /dev/null +++ b/tests/rules_engine.rs @@ -0,0 +1,77 @@ +use alloy_primitives::U256; +use mintpool::{rule, typed_rule}; +use mintpool::premints::zora_premint_v2::types::ZoraPremintV2; +use mintpool::rules::{Rule, RuleContext, RulesEngine}; +use mintpool::types::{Premint, PremintTypes, SimplePremint}; + + +async fn simple_rule(item: PremintTypes, context: RuleContext) -> eyre::Result { + Ok(true) +} + +async fn conditional_rule(item: PremintTypes, context: RuleContext) -> eyre::Result { + match item { + PremintTypes::Simple(s) => Ok(s.metadata().chain_id == U256::default()), + _ => Ok(true), + } +} + +async fn simple_typed_rule(item: SimplePremint, context: RuleContext) -> eyre::Result { + Ok(true) +} + +async fn simple_typed_zora_rule( + item: ZoraPremintV2, + context: RuleContext, +) -> eyre::Result { + Ok(true) +} + +#[tokio::test] +async fn test_simple_rule() { + let context = RuleContext {}; + let rule = rule!(simple_rule); + let result = rule + .check(PremintTypes::Simple(Default::default()), context) + .await + .unwrap(); + assert!(result); +} + +#[tokio::test] +async fn test_simple_rules_engine() { + let mut re = RulesEngine::new(); + let context = RuleContext {}; + re.add_rule(rule!(simple_rule)); + re.add_rule(rule!(conditional_rule)); + + let result = re + .evaluate(PremintTypes::Simple(Default::default()), context) + .await; + + assert!(result.unwrap()); +} + +#[tokio::test] +async fn test_typed_rules_engine() { + let mut re = RulesEngine::new(); + let context = RuleContext {}; + + let rule = typed_rule!(PremintTypes::Simple, simple_typed_rule); + let rule2 = typed_rule!(PremintTypes::ZoraV2, simple_typed_zora_rule); + + assert_eq!(rule.rule_name(), "PremintTypes::Simple::simple_typed_rule"); + assert_eq!( + rule2.rule_name(), + "PremintTypes::ZoraV2::simple_typed_zora_rule" + ); + + re.add_rule(rule); + re.add_rule(rule2); + + let result = re + .evaluate(PremintTypes::Simple(Default::default()), context) + .await; + + assert!(result.unwrap()); +} \ No newline at end of file From 3862ccece40dcdb2c441b4513587b3ed73b5a9c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bierlein?= Date: Thu, 4 Apr 2024 13:06:19 +0200 Subject: [PATCH 6/8] Move tests back --- src/rules.rs | 89 +++++++++++++++++++++++++++++++++++++++++-- tests/rules_engine.rs | 77 ------------------------------------- 2 files changed, 85 insertions(+), 81 deletions(-) delete mode 100644 tests/rules_engine.rs diff --git a/src/rules.rs b/src/rules.rs index e9c1307..3fc487b 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -32,7 +32,7 @@ where #[macro_export] macro_rules! rule { ($fn:tt) => { - mintpool::rules::FnRule(stringify!($fn), $fn) + crate::rules::FnRule(stringify!($fn), $fn) }; } @@ -42,11 +42,11 @@ macro_rules! typed_rule { struct TypedRule; #[async_trait::async_trait] - impl mintpool::rules::Rule for TypedRule { + impl crate::rules::Rule for TypedRule { async fn check( &self, - item: mintpool::types::PremintTypes, - context: mintpool::rules::RuleContext, + item: crate::types::PremintTypes, + context: crate::rules::RuleContext, ) -> eyre::Result { match item { $t(premint) => $fn(premint, context).await, @@ -100,4 +100,85 @@ impl RulesEngine { Ok(true) } +} + +#[cfg(test)] +mod test { + use super::*; + + use alloy_primitives::U256; + use crate::premints::zora_premint_v2::types::ZoraPremintV2; + use crate::types::SimplePremint; + + + async fn simple_rule(item: PremintTypes, context: RuleContext) -> eyre::Result { + Ok(true) + } + + async fn conditional_rule(item: PremintTypes, context: RuleContext) -> eyre::Result { + match item { + PremintTypes::Simple(s) => Ok(s.metadata().chain_id == U256::default()), + _ => Ok(true), + } + } + + async fn simple_typed_rule(item: SimplePremint, context: RuleContext) -> eyre::Result { + Ok(true) + } + + async fn simple_typed_zora_rule( + item: ZoraPremintV2, + context: RuleContext, + ) -> eyre::Result { + Ok(true) + } + + #[tokio::test] + async fn test_simple_rule() { + let context = RuleContext {}; + let rule = rule!(simple_rule); + let result = rule + .check(PremintTypes::Simple(Default::default()), context) + .await + .unwrap(); + assert!(result); + } + + #[tokio::test] + async fn test_simple_rules_engine() { + let mut re = RulesEngine::new(); + let context = RuleContext {}; + re.add_rule(rule!(simple_rule)); + re.add_rule(rule!(conditional_rule)); + + let result = re + .evaluate(PremintTypes::Simple(Default::default()), context) + .await; + + assert!(result.unwrap()); + } + + #[tokio::test] + async fn test_typed_rules_engine() { + let mut re = RulesEngine::new(); + let context = RuleContext {}; + + let rule = typed_rule!(PremintTypes::Simple, simple_typed_rule); + let rule2 = typed_rule!(PremintTypes::ZoraV2, simple_typed_zora_rule); + + assert_eq!(rule.rule_name(), "PremintTypes::Simple::simple_typed_rule"); + assert_eq!( + rule2.rule_name(), + "PremintTypes::ZoraV2::simple_typed_zora_rule" + ); + + re.add_rule(rule); + re.add_rule(rule2); + + let result = re + .evaluate(PremintTypes::Simple(Default::default()), context) + .await; + + assert!(result.unwrap()); + } } \ No newline at end of file diff --git a/tests/rules_engine.rs b/tests/rules_engine.rs deleted file mode 100644 index 4d33996..0000000 --- a/tests/rules_engine.rs +++ /dev/null @@ -1,77 +0,0 @@ -use alloy_primitives::U256; -use mintpool::{rule, typed_rule}; -use mintpool::premints::zora_premint_v2::types::ZoraPremintV2; -use mintpool::rules::{Rule, RuleContext, RulesEngine}; -use mintpool::types::{Premint, PremintTypes, SimplePremint}; - - -async fn simple_rule(item: PremintTypes, context: RuleContext) -> eyre::Result { - Ok(true) -} - -async fn conditional_rule(item: PremintTypes, context: RuleContext) -> eyre::Result { - match item { - PremintTypes::Simple(s) => Ok(s.metadata().chain_id == U256::default()), - _ => Ok(true), - } -} - -async fn simple_typed_rule(item: SimplePremint, context: RuleContext) -> eyre::Result { - Ok(true) -} - -async fn simple_typed_zora_rule( - item: ZoraPremintV2, - context: RuleContext, -) -> eyre::Result { - Ok(true) -} - -#[tokio::test] -async fn test_simple_rule() { - let context = RuleContext {}; - let rule = rule!(simple_rule); - let result = rule - .check(PremintTypes::Simple(Default::default()), context) - .await - .unwrap(); - assert!(result); -} - -#[tokio::test] -async fn test_simple_rules_engine() { - let mut re = RulesEngine::new(); - let context = RuleContext {}; - re.add_rule(rule!(simple_rule)); - re.add_rule(rule!(conditional_rule)); - - let result = re - .evaluate(PremintTypes::Simple(Default::default()), context) - .await; - - assert!(result.unwrap()); -} - -#[tokio::test] -async fn test_typed_rules_engine() { - let mut re = RulesEngine::new(); - let context = RuleContext {}; - - let rule = typed_rule!(PremintTypes::Simple, simple_typed_rule); - let rule2 = typed_rule!(PremintTypes::ZoraV2, simple_typed_zora_rule); - - assert_eq!(rule.rule_name(), "PremintTypes::Simple::simple_typed_rule"); - assert_eq!( - rule2.rule_name(), - "PremintTypes::ZoraV2::simple_typed_zora_rule" - ); - - re.add_rule(rule); - re.add_rule(rule2); - - let result = re - .evaluate(PremintTypes::Simple(Default::default()), context) - .await; - - assert!(result.unwrap()); -} \ No newline at end of file From afd8012e38d14691426e8d4422641155f580fb78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bierlein?= Date: Thu, 4 Apr 2024 13:06:35 +0200 Subject: [PATCH 7/8] fmt --- src/rules.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/rules.rs b/src/rules.rs index 3fc487b..69b26b3 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -106,10 +106,9 @@ impl RulesEngine { mod test { use super::*; - use alloy_primitives::U256; use crate::premints::zora_premint_v2::types::ZoraPremintV2; use crate::types::SimplePremint; - + use alloy_primitives::U256; async fn simple_rule(item: PremintTypes, context: RuleContext) -> eyre::Result { Ok(true) @@ -181,4 +180,4 @@ mod test { assert!(result.unwrap()); } -} \ No newline at end of file +} From 42b40b8ecbd8c094d001fe80e432eb8dba5e77cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bierlein?= Date: Thu, 4 Apr 2024 13:08:23 +0200 Subject: [PATCH 8/8] fmt --- src/rules.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rules.rs b/src/rules.rs index 69b26b3..0b3743b 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -104,11 +104,12 @@ impl RulesEngine { #[cfg(test)] mod test { - use super::*; + use alloy_primitives::U256; use crate::premints::zora_premint_v2::types::ZoraPremintV2; use crate::types::SimplePremint; - use alloy_primitives::U256; + + use super::*; async fn simple_rule(item: PremintTypes, context: RuleContext) -> eyre::Result { Ok(true)