diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 3343942cc1..d369bbb5f6 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -2473,9 +2473,11 @@ version = "2.0.0" dependencies = [ "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", + "node-runtime 2.0.0", "sr-primitives 2.0.0", "srml-contracts-rpc 2.0.0", "srml-system-rpc 2.0.0", + "srml-transaction-payment-rpc 2.0.0", "substrate-client 2.0.0", "substrate-transaction-pool 2.0.0", ] @@ -2534,6 +2536,7 @@ dependencies = [ "srml-system-rpc-runtime-api 2.0.0", "srml-timestamp 2.0.0", "srml-transaction-payment 2.0.0", + "srml-transaction-payment-rpc-runtime-api 2.0.0", "srml-treasury 2.0.0", "srml-utility 2.0.0", "substrate-client 2.0.0", @@ -4617,9 +4620,37 @@ dependencies = [ "srml-balances 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", + "srml-transaction-payment-rpc-runtime-api 2.0.0", "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-transaction-payment-rpc" +version = "2.0.0" +dependencies = [ + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 2.0.0", + "srml-transaction-payment-rpc-runtime-api 2.0.0", + "substrate-client 2.0.0", + "substrate-primitives 2.0.0", + "substrate-rpc-primitives 2.0.0", +] + +[[package]] +name = "srml-transaction-payment-rpc-runtime-api" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "substrate-client 2.0.0", +] + [[package]] name = "srml-treasury" version = "2.0.0" diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index 2c1e361fc9..2d68511b2e 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -82,6 +82,7 @@ members = [ "srml/aura", "srml/balances", "srml/contracts", + "srml/contracts/rpc", "srml/collective", "srml/democracy", "srml/elections", @@ -109,6 +110,7 @@ members = [ "srml/timestamp", "srml/treasury", "srml/transaction-payment", + "srml/transaction-payment/rpc", "srml/utility", "node/cli", "node/executor", diff --git a/substrate/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/substrate/core/sr-primitives/src/generic/unchecked_extrinsic.rs index c7bff1f4c8..befa857dff 100644 --- a/substrate/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/substrate/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -23,6 +23,7 @@ use codec::{Decode, Encode, EncodeLike, Input, Error}; use crate::{ traits::{self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic, IdentifyAccount}, generic::CheckedExtrinsic, transaction_validity::{TransactionValidityError, InvalidTransaction}, + weights::{GetDispatchInfo, DispatchInfo}, }; const TRANSACTION_VERSION: u8 = 4; @@ -280,6 +281,17 @@ where } } +impl GetDispatchInfo + for UncheckedExtrinsic +where + Call: GetDispatchInfo, + Extra: SignedExtension, +{ + fn get_dispatch_info(&self) -> DispatchInfo { + self.function.get_dispatch_info() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/substrate/core/sr-primitives/src/weights.rs b/substrate/core/sr-primitives/src/weights.rs index 89852eb595..088f13244e 100644 --- a/substrate/core/sr-primitives/src/weights.rs +++ b/substrate/core/sr-primitives/src/weights.rs @@ -35,9 +35,13 @@ //! Note that the decl_module macro _cannot_ enforce this and will simply fail if an invalid struct //! (something that does not implement `Weighable`) is passed in. +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; +use codec::{Encode, Decode}; use arithmetic::traits::Bounded; use crate::RuntimeDebug; +/// Re-export priority as type pub use crate::transaction_validity::TransactionPriority; /// Numeric range of a transaction weight. @@ -58,10 +62,10 @@ pub trait ClassifyDispatch { fn classify_dispatch(&self, target: T) -> DispatchClass; } -/// A generalized group of dispatch types. This is only distinguishing normal, user-triggered -/// transactions (`Normal`) and anything beyond which serves a higher purpose to the system -/// (`Operational`). -#[derive(PartialEq, Eq, Clone, Copy, RuntimeDebug)] +/// A generalized group of dispatch types. This is only distinguishing normal, user-triggered transactions +/// (`Normal`) and anything beyond which serves a higher purpose to the system (`Operational`). +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] pub enum DispatchClass { /// A normal dispatch. Normal, diff --git a/substrate/node/rpc/Cargo.toml b/substrate/node/rpc/Cargo.toml index 5d2ca81e0f..5e8b761489 100644 --- a/substrate/node/rpc/Cargo.toml +++ b/substrate/node/rpc/Cargo.toml @@ -8,7 +8,9 @@ edition = "2018" client = { package = "substrate-client", path = "../../core/client" } jsonrpc-core = "13.2.0" node-primitives = { path = "../primitives" } +node-runtime = { path = "../runtime" } sr-primitives = { path = "../../core/sr-primitives" } srml-contracts-rpc = { path = "../../srml/contracts/rpc/" } +srml-transaction-payment-rpc = { path = "../../srml/transaction-payment/rpc/" } srml-system-rpc = { path = "../../srml/system/rpc/" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } diff --git a/substrate/node/rpc/src/lib.rs b/substrate/node/rpc/src/lib.rs index 398d458e63..99321373f8 100644 --- a/substrate/node/rpc/src/lib.rs +++ b/substrate/node/rpc/src/lib.rs @@ -32,6 +32,7 @@ use std::sync::Arc; use node_primitives::{Block, AccountId, Index, Balance}; +use node_runtime::UncheckedExtrinsic; use sr_primitives::traits::ProvideRuntimeApi; use transaction_pool::txpool::{ChainApi, Pool}; @@ -42,18 +43,23 @@ pub fn create(client: Arc, pool: Arc>) -> jsonrpc_core::IoHa C: Send + Sync + 'static, C::Api: srml_system_rpc::AccountNonceApi, C::Api: srml_contracts_rpc::ContractsRuntimeApi, + C::Api: srml_transaction_payment_rpc::TransactionPaymentRuntimeApi, P: ChainApi + Sync + Send + 'static, M: jsonrpc_core::Metadata + Default, { use srml_system_rpc::{System, SystemApi}; use srml_contracts_rpc::{Contracts, ContractsApi}; + use srml_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; let mut io = jsonrpc_core::IoHandler::default(); io.extend_with( SystemApi::to_delegate(System::new(client.clone(), pool)) ); io.extend_with( - ContractsApi::to_delegate(Contracts::new(client)) + ContractsApi::to_delegate(Contracts::new(client.clone())) + ); + io.extend_with( + TransactionPaymentApi::to_delegate(TransactionPayment::new(client)) ); io } diff --git a/substrate/node/runtime/Cargo.toml b/substrate/node/runtime/Cargo.toml index 94a7683dc5..0aa2dc551e 100644 --- a/substrate/node/runtime/Cargo.toml +++ b/substrate/node/runtime/Cargo.toml @@ -52,6 +52,7 @@ timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default treasury = { package = "srml-treasury", path = "../../srml/treasury", default-features = false } utility = { package = "srml-utility", path = "../../srml/utility", default-features = false } transaction-payment = { package = "srml-transaction-payment", path = "../../srml/transaction-payment", default-features = false } +transaction-payment-rpc-runtime-api = { package = "srml-transaction-payment-rpc-runtime-api", path = "../../srml/transaction-payment/rpc/runtime-api/", default-features = false } [build-dependencies] wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.4", path = "../../core/utils/wasm-builder-runner" } @@ -103,5 +104,6 @@ std = [ "treasury/std", "utility/std", "transaction-payment/std", + "transaction-payment-rpc-runtime-api/std", "version/std", ] diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index a6bd25a73e..3dba79d27b 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -50,6 +50,8 @@ use version::NativeVersion; use primitives::OpaqueMetadata; use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; use im_online::sr25519::{AuthorityId as ImOnlineId}; +use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; +use contracts_rpc_runtime_api::ContractExecResult; use system::offchain::TransactionSubmitter; #[cfg(any(feature = "std", test))] @@ -661,9 +663,7 @@ impl_runtime_apis! { value: Balance, gas_limit: u64, input_data: Vec, - ) -> contracts_rpc_runtime_api::ContractExecResult { - use contracts_rpc_runtime_api::ContractExecResult; - + ) -> ContractExecResult { let exec_result = Contracts::bare_call( origin, dest.into(), @@ -681,9 +681,20 @@ impl_runtime_apis! { } } + impl transaction_payment_rpc_runtime_api::TransactionPaymentApi< + Block, + Balance, + UncheckedExtrinsic, + > for Runtime { + fn query_info(uxt: UncheckedExtrinsic, len: u32) -> RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + } + impl substrate_session::SessionKeys for Runtime { fn generate_session_keys(seed: Option>) -> Vec { - let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s).expect("Seed is an utf8 string")); + let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s) + .expect("Seed is an utf8 string")); SessionKeys::generate(seed) } } diff --git a/substrate/srml/executive/src/lib.rs b/substrate/srml/executive/src/lib.rs index 401f07d206..927a7fef25 100644 --- a/substrate/srml/executive/src/lib.rs +++ b/substrate/srml/executive/src/lib.rs @@ -571,7 +571,7 @@ mod tests { assert!(Executive::apply_extrinsic(x2.clone()).unwrap().is_ok()); // default weight for `TestXt` == encoded length. - assert_eq!(>::all_extrinsics_weight(), (3 * len).into()); + assert_eq!(>::all_extrinsics_weight(), (3 * len) as u32); assert_eq!(>::all_extrinsics_len(), 3 * len); let _ = >::finalize(); diff --git a/substrate/srml/transaction-payment/Cargo.toml b/substrate/srml/transaction-payment/Cargo.toml index 7f8eddab19..cbce1e945e 100644 --- a/substrate/srml/transaction-payment/Cargo.toml +++ b/substrate/srml/transaction-payment/Cargo.toml @@ -10,6 +10,7 @@ rstd = { package = "sr-std", path = "../../core/sr-std", default-features = fals sr-primitives = { path = "../../core/sr-primitives", default-features = false } support = { package = "srml-support", path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } +transaction-payment-rpc-runtime-api = { package = "srml-transaction-payment-rpc-runtime-api", path = "./rpc/runtime-api", default-features = false } [dev-dependencies] runtime-io = { package = "sr-io", path = "../../core/sr-io" } @@ -24,4 +25,5 @@ std = [ "sr-primitives/std", "support/std", "system/std", + "transaction-payment-rpc-runtime-api/std" ] diff --git a/substrate/srml/transaction-payment/rpc/Cargo.toml b/substrate/srml/transaction-payment/rpc/Cargo.toml new file mode 100644 index 0000000000..e3dc6f553f --- /dev/null +++ b/substrate/srml/transaction-payment/rpc/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "srml-transaction-payment-rpc" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../../core/client" } +codec = { package = "parity-scale-codec", version = "1.0.0" } +jsonrpc-core = "13.2.0" +jsonrpc-core-client = "13.2.0" +jsonrpc-derive = "13.2.0" +primitives = { package = "substrate-primitives", path = "../../../core/primitives" } +rpc-primitives = { package = "substrate-rpc-primitives", path = "../../../core/rpc/primitives" } +serde = { version = "1.0.101", features = ["derive"] } +sr-primitives = { path = "../../../core/sr-primitives" } +srml-transaction-payment-rpc-runtime-api = { path = "./runtime-api" } diff --git a/substrate/srml/transaction-payment/rpc/runtime-api/Cargo.toml b/substrate/srml/transaction-payment/rpc/runtime-api/Cargo.toml new file mode 100644 index 0000000000..c26f295f4b --- /dev/null +++ b/substrate/srml/transaction-payment/rpc/runtime-api/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "srml-transaction-payment-rpc-runtime-api" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +serde = { version = "1.0.101", optional = true, features = ["derive"] } +client = { package = "substrate-client", path = "../../../../core/client", default-features = false } +codec = { package = "parity-scale-codec", version = "1.0.6", default-features = false, features = ["derive"] } +rstd = { package = "sr-std", path = "../../../../core/sr-std", default-features = false } +sr-primitives = { path = "../../../../core/sr-primitives", default-features = false } + +[features] +default = ["std"] +std = [ + "serde", + "client/std", + "codec/std", + "rstd/std", + "sr-primitives/std", +] diff --git a/substrate/srml/transaction-payment/rpc/runtime-api/src/lib.rs b/substrate/srml/transaction-payment/rpc/runtime-api/src/lib.rs new file mode 100644 index 0000000000..dc6360ca88 --- /dev/null +++ b/substrate/srml/transaction-payment/rpc/runtime-api/src/lib.rs @@ -0,0 +1,47 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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. If not, see . + +//! Runtime API definition for transaction payment module. + +#![cfg_attr(not(feature = "std"), no_std)] + +use rstd::prelude::*; +use sr_primitives::weights::{Weight, DispatchClass}; +use codec::{Encode, Codec, Decode}; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +/// Some information related to a dispatchable that can be queried from the runtime. +#[derive(Eq, PartialEq, Encode, Decode, Default)] +#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +pub struct RuntimeDispatchInfo { + /// Weight of this dispatch. + pub weight: Weight, + /// Class of this dispatch. + pub class: DispatchClass, + /// The partial inclusion fee of this dispatch. This does not include tip or anything else which + /// is dependent on the signature (aka. depends on a `SignedExtension`). + pub partial_fee: Balance, +} + +client::decl_runtime_apis! { + pub trait TransactionPaymentApi where + Balance: Codec, + Extrinsic: Codec, + { + fn query_info(uxt: Extrinsic, len: u32) -> RuntimeDispatchInfo; + } +} diff --git a/substrate/srml/transaction-payment/rpc/src/lib.rs b/substrate/srml/transaction-payment/rpc/src/lib.rs new file mode 100644 index 0000000000..6ee3c7eddb --- /dev/null +++ b/substrate/srml/transaction-payment/rpc/src/lib.rs @@ -0,0 +1,108 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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. If not, see . + +//! RPC interface for the transaction payment module. + +use std::sync::Arc; +use codec::{Codec, Decode}; +use client::blockchain::HeaderBackend; +use jsonrpc_core::{Error as RpcError, ErrorCode, Result}; +use jsonrpc_derive::rpc; +use sr_primitives::{ + generic::BlockId, + traits::{Block as BlockT, ProvideRuntimeApi}, +}; +use primitives::Bytes; +use srml_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; +pub use srml_transaction_payment_rpc_runtime_api::TransactionPaymentApi as TransactionPaymentRuntimeApi; +pub use self::gen_client::Client as TransactionPaymentClient; + +#[rpc] +pub trait TransactionPaymentApi { + #[rpc(name = "payment_queryInfo")] + fn query_info( + &self, + encoded_xt: Bytes, + at: Option + ) -> Result>; +} + +/// A struct that implements the [`TransactionPaymentApi`]. +pub struct TransactionPayment { + client: Arc, + _marker: std::marker::PhantomData

, +} + +impl TransactionPayment { + /// Create new `TransactionPayment` with the given reference to the client. + pub fn new(client: Arc) -> Self { + TransactionPayment { client, _marker: Default::default() } + } +} + +/// Error type of this RPC api. +pub enum Error { + /// The transaction was not decodable. + DecodeError, + /// The call to runtime failed. + RuntimeError, +} + +impl From for i64 { + fn from(e: Error) -> i64 { + match e { + Error::RuntimeError => 1, + Error::DecodeError => 2, + } + } +} + +impl TransactionPaymentApi<::Hash, Balance> + for TransactionPayment +where + Block: BlockT, + C: Send + Sync + 'static, + C: ProvideRuntimeApi, + C: HeaderBackend, + C::Api: TransactionPaymentRuntimeApi, + Balance: Codec, + Extrinsic: Codec + Send + Sync + 'static, +{ + fn query_info( + &self, + encoded_xt: Bytes, + at: Option<::Hash> + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash + )); + + let encoded_len = encoded_xt.len() as u32; + + let uxt: Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::DecodeError.into()), + message: "Unable to query dispatch info.".into(), + data: Some(format!("{:?}", e).into()), + })?; + api.query_info(&at, uxt, encoded_len).map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to query dispatch info.".into(), + data: Some(format!("{:?}", e).into()), + }) + } +} diff --git a/substrate/srml/transaction-payment/src/lib.rs b/substrate/srml/transaction-payment/src/lib.rs index 6ebda53b72..2314edf053 100644 --- a/substrate/srml/transaction-payment/src/lib.rs +++ b/substrate/srml/transaction-payment/src/lib.rs @@ -44,8 +44,9 @@ use sr_primitives::{ TransactionValidity, }, traits::{Zero, Saturating, SignedExtension, SaturatedConversion, Convert}, - weights::{Weight, DispatchInfo}, + weights::{Weight, DispatchInfo, GetDispatchInfo}, }; +use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; type Multiplier = Fixed64; type BalanceOf = @@ -95,7 +96,33 @@ decl_module! { } } -impl Module {} +impl Module { + /// Query the data that we know about the fee of a given `call`. + /// + /// As this module is not and cannot be aware of the internals of a signed extension, it only + /// interprets them as some encoded value and takes their length into account. + /// + /// All dispatchables must be annotated with weight and will have some fee info. This function + /// always returns. + // NOTE: we can actually make it understand `ChargeTransactionPayment`, but would be some hassle + // for sure. We have to make it aware of the index of `ChargeTransactionPayment` in `Extra`. + // Alternatively, we could actually execute the tx's per-dispatch and record the balance of the + // sender before and after the pipeline.. but this is way too much hassle for a very very little + // potential gain in the future. + pub fn query_info( + unchecked_extrinsic: Extrinsic, + len: u32, + ) -> RuntimeDispatchInfo> + where T: Send + Sync, + { + let dispatch_info = ::get_dispatch_info(&unchecked_extrinsic); + + let partial_fee = >::compute_fee(len, dispatch_info, 0u32.into()); + let DispatchInfo { weight, class } = dispatch_info; + + RuntimeDispatchInfo { weight, class, partial_fee } + } +} /// Require the transactor pay for themselves and maybe include a tip to gain additional priority /// in the queue. @@ -117,9 +144,9 @@ impl ChargeTransactionPayment { /// and the time it consumes. /// - (optional) _tip_: if included in the transaction, it will be added on top. Only signed /// transactions can have a tip. - fn compute_fee(len: usize, info: DispatchInfo, tip: BalanceOf) -> BalanceOf { + fn compute_fee(len: u32, info: DispatchInfo, tip: BalanceOf) -> BalanceOf { let len_fee = if info.pay_length_fee() { - let len = >::from(len as u32); + let len = >::from(len); let base = T::TransactionBaseFee::get(); let per_byte = T::TransactionByteFee::get(); base.saturating_add(per_byte.saturating_mul(len)) @@ -172,7 +199,7 @@ impl SignedExtension for ChargeTransactionPayment ) -> TransactionValidity { // pay any fees. let tip = self.0; - let fee = Self::compute_fee(len, info, tip); + let fee = Self::compute_fee(len as u32, info, tip); let imbalance = match T::Currency::withdraw( who, fee, @@ -199,17 +226,27 @@ impl SignedExtension for ChargeTransactionPayment #[cfg(test)] mod tests { use super::*; - use support::{parameter_types, impl_outer_origin}; + use codec::Encode; + use support::{parameter_types, impl_outer_origin, impl_outer_dispatch}; use primitives::H256; use sr_primitives::{ Perbill, - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - weights::DispatchClass, + testing::{Header, TestXt}, + traits::{BlakeTwo256, IdentityLookup, Extrinsic}, + weights::{DispatchClass, DispatchInfo, GetDispatchInfo}, }; + use balances::Call as BalancesCall; use rstd::cell::RefCell; + use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; - const CALL: &::Call = &(); + const CALL: &::Call = &Call::Balances(BalancesCall::transfer(2, 69)); + + impl_outer_dispatch! { + pub enum Call for Runtime where origin: Origin { + balances::Balances, + system::System, + } + } #[derive(Clone, PartialEq, Eq, Debug)] pub struct Runtime; @@ -229,7 +266,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = (); + type Call = Call; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; @@ -294,6 +331,8 @@ mod tests { } type Balances = balances::Module; + type System = system::Module; + type TransactionPayment = Module; pub struct ExtBuilder { balance_factor: u64, @@ -457,6 +496,39 @@ mod tests { assert_eq!(Balances::free_balance(&1), 100 - 10 - (5 + 10 + 3) * 3 / 2); }) } + + #[test] + fn query_info_works() { + let call = Call::Balances(BalancesCall::transfer(2, 69)); + let origin = 111111; + let extra = (); + let xt = TestXt::new(call, Some((origin, extra))).unwrap(); + let info = xt.get_dispatch_info(); + let ext = xt.encode(); + let len = ext.len() as u32; + ExtBuilder::default() + .fees(5, 1, 2) + .build() + .execute_with(|| + { + // all fees should be x1.5 + NextFeeMultiplier::put(Fixed64::from_rational(1, 2)); + + assert_eq!( + TransactionPayment::query_info(xt, len), + RuntimeDispatchInfo { + weight: info.weight, + class: info.class, + partial_fee: ( + 5 /* base */ + + len as u64 /* len * 1 */ + + info.weight.min(MaximumBlockWeight::get()) as u64 * 2 /* weight * weight_to_fee */ + ) * 3 / 2 + }, + ); + + }); + } }