From 8cf652605f13e9d8b40b4b07f454287d351dec5e Mon Sep 17 00:00:00 2001 From: David Craven Date: Wed, 15 Apr 2020 09:21:19 +0200 Subject: [PATCH] Custom extra (#89) * Run rustfmt. * Make extra customizable. * Update to alpha 6. --- examples/kusama_balance_transfer.rs | 11 ++- examples/submit_and_watch.rs | 5 +- src/extrinsic.rs | 57 +++++++-------- src/frame/system.rs | 8 ++- src/lib.rs | 106 +++++++++++++++------------- 5 files changed, 101 insertions(+), 86 deletions(-) diff --git a/examples/kusama_balance_transfer.rs b/examples/kusama_balance_transfer.rs index bb7e1ff1c5..5255244365 100644 --- a/examples/kusama_balance_transfer.rs +++ b/examples/kusama_balance_transfer.rs @@ -39,8 +39,13 @@ async fn transfer_balance() -> Result { // note use of `KusamaRuntime` substrate_subxt::ClientBuilder::::new() - .build().await? - .xt(signer, None).await? - .submit(balances::transfer::(dest.clone().into(), 10_000)) + .build() + .await? + .xt(signer, None) + .await? + .submit(balances::transfer::( + dest.clone().into(), + 10_000, + )) .await } diff --git a/examples/submit_and_watch.rs b/examples/submit_and_watch.rs index c40553c50b..09d3a77d81 100644 --- a/examples/submit_and_watch.rs +++ b/examples/submit_and_watch.rs @@ -51,9 +51,8 @@ fn main() { match result { Ok(extrinsic_success) => { match extrinsic_success - .find_event::<(AccountId, AccountId, Balance)>( - "Balances", "Transfer", - ) { + .find_event::<(AccountId, AccountId, Balance)>("Balances", "Transfer") + { Some(Ok((_from, _to, value))) => { println!("Balance transfer success: value: {:?}", value) } diff --git a/src/extrinsic.rs b/src/extrinsic.rs index 9429869fb3..c9c53dce8e 100644 --- a/src/extrinsic.rs +++ b/src/extrinsic.rs @@ -53,10 +53,10 @@ use crate::frame::{ /// returned via `additional_signed()`. #[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)] pub struct CheckVersion( - PhantomData, + pub PhantomData, /// Local version to be used for `AdditionalSigned` #[codec(skip)] - u32, + pub u32, ); impl SignedExtension for CheckVersion @@ -68,7 +68,6 @@ where type Call = (); type AdditionalSigned = u32; type Pre = (); - type DispatchInfo = (); fn additional_signed( &self, ) -> Result { @@ -84,10 +83,10 @@ where /// returned via `additional_signed()`. #[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)] pub struct CheckGenesis( - PhantomData, + pub PhantomData, /// Local genesis hash to be used for `AdditionalSigned` #[codec(skip)] - T::Hash, + pub T::Hash, ); impl SignedExtension for CheckGenesis @@ -99,7 +98,6 @@ where type Call = (); type AdditionalSigned = T::Hash; type Pre = (); - type DispatchInfo = (); fn additional_signed( &self, ) -> Result { @@ -117,10 +115,10 @@ where #[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)] pub struct CheckEra( /// The default structure for the Extra encoding - (Era, PhantomData), + pub (Era, PhantomData), /// Local genesis hash to be used for `AdditionalSigned` #[codec(skip)] - T::Hash, + pub T::Hash, ); impl SignedExtension for CheckEra @@ -132,7 +130,6 @@ where type Call = (); type AdditionalSigned = T::Hash; type Pre = (); - type DispatchInfo = (); fn additional_signed( &self, ) -> Result { @@ -142,7 +139,7 @@ where /// Nonce check and increment to give replay protection for transactions. #[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)] -pub struct CheckNonce(#[codec(compact)] T::Index); +pub struct CheckNonce(#[codec(compact)] pub T::Index); impl SignedExtension for CheckNonce where @@ -153,7 +150,6 @@ where type Call = (); type AdditionalSigned = (); type Pre = (); - type DispatchInfo = (); fn additional_signed( &self, ) -> Result { @@ -163,7 +159,7 @@ where /// Resource limit check. #[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)] -pub struct CheckWeight(PhantomData); +pub struct CheckWeight(pub PhantomData); impl SignedExtension for CheckWeight where @@ -174,7 +170,6 @@ where type Call = (); type AdditionalSigned = (); type Pre = (); - type DispatchInfo = (); fn additional_signed( &self, ) -> Result { @@ -185,7 +180,7 @@ where /// Require the transactor pay for themselves and maybe include a tip to gain additional priority /// in the queue. #[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)] -pub struct ChargeTransactionPayment(#[codec(compact)] T::Balance); +pub struct ChargeTransactionPayment(#[codec(compact)] pub T::Balance); impl SignedExtension for ChargeTransactionPayment where @@ -196,7 +191,6 @@ where type Call = (); type AdditionalSigned = (); type Pre = (); - type DispatchInfo = (); fn additional_signed( &self, ) -> Result { @@ -206,7 +200,7 @@ where /// Checks if a transaction would exhausts the block gas limit. #[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)] -pub struct CheckBlockGasLimit(PhantomData); +pub struct CheckBlockGasLimit(pub PhantomData); impl SignedExtension for CheckBlockGasLimit where @@ -217,7 +211,6 @@ where type Call = (); type AdditionalSigned = (); type Pre = (); - type DispatchInfo = (); fn additional_signed( &self, ) -> Result { @@ -225,12 +218,19 @@ where } } -pub trait SignedExtra { +/// Trait for implementing transaction extras for a runtime. +pub trait SignedExtra { + /// The type the extras. type Extra: SignedExtension; + /// Creates a new `SignedExtra`. + fn new(version: u32, nonce: T::Index, genesis_hash: T::Hash) -> Self; + + /// Returns the transaction extra. fn extra(&self) -> Self::Extra; } +/// Default `SignedExtra` for substrate runtimes. #[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)] pub struct DefaultExtra { version: u32, @@ -238,16 +238,6 @@ pub struct DefaultExtra { genesis_hash: T::Hash, } -impl DefaultExtra { - pub fn new(version: u32, nonce: T::Index, genesis_hash: T::Hash) -> Self { - DefaultExtra { - version, - nonce, - genesis_hash, - } - } -} - impl SignedExtra for DefaultExtra { type Extra = ( CheckVersion, @@ -259,6 +249,14 @@ impl SignedExtra for DefaultExtra { CheckBlockGasLimit, ); + fn new(version: u32, nonce: T::Index, genesis_hash: T::Hash) -> Self { + DefaultExtra { + version, + nonce, + genesis_hash, + } + } + fn extra(&self) -> Self::Extra { ( CheckVersion(PhantomData, self.version), @@ -279,7 +277,6 @@ impl SignedExtension for DefaultExtra { type AdditionalSigned = <>::Extra as SignedExtension>::AdditionalSigned; type Pre = (); - type DispatchInfo = (); fn additional_signed( &self, @@ -288,7 +285,7 @@ impl SignedExtension for DefaultExtra { } } -pub fn create_and_sign( +pub(crate) fn create_and_sign( signer: P, call: C, extra: E, diff --git a/src/frame/system.rs b/src/frame/system.rs index 81486c5949..5fee8f5bc7 100644 --- a/src/frame/system.rs +++ b/src/frame/system.rs @@ -40,6 +40,7 @@ use sp_runtime::{ MaybeSerialize, MaybeSerializeDeserialize, Member, + SignedExtension, SimpleBitOps, }, RuntimeDebug, @@ -51,6 +52,7 @@ use std::{ use crate::{ error::Error, + extrinsic::SignedExtra, frame::{ balances::Balances, Call, @@ -157,8 +159,10 @@ pub trait SystemStore { ) -> Pin, Error>> + Send>>; } -impl SystemStore - for Client +impl SystemStore + for Client +where + E: SignedExtra + SignedExtension + 'static, { type System = T; diff --git a/src/lib.rs b/src/lib.rs index 91e2def0e8..88d015743b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,6 +65,7 @@ use sp_runtime::{ }, traits::{ IdentifyAccount, + SignedExtension, Verify, }, MultiSignature, @@ -82,6 +83,7 @@ mod runtimes; pub use self::{ error::Error, events::RawEvent, + extrinsic::*, frame::*, rpc::ExtrinsicSuccess, runtimes::*, @@ -91,10 +93,6 @@ use self::{ EventsDecoder, EventsError, }, - extrinsic::{ - DefaultExtra, - SignedExtra, - }, frame::{ balances::Balances, system::{ @@ -114,12 +112,12 @@ use self::{ /// ClientBuilder for constructing a Client. #[derive(Default)] -pub struct ClientBuilder { - _marker: std::marker::PhantomData<(T, S)>, +pub struct ClientBuilder> { + _marker: std::marker::PhantomData<(T, S, E)>, url: Option, } -impl ClientBuilder { +impl ClientBuilder { /// Creates a new ClientBuilder. pub fn new() -> Self { Self { @@ -135,7 +133,7 @@ impl ClientBuilder { } /// Creates a new Client. - pub async fn build(self) -> Result, Error> { + pub async fn build(self) -> Result, Error> { let url = self.url.unwrap_or("ws://127.0.0.1:9944".to_string()); let rpc = Rpc::connect_ws(&url).await?; @@ -156,15 +154,15 @@ impl ClientBuilder { } /// Client to interface with a substrate node. -pub struct Client { +pub struct Client> { rpc: Rpc, genesis_hash: T::Hash, metadata: Metadata, runtime_version: RuntimeVersion, - _marker: PhantomData S>, + _marker: PhantomData<(fn() -> S, E)>, } -impl Clone for Client { +impl Clone for Client { fn clone(&self) -> Self { Self { rpc: self.rpc.clone(), @@ -176,7 +174,10 @@ impl Clone for Client { } } -impl Client { +impl Client +where + E: SignedExtra + SignedExtension + 'static, +{ /// Returns the chain metadata. pub fn metadata(&self) -> &Metadata { &self.metadata @@ -256,18 +257,18 @@ impl Client { } /// Create and submit an extrinsic and return corresponding Hash if successful - pub async fn submit_extrinsic( + pub async fn submit_extrinsic( &self, - extrinsic: E, + extrinsic: X, ) -> Result { let xt_hash = self.rpc.submit_extrinsic(extrinsic).await?; Ok(xt_hash) } /// Create and submit an extrinsic and return corresponding Event if successful - pub async fn submit_and_watch_extrinsic( + pub async fn submit_and_watch_extrinsic( self, - extrinsic: E, + extrinsic: X, decoder: EventsDecoder, ) -> Result, Error> { let success = self @@ -304,10 +305,7 @@ impl Client { &self, account_id: ::AccountId, call: Call, - ) -> Result< - Vec, - Error, - > + ) -> Result, Error> where C: codec::Encode, { @@ -318,7 +316,7 @@ impl Client { .metadata() .module_with_calls(&call.module) .and_then(|module| module.call(&call.function, call.args))?; - let extra: extrinsic::DefaultExtra = extrinsic::DefaultExtra::new(version, account_nonce, genesis_hash); + let extra: E = E::new(version, account_nonce, genesis_hash); let raw_payload = SignedPayload::new(call, extra.extra())?; Ok(raw_payload.encode()) } @@ -328,7 +326,7 @@ impl Client { &self, signer: P, nonce: Option, - ) -> Result, Error> + ) -> Result, Error> where P: Pair, P::Signature: Codec, @@ -355,17 +353,18 @@ impl Client { /// Transaction builder. #[derive(Clone)] -pub struct XtBuilder { - client: Client, +pub struct XtBuilder { + client: Client, nonce: T::Index, runtime_version: RuntimeVersion, genesis_hash: T::Hash, signer: P, } -impl XtBuilder +impl XtBuilder where P: Pair, + E: SignedExtra + SignedExtension + 'static, { /// Returns the chain metadata. pub fn metadata(&self) -> &Metadata { @@ -378,36 +377,32 @@ where } /// Sets the nonce to a new value. - pub fn set_nonce(&mut self, nonce: T::Index) -> &mut XtBuilder { + pub fn set_nonce(&mut self, nonce: T::Index) -> &mut XtBuilder { self.nonce = nonce; self } /// Increment the nonce - pub fn increment_nonce(&mut self) -> &mut XtBuilder { + pub fn increment_nonce(&mut self) -> &mut XtBuilder { self.set_nonce(self.nonce() + 1.into()); self } } -impl XtBuilder +impl XtBuilder where P: Pair, S: Verify + Codec + From, S::Signer: From + IdentifyAccount, T::Address: From, + E: SignedExtra + SignedExtension + 'static, { /// Creates and signs an Extrinsic for the supplied `Call` pub fn create_and_sign( &self, call: Call, ) -> Result< - UncheckedExtrinsic< - T::Address, - Encoded, - S, - as SignedExtra>::Extra, - >, + UncheckedExtrinsic>::Extra>, Error, > where @@ -428,7 +423,7 @@ where account_nonce ); - let extra = extrinsic::DefaultExtra::new(version, account_nonce, genesis_hash); + let extra = E::new(version, account_nonce, genesis_hash); let xt = extrinsic::create_and_sign::<_, _, _, S, _>(signer, call, extra)?; Ok(xt) } @@ -441,7 +436,7 @@ where } /// Submits transaction to the chain and watch for events. - pub fn watch(self) -> EventsSubscriber { + pub fn watch(self) -> EventsSubscriber { let metadata = self.client.metadata().clone(); let decoder = EventsDecoder::try_from(metadata).map_err(Into::into); EventsSubscriber { @@ -453,19 +448,20 @@ where } /// Submits an extrinsic and subscribes to the triggered events -pub struct EventsSubscriber { - client: Client, - builder: XtBuilder, +pub struct EventsSubscriber { + client: Client, + builder: XtBuilder, decoder: Result, EventsError>, } -impl - EventsSubscriber +impl + EventsSubscriber where P: Pair, S: Verify + Codec + From, S::Signer: From + IdentifyAccount, T::Address: From, + E: SignedExtra + SignedExtension + 'static, { /// Access the events decoder for registering custom type sizes pub fn events_decoder< @@ -511,7 +507,10 @@ impl codec::Encode for Encoded { #[cfg(test)] mod tests { - use sp_keyring::{ AccountKeyring, Ed25519Keyring }; + use sp_keyring::{ + AccountKeyring, + Ed25519Keyring, + }; use super::*; use crate::{ @@ -616,7 +615,6 @@ mod tests { #[test] #[ignore] // requires locally running substrate node fn test_create_raw_payload() { - let result: Result<_, Error> = async_std::task::block_on(async move { let signer_pair = Ed25519Keyring::Alice.pair(); let signer_account_id = Ed25519Keyring::Alice.to_account_id(); @@ -624,20 +622,32 @@ mod tests { let client = test_client().await; - // create raw payload with AccoundId and sign it - let raw_payload = client.create_raw_payload(signer_account_id, balances::transfer::(dest.clone().into(), 10_000)).await?; - let raw_signature = signer_pair.sign(raw_payload.encode().split_off(2).as_slice()); + // create raw payload with AccoundId and sign it + let raw_payload = client + .create_raw_payload( + signer_account_id, + balances::transfer::(dest.clone().into(), 10_000), + ) + .await?; + let raw_signature = + signer_pair.sign(raw_payload.encode().split_off(2).as_slice()); let raw_multisig = MultiSignature::from(raw_signature); // create signature with Xtbuilder let xt = client.xt(signer_pair.clone(), None).await?; - let xt_multi_sig = xt.create_and_sign(balances::transfer::(dest.clone().into(), 10_000))?.signature.unwrap().1; + let xt_multi_sig = xt + .create_and_sign(balances::transfer::( + dest.clone().into(), + 10_000, + ))? + .signature + .unwrap() + .1; // compare signatures assert_eq!(raw_multisig, xt_multi_sig); Ok(()) - }); assert!(result.is_ok())