mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 01:11:10 +00:00
Make sp_core and sp_runtime dependencies optional, and bump to latest (#760)
* begin porting over traits; remove Config use of Hash * port over the Header bits that we need * sp_core_hashing where possible, move Verify to PairSigner, remove unused errors * tidy up Config things and move related bits into one place * fix codegen * copy Era over * move AccountId, Address, Signer to Signer trait and a pass over fixing examples * impl MultiAddress, MultiSignature, AccountId32 and add back to Config (for decoding later) * Copy over StorageKey, StorageData, StorageChangeSet * subxt core compiling with no sp_core or sp_runtime * Get examples compiling * pass over fixing tests * cargo fmt * clippy tweaks and update polkadot.rs * fix codegen docs * port over special DigestItem encoding/decoding * clippy and doc fixes * cargo fmt and example fix * more cargo fmt-ing... * substrate-extra to substrate-compat * cargo.toml comments * simplify PairSigner trait bounds * move RPC types to a separate file * fix docs * Add some tests for things and other PR feedback * bump to latest sp deps * avoid needing substrate-compat feature in a test
This commit is contained in:
+14
-14
@@ -169,23 +169,23 @@ impl RuntimeGenerator {
|
||||
),
|
||||
(
|
||||
"sp_core::crypto::AccountId32",
|
||||
parse_quote!(#crate_path::ext::sp_core::crypto::AccountId32),
|
||||
),
|
||||
(
|
||||
"primitive_types::H160",
|
||||
parse_quote!(#crate_path::ext::sp_core::H160),
|
||||
),
|
||||
(
|
||||
"primitive_types::H256",
|
||||
parse_quote!(#crate_path::ext::sp_core::H256),
|
||||
),
|
||||
(
|
||||
"primitive_types::H512",
|
||||
parse_quote!(#crate_path::ext::sp_core::H512),
|
||||
parse_quote!(#crate_path::utils::AccountId32),
|
||||
),
|
||||
(
|
||||
"sp_runtime::multiaddress::MultiAddress",
|
||||
parse_quote!(#crate_path::ext::sp_runtime::MultiAddress),
|
||||
parse_quote!(#crate_path::utils::MultiAddress),
|
||||
),
|
||||
(
|
||||
"primitive_types::H160",
|
||||
parse_quote!(#crate_path::utils::H160),
|
||||
),
|
||||
(
|
||||
"primitive_types::H256",
|
||||
parse_quote!(#crate_path::utils::H256),
|
||||
),
|
||||
(
|
||||
"primitive_types::H512",
|
||||
parse_quote!(#crate_path::utils::H512),
|
||||
),
|
||||
(
|
||||
"frame_support::traits::misc::WrapperKeepOpaque",
|
||||
|
||||
+3
-1
@@ -14,8 +14,10 @@ description = "Subxt example usage"
|
||||
[dev-dependencies]
|
||||
subxt = { path = "../subxt" }
|
||||
tokio = { version = "1.8", features = ["rt-multi-thread", "macros", "time"] }
|
||||
sp-keyring = "7.0.0"
|
||||
sp-keyring = "12.0.0"
|
||||
futures = "0.3.13"
|
||||
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "full", "bit-vec"] }
|
||||
hex = "0.4.3"
|
||||
tracing-subscriber = "0.3.11"
|
||||
sp-core = { version = "11.0.0", default-features = false }
|
||||
sp-runtime = { version = "12.0.0" }
|
||||
|
||||
@@ -12,14 +12,16 @@
|
||||
|
||||
use sp_keyring::AccountKeyring;
|
||||
use subxt::{
|
||||
tx::{
|
||||
Era,
|
||||
PairSigner,
|
||||
PlainTip,
|
||||
PolkadotExtrinsicParamsBuilder as Params,
|
||||
config::{
|
||||
polkadot::{
|
||||
Era,
|
||||
PlainTip,
|
||||
PolkadotExtrinsicParamsBuilder as Params,
|
||||
},
|
||||
PolkadotConfig,
|
||||
},
|
||||
tx::PairSigner,
|
||||
OnlineClient,
|
||||
PolkadotConfig,
|
||||
};
|
||||
|
||||
#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")]
|
||||
|
||||
@@ -24,7 +24,7 @@ pub mod polkadot {}
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let api = OnlineClient::<PolkadotConfig>::new().await?;
|
||||
|
||||
let addr = AccountKeyring::Bob.to_account_id();
|
||||
let addr = AccountKeyring::Bob.to_account_id().into();
|
||||
|
||||
// Construct storage addresses to access:
|
||||
let staking_bonded = polkadot::storage().staking().bonded(&addr);
|
||||
|
||||
@@ -8,13 +8,11 @@
|
||||
use sp_keyring::AccountKeyring;
|
||||
use subxt::{
|
||||
config::{
|
||||
substrate::SubstrateExtrinsicParams,
|
||||
Config,
|
||||
SubstrateConfig,
|
||||
},
|
||||
tx::{
|
||||
PairSigner,
|
||||
SubstrateExtrinsicParams,
|
||||
},
|
||||
tx::PairSigner,
|
||||
OnlineClient,
|
||||
};
|
||||
|
||||
@@ -34,10 +32,10 @@ impl Config for MyConfig {
|
||||
type Index = u64;
|
||||
type BlockNumber = <SubstrateConfig as Config>::BlockNumber;
|
||||
type Hash = <SubstrateConfig as Config>::Hash;
|
||||
type Hashing = <SubstrateConfig as Config>::Hashing;
|
||||
type Hasher = <SubstrateConfig as Config>::Hasher;
|
||||
type Header = <SubstrateConfig as Config>::Header;
|
||||
type AccountId = <SubstrateConfig as Config>::AccountId;
|
||||
type Address = <SubstrateConfig as Config>::Address;
|
||||
type Header = <SubstrateConfig as Config>::Header;
|
||||
type Signature = <SubstrateConfig as Config>::Signature;
|
||||
// ExtrinsicParams makes use of the index type, so we need to adjust it
|
||||
// too to align with our modified index type, above:
|
||||
|
||||
@@ -10,15 +10,13 @@
|
||||
//! polkadot --dev --tmp
|
||||
//! ```
|
||||
|
||||
use sp_core::{
|
||||
sr25519,
|
||||
Pair,
|
||||
};
|
||||
use sp_keyring::AccountKeyring;
|
||||
use subxt::{
|
||||
ext::{
|
||||
sp_core::{
|
||||
sr25519,
|
||||
Pair,
|
||||
},
|
||||
sp_runtime::AccountId32,
|
||||
},
|
||||
utils::AccountId32,
|
||||
OnlineClient,
|
||||
PolkadotConfig,
|
||||
};
|
||||
|
||||
@@ -54,7 +54,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// threshold
|
||||
1,
|
||||
// other signatories
|
||||
vec![signer_account_id],
|
||||
vec![signer_account_id.into()],
|
||||
// maybe timepoint
|
||||
None,
|
||||
// call
|
||||
|
||||
@@ -11,11 +11,7 @@
|
||||
//! ```
|
||||
|
||||
use subxt::{
|
||||
ext::sp_runtime::{
|
||||
generic::Header,
|
||||
traits::BlakeTwo256,
|
||||
},
|
||||
rpc::Subscription,
|
||||
config::Header,
|
||||
OnlineClient,
|
||||
PolkadotConfig,
|
||||
};
|
||||
@@ -28,8 +24,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
OnlineClient::<PolkadotConfig>::from_url("wss://rpc.polkadot.io:443").await?;
|
||||
|
||||
// For non-finalised blocks use `.subscribe_blocks()`
|
||||
let mut blocks: Subscription<Header<u32, BlakeTwo256>> =
|
||||
api.rpc().subscribe_finalized_block_headers().await?;
|
||||
let mut blocks = api.rpc().subscribe_finalized_block_headers().await?;
|
||||
|
||||
while let Some(Ok(block)) = blocks.next().await {
|
||||
println!(
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ description = "Command line utilities for checking metadata compatibility betwee
|
||||
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "full"] }
|
||||
frame-metadata = "15.0.0"
|
||||
scale-info = "2.0.0"
|
||||
sp-core = "7.0.0"
|
||||
sp-core-hashing = "6.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] }
|
||||
|
||||
+2
-2
@@ -32,8 +32,8 @@ enum TypeBeingHashed {
|
||||
}
|
||||
|
||||
/// Hashing function utilized internally.
|
||||
fn hash(bytes: &[u8]) -> [u8; 32] {
|
||||
sp_core::hashing::twox_256(bytes)
|
||||
fn hash(data: &[u8]) -> [u8; 32] {
|
||||
sp_core_hashing::twox_256(data)
|
||||
}
|
||||
|
||||
/// XOR two hashes together. If we have two pseudorandom hashes, then this will
|
||||
|
||||
+26
-6
@@ -14,7 +14,14 @@ description = "Submit extrinsics (transactions) to a substrate node via RPC"
|
||||
keywords = ["parity", "substrate", "blockchain"]
|
||||
|
||||
[features]
|
||||
default = ["jsonrpsee-ws"]
|
||||
default = ["jsonrpsee-ws", "substrate-compat"]
|
||||
|
||||
# Activate this feature to pull in extra Substrate dependencies which make it
|
||||
# possible to provide a proper extrinsic Signer implementation (PairSigner).
|
||||
substrate-compat = [
|
||||
"sp-core",
|
||||
"sp-runtime"
|
||||
]
|
||||
|
||||
# Activate this to expose functionality only used for integration testing.
|
||||
# The exposed functionality is subject to breaking changes at any point,
|
||||
@@ -32,7 +39,7 @@ scale-info = "2.0.0"
|
||||
scale-value = "0.6.0"
|
||||
scale-bits = "0.3"
|
||||
scale-decode = "0.4.0"
|
||||
futures = { version = "0.3.13", default-features = false }
|
||||
futures = { version = "0.3.13", default-features = false, features = ["std"] }
|
||||
hex = "0.4.3"
|
||||
jsonrpsee = { version = "0.16", optional = true, features = ["jsonrpsee-types"] }
|
||||
serde = { version = "1.0.124", features = ["derive"] }
|
||||
@@ -40,15 +47,24 @@ serde_json = { version = "1.0.64", features = ["raw_value"] }
|
||||
thiserror = "1.0.24"
|
||||
tracing = "0.1.34"
|
||||
parking_lot = "0.12.0"
|
||||
frame-metadata = "15.0.0"
|
||||
derivative = "2.2.0"
|
||||
|
||||
subxt-macro = { version = "0.25.0", path = "../macro" }
|
||||
subxt-metadata = { version = "0.25.0", path = "../metadata" }
|
||||
|
||||
sp-core = { version = "7.0.0", default-features = false }
|
||||
sp-runtime = "7.0.0"
|
||||
# Provides some deserialization, types like U256/H256 and hashing impls like twox/blake256:
|
||||
impl-serde = { version = "0.4.0" }
|
||||
primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info", "serde"] }
|
||||
sp-core-hashing = "6.0.0"
|
||||
|
||||
frame-metadata = "15.0.0"
|
||||
derivative = "2.2.0"
|
||||
# For ss58 encoding AccountId32 to serialize them properly:
|
||||
base58 = { version = "0.2.0" }
|
||||
blake2 = { version = "0.10.4", default-features = false }
|
||||
|
||||
# These are only included is "substrate-compat" is enabled.
|
||||
sp-core = { version = "11.0.0", default-features = false, optional = true }
|
||||
sp-runtime = { version = "12.0.0", optional = true }
|
||||
|
||||
[target.wasm32-unknown-unknown.dependencies]
|
||||
getrandom = { version = "0.2", features = ["js"] }
|
||||
@@ -58,3 +74,7 @@ bitvec = "1"
|
||||
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "full", "bit-vec"] }
|
||||
scale-info = { version = "2.0.0", features = ["bit-vec"] }
|
||||
tokio = { version = "1.8", features = ["macros", "time", "rt-multi-thread"] }
|
||||
sp-core = { version = "11.0.0", default-features = false }
|
||||
sp-runtime = { version = "12.0.0" }
|
||||
sp-keyring = "12.0.0"
|
||||
sp-version = "10.0.0"
|
||||
|
||||
@@ -7,20 +7,20 @@ use crate::{
|
||||
OfflineClientT,
|
||||
OnlineClientT,
|
||||
},
|
||||
config::{
|
||||
Config,
|
||||
Hasher,
|
||||
Header,
|
||||
},
|
||||
error::{
|
||||
BlockError,
|
||||
Error,
|
||||
},
|
||||
events,
|
||||
rpc::ChainBlockResponse,
|
||||
Config,
|
||||
rpc::types::ChainBlockResponse,
|
||||
};
|
||||
use derivative::Derivative;
|
||||
use futures::lock::Mutex as AsyncMutex;
|
||||
use sp_runtime::traits::{
|
||||
Hash,
|
||||
Header,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// A representation of a block.
|
||||
@@ -56,7 +56,7 @@ where
|
||||
|
||||
/// Return the block number.
|
||||
pub fn number(&self) -> T::BlockNumber {
|
||||
*self.header().number()
|
||||
self.header().number()
|
||||
}
|
||||
|
||||
/// Return the entire block header.
|
||||
@@ -170,7 +170,7 @@ where
|
||||
pub async fn events(&self) -> Result<ExtrinsicEvents<T>, Error> {
|
||||
let events =
|
||||
get_events(&self.client, self.block_hash, &self.cached_events).await?;
|
||||
let ext_hash = T::Hashing::hash_of(&self.bytes);
|
||||
let ext_hash = T::Hasher::hash_of(&self.bytes);
|
||||
Ok(ExtrinsicEvents::new(ext_hash, self.index, events))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
use super::Block;
|
||||
use crate::{
|
||||
client::OnlineClientT,
|
||||
config::{
|
||||
Config,
|
||||
Header,
|
||||
},
|
||||
error::{
|
||||
BlockError,
|
||||
Error,
|
||||
},
|
||||
utils::PhantomDataSendSync,
|
||||
Config,
|
||||
};
|
||||
use derivative::Derivative;
|
||||
use futures::{
|
||||
@@ -19,7 +22,6 @@ use futures::{
|
||||
Stream,
|
||||
StreamExt,
|
||||
};
|
||||
use sp_runtime::traits::Header;
|
||||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
@@ -137,7 +139,7 @@ where
|
||||
.rpc()
|
||||
.header(Some(last_finalized_block_hash))
|
||||
.await?
|
||||
.map(|h| (*h.number()).into());
|
||||
.map(|h| h.number().into());
|
||||
|
||||
let sub = client.rpc().subscribe_finalized_block_headers().await?;
|
||||
|
||||
@@ -203,7 +205,7 @@ where
|
||||
};
|
||||
|
||||
// We want all previous details up to, but not including this current block num.
|
||||
let end_block_num = (*header.number()).into();
|
||||
let end_block_num = header.number().into();
|
||||
|
||||
// This is one after the last block we returned details for last time.
|
||||
let start_block_num = last_block_num.map(|n| n + 1).unwrap_or(end_block_num);
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::{
|
||||
blocks::BlocksClient,
|
||||
constants::ConstantsClient,
|
||||
events::EventsClient,
|
||||
rpc::RuntimeVersion,
|
||||
rpc::types::RuntimeVersion,
|
||||
storage::StorageClient,
|
||||
tx::TxClient,
|
||||
Config,
|
||||
|
||||
@@ -12,10 +12,12 @@ use crate::{
|
||||
error::Error,
|
||||
events::EventsClient,
|
||||
rpc::{
|
||||
types::{
|
||||
RuntimeVersion,
|
||||
Subscription,
|
||||
},
|
||||
Rpc,
|
||||
RpcClientT,
|
||||
RuntimeVersion,
|
||||
Subscription,
|
||||
},
|
||||
storage::StorageClient,
|
||||
tx::TxClient,
|
||||
|
||||
@@ -2,19 +2,26 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! This module contains a trait which controls the parameters that must
|
||||
//! be provided in order to successfully construct an extrinsic. A basic
|
||||
//! implementation of the trait is provided ([`BaseExtrinsicParams`]) which is
|
||||
//! used by the provided Substrate and Polkadot configuration.
|
||||
|
||||
use crate::{
|
||||
utils::Encoded,
|
||||
Config,
|
||||
};
|
||||
use codec::{
|
||||
Compact,
|
||||
Decode,
|
||||
Encode,
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
use derivative::Derivative;
|
||||
|
||||
// We require Era as a param below, so make it available from here.
|
||||
pub use sp_runtime::generic::Era;
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
|
||||
/// This trait allows you to configure the "signed extra" and
|
||||
/// "additional" parameters that are signed and used in transactions.
|
||||
@@ -48,22 +55,6 @@ pub trait ExtrinsicParams<Index, Hash>: Debug + 'static {
|
||||
fn encode_additional_to(&self, v: &mut Vec<u8>);
|
||||
}
|
||||
|
||||
/// A struct representing the signed extra and additional parameters required
|
||||
/// to construct a transaction for the default substrate node.
|
||||
pub type SubstrateExtrinsicParams<T> = BaseExtrinsicParams<T, AssetTip>;
|
||||
|
||||
/// A builder which leads to [`SubstrateExtrinsicParams`] being constructed.
|
||||
/// This is what you provide to methods like `sign_and_submit()`.
|
||||
pub type SubstrateExtrinsicParamsBuilder<T> = BaseExtrinsicParamsBuilder<T, AssetTip>;
|
||||
|
||||
/// A struct representing the signed extra and additional parameters required
|
||||
/// to construct a transaction for a polkadot node.
|
||||
pub type PolkadotExtrinsicParams<T> = BaseExtrinsicParams<T, PlainTip>;
|
||||
|
||||
/// A builder which leads to [`PolkadotExtrinsicParams`] being constructed.
|
||||
/// This is what you provide to methods like `sign_and_submit()`.
|
||||
pub type PolkadotExtrinsicParamsBuilder<T> = BaseExtrinsicParamsBuilder<T, PlainTip>;
|
||||
|
||||
/// An implementation of [`ExtrinsicParams`] that is suitable for constructing
|
||||
/// extrinsics that can be sent to a node with the same signed extra and additional
|
||||
/// parameters as a Polkadot/Substrate node. The way that tip payments are specified
|
||||
@@ -90,8 +81,9 @@ pub struct BaseExtrinsicParams<T: Config, Tip: Debug> {
|
||||
/// construct a [`BaseExtrinsicParams`] value. This implements [`Default`], which allows
|
||||
/// [`BaseExtrinsicParams`] to be used with convenience methods like `sign_and_submit_default()`.
|
||||
///
|
||||
/// Prefer to use [`SubstrateExtrinsicParamsBuilder`] for a version of this tailored towards
|
||||
/// Substrate, or [`PolkadotExtrinsicParamsBuilder`] for a version tailored to Polkadot.
|
||||
/// Prefer to use [`super::substrate::SubstrateExtrinsicParamsBuilder`] for a version of this
|
||||
/// tailored towards Substrate, or [`super::polkadot::PolkadotExtrinsicParamsBuilder`] for a
|
||||
/// version tailored to Polkadot.
|
||||
#[derive(Derivative)]
|
||||
#[derivative(
|
||||
Debug(bound = "Tip: Debug"),
|
||||
@@ -185,53 +177,94 @@ impl<T: Config, Tip: Debug + Encode + 'static> ExtrinsicParams<T::Index, T::Hash
|
||||
}
|
||||
}
|
||||
|
||||
/// A tip payment.
|
||||
#[derive(Copy, Clone, Debug, Default, Encode)]
|
||||
pub struct PlainTip {
|
||||
#[codec(compact)]
|
||||
tip: u128,
|
||||
// Dev note: This and related bits taken from `sp_runtime::generic::Era`
|
||||
/// An era to describe the longevity of a transaction.
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub enum Era {
|
||||
/// The transaction is valid forever. The genesis hash must be present in the signed content.
|
||||
Immortal,
|
||||
|
||||
/// Period and phase are encoded:
|
||||
/// - The period of validity from the block hash found in the signing material.
|
||||
/// - The phase in the period that this transaction's lifetime begins (and, importantly,
|
||||
/// implies which block hash is included in the signature material). If the `period` is
|
||||
/// greater than 1 << 12, then it will be a factor of the times greater than 1<<12 that
|
||||
/// `period` is.
|
||||
///
|
||||
/// When used on `FRAME`-based runtimes, `period` cannot exceed `BlockHashCount` parameter
|
||||
/// of `system` module.
|
||||
Mortal(Period, Phase),
|
||||
}
|
||||
|
||||
impl PlainTip {
|
||||
/// Create a new tip of the amount provided.
|
||||
pub fn new(amount: u128) -> Self {
|
||||
PlainTip { tip: amount }
|
||||
/// Era period
|
||||
pub type Period = u64;
|
||||
|
||||
/// Era phase
|
||||
pub type Phase = u64;
|
||||
|
||||
// E.g. with period == 4:
|
||||
// 0 10 20 30 40
|
||||
// 0123456789012345678901234567890123456789012
|
||||
// |...|
|
||||
// authored -/ \- expiry
|
||||
// phase = 1
|
||||
// n = Q(current - phase, period) + phase
|
||||
impl Era {
|
||||
/// Create a new era based on a period (which should be a power of two between 4 and 65536
|
||||
/// inclusive) and a block number on which it should start (or, for long periods, be shortly
|
||||
/// after the start).
|
||||
///
|
||||
/// If using `Era` in the context of `FRAME` runtime, make sure that `period`
|
||||
/// does not exceed `BlockHashCount` parameter passed to `system` module, since that
|
||||
/// prunes old blocks and renders transactions immediately invalid.
|
||||
pub fn mortal(period: u64, current: u64) -> Self {
|
||||
let period = period
|
||||
.checked_next_power_of_two()
|
||||
.unwrap_or(1 << 16)
|
||||
.clamp(4, 1 << 16);
|
||||
let phase = current % period;
|
||||
let quantize_factor = (period >> 12).max(1);
|
||||
let quantized_phase = phase / quantize_factor * quantize_factor;
|
||||
|
||||
Self::Mortal(period, quantized_phase)
|
||||
}
|
||||
|
||||
/// Create an "immortal" transaction.
|
||||
pub fn immortal() -> Self {
|
||||
Self::Immortal
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for PlainTip {
|
||||
fn from(n: u128) -> Self {
|
||||
PlainTip::new(n)
|
||||
}
|
||||
}
|
||||
|
||||
/// A tip payment made in the form of a specific asset.
|
||||
#[derive(Copy, Clone, Debug, Default, Encode)]
|
||||
pub struct AssetTip {
|
||||
#[codec(compact)]
|
||||
tip: u128,
|
||||
asset: Option<u32>,
|
||||
}
|
||||
|
||||
impl AssetTip {
|
||||
/// Create a new tip of the amount provided.
|
||||
pub fn new(amount: u128) -> Self {
|
||||
AssetTip {
|
||||
tip: amount,
|
||||
asset: None,
|
||||
// Both copied from `sp_runtime::generic::Era`; this is the wire interface and so
|
||||
// it's really the most important bit here.
|
||||
impl Encode for Era {
|
||||
fn encode_to<T: codec::Output + ?Sized>(&self, output: &mut T) {
|
||||
match self {
|
||||
Self::Immortal => output.push_byte(0),
|
||||
Self::Mortal(period, phase) => {
|
||||
let quantize_factor = (*period >> 12).max(1);
|
||||
let encoded = (period.trailing_zeros() - 1).clamp(1, 15) as u16
|
||||
| ((phase / quantize_factor) << 4) as u16;
|
||||
encoded.encode_to(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Designate the tip as being of a particular asset class.
|
||||
/// If this is not set, then the native currency is used.
|
||||
pub fn of_asset(mut self, asset: u32) -> Self {
|
||||
self.asset = Some(asset);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for AssetTip {
|
||||
fn from(n: u128) -> Self {
|
||||
AssetTip::new(n)
|
||||
}
|
||||
impl Decode for Era {
|
||||
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
|
||||
let first = input.read_byte()?;
|
||||
if first == 0 {
|
||||
Ok(Self::Immortal)
|
||||
} else {
|
||||
let encoded = first as u64 + ((input.read_byte()? as u64) << 8);
|
||||
let period = 2 << (encoded % (1 << 4));
|
||||
let quantize_factor = (period >> 12).max(1);
|
||||
let phase = (encoded >> 4) * quantize_factor;
|
||||
if period >= 4 && phase < period {
|
||||
Ok(Self::Mortal(period, phase))
|
||||
} else {
|
||||
Err("Invalid period and phase".into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,20 +8,21 @@
|
||||
//! default Substrate node implementation, and [`PolkadotConfig`] for a
|
||||
//! Polkadot node.
|
||||
|
||||
pub mod extrinsic_params;
|
||||
pub mod polkadot;
|
||||
pub mod substrate;
|
||||
|
||||
use codec::{
|
||||
Codec,
|
||||
Encode,
|
||||
EncodeLike,
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
use sp_runtime::traits::{
|
||||
AtLeast32Bit,
|
||||
Hash,
|
||||
Header,
|
||||
MaybeSerializeDeserialize,
|
||||
Member,
|
||||
Verify,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
pub use extrinsic_params::ExtrinsicParams;
|
||||
pub use polkadot::PolkadotConfig;
|
||||
pub use substrate::SubstrateConfig;
|
||||
|
||||
/// Runtime types.
|
||||
// Note: the 'static bound isn't strictly required, but currently deriving TypeInfo
|
||||
@@ -34,7 +35,6 @@ pub trait Config: 'static {
|
||||
+ Member
|
||||
+ serde::de::DeserializeOwned
|
||||
+ Default
|
||||
+ AtLeast32Bit
|
||||
+ Copy
|
||||
+ scale_info::TypeInfo
|
||||
+ Into<u64>;
|
||||
@@ -44,14 +44,15 @@ pub trait Config: 'static {
|
||||
+ Member
|
||||
+ Default
|
||||
+ Copy
|
||||
+ core::hash::Hash
|
||||
+ core::str::FromStr
|
||||
+ std::hash::Hash
|
||||
+ std::str::FromStr
|
||||
+ Into<u64>;
|
||||
|
||||
/// The output of the `Hashing` function.
|
||||
type Hash: Parameter
|
||||
+ Member
|
||||
+ MaybeSerializeDeserialize
|
||||
+ serde::Serialize
|
||||
+ serde::de::DeserializeOwned
|
||||
+ Ord
|
||||
+ Default
|
||||
+ Copy
|
||||
@@ -60,85 +61,97 @@ pub trait Config: 'static {
|
||||
+ AsMut<[u8]>
|
||||
+ scale_info::TypeInfo;
|
||||
|
||||
/// The account ID type.
|
||||
type AccountId: Clone + Serialize;
|
||||
|
||||
/// The address type.
|
||||
type Address: Encode + From<Self::AccountId>;
|
||||
|
||||
/// The signature type.
|
||||
type Signature: Encode;
|
||||
|
||||
/// The hashing system (algorithm) being used in the runtime (e.g. Blake2).
|
||||
type Hashing: Hash<Output = Self::Hash>;
|
||||
|
||||
/// The user account identifier type for the runtime.
|
||||
type AccountId: Parameter + Member + serde::Serialize;
|
||||
|
||||
/// The address type. This instead of `<frame_system::Trait::Lookup as StaticLookup>::Source`.
|
||||
type Address: Codec + Clone + PartialEq;
|
||||
type Hasher: Hasher<Output = Self::Hash>;
|
||||
|
||||
/// The block header.
|
||||
type Header: Parameter
|
||||
+ Header<Number = Self::BlockNumber, Hash = Self::Hash>
|
||||
+ Header<Number = Self::BlockNumber, Hasher = Self::Hasher>
|
||||
+ Member
|
||||
+ serde::de::DeserializeOwned;
|
||||
|
||||
/// Signature type.
|
||||
type Signature: Verify + Encode + Send + Sync + 'static;
|
||||
|
||||
/// This type defines the extrinsic extra and additional parameters.
|
||||
type ExtrinsicParams: crate::tx::ExtrinsicParams<Self::Index, Self::Hash>;
|
||||
type ExtrinsicParams: extrinsic_params::ExtrinsicParams<Self::Index, Self::Hash>;
|
||||
}
|
||||
|
||||
/// Parameter trait copied from `substrate::frame_support`
|
||||
/// Parameter trait copied from `substrate::frame_support`.
|
||||
pub trait Parameter: Codec + EncodeLike + Clone + Eq + Debug {}
|
||||
impl<T> Parameter for T where T: Codec + EncodeLike + Clone + Eq + Debug {}
|
||||
|
||||
/// Default set of commonly used types by Substrate runtimes.
|
||||
// Note: We only use this at the type level, so it should be impossible to
|
||||
// create an instance of it.
|
||||
pub enum SubstrateConfig {}
|
||||
/// A type that can be used in runtime structures. Copied from `sp_runtime::traits`.
|
||||
pub trait Member: Send + Sync + Sized + Debug + Eq + PartialEq + Clone + 'static {}
|
||||
impl<T: Send + Sync + Sized + Debug + Eq + PartialEq + Clone + 'static> Member for T {}
|
||||
|
||||
impl Config for SubstrateConfig {
|
||||
type Index = u32;
|
||||
type BlockNumber = u32;
|
||||
type Hash = sp_core::H256;
|
||||
type Hashing = sp_runtime::traits::BlakeTwo256;
|
||||
type AccountId = sp_runtime::AccountId32;
|
||||
type Address = sp_runtime::MultiAddress<Self::AccountId, u32>;
|
||||
type Header =
|
||||
sp_runtime::generic::Header<Self::BlockNumber, sp_runtime::traits::BlakeTwo256>;
|
||||
type Signature = sp_runtime::MultiSignature;
|
||||
type ExtrinsicParams = crate::tx::SubstrateExtrinsicParams<Self>;
|
||||
/// This represents the hasher used by a node to hash things like block headers
|
||||
/// and extrinsics.
|
||||
pub trait Hasher {
|
||||
/// The type given back from the hash operation
|
||||
type Output;
|
||||
|
||||
/// Hash some bytes to the given output type.
|
||||
fn hash(s: &[u8]) -> Self::Output;
|
||||
|
||||
/// Hash some SCALE encodable type to the given output type.
|
||||
fn hash_of<S: Encode>(s: &S) -> Self::Output {
|
||||
let out = s.encode();
|
||||
Self::hash(&out)
|
||||
}
|
||||
}
|
||||
|
||||
/// Default set of commonly used types by Polkadot nodes.
|
||||
pub type PolkadotConfig = WithExtrinsicParams<
|
||||
SubstrateConfig,
|
||||
crate::tx::PolkadotExtrinsicParams<SubstrateConfig>,
|
||||
>;
|
||||
/// This represents the block header type used by a node.
|
||||
pub trait Header: Sized + Encode {
|
||||
/// The block number type for this header.
|
||||
type Number;
|
||||
/// The hasher used to hash this header.
|
||||
type Hasher: Hasher;
|
||||
|
||||
/// Return the block number of this header.
|
||||
fn number(&self) -> Self::Number;
|
||||
|
||||
/// Hash this header.
|
||||
fn hash(&self) -> <Self::Hasher as Hasher>::Output {
|
||||
Self::Hasher::hash_of(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Take a type implementing [`Config`] (eg [`SubstrateConfig`]), and some type which describes the
|
||||
/// additional and extra parameters to pass to an extrinsic (see [`crate::tx::ExtrinsicParams`]),
|
||||
/// and returns a type implementing [`Config`] with those new `ExtrinsicParams`.
|
||||
/// additional and extra parameters to pass to an extrinsic (see [`ExtrinsicParams`]),
|
||||
/// and returns a type implementing [`Config`] with those new [`ExtrinsicParams`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use subxt::config::{ SubstrateConfig, WithExtrinsicParams };
|
||||
/// use subxt::tx::PolkadotExtrinsicParams;
|
||||
/// use subxt::config::{ SubstrateConfig, WithExtrinsicParams, polkadot::PolkadotExtrinsicParams };
|
||||
///
|
||||
/// // This is how PolkadotConfig is implemented:
|
||||
/// type PolkadotConfig = WithExtrinsicParams<SubstrateConfig, PolkadotExtrinsicParams<SubstrateConfig>>;
|
||||
/// ```
|
||||
pub struct WithExtrinsicParams<
|
||||
T: Config,
|
||||
E: crate::tx::ExtrinsicParams<T::Index, T::Hash>,
|
||||
E: extrinsic_params::ExtrinsicParams<T::Index, T::Hash>,
|
||||
> {
|
||||
_marker: std::marker::PhantomData<(T, E)>,
|
||||
}
|
||||
|
||||
impl<T: Config, E: crate::tx::ExtrinsicParams<T::Index, T::Hash>> Config
|
||||
impl<T: Config, E: extrinsic_params::ExtrinsicParams<T::Index, T::Hash>> Config
|
||||
for WithExtrinsicParams<T, E>
|
||||
{
|
||||
type Index = T::Index;
|
||||
type BlockNumber = T::BlockNumber;
|
||||
type Hash = T::Hash;
|
||||
type Hashing = T::Hashing;
|
||||
type AccountId = T::AccountId;
|
||||
type Address = T::Address;
|
||||
type Header = T::Header;
|
||||
type Signature = T::Signature;
|
||||
type Hasher = T::Hasher;
|
||||
type Header = T::Header;
|
||||
type ExtrinsicParams = E;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! Polkadot specific configuration
|
||||
|
||||
use codec::Encode;
|
||||
|
||||
use super::extrinsic_params::{
|
||||
BaseExtrinsicParams,
|
||||
BaseExtrinsicParamsBuilder,
|
||||
};
|
||||
|
||||
/// Default set of commonly used types by Polkadot nodes.
|
||||
pub type PolkadotConfig = super::WithExtrinsicParams<
|
||||
super::SubstrateConfig,
|
||||
PolkadotExtrinsicParams<super::SubstrateConfig>,
|
||||
>;
|
||||
|
||||
/// A struct representing the signed extra and additional parameters required
|
||||
/// to construct a transaction for a polkadot node.
|
||||
pub type PolkadotExtrinsicParams<T> = BaseExtrinsicParams<T, PlainTip>;
|
||||
|
||||
/// A builder which leads to [`PolkadotExtrinsicParams`] being constructed.
|
||||
/// This is what you provide to methods like `sign_and_submit()`.
|
||||
pub type PolkadotExtrinsicParamsBuilder<T> = BaseExtrinsicParamsBuilder<T, PlainTip>;
|
||||
|
||||
// Because Era is one of the args to our extrinsic params.
|
||||
pub use super::extrinsic_params::Era;
|
||||
|
||||
/// A tip payment.
|
||||
#[derive(Copy, Clone, Debug, Default, Encode)]
|
||||
pub struct PlainTip {
|
||||
#[codec(compact)]
|
||||
tip: u128,
|
||||
}
|
||||
|
||||
impl PlainTip {
|
||||
/// Create a new tip of the amount provided.
|
||||
pub fn new(amount: u128) -> Self {
|
||||
PlainTip { tip: amount }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for PlainTip {
|
||||
fn from(n: u128) -> Self {
|
||||
PlainTip::new(n)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! Substrate specific configuration
|
||||
|
||||
use super::{
|
||||
extrinsic_params::{
|
||||
BaseExtrinsicParams,
|
||||
BaseExtrinsicParamsBuilder,
|
||||
},
|
||||
Config,
|
||||
Hasher,
|
||||
Header,
|
||||
};
|
||||
use codec::{
|
||||
Decode,
|
||||
Encode,
|
||||
};
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
|
||||
pub use crate::utils::{
|
||||
account_id::AccountId32,
|
||||
multi_address::MultiAddress,
|
||||
multi_signature::MultiSignature,
|
||||
};
|
||||
pub use primitive_types::{
|
||||
H256,
|
||||
U256,
|
||||
};
|
||||
|
||||
/// Default set of commonly used types by Substrate runtimes.
|
||||
// Note: We only use this at the type level, so it should be impossible to
|
||||
// create an instance of it.
|
||||
pub enum SubstrateConfig {}
|
||||
|
||||
impl Config for SubstrateConfig {
|
||||
type Index = u32;
|
||||
type BlockNumber = u32;
|
||||
type Hash = H256;
|
||||
type AccountId = AccountId32;
|
||||
type Address = MultiAddress<Self::AccountId, u32>;
|
||||
type Signature = MultiSignature;
|
||||
type Hasher = BlakeTwo256;
|
||||
type Header = SubstrateHeader<Self::BlockNumber, BlakeTwo256>;
|
||||
type ExtrinsicParams = SubstrateExtrinsicParams<Self>;
|
||||
}
|
||||
|
||||
/// A struct representing the signed extra and additional parameters required
|
||||
/// to construct a transaction for the default substrate node.
|
||||
pub type SubstrateExtrinsicParams<T> = BaseExtrinsicParams<T, AssetTip>;
|
||||
|
||||
/// A builder which leads to [`SubstrateExtrinsicParams`] being constructed.
|
||||
/// This is what you provide to methods like `sign_and_submit()`.
|
||||
pub type SubstrateExtrinsicParamsBuilder<T> = BaseExtrinsicParamsBuilder<T, AssetTip>;
|
||||
|
||||
// Because Era is one of the args to our extrinsic params.
|
||||
pub use super::extrinsic_params::Era;
|
||||
|
||||
/// A tip payment made in the form of a specific asset.
|
||||
#[derive(Copy, Clone, Debug, Default, Encode)]
|
||||
pub struct AssetTip {
|
||||
#[codec(compact)]
|
||||
tip: u128,
|
||||
asset: Option<u32>,
|
||||
}
|
||||
|
||||
impl AssetTip {
|
||||
/// Create a new tip of the amount provided.
|
||||
pub fn new(amount: u128) -> Self {
|
||||
AssetTip {
|
||||
tip: amount,
|
||||
asset: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Designate the tip as being of a particular asset class.
|
||||
/// If this is not set, then the native currency is used.
|
||||
pub fn of_asset(mut self, asset: u32) -> Self {
|
||||
self.asset = Some(asset);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for AssetTip {
|
||||
fn from(n: u128) -> Self {
|
||||
AssetTip::new(n)
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that can hash values using the blaks2_256 algorithm.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode)]
|
||||
pub struct BlakeTwo256;
|
||||
|
||||
impl Hasher for BlakeTwo256 {
|
||||
type Output = H256;
|
||||
fn hash(s: &[u8]) -> Self::Output {
|
||||
sp_core_hashing::blake2_256(s).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// A generic Substrate header type, adapted from `sp_runtime::generic::Header`.
|
||||
/// The block number and hasher can be configured to adapt this for other nodes.
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SubstrateHeader<N: Copy + Into<U256> + TryFrom<U256>, H: Hasher> {
|
||||
/// The parent hash.
|
||||
pub parent_hash: H::Output,
|
||||
/// The block number.
|
||||
#[serde(
|
||||
serialize_with = "serialize_number",
|
||||
deserialize_with = "deserialize_number"
|
||||
)]
|
||||
#[codec(compact)]
|
||||
pub number: N,
|
||||
/// The state trie merkle root
|
||||
pub state_root: H::Output,
|
||||
/// The merkle root of the extrinsics.
|
||||
pub extrinsics_root: H::Output,
|
||||
/// A chain-specific digest of data useful for light clients or referencing auxiliary data.
|
||||
pub digest: Digest,
|
||||
}
|
||||
|
||||
impl<N: Copy + Into<U256> + TryFrom<U256> + Encode, H: Hasher + Encode> Header
|
||||
for SubstrateHeader<N, H>
|
||||
where
|
||||
N: Copy + Into<U256> + TryFrom<U256> + Encode,
|
||||
H: Hasher + Encode,
|
||||
SubstrateHeader<N, H>: Encode,
|
||||
{
|
||||
type Number = N;
|
||||
type Hasher = H;
|
||||
fn number(&self) -> Self::Number {
|
||||
self.number
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic header digest. From `sp_runtime::generic::digest`.
|
||||
#[derive(
|
||||
Encode, Decode, Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Default,
|
||||
)]
|
||||
pub struct Digest {
|
||||
/// A list of digest items.
|
||||
pub logs: Vec<DigestItem>,
|
||||
}
|
||||
|
||||
/// Digest item that is able to encode/decode 'system' digest items and
|
||||
/// provide opaque access to other items. From `sp_runtime::generic::digest`.
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum DigestItem {
|
||||
/// A pre-runtime digest.
|
||||
///
|
||||
/// These are messages from the consensus engine to the runtime, although
|
||||
/// the consensus engine can (and should) read them itself to avoid
|
||||
/// code and state duplication. It is erroneous for a runtime to produce
|
||||
/// these, but this is not (yet) checked.
|
||||
///
|
||||
/// NOTE: the runtime is not allowed to panic or fail in an `on_initialize`
|
||||
/// call if an expected `PreRuntime` digest is not present. It is the
|
||||
/// responsibility of a external block verifier to check this. Runtime API calls
|
||||
/// will initialize the block without pre-runtime digests, so initialization
|
||||
/// cannot fail when they are missing.
|
||||
PreRuntime(ConsensusEngineId, Vec<u8>),
|
||||
|
||||
/// A message from the runtime to the consensus engine. This should *never*
|
||||
/// be generated by the native code of any consensus engine, but this is not
|
||||
/// checked (yet).
|
||||
Consensus(ConsensusEngineId, Vec<u8>),
|
||||
|
||||
/// Put a Seal on it. This is only used by native code, and is never seen
|
||||
/// by runtimes.
|
||||
Seal(ConsensusEngineId, Vec<u8>),
|
||||
|
||||
/// Some other thing. Unsupported and experimental.
|
||||
Other(Vec<u8>),
|
||||
|
||||
/// An indication for the light clients that the runtime execution
|
||||
/// environment is updated.
|
||||
///
|
||||
/// Currently this is triggered when:
|
||||
/// 1. Runtime code blob is changed or
|
||||
/// 2. `heap_pages` value is changed.
|
||||
RuntimeEnvironmentUpdated,
|
||||
}
|
||||
|
||||
// From sp_runtime::generic, DigestItem enum indexes are encoded using this:
|
||||
#[repr(u32)]
|
||||
#[derive(Encode, Decode)]
|
||||
enum DigestItemType {
|
||||
Other = 0u32,
|
||||
Consensus = 4u32,
|
||||
Seal = 5u32,
|
||||
PreRuntime = 6u32,
|
||||
RuntimeEnvironmentUpdated = 8u32,
|
||||
}
|
||||
impl Encode for DigestItem {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let mut v = Vec::new();
|
||||
|
||||
match self {
|
||||
Self::Consensus(val, data) => {
|
||||
DigestItemType::Consensus.encode_to(&mut v);
|
||||
(val, data).encode_to(&mut v);
|
||||
}
|
||||
Self::Seal(val, sig) => {
|
||||
DigestItemType::Seal.encode_to(&mut v);
|
||||
(val, sig).encode_to(&mut v);
|
||||
}
|
||||
Self::PreRuntime(val, data) => {
|
||||
DigestItemType::PreRuntime.encode_to(&mut v);
|
||||
(val, data).encode_to(&mut v);
|
||||
}
|
||||
Self::Other(val) => {
|
||||
DigestItemType::Other.encode_to(&mut v);
|
||||
val.encode_to(&mut v);
|
||||
}
|
||||
Self::RuntimeEnvironmentUpdated => {
|
||||
DigestItemType::RuntimeEnvironmentUpdated.encode_to(&mut v);
|
||||
}
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
impl Decode for DigestItem {
|
||||
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
|
||||
let item_type: DigestItemType = Decode::decode(input)?;
|
||||
match item_type {
|
||||
DigestItemType::PreRuntime => {
|
||||
let vals: (ConsensusEngineId, Vec<u8>) = Decode::decode(input)?;
|
||||
Ok(Self::PreRuntime(vals.0, vals.1))
|
||||
}
|
||||
DigestItemType::Consensus => {
|
||||
let vals: (ConsensusEngineId, Vec<u8>) = Decode::decode(input)?;
|
||||
Ok(Self::Consensus(vals.0, vals.1))
|
||||
}
|
||||
DigestItemType::Seal => {
|
||||
let vals: (ConsensusEngineId, Vec<u8>) = Decode::decode(input)?;
|
||||
Ok(Self::Seal(vals.0, vals.1))
|
||||
}
|
||||
DigestItemType::Other => Ok(Self::Other(Decode::decode(input)?)),
|
||||
DigestItemType::RuntimeEnvironmentUpdated => {
|
||||
Ok(Self::RuntimeEnvironmentUpdated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Consensus engine unique ID. From `sp_runtime::ConsensusEngineId`.
|
||||
pub type ConsensusEngineId = [u8; 4];
|
||||
|
||||
impl serde::Serialize for DigestItem {
|
||||
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
self.using_encoded(|bytes| impl_serde::serialize::serialize(bytes, seq))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> serde::Deserialize<'a> for DigestItem {
|
||||
fn deserialize<D>(de: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'a>,
|
||||
{
|
||||
let r = impl_serde::serialize::deserialize(de)?;
|
||||
Decode::decode(&mut &r[..])
|
||||
.map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_number<S, T: Copy + Into<U256> + TryFrom<U256>>(
|
||||
val: &T,
|
||||
s: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let u256: U256 = (*val).into();
|
||||
serde::Serialize::serialize(&u256, s)
|
||||
}
|
||||
|
||||
fn deserialize_number<'a, D, T: Copy + Into<U256> + TryFrom<U256>>(
|
||||
d: D,
|
||||
) -> Result<T, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'a>,
|
||||
{
|
||||
let u256: U256 = serde::Deserialize::deserialize(d)?;
|
||||
TryFrom::try_from(u256).map_err(|_| serde::de::Error::custom("Try from failed"))
|
||||
}
|
||||
@@ -19,8 +19,6 @@ pub use scale_value::scale::{
|
||||
DecodeError,
|
||||
EncodeError,
|
||||
};
|
||||
pub use sp_core::crypto::SecretStringError;
|
||||
pub use sp_runtime::transaction_validity::TransactionValidityError;
|
||||
|
||||
/// The underlying error enum, generic over the type held by the `Runtime`
|
||||
/// variant. Prefer to use the [`Error<E>`] and [`Error`] aliases over
|
||||
@@ -39,12 +37,6 @@ pub enum Error {
|
||||
/// Serde serialization error
|
||||
#[error("Serde json error: {0}")]
|
||||
Serialization(#[from] serde_json::error::Error),
|
||||
/// Secret string error.
|
||||
#[error("Secret String Error")]
|
||||
SecretString(SecretStringError),
|
||||
/// Extrinsic validity error
|
||||
#[error("Transaction Validity Error: {0:?}")]
|
||||
Invalid(TransactionValidityError),
|
||||
/// Invalid metadata error
|
||||
#[error("Invalid Metadata: {0}")]
|
||||
InvalidMetadata(#[from] InvalidMetadataError),
|
||||
@@ -74,18 +66,6 @@ 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())
|
||||
|
||||
@@ -6,13 +6,10 @@ use crate::{
|
||||
client::OnlineClientT,
|
||||
error::Error,
|
||||
events::Events,
|
||||
rpc::types::StorageKey,
|
||||
Config,
|
||||
};
|
||||
use derivative::Derivative;
|
||||
use sp_core::{
|
||||
storage::StorageKey,
|
||||
twox_128,
|
||||
};
|
||||
use std::future::Future;
|
||||
|
||||
/// A client for working with events.
|
||||
@@ -74,8 +71,8 @@ where
|
||||
|
||||
// The storage key needed to access events.
|
||||
fn system_events_key() -> StorageKey {
|
||||
let mut storage_key = twox_128(b"System").to_vec();
|
||||
storage_key.extend(twox_128(b"Events").to_vec());
|
||||
let mut storage_key = sp_core_hashing::twox_128(b"System").to_vec();
|
||||
storage_key.extend(sp_core_hashing::twox_128(b"Events").to_vec());
|
||||
StorageKey(storage_key)
|
||||
}
|
||||
|
||||
|
||||
@@ -181,6 +181,4 @@ pub mod ext {
|
||||
pub use frame_metadata;
|
||||
pub use scale_bits;
|
||||
pub use scale_value;
|
||||
pub use sp_core;
|
||||
pub use sp_runtime;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,10 @@ mod rpc;
|
||||
mod rpc_client;
|
||||
mod rpc_client_t;
|
||||
|
||||
// Expose the `Rpc` struct and any associated types.
|
||||
// Expose our RPC types here.
|
||||
pub mod types;
|
||||
|
||||
// Expose the `Rpc` struct.
|
||||
pub use rpc::*;
|
||||
|
||||
pub use rpc_client_t::{
|
||||
|
||||
+33
-368
@@ -41,6 +41,7 @@
|
||||
|
||||
use super::{
|
||||
rpc_params,
|
||||
types,
|
||||
RpcClient,
|
||||
RpcClientT,
|
||||
Subscription,
|
||||
@@ -56,293 +57,8 @@ use codec::{
|
||||
Encode,
|
||||
};
|
||||
use frame_metadata::RuntimeMetadataPrefixed;
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
use sp_core::{
|
||||
storage::{
|
||||
StorageChangeSet,
|
||||
StorageData,
|
||||
StorageKey,
|
||||
},
|
||||
Bytes,
|
||||
U256,
|
||||
};
|
||||
use sp_runtime::ApplyExtrinsicResult;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
/// A number type that can be serialized both as a number or a string that encodes a number in a
|
||||
/// string.
|
||||
///
|
||||
/// We allow two representations of the block number as input. Either we deserialize to the type
|
||||
/// that is specified in the block type or we attempt to parse given hex value.
|
||||
///
|
||||
/// The primary motivation for having this type is to avoid overflows when using big integers in
|
||||
/// JavaScript (which we consider as an important RPC API consumer).
|
||||
#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
#[serde(untagged)]
|
||||
pub enum NumberOrHex {
|
||||
/// The number represented directly.
|
||||
Number(u64),
|
||||
/// Hex representation of the number.
|
||||
Hex(U256),
|
||||
}
|
||||
|
||||
/// The response from `chain_getBlock`
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(bound = "T: Config")]
|
||||
pub struct ChainBlockResponse<T: Config> {
|
||||
/// The block itself.
|
||||
pub block: ChainBlock<T>,
|
||||
/// Block justification.
|
||||
pub justifications: Option<sp_runtime::Justifications>,
|
||||
}
|
||||
|
||||
/// Block details in the [`ChainBlockResponse`].
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ChainBlock<T: Config> {
|
||||
/// The block header.
|
||||
pub header: T::Header,
|
||||
/// The accompanying extrinsics.
|
||||
pub extrinsics: Vec<ChainBlockExtrinsic>,
|
||||
}
|
||||
|
||||
/// Bytes representing an extrinsic in a [`ChainBlock`].
|
||||
#[derive(Debug)]
|
||||
pub struct ChainBlockExtrinsic(pub Vec<u8>);
|
||||
|
||||
impl<'a> ::serde::Deserialize<'a> for ChainBlockExtrinsic {
|
||||
fn deserialize<D>(de: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: ::serde::Deserializer<'a>,
|
||||
{
|
||||
let r = sp_core::bytes::deserialize(de)?;
|
||||
let bytes = Decode::decode(&mut &r[..])
|
||||
.map_err(|e| ::serde::de::Error::custom(format!("Decode error: {}", e)))?;
|
||||
Ok(ChainBlockExtrinsic(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for NumberOrHex to allow custom From impls
|
||||
#[derive(Serialize)]
|
||||
pub struct BlockNumber(NumberOrHex);
|
||||
|
||||
impl From<NumberOrHex> for BlockNumber {
|
||||
fn from(x: NumberOrHex) -> Self {
|
||||
BlockNumber(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NumberOrHex {
|
||||
fn default() -> Self {
|
||||
Self::Number(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl NumberOrHex {
|
||||
/// Converts this number into an U256.
|
||||
pub fn into_u256(self) -> U256 {
|
||||
match self {
|
||||
NumberOrHex::Number(n) => n.into(),
|
||||
NumberOrHex::Hex(h) => h,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for NumberOrHex {
|
||||
fn from(n: u32) -> Self {
|
||||
NumberOrHex::Number(n.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for NumberOrHex {
|
||||
fn from(n: u64) -> Self {
|
||||
NumberOrHex::Number(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for NumberOrHex {
|
||||
fn from(n: u128) -> Self {
|
||||
NumberOrHex::Hex(n.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<U256> for NumberOrHex {
|
||||
fn from(n: U256) -> Self {
|
||||
NumberOrHex::Hex(n)
|
||||
}
|
||||
}
|
||||
|
||||
/// An error type that signals an out-of-range conversion attempt.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Out-of-range conversion attempt")]
|
||||
pub struct TryFromIntError;
|
||||
|
||||
impl TryFrom<NumberOrHex> for u32 {
|
||||
type Error = TryFromIntError;
|
||||
fn try_from(num_or_hex: NumberOrHex) -> Result<u32, Self::Error> {
|
||||
num_or_hex
|
||||
.into_u256()
|
||||
.try_into()
|
||||
.map_err(|_| TryFromIntError)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<NumberOrHex> for u64 {
|
||||
type Error = TryFromIntError;
|
||||
fn try_from(num_or_hex: NumberOrHex) -> Result<u64, Self::Error> {
|
||||
num_or_hex
|
||||
.into_u256()
|
||||
.try_into()
|
||||
.map_err(|_| TryFromIntError)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<NumberOrHex> for u128 {
|
||||
type Error = TryFromIntError;
|
||||
fn try_from(num_or_hex: NumberOrHex) -> Result<u128, Self::Error> {
|
||||
num_or_hex
|
||||
.into_u256()
|
||||
.try_into()
|
||||
.map_err(|_| TryFromIntError)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NumberOrHex> for U256 {
|
||||
fn from(num_or_hex: NumberOrHex) -> U256 {
|
||||
num_or_hex.into_u256()
|
||||
}
|
||||
}
|
||||
|
||||
// All unsigned ints can be converted into a BlockNumber:
|
||||
macro_rules! into_block_number {
|
||||
($($t: ty)+) => {
|
||||
$(
|
||||
impl From<$t> for BlockNumber {
|
||||
fn from(x: $t) -> Self {
|
||||
NumberOrHex::Number(x.into()).into()
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
into_block_number!(u8 u16 u32 u64);
|
||||
|
||||
/// Arbitrary properties defined in the chain spec as a JSON object.
|
||||
pub type SystemProperties = serde_json::Map<String, serde_json::Value>;
|
||||
|
||||
/// Possible transaction status events.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This is copied from `sp-transaction-pool` to avoid a dependency on that crate. Therefore it
|
||||
/// must be kept compatible with that type from the target substrate version.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum SubstrateTxStatus<Hash, BlockHash> {
|
||||
/// Transaction is part of the future queue.
|
||||
Future,
|
||||
/// Transaction is part of the ready queue.
|
||||
Ready,
|
||||
/// The transaction has been broadcast to the given peers.
|
||||
Broadcast(Vec<String>),
|
||||
/// Transaction has been included in block with given hash.
|
||||
InBlock(BlockHash),
|
||||
/// The block this transaction was included in has been retracted.
|
||||
Retracted(BlockHash),
|
||||
/// Maximum number of finality watchers has been reached,
|
||||
/// old watchers are being removed.
|
||||
FinalityTimeout(BlockHash),
|
||||
/// Transaction has been finalized by a finality-gadget, e.g GRANDPA
|
||||
Finalized(BlockHash),
|
||||
/// Transaction has been replaced in the pool, by another transaction
|
||||
/// that provides the same tags. (e.g. same (sender, nonce)).
|
||||
Usurped(Hash),
|
||||
/// Transaction has been dropped from the pool because of the limit.
|
||||
Dropped,
|
||||
/// Transaction is no longer valid in the current state.
|
||||
Invalid,
|
||||
}
|
||||
|
||||
/// This contains the runtime version information necessary to make transactions, as obtained from
|
||||
/// the RPC call `state_getRuntimeVersion`,
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RuntimeVersion {
|
||||
/// Version of the runtime specification. A full-node will not attempt to use its native
|
||||
/// runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`,
|
||||
/// `spec_version` and `authoring_version` are the same between Wasm and native.
|
||||
pub spec_version: u32,
|
||||
|
||||
/// All existing dispatches are fully compatible when this number doesn't change. If this
|
||||
/// number changes, then `spec_version` must change, also.
|
||||
///
|
||||
/// This number must change when an existing dispatchable (module ID, dispatch ID) is changed,
|
||||
/// either through an alteration in its user-level semantics, a parameter
|
||||
/// added/removed/changed, a dispatchable being removed, a module being removed, or a
|
||||
/// dispatchable/module changing its index.
|
||||
///
|
||||
/// It need *not* change when a new module is added or when a dispatchable is added.
|
||||
pub transaction_version: u32,
|
||||
|
||||
/// The other fields present may vary and aren't necessary for `subxt`; they are preserved in
|
||||
/// this map.
|
||||
#[serde(flatten)]
|
||||
pub other: HashMap<String, serde_json::Value>,
|
||||
}
|
||||
|
||||
/// ReadProof struct returned by the RPC
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This is copied from `sc-rpc-api` to avoid a dependency on that crate. Therefore it
|
||||
/// must be kept compatible with that type from the target substrate version.
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ReadProof<Hash> {
|
||||
/// Block hash used to generate the proof
|
||||
pub at: Hash,
|
||||
/// A proof used to prove that storage entries are included in the storage trie
|
||||
pub proof: Vec<Bytes>,
|
||||
}
|
||||
|
||||
/// Statistics of a block returned by the `dev_getBlockStats` RPC.
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BlockStats {
|
||||
/// The length in bytes of the storage proof produced by executing the block.
|
||||
pub witness_len: u64,
|
||||
/// The length in bytes of the storage proof after compaction.
|
||||
pub witness_compact_len: u64,
|
||||
/// Length of the block in bytes.
|
||||
///
|
||||
/// This information can also be acquired by downloading the whole block. This merely
|
||||
/// saves some complexity on the client side.
|
||||
pub block_len: u64,
|
||||
/// Number of extrinsics in the block.
|
||||
///
|
||||
/// This information can also be acquired by downloading the whole block. This merely
|
||||
/// saves some complexity on the client side.
|
||||
pub num_extrinsics: u64,
|
||||
}
|
||||
|
||||
/// Health struct returned by the RPC
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Health {
|
||||
/// Number of connected peers
|
||||
pub peers: usize,
|
||||
/// Is the node syncing
|
||||
pub is_syncing: bool,
|
||||
/// Should this node have any peers
|
||||
///
|
||||
/// Might be false for local chains or when running without discovery.
|
||||
pub should_have_peers: bool,
|
||||
}
|
||||
use serde::Serialize;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Client for substrate rpc interfaces
|
||||
pub struct Rpc<T: Config> {
|
||||
@@ -382,7 +98,7 @@ impl<T: Config> Rpc<T> {
|
||||
&self,
|
||||
key: &[u8],
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<Option<StorageData>, Error> {
|
||||
) -> Result<Option<types::StorageData>, Error> {
|
||||
let params = rpc_params![to_hex(key), hash];
|
||||
let data = self.client.request("state_getStorage", params).await?;
|
||||
Ok(data)
|
||||
@@ -397,7 +113,7 @@ impl<T: Config> Rpc<T> {
|
||||
count: u32,
|
||||
start_key: Option<&[u8]>,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<Vec<StorageKey>, Error> {
|
||||
) -> Result<Vec<types::StorageKey>, Error> {
|
||||
let start_key = start_key.map(to_hex);
|
||||
let params = rpc_params![to_hex(key), count, start_key, hash];
|
||||
let data = self.client.request("state_getKeysPaged", params).await?;
|
||||
@@ -410,7 +126,7 @@ impl<T: Config> Rpc<T> {
|
||||
keys: impl IntoIterator<Item = &[u8]>,
|
||||
from: T::Hash,
|
||||
to: Option<T::Hash>,
|
||||
) -> Result<Vec<StorageChangeSet<T::Hash>>, Error> {
|
||||
) -> Result<Vec<types::StorageChangeSet<T::Hash>>, Error> {
|
||||
let keys: Vec<String> = keys.into_iter().map(to_hex).collect();
|
||||
let params = rpc_params![keys, from, to];
|
||||
self.client
|
||||
@@ -424,7 +140,7 @@ impl<T: Config> Rpc<T> {
|
||||
&self,
|
||||
keys: impl IntoIterator<Item = &[u8]>,
|
||||
at: Option<T::Hash>,
|
||||
) -> Result<Vec<StorageChangeSet<T::Hash>>, Error> {
|
||||
) -> Result<Vec<types::StorageChangeSet<T::Hash>>, Error> {
|
||||
let keys: Vec<String> = keys.into_iter().map(to_hex).collect();
|
||||
let params = rpc_params![keys, at];
|
||||
self.client
|
||||
@@ -444,7 +160,7 @@ impl<T: Config> Rpc<T> {
|
||||
|
||||
/// Fetch the metadata
|
||||
pub async fn metadata(&self, at: Option<T::Hash>) -> Result<Metadata, Error> {
|
||||
let bytes: Bytes = self
|
||||
let bytes: types::Bytes = self
|
||||
.client
|
||||
.request("state_getMetadata", rpc_params![at])
|
||||
.await?;
|
||||
@@ -454,14 +170,14 @@ impl<T: Config> Rpc<T> {
|
||||
}
|
||||
|
||||
/// Fetch system properties
|
||||
pub async fn system_properties(&self) -> Result<SystemProperties, Error> {
|
||||
pub async fn system_properties(&self) -> Result<types::SystemProperties, Error> {
|
||||
self.client
|
||||
.request("system_properties", rpc_params![])
|
||||
.await
|
||||
}
|
||||
|
||||
/// Fetch system health
|
||||
pub async fn system_health(&self) -> Result<Health, Error> {
|
||||
pub async fn system_health(&self) -> Result<types::Health, Error> {
|
||||
self.client.request("system_health", rpc_params![]).await
|
||||
}
|
||||
|
||||
@@ -481,9 +197,9 @@ impl<T: Config> Rpc<T> {
|
||||
}
|
||||
|
||||
/// Fetch the current nonce for the given account ID.
|
||||
pub async fn system_account_next_index(
|
||||
pub async fn system_account_next_index<AccountId: Serialize>(
|
||||
&self,
|
||||
account: &T::AccountId,
|
||||
account: &AccountId,
|
||||
) -> Result<T::Index, Error> {
|
||||
self.client
|
||||
.request("system_accountNextIndex", rpc_params![account])
|
||||
@@ -503,7 +219,7 @@ impl<T: Config> Rpc<T> {
|
||||
/// Get a block hash, returns hash of latest block by default
|
||||
pub async fn block_hash(
|
||||
&self,
|
||||
block_number: Option<BlockNumber>,
|
||||
block_number: Option<types::BlockNumber>,
|
||||
) -> Result<Option<T::Hash>, Error> {
|
||||
let params = rpc_params![block_number];
|
||||
let block_hash = self.client.request("chain_getBlockHash", params).await?;
|
||||
@@ -523,7 +239,7 @@ impl<T: Config> Rpc<T> {
|
||||
pub async fn block(
|
||||
&self,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<Option<ChainBlockResponse<T>>, Error> {
|
||||
) -> Result<Option<types::ChainBlockResponse<T>>, Error> {
|
||||
let params = rpc_params![hash];
|
||||
let block = self.client.request("chain_getBlock", params).await?;
|
||||
Ok(block)
|
||||
@@ -537,7 +253,7 @@ impl<T: Config> Rpc<T> {
|
||||
pub async fn block_stats(
|
||||
&self,
|
||||
block_hash: T::Hash,
|
||||
) -> Result<Option<BlockStats>, Error> {
|
||||
) -> Result<Option<types::BlockStats>, Error> {
|
||||
let params = rpc_params![block_hash];
|
||||
let stats = self.client.request("dev_getBlockStats", params).await?;
|
||||
Ok(stats)
|
||||
@@ -548,7 +264,7 @@ impl<T: Config> Rpc<T> {
|
||||
&self,
|
||||
keys: impl IntoIterator<Item = &[u8]>,
|
||||
hash: Option<T::Hash>,
|
||||
) -> Result<ReadProof<T::Hash>, Error> {
|
||||
) -> Result<types::ReadProof<T::Hash>, Error> {
|
||||
let keys: Vec<String> = keys.into_iter().map(to_hex).collect();
|
||||
let params = rpc_params![keys, hash];
|
||||
let proof = self.client.request("state_getReadProof", params).await?;
|
||||
@@ -559,7 +275,7 @@ impl<T: Config> Rpc<T> {
|
||||
pub async fn runtime_version(
|
||||
&self,
|
||||
at: Option<T::Hash>,
|
||||
) -> Result<RuntimeVersion, Error> {
|
||||
) -> Result<types::RuntimeVersion, Error> {
|
||||
let params = rpc_params![at];
|
||||
let version = self
|
||||
.client
|
||||
@@ -629,7 +345,7 @@ impl<T: Config> Rpc<T> {
|
||||
/// Subscribe to runtime version updates that produce changes in the metadata.
|
||||
pub async fn subscribe_runtime_version(
|
||||
&self,
|
||||
) -> Result<Subscription<RuntimeVersion>, Error> {
|
||||
) -> Result<Subscription<types::RuntimeVersion>, Error> {
|
||||
let subscription = self
|
||||
.client
|
||||
.subscribe(
|
||||
@@ -646,7 +362,7 @@ impl<T: Config> Rpc<T> {
|
||||
&self,
|
||||
extrinsic: X,
|
||||
) -> Result<T::Hash, Error> {
|
||||
let bytes: Bytes = extrinsic.encode().into();
|
||||
let bytes: types::Bytes = extrinsic.encode().into();
|
||||
let params = rpc_params![bytes];
|
||||
let xt_hash = self
|
||||
.client
|
||||
@@ -659,8 +375,8 @@ impl<T: Config> Rpc<T> {
|
||||
pub async fn watch_extrinsic<X: Encode>(
|
||||
&self,
|
||||
extrinsic: X,
|
||||
) -> Result<Subscription<SubstrateTxStatus<T::Hash, T::Hash>>, Error> {
|
||||
let bytes: Bytes = extrinsic.encode().into();
|
||||
) -> Result<Subscription<types::SubstrateTxStatus<T::Hash, T::Hash>>, Error> {
|
||||
let bytes: types::Bytes = extrinsic.encode().into();
|
||||
let params = rpc_params![bytes];
|
||||
let subscription = self
|
||||
.client
|
||||
@@ -678,7 +394,7 @@ impl<T: Config> Rpc<T> {
|
||||
&self,
|
||||
key_type: String,
|
||||
suri: String,
|
||||
public: Bytes,
|
||||
public: types::Bytes,
|
||||
) -> Result<(), Error> {
|
||||
let params = rpc_params![key_type, suri, public];
|
||||
self.client.request("author_insertKey", params).await?;
|
||||
@@ -686,7 +402,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<types::Bytes, Error> {
|
||||
self.client
|
||||
.request("author_rotateKeys", rpc_params![])
|
||||
.await
|
||||
@@ -697,7 +413,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: types::Bytes,
|
||||
) -> Result<bool, Error> {
|
||||
let params = rpc_params![session_keys];
|
||||
self.client.request("author_hasSessionKeys", params).await
|
||||
}
|
||||
@@ -707,7 +426,7 @@ impl<T: Config> Rpc<T> {
|
||||
/// Returns `true` if a private key could be found.
|
||||
pub async fn has_key(
|
||||
&self,
|
||||
public_key: Bytes,
|
||||
public_key: types::Bytes,
|
||||
key_type: String,
|
||||
) -> Result<bool, Error> {
|
||||
let params = rpc_params![public_key, key_type];
|
||||
@@ -716,73 +435,19 @@ impl<T: Config> Rpc<T> {
|
||||
|
||||
/// Submits the extrinsic to the dry_run RPC, to test if it would succeed.
|
||||
///
|
||||
/// Returns `Ok` with an [`ApplyExtrinsicResult`], which is the result of applying of an extrinsic.
|
||||
/// Returns a [`types::DryRunResult`], which is the result of performing the dry run.
|
||||
pub async fn dry_run(
|
||||
&self,
|
||||
encoded_signed: &[u8],
|
||||
at: Option<T::Hash>,
|
||||
) -> Result<ApplyExtrinsicResult, Error> {
|
||||
) -> Result<types::DryRunResult, Error> {
|
||||
let params = rpc_params![to_hex(encoded_signed), at];
|
||||
let result_bytes: Bytes = self.client.request("system_dryRun", params).await?;
|
||||
let data: ApplyExtrinsicResult =
|
||||
codec::Decode::decode(&mut result_bytes.0.as_slice())?;
|
||||
Ok(data)
|
||||
let result_bytes: types::Bytes =
|
||||
self.client.request("system_dryRun", params).await?;
|
||||
Ok(types::decode_dry_run_result(&mut &*result_bytes.0)?)
|
||||
}
|
||||
}
|
||||
|
||||
fn to_hex(bytes: impl AsRef<[u8]>) -> String {
|
||||
format!("0x{}", hex::encode(bytes.as_ref()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
/// A util function to assert the result of serialization and deserialization is the same.
|
||||
pub(crate) fn assert_deser<T>(s: &str, expected: T)
|
||||
where
|
||||
T: std::fmt::Debug
|
||||
+ serde::ser::Serialize
|
||||
+ serde::de::DeserializeOwned
|
||||
+ PartialEq,
|
||||
{
|
||||
assert_eq!(serde_json::from_str::<T>(s).unwrap(), expected);
|
||||
assert_eq!(serde_json::to_string(&expected).unwrap(), s);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deser_runtime_version() {
|
||||
let val: RuntimeVersion = serde_json::from_str(
|
||||
r#"{
|
||||
"specVersion": 123,
|
||||
"transactionVersion": 456,
|
||||
"foo": true,
|
||||
"wibble": [1,2,3]
|
||||
}"#,
|
||||
)
|
||||
.expect("deserializing failed");
|
||||
|
||||
let mut m = std::collections::HashMap::new();
|
||||
m.insert("foo".to_owned(), serde_json::json!(true));
|
||||
m.insert("wibble".to_owned(), serde_json::json!([1, 2, 3]));
|
||||
|
||||
assert_eq!(
|
||||
val,
|
||||
RuntimeVersion {
|
||||
spec_version: 123,
|
||||
transaction_version: 456,
|
||||
other: m
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_serialize_and_deserialize() {
|
||||
assert_deser(r#""0x1234""#, NumberOrHex::Hex(0x1234.into()));
|
||||
assert_deser(r#""0x0""#, NumberOrHex::Hex(0.into()));
|
||||
assert_deser(r#"5"#, NumberOrHex::Number(5));
|
||||
assert_deser(r#"10000"#, NumberOrHex::Number(10000));
|
||||
assert_deser(r#"0"#, NumberOrHex::Number(0));
|
||||
assert_deser(r#"1000000000000"#, NumberOrHex::Number(1000000000000));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,558 @@
|
||||
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! Types sent to/from the Substrate RPC interface.
|
||||
|
||||
use crate::Config;
|
||||
use codec::{
|
||||
Decode,
|
||||
Encode,
|
||||
};
|
||||
use primitive_types::U256;
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
// Subscription types are returned from some calls, so expose it with the rest of the returned types.
|
||||
pub use super::rpc_client::Subscription;
|
||||
|
||||
/// Signal what the result of doing a dry run of an extrinsic is.
|
||||
pub type DryRunResult = Result<(), DryRunError>;
|
||||
|
||||
/// An error dry running an extrinsic.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum DryRunError {
|
||||
/// The extrinsic will not be included in the block
|
||||
TransactionValidityError,
|
||||
/// The extrinsic will be included in the block, but the call failed to dispatch.
|
||||
DispatchError,
|
||||
}
|
||||
|
||||
/// dryRun returns an ApplyExtrinsicResult, which is basically a
|
||||
/// `Result<Result<(), DispatchError>, TransactionValidityError>`. We want to convert this to
|
||||
/// a [`DryRunResult`].
|
||||
///
|
||||
/// - if `Ok(inner)`, the transaction will be included in the block
|
||||
/// - if `Ok(Ok(()))`, the transaction will be included and the call will be dispatched
|
||||
/// successfully
|
||||
/// - if `Ok(Err(e))`, the transaction will be included but there is some error dispatching
|
||||
/// the call to the module.
|
||||
///
|
||||
/// The errors get a bit involved and have been known to change over time. At the moment
|
||||
/// then, we will keep things simple here and just decode the Result portion (ie the initial bytes)
|
||||
/// and ignore the rest.
|
||||
pub(crate) fn decode_dry_run_result<I: codec::Input>(
|
||||
input: &mut I,
|
||||
) -> Result<DryRunResult, codec::Error> {
|
||||
let res = match <Result<Result<(), ()>, ()>>::decode(input)? {
|
||||
Ok(Ok(())) => Ok(()),
|
||||
Ok(Err(())) => Err(DryRunError::DispatchError),
|
||||
Err(()) => Err(DryRunError::TransactionValidityError),
|
||||
};
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// A number type that can be serialized both as a number or a string that encodes a number in a
|
||||
/// string.
|
||||
///
|
||||
/// We allow two representations of the block number as input. Either we deserialize to the type
|
||||
/// that is specified in the block type or we attempt to parse given hex value.
|
||||
///
|
||||
/// The primary motivation for having this type is to avoid overflows when using big integers in
|
||||
/// JavaScript (which we consider as an important RPC API consumer).
|
||||
#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
#[serde(untagged)]
|
||||
pub enum NumberOrHex {
|
||||
/// The number represented directly.
|
||||
Number(u64),
|
||||
/// Hex representation of the number.
|
||||
Hex(U256),
|
||||
}
|
||||
|
||||
/// Hex-serialized shim for `Vec<u8>`.
|
||||
#[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Hash, PartialOrd, Ord, Debug)]
|
||||
pub struct Bytes(#[serde(with = "impl_serde::serialize")] pub Vec<u8>);
|
||||
impl std::ops::Deref for Bytes {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
&self.0[..]
|
||||
}
|
||||
}
|
||||
impl From<Vec<u8>> for Bytes {
|
||||
fn from(s: Vec<u8>) -> Self {
|
||||
Bytes(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// The response from `chain_getBlock`
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(bound = "T: Config")]
|
||||
pub struct ChainBlockResponse<T: Config> {
|
||||
/// The block itself.
|
||||
pub block: ChainBlock<T>,
|
||||
/// Block justification.
|
||||
pub justifications: Option<Vec<Justification>>,
|
||||
}
|
||||
|
||||
/// Block details in the [`ChainBlockResponse`].
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ChainBlock<T: Config> {
|
||||
/// The block header.
|
||||
pub header: T::Header,
|
||||
/// The accompanying extrinsics.
|
||||
pub extrinsics: Vec<ChainBlockExtrinsic>,
|
||||
}
|
||||
|
||||
/// An abstraction over justification for a block's validity under a consensus algorithm.
|
||||
pub type Justification = (ConsensusEngineId, EncodedJustification);
|
||||
/// Consensus engine unique ID.
|
||||
pub type ConsensusEngineId = [u8; 4];
|
||||
/// The encoded justification specific to a consensus engine.
|
||||
pub type EncodedJustification = Vec<u8>;
|
||||
|
||||
/// Bytes representing an extrinsic in a [`ChainBlock`].
|
||||
#[derive(Debug)]
|
||||
pub struct ChainBlockExtrinsic(pub Vec<u8>);
|
||||
|
||||
impl<'a> ::serde::Deserialize<'a> for ChainBlockExtrinsic {
|
||||
fn deserialize<D>(de: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: ::serde::Deserializer<'a>,
|
||||
{
|
||||
let r = impl_serde::serialize::deserialize(de)?;
|
||||
let bytes = Decode::decode(&mut &r[..])
|
||||
.map_err(|e| ::serde::de::Error::custom(format!("Decode error: {}", e)))?;
|
||||
Ok(ChainBlockExtrinsic(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for NumberOrHex to allow custom From impls
|
||||
#[derive(Serialize)]
|
||||
pub struct BlockNumber(NumberOrHex);
|
||||
|
||||
impl From<NumberOrHex> for BlockNumber {
|
||||
fn from(x: NumberOrHex) -> Self {
|
||||
BlockNumber(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NumberOrHex {
|
||||
fn default() -> Self {
|
||||
Self::Number(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl NumberOrHex {
|
||||
/// Converts this number into an U256.
|
||||
pub fn into_u256(self) -> U256 {
|
||||
match self {
|
||||
NumberOrHex::Number(n) => n.into(),
|
||||
NumberOrHex::Hex(h) => h,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for NumberOrHex {
|
||||
fn from(n: u32) -> Self {
|
||||
NumberOrHex::Number(n.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for NumberOrHex {
|
||||
fn from(n: u64) -> Self {
|
||||
NumberOrHex::Number(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for NumberOrHex {
|
||||
fn from(n: u128) -> Self {
|
||||
NumberOrHex::Hex(n.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<U256> for NumberOrHex {
|
||||
fn from(n: U256) -> Self {
|
||||
NumberOrHex::Hex(n)
|
||||
}
|
||||
}
|
||||
|
||||
/// An error type that signals an out-of-range conversion attempt.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Out-of-range conversion attempt")]
|
||||
pub struct TryFromIntError;
|
||||
|
||||
impl TryFrom<NumberOrHex> for u32 {
|
||||
type Error = TryFromIntError;
|
||||
fn try_from(num_or_hex: NumberOrHex) -> Result<u32, Self::Error> {
|
||||
num_or_hex
|
||||
.into_u256()
|
||||
.try_into()
|
||||
.map_err(|_| TryFromIntError)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<NumberOrHex> for u64 {
|
||||
type Error = TryFromIntError;
|
||||
fn try_from(num_or_hex: NumberOrHex) -> Result<u64, Self::Error> {
|
||||
num_or_hex
|
||||
.into_u256()
|
||||
.try_into()
|
||||
.map_err(|_| TryFromIntError)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<NumberOrHex> for u128 {
|
||||
type Error = TryFromIntError;
|
||||
fn try_from(num_or_hex: NumberOrHex) -> Result<u128, Self::Error> {
|
||||
num_or_hex
|
||||
.into_u256()
|
||||
.try_into()
|
||||
.map_err(|_| TryFromIntError)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NumberOrHex> for U256 {
|
||||
fn from(num_or_hex: NumberOrHex) -> U256 {
|
||||
num_or_hex.into_u256()
|
||||
}
|
||||
}
|
||||
|
||||
// All unsigned ints can be converted into a BlockNumber:
|
||||
macro_rules! into_block_number {
|
||||
($($t: ty)+) => {
|
||||
$(
|
||||
impl From<$t> for BlockNumber {
|
||||
fn from(x: $t) -> Self {
|
||||
NumberOrHex::Number(x.into()).into()
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
into_block_number!(u8 u16 u32 u64);
|
||||
|
||||
/// Arbitrary properties defined in the chain spec as a JSON object.
|
||||
pub type SystemProperties = serde_json::Map<String, serde_json::Value>;
|
||||
|
||||
/// Possible transaction status events.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This is copied from `sp-transaction-pool` to avoid a dependency on that crate. Therefore it
|
||||
/// must be kept compatible with that type from the target substrate version.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum SubstrateTxStatus<Hash, BlockHash> {
|
||||
/// Transaction is part of the future queue.
|
||||
Future,
|
||||
/// Transaction is part of the ready queue.
|
||||
Ready,
|
||||
/// The transaction has been broadcast to the given peers.
|
||||
Broadcast(Vec<String>),
|
||||
/// Transaction has been included in block with given hash.
|
||||
InBlock(BlockHash),
|
||||
/// The block this transaction was included in has been retracted.
|
||||
Retracted(BlockHash),
|
||||
/// Maximum number of finality watchers has been reached,
|
||||
/// old watchers are being removed.
|
||||
FinalityTimeout(BlockHash),
|
||||
/// Transaction has been finalized by a finality-gadget, e.g GRANDPA
|
||||
Finalized(BlockHash),
|
||||
/// Transaction has been replaced in the pool, by another transaction
|
||||
/// that provides the same tags. (e.g. same (sender, nonce)).
|
||||
Usurped(Hash),
|
||||
/// Transaction has been dropped from the pool because of the limit.
|
||||
Dropped,
|
||||
/// Transaction is no longer valid in the current state.
|
||||
Invalid,
|
||||
}
|
||||
|
||||
/// This contains the runtime version information necessary to make transactions, as obtained from
|
||||
/// the RPC call `state_getRuntimeVersion`,
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RuntimeVersion {
|
||||
/// Version of the runtime specification. A full-node will not attempt to use its native
|
||||
/// runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`,
|
||||
/// `spec_version` and `authoring_version` are the same between Wasm and native.
|
||||
pub spec_version: u32,
|
||||
|
||||
/// All existing dispatches are fully compatible when this number doesn't change. If this
|
||||
/// number changes, then `spec_version` must change, also.
|
||||
///
|
||||
/// This number must change when an existing dispatchable (module ID, dispatch ID) is changed,
|
||||
/// either through an alteration in its user-level semantics, a parameter
|
||||
/// added/removed/changed, a dispatchable being removed, a module being removed, or a
|
||||
/// dispatchable/module changing its index.
|
||||
///
|
||||
/// It need *not* change when a new module is added or when a dispatchable is added.
|
||||
pub transaction_version: u32,
|
||||
|
||||
/// The other fields present may vary and aren't necessary for `subxt`; they are preserved in
|
||||
/// this map.
|
||||
#[serde(flatten)]
|
||||
pub other: HashMap<String, serde_json::Value>,
|
||||
}
|
||||
|
||||
/// ReadProof struct returned by the RPC
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This is copied from `sc-rpc-api` to avoid a dependency on that crate. Therefore it
|
||||
/// must be kept compatible with that type from the target substrate version.
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ReadProof<Hash> {
|
||||
/// Block hash used to generate the proof
|
||||
pub at: Hash,
|
||||
/// A proof used to prove that storage entries are included in the storage trie
|
||||
pub proof: Vec<Bytes>,
|
||||
}
|
||||
|
||||
/// Statistics of a block returned by the `dev_getBlockStats` RPC.
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BlockStats {
|
||||
/// The length in bytes of the storage proof produced by executing the block.
|
||||
pub witness_len: u64,
|
||||
/// The length in bytes of the storage proof after compaction.
|
||||
pub witness_compact_len: u64,
|
||||
/// Length of the block in bytes.
|
||||
///
|
||||
/// This information can also be acquired by downloading the whole block. This merely
|
||||
/// saves some complexity on the client side.
|
||||
pub block_len: u64,
|
||||
/// Number of extrinsics in the block.
|
||||
///
|
||||
/// This information can also be acquired by downloading the whole block. This merely
|
||||
/// saves some complexity on the client side.
|
||||
pub num_extrinsics: u64,
|
||||
}
|
||||
|
||||
/// Storage key.
|
||||
#[derive(
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Hash,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Clone,
|
||||
Encode,
|
||||
Decode,
|
||||
Debug,
|
||||
)]
|
||||
pub struct StorageKey(#[serde(with = "impl_serde::serialize")] pub Vec<u8>);
|
||||
impl AsRef<[u8]> for StorageKey {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Storage data.
|
||||
#[derive(
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Hash,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Clone,
|
||||
Encode,
|
||||
Decode,
|
||||
Debug,
|
||||
)]
|
||||
pub struct StorageData(#[serde(with = "impl_serde::serialize")] pub Vec<u8>);
|
||||
impl AsRef<[u8]> for StorageData {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Storage change set
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StorageChangeSet<Hash> {
|
||||
/// Block hash
|
||||
pub block: Hash,
|
||||
/// A list of changes
|
||||
pub changes: Vec<(StorageKey, Option<StorageData>)>,
|
||||
}
|
||||
|
||||
/// Health struct returned by the RPC
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Health {
|
||||
/// Number of connected peers
|
||||
pub peers: usize,
|
||||
/// Is the node syncing
|
||||
pub is_syncing: bool,
|
||||
/// Should this node have any peers
|
||||
///
|
||||
/// Might be false for local chains or when running without discovery.
|
||||
pub should_have_peers: bool,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
/// A util function to assert the result of serialization and deserialization is the same.
|
||||
pub fn assert_deser<T>(s: &str, expected: T)
|
||||
where
|
||||
T: std::fmt::Debug
|
||||
+ serde::ser::Serialize
|
||||
+ serde::de::DeserializeOwned
|
||||
+ PartialEq,
|
||||
{
|
||||
assert_eq!(serde_json::from_str::<T>(s).unwrap(), expected);
|
||||
assert_eq!(serde_json::to_string(&expected).unwrap(), s);
|
||||
}
|
||||
|
||||
// Check that some A can be serialized and then deserialized into some B.
|
||||
pub fn assert_ser_deser<A, B>(a: &A, b: &B)
|
||||
where
|
||||
A: serde::Serialize,
|
||||
B: serde::de::DeserializeOwned + PartialEq + std::fmt::Debug,
|
||||
{
|
||||
let json = serde_json::to_string(a).expect("serializing failed");
|
||||
let new_b: B = serde_json::from_str(&json).expect("deserializing failed");
|
||||
|
||||
assert_eq!(b, &new_b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_version_is_substrate_compatible() {
|
||||
use sp_version::RuntimeVersion as SpRuntimeVersion;
|
||||
|
||||
let substrate_runtime_version = SpRuntimeVersion {
|
||||
spec_version: 123,
|
||||
transaction_version: 456,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&substrate_runtime_version)
|
||||
.expect("serializing failed");
|
||||
let val: RuntimeVersion =
|
||||
serde_json::from_str(&json).expect("deserializing failed");
|
||||
|
||||
// We ignore any other properties.
|
||||
assert_eq!(val.spec_version, 123);
|
||||
assert_eq!(val.transaction_version, 456);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_version_handles_arbitrary_params() {
|
||||
let val: RuntimeVersion = serde_json::from_str(
|
||||
r#"{
|
||||
"specVersion": 123,
|
||||
"transactionVersion": 456,
|
||||
"foo": true,
|
||||
"wibble": [1,2,3]
|
||||
}"#,
|
||||
)
|
||||
.expect("deserializing failed");
|
||||
|
||||
let mut m = std::collections::HashMap::new();
|
||||
m.insert("foo".to_owned(), serde_json::json!(true));
|
||||
m.insert("wibble".to_owned(), serde_json::json!([1, 2, 3]));
|
||||
|
||||
assert_eq!(
|
||||
val,
|
||||
RuntimeVersion {
|
||||
spec_version: 123,
|
||||
transaction_version: 456,
|
||||
other: m
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn number_or_hex_deserializes_from_either_repr() {
|
||||
assert_deser(r#""0x1234""#, NumberOrHex::Hex(0x1234.into()));
|
||||
assert_deser(r#""0x0""#, NumberOrHex::Hex(0.into()));
|
||||
assert_deser(r#"5"#, NumberOrHex::Number(5));
|
||||
assert_deser(r#"10000"#, NumberOrHex::Number(10000));
|
||||
assert_deser(r#"0"#, NumberOrHex::Number(0));
|
||||
assert_deser(r#"1000000000000"#, NumberOrHex::Number(1000000000000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dry_run_result_is_substrate_compatible() {
|
||||
use sp_runtime::{
|
||||
transaction_validity::{
|
||||
InvalidTransaction as SpInvalidTransaction,
|
||||
TransactionValidityError as SpTransactionValidityError,
|
||||
},
|
||||
ApplyExtrinsicResult as SpApplyExtrinsicResult,
|
||||
DispatchError as SpDispatchError,
|
||||
};
|
||||
|
||||
let pairs = vec![
|
||||
// All ok
|
||||
(SpApplyExtrinsicResult::Ok(Ok(())), Ok(())),
|
||||
// Some transaction error
|
||||
(
|
||||
SpApplyExtrinsicResult::Err(SpTransactionValidityError::Invalid(
|
||||
SpInvalidTransaction::BadProof,
|
||||
)),
|
||||
Err(DryRunError::TransactionValidityError),
|
||||
),
|
||||
// Some dispatch error
|
||||
(
|
||||
SpApplyExtrinsicResult::Ok(Err(SpDispatchError::BadOrigin)),
|
||||
Err(DryRunError::DispatchError),
|
||||
),
|
||||
];
|
||||
|
||||
for (actual, expected) in pairs {
|
||||
let encoded = actual.encode();
|
||||
assert_eq!(decode_dry_run_result(&mut &*encoded).unwrap(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn justification_is_substrate_compatible() {
|
||||
use sp_runtime::Justification as SpJustification;
|
||||
|
||||
// As much as anything, this just checks that the Justification type
|
||||
// is still a tuple as given.
|
||||
assert_ser_deser::<SpJustification, Justification>(
|
||||
&([1, 2, 3, 4], vec![5, 6, 7, 8]),
|
||||
&([1, 2, 3, 4], vec![5, 6, 7, 8]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn storage_types_are_substrate_compatible() {
|
||||
use sp_core::storage::{
|
||||
StorageChangeSet as SpStorageChangeSet,
|
||||
StorageData as SpStorageData,
|
||||
StorageKey as SpStorageKey,
|
||||
};
|
||||
|
||||
assert_ser_deser(
|
||||
&SpStorageKey(vec![1, 2, 3, 4, 5]),
|
||||
&StorageKey(vec![1, 2, 3, 4, 5]),
|
||||
);
|
||||
assert_ser_deser(
|
||||
&SpStorageData(vec![1, 2, 3, 4, 5]),
|
||||
&StorageData(vec![1, 2, 3, 4, 5]),
|
||||
);
|
||||
assert_ser_deser(
|
||||
&SpStorageChangeSet {
|
||||
block: 1u64,
|
||||
changes: vec![(SpStorageKey(vec![1]), Some(SpStorageData(vec![2])))],
|
||||
},
|
||||
&StorageChangeSet {
|
||||
block: 1u64,
|
||||
changes: vec![(StorageKey(vec![1]), Some(StorageData(vec![2])))],
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@ pub use storage_client::{
|
||||
StorageClient,
|
||||
};
|
||||
|
||||
// Re-export as this is used in the public API:
|
||||
pub use sp_core::storage::StorageKey;
|
||||
// Re-export as this is used in the public API in this module:
|
||||
pub use crate::rpc::types::StorageKey;
|
||||
|
||||
/// Types representing an address which describes where a storage
|
||||
/// entry lives and how to properly decode it.
|
||||
|
||||
@@ -16,15 +16,15 @@ use crate::{
|
||||
DecodeWithMetadata,
|
||||
Metadata,
|
||||
},
|
||||
rpc::types::{
|
||||
StorageData,
|
||||
StorageKey,
|
||||
},
|
||||
Config,
|
||||
};
|
||||
use derivative::Derivative;
|
||||
use frame_metadata::StorageEntryType;
|
||||
use scale_info::form::PortableForm;
|
||||
use sp_core::storage::{
|
||||
StorageData,
|
||||
StorageKey,
|
||||
};
|
||||
use std::{
|
||||
future::Future,
|
||||
marker::PhantomData,
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// see LICENSE for license details.
|
||||
|
||||
use codec::Encode;
|
||||
pub use sp_runtime::traits::SignedExtension;
|
||||
|
||||
// We use this type a bunch, so export it from here.
|
||||
pub use frame_metadata::StorageHasher;
|
||||
@@ -37,16 +36,16 @@ impl StorageMapKey {
|
||||
pub(super) fn hash_bytes(input: &[u8], hasher: &StorageHasher, bytes: &mut Vec<u8>) {
|
||||
match hasher {
|
||||
StorageHasher::Identity => bytes.extend(input),
|
||||
StorageHasher::Blake2_128 => bytes.extend(sp_core::blake2_128(input)),
|
||||
StorageHasher::Blake2_128 => bytes.extend(sp_core_hashing::blake2_128(input)),
|
||||
StorageHasher::Blake2_128Concat => {
|
||||
bytes.extend(sp_core::blake2_128(input));
|
||||
bytes.extend(sp_core_hashing::blake2_128(input));
|
||||
bytes.extend(input);
|
||||
}
|
||||
StorageHasher::Blake2_256 => bytes.extend(sp_core::blake2_256(input)),
|
||||
StorageHasher::Twox128 => bytes.extend(sp_core::twox_128(input)),
|
||||
StorageHasher::Twox256 => bytes.extend(sp_core::twox_256(input)),
|
||||
StorageHasher::Blake2_256 => bytes.extend(sp_core_hashing::blake2_256(input)),
|
||||
StorageHasher::Twox128 => bytes.extend(sp_core_hashing::twox_128(input)),
|
||||
StorageHasher::Twox256 => bytes.extend(sp_core_hashing::twox_256(input)),
|
||||
StorageHasher::Twox64Concat => {
|
||||
bytes.extend(sp_core::twox_64(input));
|
||||
bytes.extend(sp_core_hashing::twox_64(input));
|
||||
bytes.extend(input);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ pub fn write_storage_address_root_bytes<Address: StorageAddress>(
|
||||
addr: &Address,
|
||||
out: &mut Vec<u8>,
|
||||
) {
|
||||
out.extend(sp_core::twox_128(addr.pallet_name().as_bytes()));
|
||||
out.extend(sp_core::twox_128(addr.entry_name().as_bytes()));
|
||||
out.extend(sp_core_hashing::twox_128(addr.pallet_name().as_bytes()));
|
||||
out.extend(sp_core_hashing::twox_128(addr.entry_name().as_bytes()));
|
||||
}
|
||||
|
||||
/// Outputs the [`storage_address_root_bytes`] as well as any additional bytes that represent
|
||||
|
||||
+10
-30
@@ -2,45 +2,25 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! Create signed or unsigned extrinsics.
|
||||
//!
|
||||
//! This modules exposes the extrinsic's parameters and the ability to sign an extrinsic.
|
||||
//!
|
||||
//! Create and submit extrinsics.
|
||||
//!
|
||||
//! An extrinsic is submitted with an "signed extra" and "additional" parameters, which can be
|
||||
//! different for each chain. The trait [ExtrinsicParams] determines exactly which
|
||||
//! additional and signed extra parameters are used when constructing an extrinsic.
|
||||
//!
|
||||
//!
|
||||
//! The structure [BaseExtrinsicParams] is a base implementation of the trait which
|
||||
//! configures most of the "signed extra" and "additional" parameters as needed for
|
||||
//! Polkadot and Substrate nodes. Only the shape of the tip payments differs, leading to
|
||||
//! [SubstrateExtrinsicParams] and [PolkadotExtrinsicParams] structs which pick an
|
||||
//! appropriate shape for Substrate/Polkadot chains respectively.
|
||||
//! different for each chain. The trait [`crate::config::ExtrinsicParams`] determines exactly which
|
||||
//! additional and signed extra parameters are used when constructing an extrinsic, and is a part
|
||||
//! of the chain configuration (see [`crate::config::Config`]).
|
||||
|
||||
mod params;
|
||||
mod signer;
|
||||
mod tx_client;
|
||||
mod tx_payload;
|
||||
mod tx_progress;
|
||||
|
||||
// The PairSigner impl currently relies on Substrate bits and pieces, so make it an optional
|
||||
// feature if we want to avoid needing sp_core and sp_runtime.
|
||||
#[cfg(feature = "substrate-compat")]
|
||||
pub use self::signer::PairSigner;
|
||||
|
||||
pub use self::{
|
||||
params::{
|
||||
AssetTip,
|
||||
BaseExtrinsicParams,
|
||||
BaseExtrinsicParamsBuilder,
|
||||
Era,
|
||||
ExtrinsicParams,
|
||||
PlainTip,
|
||||
PolkadotExtrinsicParams,
|
||||
PolkadotExtrinsicParamsBuilder,
|
||||
SubstrateExtrinsicParams,
|
||||
SubstrateExtrinsicParamsBuilder,
|
||||
},
|
||||
signer::{
|
||||
PairSigner,
|
||||
Signer,
|
||||
},
|
||||
signer::Signer,
|
||||
tx_client::{
|
||||
SubmittableExtrinsic,
|
||||
TxClient,
|
||||
|
||||
+69
-50
@@ -6,11 +6,6 @@
|
||||
//! [substrate](https://github.com/paritytech/substrate) node via RPC.
|
||||
|
||||
use crate::Config;
|
||||
use sp_core::Pair;
|
||||
use sp_runtime::traits::{
|
||||
IdentifyAccount,
|
||||
Verify,
|
||||
};
|
||||
|
||||
/// Signing transactions requires a [`Signer`]. This is responsible for
|
||||
/// providing the "from" account that the transaction is being signed by,
|
||||
@@ -29,55 +24,79 @@ pub trait Signer<T: Config> {
|
||||
fn sign(&self, signer_payload: &[u8]) -> T::Signature;
|
||||
}
|
||||
|
||||
/// A [`Signer`] implementation that can be constructed from an [`Pair`].
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PairSigner<T: Config, P: Pair> {
|
||||
account_id: T::AccountId,
|
||||
signer: P,
|
||||
}
|
||||
#[cfg(feature = "substrate-compat")]
|
||||
pub use pair_signer::PairSigner;
|
||||
|
||||
impl<T, P> PairSigner<T, P>
|
||||
where
|
||||
T: Config,
|
||||
T::Signature: From<P::Signature>,
|
||||
<T::Signature as Verify>::Signer:
|
||||
From<P::Public> + IdentifyAccount<AccountId = T::AccountId>,
|
||||
P: Pair,
|
||||
{
|
||||
/// Creates a new [`Signer`] from a [`Pair`].
|
||||
pub fn new(signer: P) -> Self {
|
||||
let account_id =
|
||||
<T::Signature as Verify>::Signer::from(signer.public()).into_account();
|
||||
Self { account_id, signer }
|
||||
// A signer suitable for substrate based chains. This provides compatibility with Substrate
|
||||
// packages like sp_keyring and such, and so relies on sp_core and sp_runtime to be included.
|
||||
#[cfg(feature = "substrate-compat")]
|
||||
mod pair_signer {
|
||||
use super::Signer;
|
||||
use crate::Config;
|
||||
use sp_core::Pair as PairT;
|
||||
use sp_runtime::{
|
||||
traits::{
|
||||
IdentifyAccount,
|
||||
Verify,
|
||||
},
|
||||
AccountId32 as SpAccountId32,
|
||||
MultiSignature as SpMultiSignature,
|
||||
};
|
||||
|
||||
/// A [`Signer`] implementation that can be constructed from an [`sp_core::Pair`].
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PairSigner<T: Config, Pair> {
|
||||
account_id: T::AccountId,
|
||||
signer: Pair,
|
||||
}
|
||||
|
||||
/// Returns the [`Pair`] implementation used to construct this.
|
||||
pub fn signer(&self) -> &P {
|
||||
&self.signer
|
||||
impl<T, Pair> PairSigner<T, Pair>
|
||||
where
|
||||
T: Config,
|
||||
Pair: PairT,
|
||||
// We go via an sp_runtime::MultiSignature. We can probably generalise this
|
||||
// by implementing some of these traits on our built-in MultiSignature and then
|
||||
// requiring them on all T::Signatures, to avoid any go-between.
|
||||
<SpMultiSignature as Verify>::Signer: From<Pair::Public>,
|
||||
T::AccountId: From<SpAccountId32>,
|
||||
{
|
||||
/// Creates a new [`Signer`] from an [`sp_core::Pair`].
|
||||
pub fn new(signer: Pair) -> Self {
|
||||
let account_id = <SpMultiSignature as Verify>::Signer::from(signer.public())
|
||||
.into_account();
|
||||
Self {
|
||||
account_id: account_id.into(),
|
||||
signer,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the [`sp_core::Pair`] implementation used to construct this.
|
||||
pub fn signer(&self) -> &Pair {
|
||||
&self.signer
|
||||
}
|
||||
|
||||
/// Return the account ID.
|
||||
pub fn account_id(&self) -> &T::AccountId {
|
||||
&self.account_id
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the account ID.
|
||||
pub fn account_id(&self) -> &T::AccountId {
|
||||
&self.account_id
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, P> Signer<T> for PairSigner<T, P>
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: Into<T::Address> + Clone + 'static,
|
||||
P: Pair + 'static,
|
||||
P::Signature: Into<T::Signature> + 'static,
|
||||
{
|
||||
fn account_id(&self) -> &T::AccountId {
|
||||
&self.account_id
|
||||
}
|
||||
|
||||
fn address(&self) -> T::Address {
|
||||
self.account_id.clone().into()
|
||||
}
|
||||
|
||||
fn sign(&self, signer_payload: &[u8]) -> T::Signature {
|
||||
self.signer.sign(signer_payload).into()
|
||||
impl<T, Pair> Signer<T> for PairSigner<T, Pair>
|
||||
where
|
||||
T: Config,
|
||||
Pair: PairT,
|
||||
Pair::Signature: Into<T::Signature>,
|
||||
{
|
||||
fn account_id(&self) -> &T::AccountId {
|
||||
&self.account_id
|
||||
}
|
||||
|
||||
fn address(&self) -> T::Address {
|
||||
self.account_id.clone().into()
|
||||
}
|
||||
|
||||
fn sign(&self, signer_payload: &[u8]) -> T::Signature {
|
||||
self.signer.sign(signer_payload).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-26
@@ -8,27 +8,29 @@ use crate::{
|
||||
OfflineClientT,
|
||||
OnlineClientT,
|
||||
},
|
||||
config::{
|
||||
Config,
|
||||
ExtrinsicParams,
|
||||
Hasher,
|
||||
},
|
||||
error::Error,
|
||||
tx::{
|
||||
ExtrinsicParams,
|
||||
Signer,
|
||||
Signer as SignerT,
|
||||
TxProgress,
|
||||
},
|
||||
utils::{
|
||||
Encoded,
|
||||
PhantomDataSendSync,
|
||||
},
|
||||
Config,
|
||||
};
|
||||
use codec::{
|
||||
Compact,
|
||||
Encode,
|
||||
};
|
||||
use derivative::Derivative;
|
||||
use sp_runtime::{
|
||||
traits::Hash,
|
||||
ApplyExtrinsicResult,
|
||||
};
|
||||
|
||||
// This is returned from an API below, so expose it here.
|
||||
pub use crate::rpc::types::DryRunResult;
|
||||
|
||||
/// A client for working with transactions.
|
||||
#[derive(Derivative)]
|
||||
@@ -121,15 +123,16 @@ impl<T: Config, C: OfflineClientT<T>> TxClient<T, C> {
|
||||
}
|
||||
|
||||
/// Creates a raw signed extrinsic without submitting it.
|
||||
pub fn create_signed_with_nonce<Call>(
|
||||
pub fn create_signed_with_nonce<Call, Signer>(
|
||||
&self,
|
||||
call: &Call,
|
||||
signer: &(dyn Signer<T> + Send + Sync),
|
||||
signer: &Signer,
|
||||
account_nonce: T::Index,
|
||||
other_params: <T::ExtrinsicParams as ExtrinsicParams<T::Index, T::Hash>>::OtherParams,
|
||||
) -> Result<SubmittableExtrinsic<T, C>, Error>
|
||||
where
|
||||
Call: TxPayload,
|
||||
Signer: SignerT<T>,
|
||||
{
|
||||
// 1. Validate this call against the current node metadata if the call comes
|
||||
// with a hash allowing us to do so.
|
||||
@@ -166,7 +169,7 @@ impl<T: Config, C: OfflineClientT<T>> TxClient<T, C> {
|
||||
additional_and_extra_params.encode_extra_to(&mut bytes);
|
||||
additional_and_extra_params.encode_additional_to(&mut bytes);
|
||||
if bytes.len() > 256 {
|
||||
signer.sign(&sp_core::blake2_256(&bytes))
|
||||
signer.sign(T::Hasher::hash_of(&bytes).as_ref())
|
||||
} else {
|
||||
signer.sign(&bytes)
|
||||
}
|
||||
@@ -214,14 +217,15 @@ where
|
||||
C: OnlineClientT<T>,
|
||||
{
|
||||
/// Creates a raw signed extrinsic, without submitting it.
|
||||
pub async fn create_signed<Call>(
|
||||
pub async fn create_signed<Call, Signer>(
|
||||
&self,
|
||||
call: &Call,
|
||||
signer: &(dyn Signer<T> + Send + Sync),
|
||||
signer: &Signer,
|
||||
other_params: <T::ExtrinsicParams as ExtrinsicParams<T::Index, T::Hash>>::OtherParams,
|
||||
) -> Result<SubmittableExtrinsic<T, C>, Error>
|
||||
where
|
||||
Call: TxPayload,
|
||||
Signer: SignerT<T>,
|
||||
{
|
||||
// Get nonce from the node.
|
||||
let account_nonce = self
|
||||
@@ -238,13 +242,14 @@ where
|
||||
///
|
||||
/// Returns a [`TxProgress`], which can be used to track the status of the transaction
|
||||
/// and obtain details about it, once it has made it into a block.
|
||||
pub async fn sign_and_submit_then_watch_default<Call>(
|
||||
pub async fn sign_and_submit_then_watch_default<Call, Signer>(
|
||||
&self,
|
||||
call: &Call,
|
||||
signer: &(dyn Signer<T> + Send + Sync),
|
||||
signer: &Signer,
|
||||
) -> Result<TxProgress<T, C>, Error>
|
||||
where
|
||||
Call: TxPayload,
|
||||
Signer: SignerT<T>,
|
||||
<T::ExtrinsicParams as ExtrinsicParams<T::Index, T::Hash>>::OtherParams: Default,
|
||||
{
|
||||
self.sign_and_submit_then_watch(call, signer, Default::default())
|
||||
@@ -255,14 +260,15 @@ where
|
||||
///
|
||||
/// Returns a [`TxProgress`], which can be used to track the status of the transaction
|
||||
/// and obtain details about it, once it has made it into a block.
|
||||
pub async fn sign_and_submit_then_watch<Call>(
|
||||
pub async fn sign_and_submit_then_watch<Call, Signer>(
|
||||
&self,
|
||||
call: &Call,
|
||||
signer: &(dyn Signer<T> + Send + Sync),
|
||||
signer: &Signer,
|
||||
other_params: <T::ExtrinsicParams as ExtrinsicParams<T::Index, T::Hash>>::OtherParams,
|
||||
) -> Result<TxProgress<T, C>, Error>
|
||||
where
|
||||
Call: TxPayload,
|
||||
Signer: SignerT<T>,
|
||||
{
|
||||
self.create_signed(call, signer, other_params)
|
||||
.await?
|
||||
@@ -280,13 +286,14 @@ where
|
||||
///
|
||||
/// Success does not mean the extrinsic has been included in the block, just that it is valid
|
||||
/// and has been included in the transaction pool.
|
||||
pub async fn sign_and_submit_default<Call>(
|
||||
pub async fn sign_and_submit_default<Call, Signer>(
|
||||
&self,
|
||||
call: &Call,
|
||||
signer: &(dyn Signer<T> + Send + Sync),
|
||||
signer: &Signer,
|
||||
) -> Result<T::Hash, Error>
|
||||
where
|
||||
Call: TxPayload,
|
||||
Signer: SignerT<T>,
|
||||
<T::ExtrinsicParams as ExtrinsicParams<T::Index, T::Hash>>::OtherParams: Default,
|
||||
{
|
||||
self.sign_and_submit(call, signer, Default::default()).await
|
||||
@@ -300,14 +307,15 @@ where
|
||||
///
|
||||
/// Success does not mean the extrinsic has been included in the block, just that it is valid
|
||||
/// and has been included in the transaction pool.
|
||||
pub async fn sign_and_submit<Call>(
|
||||
pub async fn sign_and_submit<Call, Signer>(
|
||||
&self,
|
||||
call: &Call,
|
||||
signer: &(dyn Signer<T> + Send + Sync),
|
||||
signer: &Signer,
|
||||
other_params: <T::ExtrinsicParams as ExtrinsicParams<T::Index, T::Hash>>::OtherParams,
|
||||
) -> Result<T::Hash, Error>
|
||||
where
|
||||
Call: TxPayload,
|
||||
Signer: SignerT<T>,
|
||||
{
|
||||
self.create_signed(call, signer, other_params)
|
||||
.await?
|
||||
@@ -366,7 +374,7 @@ where
|
||||
/// and obtain details about it, once it has made it into a block.
|
||||
pub async fn submit_and_watch(&self) -> Result<TxProgress<T, C>, Error> {
|
||||
// Get a hash of the extrinsic (we'll need this later).
|
||||
let ext_hash = T::Hashing::hash_of(&self.encoded);
|
||||
let ext_hash = T::Hasher::hash_of(&self.encoded);
|
||||
|
||||
// Submit and watch for transaction progress.
|
||||
let sub = self.client.rpc().watch_extrinsic(&self.encoded).await?;
|
||||
@@ -388,11 +396,8 @@ where
|
||||
|
||||
/// Submits the extrinsic to the dry_run RPC, to test if it would succeed.
|
||||
///
|
||||
/// Returns `Ok` with an [`ApplyExtrinsicResult`], which is the result of applying of an extrinsic.
|
||||
pub async fn dry_run(
|
||||
&self,
|
||||
at: Option<T::Hash>,
|
||||
) -> Result<ApplyExtrinsicResult, Error> {
|
||||
/// Returns `Ok` with a [`DryRunResult`], which is the result of attempting to dry run the extrinsic.
|
||||
pub async fn dry_run(&self, at: Option<T::Hash>) -> Result<DryRunResult, Error> {
|
||||
self.client.rpc().dry_run(self.encoded(), at).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use crate::{
|
||||
TransactionError,
|
||||
},
|
||||
events::EventsClient,
|
||||
rpc::{
|
||||
rpc::types::{
|
||||
Subscription,
|
||||
SubstrateTxStatus,
|
||||
},
|
||||
@@ -26,9 +26,6 @@ use futures::{
|
||||
Stream,
|
||||
StreamExt,
|
||||
};
|
||||
use sp_runtime::traits::Hash;
|
||||
|
||||
pub use sp_runtime::traits::SignedExtension;
|
||||
|
||||
/// This struct represents a subscription to the progress of some transaction.
|
||||
#[derive(Derivative)]
|
||||
@@ -373,7 +370,8 @@ impl<T: Config, C: OnlineClientT<T>> TxInBlock<T, C> {
|
||||
let extrinsic_idx = block.block.extrinsics
|
||||
.iter()
|
||||
.position(|ext| {
|
||||
let hash = T::Hashing::hash_of(&ext.0);
|
||||
use crate::config::Hasher;
|
||||
let hash = T::Hasher::hash_of(&ext.0);
|
||||
hash == self.ext_hash
|
||||
})
|
||||
// If we successfully obtain the block hash we think contains our
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! The "default" Substrate/Polkadot AccountId. This is used in codegen, as well as signing related bits.
|
||||
//! This doesn't contain much functionality itself, but is easy to convert to/from an `sp_core::AccountId32`
|
||||
//! for instance, to gain functionality without forcing a dependency on Substrate crates here.
|
||||
|
||||
use codec::{
|
||||
Decode,
|
||||
Encode,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
/// A 32-byte cryptographic identifier. This is a simplified version of Substrate's
|
||||
/// `sp_core::crypto::AccountId32`. To obtain more functionality, convert this into
|
||||
/// that type.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)]
|
||||
pub struct AccountId32(pub [u8; 32]);
|
||||
|
||||
impl AsRef<[u8]> for AccountId32 {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 32]> for AccountId32 {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 32]> for AccountId32 {
|
||||
fn from(x: [u8; 32]) -> Self {
|
||||
AccountId32(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl AccountId32 {
|
||||
// Return the ss58-check string for this key. Adapted from `sp_core::crypto`. We need this to
|
||||
// serialize our account appropriately but otherwise don't care.
|
||||
fn to_ss58check(&self) -> String {
|
||||
// For serializing to a string to obtain the account nonce, we use the default substrate
|
||||
// prefix (since we have no way to otherwise pick one). It doesn't really matter, since when
|
||||
// it's deserialized back in system_accountNextIndex, we ignore this (so long as it's valid).
|
||||
const SUBSTRATE_SS58_PREFIX: u8 = 42;
|
||||
// prefix <= 63 just take up one byte at the start:
|
||||
let mut v = vec![SUBSTRATE_SS58_PREFIX];
|
||||
// then push the account ID bytes.
|
||||
v.extend(self.0);
|
||||
// then push a 2 byte checksum of what we have so far.
|
||||
let r = ss58hash(&v);
|
||||
v.extend(&r[0..2]);
|
||||
// then encode to base58.
|
||||
use base58::ToBase58;
|
||||
v.to_base58()
|
||||
}
|
||||
|
||||
// This isn't strictly needed, but to give our AccountId32 a little more usefulness, we also
|
||||
// implement the logic needed to decode an AccountId32 from an SS58 encoded string. This is exposed
|
||||
// via a `FromStr` impl.
|
||||
fn from_ss58check(s: &str) -> Result<Self, FromSs58Error> {
|
||||
const CHECKSUM_LEN: usize = 2;
|
||||
let body_len = 32;
|
||||
|
||||
use base58::FromBase58;
|
||||
let data = s.from_base58().map_err(|_| FromSs58Error::BadBase58)?;
|
||||
if data.len() < 2 {
|
||||
return Err(FromSs58Error::BadLength)
|
||||
}
|
||||
let prefix_len = match data[0] {
|
||||
0..=63 => 1,
|
||||
64..=127 => 2,
|
||||
_ => return Err(FromSs58Error::InvalidPrefix),
|
||||
};
|
||||
if data.len() != prefix_len + body_len + CHECKSUM_LEN {
|
||||
return Err(FromSs58Error::BadLength)
|
||||
}
|
||||
let hash = ss58hash(&data[0..body_len + prefix_len]);
|
||||
let checksum = &hash[0..CHECKSUM_LEN];
|
||||
if data[body_len + prefix_len..body_len + prefix_len + CHECKSUM_LEN] != *checksum
|
||||
{
|
||||
// Invalid checksum.
|
||||
return Err(FromSs58Error::InvalidChecksum)
|
||||
}
|
||||
|
||||
let result = data[prefix_len..body_len + prefix_len]
|
||||
.try_into()
|
||||
.map_err(|_| FromSs58Error::BadLength)?;
|
||||
Ok(AccountId32(result))
|
||||
}
|
||||
}
|
||||
|
||||
/// An error obtained from trying to interpret an SS58 encoded string into an AccountId32
|
||||
#[derive(thiserror::Error, Clone, Copy, Eq, PartialEq, Debug)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum FromSs58Error {
|
||||
#[error("Base 58 requirement is violated")]
|
||||
BadBase58,
|
||||
#[error("Length is bad")]
|
||||
BadLength,
|
||||
#[error("Invalid checksum")]
|
||||
InvalidChecksum,
|
||||
#[error("Invalid SS58 prefix byte.")]
|
||||
InvalidPrefix,
|
||||
}
|
||||
|
||||
// We do this just to get a checksum to help verify the validity of the address in to_ss58check
|
||||
fn ss58hash(data: &[u8]) -> Vec<u8> {
|
||||
use blake2::{
|
||||
Blake2b512,
|
||||
Digest,
|
||||
};
|
||||
const PREFIX: &[u8] = b"SS58PRE";
|
||||
let mut ctx = Blake2b512::new();
|
||||
ctx.update(PREFIX);
|
||||
ctx.update(data);
|
||||
ctx.finalize().to_vec()
|
||||
}
|
||||
|
||||
impl Serialize for AccountId32 {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.to_ss58check())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AccountId32 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_ss58check())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for AccountId32 {
|
||||
type Err = FromSs58Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
AccountId32::from_ss58check(s)
|
||||
}
|
||||
}
|
||||
|
||||
// Improve compat with the substrate version if we're using those crates:
|
||||
#[cfg(feature = "substrate-compat")]
|
||||
mod substrate_impls {
|
||||
use super::*;
|
||||
|
||||
impl From<sp_runtime::AccountId32> for AccountId32 {
|
||||
fn from(value: sp_runtime::AccountId32) -> Self {
|
||||
Self(value.into())
|
||||
}
|
||||
}
|
||||
impl From<sp_core::sr25519::Public> for AccountId32 {
|
||||
fn from(value: sp_core::sr25519::Public) -> Self {
|
||||
let acc: sp_runtime::AccountId32 = value.into();
|
||||
acc.into()
|
||||
}
|
||||
}
|
||||
impl From<sp_core::ed25519::Public> for AccountId32 {
|
||||
fn from(value: sp_core::ed25519::Public) -> Self {
|
||||
let acc: sp_runtime::AccountId32 = value.into();
|
||||
acc.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
use sp_core::crypto::Ss58Codec;
|
||||
use sp_keyring::AccountKeyring;
|
||||
|
||||
#[test]
|
||||
fn ss58_is_compatible_with_substrate_impl() {
|
||||
let keyrings = vec![
|
||||
AccountKeyring::Alice,
|
||||
AccountKeyring::Bob,
|
||||
AccountKeyring::Charlie,
|
||||
];
|
||||
|
||||
for keyring in keyrings {
|
||||
let substrate_account = keyring.to_account_id();
|
||||
// Avoid "From" impl hidden behind "substrate-compat" feature so that this test
|
||||
// can work either way:
|
||||
let local_account = AccountId32(substrate_account.clone().into());
|
||||
|
||||
// Both should encode to ss58 the same way:
|
||||
let substrate_ss58 = substrate_account.to_ss58check();
|
||||
assert_eq!(substrate_ss58, local_account.to_ss58check());
|
||||
|
||||
// Both should decode from ss58 back to the same:
|
||||
assert_eq!(
|
||||
sp_core::crypto::AccountId32::from_ss58check(&substrate_ss58).unwrap(),
|
||||
substrate_account
|
||||
);
|
||||
assert_eq!(
|
||||
AccountId32::from_ss58check(&substrate_ss58).unwrap(),
|
||||
local_account
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,10 @@
|
||||
|
||||
//! Miscellaneous utility helpers.
|
||||
|
||||
pub mod account_id;
|
||||
pub mod bits;
|
||||
pub mod multi_address;
|
||||
pub mod multi_signature;
|
||||
|
||||
use codec::{
|
||||
Decode,
|
||||
@@ -13,6 +16,18 @@ use codec::{
|
||||
};
|
||||
use derivative::Derivative;
|
||||
|
||||
pub use account_id::AccountId32;
|
||||
pub use multi_address::MultiAddress;
|
||||
pub use multi_signature::MultiSignature;
|
||||
|
||||
// Used in codegen
|
||||
#[doc(hidden)]
|
||||
pub use primitive_types::{
|
||||
H160,
|
||||
H256,
|
||||
H512,
|
||||
};
|
||||
|
||||
/// Wraps an already encoded byte vector, prevents being encoded as a raw byte vector as part of
|
||||
/// the transaction payload
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! The "default" Substrate/Polkadot Address type. This is used in codegen, as well as signing related bits.
|
||||
//! This doesn't contain much functionality itself, but is easy to convert to/from an `sp_runtime::MultiAddress`
|
||||
//! for instance, to gain functionality without forcing a dependency on Substrate crates here.
|
||||
|
||||
use codec::{
|
||||
Decode,
|
||||
Encode,
|
||||
};
|
||||
|
||||
/// A multi-format address wrapper for on-chain accounts. This is a simplified version of Substrate's
|
||||
/// `sp_runtime::MultiAddress`. To obtain more functionality, convert this into that type (this conversion
|
||||
/// functionality is provided via `From` impls if the `substrate-compat` feature is enabled).
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)]
|
||||
pub enum MultiAddress<AccountId, AccountIndex> {
|
||||
/// It's an account ID (pubkey).
|
||||
Id(AccountId),
|
||||
/// It's an account index.
|
||||
Index(#[codec(compact)] AccountIndex),
|
||||
/// It's some arbitrary raw bytes.
|
||||
Raw(Vec<u8>),
|
||||
/// It's a 32 byte representation.
|
||||
Address32([u8; 32]),
|
||||
/// Its a 20 byte representation.
|
||||
Address20([u8; 20]),
|
||||
}
|
||||
|
||||
impl<AccountId, AccountIndex> From<AccountId> for MultiAddress<AccountId, AccountIndex> {
|
||||
fn from(a: AccountId) -> Self {
|
||||
Self::Id(a)
|
||||
}
|
||||
}
|
||||
|
||||
// Improve compat with the substrate version if we're using those crates:
|
||||
#[cfg(feature = "substrate-compat")]
|
||||
mod substrate_impls {
|
||||
use super::{
|
||||
super::AccountId32,
|
||||
*,
|
||||
};
|
||||
|
||||
impl<N> From<sp_runtime::AccountId32> for MultiAddress<AccountId32, N> {
|
||||
fn from(value: sp_runtime::AccountId32) -> Self {
|
||||
let val: AccountId32 = value.into();
|
||||
val.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Id, N> From<sp_runtime::MultiAddress<Id, N>> for MultiAddress<AccountId32, N>
|
||||
where
|
||||
Id: Into<AccountId32>,
|
||||
{
|
||||
fn from(value: sp_runtime::MultiAddress<Id, N>) -> Self {
|
||||
match value {
|
||||
sp_runtime::MultiAddress::Id(v) => Self::Id(v.into()),
|
||||
sp_runtime::MultiAddress::Index(v) => Self::Index(v),
|
||||
sp_runtime::MultiAddress::Raw(v) => Self::Raw(v),
|
||||
sp_runtime::MultiAddress::Address32(v) => Self::Address32(v),
|
||||
sp_runtime::MultiAddress::Address20(v) => Self::Address20(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! The "default" Substrate/Polkadot Signature type. This is used in codegen, as well as signing related bits.
|
||||
//! This doesn't contain much functionality itself, but is easy to convert to/from an `sp_runtime::MultiSignature`
|
||||
//! for instance, to gain functionality without forcing a dependency on Substrate crates here.
|
||||
|
||||
use codec::{
|
||||
Decode,
|
||||
Encode,
|
||||
};
|
||||
|
||||
/// Signature container that can store known signature types. This is a simplified version of
|
||||
/// `sp_runtime::MultiSignature`. To obtain more functionality, convert this into that type.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)]
|
||||
pub enum MultiSignature {
|
||||
/// An Ed25519 signature.
|
||||
Ed25519([u8; 64]),
|
||||
/// An Sr25519 signature.
|
||||
Sr25519([u8; 64]),
|
||||
/// An ECDSA/SECP256k1 signature (a 512-bit value, plus 8 bits for recovery ID).
|
||||
Ecdsa([u8; 65]),
|
||||
}
|
||||
|
||||
// Improve compat with the substrate version if we're using those crates:
|
||||
#[cfg(feature = "substrate-compat")]
|
||||
mod substrate_impls {
|
||||
use super::*;
|
||||
|
||||
impl From<sp_runtime::MultiSignature> for MultiSignature {
|
||||
fn from(value: sp_runtime::MultiSignature) -> Self {
|
||||
match value {
|
||||
sp_runtime::MultiSignature::Ed25519(s) => Self::Ed25519(s.0),
|
||||
sp_runtime::MultiSignature::Sr25519(s) => Self::Sr25519(s.0),
|
||||
sp_runtime::MultiSignature::Ecdsa(s) => Self::Ecdsa(s.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sp_core::ed25519::Signature> for MultiSignature {
|
||||
fn from(value: sp_core::ed25519::Signature) -> Self {
|
||||
let sig: sp_runtime::MultiSignature = value.into();
|
||||
sig.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sp_core::sr25519::Signature> for MultiSignature {
|
||||
fn from(value: sp_core::sr25519::Signature) -> Self {
|
||||
let sig: sp_runtime::MultiSignature = value.into();
|
||||
sig.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sp_core::ecdsa::Signature> for MultiSignature {
|
||||
fn from(value: sp_core::ecdsa::Signature) -> Self {
|
||||
let sig: sp_runtime::MultiSignature = value.into();
|
||||
sig.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,9 @@ futures = "0.3.13"
|
||||
hex = "0.4.3"
|
||||
regex = "1.5.0"
|
||||
scale-info = { version = "2.0.0", features = ["bit-vec"] }
|
||||
sp-core = { version = "7.0.0", default-features = false }
|
||||
sp-keyring = "7.0.0"
|
||||
sp-runtime = "7.0.0"
|
||||
sp-core = { version = "11.0.0", default-features = false }
|
||||
sp-keyring = "12.0.0"
|
||||
sp-runtime = "12.0.0"
|
||||
syn = "1.0.0"
|
||||
subxt = { version = "0.25.0", path = "../../subxt" }
|
||||
subxt-codegen = { version = "0.25.0", path = "../../codegen" }
|
||||
|
||||
@@ -75,8 +75,8 @@ async fn missing_block_headers_will_be_filled_in() -> Result<(), subxt::Error> {
|
||||
while let Some(header) = all_finalized_blocks.next().await {
|
||||
let header = header?;
|
||||
|
||||
use sp_runtime::traits::Header;
|
||||
let block_number: u128 = (*header.number()).into();
|
||||
use subxt::config::Header;
|
||||
let block_number: u128 = header.number().into();
|
||||
|
||||
if let Some(last) = last_block_number {
|
||||
assert_eq!(last + 1, block_number);
|
||||
|
||||
@@ -17,7 +17,10 @@ use sp_core::{
|
||||
Pair,
|
||||
};
|
||||
use sp_keyring::AccountKeyring;
|
||||
use subxt::error::DispatchError;
|
||||
use subxt::{
|
||||
error::DispatchError,
|
||||
rpc::types::DryRunError,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
async fn insert_key() {
|
||||
@@ -162,8 +165,7 @@ async fn dry_run_passes() {
|
||||
.dry_run(None)
|
||||
.await
|
||||
.expect("dryrunning failed")
|
||||
.expect("expected dryrunning to be successful")
|
||||
.unwrap();
|
||||
.expect("dry run should be successful");
|
||||
|
||||
signed_extrinsic
|
||||
.submit_and_watch()
|
||||
@@ -198,15 +200,9 @@ async fn dry_run_fails() {
|
||||
let dry_run_res = signed_extrinsic
|
||||
.dry_run(None)
|
||||
.await
|
||||
.expect("dryrunning failed")
|
||||
.expect("expected dryrun transaction to be valid");
|
||||
.expect("dryrunning failed");
|
||||
|
||||
if let Err(sp_runtime::DispatchError::Module(module_error)) = dry_run_res {
|
||||
assert_eq!(module_error.index, 6);
|
||||
assert_eq!(module_error.error, [2, 0, 0, 0]);
|
||||
} else {
|
||||
panic!("expected a module error when dryrunning");
|
||||
}
|
||||
assert_eq!(dry_run_res, Err(DryRunError::DispatchError));
|
||||
|
||||
let res = signed_extrinsic
|
||||
.submit_and_watch()
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
/// Generate by:
|
||||
///
|
||||
/// - run `polkadot --dev --tmp` node locally
|
||||
/// - `cargo run --release -p subxt-cli -- codegen | rustfmt > integration-tests/src/codegen/polkadot.rs`
|
||||
/// - `cargo run -p subxt-cli -- codegen | rustfmt > testing/integration-tests/src/codegen/polkadot.rs`
|
||||
#[rustfmt::skip]
|
||||
#[allow(clippy::all)]
|
||||
mod polkadot;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -18,13 +18,15 @@ use sp_core::{
|
||||
Pair as _,
|
||||
};
|
||||
use sp_keyring::AccountKeyring;
|
||||
use sp_runtime::{
|
||||
AccountId32,
|
||||
MultiAddress,
|
||||
};
|
||||
use subxt::error::{
|
||||
DispatchError,
|
||||
Error,
|
||||
use subxt::{
|
||||
error::{
|
||||
DispatchError,
|
||||
Error,
|
||||
},
|
||||
utils::{
|
||||
AccountId32,
|
||||
MultiAddress,
|
||||
},
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
@@ -250,8 +252,9 @@ async fn storage_total_issuance() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn storage_balance_lock() -> Result<(), subxt::Error> {
|
||||
let bob = pair_signer(AccountKeyring::Bob.pair());
|
||||
let charlie = AccountKeyring::Charlie.to_account_id();
|
||||
let bob_signer = pair_signer(AccountKeyring::Bob.pair());
|
||||
let bob: AccountId32 = AccountKeyring::Bob.to_account_id().into();
|
||||
let charlie: AccountId32 = AccountKeyring::Charlie.to_account_id().into();
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
@@ -262,16 +265,14 @@ async fn storage_balance_lock() -> Result<(), subxt::Error> {
|
||||
);
|
||||
|
||||
api.tx()
|
||||
.sign_and_submit_then_watch_default(&tx, &bob)
|
||||
.sign_and_submit_then_watch_default(&tx, &bob_signer)
|
||||
.await?
|
||||
.wait_for_finalized_success()
|
||||
.await?
|
||||
.find_first::<system::events::ExtrinsicSuccess>()?
|
||||
.expect("No ExtrinsicSuccess Event found");
|
||||
|
||||
let locks_addr = node_runtime::storage()
|
||||
.balances()
|
||||
.locks(AccountKeyring::Bob.to_account_id());
|
||||
let locks_addr = node_runtime::storage().balances().locks(bob);
|
||||
|
||||
let locks = api.storage().fetch_or_default(&locks_addr, None).await?;
|
||||
|
||||
@@ -330,12 +331,13 @@ async fn transfer_error() {
|
||||
#[tokio::test]
|
||||
async fn transfer_implicit_subscription() {
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
let bob = AccountKeyring::Bob.to_account_id();
|
||||
let bob_addr = bob.clone().into();
|
||||
let bob: AccountId32 = AccountKeyring::Bob.to_account_id().into();
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
let to_bob_tx = node_runtime::tx().balances().transfer(bob_addr, 10_000);
|
||||
let to_bob_tx = node_runtime::tx()
|
||||
.balances()
|
||||
.transfer(bob.clone().into(), 10_000);
|
||||
|
||||
let event = api
|
||||
.tx()
|
||||
@@ -353,7 +355,7 @@ async fn transfer_implicit_subscription() {
|
||||
event,
|
||||
balances::events::Transfer {
|
||||
from: alice.account_id().clone(),
|
||||
to: bob.clone(),
|
||||
to: bob,
|
||||
amount: 10_000
|
||||
}
|
||||
);
|
||||
|
||||
@@ -18,12 +18,12 @@ use crate::{
|
||||
TestContext,
|
||||
};
|
||||
use sp_core::sr25519::Pair;
|
||||
use sp_runtime::MultiAddress;
|
||||
use subxt::{
|
||||
tx::{
|
||||
PairSigner,
|
||||
TxProgress,
|
||||
},
|
||||
utils::MultiAddress,
|
||||
Config,
|
||||
Error,
|
||||
OnlineClient,
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::{
|
||||
utils::wait_for_blocks,
|
||||
};
|
||||
use sp_keyring::AccountKeyring;
|
||||
use subxt::utils::AccountId32;
|
||||
|
||||
#[tokio::test]
|
||||
async fn storage_plain_lookup() -> Result<(), subxt::Error> {
|
||||
@@ -32,7 +33,7 @@ async fn storage_map_lookup() -> Result<(), subxt::Error> {
|
||||
let api = ctx.client();
|
||||
|
||||
let signer = pair_signer(AccountKeyring::Alice.pair());
|
||||
let alice = AccountKeyring::Alice.to_account_id();
|
||||
let alice: AccountId32 = AccountKeyring::Alice.to_account_id().into();
|
||||
|
||||
// Do some transaction to bump the Alice nonce to 1:
|
||||
let remark_tx = node_runtime::tx().system().remark(vec![1, 2, 3, 4, 5]);
|
||||
@@ -43,7 +44,7 @@ async fn storage_map_lookup() -> Result<(), subxt::Error> {
|
||||
.await?;
|
||||
|
||||
// Look up the nonce for the user (we expect it to be 1).
|
||||
let nonce_addr = node_runtime::storage().system().account(&alice);
|
||||
let nonce_addr = node_runtime::storage().system().account(alice);
|
||||
let entry = api.storage().fetch_or_default(&nonce_addr, None).await?;
|
||||
assert_eq!(entry.nonce, 1);
|
||||
|
||||
@@ -90,8 +91,8 @@ async fn storage_n_map_storage_lookup() -> Result<(), subxt::Error> {
|
||||
// we "approveTransfer" of some of this asset class. This gives us an
|
||||
// entry in the `Approvals` StorageNMap that we can try to look up.
|
||||
let signer = pair_signer(AccountKeyring::Alice.pair());
|
||||
let alice = AccountKeyring::Alice.to_account_id();
|
||||
let bob = AccountKeyring::Bob.to_account_id();
|
||||
let alice: AccountId32 = AccountKeyring::Alice.to_account_id().into();
|
||||
let bob: AccountId32 = AccountKeyring::Bob.to_account_id().into();
|
||||
|
||||
let tx1 = node_runtime::tx()
|
||||
.assets()
|
||||
@@ -111,7 +112,7 @@ async fn storage_n_map_storage_lookup() -> Result<(), subxt::Error> {
|
||||
.await?;
|
||||
|
||||
// The actual test; look up this approval in storage:
|
||||
let addr = node_runtime::storage().assets().approvals(99, &alice, &bob);
|
||||
let addr = node_runtime::storage().assets().approvals(99, alice, bob);
|
||||
let entry = api.storage().fetch(&addr, None).await?;
|
||||
assert_eq!(entry.map(|a| a.amount), Some(123));
|
||||
Ok(())
|
||||
|
||||
@@ -6,12 +6,11 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
subxt = { path = "../../subxt" }
|
||||
sp-runtime = "7.0.0"
|
||||
sp-runtime = "12.0.0"
|
||||
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "full", "bit-vec"] }
|
||||
|
||||
[build-dependencies]
|
||||
subxt = { path = "../../subxt" }
|
||||
sp-core = { version = "7.0.0", default-features = false }
|
||||
tokio = { version = "1.8", features = ["macros", "rt-multi-thread"] }
|
||||
which = "4.2.2"
|
||||
jsonrpsee = { version = "0.16.0", features = ["async-client", "client-ws-transport"] }
|
||||
|
||||
@@ -47,7 +47,7 @@ async fn run() {
|
||||
};
|
||||
|
||||
// Download metadata from binary; retry until successful, or a limit is hit.
|
||||
let metadata_bytes: sp_core::Bytes = {
|
||||
let metadata_bytes: subxt::rpc::types::Bytes = {
|
||||
const MAX_RETRIES: usize = 6;
|
||||
let mut retries = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user