mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +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:
+119
-41
@@ -24,10 +24,8 @@ use crate::{
|
||||
HasModuleError,
|
||||
},
|
||||
extrinsic::{
|
||||
self,
|
||||
SignedExtra,
|
||||
ExtrinsicParams,
|
||||
Signer,
|
||||
UncheckedExtrinsic,
|
||||
},
|
||||
rpc::{
|
||||
Rpc,
|
||||
@@ -39,9 +37,14 @@ use crate::{
|
||||
transaction::TransactionProgress,
|
||||
Call,
|
||||
Config,
|
||||
Encoded,
|
||||
Metadata,
|
||||
};
|
||||
use codec::Decode;
|
||||
use codec::{
|
||||
Compact,
|
||||
Decode,
|
||||
Encode,
|
||||
};
|
||||
use derivative::Derivative;
|
||||
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>
|
||||
where
|
||||
T: Config,
|
||||
X: SignedExtra<T>,
|
||||
X: ExtrinsicParams<T>,
|
||||
C: Call + Send + Sync,
|
||||
E: Decode + HasModuleError,
|
||||
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.
|
||||
///
|
||||
/// 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(
|
||||
self,
|
||||
signer: &(dyn Signer<T, X> + Send + Sync),
|
||||
) -> Result<TransactionProgress<'client, T, E, Evs>, BasicError>
|
||||
where
|
||||
<<X as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
||||
Send + Sync + 'static,
|
||||
{
|
||||
signer: &(dyn Signer<T> + Send + Sync),
|
||||
other_params: X::OtherParams,
|
||||
) -> Result<TransactionProgress<'client, T, E, Evs>, BasicError> {
|
||||
// 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).
|
||||
let ext_hash = T::Hashing::hash_of(&extrinsic);
|
||||
@@ -226,6 +242,26 @@ where
|
||||
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.
|
||||
///
|
||||
/// Returns `Ok` with the extrinsic hash if it is valid extrinsic.
|
||||
@@ -236,26 +272,20 @@ where
|
||||
/// and has been included in the transaction pool.
|
||||
pub async fn sign_and_submit(
|
||||
self,
|
||||
signer: &(dyn Signer<T, X> + Send + Sync),
|
||||
) -> Result<T::Hash, BasicError>
|
||||
where
|
||||
<<X as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
||||
Send + Sync + 'static,
|
||||
{
|
||||
let extrinsic = self.create_signed(signer, Default::default()).await?;
|
||||
signer: &(dyn Signer<T> + Send + Sync),
|
||||
other_params: X::OtherParams,
|
||||
) -> Result<T::Hash, BasicError> {
|
||||
let extrinsic = self.create_signed(signer, other_params).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(
|
||||
&self,
|
||||
signer: &(dyn Signer<T, X> + Send + Sync),
|
||||
additional_params: X::Parameters,
|
||||
) -> Result<UncheckedExtrinsic<T, X>, BasicError>
|
||||
where
|
||||
<<X as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
||||
Send + Sync + 'static,
|
||||
{
|
||||
signer: &(dyn Signer<T> + Send + Sync),
|
||||
other_params: X::OtherParams,
|
||||
) -> Result<Encoded, BasicError> {
|
||||
// 1. Get nonce
|
||||
let account_nonce = if let Some(nonce) = signer.nonce() {
|
||||
nonce
|
||||
} else {
|
||||
@@ -264,21 +294,69 @@ where
|
||||
.system_account_next_index(signer.account_id())
|
||||
.await?
|
||||
};
|
||||
let call = self
|
||||
.client
|
||||
.metadata()
|
||||
.pallet(C::PALLET)
|
||||
.and_then(|pallet| pallet.encode_call(&self.call))?;
|
||||
|
||||
let signed = extrinsic::create_signed(
|
||||
&self.client.runtime_version,
|
||||
self.client.genesis_hash,
|
||||
// 2. SCALE encode call data to bytes (pallet u8, call u8, call params).
|
||||
let call_data = {
|
||||
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,
|
||||
call,
|
||||
signer,
|
||||
additional_params,
|
||||
)
|
||||
.await?;
|
||||
Ok(signed)
|
||||
self.client.genesis_hash,
|
||||
other_params,
|
||||
);
|
||||
|
||||
// 4. Construct signature. This is compatible with the Encode impl
|
||||
// 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
|
||||
+ AtLeast32Bit
|
||||
+ Copy
|
||||
+ scale_info::TypeInfo;
|
||||
+ scale_info::TypeInfo
|
||||
+ Into<u64>;
|
||||
|
||||
/// The block number type used by the runtime.
|
||||
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.
|
||||
|
||||
mod extra;
|
||||
mod params;
|
||||
mod signer;
|
||||
|
||||
pub use self::{
|
||||
extra::{
|
||||
ChargeAssetTxPayment,
|
||||
ChargeTransactionPayment,
|
||||
CheckGenesis,
|
||||
CheckMortality,
|
||||
CheckNonce,
|
||||
CheckSpecVersion,
|
||||
CheckTxVersion,
|
||||
CheckWeight,
|
||||
DefaultExtra,
|
||||
DefaultExtraWithTxPayment,
|
||||
SignedExtra,
|
||||
params::{
|
||||
AssetTip,
|
||||
Era,
|
||||
ExtrinsicParams,
|
||||
PlainTip,
|
||||
PolkadotExtrinsicParams,
|
||||
PolkadotExtrinsicParamsBuilder,
|
||||
SubstrateExtrinsicParams,
|
||||
SubstrateExtrinsicParamsBuilder,
|
||||
},
|
||||
signer::{
|
||||
PairSigner,
|
||||
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
|
||||
//! [substrate](https://github.com/paritytech/substrate) node via RPC.
|
||||
|
||||
use super::{
|
||||
SignedExtra,
|
||||
SignedPayload,
|
||||
UncheckedExtrinsic,
|
||||
};
|
||||
use crate::Config;
|
||||
use codec::Encode;
|
||||
use sp_core::Pair;
|
||||
use sp_runtime::traits::{
|
||||
IdentifyAccount,
|
||||
SignedExtension,
|
||||
Verify,
|
||||
};
|
||||
|
||||
/// Extrinsic signer.
|
||||
#[async_trait::async_trait]
|
||||
pub trait Signer<T: Config, E: SignedExtra<T>> {
|
||||
/// Returns the account id.
|
||||
fn account_id(&self) -> &T::AccountId;
|
||||
|
||||
/// Signing transactions requires a [`Signer`]. This is responsible for
|
||||
/// providing the "from" account that the transaction is being signed by,
|
||||
/// as well as actually signing a SCALE encoded payload. Optionally, a
|
||||
/// signer can also provide the nonce for the transaction to use.
|
||||
pub trait Signer<T: Config> {
|
||||
/// Optionally returns a nonce.
|
||||
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
|
||||
/// refused the operation.
|
||||
async fn sign(
|
||||
&self,
|
||||
extrinsic: SignedPayload<T, E>,
|
||||
) -> Result<UncheckedExtrinsic<T, E>, String>;
|
||||
fn sign(&self, signer_payload: &[u8]) -> T::Signature;
|
||||
}
|
||||
|
||||
/// Extrinsic signer using a private key.
|
||||
/// A [`Signer`] implementation that can be constructed from an [`Pair`].
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PairSigner<T: Config, E, P: Pair> {
|
||||
pub struct PairSigner<T: Config, P: Pair> {
|
||||
account_id: T::AccountId,
|
||||
nonce: Option<T::Index>,
|
||||
signer: P,
|
||||
marker: std::marker::PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<T, E, P> PairSigner<T, E, P>
|
||||
impl<T, P> PairSigner<T, P>
|
||||
where
|
||||
T: Config,
|
||||
E: SignedExtra<T>,
|
||||
T::Signature: From<P::Signature>,
|
||||
<T::Signature as Verify>::Signer:
|
||||
From<P::Public> + IdentifyAccount<AccountId = T::AccountId>,
|
||||
P: Pair,
|
||||
{
|
||||
/// Creates a new `Signer` from a `Pair`.
|
||||
/// Creates a new [`Signer`] from a [`Pair`].
|
||||
pub fn new(signer: P) -> Self {
|
||||
let account_id =
|
||||
<T::Signature as Verify>::Signer::from(signer.public()).into_account();
|
||||
@@ -76,11 +69,11 @@ where
|
||||
account_id,
|
||||
nonce: None,
|
||||
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) {
|
||||
self.nonce = Some(nonce);
|
||||
}
|
||||
@@ -90,43 +83,37 @@ where
|
||||
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 {
|
||||
&self.signer
|
||||
}
|
||||
|
||||
/// Return the account ID.
|
||||
pub fn account_id(&self) -> &T::AccountId {
|
||||
&self.account_id
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<T, E, P> Signer<T, E> for PairSigner<T, E, P>
|
||||
impl<T, P> Signer<T> for PairSigner<T, P>
|
||||
where
|
||||
T: Config,
|
||||
E: SignedExtra<T>,
|
||||
T::AccountId: Into<T::Address> + 'static,
|
||||
<<E as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
|
||||
Send + Sync + 'static,
|
||||
T::AccountId: Into<T::Address> + Clone + 'static,
|
||||
P: Pair + 'static,
|
||||
P::Signature: Into<T::Signature> + 'static,
|
||||
{
|
||||
fn account_id(&self) -> &T::AccountId {
|
||||
&self.account_id
|
||||
}
|
||||
|
||||
fn nonce(&self) -> Option<T::Index> {
|
||||
self.nonce
|
||||
}
|
||||
|
||||
async fn sign(
|
||||
&self,
|
||||
extrinsic: SignedPayload<T, E>,
|
||||
) -> Result<UncheckedExtrinsic<T, E>, String> {
|
||||
let signature = extrinsic.using_encoded(|payload| self.signer.sign(payload));
|
||||
let (call, extra, _) = extrinsic.deconstruct();
|
||||
let extrinsic = UncheckedExtrinsic::<T, E>::new_signed(
|
||||
call,
|
||||
self.account_id.clone().into(),
|
||||
signature.into(),
|
||||
extra,
|
||||
);
|
||||
Ok(extrinsic)
|
||||
fn account_id(&self) -> &T::AccountId {
|
||||
&self.account_id
|
||||
}
|
||||
|
||||
fn address(&self) -> T::Address {
|
||||
self.account_id.clone().into()
|
||||
}
|
||||
|
||||
fn sign(&self, signer_payload: &[u8]) -> T::Signature {
|
||||
self.signer.sign(signer_payload).into()
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -90,12 +90,11 @@ pub use crate::{
|
||||
RawEventDetails,
|
||||
},
|
||||
extrinsic::{
|
||||
DefaultExtra,
|
||||
DefaultExtraWithTxPayment,
|
||||
PairSigner,
|
||||
SignedExtra,
|
||||
Signer,
|
||||
UncheckedExtrinsic,
|
||||
PolkadotExtrinsicParams,
|
||||
PolkadotExtrinsicParamsBuilder,
|
||||
SubstrateExtrinsicParams,
|
||||
SubstrateExtrinsicParamsBuilder,
|
||||
},
|
||||
metadata::{
|
||||
ErrorMetadata,
|
||||
|
||||
+11
-10
@@ -30,10 +30,7 @@ use frame_metadata::{
|
||||
META_RESERVED,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Call,
|
||||
Encoded,
|
||||
};
|
||||
use crate::Call;
|
||||
use scale_info::{
|
||||
form::PortableForm,
|
||||
Type,
|
||||
@@ -148,18 +145,22 @@ impl PalletMetadata {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Encode a call based on this pallet metadata.
|
||||
pub fn encode_call<C>(&self, call: &C) -> Result<Encoded, MetadataError>
|
||||
/// Get the index of this pallet.
|
||||
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
|
||||
C: Call,
|
||||
{
|
||||
let fn_index = self
|
||||
let fn_index = *self
|
||||
.calls
|
||||
.get(C::FUNCTION)
|
||||
.ok_or(MetadataError::CallNotFound(C::FUNCTION))?;
|
||||
let mut bytes = vec![self.index, *fn_index];
|
||||
bytes.extend(call.encode());
|
||||
Ok(Encoded(bytes))
|
||||
Ok(fn_index)
|
||||
}
|
||||
|
||||
/// Return [`StorageEntryMetadata`] given some storage key.
|
||||
|
||||
Reference in New Issue
Block a user