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

Add ExtrinsicError #616

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/examples/custom_nonce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use sp_runtime::{generic::Era, MultiAddress};
use substrate_api_client::{
ac_primitives::{AssetRuntimeConfig, ExtrinsicSigner, GenericAdditionalParams},
rpc::JsonrpseeClient,
Api, Error, GetChainInfo, SubmitAndWatch, UnexpectedTxStatus, XtStatus,
Api, Error, ExtrinsicError, GetChainInfo, SubmitAndWatch, UnexpectedTxStatus, XtStatus,
};

// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig.
Expand Down Expand Up @@ -64,7 +64,7 @@ async fn main() {
let result = api.submit_and_watch_extrinsic_until_without_events(xt, XtStatus::InBlock);
println!("Returned Result {:?}", result);
match result {
Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Future)) => {
Err(ExtrinsicError::ApiError(Error::UnexpectedTxStatus(UnexpectedTxStatus::Future))) => {
// All good, we expected a Future Error.
},
_ => panic!("Expected a future error"),
Expand Down
33 changes: 26 additions & 7 deletions src/api/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@

*/

use crate::{api::UnexpectedTxStatus, rpc::Error as RpcClientError};
use crate::{api::UnexpectedTxStatus, rpc::Error as RpcClientError, ExtrinsicReport};
use ac_node_api::{
error::DispatchError,
metadata::{InvalidMetadataError, MetadataError},
};
use alloc::boxed::Box;
use codec::Decode;

pub type Result<T> = core::result::Result<T, Error>;

Expand All @@ -40,14 +41,10 @@ pub enum Error {
NodeApi(ac_node_api::error::Error),
/// Encode / Decode Error.
Codec(codec::Error),
/// Could not convert NumberOrHex with try_from.
TryFromIntError,
/// Node Api Dispatch Error.
Dispatch(DispatchError),
/// Encountered unexpected tx status during watch process.
UnexpectedTxStatus(UnexpectedTxStatus),
/// Could not send update because the Stream has been closed unexpectedly.
NoStream,
/// Could not convert NumberOrHex with try_from.
TryFromIntError,
/// Could not find the expected extrinsic.
ExtrinsicNotFound,
/// Could not find the expected block hash.
Expand All @@ -57,3 +54,25 @@ pub enum Error {
/// Any custom Error.
Other(Box<dyn core::error::Error + Send + Sync + 'static>),
}

pub type ExtrinsicResult<T, Hash> = core::result::Result<T, ExtrinsicError<Hash>>;

/// Error Type returned upon submission error.
#[derive(Debug, derive_more::From)]
pub enum ExtrinsicError<Hash: Decode> {
/// Extrinsic was not successfully executed onchain.
FailedExtrinsic(FailedExtrinsicError<Hash>),
/// Api Error.
ApiError(Error),
/// Rpc Client Error.
RpcClient(RpcClientError),
/// Could not send update because the Stream has been closed unexpectedly.
NoStream,
}

/// Encountered unexpected tx status during watch process.
#[derive(Debug)]
pub struct FailedExtrinsicError<Hash: Decode> {
pub dispatch_error: DispatchError,
pub report: ExtrinsicReport<Hash>,
}
2 changes: 1 addition & 1 deletion src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize};
use sp_core::Bytes;

pub use api_client::Api;
pub use error::{Error, Result};
pub use error::{Error, ExtrinsicError, ExtrinsicResult, Result};
pub use rpc_api::{
FetchEvents, GetAccountInformation, GetBalance, GetChainInfo, GetStorage,
GetTransactionPayment, SubmitAndWatch, SubmitExtrinsic, SubscribeChain, SubscribeEvents,
Expand Down
64 changes: 39 additions & 25 deletions src/api/rpc_api/author.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
//! Interface to common author rpc functions and helpers thereof.

use crate::{
api::{rpc_api::events::FetchEvents, Error, Result},
api::{rpc_api::events::FetchEvents, Error, ExtrinsicError, ExtrinsicResult},
error::FailedExtrinsicError,
rpc::{HandleSubscription, Request, Subscribe},
Api, ExtrinsicReport, TransactionStatus, XtStatus,
};
Expand All @@ -32,14 +33,14 @@ pub type TransactionSubscriptionFor<Client, Hash> =
/// Simple extrinsic submission without any subscription.
#[maybe_async::maybe_async(?Send)]
pub trait SubmitExtrinsic {
type Hash;
type Hash: Decode;

/// Submit an encodable extrinsic to the substrate node.
/// Returns the extrinsic hash.
async fn submit_extrinsic<Address, Call, Signature, SignedExtra>(
&self,
extrinsic: UncheckedExtrinsicV4<Address, Call, Signature, SignedExtra>,
) -> Result<Self::Hash>
) -> ExtrinsicResult<Self::Hash, Self::Hash>
where
Address: Encode,
Call: Encode,
Expand All @@ -48,7 +49,10 @@ pub trait SubmitExtrinsic {

/// Submit an encoded, opaque extrsinic to the substrate node.
/// Returns the extrinsic hash.
async fn submit_opaque_extrinsic(&self, encoded_extrinsic: &Bytes) -> Result<Self::Hash>;
async fn submit_opaque_extrinsic(
&self,
encoded_extrinsic: &Bytes,
) -> ExtrinsicResult<Self::Hash, Self::Hash>;
}

#[maybe_async::maybe_async(?Send)]
Expand All @@ -62,7 +66,7 @@ where
async fn submit_extrinsic<Address, Call, Signature, SignedExtra>(
&self,
extrinsic: UncheckedExtrinsicV4<Address, Call, Signature, SignedExtra>,
) -> Result<Self::Hash>
) -> ExtrinsicResult<Self::Hash, Self::Hash>
where
Address: Encode,
Call: Encode,
Expand All @@ -72,7 +76,10 @@ where
self.submit_opaque_extrinsic(&extrinsic.encode().into()).await
}

async fn submit_opaque_extrinsic(&self, encoded_extrinsic: &Bytes) -> Result<Self::Hash> {
async fn submit_opaque_extrinsic(
&self,
encoded_extrinsic: &Bytes,
) -> ExtrinsicResult<Self::Hash, Self::Hash> {
let hex_encoded_xt = rpc_params![encoded_extrinsic];
debug!("sending extrinsic: {:?}", hex_encoded_xt);
let xt_hash = self.client().request("author_submitExtrinsic", hex_encoded_xt).await?;
Expand All @@ -90,7 +97,7 @@ pub trait SubmitAndWatch {
async fn submit_and_watch_extrinsic<Address, Call, Signature, SignedExtra>(
&self,
extrinsic: UncheckedExtrinsicV4<Address, Call, Signature, SignedExtra>,
) -> Result<TransactionSubscriptionFor<Self::Client, Self::Hash>>
) -> ExtrinsicResult<TransactionSubscriptionFor<Self::Client, Self::Hash>, Self::Hash>
where
Address: Encode,
Call: Encode,
Expand All @@ -102,7 +109,7 @@ pub trait SubmitAndWatch {
async fn submit_and_watch_opaque_extrinsic(
&self,
encoded_extrinsic: &Bytes,
) -> Result<TransactionSubscriptionFor<Self::Client, Self::Hash>>;
) -> ExtrinsicResult<TransactionSubscriptionFor<Self::Client, Self::Hash>, Self::Hash>;

/// Submit an extrinsic and watch it until the desired status
/// is reached, if no error is encountered previously.
Expand All @@ -128,7 +135,7 @@ pub trait SubmitAndWatch {
&self,
extrinsic: UncheckedExtrinsicV4<Address, Call, Signature, SignedExtra>,
watch_until: XtStatus,
) -> Result<ExtrinsicReport<Self::Hash>>
) -> ExtrinsicResult<ExtrinsicReport<Self::Hash>, Self::Hash>
where
Address: Encode,
Call: Encode,
Expand Down Expand Up @@ -159,7 +166,7 @@ pub trait SubmitAndWatch {
&self,
encoded_extrinsic: &Bytes,
watch_until: XtStatus,
) -> Result<ExtrinsicReport<Self::Hash>>;
) -> ExtrinsicResult<ExtrinsicReport<Self::Hash>, Self::Hash>;

/// Submit an extrinsic and watch it until the desired status
/// is reached, if no error is encountered previously.
Expand All @@ -180,7 +187,7 @@ pub trait SubmitAndWatch {
&self,
extrinsic: UncheckedExtrinsicV4<Address, Call, Signature, SignedExtra>,
watch_until: XtStatus,
) -> Result<ExtrinsicReport<Self::Hash>>
) -> ExtrinsicResult<ExtrinsicReport<Self::Hash>, Self::Hash>
where
Address: Encode,
Call: Encode,
Expand All @@ -201,7 +208,7 @@ pub trait SubmitAndWatch {
&self,
encoded_extrinsic: &Bytes,
watch_until: XtStatus,
) -> Result<ExtrinsicReport<Self::Hash>>;
) -> ExtrinsicResult<ExtrinsicReport<Self::Hash>, Self::Hash>;
}

#[maybe_async::maybe_async(?Send)]
Expand All @@ -227,7 +234,7 @@ pub trait SubmitAndWatchUntilSuccess {
&self,
extrinsic: UncheckedExtrinsicV4<Address, Call, Signature, SignedExtra>,
wait_for_finalized: bool,
) -> Result<ExtrinsicReport<Self::Hash>>
) -> ExtrinsicResult<ExtrinsicReport<Self::Hash>, Self::Hash>
where
Address: Encode,
Call: Encode,
Expand All @@ -252,7 +259,7 @@ pub trait SubmitAndWatchUntilSuccess {
&self,
encoded_extrinsic: &Bytes,
wait_for_finalized: bool,
) -> Result<ExtrinsicReport<Self::Hash>>;
) -> ExtrinsicResult<ExtrinsicReport<Self::Hash>, Self::Hash>;
}

#[maybe_async::maybe_async(?Send)]
Expand All @@ -267,7 +274,7 @@ where
async fn submit_and_watch_extrinsic<Address, Call, Signature, SignedExtra>(
&self,
extrinsic: UncheckedExtrinsicV4<Address, Call, Signature, SignedExtra>,
) -> Result<TransactionSubscriptionFor<Self::Client, Self::Hash>>
) -> ExtrinsicResult<TransactionSubscriptionFor<Self::Client, Self::Hash>, Self::Hash>
where
Address: Encode,
Call: Encode,
Expand All @@ -280,7 +287,7 @@ where
async fn submit_and_watch_opaque_extrinsic(
&self,
encoded_extrinsic: &Bytes,
) -> Result<TransactionSubscriptionFor<Self::Client, Self::Hash>> {
) -> ExtrinsicResult<TransactionSubscriptionFor<Self::Client, Self::Hash>, Self::Hash> {
self.client()
.subscribe(
"author_submitAndWatchExtrinsic",
Expand All @@ -295,7 +302,7 @@ where
&self,
extrinsic: UncheckedExtrinsicV4<Address, Call, Signature, SignedExtra>,
watch_until: XtStatus,
) -> Result<ExtrinsicReport<Self::Hash>>
) -> ExtrinsicResult<ExtrinsicReport<Self::Hash>, Self::Hash>
where
Address: Encode,
Call: Encode,
Expand All @@ -310,7 +317,7 @@ where
&self,
encoded_extrinsic: &Bytes,
watch_until: XtStatus,
) -> Result<ExtrinsicReport<Self::Hash>> {
) -> ExtrinsicResult<ExtrinsicReport<Self::Hash>, Self::Hash> {
let mut report = self
.submit_and_watch_opaque_extrinsic_until_without_events(encoded_extrinsic, watch_until)
.await?;
Expand All @@ -321,11 +328,18 @@ where
let block_hash = report.block_hash.ok_or(Error::BlockHashNotFound)?;
let extrinsic_events =
self.fetch_events_for_extrinsic(block_hash, report.extrinsic_hash).await?;

// Ensure that the extrins has been successful. If not, return an error.
for event in &extrinsic_events {
event.check_if_failed()?;
if let Err(dispatch_error) = event.check_if_failed() {
report.events = Some(extrinsic_events);
let failed_extrinisc_error = FailedExtrinsicError { dispatch_error, report };
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now return the full information instead of just the dispatch error.

return Err(ExtrinsicError::FailedExtrinsic(failed_extrinisc_error))
}
}

report.events = Some(extrinsic_events);

Ok(report)
}

Expand All @@ -338,7 +352,7 @@ where
&self,
extrinsic: UncheckedExtrinsicV4<Address, Call, Signature, SignedExtra>,
watch_until: XtStatus,
) -> Result<ExtrinsicReport<Self::Hash>>
) -> ExtrinsicResult<ExtrinsicReport<Self::Hash>, Self::Hash>
where
Address: Encode,
Call: Encode,
Expand All @@ -356,7 +370,7 @@ where
&self,
encoded_extrinsic: &Bytes,
watch_until: XtStatus,
) -> Result<ExtrinsicReport<Self::Hash>> {
) -> ExtrinsicResult<ExtrinsicReport<Self::Hash>, Self::Hash> {
let tx_hash = T::Hasher::hash_of(&encoded_extrinsic.0);
let mut subscription: TransactionSubscriptionFor<Self::Client, Self::Hash> =
self.submit_and_watch_opaque_extrinsic(encoded_extrinsic).await?;
Expand All @@ -377,11 +391,11 @@ where
},
Err(e) => {
subscription.unsubscribe().await?;
return Err(e)
return Err(e.into())
},
}
}
Err(Error::NoStream)
Err(ExtrinsicError::NoStream)
}
}

Expand All @@ -398,7 +412,7 @@ where
&self,
extrinsic: UncheckedExtrinsicV4<Address, Call, Signature, SignedExtra>,
wait_for_finalized: bool,
) -> Result<ExtrinsicReport<Self::Hash>>
) -> ExtrinsicResult<ExtrinsicReport<Self::Hash>, Self::Hash>
where
Address: Encode,
Call: Encode,
Expand All @@ -418,7 +432,7 @@ where
&self,
encoded_extrinsic: &Bytes,
wait_for_finalized: bool,
) -> Result<ExtrinsicReport<Self::Hash>> {
) -> ExtrinsicResult<ExtrinsicReport<Self::Hash>, Self::Hash> {
let xt_status = match wait_for_finalized {
true => XtStatus::Finalized,
false => XtStatus::InBlock,
Expand Down
Loading