mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 05:21:08 +00:00
Obtain DispatchError::Module info dynamically (#453)
* Add error information back into metadata to roll back removal in #394 * Go back to obtaining runtime error info * re-do codegen too to check that it's all gravy * Convert DispatchError module errors into a module variant to make them easier to work with * Fix broken doc link
This commit is contained in:
+21
-147
@@ -15,64 +15,18 @@
|
||||
// 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 proc_macro2::TokenStream as TokenStream2;
|
||||
use proc_macro_error::abort_call_site;
|
||||
use quote::quote;
|
||||
use scale_info::TypeDef;
|
||||
|
||||
/// 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
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
/// The aim of this is to implement the `::subxt::HasModuleError` trait for
|
||||
/// the generated `DispatchError`, so that we can obtain the module error details,
|
||||
/// if applicable, from it.
|
||||
pub fn generate_has_module_error_impl(
|
||||
metadata: &RuntimeMetadataV14,
|
||||
types_mod_ident: &syn::Ident,
|
||||
) -> TokenStream2 {
|
||||
let dispatch_error_def = metadata
|
||||
.types
|
||||
.types()
|
||||
@@ -111,108 +65,28 @@ pub fn generate_error_details(metadata: &RuntimeMetadataV14) -> ErrorDetails {
|
||||
false
|
||||
};
|
||||
|
||||
let dispatch_error_impl_fn = if module_variant_is_struct {
|
||||
let trait_fn_body = if module_variant_is_struct {
|
||||
quote! {
|
||||
pub fn details(&self) -> Option<ErrorDetails> {
|
||||
if let Self::Module { error, index } = self {
|
||||
match (index, error) {
|
||||
#( #match_body_items ),*,
|
||||
_ => None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
if let &Self::Module { index, error } = self {
|
||||
Some((index, error))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
pub fn details(&self) -> Option<ErrorDetails> {
|
||||
if let Self::Module (module_error) = self {
|
||||
match (module_error.index, module_error.error) {
|
||||
#( #match_body_items ),*,
|
||||
_ => None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
if let Self::Module (module_error) = self {
|
||||
Some((module_error.index, module_error.error))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ErrorDetails {
|
||||
type_def: quote! {
|
||||
pub struct ErrorDetails {
|
||||
pub pallet: &'static str,
|
||||
pub error: &'static str,
|
||||
pub docs: &'static str,
|
||||
}
|
||||
},
|
||||
dispatch_error_impl_fn,
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
quote! {
|
||||
impl ::subxt::HasModuleError for #types_mod_ident::sp_runtime::DispatchError {
|
||||
fn module_error_indices(&self) -> Option<(u8,u8)> {
|
||||
#trait_fn_body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,9 +265,8 @@ 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;
|
||||
let has_module_error_impl =
|
||||
errors::generate_has_module_error_impl(&self.metadata, types_mod_ident);
|
||||
|
||||
let default_account_data_ident = format_ident!("DefaultAccountData");
|
||||
let default_account_data_impl = generate_default_account_data_impl(
|
||||
@@ -291,12 +290,8 @@ impl RuntimeGenerator {
|
||||
|
||||
/// The default error type returned when there is a runtime issue.
|
||||
pub type DispatchError = #types_mod_ident::sp_runtime::DispatchError;
|
||||
|
||||
// Statically generate error information so that we don't need runtime metadata for it.
|
||||
#error_type
|
||||
impl DispatchError {
|
||||
#error_fn
|
||||
}
|
||||
// Impl HasModuleError on DispatchError so we can pluck out module error details.
|
||||
#has_module_error_impl
|
||||
|
||||
#default_account_data_impl
|
||||
|
||||
|
||||
+5
-2
@@ -19,7 +19,10 @@ use sp_runtime::traits::Hash;
|
||||
pub use sp_runtime::traits::SignedExtension;
|
||||
|
||||
use crate::{
|
||||
error::BasicError,
|
||||
error::{
|
||||
BasicError,
|
||||
HasModuleError,
|
||||
},
|
||||
extrinsic::{
|
||||
self,
|
||||
SignedExtra,
|
||||
@@ -206,7 +209,7 @@ where
|
||||
X: SignedExtra<T>,
|
||||
A: AccountData,
|
||||
C: Call + Send + Sync,
|
||||
E: Decode,
|
||||
E: Decode + HasModuleError,
|
||||
Evs: Decode,
|
||||
{
|
||||
/// Create a new [`SubmittableExtrinsic`].
|
||||
|
||||
@@ -70,6 +70,9 @@ pub enum GenericError<E> {
|
||||
/// Transaction progress error.
|
||||
#[error("Transaction error: {0}")]
|
||||
Transaction(#[from] TransactionError),
|
||||
#[error("Module error: {0}")]
|
||||
/// An error from the `Module` variant of the generated `DispatchError`.
|
||||
Module(ModuleError),
|
||||
/// Other error.
|
||||
#[error("Other error: {0}")]
|
||||
Other(String),
|
||||
@@ -94,6 +97,7 @@ impl<E> GenericError<E> {
|
||||
GenericError::Metadata(e) => GenericError::Metadata(e),
|
||||
GenericError::EventsDecoding(e) => GenericError::EventsDecoding(e),
|
||||
GenericError::Transaction(e) => GenericError::Transaction(e),
|
||||
GenericError::Module(e) => GenericError::Module(e),
|
||||
GenericError::Other(e) => GenericError::Other(e),
|
||||
// This is the only branch we really care about:
|
||||
GenericError::Runtime(e) => GenericError::Runtime(f(e)),
|
||||
@@ -167,3 +171,24 @@ pub enum TransactionError {
|
||||
#[error("The block containing the transaction can no longer be found (perhaps it was on a non-finalized fork?)")]
|
||||
BlockHashNotFound,
|
||||
}
|
||||
|
||||
/// Details about a module error that has occurred.
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
#[error("{pallet}: {error}\n\n{}", .description.join("\n"))]
|
||||
pub struct ModuleError {
|
||||
/// The name of the pallet that the error came from.
|
||||
pub pallet: String,
|
||||
/// The name of the error.
|
||||
pub error: String,
|
||||
/// A description of the error.
|
||||
pub description: Vec<String>,
|
||||
}
|
||||
|
||||
/// This trait is automatically implemented for the generated `DispatchError`,
|
||||
/// so that we can pluck out information about the `Module` error variant, if`
|
||||
/// it exists.
|
||||
pub trait HasModuleError {
|
||||
/// If the error has a `Module` variant, return a tuple of the
|
||||
/// pallet index and error index. Else, return `None`.
|
||||
fn module_error_indices(&self) -> Option<(u8, u8)>;
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ pub use crate::{
|
||||
BasicError,
|
||||
Error,
|
||||
GenericError,
|
||||
HasModuleError,
|
||||
RuntimeError,
|
||||
TransactionError,
|
||||
},
|
||||
@@ -98,6 +99,7 @@ pub use crate::{
|
||||
UncheckedExtrinsic,
|
||||
},
|
||||
metadata::{
|
||||
ErrorMetadata,
|
||||
Metadata,
|
||||
MetadataError,
|
||||
PalletMetadata,
|
||||
|
||||
@@ -84,6 +84,7 @@ pub struct Metadata {
|
||||
metadata: RuntimeMetadataLastVersion,
|
||||
pallets: HashMap<String, PalletMetadata>,
|
||||
events: HashMap<(u8, u8), EventMetadata>,
|
||||
errors: HashMap<(u8, u8), ErrorMetadata>,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
@@ -107,6 +108,19 @@ 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)
|
||||
@@ -169,6 +183,7 @@ impl PalletMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata for specific events.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EventMetadata {
|
||||
pallet: String,
|
||||
@@ -193,6 +208,31 @@ impl EventMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata for specific errors.
|
||||
#[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")]
|
||||
@@ -293,10 +333,36 @@ 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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ use crate::{
|
||||
error::{
|
||||
BasicError,
|
||||
Error,
|
||||
HasModuleError,
|
||||
ModuleError,
|
||||
RuntimeError,
|
||||
TransactionError,
|
||||
},
|
||||
@@ -54,7 +56,7 @@ use jsonrpsee::core::{
|
||||
/// returned from [`crate::SubmittableExtrinsic::sign_and_submit_then_watch()`].
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Debug(bound = ""))]
|
||||
pub struct TransactionProgress<'client, T: Config, E: Decode, Evs: Decode> {
|
||||
pub struct TransactionProgress<'client, T: Config, E, Evs> {
|
||||
sub: Option<RpcSubscription<SubstrateTransactionStatus<T::Hash, T::Hash>>>,
|
||||
ext_hash: T::Hash,
|
||||
client: &'client Client<T>,
|
||||
@@ -64,12 +66,11 @@ pub struct TransactionProgress<'client, T: Config, E: Decode, Evs: Decode> {
|
||||
// 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, E: Decode, Evs: Decode> Unpin
|
||||
for TransactionProgress<'client, T, E, Evs>
|
||||
{
|
||||
}
|
||||
impl<'client, T: Config, E, Evs> Unpin for TransactionProgress<'client, T, E, Evs> {}
|
||||
|
||||
impl<'client, T: Config, E: Decode, Evs: Decode> TransactionProgress<'client, T, E, Evs> {
|
||||
impl<'client, T: Config, E: Decode + HasModuleError, Evs: Decode>
|
||||
TransactionProgress<'client, T, E, Evs>
|
||||
{
|
||||
/// Instantiate a new [`TransactionProgress`] from a custom subscription.
|
||||
pub fn new(
|
||||
sub: RpcSubscription<SubstrateTransactionStatus<T::Hash, T::Hash>>,
|
||||
@@ -171,7 +172,7 @@ impl<'client, T: Config, E: Decode, Evs: Decode> TransactionProgress<'client, T,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'client, T: Config, E: Decode, Evs: Decode> Stream
|
||||
impl<'client, T: Config, E: Decode + HasModuleError, Evs: Decode> Stream
|
||||
for TransactionProgress<'client, T, E, Evs>
|
||||
{
|
||||
type Item = Result<TransactionStatus<'client, T, E, Evs>, BasicError>;
|
||||
@@ -340,7 +341,9 @@ pub struct TransactionInBlock<'client, T: Config, E: Decode, Evs: Decode> {
|
||||
_error: PhantomDataSendSync<(E, Evs)>,
|
||||
}
|
||||
|
||||
impl<'client, T: Config, E: Decode, Evs: Decode> TransactionInBlock<'client, T, E, Evs> {
|
||||
impl<'client, T: Config, E: Decode + HasModuleError, Evs: Decode>
|
||||
TransactionInBlock<'client, T, E, Evs>
|
||||
{
|
||||
pub(crate) fn new(
|
||||
block_hash: T::Hash,
|
||||
ext_hash: T::Hash,
|
||||
@@ -387,7 +390,18 @@ impl<'client, T: Config, E: Decode, Evs: Decode> TransactionInBlock<'client, T,
|
||||
let ev = ev?;
|
||||
if &ev.pallet == "System" && &ev.variant == "ExtrinsicFailed" {
|
||||
let dispatch_error = E::decode(&mut &*ev.data)?;
|
||||
return Err(Error::Runtime(RuntimeError(dispatch_error)))
|
||||
if let Some((pallet_idx, error_idx)) =
|
||||
dispatch_error.module_error_indices()
|
||||
{
|
||||
let details = self.client.metadata().error(pallet_idx, error_idx)?;
|
||||
return Err(Error::Module(ModuleError {
|
||||
pallet: details.pallet().to_string(),
|
||||
error: details.error().to_string(),
|
||||
description: details.description().to_vec(),
|
||||
}))
|
||||
} else {
|
||||
return Err(Error::Runtime(RuntimeError(dispatch_error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1484
-1398
File diff suppressed because one or more lines are too long
@@ -154,9 +154,9 @@ async fn transfer_error() {
|
||||
let alice_addr = alice.account_id().clone().into();
|
||||
let hans = pair_signer(Pair::generate().0);
|
||||
let hans_address = hans.account_id().clone().into();
|
||||
let cxt = test_context().await;
|
||||
let ctx = test_context().await;
|
||||
|
||||
cxt.api
|
||||
ctx.api
|
||||
.tx()
|
||||
.balances()
|
||||
.transfer(hans_address, 100_000_000_000_000_000)
|
||||
@@ -167,7 +167,7 @@ async fn transfer_error() {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let res = cxt
|
||||
let res = ctx
|
||||
.api
|
||||
.tx()
|
||||
.balances()
|
||||
@@ -178,10 +178,9 @@ async fn transfer_error() {
|
||||
.wait_for_finalized_success()
|
||||
.await;
|
||||
|
||||
if let Err(Error::Runtime(err)) = res {
|
||||
let details = err.inner().details().unwrap();
|
||||
assert_eq!(details.pallet, "Balances");
|
||||
assert_eq!(details.error, "InsufficientBalance");
|
||||
if let Err(Error::Module(err)) = res {
|
||||
assert_eq!(err.pallet, "Balances");
|
||||
assert_eq!(err.error, "InsufficientBalance");
|
||||
} else {
|
||||
panic!("expected a runtime module error");
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ fn default_validator_prefs() -> ValidatorPrefs {
|
||||
#[async_std::test]
|
||||
async fn validate_with_controller_account() {
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
let cxt = test_context().await;
|
||||
cxt.api
|
||||
let ctx = test_context().await;
|
||||
ctx.api
|
||||
.tx()
|
||||
.staking()
|
||||
.validate(default_validator_prefs())
|
||||
@@ -69,8 +69,8 @@ async fn validate_with_controller_account() {
|
||||
#[async_std::test]
|
||||
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
|
||||
let ctx = test_context().await;
|
||||
let announce_validator = ctx
|
||||
.api
|
||||
.tx()
|
||||
.staking()
|
||||
@@ -79,10 +79,9 @@ async fn validate_not_possible_for_stash_account() -> Result<(), Error<DispatchE
|
||||
.await?
|
||||
.wait_for_finalized_success()
|
||||
.await;
|
||||
assert_matches!(announce_validator, Err(Error::Runtime(err)) => {
|
||||
let details = err.inner().details().unwrap();
|
||||
assert_eq!(details.pallet, "Staking");
|
||||
assert_eq!(details.error, "NotController");
|
||||
assert_matches!(announce_validator, Err(Error::Module(err)) => {
|
||||
assert_eq!(err.pallet, "Staking");
|
||||
assert_eq!(err.error, "NotController");
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@@ -91,9 +90,9 @@ async fn validate_not_possible_for_stash_account() -> Result<(), Error<DispatchE
|
||||
async fn nominate_with_controller_account() {
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
let bob = pair_signer(AccountKeyring::Bob.pair());
|
||||
let cxt = test_context().await;
|
||||
let ctx = test_context().await;
|
||||
|
||||
cxt.api
|
||||
ctx.api
|
||||
.tx()
|
||||
.staking()
|
||||
.nominate(vec![bob.account_id().clone().into()])
|
||||
@@ -109,9 +108,9 @@ async fn nominate_with_controller_account() {
|
||||
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;
|
||||
let ctx = test_context().await;
|
||||
|
||||
let nomination = cxt
|
||||
let nomination = ctx
|
||||
.api
|
||||
.tx()
|
||||
.staking()
|
||||
@@ -121,10 +120,9 @@ async fn nominate_not_possible_for_stash_account() -> Result<(), Error<DispatchE
|
||||
.wait_for_finalized_success()
|
||||
.await;
|
||||
|
||||
assert_matches!(nomination, Err(Error::Runtime(err)) => {
|
||||
let details = err.inner().details().unwrap();
|
||||
assert_eq!(details.pallet, "Staking");
|
||||
assert_eq!(details.error, "NotController");
|
||||
assert_matches!(nomination, Err(Error::Module(err)) => {
|
||||
assert_eq!(err.pallet, "Staking");
|
||||
assert_eq!(err.error, "NotController");
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@@ -134,10 +132,10 @@ 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());
|
||||
let cxt = test_context().await;
|
||||
let ctx = test_context().await;
|
||||
|
||||
// this will fail the second time, which is why this is one test, not two
|
||||
cxt.api
|
||||
ctx.api
|
||||
.tx()
|
||||
.staking()
|
||||
.nominate(vec![bob_stash.account_id().clone().into()])
|
||||
@@ -146,7 +144,7 @@ async fn chill_works_for_controller_only() -> Result<(), Error<DispatchError>> {
|
||||
.wait_for_finalized_success()
|
||||
.await?;
|
||||
|
||||
let ledger = cxt
|
||||
let ledger = ctx
|
||||
.api
|
||||
.storage()
|
||||
.staking()
|
||||
@@ -155,7 +153,7 @@ async fn chill_works_for_controller_only() -> Result<(), Error<DispatchError>> {
|
||||
.unwrap();
|
||||
assert_eq!(alice_stash.account_id(), &ledger.stash);
|
||||
|
||||
let chill = cxt
|
||||
let chill = ctx
|
||||
.api
|
||||
.tx()
|
||||
.staking()
|
||||
@@ -165,13 +163,12 @@ async fn chill_works_for_controller_only() -> Result<(), Error<DispatchError>> {
|
||||
.wait_for_finalized_success()
|
||||
.await;
|
||||
|
||||
assert_matches!(chill, Err(Error::Runtime(err)) => {
|
||||
let details = err.inner().details().unwrap();
|
||||
assert_eq!(details.pallet, "Staking");
|
||||
assert_eq!(details.error, "NotController");
|
||||
assert_matches!(chill, Err(Error::Module(err)) => {
|
||||
assert_eq!(err.pallet, "Staking");
|
||||
assert_eq!(err.error, "NotController");
|
||||
});
|
||||
|
||||
let is_chilled = cxt
|
||||
let is_chilled = ctx
|
||||
.api
|
||||
.tx()
|
||||
.staking()
|
||||
@@ -189,9 +186,9 @@ async fn chill_works_for_controller_only() -> Result<(), Error<DispatchError>> {
|
||||
#[async_std::test]
|
||||
async fn tx_bond() -> Result<(), Error<DispatchError>> {
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
let cxt = test_context().await;
|
||||
let ctx = test_context().await;
|
||||
|
||||
let bond = cxt
|
||||
let bond = ctx
|
||||
.api
|
||||
.tx()
|
||||
.staking()
|
||||
@@ -207,7 +204,7 @@ async fn tx_bond() -> Result<(), Error<DispatchError>> {
|
||||
|
||||
assert!(bond.is_ok());
|
||||
|
||||
let bond_again = cxt
|
||||
let bond_again = ctx
|
||||
.api
|
||||
.tx()
|
||||
.staking()
|
||||
@@ -221,26 +218,25 @@ async fn tx_bond() -> Result<(), Error<DispatchError>> {
|
||||
.wait_for_finalized_success()
|
||||
.await;
|
||||
|
||||
assert_matches!(bond_again, Err(Error::Runtime(err)) => {
|
||||
let details = err.inner().details().unwrap();
|
||||
assert_eq!(details.pallet, "Staking");
|
||||
assert_eq!(details.error, "AlreadyBonded");
|
||||
assert_matches!(bond_again, Err(Error::Module(err)) => {
|
||||
assert_eq!(err.pallet, "Staking");
|
||||
assert_eq!(err.error, "AlreadyBonded");
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn storage_history_depth() -> Result<(), Error<DispatchError>> {
|
||||
let cxt = test_context().await;
|
||||
let history_depth = cxt.api.storage().staking().history_depth(None).await?;
|
||||
let ctx = test_context().await;
|
||||
let history_depth = ctx.api.storage().staking().history_depth(None).await?;
|
||||
assert_eq!(history_depth, 84);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn storage_current_era() -> Result<(), Error<DispatchError>> {
|
||||
let cxt = test_context().await;
|
||||
let _current_era = cxt
|
||||
let ctx = test_context().await;
|
||||
let _current_era = ctx
|
||||
.api
|
||||
.storage()
|
||||
.staking()
|
||||
@@ -252,8 +248,8 @@ async fn storage_current_era() -> Result<(), Error<DispatchError>> {
|
||||
|
||||
#[async_std::test]
|
||||
async fn storage_era_reward_points() -> Result<(), Error<DispatchError>> {
|
||||
let cxt = test_context().await;
|
||||
let current_era_result = cxt
|
||||
let ctx = test_context().await;
|
||||
let current_era_result = ctx
|
||||
.api
|
||||
.storage()
|
||||
.staking()
|
||||
|
||||
Reference in New Issue
Block a user