From b1c88490d86242ec55d04392338e7b6ade68e99a Mon Sep 17 00:00:00 2001 From: Gustavo Inacio Date: Thu, 19 Sep 2024 17:47:01 +0200 Subject: [PATCH] feat!: add context to checks BREAKING CHANGE Signed-off-by: Gustavo Inacio --- tap_core/Cargo.toml | 1 + tap_core/src/manager/context/memory.rs | 6 +-- tap_core/src/manager/mod.rs | 5 ++- tap_core/src/manager/tap_manager.rs | 11 ++++-- tap_core/src/rav.rs | 2 +- tap_core/src/receipt/checks.rs | 10 ++--- tap_core/src/receipt/mod.rs | 2 + tap_core/src/receipt/received_receipt.rs | 24 +++++++----- tap_core/tests/manager_test.rs | 41 ++++++++++++--------- tap_core/tests/received_receipt_test.rs | 14 +++++-- tap_integration_tests/tests/indexer_mock.rs | 10 +++-- 11 files changed, 77 insertions(+), 49 deletions(-) diff --git a/tap_core/Cargo.toml b/tap_core/Cargo.toml index 4dd48f0d..553a62ae 100644 --- a/tap_core/Cargo.toml +++ b/tap_core/Cargo.toml @@ -15,6 +15,7 @@ anyhow.workspace = true rand.workspace = true thiserror = "1.0.38" async-trait = "0.1.72" +anymap3 = "1.0.0" [dev-dependencies] criterion = { version = "0.5", features = ["async_std"] } diff --git a/tap_core/src/manager/context/memory.rs b/tap_core/src/manager/context/memory.rs index 0ac8ff8e..21eff1b7 100644 --- a/tap_core/src/manager/context/memory.rs +++ b/tap_core/src/manager/context/memory.rs @@ -263,7 +263,7 @@ pub mod checks { receipt::{ checks::{Check, CheckError, CheckResult, ReceiptCheck}, state::Checking, - ReceiptError, ReceiptWithState, + Context, ReceiptError, ReceiptWithState, }, signed_message::MessageId, }; @@ -296,7 +296,7 @@ pub mod checks { #[async_trait::async_trait] impl Check for AllocationIdCheck { - async fn check(&self, receipt: &ReceiptWithState) -> CheckResult { + async fn check(&self, _: &Context, receipt: &ReceiptWithState) -> CheckResult { let received_allocation_id = receipt.signed_receipt().message.allocation_id; if self .allocation_ids @@ -323,7 +323,7 @@ pub mod checks { #[async_trait::async_trait] impl Check for SignatureCheck { - async fn check(&self, receipt: &ReceiptWithState) -> CheckResult { + async fn check(&self, _: &Context, receipt: &ReceiptWithState) -> CheckResult { let recovered_address = receipt .signed_receipt() .recover_signer(&self.domain_separator) diff --git a/tap_core/src/manager/mod.rs b/tap_core/src/manager/mod.rs index ab439b5e..7696796e 100644 --- a/tap_core/src/manager/mod.rs +++ b/tap_core/src/manager/mod.rs @@ -39,7 +39,8 @@ //! ReceiptWithState, //! state::Checking, //! checks::CheckList, -//! ReceiptError +//! ReceiptError, +//! Context //! }, //! manager::{ //! Manager, @@ -70,7 +71,7 @@ //! let receipt = EIP712SignedMessage::new(&domain_separator, message, &wallet).unwrap(); //! //! let manager = Manager::new(domain_separator, MyContext, CheckList::empty()); -//! manager.verify_and_store_receipt(receipt).await.unwrap() +//! manager.verify_and_store_receipt(&Context::new(), receipt).await.unwrap() //! # } //! ``` //! diff --git a/tap_core/src/manager/tap_manager.rs b/tap_core/src/manager/tap_manager.rs index ef0d47fc..304e4d17 100644 --- a/tap_core/src/manager/tap_manager.rs +++ b/tap_core/src/manager/tap_manager.rs @@ -9,7 +9,7 @@ use crate::{ receipt::{ checks::{CheckBatch, CheckList, TimestampCheck, UniqueCheck}, state::{Failed, Reserved}, - ReceiptError, ReceiptWithState, SignedReceipt, + Context, ReceiptError, ReceiptWithState, SignedReceipt, }, Error, }; @@ -99,6 +99,7 @@ where { async fn collect_receipts( &self, + ctx: &Context, timestamp_buffer_ns: u64, min_timestamp_ns: u64, limit: Option, @@ -140,7 +141,7 @@ where for receipt in checking_receipts.into_iter() { let receipt = receipt - .finalize_receipt_checks(&self.checks) + .finalize_receipt_checks(ctx, &self.checks) .await .map_err(|e| Error::ReceiptError(ReceiptError::RetryableCheck(e)))?; @@ -184,6 +185,7 @@ where /// pub async fn create_rav_request( &self, + ctx: &Context, timestamp_buffer_ns: u64, receipts_limit: Option, ) -> Result { @@ -194,7 +196,7 @@ where .unwrap_or(0); let (valid_receipts, invalid_receipts) = self - .collect_receipts(timestamp_buffer_ns, min_timestamp_ns, receipts_limit) + .collect_receipts(ctx, timestamp_buffer_ns, min_timestamp_ns, receipts_limit) .await?; let expected_rav = Self::generate_expected_rav(&valid_receipts, previous_rav.clone()); @@ -271,12 +273,13 @@ where /// pub async fn verify_and_store_receipt( &self, + ctx: &Context, signed_receipt: SignedReceipt, ) -> std::result::Result<(), Error> { let mut received_receipt = ReceiptWithState::new(signed_receipt); // perform checks - received_receipt.perform_checks(&self.checks).await?; + received_receipt.perform_checks(ctx, &self.checks).await?; // store the receipt self.context diff --git a/tap_core/src/rav.rs b/tap_core/src/rav.rs index ad3149c4..78ea2c80 100644 --- a/tap_core/src/rav.rs +++ b/tap_core/src/rav.rs @@ -26,7 +26,7 @@ //! 1. Create a [`RAVRequest`] with the valid receipts and the previous RAV. //! 2. Send the request to the aggregator. //! 3. The aggregator will verify the request and increment the total amount that -//! has been aggregated. +//! has been aggregated. //! 4. The aggregator will return a [`SignedRAV`]. //! 5. Store the [`SignedRAV`]. //! 6. Repeat the process until the allocation is closed. diff --git a/tap_core/src/receipt/checks.rs b/tap_core/src/receipt/checks.rs index c0abddef..4820cf8d 100644 --- a/tap_core/src/receipt/checks.rs +++ b/tap_core/src/receipt/checks.rs @@ -12,7 +12,7 @@ //! # use std::sync::Arc; //! use tap_core::{ //! receipt::checks::{Check, CheckResult, ReceiptCheck}, -//! receipt::{ReceiptWithState, state::Checking} +//! receipt::{Context, ReceiptWithState, state::Checking} //! }; //! # use async_trait::async_trait; //! @@ -20,7 +20,7 @@ //! //! #[async_trait] //! impl Check for MyCheck { -//! async fn check(&self, receipt: &ReceiptWithState) -> CheckResult { +//! async fn check(&self, ctx: &Context, receipt: &ReceiptWithState) -> CheckResult { //! // Implement your check here //! Ok(()) //! } @@ -33,7 +33,7 @@ use crate::signed_message::{SignatureBytes, SignatureBytesExt}; use super::{ state::{Checking, Failed}, - ReceiptError, ReceiptWithState, + Context, ReceiptError, ReceiptWithState, }; use std::{ collections::HashSet, @@ -80,7 +80,7 @@ impl Deref for CheckList { /// Check trait is implemented by the lib user to validate receipts before they are stored. #[async_trait::async_trait] pub trait Check { - async fn check(&self, receipt: &ReceiptWithState) -> CheckResult; + async fn check(&self, ctx: &Context, receipt: &ReceiptWithState) -> CheckResult; } /// CheckBatch is mostly used by the lib to implement checks @@ -119,7 +119,7 @@ impl StatefulTimestampCheck { #[async_trait::async_trait] impl Check for StatefulTimestampCheck { - async fn check(&self, receipt: &ReceiptWithState) -> CheckResult { + async fn check(&self, _: &Context, receipt: &ReceiptWithState) -> CheckResult { let min_timestamp_ns = *self.min_timestamp_ns.read().unwrap(); let signed_receipt = receipt.signed_receipt(); if signed_receipt.message.timestamp_ns <= min_timestamp_ns { diff --git a/tap_core/src/receipt/mod.rs b/tap_core/src/receipt/mod.rs index 871616d6..d1f947d1 100644 --- a/tap_core/src/receipt/mod.rs +++ b/tap_core/src/receipt/mod.rs @@ -36,3 +36,5 @@ pub type SignedReceipt = EIP712SignedMessage; /// Result type for receipt pub type ReceiptResult = Result; + +pub type Context = anymap3::Map; diff --git a/tap_core/src/receipt/received_receipt.rs b/tap_core/src/receipt/received_receipt.rs index 41d59c2e..3b94f014 100644 --- a/tap_core/src/receipt/received_receipt.rs +++ b/tap_core/src/receipt/received_receipt.rs @@ -16,7 +16,7 @@ use alloy::dyn_abi::Eip712Domain; use super::checks::CheckError; -use super::{Receipt, ReceiptError, ReceiptResult, SignedReceipt}; +use super::{Context, Receipt, ReceiptError, ReceiptResult, SignedReceipt}; use crate::receipt::state::{AwaitingReserve, Checking, Failed, ReceiptState, Reserved}; use crate::{ manager::adapters::EscrowHandler, receipt::checks::ReceiptCheck, @@ -28,16 +28,15 @@ pub type ResultReceipt = std::result::Result, ReceiptWith /// Typestate pattern for tracking the state of a receipt /// /// - The [ `ReceiptState` ] trait represents the different states a receipt -/// can be in. +/// can be in. /// - The [ `Checking` ] state is used to represent a receipt that is currently -/// being checked. +/// being checked. /// - The [ `Failed` ] state is used to represent a receipt that has failed a -/// check or validation. +/// check or validation. /// - The [ `AwaitingReserve` ] state is used to represent a receipt that has -/// passed all checks and is -/// awaiting escrow reservation. +/// passed all checks and is awaiting escrow reservation. /// - The [ `Reserved` ] state is used to represent a receipt that has -/// successfully reserved escrow. +/// successfully reserved escrow. #[derive(Debug, Clone)] pub struct ReceiptWithState where @@ -90,10 +89,14 @@ impl ReceiptWithState { /// cannot be comleted in the receipts current internal state. /// All other checks must be complete before `CheckAndReserveEscrow`. /// - pub async fn perform_checks(&mut self, checks: &[ReceiptCheck]) -> ReceiptResult<()> { + pub async fn perform_checks( + &mut self, + ctx: &Context, + checks: &[ReceiptCheck], + ) -> ReceiptResult<()> { for check in checks { // return early on an error - check.check(self).await.map_err(|e| match e { + check.check(ctx, self).await.map_err(|e| match e { CheckError::Retryable(e) => ReceiptError::RetryableCheck(e.to_string()), CheckError::Failed(e) => ReceiptError::CheckFailure(e.to_string()), })?; @@ -108,9 +111,10 @@ impl ReceiptWithState { /// pub async fn finalize_receipt_checks( mut self, + ctx: &Context, checks: &[ReceiptCheck], ) -> Result, String> { - let all_checks_passed = self.perform_checks(checks).await; + let all_checks_passed = self.perform_checks(ctx, checks).await; if let Err(ReceiptError::RetryableCheck(e)) = all_checks_passed { Err(e.to_string()) } else if let Err(e) = all_checks_passed { diff --git a/tap_core/tests/manager_test.rs b/tap_core/tests/manager_test.rs index a18f6223..e8a05082 100644 --- a/tap_core/tests/manager_test.rs +++ b/tap_core/tests/manager_test.rs @@ -27,7 +27,7 @@ use tap_core::{ receipt::{ checks::{Check, CheckError, CheckList, StatefulTimestampCheck}, state::Checking, - Receipt, ReceiptWithState, + Context, Receipt, ReceiptWithState, }, signed_message::EIP712SignedMessage, tap_eip712_domain, @@ -145,7 +145,7 @@ async fn manager_verify_and_store_varying_initial_checks( .insert(signer.address(), 999999); assert!(manager - .verify_and_store_receipt(signed_receipt) + .verify_and_store_receipt(&Context::new(), signed_receipt) .await .is_ok()); } @@ -184,11 +184,11 @@ async fn manager_create_rav_request_all_valid_receipts( stored_signed_receipts.push(signed_receipt.clone()); query_appraisals.write().unwrap().insert(query_id, value); assert!(manager - .verify_and_store_receipt(signed_receipt) + .verify_and_store_receipt(&Context::new(), signed_receipt) .await .is_ok()); } - let rav_request_result = manager.create_rav_request(0, None).await; + let rav_request_result = manager.create_rav_request(&Context::new(), 0, None).await; assert!(rav_request_result.is_ok()); let rav_request = rav_request_result.unwrap(); @@ -279,12 +279,12 @@ async fn manager_create_multiple_rav_requests_all_valid_receipts( stored_signed_receipts.push(signed_receipt.clone()); query_appraisals.write().unwrap().insert(query_id, value); assert!(manager - .verify_and_store_receipt(signed_receipt) + .verify_and_store_receipt(&Context::new(), signed_receipt) .await .is_ok()); expected_accumulated_value += value; } - let rav_request_result = manager.create_rav_request(0, None).await; + let rav_request_result = manager.create_rav_request(&Context::new(), 0, None).await; assert!(rav_request_result.is_ok()); let rav_request = rav_request_result.unwrap(); @@ -323,12 +323,12 @@ async fn manager_create_multiple_rav_requests_all_valid_receipts( stored_signed_receipts.push(signed_receipt.clone()); query_appraisals.write().unwrap().insert(query_id, value); assert!(manager - .verify_and_store_receipt(signed_receipt) + .verify_and_store_receipt(&Context::new(), signed_receipt) .await .is_ok()); expected_accumulated_value += value; } - let rav_request_result = manager.create_rav_request(0, None).await; + let rav_request_result = manager.create_rav_request(&Context::new(), 0, None).await; assert!(rav_request_result.is_ok()); let rav_request = rav_request_result.unwrap(); @@ -391,7 +391,7 @@ async fn manager_create_multiple_rav_requests_all_valid_receipts_consecutive_tim stored_signed_receipts.push(signed_receipt.clone()); query_appraisals.write().unwrap().insert(query_id, value); assert!(manager - .verify_and_store_receipt(signed_receipt) + .verify_and_store_receipt(&Context::new(), signed_receipt) .await .is_ok()); expected_accumulated_value += value; @@ -403,7 +403,7 @@ async fn manager_create_multiple_rav_requests_all_valid_receipts_consecutive_tim manager.remove_obsolete_receipts().await.unwrap(); } - let rav_request_1_result = manager.create_rav_request(0, None).await; + let rav_request_1_result = manager.create_rav_request(&Context::new(), 0, None).await; assert!(rav_request_1_result.is_ok()); let rav_request_1 = rav_request_1_result.unwrap(); @@ -438,7 +438,7 @@ async fn manager_create_multiple_rav_requests_all_valid_receipts_consecutive_tim stored_signed_receipts.push(signed_receipt.clone()); query_appraisals.write().unwrap().insert(query_id, value); assert!(manager - .verify_and_store_receipt(signed_receipt) + .verify_and_store_receipt(&Context::new(), signed_receipt) .await .is_ok()); expected_accumulated_value += value; @@ -458,7 +458,7 @@ async fn manager_create_multiple_rav_requests_all_valid_receipts_consecutive_tim ); } - let rav_request_2_result = manager.create_rav_request(0, None).await; + let rav_request_2_result = manager.create_rav_request(&Context::new(), 0, None).await; assert!(rav_request_2_result.is_ok()); let rav_request_2 = rav_request_2_result.unwrap(); @@ -518,12 +518,15 @@ async fn manager_create_rav_and_ignore_invalid_receipts( let signed_receipt = EIP712SignedMessage::new(&domain_separator, receipt, &signer).unwrap(); stored_signed_receipts.push(signed_receipt.clone()); manager - .verify_and_store_receipt(signed_receipt) + .verify_and_store_receipt(&Context::new(), signed_receipt) .await .unwrap(); } - let rav_request = manager.create_rav_request(0, None).await.unwrap(); + let rav_request = manager + .create_rav_request(&Context::new(), 0, None) + .await + .unwrap(); let expected_rav = rav_request.expected_rav.unwrap(); assert_eq!(rav_request.valid_receipts.len(), 1); @@ -544,7 +547,11 @@ async fn test_retryable_checks( #[async_trait::async_trait] impl Check for RetryableCheck { - async fn check(&self, receipt: &ReceiptWithState) -> Result<(), CheckError> { + async fn check( + &self, + _: &Context, + receipt: &ReceiptWithState, + ) -> Result<(), CheckError> { // we want to fail only if nonce is 5 and if is create rav step if self.0.load(std::sync::atomic::Ordering::SeqCst) && receipt.signed_receipt().message.nonce == 5 @@ -591,14 +598,14 @@ async fn test_retryable_checks( let signed_receipt = EIP712SignedMessage::new(&domain_separator, receipt, &signer).unwrap(); stored_signed_receipts.push(signed_receipt.clone()); manager - .verify_and_store_receipt(signed_receipt) + .verify_and_store_receipt(&Context::new(), signed_receipt) .await .unwrap(); } is_create_rav.store(true, std::sync::atomic::Ordering::SeqCst); - let rav_request = manager.create_rav_request(0, None).await; + let rav_request = manager.create_rav_request(&Context::new(), 0, None).await; assert_eq!( rav_request.expect_err("Didn't fail").to_string(), diff --git a/tap_core/tests/received_receipt_test.rs b/tap_core/tests/received_receipt_test.rs index 78e926a4..2b6c6e0b 100644 --- a/tap_core/tests/received_receipt_test.rs +++ b/tap_core/tests/received_receipt_test.rs @@ -15,7 +15,7 @@ use tap_core::{ }, receipt::{ checks::{ReceiptCheck, StatefulTimestampCheck}, - Receipt, ReceiptWithState, + Context, Receipt, ReceiptWithState, }, signed_message::EIP712SignedMessage, tap_eip712_domain, @@ -138,7 +138,9 @@ async fn partial_then_full_check_valid_receipt( let mut received_receipt = ReceiptWithState::new(signed_receipt); - let result = received_receipt.perform_checks(&checks).await; + let result = received_receipt + .perform_checks(&Context::new(), &checks) + .await; assert!(result.is_ok()); } @@ -180,7 +182,9 @@ async fn partial_then_finalize_valid_receipt( let received_receipt = ReceiptWithState::new(signed_receipt); - let awaiting_escrow_receipt = received_receipt.finalize_receipt_checks(&checks).await; + let awaiting_escrow_receipt = received_receipt + .finalize_receipt_checks(&Context::new(), &checks) + .await; assert!(awaiting_escrow_receipt.is_ok()); let awaiting_escrow_receipt = awaiting_escrow_receipt.unwrap(); @@ -230,7 +234,9 @@ async fn standard_lifetime_valid_receipt( let received_receipt = ReceiptWithState::new(signed_receipt); - let awaiting_escrow_receipt = received_receipt.finalize_receipt_checks(&checks).await; + let awaiting_escrow_receipt = received_receipt + .finalize_receipt_checks(&Context::new(), &checks) + .await; assert!(awaiting_escrow_receipt.is_ok()); let awaiting_escrow_receipt = awaiting_escrow_receipt.unwrap(); diff --git a/tap_integration_tests/tests/indexer_mock.rs b/tap_integration_tests/tests/indexer_mock.rs index 433e38a2..28fdfb76 100644 --- a/tap_integration_tests/tests/indexer_mock.rs +++ b/tap_integration_tests/tests/indexer_mock.rs @@ -22,7 +22,7 @@ use tap_core::{ Manager, }, rav::SignedRAV, - receipt::{checks::CheckList, SignedReceipt}, + receipt::{checks::CheckList, Context, SignedReceipt}, }; /// Rpc trait represents a JSON-RPC server that has a single async method `request`. /// This method is designed to handle incoming JSON-RPC requests. @@ -90,7 +90,11 @@ where &self, receipt: SignedReceipt, ) -> Result<(), jsonrpsee::types::ErrorObjectOwned> { - let verify_result = match self.manager.verify_and_store_receipt(receipt).await { + let verify_result = match self + .manager + .verify_and_store_receipt(&Context::new(), receipt) + .await + { Ok(_) => Ok(()), Err(e) => Err(to_rpc_error( Box::new(e), @@ -182,7 +186,7 @@ where E: ReceiptRead + RAVRead + RAVStore + EscrowHandler, { // Create the aggregate_receipts request params - let rav_request = manager.create_rav_request(time_stamp_buffer, None).await?; + let rav_request = manager.create_rav_request(&Context::new(), time_stamp_buffer, None).await?; // To-do: Need to add previous RAV, when tap_manager supports replacing receipts let params = rpc_params!(