mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
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:
+2
-1
@@ -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"
|
||||
|
||||
@@ -4,6 +4,7 @@ use parity_scale_codec::{
|
||||
HasCompact,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Encoded(pub Vec<u8>);
|
||||
|
||||
impl Encode for Encoded {
|
||||
|
||||
+176
-37
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user