From 17abfb49b2bc3f79b9af6832e988d147b5ba841c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 21 Nov 2019 17:53:45 +0000 Subject: [PATCH] Refactor: simplify module call definitions (#24) * Refactor: simplify module call definitions * Fix compilation errors after merge * Add missing comments and remove unused imports * Now it compiles --- src/codec.rs | 12 +-- src/lib.rs | 84 ++++++----------- src/palette/balances.rs | 87 +++++------------- src/palette/contracts.rs | 192 ++++++++++++++------------------------- src/palette/mod.rs | 20 ++-- src/palette/system.rs | 62 ++----------- 6 files changed, 135 insertions(+), 322 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index 7b1d2d9135da8..4cebf2a77770c 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -1,8 +1,4 @@ -use parity_scale_codec::{ - Encode, - EncodeAsRef, - HasCompact, -}; +use parity_scale_codec::Encode; #[derive(Clone)] pub struct Encoded(pub Vec); @@ -12,9 +8,3 @@ impl Encode for Encoded { self.0.to_owned() } } - -pub fn compact(t: T) -> Encoded { - let encodable: <::Type as EncodeAsRef<'_, T>>::RefType = - From::from(&t); - Encoded(encodable.encode()) -} diff --git a/src/lib.rs b/src/lib.rs index 482e659bfb535..de99b260af46c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ use metadata::Metadata; use parity_scale_codec::{ Codec, Decode, + Encode, }; use runtime_primitives::{ generic::UncheckedExtrinsic, @@ -61,15 +62,14 @@ use crate::{ DefaultExtra, SignedExtra, }, - metadata::MetadataError, palette::{ + Call, balances::Balances, system::{ System, SystemEvent, SystemStore, }, - ModuleCalls, }, rpc::{ BlockNumber, @@ -266,30 +266,21 @@ impl Client { runtime_version, genesis_hash, signer, - call: None, - marker: PhantomData, } }) } } -/// The extrinsic builder is ready to finalize construction. -pub enum Valid {} -/// The extrinsic builder is not ready to finalize construction. -pub enum Invalid {} - /// Transaction builder. -pub struct XtBuilder { +pub struct XtBuilder { client: Client, nonce: T::Index, runtime_version: RuntimeVersion, genesis_hash: T::Hash, signer: P, - call: Option>, - marker: PhantomData V>, } -impl XtBuilder +impl XtBuilder where P: Pair, { @@ -304,42 +295,19 @@ 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 } - - /// Sets the module call to a new value - pub fn set_call(&self, module: &'static str, f: F) -> XtBuilder - where - F: FnOnce(ModuleCalls) -> Result, - { - let call = self - .metadata() - .module(module) - .and_then(|module| f(ModuleCalls::new(module))) - .map_err(Into::into); - - XtBuilder { - client: self.client.clone(), - nonce: self.nonce.clone(), - runtime_version: self.runtime_version.clone(), - genesis_hash: self.genesis_hash.clone(), - signer: self.signer.clone(), - call: Some(call), - marker: PhantomData, - } - } } -impl - XtBuilder +impl XtBuilder where P: Pair, S: Verify + Codec + From, @@ -347,8 +315,9 @@ where T::Address: From, { /// Creates and signs an Extrinsic for the supplied `Call` - pub fn create_and_sign( + pub fn create_and_sign( &self, + call: Call, ) -> Result< UncheckedExtrinsic< T::Address, @@ -357,15 +326,18 @@ where as SignedExtra>::Extra, >, Error, - > { + > + where + C: parity_scale_codec::Encode, + { let signer = self.signer.clone(); let account_nonce = self.nonce.clone(); let version = self.runtime_version.spec_version; let genesis_hash = self.genesis_hash.clone(); let call = self - .call - .clone() - .expect("A Valid extrinisic builder has a call; qed")?; + .metadata() + .module(&call.module) + .and_then(|module| module.call(&call.function, call.args))?; log::info!( "Creating Extrinsic with genesis hash {:?} and account nonce {:?}", @@ -379,9 +351,9 @@ where } /// Submits a transaction to the chain. - pub fn submit(&self) -> impl Future { + pub fn submit(&self, call: Call) -> impl Future { let cli = self.client.connect(); - self.create_and_sign() + self.create_and_sign(call) .into_future() .map_err(Into::into) .and_then(move |extrinsic| { @@ -390,8 +362,9 @@ where } /// Submits transaction to the chain and watch for events. - pub fn submit_and_watch( + pub fn submit_and_watch( &self, + call: Call ) -> impl Future, Error = Error> { let cli = self.client.connect(); let metadata = self.client.metadata().clone(); @@ -399,7 +372,7 @@ where .into_future() .map_err(Into::into); - self.create_and_sign() + self.create_and_sign(call) .into_future() .map_err(Into::into) .join(decoder) @@ -419,9 +392,7 @@ mod tests { balances::{ Balances, BalancesStore, - BalancesXt, }, - contracts::ContractsXt, }, DefaultNodeRuntime as Runtime, }; @@ -454,15 +425,14 @@ mod tests { let dest = AccountKeyring::Bob.to_account_id(); let transfer = xt - .balances(|calls| calls.transfer(dest.clone().into(), 10_000)) - .submit(); + .submit(balances::transfer::(dest.clone().into(), 10_000)); rt.block_on(transfer).unwrap(); // check that nonce is handled correctly let transfer = xt .increment_nonce() - .balances(|calls| calls.transfer(dest.clone().into(), 10_000)) - .submit(); + .submit(balances::transfer::(dest.clone().into(), 10_000)); + rt.block_on(transfer).unwrap(); } @@ -483,8 +453,7 @@ mod tests { let wasm = wabt::wat2wasm(CONTRACT).expect("invalid wabt"); let put_code = xt - .contracts(|call| call.put_code(500_000, wasm)) - .submit_and_watch(); + .submit_and_watch(contracts::put_code(500_000, wasm)); let success = rt .block_on(put_code) @@ -561,8 +530,9 @@ mod tests { let transfer = pallet_balances::Call::transfer(address.clone(), amount); let call = node_runtime::Call::Balances(transfer); + let subxt_transfer = crate::palette::balances::transfer::(address, amount); let call2 = balances - .call("transfer", (address, codec::compact(amount))) + .call("transfer", subxt_transfer.args) .unwrap(); assert_eq!(call.encode().to_vec(), call2.0); diff --git a/src/palette/balances.rs b/src/palette/balances.rs index 3d12cdaea06b9..b3991cf649d46 100644 --- a/src/palette/balances.rs +++ b/src/palette/balances.rs @@ -1,34 +1,24 @@ //! Implements support for the pallet_balances module. use crate::{ - codec::{ - compact, - Encoded, - }, error::Error, - metadata::MetadataError, palette::{ + Call, system::System, - ModuleCalls, }, Client, - Valid, - XtBuilder, }; use futures::future::{ self, Future, }; -use parity_scale_codec::Codec; +use parity_scale_codec::{Encode, Codec}; use runtime_primitives::traits::{ - IdentifyAccount, MaybeSerialize, Member, SimpleArithmetic, - Verify, }; use runtime_support::Parameter; use std::fmt::Debug; -use substrate_primitives::Pair; /// The subset of the `pallet_balances::Trait` that a client must implement. pub trait Balances: System { @@ -101,61 +91,26 @@ impl BalancesStore for Client { } } -/// The Balances extension trait for the XtBuilder. -pub trait BalancesXt { - /// Balances type. - type Balances: Balances; - /// Keypair type - type Pair: Pair; - /// Signature type - type Signature: Verify; - - /// Create a call for the pallet balances module - fn balances( - &self, - f: F, - ) -> XtBuilder - where - F: FnOnce( - ModuleCalls, - ) -> Result; -} - -impl BalancesXt for XtBuilder -where - P: Pair, - S: Verify, - S::Signer: From + IdentifyAccount, -{ - type Balances = T; - type Pair = P; - type Signature = S; +const MODULE: &str = "Balances"; +const TRANSFER: &str = "transfer"; - fn balances(&self, f: F) -> XtBuilder - where - F: FnOnce( - ModuleCalls, - ) -> Result, - { - self.set_call("Balances", f) - } +/// Arguments for transferring a balance +#[derive(Encode)] +pub struct TransferArgs { + to: ::Address, + #[codec(compact)] + amount: ::Balance } -impl ModuleCalls -where - P: Pair, -{ - /// Transfer some liquid free balance to another account. - /// - /// `transfer` will set the `FreeBalance` of the sender and receiver. - /// It will decrease the total issuance of the system by the `TransferFee`. - /// If the sender's account is below the existential deposit as a result - /// of the transfer, the account will be reaped. - pub fn transfer( - self, - to: ::Address, - amount: ::Balance, - ) -> Result { - self.module.call("transfer", (to, compact(amount))) - } +/// Transfer some liquid free balance to another account. +/// +/// `transfer` will set the `FreeBalance` of the sender and receiver. +/// It will decrease the total issuance of the system by the `TransferFee`. +/// If the sender's account is below the existential deposit as a result +/// of the transfer, the account will be reaped. +pub fn transfer( + to: ::Address, + amount: ::Balance, +) -> Call> { + Call::new(MODULE, TRANSFER, TransferArgs { to, amount }) } diff --git a/src/palette/contracts.rs b/src/palette/contracts.rs index 8076e58bf19c7..78a02669d0a80 100644 --- a/src/palette/contracts.rs +++ b/src/palette/contracts.rs @@ -1,23 +1,17 @@ //! Implements support for the pallet_contracts module. use crate::{ - codec::{ - compact, - Encoded, - }, - metadata::MetadataError, palette::{ + Call, balances::Balances, system::System, - ModuleCalls, }, - Valid, - XtBuilder, -}; -use runtime_primitives::traits::{ - IdentifyAccount, - Verify, }; -use substrate_primitives::Pair; +use parity_scale_codec::Encode; + +const MODULE: &str = "Contracts"; +const PUT_CODE: &str = "put_code"; +const CREATE: &str = "create"; +const CALL: &str = "call"; /// Gas units are chosen to be represented by u64 so that gas metering /// instructions can operate on them efficiently. @@ -26,122 +20,76 @@ pub type Gas = u64; /// The subset of the `pallet_contracts::Trait` that a client must implement. pub trait Contracts: System + Balances {} -/// Blanket impl for using existing runtime types -impl< - T: pallet_contracts::Trait - + palette_system::Trait - + pallet_balances::Trait - + std::fmt::Debug, - > Contracts for T -where - ::Header: serde::de::DeserializeOwned, -{ +/// Arguments for uploading contract code to the chain +#[derive(Encode)] +pub struct PutCodeArgs { + #[codec(compact)] + gas_limit: Gas, + code: Vec, } -/// The Contracts extension trait for the XtBuilder. -pub trait ContractsXt { - /// Contracts type. - type Contracts: Contracts; - /// Key Pair Type - type Pair: Pair; - /// Signature type - type Signature: Verify; - - /// Create a call for the pallet contracts module - fn contracts( - &self, - f: F, - ) -> XtBuilder - where - F: FnOnce( - ModuleCalls, - ) -> Result; +/// Arguments for creating an instance of a contract +#[derive(Encode)] +pub struct CreateArgs { + endowment: ::Balance, + #[codec(compact)] + gas_limit: Gas, + code_hash: ::Hash, + data: Vec, } -impl ContractsXt for XtBuilder -where - P: Pair, - S: Verify, - S::Signer: From + IdentifyAccount, -{ - type Contracts = T; - type Pair = P; - type Signature = S; - - fn contracts(&self, f: F) -> XtBuilder - where - F: FnOnce( - ModuleCalls, - ) -> Result, - { - self.set_call("Contracts", f) - } +/// Arguments for calling a contract +#[derive(Encode)] +pub struct CallArgs { + dest: ::Address, + value: ::Balance, + #[codec(compact)] + gas_limit: Gas, + data: Vec, } -impl ModuleCalls -where - P: Pair, -{ - /// Stores the given binary Wasm code into the chain's storage and returns - /// its `codehash`. - /// You can instantiate contracts only with stored code. - pub fn put_code( - &self, - gas_limit: Gas, - code: Vec, - ) -> Result { - self.module.call("put_code", (compact(gas_limit), code)) - } - - /// Creates a new contract from the `codehash` generated by `put_code`, - /// optionally transferring some balance. - /// - /// Creation is executed as follows: - /// - /// - The destination address is computed based on the sender and hash of - /// the code. - /// - The smart-contract account is created at the computed address. - /// - The `ctor_code` is executed in the context of the newly-created - /// account. Buffer returned after the execution is saved as the `code` - /// of the account. That code will be invoked upon any call received by - /// this account. - /// - The contract is initialized. - pub fn create( - &self, - endowment: ::Balance, - gas_limit: Gas, - code_hash: ::Hash, - data: Vec, - ) -> Result { - self.module.call( - "create", - (compact(endowment), compact(gas_limit), code_hash, data), - ) - } +/// Stores the given binary Wasm code into the chain's storage and returns +/// its `codehash`. +/// You can instantiate contracts only with stored code. +pub fn put_code(gas_limit: Gas, code: Vec) -> Call { + Call::new(MODULE, PUT_CODE, PutCodeArgs { gas_limit, code }) +} - /// Makes a call to an account, optionally transferring some balance. - /// - /// * If the account is a smart-contract account, the associated code will - /// be executed and any value will be transferred. - /// * If the account is a regular account, any value will be transferred. - /// * If no account exists and the call value is not less than - /// `existential_deposit`, a regular account will be created and any value - /// will be transferred. - pub fn call( - &self, - dest: ::Address, - value: ::Balance, - gas_limit: Gas, - data: Vec, - ) -> Result { - self.module - .call("call", (dest, compact(value), compact(gas_limit), data)) - } +/// Creates a new contract from the `codehash` generated by `put_code`, +/// optionally transferring some balance. +/// +/// Creation is executed as follows: +/// +/// - The destination address is computed based on the sender and hash of +/// the code. +/// - The smart-contract account is created at the computed address. +/// - The `ctor_code` is executed in the context of the newly-created +/// account. Buffer returned after the execution is saved as the `code`https://www.bbc.co.uk/ +/// of the account. That code will be invoked upon any call received by +/// this account. +/// - The contract is initialized. +pub fn create( + endowment: ::Balance, + gas_limit: Gas, + code_hash: ::Hash, + data: Vec, +) -> Call> { + Call::new(MODULE, CREATE, CreateArgs { endowment, gas_limit, code_hash, data }) } -/// Contracts Events -#[derive(parity_scale_codec::Decode)] -pub enum Event { - /// Contract code stored - CodeStored(T::Hash), +/// Makes a call to an account, optionally transferring some balance. +/// +/// * If the account is a smart-contract account, the associated code will +/// be executed and any value will be transferred. +/// * If the account is a regular account, any value will be transferred. +/// * If no account exists and the call value is not less than +/// `existential_deposit`, a regular account will be created and any value +/// will be transferred. +pub fn call( + dest: ::Address, + value: ::Balance, + gas_limit: Gas, + data: Vec, +) -> Call> { + Call::new(MODULE, CALL, CallArgs { dest, value, gas_limit, data }) } diff --git a/src/palette/mod.rs b/src/palette/mod.rs index cce486afa6c51..160ecdcf750e8 100644 --- a/src/palette/mod.rs +++ b/src/palette/mod.rs @@ -1,24 +1,20 @@ //! Implements support for built-in runtime modules. -use crate::metadata::ModuleMetadata; -use std::marker::PhantomData; +use parity_scale_codec::Encode; pub mod balances; pub mod contracts; pub mod system; /// Creates module calls -pub struct ModuleCalls { - module: ModuleMetadata, - marker: PhantomData (T, P)>, +pub struct Call { + pub module: &'static str, + pub function: &'static str, + pub args: T, } -impl ModuleCalls { - /// Create new module calls - pub fn new(module: &ModuleMetadata) -> Self { - ModuleCalls:: { - module: module.clone(), - marker: PhantomData, - } +impl Call { + pub fn new(module: &'static str, function: &'static str, args: T) -> Self { + Call { module, function, args } } } diff --git a/src/palette/system.rs b/src/palette/system.rs index 49a52bc34bfba..039ef118b4346 100644 --- a/src/palette/system.rs +++ b/src/palette/system.rs @@ -1,15 +1,11 @@ //! Implements support for the palette_system module. use crate::{ - codec::Encoded, error::Error, - metadata::MetadataError, palette::{ + Call, balances::Balances, - ModuleCalls, }, Client, - Valid, - XtBuilder, }; use futures::future::{ self, @@ -21,7 +17,6 @@ use runtime_primitives::traits::{ CheckEqual, Hash, Header, - IdentifyAccount, MaybeDisplay, MaybeSerialize, MaybeSerializeDeserialize, @@ -29,12 +24,10 @@ use runtime_primitives::traits::{ SimpleArithmetic, SimpleBitOps, StaticLookup, - Verify, }; use runtime_support::Parameter; use serde::de::DeserializeOwned; use std::fmt::Debug; -use substrate_primitives::Pair; /// The subset of the `palette::Trait` that a client must implement. pub trait System: 'static + Eq + Clone + Debug { @@ -145,54 +138,15 @@ impl SystemStore for Client { } } -/// The System extension trait for the XtBuilder. -pub trait SystemXt { - /// System type. - type System: System; - /// Keypair type - type Pair: Pair; - /// Signature type - type Signature: Verify; +const MODULE: &str = "System"; +const SET_CODE: &str = "set_code"; - /// Create a call for the pallet system module - fn system( - &self, - f: F, - ) -> XtBuilder - where - F: FnOnce( - ModuleCalls, - ) -> Result; -} - -impl SystemXt for XtBuilder -where - P: Pair, - S: Verify, - S::Signer: From + IdentifyAccount, -{ - type System = T; - type Pair = P; - type Signature = S; - - fn system(&self, f: F) -> XtBuilder - where - F: FnOnce( - ModuleCalls, - ) -> Result, - { - self.set_call("System", f) - } -} +/// Arguments for updating the runtime code +pub type SetCode = Vec; -impl ModuleCalls -where - P: Pair, -{ - /// Sets the new code. - pub fn set_code(&self, code: Vec) -> Result { - self.module.call("set_code", code) - } +/// Sets the new code. +pub fn set_code(code: Vec) -> Call { + Call::new(MODULE, SET_CODE, code) } /// Event for the System module.