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
This commit is contained in:
Andrew Jones
2019-08-20 16:57:06 +01:00
committed by GitHub
parent 151c7f7e0a
commit d46b6a975e
9 changed files with 379 additions and 311 deletions
+2 -1
View File
@@ -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"
+1
View File
@@ -4,6 +4,7 @@ use parity_scale_codec::{
HasCompact,
};
#[derive(Clone)]
pub struct Encoded(pub Vec<u8>);
impl Encode for Encoded {
+176 -37
View File
@@ -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<T: System + 'static> Client<T> {
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<T: System, P> {
pub struct XtBuilder<T: System, P, V = Invalid> {
client: Client<T>,
nonce: T::Index,
genesis_hash: T::Hash,
signer: P,
call: Option<Result<Encoded, MetadataError>>,
marker: PhantomData<fn() -> V>,
}
impl<T: System + 'static, P> XtBuilder<T, P>
impl<T: System + 'static, P, V> XtBuilder<T, P, V>
where
P: Pair,
P::Public: Into<<T::Lookup as StaticLookup>::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<T, P, V> {
self.nonce = nonce;
self
}
/// Increment the nonce
pub fn increment_nonce(&mut self) -> &mut XtBuilder<T, P, V> {
self.set_nonce(self.nonce() + 1.into());
self
}
/// Sets the module call to a new value
pub fn set_call<F>(&self, module: &'static str, f: F) -> XtBuilder<T, P, Valid>
where
F: FnOnce(ModuleCalls<T, P>) -> Result<Encoded, MetadataError>,
{
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<T: System + 'static, P> XtBuilder<T, P, Valid>
where
P: Pair,
P::Public: Into<<T::Lookup as StaticLookup>::Source>,
P::Signature: Codec,
{
/// Creates and signs an Extrinsic for the supplied `Call`
pub fn create_and_sign(
&self,
) -> Result<
UncheckedExtrinsic<
<T::Lookup as StaticLookup>::Source,
Encoded,
P::Signature,
T::SignedExtra,
>,
MetadataError,
>
where
P: Pair,
P::Public: Into<<T::Lookup as StaticLookup>::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<C: Encode + Send>(
&mut self,
call: C,
) -> impl Future<Item = T::Hash, 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_extrinsic(signer, call, nonce, genesis_hash))
pub fn submit(&self) -> impl Future<Item = T::Hash, Error = Error> {
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<C: Encode + Send>(
&mut self,
call: C,
pub fn submit_and_watch(
&self,
) -> impl Future<Item = ExtrinsicSuccess<T>, 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 = <node_runtime::Runtime as srml_balances::Trait>::Balance;
}
impl Contracts for Runtime {}
type Index = <Runtime as System>::Index;
type AccountId = <Runtime as System>::AccountId;
type Address = <<Runtime as System>::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]
+1 -1
View File
@@ -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),
+40 -126
View File
@@ -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<T: System> Rpc<T> {
}
}
impl<T: System> Rpc<T> {
/// Create and submit an extrinsic and return corresponding Hash if successful
pub fn submit_extrinsic<C, P>(
self,
signer: P,
call: C,
account_nonce: T::Index,
genesis_hash: T::Hash,
) -> impl Future<Item = T::Hash, Error = Error>
where
C: Encode + Send,
P: Pair,
P::Public: Into<<T::Lookup as StaticLookup>::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<C, P>(
signer: &P,
call: C,
account_nonce: T::Index,
genesis_hash: T::Hash,
) -> UncheckedExtrinsic<
<T::Lookup as StaticLookup>::Source,
C,
P::Signature,
T::SignedExtra,
>
where
C: Encode + Send,
P: Pair,
P::Public: Into<<T::Lookup as StaticLookup>::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<T: System> Rpc<T> {
.map_err(Into::into)
}
/// Submit an extrinsic, waiting for it to be finalized.
/// If successful, returns the block hash.
fn submit_and_watch<C, P>(
/// Create and submit an extrinsic and return corresponding Hash if successful
pub fn submit_extrinsic<E>(
self,
extrinsic: UncheckedExtrinsic<
<T::Lookup as StaticLookup>::Source,
C,
P::Signature,
T::SignedExtra,
>,
extrinsic: E,
) -> impl Future<Item = T::Hash, Error = Error>
where
C: Encode + Send,
P: Pair,
P::Public: Into<<T::Lookup as StaticLookup>::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<C, P>(
pub fn submit_and_watch_extrinsic<E>(
self,
signer: P,
call: C,
account_nonce: T::Index,
genesis_hash: T::Hash,
extrinsic: E,
) -> impl Future<Item = ExtrinsicSuccess<T>, Error = Error>
where
C: Encode + Send,
P: Pair,
P::Public: Into<<T::Lookup as StaticLookup>::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::<C, P>(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
+48 -35
View File
@@ -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<T: Balances + 'static> BalancesStore for Client<T> {
}
/// 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<F>(&self, f: F) -> XtBuilder<Self::Balances, Self::Pair, Valid>
where
F: FnOnce(
ModuleCalls<Self::Balances, Self::Pair>,
) -> Result<Encoded, MetadataError>;
}
impl<T: Balances + 'static, P, V> BalancesXt for XtBuilder<T, P, V>
where
P: Pair,
{
type Balances = T;
type Pair = P;
fn balances<F>(&self, f: F) -> XtBuilder<T, P, Valid>
where
F: FnOnce(
ModuleCalls<Self::Balances, Self::Pair>,
) -> Result<Encoded, MetadataError>,
{
self.set_call("Balances", f)
}
}
impl<T: Balances + 'static, P> ModuleCalls<T, P>
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: <<Self::Balances as System>::Lookup as StaticLookup>::Source,
amount: <Self::Balances as Balances>::Balance,
) -> Box<dyn Future<Item = <Self::Balances as System>::Hash, Error = Error> + Send>;
}
impl<T: Balances + 'static, P> BalancesCalls for XtBuilder<T, P>
where
P: Pair,
P::Public: Into<<<T as System>::Lookup as StaticLookup>::Source>,
P::Signature: Codec,
{
type Balances = T;
fn transfer(
&mut self,
to: <<Self::Balances as System>::Lookup as StaticLookup>::Source,
amount: <Self::Balances as Balances>::Balance,
) -> Box<dyn Future<Item = <Self::Balances as System>::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: <<T as System>::Lookup as StaticLookup>::Source,
amount: <T as Balances>::Balance,
) -> Result<Encoded, MetadataError> {
self.module.call("transfer", (to, compact(amount)))
}
}
+61 -90
View File
@@ -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<F>(&self, f: F) -> XtBuilder<Self::Contracts, Self::Pair, Valid>
where
F: FnOnce(
ModuleCalls<Self::Contracts, Self::Pair>,
) -> Result<Encoded, MetadataError>;
}
impl<T: Contracts + 'static, P, V> ContractsXt for XtBuilder<T, P, V>
where
P: Pair,
{
type Contracts = T;
type Pair = P;
fn contracts<F>(&self, f: F) -> XtBuilder<T, P, Valid>
where
F: FnOnce(
ModuleCalls<Self::Contracts, Self::Pair>,
) -> Result<Encoded, MetadataError>,
{
self.set_call("Contracts", f)
}
}
impl<T: Contracts + 'static, P> ModuleCalls<T, P>
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<u8>,
) -> Box<dyn Future<Item = <Self::Contracts as System>::Hash, Error = Error> + Send>;
) -> Result<Encoded, MetadataError> {
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: <Self::Contracts as Balances>::Balance,
pub fn create(
&self,
endowment: <T as Balances>::Balance,
gas_limit: Gas,
code_hash: <Self::Contracts as System>::Hash,
code_hash: <T as System>::Hash,
data: Vec<u8>,
) -> Box<dyn Future<Item = <Self::Contracts as System>::Hash, Error = Error> + Send>;
) -> Result<Encoded, MetadataError> {
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: <<Self::Contracts as System>::Lookup as StaticLookup>::Source,
value: <Self::Contracts as Balances>::Balance,
pub fn call(
&self,
dest: <<T as System>::Lookup as StaticLookup>::Source,
value: <T as Balances>::Balance,
gas_limit: Gas,
data: Vec<u8>,
) -> Box<dyn Future<Item = <Self::Contracts as System>::Hash, Error = Error> + Send>;
}
impl<T: Contracts + 'static, P> ContractsCall for XtBuilder<T, P>
where
P: Pair,
P::Public: Into<<<T as System>::Lookup as StaticLookup>::Source>,
P::Signature: Codec,
{
type Contracts = T;
fn put_code(
&mut self,
gas_limit: Gas,
code: Vec<u8>,
) -> Box<dyn Future<Item = <Self::Contracts as System>::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: <Self::Contracts as Balances>::Balance,
gas_limit: Gas,
code_hash: <Self::Contracts as System>::Hash,
data: Vec<u8>,
) -> Box<dyn Future<Item = <Self::Contracts as System>::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: <<Self::Contracts as System>::Lookup as StaticLookup>::Source,
value: <Self::Contracts as Balances>::Balance,
gas_limit: Gas,
data: Vec<u8>,
) -> Box<dyn Future<Item = <Self::Contracts as System>::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<Encoded, MetadataError> {
self.module
.call("call", (dest, compact(value), compact(gas_limit), data))
}
}
+19
View File
@@ -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<T, P> {
module: ModuleMetadata,
marker: PhantomData<fn() -> (T, P)>,
}
impl<T, P> ModuleCalls<T, P> {
/// Create new module calls
pub fn new(module: &ModuleMetadata) -> Self {
ModuleCalls::<T, P> {
module: module.clone(),
marker: PhantomData,
}
}
}
+31 -21
View File
@@ -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<T: System + 'static> SystemStore for Client<T> {
}
/// 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<u8>,
) -> Box<dyn Future<Item = <Self::System as System>::Hash, Error = Error> + Send>;
/// Create a call for the srml system module
fn system<F>(&self, f: F) -> XtBuilder<Self::System, Self::Pair, Valid>
where
F: FnOnce(
ModuleCalls<Self::System, Self::Pair>,
) -> Result<Encoded, MetadataError>;
}
impl<T: System + 'static, P> SystemCalls for XtBuilder<T, P>
impl<T: System + 'static, P, V> SystemXt for XtBuilder<T, P, V>
where
P: Pair,
P::Public: Into<<<T as System>::Lookup as StaticLookup>::Source>,
P::Signature: Codec,
{
type System = T;
type Pair = P;
fn set_code(
&mut self,
code: Vec<u8>,
) -> Box<dyn Future<Item = <Self::System as System>::Hash, Error = Error> + Send>
fn system<F>(&self, f: F) -> XtBuilder<T, P, Valid>
where
F: FnOnce(
ModuleCalls<Self::System, Self::Pair>,
) -> Result<Encoded, MetadataError>,
{
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<T: System + 'static, P> ModuleCalls<T, P>
where
P: Pair,
{
/// Sets the new code.
pub fn set_code(&self, code: Vec<u8>) -> Result<Encoded, MetadataError> {
self.module.call("set_code", code)
}
}