,
+ /// Transaction pool instance.
+ pub pool: Arc,
/// Remote access to the blockchain (async).
pub remote_blockchain: Arc>,
/// Fetcher instance.
pub fetcher: Arc,
}
-impl LightDeps {
- /// Create empty `LightDeps` with given `F` type.
- ///
- /// This is a convenience method to be used in the service builder,
- /// to make sure the type of the `LightDeps` is matching.
- pub fn none(_: Option>) -> Option {
- None
- }
+/// Extra dependencies for BABE.
+pub struct BabeDeps {
+ /// BABE protocol config.
+ pub babe_config: Config,
+ /// BABE pending epoch changes.
+ pub shared_epoch_changes: SharedEpochChanges,
+ /// The keystore that manages the keys of the node.
+ pub keystore: KeyStorePtr,
}
-/// Instantiate all RPC extensions.
-///
-/// If you provide `LightDeps`, the system is configured for light client.
-pub fn create(
- client: Arc,
- pool: Arc,
- light_deps: Option>,
+/// Full client dependencies.
+pub struct FullDeps {
+ /// The client instance to use.
+ pub client: Arc,
+ /// Transaction pool instance.
+ pub pool: Arc,
+ /// The SelectChain Strategy
+ pub select_chain: SC,
+ /// BABE specific dependencies.
+ pub babe: BabeDeps,
+}
+
+/// Instantiate all Full RPC extensions.
+pub fn create_full(
+ deps: FullDeps,
) -> jsonrpc_core::IoHandler where
C: ProvideRuntimeApi,
- C: sc_client::blockchain::HeaderBackend,
+ C: HeaderBackend + HeaderMetadata + 'static,
C: Send + Sync + 'static,
C::Api: substrate_frame_rpc_system::AccountNonceApi,
C::Api: pallet_contracts_rpc::ContractsRuntimeApi,
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi,
- F: sc_client::light::fetcher::Fetcher + 'static,
+ C::Api: BabeApi,
+ ::Error: fmt::Debug,
P: TransactionPool + 'static,
M: jsonrpc_core::Metadata + Default,
+ SC: SelectChain +'static,
{
- use substrate_frame_rpc_system::{FullSystem, LightSystem, SystemApi};
+ use substrate_frame_rpc_system::{FullSystem, SystemApi};
use pallet_contracts_rpc::{Contracts, ContractsApi};
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
let mut io = jsonrpc_core::IoHandler::default();
+ let FullDeps {
+ client,
+ pool,
+ select_chain,
+ babe
+ } = deps;
+ let BabeDeps {
+ keystore,
+ babe_config,
+ shared_epoch_changes,
+ } = babe;
+
+ io.extend_with(
+ SystemApi::to_delegate(FullSystem::new(client.clone(), pool))
+ );
+ // Making synchronous calls in light client freezes the browser currently,
+ // more context: https://github.com/paritytech/substrate/pull/3480
+ // These RPCs should use an asynchronous caller instead.
+ io.extend_with(
+ ContractsApi::to_delegate(Contracts::new(client.clone()))
+ );
+ io.extend_with(
+ TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone()))
+ );
+ io.extend_with(
+ sc_consensus_babe_rpc::BabeApi::to_delegate(
+ BabeRPCHandler::new(client, shared_epoch_changes, keystore, babe_config, select_chain)
+ )
+ );
+
+ io
+}
+
+/// Instantiate all Light RPC extensions.
+pub fn create_light(
+ deps: LightDeps,
+) -> jsonrpc_core::IoHandler where
+ C: sc_client::blockchain::HeaderBackend,
+ C: Send + Sync + 'static,
+ F: sc_client::light::fetcher::Fetcher + 'static,
+ P: TransactionPool + 'static,
+ M: jsonrpc_core::Metadata + Default,
+{
+ use substrate_frame_rpc_system::{LightSystem, SystemApi};
+
+ let LightDeps {
+ client,
+ pool,
+ remote_blockchain,
+ fetcher
+ } = deps;
+ let mut io = jsonrpc_core::IoHandler::default();
+ io.extend_with(
+ SystemApi::::to_delegate(LightSystem::new(client, remote_blockchain, fetcher, pool))
+ );
- if let Some(LightDeps { remote_blockchain, fetcher }) = light_deps {
- io.extend_with(
- SystemApi::::to_delegate(LightSystem::new(client, remote_blockchain, fetcher, pool))
- );
- } else {
- io.extend_with(
- SystemApi::to_delegate(FullSystem::new(client.clone(), pool))
- );
-
- // Making synchronous calls in light client freezes the browser currently,
- // more context: https://github.com/paritytech/substrate/pull/3480
- // These RPCs should use an asynchronous caller instead.
- io.extend_with(
- ContractsApi::to_delegate(Contracts::new(client.clone()))
- );
- io.extend_with(
- TransactionPaymentApi::to_delegate(TransactionPayment::new(client))
- );
- }
io
}
diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml
index 3f8e8b6731477e4cbaabaf4e3012bb139d259e6d..66e9dece177bb9fd4f7a1e1867301b3529ba54d0 100644
--- a/bin/node/runtime/Cargo.toml
+++ b/bin/node/runtime/Cargo.toml
@@ -1,10 +1,12 @@
[package]
name = "node-runtime"
-version = "2.0.0"
+version = "2.0.0-alpha.3"
authors = ["Parity Technologies "]
edition = "2018"
build = "build.rs"
license = "GPL-3.0"
+homepage = "https://substrate.dev"
+repository = "https://github.com/paritytech/substrate/"
[dependencies]
@@ -15,63 +17,64 @@ rustc-hex = { version = "2.0", optional = true }
serde = { version = "1.0.102", optional = true }
# primitives
-sp-authority-discovery = { version = "2.0.0", default-features = false, path = "../../../primitives/authority-discovery" }
-sp-consensus-babe = { version = "0.8", default-features = false, path = "../../../primitives/consensus/babe" }
-sp-block-builder = { path = "../../../primitives/block-builder", default-features = false}
-sp-inherents = { version = "2.0.0", default-features = false, path = "../../../primitives/inherents" }
-node-primitives = { version = "2.0.0", default-features = false, path = "../primitives" }
-sp-offchain = { version = "2.0.0", default-features = false, path = "../../../primitives/offchain" }
-sp-core = { version = "2.0.0", default-features = false, path = "../../../primitives/core" }
-sp-std = { version = "2.0.0", default-features = false, path = "../../../primitives/std" }
-sp-api = { version = "2.0.0", default-features = false, path = "../../../primitives/api" }
-sp-runtime = { version = "2.0.0", default-features = false, path = "../../../primitives/runtime" }
-sp-staking = { version = "2.0.0", default-features = false, path = "../../../primitives/staking" }
-sp-keyring = { version = "2.0.0", optional = true, path = "../../../primitives/keyring" }
-sp-session = { version = "2.0.0", default-features = false, path = "../../../primitives/session" }
-sp-transaction-pool = { version = "2.0.0", default-features = false, path = "../../../primitives/transaction-pool" }
-sp-version = { version = "2.0.0", default-features = false, path = "../../../primitives/version" }
+sp-authority-discovery = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/authority-discovery" }
+sp-consensus-babe = { version = "0.8.0-alpha.2", default-features = false, path = "../../../primitives/consensus/babe" }
+sp-block-builder = { path = "../../../primitives/block-builder", default-features = false, version = "2.0.0-alpha.2"}
+sp-inherents = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/inherents" }
+node-primitives = { version = "2.0.0-alpha.2", default-features = false, path = "../primitives" }
+sp-offchain = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/offchain" }
+sp-core = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/core" }
+sp-std = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/std" }
+sp-api = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/api" }
+sp-runtime = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/runtime" }
+sp-staking = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/staking" }
+sp-keyring = { version = "2.0.0-alpha.2", optional = true, path = "../../../primitives/keyring" }
+sp-session = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/session" }
+sp-transaction-pool = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/transaction-pool" }
+sp-version = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/version" }
# frame dependencies
-frame-executive = { version = "2.0.0", default-features = false, path = "../../../frame/executive" }
-frame-support = { version = "2.0.0", default-features = false, path = "../../../frame/support" }
-frame-system = { version = "2.0.0", default-features = false, path = "../../../frame/system" }
-frame-system-rpc-runtime-api = { version = "2.0.0", default-features = false, path = "../../../frame/system/rpc/runtime-api/" }
-pallet-authority-discovery = { version = "2.0.0", default-features = false, path = "../../../frame/authority-discovery" }
-pallet-authorship = { version = "2.0.0", default-features = false, path = "../../../frame/authorship" }
-pallet-babe = { version = "2.0.0", default-features = false, path = "../../../frame/babe" }
-pallet-balances = { version = "2.0.0", default-features = false, path = "../../../frame/balances" }
-pallet-collective = { version = "2.0.0", default-features = false, path = "../../../frame/collective" }
-pallet-contracts = { version = "2.0.0", default-features = false, path = "../../../frame/contracts" }
-pallet-contracts-primitives = { version = "2.0.0", default-features = false, path = "../../../frame/contracts/common/" }
-pallet-contracts-rpc-runtime-api = { version = "0.8.0", default-features = false, path = "../../../frame/contracts/rpc/runtime-api/" }
-pallet-democracy = { version = "2.0.0", default-features = false, path = "../../../frame/democracy" }
-pallet-elections-phragmen = { version = "2.0.0", default-features = false, path = "../../../frame/elections-phragmen" }
-pallet-finality-tracker = { version = "2.0.0", default-features = false, path = "../../../frame/finality-tracker" }
-pallet-grandpa = { version = "2.0.0", default-features = false, path = "../../../frame/grandpa" }
-pallet-im-online = { version = "2.0.0", default-features = false, path = "../../../frame/im-online" }
-pallet-indices = { version = "2.0.0", default-features = false, path = "../../../frame/indices" }
-pallet-identity = { version = "2.0.0", default-features = false, path = "../../../frame/identity" }
-pallet-membership = { version = "2.0.0", default-features = false, path = "../../../frame/membership" }
-pallet-offences = { version = "2.0.0", default-features = false, path = "../../../frame/offences" }
-pallet-randomness-collective-flip = { version = "2.0.0", default-features = false, path = "../../../frame/randomness-collective-flip" }
-pallet-recovery = { version = "2.0.0", default-features = false, path = "../../../frame/recovery" }
-pallet-session = { version = "2.0.0", features = ["historical"], path = "../../../frame/session", default-features = false }
-pallet-staking = { version = "2.0.0", features = ["migrate"], path = "../../../frame/staking", default-features = false }
-pallet-staking-reward-curve = { version = "2.0.0", path = "../../../frame/staking/reward-curve" }
-pallet-sudo = { version = "2.0.0", default-features = false, path = "../../../frame/sudo" }
-pallet-society = { version = "2.0.0", default-features = false, path = "../../../frame/society" }
-pallet-timestamp = { version = "2.0.0", default-features = false, path = "../../../frame/timestamp" }
-pallet-treasury = { version = "2.0.0", default-features = false, path = "../../../frame/treasury" }
-pallet-utility = { version = "2.0.0", default-features = false, path = "../../../frame/utility" }
-pallet-transaction-payment = { version = "2.0.0", default-features = false, path = "../../../frame/transaction-payment" }
-pallet-transaction-payment-rpc-runtime-api = { version = "2.0.0", default-features = false, path = "../../../frame/transaction-payment/rpc/runtime-api/" }
-pallet-vesting = { version = "2.0.0", default-features = false, path = "../../../frame/vesting" }
+frame-executive = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/executive" }
+frame-benchmarking = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/benchmarking" }
+frame-support = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/support" }
+frame-system = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/system" }
+frame-system-rpc-runtime-api = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/system/rpc/runtime-api/" }
+pallet-authority-discovery = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/authority-discovery" }
+pallet-authorship = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/authorship" }
+pallet-babe = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/babe" }
+pallet-balances = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/balances" }
+pallet-collective = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/collective" }
+pallet-contracts = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/contracts" }
+pallet-contracts-primitives = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/contracts/common/" }
+pallet-contracts-rpc-runtime-api = { version = "0.8.0-alpha.2", default-features = false, path = "../../../frame/contracts/rpc/runtime-api/" }
+pallet-democracy = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/democracy" }
+pallet-elections-phragmen = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/elections-phragmen" }
+pallet-finality-tracker = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/finality-tracker" }
+pallet-grandpa = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/grandpa" }
+pallet-im-online = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/im-online" }
+pallet-indices = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/indices" }
+pallet-identity = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/identity" }
+pallet-membership = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/membership" }
+pallet-offences = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/offences" }
+pallet-randomness-collective-flip = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/randomness-collective-flip" }
+pallet-recovery = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/recovery" }
+pallet-session = { version = "2.0.0-alpha.2", features = ["historical"], path = "../../../frame/session", default-features = false }
+pallet-staking = { version = "2.0.0-alpha.2", features = ["migrate"], path = "../../../frame/staking", default-features = false }
+pallet-staking-reward-curve = { version = "2.0.0-alpha.2", path = "../../../frame/staking/reward-curve" }
+pallet-sudo = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/sudo" }
+pallet-society = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/society" }
+pallet-timestamp = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/timestamp" }
+pallet-treasury = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/treasury" }
+pallet-utility = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/utility" }
+pallet-transaction-payment = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/transaction-payment" }
+pallet-transaction-payment-rpc-runtime-api = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/transaction-payment/rpc/runtime-api/" }
+pallet-vesting = { version = "2.0.0-alpha.2", default-features = false, path = "../../../frame/vesting" }
[build-dependencies]
-wasm-builder-runner = { version = "1.0.4", package = "substrate-wasm-builder-runner", path = "../../../utils/wasm-builder-runner" }
+wasm-builder-runner = { version = "1.0.5", package = "substrate-wasm-builder-runner", path = "../../../utils/wasm-builder-runner" }
[dev-dependencies]
-sp-io = { version = "2.0.0", path = "../../../primitives/io" }
+sp-io = { version = "2.0.0-alpha.2", path = "../../../primitives/io" }
[features]
default = ["std"]
@@ -115,6 +118,7 @@ std = [
"sp-session/std",
"pallet-sudo/std",
"frame-support/std",
+ "frame-benchmarking/std",
"frame-system-rpc-runtime-api/std",
"frame-system/std",
"pallet-timestamp/std",
diff --git a/bin/node/runtime/src/constants.rs b/bin/node/runtime/src/constants.rs
index b2c880c08bbf8098e16154e99f3a797a6d27eec8..bf12492f8db029dc22b519dd52af74adcad99a7f 100644
--- a/bin/node/runtime/src/constants.rs
+++ b/bin/node/runtime/src/constants.rs
@@ -38,7 +38,7 @@ pub mod time {
/// a slot being empty).
/// This value is only used indirectly to define the unit constants below
/// that are expressed in blocks. The rest of the code should use
- /// `SLOT_DURATION` instead (like the timestamp module for calculating the
+ /// `SLOT_DURATION` instead (like the Timestamp pallet for calculating the
/// minimum period).
///
/// If using BABE with secondary slots (default) then all of the slots will
diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs
index db8e62c6ab4e50e362b43c7be63577442091a613..85889a50c20b98116317e4238ac5733f1e599b89 100644
--- a/bin/node/runtime/src/lib.rs
+++ b/bin/node/runtime/src/lib.rs
@@ -27,17 +27,18 @@ use frame_support::{
traits::{SplitTwoWays, Currency, Randomness},
};
use sp_core::u32_trait::{_1, _2, _3, _4};
-use node_primitives::{AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, Moment, Signature};
+pub use node_primitives::{AccountId, Signature};
+use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment};
use sp_api::impl_runtime_apis;
use sp_runtime::{
- Permill, Perbill, Percent, ApplyExtrinsicResult, impl_opaque_keys, generic, create_runtime_str,
- BenchmarkResults,
+ Permill, Perbill, Percent, ApplyExtrinsicResult, RuntimeString,
+ impl_opaque_keys, generic, create_runtime_str,
};
use sp_runtime::curve::PiecewiseLinear;
use sp_runtime::transaction_validity::TransactionValidity;
use sp_runtime::traits::{
self, BlakeTwo256, Block as BlockT, StaticLookup, SaturatedConversion,
- ConvertInto, OpaqueKeys, Benchmarking,
+ ConvertInto, OpaqueKeys,
};
use sp_version::RuntimeVersion;
#[cfg(any(feature = "std", test))]
@@ -81,7 +82,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// and set impl_version to 0. If only runtime
// implementation changes and behavior does not, then leave spec_version as
// is and increment impl_version.
- spec_version: 217,
+ spec_version: 227,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
};
@@ -129,6 +130,9 @@ impl frame_system::Trait for Runtime {
type AvailableBlockRatio = AvailableBlockRatio;
type Version = Version;
type ModuleToIndex = ModuleToIndex;
+ type AccountData = pallet_balances::AccountData;
+ type OnNewAccount = ();
+ type OnKilledAccount = ();
}
parameter_types! {
@@ -159,27 +163,27 @@ impl pallet_babe::Trait for Runtime {
type EpochChangeTrigger = pallet_babe::ExternalTrigger;
}
+parameter_types! {
+ pub const IndexDeposit: Balance = 1 * DOLLARS;
+}
+
impl pallet_indices::Trait for Runtime {
type AccountIndex = AccountIndex;
- type IsDeadAccount = Balances;
- type ResolveHint = pallet_indices::SimpleResolveHint;
type Event = Event;
+ type Currency = Balances;
+ type Deposit = IndexDeposit;
}
parameter_types! {
pub const ExistentialDeposit: Balance = 1 * DOLLARS;
- pub const CreationFee: Balance = 1 * CENTS;
}
impl pallet_balances::Trait for Runtime {
type Balance = Balance;
- type OnReapAccount = ((((System, Staking), Contracts), Session), Recovery);
- type OnNewAccount = Indices;
- type Event = Event;
type DustRemoval = ();
- type TransferPayment = ();
+ type Event = Event;
type ExistentialDeposit = ExistentialDeposit;
- type CreationFee = CreationFee;
+ type AccountStore = frame_system::Module;
}
parameter_types! {
@@ -234,13 +238,13 @@ parameter_types! {
}
impl pallet_session::Trait for Runtime {
- type SessionManager = Staking;
- type SessionHandler = ::KeyTypeIdProviders;
- type ShouldEndSession = Babe;
type Event = Event;
- type Keys = SessionKeys;
type ValidatorId = ::AccountId;
type ValidatorIdOf = pallet_staking::StashOf;
+ type ShouldEndSession = Babe;
+ type SessionManager = Staking;
+ type SessionHandler = ::KeyTypeIdProviders;
+ type Keys = SessionKeys;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
}
@@ -302,7 +306,6 @@ impl pallet_democracy::Trait for Runtime {
type EnactmentPeriod = EnactmentPeriod;
type LaunchPeriod = LaunchPeriod;
type VotingPeriod = VotingPeriod;
- type EmergencyVotingPeriod = EmergencyVotingPeriod;
type MinimumDeposit = MinimumDeposit;
/// A straight majority of the council can decide what their next motion is.
type ExternalOrigin = pallet_collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilCollective>;
@@ -314,6 +317,7 @@ impl pallet_democracy::Trait for Runtime {
/// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote
/// be tabled immediately and with a shorter voting/enactment period.
type FastTrackOrigin = pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalCollective>;
+ type EmergencyVotingPeriod = EmergencyVotingPeriod;
// To cancel a proposal which has been passed, 2/3 of the council must agree to it.
type CancellationOrigin = pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilCollective>;
// Any single technical committee member may veto a coming council proposal, however they can
@@ -342,16 +346,16 @@ parameter_types! {
impl pallet_elections_phragmen::Trait for Runtime {
type Event = Event;
type Currency = Balances;
+ type ChangeMembers = Council;
type CurrencyToVote = CurrencyToVoteHandler;
type CandidacyBond = CandidacyBond;
type VotingBond = VotingBond;
- type TermDuration = TermDuration;
- type DesiredMembers = DesiredMembers;
- type DesiredRunnersUp = DesiredRunnersUp;
type LoserCandidate = ();
type BadReport = ();
type KickedMember = ();
- type ChangeMembers = Council;
+ type DesiredMembers = DesiredMembers;
+ type DesiredRunnersUp = DesiredRunnersUp;
+ type TermDuration = TermDuration;
}
type TechnicalCollective = pallet_collective::Instance2;
@@ -386,22 +390,20 @@ impl pallet_treasury::Trait for Runtime {
type Currency = Balances;
type ApproveOrigin = pallet_collective::EnsureMembers<_4, AccountId, CouncilCollective>;
type RejectOrigin = pallet_collective::EnsureMembers<_2, AccountId, CouncilCollective>;
+ type Tippers = Elections;
+ type TipCountdown = TipCountdown;
+ type TipFindersFee = TipFindersFee;
+ type TipReportDepositBase = TipReportDepositBase;
+ type TipReportDepositPerByte = TipReportDepositPerByte;
type Event = Event;
type ProposalRejection = ();
type ProposalBond = ProposalBond;
type ProposalBondMinimum = ProposalBondMinimum;
type SpendPeriod = SpendPeriod;
type Burn = Burn;
- type Tippers = Elections;
- type TipCountdown = TipCountdown;
- type TipFindersFee = TipFindersFee;
- type TipReportDepositBase = TipReportDepositBase;
- type TipReportDepositPerByte = TipReportDepositPerByte;
}
parameter_types! {
- pub const ContractTransferFee: Balance = 1 * CENTS;
- pub const ContractCreationFee: Balance = 1 * CENTS;
pub const ContractTransactionBaseFee: Balance = 1 * CENTS;
pub const ContractTransactionByteFee: Balance = 10 * MILLICENTS;
pub const ContractFee: Balance = 1 * CENTS;
@@ -417,7 +419,7 @@ impl pallet_contracts::Trait for Runtime {
type Randomness = RandomnessCollectiveFlip;
type Call = Call;
type Event = Event;
- type DetermineContractAddress = pallet_contracts::SimpleAddressDeterminator;
+ type DetermineContractAddress = pallet_contracts::SimpleAddressDeterminer;
type ComputeDispatchFee = pallet_contracts::DefaultDispatchFeeComputor;
type TrieIdGenerator = pallet_contracts::TrieIdFromParentCounter;
type GasPayment = ();
@@ -428,7 +430,6 @@ impl pallet_contracts::Trait for Runtime {
type RentByteFee = RentByteFee;
type RentDepositOffset = RentDepositOffset;
type SurchargeReward = SurchargeReward;
- type CreationFee = ContractCreationFee;
type TransactionBaseFee = ContractTransactionBaseFee;
type TransactionByteFee = ContractTransactionByteFee;
type ContractFee = ContractFee;
@@ -441,7 +442,7 @@ impl pallet_contracts::Trait for Runtime {
impl pallet_sudo::Trait for Runtime {
type Event = Event;
- type Proposal = Call;
+ type Call = Call;
}
/// A runtime transaction submitter.
@@ -453,11 +454,11 @@ parameter_types! {
impl pallet_im_online::Trait for Runtime {
type AuthorityId = ImOnlineId;
- type Call = Call;
type Event = Event;
+ type Call = Call;
type SubmitTransaction = SubmitTransaction;
- type ReportUnresponsiveness = Offences;
type SessionDuration = SessionDuration;
+ type ReportUnresponsiveness = Offences;
}
impl pallet_offences::Trait for Runtime {
@@ -494,14 +495,14 @@ parameter_types! {
impl pallet_identity::Trait for Runtime {
type Event = Event;
type Currency = Balances;
- type Slashed = Treasury;
type BasicDeposit = BasicDeposit;
type FieldDeposit = FieldDeposit;
type SubAccountDeposit = SubAccountDeposit;
type MaxSubAccounts = MaxSubAccounts;
type MaxAdditionalFields = MaxAdditionalFields;
- type RegistrarOrigin = pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>;
+ type Slashed = Treasury;
type ForceOrigin = pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>;
+ type RegistrarOrigin = pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>;
}
impl frame_system::offchain::CreateTransaction for Runtime {
@@ -599,15 +600,15 @@ construct_runtime!(
NodeBlock = node_primitives::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
- System: frame_system::{Module, Call, Storage, Config, Event},
+ System: frame_system::{Module, Call, Config, Storage, Event},
Utility: pallet_utility::{Module, Call, Storage, Event},
Babe: pallet_babe::{Module, Call, Storage, Config, Inherent(Timestamp)},
Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},
Authorship: pallet_authorship::{Module, Call, Storage, Inherent},
- Indices: pallet_indices,
- Balances: pallet_balances,
+ Indices: pallet_indices::{Module, Call, Storage, Config, Event},
+ Balances: pallet_balances::{Module, Call, Storage, Config, Event},
TransactionPayment: pallet_transaction_payment::{Module, Storage},
- Staking: pallet_staking,
+ Staking: pallet_staking::{Module, Call, Config, Storage, Event},
Session: pallet_session::{Module, Call, Storage, Event, Config},
Democracy: pallet_democracy::{Module, Call, Storage, Config, Event},
Council: pallet_collective::::{Module, Call, Storage, Origin, Event, Config},
@@ -617,8 +618,8 @@ construct_runtime!(
FinalityTracker: pallet_finality_tracker::{Module, Call, Inherent},
Grandpa: pallet_grandpa::{Module, Call, Storage, Config, Event},
Treasury: pallet_treasury::{Module, Call, Storage, Config, Event},
- Contracts: pallet_contracts,
- Sudo: pallet_sudo,
+ Contracts: pallet_contracts::{Module, Call, Config, Storage, Event},
+ Sudo: pallet_sudo::{Module, Call, Config, Storage, Event},
ImOnline: pallet_im_online::{Module, Call, Storage, Event, ValidateUnsigned, Config},
AuthorityDiscovery: pallet_authority_discovery::{Module, Call, Config},
Offences: pallet_offences::{Module, Call, Storage, Event},
@@ -685,6 +686,10 @@ impl_runtime_apis! {
Executive::apply_extrinsic(extrinsic)
}
+ fn apply_trusted_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult {
+ Executive::apply_trusted_extrinsic(extrinsic)
+ }
+
fn finalize_block() -> ::Header {
Executive::finalize_block()
}
@@ -736,6 +741,10 @@ impl_runtime_apis! {
secondary_slots: true,
}
}
+
+ fn current_epoch_start() -> sp_consensus_babe::SlotNumber {
+ Babe::current_epoch_start()
+ }
}
impl sp_authority_discovery::AuthorityDiscoveryApi for Runtime {
@@ -807,28 +816,47 @@ impl_runtime_apis! {
}
}
- impl crate::Benchmark for Runtime {
- fn dispatch_benchmark(module: Vec, extrinsic: Vec, steps: u32, repeat: u32)
- -> Option>
- {
- match module.as_slice() {
- b"pallet-balances" | b"balances" => Balances::run_benchmark(extrinsic, steps, repeat).ok(),
- b"pallet-identity" | b"identity" => Identity::run_benchmark(extrinsic, steps, repeat).ok(),
- b"pallet-timestamp" | b"timestamp" => Timestamp::run_benchmark(extrinsic, steps, repeat).ok(),
- _ => return None,
- }
+ impl frame_benchmarking::Benchmark for Runtime {
+ fn dispatch_benchmark(
+ module: Vec,
+ extrinsic: Vec,
+ lowest_range_values: Vec,
+ highest_range_values: Vec,
+ steps: Vec,
+ repeat: u32,
+ ) -> Result, RuntimeString> {
+ use frame_benchmarking::Benchmarking;
+
+ let result = match module.as_slice() {
+ b"pallet-balances" | b"balances" => Balances::run_benchmark(
+ extrinsic,
+ lowest_range_values,
+ highest_range_values,
+ steps,
+ repeat,
+ ),
+ b"pallet-identity" | b"identity" => Identity::run_benchmark(
+ extrinsic,
+ lowest_range_values,
+ highest_range_values,
+ steps,
+ repeat,
+ ),
+ b"pallet-timestamp" | b"timestamp" => Timestamp::run_benchmark(
+ extrinsic,
+ lowest_range_values,
+ highest_range_values,
+ steps,
+ repeat,
+ ),
+ _ => Err("Benchmark not found for this pallet."),
+ };
+
+ result.map_err(|e| e.into())
}
}
}
-sp_api::decl_runtime_apis! {
- pub trait Benchmark
- {
- fn dispatch_benchmark(module: Vec, extrinsic: Vec, steps: u32, repeat: u32)
- -> Option>;
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml
index 051460e839eea5e2aa8e17ff76ea339809889d4c..30402c54905b8d241e137ff5913850dfb830907e 100644
--- a/bin/node/testing/Cargo.toml
+++ b/bin/node/testing/Cargo.toml
@@ -1,33 +1,57 @@
[package]
name = "node-testing"
-version = "2.0.0"
+version = "2.0.0-alpha.3"
authors = ["Parity Technologies "]
description = "Test utilities for Substrate node."
edition = "2018"
license = "GPL-3.0"
+homepage = "https://substrate.dev"
+repository = "https://github.com/paritytech/substrate/"
+publish = true
[dependencies]
-pallet-balances = { version = "2.0.0", path = "../../../frame/balances" }
-sc-client = { version = "0.8", path = "../../../client/" }
+pallet-balances = { version = "2.0.0-alpha.2", path = "../../../frame/balances" }
+sc-client = { version = "0.8.0-alpha.2", path = "../../../client/" }
+sc-client-db = { version = "0.8.0-alpha.2", path = "../../../client/db/", features = ["kvdb-rocksdb"] }
+sc-client-api = { version = "2.0.0-alpha.2", path = "../../../client/api/" }
codec = { package = "parity-scale-codec", version = "1.0.0" }
-pallet-contracts = { version = "2.0.0", path = "../../../frame/contracts" }
-pallet-grandpa = { version = "2.0.0", path = "../../../frame/grandpa" }
-pallet-indices = { version = "2.0.0", path = "../../../frame/indices" }
-sp-keyring = { version = "2.0.0", path = "../../../primitives/keyring" }
-node-executor = { version = "2.0.0", path = "../executor" }
-node-primitives = { version = "2.0.0", path = "../primitives" }
-node-runtime = { version = "2.0.0", path = "../runtime" }
-sp-core = { version = "2.0.0", path = "../../../primitives/core" }
-sp-io = { version = "2.0.0", path = "../../../primitives/io" }
-frame-support = { version = "2.0.0", path = "../../../frame/support" }
-pallet-session = { version = "2.0.0", path = "../../../frame/session" }
-pallet-society = { version = "2.0.0", path = "../../../frame/society" }
-sp-runtime = { version = "2.0.0", path = "../../../primitives/runtime" }
-pallet-staking = { version = "2.0.0", path = "../../../frame/staking" }
-sc-executor = { version = "0.8", path = "../../../client/executor" }
-frame-system = { version = "2.0.0", path = "../../../frame/system" }
-substrate-test-client = { version = "2.0.0", path = "../../../test-utils/client" }
-pallet-timestamp = { version = "2.0.0", path = "../../../frame/timestamp" }
-pallet-transaction-payment = { version = "2.0.0", path = "../../../frame/transaction-payment" }
-pallet-treasury = { version = "2.0.0", path = "../../../frame/treasury" }
+pallet-contracts = { version = "2.0.0-alpha.2", path = "../../../frame/contracts" }
+pallet-grandpa = { version = "2.0.0-alpha.2", path = "../../../frame/grandpa" }
+pallet-indices = { version = "2.0.0-alpha.2", path = "../../../frame/indices" }
+sp-keyring = { version = "2.0.0-alpha.2", path = "../../../primitives/keyring" }
+node-executor = { version = "2.0.0-alpha.2", path = "../executor" }
+node-primitives = { version = "2.0.0-alpha.2", path = "../primitives" }
+node-runtime = { version = "2.0.0-alpha.2", path = "../runtime" }
+sp-core = { version = "2.0.0-alpha.2", path = "../../../primitives/core" }
+sp-io = { version = "2.0.0-alpha.2", path = "../../../primitives/io" }
+frame-support = { version = "2.0.0-alpha.2", path = "../../../frame/support" }
+pallet-session = { version = "2.0.0-alpha.2", path = "../../../frame/session" }
+pallet-society = { version = "2.0.0-alpha.2", path = "../../../frame/society" }
+sp-runtime = { version = "2.0.0-alpha.2", path = "../../../primitives/runtime" }
+pallet-staking = { version = "2.0.0-alpha.2", path = "../../../frame/staking" }
+sc-executor = { version = "0.8.0-alpha.2", path = "../../../client/executor", features = ["wasmtime"] }
+sp-consensus = { version = "0.8.0-alpha.2", path = "../../../primitives/consensus/common" }
+frame-system = { version = "2.0.0-alpha.2", path = "../../../frame/system" }
+substrate-test-client = { version = "2.0.0-dev", path = "../../../test-utils/client" }
+pallet-timestamp = { version = "2.0.0-alpha.2", path = "../../../frame/timestamp" }
+pallet-transaction-payment = { version = "2.0.0-alpha.2", path = "../../../frame/transaction-payment" }
+pallet-treasury = { version = "2.0.0-alpha.2", path = "../../../frame/treasury" }
wabt = "0.9.2"
+sp-api = { version = "2.0.0-alpha.2", path = "../../../primitives/api" }
+sp-finality-tracker = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/finality-tracker" }
+sp-timestamp = { version = "2.0.0-alpha.2", default-features = false, path = "../../../primitives/timestamp" }
+sp-block-builder = { version = "2.0.0-alpha.2", path = "../../../primitives/block-builder" }
+sp-inherents = { version = "2.0.0-alpha.2", path = "../../../primitives/inherents" }
+sp-blockchain = { version = "2.0.0-alpha.2", path = "../../../primitives/blockchain" }
+log = "0.4.8"
+tempfile = "3.1.0"
+fs_extra = "1"
+
+[dev-dependencies]
+criterion = "0.3.0"
+sc-cli = { version = "0.8.0-alpha.2", path = "../../../client/cli" }
+sc-service = { version = "0.8.0-alpha.2", path = "../../../client/service", features = ["rocksdb"] }
+
+[[bench]]
+name = "import"
+harness = false
diff --git a/bin/node/testing/benches/import.rs b/bin/node/testing/benches/import.rs
new file mode 100644
index 0000000000000000000000000000000000000000..79cb71b164371e3bd6bb29c0f58ce2efa28a59af
--- /dev/null
+++ b/bin/node/testing/benches/import.rs
@@ -0,0 +1,205 @@
+// Copyright 2020 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 .
+
+//! Block import benchmark.
+//!
+//! This benchmark is expected to measure block import operation of
+//! some more or less full block.
+//!
+//! As we also want to protect against cold-cache attacks, this
+//! benchmark should not rely on any caching (except those that
+//! DO NOT depend on user input). Thus block generation should be
+//! based on randomized operation.
+//!
+//! This is supposed to be very simple benchmark and is not subject
+//! to much configuring - just block full of randomized transactions.
+//! It is not supposed to measure runtime modules weight correctness
+
+use std::fmt;
+use node_testing::bench::{BenchDb, Profile};
+use node_primitives::Block;
+use sp_runtime::generic::BlockId;
+use criterion::{Criterion, criterion_group, criterion_main};
+use sc_client_api::backend::Backend;
+
+criterion_group!(
+ name = benches;
+ config = Criterion::default().sample_size(20).warm_up_time(std::time::Duration::from_secs(20));
+ targets = bench_block_import
+);
+criterion_group!(
+ name = wasm_size;
+ config = Criterion::default().sample_size(10);
+ targets = bench_wasm_size_import
+);
+criterion_group!(
+ name = profile;
+ config = Criterion::default().sample_size(10);
+ targets = profile_block_import
+);
+criterion_main!(benches, profile);
+
+fn bench_block_import(c: &mut Criterion) {
+ sc_cli::init_logger("");
+ // for future uses, uncomment if something wrong.
+ // sc_cli::init_logger("sc_client=debug");
+
+ let mut bench_db = BenchDb::new(128);
+ let block = bench_db.generate_block(100);
+
+ log::trace!(
+ target: "bench-logistics",
+ "Seed database directory: {}",
+ bench_db.path().display(),
+ );
+
+ c.bench_function_over_inputs("import block",
+ move |bencher, profile| {
+ bencher.iter_batched(
+ || {
+ let context = bench_db.create_context(*profile);
+
+ // mostly to just launch compiler before benching!
+ let version = context.client.runtime_version_at(&BlockId::Number(0))
+ .expect("Failed to get runtime version")
+ .spec_version;
+
+ log::trace!(
+ target: "bench-logistics",
+ "Next iteration database directory: {}, runtime version: {}",
+ context.path().display(), version,
+ );
+
+ context
+ },
+ |mut context| {
+ let start = std::time::Instant::now();
+ context.import_block(block.clone());
+ let elapsed = start.elapsed();
+
+ log::info!(
+ target: "bench-logistics",
+ "imported block with {} tx, took: {:#?}",
+ block.extrinsics.len(),
+ elapsed,
+ );
+
+ log::info!(
+ target: "bench-logistics",
+ "usage info: {}",
+ context.backend.usage_info()
+ .expect("RocksDB backend always provides usage info!"),
+ );
+ },
+ criterion::BatchSize::PerIteration,
+ );
+ },
+ vec![Profile::Wasm, Profile::Native],
+ );
+}
+
+// This is not an actual benchmark, so don't use it to measure anything.
+// It just produces special pattern of cpu load that allows easy picking
+// the part of block import for the profiling in the tool of choice.
+fn profile_block_import(c: &mut Criterion) {
+ sc_cli::init_logger("");
+
+ let mut bench_db = BenchDb::new(128);
+ let block = bench_db.generate_block(100);
+
+ c.bench_function("profile block",
+ move |bencher| {
+ bencher.iter_batched(
+ || {
+ bench_db.create_context(Profile::Native)
+ },
+ |mut context| {
+ // until better osx signpost/callgrind signal is possible to use
+ // in rust, we just pause everything completely to help choosing
+ // actual profiling interval
+ std::thread::park_timeout(std::time::Duration::from_secs(2));
+ context.import_block(block.clone());
+ // and here as well
+ std::thread::park_timeout(std::time::Duration::from_secs(2));
+ log::info!(
+ target: "bench-logistics",
+ "imported block, usage info: {}",
+ context.backend.usage_info()
+ .expect("RocksDB backend always provides usage info!"),
+ )
+ },
+ criterion::BatchSize::PerIteration,
+ );
+ },
+ );
+}
+
+struct Setup {
+ db: BenchDb,
+ block: Block,
+}
+
+struct SetupIterator {
+ current: usize,
+ finish: usize,
+ multiplier: usize,
+}
+
+impl SetupIterator {
+ fn new(current: usize, finish: usize, multiplier: usize) -> Self {
+ SetupIterator { current, finish, multiplier }
+ }
+}
+
+impl Iterator for SetupIterator {
+ type Item = Setup;
+
+ fn next(&mut self) -> Option {
+ if self.current >= self.finish { return None }
+
+ self.current += 1;
+
+ let size = self.current * self.multiplier;
+ let mut db = BenchDb::new(size);
+ let block = db.generate_block(size);
+ Some(Setup { db, block })
+ }
+}
+
+impl fmt::Debug for Setup {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Setup: {} tx/block", self.block.extrinsics.len())
+ }
+}
+
+fn bench_wasm_size_import(c: &mut Criterion) {
+ sc_cli::init_logger("");
+
+ c.bench_function_over_inputs("wasm_size_import",
+ move |bencher, setup| {
+ bencher.iter_batched(
+ || {
+ setup.db.create_context(Profile::Wasm)
+ },
+ |mut context| {
+ context.import_block(setup.block.clone());
+ },
+ criterion::BatchSize::PerIteration,
+ );
+ },
+ SetupIterator::new(5, 15, 50),
+ );
+}
diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs
new file mode 100644
index 0000000000000000000000000000000000000000..58a7ab933eeb9d55f31bd1b9e45d91b69a4c40c4
--- /dev/null
+++ b/bin/node/testing/src/bench.rs
@@ -0,0 +1,424 @@
+// Copyright 2019-2020 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 .
+
+//! Benchmarking module.
+//!
+//! Utilities to do full-scale benchmarks involving database. With `BenchDb` you
+//! can pregenerate seed database and `clone` it for every iteration of your benchmarks
+//! or tests to get consistent, smooth benchmark experience!
+
+use std::{sync::Arc, path::Path, collections::BTreeMap};
+
+use node_primitives::Block;
+use crate::client::{Client, Backend};
+use crate::keyring::*;
+use sc_client_db::PruningMode;
+use sc_executor::{NativeExecutor, WasmExecutionMethod};
+use sp_consensus::{
+ BlockOrigin, BlockImport, BlockImportParams,
+ ForkChoiceStrategy, ImportResult, ImportedAux
+};
+use sp_runtime::{
+ generic::BlockId,
+ OpaqueExtrinsic,
+ traits::{Block as BlockT, Verify, Zero, IdentifyAccount},
+};
+use codec::{Decode, Encode};
+use node_runtime::{
+ Call,
+ CheckedExtrinsic,
+ constants::currency::DOLLARS,
+ UncheckedExtrinsic,
+ MinimumPeriod,
+ BalancesCall,
+ AccountId,
+ Signature,
+};
+use sp_core::ExecutionContext;
+use sp_api::ProvideRuntimeApi;
+use sp_block_builder::BlockBuilder;
+use sp_inherents::InherentData;
+use sc_client_api::{
+ ExecutionStrategy,
+ execution_extensions::{ExecutionExtensions, ExecutionStrategies},
+};
+use sp_core::{Pair, Public, sr25519};
+
+/// Keyring full of accounts for benching.
+///
+/// Accounts are ordered:
+/// //endowed-user//00
+/// //endowed-user//01
+/// ...
+/// //endowed-user//N
+#[derive(Clone)]
+pub struct BenchKeyring {
+ accounts: BTreeMap,
+}
+
+/// Pre-initialized benchmarking database.
+///
+/// This is prepared database with genesis and keyring
+/// that can be cloned and then used for any benchmarking.
+pub struct BenchDb {
+ keyring: BenchKeyring,
+ directory_guard: Guard,
+}
+
+impl Clone for BenchDb {
+ fn clone(&self) -> Self {
+ let keyring = self.keyring.clone();
+ let dir = tempfile::tempdir().expect("temp dir creation failed");
+
+ let seed_dir = self.directory_guard.0.path();
+
+ log::trace!(
+ target: "bench-logistics",
+ "Copying seed db from {} to {}",
+ seed_dir.to_string_lossy(),
+ dir.path().to_string_lossy(),
+ );
+ let seed_db_files = std::fs::read_dir(seed_dir)
+ .expect("failed to list file in seed dir")
+ .map(|f_result|
+ f_result.expect("failed to read file in seed db")
+ .path()
+ .clone()
+ ).collect();
+ fs_extra::copy_items(
+ &seed_db_files,
+ dir.path(),
+ &fs_extra::dir::CopyOptions::new(),
+ ).expect("Copy of seed database is ok");
+
+ BenchDb { keyring, directory_guard: Guard(dir) }
+ }
+}
+
+impl BenchDb {
+ /// New immutable benchmarking database.
+ ///
+ /// This will generate database files in random temporary directory
+ /// and keep it there until struct is dropped.
+ ///
+ /// You can `clone` this database or you can `create_context` from it
+ /// (which also do `clone`) to run actual operation against new database
+ /// which will be identical to this.
+ pub fn new(keyring_length: usize) -> Self {
+ let keyring = BenchKeyring::new(keyring_length);
+
+ let dir = tempfile::tempdir().expect("temp dir creation failed");
+ log::trace!(
+ target: "bench-logistics",
+ "Created seed db at {}",
+ dir.path().to_string_lossy(),
+ );
+ let (_client, _backend) = Self::bench_client(dir.path(), Profile::Native, &keyring);
+ let directory_guard = Guard(dir);
+
+ BenchDb { keyring, directory_guard }
+ }
+
+ // This should return client that is doing everything that full node
+ // is doing.
+ //
+ // - This client should use best wasm execution method.
+ // - This client should work with real database only.
+ fn bench_client(dir: &std::path::Path, profile: Profile, keyring: &BenchKeyring) -> (Client, std::sync::Arc) {
+ let db_config = sc_client_db::DatabaseSettings {
+ state_cache_size: 16*1024*1024,
+ state_cache_child_ratio: Some((0, 100)),
+ pruning: PruningMode::ArchiveAll,
+ source: sc_client_db::DatabaseSettingsSrc::Path {
+ path: dir.into(),
+ cache_size: None,
+ },
+ };
+
+ let (client, backend) = sc_client_db::new_client(
+ db_config,
+ NativeExecutor::new(WasmExecutionMethod::Compiled, None),
+ &keyring.generate_genesis(),
+ None,
+ None,
+ ExecutionExtensions::new(profile.into_execution_strategies(), None),
+ ).expect("Should not fail");
+
+ (client, backend)
+ }
+
+ /// Generate new block using this database.
+ pub fn generate_block(&mut self, transactions: usize) -> Block {
+ let (client, _backend) = Self::bench_client(
+ self.directory_guard.path(),
+ Profile::Wasm,
+ &self.keyring,
+ );
+
+ let version = client.runtime_version_at(&BlockId::number(0))
+ .expect("There should be runtime version at 0")
+ .spec_version;
+
+ let genesis_hash = client.block_hash(Zero::zero())
+ .expect("Database error?")
+ .expect("Genesis block always exists; qed")
+ .into();
+
+ let mut block = client
+ .new_block(Default::default())
+ .expect("Block creation failed");
+
+ let timestamp = 1 * MinimumPeriod::get();
+
+ let mut inherent_data = InherentData::new();
+ inherent_data.put_data(sp_timestamp::INHERENT_IDENTIFIER, ×tamp)
+ .expect("Put timestamp failed");
+ inherent_data.put_data(sp_finality_tracker::INHERENT_IDENTIFIER, &0)
+ .expect("Put finality tracker failed");
+
+ for extrinsic in client.runtime_api()
+ .inherent_extrinsics_with_context(
+ &BlockId::number(0),
+ ExecutionContext::BlockConstruction,
+ inherent_data,
+ ).expect("Get inherents failed")
+ {
+ block.push(extrinsic).expect("Push inherent failed");
+ }
+
+ let mut iteration = 0;
+ let start = std::time::Instant::now();
+ for _ in 0..transactions {
+
+ let sender = self.keyring.at(iteration);
+ let receiver = get_account_id_from_seed::(
+ &format!("random-user//{}", iteration)
+ );
+
+ let signed = self.keyring.sign(
+ CheckedExtrinsic {
+ signed: Some((sender, signed_extra(0, 1*DOLLARS))),
+ function: Call::Balances(
+ BalancesCall::transfer(
+ pallet_indices::address::Address::Id(receiver),
+ 1*DOLLARS
+ )
+ ),
+ },
+ version,
+ genesis_hash,
+ );
+
+ let encoded = Encode::encode(&signed);
+
+ let opaque = OpaqueExtrinsic::decode(&mut &encoded[..])
+ .expect("Failed to decode opaque");
+
+ match block.push(opaque) {
+ Err(sp_blockchain::Error::ApplyExtrinsicFailed(
+ sp_blockchain::ApplyExtrinsicFailed::Validity(e)
+ )) if e.exhausted_resources() => {
+ break;
+ },
+ Err(err) => panic!("Error pushing transaction: {:?}", err),
+ Ok(_) => {},
+ }
+ iteration += 1;
+ }
+ let block = block.build().expect("Block build failed").block;
+
+ log::info!(
+ target: "bench-logistics",
+ "Block construction: {:#?} ({} tx)",
+ start.elapsed(), block.extrinsics.len()
+ );
+
+ block
+ }
+
+ /// Database path.
+ pub fn path(&self) -> &Path {
+ self.directory_guard.path()
+ }
+
+ /// Clone this database and create context for testing/benchmarking.
+ pub fn create_context(&self, profile: Profile) -> BenchContext {
+ let BenchDb { directory_guard, keyring } = self.clone();
+ let (client, backend) = Self::bench_client(directory_guard.path(), profile, &keyring);
+
+ BenchContext {
+ client, backend, db_guard: directory_guard,
+ }
+ }
+}
+
+impl BenchKeyring {
+ /// New keyring.
+ ///
+ /// `length` is the number of accounts generated.
+ pub fn new(length: usize) -> Self {
+ let mut accounts = BTreeMap::new();
+
+ for n in 0..length {
+ let seed = format!("//endowed-user/{}", n);
+ let pair = sr25519::Pair::from_string(&seed, None).expect("failed to generate pair");
+ let account_id = AccountPublic::from(pair.public()).into_account();
+ accounts.insert(account_id, pair);
+ }
+
+ Self { accounts }
+ }
+
+ /// Generated account id-s from keyring keypairs.
+ pub fn collect_account_ids(&self) -> Vec {
+ self.accounts.keys().cloned().collect()
+ }
+
+ /// Get account id at position `index`
+ pub fn at(&self, index: usize) -> AccountId {
+ self.accounts.keys().nth(index).expect("Failed to get account").clone()
+ }
+
+ /// Sign transaction with keypair from this keyring.
+ pub fn sign(&self, xt: CheckedExtrinsic, version: u32, genesis_hash: [u8; 32]) -> UncheckedExtrinsic {
+ match xt.signed {
+ Some((signed, extra)) => {
+ let payload = (xt.function, extra.clone(), version, genesis_hash, genesis_hash);
+ let key = self.accounts.get(&signed).expect("Account id not found in keyring");
+ let signature = payload.using_encoded(|b| {
+ if b.len() > 256 {
+ key.sign(&sp_io::hashing::blake2_256(b))
+ } else {
+ key.sign(b)
+ }
+ }).into();
+ UncheckedExtrinsic {
+ signature: Some((pallet_indices::address::Address::Id(signed), signature, extra)),
+ function: payload.0,
+ }
+ }
+ None => UncheckedExtrinsic {
+ signature: None,
+ function: xt.function,
+ },
+ }
+ }
+
+ /// Generate genesis with accounts from this keyring endowed with some balance.
+ pub fn generate_genesis(&self) -> node_runtime::GenesisConfig {
+ crate::genesis::config_endowed(
+ false,
+ Some(node_runtime::WASM_BINARY),
+ self.collect_account_ids(),
+ )
+ }
+}
+
+/// Profile for exetion strategies.
+#[derive(Clone, Copy, Debug)]
+pub enum Profile {
+ /// As native as possible.
+ Native,
+ /// As wasm as possible.
+ Wasm,
+}
+
+impl Profile {
+ fn into_execution_strategies(self) -> ExecutionStrategies {
+ match self {
+ Profile::Wasm => ExecutionStrategies {
+ syncing: ExecutionStrategy::AlwaysWasm,
+ importing: ExecutionStrategy::AlwaysWasm,
+ block_construction: ExecutionStrategy::AlwaysWasm,
+ offchain_worker: ExecutionStrategy::AlwaysWasm,
+ other: ExecutionStrategy::AlwaysWasm,
+ },
+ Profile::Native => ExecutionStrategies {
+ syncing: ExecutionStrategy::NativeElseWasm,
+ importing: ExecutionStrategy::NativeElseWasm,
+ block_construction: ExecutionStrategy::NativeElseWasm,
+ offchain_worker: ExecutionStrategy::NativeElseWasm,
+ other: ExecutionStrategy::NativeElseWasm,
+ }
+ }
+ }
+}
+
+struct Guard(tempfile::TempDir);
+
+impl Guard {
+ fn path(&self) -> &Path {
+ self.0.path()
+ }
+}
+
+/// Benchmarking/test context holding instantiated client and backend references.
+pub struct BenchContext {
+ /// Node client.
+ pub client: Client,
+ /// Node backend.
+ pub backend: Arc,
+
+ db_guard: Guard,
+}
+
+type AccountPublic =