Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

452 vault client retries transaction submission for unrecoverable errors #453

52 changes: 50 additions & 2 deletions clients/runtime/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ pub enum Error {
CurrencyNotFound,
#[error("PrometheusError: {0}")]
PrometheusError(#[from] PrometheusError),
#[error("Unkown transaction pool issue")]
TransactionPoolIssue,
}

pub enum Recoverability {
Recoverable(String),
Unrecoverable(String),
}

enum RecoverableError {
InabilityToPayFees,
OutdatedTransaction,
}

impl Error {
Expand Down Expand Up @@ -121,10 +133,28 @@ impl Error {
}
}

pub fn is_invalid_transaction(&self) -> Option<String> {
pub fn is_invalid_transaction(&self) -> Option<Recoverability> {
self.map_custom_error(|custom_error| {
if custom_error.code() == POOL_INVALID_TX {
Some(custom_error.data().map(ToString::to_string).unwrap_or_default())
let data_string = custom_error.data().map(ToString::to_string).unwrap_or_default();

if RecoverableError::is_recoverable(&data_string) {
return Some(Recoverability::Recoverable(data_string))
}

return Some(Recoverability::Unrecoverable(data_string))
} else {
None
}
})
}

pub fn is_pool_issue(&self) -> Option<()> {
gianfra-t marked this conversation as resolved.
Show resolved Hide resolved
self.map_custom_error(|custom_error| {
if custom_error.code() == POOL_UNACTIONABLE ||
custom_error.code() == POOL_UNKNOWN_VALIDITY
gianfra-t marked this conversation as resolved.
Show resolved Hide resolved
{
Some(())
} else {
None
}
Expand Down Expand Up @@ -185,6 +215,22 @@ impl Error {
}
}

impl RecoverableError {
// The string which is used to match the error type
fn as_str(&self) -> &'static str {
match self {
gianfra-t marked this conversation as resolved.
Show resolved Hide resolved
RecoverableError::InabilityToPayFees => "Inability to pay some fees",
RecoverableError::OutdatedTransaction => "Transaction is outdated",
}
}

fn is_recoverable(error_message: &str) -> bool {
[RecoverableError::InabilityToPayFees, RecoverableError::OutdatedTransaction]
.iter()
.any(|error| error_message.contains(error.as_str()))
}
}

#[derive(Error, Debug)]
pub enum KeyLoadingError {
#[error("Key not found in file")]
Expand All @@ -200,4 +246,6 @@ pub enum KeyLoadingError {
// https://github.com/paritytech/substrate/blob/e60597dff0aa7ffad623be2cc6edd94c7dc51edd/client/rpc-api/src/author/error.rs#L80
const BASE_ERROR: i32 = 1000;
const POOL_INVALID_TX: i32 = BASE_ERROR + 10;
const POOL_UNKNOWN_VALIDITY: i32 = POOL_INVALID_TX + 1;
const POOL_TOO_LOW_PRIORITY: i32 = POOL_INVALID_TX + 4;
const POOL_UNACTIONABLE: i32 = POOL_INVALID_TX + 8;
29 changes: 19 additions & 10 deletions clients/runtime/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use primitives::Hash;

use crate::{
conn::{new_websocket_client, new_websocket_client_with_retry},
error::Recoverability,
metadata, notify_retry,
types::*,
AccountId, Error, RetryPolicy, ShutdownSender, SpacewalkRuntime, SpacewalkSigner, SubxtError,
Expand Down Expand Up @@ -233,17 +234,25 @@ impl SpacewalkParachain {
|result| async {
match result.map_err(Into::<Error>::into) {
Ok(te) => Ok(te),
Err(err) =>
if let Some(data) = err.is_invalid_transaction() {
Err(RetryPolicy::Skip(Error::InvalidTransaction(data)))
} else if err.is_pool_too_low_priority().is_some() {
Err(RetryPolicy::Skip(Error::PoolTooLowPriority))
} else if err.is_block_hash_not_found_error() {
log::info!("Re-sending transaction after apparent fork");
Err(RetryPolicy::Skip(Error::BlockHashNotFound))
} else {
Err(RetryPolicy::Throw(err))
Err(err) => match err.is_invalid_transaction() {
Some(Recoverability::Recoverable(data)) =>
Err(RetryPolicy::Skip(Error::InvalidTransaction(data))),
Some(Recoverability::Unrecoverable(data)) =>
Err(RetryPolicy::Throw(Error::InvalidTransaction(data))),
None => {
// Handle other errors
if err.is_pool_too_low_priority().is_some() {
Err(RetryPolicy::Skip(Error::PoolTooLowPriority))
} else if err.is_block_hash_not_found_error() {
log::info!("Re-sending transaction after apparent fork");
Err(RetryPolicy::Skip(Error::BlockHashNotFound))
} else if err.is_pool_issue().is_some() {
Err(RetryPolicy::Skip(Error::TransactionPoolIssue))
} else {
Err(RetryPolicy::Throw(err))
}
},
},
}
},
)
Expand Down
8 changes: 7 additions & 1 deletion clients/vault/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,13 @@ impl Service<VaultServiceConfig, Error> for VaultService {
}

async fn start(&mut self) -> Result<(), ServiceError<Error>> {
self.run_service().await
let result = self.run_service().await;
if let Err(error) = result {
let _ = self.shutdown.send(());
Err(error)
} else {
result
}
}
}

Expand Down
Loading