miden_node_proto/errors/
mod.rs1use std::any::type_name;
2use std::fmt;
3
4pub use miden_node_grpc_error_macro::GrpcError;
6use miden_protocol::utils::serde::DeserializationError;
7
8#[cfg(test)]
9mod test_macro;
10
11#[derive(Debug)]
21pub struct ConversionError {
22 path: Vec<&'static str>,
23 source: Box<dyn std::error::Error + Send + Sync>,
24}
25
26impl ConversionError {
27 pub fn new(source: impl std::error::Error + Send + Sync + 'static) -> Self {
29 Self {
30 path: Vec::new(),
31 source: Box::new(source),
32 }
33 }
34
35 #[must_use]
45 pub fn context(mut self, field: &'static str) -> Self {
46 self.path.push(field);
47 self
48 }
49
50 pub fn missing_field<T: prost::Message>(field_name: &'static str) -> Self {
52 Self {
53 path: Vec::new(),
54 source: Box::new(MissingFieldError { entity: type_name::<T>(), field_name }),
55 }
56 }
57
58 pub fn deserialization(entity: &'static str, source: DeserializationError) -> Self {
60 Self {
61 path: Vec::new(),
62 source: Box::new(DeserializationErrorWrapper { entity, source }),
63 }
64 }
65
66 pub fn message(msg: impl Into<String>) -> Self {
68 Self {
69 path: Vec::new(),
70 source: Box::new(StringError(msg.into())),
71 }
72 }
73}
74
75impl fmt::Display for ConversionError {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 if !self.path.is_empty() {
78 for (i, segment) in self.path.iter().rev().enumerate() {
80 if i > 0 {
81 f.write_str(".")?;
82 }
83 f.write_str(segment)?;
84 }
85 f.write_str(": ")?;
86 }
87 write!(f, "{}", self.source)
88 }
89}
90
91impl std::error::Error for ConversionError {
92 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
93 Some(&*self.source)
94 }
95}
96
97impl From<ConversionError> for tonic::Status {
98 fn from(value: ConversionError) -> Self {
99 tonic::Status::invalid_argument(value.to_string())
100 }
101}
102
103#[derive(Debug)]
107struct MissingFieldError {
108 entity: &'static str,
109 field_name: &'static str,
110}
111
112impl fmt::Display for MissingFieldError {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 write!(f, "field `{}::{}` is missing", self.entity, self.field_name)
115 }
116}
117
118impl std::error::Error for MissingFieldError {}
119
120#[derive(Debug)]
121struct DeserializationErrorWrapper {
122 entity: &'static str,
123 source: DeserializationError,
124}
125
126impl fmt::Display for DeserializationErrorWrapper {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 write!(f, "failed to deserialize {}: {}", self.entity, self.source)
129 }
130}
131
132impl std::error::Error for DeserializationErrorWrapper {
133 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
134 Some(&self.source)
135 }
136}
137
138#[derive(Debug)]
139struct StringError(String);
140
141impl fmt::Display for StringError {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 f.write_str(&self.0)
144 }
145}
146
147impl std::error::Error for StringError {}
148
149pub trait ConversionResultExt<T> {
166 fn context(self, field: &'static str) -> Result<T, ConversionError>;
168}
169
170impl<T, E: Into<ConversionError>> ConversionResultExt<T> for Result<T, E> {
171 fn context(self, field: &'static str) -> Result<T, ConversionError> {
172 self.map_err(|e| e.into().context(field))
173 }
174}
175
176macro_rules! impl_from_for_conversion_error {
180 ($($ty:ty),* $(,)?) => {
181 $(
182 impl From<$ty> for ConversionError {
183 fn from(e: $ty) -> Self {
184 Self::new(e)
185 }
186 }
187 )*
188 };
189}
190
191impl_from_for_conversion_error!(
192 hex::FromHexError,
193 miden_protocol::errors::AccountError,
194 miden_protocol::errors::AssetError,
195 miden_protocol::errors::AssetVaultError,
196 miden_protocol::errors::FeeError,
197 miden_protocol::errors::NoteError,
198 miden_protocol::errors::StorageSlotNameError,
199 miden_protocol::crypto::merkle::MerkleError,
200 miden_protocol::crypto::merkle::smt::SmtLeafError,
201 miden_protocol::crypto::merkle::smt::SmtProofError,
202 miden_standards::note::NetworkAccountTargetError,
203 std::num::TryFromIntError,
204 DeserializationError,
205);