Skip to main content

soil_client/blockchain/
error.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later WITH Classpath-exception-2.0
6
7//! Substrate client possible errors.
8
9use crate::consensus;
10use codec::Error as CodecError;
11use std::{self, result};
12use subsoil::api::ApiError;
13use subsoil::runtime::transaction_validity::TransactionValidityError;
14
15/// Client Result type alias
16pub type Result<T> = result::Result<T, Error>;
17
18/// Error when the runtime failed to apply an extrinsic.
19#[derive(Debug, thiserror::Error)]
20#[allow(missing_docs)]
21pub enum ApplyExtrinsicFailed {
22	/// The transaction cannot be included into the current block.
23	///
24	/// This doesn't necessary mean that the transaction itself is invalid, but it might be just
25	/// unapplicable onto the current block.
26	#[error("Extrinsic is not valid: {0:?}")]
27	Validity(#[from] TransactionValidityError),
28
29	#[error("Application specific error")]
30	Application(#[source] Box<dyn 'static + std::error::Error + Send + Sync>),
31}
32
33/// Substrate Client error
34#[derive(Debug, thiserror::Error)]
35#[allow(missing_docs)]
36#[non_exhaustive]
37pub enum Error {
38	#[error("Cancelled oneshot channel {0}")]
39	OneShotCancelled(#[from] futures::channel::oneshot::Canceled),
40
41	#[error(transparent)]
42	Consensus(#[from] crate::consensus::Error),
43
44	#[error("Backend error: {0}")]
45	Backend(String),
46
47	#[error("UnknownBlock: {0}")]
48	UnknownBlock(String),
49
50	#[error("UnknownBlocks: {0}")]
51	UnknownBlocks(String),
52
53	#[error(transparent)]
54	ApplyExtrinsicFailed(#[from] ApplyExtrinsicFailed),
55
56	#[error("Child type is invalid")]
57	InvalidChildType,
58
59	#[error("RemoteBodyRequest: invalid extrinsics root expected: {expected} but got {received}")]
60	ExtrinsicRootInvalid { received: String, expected: String },
61
62	// `inner` cannot be made member, since it lacks `std::error::Error` trait bounds.
63	#[error("Execution failed: {0}")]
64	Execution(Box<dyn subsoil::state_machine::Error>),
65
66	#[error("Blockchain")]
67	Blockchain(#[source] Box<Error>),
68
69	/// A error used by various storage subsystems.
70	///
71	/// Eventually this will be replaced.
72	#[error("{0}")]
73	StorageChanges(subsoil::state_machine::DefaultError),
74
75	#[error("Invalid child storage key")]
76	InvalidChildStorageKey,
77
78	#[error("Current state of blockchain has invalid authorities set")]
79	InvalidAuthoritiesSet,
80
81	#[error("Failed to get runtime version: {0}")]
82	VersionInvalid(String),
83
84	#[error("Provided state is invalid")]
85	InvalidState,
86
87	#[error("error decoding justification for header")]
88	JustificationDecode,
89
90	#[error("bad justification for header: {0}")]
91	BadJustification(String),
92
93	#[error("outdated justification")]
94	OutdatedJustification,
95
96	#[error("This method is not currently available when running in light client mode")]
97	NotAvailableOnLightClient,
98
99	#[error("Remote node has responded with invalid header proof")]
100	InvalidCHTProof,
101
102	#[error("Remote data fetch has been cancelled")]
103	RemoteFetchCancelled,
104
105	#[error("Remote data fetch has been failed")]
106	RemoteFetchFailed,
107
108	#[error("Error decoding call result of {0}")]
109	CallResultDecode(&'static str, #[source] CodecError),
110
111	#[error("Error at calling runtime api: {0}")]
112	RuntimeApiError(#[from] ApiError),
113
114	#[error("Runtime :code missing in storage")]
115	RuntimeCodeMissing,
116
117	#[error("Changes tries are not supported by the runtime")]
118	ChangesTriesNotSupported,
119
120	#[error("Error reading changes tries configuration")]
121	ErrorReadingChangesTriesConfig,
122
123	#[error("Failed to check changes proof: {0}")]
124	ChangesTrieAccessFailed(String),
125
126	#[error("Did not finalize blocks in sequential order.")]
127	NonSequentialFinalization(String),
128
129	#[error("Potential long-range attack: block not in finalized chain.")]
130	NotInFinalizedChain,
131
132	#[error("Failed to get hash of block for building CHT")]
133	MissingHashRequiredForCHT,
134
135	#[error("Calculated state root does not match.")]
136	InvalidStateRoot,
137
138	#[error("Incomplete block import pipeline.")]
139	IncompletePipeline,
140
141	#[error("Transaction pool not ready for block production.")]
142	TransactionPoolNotReady,
143
144	#[error("Database error: {0}")]
145	DatabaseError(#[from] subsoil::database::error::DatabaseError),
146
147	#[error("Failed to get header for hash {0}")]
148	MissingHeader(String),
149
150	#[error("State Database error: {0}")]
151	StateDatabase(String),
152
153	#[error("Statement store error: {0}")]
154	StatementStore(String),
155
156	#[error("Failed to set the chain head to a block that's too old.")]
157	SetHeadTooOld,
158
159	#[error(transparent)]
160	Application(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
161
162	// Should be removed/improved once
163	// the storage `fn`s returns typed errors.
164	#[error("Runtime code error: {0}")]
165	RuntimeCode(&'static str),
166
167	// Should be removed/improved once
168	// the storage `fn`s returns typed errors.
169	#[error("Storage error: {0}")]
170	Storage(String),
171}
172
173impl From<Box<dyn subsoil::state_machine::Error + Send + Sync + 'static>> for Error {
174	fn from(e: Box<dyn subsoil::state_machine::Error + Send + Sync + 'static>) -> Self {
175		Self::from_state(e)
176	}
177}
178
179impl From<Box<dyn subsoil::state_machine::Error>> for Error {
180	fn from(e: Box<dyn subsoil::state_machine::Error>) -> Self {
181		Self::from_state(e)
182	}
183}
184
185impl From<Error> for ApiError {
186	fn from(err: Error) -> ApiError {
187		match err {
188			Error::UnknownBlock(msg) => ApiError::UnknownBlock(msg),
189			Error::RuntimeApiError(err) => err,
190			e => ApiError::Application(Box::new(e)),
191		}
192	}
193}
194
195impl Error {
196	/// Chain a blockchain error.
197	pub fn from_blockchain(e: Box<Error>) -> Self {
198		Error::Blockchain(e)
199	}
200
201	/// Chain a state error.
202	pub fn from_state(e: Box<dyn subsoil::state_machine::Error>) -> Self {
203		Error::Execution(e)
204	}
205
206	/// Construct from a state db error.
207	// Can not be done directly, since that would make cargo run out of stack if
208	// `soil-state-db` is lib is added as dependency.
209	pub fn from_state_db<E>(e: E) -> Self
210	where
211		E: std::fmt::Debug,
212	{
213		Error::StateDatabase(format!("{:?}", e))
214	}
215}