diff --git a/Cargo.toml b/Cargo.toml
index 9c0490023d..5f183328aa 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -25,6 +25,8 @@ runtime_primitives = { git = "https://github.com/paritytech/substrate/", package
serde = { version = "1.0", features = ["derive"] }
sr-version = { git = "https://github.com/paritytech/substrate/", package = "sr-version" }
srml-system = { git = "https://github.com/paritytech/substrate/", package = "srml-system" }
+srml-balances = { git = "https://github.com/paritytech/substrate/", package = "srml-balances" }
+srml-contracts = { git = "https://github.com/paritytech/substrate/", package = "srml-contracts" }
substrate-rpc-api = { git = "https://github.com/paritytech/substrate/", package = "substrate-rpc-api" }
substrate-rpc-primitives = { git = "https://github.com/paritytech/substrate/", package = "substrate-rpc-primitives" }
substrate-primitives = { git = "https://github.com/paritytech/substrate/", package = "substrate-primitives" }
@@ -34,8 +36,6 @@ url = "1.7"
[dev-dependencies]
env_logger = "0.6"
node-runtime = { git = "https://github.com/paritytech/substrate/", package = "node-runtime" }
-srml-balances = { git = "https://github.com/paritytech/substrate/", package = "srml-balances" }
-srml-contracts = { git = "https://github.com/paritytech/substrate/", package = "srml-contracts" }
substrate-keyring = { git = "https://github.com/paritytech/substrate/", package = "substrate-keyring" }
tokio = "0.1"
wabt = "0.9.0"
diff --git a/src/error.rs b/src/error.rs
index 9557bcb6a2..9e9cfb98cb 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -20,6 +20,7 @@ use crate::{
};
use jsonrpc_core_client::RpcError;
use parity_scale_codec::Error as CodecError;
+use runtime_primitives::transaction_validity::TransactionValidityError;
use std::io::Error as IoError;
use substrate_primitives::crypto::SecretStringError;
@@ -39,6 +40,9 @@ pub enum Error {
SecretString(SecretStringError),
/// Metadata error.
Metadata(MetadataError),
+ /// Extrinsic validity error
+ #[display(fmt = "Transaction Validity Error: {:?}", _0)]
+ Invalid(TransactionValidityError),
/// Other error.
Other(String),
}
diff --git a/src/extrinsic.rs b/src/extrinsic.rs
new file mode 100644
index 0000000000..1f51cfdc2f
--- /dev/null
+++ b/src/extrinsic.rs
@@ -0,0 +1,263 @@
+// Copyright 2019 Parity Technologies (UK) Ltd.
+// This file is part of substrate-subxt.
+//
+// subxt is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// subxt is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with substrate-subxt. If not, see .
+
+use crate::srml::{
+ balances::Balances,
+ system::System,
+};
+use parity_scale_codec::{
+ Codec,
+ Decode,
+ Encode,
+};
+use runtime_primitives::{
+ generic::{
+ Era,
+ SignedPayload,
+ UncheckedExtrinsic,
+ },
+ traits::SignedExtension,
+ transaction_validity::TransactionValidityError,
+};
+use std::marker::PhantomData;
+use substrate_primitives::Pair;
+
+/// SignedExtra checks copied from substrate, in order to remove requirement to implement
+/// substrate's `srml_system::Trait`
+
+/// Ensure the runtime version registered in the transaction is the same as at present.
+///
+/// # Note
+///
+/// This is modified from the substrate version to allow passing in of the version, which is
+/// returned via `additional_signed()`.
+#[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)]
+pub struct CheckVersion(
+ PhantomData,
+ /// Local version to be used for `AdditionalSigned`
+ #[codec(skip)]
+ u32,
+);
+
+impl SignedExtension for CheckVersion where T: System + Send + Sync {
+ type AccountId = u64;
+ type Call = ();
+ type AdditionalSigned = u32;
+ type Pre = ();
+ fn additional_signed(&self) -> Result {
+ Ok(self.1)
+ }
+}
+
+/// Check genesis hash
+///
+/// # Note
+///
+/// This is modified from the substrate version to allow passing in of the genesis hash, which is
+/// returned via `additional_signed()`.
+#[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)]
+pub struct CheckGenesis(
+ PhantomData,
+ /// Local genesis hash to be used for `AdditionalSigned`
+ #[codec(skip)]
+ T::Hash,
+);
+
+impl SignedExtension for CheckGenesis where T: System + Send + Sync {
+ type AccountId = u64;
+ type Call = ();
+ type AdditionalSigned = T::Hash;
+ type Pre = ();
+ fn additional_signed(&self) -> Result {
+ Ok(self.1)
+ }
+}
+
+/// Check for transaction mortality.
+///
+/// # Note
+///
+/// This is modified from the substrate version to allow passing in of the genesis hash, which is
+/// returned via `additional_signed()`. It assumes therefore `Era::Immortal` (The transaction is
+/// valid forever)
+#[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)]
+pub struct CheckEra(
+ /// The default structure for the Extra encoding
+ (Era, PhantomData),
+ /// Local genesis hash to be used for `AdditionalSigned`
+ #[codec(skip)]
+ T::Hash,
+);
+
+impl SignedExtension for CheckEra where T: System + Send + Sync {
+ type AccountId = u64;
+ type Call = ();
+ type AdditionalSigned = T::Hash;
+ type Pre = ();
+ fn additional_signed(&self) -> Result {
+ Ok(self.1)
+ }
+}
+
+/// Nonce check and increment to give replay protection for transactions.
+#[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)]
+pub struct CheckNonce(#[codec(compact)] T::Index);
+
+impl SignedExtension for CheckNonce where T: System + Send + Sync {
+ type AccountId = u64;
+ type Call = ();
+ type AdditionalSigned = ();
+ type Pre = ();
+ fn additional_signed(&self) -> Result {
+ Ok(())
+ }
+}
+
+/// Resource limit check.
+#[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)]
+pub struct CheckWeight(PhantomData);
+
+impl SignedExtension for CheckWeight where T: System + Send + Sync {
+ type AccountId = u64;
+ type Call = ();
+ type AdditionalSigned = ();
+ type Pre = ();
+ fn additional_signed(&self) -> Result {
+ Ok(())
+ }
+}
+
+/// Require the transactor pay for themselves and maybe include a tip to gain additional priority
+/// in the queue.
+#[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)]
+pub struct TakeFees(#[codec(compact)] T::Balance);
+
+impl SignedExtension for TakeFees where T: Balances + Send + Sync {
+ type AccountId = u64;
+ type Call = ();
+ type AdditionalSigned = ();
+ type Pre = ();
+ fn additional_signed(&self) -> Result {
+ Ok(())
+ }
+}
+
+/// Checks if a transaction would exhausts the block gas limit.
+#[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)]
+pub struct CheckBlockGasLimit(PhantomData);
+
+impl SignedExtension for CheckBlockGasLimit where T: System + Send + Sync {
+ type AccountId = u64;
+ type Call = ();
+ type AdditionalSigned = ();
+ type Pre = ();
+ fn additional_signed(&self) -> Result {
+ Ok(())
+ }
+}
+
+pub trait SignedExtra {
+ type Extra: SignedExtension;
+
+ fn extra(&self) -> Self::Extra;
+}
+
+#[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)]
+pub struct DefaultExtra {
+ version: u32,
+ nonce: T::Index,
+ genesis_hash: T::Hash,
+}
+
+impl DefaultExtra {
+ pub fn new(version: u32, nonce: T::Index, genesis_hash: T::Hash) -> Self {
+ DefaultExtra {
+ version,
+ nonce,
+ genesis_hash,
+ }
+ }
+}
+
+impl SignedExtra for DefaultExtra {
+ type Extra = (
+ CheckVersion,
+ CheckGenesis,
+ CheckEra,
+ CheckNonce,
+ CheckWeight,
+ TakeFees,
+ CheckBlockGasLimit,
+ );
+
+ fn extra(&self) -> Self::Extra {
+ (
+ CheckVersion(PhantomData, self.version),
+ CheckGenesis(PhantomData, self.genesis_hash),
+ CheckEra((Era::Immortal, PhantomData), self.genesis_hash),
+ CheckNonce(self.nonce),
+ CheckWeight(PhantomData),
+ TakeFees(::Balance::default()),
+ CheckBlockGasLimit(PhantomData),
+ )
+ }
+}
+
+impl SignedExtension for DefaultExtra {
+ type AccountId = T::AccountId;
+ type Call = ();
+ type AdditionalSigned =
+ <>::Extra as SignedExtension>::AdditionalSigned;
+ type Pre = ();
+
+ fn additional_signed(
+ &self,
+ ) -> Result {
+ self.extra().additional_signed()
+ }
+}
+
+pub fn create_and_sign(
+ signer: P,
+ call: C,
+ extra: E,
+) -> Result<
+ UncheckedExtrinsic<
+ T::Address,
+ C,
+ P::Signature,
+ >::Extra,
+ >,
+ TransactionValidityError,
+>
+where
+ P: Pair,
+ P::Public: Into,
+ P::Signature: Codec,
+ C: Encode,
+ E: SignedExtra + SignedExtension,
+{
+ let raw_payload = SignedPayload::new(call, extra.extra())?;
+ let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
+ let (call, extra, _) = raw_payload.deconstruct();
+
+ Ok(UncheckedExtrinsic::new_signed(
+ call,
+ signer.public().into(),
+ signature.into(),
+ extra,
+ ))
+}
diff --git a/src/lib.rs b/src/lib.rs
index 166e8a2fab..4cbc3e66f8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -31,19 +31,14 @@ use metadata::Metadata;
use parity_scale_codec::{
Codec,
Decode,
- Encode,
-};
-use runtime_primitives::{
- generic::UncheckedExtrinsic,
- traits::StaticLookup,
};
+use runtime_primitives::generic::UncheckedExtrinsic;
use sr_version::RuntimeVersion;
use std::{
convert::TryFrom,
marker::PhantomData,
};
use substrate_primitives::{
- blake2_256,
storage::{
StorageChangeSet,
StorageKey,
@@ -55,6 +50,10 @@ use url::Url;
use crate::{
codec::Encoded,
events::EventsDecoder,
+ extrinsic::{
+ DefaultExtra,
+ SignedExtra,
+ },
metadata::MetadataError,
rpc::{
BlockNumber,
@@ -76,6 +75,7 @@ use crate::{
mod codec;
mod error;
mod events;
+mod extrinsic;
mod metadata;
mod rpc;
mod srml;
@@ -235,7 +235,7 @@ impl Client {
) -> impl Future- , Error = Error>
where
P: Pair,
- P::Public: Into + Into<::Source>,
+ P::Public: Into + Into,
P::Signature: Codec,
{
let client = self.clone();
@@ -324,10 +324,10 @@ where
}
}
-impl XtBuilder
+impl XtBuilder
where
P: Pair,
- P::Public: Into<::Source>,
+ P::Public: Into,
P::Signature: Codec,
{
/// Creates and signs an Extrinsic for the supplied `Call`
@@ -335,16 +335,16 @@ where
&self,
) -> Result<
UncheckedExtrinsic<
- ::Source,
+ T::Address,
Encoded,
P::Signature,
- T::SignedExtra,
+ as SignedExtra>::Extra,
>,
- MetadataError,
+ Error,
>
where
P: Pair,
- P::Public: Into<::Source>,
+ P::Public: Into,
P::Signature: Codec,
{
let signer = self.signer.clone();
@@ -362,27 +362,9 @@ where
account_nonce
);
- let extra = T::extra(account_nonce);
- let raw_payload = (
- call.clone(),
- extra.clone(),
- version,
- (&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,
- ))
+ let extra = extrinsic::DefaultExtra::new(version, account_nonce, genesis_hash);
+ let xt = extrinsic::create_and_sign(signer, call, extra)?;
+ Ok(xt)
}
/// Submits a transaction to the chain.
@@ -427,14 +409,11 @@ mod tests {
BalancesStore,
BalancesXt,
},
- contracts::{
- Contracts,
- ContractsXt,
- },
+ contracts::ContractsXt,
};
use futures::stream::Stream;
+ use node_runtime::Runtime;
use parity_scale_codec::Encode;
- use runtime_primitives::generic::Era;
use runtime_support::StorageMap;
use substrate_keyring::AccountKeyring;
use substrate_primitives::{
@@ -442,47 +421,9 @@ mod tests {
Pair,
};
- struct Runtime;
-
- impl System for Runtime {
- type Index = ::Index;
- type BlockNumber = ::BlockNumber;
- type Hash = ::Hash;
- type Hashing = ::Hashing;
- type AccountId = ::AccountId;
- type Lookup = ::Lookup;
- type Header = ::Header;
- type Event = ::Event;
-
- type SignedExtra = (
- srml_system::CheckVersion,
- srml_system::CheckGenesis,
- srml_system::CheckEra,
- srml_system::CheckNonce,
- srml_system::CheckWeight,
- srml_balances::TakeFees,
- );
- fn extra(nonce: Self::Index) -> Self::SignedExtra {
- (
- srml_system::CheckVersion::::new(),
- srml_system::CheckGenesis::::new(),
- srml_system::CheckEra::::from(Era::Immortal),
- srml_system::CheckNonce::::from(nonce),
- srml_system::CheckWeight::::new(),
- srml_balances::TakeFees::::from(0),
- )
- }
- }
-
- impl Balances for Runtime {
- type Balance = ::Balance;
- }
-
- impl Contracts for Runtime {}
-
type Index = ::Index;
type AccountId = ::AccountId;
- type Address = <::Lookup as StaticLookup>::Source;
+ type Address = ::Address;
type Balance = ::Balance;
fn test_setup() -> (tokio::runtime::Runtime, Client) {
diff --git a/src/srml/balances.rs b/src/srml/balances.rs
index 2061f63825..425815f391 100644
--- a/src/srml/balances.rs
+++ b/src/srml/balances.rs
@@ -23,7 +23,6 @@ use runtime_primitives::traits::{
MaybeSerializeDebug,
Member,
SimpleArithmetic,
- StaticLookup,
};
use runtime_support::Parameter;
use substrate_primitives::Pair;
@@ -41,6 +40,14 @@ pub trait Balances: System {
+ From<::BlockNumber>;
}
+/// Blanket impl for using existing runtime types
+impl Balances for T
+where
+ ::Header: serde::de::DeserializeOwned,
+{
+ type Balance = T::Balance;
+}
+
/// The Balances extension trait for the Client.
pub trait BalancesStore {
/// Balances type.
@@ -134,7 +141,7 @@ where
/// of the transfer, the account will be reaped.
pub fn transfer(
self,
- to: <::Lookup as StaticLookup>::Source,
+ to: ::Address,
amount: ::Balance,
) -> Result {
self.module.call("transfer", (to, compact(amount)))
diff --git a/src/srml/contracts.rs b/src/srml/contracts.rs
index 12873156d2..d6e8e41e0e 100644
--- a/src/srml/contracts.rs
+++ b/src/srml/contracts.rs
@@ -13,7 +13,6 @@ use crate::{
Valid,
XtBuilder,
};
-use runtime_primitives::traits::StaticLookup;
use substrate_primitives::Pair;
/// Gas units are chosen to be represented by u64 so that gas metering
@@ -23,6 +22,18 @@ pub type Gas = u64;
/// The subset of the `srml_contracts::Trait` that a client must implement.
pub trait Contracts: System + Balances {}
+/// Blanket impl for using existing runtime types
+impl<
+ T: srml_contracts::Trait
+ + srml_system::Trait
+ + srml_balances::Trait
+ + std::fmt::Debug,
+ > Contracts for T
+where
+ ::Header: serde::de::DeserializeOwned,
+{
+}
+
/// The Contracts extension trait for the XtBuilder.
pub trait ContractsXt {
/// Contracts type.
@@ -106,7 +117,7 @@ where
/// will be transferred.
pub fn call(
&self,
- dest: <::Lookup as StaticLookup>::Source,
+ dest: ::Address,
value: ::Balance,
gas_limit: Gas,
data: Vec,
diff --git a/src/srml/system.rs b/src/srml/system.rs
index f377682486..921d3c5b0c 100644
--- a/src/srml/system.rs
+++ b/src/srml/system.rs
@@ -15,27 +15,27 @@ use futures::future::{
self,
Future,
};
+use parity_scale_codec::Codec;
use runtime_primitives::traits::{
Bounded,
CheckEqual,
Hash,
Header,
+ MaybeDebug,
MaybeDisplay,
MaybeSerializeDebug,
MaybeSerializeDebugButNotDeserialize,
Member,
- SignedExtension,
SimpleArithmetic,
SimpleBitOps,
StaticLookup,
};
use runtime_support::Parameter;
use serde::de::DeserializeOwned;
-use srml_system::Event;
use substrate_primitives::Pair;
/// The subset of the `srml_system::Trait` that a client must implement.
-pub trait System {
+pub trait System: 'static + Eq + Clone + std::fmt::Debug {
/// Account index (aka nonce) type. This stores the number of previous
/// transactions associated with a sender account.
type Index: Parameter
@@ -81,28 +81,27 @@ pub trait System {
+ Ord
+ Default;
- /// Converting trait to take a source type and convert to `AccountId`.
- ///
- /// Used to define the type and conversion mechanism for referencing
- /// accounts in transactions. It's perfectly reasonable for this to be an
- /// identity conversion (with the source type being `AccountId`), but other
- /// modules (e.g. Indices module) may provide more functional/efficient
- /// alternatives.
- type Lookup: StaticLookup;
+ /// The address type. This instead of `::Source`.
+ type Address: Codec + Clone + PartialEq + MaybeDebug;
/// The block header.
type Header: Parameter
+ Header
+ DeserializeOwned;
+}
- /// The aggregated event type of the runtime.
- type Event: Parameter + Member + From;
-
- /// The `SignedExtension` to the basic transaction logic.
- type SignedExtra: SignedExtension;
-
- /// Creates the `SignedExtra` from the account nonce.
- fn extra(nonce: Self::Index) -> Self::SignedExtra;
+/// Blanket impl for using existing runtime types
+impl System for T
+where
+ ::Header: serde::de::DeserializeOwned,
+{
+ type Index = T::Index;
+ type BlockNumber = T::BlockNumber;
+ type Hash = T::Hash;
+ type Hashing = T::Hashing;
+ type AccountId = T::AccountId;
+ type Address = ::Source;
+ type Header = T::Header;
}
/// The System extension trait for the Client.