From d46b6a975ec28a7243c207ef9cbf2c7c52447910 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 20 Aug 2019 16:57:06 +0100 Subject: [PATCH] Allow either `submit` or `submit_and_watch` on the builder. (#9) * Refactor: allow submit and submit_and_watch, separate module builders * Convert Balances, and use generic ModuleCalls * Convert System, and use generic ModuleCalls * Extract common calls to set_call * rustfmt * Test contract put_code with valid contract * Patch jsonrpc client dependency for bugfix * Handle result from call builder inside submit * Use patched version of jsonrpc * Lift module calls to Error * jsonrpc 13.0 * Remove unused static constraints --- Cargo.toml | 3 +- src/codec.rs | 1 + src/lib.rs | 213 ++++++++++++++++++++++++++++++++++-------- src/metadata.rs | 2 +- src/rpc.rs | 166 ++++++++------------------------ src/srml/balances.rs | 83 +++++++++------- src/srml/contracts.rs | 151 ++++++++++++------------------ src/srml/mod.rs | 19 ++++ src/srml/system.rs | 52 ++++++----- 9 files changed, 379 insertions(+), 311 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2d2e05f6fd..9f5ae6a13d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ include = ["/Cargo.toml", "src/**/*.rs", "/README.md", "/LICENSE"] derive_more = "0.14.0" log = "0.4" futures = "0.1.28" -jsonrpc-core-client = { version = "12.1.0", features = ["ws"] } +jsonrpc-core-client = { version = "13.0", features = ["ws"] } num-traits = { version = "0.2", default-features = false } parity-scale-codec = { version = "1.0", default-features = false, features = ["derive", "full"] } runtime_metadata = { git = "https://github.com/paritytech/substrate/", package = "srml-metadata" } @@ -35,3 +35,4 @@ node-runtime = { git = "https://github.com/paritytech/substrate/", package = "no srml-balances = { git = "https://github.com/paritytech/substrate/", package = "srml-balances" } substrate-keyring = { git = "https://github.com/paritytech/substrate/", package = "substrate-keyring" } tokio = "0.1" +wabt = "0.9.0" diff --git a/src/codec.rs b/src/codec.rs index 801a1dd0aa..7b1d2d9135 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -4,6 +4,7 @@ use parity_scale_codec::{ HasCompact, }; +#[derive(Clone)] pub struct Encoded(pub Vec); impl Encode for Encoded { diff --git a/src/lib.rs b/src/lib.rs index e6bad354ab..5eea7302fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ use futures::future::{ self, Either, Future, + IntoFuture, }; use jsonrpc_core_client::transports::ws; use metadata::Metadata; @@ -32,8 +33,13 @@ use parity_scale_codec::{ Decode, Encode, }; -use runtime_primitives::traits::StaticLookup; +use runtime_primitives::{ + generic::UncheckedExtrinsic, + traits::StaticLookup, +}; +use std::marker::PhantomData; use substrate_primitives::{ + blake2_256, storage::{ StorageChangeSet, StorageKey, @@ -43,13 +49,18 @@ use substrate_primitives::{ use url::Url; use crate::{ + codec::Encoded, + metadata::MetadataError, rpc::{ MapStream, Rpc, }, - srml::system::{ - System, - SystemStore, + srml::{ + system::{ + System, + SystemStore, + }, + ModuleCalls, }, }; pub use error::Error; @@ -208,27 +219,37 @@ impl Client { None => Either::B(self.account_nonce(signer.public().into())), } .map(|nonce| { + let genesis_hash = client.genesis_hash.clone(); XtBuilder { client, nonce, + 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, + genesis_hash: T::Hash, signer: P, + call: Option>, + marker: PhantomData V>, } -impl XtBuilder +impl XtBuilder where P: Pair, - P::Public: Into<::Source>, - P::Signature: Codec, { /// Returns the chain metadata. pub fn metadata(&self) -> &Metadata { @@ -241,46 +262,132 @@ where } /// Sets the nonce to a new value. - pub fn set_nonce(&mut self, nonce: T::Index) { + 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 { + 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(), + genesis_hash: self.genesis_hash.clone(), + signer: self.signer.clone(), + call: Some(call), + marker: PhantomData, + } + } +} + +impl XtBuilder +where + P: Pair, + P::Public: Into<::Source>, + P::Signature: Codec, +{ + /// Creates and signs an Extrinsic for the supplied `Call` + pub fn create_and_sign( + &self, + ) -> Result< + UncheckedExtrinsic< + ::Source, + Encoded, + P::Signature, + T::SignedExtra, + >, + MetadataError, + > + where + P: Pair, + P::Public: Into<::Source>, + P::Signature: Codec, + { + let signer = self.signer.clone(); + let account_nonce = self.nonce.clone(); + let genesis_hash = self.genesis_hash.clone(); + let call = self + .call + .clone() + .expect("A Valid extrinisic builder has a call; qed")?; + + log::info!( + "Creating Extrinsic with genesis hash {:?} and account nonce {:?}", + genesis_hash, + account_nonce + ); + + let extra = T::extra(account_nonce); + let raw_payload = (call.clone(), extra.clone(), (&genesis_hash, &genesis_hash)); + let signature = raw_payload.using_encoded(|payload| { + if payload.len() > 256 { + signer.sign(&blake2_256(payload)[..]) + } else { + signer.sign(payload) + } + }); + + Ok(UncheckedExtrinsic::new_signed( + raw_payload.0, + signer.public().into(), + signature.into(), + extra, + )) } /// Submits a transaction to the chain. - pub fn submit( - &mut self, - call: C, - ) -> impl Future { - let signer = self.signer.clone(); - let nonce = self.nonce.clone(); - let genesis_hash = self.client.genesis_hash.clone(); - self.set_nonce(nonce + 1.into()); - self.client - .connect() - .and_then(move |rpc| rpc.submit_extrinsic(signer, call, nonce, genesis_hash)) + pub fn submit(&self) -> impl Future { + let cli = self.client.connect(); + self.create_and_sign() + .into_future() + .map_err(Into::into) + .and_then(move |extrinsic| { + cli.and_then(move |rpc| rpc.submit_extrinsic(extrinsic)) + }) } /// Submits transaction to the chain and watch for events. - pub fn submit_and_watch( - &mut self, - call: C, + pub fn submit_and_watch( + &self, ) -> impl Future, Error = Error> { - let signer = self.signer.clone(); - let nonce = self.nonce.clone(); - let genesis_hash = self.client.genesis_hash.clone(); - self.set_nonce(nonce + 1.into()); - self.client.connect().and_then(move |rpc| { - rpc.submit_and_watch_extrinsic(signer, call, nonce, genesis_hash) - }) + let cli = self.client.connect(); + self.create_and_sign() + .into_future() + .map_err(Into::into) + .and_then(move |extrinsic| { + cli.and_then(move |rpc| rpc.submit_and_watch_extrinsic(extrinsic)) + }) } } #[cfg(test)] mod tests { use super::*; - use crate::srml::balances::{ - Balances, - BalancesCalls, - BalancesStore, + use crate::srml::{ + balances::{ + Balances, + BalancesStore, + BalancesXt, + }, + contracts::{ + Contracts, + ContractsXt, + }, }; use futures::stream::Stream; use parity_scale_codec::Encode; @@ -327,6 +434,8 @@ mod tests { type Balance = ::Balance; } + impl Contracts for Runtime {} + type Index = ::Index; type AccountId = ::AccountId; type Address = <::Lookup as StaticLookup>::Source; @@ -349,11 +458,41 @@ mod tests { let mut xt = rt.block_on(client.xt(signer, None)).unwrap(); let dest = AccountKeyring::Bob.pair().public(); - rt.block_on(xt.transfer(dest.clone().into(), 10_000)) - .unwrap(); + let transfer = xt + .balances(|calls| calls.transfer(dest.clone().into(), 10_000)) + .submit(); + rt.block_on(transfer).unwrap(); // check that nonce is handled correctly - rt.block_on(xt.transfer(dest.into(), 10_000)).unwrap(); + let transfer = xt + .increment_nonce() + .balances(|calls| calls.transfer(dest.clone().into(), 10_000)) + .submit(); + rt.block_on(transfer).unwrap(); + } + + #[test] + #[ignore] // requires locally running substrate node + fn test_tx_contract_put_code() { + let (mut rt, client) = test_setup(); + + let signer = AccountKeyring::Alice.pair(); + let xt = rt.block_on(client.xt(signer, None)).unwrap(); + + const CONTRACT: &str = r#" +(module + (func (export "call")) + (func (export "deploy")) +) +"#; + let wasm = wabt::wat2wasm(CONTRACT).expect("invalid wabt"); + + let put_code = xt + .contracts(|call| call.put_code(500_000, wasm)) + .submit_and_watch(); + + rt.block_on(put_code) + .expect("Extrinsic should be included in a block"); } #[test] diff --git a/src/metadata.rs b/src/metadata.rs index a81d03939c..4ec1cb9316 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -19,7 +19,7 @@ use std::{ }; use substrate_primitives::storage::StorageKey; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum MetadataError { ModuleNotFound(&'static str), CallNotFound(&'static str), diff --git a/src/rpc.rs b/src/rpc.rs index 9d27a92491..415ce74356 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -27,7 +27,6 @@ use jsonrpc_core_client::RpcChannel; use log; use num_traits::bounds::Bounded; use parity_scale_codec::{ - Codec, Decode, Encode, }; @@ -37,17 +36,11 @@ use runtime_primitives::{ generic::{ Block, SignedBlock, - UncheckedExtrinsic, }, - traits::StaticLookup, OpaqueExtrinsic, }; use std::convert::TryInto; -use substrate_primitives::{ - blake2_256, - storage::StorageKey, - Pair, -}; +use substrate_primitives::storage::StorageKey; use substrate_rpc::{ author::AuthorClient, chain::{ @@ -114,72 +107,6 @@ impl Rpc { } } -impl Rpc { - /// Create and submit an extrinsic and return corresponding Hash if successful - pub fn submit_extrinsic( - self, - signer: P, - call: C, - account_nonce: T::Index, - genesis_hash: T::Hash, - ) -> impl Future - where - C: Encode + Send, - P: Pair, - P::Public: Into<::Source>, - P::Signature: Codec, - { - let extrinsic = - Self::create_and_sign_extrinsic(&signer, call, account_nonce, genesis_hash); - - self.author - .submit_extrinsic(extrinsic.encode().into()) - .map_err(Into::into) - } - - /// Creates and signs an Extrinsic for the supplied `Call` - fn create_and_sign_extrinsic( - signer: &P, - call: C, - account_nonce: T::Index, - genesis_hash: T::Hash, - ) -> UncheckedExtrinsic< - ::Source, - C, - P::Signature, - T::SignedExtra, - > - where - C: Encode + Send, - P: Pair, - P::Public: Into<::Source>, - P::Signature: Codec, - { - log::info!( - "Creating Extrinsic with genesis hash {:?} and account nonce {:?}", - genesis_hash, - account_nonce - ); - - let extra = T::extra(account_nonce); - let raw_payload = (call, extra.clone(), (&genesis_hash, &genesis_hash)); - let signature = raw_payload.using_encoded(|payload| { - if payload.len() > 256 { - signer.sign(&blake2_256(payload)[..]) - } else { - signer.sign(payload) - } - }); - - UncheckedExtrinsic::new_signed( - raw_payload.0, - signer.public().into(), - signature.into(), - extra, - ) - } -} - use crate::ExtrinsicSuccess; use futures::{ future::IntoFuture, @@ -249,77 +176,64 @@ impl Rpc { .map_err(Into::into) } - /// Submit an extrinsic, waiting for it to be finalized. - /// If successful, returns the block hash. - fn submit_and_watch( + /// Create and submit an extrinsic and return corresponding Hash if successful + pub fn submit_extrinsic( self, - extrinsic: UncheckedExtrinsic< - ::Source, - C, - P::Signature, - T::SignedExtra, - >, + extrinsic: E, ) -> impl Future where - C: Encode + Send, - P: Pair, - P::Public: Into<::Source>, - P::Signature: Codec, + E: Encode, { self.author - .watch_extrinsic(extrinsic.encode().into()) + .submit_extrinsic(extrinsic.encode().into()) .map_err(Into::into) - .and_then(|stream| { - stream - .filter_map(|status| { - log::info!("received status {:?}", status); - match status { - // ignore in progress extrinsic for now - Status::Future | Status::Ready | Status::Broadcast(_) => None, - Status::Finalized(block_hash) => Some(Ok(block_hash)), - Status::Usurped(_) => Some(Err("Extrinsic Usurped".into())), - Status::Dropped => Some(Err("Extrinsic Dropped".into())), - Status::Invalid => Some(Err("Extrinsic Invalid".into())), - } - }) - .into_future() - .map_err(|(e, _)| e.into()) - .and_then(|(result, _)| { - result - .ok_or(Error::from("Stream terminated")) - .and_then(|r| r) - .into_future() - }) - }) } /// Create and submit an extrinsic and return corresponding Event if successful - pub fn submit_and_watch_extrinsic( + pub fn submit_and_watch_extrinsic( self, - signer: P, - call: C, - account_nonce: T::Index, - genesis_hash: T::Hash, + extrinsic: E, ) -> impl Future, Error = Error> where - C: Encode + Send, - P: Pair, - P::Public: Into<::Source>, - P::Signature: Codec, + E: Encode, { let events = self.subscribe_events().map_err(Into::into); events.and_then(move |events| { - let extrinsic = Self::create_and_sign_extrinsic( - &signer, - call, - account_nonce, - genesis_hash, - ); let ext_hash = T::Hashing::hash_of(&extrinsic); log::info!("Submitting Extrinsic `{:?}`", ext_hash); let chain = self.chain.clone(); - self.submit_and_watch::(extrinsic) + self.author + .watch_extrinsic(extrinsic.encode().into()) + .map_err(Into::into) + .and_then(|stream| { + stream + .filter_map(|status| { + log::info!("received status {:?}", status); + match status { + // ignore in progress extrinsic for now + Status::Future | Status::Ready | Status::Broadcast(_) => { + None + } + Status::Finalized(block_hash) => Some(Ok(block_hash)), + Status::Usurped(_) => { + Some(Err("Extrinsic Usurped".into())) + } + Status::Dropped => Some(Err("Extrinsic Dropped".into())), + Status::Invalid => Some(Err("Extrinsic Invalid".into())), + } + }) + .into_future() + .map_err(|(e, _)| e.into()) + .and_then(|(result, _)| { + log::info!("received result {:?}", result); + + result + .ok_or(Error::from("Stream terminated")) + .and_then(|r| r) + .into_future() + }) + }) .and_then(move |bh| { log::info!("Fetching block {:?}", bh); chain diff --git a/src/srml/balances.rs b/src/srml/balances.rs index a7d4ce0a85..2061f63825 100644 --- a/src/srml/balances.rs +++ b/src/srml/balances.rs @@ -1,9 +1,17 @@ //! Implements support for the srml_balances module. use crate::{ - codec::compact, + codec::{ + compact, + Encoded, + }, error::Error, - srml::system::System, + metadata::MetadataError, + srml::{ + system::System, + ModuleCalls, + }, Client, + Valid, XtBuilder, }; use futures::future::{ @@ -83,47 +91,52 @@ impl BalancesStore for Client { } /// The Balances extension trait for the XtBuilder. -pub trait BalancesCalls { +pub trait BalancesXt { /// Balances type. type Balances: Balances; + /// Keypair type + type Pair: Pair; + /// Create a call for the srml balances module + fn balances(&self, f: F) -> XtBuilder + where + F: FnOnce( + ModuleCalls, + ) -> Result; +} + +impl BalancesXt for XtBuilder +where + P: Pair, +{ + type Balances = T; + type Pair = P; + + fn balances(&self, f: F) -> XtBuilder + where + F: FnOnce( + ModuleCalls, + ) -> Result, + { + self.set_call("Balances", f) + } +} + +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. - fn transfer( - &mut self, - to: <::Lookup as StaticLookup>::Source, - amount: ::Balance, - ) -> Box::Hash, Error = Error> + Send>; -} - -impl BalancesCalls for XtBuilder -where - P: Pair, - P::Public: Into<<::Lookup as StaticLookup>::Source>, - P::Signature: Codec, -{ - type Balances = T; - - fn transfer( - &mut self, - to: <::Lookup as StaticLookup>::Source, - amount: ::Balance, - ) -> Box::Hash, Error = Error> + Send> - { - let transfer_call = || { - Ok(self - .metadata() - .module("Balances")? - .call("transfer", (to, compact(amount)))?) - }; - let call = match transfer_call() { - Ok(call) => call, - Err(err) => return Box::new(future::err(err)), - }; - Box::new(self.submit(call)) + pub fn transfer( + self, + to: <::Lookup as StaticLookup>::Source, + amount: ::Balance, + ) -> Result { + self.module.call("transfer", (to, compact(amount))) } } diff --git a/src/srml/contracts.rs b/src/srml/contracts.rs index bcea12cda2..a9d7b843d9 100644 --- a/src/srml/contracts.rs +++ b/src/srml/contracts.rs @@ -1,18 +1,18 @@ //! Implements support for the srml_contracts module. use crate::{ - codec::compact, - error::Error, + codec::{ + compact, + Encoded, + }, + metadata::MetadataError, srml::{ balances::Balances, system::System, + ModuleCalls, }, + Valid, XtBuilder, }; -use futures::future::{ - self, - Future, -}; -use parity_scale_codec::Codec; use runtime_primitives::traits::StaticLookup; use substrate_primitives::Pair; @@ -24,18 +24,51 @@ pub type Gas = u64; pub trait Contracts: System + Balances {} /// The Contracts extension trait for the XtBuilder. -pub trait ContractsCall { +pub trait ContractsXt { /// Contracts type. type Contracts: Contracts; + /// Key Pair Type + type Pair: Pair; + /// Create a call for the srml contracts module + fn contracts(&self, f: F) -> XtBuilder + where + F: FnOnce( + ModuleCalls, + ) -> Result; +} + +impl ContractsXt for XtBuilder +where + P: Pair, +{ + type Contracts = T; + type Pair = P; + + fn contracts(&self, f: F) -> XtBuilder + where + F: FnOnce( + ModuleCalls, + ) -> Result, + { + self.set_call("Contracts", f) + } +} + +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. - fn put_code( - &mut self, + pub fn put_code( + &self, gas_limit: Gas, code: Vec, - ) -> Box::Hash, Error = Error> + Send>; + ) -> 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. @@ -50,13 +83,18 @@ pub trait ContractsCall { /// of the account. That code will be invoked upon any call received by /// this account. /// - The contract is initialized. - fn create( - &mut self, - endowment: ::Balance, + pub fn create( + &self, + endowment: ::Balance, gas_limit: Gas, - code_hash: ::Hash, + code_hash: ::Hash, data: Vec, - ) -> Box::Hash, Error = Error> + Send>; + ) -> Result { + self.module.call( + "create", + (compact(endowment), compact(gas_limit), code_hash, data), + ) + } /// Makes a call to an account, optionally transferring some balance. /// @@ -66,81 +104,14 @@ pub trait ContractsCall { /// * 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. - fn call( - &mut self, - dest: <::Lookup as StaticLookup>::Source, - value: ::Balance, + pub fn call( + &self, + dest: <::Lookup as StaticLookup>::Source, + value: ::Balance, gas_limit: Gas, data: Vec, - ) -> Box::Hash, Error = Error> + Send>; -} - -impl ContractsCall for XtBuilder -where - P: Pair, - P::Public: Into<<::Lookup as StaticLookup>::Source>, - P::Signature: Codec, -{ - type Contracts = T; - - fn put_code( - &mut self, - gas_limit: Gas, - code: Vec, - ) -> Box::Hash, Error = Error> + Send> - { - let put_code_call = || { - Ok(self - .metadata() - .module("Contracts")? - .call("put_code", (compact(gas_limit), code))?) - }; - let call = match put_code_call() { - Ok(call) => call, - Err(err) => return Box::new(future::err(err)), - }; - Box::new(self.submit(call)) - } - - fn create( - &mut self, - endowment: ::Balance, - gas_limit: Gas, - code_hash: ::Hash, - data: Vec, - ) -> Box::Hash, Error = Error> + Send> - { - let create_call = || { - Ok(self.metadata().module("Contracts")?.call( - "create", - (compact(endowment), compact(gas_limit), code_hash, data), - )?) - }; - let call = match create_call() { - Ok(call) => call, - Err(err) => return Box::new(future::err(err)), - }; - Box::new(self.submit(call)) - } - - fn call( - &mut self, - dest: <::Lookup as StaticLookup>::Source, - value: ::Balance, - gas_limit: Gas, - data: Vec, - ) -> Box::Hash, Error = Error> + Send> - { - let call_call = || { - Ok(self - .metadata() - .module("Contracts")? - .call("call", (dest, compact(value), compact(gas_limit), data))?) - }; - let call = match call_call() { - Ok(call) => call, - Err(err) => return Box::new(future::err(err)), - }; - Box::new(self.submit(call)) + ) -> Result { + self.module + .call("call", (dest, compact(value), compact(gas_limit), data)) } } diff --git a/src/srml/mod.rs b/src/srml/mod.rs index 38cfc8eb1a..cce486afa6 100644 --- a/src/srml/mod.rs +++ b/src/srml/mod.rs @@ -1,5 +1,24 @@ //! Implements support for built-in runtime modules. +use crate::metadata::ModuleMetadata; +use std::marker::PhantomData; + pub mod balances; pub mod contracts; pub mod system; + +/// Creates module calls +pub struct ModuleCalls { + module: ModuleMetadata, + marker: PhantomData (T, P)>, +} + +impl ModuleCalls { + /// Create new module calls + pub fn new(module: &ModuleMetadata) -> Self { + ModuleCalls:: { + module: module.clone(), + marker: PhantomData, + } + } +} diff --git a/src/srml/system.rs b/src/srml/system.rs index d7cde34470..5226af1724 100644 --- a/src/srml/system.rs +++ b/src/srml/system.rs @@ -1,14 +1,17 @@ //! Implements support for the srml_system module. use crate::{ + codec::Encoded, error::Error, + metadata::MetadataError, + srml::ModuleCalls, Client, + Valid, XtBuilder, }; use futures::future::{ self, Future, }; -use parity_scale_codec::Codec; use runtime_primitives::traits::{ Bounded, CheckEqual, @@ -135,36 +138,43 @@ impl SystemStore for Client { } /// The System extension trait for the XtBuilder. -pub trait SystemCalls { +pub trait SystemXt { /// System type. type System: System; + /// Keypair type + type Pair: Pair; - /// Sets the new code. - fn set_code( - &mut self, - code: Vec, - ) -> Box::Hash, Error = Error> + Send>; + /// Create a call for the srml system module + fn system(&self, f: F) -> XtBuilder + where + F: FnOnce( + ModuleCalls, + ) -> Result; } -impl SystemCalls for XtBuilder +impl SystemXt for XtBuilder where P: Pair, - P::Public: Into<<::Lookup as StaticLookup>::Source>, - P::Signature: Codec, { type System = T; + type Pair = P; - fn set_code( - &mut self, - code: Vec, - ) -> Box::Hash, Error = Error> + Send> + fn system(&self, f: F) -> XtBuilder + where + F: FnOnce( + ModuleCalls, + ) -> Result, { - let set_code_call = - || Ok(self.metadata().module("System")?.call("set_code", code)?); - let call = match set_code_call() { - Ok(call) => call, - Err(err) => return Box::new(future::err(err)), - }; - Box::new(self.submit(call)) + self.set_call("System", f) + } +} + +impl ModuleCalls +where + P: Pair, +{ + /// Sets the new code. + pub fn set_code(&self, code: Vec) -> Result { + self.module.call("set_code", code) } }