feat: Mortal extrinsic construction

This commit is contained in:
emostov
2020-12-13 20:13:16 -08:00
parent 80aff7eb6e
commit c9059d1a32
8 changed files with 112 additions and 14 deletions
+9 -5
View File
@@ -138,14 +138,13 @@ where
///
/// # 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)
/// This is modified from the substrate version to allow passing in a hash (either the genesis hash
/// if immortal or current hash if mortal. The hash is returned via `additional_signed()`.
#[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)]
pub struct CheckEra<T: System>(
/// The default structure for the Extra encoding
pub (Era, PhantomData<T>),
/// Local genesis hash to be used for `AdditionalSigned`
/// Local hash to be used for `AdditionalSigned`
#[codec(skip)]
pub T::Hash,
);
@@ -238,6 +237,7 @@ pub trait SignedExtra<T: System>: SignedExtension {
tx_version: u32,
nonce: T::Index,
genesis_hash: T::Hash,
era_info: (Era, T::Hash)
) -> Self;
/// Returns the transaction extra.
@@ -251,6 +251,8 @@ pub struct DefaultExtra<T: System> {
tx_version: u32,
nonce: T::Index,
genesis_hash: T::Hash,
// Era and either the genesis_hash if immortal or the current hash if mortal
era_info: (Era, T::Hash)
}
impl<T: System + Balances + Clone + Debug + Eq + Send + Sync> SignedExtra<T>
@@ -271,12 +273,14 @@ impl<T: System + Balances + Clone + Debug + Eq + Send + Sync> SignedExtra<T>
tx_version: u32,
nonce: T::Index,
genesis_hash: T::Hash,
era_info: (Era, T::Hash)
) -> Self {
DefaultExtra {
spec_version,
tx_version,
nonce,
genesis_hash,
era_info,
}
}
@@ -285,7 +289,7 @@ impl<T: System + Balances + Clone + Debug + Eq + Send + Sync> SignedExtra<T>
CheckSpecVersion(PhantomData, self.spec_version),
CheckTxVersion(PhantomData, self.tx_version),
CheckGenesis(PhantomData, self.genesis_hash),
CheckEra((Era::Immortal, PhantomData), self.genesis_hash),
CheckEra((self.era_info.0, PhantomData), self.era_info.1),
CheckNonce(self.nonce),
CheckWeight(PhantomData),
ChargeTransactionPayment(<T as Balances>::Balance::default()),
+16 -2
View File
@@ -31,7 +31,10 @@ pub use self::{
},
};
use sp_runtime::traits::SignedExtension;
use sp_runtime::{
traits::SignedExtension,
generic::Era
};
use sp_version::RuntimeVersion;
use crate::{
@@ -41,6 +44,10 @@ use crate::{
Error,
};
/// A reasonable default for `era_period`
pub const DEFAULT_ERA_PERIOD: u64 = 64;
/// UncheckedExtrinsic type.
pub type UncheckedExtrinsic<T> = sp_runtime::generic::UncheckedExtrinsic<
<T as System>::Address,
@@ -59,6 +66,7 @@ pub async fn create_signed<T>(
nonce: T::Index,
call: Encoded,
signer: &(dyn Signer<T> + Send + Sync),
era_opts: Option<(u64, u64, T::Hash)>,
) -> Result<UncheckedExtrinsic<T>, Error>
where
T: Runtime,
@@ -67,7 +75,13 @@ where
{
let spec_version = runtime_version.spec_version;
let tx_version = runtime_version.transaction_version;
let extra: T::Extra = T::Extra::new(spec_version, tx_version, nonce, genesis_hash);
let era_info = match era_opts {
Some((period, cur_num, cur_hash)) => {
(Era::mortal(period, cur_num), cur_hash)
},
None => (Era::Immortal, genesis_hash)
};
let extra: T::Extra = T::Extra::new(spec_version, tx_version, nonce, genesis_hash, era_info);
let payload = SignedPayload::<T>::new(call, extra.extra())?;
let signed = signer.sign(payload).await?;
Ok(signed)
+55 -2
View File
@@ -63,6 +63,12 @@ use sp_core::{
pub use sp_runtime::traits::SignedExtension;
pub use sp_version::RuntimeVersion;
use std::marker::PhantomData;
use sp_runtime::{
traits::{Block, Header},
SaturatedConversion
};
use quote::{TokenStreamExt, quote};
use proc_macro2::TokenStream;
mod error;
mod events;
@@ -84,6 +90,7 @@ pub use crate::{
SignedExtra,
Signer,
UncheckedExtrinsic,
DEFAULT_ERA_PERIOD
},
frame::*,
metadata::{
@@ -193,6 +200,37 @@ pub struct Client<T: Runtime> {
page_size: u32,
}
/// Construction options for a signed extrinsic
// TODO: tip can go in here https://github.com/paritytech/substrate-subxt/issues/187
#[derive(Clone)]
pub struct SignedOptions {
/// The period, measured in blocks, that transaction will live for, starting from a checkpoint
/// block. A good default is 64 (64 * 6secs = 6min 40sec).
///
/// `era_period == None`: immortal transaction.
/// `0 <= era_period <= 65536`: rounded up to the closest power of 2, starting at 4.
/// `65536 < era_period`: 65536.
// pub era_period: Option<u64>,
pub era_period: Option<u64>,
}
// https://github.com/dtolnay/quote/issues/129#issue-481909264
fn options_to_tokens<T : quote::ToTokens>(input: &core::option::Option<T>) -> TokenStream {
match input {
Some(value) => quote!(core::option::Option::Some(#value)),
None => quote!(core::option::Option::None)
}
}
impl quote::ToTokens for self::SignedOptions {
fn to_tokens(&self, tokens: &mut TokenStream) {
let era_period = options_to_tokens(&self.era_period);
tokens.append_all(quote!(
SignedOptions {
era_period: #era_period
}
));
}
}
impl<T: Runtime> Clone for Client<T> {
fn clone(&self) -> Self {
Self {
@@ -444,6 +482,7 @@ impl<T: Runtime> Client<T> {
&self,
call: C,
signer: &(dyn Signer<T> + Send + Sync),
opts: SignedOptions,
) -> Result<UncheckedExtrinsic<T>, Error>
where
<<T::Extra as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
@@ -455,12 +494,24 @@ impl<T: Runtime> Client<T> {
self.account(signer.account_id(), None).await?.nonce
};
let call = self.encode(call)?;
let era_opts = if opts.era_period.is_some() {
let era_period = opts.era_period.unwrap();
let current_block = self.block(None::<T::Hash>).await?.unwrap().block;
let current_number = (*current_block.header().number()).saturated_into::<u64>();
let current_hash = current_block.hash();
Some((era_period, current_number, current_hash))
} else {
None
};
let signed = extrinsic::create_signed(
&self.runtime_version,
self.genesis_hash,
account_nonce,
call,
signer,
era_opts,
)
.await?;
Ok(signed)
@@ -498,12 +549,13 @@ impl<T: Runtime> Client<T> {
&self,
call: C,
signer: &(dyn Signer<T> + Send + Sync),
opts: SignedOptions,
) -> Result<T::Hash, Error>
where
<<T::Extra as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
Send + Sync,
{
let extrinsic = self.create_signed(call, signer).await?;
let extrinsic = self.create_signed(call, signer, opts).await?;
self.submit_extrinsic(extrinsic).await
}
@@ -512,12 +564,13 @@ impl<T: Runtime> Client<T> {
&self,
call: C,
signer: &(dyn Signer<T> + Send + Sync),
opts: SignedOptions,
) -> Result<ExtrinsicSuccess<T>, Error>
where
<<T::Extra as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
Send + Sync,
{
let extrinsic = self.create_signed(call, signer).await?;
let extrinsic = self.create_signed(call, signer, opts).await?;
let decoder = self.events_decoder::<C>();
self.submit_and_watch_extrinsic(extrinsic, decoder).await
}