mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 08:51:09 +00:00
Use the generated DispatchError instead of the hardcoded Substrate one (#394)
* WIP DispatchError generic param * main crate now compiling with new E generic param for DispatchError * Remove E param from RpcClient since it doesn't really need it * Point to generated DispatchError in codegen so no need for additional param there * More error hunting; cargo check --all-targets passes now * Use our own RuntimeVersion struct (for now) to avoid error decoding into sp_version::RuntimeVersion * cargo fmt * fix docs and expose private documented thing that I think should be pub * move error info to compile time so that we can make DispatchError a little nicer to work with * cargo fmt * clippy * Rework error handling to remove <E> param in most cases * fix Error doc ambiguity (hopefully) * doc tweaks * docs: remove dismbiguation thing that isn't needed now * One more Error<E> that can be a BasicError * rewrite pallet errors thing into normal loops to tidy * tidy errors codegen a little * tidy examples/custom_type_derives.rs a little * cargo fmt * silcnce clippy in example
This commit is contained in:
@@ -68,7 +68,7 @@ pub fn generate_calls(
|
||||
pub fn #fn_name(
|
||||
&self,
|
||||
#( #call_fn_args, )*
|
||||
) -> ::subxt::SubmittableExtrinsic<'a, T, E, A, #call_struct_name> {
|
||||
) -> ::subxt::SubmittableExtrinsic<'a, T, X, A, #call_struct_name, DispatchError> {
|
||||
let call = #call_struct_name { #( #call_args, )* };
|
||||
::subxt::SubmittableExtrinsic::new(self.client, call)
|
||||
}
|
||||
@@ -80,17 +80,20 @@ pub fn generate_calls(
|
||||
quote! {
|
||||
pub mod calls {
|
||||
use super::#types_mod_ident;
|
||||
|
||||
type DispatchError = #types_mod_ident::sp_runtime::DispatchError;
|
||||
|
||||
#( #call_structs )*
|
||||
|
||||
pub struct TransactionApi<'a, T: ::subxt::Config, E, A> {
|
||||
pub struct TransactionApi<'a, T: ::subxt::Config, X, A> {
|
||||
client: &'a ::subxt::Client<T>,
|
||||
marker: ::core::marker::PhantomData<(E, A)>,
|
||||
marker: ::core::marker::PhantomData<(X, A)>,
|
||||
}
|
||||
|
||||
impl<'a, T, E, A> TransactionApi<'a, T, E, A>
|
||||
impl<'a, T, X, A> TransactionApi<'a, T, X, A>
|
||||
where
|
||||
T: ::subxt::Config,
|
||||
E: ::subxt::SignedExtra<T>,
|
||||
X: ::subxt::SignedExtra<T>,
|
||||
A: ::subxt::AccountData<T>,
|
||||
{
|
||||
pub fn new(client: &'a ::subxt::Client<T>) -> Self {
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||
// This file is part of subxt.
|
||||
//
|
||||
// subxt is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// subxt is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use frame_metadata::v14::RuntimeMetadataV14;
|
||||
use proc_macro2::{
|
||||
Span as Span2,
|
||||
TokenStream as TokenStream2,
|
||||
};
|
||||
use quote::quote;
|
||||
|
||||
/// Tokens which allow us to provide static error information in the generated output.
|
||||
pub struct ErrorDetails {
|
||||
/// This type definition will be used in the `dispatch_error_impl_fn` and is
|
||||
/// expected to be generated somewhere in scope for that to be possible.
|
||||
pub type_def: TokenStream2,
|
||||
// A function which will live in an impl block for our `DispatchError`,
|
||||
// to statically return details for known error types:
|
||||
pub dispatch_error_impl_fn: TokenStream2,
|
||||
}
|
||||
|
||||
impl ErrorDetails {
|
||||
fn emit_compile_error(err: &str) -> ErrorDetails {
|
||||
let err_lit_str = syn::LitStr::new(err, Span2::call_site());
|
||||
ErrorDetails {
|
||||
type_def: quote!(),
|
||||
dispatch_error_impl_fn: quote!(compile_error!(#err_lit_str)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The purpose of this is to enumerate all of the possible `(module_index, error_index)` error
|
||||
/// variants, so that we can convert `u8` error codes inside a generated `DispatchError` into
|
||||
/// nicer error strings with documentation. To do this, we emit the type we'll return instances of,
|
||||
/// and a function that returns such an instance for all of the error codes seen in the metadata.
|
||||
pub fn generate_error_details(metadata: &RuntimeMetadataV14) -> ErrorDetails {
|
||||
let errors = match pallet_errors(metadata) {
|
||||
Ok(errors) => errors,
|
||||
Err(e) => {
|
||||
let err_string =
|
||||
format!("Failed to generate error details from metadata: {}", e);
|
||||
return ErrorDetails::emit_compile_error(&err_string)
|
||||
}
|
||||
};
|
||||
|
||||
let match_body_items = errors.into_iter().map(|err| {
|
||||
let docs = err.docs;
|
||||
let pallet_index = err.pallet_index;
|
||||
let error_index = err.error_index;
|
||||
let pallet_name = err.pallet;
|
||||
let error_name = err.error;
|
||||
|
||||
quote! {
|
||||
(#pallet_index, #error_index) => Some(ErrorDetails {
|
||||
pallet: #pallet_name,
|
||||
error: #error_name,
|
||||
docs: #docs
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
ErrorDetails {
|
||||
type_def: quote! {
|
||||
pub struct ErrorDetails {
|
||||
pub pallet: &'static str,
|
||||
pub error: &'static str,
|
||||
pub docs: &'static str,
|
||||
}
|
||||
},
|
||||
dispatch_error_impl_fn: quote! {
|
||||
pub fn details(&self) -> Option<ErrorDetails> {
|
||||
if let Self::Module { index, error } = self {
|
||||
match (index, error) {
|
||||
#( #match_body_items ),*,
|
||||
_ => None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn pallet_errors(
|
||||
metadata: &RuntimeMetadataV14,
|
||||
) -> Result<Vec<ErrorMetadata>, InvalidMetadataError> {
|
||||
let get_type_def_variant = |type_id: u32| {
|
||||
let ty = metadata
|
||||
.types
|
||||
.resolve(type_id)
|
||||
.ok_or(InvalidMetadataError::MissingType(type_id))?;
|
||||
if let scale_info::TypeDef::Variant(var) = ty.type_def() {
|
||||
Ok(var)
|
||||
} else {
|
||||
Err(InvalidMetadataError::TypeDefNotVariant(type_id))
|
||||
}
|
||||
};
|
||||
|
||||
let mut pallet_errors = vec![];
|
||||
for pallet in &metadata.pallets {
|
||||
let error = match &pallet.error {
|
||||
Some(err) => err,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let type_def_variant = get_type_def_variant(error.ty.id())?;
|
||||
for var in type_def_variant.variants().iter() {
|
||||
pallet_errors.push(ErrorMetadata {
|
||||
pallet_index: pallet.index,
|
||||
error_index: var.index(),
|
||||
pallet: pallet.name.clone(),
|
||||
error: var.name().clone(),
|
||||
docs: var.docs().join("\n"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(pallet_errors)
|
||||
}
|
||||
|
||||
/// Information about each error that we find in the metadata;
|
||||
/// used to generate the static error information.
|
||||
#[derive(Clone, Debug)]
|
||||
struct ErrorMetadata {
|
||||
pub pallet_index: u8,
|
||||
pub error_index: u8,
|
||||
pub pallet: String,
|
||||
pub error: String,
|
||||
pub docs: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum InvalidMetadataError {
|
||||
MissingType(u32),
|
||||
TypeDefNotVariant(u32),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for InvalidMetadataError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
InvalidMetadataError::MissingType(n) => {
|
||||
write!(f, "Type {} missing from type registry", n)
|
||||
}
|
||||
InvalidMetadataError::TypeDefNotVariant(n) => {
|
||||
write!(f, "Type {} was not a variant/enum type", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
-12
@@ -15,6 +15,7 @@
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
mod calls;
|
||||
mod errors;
|
||||
mod events;
|
||||
mod storage;
|
||||
|
||||
@@ -216,6 +217,10 @@ impl RuntimeGenerator {
|
||||
pallet.calls.as_ref().map(|_| pallet_mod_name)
|
||||
});
|
||||
|
||||
let error_details = errors::generate_error_details(&self.metadata);
|
||||
let error_type = error_details.type_def;
|
||||
let error_fn = error_details.dispatch_error_impl_fn;
|
||||
|
||||
quote! {
|
||||
#[allow(dead_code, unused_imports, non_camel_case_types)]
|
||||
pub mod #mod_ident {
|
||||
@@ -227,6 +232,15 @@ impl RuntimeGenerator {
|
||||
/// constructing a transaction.
|
||||
pub type DefaultAccountData = self::system::storage::Account;
|
||||
|
||||
/// The default error type returned when there is a runtime issue.
|
||||
pub type DispatchError = self::runtime_types::sp_runtime::DispatchError;
|
||||
|
||||
// Statically generate error information so that we don't need runtime metadata for it.
|
||||
#error_type
|
||||
impl DispatchError {
|
||||
#error_fn
|
||||
}
|
||||
|
||||
impl ::subxt::AccountData<::subxt::DefaultConfig> for DefaultAccountData {
|
||||
fn nonce(result: &<Self as ::subxt::StorageEntry>::Value) -> <::subxt::DefaultConfig as ::subxt::Config>::Index {
|
||||
result.nonce
|
||||
@@ -236,31 +250,31 @@ impl RuntimeGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RuntimeApi<T: ::subxt::Config, E> {
|
||||
pub struct RuntimeApi<T: ::subxt::Config, X> {
|
||||
pub client: ::subxt::Client<T>,
|
||||
marker: ::core::marker::PhantomData<E>,
|
||||
marker: ::core::marker::PhantomData<X>,
|
||||
}
|
||||
|
||||
impl<T, E> ::core::convert::From<::subxt::Client<T>> for RuntimeApi<T, E>
|
||||
impl<T, X> ::core::convert::From<::subxt::Client<T>> for RuntimeApi<T, X>
|
||||
where
|
||||
T: ::subxt::Config,
|
||||
E: ::subxt::SignedExtra<T>,
|
||||
X: ::subxt::SignedExtra<T>,
|
||||
{
|
||||
fn from(client: ::subxt::Client<T>) -> Self {
|
||||
Self { client, marker: ::core::marker::PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, E> RuntimeApi<T, E>
|
||||
impl<'a, T, X> RuntimeApi<T, X>
|
||||
where
|
||||
T: ::subxt::Config,
|
||||
E: ::subxt::SignedExtra<T>,
|
||||
X: ::subxt::SignedExtra<T>,
|
||||
{
|
||||
pub fn storage(&'a self) -> StorageApi<'a, T> {
|
||||
StorageApi { client: &self.client }
|
||||
}
|
||||
|
||||
pub fn tx(&'a self) -> TransactionApi<'a, T, E, DefaultAccountData> {
|
||||
pub fn tx(&'a self) -> TransactionApi<'a, T, X, DefaultAccountData> {
|
||||
TransactionApi { client: &self.client, marker: ::core::marker::PhantomData }
|
||||
}
|
||||
}
|
||||
@@ -280,19 +294,19 @@ impl RuntimeGenerator {
|
||||
)*
|
||||
}
|
||||
|
||||
pub struct TransactionApi<'a, T: ::subxt::Config, E, A> {
|
||||
pub struct TransactionApi<'a, T: ::subxt::Config, X, A> {
|
||||
client: &'a ::subxt::Client<T>,
|
||||
marker: ::core::marker::PhantomData<(E, A)>,
|
||||
marker: ::core::marker::PhantomData<(X, A)>,
|
||||
}
|
||||
|
||||
impl<'a, T, E, A> TransactionApi<'a, T, E, A>
|
||||
impl<'a, T, X, A> TransactionApi<'a, T, X, A>
|
||||
where
|
||||
T: ::subxt::Config,
|
||||
E: ::subxt::SignedExtra<T>,
|
||||
X: ::subxt::SignedExtra<T>,
|
||||
A: ::subxt::AccountData<T>,
|
||||
{
|
||||
#(
|
||||
pub fn #pallets_with_calls(&self) -> #pallets_with_calls::calls::TransactionApi<'a, T, E, A> {
|
||||
pub fn #pallets_with_calls(&self) -> #pallets_with_calls::calls::TransactionApi<'a, T, X, A> {
|
||||
#pallets_with_calls::calls::TransactionApi::new(self.client)
|
||||
}
|
||||
)*
|
||||
|
||||
@@ -50,6 +50,7 @@ pub fn generate_storage(
|
||||
quote! {
|
||||
pub mod storage {
|
||||
use super::#types_mod_ident;
|
||||
|
||||
#( #storage_structs )*
|
||||
|
||||
pub struct StorageApi<'a, T: ::subxt::Config> {
|
||||
@@ -195,7 +196,7 @@ fn generate_storage_entry_fns(
|
||||
pub async fn #fn_name_iter(
|
||||
&self,
|
||||
hash: ::core::option::Option<T::Hash>,
|
||||
) -> ::core::result::Result<::subxt::KeyIter<'a, T, #entry_struct_ident>, ::subxt::Error> {
|
||||
) -> ::core::result::Result<::subxt::KeyIter<'a, T, #entry_struct_ident>, ::subxt::BasicError> {
|
||||
self.client.storage().iter(hash).await
|
||||
}
|
||||
)
|
||||
@@ -211,7 +212,7 @@ fn generate_storage_entry_fns(
|
||||
&self,
|
||||
#( #key_args, )*
|
||||
hash: ::core::option::Option<T::Hash>,
|
||||
) -> ::core::result::Result<#return_ty, ::subxt::Error> {
|
||||
) -> ::core::result::Result<#return_ty, ::subxt::BasicError> {
|
||||
let entry = #constructor;
|
||||
self.client.storage().#fetch(&entry, hash).await
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ impl Default for GeneratedTypeDerives {
|
||||
let mut derives = Punctuated::new();
|
||||
derives.push(syn::parse_quote!(::subxt::codec::Encode));
|
||||
derives.push(syn::parse_quote!(::subxt::codec::Decode));
|
||||
derives.push(syn::parse_quote!(Debug));
|
||||
Self::new(derives)
|
||||
}
|
||||
}
|
||||
|
||||
+34
-34
@@ -64,7 +64,7 @@ fn generate_struct_with_primitives() {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct S {
|
||||
pub a: ::core::primitive::bool,
|
||||
pub b: ::core::primitive::u32,
|
||||
@@ -110,12 +110,12 @@ fn generate_struct_with_a_struct_field() {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Child {
|
||||
pub a: ::core::primitive::i32,
|
||||
}
|
||||
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Parent {
|
||||
pub a: ::core::primitive::bool,
|
||||
pub b: root::subxt_codegen::types::tests::Child,
|
||||
@@ -155,10 +155,10 @@ fn generate_tuple_struct() {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Child(pub ::core::primitive::i32,);
|
||||
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Parent(pub ::core::primitive::bool, pub root::subxt_codegen::types::tests::Child,);
|
||||
}
|
||||
}
|
||||
@@ -238,43 +238,43 @@ fn derive_compact_as_for_uint_wrapper_structs() {
|
||||
use super::root;
|
||||
|
||||
#[derive(::subxt::codec::CompactAs)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Su128 { pub a: ::core::primitive::u128, }
|
||||
|
||||
#[derive(::subxt::codec::CompactAs)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Su16 { pub a: ::core::primitive::u16, }
|
||||
|
||||
#[derive(::subxt::codec::CompactAs)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Su32 { pub a: ::core::primitive::u32, }
|
||||
|
||||
#[derive(::subxt::codec::CompactAs)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Su64 { pub a: ::core::primitive::u64, }
|
||||
|
||||
#[derive(::subxt::codec::CompactAs)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Su8 { pub a: ::core::primitive::u8, }
|
||||
|
||||
#[derive(::subxt::codec::CompactAs)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct TSu128(pub ::core::primitive::u128,);
|
||||
|
||||
#[derive(::subxt::codec::CompactAs)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct TSu16(pub ::core::primitive::u16,);
|
||||
|
||||
#[derive(::subxt::codec::CompactAs)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct TSu32(pub ::core::primitive::u32,);
|
||||
|
||||
#[derive(::subxt::codec::CompactAs)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct TSu64(pub ::core::primitive::u64,);
|
||||
|
||||
#[derive(::subxt::codec::CompactAs)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct TSu8(pub ::core::primitive::u8,);
|
||||
}
|
||||
}
|
||||
@@ -310,7 +310,7 @@ fn generate_enum() {
|
||||
quote! {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub enum E {
|
||||
# [codec (index = 0)]
|
||||
A,
|
||||
@@ -368,7 +368,7 @@ fn compact_fields() {
|
||||
quote! {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub enum E {
|
||||
# [codec (index = 0)]
|
||||
A {
|
||||
@@ -379,12 +379,12 @@ fn compact_fields() {
|
||||
B( #[codec(compact)] ::core::primitive::u32,),
|
||||
}
|
||||
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct S {
|
||||
#[codec(compact)] pub a: ::core::primitive::u32,
|
||||
}
|
||||
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct TupleStruct(#[codec(compact)] pub ::core::primitive::u32,);
|
||||
}
|
||||
}
|
||||
@@ -418,7 +418,7 @@ fn generate_array_field() {
|
||||
quote! {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct S {
|
||||
pub a: [::core::primitive::u8; 32usize],
|
||||
}
|
||||
@@ -455,7 +455,7 @@ fn option_fields() {
|
||||
quote! {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct S {
|
||||
pub a: ::core::option::Option<::core::primitive::bool>,
|
||||
pub b: ::core::option::Option<::core::primitive::u32>,
|
||||
@@ -495,7 +495,7 @@ fn box_fields_struct() {
|
||||
quote! {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct S {
|
||||
pub a: ::std::boxed::Box<::core::primitive::bool>,
|
||||
pub b: ::std::boxed::Box<::core::primitive::u32>,
|
||||
@@ -535,7 +535,7 @@ fn box_fields_enum() {
|
||||
quote! {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub enum E {
|
||||
# [codec (index = 0)]
|
||||
A(::std::boxed::Box<::core::primitive::bool>,),
|
||||
@@ -575,7 +575,7 @@ fn range_fields() {
|
||||
quote! {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct S {
|
||||
pub a: ::core::ops::Range<::core::primitive::u32>,
|
||||
pub b: ::core::ops::RangeInclusive<::core::primitive::u32>,
|
||||
@@ -619,12 +619,12 @@ fn generics() {
|
||||
quote! {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Bar {
|
||||
pub b: root::subxt_codegen::types::tests::Foo<::core::primitive::u32>,
|
||||
pub c: root::subxt_codegen::types::tests::Foo<::core::primitive::u8>,
|
||||
}
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Foo<_0> {
|
||||
pub a: _0,
|
||||
}
|
||||
@@ -667,12 +667,12 @@ fn generics_nested() {
|
||||
quote! {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Bar<_0> {
|
||||
pub b: root::subxt_codegen::types::tests::Foo<_0, ::core::primitive::u32>,
|
||||
}
|
||||
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Foo<_0, _1> {
|
||||
pub a: _0,
|
||||
pub b: ::core::option::Option<(_0, _1,)>,
|
||||
@@ -718,7 +718,7 @@ fn generate_bitvec() {
|
||||
quote! {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct S {
|
||||
pub lsb: ::subxt::bitvec::vec::BitVec<root::bitvec::order::Lsb0, ::core::primitive::u8>,
|
||||
pub msb: ::subxt::bitvec::vec::BitVec<root::bitvec::order::Msb0, ::core::primitive::u16>,
|
||||
@@ -772,12 +772,12 @@ fn generics_with_alias_adds_phantom_data_marker() {
|
||||
pub mod tests {
|
||||
use super::root;
|
||||
#[derive(::subxt::codec::CompactAs)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct NamedFields<_0> {
|
||||
pub b: ::core::primitive::u32,
|
||||
#[codec(skip)] pub __subxt_unused_type_params: ::core::marker::PhantomData<_0>,
|
||||
}
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct UnnamedFields<_0, _1> (
|
||||
pub (::core::primitive::u32, ::core::primitive::u32,),
|
||||
#[codec(skip)] pub ::core::marker::PhantomData<(_0, _1)>,
|
||||
@@ -840,20 +840,20 @@ fn modules() {
|
||||
pub mod b {
|
||||
use super::root;
|
||||
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Bar {
|
||||
pub a: root::subxt_codegen::types::tests::m::a::Foo,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Foo {}
|
||||
}
|
||||
|
||||
pub mod c {
|
||||
use super::root;
|
||||
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode)]
|
||||
#[derive(::subxt::codec::Encode, ::subxt::codec::Decode, Debug)]
|
||||
pub struct Foo {
|
||||
pub a: root::subxt_codegen::types::tests::m::a::b::Bar,
|
||||
}
|
||||
|
||||
@@ -14,9 +14,13 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#![allow(clippy::redundant_clone)]
|
||||
|
||||
#[subxt::subxt(
|
||||
runtime_metadata_path = "examples/polkadot_metadata.scale",
|
||||
generated_type_derives = "Clone, Debug"
|
||||
// We can add (certain) custom derives to the generated types by providing
|
||||
// a comma separated list to the below attribute. Most useful for adding `Clone`:
|
||||
generated_type_derives = "Clone, Hash"
|
||||
)]
|
||||
pub mod polkadot {}
|
||||
|
||||
@@ -25,6 +29,6 @@ use polkadot::runtime_types::frame_support::PalletId;
|
||||
#[async_std::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let pallet_id = PalletId([1u8; 8]);
|
||||
let _ = <PalletId as Clone>::clone(&pallet_id);
|
||||
let _ = pallet_id.clone();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+20
-16
@@ -19,7 +19,7 @@ use sp_runtime::traits::Hash;
|
||||
pub use sp_runtime::traits::SignedExtension;
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
error::BasicError,
|
||||
events::EventsDecoder,
|
||||
extrinsic::{
|
||||
self,
|
||||
@@ -40,6 +40,7 @@ use crate::{
|
||||
Config,
|
||||
Metadata,
|
||||
};
|
||||
use codec::Decode;
|
||||
use derivative::Derivative;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -80,7 +81,7 @@ impl ClientBuilder {
|
||||
}
|
||||
|
||||
/// Creates a new Client.
|
||||
pub async fn build<T: Config>(self) -> Result<Client<T>, Error> {
|
||||
pub async fn build<T: Config>(self) -> Result<Client<T>, BasicError> {
|
||||
let client = if let Some(client) = self.client {
|
||||
client
|
||||
} else {
|
||||
@@ -186,18 +187,19 @@ impl<T: Config> Client<T> {
|
||||
}
|
||||
|
||||
/// A constructed call ready to be signed and submitted.
|
||||
pub struct SubmittableExtrinsic<'client, T: Config, E, A, C> {
|
||||
pub struct SubmittableExtrinsic<'client, T: Config, X, A, C, E: Decode> {
|
||||
client: &'client Client<T>,
|
||||
call: C,
|
||||
marker: std::marker::PhantomData<(E, A)>,
|
||||
marker: std::marker::PhantomData<(X, A, E)>,
|
||||
}
|
||||
|
||||
impl<'client, T, E, A, C> SubmittableExtrinsic<'client, T, E, A, C>
|
||||
impl<'client, T, X, A, C, E> SubmittableExtrinsic<'client, T, X, A, C, E>
|
||||
where
|
||||
T: Config,
|
||||
E: SignedExtra<T>,
|
||||
X: SignedExtra<T>,
|
||||
A: AccountData<T>,
|
||||
C: Call + Send + Sync,
|
||||
E: Decode,
|
||||
{
|
||||
/// Create a new [`SubmittableExtrinsic`].
|
||||
pub fn new(client: &'client Client<T>, call: C) -> Self {
|
||||
@@ -214,16 +216,18 @@ where
|
||||
/// and obtain details about it, once it has made it into a block.
|
||||
pub async fn sign_and_submit_then_watch(
|
||||
self,
|
||||
signer: &(dyn Signer<T, E> + Send + Sync),
|
||||
) -> Result<TransactionProgress<'client, T>, Error>
|
||||
signer: &(dyn Signer<T, X> + Send + Sync),
|
||||
) -> Result<TransactionProgress<'client, T, E>, BasicError>
|
||||
where
|
||||
<<E as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
||||
<<X as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
||||
Send + Sync + 'static,
|
||||
{
|
||||
// Sign the call data to create our extrinsic.
|
||||
let extrinsic = self.create_signed(signer, Default::default()).await?;
|
||||
|
||||
// Get a hash of the extrinsic (we'll need this later).
|
||||
let ext_hash = T::Hashing::hash_of(&extrinsic);
|
||||
|
||||
// Submit and watch for transaction progress.
|
||||
let sub = self.client.rpc().watch_extrinsic(extrinsic).await?;
|
||||
|
||||
@@ -240,10 +244,10 @@ where
|
||||
/// and has been included in the transaction pool.
|
||||
pub async fn sign_and_submit(
|
||||
self,
|
||||
signer: &(dyn Signer<T, E> + Send + Sync),
|
||||
) -> Result<T::Hash, Error>
|
||||
signer: &(dyn Signer<T, X> + Send + Sync),
|
||||
) -> Result<T::Hash, BasicError>
|
||||
where
|
||||
<<E as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
||||
<<X as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
||||
Send + Sync + 'static,
|
||||
{
|
||||
let extrinsic = self.create_signed(signer, Default::default()).await?;
|
||||
@@ -253,11 +257,11 @@ where
|
||||
/// Creates a signed extrinsic.
|
||||
pub async fn create_signed(
|
||||
&self,
|
||||
signer: &(dyn Signer<T, E> + Send + Sync),
|
||||
additional_params: E::Parameters,
|
||||
) -> Result<UncheckedExtrinsic<T, E>, Error>
|
||||
signer: &(dyn Signer<T, X> + Send + Sync),
|
||||
additional_params: X::Parameters,
|
||||
) -> Result<UncheckedExtrinsic<T, X>, BasicError>
|
||||
where
|
||||
<<E as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
||||
<<X as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
||||
Send + Sync + 'static,
|
||||
{
|
||||
let account_nonce = if let Some(nonce) = signer.nonce() {
|
||||
|
||||
+93
-88
@@ -20,19 +20,23 @@ use crate::{
|
||||
InvalidMetadataError,
|
||||
MetadataError,
|
||||
},
|
||||
Metadata,
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
use jsonrpsee::core::error::Error as RequestError;
|
||||
use sp_core::crypto::SecretStringError;
|
||||
use sp_runtime::{
|
||||
transaction_validity::TransactionValidityError,
|
||||
DispatchError,
|
||||
};
|
||||
use thiserror::Error;
|
||||
use sp_runtime::transaction_validity::TransactionValidityError;
|
||||
|
||||
/// Error enum.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// An error that may contain some runtime error `E`
|
||||
pub type Error<E> = GenericError<RuntimeError<E>>;
|
||||
|
||||
/// An error that will never contain a runtime error.
|
||||
pub type BasicError = GenericError<std::convert::Infallible>;
|
||||
|
||||
/// The underlying error enum, generic over the type held by the `Runtime`
|
||||
/// variant. Prefer to use the [`Error<E>`] and [`BasicError`] aliases over
|
||||
/// using this type directly.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum GenericError<E> {
|
||||
/// Io error.
|
||||
#[error("Io error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
@@ -58,8 +62,8 @@ pub enum Error {
|
||||
#[error("Metadata: {0}")]
|
||||
Metadata(#[from] MetadataError),
|
||||
/// Runtime error.
|
||||
#[error("Runtime error: {0}")]
|
||||
Runtime(#[from] RuntimeError),
|
||||
#[error("Runtime error: {0:?}")]
|
||||
Runtime(E),
|
||||
/// Events decoding error.
|
||||
#[error("Events decoding error: {0}")]
|
||||
EventsDecoding(#[from] EventsDecodingError),
|
||||
@@ -71,87 +75,88 @@ pub enum Error {
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl From<SecretStringError> for Error {
|
||||
fn from(error: SecretStringError) -> Self {
|
||||
Error::SecretString(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransactionValidityError> for Error {
|
||||
fn from(error: TransactionValidityError) -> Self {
|
||||
Error::Invalid(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Error {
|
||||
fn from(error: &str) -> Self {
|
||||
Error::Other(error.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Error {
|
||||
fn from(error: String) -> Self {
|
||||
Error::Other(error)
|
||||
}
|
||||
}
|
||||
|
||||
/// Runtime error.
|
||||
#[derive(Clone, Debug, Eq, Error, PartialEq)]
|
||||
pub enum RuntimeError {
|
||||
/// Module error.
|
||||
#[error("Runtime module error: {0}")]
|
||||
Module(PalletError),
|
||||
/// At least one consumer is remaining so the account cannot be destroyed.
|
||||
#[error("At least one consumer is remaining so the account cannot be destroyed.")]
|
||||
ConsumerRemaining,
|
||||
/// There are no providers so the account cannot be created.
|
||||
#[error("There are no providers so the account cannot be created.")]
|
||||
NoProviders,
|
||||
/// Bad origin.
|
||||
#[error("Bad origin: throw by ensure_signed, ensure_root or ensure_none.")]
|
||||
BadOrigin,
|
||||
/// Cannot lookup.
|
||||
#[error("Cannot lookup some information required to validate the transaction.")]
|
||||
CannotLookup,
|
||||
/// Other error.
|
||||
#[error("Other error: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl RuntimeError {
|
||||
/// Converts a `DispatchError` into a subxt error.
|
||||
pub fn from_dispatch(
|
||||
metadata: &Metadata,
|
||||
error: DispatchError,
|
||||
) -> Result<Self, Error> {
|
||||
match error {
|
||||
DispatchError::Module {
|
||||
index,
|
||||
error,
|
||||
message: _,
|
||||
} => {
|
||||
let error = metadata.error(index, error)?;
|
||||
Ok(Self::Module(PalletError {
|
||||
pallet: error.pallet().to_string(),
|
||||
error: error.error().to_string(),
|
||||
description: error.description().to_vec(),
|
||||
}))
|
||||
}
|
||||
DispatchError::BadOrigin => Ok(Self::BadOrigin),
|
||||
DispatchError::CannotLookup => Ok(Self::CannotLookup),
|
||||
DispatchError::ConsumerRemaining => Ok(Self::ConsumerRemaining),
|
||||
DispatchError::NoProviders => Ok(Self::NoProviders),
|
||||
DispatchError::Arithmetic(_math_error) => {
|
||||
Ok(Self::Other("math_error".into()))
|
||||
}
|
||||
DispatchError::Token(_token_error) => Ok(Self::Other("token error".into())),
|
||||
DispatchError::Other(msg) => Ok(Self::Other(msg.to_string())),
|
||||
impl<E> GenericError<E> {
|
||||
/// [`GenericError`] is parameterised over the type that it holds in the `Runtime`
|
||||
/// variant. This function allows us to map the Runtime error contained within (if present)
|
||||
/// to a different type.
|
||||
pub fn map_runtime_err<F, NewE>(self, f: F) -> GenericError<NewE>
|
||||
where
|
||||
F: FnOnce(E) -> NewE,
|
||||
{
|
||||
match self {
|
||||
GenericError::Io(e) => GenericError::Io(e),
|
||||
GenericError::Codec(e) => GenericError::Codec(e),
|
||||
GenericError::Rpc(e) => GenericError::Rpc(e),
|
||||
GenericError::Serialization(e) => GenericError::Serialization(e),
|
||||
GenericError::SecretString(e) => GenericError::SecretString(e),
|
||||
GenericError::Invalid(e) => GenericError::Invalid(e),
|
||||
GenericError::InvalidMetadata(e) => GenericError::InvalidMetadata(e),
|
||||
GenericError::Metadata(e) => GenericError::Metadata(e),
|
||||
GenericError::EventsDecoding(e) => GenericError::EventsDecoding(e),
|
||||
GenericError::Transaction(e) => GenericError::Transaction(e),
|
||||
GenericError::Other(e) => GenericError::Other(e),
|
||||
// This is the only branch we really care about:
|
||||
GenericError::Runtime(e) => GenericError::Runtime(f(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BasicError {
|
||||
/// Convert an [`BasicError`] into any
|
||||
/// arbitrary [`Error<E>`].
|
||||
pub fn into_error<E>(self) -> Error<E> {
|
||||
self.map_runtime_err(|e| match e {})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> From<BasicError> for Error<E> {
|
||||
fn from(err: BasicError) -> Self {
|
||||
err.into_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> From<SecretStringError> for GenericError<E> {
|
||||
fn from(error: SecretStringError) -> Self {
|
||||
GenericError::SecretString(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> From<TransactionValidityError> for GenericError<E> {
|
||||
fn from(error: TransactionValidityError) -> Self {
|
||||
GenericError::Invalid(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> From<&str> for GenericError<E> {
|
||||
fn from(error: &str) -> Self {
|
||||
GenericError::Other(error.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> From<String> for GenericError<E> {
|
||||
fn from(error: String) -> Self {
|
||||
GenericError::Other(error)
|
||||
}
|
||||
}
|
||||
|
||||
/// This is used in the place of the `E` in [`GenericError<E>`] when we may have a
|
||||
/// Runtime Error. We use this wrapper so that it is possible to implement
|
||||
/// `From<Error<Infallible>` for `Error<RuntimeError<E>>`.
|
||||
///
|
||||
/// This should not be used as a type; prefer to use the alias [`Error<E>`] when referring
|
||||
/// to errors which may contain some Runtime error `E`.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct RuntimeError<E>(pub E);
|
||||
|
||||
impl<E> RuntimeError<E> {
|
||||
/// Extract the actual runtime error from this struct.
|
||||
pub fn inner(self) -> E {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Module error.
|
||||
#[derive(Clone, Debug, Eq, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
|
||||
#[error("{error} from {pallet}")]
|
||||
pub struct PalletError {
|
||||
/// The module where the error originated.
|
||||
@@ -163,7 +168,7 @@ pub struct PalletError {
|
||||
}
|
||||
|
||||
/// Transaction error.
|
||||
#[derive(Clone, Debug, Eq, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
|
||||
pub enum TransactionError {
|
||||
/// The finality subscription expired (after ~512 blocks we give up if the
|
||||
/// block hasn't yet been finalized).
|
||||
|
||||
+6
-6
@@ -15,12 +15,12 @@
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
error::BasicError,
|
||||
metadata::{
|
||||
EventMetadata,
|
||||
MetadataError,
|
||||
},
|
||||
Config,
|
||||
Error,
|
||||
Event,
|
||||
Metadata,
|
||||
PhantomDataSendSync,
|
||||
@@ -89,7 +89,7 @@ impl<T: Config> EventsDecoder<T> {
|
||||
pub fn decode_events(
|
||||
&self,
|
||||
input: &mut &[u8],
|
||||
) -> Result<Vec<(Phase, RawEvent)>, Error> {
|
||||
) -> Result<Vec<(Phase, RawEvent)>, BasicError> {
|
||||
let compact_len = <Compact<u32>>::decode(input)?;
|
||||
let len = compact_len.0 as usize;
|
||||
log::debug!("decoding {} events", len);
|
||||
@@ -142,7 +142,7 @@ impl<T: Config> EventsDecoder<T> {
|
||||
event_metadata: &EventMetadata,
|
||||
input: &mut &[u8],
|
||||
output: &mut Vec<u8>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), BasicError> {
|
||||
log::debug!(
|
||||
"Decoding Event '{}::{}'",
|
||||
event_metadata.pallet(),
|
||||
@@ -160,7 +160,7 @@ impl<T: Config> EventsDecoder<T> {
|
||||
type_id: u32,
|
||||
input: &mut &[u8],
|
||||
output: &mut Vec<u8>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), BasicError> {
|
||||
let ty = self
|
||||
.metadata
|
||||
.resolve_type(type_id)
|
||||
@@ -169,7 +169,7 @@ impl<T: Config> EventsDecoder<T> {
|
||||
fn decode_raw<T: Codec>(
|
||||
input: &mut &[u8],
|
||||
output: &mut Vec<u8>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), BasicError> {
|
||||
let decoded = T::decode(input)?;
|
||||
decoded.encode_to(output);
|
||||
Ok(())
|
||||
@@ -190,7 +190,7 @@ impl<T: Config> EventsDecoder<T> {
|
||||
.iter()
|
||||
.find(|v| v.index() == variant_index)
|
||||
.ok_or_else(|| {
|
||||
Error::Other(format!("Variant {} not found", variant_index))
|
||||
BasicError::Other(format!("Variant {} not found", variant_index))
|
||||
})?;
|
||||
for field in variant.fields() {
|
||||
self.decode_type(field.ty().id(), input, output)?;
|
||||
|
||||
+14
-13
@@ -22,6 +22,7 @@ mod signer;
|
||||
pub use self::{
|
||||
extra::{
|
||||
ChargeAssetTxPayment,
|
||||
ChargeTransactionPayment,
|
||||
CheckGenesis,
|
||||
CheckMortality,
|
||||
CheckNonce,
|
||||
@@ -41,48 +42,48 @@ pub use self::{
|
||||
use sp_runtime::traits::SignedExtension;
|
||||
|
||||
use crate::{
|
||||
error::BasicError,
|
||||
rpc::RuntimeVersion,
|
||||
Config,
|
||||
Encoded,
|
||||
Error,
|
||||
};
|
||||
|
||||
/// UncheckedExtrinsic type.
|
||||
pub type UncheckedExtrinsic<T, E> = sp_runtime::generic::UncheckedExtrinsic<
|
||||
pub type UncheckedExtrinsic<T, X> = sp_runtime::generic::UncheckedExtrinsic<
|
||||
<T as Config>::Address,
|
||||
Encoded,
|
||||
<T as Config>::Signature,
|
||||
<E as SignedExtra<T>>::Extra,
|
||||
<X as SignedExtra<T>>::Extra,
|
||||
>;
|
||||
|
||||
/// SignedPayload type.
|
||||
pub type SignedPayload<T, E> =
|
||||
sp_runtime::generic::SignedPayload<Encoded, <E as SignedExtra<T>>::Extra>;
|
||||
pub type SignedPayload<T, X> =
|
||||
sp_runtime::generic::SignedPayload<Encoded, <X as SignedExtra<T>>::Extra>;
|
||||
|
||||
/// Creates a signed extrinsic
|
||||
pub async fn create_signed<T, E>(
|
||||
pub async fn create_signed<T, X>(
|
||||
runtime_version: &RuntimeVersion,
|
||||
genesis_hash: T::Hash,
|
||||
nonce: T::Index,
|
||||
call: Encoded,
|
||||
signer: &(dyn Signer<T, E> + Send + Sync),
|
||||
additional_params: E::Parameters,
|
||||
) -> Result<UncheckedExtrinsic<T, E>, Error>
|
||||
signer: &(dyn Signer<T, X> + Send + Sync),
|
||||
additional_params: X::Parameters,
|
||||
) -> Result<UncheckedExtrinsic<T, X>, BasicError>
|
||||
where
|
||||
T: Config,
|
||||
E: SignedExtra<T>,
|
||||
<E::Extra as SignedExtension>::AdditionalSigned: Send + Sync,
|
||||
X: SignedExtra<T>,
|
||||
<X::Extra as SignedExtension>::AdditionalSigned: Send + Sync,
|
||||
{
|
||||
let spec_version = runtime_version.spec_version;
|
||||
let tx_version = runtime_version.transaction_version;
|
||||
let extra = E::new(
|
||||
let extra = X::new(
|
||||
spec_version,
|
||||
tx_version,
|
||||
nonce,
|
||||
genesis_hash,
|
||||
additional_params,
|
||||
);
|
||||
let payload = SignedPayload::<T, E>::new(call, extra.extra())?;
|
||||
let payload = SignedPayload::<T, X>::new(call, extra.extra())?;
|
||||
let signed = signer.sign(payload).await?;
|
||||
Ok(signed)
|
||||
}
|
||||
|
||||
+1
-1
@@ -79,9 +79,9 @@ pub use crate::{
|
||||
DefaultConfig,
|
||||
},
|
||||
error::{
|
||||
BasicError,
|
||||
Error,
|
||||
PalletError,
|
||||
RuntimeError,
|
||||
TransactionError,
|
||||
},
|
||||
events::{
|
||||
|
||||
@@ -84,7 +84,6 @@ pub struct Metadata {
|
||||
metadata: RuntimeMetadataLastVersion,
|
||||
pallets: HashMap<String, PalletMetadata>,
|
||||
events: HashMap<(u8, u8), EventMetadata>,
|
||||
errors: HashMap<(u8, u8), ErrorMetadata>,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
@@ -108,19 +107,6 @@ impl Metadata {
|
||||
Ok(event)
|
||||
}
|
||||
|
||||
/// Returns the metadata for the error at the given pallet and error indices.
|
||||
pub fn error(
|
||||
&self,
|
||||
pallet_index: u8,
|
||||
error_index: u8,
|
||||
) -> Result<&ErrorMetadata, MetadataError> {
|
||||
let error = self
|
||||
.errors
|
||||
.get(&(pallet_index, error_index))
|
||||
.ok_or(MetadataError::ErrorNotFound(pallet_index, error_index))?;
|
||||
Ok(error)
|
||||
}
|
||||
|
||||
/// Resolve a type definition.
|
||||
pub fn resolve_type(&self, id: u32) -> Option<&Type<PortableForm>> {
|
||||
self.metadata.types.resolve(id)
|
||||
@@ -207,30 +193,6 @@ impl EventMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ErrorMetadata {
|
||||
pallet: String,
|
||||
error: String,
|
||||
variant: Variant<PortableForm>,
|
||||
}
|
||||
|
||||
impl ErrorMetadata {
|
||||
/// Get the name of the pallet from which the error originates.
|
||||
pub fn pallet(&self) -> &str {
|
||||
&self.pallet
|
||||
}
|
||||
|
||||
/// Get the name of the specific pallet error.
|
||||
pub fn error(&self) -> &str {
|
||||
&self.error
|
||||
}
|
||||
|
||||
/// Get the description of the specific pallet error.
|
||||
pub fn description(&self) -> &[String] {
|
||||
self.variant.docs()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum InvalidMetadataError {
|
||||
#[error("Invalid prefix")]
|
||||
@@ -331,36 +293,10 @@ impl TryFrom<RuntimeMetadataPrefixed> for Metadata {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let pallet_errors = metadata
|
||||
.pallets
|
||||
.iter()
|
||||
.filter_map(|pallet| {
|
||||
pallet.error.as_ref().map(|error| {
|
||||
let type_def_variant = get_type_def_variant(error.ty.id())?;
|
||||
Ok((pallet, type_def_variant))
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let errors = pallet_errors
|
||||
.iter()
|
||||
.flat_map(|(pallet, type_def_variant)| {
|
||||
type_def_variant.variants().iter().map(move |var| {
|
||||
let key = (pallet.index, var.index());
|
||||
let value = ErrorMetadata {
|
||||
pallet: pallet.name.clone(),
|
||||
error: var.name().clone(),
|
||||
variant: var.clone(),
|
||||
};
|
||||
(key, value)
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Self {
|
||||
metadata,
|
||||
pallets,
|
||||
events,
|
||||
errors,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+55
-54
@@ -26,6 +26,17 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::BasicError,
|
||||
storage::StorageKeyPrefix,
|
||||
subscription::{
|
||||
EventStorageSubscription,
|
||||
FinalizedEventStorageSubscription,
|
||||
SystemEvents,
|
||||
},
|
||||
Config,
|
||||
Metadata,
|
||||
};
|
||||
use codec::{
|
||||
Decode,
|
||||
Encode,
|
||||
@@ -72,18 +83,6 @@ use sp_runtime::generic::{
|
||||
SignedBlock,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
storage::StorageKeyPrefix,
|
||||
subscription::{
|
||||
EventStorageSubscription,
|
||||
FinalizedEventStorageSubscription,
|
||||
SystemEvents,
|
||||
},
|
||||
Config,
|
||||
Metadata,
|
||||
};
|
||||
|
||||
/// A number type that can be serialized both as a number or a string that encodes a number in a
|
||||
/// string.
|
||||
///
|
||||
@@ -211,7 +210,7 @@ impl RpcClient {
|
||||
/// Infers the protocol from the URL, supports:
|
||||
/// - Websockets (`ws://`, `wss://`)
|
||||
/// - Http (`http://`, `https://`)
|
||||
pub async fn try_from_url(url: &str) -> Result<Self, Error> {
|
||||
pub async fn try_from_url(url: &str) -> Result<Self, RpcError> {
|
||||
if url.starts_with("ws://") || url.starts_with("wss://") {
|
||||
let client = WsClientBuilder::default()
|
||||
.max_notifs_per_subscription(4096)
|
||||
@@ -229,14 +228,12 @@ impl RpcClient {
|
||||
&self,
|
||||
method: &str,
|
||||
params: &[JsonValue],
|
||||
) -> Result<T, Error> {
|
||||
) -> Result<T, RpcError> {
|
||||
let params = Some(params.into());
|
||||
log::debug!("request {}: {:?}", method, params);
|
||||
let data = match self {
|
||||
Self::WebSocket(inner) => {
|
||||
inner.request(method, params).await.map_err(Into::into)
|
||||
}
|
||||
Self::Http(inner) => inner.request(method, params).await.map_err(Into::into),
|
||||
RpcClient::WebSocket(inner) => inner.request(method, params).await,
|
||||
RpcClient::Http(inner) => inner.request(method, params).await,
|
||||
};
|
||||
data
|
||||
}
|
||||
@@ -247,20 +244,18 @@ impl RpcClient {
|
||||
subscribe_method: &str,
|
||||
params: &[JsonValue],
|
||||
unsubscribe_method: &str,
|
||||
) -> Result<Subscription<T>, Error> {
|
||||
) -> Result<Subscription<T>, RpcError> {
|
||||
let params = Some(params.into());
|
||||
match self {
|
||||
Self::WebSocket(inner) => {
|
||||
RpcClient::WebSocket(inner) => {
|
||||
inner
|
||||
.subscribe(subscribe_method, params, unsubscribe_method)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
Self::Http(_) => {
|
||||
RpcClient::Http(_) => {
|
||||
Err(RpcError::Custom(
|
||||
"Subscriptions not supported on HTTP transport".to_owned(),
|
||||
)
|
||||
.into())
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -335,7 +330,7 @@ impl<T: Config> Rpc<T> {
|
||||
&self,
|
||||
key: &StorageKey,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<Option<StorageData>, Error> {
|
||||
) -> Result<Option<StorageData>, BasicError> {
|
||||
let params = &[to_json_value(key)?, to_json_value(hash)?];
|
||||
let data = self.client.request("state_getStorage", params).await?;
|
||||
Ok(data)
|
||||
@@ -350,7 +345,7 @@ impl<T: Config> Rpc<T> {
|
||||
count: u32,
|
||||
start_key: Option<StorageKey>,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<Vec<StorageKey>, Error> {
|
||||
) -> Result<Vec<StorageKey>, BasicError> {
|
||||
let prefix = prefix.map(|p| p.to_storage_key());
|
||||
let params = &[
|
||||
to_json_value(prefix)?,
|
||||
@@ -368,7 +363,7 @@ impl<T: Config> Rpc<T> {
|
||||
keys: Vec<StorageKey>,
|
||||
from: T::Hash,
|
||||
to: Option<T::Hash>,
|
||||
) -> Result<Vec<StorageChangeSet<T::Hash>>, Error> {
|
||||
) -> Result<Vec<StorageChangeSet<T::Hash>>, BasicError> {
|
||||
let params = &[
|
||||
to_json_value(keys)?,
|
||||
to_json_value(from)?,
|
||||
@@ -385,7 +380,7 @@ impl<T: Config> Rpc<T> {
|
||||
&self,
|
||||
keys: &[StorageKey],
|
||||
at: Option<T::Hash>,
|
||||
) -> Result<Vec<StorageChangeSet<T::Hash>>, Error> {
|
||||
) -> Result<Vec<StorageChangeSet<T::Hash>>, BasicError> {
|
||||
let params = &[to_json_value(keys)?, to_json_value(at)?];
|
||||
self.client
|
||||
.request("state_queryStorageAt", params)
|
||||
@@ -394,7 +389,7 @@ impl<T: Config> Rpc<T> {
|
||||
}
|
||||
|
||||
/// Fetch the genesis hash
|
||||
pub async fn genesis_hash(&self) -> Result<T::Hash, Error> {
|
||||
pub async fn genesis_hash(&self) -> Result<T::Hash, BasicError> {
|
||||
let block_zero = Some(ListOrValue::Value(NumberOrHex::Number(0)));
|
||||
let params = &[to_json_value(block_zero)?];
|
||||
let list_or_value: ListOrValue<Option<T::Hash>> =
|
||||
@@ -408,7 +403,7 @@ impl<T: Config> Rpc<T> {
|
||||
}
|
||||
|
||||
/// Fetch the metadata
|
||||
pub async fn metadata(&self) -> Result<Metadata, Error> {
|
||||
pub async fn metadata(&self) -> Result<Metadata, BasicError> {
|
||||
let bytes: Bytes = self.client.request("state_getMetadata", &[]).await?;
|
||||
let meta: RuntimeMetadataPrefixed = Decode::decode(&mut &bytes[..])?;
|
||||
let metadata: Metadata = meta.try_into()?;
|
||||
@@ -416,22 +411,22 @@ impl<T: Config> Rpc<T> {
|
||||
}
|
||||
|
||||
/// Fetch system properties
|
||||
pub async fn system_properties(&self) -> Result<SystemProperties, Error> {
|
||||
pub async fn system_properties(&self) -> Result<SystemProperties, BasicError> {
|
||||
Ok(self.client.request("system_properties", &[]).await?)
|
||||
}
|
||||
|
||||
/// Fetch system chain
|
||||
pub async fn system_chain(&self) -> Result<String, Error> {
|
||||
pub async fn system_chain(&self) -> Result<String, BasicError> {
|
||||
Ok(self.client.request("system_chain", &[]).await?)
|
||||
}
|
||||
|
||||
/// Fetch system name
|
||||
pub async fn system_name(&self) -> Result<String, Error> {
|
||||
pub async fn system_name(&self) -> Result<String, BasicError> {
|
||||
Ok(self.client.request("system_name", &[]).await?)
|
||||
}
|
||||
|
||||
/// Fetch system version
|
||||
pub async fn system_version(&self) -> Result<String, Error> {
|
||||
pub async fn system_version(&self) -> Result<String, BasicError> {
|
||||
Ok(self.client.request("system_version", &[]).await?)
|
||||
}
|
||||
|
||||
@@ -439,7 +434,7 @@ impl<T: Config> Rpc<T> {
|
||||
pub async fn header(
|
||||
&self,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<Option<T::Header>, Error> {
|
||||
) -> Result<Option<T::Header>, BasicError> {
|
||||
let params = &[to_json_value(hash)?];
|
||||
let header = self.client.request("chain_getHeader", params).await?;
|
||||
Ok(header)
|
||||
@@ -449,7 +444,7 @@ impl<T: Config> Rpc<T> {
|
||||
pub async fn block_hash(
|
||||
&self,
|
||||
block_number: Option<BlockNumber>,
|
||||
) -> Result<Option<T::Hash>, Error> {
|
||||
) -> Result<Option<T::Hash>, BasicError> {
|
||||
let block_number = block_number.map(ListOrValue::Value);
|
||||
let params = &[to_json_value(block_number)?];
|
||||
let list_or_value = self.client.request("chain_getBlockHash", params).await?;
|
||||
@@ -460,7 +455,7 @@ impl<T: Config> Rpc<T> {
|
||||
}
|
||||
|
||||
/// Get a block hash of the latest finalized block
|
||||
pub async fn finalized_head(&self) -> Result<T::Hash, Error> {
|
||||
pub async fn finalized_head(&self) -> Result<T::Hash, BasicError> {
|
||||
let hash = self.client.request("chain_getFinalizedHead", &[]).await?;
|
||||
Ok(hash)
|
||||
}
|
||||
@@ -469,7 +464,7 @@ impl<T: Config> Rpc<T> {
|
||||
pub async fn block(
|
||||
&self,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<Option<ChainBlock<T>>, Error> {
|
||||
) -> Result<Option<ChainBlock<T>>, BasicError> {
|
||||
let params = &[to_json_value(hash)?];
|
||||
let block = self.client.request("chain_getBlock", params).await?;
|
||||
Ok(block)
|
||||
@@ -480,7 +475,7 @@ impl<T: Config> Rpc<T> {
|
||||
&self,
|
||||
keys: Vec<StorageKey>,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<ReadProof<T::Hash>, Error> {
|
||||
) -> Result<ReadProof<T::Hash>, BasicError> {
|
||||
let params = &[to_json_value(keys)?, to_json_value(hash)?];
|
||||
let proof = self.client.request("state_getReadProof", params).await?;
|
||||
Ok(proof)
|
||||
@@ -490,7 +485,7 @@ impl<T: Config> Rpc<T> {
|
||||
pub async fn runtime_version(
|
||||
&self,
|
||||
at: Option<T::Hash>,
|
||||
) -> Result<RuntimeVersion, Error> {
|
||||
) -> Result<RuntimeVersion, BasicError> {
|
||||
let params = &[to_json_value(at)?];
|
||||
let version = self
|
||||
.client
|
||||
@@ -503,7 +498,9 @@ impl<T: Config> Rpc<T> {
|
||||
///
|
||||
/// *WARNING* these may not be included in the finalized chain, use
|
||||
/// `subscribe_finalized_events` to ensure events are finalized.
|
||||
pub async fn subscribe_events(&self) -> Result<EventStorageSubscription<T>, Error> {
|
||||
pub async fn subscribe_events(
|
||||
&self,
|
||||
) -> Result<EventStorageSubscription<T>, BasicError> {
|
||||
let keys = Some(vec![StorageKey::from(SystemEvents::new())]);
|
||||
let params = &[to_json_value(keys)?];
|
||||
|
||||
@@ -517,7 +514,7 @@ impl<T: Config> Rpc<T> {
|
||||
/// Subscribe to finalized events.
|
||||
pub async fn subscribe_finalized_events(
|
||||
&self,
|
||||
) -> Result<EventStorageSubscription<T>, Error> {
|
||||
) -> Result<EventStorageSubscription<T>, BasicError> {
|
||||
Ok(EventStorageSubscription::Finalized(
|
||||
FinalizedEventStorageSubscription::new(
|
||||
self.clone(),
|
||||
@@ -527,7 +524,7 @@ impl<T: Config> Rpc<T> {
|
||||
}
|
||||
|
||||
/// Subscribe to blocks.
|
||||
pub async fn subscribe_blocks(&self) -> Result<Subscription<T::Header>, Error> {
|
||||
pub async fn subscribe_blocks(&self) -> Result<Subscription<T::Header>, BasicError> {
|
||||
let subscription = self
|
||||
.client
|
||||
.subscribe("chain_subscribeNewHeads", &[], "chain_unsubscribeNewHeads")
|
||||
@@ -539,7 +536,7 @@ impl<T: Config> Rpc<T> {
|
||||
/// Subscribe to finalized blocks.
|
||||
pub async fn subscribe_finalized_blocks(
|
||||
&self,
|
||||
) -> Result<Subscription<T::Header>, Error> {
|
||||
) -> Result<Subscription<T::Header>, BasicError> {
|
||||
let subscription = self
|
||||
.client
|
||||
.subscribe(
|
||||
@@ -552,10 +549,10 @@ impl<T: Config> Rpc<T> {
|
||||
}
|
||||
|
||||
/// Create and submit an extrinsic and return corresponding Hash if successful
|
||||
pub async fn submit_extrinsic<E: Encode>(
|
||||
pub async fn submit_extrinsic<X: Encode>(
|
||||
&self,
|
||||
extrinsic: E,
|
||||
) -> Result<T::Hash, Error> {
|
||||
extrinsic: X,
|
||||
) -> Result<T::Hash, BasicError> {
|
||||
let bytes: Bytes = extrinsic.encode().into();
|
||||
let params = &[to_json_value(bytes)?];
|
||||
let xt_hash = self
|
||||
@@ -566,10 +563,11 @@ impl<T: Config> Rpc<T> {
|
||||
}
|
||||
|
||||
/// Create and submit an extrinsic and return a subscription to the events triggered.
|
||||
pub async fn watch_extrinsic<E: Encode>(
|
||||
pub async fn watch_extrinsic<X: Encode>(
|
||||
&self,
|
||||
extrinsic: E,
|
||||
) -> Result<Subscription<SubstrateTransactionStatus<T::Hash, T::Hash>>, Error> {
|
||||
extrinsic: X,
|
||||
) -> Result<Subscription<SubstrateTransactionStatus<T::Hash, T::Hash>>, BasicError>
|
||||
{
|
||||
let bytes: Bytes = extrinsic.encode().into();
|
||||
let params = &[to_json_value(bytes)?];
|
||||
let subscription = self
|
||||
@@ -589,7 +587,7 @@ impl<T: Config> Rpc<T> {
|
||||
key_type: String,
|
||||
suri: String,
|
||||
public: Bytes,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), BasicError> {
|
||||
let params = &[
|
||||
to_json_value(key_type)?,
|
||||
to_json_value(suri)?,
|
||||
@@ -600,7 +598,7 @@ impl<T: Config> Rpc<T> {
|
||||
}
|
||||
|
||||
/// Generate new session keys and returns the corresponding public keys.
|
||||
pub async fn rotate_keys(&self) -> Result<Bytes, Error> {
|
||||
pub async fn rotate_keys(&self) -> Result<Bytes, BasicError> {
|
||||
Ok(self.client.request("author_rotateKeys", &[]).await?)
|
||||
}
|
||||
|
||||
@@ -609,7 +607,10 @@ impl<T: Config> Rpc<T> {
|
||||
/// `session_keys` is the SCALE encoded session keys object from the runtime.
|
||||
///
|
||||
/// Returns `true` iff all private keys could be found.
|
||||
pub async fn has_session_keys(&self, session_keys: Bytes) -> Result<bool, Error> {
|
||||
pub async fn has_session_keys(
|
||||
&self,
|
||||
session_keys: Bytes,
|
||||
) -> Result<bool, BasicError> {
|
||||
let params = &[to_json_value(session_keys)?];
|
||||
Ok(self.client.request("author_hasSessionKeys", params).await?)
|
||||
}
|
||||
@@ -621,7 +622,7 @@ impl<T: Config> Rpc<T> {
|
||||
&self,
|
||||
public_key: Bytes,
|
||||
key_type: String,
|
||||
) -> Result<bool, Error> {
|
||||
) -> Result<bool, BasicError> {
|
||||
let params = &[to_json_value(public_key)?, to_json_value(key_type)?];
|
||||
Ok(self.client.request("author_hasKey", params).await?)
|
||||
}
|
||||
|
||||
+9
-9
@@ -30,13 +30,13 @@ pub use sp_version::RuntimeVersion;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
error::BasicError,
|
||||
metadata::{
|
||||
Metadata,
|
||||
MetadataError,
|
||||
},
|
||||
rpc::Rpc,
|
||||
Config,
|
||||
Error,
|
||||
StorageHasher,
|
||||
};
|
||||
|
||||
@@ -163,7 +163,7 @@ impl<'a, T: Config> StorageClient<'a, T> {
|
||||
&self,
|
||||
key: StorageKey,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<Option<V>, Error> {
|
||||
) -> Result<Option<V>, BasicError> {
|
||||
if let Some(data) = self.rpc.storage(&key, hash).await? {
|
||||
Ok(Some(Decode::decode(&mut &data.0[..])?))
|
||||
} else {
|
||||
@@ -176,7 +176,7 @@ impl<'a, T: Config> StorageClient<'a, T> {
|
||||
&self,
|
||||
key: StorageKey,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<Option<StorageData>, Error> {
|
||||
) -> Result<Option<StorageData>, BasicError> {
|
||||
self.rpc.storage(&key, hash).await
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ impl<'a, T: Config> StorageClient<'a, T> {
|
||||
&self,
|
||||
store: &F,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<Option<F::Value>, Error> {
|
||||
) -> Result<Option<F::Value>, BasicError> {
|
||||
let prefix = StorageKeyPrefix::new::<F>();
|
||||
let key = store.key().final_key(prefix);
|
||||
self.fetch_unhashed::<F::Value>(key, hash).await
|
||||
@@ -196,7 +196,7 @@ impl<'a, T: Config> StorageClient<'a, T> {
|
||||
&self,
|
||||
store: &F,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<F::Value, Error> {
|
||||
) -> Result<F::Value, BasicError> {
|
||||
if let Some(data) = self.fetch(store, hash).await? {
|
||||
Ok(data)
|
||||
} else {
|
||||
@@ -214,7 +214,7 @@ impl<'a, T: Config> StorageClient<'a, T> {
|
||||
keys: Vec<StorageKey>,
|
||||
from: T::Hash,
|
||||
to: Option<T::Hash>,
|
||||
) -> Result<Vec<StorageChangeSet<T::Hash>>, Error> {
|
||||
) -> Result<Vec<StorageChangeSet<T::Hash>>, BasicError> {
|
||||
self.rpc.query_storage(keys, from, to).await
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ impl<'a, T: Config> StorageClient<'a, T> {
|
||||
count: u32,
|
||||
start_key: Option<StorageKey>,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<Vec<StorageKey>, Error> {
|
||||
) -> Result<Vec<StorageKey>, BasicError> {
|
||||
let prefix = StorageKeyPrefix::new::<F>();
|
||||
let keys = self
|
||||
.rpc
|
||||
@@ -239,7 +239,7 @@ impl<'a, T: Config> StorageClient<'a, T> {
|
||||
pub async fn iter<F: StorageEntry>(
|
||||
&self,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<KeyIter<'a, T, F>, Error> {
|
||||
) -> Result<KeyIter<'a, T, F>, BasicError> {
|
||||
let hash = if let Some(hash) = hash {
|
||||
hash
|
||||
} else {
|
||||
@@ -271,7 +271,7 @@ pub struct KeyIter<'a, T: Config, F: StorageEntry> {
|
||||
|
||||
impl<'a, T: Config, F: StorageEntry> KeyIter<'a, T, F> {
|
||||
/// Returns the next key value pair from a map.
|
||||
pub async fn next(&mut self) -> Result<Option<(StorageKey, F::Value)>, Error> {
|
||||
pub async fn next(&mut self) -> Result<Option<(StorageKey, F::Value)>, BasicError> {
|
||||
loop {
|
||||
if let Some((k, v)) = self.buffer.pop() {
|
||||
return Ok(Some((k, Decode::decode(&mut &v.0[..])?)))
|
||||
|
||||
+18
-17
@@ -14,6 +14,17 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
error::BasicError,
|
||||
events::{
|
||||
EventsDecoder,
|
||||
RawEvent,
|
||||
},
|
||||
rpc::Rpc,
|
||||
Config,
|
||||
Event,
|
||||
Phase,
|
||||
};
|
||||
use jsonrpsee::core::{
|
||||
client::Subscription,
|
||||
DeserializeOwned,
|
||||
@@ -28,18 +39,6 @@ use sp_core::{
|
||||
use sp_runtime::traits::Header;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
events::{
|
||||
EventsDecoder,
|
||||
RawEvent,
|
||||
},
|
||||
rpc::Rpc,
|
||||
Config,
|
||||
Event,
|
||||
Phase,
|
||||
};
|
||||
|
||||
/// Event subscription simplifies filtering a storage change set stream for
|
||||
/// events of interest.
|
||||
pub struct EventSubscription<'a, T: Config> {
|
||||
@@ -58,11 +57,13 @@ enum BlockReader<'a, T: Config> {
|
||||
},
|
||||
/// Mock event listener for unit tests
|
||||
#[cfg(test)]
|
||||
Mock(Box<dyn Iterator<Item = (T::Hash, Result<Vec<(Phase, RawEvent)>, Error>)>>),
|
||||
Mock(Box<dyn Iterator<Item = (T::Hash, Result<Vec<(Phase, RawEvent)>, BasicError>)>>),
|
||||
}
|
||||
|
||||
impl<'a, T: Config> BlockReader<'a, T> {
|
||||
async fn next(&mut self) -> Option<(T::Hash, Result<Vec<(Phase, RawEvent)>, Error>)> {
|
||||
async fn next(
|
||||
&mut self,
|
||||
) -> Option<(T::Hash, Result<Vec<(Phase, RawEvent)>, BasicError>)> {
|
||||
match self {
|
||||
BlockReader::Decoder {
|
||||
subscription,
|
||||
@@ -117,12 +118,12 @@ impl<'a, T: Config> EventSubscription<'a, T> {
|
||||
}
|
||||
|
||||
/// Filters events by type.
|
||||
pub fn filter_event<E: Event>(&mut self) {
|
||||
self.event = Some((E::PALLET, E::EVENT));
|
||||
pub fn filter_event<Ev: Event>(&mut self) {
|
||||
self.event = Some((Ev::PALLET, Ev::EVENT));
|
||||
}
|
||||
|
||||
/// Gets the next event.
|
||||
pub async fn next(&mut self) -> Option<Result<RawEvent, Error>> {
|
||||
pub async fn next(&mut self) -> Option<Result<RawEvent, BasicError>> {
|
||||
loop {
|
||||
if let Some(raw_event) = self.events.pop_front() {
|
||||
return Some(Ok(raw_event))
|
||||
|
||||
+66
-48
@@ -16,10 +16,19 @@
|
||||
|
||||
use std::task::Poll;
|
||||
|
||||
use crate::PhantomDataSendSync;
|
||||
use codec::Decode;
|
||||
use sp_core::storage::StorageKey;
|
||||
use sp_runtime::traits::Hash;
|
||||
pub use sp_runtime::traits::SignedExtension;
|
||||
pub use sp_version::RuntimeVersion;
|
||||
|
||||
use crate::{
|
||||
client::Client,
|
||||
error::{
|
||||
BasicError,
|
||||
Error,
|
||||
RuntimeError,
|
||||
TransactionError,
|
||||
},
|
||||
rpc::SubstrateTransactionStatus,
|
||||
@@ -36,27 +45,24 @@ use jsonrpsee::core::{
|
||||
client::Subscription as RpcSubscription,
|
||||
Error as RpcError,
|
||||
};
|
||||
use sp_core::storage::StorageKey;
|
||||
use sp_runtime::traits::Hash;
|
||||
pub use sp_runtime::traits::SignedExtension;
|
||||
pub use sp_version::RuntimeVersion;
|
||||
|
||||
/// This struct represents a subscription to the progress of some transaction, and is
|
||||
/// returned from [`crate::SubmittableExtrinsic::sign_and_submit_then_watch()`].
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Debug(bound = ""))]
|
||||
pub struct TransactionProgress<'client, T: Config> {
|
||||
pub struct TransactionProgress<'client, T: Config, E: Decode> {
|
||||
sub: Option<RpcSubscription<SubstrateTransactionStatus<T::Hash, T::Hash>>>,
|
||||
ext_hash: T::Hash,
|
||||
client: &'client Client<T>,
|
||||
_error: PhantomDataSendSync<E>,
|
||||
}
|
||||
|
||||
// The above type is not `Unpin` by default unless the generic param `T` is,
|
||||
// so we manually make it clear that Unpin is actually fine regardless of `T`
|
||||
// (we don't care if this moves around in memory while it's "pinned").
|
||||
impl<'client, T: Config> Unpin for TransactionProgress<'client, T> {}
|
||||
impl<'client, T: Config, E: Decode> Unpin for TransactionProgress<'client, T, E> {}
|
||||
|
||||
impl<'client, T: Config> TransactionProgress<'client, T> {
|
||||
impl<'client, T: Config, E: Decode> TransactionProgress<'client, T, E> {
|
||||
/// Instantiate a new [`TransactionProgress`] from a custom subscription.
|
||||
pub fn new(
|
||||
sub: RpcSubscription<SubstrateTransactionStatus<T::Hash, T::Hash>>,
|
||||
@@ -67,6 +73,7 @@ impl<'client, T: Config> TransactionProgress<'client, T> {
|
||||
sub: Some(sub),
|
||||
client,
|
||||
ext_hash,
|
||||
_error: PhantomDataSendSync::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +82,7 @@ impl<'client, T: Config> TransactionProgress<'client, T> {
|
||||
/// avoid importing that trait if you don't otherwise need it.
|
||||
pub async fn next_item(
|
||||
&mut self,
|
||||
) -> Option<Result<TransactionStatus<'client, T>, Error>> {
|
||||
) -> Option<Result<TransactionStatus<'client, T, E>, BasicError>> {
|
||||
self.next().await
|
||||
}
|
||||
|
||||
@@ -92,7 +99,7 @@ impl<'client, T: Config> TransactionProgress<'client, T> {
|
||||
/// level [`TransactionProgress::next_item()`] API if you'd like to handle these statuses yourself.
|
||||
pub async fn wait_for_in_block(
|
||||
mut self,
|
||||
) -> Result<TransactionInBlock<'client, T>, Error> {
|
||||
) -> Result<TransactionInBlock<'client, T, E>, BasicError> {
|
||||
while let Some(status) = self.next_item().await {
|
||||
match status? {
|
||||
// Finalized or otherwise in a block! Return.
|
||||
@@ -122,7 +129,7 @@ impl<'client, T: Config> TransactionProgress<'client, T> {
|
||||
/// level [`TransactionProgress::next_item()`] API if you'd like to handle these statuses yourself.
|
||||
pub async fn wait_for_finalized(
|
||||
mut self,
|
||||
) -> Result<TransactionInBlock<'client, T>, Error> {
|
||||
) -> Result<TransactionInBlock<'client, T, E>, BasicError> {
|
||||
while let Some(status) = self.next_item().await {
|
||||
match status? {
|
||||
// Finalized! Return.
|
||||
@@ -149,14 +156,16 @@ impl<'client, T: Config> TransactionProgress<'client, T> {
|
||||
/// may well indicate with some probability that the transaction will not make it into a block,
|
||||
/// there is no guarantee that this is true. Thus, we prefer to "play it safe" here. Use the lower
|
||||
/// level [`TransactionProgress::next_item()`] API if you'd like to handle these statuses yourself.
|
||||
pub async fn wait_for_finalized_success(self) -> Result<TransactionEvents<T>, Error> {
|
||||
pub async fn wait_for_finalized_success(
|
||||
self,
|
||||
) -> Result<TransactionEvents<T>, Error<E>> {
|
||||
let evs = self.wait_for_finalized().await?.wait_for_success().await?;
|
||||
Ok(evs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'client, T: Config> Stream for TransactionProgress<'client, T> {
|
||||
type Item = Result<TransactionStatus<'client, T>, Error>;
|
||||
impl<'client, T: Config, E: Decode> Stream for TransactionProgress<'client, T, E> {
|
||||
type Item = Result<TransactionStatus<'client, T, E>, BasicError>;
|
||||
|
||||
fn poll_next(
|
||||
mut self: std::pin::Pin<&mut Self>,
|
||||
@@ -177,11 +186,11 @@ impl<'client, T: Config> Stream for TransactionProgress<'client, T> {
|
||||
TransactionStatus::Broadcast(peers)
|
||||
}
|
||||
SubstrateTransactionStatus::InBlock(hash) => {
|
||||
TransactionStatus::InBlock(TransactionInBlock {
|
||||
block_hash: hash,
|
||||
ext_hash: self.ext_hash,
|
||||
client: self.client,
|
||||
})
|
||||
TransactionStatus::InBlock(TransactionInBlock::new(
|
||||
hash,
|
||||
self.ext_hash,
|
||||
self.client,
|
||||
))
|
||||
}
|
||||
SubstrateTransactionStatus::Retracted(hash) => {
|
||||
TransactionStatus::Retracted(hash)
|
||||
@@ -206,11 +215,11 @@ impl<'client, T: Config> Stream for TransactionProgress<'client, T> {
|
||||
}
|
||||
SubstrateTransactionStatus::Finalized(hash) => {
|
||||
self.sub = None;
|
||||
TransactionStatus::Finalized(TransactionInBlock {
|
||||
block_hash: hash,
|
||||
ext_hash: self.ext_hash,
|
||||
client: self.client,
|
||||
})
|
||||
TransactionStatus::Finalized(TransactionInBlock::new(
|
||||
hash,
|
||||
self.ext_hash,
|
||||
self.client,
|
||||
))
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -265,7 +274,7 @@ impl<'client, T: Config> Stream for TransactionProgress<'client, T> {
|
||||
/// or that finality gadget is lagging behind.
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Debug(bound = ""))]
|
||||
pub enum TransactionStatus<'client, T: Config> {
|
||||
pub enum TransactionStatus<'client, T: Config, E: Decode> {
|
||||
/// The transaction is part of the "future" queue.
|
||||
Future,
|
||||
/// The transaction is part of the "ready" queue.
|
||||
@@ -273,7 +282,7 @@ pub enum TransactionStatus<'client, T: Config> {
|
||||
/// The transaction has been broadcast to the given peers.
|
||||
Broadcast(Vec<String>),
|
||||
/// The transaction has been included in a block with given hash.
|
||||
InBlock(TransactionInBlock<'client, T>),
|
||||
InBlock(TransactionInBlock<'client, T, E>),
|
||||
/// The block this transaction was included in has been retracted,
|
||||
/// probably because it did not make it onto the blocks which were
|
||||
/// finalized.
|
||||
@@ -282,7 +291,7 @@ pub enum TransactionStatus<'client, T: Config> {
|
||||
/// blocks, and so the subscription has ended.
|
||||
FinalityTimeout(T::Hash),
|
||||
/// The transaction has been finalized by a finality-gadget, e.g GRANDPA.
|
||||
Finalized(TransactionInBlock<'client, T>),
|
||||
Finalized(TransactionInBlock<'client, T, E>),
|
||||
/// The transaction has been replaced in the pool by another transaction
|
||||
/// that provides the same tags. (e.g. same (sender, nonce)).
|
||||
Usurped(T::Hash),
|
||||
@@ -292,10 +301,10 @@ pub enum TransactionStatus<'client, T: Config> {
|
||||
Invalid,
|
||||
}
|
||||
|
||||
impl<'client, T: Config> TransactionStatus<'client, T> {
|
||||
impl<'client, T: Config, E: Decode> TransactionStatus<'client, T, E> {
|
||||
/// A convenience method to return the `Finalized` details. Returns
|
||||
/// [`None`] if the enum variant is not [`TransactionStatus::Finalized`].
|
||||
pub fn as_finalized(&self) -> Option<&TransactionInBlock<'client, T>> {
|
||||
pub fn as_finalized(&self) -> Option<&TransactionInBlock<'client, T, E>> {
|
||||
match self {
|
||||
Self::Finalized(val) => Some(val),
|
||||
_ => None,
|
||||
@@ -304,7 +313,7 @@ impl<'client, T: Config> TransactionStatus<'client, T> {
|
||||
|
||||
/// A convenience method to return the `InBlock` details. Returns
|
||||
/// [`None`] if the enum variant is not [`TransactionStatus::InBlock`].
|
||||
pub fn as_in_block(&self) -> Option<&TransactionInBlock<'client, T>> {
|
||||
pub fn as_in_block(&self) -> Option<&TransactionInBlock<'client, T, E>> {
|
||||
match self {
|
||||
Self::InBlock(val) => Some(val),
|
||||
_ => None,
|
||||
@@ -315,13 +324,27 @@ impl<'client, T: Config> TransactionStatus<'client, T> {
|
||||
/// This struct represents a transaction that has made it into a block.
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Debug(bound = ""))]
|
||||
pub struct TransactionInBlock<'client, T: Config> {
|
||||
pub struct TransactionInBlock<'client, T: Config, E: Decode> {
|
||||
block_hash: T::Hash,
|
||||
ext_hash: T::Hash,
|
||||
client: &'client Client<T>,
|
||||
_error: PhantomDataSendSync<E>,
|
||||
}
|
||||
|
||||
impl<'client, T: Config> TransactionInBlock<'client, T> {
|
||||
impl<'client, T: Config, E: Decode> TransactionInBlock<'client, T, E> {
|
||||
pub(crate) fn new(
|
||||
block_hash: T::Hash,
|
||||
ext_hash: T::Hash,
|
||||
client: &'client Client<T>,
|
||||
) -> Self {
|
||||
Self {
|
||||
block_hash,
|
||||
ext_hash,
|
||||
client,
|
||||
_error: PhantomDataSendSync::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the hash of the block that the transaction has made it into.
|
||||
pub fn block_hash(&self) -> T::Hash {
|
||||
self.block_hash
|
||||
@@ -345,19 +368,14 @@ impl<'client, T: Config> TransactionInBlock<'client, T> {
|
||||
///
|
||||
/// **Note:** This has to download block details from the node and decode events
|
||||
/// from them.
|
||||
pub async fn wait_for_success(&self) -> Result<TransactionEvents<T>, Error> {
|
||||
pub async fn wait_for_success(&self) -> Result<TransactionEvents<T>, Error<E>> {
|
||||
let events = self.fetch_events().await?;
|
||||
|
||||
// Try to find any errors; return the first one we encounter.
|
||||
for ev in events.as_slice() {
|
||||
if &ev.pallet == "System" && &ev.variant == "ExtrinsicFailed" {
|
||||
use codec::Decode;
|
||||
let dispatch_error = sp_runtime::DispatchError::decode(&mut &*ev.data)?;
|
||||
let runtime_error = crate::RuntimeError::from_dispatch(
|
||||
self.client.metadata(),
|
||||
dispatch_error,
|
||||
)?;
|
||||
return Err(runtime_error.into())
|
||||
let dispatch_error = E::decode(&mut &*ev.data)?;
|
||||
return Err(Error::Runtime(RuntimeError(dispatch_error)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,13 +388,13 @@ impl<'client, T: Config> TransactionInBlock<'client, T> {
|
||||
///
|
||||
/// **Note:** This has to download block details from the node and decode events
|
||||
/// from them.
|
||||
pub async fn fetch_events(&self) -> Result<TransactionEvents<T>, Error> {
|
||||
pub async fn fetch_events(&self) -> Result<TransactionEvents<T>, BasicError> {
|
||||
let block = self
|
||||
.client
|
||||
.rpc()
|
||||
.block(Some(self.block_hash))
|
||||
.await?
|
||||
.ok_or(Error::Transaction(TransactionError::BlockHashNotFound))?;
|
||||
.ok_or(BasicError::Transaction(TransactionError::BlockHashNotFound))?;
|
||||
|
||||
let extrinsic_idx = block.block.extrinsics
|
||||
.iter()
|
||||
@@ -386,7 +404,7 @@ impl<'client, T: Config> TransactionInBlock<'client, T> {
|
||||
})
|
||||
// If we successfully obtain the block hash we think contains our
|
||||
// extrinsic, the extrinsic should be in there somewhere..
|
||||
.ok_or(Error::Transaction(TransactionError::BlockHashNotFound))?;
|
||||
.ok_or(BasicError::Transaction(TransactionError::BlockHashNotFound))?;
|
||||
|
||||
let raw_events = self
|
||||
.client
|
||||
@@ -446,10 +464,10 @@ impl<T: Config> TransactionEvents<T> {
|
||||
|
||||
/// Find all of the events matching the event type provided as a generic parameter. This
|
||||
/// will return an error if a matching event is found but cannot be properly decoded.
|
||||
pub fn find_events<E: crate::Event>(&self) -> Result<Vec<E>, Error> {
|
||||
pub fn find_events<Ev: crate::Event>(&self) -> Result<Vec<Ev>, BasicError> {
|
||||
self.events
|
||||
.iter()
|
||||
.filter_map(|e| e.as_event::<E>().map_err(Into::into).transpose())
|
||||
.filter_map(|e| e.as_event::<Ev>().map_err(Into::into).transpose())
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -458,18 +476,18 @@ impl<T: Config> TransactionEvents<T> {
|
||||
///
|
||||
/// Use [`TransactionEvents::find_events`], or iterate over [`TransactionEvents`] yourself
|
||||
/// if you'd like to handle multiple events of the same type.
|
||||
pub fn find_first_event<E: crate::Event>(&self) -> Result<Option<E>, Error> {
|
||||
pub fn find_first_event<Ev: crate::Event>(&self) -> Result<Option<Ev>, BasicError> {
|
||||
self.events
|
||||
.iter()
|
||||
.filter_map(|e| e.as_event::<E>().transpose())
|
||||
.filter_map(|e| e.as_event::<Ev>().transpose())
|
||||
.next()
|
||||
.transpose()
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Find an event. Returns true if it was found.
|
||||
pub fn has_event<E: crate::Event>(&self) -> Result<bool, Error> {
|
||||
Ok(self.find_first_event::<E>()?.is_some())
|
||||
pub fn has_event<Ev: crate::Event>(&self) -> Result<bool, BasicError> {
|
||||
Ok(self.find_first_event::<Ev>()?.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ async fn run() {
|
||||
r#"
|
||||
#[subxt::subxt(
|
||||
runtime_metadata_path = "{}",
|
||||
generated_type_derives = "Debug, Eq, PartialEq"
|
||||
generated_type_derives = "Eq, PartialEq"
|
||||
)]
|
||||
pub mod node_runtime {{
|
||||
#[subxt(substitute_type = "sp_arithmetic::per_things::Perbill")]
|
||||
|
||||
+2901
-2041
File diff suppressed because one or more lines are too long
@@ -19,6 +19,7 @@ use crate::{
|
||||
balances,
|
||||
runtime_types,
|
||||
system,
|
||||
DispatchError,
|
||||
},
|
||||
pair_signer,
|
||||
test_context,
|
||||
@@ -33,13 +34,11 @@ use subxt::{
|
||||
DefaultConfig,
|
||||
Error,
|
||||
EventSubscription,
|
||||
PalletError,
|
||||
RuntimeError,
|
||||
Signer,
|
||||
};
|
||||
|
||||
#[async_std::test]
|
||||
async fn tx_basic_transfer() -> Result<(), subxt::Error> {
|
||||
async fn tx_basic_transfer() -> Result<(), subxt::Error<DispatchError>> {
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
let bob = pair_signer(AccountKeyring::Bob.pair());
|
||||
let bob_address = bob.account_id().clone().into();
|
||||
@@ -111,7 +110,7 @@ async fn storage_total_issuance() {
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn storage_balance_lock() -> Result<(), subxt::Error> {
|
||||
async fn storage_balance_lock() -> Result<(), subxt::Error<DispatchError>> {
|
||||
let bob = pair_signer(AccountKeyring::Bob.pair());
|
||||
let charlie = AccountKeyring::Charlie.to_account_id();
|
||||
let cxt = test_context().await;
|
||||
@@ -181,13 +180,10 @@ async fn transfer_error() {
|
||||
.wait_for_finalized_success()
|
||||
.await;
|
||||
|
||||
if let Err(Error::Runtime(RuntimeError::Module(error))) = res {
|
||||
let error2 = PalletError {
|
||||
pallet: "Balances".into(),
|
||||
error: "InsufficientBalance".into(),
|
||||
description: vec!["Balance too low to send value".to_string()],
|
||||
};
|
||||
assert_eq!(error, error2);
|
||||
if let Err(Error::Runtime(err)) = res {
|
||||
let details = err.inner().details().unwrap();
|
||||
assert_eq!(details.pallet, "Balances");
|
||||
assert_eq!(details.error, "InsufficientBalance");
|
||||
} else {
|
||||
panic!("expected a runtime module error");
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ use crate::{
|
||||
},
|
||||
system,
|
||||
DefaultAccountData,
|
||||
DispatchError,
|
||||
},
|
||||
test_context,
|
||||
NodeRuntimeSignedExtra,
|
||||
@@ -67,7 +68,9 @@ impl ContractsTestContext {
|
||||
self.cxt.api.tx().contracts()
|
||||
}
|
||||
|
||||
async fn instantiate_with_code(&self) -> Result<(Hash, AccountId), Error> {
|
||||
async fn instantiate_with_code(
|
||||
&self,
|
||||
) -> Result<(Hash, AccountId), Error<DispatchError>> {
|
||||
log::info!("instantiate_with_code:");
|
||||
const CONTRACT: &str = r#"
|
||||
(module
|
||||
@@ -118,7 +121,7 @@ impl ContractsTestContext {
|
||||
code_hash: Hash,
|
||||
data: Vec<u8>,
|
||||
salt: Vec<u8>,
|
||||
) -> Result<AccountId, Error> {
|
||||
) -> Result<AccountId, Error<DispatchError>> {
|
||||
// call instantiate extrinsic
|
||||
let result = self
|
||||
.contracts_tx()
|
||||
@@ -147,7 +150,8 @@ impl ContractsTestContext {
|
||||
&self,
|
||||
contract: AccountId,
|
||||
input_data: Vec<u8>,
|
||||
) -> Result<TransactionProgress<'_, DefaultConfig>, Error> {
|
||||
) -> Result<TransactionProgress<'_, DefaultConfig, DispatchError>, Error<DispatchError>>
|
||||
{
|
||||
log::info!("call: {:?}", contract);
|
||||
let result = self
|
||||
.contracts_tx()
|
||||
|
||||
@@ -21,6 +21,7 @@ use crate::{
|
||||
ValidatorPrefs,
|
||||
},
|
||||
staking,
|
||||
DispatchError,
|
||||
},
|
||||
pair_signer,
|
||||
test_context,
|
||||
@@ -33,7 +34,6 @@ use sp_core::{
|
||||
use sp_keyring::AccountKeyring;
|
||||
use subxt::{
|
||||
Error,
|
||||
RuntimeError,
|
||||
Signer,
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ async fn validate_with_controller_account() {
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn validate_not_possible_for_stash_account() -> Result<(), Error> {
|
||||
async fn validate_not_possible_for_stash_account() -> Result<(), Error<DispatchError>> {
|
||||
let alice_stash = pair_signer(get_from_seed("Alice//stash"));
|
||||
let cxt = test_context().await;
|
||||
let announce_validator = cxt
|
||||
@@ -79,9 +79,10 @@ async fn validate_not_possible_for_stash_account() -> Result<(), Error> {
|
||||
.await?
|
||||
.wait_for_finalized_success()
|
||||
.await;
|
||||
assert_matches!(announce_validator, Err(Error::Runtime(RuntimeError::Module(module_err))) => {
|
||||
assert_eq!(module_err.pallet, "Staking");
|
||||
assert_eq!(module_err.error, "NotController");
|
||||
assert_matches!(announce_validator, Err(Error::Runtime(err)) => {
|
||||
let details = err.inner().details().unwrap();
|
||||
assert_eq!(details.pallet, "Staking");
|
||||
assert_eq!(details.error, "NotController");
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@@ -105,7 +106,7 @@ async fn nominate_with_controller_account() {
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn nominate_not_possible_for_stash_account() -> Result<(), Error> {
|
||||
async fn nominate_not_possible_for_stash_account() -> Result<(), Error<DispatchError>> {
|
||||
let alice_stash = pair_signer(get_from_seed("Alice//stash"));
|
||||
let bob = pair_signer(AccountKeyring::Bob.pair());
|
||||
let cxt = test_context().await;
|
||||
@@ -120,15 +121,16 @@ async fn nominate_not_possible_for_stash_account() -> Result<(), Error> {
|
||||
.wait_for_finalized_success()
|
||||
.await;
|
||||
|
||||
assert_matches!(nomination, Err(Error::Runtime(RuntimeError::Module(module_err))) => {
|
||||
assert_eq!(module_err.pallet, "Staking");
|
||||
assert_eq!(module_err.error, "NotController");
|
||||
assert_matches!(nomination, Err(Error::Runtime(err)) => {
|
||||
let details = err.inner().details().unwrap();
|
||||
assert_eq!(details.pallet, "Staking");
|
||||
assert_eq!(details.error, "NotController");
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn chill_works_for_controller_only() -> Result<(), Error> {
|
||||
async fn chill_works_for_controller_only() -> Result<(), Error<DispatchError>> {
|
||||
let alice_stash = pair_signer(get_from_seed("Alice//stash"));
|
||||
let bob_stash = pair_signer(get_from_seed("Bob//stash"));
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
@@ -163,9 +165,10 @@ async fn chill_works_for_controller_only() -> Result<(), Error> {
|
||||
.wait_for_finalized_success()
|
||||
.await;
|
||||
|
||||
assert_matches!(chill, Err(Error::Runtime(RuntimeError::Module(module_err))) => {
|
||||
assert_eq!(module_err.pallet, "Staking");
|
||||
assert_eq!(module_err.error, "NotController");
|
||||
assert_matches!(chill, Err(Error::Runtime(err)) => {
|
||||
let details = err.inner().details().unwrap();
|
||||
assert_eq!(details.pallet, "Staking");
|
||||
assert_eq!(details.error, "NotController");
|
||||
});
|
||||
|
||||
let is_chilled = cxt
|
||||
@@ -184,7 +187,7 @@ async fn chill_works_for_controller_only() -> Result<(), Error> {
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn tx_bond() -> Result<(), Error> {
|
||||
async fn tx_bond() -> Result<(), Error<DispatchError>> {
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
let cxt = test_context().await;
|
||||
|
||||
@@ -218,16 +221,16 @@ async fn tx_bond() -> Result<(), Error> {
|
||||
.wait_for_finalized_success()
|
||||
.await;
|
||||
|
||||
assert_matches!(bond_again, Err(Error::Runtime(RuntimeError::Module(module_err))) => {
|
||||
assert_eq!(module_err.pallet, "Staking");
|
||||
assert_eq!(module_err.error, "AlreadyBonded");
|
||||
assert_matches!(bond_again, Err(Error::Runtime(err)) => {
|
||||
let details = err.inner().details().unwrap();
|
||||
assert_eq!(details.pallet, "Staking");
|
||||
assert_eq!(details.error, "AlreadyBonded");
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn storage_history_depth() -> Result<(), Error> {
|
||||
async fn storage_history_depth() -> Result<(), Error<DispatchError>> {
|
||||
let cxt = test_context().await;
|
||||
let history_depth = cxt.api.storage().staking().history_depth(None).await?;
|
||||
assert_eq!(history_depth, 84);
|
||||
@@ -235,7 +238,7 @@ async fn storage_history_depth() -> Result<(), Error> {
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn storage_current_era() -> Result<(), Error> {
|
||||
async fn storage_current_era() -> Result<(), Error<DispatchError>> {
|
||||
let cxt = test_context().await;
|
||||
let _current_era = cxt
|
||||
.api
|
||||
@@ -248,7 +251,7 @@ async fn storage_current_era() -> Result<(), Error> {
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn storage_era_reward_points() -> Result<(), Error> {
|
||||
async fn storage_era_reward_points() -> Result<(), Error<DispatchError>> {
|
||||
let cxt = test_context().await;
|
||||
let current_era_result = cxt
|
||||
.api
|
||||
|
||||
@@ -18,6 +18,7 @@ use crate::{
|
||||
node_runtime::{
|
||||
runtime_types,
|
||||
sudo,
|
||||
DispatchError,
|
||||
},
|
||||
pair_signer,
|
||||
test_context,
|
||||
@@ -28,7 +29,7 @@ type Call = runtime_types::node_runtime::Call;
|
||||
type BalancesCall = runtime_types::pallet_balances::pallet::Call;
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_sudo() -> Result<(), subxt::Error> {
|
||||
async fn test_sudo() -> Result<(), subxt::Error<DispatchError>> {
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
let bob = AccountKeyring::Bob.to_account_id().into();
|
||||
let cxt = test_context().await;
|
||||
@@ -54,7 +55,7 @@ async fn test_sudo() -> Result<(), subxt::Error> {
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_sudo_unchecked_weight() -> Result<(), subxt::Error> {
|
||||
async fn test_sudo_unchecked_weight() -> Result<(), subxt::Error<DispatchError>> {
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
let bob = AccountKeyring::Bob.to_account_id().into();
|
||||
let cxt = test_context().await;
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
node_runtime::system,
|
||||
node_runtime::{
|
||||
system,
|
||||
DispatchError,
|
||||
},
|
||||
pair_signer,
|
||||
test_context,
|
||||
};
|
||||
@@ -24,7 +27,7 @@ use sp_keyring::AccountKeyring;
|
||||
use subxt::Signer;
|
||||
|
||||
#[async_std::test]
|
||||
async fn storage_account() -> Result<(), subxt::Error> {
|
||||
async fn storage_account() -> Result<(), subxt::Error<DispatchError>> {
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
|
||||
let cxt = test_context().await;
|
||||
@@ -40,7 +43,7 @@ async fn storage_account() -> Result<(), subxt::Error> {
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn tx_remark_with_event() -> Result<(), subxt::Error> {
|
||||
async fn tx_remark_with_event() -> Result<(), subxt::Error<DispatchError>> {
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
let cxt = test_context().await;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user