mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-21 16:45:41 +00:00
Simplify creating and signing extrinsics (#490)
* WIP extrinsic api updates * First pass done; now to get things compiling again * document and tweak new structs/traits * cargo check --all-targets now compiles without issue * Polkadot and Substrate take different extra params; support both * Fix transaction format (missing byte from AccountId -> Address) and fmt * Tweak Signer trait * Tweak comments and such in extrinsic params * check all examples against newer polkadot, add new one with params, import path tweaks * clippy fix, and save an allocation when signing * Remove unnecessary Default clauses * Tidy up and fix comments. Panic if payload size >4GB * fix typo
This commit is contained in:
@@ -38,13 +38,13 @@ resides ([`CARGO_MANIFEST_DIR`](https://doc.rust-lang.org/cargo/reference/enviro
|
|||||||
### Initializing the API client
|
### Initializing the API client
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use subxt::{ClientBuilder, DefaultConfig, DefaultExtra};
|
use subxt::{ClientBuilder, DefaultConfig, SubstrateExtrinsicParams};
|
||||||
|
|
||||||
let api = ClientBuilder::new()
|
let api = ClientBuilder::new()
|
||||||
.set_url("wss://rpc.polkadot.io:443")
|
.set_url("wss://rpc.polkadot.io:443")
|
||||||
.build()
|
.build()
|
||||||
.await?
|
.await?
|
||||||
.to_runtime_api::<node_runtime::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();
|
.to_runtime_api::<node_runtime::RuntimeApi<DefaultConfig, SubstrateExtrinsicParams<DefaultConfig>>>();
|
||||||
```
|
```
|
||||||
|
|
||||||
The `RuntimeApi` type is generated by the `subxt` macro from the supplied metadata. This can be parameterized with user
|
The `RuntimeApi` type is generated by the `subxt` macro from the supplied metadata. This can be parameterized with user
|
||||||
@@ -53,7 +53,7 @@ chain.
|
|||||||
|
|
||||||
### Querying Storage
|
### Querying Storage
|
||||||
|
|
||||||
Call the generated `RuntimeApi::storage()` method, followed by the `pallet_name()` and then the `storage_item_name()`.
|
Call the generated `RuntimeApi::storage()` method, followed by the `pallet_name()` and then the `storage_item_name()`.
|
||||||
|
|
||||||
So in order to query `Balances::TotalIssuance`:
|
So in order to query `Balances::TotalIssuance`:
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ pub fn generate_calls(
|
|||||||
impl<'a, T, X> TransactionApi<'a, T, X>
|
impl<'a, T, X> TransactionApi<'a, T, X>
|
||||||
where
|
where
|
||||||
T: ::subxt::Config,
|
T: ::subxt::Config,
|
||||||
X: ::subxt::SignedExtra<T>,
|
X: ::subxt::extrinsic::ExtrinsicParams<T>,
|
||||||
{
|
{
|
||||||
pub fn new(client: &'a ::subxt::Client<T>) -> Self {
|
pub fn new(client: &'a ::subxt::Client<T>) -> Self {
|
||||||
Self { client, marker: ::core::marker::PhantomData }
|
Self { client, marker: ::core::marker::PhantomData }
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ impl RuntimeGenerator {
|
|||||||
impl<T, X> ::core::convert::From<::subxt::Client<T>> for RuntimeApi<T, X>
|
impl<T, X> ::core::convert::From<::subxt::Client<T>> for RuntimeApi<T, X>
|
||||||
where
|
where
|
||||||
T: ::subxt::Config,
|
T: ::subxt::Config,
|
||||||
X: ::subxt::SignedExtra<T>
|
X: ::subxt::extrinsic::ExtrinsicParams<T>
|
||||||
{
|
{
|
||||||
fn from(client: ::subxt::Client<T>) -> Self {
|
fn from(client: ::subxt::Client<T>) -> Self {
|
||||||
Self { client, marker: ::core::marker::PhantomData }
|
Self { client, marker: ::core::marker::PhantomData }
|
||||||
@@ -298,7 +298,7 @@ impl RuntimeGenerator {
|
|||||||
impl<'a, T, X> RuntimeApi<T, X>
|
impl<'a, T, X> RuntimeApi<T, X>
|
||||||
where
|
where
|
||||||
T: ::subxt::Config,
|
T: ::subxt::Config,
|
||||||
X: ::subxt::SignedExtra<T>,
|
X: ::subxt::extrinsic::ExtrinsicParams<T>,
|
||||||
{
|
{
|
||||||
pub fn constants(&'a self) -> ConstantsApi {
|
pub fn constants(&'a self) -> ConstantsApi {
|
||||||
ConstantsApi
|
ConstantsApi
|
||||||
@@ -368,7 +368,7 @@ impl RuntimeGenerator {
|
|||||||
impl<'a, T, X> TransactionApi<'a, T, X>
|
impl<'a, T, X> TransactionApi<'a, T, X>
|
||||||
where
|
where
|
||||||
T: ::subxt::Config,
|
T: ::subxt::Config,
|
||||||
X: ::subxt::SignedExtra<T>,
|
X: ::subxt::extrinsic::ExtrinsicParams<T>,
|
||||||
{
|
{
|
||||||
#(
|
#(
|
||||||
pub fn #pallets_with_calls(&self) -> #pallets_with_calls::calls::TransactionApi<'a, T, X> {
|
pub fn #pallets_with_calls(&self) -> #pallets_with_calls::calls::TransactionApi<'a, T, X> {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.13-82616422d0-aarch64-macos.
|
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.18-f6d6ab005d-aarch64-macos.
|
||||||
//!
|
//!
|
||||||
//! E.g.
|
//! E.g.
|
||||||
//! ```bash
|
//! ```bash
|
||||||
@@ -26,8 +26,8 @@ use sp_keyring::AccountKeyring;
|
|||||||
use subxt::{
|
use subxt::{
|
||||||
ClientBuilder,
|
ClientBuilder,
|
||||||
DefaultConfig,
|
DefaultConfig,
|
||||||
DefaultExtra,
|
|
||||||
PairSigner,
|
PairSigner,
|
||||||
|
PolkadotExtrinsicParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
||||||
@@ -43,12 +43,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let api = ClientBuilder::new()
|
let api = ClientBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.await?
|
.await?
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();
|
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<DefaultConfig>>>();
|
||||||
let hash = api
|
let hash = api
|
||||||
.tx()
|
.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(dest, 10_000)
|
.transfer(dest, 123_456_789_012_345)
|
||||||
.sign_and_submit(&signer)
|
.sign_and_submit_default(&signer)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
println!("Balance transfer extrinsic submitted: {}", hash);
|
println!("Balance transfer extrinsic submitted: {}", hash);
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of subxt.
|
||||||
|
//
|
||||||
|
// subxt is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// subxt is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.18-f6d6ab005d-aarch64-macos.
|
||||||
|
//!
|
||||||
|
//! E.g.
|
||||||
|
//! ```bash
|
||||||
|
//! curl "https://github.com/paritytech/polkadot/releases/download/v0.9.13/polkadot" --output /usr/local/bin/polkadot --location
|
||||||
|
//! polkadot --dev --tmp
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use sp_keyring::AccountKeyring;
|
||||||
|
use subxt::{
|
||||||
|
extrinsic::{
|
||||||
|
Era,
|
||||||
|
PlainTip,
|
||||||
|
},
|
||||||
|
ClientBuilder,
|
||||||
|
DefaultConfig,
|
||||||
|
PairSigner,
|
||||||
|
PolkadotExtrinsicParams,
|
||||||
|
PolkadotExtrinsicParamsBuilder as Params,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
||||||
|
pub mod polkadot {}
|
||||||
|
|
||||||
|
#[async_std::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
||||||
|
let dest = AccountKeyring::Bob.to_account_id().into();
|
||||||
|
|
||||||
|
let api = ClientBuilder::new()
|
||||||
|
.build()
|
||||||
|
.await?
|
||||||
|
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<DefaultConfig>>>();
|
||||||
|
|
||||||
|
// Configure the transaction tip and era:
|
||||||
|
let tx_params = Params::new()
|
||||||
|
.tip(PlainTip::new(20_000_000_000))
|
||||||
|
.era(Era::Immortal, *api.client.genesis());
|
||||||
|
|
||||||
|
// Send the transaction:
|
||||||
|
let hash = api
|
||||||
|
.tx()
|
||||||
|
.balances()
|
||||||
|
.transfer(dest, 123_456_789_012_345)
|
||||||
|
.sign_and_submit(&signer, tx_params)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Balance transfer extrinsic submitted: {}", hash);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.13-82616422d0-aarch64-macos.
|
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.18-f6d6ab005d-aarch64-macos.
|
||||||
//!
|
//!
|
||||||
//! E.g.
|
//! E.g.
|
||||||
//! ```bash
|
//! ```bash
|
||||||
@@ -27,8 +27,8 @@ use subxt::{
|
|||||||
ClientBuilder,
|
ClientBuilder,
|
||||||
Config,
|
Config,
|
||||||
DefaultConfig,
|
DefaultConfig,
|
||||||
DefaultExtra,
|
|
||||||
PairSigner,
|
PairSigner,
|
||||||
|
PolkadotExtrinsicParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
||||||
@@ -60,7 +60,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let api = ClientBuilder::new()
|
let api = ClientBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.await?
|
.await?
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<MyConfig, DefaultExtra<MyConfig>>>();
|
.to_runtime_api::<polkadot::RuntimeApi<MyConfig, PolkadotExtrinsicParams<MyConfig>>>();
|
||||||
|
|
||||||
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
||||||
let dest = AccountKeyring::Bob.to_account_id().into();
|
let dest = AccountKeyring::Bob.to_account_id().into();
|
||||||
@@ -69,7 +69,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
.tx()
|
.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(dest, 10_000)
|
.transfer(dest, 10_000)
|
||||||
.sign_and_submit(&signer)
|
.sign_and_submit_default(&signer)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
println!("Balance transfer extrinsic submitted: {}", hash);
|
println!("Balance transfer extrinsic submitted: {}", hash);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Example verified against polkadot 0.9.13-82616422d0-aarch64-macos.
|
//! Example verified against polkadot 0.9.18-f6d6ab005d-aarch64-macos.
|
||||||
|
|
||||||
#![allow(clippy::redundant_clone)]
|
#![allow(clippy::redundant_clone)]
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.13-82616422d0-aarch64-macos.
|
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.18-f6d6ab005d-aarch64-macos.
|
||||||
//!
|
//!
|
||||||
//! E.g.
|
//! E.g.
|
||||||
//! ```bash
|
//! ```bash
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
use subxt::{
|
use subxt::{
|
||||||
ClientBuilder,
|
ClientBuilder,
|
||||||
DefaultConfig,
|
DefaultConfig,
|
||||||
DefaultExtra,
|
PolkadotExtrinsicParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
||||||
@@ -38,7 +38,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let api = ClientBuilder::new()
|
let api = ClientBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.await?
|
.await?
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();
|
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<DefaultConfig>>>();
|
||||||
|
|
||||||
let mut iter = api.storage().system().account_iter(None).await?;
|
let mut iter = api.storage().system().account_iter(None).await?;
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ use subxt::{
|
|||||||
sp_runtime::AccountId32,
|
sp_runtime::AccountId32,
|
||||||
ClientBuilder,
|
ClientBuilder,
|
||||||
DefaultConfig,
|
DefaultConfig,
|
||||||
DefaultExtra,
|
PolkadotExtrinsicParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
||||||
@@ -44,7 +44,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let api = ClientBuilder::new()
|
let api = ClientBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.await?
|
.await?
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();
|
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<DefaultConfig>>>();
|
||||||
|
|
||||||
let era = api.storage().staking().active_era(None).await?.unwrap();
|
let era = api.storage().staking().active_era(None).await?.unwrap();
|
||||||
println!(
|
println!(
|
||||||
|
|||||||
Binary file not shown.
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.13-82616422d0-aarch64-macos.
|
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.18-f6d6ab005d-aarch64-macos.
|
||||||
//!
|
//!
|
||||||
//! E.g.
|
//! E.g.
|
||||||
//! ```bash
|
//! ```bash
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
use subxt::{
|
use subxt::{
|
||||||
ClientBuilder,
|
ClientBuilder,
|
||||||
DefaultConfig,
|
DefaultConfig,
|
||||||
DefaultExtra,
|
PolkadotExtrinsicParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
||||||
@@ -39,7 +39,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
.set_url("wss://rpc.polkadot.io:443")
|
.set_url("wss://rpc.polkadot.io:443")
|
||||||
.build()
|
.build()
|
||||||
.await?
|
.await?
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();
|
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<DefaultConfig>>>();
|
||||||
|
|
||||||
let block_number = 1u32;
|
let block_number = 1u32;
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.13-82616422d0-aarch64-macos.
|
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.18-f6d6ab005d-aarch64-macos.
|
||||||
//!
|
//!
|
||||||
//! E.g.
|
//! E.g.
|
||||||
//! ```bash
|
//! ```bash
|
||||||
@@ -27,8 +27,8 @@ use sp_keyring::AccountKeyring;
|
|||||||
use subxt::{
|
use subxt::{
|
||||||
ClientBuilder,
|
ClientBuilder,
|
||||||
DefaultConfig,
|
DefaultConfig,
|
||||||
DefaultExtra,
|
|
||||||
PairSigner,
|
PairSigner,
|
||||||
|
PolkadotExtrinsicParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
||||||
@@ -55,13 +55,13 @@ async fn simple_transfer() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let api = ClientBuilder::new()
|
let api = ClientBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.await?
|
.await?
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<_>>>();
|
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<_>>>();
|
||||||
|
|
||||||
let balance_transfer = api
|
let balance_transfer = api
|
||||||
.tx()
|
.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(dest, 10_000)
|
.transfer(dest, 10_000)
|
||||||
.sign_and_submit_then_watch(&signer)
|
.sign_and_submit_then_watch_default(&signer)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?;
|
.await?;
|
||||||
@@ -87,13 +87,13 @@ async fn simple_transfer_separate_events() -> Result<(), Box<dyn std::error::Err
|
|||||||
let api = ClientBuilder::new()
|
let api = ClientBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.await?
|
.await?
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<_>>>();
|
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<_>>>();
|
||||||
|
|
||||||
let balance_transfer = api
|
let balance_transfer = api
|
||||||
.tx()
|
.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(dest, 10_000)
|
.transfer(dest, 10_000)
|
||||||
.sign_and_submit_then_watch(&signer)
|
.sign_and_submit_then_watch_default(&signer)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized()
|
.wait_for_finalized()
|
||||||
.await?;
|
.await?;
|
||||||
@@ -138,13 +138,13 @@ async fn handle_transfer_events() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let api = ClientBuilder::new()
|
let api = ClientBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.await?
|
.await?
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<_>>>();
|
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<_>>>();
|
||||||
|
|
||||||
let mut balance_transfer_progress = api
|
let mut balance_transfer_progress = api
|
||||||
.tx()
|
.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(dest, 10_000)
|
.transfer(dest, 10_000)
|
||||||
.sign_and_submit_then_watch(&signer)
|
.sign_and_submit_then_watch_default(&signer)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
while let Some(ev) = balance_transfer_progress.next().await {
|
while let Some(ev) = balance_transfer_progress.next().await {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.13-82616422d0-aarch64-macos.
|
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.18-f6d6ab005d-aarch64-macos.
|
||||||
//!
|
//!
|
||||||
//! E.g.
|
//! E.g.
|
||||||
//! ```bash
|
//! ```bash
|
||||||
@@ -28,8 +28,8 @@ use std::time::Duration;
|
|||||||
use subxt::{
|
use subxt::{
|
||||||
ClientBuilder,
|
ClientBuilder,
|
||||||
DefaultConfig,
|
DefaultConfig,
|
||||||
DefaultExtra,
|
|
||||||
PairSigner,
|
PairSigner,
|
||||||
|
PolkadotExtrinsicParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
||||||
@@ -44,7 +44,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let api = ClientBuilder::new()
|
let api = ClientBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.await?
|
.await?
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();
|
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<DefaultConfig>>>();
|
||||||
|
|
||||||
// Subscribe to any events that occur:
|
// Subscribe to any events that occur:
|
||||||
let mut event_sub = api.events().subscribe().await?;
|
let mut event_sub = api.events().subscribe().await?;
|
||||||
@@ -52,11 +52,15 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// While this subscription is active, balance transfers are made somewhere:
|
// While this subscription is active, balance transfers are made somewhere:
|
||||||
async_std::task::spawn(async {
|
async_std::task::spawn(async {
|
||||||
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
||||||
let api = ClientBuilder::new()
|
let api =
|
||||||
.build()
|
ClientBuilder::new()
|
||||||
.await
|
.build()
|
||||||
.unwrap()
|
.await
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();
|
.unwrap()
|
||||||
|
.to_runtime_api::<polkadot::RuntimeApi<
|
||||||
|
DefaultConfig,
|
||||||
|
PolkadotExtrinsicParams<DefaultConfig>,
|
||||||
|
>>();
|
||||||
|
|
||||||
let mut transfer_amount = 1_000_000_000;
|
let mut transfer_amount = 1_000_000_000;
|
||||||
|
|
||||||
@@ -65,7 +69,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
api.tx()
|
api.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(AccountKeyring::Bob.to_account_id().into(), transfer_amount)
|
.transfer(AccountKeyring::Bob.to_account_id().into(), transfer_amount)
|
||||||
.sign_and_submit(&signer)
|
.sign_and_submit_default(&signer)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.13-82616422d0-aarch64-macos.
|
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.18-f6d6ab005d-aarch64-macos.
|
||||||
//!
|
//!
|
||||||
//! E.g.
|
//! E.g.
|
||||||
//! ```bash
|
//! ```bash
|
||||||
@@ -28,8 +28,8 @@ use std::time::Duration;
|
|||||||
use subxt::{
|
use subxt::{
|
||||||
ClientBuilder,
|
ClientBuilder,
|
||||||
DefaultConfig,
|
DefaultConfig,
|
||||||
DefaultExtra,
|
|
||||||
PairSigner,
|
PairSigner,
|
||||||
|
PolkadotExtrinsicParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
||||||
@@ -45,7 +45,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let api = ClientBuilder::new()
|
let api = ClientBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.await?
|
.await?
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();
|
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<DefaultConfig>>>();
|
||||||
|
|
||||||
// Subscribe to just balance transfer events, making use of `filter_events`
|
// Subscribe to just balance transfer events, making use of `filter_events`
|
||||||
// to select a single event type (note the 1-tuple) to filter out and return.
|
// to select a single event type (note the 1-tuple) to filter out and return.
|
||||||
@@ -58,18 +58,22 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// While this subscription is active, we imagine some balance transfers are made somewhere else:
|
// While this subscription is active, we imagine some balance transfers are made somewhere else:
|
||||||
async_std::task::spawn(async {
|
async_std::task::spawn(async {
|
||||||
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
||||||
let api = ClientBuilder::new()
|
let api =
|
||||||
.build()
|
ClientBuilder::new()
|
||||||
.await
|
.build()
|
||||||
.unwrap()
|
.await
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();
|
.unwrap()
|
||||||
|
.to_runtime_api::<polkadot::RuntimeApi<
|
||||||
|
DefaultConfig,
|
||||||
|
PolkadotExtrinsicParams<DefaultConfig>,
|
||||||
|
>>();
|
||||||
|
|
||||||
// Make small balance transfers from Alice to Bob in a loop:
|
// Make small balance transfers from Alice to Bob in a loop:
|
||||||
loop {
|
loop {
|
||||||
api.tx()
|
api.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(AccountKeyring::Bob.to_account_id().into(), 1_000_000_000)
|
.transfer(AccountKeyring::Bob.to_account_id().into(), 1_000_000_000)
|
||||||
.sign_and_submit(&signer)
|
.sign_and_submit_default(&signer)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
async_std::task::sleep(Duration::from_secs(10)).await;
|
async_std::task::sleep(Duration::from_secs(10)).await;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.13-82616422d0-aarch64-macos.
|
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.18-f6d6ab005d-aarch64-macos.
|
||||||
//!
|
//!
|
||||||
//! E.g.
|
//! E.g.
|
||||||
//! ```bash
|
//! ```bash
|
||||||
@@ -28,8 +28,8 @@ use std::time::Duration;
|
|||||||
use subxt::{
|
use subxt::{
|
||||||
ClientBuilder,
|
ClientBuilder,
|
||||||
DefaultConfig,
|
DefaultConfig,
|
||||||
DefaultExtra,
|
|
||||||
PairSigner,
|
PairSigner,
|
||||||
|
PolkadotExtrinsicParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
|
||||||
@@ -45,7 +45,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let api = ClientBuilder::new()
|
let api = ClientBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.await?
|
.await?
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();
|
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<DefaultConfig>>>();
|
||||||
|
|
||||||
// Subscribe to several balance related events. If we ask for more than one event,
|
// Subscribe to several balance related events. If we ask for more than one event,
|
||||||
// we'll be given a correpsonding tuple of `Option`'s, with exactly one
|
// we'll be given a correpsonding tuple of `Option`'s, with exactly one
|
||||||
@@ -59,18 +59,22 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// While this subscription is active, we imagine some balance transfers are made somewhere else:
|
// While this subscription is active, we imagine some balance transfers are made somewhere else:
|
||||||
async_std::task::spawn(async {
|
async_std::task::spawn(async {
|
||||||
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
||||||
let api = ClientBuilder::new()
|
let api =
|
||||||
.build()
|
ClientBuilder::new()
|
||||||
.await
|
.build()
|
||||||
.unwrap()
|
.await
|
||||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();
|
.unwrap()
|
||||||
|
.to_runtime_api::<polkadot::RuntimeApi<
|
||||||
|
DefaultConfig,
|
||||||
|
PolkadotExtrinsicParams<DefaultConfig>,
|
||||||
|
>>();
|
||||||
|
|
||||||
// Make small balance transfers from Alice to Bob in a loop:
|
// Make small balance transfers from Alice to Bob in a loop:
|
||||||
loop {
|
loop {
|
||||||
api.tx()
|
api.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(AccountKeyring::Bob.to_account_id().into(), 1_000_000_000)
|
.transfer(AccountKeyring::Bob.to_account_id().into(), 1_000_000_000)
|
||||||
.sign_and_submit(&signer)
|
.sign_and_submit_default(&signer)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
async_std::task::sleep(Duration::from_secs(10)).await;
|
async_std::task::sleep(Duration::from_secs(10)).await;
|
||||||
|
|||||||
+119
-41
@@ -24,10 +24,8 @@ use crate::{
|
|||||||
HasModuleError,
|
HasModuleError,
|
||||||
},
|
},
|
||||||
extrinsic::{
|
extrinsic::{
|
||||||
self,
|
ExtrinsicParams,
|
||||||
SignedExtra,
|
|
||||||
Signer,
|
Signer,
|
||||||
UncheckedExtrinsic,
|
|
||||||
},
|
},
|
||||||
rpc::{
|
rpc::{
|
||||||
Rpc,
|
Rpc,
|
||||||
@@ -39,9 +37,14 @@ use crate::{
|
|||||||
transaction::TransactionProgress,
|
transaction::TransactionProgress,
|
||||||
Call,
|
Call,
|
||||||
Config,
|
Config,
|
||||||
|
Encoded,
|
||||||
Metadata,
|
Metadata,
|
||||||
};
|
};
|
||||||
use codec::Decode;
|
use codec::{
|
||||||
|
Compact,
|
||||||
|
Decode,
|
||||||
|
Encode,
|
||||||
|
};
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@@ -188,7 +191,7 @@ pub struct SubmittableExtrinsic<'client, T: Config, X, C, E: Decode, Evs: Decode
|
|||||||
impl<'client, T, X, C, E, Evs> SubmittableExtrinsic<'client, T, X, C, E, Evs>
|
impl<'client, T, X, C, E, Evs> SubmittableExtrinsic<'client, T, X, C, E, Evs>
|
||||||
where
|
where
|
||||||
T: Config,
|
T: Config,
|
||||||
X: SignedExtra<T>,
|
X: ExtrinsicParams<T>,
|
||||||
C: Call + Send + Sync,
|
C: Call + Send + Sync,
|
||||||
E: Decode + HasModuleError,
|
E: Decode + HasModuleError,
|
||||||
Evs: Decode,
|
Evs: Decode,
|
||||||
@@ -202,20 +205,33 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates and signs an extrinsic and submits it to the chain. Passes default parameters
|
||||||
|
/// to construct the "signed extra" and "additional" payloads needed by the extrinsic.
|
||||||
|
///
|
||||||
|
/// Returns a [`TransactionProgress`], 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(
|
||||||
|
self,
|
||||||
|
signer: &(dyn Signer<T> + Send + Sync),
|
||||||
|
) -> Result<TransactionProgress<'client, T, E, Evs>, BasicError>
|
||||||
|
where
|
||||||
|
X::OtherParams: Default,
|
||||||
|
{
|
||||||
|
self.sign_and_submit_then_watch(signer, Default::default())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates and signs an extrinsic and submits it to the chain.
|
/// Creates and signs an extrinsic and submits it to the chain.
|
||||||
///
|
///
|
||||||
/// Returns a [`TransactionProgress`], which can be used to track the status of the transaction
|
/// Returns a [`TransactionProgress`], which can be used to track the status of the transaction
|
||||||
/// and obtain details about it, once it has made it into a block.
|
/// and obtain details about it, once it has made it into a block.
|
||||||
pub async fn sign_and_submit_then_watch(
|
pub async fn sign_and_submit_then_watch(
|
||||||
self,
|
self,
|
||||||
signer: &(dyn Signer<T, X> + Send + Sync),
|
signer: &(dyn Signer<T> + Send + Sync),
|
||||||
) -> Result<TransactionProgress<'client, T, E, Evs>, BasicError>
|
other_params: X::OtherParams,
|
||||||
where
|
) -> Result<TransactionProgress<'client, T, E, Evs>, BasicError> {
|
||||||
<<X as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
|
||||||
Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
// Sign the call data to create our extrinsic.
|
// Sign the call data to create our extrinsic.
|
||||||
let extrinsic = self.create_signed(signer, Default::default()).await?;
|
let extrinsic = self.create_signed(signer, other_params).await?;
|
||||||
|
|
||||||
// Get a hash of the extrinsic (we'll need this later).
|
// Get a hash of the extrinsic (we'll need this later).
|
||||||
let ext_hash = T::Hashing::hash_of(&extrinsic);
|
let ext_hash = T::Hashing::hash_of(&extrinsic);
|
||||||
@@ -226,6 +242,26 @@ where
|
|||||||
Ok(TransactionProgress::new(sub, self.client, ext_hash))
|
Ok(TransactionProgress::new(sub, self.client, ext_hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates and signs an extrinsic and submits to the chain for block inclusion. Passes
|
||||||
|
/// default parameters to construct the "signed extra" and "additional" payloads needed
|
||||||
|
/// by the extrinsic.
|
||||||
|
///
|
||||||
|
/// Returns `Ok` with the extrinsic hash if it is valid extrinsic.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// 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(
|
||||||
|
self,
|
||||||
|
signer: &(dyn Signer<T> + Send + Sync),
|
||||||
|
) -> Result<T::Hash, BasicError>
|
||||||
|
where
|
||||||
|
X::OtherParams: Default,
|
||||||
|
{
|
||||||
|
self.sign_and_submit(signer, Default::default()).await
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates and signs an extrinsic and submits to the chain for block inclusion.
|
/// Creates and signs an extrinsic and submits to the chain for block inclusion.
|
||||||
///
|
///
|
||||||
/// Returns `Ok` with the extrinsic hash if it is valid extrinsic.
|
/// Returns `Ok` with the extrinsic hash if it is valid extrinsic.
|
||||||
@@ -236,26 +272,20 @@ where
|
|||||||
/// and has been included in the transaction pool.
|
/// and has been included in the transaction pool.
|
||||||
pub async fn sign_and_submit(
|
pub async fn sign_and_submit(
|
||||||
self,
|
self,
|
||||||
signer: &(dyn Signer<T, X> + Send + Sync),
|
signer: &(dyn Signer<T> + Send + Sync),
|
||||||
) -> Result<T::Hash, BasicError>
|
other_params: X::OtherParams,
|
||||||
where
|
) -> Result<T::Hash, BasicError> {
|
||||||
<<X as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
let extrinsic = self.create_signed(signer, other_params).await?;
|
||||||
Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
let extrinsic = self.create_signed(signer, Default::default()).await?;
|
|
||||||
self.client.rpc().submit_extrinsic(extrinsic).await
|
self.client.rpc().submit_extrinsic(extrinsic).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a signed extrinsic.
|
/// Creates a returns a raw signed extrinsic, without submitting it.
|
||||||
pub async fn create_signed(
|
pub async fn create_signed(
|
||||||
&self,
|
&self,
|
||||||
signer: &(dyn Signer<T, X> + Send + Sync),
|
signer: &(dyn Signer<T> + Send + Sync),
|
||||||
additional_params: X::Parameters,
|
other_params: X::OtherParams,
|
||||||
) -> Result<UncheckedExtrinsic<T, X>, BasicError>
|
) -> Result<Encoded, BasicError> {
|
||||||
where
|
// 1. Get nonce
|
||||||
<<X as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
|
||||||
Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
let account_nonce = if let Some(nonce) = signer.nonce() {
|
let account_nonce = if let Some(nonce) = signer.nonce() {
|
||||||
nonce
|
nonce
|
||||||
} else {
|
} else {
|
||||||
@@ -264,21 +294,69 @@ where
|
|||||||
.system_account_next_index(signer.account_id())
|
.system_account_next_index(signer.account_id())
|
||||||
.await?
|
.await?
|
||||||
};
|
};
|
||||||
let call = self
|
|
||||||
.client
|
|
||||||
.metadata()
|
|
||||||
.pallet(C::PALLET)
|
|
||||||
.and_then(|pallet| pallet.encode_call(&self.call))?;
|
|
||||||
|
|
||||||
let signed = extrinsic::create_signed(
|
// 2. SCALE encode call data to bytes (pallet u8, call u8, call params).
|
||||||
&self.client.runtime_version,
|
let call_data = {
|
||||||
self.client.genesis_hash,
|
let mut bytes = Vec::new();
|
||||||
|
let pallet = self.client.metadata().pallet(C::PALLET)?;
|
||||||
|
bytes.push(pallet.index());
|
||||||
|
bytes.push(pallet.call_index::<C>()?);
|
||||||
|
self.call.encode_to(&mut bytes);
|
||||||
|
Encoded(bytes)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 3. Construct our custom additional/extra params.
|
||||||
|
let additional_and_extra_params = X::new(
|
||||||
|
self.client.runtime_version.spec_version,
|
||||||
|
self.client.runtime_version.transaction_version,
|
||||||
account_nonce,
|
account_nonce,
|
||||||
call,
|
self.client.genesis_hash,
|
||||||
signer,
|
other_params,
|
||||||
additional_params,
|
);
|
||||||
)
|
|
||||||
.await?;
|
// 4. Construct signature. This is compatible with the Encode impl
|
||||||
Ok(signed)
|
// for SignedPayload (which is this payload of bytes that we'd like)
|
||||||
|
// to sign. See:
|
||||||
|
// https://github.com/paritytech/substrate/blob/9a6d706d8db00abb6ba183839ec98ecd9924b1f8/primitives/runtime/src/generic/unchecked_extrinsic.rs#L215)
|
||||||
|
let signature = {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
call_data.encode_to(&mut bytes);
|
||||||
|
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))
|
||||||
|
} else {
|
||||||
|
signer.sign(&bytes)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 5. Encode extrinsic, now that we have the parts we need. This is compatible
|
||||||
|
// with the Encode impl for UncheckedExtrinsic (protocol version 4).
|
||||||
|
let extrinsic = {
|
||||||
|
let mut encoded_inner = Vec::new();
|
||||||
|
// "is signed" + transaction protocol version (4)
|
||||||
|
(0b10000000 + 4u8).encode_to(&mut encoded_inner);
|
||||||
|
// from address for signature
|
||||||
|
signer.address().encode_to(&mut encoded_inner);
|
||||||
|
// the signature bytes
|
||||||
|
signature.encode_to(&mut encoded_inner);
|
||||||
|
// attach custom extra params
|
||||||
|
additional_and_extra_params.encode_extra_to(&mut encoded_inner);
|
||||||
|
// and now, call data
|
||||||
|
call_data.encode_to(&mut encoded_inner);
|
||||||
|
// now, prefix byte length:
|
||||||
|
let len = Compact(
|
||||||
|
u32::try_from(encoded_inner.len())
|
||||||
|
.expect("extrinsic size expected to be <4GB"),
|
||||||
|
);
|
||||||
|
let mut encoded = Vec::new();
|
||||||
|
len.encode_to(&mut encoded);
|
||||||
|
encoded.extend(encoded_inner);
|
||||||
|
encoded
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wrap in Encoded to ensure that any more "encode" calls leave it in the right state.
|
||||||
|
// maybe we can just return the raw bytes..
|
||||||
|
Ok(Encoded(extrinsic))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -43,7 +43,8 @@ pub trait Config: 'static {
|
|||||||
+ Default
|
+ Default
|
||||||
+ AtLeast32Bit
|
+ AtLeast32Bit
|
||||||
+ Copy
|
+ Copy
|
||||||
+ scale_info::TypeInfo;
|
+ scale_info::TypeInfo
|
||||||
|
+ Into<u64>;
|
||||||
|
|
||||||
/// The block number type used by the runtime.
|
/// The block number type used by the runtime.
|
||||||
type BlockNumber: Parameter
|
type BlockNumber: Parameter
|
||||||
|
|||||||
@@ -1,481 +0,0 @@
|
|||||||
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of subxt.
|
|
||||||
//
|
|
||||||
// subxt is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// subxt is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use crate::PhantomDataSendSync;
|
|
||||||
use codec::{
|
|
||||||
Decode,
|
|
||||||
Encode,
|
|
||||||
};
|
|
||||||
use derivative::Derivative;
|
|
||||||
use scale_info::TypeInfo;
|
|
||||||
use sp_runtime::{
|
|
||||||
generic::Era,
|
|
||||||
traits::{
|
|
||||||
DispatchInfoOf,
|
|
||||||
SignedExtension,
|
|
||||||
},
|
|
||||||
transaction_validity::TransactionValidityError,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::Config;
|
|
||||||
|
|
||||||
/// Extra type.
|
|
||||||
// pub type Extra<T> = <<T as Config>::Extra as SignedExtra<T>>::Extra;
|
|
||||||
|
|
||||||
/// SignedExtra checks copied from substrate, in order to remove requirement to implement
|
|
||||||
/// substrate's `frame_system::Trait`
|
|
||||||
|
|
||||||
/// Ensure the runtime version registered in the transaction is the same as at present.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// This is modified from the substrate version to allow passing in of the version, which is
|
|
||||||
/// returned via `additional_signed()`.
|
|
||||||
|
|
||||||
/// Ensure the runtime version registered in the transaction is the same as at present.
|
|
||||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
|
||||||
#[derivative(
|
|
||||||
Clone(bound = ""),
|
|
||||||
PartialEq(bound = ""),
|
|
||||||
Debug(bound = ""),
|
|
||||||
Eq(bound = "")
|
|
||||||
)]
|
|
||||||
#[scale_info(skip_type_params(T))]
|
|
||||||
pub struct CheckSpecVersion<T: Config>(
|
|
||||||
pub PhantomDataSendSync<T>,
|
|
||||||
/// Local version to be used for `AdditionalSigned`
|
|
||||||
#[codec(skip)]
|
|
||||||
pub u32,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<T: Config> SignedExtension for CheckSpecVersion<T> {
|
|
||||||
const IDENTIFIER: &'static str = "CheckSpecVersion";
|
|
||||||
type AccountId = T::AccountId;
|
|
||||||
type Call = ();
|
|
||||||
type AdditionalSigned = u32;
|
|
||||||
type Pre = ();
|
|
||||||
fn additional_signed(
|
|
||||||
&self,
|
|
||||||
) -> Result<Self::AdditionalSigned, TransactionValidityError> {
|
|
||||||
Ok(self.1)
|
|
||||||
}
|
|
||||||
fn pre_dispatch(
|
|
||||||
self,
|
|
||||||
_who: &Self::AccountId,
|
|
||||||
_call: &Self::Call,
|
|
||||||
_info: &DispatchInfoOf<Self::Call>,
|
|
||||||
_len: usize,
|
|
||||||
) -> Result<Self::Pre, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ensure the transaction version registered in the transaction is the same as at present.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// This is modified from the substrate version to allow passing in of the version, which is
|
|
||||||
/// returned via `additional_signed()`.
|
|
||||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
|
||||||
#[derivative(
|
|
||||||
Clone(bound = ""),
|
|
||||||
PartialEq(bound = ""),
|
|
||||||
Debug(bound = ""),
|
|
||||||
Eq(bound = "")
|
|
||||||
)]
|
|
||||||
#[scale_info(skip_type_params(T))]
|
|
||||||
pub struct CheckTxVersion<T: Config>(
|
|
||||||
pub PhantomDataSendSync<T>,
|
|
||||||
/// Local version to be used for `AdditionalSigned`
|
|
||||||
#[codec(skip)]
|
|
||||||
pub u32,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<T: Config> SignedExtension for CheckTxVersion<T> {
|
|
||||||
const IDENTIFIER: &'static str = "CheckTxVersion";
|
|
||||||
type AccountId = T::AccountId;
|
|
||||||
type Call = ();
|
|
||||||
type AdditionalSigned = u32;
|
|
||||||
type Pre = ();
|
|
||||||
fn additional_signed(
|
|
||||||
&self,
|
|
||||||
) -> Result<Self::AdditionalSigned, TransactionValidityError> {
|
|
||||||
Ok(self.1)
|
|
||||||
}
|
|
||||||
fn pre_dispatch(
|
|
||||||
self,
|
|
||||||
_who: &Self::AccountId,
|
|
||||||
_call: &Self::Call,
|
|
||||||
_info: &DispatchInfoOf<Self::Call>,
|
|
||||||
_len: usize,
|
|
||||||
) -> Result<Self::Pre, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check genesis hash
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// This is modified from the substrate version to allow passing in of the genesis hash, which is
|
|
||||||
/// returned via `additional_signed()`.
|
|
||||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
|
||||||
#[derivative(
|
|
||||||
Clone(bound = ""),
|
|
||||||
PartialEq(bound = ""),
|
|
||||||
Debug(bound = ""),
|
|
||||||
Eq(bound = "")
|
|
||||||
)]
|
|
||||||
#[scale_info(skip_type_params(T))]
|
|
||||||
pub struct CheckGenesis<T: Config>(
|
|
||||||
pub PhantomDataSendSync<T>,
|
|
||||||
/// Local genesis hash to be used for `AdditionalSigned`
|
|
||||||
#[codec(skip)]
|
|
||||||
pub T::Hash,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<T: Config> SignedExtension for CheckGenesis<T> {
|
|
||||||
const IDENTIFIER: &'static str = "CheckGenesis";
|
|
||||||
type AccountId = T::AccountId;
|
|
||||||
type Call = ();
|
|
||||||
type AdditionalSigned = T::Hash;
|
|
||||||
type Pre = ();
|
|
||||||
fn additional_signed(
|
|
||||||
&self,
|
|
||||||
) -> Result<Self::AdditionalSigned, TransactionValidityError> {
|
|
||||||
Ok(self.1)
|
|
||||||
}
|
|
||||||
fn pre_dispatch(
|
|
||||||
self,
|
|
||||||
_who: &Self::AccountId,
|
|
||||||
_call: &Self::Call,
|
|
||||||
_info: &DispatchInfoOf<Self::Call>,
|
|
||||||
_len: usize,
|
|
||||||
) -> Result<Self::Pre, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check for transaction mortality.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// This is modified from the substrate version to allow passing in of the genesis hash, which is
|
|
||||||
/// returned via `additional_signed()`. It assumes therefore `Era::Immortal` (The transaction is
|
|
||||||
/// valid forever)
|
|
||||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
|
||||||
#[derivative(
|
|
||||||
Clone(bound = ""),
|
|
||||||
PartialEq(bound = ""),
|
|
||||||
Debug(bound = ""),
|
|
||||||
Eq(bound = "")
|
|
||||||
)]
|
|
||||||
#[scale_info(skip_type_params(T))]
|
|
||||||
pub struct CheckMortality<T: Config>(
|
|
||||||
/// The default structure for the Extra encoding
|
|
||||||
pub (Era, PhantomDataSendSync<T>),
|
|
||||||
/// Local genesis hash to be used for `AdditionalSigned`
|
|
||||||
#[codec(skip)]
|
|
||||||
pub T::Hash,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<T: Config> SignedExtension for CheckMortality<T> {
|
|
||||||
const IDENTIFIER: &'static str = "CheckMortality";
|
|
||||||
type AccountId = T::AccountId;
|
|
||||||
type Call = ();
|
|
||||||
type AdditionalSigned = T::Hash;
|
|
||||||
type Pre = ();
|
|
||||||
fn additional_signed(
|
|
||||||
&self,
|
|
||||||
) -> Result<Self::AdditionalSigned, TransactionValidityError> {
|
|
||||||
Ok(self.1)
|
|
||||||
}
|
|
||||||
fn pre_dispatch(
|
|
||||||
self,
|
|
||||||
_who: &Self::AccountId,
|
|
||||||
_call: &Self::Call,
|
|
||||||
_info: &DispatchInfoOf<Self::Call>,
|
|
||||||
_len: usize,
|
|
||||||
) -> Result<Self::Pre, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Nonce check and increment to give replay protection for transactions.
|
|
||||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
|
||||||
#[derivative(
|
|
||||||
Clone(bound = ""),
|
|
||||||
PartialEq(bound = ""),
|
|
||||||
Debug(bound = ""),
|
|
||||||
Eq(bound = "")
|
|
||||||
)]
|
|
||||||
#[scale_info(skip_type_params(T))]
|
|
||||||
pub struct CheckNonce<T: Config>(#[codec(compact)] pub T::Index);
|
|
||||||
|
|
||||||
impl<T: Config> SignedExtension for CheckNonce<T> {
|
|
||||||
const IDENTIFIER: &'static str = "CheckNonce";
|
|
||||||
type AccountId = T::AccountId;
|
|
||||||
type Call = ();
|
|
||||||
type AdditionalSigned = ();
|
|
||||||
type Pre = ();
|
|
||||||
fn additional_signed(
|
|
||||||
&self,
|
|
||||||
) -> Result<Self::AdditionalSigned, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn pre_dispatch(
|
|
||||||
self,
|
|
||||||
_who: &Self::AccountId,
|
|
||||||
_call: &Self::Call,
|
|
||||||
_info: &DispatchInfoOf<Self::Call>,
|
|
||||||
_len: usize,
|
|
||||||
) -> Result<Self::Pre, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resource limit check.
|
|
||||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
|
||||||
#[derivative(
|
|
||||||
Clone(bound = ""),
|
|
||||||
PartialEq(bound = ""),
|
|
||||||
Debug(bound = ""),
|
|
||||||
Eq(bound = "")
|
|
||||||
)]
|
|
||||||
#[scale_info(skip_type_params(T))]
|
|
||||||
pub struct CheckWeight<T: Config>(pub PhantomDataSendSync<T>);
|
|
||||||
|
|
||||||
impl<T: Config> SignedExtension for CheckWeight<T> {
|
|
||||||
const IDENTIFIER: &'static str = "CheckWeight";
|
|
||||||
type AccountId = T::AccountId;
|
|
||||||
type Call = ();
|
|
||||||
type AdditionalSigned = ();
|
|
||||||
type Pre = ();
|
|
||||||
fn additional_signed(
|
|
||||||
&self,
|
|
||||||
) -> Result<Self::AdditionalSigned, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn pre_dispatch(
|
|
||||||
self,
|
|
||||||
_who: &Self::AccountId,
|
|
||||||
_call: &Self::Call,
|
|
||||||
_info: &DispatchInfoOf<Self::Call>,
|
|
||||||
_len: usize,
|
|
||||||
) -> Result<Self::Pre, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Require the transactor pay for themselves and maybe include a tip to gain additional priority
|
|
||||||
/// in the queue.
|
|
||||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
|
||||||
#[derivative(
|
|
||||||
Clone(bound = ""),
|
|
||||||
PartialEq(bound = ""),
|
|
||||||
Debug(bound = ""),
|
|
||||||
Eq(bound = ""),
|
|
||||||
Default(bound = "")
|
|
||||||
)]
|
|
||||||
#[scale_info(skip_type_params(T))]
|
|
||||||
pub struct ChargeTransactionPayment<T: Config>(
|
|
||||||
#[codec(compact)] u128,
|
|
||||||
pub PhantomDataSendSync<T>,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<T: Config> SignedExtension for ChargeTransactionPayment<T> {
|
|
||||||
const IDENTIFIER: &'static str = "ChargeTransactionPayment";
|
|
||||||
type AccountId = T::AccountId;
|
|
||||||
type Call = ();
|
|
||||||
type AdditionalSigned = ();
|
|
||||||
type Pre = ();
|
|
||||||
fn additional_signed(
|
|
||||||
&self,
|
|
||||||
) -> Result<Self::AdditionalSigned, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn pre_dispatch(
|
|
||||||
self,
|
|
||||||
_who: &Self::AccountId,
|
|
||||||
_call: &Self::Call,
|
|
||||||
_info: &DispatchInfoOf<Self::Call>,
|
|
||||||
_len: usize,
|
|
||||||
) -> Result<Self::Pre, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Require the transactor pay for themselves and maybe include a tip to gain additional priority
|
|
||||||
/// in the queue.
|
|
||||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
|
||||||
#[derivative(
|
|
||||||
Clone(bound = ""),
|
|
||||||
PartialEq(bound = ""),
|
|
||||||
Debug(bound = ""),
|
|
||||||
Eq(bound = ""),
|
|
||||||
Default(bound = "")
|
|
||||||
)]
|
|
||||||
#[scale_info(skip_type_params(T))]
|
|
||||||
pub struct ChargeAssetTxPayment<T: Config> {
|
|
||||||
/// The tip for the block author.
|
|
||||||
#[codec(compact)]
|
|
||||||
pub tip: u128,
|
|
||||||
/// The asset with which to pay the tip.
|
|
||||||
pub asset_id: Option<u32>,
|
|
||||||
/// Marker for unused type parameter.
|
|
||||||
pub marker: PhantomDataSendSync<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Config> SignedExtension for ChargeAssetTxPayment<T> {
|
|
||||||
const IDENTIFIER: &'static str = "ChargeAssetTxPayment";
|
|
||||||
type AccountId = T::AccountId;
|
|
||||||
type Call = ();
|
|
||||||
type AdditionalSigned = ();
|
|
||||||
type Pre = ();
|
|
||||||
fn additional_signed(
|
|
||||||
&self,
|
|
||||||
) -> Result<Self::AdditionalSigned, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn pre_dispatch(
|
|
||||||
self,
|
|
||||||
_who: &Self::AccountId,
|
|
||||||
_call: &Self::Call,
|
|
||||||
_info: &DispatchInfoOf<Self::Call>,
|
|
||||||
_len: usize,
|
|
||||||
) -> Result<Self::Pre, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait for implementing transaction extras for a runtime.
|
|
||||||
pub trait SignedExtra<T: Config>: SignedExtension {
|
|
||||||
/// The type the extras.
|
|
||||||
type Extra: SignedExtension + Send + Sync;
|
|
||||||
/// The additional config parameters.
|
|
||||||
type Parameters: Default + Send + Sync;
|
|
||||||
|
|
||||||
/// Creates a new `SignedExtra`.
|
|
||||||
fn new(
|
|
||||||
spec_version: u32,
|
|
||||||
tx_version: u32,
|
|
||||||
nonce: T::Index,
|
|
||||||
genesis_hash: T::Hash,
|
|
||||||
additional_params: Self::Parameters,
|
|
||||||
) -> Self;
|
|
||||||
|
|
||||||
/// Returns the transaction extra.
|
|
||||||
fn extra(&self) -> Self::Extra;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Default `SignedExtra` for substrate runtimes.
|
|
||||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
|
||||||
#[derivative(
|
|
||||||
Clone(bound = ""),
|
|
||||||
PartialEq(bound = ""),
|
|
||||||
Debug(bound = ""),
|
|
||||||
Eq(bound = "")
|
|
||||||
)]
|
|
||||||
#[scale_info(skip_type_params(T))]
|
|
||||||
pub struct DefaultExtraWithTxPayment<T: Config, X> {
|
|
||||||
spec_version: u32,
|
|
||||||
tx_version: u32,
|
|
||||||
nonce: T::Index,
|
|
||||||
genesis_hash: T::Hash,
|
|
||||||
marker: PhantomDataSendSync<X>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, X> SignedExtra<T> for DefaultExtraWithTxPayment<T, X>
|
|
||||||
where
|
|
||||||
T: Config,
|
|
||||||
X: SignedExtension<AccountId = T::AccountId, Call = ()> + Default,
|
|
||||||
{
|
|
||||||
type Extra = (
|
|
||||||
CheckSpecVersion<T>,
|
|
||||||
CheckTxVersion<T>,
|
|
||||||
CheckGenesis<T>,
|
|
||||||
CheckMortality<T>,
|
|
||||||
CheckNonce<T>,
|
|
||||||
CheckWeight<T>,
|
|
||||||
X,
|
|
||||||
);
|
|
||||||
type Parameters = ();
|
|
||||||
|
|
||||||
fn new(
|
|
||||||
spec_version: u32,
|
|
||||||
tx_version: u32,
|
|
||||||
nonce: T::Index,
|
|
||||||
genesis_hash: T::Hash,
|
|
||||||
_params: Self::Parameters,
|
|
||||||
) -> Self {
|
|
||||||
DefaultExtraWithTxPayment {
|
|
||||||
spec_version,
|
|
||||||
tx_version,
|
|
||||||
nonce,
|
|
||||||
genesis_hash,
|
|
||||||
marker: PhantomDataSendSync::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extra(&self) -> Self::Extra {
|
|
||||||
(
|
|
||||||
CheckSpecVersion(PhantomDataSendSync::new(), self.spec_version),
|
|
||||||
CheckTxVersion(PhantomDataSendSync::new(), self.tx_version),
|
|
||||||
CheckGenesis(PhantomDataSendSync::new(), self.genesis_hash),
|
|
||||||
CheckMortality(
|
|
||||||
(Era::Immortal, PhantomDataSendSync::new()),
|
|
||||||
self.genesis_hash,
|
|
||||||
),
|
|
||||||
CheckNonce(self.nonce),
|
|
||||||
CheckWeight(PhantomDataSendSync::new()),
|
|
||||||
X::default(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, X: SignedExtension<AccountId = T::AccountId, Call = ()> + Default> SignedExtension
|
|
||||||
for DefaultExtraWithTxPayment<T, X>
|
|
||||||
where
|
|
||||||
T: Config,
|
|
||||||
X: SignedExtension,
|
|
||||||
{
|
|
||||||
const IDENTIFIER: &'static str = "DefaultExtra";
|
|
||||||
type AccountId = T::AccountId;
|
|
||||||
type Call = ();
|
|
||||||
type AdditionalSigned =
|
|
||||||
<<Self as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned;
|
|
||||||
type Pre = ();
|
|
||||||
|
|
||||||
fn additional_signed(
|
|
||||||
&self,
|
|
||||||
) -> Result<Self::AdditionalSigned, TransactionValidityError> {
|
|
||||||
self.extra().additional_signed()
|
|
||||||
}
|
|
||||||
fn pre_dispatch(
|
|
||||||
self,
|
|
||||||
_who: &Self::AccountId,
|
|
||||||
_call: &Self::Call,
|
|
||||||
_info: &DispatchInfoOf<Self::Call>,
|
|
||||||
_len: usize,
|
|
||||||
) -> Result<Self::Pre, TransactionValidityError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A default `SignedExtra` configuration, with [`ChargeTransactionPayment`] for tipping.
|
|
||||||
///
|
|
||||||
/// Note that this must match the `SignedExtra` type in the target runtime's extrinsic definition.
|
|
||||||
pub type DefaultExtra<T> = DefaultExtraWithTxPayment<T, ChargeTransactionPayment<T>>;
|
|
||||||
+10
-62
@@ -16,74 +16,22 @@
|
|||||||
|
|
||||||
//! Create signed or unsigned extrinsics.
|
//! Create signed or unsigned extrinsics.
|
||||||
|
|
||||||
mod extra;
|
mod params;
|
||||||
mod signer;
|
mod signer;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
extra::{
|
params::{
|
||||||
ChargeAssetTxPayment,
|
AssetTip,
|
||||||
ChargeTransactionPayment,
|
Era,
|
||||||
CheckGenesis,
|
ExtrinsicParams,
|
||||||
CheckMortality,
|
PlainTip,
|
||||||
CheckNonce,
|
PolkadotExtrinsicParams,
|
||||||
CheckSpecVersion,
|
PolkadotExtrinsicParamsBuilder,
|
||||||
CheckTxVersion,
|
SubstrateExtrinsicParams,
|
||||||
CheckWeight,
|
SubstrateExtrinsicParamsBuilder,
|
||||||
DefaultExtra,
|
|
||||||
DefaultExtraWithTxPayment,
|
|
||||||
SignedExtra,
|
|
||||||
},
|
},
|
||||||
signer::{
|
signer::{
|
||||||
PairSigner,
|
PairSigner,
|
||||||
Signer,
|
Signer,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use sp_runtime::traits::SignedExtension;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
error::BasicError,
|
|
||||||
rpc::RuntimeVersion,
|
|
||||||
Config,
|
|
||||||
Encoded,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// UncheckedExtrinsic type.
|
|
||||||
pub type UncheckedExtrinsic<T, X> = sp_runtime::generic::UncheckedExtrinsic<
|
|
||||||
<T as Config>::Address,
|
|
||||||
Encoded,
|
|
||||||
<T as Config>::Signature,
|
|
||||||
<X as SignedExtra<T>>::Extra,
|
|
||||||
>;
|
|
||||||
|
|
||||||
/// SignedPayload type.
|
|
||||||
pub type SignedPayload<T, X> =
|
|
||||||
sp_runtime::generic::SignedPayload<Encoded, <X as SignedExtra<T>>::Extra>;
|
|
||||||
|
|
||||||
/// Creates a signed extrinsic
|
|
||||||
pub async fn create_signed<T, X>(
|
|
||||||
runtime_version: &RuntimeVersion,
|
|
||||||
genesis_hash: T::Hash,
|
|
||||||
nonce: T::Index,
|
|
||||||
call: Encoded,
|
|
||||||
signer: &(dyn Signer<T, X> + Send + Sync),
|
|
||||||
additional_params: X::Parameters,
|
|
||||||
) -> Result<UncheckedExtrinsic<T, X>, BasicError>
|
|
||||||
where
|
|
||||||
T: Config,
|
|
||||||
X: SignedExtra<T>,
|
|
||||||
<X::Extra as SignedExtension>::AdditionalSigned: Send + Sync,
|
|
||||||
{
|
|
||||||
let spec_version = runtime_version.spec_version;
|
|
||||||
let tx_version = runtime_version.transaction_version;
|
|
||||||
let extra = X::new(
|
|
||||||
spec_version,
|
|
||||||
tx_version,
|
|
||||||
nonce,
|
|
||||||
genesis_hash,
|
|
||||||
additional_params,
|
|
||||||
);
|
|
||||||
let payload = SignedPayload::<T, X>::new(call, extra.extra())?;
|
|
||||||
let signed = signer.sign(payload).await?;
|
|
||||||
Ok(signed)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,237 @@
|
|||||||
|
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of subxt.
|
||||||
|
//
|
||||||
|
// subxt is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// subxt is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use codec::{
|
||||||
|
Compact,
|
||||||
|
Encode,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Config,
|
||||||
|
Encoded,
|
||||||
|
};
|
||||||
|
|
||||||
|
// We require Era as a param below, so make it available from here.
|
||||||
|
pub use sp_runtime::generic::Era;
|
||||||
|
|
||||||
|
/// This trait allows you to configure the "signed extra" and
|
||||||
|
/// "additional" parameters that are signed and used in transactions.
|
||||||
|
/// see [`BaseExtrinsicParams`] for an implementation that is compatible with
|
||||||
|
/// a Polkadot node.
|
||||||
|
pub trait ExtrinsicParams<T: Config> {
|
||||||
|
/// These parameters can be provided to the constructor along with
|
||||||
|
/// some default parameters that `subxt` understands, in order to
|
||||||
|
/// help construct your [`ExtrinsicParams`] object.
|
||||||
|
type OtherParams;
|
||||||
|
|
||||||
|
/// Construct a new instance of our [`ExtrinsicParams`]
|
||||||
|
fn new(
|
||||||
|
spec_version: u32,
|
||||||
|
tx_version: u32,
|
||||||
|
nonce: T::Index,
|
||||||
|
genesis_hash: T::Hash,
|
||||||
|
other_params: Self::OtherParams,
|
||||||
|
) -> Self;
|
||||||
|
|
||||||
|
/// This is expected to SCALE encode the "signed extra" parameters
|
||||||
|
/// to some buffer that has been provided. These are the parameters
|
||||||
|
/// which are sent along with the transaction, as well as taken into
|
||||||
|
/// account when signing the transaction.
|
||||||
|
fn encode_extra_to(&self, v: &mut Vec<u8>);
|
||||||
|
|
||||||
|
/// This is expected to SCALE encode the "additional" parameters
|
||||||
|
/// to some buffer that has been provided. These parameters are _not_
|
||||||
|
/// sent along with the transaction, but are taken into account when
|
||||||
|
/// signing it, meaning the client and node must agree on their values.
|
||||||
|
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
|
||||||
|
/// differs between Substrate and Polkadot nodes, and so we are generic over that in
|
||||||
|
/// order to support both here with relative ease.
|
||||||
|
///
|
||||||
|
/// If your node differs in the "signed extra" and "additional" parameters expected
|
||||||
|
/// to be sent/signed with a transaction, then you can define your own type which
|
||||||
|
/// implements the [`ExtrinsicParams`] trait.
|
||||||
|
pub struct BaseExtrinsicParams<T: Config, Tip> {
|
||||||
|
era: Era,
|
||||||
|
nonce: T::Index,
|
||||||
|
tip: Tip,
|
||||||
|
spec_version: u32,
|
||||||
|
transaction_version: u32,
|
||||||
|
genesis_hash: T::Hash,
|
||||||
|
mortality_checkpoint: T::Hash,
|
||||||
|
marker: std::marker::PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This builder allows you to provide the parameters that can be configured in order to
|
||||||
|
/// 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.
|
||||||
|
pub struct BaseExtrinsicParamsBuilder<T: Config, Tip> {
|
||||||
|
era: Era,
|
||||||
|
mortality_checkpoint: Option<T::Hash>,
|
||||||
|
tip: Tip,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config, Tip: Default> BaseExtrinsicParamsBuilder<T, Tip> {
|
||||||
|
/// Instantiate the default set of [`BaseExtrinsicParamsBuilder`]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the [`Era`], which defines how long the transaction will be valid for
|
||||||
|
/// (it can be either immortal, or it can be mortal and expire after a certain amount
|
||||||
|
/// of time). The second argument is the block hash after which the transaction
|
||||||
|
/// becomes valid, and must align with the era phase (see the [`Era::Mortal`] docs
|
||||||
|
/// for more detail on that).
|
||||||
|
pub fn era(mut self, era: Era, checkpoint: T::Hash) -> Self {
|
||||||
|
self.era = era;
|
||||||
|
self.mortality_checkpoint = Some(checkpoint);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the tip you'd like to give to the block author
|
||||||
|
/// for this transaction.
|
||||||
|
pub fn tip(mut self, tip: impl Into<Tip>) -> Self {
|
||||||
|
self.tip = tip.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config, Tip: Default> Default for BaseExtrinsicParamsBuilder<T, Tip> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
era: Era::Immortal,
|
||||||
|
mortality_checkpoint: None,
|
||||||
|
tip: Tip::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config, Tip: Encode> ExtrinsicParams<T> for BaseExtrinsicParams<T, Tip> {
|
||||||
|
type OtherParams = BaseExtrinsicParamsBuilder<T, Tip>;
|
||||||
|
|
||||||
|
fn new(
|
||||||
|
// Provided from subxt client:
|
||||||
|
spec_version: u32,
|
||||||
|
transaction_version: u32,
|
||||||
|
nonce: T::Index,
|
||||||
|
genesis_hash: T::Hash,
|
||||||
|
// Provided externally:
|
||||||
|
other_params: Self::OtherParams,
|
||||||
|
) -> Self {
|
||||||
|
BaseExtrinsicParams {
|
||||||
|
era: other_params.era,
|
||||||
|
mortality_checkpoint: other_params
|
||||||
|
.mortality_checkpoint
|
||||||
|
.unwrap_or(genesis_hash),
|
||||||
|
tip: other_params.tip,
|
||||||
|
nonce,
|
||||||
|
spec_version,
|
||||||
|
transaction_version,
|
||||||
|
genesis_hash,
|
||||||
|
marker: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_extra_to(&self, v: &mut Vec<u8>) {
|
||||||
|
let nonce: u64 = self.nonce.into();
|
||||||
|
let tip = Encoded(self.tip.encode());
|
||||||
|
(self.era, Compact(nonce), tip).encode_to(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_additional_to(&self, v: &mut Vec<u8>) {
|
||||||
|
(
|
||||||
|
self.spec_version,
|
||||||
|
self.transaction_version,
|
||||||
|
self.genesis_hash,
|
||||||
|
self.mortality_checkpoint,
|
||||||
|
)
|
||||||
|
.encode_to(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A tip payment.
|
||||||
|
#[derive(Copy, Clone, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A tip payment made in the form of a specific asset.
|
||||||
|
#[derive(Copy, Clone, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,58 +17,51 @@
|
|||||||
//! A library to **sub**mit e**xt**rinsics to a
|
//! A library to **sub**mit e**xt**rinsics to a
|
||||||
//! [substrate](https://github.com/paritytech/substrate) node via RPC.
|
//! [substrate](https://github.com/paritytech/substrate) node via RPC.
|
||||||
|
|
||||||
use super::{
|
|
||||||
SignedExtra,
|
|
||||||
SignedPayload,
|
|
||||||
UncheckedExtrinsic,
|
|
||||||
};
|
|
||||||
use crate::Config;
|
use crate::Config;
|
||||||
use codec::Encode;
|
|
||||||
use sp_core::Pair;
|
use sp_core::Pair;
|
||||||
use sp_runtime::traits::{
|
use sp_runtime::traits::{
|
||||||
IdentifyAccount,
|
IdentifyAccount,
|
||||||
SignedExtension,
|
|
||||||
Verify,
|
Verify,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Extrinsic signer.
|
/// Signing transactions requires a [`Signer`]. This is responsible for
|
||||||
#[async_trait::async_trait]
|
/// providing the "from" account that the transaction is being signed by,
|
||||||
pub trait Signer<T: Config, E: SignedExtra<T>> {
|
/// as well as actually signing a SCALE encoded payload. Optionally, a
|
||||||
/// Returns the account id.
|
/// signer can also provide the nonce for the transaction to use.
|
||||||
fn account_id(&self) -> &T::AccountId;
|
pub trait Signer<T: Config> {
|
||||||
|
|
||||||
/// Optionally returns a nonce.
|
/// Optionally returns a nonce.
|
||||||
fn nonce(&self) -> Option<T::Index>;
|
fn nonce(&self) -> Option<T::Index>;
|
||||||
|
|
||||||
/// Takes an unsigned extrinsic and returns a signed extrinsic.
|
/// Return the "from" account ID.
|
||||||
|
fn account_id(&self) -> &T::AccountId;
|
||||||
|
|
||||||
|
/// Return the "from" address.
|
||||||
|
fn address(&self) -> T::Address;
|
||||||
|
|
||||||
|
/// Takes a signer payload for an extrinsic, and returns a signature based on it.
|
||||||
///
|
///
|
||||||
/// Some signers may fail, for instance because the hardware on which the keys are located has
|
/// Some signers may fail, for instance because the hardware on which the keys are located has
|
||||||
/// refused the operation.
|
/// refused the operation.
|
||||||
async fn sign(
|
fn sign(&self, signer_payload: &[u8]) -> T::Signature;
|
||||||
&self,
|
|
||||||
extrinsic: SignedPayload<T, E>,
|
|
||||||
) -> Result<UncheckedExtrinsic<T, E>, String>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extrinsic signer using a private key.
|
/// A [`Signer`] implementation that can be constructed from an [`Pair`].
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PairSigner<T: Config, E, P: Pair> {
|
pub struct PairSigner<T: Config, P: Pair> {
|
||||||
account_id: T::AccountId,
|
account_id: T::AccountId,
|
||||||
nonce: Option<T::Index>,
|
nonce: Option<T::Index>,
|
||||||
signer: P,
|
signer: P,
|
||||||
marker: std::marker::PhantomData<E>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, E, P> PairSigner<T, E, P>
|
impl<T, P> PairSigner<T, P>
|
||||||
where
|
where
|
||||||
T: Config,
|
T: Config,
|
||||||
E: SignedExtra<T>,
|
|
||||||
T::Signature: From<P::Signature>,
|
T::Signature: From<P::Signature>,
|
||||||
<T::Signature as Verify>::Signer:
|
<T::Signature as Verify>::Signer:
|
||||||
From<P::Public> + IdentifyAccount<AccountId = T::AccountId>,
|
From<P::Public> + IdentifyAccount<AccountId = T::AccountId>,
|
||||||
P: Pair,
|
P: Pair,
|
||||||
{
|
{
|
||||||
/// Creates a new `Signer` from a `Pair`.
|
/// Creates a new [`Signer`] from a [`Pair`].
|
||||||
pub fn new(signer: P) -> Self {
|
pub fn new(signer: P) -> Self {
|
||||||
let account_id =
|
let account_id =
|
||||||
<T::Signature as Verify>::Signer::from(signer.public()).into_account();
|
<T::Signature as Verify>::Signer::from(signer.public()).into_account();
|
||||||
@@ -76,11 +69,11 @@ where
|
|||||||
account_id,
|
account_id,
|
||||||
nonce: None,
|
nonce: None,
|
||||||
signer,
|
signer,
|
||||||
marker: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the nonce to a new value.
|
/// Sets the nonce to a new value. By default, the nonce will
|
||||||
|
/// be retrieved from the node. Setting one here will override that.
|
||||||
pub fn set_nonce(&mut self, nonce: T::Index) {
|
pub fn set_nonce(&mut self, nonce: T::Index) {
|
||||||
self.nonce = Some(nonce);
|
self.nonce = Some(nonce);
|
||||||
}
|
}
|
||||||
@@ -90,43 +83,37 @@ where
|
|||||||
self.nonce = self.nonce.map(|nonce| nonce + 1u32.into());
|
self.nonce = self.nonce.map(|nonce| nonce + 1u32.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the signer.
|
/// Returns the [`Pair`] implementation used to construct this.
|
||||||
pub fn signer(&self) -> &P {
|
pub fn signer(&self) -> &P {
|
||||||
&self.signer
|
&self.signer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the account ID.
|
||||||
|
pub fn account_id(&self) -> &T::AccountId {
|
||||||
|
&self.account_id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
impl<T, P> Signer<T> for PairSigner<T, P>
|
||||||
impl<T, E, P> Signer<T, E> for PairSigner<T, E, P>
|
|
||||||
where
|
where
|
||||||
T: Config,
|
T: Config,
|
||||||
E: SignedExtra<T>,
|
T::AccountId: Into<T::Address> + Clone + 'static,
|
||||||
T::AccountId: Into<T::Address> + 'static,
|
|
||||||
<<E as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
|
||||||
Send + Sync + 'static,
|
|
||||||
P: Pair + 'static,
|
P: Pair + 'static,
|
||||||
P::Signature: Into<T::Signature> + 'static,
|
P::Signature: Into<T::Signature> + 'static,
|
||||||
{
|
{
|
||||||
fn account_id(&self) -> &T::AccountId {
|
|
||||||
&self.account_id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nonce(&self) -> Option<T::Index> {
|
fn nonce(&self) -> Option<T::Index> {
|
||||||
self.nonce
|
self.nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn sign(
|
fn account_id(&self) -> &T::AccountId {
|
||||||
&self,
|
&self.account_id
|
||||||
extrinsic: SignedPayload<T, E>,
|
}
|
||||||
) -> Result<UncheckedExtrinsic<T, E>, String> {
|
|
||||||
let signature = extrinsic.using_encoded(|payload| self.signer.sign(payload));
|
fn address(&self) -> T::Address {
|
||||||
let (call, extra, _) = extrinsic.deconstruct();
|
self.account_id.clone().into()
|
||||||
let extrinsic = UncheckedExtrinsic::<T, E>::new_signed(
|
}
|
||||||
call,
|
|
||||||
self.account_id.clone().into(),
|
fn sign(&self, signer_payload: &[u8]) -> T::Signature {
|
||||||
signature.into(),
|
self.signer.sign(signer_payload).into()
|
||||||
extra,
|
|
||||||
);
|
|
||||||
Ok(extrinsic)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-5
@@ -90,12 +90,11 @@ pub use crate::{
|
|||||||
RawEventDetails,
|
RawEventDetails,
|
||||||
},
|
},
|
||||||
extrinsic::{
|
extrinsic::{
|
||||||
DefaultExtra,
|
|
||||||
DefaultExtraWithTxPayment,
|
|
||||||
PairSigner,
|
PairSigner,
|
||||||
SignedExtra,
|
PolkadotExtrinsicParams,
|
||||||
Signer,
|
PolkadotExtrinsicParamsBuilder,
|
||||||
UncheckedExtrinsic,
|
SubstrateExtrinsicParams,
|
||||||
|
SubstrateExtrinsicParamsBuilder,
|
||||||
},
|
},
|
||||||
metadata::{
|
metadata::{
|
||||||
ErrorMetadata,
|
ErrorMetadata,
|
||||||
|
|||||||
+11
-10
@@ -30,10 +30,7 @@ use frame_metadata::{
|
|||||||
META_RESERVED,
|
META_RESERVED,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::Call;
|
||||||
Call,
|
|
||||||
Encoded,
|
|
||||||
};
|
|
||||||
use scale_info::{
|
use scale_info::{
|
||||||
form::PortableForm,
|
form::PortableForm,
|
||||||
Type,
|
Type,
|
||||||
@@ -148,18 +145,22 @@ impl PalletMetadata {
|
|||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encode a call based on this pallet metadata.
|
/// Get the index of this pallet.
|
||||||
pub fn encode_call<C>(&self, call: &C) -> Result<Encoded, MetadataError>
|
pub fn index(&self) -> u8 {
|
||||||
|
self.index
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempt to resolve a call into an index in this pallet, failing
|
||||||
|
/// if the call is not found in this pallet.
|
||||||
|
pub fn call_index<C>(&self) -> Result<u8, MetadataError>
|
||||||
where
|
where
|
||||||
C: Call,
|
C: Call,
|
||||||
{
|
{
|
||||||
let fn_index = self
|
let fn_index = *self
|
||||||
.calls
|
.calls
|
||||||
.get(C::FUNCTION)
|
.get(C::FUNCTION)
|
||||||
.ok_or(MetadataError::CallNotFound(C::FUNCTION))?;
|
.ok_or(MetadataError::CallNotFound(C::FUNCTION))?;
|
||||||
let mut bytes = vec![self.index, *fn_index];
|
Ok(fn_index)
|
||||||
bytes.extend(call.encode());
|
|
||||||
Ok(Encoded(bytes))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return [`StorageEntryMetadata`] given some storage key.
|
/// Return [`StorageEntryMetadata`] given some storage key.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use sp_keyring::AccountKeyring;
|
use sp_keyring::AccountKeyring;
|
||||||
use subxt::Signer;
|
|
||||||
|
|
||||||
// Check that we can subscribe to non-finalized block events.
|
// Check that we can subscribe to non-finalized block events.
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
@@ -118,7 +117,7 @@ async fn balance_transfer_subscription() -> Result<(), subxt::BasicError> {
|
|||||||
.tx()
|
.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(bob.clone().into(), 10_000)
|
.transfer(bob.clone().into(), 10_000)
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Wait for the next balance transfer event in our subscription stream
|
// Wait for the next balance transfer event in our subscription stream
|
||||||
|
|||||||
@@ -34,10 +34,7 @@ use sp_runtime::{
|
|||||||
AccountId32,
|
AccountId32,
|
||||||
MultiAddress,
|
MultiAddress,
|
||||||
};
|
};
|
||||||
use subxt::{
|
use subxt::Error;
|
||||||
Error,
|
|
||||||
Signer,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
async fn tx_basic_transfer() -> Result<(), subxt::Error<DispatchError>> {
|
async fn tx_basic_transfer() -> Result<(), subxt::Error<DispatchError>> {
|
||||||
@@ -62,7 +59,7 @@ async fn tx_basic_transfer() -> Result<(), subxt::Error<DispatchError>> {
|
|||||||
.tx()
|
.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(bob_address, 10_000)
|
.transfer(bob_address, 10_000)
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?;
|
.await?;
|
||||||
@@ -118,7 +115,7 @@ async fn multiple_transfers_work_nonce_incremented(
|
|||||||
.tx()
|
.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(bob_address.clone(), 10_000)
|
.transfer(bob_address.clone(), 10_000)
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_in_block() // Don't need to wait for finalization; this is quicker.
|
.wait_for_in_block() // Don't need to wait for finalization; this is quicker.
|
||||||
.await?
|
.await?
|
||||||
@@ -163,7 +160,7 @@ async fn storage_balance_lock() -> Result<(), subxt::Error<DispatchError>> {
|
|||||||
100_000_000_000_000,
|
100_000_000_000_000,
|
||||||
runtime_types::pallet_staking::RewardDestination::Stash,
|
runtime_types::pallet_staking::RewardDestination::Stash,
|
||||||
)
|
)
|
||||||
.sign_and_submit_then_watch(&bob)
|
.sign_and_submit_then_watch_default(&bob)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?
|
.await?
|
||||||
@@ -203,7 +200,7 @@ async fn transfer_error() {
|
|||||||
.tx()
|
.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(hans_address, 100_000_000_000_000_000)
|
.transfer(hans_address, 100_000_000_000_000_000)
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
@@ -215,7 +212,7 @@ async fn transfer_error() {
|
|||||||
.tx()
|
.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(alice_addr, 100_000_000_000_000_000)
|
.transfer(alice_addr, 100_000_000_000_000_000)
|
||||||
.sign_and_submit_then_watch(&hans)
|
.sign_and_submit_then_watch_default(&hans)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
@@ -242,7 +239,7 @@ async fn transfer_implicit_subscription() {
|
|||||||
.tx()
|
.tx()
|
||||||
.balances()
|
.balances()
|
||||||
.transfer(bob_addr, 10_000)
|
.transfer(bob_addr, 10_000)
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ use crate::{
|
|||||||
DispatchError,
|
DispatchError,
|
||||||
},
|
},
|
||||||
test_context,
|
test_context,
|
||||||
NodeRuntimeSignedExtra,
|
NodeRuntimeParams,
|
||||||
TestContext,
|
TestContext,
|
||||||
};
|
};
|
||||||
use sp_core::sr25519::Pair;
|
use sp_core::sr25519::Pair;
|
||||||
@@ -44,7 +44,7 @@ use subxt::{
|
|||||||
|
|
||||||
struct ContractsTestContext {
|
struct ContractsTestContext {
|
||||||
cxt: TestContext,
|
cxt: TestContext,
|
||||||
signer: PairSigner<DefaultConfig, NodeRuntimeSignedExtra, Pair>,
|
signer: PairSigner<DefaultConfig, Pair>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Hash = <DefaultConfig as Config>::Hash;
|
type Hash = <DefaultConfig as Config>::Hash;
|
||||||
@@ -62,7 +62,7 @@ impl ContractsTestContext {
|
|||||||
self.cxt.client()
|
self.cxt.client()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contracts_tx(&self) -> TransactionApi<DefaultConfig, NodeRuntimeSignedExtra> {
|
fn contracts_tx(&self) -> TransactionApi<DefaultConfig, NodeRuntimeParams> {
|
||||||
self.cxt.api.tx().contracts()
|
self.cxt.api.tx().contracts()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ impl ContractsTestContext {
|
|||||||
vec![], // data
|
vec![], // data
|
||||||
vec![], // salt
|
vec![], // salt
|
||||||
)
|
)
|
||||||
.sign_and_submit_then_watch(&self.signer)
|
.sign_and_submit_then_watch_default(&self.signer)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?;
|
.await?;
|
||||||
@@ -131,7 +131,7 @@ impl ContractsTestContext {
|
|||||||
data,
|
data,
|
||||||
salt,
|
salt,
|
||||||
)
|
)
|
||||||
.sign_and_submit_then_watch(&self.signer)
|
.sign_and_submit_then_watch_default(&self.signer)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?;
|
.await?;
|
||||||
@@ -162,7 +162,7 @@ impl ContractsTestContext {
|
|||||||
None, // storage_deposit_limit
|
None, // storage_deposit_limit
|
||||||
input_data,
|
input_data,
|
||||||
)
|
)
|
||||||
.sign_and_submit_then_watch(&self.signer)
|
.sign_and_submit_then_watch_default(&self.signer)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
log::info!("Call result: {:?}", result);
|
log::info!("Call result: {:?}", result);
|
||||||
|
|||||||
@@ -32,10 +32,7 @@ use sp_core::{
|
|||||||
Pair,
|
Pair,
|
||||||
};
|
};
|
||||||
use sp_keyring::AccountKeyring;
|
use sp_keyring::AccountKeyring;
|
||||||
use subxt::{
|
use subxt::Error;
|
||||||
Error,
|
|
||||||
Signer,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Helper function to generate a crypto pair from seed
|
/// Helper function to generate a crypto pair from seed
|
||||||
fn get_from_seed(seed: &str) -> sr25519::Pair {
|
fn get_from_seed(seed: &str) -> sr25519::Pair {
|
||||||
@@ -58,7 +55,7 @@ async fn validate_with_controller_account() {
|
|||||||
.tx()
|
.tx()
|
||||||
.staking()
|
.staking()
|
||||||
.validate(default_validator_prefs())
|
.validate(default_validator_prefs())
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
@@ -75,7 +72,7 @@ async fn validate_not_possible_for_stash_account() -> Result<(), Error<DispatchE
|
|||||||
.tx()
|
.tx()
|
||||||
.staking()
|
.staking()
|
||||||
.validate(default_validator_prefs())
|
.validate(default_validator_prefs())
|
||||||
.sign_and_submit_then_watch(&alice_stash)
|
.sign_and_submit_then_watch_default(&alice_stash)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await;
|
.await;
|
||||||
@@ -96,7 +93,7 @@ async fn nominate_with_controller_account() {
|
|||||||
.tx()
|
.tx()
|
||||||
.staking()
|
.staking()
|
||||||
.nominate(vec![bob.account_id().clone().into()])
|
.nominate(vec![bob.account_id().clone().into()])
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
@@ -115,7 +112,7 @@ async fn nominate_not_possible_for_stash_account() -> Result<(), Error<DispatchE
|
|||||||
.tx()
|
.tx()
|
||||||
.staking()
|
.staking()
|
||||||
.nominate(vec![bob.account_id().clone().into()])
|
.nominate(vec![bob.account_id().clone().into()])
|
||||||
.sign_and_submit_then_watch(&alice_stash)
|
.sign_and_submit_then_watch_default(&alice_stash)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await;
|
.await;
|
||||||
@@ -139,7 +136,7 @@ async fn chill_works_for_controller_only() -> Result<(), Error<DispatchError>> {
|
|||||||
.tx()
|
.tx()
|
||||||
.staking()
|
.staking()
|
||||||
.nominate(vec![bob_stash.account_id().clone().into()])
|
.nominate(vec![bob_stash.account_id().clone().into()])
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?;
|
.await?;
|
||||||
@@ -158,7 +155,7 @@ async fn chill_works_for_controller_only() -> Result<(), Error<DispatchError>> {
|
|||||||
.tx()
|
.tx()
|
||||||
.staking()
|
.staking()
|
||||||
.chill()
|
.chill()
|
||||||
.sign_and_submit_then_watch(&alice_stash)
|
.sign_and_submit_then_watch_default(&alice_stash)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await;
|
.await;
|
||||||
@@ -173,7 +170,7 @@ async fn chill_works_for_controller_only() -> Result<(), Error<DispatchError>> {
|
|||||||
.tx()
|
.tx()
|
||||||
.staking()
|
.staking()
|
||||||
.chill()
|
.chill()
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?
|
.await?
|
||||||
@@ -197,7 +194,7 @@ async fn tx_bond() -> Result<(), Error<DispatchError>> {
|
|||||||
100_000_000_000_000,
|
100_000_000_000_000,
|
||||||
RewardDestination::Stash,
|
RewardDestination::Stash,
|
||||||
)
|
)
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await;
|
.await;
|
||||||
@@ -213,7 +210,7 @@ async fn tx_bond() -> Result<(), Error<DispatchError>> {
|
|||||||
100_000_000_000_000,
|
100_000_000_000_000,
|
||||||
RewardDestination::Stash,
|
RewardDestination::Stash,
|
||||||
)
|
)
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ async fn test_sudo() -> Result<(), subxt::Error<DispatchError>> {
|
|||||||
.tx()
|
.tx()
|
||||||
.sudo()
|
.sudo()
|
||||||
.sudo(call)
|
.sudo(call)
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?
|
.await?
|
||||||
@@ -70,7 +70,7 @@ async fn test_sudo_unchecked_weight() -> Result<(), subxt::Error<DispatchError>>
|
|||||||
.tx()
|
.tx()
|
||||||
.sudo()
|
.sudo()
|
||||||
.sudo_unchecked_weight(call, 0)
|
.sudo_unchecked_weight(call, 0)
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?
|
.await?
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use assert_matches::assert_matches;
|
use assert_matches::assert_matches;
|
||||||
use sp_keyring::AccountKeyring;
|
use sp_keyring::AccountKeyring;
|
||||||
use subxt::Signer;
|
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
async fn storage_account() -> Result<(), subxt::Error<DispatchError>> {
|
async fn storage_account() -> Result<(), subxt::Error<DispatchError>> {
|
||||||
@@ -52,7 +51,7 @@ async fn tx_remark_with_event() -> Result<(), subxt::Error<DispatchError>> {
|
|||||||
.tx()
|
.tx()
|
||||||
.system()
|
.system()
|
||||||
.remark_with_event(b"remarkable".to_vec())
|
.remark_with_event(b"remarkable".to_vec())
|
||||||
.sign_and_submit_then_watch(&alice)
|
.sign_and_submit_then_watch_default(&alice)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?
|
.await?
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ async fn storage_map_lookup() -> Result<(), subxt::Error<DispatchError>> {
|
|||||||
.tx()
|
.tx()
|
||||||
.system()
|
.system()
|
||||||
.remark(vec![1, 2, 3, 4, 5])
|
.remark(vec![1, 2, 3, 4, 5])
|
||||||
.sign_and_submit_then_watch(&signer)
|
.sign_and_submit_then_watch_default(&signer)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?;
|
.await?;
|
||||||
@@ -114,7 +114,7 @@ async fn storage_n_map_storage_lookup() -> Result<(), subxt::Error<DispatchError
|
|||||||
.tx()
|
.tx()
|
||||||
.assets()
|
.assets()
|
||||||
.create(99, alice.clone().into(), 1)
|
.create(99, alice.clone().into(), 1)
|
||||||
.sign_and_submit_then_watch(&signer)
|
.sign_and_submit_then_watch_default(&signer)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?;
|
.await?;
|
||||||
@@ -122,7 +122,7 @@ async fn storage_n_map_storage_lookup() -> Result<(), subxt::Error<DispatchError
|
|||||||
.tx()
|
.tx()
|
||||||
.assets()
|
.assets()
|
||||||
.approve_transfer(99, bob.clone().into(), 123)
|
.approve_transfer(99, bob.clone().into(), 123)
|
||||||
.sign_and_submit_then_watch(&signer)
|
.sign_and_submit_then_watch_default(&signer)
|
||||||
.await?
|
.await?
|
||||||
.wait_for_finalized_success()
|
.wait_for_finalized_success()
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
@@ -22,18 +22,16 @@ pub(crate) use crate::{
|
|||||||
use sp_core::sr25519::Pair;
|
use sp_core::sr25519::Pair;
|
||||||
use sp_keyring::AccountKeyring;
|
use sp_keyring::AccountKeyring;
|
||||||
use subxt::{
|
use subxt::{
|
||||||
extrinsic::ChargeAssetTxPayment,
|
|
||||||
Client,
|
Client,
|
||||||
DefaultConfig,
|
DefaultConfig,
|
||||||
DefaultExtraWithTxPayment,
|
|
||||||
PairSigner,
|
PairSigner,
|
||||||
|
SubstrateExtrinsicParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// substrate node should be installed on the $PATH
|
/// substrate node should be installed on the $PATH
|
||||||
const SUBSTRATE_NODE_PATH: &str = "substrate";
|
const SUBSTRATE_NODE_PATH: &str = "substrate";
|
||||||
|
|
||||||
pub type NodeRuntimeSignedExtra =
|
pub type NodeRuntimeParams = SubstrateExtrinsicParams<DefaultConfig>;
|
||||||
DefaultExtraWithTxPayment<DefaultConfig, ChargeAssetTxPayment<DefaultConfig>>;
|
|
||||||
|
|
||||||
pub async fn test_node_process_with(
|
pub async fn test_node_process_with(
|
||||||
key: AccountKeyring,
|
key: AccountKeyring,
|
||||||
@@ -60,7 +58,7 @@ pub async fn test_node_process() -> TestNodeProcess<DefaultConfig> {
|
|||||||
|
|
||||||
pub struct TestContext {
|
pub struct TestContext {
|
||||||
pub node_proc: TestNodeProcess<DefaultConfig>,
|
pub node_proc: TestNodeProcess<DefaultConfig>,
|
||||||
pub api: node_runtime::RuntimeApi<DefaultConfig, NodeRuntimeSignedExtra>,
|
pub api: node_runtime::RuntimeApi<DefaultConfig, NodeRuntimeParams>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestContext {
|
impl TestContext {
|
||||||
@@ -76,8 +74,6 @@ pub async fn test_context() -> TestContext {
|
|||||||
TestContext { node_proc, api }
|
TestContext { node_proc, api }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pair_signer(
|
pub fn pair_signer(pair: Pair) -> PairSigner<DefaultConfig, Pair> {
|
||||||
pair: Pair,
|
|
||||||
) -> PairSigner<DefaultConfig, NodeRuntimeSignedExtra, Pair> {
|
|
||||||
PairSigner::new(pair)
|
PairSigner::new(pair)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user