From ce4dd1999d1111205fe43554a1483187a1862734 Mon Sep 17 00:00:00 2001 From: Gustavo Inacio Date: Wed, 31 Jul 2024 15:00:04 -0300 Subject: [PATCH] feat!: add recoverable errors to checks Signed-off-by: Gustavo Inacio --- tap_core/src/manager/context/memory.rs | 32 ++++++++++++++++-------- tap_core/src/manager/tap_manager.rs | 7 ++++-- tap_core/src/receipt/checks.rs | 22 +++++++++++----- tap_core/src/receipt/error.rs | 2 ++ tap_core/src/receipt/received_receipt.rs | 20 ++++++++------- tap_core/tests/received_receipt_test.rs | 2 ++ 6 files changed, 57 insertions(+), 28 deletions(-) diff --git a/tap_core/src/manager/context/memory.rs b/tap_core/src/manager/context/memory.rs index a475cca8..c66dc8e8 100644 --- a/tap_core/src/manager/context/memory.rs +++ b/tap_core/src/manager/context/memory.rs @@ -261,7 +261,7 @@ impl EscrowHandler for InMemoryContext { pub mod checks { use crate::{ receipt::{ - checks::{Check, CheckResult, ReceiptCheck}, + checks::{Check, CheckError, CheckResult, ReceiptCheck}, state::Checking, ReceiptError, ReceiptWithState, }, @@ -306,10 +306,12 @@ pub mod checks { { Ok(()) } else { - Err(ReceiptError::InvalidAllocationID { - received_allocation_id, - } - .into()) + Err(CheckError::Failure( + ReceiptError::InvalidAllocationID { + received_allocation_id, + } + .into(), + )) } } } @@ -325,14 +327,22 @@ pub mod checks { let recovered_address = receipt .signed_receipt() .recover_signer(&self.domain_separator) - .map_err(|e| ReceiptError::InvalidSignature { - source_error_message: e.to_string(), + .map_err(|e| { + CheckError::Failure( + ReceiptError::InvalidSignature { + source_error_message: e.to_string(), + } + .into(), + ) })?; + if !self.valid_signers.contains(&recovered_address) { - Err(ReceiptError::InvalidSignature { - source_error_message: "Invalid signer".to_string(), - } - .into()) + Err(CheckError::Failure( + ReceiptError::InvalidSignature { + source_error_message: "Invalid signer".to_string(), + } + .into(), + )) } else { Ok(()) } diff --git a/tap_core/src/manager/tap_manager.rs b/tap_core/src/manager/tap_manager.rs index ec856835..14fad60c 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}, - ReceiptWithState, SignedReceipt, + ReceiptError, ReceiptWithState, SignedReceipt, }, Error, }; @@ -139,7 +139,10 @@ where failed_receipts.extend(already_failed); for receipt in checking_receipts.into_iter() { - let receipt = receipt.finalize_receipt_checks(&self.checks).await; + let receipt = receipt + .finalize_receipt_checks(&self.checks) + .await + .map_err(|e| Error::ReceiptError(ReceiptError::RecoverableCheckError(e)))?; match receipt { Ok(checked) => awaiting_reserve_receipts.push(checked), diff --git a/tap_core/src/receipt/checks.rs b/tap_core/src/receipt/checks.rs index d61b4d9c..5ece5ac7 100644 --- a/tap_core/src/receipt/checks.rs +++ b/tap_core/src/receipt/checks.rs @@ -45,7 +45,15 @@ use std::{ pub type ReceiptCheck = Arc; /// Result of a check operation. It uses the `anyhow` crate to handle errors. -pub type CheckResult = anyhow::Result<()>; +pub type CheckResult = Result<(), CheckError>; + +#[derive(thiserror::Error, Debug)] +pub enum CheckError { + #[error(transparent)] + Recoverable(anyhow::Error), + #[error(transparent)] + Failure(anyhow::Error), +} /// CheckList is a NewType pattern to store a list of checks. /// It is a wrapper around an Arc of ReceiptCheck[]. @@ -115,11 +123,13 @@ impl Check for StatefulTimestampCheck { 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 { - return Err(ReceiptError::InvalidTimestamp { - received_timestamp: signed_receipt.message.timestamp_ns, - timestamp_min: min_timestamp_ns, - } - .into()); + return Err(CheckError::Failure( + ReceiptError::InvalidTimestamp { + received_timestamp: signed_receipt.message.timestamp_ns, + timestamp_min: min_timestamp_ns, + } + .into(), + )); } Ok(()) } diff --git a/tap_core/src/receipt/error.rs b/tap_core/src/receipt/error.rs index d002c64d..28a5d894 100644 --- a/tap_core/src/receipt/error.rs +++ b/tap_core/src/receipt/error.rs @@ -24,4 +24,6 @@ pub enum ReceiptError { SubtractEscrowFailed, #[error("Issue encountered while performing check: {0}")] CheckFailedToComplete(String), + #[error("Issue encountered while performing check: {0}")] + RecoverableCheckError(String), } diff --git a/tap_core/src/receipt/received_receipt.rs b/tap_core/src/receipt/received_receipt.rs index 82f439ad..260e2590 100644 --- a/tap_core/src/receipt/received_receipt.rs +++ b/tap_core/src/receipt/received_receipt.rs @@ -15,6 +15,7 @@ use alloy::dyn_abi::Eip712Domain; +use super::checks::CheckError; use super::{Receipt, ReceiptError, ReceiptResult, SignedReceipt}; use crate::receipt::state::{AwaitingReserve, Checking, Failed, ReceiptState, Reserved}; use crate::{ @@ -92,10 +93,10 @@ impl ReceiptWithState { pub async fn perform_checks(&mut self, checks: &[ReceiptCheck]) -> ReceiptResult<()> { for check in checks { // return early on an error - check - .check(self) - .await - .map_err(|e| ReceiptError::CheckFailedToComplete(e.to_string()))?; + check.check(self).await.map_err(|e| match e { + CheckError::Recoverable(e) => ReceiptError::RecoverableCheckError(e.to_string()), + CheckError::Failure(e) => ReceiptError::CheckFailedToComplete(e.to_string()), + })?; } Ok(()) } @@ -108,14 +109,15 @@ impl ReceiptWithState { pub async fn finalize_receipt_checks( mut self, checks: &[ReceiptCheck], - ) -> ResultReceipt { + ) -> Result, String> { let all_checks_passed = self.perform_checks(checks).await; - - if let Err(e) = all_checks_passed { - Err(self.perform_state_error(e)) + if let Err(ReceiptError::RecoverableCheckError(e)) = all_checks_passed { + Err(e.to_string()) + } else if let Err(e) = all_checks_passed { + Ok(Err(self.perform_state_error(e))) } else { let checked = self.perform_state_changes(AwaitingReserve); - Ok(checked) + Ok(Ok(checked)) } } } diff --git a/tap_core/tests/received_receipt_test.rs b/tap_core/tests/received_receipt_test.rs index a3de5bd9..78e926a4 100644 --- a/tap_core/tests/received_receipt_test.rs +++ b/tap_core/tests/received_receipt_test.rs @@ -185,6 +185,7 @@ async fn partial_then_finalize_valid_receipt( let awaiting_escrow_receipt = awaiting_escrow_receipt.unwrap(); let receipt = awaiting_escrow_receipt + .unwrap() .check_and_reserve_escrow(&context, &domain_separator) .await; assert!(receipt.is_ok()); @@ -234,6 +235,7 @@ async fn standard_lifetime_valid_receipt( let awaiting_escrow_receipt = awaiting_escrow_receipt.unwrap(); let receipt = awaiting_escrow_receipt + .unwrap() .check_and_reserve_escrow(&context, &domain_separator) .await; assert!(receipt.is_ok());