Skip to content

Commit

Permalink
Refactor: simplify module call definitions (paritytech#24)
Browse files Browse the repository at this point in the history
* Refactor: simplify module call definitions

* Fix compilation errors after merge

* Add missing comments and remove unused imports

* Now it compiles
  • Loading branch information
ascjones authored Nov 21, 2019
1 parent 5242939 commit 17abfb4
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 322 deletions.
12 changes: 1 addition & 11 deletions src/codec.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
use parity_scale_codec::{
Encode,
EncodeAsRef,
HasCompact,
};
use parity_scale_codec::Encode;

#[derive(Clone)]
pub struct Encoded(pub Vec<u8>);
Expand All @@ -12,9 +8,3 @@ impl Encode for Encoded {
self.0.to_owned()
}
}

pub fn compact<T: HasCompact>(t: T) -> Encoded {
let encodable: <<T as HasCompact>::Type as EncodeAsRef<'_, T>>::RefType =
From::from(&t);
Encoded(encodable.encode())
}
84 changes: 27 additions & 57 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use metadata::Metadata;
use parity_scale_codec::{
Codec,
Decode,
Encode,
};
use runtime_primitives::{
generic::UncheckedExtrinsic,
Expand Down Expand Up @@ -61,15 +62,14 @@ use crate::{
DefaultExtra,
SignedExtra,
},
metadata::MetadataError,
palette::{
Call,
balances::Balances,
system::{
System,
SystemEvent,
SystemStore,
},
ModuleCalls,
},
rpc::{
BlockNumber,
Expand Down Expand Up @@ -266,30 +266,21 @@ impl<T: System + Balances + 'static, S: 'static> Client<T, S> {
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<T: System, P, S, V = Invalid> {
pub struct XtBuilder<T: System, P, S> {
client: Client<T, S>,
nonce: T::Index,
runtime_version: RuntimeVersion,
genesis_hash: T::Hash,
signer: P,
call: Option<Result<Encoded, MetadataError>>,
marker: PhantomData<fn() -> V>,
}

impl<T: System + Balances + 'static, P, S: 'static, V> XtBuilder<T, P, S, V>
impl<T: System + Balances + 'static, P, S: 'static> XtBuilder<T, P, S>
where
P: Pair,
{
Expand All @@ -304,51 +295,29 @@ where
}

/// Sets the nonce to a new value.
pub fn set_nonce(&mut self, nonce: T::Index) -> &mut XtBuilder<T, P, S, V> {
pub fn set_nonce(&mut self, nonce: T::Index) -> &mut XtBuilder<T, P, S> {
self.nonce = nonce;
self
}

/// Increment the nonce
pub fn increment_nonce(&mut self) -> &mut XtBuilder<T, P, S, V> {
pub fn increment_nonce(&mut self) -> &mut XtBuilder<T, P, S> {
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, S, 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(),
runtime_version: self.runtime_version.clone(),
genesis_hash: self.genesis_hash.clone(),
signer: self.signer.clone(),
call: Some(call),
marker: PhantomData,
}
}
}

impl<T: System + Balances + Send + Sync + 'static, P, S: 'static>
XtBuilder<T, P, S, Valid>
impl<T: System + Balances + Send + Sync + 'static, P, S: 'static> XtBuilder<T, P, S>
where
P: Pair,
S: Verify + Codec + From<P::Signature>,
S::Signer: From<P::Public> + IdentifyAccount<AccountId = T::AccountId>,
T::Address: From<T::AccountId>,
{
/// Creates and signs an Extrinsic for the supplied `Call`
pub fn create_and_sign(
pub fn create_and_sign<C>(
&self,
call: Call<C>,
) -> Result<
UncheckedExtrinsic<
T::Address,
Expand All @@ -357,15 +326,18 @@ where
<DefaultExtra<T> as SignedExtra<T>>::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 {:?}",
Expand All @@ -379,9 +351,9 @@ where
}

/// Submits a transaction to the chain.
pub fn submit(&self) -> impl Future<Item = T::Hash, Error = Error> {
pub fn submit<C: Encode>(&self, call: Call<C>) -> impl Future<Item = T::Hash, Error = Error> {
let cli = self.client.connect();
self.create_and_sign()
self.create_and_sign(call)
.into_future()
.map_err(Into::into)
.and_then(move |extrinsic| {
Expand All @@ -390,16 +362,17 @@ where
}

/// Submits transaction to the chain and watch for events.
pub fn submit_and_watch(
pub fn submit_and_watch<C: Encode>(
&self,
call: Call<C>
) -> impl Future<Item = ExtrinsicSuccess<T>, Error = Error> {
let cli = self.client.connect();
let metadata = self.client.metadata().clone();
let decoder = EventsDecoder::try_from(metadata)
.into_future()
.map_err(Into::into);

self.create_and_sign()
self.create_and_sign(call)
.into_future()
.map_err(Into::into)
.join(decoder)
Expand All @@ -419,9 +392,7 @@ mod tests {
balances::{
Balances,
BalancesStore,
BalancesXt,
},
contracts::ContractsXt,
},
DefaultNodeRuntime as Runtime,
};
Expand Down Expand Up @@ -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::<Runtime>(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::<Runtime>(dest.clone().into(), 10_000));

rt.block_on(transfer).unwrap();
}

Expand All @@ -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)
Expand Down Expand Up @@ -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::<Runtime>(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);

Expand Down
87 changes: 21 additions & 66 deletions src/palette/balances.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -101,61 +91,26 @@ impl<T: Balances + 'static, S: 'static> BalancesStore for Client<T, S> {
}
}

/// 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<F>(
&self,
f: F,
) -> XtBuilder<Self::Balances, Self::Pair, Self::Signature, Valid>
where
F: FnOnce(
ModuleCalls<Self::Balances, Self::Pair>,
) -> Result<Encoded, MetadataError>;
}

impl<T: Balances + 'static, P, S: 'static, V> BalancesXt for XtBuilder<T, P, S, V>
where
P: Pair,
S: Verify,
S::Signer: From<P::Public> + IdentifyAccount<AccountId = T::AccountId>,
{
type Balances = T;
type Pair = P;
type Signature = S;
const MODULE: &str = "Balances";
const TRANSFER: &str = "transfer";

fn balances<F>(&self, f: F) -> XtBuilder<T, P, S, Valid>
where
F: FnOnce(
ModuleCalls<Self::Balances, Self::Pair>,
) -> Result<Encoded, MetadataError>,
{
self.set_call("Balances", f)
}
/// Arguments for transferring a balance
#[derive(Encode)]
pub struct TransferArgs<T: Balances> {
to: <T as System>::Address,
#[codec(compact)]
amount: <T as Balances>::Balance
}

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.
pub fn transfer(
self,
to: <T as System>::Address,
amount: <T as Balances>::Balance,
) -> Result<Encoded, MetadataError> {
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<T: Balances>(
to: <T as System>::Address,
amount: <T as Balances>::Balance,
) -> Call<TransferArgs<T>> {
Call::new(MODULE, TRANSFER, TransferArgs { to, amount })
}
Loading

0 comments on commit 17abfb4

Please sign in to comment.