1use super::{Error, MetadataError};
12use crate::metadata::Metadata;
13use alloc::{
14 borrow::Cow,
15 string::{String, ToString},
16 vec::Vec,
17};
18use codec::{Decode, Encode};
19use core::{fmt::Debug, marker::PhantomData};
20use derive_more::From;
21use log::*;
22use scale_decode::{visitor::DecodeAsTypeResult, DecodeAsType, TypeResolver};
23
24#[derive(Debug, From, PartialEq)]
27pub enum DispatchError {
28 Other,
30 CannotLookup,
32 BadOrigin,
34 Module(ModuleError),
36 ConsumerRemaining,
38 NoProviders,
40 TooManyConsumers,
42 Token(TokenError),
44 Arithmetic(ArithmeticError),
46 Transactional(TransactionalError),
48 Exhausted,
50 Corruption,
52 Unavailable,
54 RootNotAllowed,
56}
57
58impl DispatchError {
59 pub fn decode_from<'a>(
62 bytes: impl Into<Cow<'a, [u8]>>,
63 metadata: &Metadata,
64 ) -> Result<Self, Error> {
65 let bytes = bytes.into();
66 let dispatch_error_ty_id =
67 metadata.dispatch_error_ty().ok_or(MetadataError::DispatchErrorNotFound)?;
68
69 #[derive(DecodeAsType)]
73 enum DecodedDispatchError {
74 Other,
75 CannotLookup,
76 BadOrigin,
77 Module(DecodedModuleErrorBytes),
78 ConsumerRemaining,
79 NoProviders,
80 TooManyConsumers,
81 Token(TokenError),
82 Arithmetic(ArithmeticError),
83 Transactional(TransactionalError),
84 Exhausted,
85 Corruption,
86 Unavailable,
87 RootNotAllowed,
88 }
89
90 struct DecodedModuleErrorBytes(Vec<u8>);
94 struct DecodedModuleErrorBytesVisitor<R: TypeResolver>(PhantomData<R>);
95 impl<R: TypeResolver> scale_decode::Visitor for DecodedModuleErrorBytesVisitor<R> {
96 type Error = scale_decode::Error;
97 type Value<'scale, 'info> = DecodedModuleErrorBytes;
98 type TypeResolver = R;
99
100 fn unchecked_decode_as_type<'scale, 'info>(
101 self,
102 input: &mut &'scale [u8],
103 _type_id: R::TypeId,
104 _types: &'info R,
105 ) -> DecodeAsTypeResult<Self, Result<Self::Value<'scale, 'info>, Self::Error>> {
106 DecodeAsTypeResult::Decoded(Ok(DecodedModuleErrorBytes(input.to_vec())))
107 }
108 }
109
110 impl scale_decode::IntoVisitor for DecodedModuleErrorBytes {
111 type AnyVisitor<R: TypeResolver> = DecodedModuleErrorBytesVisitor<R>;
112 fn into_visitor<R: TypeResolver>() -> DecodedModuleErrorBytesVisitor<R> {
113 DecodedModuleErrorBytesVisitor(PhantomData)
114 }
115 }
116
117 let decoded_dispatch_err = DecodedDispatchError::decode_as_type(
119 &mut &*bytes,
120 dispatch_error_ty_id,
121 metadata.types(),
122 )?;
123
124 let dispatch_error = match decoded_dispatch_err {
126 DecodedDispatchError::Other => DispatchError::Other,
128 DecodedDispatchError::CannotLookup => DispatchError::CannotLookup,
129 DecodedDispatchError::BadOrigin => DispatchError::BadOrigin,
130 DecodedDispatchError::ConsumerRemaining => DispatchError::ConsumerRemaining,
131 DecodedDispatchError::NoProviders => DispatchError::NoProviders,
132 DecodedDispatchError::TooManyConsumers => DispatchError::TooManyConsumers,
133 DecodedDispatchError::Token(val) => DispatchError::Token(val),
134 DecodedDispatchError::Arithmetic(val) => DispatchError::Arithmetic(val),
135 DecodedDispatchError::Transactional(val) => DispatchError::Transactional(val),
136 DecodedDispatchError::Exhausted => DispatchError::Exhausted,
137 DecodedDispatchError::Corruption => DispatchError::Corruption,
138 DecodedDispatchError::Unavailable => DispatchError::Unavailable,
139 DecodedDispatchError::RootNotAllowed => DispatchError::RootNotAllowed,
140 DecodedDispatchError::Module(module_bytes) => {
142 let module_bytes = module_bytes.0;
143
144 let raw = if module_bytes.len() == 2 {
147 RawModuleError {
148 pallet_index: module_bytes[0],
149 error: [module_bytes[1], 0, 0, 0],
150 }
151 } else if module_bytes.len() == 5 {
152 RawModuleError {
153 pallet_index: module_bytes[0],
154 error: [module_bytes[1], module_bytes[2], module_bytes[3], module_bytes[4]],
155 }
156 } else {
157 warn!("Can't decode error sp_runtime::DispatchError: bytes do not match known shapes");
158 return Err(Error::Unknown(bytes.to_vec()))
160 };
161
162 let pallet_metadata = metadata.pallet_by_index_err(raw.pallet_index)?;
163 let error_details = pallet_metadata
164 .error_variant_by_index(raw.error[0])
165 .ok_or(MetadataError::ErrorNotFound(raw.pallet_index, raw.error[0]))?;
166
167 DispatchError::Module(ModuleError {
169 pallet: pallet_metadata.name().to_string(),
170 error: error_details.name.clone(),
171 description: error_details.docs.clone(),
172 raw,
173 })
174 },
175 };
176
177 Ok(dispatch_error)
178 }
179}
180
181#[derive(Clone, Debug, Eq, PartialEq, Encode, Decode, DecodeAsType)]
184pub enum TokenError {
185 FundsUnavailable,
187 OnlyProvider,
189 BelowMinimum,
191 CannotCreate,
193 UnknownAsset,
195 Frozen,
197 Unsupported,
199 CannotCreateHold,
201 NotExpendable,
203 Blocked,
205}
206
207#[derive(Clone, Debug, Eq, PartialEq, Encode, Decode, DecodeAsType)]
210pub enum ArithmeticError {
211 Underflow,
213 Overflow,
215 DivisionByZero,
217}
218
219#[derive(Clone, Debug, Eq, PartialEq, Encode, Decode, DecodeAsType)]
222pub enum TransactionalError {
223 LimitReached,
225 NoLayer,
227}
228
229#[derive(Clone, Debug)]
231pub struct ModuleError {
232 pub pallet: String,
234 pub error: String,
236 pub description: Vec<String>,
238 pub raw: RawModuleError,
240}
241
242impl PartialEq for ModuleError {
243 fn eq(&self, other: &Self) -> bool {
244 self.raw == other.raw
246 }
247}
248
249#[derive(Clone, Copy, Debug, PartialEq, Eq)]
253pub struct RawModuleError {
254 pub pallet_index: u8,
256 pub error: [u8; 4],
258}
259
260impl RawModuleError {
261 pub fn error_index(&self) -> u8 {
263 self.error[0]
265 }
266}