referrerpolicy=no-referrer-when-downgrade

sc_rpc_spec_v2/transaction/
error.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Transaction RPC errors.
20//!
21//! Errors are interpreted as transaction events for subscriptions.
22
23use crate::transaction::event::{TransactionError, TransactionEvent};
24use jsonrpsee::types::error::ErrorObject;
25use sc_transaction_pool_api::error::Error as PoolError;
26use sp_runtime::transaction_validity::InvalidTransaction;
27
28/// Transaction RPC errors.
29#[derive(Debug, thiserror::Error)]
30pub enum Error {
31	/// Transaction pool error.
32	#[error("Transaction pool error: {}", .0)]
33	Pool(#[from] PoolError),
34	/// Verification error.
35	#[error("Extrinsic verification error: {}", .0)]
36	Verification(Box<dyn std::error::Error + Send + Sync>),
37}
38
39impl<Hash> From<Error> for TransactionEvent<Hash> {
40	fn from(e: Error) -> Self {
41		match e {
42			Error::Verification(e) => TransactionEvent::Invalid(TransactionError {
43				error: format!("Verification error: {}", e),
44			}),
45			Error::Pool(PoolError::InvalidTransaction(InvalidTransaction::Custom(e))) => {
46				TransactionEvent::Invalid(TransactionError {
47					error: format!("Invalid transaction with custom error: {}", e),
48				})
49			},
50			Error::Pool(PoolError::InvalidTransaction(InvalidTransaction::Module(e))) => {
51				TransactionEvent::Invalid(TransactionError {
52					error: format!(
53						"Invalid transaction: module invalidity (pallet: {}, error: {})",
54						e.index, e.error
55					),
56				})
57			},
58			Error::Pool(PoolError::InvalidTransaction(e)) => {
59				let msg: &str = e.into();
60				TransactionEvent::Invalid(TransactionError {
61					error: format!("Invalid transaction: {}", msg),
62				})
63			},
64			Error::Pool(PoolError::UnknownTransaction(e)) => {
65				let msg: &str = e.into();
66				TransactionEvent::Invalid(TransactionError {
67					error: format!("Unknown transaction validity: {}", msg),
68				})
69			},
70			Error::Pool(PoolError::TemporarilyBanned) => {
71				TransactionEvent::Invalid(TransactionError {
72					error: "Transaction is temporarily banned".into(),
73				})
74			},
75			Error::Pool(PoolError::AlreadyImported(_)) => {
76				TransactionEvent::Invalid(TransactionError {
77					error: "Transaction is already imported".into(),
78				})
79			},
80			Error::Pool(PoolError::TooLowPriority { old, new }) => {
81				TransactionEvent::Invalid(TransactionError {
82					error: format!(
83						"The priority of the transaction is too low (pool {} > current {})",
84						old, new
85					),
86				})
87			},
88			Error::Pool(PoolError::CycleDetected) => TransactionEvent::Invalid(TransactionError {
89				error: "The transaction contains a cyclic dependency".into(),
90			}),
91			Error::Pool(PoolError::ImmediatelyDropped) => {
92				TransactionEvent::Invalid(TransactionError {
93					error: "The transaction could not enter the pool because of the limit".into(),
94				})
95			},
96			Error::Pool(PoolError::Unactionable) => TransactionEvent::Invalid(TransactionError {
97				error: "Transaction cannot be propagated and the local node does not author blocks"
98					.into(),
99			}),
100			Error::Pool(PoolError::NoTagsProvided) => TransactionEvent::Invalid(TransactionError {
101				error: "Transaction does not provide any tags, so the pool cannot identify it"
102					.into(),
103			}),
104			Error::Pool(PoolError::InvalidBlockId(_)) => {
105				TransactionEvent::Invalid(TransactionError {
106					error: "The provided block ID is not valid".into(),
107				})
108			},
109			Error::Pool(PoolError::RejectedFutureTransaction) => {
110				TransactionEvent::Invalid(TransactionError {
111					error: "The pool is not accepting future transactions".into(),
112				})
113			},
114		}
115	}
116}
117
118/// TransactionBroadcast error.
119#[derive(Debug, thiserror::Error)]
120pub enum ErrorBroadcast {
121	/// The provided operation ID is invalid.
122	#[error("Invalid operation id")]
123	InvalidOperationID,
124}
125
126/// General purpose errors, as defined in
127/// <https://www.jsonrpc.org/specification#error_object>.
128pub mod json_rpc_spec {
129	/// Invalid parameter error.
130	pub const INVALID_PARAM_ERROR: i32 = -32602;
131}
132
133impl From<ErrorBroadcast> for ErrorObject<'static> {
134	fn from(e: ErrorBroadcast) -> Self {
135		let msg = e.to_string();
136
137		match e {
138			ErrorBroadcast::InvalidOperationID => {
139				ErrorObject::owned(json_rpc_spec::INVALID_PARAM_ERROR, msg, None::<()>)
140			},
141		}
142	}
143}
144
145#[cfg(test)]
146mod tests {
147	use super::*;
148	use sp_runtime::ModuleInvalidity;
149
150	#[test]
151	fn module_invalidity_becomes_invalid_transaction_event() {
152		let on_node = ModuleInvalidity { index: 42, error: 1 };
153		let err = Error::Pool(PoolError::InvalidTransaction(InvalidTransaction::Module(on_node)));
154
155		let event: TransactionEvent<u64> = err.into();
156
157		assert_eq!(
158			event,
159			TransactionEvent::Invalid(TransactionError {
160				error: "Invalid transaction: module invalidity (pallet: 42, error: 1)".into(),
161			})
162		);
163	}
164}