From 9c98fdedce41d075320770734b217538a9b5898e Mon Sep 17 00:00:00 2001 From: David Edey Date: Tue, 26 Nov 2024 14:04:56 +0000 Subject: [PATCH] feat: Add `ContextualDisplay` to `TransactionValidationError` --- radix-rust/src/contextual_display.rs | 34 ++++++++++ radix-transactions/src/errors.rs | 93 ++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/radix-rust/src/contextual_display.rs b/radix-rust/src/contextual_display.rs index 42cd18797e..17ca431f6a 100644 --- a/radix-rust/src/contextual_display.rs +++ b/radix-rust/src/contextual_display.rs @@ -70,6 +70,21 @@ pub trait ContextualDisplay { } } + /// Returns an object implementing [`fmt::Debug`] using the contextual display implementation. + /// + /// Typically you should use [`format`] instead. + /// + /// [`format`]: #method.format + fn debug_as_display<'a, 'b, TContext: Into>( + &'a self, + context: TContext, + ) -> ContextDebuggableAsDisplay<'a, Self, Context> { + ContextDebuggableAsDisplay { + value: self, + context: context.into(), + } + } + fn to_string<'a, 'b, TContext: Into>(&'a self, context: TContext) -> String { self.display(context).to_string() } @@ -93,3 +108,22 @@ where .map_err(|_| fmt::Error) // We eat any errors into fmt::Error } } + +pub struct ContextDebuggableAsDisplay<'a, TValue, TContext> +where + TValue: ContextualDisplay + ?Sized, +{ + value: &'a TValue, + context: TContext, +} + +impl<'a, 'b, TValue, TContext> fmt::Debug for ContextDebuggableAsDisplay<'a, TValue, TContext> +where + TValue: ContextualDisplay + ?Sized, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.value + .contextual_format(f, &self.context) + .map_err(|_| fmt::Error) // We eat any errors into fmt::Error + } +} diff --git a/radix-transactions/src/errors.rs b/radix-transactions/src/errors.rs index 681155d2d5..7152cc6706 100644 --- a/radix-transactions/src/errors.rs +++ b/radix-transactions/src/errors.rs @@ -69,6 +69,41 @@ pub enum TransactionValidationError { SignatureValidationError(TransactionValidationErrorLocation, SignatureValidationError), } +impl<'a> ContextualDisplay> for TransactionValidationError { + type Error = fmt::Error; + + fn contextual_format( + &self, + f: &mut fmt::Formatter, + context: &TransactionHashDisplayContext<'a>, + ) -> Result<(), Self::Error> { + match self { + Self::TransactionVersionNotPermitted(arg0) => f + .debug_tuple("TransactionVersionNotPermitted") + .field(arg0) + .finish(), + Self::TransactionTooLarge => write!(f, "TransactionTooLarge"), + Self::EncodeError(arg0) => f.debug_tuple("EncodeError").field(arg0).finish(), + Self::PrepareError(arg0) => f.debug_tuple("PrepareError").field(arg0).finish(), + Self::SubintentStructureError(arg0, arg1) => f + .debug_tuple("SubintentStructureError") + .field(&arg0.debug_as_display(*context)) + .field(&arg1.debug_as_display(*context)) + .finish(), + Self::IntentValidationError(arg0, arg1) => f + .debug_tuple("IntentValidationError") + .field(&arg0.debug_as_display(*context)) + .field(arg1) + .finish(), + Self::SignatureValidationError(arg0, arg1) => f + .debug_tuple("SignatureValidationError") + .field(&arg0.debug_as_display(*context)) + .field(arg1) + .finish(), + } + } +} + pub enum IntentSpecifier { RootTransactionIntent(TransactionIntentHash), RootSubintent(SubintentHash), @@ -93,6 +128,37 @@ impl TransactionValidationErrorLocation { } } +impl<'a> ContextualDisplay> + for TransactionValidationErrorLocation +{ + type Error = fmt::Error; + + fn contextual_format( + &self, + f: &mut fmt::Formatter, + context: &TransactionHashDisplayContext<'a>, + ) -> Result<(), Self::Error> { + // Copied from the auto-generated `Debug` implementation, and tweaked + match self { + Self::RootTransactionIntent(arg0) => f + .debug_tuple("RootTransactionIntent") + .field(&arg0.debug_as_display(*context)) + .finish(), + Self::RootSubintent(arg0) => f + .debug_tuple("RootSubintent") + .field(&arg0.debug_as_display(*context)) + .finish(), + Self::NonRootSubintent(arg0, arg1) => f + .debug_tuple("NonRootSubintent") + .field(arg0) + .field(&arg1.debug_as_display(*context)) + .finish(), + Self::AcrossTransaction => write!(f, "AcrossTransaction"), + Self::Unlocatable => write!(f, "Unlocatable"), + } + } +} + impl From for TransactionValidationError { fn from(value: PrepareError) -> Self { Self::PrepareError(value) @@ -176,6 +242,33 @@ pub enum SubintentStructureError { MismatchingYieldChildAndYieldParentCountsForSubintent, } +impl<'a> ContextualDisplay> for SubintentStructureError { + type Error = fmt::Error; + + fn contextual_format( + &self, + f: &mut fmt::Formatter, + context: &TransactionHashDisplayContext<'a>, + ) -> Result<(), Self::Error> { + // Copied from the auto-generated `Debug` implementation, and tweaked + match self { + Self::DuplicateSubintent => write!(f, "DuplicateSubintent"), + Self::SubintentHasMultipleParents => write!(f, "SubintentHasMultipleParents"), + Self::ChildSubintentNotIncludedInTransaction(arg0) => f + .debug_tuple("ChildSubintentNotIncludedInTransaction") + .field(&arg0.debug_as_display(*context)) + .finish(), + Self::SubintentExceedsMaxDepth => write!(f, "SubintentExceedsMaxDepth"), + Self::SubintentIsNotReachableFromTheTransactionIntent => { + write!(f, "SubintentIsNotReachableFromTheTransactionIntent") + } + Self::MismatchingYieldChildAndYieldParentCountsForSubintent => { + write!(f, "MismatchingYieldChildAndYieldParentCountsForSubintent") + } + } + } +} + impl SubintentStructureError { pub fn for_unindexed(self) -> TransactionValidationError { TransactionValidationError::SubintentStructureError(