Run cargo fmt on the whole code base (#9394)

* Run cargo fmt on the whole code base

* Second run

* Add CI check

* Fix compilation

* More unnecessary braces

* Handle weights

* Use --all

* Use correct attributes...

* Fix UI tests

* AHHHHHHHHH

* 🤦

* Docs

* Fix compilation

* 🤷

* Please stop

* 🤦 x 2

* More

* make rustfmt.toml consistent with polkadot

Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
Bastian Köcher
2021-07-21 16:32:32 +02:00
committed by GitHub
parent d451c38c1c
commit 7b56ab15b4
1010 changed files with 53339 additions and 51208 deletions
+8
View File
@@ -233,6 +233,14 @@ cargo-deny:
# FIXME: Temorarily allow to fail. # FIXME: Temorarily allow to fail.
allow_failure: true allow_failure: true
cargo-fmt:
stage: test
<<: *docker-env
<<: *test-refs
script:
- cargo +nightly fmt --all -- --check
allow_failure: true
cargo-check-benches: cargo-check-benches:
stage: test stage: test
<<: *docker-env <<: *docker-env
@@ -26,6 +26,7 @@
// {{arg}} // {{arg}}
{{/each}} {{/each}}
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)] #![allow(unused_parens)]
#![allow(unused_imports)] #![allow(unused_imports)]
@@ -1,12 +1,12 @@
use sp_core::{Pair, Public, sr25519};
use node_template_runtime::{ use node_template_runtime::{
AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,
SudoConfig, SystemConfig, WASM_BINARY, Signature SystemConfig, WASM_BINARY,
}; };
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_finality_grandpa::AuthorityId as GrandpaId;
use sp_runtime::traits::{Verify, IdentifyAccount};
use sc_service::ChainType; use sc_service::ChainType;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_core::{sr25519, Pair, Public};
use sp_finality_grandpa::AuthorityId as GrandpaId;
use sp_runtime::traits::{IdentifyAccount, Verify};
// The URL for the telemetry server. // The URL for the telemetry server.
// const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; // const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
@@ -24,18 +24,16 @@ pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Pu
type AccountPublic = <Signature as Verify>::Signer; type AccountPublic = <Signature as Verify>::Signer;
/// Generate an account ID from seed. /// Generate an account ID from seed.
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId where pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
AccountPublic: From<<TPublic::Pair as Pair>::Public> where
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{ {
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account() AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
} }
/// Generate an Aura authority key. /// Generate an Aura authority key.
pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {
( (get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))
get_from_seed::<AuraId>(s),
get_from_seed::<GrandpaId>(s),
)
} }
pub fn development_config() -> Result<ChainSpec, String> { pub fn development_config() -> Result<ChainSpec, String> {
@@ -47,23 +45,23 @@ pub fn development_config() -> Result<ChainSpec, String> {
// ID // ID
"dev", "dev",
ChainType::Development, ChainType::Development,
move || testnet_genesis( move || {
wasm_binary, testnet_genesis(
// Initial PoA authorities wasm_binary,
vec![ // Initial PoA authorities
authority_keys_from_seed("Alice"), vec![authority_keys_from_seed("Alice")],
], // Sudo account
// Sudo account
get_account_id_from_seed::<sr25519::Public>("Alice"),
// Pre-funded accounts
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"), get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"), // Pre-funded accounts
get_account_id_from_seed::<sr25519::Public>("Alice//stash"), vec![
get_account_id_from_seed::<sr25519::Public>("Bob//stash"), get_account_id_from_seed::<sr25519::Public>("Alice"),
], get_account_id_from_seed::<sr25519::Public>("Bob"),
true, get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
), get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
],
true,
)
},
// Bootnodes // Bootnodes
vec![], vec![],
// Telemetry // Telemetry
@@ -86,32 +84,31 @@ pub fn local_testnet_config() -> Result<ChainSpec, String> {
// ID // ID
"local_testnet", "local_testnet",
ChainType::Local, ChainType::Local,
move || testnet_genesis( move || {
wasm_binary, testnet_genesis(
// Initial PoA authorities wasm_binary,
vec![ // Initial PoA authorities
authority_keys_from_seed("Alice"), vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")],
authority_keys_from_seed("Bob"), // Sudo account
],
// Sudo account
get_account_id_from_seed::<sr25519::Public>("Alice"),
// Pre-funded accounts
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"), get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"), // Pre-funded accounts
get_account_id_from_seed::<sr25519::Public>("Charlie"), vec![
get_account_id_from_seed::<sr25519::Public>("Dave"), get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Eve"), get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Ferdie"), get_account_id_from_seed::<sr25519::Public>("Charlie"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"), get_account_id_from_seed::<sr25519::Public>("Dave"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"), get_account_id_from_seed::<sr25519::Public>("Eve"),
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"), get_account_id_from_seed::<sr25519::Public>("Ferdie"),
get_account_id_from_seed::<sr25519::Public>("Dave//stash"), get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Eve//stash"), get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"), get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
], get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
true, get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
), get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
],
true,
)
},
// Bootnodes // Bootnodes
vec![], vec![],
// Telemetry // Telemetry
@@ -141,7 +138,7 @@ fn testnet_genesis(
}, },
balances: BalancesConfig { balances: BalancesConfig {
// Configure endowed accounts with initial balance of 1 << 60. // Configure endowed accounts with initial balance of 1 << 60.
balances: endowed_accounts.iter().cloned().map(|k|(k, 1 << 60)).collect(), balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
}, },
aura: AuraConfig { aura: AuraConfig {
authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(), authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),
+1 -1
View File
@@ -1,5 +1,5 @@
use structopt::StructOpt;
use sc_cli::RunCmd; use sc_cli::RunCmd;
use structopt::StructOpt;
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
pub struct Cli { pub struct Cli {
+24 -23
View File
@@ -15,11 +15,14 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::{chain_spec, service}; use crate::{
use crate::cli::{Cli, Subcommand}; chain_spec,
use sc_cli::{SubstrateCli, RuntimeVersion, Role, ChainSpec}; cli::{Cli, Subcommand},
use sc_service::PartialComponents; service,
};
use node_template_runtime::Block; use node_template_runtime::Block;
use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli};
use sc_service::PartialComponents;
impl SubstrateCli for Cli { impl SubstrateCli for Cli {
fn impl_name() -> String { fn impl_name() -> String {
@@ -50,9 +53,8 @@ impl SubstrateCli for Cli {
Ok(match id { Ok(match id {
"dev" => Box::new(chain_spec::development_config()?), "dev" => Box::new(chain_spec::development_config()?),
"" | "local" => Box::new(chain_spec::local_testnet_config()?), "" | "local" => Box::new(chain_spec::local_testnet_config()?),
path => Box::new(chain_spec::ChainSpec::from_json_file( path =>
std::path::PathBuf::from(path), Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
)?),
}) })
} }
@@ -74,32 +76,30 @@ pub fn run() -> sc_cli::Result<()> {
Some(Subcommand::CheckBlock(cmd)) => { Some(Subcommand::CheckBlock(cmd)) => {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.async_run(|config| { runner.async_run(|config| {
let PartialComponents { client, task_manager, import_queue, ..} let PartialComponents { client, task_manager, import_queue, .. } =
= service::new_partial(&config)?; service::new_partial(&config)?;
Ok((cmd.run(client, import_queue), task_manager)) Ok((cmd.run(client, import_queue), task_manager))
}) })
}, },
Some(Subcommand::ExportBlocks(cmd)) => { Some(Subcommand::ExportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.async_run(|config| { runner.async_run(|config| {
let PartialComponents { client, task_manager, ..} let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?;
= service::new_partial(&config)?;
Ok((cmd.run(client, config.database), task_manager)) Ok((cmd.run(client, config.database), task_manager))
}) })
}, },
Some(Subcommand::ExportState(cmd)) => { Some(Subcommand::ExportState(cmd)) => {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.async_run(|config| { runner.async_run(|config| {
let PartialComponents { client, task_manager, ..} let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?;
= service::new_partial(&config)?;
Ok((cmd.run(client, config.chain_spec), task_manager)) Ok((cmd.run(client, config.chain_spec), task_manager))
}) })
}, },
Some(Subcommand::ImportBlocks(cmd)) => { Some(Subcommand::ImportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.async_run(|config| { runner.async_run(|config| {
let PartialComponents { client, task_manager, import_queue, ..} let PartialComponents { client, task_manager, import_queue, .. } =
= service::new_partial(&config)?; service::new_partial(&config)?;
Ok((cmd.run(client, import_queue), task_manager)) Ok((cmd.run(client, import_queue), task_manager))
}) })
}, },
@@ -110,29 +110,30 @@ pub fn run() -> sc_cli::Result<()> {
Some(Subcommand::Revert(cmd)) => { Some(Subcommand::Revert(cmd)) => {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.async_run(|config| { runner.async_run(|config| {
let PartialComponents { client, task_manager, backend, ..} let PartialComponents { client, task_manager, backend, .. } =
= service::new_partial(&config)?; service::new_partial(&config)?;
Ok((cmd.run(client, backend), task_manager)) Ok((cmd.run(client, backend), task_manager))
}) })
}, },
Some(Subcommand::Benchmark(cmd)) => { Some(Subcommand::Benchmark(cmd)) =>
if cfg!(feature = "runtime-benchmarks") { if cfg!(feature = "runtime-benchmarks") {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run::<Block, service::Executor>(config)) runner.sync_run(|config| cmd.run::<Block, service::Executor>(config))
} else { } else {
Err("Benchmarking wasn't enabled when building the node. \ Err("Benchmarking wasn't enabled when building the node. \
You can enable it with `--features runtime-benchmarks`.".into()) You can enable it with `--features runtime-benchmarks`."
} .into())
}, },
None => { None => {
let runner = cli.create_runner(&cli.run)?; let runner = cli.create_runner(&cli.run)?;
runner.run_node_until_exit(|config| async move { runner.run_node_until_exit(|config| async move {
match config.role { match config.role {
Role::Light => service::new_light(config), Role::Light => service::new_light(config),
_ => service::new_full(config), _ => service::new_full(config),
}.map_err(sc_cli::Error::Service) }
.map_err(sc_cli::Error::Service)
}) })
} },
} }
} }
+1 -1
View File
@@ -1,3 +1,3 @@
pub mod chain_spec; pub mod chain_spec;
pub mod service;
pub mod rpc; pub mod rpc;
pub mod service;
+10 -20
View File
@@ -8,12 +8,11 @@
use std::sync::Arc; use std::sync::Arc;
use node_template_runtime::{opaque::Block, AccountId, Balance, Index}; use node_template_runtime::{opaque::Block, AccountId, Balance, Index};
use sp_api::ProvideRuntimeApi;
use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend};
use sp_block_builder::BlockBuilder;
pub use sc_rpc_api::DenyUnsafe; pub use sc_rpc_api::DenyUnsafe;
use sc_transaction_pool_api::TransactionPool; use sc_transaction_pool_api::TransactionPool;
use sp_api::ProvideRuntimeApi;
use sp_block_builder::BlockBuilder;
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
/// Full client dependencies. /// Full client dependencies.
pub struct FullDeps<C, P> { pub struct FullDeps<C, P> {
@@ -26,34 +25,25 @@ pub struct FullDeps<C, P> {
} }
/// Instantiate all full RPC extensions. /// Instantiate all full RPC extensions.
pub fn create_full<C, P>( pub fn create_full<C, P>(deps: FullDeps<C, P>) -> jsonrpc_core::IoHandler<sc_rpc::Metadata>
deps: FullDeps<C, P>, where
) -> jsonrpc_core::IoHandler<sc_rpc::Metadata> where
C: ProvideRuntimeApi<Block>, C: ProvideRuntimeApi<Block>,
C: HeaderBackend<Block> + HeaderMetadata<Block, Error=BlockChainError> + 'static, C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError> + 'static,
C: Send + Sync + 'static, C: Send + Sync + 'static,
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>, C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>, C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
C::Api: BlockBuilder<Block>, C::Api: BlockBuilder<Block>,
P: TransactionPool + 'static, P: TransactionPool + 'static,
{ {
use substrate_frame_rpc_system::{FullSystem, SystemApi};
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
use substrate_frame_rpc_system::{FullSystem, SystemApi};
let mut io = jsonrpc_core::IoHandler::default(); let mut io = jsonrpc_core::IoHandler::default();
let FullDeps { let FullDeps { client, pool, deny_unsafe } = deps;
client,
pool,
deny_unsafe,
} = deps;
io.extend_with( io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe)));
SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))
);
io.extend_with( io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone())));
TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone()))
);
// Extend this RPC with a custom API by using the following syntax. // Extend this RPC with a custom API by using the following syntax.
// `YourRpcStruct` should have a reference to a client, which is needed // `YourRpcStruct` should have a reference to a client, which is needed
+83 -71
View File
@@ -1,17 +1,17 @@
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service. //! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
use std::{sync::Arc, time::Duration};
use sc_client_api::{ExecutorProvider, RemoteBackend};
use node_template_runtime::{self, opaque::Block, RuntimeApi}; use node_template_runtime::{self, opaque::Block, RuntimeApi};
use sc_service::{error::Error as ServiceError, Configuration, TaskManager}; use sc_client_api::{ExecutorProvider, RemoteBackend};
use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams};
use sc_executor::native_executor_instance; use sc_executor::native_executor_instance;
pub use sc_executor::NativeExecutor; pub use sc_executor::NativeExecutor;
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
use sc_consensus_aura::{ImportQueueParams, StartAuraParams, SlotProportion};
use sc_finality_grandpa::SharedVoterState; use sc_finality_grandpa::SharedVoterState;
use sc_keystore::LocalKeystore; use sc_keystore::LocalKeystore;
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
use sc_telemetry::{Telemetry, TelemetryWorker}; use sc_telemetry::{Telemetry, TelemetryWorker};
use sp_consensus::SlotData; use sp_consensus::SlotData;
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
use std::{sync::Arc, time::Duration};
// Our native executor instance. // Our native executor instance.
native_executor_instance!( native_executor_instance!(
@@ -25,22 +25,35 @@ type FullClient = sc_service::TFullClient<Block, RuntimeApi, Executor>;
type FullBackend = sc_service::TFullBackend<Block>; type FullBackend = sc_service::TFullBackend<Block>;
type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>; type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponents< pub fn new_partial(
FullClient, FullBackend, FullSelectChain, config: &Configuration,
sp_consensus::DefaultImportQueue<Block, FullClient>, ) -> Result<
sc_transaction_pool::FullPool<Block, FullClient>, sc_service::PartialComponents<
( FullClient,
sc_finality_grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, FullSelectChain>, FullBackend,
sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>, FullSelectChain,
Option<Telemetry>, sp_consensus::DefaultImportQueue<Block, FullClient>,
) sc_transaction_pool::FullPool<Block, FullClient>,
>, ServiceError> { (
sc_finality_grandpa::GrandpaBlockImport<
FullBackend,
Block,
FullClient,
FullSelectChain,
>,
sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
Option<Telemetry>,
),
>,
ServiceError,
> {
if config.keystore_remote.is_some() { if config.keystore_remote.is_some() {
return Err(ServiceError::Other( return Err(ServiceError::Other(format!("Remote Keystores are not supported.")))
format!("Remote Keystores are not supported.")))
} }
let telemetry = config.telemetry_endpoints.clone() let telemetry = config
.telemetry_endpoints
.clone()
.filter(|x| !x.is_empty()) .filter(|x| !x.is_empty())
.map(|endpoints| -> Result<_, sc_telemetry::Error> { .map(|endpoints| -> Result<_, sc_telemetry::Error> {
let worker = TelemetryWorker::new(16)?; let worker = TelemetryWorker::new(16)?;
@@ -56,11 +69,10 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen
)?; )?;
let client = Arc::new(client); let client = Arc::new(client);
let telemetry = telemetry let telemetry = telemetry.map(|(worker, telemetry)| {
.map(|(worker, telemetry)| { task_manager.spawn_handle().spawn("telemetry", worker.run());
task_manager.spawn_handle().spawn("telemetry", worker.run()); telemetry
telemetry });
});
let select_chain = sc_consensus::LongestChain::new(backend.clone()); let select_chain = sc_consensus::LongestChain::new(backend.clone());
@@ -81,8 +93,8 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen
let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration(); let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>( let import_queue =
ImportQueueParams { sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
block_import: grandpa_block_import.clone(), block_import: grandpa_block_import.clone(),
justification_import: Some(Box::new(grandpa_block_import.clone())), justification_import: Some(Box::new(grandpa_block_import.clone())),
client: client.clone(), client: client.clone(),
@@ -98,12 +110,13 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen
Ok((timestamp, slot)) Ok((timestamp, slot))
}, },
spawner: &task_manager.spawn_essential_handle(), spawner: &task_manager.spawn_essential_handle(),
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()), can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(
client.executor().clone(),
),
registry: config.prometheus_registry(), registry: config.prometheus_registry(),
check_for_equivocation: Default::default(), check_for_equivocation: Default::default(),
telemetry: telemetry.as_ref().map(|x| x.handle()), telemetry: telemetry.as_ref().map(|x| x.handle()),
}, })?;
)?;
Ok(sc_service::PartialComponents { Ok(sc_service::PartialComponents {
client, client,
@@ -140,10 +153,11 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
if let Some(url) = &config.keystore_remote { if let Some(url) = &config.keystore_remote {
match remote_keystore(url) { match remote_keystore(url) {
Ok(k) => keystore_container.set_remote_keystore(k), Ok(k) => keystore_container.set_remote_keystore(k),
Err(e) => { Err(e) =>
return Err(ServiceError::Other( return Err(ServiceError::Other(format!(
format!("Error hooking up remote keystore for {}: {}", url, e))) "Error hooking up remote keystore for {}: {}",
} url, e
))),
}; };
} }
@@ -162,7 +176,10 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
if config.offchain_worker.enabled { if config.offchain_worker.enabled {
sc_service::build_offchain_workers( sc_service::build_offchain_workers(
&config, task_manager.spawn_handle(), client.clone(), network.clone(), &config,
task_manager.spawn_handle(),
client.clone(),
network.clone(),
); );
} }
@@ -178,32 +195,27 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
let pool = transaction_pool.clone(); let pool = transaction_pool.clone();
Box::new(move |deny_unsafe, _| { Box::new(move |deny_unsafe, _| {
let deps = crate::rpc::FullDeps { let deps =
client: client.clone(), crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe };
pool: pool.clone(),
deny_unsafe,
};
crate::rpc::create_full(deps) crate::rpc::create_full(deps)
}) })
}; };
let _rpc_handlers = sc_service::spawn_tasks( let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
sc_service::SpawnTasksParams { network: network.clone(),
network: network.clone(), client: client.clone(),
client: client.clone(), keystore: keystore_container.sync_keystore(),
keystore: keystore_container.sync_keystore(), task_manager: &mut task_manager,
task_manager: &mut task_manager, transaction_pool: transaction_pool.clone(),
transaction_pool: transaction_pool.clone(), rpc_extensions_builder,
rpc_extensions_builder, on_demand: None,
on_demand: None, remote_blockchain: None,
remote_blockchain: None, backend,
backend, system_rpc_tx,
system_rpc_tx, config,
config, telemetry: telemetry.as_mut(),
telemetry: telemetry.as_mut(), })?;
},
)?;
if role.is_authority() { if role.is_authority() {
let proposer_factory = sc_basic_authorship::ProposerFactory::new( let proposer_factory = sc_basic_authorship::ProposerFactory::new(
@@ -257,11 +269,8 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
// if the node isn't actively participating in consensus then it doesn't // if the node isn't actively participating in consensus then it doesn't
// need a keystore, regardless of which protocol we use below. // need a keystore, regardless of which protocol we use below.
let keystore = if role.is_authority() { let keystore =
Some(keystore_container.sync_keystore()) if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None };
} else {
None
};
let grandpa_config = sc_finality_grandpa::Config { let grandpa_config = sc_finality_grandpa::Config {
// FIXME #1578 make this available through chainspec // FIXME #1578 make this available through chainspec
@@ -295,7 +304,7 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
// if it fails we take down the service with it. // if it fails we take down the service with it.
task_manager.spawn_essential_handle().spawn_blocking( task_manager.spawn_essential_handle().spawn_blocking(
"grandpa-voter", "grandpa-voter",
sc_finality_grandpa::run_grandpa_voter(grandpa_config)? sc_finality_grandpa::run_grandpa_voter(grandpa_config)?,
); );
} }
@@ -305,7 +314,9 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
/// Builds a new service for a light client. /// Builds a new service for a light client.
pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError> { pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError> {
let telemetry = config.telemetry_endpoints.clone() let telemetry = config
.telemetry_endpoints
.clone()
.filter(|x| !x.is_empty()) .filter(|x| !x.is_empty())
.map(|endpoints| -> Result<_, sc_telemetry::Error> { .map(|endpoints| -> Result<_, sc_telemetry::Error> {
let worker = TelemetryWorker::new(16)?; let worker = TelemetryWorker::new(16)?;
@@ -320,11 +331,10 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
)?; )?;
let mut telemetry = telemetry let mut telemetry = telemetry.map(|(worker, telemetry)| {
.map(|(worker, telemetry)| { task_manager.spawn_handle().spawn("telemetry", worker.run());
task_manager.spawn_handle().spawn("telemetry", worker.run()); telemetry
telemetry });
});
config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config()); config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config());
@@ -347,8 +357,8 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration(); let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>( let import_queue =
ImportQueueParams { sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
block_import: grandpa_block_import.clone(), block_import: grandpa_block_import.clone(),
justification_import: Some(Box::new(grandpa_block_import.clone())), justification_import: Some(Box::new(grandpa_block_import.clone())),
client: client.clone(), client: client.clone(),
@@ -368,8 +378,7 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
registry: config.prometheus_registry(), registry: config.prometheus_registry(),
check_for_equivocation: Default::default(), check_for_equivocation: Default::default(),
telemetry: telemetry.as_ref().map(|x| x.handle()), telemetry: telemetry.as_ref().map(|x| x.handle()),
}, })?;
)?;
let (network, system_rpc_tx, network_starter) = let (network, system_rpc_tx, network_starter) =
sc_service::build_network(sc_service::BuildNetworkParams { sc_service::build_network(sc_service::BuildNetworkParams {
@@ -384,7 +393,10 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
if config.offchain_worker.enabled { if config.offchain_worker.enabled {
sc_service::build_offchain_workers( sc_service::build_offchain_workers(
&config, task_manager.spawn_handle(), client.clone(), network.clone(), &config,
task_manager.spawn_handle(),
client.clone(),
network.clone(),
); );
} }
@@ -2,10 +2,10 @@
use super::*; use super::*;
use frame_system::RawOrigin;
use frame_benchmarking::{benchmarks, whitelisted_caller, impl_benchmark_test_suite};
#[allow(unused)] #[allow(unused)]
use crate::Pallet as Template; use crate::Pallet as Template;
use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller};
use frame_system::RawOrigin;
benchmarks! { benchmarks! {
do_something { do_something {
@@ -17,8 +17,4 @@ benchmarks! {
} }
} }
impl_benchmark_test_suite!( impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test);
Template,
crate::mock::new_test_ext(),
crate::mock::Test,
);
@@ -3,7 +3,6 @@
/// Edit this file to define custom logic or remove it if it is not needed. /// Edit this file to define custom logic or remove it if it is not needed.
/// Learn more about FRAME and the core library of Substrate FRAME pallets: /// Learn more about FRAME and the core library of Substrate FRAME pallets:
/// <https://substrate.dev/docs/en/knowledgebase/runtime/frame> /// <https://substrate.dev/docs/en/knowledgebase/runtime/frame>
pub use pallet::*; pub use pallet::*;
#[cfg(test)] #[cfg(test)]
@@ -63,7 +62,7 @@ pub mod pallet {
// These functions materialize as "extrinsics", which are often compared to transactions. // These functions materialize as "extrinsics", which are often compared to transactions.
// Dispatchable functions must be annotated with a weight and must return a DispatchResult. // Dispatchable functions must be annotated with a weight and must return a DispatchResult.
#[pallet::call] #[pallet::call]
impl<T:Config> Pallet<T> { impl<T: Config> Pallet<T> {
/// An example dispatchable that takes a singles value as a parameter, writes the value to /// An example dispatchable that takes a singles value as a parameter, writes the value to
/// storage and emits an event. This function must be dispatched by a signed extrinsic. /// storage and emits an event. This function must be dispatched by a signed extrinsic.
#[pallet::weight(10_000 + T::DbWeight::get().writes(1))] #[pallet::weight(10_000 + T::DbWeight::get().writes(1))]
@@ -1,10 +1,11 @@
use crate as pallet_template; use crate as pallet_template;
use sp_core::H256;
use frame_support::parameter_types; use frame_support::parameter_types;
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup}, testing::Header,
};
use frame_system as system; use frame_system as system;
use sp_core::H256;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentityLookup},
};
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>; type Block = frame_system::mocking::MockBlock<Test>;
@@ -1,5 +1,5 @@
use crate::{Error, mock::*}; use crate::{mock::*, Error};
use frame_support::{assert_ok, assert_noop}; use frame_support::{assert_noop, assert_ok};
#[test] #[test]
fn it_works_for_default_value() { fn it_works_for_default_value() {
@@ -15,9 +15,6 @@ fn it_works_for_default_value() {
fn correct_error_for_none_value() { fn correct_error_for_none_value() {
new_test_ext().execute_with(|| { new_test_ext().execute_with(|| {
// Ensure the expected error is thrown when no value is present. // Ensure the expected error is thrown when no value is present.
assert_noop!( assert_noop!(TemplateModule::cause_error(Origin::signed(1)), Error::<Test>::NoneValue);
TemplateModule::cause_error(Origin::signed(1)),
Error::<Test>::NoneValue
);
}); });
} }
+22 -24
View File
@@ -1,43 +1,44 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit="256"] #![recursion_limit = "256"]
// Make the WASM binary available. // Make the WASM binary available.
#[cfg(feature = "std")] #[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
use sp_std::prelude::*; use pallet_grandpa::{
use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
use sp_runtime::{
ApplyExtrinsicResult, generic, create_runtime_str, impl_opaque_keys, MultiSignature,
transaction_validity::{TransactionValidity, TransactionSource},
};
use sp_runtime::traits::{
BlakeTwo256, Block as BlockT, AccountIdLookup, Verify, IdentifyAccount, NumberFor,
}; };
use sp_api::impl_runtime_apis; use sp_api::impl_runtime_apis;
use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use pallet_grandpa::fg_primitives; use sp_runtime::{
use sp_version::RuntimeVersion; create_runtime_str, generic, impl_opaque_keys,
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, Verify},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, MultiSignature,
};
use sp_std::prelude::*;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use sp_version::NativeVersion; use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
// A few exports that help ease life for downstream crates. // A few exports that help ease life for downstream crates.
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
pub use pallet_timestamp::Call as TimestampCall;
pub use pallet_balances::Call as BalancesCall;
pub use sp_runtime::{Permill, Perbill};
pub use frame_support::{ pub use frame_support::{
construct_runtime, parameter_types, StorageValue, construct_runtime, parameter_types,
traits::{KeyOwnerProofSystem, Randomness, StorageInfo}, traits::{KeyOwnerProofSystem, Randomness, StorageInfo},
weights::{ weights::{
Weight, IdentityFee,
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
IdentityFee, Weight,
}, },
StorageValue,
}; };
pub use pallet_balances::Call as BalancesCall;
pub use pallet_timestamp::Call as TimestampCall;
use pallet_transaction_payment::CurrencyAdapter; use pallet_transaction_payment::CurrencyAdapter;
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
pub use sp_runtime::{Perbill, Permill};
/// Import the template pallet. /// Import the template pallet.
pub use pallet_template; pub use pallet_template;
@@ -123,10 +124,7 @@ pub const DAYS: BlockNumber = HOURS * 24;
/// The version information used to identify this runtime when compiled natively. /// The version information used to identify this runtime when compiled natively.
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn native_version() -> NativeVersion { pub fn native_version() -> NativeVersion {
NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
runtime_version: VERSION,
can_author_with: Default::default(),
}
} }
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
@@ -306,7 +304,7 @@ pub type SignedExtra = (
frame_system::CheckEra<Runtime>, frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>, frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>, frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime> pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
); );
/// Unchecked extrinsic type as expected by this runtime. /// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
+60 -60
View File
@@ -24,36 +24,22 @@
//! DO NOT depend on user input). Thus transaction generation should be //! DO NOT depend on user input). Thus transaction generation should be
//! based on randomized data. //! based on randomized data.
use std::{
borrow::Cow,
collections::HashMap,
pin::Pin,
sync::Arc,
};
use futures::Future; use futures::Future;
use std::{borrow::Cow, collections::HashMap, pin::Pin, sync::Arc};
use node_primitives::Block; use node_primitives::Block;
use node_testing::bench::{BenchDb, Profile, BlockType, KeyTypes, DatabaseType}; use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile};
use sp_runtime::{
generic::BlockId,
traits::NumberFor,
OpaqueExtrinsic,
};
use sc_transaction_pool_api::{ use sc_transaction_pool_api::{
ImportNotificationStream, ImportNotificationStream, PoolFuture, PoolStatus, TransactionFor, TransactionSource,
PoolFuture, TransactionStatusStreamFor, TxHash,
PoolStatus,
TransactionFor,
TransactionSource,
TransactionStatusStreamFor,
TxHash,
}; };
use sp_consensus::{Environment, Proposer}; use sp_consensus::{Environment, Proposer};
use sp_inherents::InherentDataProvider; use sp_inherents::InherentDataProvider;
use sp_runtime::{generic::BlockId, traits::NumberFor, OpaqueExtrinsic};
use crate::{ use crate::{
common::SizeType, common::SizeType,
core::{self, Path, Mode}, core::{self, Mode, Path},
}; };
pub struct ConstructionBenchmarkDescription { pub struct ConstructionBenchmarkDescription {
@@ -72,7 +58,6 @@ pub struct ConstructionBenchmark {
impl core::BenchmarkDescription for ConstructionBenchmarkDescription { impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
fn path(&self) -> Path { fn path(&self) -> Path {
let mut path = Path::new(&["node", "proposer"]); let mut path = Path::new(&["node", "proposer"]);
match self.profile { match self.profile {
@@ -104,11 +89,7 @@ impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> { fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
let mut extrinsics: Vec<Arc<PoolTransaction>> = Vec::new(); let mut extrinsics: Vec<Arc<PoolTransaction>> = Vec::new();
let mut bench_db = BenchDb::with_key_types( let mut bench_db = BenchDb::with_key_types(self.database_type, 50_000, self.key_types);
self.database_type,
50_000,
self.key_types
);
let client = bench_db.client(); let client = bench_db.client();
@@ -127,11 +108,9 @@ impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
fn name(&self) -> Cow<'static, str> { fn name(&self) -> Cow<'static, str> {
format!( format!(
"Block construction ({:?}/{}, {:?}, {:?} backend)", "Block construction ({:?}/{}, {:?}, {:?} backend)",
self.block_type, self.block_type, self.size, self.profile, self.database_type,
self.size, )
self.profile, .into()
self.database_type,
).into()
} }
} }
@@ -139,7 +118,9 @@ impl core::Benchmark for ConstructionBenchmark {
fn run(&mut self, mode: Mode) -> std::time::Duration { fn run(&mut self, mode: Mode) -> std::time::Duration {
let context = self.database.create_context(self.profile); let context = self.database.create_context(self.profile);
let _ = context.client.runtime_version_at(&BlockId::Number(0)) let _ = context
.client
.runtime_version_at(&BlockId::Number(0))
.expect("Failed to get runtime version") .expect("Failed to get runtime version")
.spec_version; .spec_version;
@@ -158,20 +139,25 @@ impl core::Benchmark for ConstructionBenchmark {
let start = std::time::Instant::now(); let start = std::time::Instant::now();
let proposer = futures::executor::block_on(proposer_factory.init( let proposer = futures::executor::block_on(
&context.client.header(&BlockId::number(0)) proposer_factory.init(
.expect("Database error querying block #0") &context
.expect("Block #0 should exist"), .client
)).expect("Proposer initialization failed"); .header(&BlockId::number(0))
.expect("Database error querying block #0")
let _block = futures::executor::block_on( .expect("Block #0 should exist"),
proposer.propose(
timestamp_provider.create_inherent_data().expect("Create inherent data failed"),
Default::default(),
std::time::Duration::from_secs(20),
None,
), ),
).map(|r| r.block).expect("Proposing failed"); )
.expect("Proposer initialization failed");
let _block = futures::executor::block_on(proposer.propose(
timestamp_provider.create_inherent_data().expect("Create inherent data failed"),
Default::default(),
std::time::Duration::from_secs(20),
None,
))
.map(|r| r.block)
.expect("Proposing failed");
let elapsed = start.elapsed(); let elapsed = start.elapsed();
@@ -191,10 +177,7 @@ pub struct PoolTransaction {
impl From<OpaqueExtrinsic> for PoolTransaction { impl From<OpaqueExtrinsic> for PoolTransaction {
fn from(e: OpaqueExtrinsic) -> Self { fn from(e: OpaqueExtrinsic) -> Self {
PoolTransaction { PoolTransaction { data: e, hash: node_primitives::Hash::zero() }
data: e,
hash: node_primitives::Hash::zero(),
}
} }
} }
@@ -210,15 +193,25 @@ impl sc_transaction_pool_api::InPoolTransaction for PoolTransaction {
&self.hash &self.hash
} }
fn priority(&self) -> &u64 { unimplemented!() } fn priority(&self) -> &u64 {
unimplemented!()
}
fn longevity(&self) -> &u64 { unimplemented!() } fn longevity(&self) -> &u64 {
unimplemented!()
}
fn requires(&self) -> &[Vec<u8>] { unimplemented!() } fn requires(&self) -> &[Vec<u8>] {
unimplemented!()
}
fn provides(&self) -> &[Vec<u8>] { unimplemented!() } fn provides(&self) -> &[Vec<u8>] {
unimplemented!()
}
fn is_propagable(&self) -> bool { unimplemented!() } fn is_propagable(&self) -> bool {
unimplemented!()
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -236,7 +229,7 @@ impl sc_transaction_pool_api::TransactionPool for Transactions {
_at: &BlockId<Self::Block>, _at: &BlockId<Self::Block>,
_source: TransactionSource, _source: TransactionSource,
_xts: Vec<TransactionFor<Self>>, _xts: Vec<TransactionFor<Self>>,
) -> PoolFuture<Vec<Result<node_primitives::Hash, Self::Error>>, Self::Error> { ) -> PoolFuture<Vec<Result<node_primitives::Hash, Self::Error>>, Self::Error> {
unimplemented!() unimplemented!()
} }
@@ -259,14 +252,21 @@ impl sc_transaction_pool_api::TransactionPool for Transactions {
unimplemented!() unimplemented!()
} }
fn ready_at(&self, _at: NumberFor<Self::Block>) fn ready_at(
-> Pin<Box<dyn Future<Output=Box<dyn Iterator<Item=Arc<Self::InPoolTransaction>> + Send>> + Send>> &self,
{ _at: NumberFor<Self::Block>,
let iter: Box<dyn Iterator<Item=Arc<PoolTransaction>> + Send> = Box::new(self.0.clone().into_iter()); ) -> Pin<
Box<
dyn Future<Output = Box<dyn Iterator<Item = Arc<Self::InPoolTransaction>> + Send>>
+ Send,
>,
> {
let iter: Box<dyn Iterator<Item = Arc<PoolTransaction>> + Send> =
Box::new(self.0.clone().into_iter());
Box::pin(futures::future::ready(iter)) Box::pin(futures::future::ready(iter))
} }
fn ready(&self) -> Box<dyn Iterator<Item=Arc<Self::InPoolTransaction>> + Send> { fn ready(&self) -> Box<dyn Iterator<Item = Arc<Self::InPoolTransaction>> + Send> {
unimplemented!() unimplemented!()
} }
+11 -11
View File
@@ -16,8 +16,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use std::{fmt, borrow::{Cow, ToOwned}};
use serde::Serialize; use serde::Serialize;
use std::{
borrow::{Cow, ToOwned},
fmt,
};
pub struct Path(Vec<String>); pub struct Path(Vec<String>);
@@ -33,7 +36,11 @@ impl Path {
} }
pub fn full(&self) -> String { pub fn full(&self) -> String {
self.0.iter().fold(String::new(), |mut val, next| { val.push_str("::"); val.push_str(next); val }) self.0.iter().fold(String::new(), |mut val, next| {
val.push_str("::");
val.push_str(next);
val
})
} }
pub fn has(&self, path: &str) -> bool { pub fn has(&self, path: &str) -> bool {
@@ -115,10 +122,7 @@ impl fmt::Display for BenchmarkOutput {
} }
} }
pub fn run_benchmark( pub fn run_benchmark(benchmark: Box<dyn BenchmarkDescription>, mode: Mode) -> BenchmarkOutput {
benchmark: Box<dyn BenchmarkDescription>,
mode: Mode,
) -> BenchmarkOutput {
let name = benchmark.name().to_owned(); let name = benchmark.name().to_owned();
let mut benchmark = benchmark.setup(); let mut benchmark = benchmark.setup();
@@ -133,11 +137,7 @@ pub fn run_benchmark(
let raw_average = (durations.iter().sum::<u128>() / (durations.len() as u128)) as u64; let raw_average = (durations.iter().sum::<u128>() / (durations.len() as u128)) as u64;
let average = (durations.iter().skip(10).take(30).sum::<u128>() / 30) as u64; let average = (durations.iter().skip(10).take(30).sum::<u128>() / 30) as u64;
BenchmarkOutput { BenchmarkOutput { name: name.into(), raw_average, average }
name: name.into(),
raw_average,
average,
}
} }
macro_rules! matrix( macro_rules! matrix(
+4 -3
View File
@@ -30,14 +30,15 @@ use crate::simple_trie::SimpleTrie;
/// return root. /// return root.
pub fn generate_trie( pub fn generate_trie(
db: Arc<dyn KeyValueDB>, db: Arc<dyn KeyValueDB>,
key_values: impl IntoIterator<Item=(Vec<u8>, Vec<u8>)>, key_values: impl IntoIterator<Item = (Vec<u8>, Vec<u8>)>,
) -> Hash { ) -> Hash {
let mut root = Hash::default(); let mut root = Hash::default();
let (db, overlay) = { let (db, overlay) = {
let mut overlay = HashMap::new(); let mut overlay = HashMap::new();
overlay.insert( overlay.insert(
hex::decode("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").expect("null key is valid"), hex::decode("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314")
.expect("null key is valid"),
Some(vec![0]), Some(vec![0]),
); );
let mut trie = SimpleTrie { db, overlay: &mut overlay }; let mut trie = SimpleTrie { db, overlay: &mut overlay };
@@ -50,7 +51,7 @@ pub fn generate_trie(
trie_db.commit(); trie_db.commit();
} }
( trie.db, overlay ) (trie.db, overlay)
}; };
let mut transaction = db.transaction(); let mut transaction = db.transaction();
+13 -19
View File
@@ -32,15 +32,15 @@
use std::borrow::Cow; use std::borrow::Cow;
use node_testing::bench::{BenchDb, Profile, BlockType, KeyTypes, DatabaseType};
use node_primitives::Block; use node_primitives::Block;
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile};
use sc_client_api::backend::Backend; use sc_client_api::backend::Backend;
use sp_runtime::generic::BlockId; use sp_runtime::generic::BlockId;
use sp_state_machine::InspectState; use sp_state_machine::InspectState;
use crate::{ use crate::{
common::SizeType, common::SizeType,
core::{self, Path, Mode}, core::{self, Mode, Path},
}; };
pub struct ImportBenchmarkDescription { pub struct ImportBenchmarkDescription {
@@ -60,7 +60,6 @@ pub struct ImportBenchmark {
impl core::BenchmarkDescription for ImportBenchmarkDescription { impl core::BenchmarkDescription for ImportBenchmarkDescription {
fn path(&self) -> Path { fn path(&self) -> Path {
let mut path = Path::new(&["node", "import"]); let mut path = Path::new(&["node", "import"]);
match self.profile { match self.profile {
@@ -91,11 +90,7 @@ impl core::BenchmarkDescription for ImportBenchmarkDescription {
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> { fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
let profile = self.profile; let profile = self.profile;
let mut bench_db = BenchDb::with_key_types( let mut bench_db = BenchDb::with_key_types(self.database_type, 50_000, self.key_types);
self.database_type,
50_000,
self.key_types
);
let block = bench_db.generate_block(self.block_type.to_content(self.size.transactions())); let block = bench_db.generate_block(self.block_type.to_content(self.size.transactions()));
Box::new(ImportBenchmark { Box::new(ImportBenchmark {
database: bench_db, database: bench_db,
@@ -108,11 +103,9 @@ impl core::BenchmarkDescription for ImportBenchmarkDescription {
fn name(&self) -> Cow<'static, str> { fn name(&self) -> Cow<'static, str> {
format!( format!(
"Block import ({:?}/{}, {:?}, {:?} backend)", "Block import ({:?}/{}, {:?}, {:?} backend)",
self.block_type, self.block_type, self.size, self.profile, self.database_type,
self.size, )
self.profile, .into()
self.database_type,
).into()
} }
} }
@@ -120,7 +113,9 @@ impl core::Benchmark for ImportBenchmark {
fn run(&mut self, mode: Mode) -> std::time::Duration { fn run(&mut self, mode: Mode) -> std::time::Duration {
let mut context = self.database.create_context(self.profile); let mut context = self.database.create_context(self.profile);
let _ = context.client.runtime_version_at(&BlockId::Number(0)) let _ = context
.client
.runtime_version_at(&BlockId::Number(0))
.expect("Failed to get runtime version") .expect("Failed to get runtime version")
.spec_version; .spec_version;
@@ -133,7 +128,8 @@ impl core::Benchmark for ImportBenchmark {
let elapsed = start.elapsed(); let elapsed = start.elapsed();
// Sanity checks. // Sanity checks.
context.client context
.client
.state_at(&BlockId::number(1)) .state_at(&BlockId::number(1))
.expect("state_at failed for block#1") .expect("state_at failed for block#1")
.inspect_state(|| { .inspect_state(|| {
@@ -155,19 +151,17 @@ impl core::Benchmark for ImportBenchmark {
BlockType::Noop => { BlockType::Noop => {
assert_eq!( assert_eq!(
node_runtime::System::events().len(), node_runtime::System::events().len(),
// should be 2 per signed extrinsic + 1 per unsigned // should be 2 per signed extrinsic + 1 per unsigned
// we have 1 unsigned and the rest are signed in the block // we have 1 unsigned and the rest are signed in the block
// those 2 events per signed are: // those 2 events per signed are:
// - deposit event for charging transaction fee // - deposit event for charging transaction fee
// - extrinsic success // - extrinsic success
(self.block.extrinsics.len() - 1) * 2 + 1, (self.block.extrinsics.len() - 1) * 2 + 1,
); );
}, },
_ => {}, _ => {},
} }
} });
);
if mode == Mode::Profile { if mode == Mode::Profile {
std::thread::park_timeout(std::time::Duration::from_secs(1)); std::thread::park_timeout(std::time::Duration::from_secs(1));
+26 -13
View File
@@ -18,9 +18,10 @@
mod common; mod common;
mod construct; mod construct;
#[macro_use] mod core; #[macro_use]
mod import; mod core;
mod generator; mod generator;
mod import;
mod simple_trie; mod simple_trie;
mod state_sizes; mod state_sizes;
mod tempdb; mod tempdb;
@@ -29,15 +30,15 @@ mod txpool;
use structopt::StructOpt; use structopt::StructOpt;
use node_testing::bench::{Profile, KeyTypes, BlockType, DatabaseType as BenchDataBaseType}; use node_testing::bench::{BlockType, DatabaseType as BenchDataBaseType, KeyTypes, Profile};
use crate::{ use crate::{
common::SizeType, common::SizeType,
core::{run_benchmark, Mode as BenchmarkMode},
tempdb::DatabaseType,
import::ImportBenchmarkDescription,
trie::{TrieReadBenchmarkDescription, TrieWriteBenchmarkDescription, DatabaseSize},
construct::ConstructionBenchmarkDescription, construct::ConstructionBenchmarkDescription,
core::{run_benchmark, Mode as BenchmarkMode},
import::ImportBenchmarkDescription,
tempdb::DatabaseType,
trie::{DatabaseSize, TrieReadBenchmarkDescription, TrieWriteBenchmarkDescription},
txpool::PoolBenchmarkDescription, txpool::PoolBenchmarkDescription,
}; };
@@ -92,14 +93,25 @@ fn main() {
SizeType::Large, SizeType::Large,
SizeType::Full, SizeType::Full,
SizeType::Custom(opt.transactions.unwrap_or(0)), SizeType::Custom(opt.transactions.unwrap_or(0)),
].iter() { ]
.iter()
{
for block_type in [ for block_type in [
BlockType::RandomTransfersKeepAlive, BlockType::RandomTransfersKeepAlive,
BlockType::RandomTransfersReaping, BlockType::RandomTransfersReaping,
BlockType::Noop, BlockType::Noop,
].iter() { ]
for database_type in [BenchDataBaseType::RocksDb, BenchDataBaseType::ParityDb].iter() { .iter()
import_benchmarks.push((profile, size.clone(), block_type.clone(), database_type)); {
for database_type in
[BenchDataBaseType::RocksDb, BenchDataBaseType::ParityDb].iter()
{
import_benchmarks.push((
profile,
size.clone(),
block_type.clone(),
database_type,
));
} }
} }
} }
@@ -163,7 +175,7 @@ fn main() {
println!("{}: {}", benchmark.name(), benchmark.path().full()) println!("{}: {}", benchmark.name(), benchmark.path().full())
} }
} }
return; return
} }
let mut results = Vec::new(); let mut results = Vec::new();
@@ -183,7 +195,8 @@ fn main() {
} }
if opt.json { if opt.json {
let json_result: String = serde_json::to_string(&results).expect("Failed to construct json"); let json_result: String =
serde_json::to_string(&results).expect("Failed to construct json");
println!("{}", json_result); println!("{}", json_result);
} }
} }
+5 -3
View File
@@ -18,10 +18,10 @@
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use hash_db::{AsHashDB, HashDB, Hasher as _, Prefix};
use kvdb::KeyValueDB; use kvdb::KeyValueDB;
use node_primitives::Hash; use node_primitives::Hash;
use sp_trie::DBValue; use sp_trie::DBValue;
use hash_db::{HashDB, AsHashDB, Prefix, Hasher as _};
pub type Hasher = sp_core::Blake2Hasher; pub type Hasher = sp_core::Blake2Hasher;
@@ -32,7 +32,9 @@ pub struct SimpleTrie<'a> {
} }
impl<'a> AsHashDB<Hasher, DBValue> for SimpleTrie<'a> { impl<'a> AsHashDB<Hasher, DBValue> for SimpleTrie<'a> {
fn as_hash_db(&self) -> &dyn hash_db::HashDB<Hasher, DBValue> { &*self } fn as_hash_db(&self) -> &dyn hash_db::HashDB<Hasher, DBValue> {
&*self
}
fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn HashDB<Hasher, DBValue> + 'b) { fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn HashDB<Hasher, DBValue> + 'b) {
&mut *self &mut *self
@@ -43,7 +45,7 @@ impl<'a> HashDB<Hasher, DBValue> for SimpleTrie<'a> {
fn get(&self, key: &Hash, prefix: Prefix) -> Option<DBValue> { fn get(&self, key: &Hash, prefix: Prefix) -> Option<DBValue> {
let key = sp_trie::prefixed_key::<Hasher>(key, prefix); let key = sp_trie::prefixed_key::<Hasher>(key, prefix);
if let Some(value) = self.overlay.get(&key) { if let Some(value) = self.overlay.get(&key) {
return value.clone(); return value.clone()
} }
self.db.get(0, &key).expect("Database backend error") self.db.get(0, &key).expect("Database backend error")
} }
+1 -1
View File
@@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
/// Kusama value size distribution /// Kusama value size distribution
pub const KUSAMA_STATE_DISTRIBUTION: &'static[(u32, u32)] = &[ pub const KUSAMA_STATE_DISTRIBUTION: &'static [(u32, u32)] = &[
(32, 35), (32, 35),
(33, 20035), (33, 20035),
(34, 5369), (34, 5369),
+23 -29
View File
@@ -16,9 +16,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use kvdb::{DBTransaction, KeyValueDB};
use kvdb_rocksdb::{Database, DatabaseConfig};
use std::{io, path::PathBuf, sync::Arc}; use std::{io, path::PathBuf, sync::Arc};
use kvdb::{KeyValueDB, DBTransaction};
use kvdb_rocksdb::{DatabaseConfig, Database};
#[derive(Debug, Clone, Copy, derive_more::Display)] #[derive(Debug, Clone, Copy, derive_more::Display)]
pub enum DatabaseType { pub enum DatabaseType {
@@ -44,13 +44,14 @@ impl KeyValueDB for ParityDbWrapper {
/// Write a transaction of changes to the buffer. /// Write a transaction of changes to the buffer.
fn write(&self, transaction: DBTransaction) -> io::Result<()> { fn write(&self, transaction: DBTransaction) -> io::Result<()> {
self.0.commit( self.0
transaction.ops.iter().map(|op| match op { .commit(transaction.ops.iter().map(|op| match op {
kvdb::DBOp::Insert { col, key, value } => (*col as u8, &key[key.len() - 32..], Some(value.to_vec())), kvdb::DBOp::Insert { col, key, value } =>
(*col as u8, &key[key.len() - 32..], Some(value.to_vec())),
kvdb::DBOp::Delete { col, key } => (*col as u8, &key[key.len() - 32..], None), kvdb::DBOp::Delete { col, key } => (*col as u8, &key[key.len() - 32..], None),
kvdb::DBOp::DeletePrefix { col: _, prefix: _ } => unimplemented!() kvdb::DBOp::DeletePrefix { col: _, prefix: _ } => unimplemented!(),
}) }))
).expect("db error"); .expect("db error");
Ok(()) Ok(())
} }
@@ -90,21 +91,19 @@ impl TempDatabase {
match db_type { match db_type {
DatabaseType::RocksDb => { DatabaseType::RocksDb => {
let db_cfg = DatabaseConfig::with_columns(1); let db_cfg = DatabaseConfig::with_columns(1);
let db = Database::open(&db_cfg, &self.0.path().to_string_lossy()).expect("Database backend error"); let db = Database::open(&db_cfg, &self.0.path().to_string_lossy())
.expect("Database backend error");
Arc::new(db) Arc::new(db)
}, },
DatabaseType::ParityDb => { DatabaseType::ParityDb => Arc::new(ParityDbWrapper({
Arc::new(ParityDbWrapper({ let mut options = parity_db::Options::with_columns(self.0.path(), 1);
let mut options = parity_db::Options::with_columns(self.0.path(), 1); let mut column_options = &mut options.columns[0];
let mut column_options = &mut options.columns[0]; column_options.ref_counted = true;
column_options.ref_counted = true; column_options.preimage = true;
column_options.preimage = true; column_options.uniform = true;
column_options.uniform = true; parity_db::Db::open(&options).expect("db open error")
parity_db::Db::open(&options).expect("db open error") })),
}))
}
} }
} }
} }
@@ -121,15 +120,10 @@ impl Clone for TempDatabase {
); );
let self_db_files = std::fs::read_dir(self_dir) let self_db_files = std::fs::read_dir(self_dir)
.expect("failed to list file in seed dir") .expect("failed to list file in seed dir")
.map(|f_result| .map(|f_result| f_result.expect("failed to read file in seed db").path())
f_result.expect("failed to read file in seed db") .collect::<Vec<PathBuf>>();
.path() fs_extra::copy_items(&self_db_files, new_dir.path(), &fs_extra::dir::CopyOptions::new())
).collect::<Vec<PathBuf>>(); .expect("Copy of seed database is ok");
fs_extra::copy_items(
&self_db_files,
new_dir.path(),
&fs_extra::dir::CopyOptions::new(),
).expect("Copy of seed database is ok");
TempDatabase(new_dir) TempDatabase(new_dir)
} }
+20 -27
View File
@@ -18,13 +18,13 @@
//! Trie benchmark (integrated). //! Trie benchmark (integrated).
use std::{borrow::Cow, collections::HashMap, sync::Arc}; use hash_db::Prefix;
use kvdb::KeyValueDB; use kvdb::KeyValueDB;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use rand::Rng; use rand::Rng;
use hash_db::Prefix;
use sp_state_machine::Backend as _; use sp_state_machine::Backend as _;
use sp_trie::{trie_types::TrieDBMut, TrieMut as _}; use sp_trie::{trie_types::TrieDBMut, TrieMut as _};
use std::{borrow::Cow, collections::HashMap, sync::Arc};
use node_primitives::Hash; use node_primitives::Hash;
@@ -32,7 +32,7 @@ use crate::{
core::{self, Mode, Path}, core::{self, Mode, Path},
generator::generate_trie, generator::generate_trie,
simple_trie::SimpleTrie, simple_trie::SimpleTrie,
tempdb::{TempDatabase, DatabaseType}, tempdb::{DatabaseType, TempDatabase},
}; };
pub const SAMPLE_SIZE: usize = 100; pub const SAMPLE_SIZE: usize = 100;
@@ -142,10 +142,7 @@ impl core::BenchmarkDescription for TrieReadBenchmarkDescription {
assert_eq!(warmup_keys.len(), SAMPLE_SIZE); assert_eq!(warmup_keys.len(), SAMPLE_SIZE);
assert_eq!(query_keys.len(), SAMPLE_SIZE); assert_eq!(query_keys.len(), SAMPLE_SIZE);
let root = generate_trie( let root = generate_trie(database.open(self.database_type), key_values);
database.open(self.database_type),
key_values,
);
Box::new(TrieReadBenchmark { Box::new(TrieReadBenchmark {
database, database,
@@ -162,7 +159,8 @@ impl core::BenchmarkDescription for TrieReadBenchmarkDescription {
self.database_size, self.database_size,
pretty_print(self.database_size.keys()), pretty_print(self.database_size.keys()),
self.database_type, self.database_type,
).into() )
.into()
} }
} }
@@ -182,12 +180,10 @@ impl core::Benchmark for TrieReadBenchmark {
let storage: Arc<dyn sp_state_machine::Storage<sp_core::Blake2Hasher>> = let storage: Arc<dyn sp_state_machine::Storage<sp_core::Blake2Hasher>> =
Arc::new(Storage(db.open(self.database_type))); Arc::new(Storage(db.open(self.database_type)));
let trie_backend = sp_state_machine::TrieBackend::new( let trie_backend = sp_state_machine::TrieBackend::new(storage, self.root);
storage,
self.root,
);
for (warmup_key, warmup_value) in self.warmup_keys.iter() { for (warmup_key, warmup_value) in self.warmup_keys.iter() {
let value = trie_backend.storage(&warmup_key[..]) let value = trie_backend
.storage(&warmup_key[..])
.expect("Failed to get key: db error") .expect("Failed to get key: db error")
.expect("Warmup key should exist"); .expect("Warmup key should exist");
@@ -218,7 +214,6 @@ pub struct TrieWriteBenchmarkDescription {
pub database_type: DatabaseType, pub database_type: DatabaseType,
} }
impl core::BenchmarkDescription for TrieWriteBenchmarkDescription { impl core::BenchmarkDescription for TrieWriteBenchmarkDescription {
fn path(&self) -> Path { fn path(&self) -> Path {
let mut path = Path::new(&["trie", "write"]); let mut path = Path::new(&["trie", "write"]);
@@ -253,10 +248,7 @@ impl core::BenchmarkDescription for TrieWriteBenchmarkDescription {
assert_eq!(warmup_keys.len(), SAMPLE_SIZE); assert_eq!(warmup_keys.len(), SAMPLE_SIZE);
let root = generate_trie( let root = generate_trie(database.open(self.database_type), key_values);
database.open(self.database_type),
key_values,
);
Box::new(TrieWriteBenchmark { Box::new(TrieWriteBenchmark {
database, database,
@@ -272,7 +264,8 @@ impl core::BenchmarkDescription for TrieWriteBenchmarkDescription {
self.database_size, self.database_size,
pretty_print(self.database_size.keys()), pretty_print(self.database_size.keys()),
self.database_type, self.database_type,
).into() )
.into()
} }
} }
@@ -292,15 +285,13 @@ impl core::Benchmark for TrieWriteBenchmark {
let mut new_root = self.root.clone(); let mut new_root = self.root.clone();
let mut overlay = HashMap::new(); let mut overlay = HashMap::new();
let mut trie = SimpleTrie { let mut trie = SimpleTrie { db: kvdb.clone(), overlay: &mut overlay };
db: kvdb.clone(), let mut trie_db_mut =
overlay: &mut overlay, TrieDBMut::from_existing(&mut trie, &mut new_root).expect("Failed to create TrieDBMut");
};
let mut trie_db_mut = TrieDBMut::from_existing(&mut trie, &mut new_root)
.expect("Failed to create TrieDBMut");
for (warmup_key, warmup_value) in self.warmup_keys.iter() { for (warmup_key, warmup_value) in self.warmup_keys.iter() {
let value = trie_db_mut.get(&warmup_key[..]) let value = trie_db_mut
.get(&warmup_key[..])
.expect("Failed to get key: db error") .expect("Failed to get key: db error")
.expect("Warmup key should exist"); .expect("Warmup key should exist");
@@ -367,7 +358,9 @@ impl SizePool {
fn value<R: Rng>(&self, rng: &mut R) -> Vec<u8> { fn value<R: Rng>(&self, rng: &mut R) -> Vec<u8> {
let sr = (rng.next_u64() % self.total as u64) as u32; let sr = (rng.next_u64() % self.total as u64) as u32;
let mut range = self.distribution.range((std::ops::Bound::Included(sr), std::ops::Bound::Unbounded)); let mut range = self
.distribution
.range((std::ops::Bound::Included(sr), std::ops::Bound::Unbounded));
let size = *range.next().unwrap().1 as usize; let size = *range.next().unwrap().1 as usize;
random_vec(rng, size) random_vec(rng, size)
} }
+19 -23
View File
@@ -23,13 +23,13 @@
use std::borrow::Cow; use std::borrow::Cow;
use node_testing::bench::{BenchDb, Profile, BlockType, KeyTypes, DatabaseType}; use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile};
use sc_transaction_pool::BasicPool; use sc_transaction_pool::BasicPool;
use sp_runtime::generic::BlockId;
use sc_transaction_pool_api::{TransactionPool, TransactionSource}; use sc_transaction_pool_api::{TransactionPool, TransactionSource};
use sp_runtime::generic::BlockId;
use crate::core::{self, Path, Mode}; use crate::core::{self, Mode, Path};
pub struct PoolBenchmarkDescription { pub struct PoolBenchmarkDescription {
pub database_type: DatabaseType, pub database_type: DatabaseType,
@@ -46,11 +46,7 @@ impl core::BenchmarkDescription for PoolBenchmarkDescription {
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> { fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
Box::new(PoolBenchmark { Box::new(PoolBenchmark {
database: BenchDb::with_key_types( database: BenchDb::with_key_types(self.database_type, 50_000, KeyTypes::Sr25519),
self.database_type,
50_000,
KeyTypes::Sr25519,
),
}) })
} }
@@ -63,7 +59,9 @@ impl core::Benchmark for PoolBenchmark {
fn run(&mut self, mode: Mode) -> std::time::Duration { fn run(&mut self, mode: Mode) -> std::time::Duration {
let context = self.database.create_context(Profile::Wasm); let context = self.database.create_context(Profile::Wasm);
let _ = context.client.runtime_version_at(&BlockId::Number(0)) let _ = context
.client
.runtime_version_at(&BlockId::Number(0))
.expect("Failed to get runtime version") .expect("Failed to get runtime version")
.spec_version; .spec_version;
@@ -80,22 +78,20 @@ impl core::Benchmark for PoolBenchmark {
context.client.clone(), context.client.clone(),
); );
let generated_transactions = self.database.block_content( let generated_transactions = self
BlockType::RandomTransfersKeepAlive.to_content(Some(100)), .database
&context.client, .block_content(
).into_iter().collect::<Vec<_>>(); BlockType::RandomTransfersKeepAlive.to_content(Some(100)),
&context.client,
)
.into_iter()
.collect::<Vec<_>>();
let start = std::time::Instant::now(); let start = std::time::Instant::now();
let submissions = generated_transactions.into_iter().map(|tx| { let submissions = generated_transactions
txpool.submit_one( .into_iter()
&BlockId::Number(0), .map(|tx| txpool.submit_one(&BlockId::Number(0), TransactionSource::External, tx));
TransactionSource::External, futures::executor::block_on(futures::future::join_all(submissions));
tx,
)
});
futures::executor::block_on(
futures::future::join_all(submissions)
);
let elapsed = start.elapsed(); let elapsed = start.elapsed();
if mode == Mode::Profile { if mode == Mode::Profile {
+9 -11
View File
@@ -28,11 +28,11 @@
//! flag and open a browser to the url that `wasm-pack test` outputs. //! flag and open a browser to the url that `wasm-pack test` outputs.
//! For more infomation see <https://rustwasm.github.io/docs/wasm-pack/>. //! For more infomation see <https://rustwasm.github.io/docs/wasm-pack/>.
use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure}; use jsonrpc_core::types::{Id, MethodCall, Params, Success, Version};
use wasm_bindgen_futures::JsFuture;
use wasm_bindgen::JsValue;
use jsonrpc_core::types::{MethodCall, Success, Version, Params, Id};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use wasm_bindgen::JsValue;
use wasm_bindgen_futures::JsFuture;
use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
wasm_bindgen_test_configure!(run_in_browser); wasm_bindgen_test_configure!(run_in_browser);
@@ -41,8 +41,9 @@ fn rpc_call(method: &str) -> String {
jsonrpc: Some(Version::V2), jsonrpc: Some(Version::V2),
method: method.into(), method: method.into(),
params: Params::None, params: Params::None,
id: Id::Num(1) id: Id::Num(1),
}).unwrap() })
.unwrap()
} }
fn deserialize_rpc_result<T: DeserializeOwned>(js_value: JsValue) -> T { fn deserialize_rpc_result<T: DeserializeOwned>(js_value: JsValue) -> T {
@@ -55,15 +56,12 @@ fn deserialize_rpc_result<T: DeserializeOwned>(js_value: JsValue) -> T {
#[wasm_bindgen_test] #[wasm_bindgen_test]
async fn runs() { async fn runs() {
let mut client = node_cli::start_client(None, "info".into()) let mut client = node_cli::start_client(None, "info".into()).unwrap();
.unwrap();
// Check that the node handles rpc calls. // Check that the node handles rpc calls.
// TODO: Re-add the code that checks if the node is syncing. // TODO: Re-add the code that checks if the node is syncing.
let chain_name: String = deserialize_rpc_result( let chain_name: String = deserialize_rpc_result(
JsFuture::from(client.rpc_send(&rpc_call("system_chain"))) JsFuture::from(client.rpc_send(&rpc_call("system_chain"))).await.unwrap(),
.await
.unwrap()
); );
assert_eq!(chain_name, "Development"); assert_eq!(chain_name, "Development");
} }
+7 -4
View File
@@ -25,8 +25,8 @@ fn main() {
mod cli { mod cli {
include!("src/cli.rs"); include!("src/cli.rs");
use std::{fs, env, path::Path};
use sc_cli::structopt::clap::Shell; use sc_cli::structopt::clap::Shell;
use std::{env, fs, path::Path};
use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed};
pub fn main() { pub fn main() {
@@ -51,9 +51,12 @@ mod cli {
Some(dir) => dir, Some(dir) => dir,
}; };
let path = Path::new(&outdir) let path = Path::new(&outdir)
.parent().unwrap() .parent()
.parent().unwrap() .unwrap()
.parent().unwrap() .parent()
.unwrap()
.parent()
.unwrap()
.join("completion-scripts"); .join("completion-scripts");
fs::create_dir(&path).ok(); fs::create_dir(&path).ok();
+5 -10
View File
@@ -17,18 +17,14 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::chain_spec::ChainSpec; use crate::chain_spec::ChainSpec;
use browser_utils::{browser_configuration, init_logging, set_console_error_panic_hook, Client};
use log::info; use log::info;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use browser_utils::{
Client,
browser_configuration, init_logging, set_console_error_panic_hook,
};
/// Starts the client. /// Starts the client.
#[wasm_bindgen] #[wasm_bindgen]
pub fn start_client(chain_spec: Option<String>, log_level: String) -> Result<Client, JsValue> { pub fn start_client(chain_spec: Option<String>, log_level: String) -> Result<Client, JsValue> {
start_inner(chain_spec, log_level) start_inner(chain_spec, log_level).map_err(|err| JsValue::from_str(&err.to_string()))
.map_err(|err| JsValue::from_str(&err.to_string()))
} }
fn start_inner( fn start_inner(
@@ -53,10 +49,9 @@ fn start_inner(
info!("👤 Role: {:?}", config.role); info!("👤 Role: {:?}", config.role);
// Create the service. This is the most heavy initialization step. // Create the service. This is the most heavy initialization step.
let (task_manager, rpc_handlers) = let (task_manager, rpc_handlers) = crate::service::new_light_base(config)
crate::service::new_light_base(config) .map(|(components, rpc_handlers, _, _, _)| (components, rpc_handlers))
.map(|(components, rpc_handlers, _, _, _)| (components, rpc_handlers)) .map_err(|e| format!("{:?}", e))?;
.map_err(|e| format!("{:?}", e))?;
Ok(browser_utils::start_client(task_manager, rpc_handlers)) Ok(browser_utils::start_client(task_manager, rpc_handlers))
} }
+171 -146
View File
@@ -18,25 +18,26 @@
//! Substrate chain configurations. //! Substrate chain configurations.
use sc_chain_spec::ChainSpecExtension; use grandpa_primitives::AuthorityId as GrandpaId;
use sp_core::{Pair, Public, crypto::UncheckedInto, sr25519};
use serde::{Serialize, Deserialize};
use node_runtime::{
AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, CouncilConfig,
DemocracyConfig, GrandpaConfig, ImOnlineConfig, SessionConfig, SessionKeys, StakerStatus,
StakingConfig, ElectionsConfig, IndicesConfig, SocietyConfig, SudoConfig, SystemConfig,
TechnicalCommitteeConfig, wasm_binary_unwrap, MAX_NOMINATIONS,
};
use node_runtime::Block;
use node_runtime::constants::currency::*;
use sc_service::ChainType;
use hex_literal::hex; use hex_literal::hex;
use node_runtime::{
constants::currency::*, wasm_binary_unwrap, AuthorityDiscoveryConfig, BabeConfig,
BalancesConfig, Block, CouncilConfig, DemocracyConfig, ElectionsConfig, GrandpaConfig,
ImOnlineConfig, IndicesConfig, SessionConfig, SessionKeys, SocietyConfig, StakerStatus,
StakingConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig, MAX_NOMINATIONS,
};
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use sc_chain_spec::ChainSpecExtension;
use sc_service::ChainType;
use sc_telemetry::TelemetryEndpoints; use sc_telemetry::TelemetryEndpoints;
use grandpa_primitives::{AuthorityId as GrandpaId}; use serde::{Deserialize, Serialize};
use sp_consensus_babe::{AuthorityId as BabeId};
use pallet_im_online::sr25519::{AuthorityId as ImOnlineId};
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use sp_runtime::{Perbill, traits::{Verify, IdentifyAccount}}; use sp_consensus_babe::AuthorityId as BabeId;
use sp_core::{crypto::UncheckedInto, sr25519, Pair, Public};
use sp_runtime::{
traits::{IdentifyAccount, Verify},
Perbill,
};
pub use node_primitives::{AccountId, Balance, Signature}; pub use node_primitives::{AccountId, Balance, Signature};
pub use node_runtime::GenesisConfig; pub use node_runtime::GenesisConfig;
@@ -59,10 +60,7 @@ pub struct Extensions {
} }
/// Specialized `ChainSpec`. /// Specialized `ChainSpec`.
pub type ChainSpec = sc_service::GenericChainSpec< pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig, Extensions>;
GenesisConfig,
Extensions,
>;
/// Flaming Fir testnet generator /// Flaming Fir testnet generator
pub fn flaming_fir_config() -> Result<ChainSpec, String> { pub fn flaming_fir_config() -> Result<ChainSpec, String> {
ChainSpec::from_json_bytes(&include_bytes!("../res/flaming-fir.json")[..]) ChainSpec::from_json_bytes(&include_bytes!("../res/flaming-fir.json")[..])
@@ -84,65 +82,94 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
// and // and
// for i in 1 2 3 4 ; do for j in session; do subkey --ed25519 inspect "$secret"//fir//$j//$i; done; done // for i in 1 2 3 4 ; do for j in session; do subkey --ed25519 inspect "$secret"//fir//$j//$i; done; done
let initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId)> = vec![( let initial_authorities: Vec<(
// 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy AccountId,
hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].into(), AccountId,
// 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq GrandpaId,
hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].into(), BabeId,
// 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC ImOnlineId,
hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"].unchecked_into(), AuthorityDiscoveryId,
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8 )> = vec![
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"].unchecked_into(), (
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8 // 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"].unchecked_into(), hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].into(),
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8 // 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"].unchecked_into(), hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].into(),
),( // 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC
// 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2 hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"]
hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].into(), .unchecked_into(),
// 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF // 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].into(), hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"]
// 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE .unchecked_into(),
hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"].unchecked_into(), // 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"]
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"].unchecked_into(), .unchecked_into(),
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ // 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"].unchecked_into(), hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"]
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ .unchecked_into(),
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"].unchecked_into(), ),
),( (
// 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp // 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2
hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].into(), hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].into(),
// 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9 // 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF
hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].into(), hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].into(),
// 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d // 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE
hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"].unchecked_into(), hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"]
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH .unchecked_into(),
hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"].unchecked_into(), // 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"]
hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"].unchecked_into(), .unchecked_into(),
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH // 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"].unchecked_into(), hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"]
),( .unchecked_into(),
// 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9 // 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].into(), hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"]
// 5EPQdAQ39WQNLCRjWsCk5jErsCitHiY5ZmjfWzzbXDoAoYbn .unchecked_into(),
hex!["66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"].into(), ),
// 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4 (
hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"].unchecked_into(), // 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].into(),
hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"].unchecked_into(), // 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].into(),
hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"].unchecked_into(), // 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"]
hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"].unchecked_into(), .unchecked_into(),
)]; // 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"]
.unchecked_into(),
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"]
.unchecked_into(),
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"]
.unchecked_into(),
),
(
// 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9
hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].into(),
// 5EPQdAQ39WQNLCRjWsCk5jErsCitHiY5ZmjfWzzbXDoAoYbn
hex!["66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"].into(),
// 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4
hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"]
.unchecked_into(),
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"]
.unchecked_into(),
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"]
.unchecked_into(),
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"]
.unchecked_into(),
),
];
// generated with secret: subkey inspect "$secret"/fir // generated with secret: subkey inspect "$secret"/fir
let root_key: AccountId = hex![ let root_key: AccountId = hex![
// 5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo // 5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo
"9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809" "9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809"
].into(); ]
.into();
let endowed_accounts: Vec<AccountId> = vec![root_key.clone()]; let endowed_accounts: Vec<AccountId> = vec![root_key.clone()];
@@ -158,8 +185,10 @@ pub fn staging_testnet_config() -> ChainSpec {
ChainType::Live, ChainType::Live,
staging_testnet_config_genesis, staging_testnet_config_genesis,
boot_nodes, boot_nodes,
Some(TelemetryEndpoints::new(vec![(STAGING_TELEMETRY_URL.to_string(), 0)]) Some(
.expect("Staging telemetry url is valid; qed")), TelemetryEndpoints::new(vec![(STAGING_TELEMETRY_URL.to_string(), 0)])
.expect("Staging telemetry url is valid; qed"),
),
None, None,
None, None,
Default::default(), Default::default(),
@@ -174,21 +203,17 @@ pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Pu
} }
/// Helper function to generate an account ID from seed /// Helper function to generate an account ID from seed
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId where pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
AccountPublic: From<<TPublic::Pair as Pair>::Public> where
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{ {
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account() AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
} }
/// Helper function to generate stash, controller and session key from seed /// Helper function to generate stash, controller and session key from seed
pub fn authority_keys_from_seed(seed: &str) -> ( pub fn authority_keys_from_seed(
AccountId, seed: &str,
AccountId, ) -> (AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId) {
GrandpaId,
BabeId,
ImOnlineId,
AuthorityDiscoveryId,
) {
( (
get_account_id_from_seed::<sr25519::Public>(&format!("{}//stash", seed)), get_account_id_from_seed::<sr25519::Public>(&format!("{}//stash", seed)),
get_account_id_from_seed::<sr25519::Public>(seed), get_account_id_from_seed::<sr25519::Public>(seed),
@@ -230,11 +255,15 @@ pub fn testnet_genesis(
] ]
}); });
// endow all authorities and nominators. // endow all authorities and nominators.
initial_authorities.iter().map(|x| &x.0).chain(initial_nominators.iter()).for_each(|x| { initial_authorities
if !endowed_accounts.contains(&x) { .iter()
endowed_accounts.push(x.clone()) .map(|x| &x.0)
} .chain(initial_nominators.iter())
}); .for_each(|x| {
if !endowed_accounts.contains(&x) {
endowed_accounts.push(x.clone())
}
});
// stakers: all validators and nominators. // stakers: all validators and nominators.
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
@@ -266,22 +295,20 @@ pub fn testnet_genesis(
changes_trie_config: Default::default(), changes_trie_config: Default::default(),
}, },
balances: BalancesConfig { balances: BalancesConfig {
balances: endowed_accounts.iter().cloned() balances: endowed_accounts.iter().cloned().map(|x| (x, ENDOWMENT)).collect(),
.map(|x| (x, ENDOWMENT))
.collect()
},
indices: IndicesConfig {
indices: vec![],
}, },
indices: IndicesConfig { indices: vec![] },
session: SessionConfig { session: SessionConfig {
keys: initial_authorities.iter().map(|x| { keys: initial_authorities
(x.0.clone(), x.0.clone(), session_keys( .iter()
x.2.clone(), .map(|x| {
x.3.clone(), (
x.4.clone(), x.0.clone(),
x.5.clone(), x.0.clone(),
)) session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()),
}).collect::<Vec<_>>(), )
})
.collect::<Vec<_>>(),
}, },
staking: StakingConfig { staking: StakingConfig {
validator_count: initial_authorities.len() as u32, validator_count: initial_authorities.len() as u32,
@@ -289,47 +316,42 @@ pub fn testnet_genesis(
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(), invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
slash_reward_fraction: Perbill::from_percent(10), slash_reward_fraction: Perbill::from_percent(10),
stakers, stakers,
.. Default::default() ..Default::default()
}, },
democracy: DemocracyConfig::default(), democracy: DemocracyConfig::default(),
elections: ElectionsConfig { elections: ElectionsConfig {
members: endowed_accounts.iter() members: endowed_accounts
.take((num_endowed_accounts + 1) / 2) .iter()
.cloned() .take((num_endowed_accounts + 1) / 2)
.map(|member| (member, STASH)) .cloned()
.collect(), .map(|member| (member, STASH))
.collect(),
}, },
council: CouncilConfig::default(), council: CouncilConfig::default(),
technical_committee: TechnicalCommitteeConfig { technical_committee: TechnicalCommitteeConfig {
members: endowed_accounts.iter() members: endowed_accounts
.take((num_endowed_accounts + 1) / 2) .iter()
.cloned() .take((num_endowed_accounts + 1) / 2)
.collect(), .cloned()
.collect(),
phantom: Default::default(), phantom: Default::default(),
}, },
sudo: SudoConfig { sudo: SudoConfig { key: root_key },
key: root_key,
},
babe: BabeConfig { babe: BabeConfig {
authorities: vec![], authorities: vec![],
epoch_config: Some(node_runtime::BABE_GENESIS_EPOCH_CONFIG), epoch_config: Some(node_runtime::BABE_GENESIS_EPOCH_CONFIG),
}, },
im_online: ImOnlineConfig { im_online: ImOnlineConfig { keys: vec![] },
keys: vec![], authority_discovery: AuthorityDiscoveryConfig { keys: vec![] },
}, grandpa: GrandpaConfig { authorities: vec![] },
authority_discovery: AuthorityDiscoveryConfig {
keys: vec![],
},
grandpa: GrandpaConfig {
authorities: vec![],
},
technical_membership: Default::default(), technical_membership: Default::default(),
treasury: Default::default(), treasury: Default::default(),
society: SocietyConfig { society: SocietyConfig {
members: endowed_accounts.iter() members: endowed_accounts
.take((num_endowed_accounts + 1) / 2) .iter()
.cloned() .take((num_endowed_accounts + 1) / 2)
.collect(), .cloned()
.collect(),
pot: 0, pot: 0,
max_members: 999, max_members: 999,
}, },
@@ -341,9 +363,7 @@ pub fn testnet_genesis(
fn development_config_genesis() -> GenesisConfig { fn development_config_genesis() -> GenesisConfig {
testnet_genesis( testnet_genesis(
vec![ vec![authority_keys_from_seed("Alice")],
authority_keys_from_seed("Alice"),
],
vec![], vec![],
get_account_id_from_seed::<sr25519::Public>("Alice"), get_account_id_from_seed::<sr25519::Public>("Alice"),
None, None,
@@ -367,10 +387,7 @@ pub fn development_config() -> ChainSpec {
fn local_testnet_genesis() -> GenesisConfig { fn local_testnet_genesis() -> GenesisConfig {
testnet_genesis( testnet_genesis(
vec![ vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")],
authority_keys_from_seed("Alice"),
authority_keys_from_seed("Bob"),
],
vec![], vec![],
get_account_id_from_seed::<sr25519::Public>("Alice"), get_account_id_from_seed::<sr25519::Public>("Alice"),
None, None,
@@ -401,9 +418,7 @@ pub(crate) mod tests {
fn local_testnet_genesis_instant_single() -> GenesisConfig { fn local_testnet_genesis_instant_single() -> GenesisConfig {
testnet_genesis( testnet_genesis(
vec![ vec![authority_keys_from_seed("Alice")],
authority_keys_from_seed("Alice"),
],
vec![], vec![],
get_account_id_from_seed::<sr25519::Public>("Alice"), get_account_id_from_seed::<sr25519::Public>("Alice"),
None, None,
@@ -446,14 +461,24 @@ pub(crate) mod tests {
sc_service_test::connectivity( sc_service_test::connectivity(
integration_test_config_with_two_authorities(), integration_test_config_with_two_authorities(),
|config| { |config| {
let NewFullBase { task_manager, client, network, transaction_pool, .. } let NewFullBase { task_manager, client, network, transaction_pool, .. } =
= new_full_base(config,|_, _| ())?; new_full_base(config, |_, _| ())?;
Ok(sc_service_test::TestNetComponents::new(task_manager, client, network, transaction_pool)) Ok(sc_service_test::TestNetComponents::new(
task_manager,
client,
network,
transaction_pool,
))
}, },
|config| { |config| {
let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?; let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?;
Ok(sc_service_test::TestNetComponents::new(keep_alive, client, network, transaction_pool)) Ok(sc_service_test::TestNetComponents::new(
} keep_alive,
client,
network,
transaction_pool,
))
},
); );
} }
+1 -1
View File
@@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use sc_cli::{RunCmd, KeySubcommand, SignCmd, VanityCmd, VerifyCmd}; use sc_cli::{KeySubcommand, RunCmd, SignCmd, VanityCmd, VerifyCmd};
use structopt::StructOpt; use structopt::StructOpt;
/// An overarching CLI command definition. /// An overarching CLI command definition.
+36 -39
View File
@@ -16,12 +16,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::{chain_spec, service, Cli, Subcommand}; use crate::{chain_spec, service, service::new_partial, Cli, Subcommand};
use node_executor::Executor; use node_executor::Executor;
use node_runtime::{Block, RuntimeApi}; use node_runtime::{Block, RuntimeApi};
use sc_cli::{Result, SubstrateCli, RuntimeVersion, Role, ChainSpec}; use sc_cli::{ChainSpec, Result, Role, RuntimeVersion, SubstrateCli};
use sc_service::PartialComponents; use sc_service::PartialComponents;
use crate::service::new_partial;
impl SubstrateCli for Cli { impl SubstrateCli for Cli {
fn impl_name() -> String { fn impl_name() -> String {
@@ -49,17 +48,19 @@ impl SubstrateCli for Cli {
} }
fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> { fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
let spec = let spec = match id {
match id { "" =>
"" => return Err("Please specify which chain you want to run, e.g. --dev or --chain=local".into()), return Err(
"dev" => Box::new(chain_spec::development_config()), "Please specify which chain you want to run, e.g. --dev or --chain=local"
"local" => Box::new(chain_spec::local_testnet_config()), .into(),
"fir" | "flaming-fir" => Box::new(chain_spec::flaming_fir_config()?), ),
"staging" => Box::new(chain_spec::staging_testnet_config()), "dev" => Box::new(chain_spec::development_config()),
path => Box::new(chain_spec::ChainSpec::from_json_file( "local" => Box::new(chain_spec::local_testnet_config()),
std::path::PathBuf::from(path), "fir" | "flaming-fir" => Box::new(chain_spec::flaming_fir_config()?),
)?), "staging" => Box::new(chain_spec::staging_testnet_config()),
}; path =>
Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
};
Ok(spec) Ok(spec)
} }
@@ -79,24 +80,25 @@ pub fn run() -> Result<()> {
match config.role { match config.role {
Role::Light => service::new_light(config), Role::Light => service::new_light(config),
_ => service::new_full(config), _ => service::new_full(config),
}.map_err(sc_cli::Error::Service) }
.map_err(sc_cli::Error::Service)
}) })
} },
Some(Subcommand::Inspect(cmd)) => { Some(Subcommand::Inspect(cmd)) => {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run::<Block, RuntimeApi, Executor>(config)) runner.sync_run(|config| cmd.run::<Block, RuntimeApi, Executor>(config))
} },
Some(Subcommand::Benchmark(cmd)) => { Some(Subcommand::Benchmark(cmd)) =>
if cfg!(feature = "runtime-benchmarks") { if cfg!(feature = "runtime-benchmarks") {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run::<Block, Executor>(config)) runner.sync_run(|config| cmd.run::<Block, Executor>(config))
} else { } else {
Err("Benchmarking wasn't enabled when building the node. \ Err("Benchmarking wasn't enabled when building the node. \
You can enable it with `--features runtime-benchmarks`.".into()) You can enable it with `--features runtime-benchmarks`."
} .into())
} },
Some(Subcommand::Key(cmd)) => cmd.run(&cli), Some(Subcommand::Key(cmd)) => cmd.run(&cli),
Some(Subcommand::Sign(cmd)) => cmd.run(), Some(Subcommand::Sign(cmd)) => cmd.run(),
Some(Subcommand::Verify(cmd)) => cmd.run(), Some(Subcommand::Verify(cmd)) => cmd.run(),
@@ -108,32 +110,30 @@ pub fn run() -> Result<()> {
Some(Subcommand::CheckBlock(cmd)) => { Some(Subcommand::CheckBlock(cmd)) => {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.async_run(|config| { runner.async_run(|config| {
let PartialComponents { client, task_manager, import_queue, ..} let PartialComponents { client, task_manager, import_queue, .. } =
= new_partial(&config)?; new_partial(&config)?;
Ok((cmd.run(client, import_queue), task_manager)) Ok((cmd.run(client, import_queue), task_manager))
}) })
}, },
Some(Subcommand::ExportBlocks(cmd)) => { Some(Subcommand::ExportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.async_run(|config| { runner.async_run(|config| {
let PartialComponents { client, task_manager, ..} let PartialComponents { client, task_manager, .. } = new_partial(&config)?;
= new_partial(&config)?;
Ok((cmd.run(client, config.database), task_manager)) Ok((cmd.run(client, config.database), task_manager))
}) })
}, },
Some(Subcommand::ExportState(cmd)) => { Some(Subcommand::ExportState(cmd)) => {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.async_run(|config| { runner.async_run(|config| {
let PartialComponents { client, task_manager, ..} let PartialComponents { client, task_manager, .. } = new_partial(&config)?;
= new_partial(&config)?;
Ok((cmd.run(client, config.chain_spec), task_manager)) Ok((cmd.run(client, config.chain_spec), task_manager))
}) })
}, },
Some(Subcommand::ImportBlocks(cmd)) => { Some(Subcommand::ImportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.async_run(|config| { runner.async_run(|config| {
let PartialComponents { client, task_manager, import_queue, ..} let PartialComponents { client, task_manager, import_queue, .. } =
= new_partial(&config)?; new_partial(&config)?;
Ok((cmd.run(client, import_queue), task_manager)) Ok((cmd.run(client, import_queue), task_manager))
}) })
}, },
@@ -144,8 +144,7 @@ pub fn run() -> Result<()> {
Some(Subcommand::Revert(cmd)) => { Some(Subcommand::Revert(cmd)) => {
let runner = cli.create_runner(cmd)?; let runner = cli.create_runner(cmd)?;
runner.async_run(|config| { runner.async_run(|config| {
let PartialComponents { client, task_manager, backend, ..} let PartialComponents { client, task_manager, backend, .. } = new_partial(&config)?;
= new_partial(&config)?;
Ok((cmd.run(client, backend), task_manager)) Ok((cmd.run(client, backend), task_manager))
}) })
}, },
@@ -156,18 +155,16 @@ pub fn run() -> Result<()> {
// we don't need any of the components of new_partial, just a runtime, or a task // we don't need any of the components of new_partial, just a runtime, or a task
// manager to do `async_run`. // manager to do `async_run`.
let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry); let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry);
let task_manager = sc_service::TaskManager::new( let task_manager =
config.task_executor.clone(), sc_service::TaskManager::new(config.task_executor.clone(), registry)
registry, .map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?;
).map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?;
Ok((cmd.run::<Block, Executor>(config), task_manager)) Ok((cmd.run::<Block, Executor>(config), task_manager))
}) })
}, },
#[cfg(not(feature = "try-runtime"))] #[cfg(not(feature = "try-runtime"))]
Some(Subcommand::TryRuntime) => { Some(Subcommand::TryRuntime) => Err("TryRuntime wasn't enabled when building the node. \
Err("TryRuntime wasn't enabled when building the node. \ You can enable it with `--features try-runtime`."
You can enable it with `--features try-runtime`.".into()) .into()),
},
} }
} }
+238 -240
View File
@@ -20,20 +20,17 @@
//! Service implementation. Specialized wrapper over substrate service. //! Service implementation. Specialized wrapper over substrate service.
use std::sync::Arc; use futures::prelude::*;
use sc_consensus_babe; use node_executor::Executor;
use node_primitives::Block; use node_primitives::Block;
use node_runtime::RuntimeApi; use node_runtime::RuntimeApi;
use sc_service::{
config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager,
};
use sc_network::{Event, NetworkService};
use sp_runtime::traits::Block as BlockT;
use futures::prelude::*;
use sc_client_api::{ExecutorProvider, RemoteBackend}; use sc_client_api::{ExecutorProvider, RemoteBackend};
use node_executor::Executor; use sc_consensus_babe::{self, SlotProportion};
use sc_network::{Event, NetworkService};
use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager};
use sc_telemetry::{Telemetry, TelemetryWorker}; use sc_telemetry::{Telemetry, TelemetryWorker};
use sc_consensus_babe::SlotProportion; use sp_runtime::traits::Block as BlockT;
use std::sync::Arc;
type FullClient = sc_service::TFullClient<Block, RuntimeApi, Executor>; type FullClient = sc_service::TFullClient<Block, RuntimeApi, Executor>;
type FullBackend = sc_service::TFullBackend<Block>; type FullBackend = sc_service::TFullBackend<Block>;
@@ -44,25 +41,29 @@ type LightClient = sc_service::TLightClient<Block, RuntimeApi, Executor>;
pub fn new_partial( pub fn new_partial(
config: &Configuration, config: &Configuration,
) -> Result<sc_service::PartialComponents< ) -> Result<
FullClient, FullBackend, FullSelectChain, sc_service::PartialComponents<
sp_consensus::DefaultImportQueue<Block, FullClient>, FullClient,
sc_transaction_pool::FullPool<Block, FullClient>, FullBackend,
( FullSelectChain,
impl Fn( sp_consensus::DefaultImportQueue<Block, FullClient>,
node_rpc::DenyUnsafe, sc_transaction_pool::FullPool<Block, FullClient>,
sc_rpc::SubscriptionTaskExecutor,
) -> node_rpc::IoHandler,
( (
sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>, impl Fn(node_rpc::DenyUnsafe, sc_rpc::SubscriptionTaskExecutor) -> node_rpc::IoHandler,
grandpa::LinkHalf<Block, FullClient, FullSelectChain>, (
sc_consensus_babe::BabeLink<Block>, sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>,
grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
sc_consensus_babe::BabeLink<Block>,
),
grandpa::SharedVoterState,
Option<Telemetry>,
), ),
grandpa::SharedVoterState, >,
Option<Telemetry>, ServiceError,
) > {
>, ServiceError> { let telemetry = config
let telemetry = config.telemetry_endpoints.clone() .telemetry_endpoints
.clone()
.filter(|x| !x.is_empty()) .filter(|x| !x.is_empty())
.map(|endpoints| -> Result<_, sc_telemetry::Error> { .map(|endpoints| -> Result<_, sc_telemetry::Error> {
let worker = TelemetryWorker::new(16)?; let worker = TelemetryWorker::new(16)?;
@@ -78,11 +79,10 @@ pub fn new_partial(
)?; )?;
let client = Arc::new(client); let client = Arc::new(client);
let telemetry = telemetry let telemetry = telemetry.map(|(worker, telemetry)| {
.map(|(worker, telemetry)| { task_manager.spawn_handle().spawn("telemetry", worker.run());
task_manager.spawn_handle().spawn("telemetry", worker.run()); telemetry
telemetry });
});
let select_chain = sc_consensus::LongestChain::new(backend.clone()); let select_chain = sc_consensus::LongestChain::new(backend.clone());
@@ -115,21 +115,19 @@ pub fn new_partial(
Some(Box::new(justification_import)), Some(Box::new(justification_import)),
client.clone(), client.clone(),
select_chain.clone(), select_chain.clone(),
move |_, ()| { move |_, ()| async move {
async move { let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot = let slot =
sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration( sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
*timestamp, *timestamp,
slot_duration, slot_duration,
); );
let uncles = let uncles =
sp_authorship::InherentDataProvider::<<Block as BlockT>::Header>::check_inherents(); sp_authorship::InherentDataProvider::<<Block as BlockT>::Header>::check_inherents();
Ok((timestamp, slot, uncles)) Ok((timestamp, slot, uncles))
}
}, },
&task_manager.spawn_essential_handle(), &task_manager.spawn_essential_handle(),
config.prometheus_registry(), config.prometheus_registry(),
@@ -213,7 +211,7 @@ pub fn new_full_base(
with_startup_data: impl FnOnce( with_startup_data: impl FnOnce(
&sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>, &sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>,
&sc_consensus_babe::BabeLink<Block>, &sc_consensus_babe::BabeLink<Block>,
) ),
) -> Result<NewFullBase, ServiceError> { ) -> Result<NewFullBase, ServiceError> {
let sc_service::PartialComponents { let sc_service::PartialComponents {
client, client,
@@ -238,7 +236,7 @@ pub fn new_full_base(
task_manager.spawn_handle(), task_manager.spawn_handle(),
backend.clone(), backend.clone(),
import_setup.1.shared_authority_set().clone(), import_setup.1.shared_authority_set().clone(),
) ),
); );
let (network, system_rpc_tx, network_starter) = let (network, system_rpc_tx, network_starter) =
@@ -254,7 +252,10 @@ pub fn new_full_base(
if config.offchain_worker.enabled { if config.offchain_worker.enabled {
sc_service::build_offchain_workers( sc_service::build_offchain_workers(
&config, task_manager.spawn_handle(), client.clone(), network.clone(), &config,
task_manager.spawn_handle(),
client.clone(),
network.clone(),
); );
} }
@@ -266,22 +267,20 @@ pub fn new_full_base(
let enable_grandpa = !config.disable_grandpa; let enable_grandpa = !config.disable_grandpa;
let prometheus_registry = config.prometheus_registry().cloned(); let prometheus_registry = config.prometheus_registry().cloned();
let _rpc_handlers = sc_service::spawn_tasks( let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
sc_service::SpawnTasksParams { config,
config, backend: backend.clone(),
backend: backend.clone(), client: client.clone(),
client: client.clone(), keystore: keystore_container.sync_keystore(),
keystore: keystore_container.sync_keystore(), network: network.clone(),
network: network.clone(), rpc_extensions_builder: Box::new(rpc_extensions_builder),
rpc_extensions_builder: Box::new(rpc_extensions_builder), transaction_pool: transaction_pool.clone(),
transaction_pool: transaction_pool.clone(), task_manager: &mut task_manager,
task_manager: &mut task_manager, on_demand: None,
on_demand: None, remote_blockchain: None,
remote_blockchain: None, system_rpc_tx,
system_rpc_tx, telemetry: telemetry.as_mut(),
telemetry: telemetry.as_mut(), })?;
},
)?;
let (block_import, grandpa_link, babe_link) = import_setup; let (block_import, grandpa_link, babe_link) = import_setup;
@@ -343,36 +342,37 @@ pub fn new_full_base(
// Spawn authority discovery module. // Spawn authority discovery module.
if role.is_authority() { if role.is_authority() {
let authority_discovery_role = sc_authority_discovery::Role::PublishAndDiscover( let authority_discovery_role =
keystore_container.keystore(), sc_authority_discovery::Role::PublishAndDiscover(keystore_container.keystore());
); let dht_event_stream =
let dht_event_stream = network.event_stream("authority-discovery") network.event_stream("authority-discovery").filter_map(|e| async move {
.filter_map(|e| async move { match e { match e {
Event::Dht(e) => Some(e), Event::Dht(e) => Some(e),
_ => None, _ => None,
}}); }
let (authority_discovery_worker, _service) = sc_authority_discovery::new_worker_and_service_with_config( });
sc_authority_discovery::WorkerConfig { let (authority_discovery_worker, _service) =
publish_non_global_ips: auth_disc_publish_non_global_ips, sc_authority_discovery::new_worker_and_service_with_config(
..Default::default() sc_authority_discovery::WorkerConfig {
}, publish_non_global_ips: auth_disc_publish_non_global_ips,
client.clone(), ..Default::default()
network.clone(), },
Box::pin(dht_event_stream), client.clone(),
authority_discovery_role, network.clone(),
prometheus_registry.clone(), Box::pin(dht_event_stream),
); authority_discovery_role,
prometheus_registry.clone(),
);
task_manager.spawn_handle().spawn("authority-discovery-worker", authority_discovery_worker.run()); task_manager
.spawn_handle()
.spawn("authority-discovery-worker", authority_discovery_worker.run());
} }
// if the node isn't actively participating in consensus then it doesn't // if the node isn't actively participating in consensus then it doesn't
// need a keystore, regardless of which protocol we use below. // need a keystore, regardless of which protocol we use below.
let keystore = if role.is_authority() { let keystore =
Some(keystore_container.sync_keystore()) if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None };
} else {
None
};
let config = grandpa::Config { let config = grandpa::Config {
// FIXME #1578 make this available through chainspec // FIXME #1578 make this available through chainspec
@@ -404,46 +404,41 @@ pub fn new_full_base(
// the GRANDPA voter task is considered infallible, i.e. // the GRANDPA voter task is considered infallible, i.e.
// if it fails we take down the service with it. // if it fails we take down the service with it.
task_manager.spawn_essential_handle().spawn_blocking( task_manager
"grandpa-voter", .spawn_essential_handle()
grandpa::run_grandpa_voter(grandpa_config)? .spawn_blocking("grandpa-voter", grandpa::run_grandpa_voter(grandpa_config)?);
);
} }
network_starter.start_network(); network_starter.start_network();
Ok(NewFullBase { Ok(NewFullBase { task_manager, client, network, transaction_pool })
task_manager,
client,
network,
transaction_pool,
})
} }
/// Builds a new service for a full client. /// Builds a new service for a full client.
pub fn new_full( pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
config: Configuration, new_full_base(config, |_, _| ()).map(|NewFullBase { task_manager, .. }| task_manager)
) -> Result<TaskManager, ServiceError> {
new_full_base(config, |_, _| ()).map(|NewFullBase { task_manager, .. }| {
task_manager
})
} }
pub fn new_light_base( pub fn new_light_base(
mut config: Configuration, mut config: Configuration,
) -> Result<( ) -> Result<
TaskManager, (
RpcHandlers, TaskManager,
Arc<LightClient>, RpcHandlers,
Arc<NetworkService<Block, <Block as BlockT>::Hash>>, Arc<LightClient>,
Arc<sc_transaction_pool::LightPool<Block, LightClient, sc_network::config::OnDemand<Block>>> Arc<NetworkService<Block, <Block as BlockT>::Hash>>,
), ServiceError> { Arc<
let telemetry = config.telemetry_endpoints.clone() sc_transaction_pool::LightPool<Block, LightClient, sc_network::config::OnDemand<Block>>,
>,
),
ServiceError,
> {
let telemetry = config
.telemetry_endpoints
.clone()
.filter(|x| !x.is_empty()) .filter(|x| !x.is_empty())
.map(|endpoints| -> Result<_, sc_telemetry::Error> { .map(|endpoints| -> Result<_, sc_telemetry::Error> {
#[cfg(feature = "browser")] #[cfg(feature = "browser")]
let transport = Some( let transport = Some(sc_telemetry::ExtTransport::new(libp2p_wasm_ext::ffi::websocket_transport()));
sc_telemetry::ExtTransport::new(libp2p_wasm_ext::ffi::websocket_transport())
);
#[cfg(not(feature = "browser"))] #[cfg(not(feature = "browser"))]
let transport = None; let transport = None;
@@ -459,11 +454,10 @@ pub fn new_light_base(
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
)?; )?;
let mut telemetry = telemetry let mut telemetry = telemetry.map(|(worker, telemetry)| {
.map(|(worker, telemetry)| { task_manager.spawn_handle().spawn("telemetry", worker.run());
task_manager.spawn_handle().spawn("telemetry", worker.run()); telemetry
telemetry });
});
config.network.extra_sets.push(grandpa::grandpa_peers_set_config()); config.network.extra_sets.push(grandpa::grandpa_peers_set_config());
@@ -567,71 +561,60 @@ pub fn new_light_base(
let rpc_extensions = node_rpc::create_light(light_deps); let rpc_extensions = node_rpc::create_light(light_deps);
let rpc_handlers = let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
sc_service::spawn_tasks(sc_service::SpawnTasksParams { on_demand: Some(on_demand),
on_demand: Some(on_demand), remote_blockchain: Some(backend.remote_blockchain()),
remote_blockchain: Some(backend.remote_blockchain()), rpc_extensions_builder: Box::new(sc_service::NoopRpcExtensionBuilder(rpc_extensions)),
rpc_extensions_builder: Box::new(sc_service::NoopRpcExtensionBuilder(rpc_extensions)), client: client.clone(),
client: client.clone(), transaction_pool: transaction_pool.clone(),
transaction_pool: transaction_pool.clone(), keystore: keystore_container.sync_keystore(),
keystore: keystore_container.sync_keystore(), config,
config, backend, system_rpc_tx, backend,
network: network.clone(), system_rpc_tx,
task_manager: &mut task_manager, network: network.clone(),
telemetry: telemetry.as_mut(), task_manager: &mut task_manager,
})?; telemetry: telemetry.as_mut(),
})?;
network_starter.start_network(); network_starter.start_network();
Ok(( Ok((task_manager, rpc_handlers, client, network, transaction_pool))
task_manager,
rpc_handlers,
client,
network,
transaction_pool,
))
} }
/// Builds a new service for a light client. /// Builds a new service for a light client.
pub fn new_light( pub fn new_light(config: Configuration) -> Result<TaskManager, ServiceError> {
config: Configuration, new_light_base(config).map(|(task_manager, _, _, _, _)| task_manager)
) -> Result<TaskManager, ServiceError> {
new_light_base(config).map(|(task_manager, _, _, _, _)| {
task_manager
})
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{sync::Arc, borrow::Cow, convert::TryInto}; use crate::service::{new_full_base, new_light_base, NewFullBase};
use sc_consensus_babe::{CompatibleDigestItem, BabeIntermediate, INTERMEDIATE_KEY};
use sc_consensus_epochs::descendent_query;
use sp_consensus::{
Environment, Proposer, BlockImportParams, BlockOrigin, ForkChoiceStrategy, BlockImport,
};
use node_primitives::{Block, DigestItem, Signature};
use node_runtime::{BalancesCall, Call, UncheckedExtrinsic, Address};
use node_runtime::constants::{currency::CENTS, time::SLOT_DURATION};
use codec::Encode; use codec::Encode;
use sp_core::{ use node_primitives::{Block, DigestItem, Signature};
crypto::Pair as CryptoPair, use node_runtime::{
H256, constants::{currency::CENTS, time::SLOT_DURATION},
Public Address, BalancesCall, Call, UncheckedExtrinsic,
}; };
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore}; use sc_client_api::BlockBackend;
use sc_consensus_babe::{BabeIntermediate, CompatibleDigestItem, INTERMEDIATE_KEY};
use sc_consensus_epochs::descendent_query;
use sc_keystore::LocalKeystore;
use sc_service_test::TestNetNode;
use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool};
use sp_consensus::{
BlockImport, BlockImportParams, BlockOrigin, Environment, ForkChoiceStrategy, Proposer,
};
use sp_core::{crypto::Pair as CryptoPair, Public, H256};
use sp_inherents::InherentDataProvider;
use sp_keyring::AccountKeyring;
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
use sp_runtime::{ use sp_runtime::{
generic::{BlockId, Era, Digest, SignedPayload}, generic::{BlockId, Digest, Era, SignedPayload},
traits::{Block as BlockT, Header as HeaderT}, key_types::BABE,
traits::Verify, traits::{Block as BlockT, Header as HeaderT, IdentifyAccount, Verify},
RuntimeAppPublic,
}; };
use sp_timestamp; use sp_timestamp;
use sp_keyring::AccountKeyring; use std::{borrow::Cow, convert::TryInto, sync::Arc};
use sc_service_test::TestNetNode;
use crate::service::{new_full_base, new_light_base, NewFullBase};
use sp_runtime::{key_types::BABE, traits::IdentifyAccount, RuntimeAppPublic};
use sc_transaction_pool_api::{MaintainedTransactionPool, ChainEvent};
use sc_client_api::BlockBackend;
use sc_keystore::LocalKeystore;
use sp_inherents::InherentDataProvider;
type AccountPublic = <Signature as Verify>::Signer; type AccountPublic = <Signature as Verify>::Signer;
@@ -641,10 +624,12 @@ mod tests {
#[ignore] #[ignore]
fn test_sync() { fn test_sync() {
let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore_path = tempfile::tempdir().expect("Creates keystore path");
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None) let keystore: SyncCryptoStorePtr =
.expect("Creates keystore")); Arc::new(LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore"));
let alice: sp_consensus_babe::AuthorityId = SyncCryptoStore::sr25519_generate_new(&*keystore, BABE, Some("//Alice")) let alice: sp_consensus_babe::AuthorityId =
.expect("Creates authority pair").into(); SyncCryptoStore::sr25519_generate_new(&*keystore, BABE, Some("//Alice"))
.expect("Creates authority pair")
.into();
let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority(); let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority();
@@ -660,25 +645,31 @@ mod tests {
chain_spec, chain_spec,
|config| { |config| {
let mut setup_handles = None; let mut setup_handles = None;
let NewFullBase { let NewFullBase { task_manager, client, network, transaction_pool, .. } =
task_manager, client, network, transaction_pool, .. new_full_base(
} = new_full_base(config, config,
| |block_import: &sc_consensus_babe::BabeBlockImport<Block, _, _>,
block_import: &sc_consensus_babe::BabeBlockImport<Block, _, _>, babe_link: &sc_consensus_babe::BabeLink<Block>| {
babe_link: &sc_consensus_babe::BabeLink<Block>, setup_handles = Some((block_import.clone(), babe_link.clone()));
| { },
setup_handles = Some((block_import.clone(), babe_link.clone())); )?;
}
)?;
let node = sc_service_test::TestNetComponents::new( let node = sc_service_test::TestNetComponents::new(
task_manager, client, network, transaction_pool task_manager,
client,
network,
transaction_pool,
); );
Ok((node, setup_handles.unwrap())) Ok((node, setup_handles.unwrap()))
}, },
|config| { |config| {
let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?; let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?;
Ok(sc_service_test::TestNetComponents::new(keep_alive, client, network, transaction_pool)) Ok(sc_service_test::TestNetComponents::new(
keep_alive,
client,
network,
transaction_pool,
))
}, },
|service, &mut (ref mut block_import, ref babe_link)| { |service, &mut (ref mut block_import, ref babe_link)| {
let parent_id = BlockId::number(service.client().chain_info().best_number); let parent_id = BlockId::number(service.client().chain_info().best_number);
@@ -686,14 +677,9 @@ mod tests {
let parent_hash = parent_header.hash(); let parent_hash = parent_header.hash();
let parent_number = *parent_header.number(); let parent_number = *parent_header.number();
futures::executor::block_on( futures::executor::block_on(service.transaction_pool().maintain(
service.transaction_pool().maintain( ChainEvent::NewBestBlock { hash: parent_header.hash(), tree_route: None },
ChainEvent::NewBestBlock { ));
hash: parent_header.hash(),
tree_route: None,
},
)
);
let mut proposer_factory = sc_basic_authorship::ProposerFactory::new( let mut proposer_factory = sc_basic_authorship::ProposerFactory::new(
service.spawn_handle(), service.spawn_handle(),
@@ -708,23 +694,30 @@ mod tests {
// even though there's only one authority some slots might be empty, // even though there's only one authority some slots might be empty,
// so we must keep trying the next slots until we can claim one. // so we must keep trying the next slots until we can claim one.
let (babe_pre_digest, epoch_descriptor) = loop { let (babe_pre_digest, epoch_descriptor) = loop {
let epoch_descriptor = babe_link.epoch_changes().shared_data().epoch_descriptor_for_child_of( let epoch_descriptor = babe_link
descendent_query(&*service.client()), .epoch_changes()
&parent_hash, .shared_data()
parent_number, .epoch_descriptor_for_child_of(
slot.into(), descendent_query(&*service.client()),
).unwrap().unwrap(); &parent_hash,
parent_number,
slot.into(),
)
.unwrap()
.unwrap();
let epoch = babe_link.epoch_changes().shared_data().epoch_data( let epoch = babe_link
&epoch_descriptor, .epoch_changes()
|slot| sc_consensus_babe::Epoch::genesis(&babe_link.config(), slot), .shared_data()
).unwrap(); .epoch_data(&epoch_descriptor, |slot| {
sc_consensus_babe::Epoch::genesis(&babe_link.config(), slot)
})
.unwrap();
if let Some(babe_pre_digest) = sc_consensus_babe::authorship::claim_slot( if let Some(babe_pre_digest) =
slot.into(), sc_consensus_babe::authorship::claim_slot(slot.into(), &epoch, &keystore)
&epoch, .map(|(digest, _)| digest)
&keystore, {
).map(|(digest, _)| digest) {
break (babe_pre_digest, epoch_descriptor) break (babe_pre_digest, epoch_descriptor)
} }
@@ -736,19 +729,21 @@ mod tests {
std::time::Duration::from_millis(SLOT_DURATION * slot).into(), std::time::Duration::from_millis(SLOT_DURATION * slot).into(),
), ),
sp_consensus_babe::inherents::InherentDataProvider::new(slot.into()), sp_consensus_babe::inherents::InherentDataProvider::new(slot.into()),
).create_inherent_data().expect("Creates inherent data"); )
.create_inherent_data()
.expect("Creates inherent data");
digest.push(<DigestItem as CompatibleDigestItem>::babe_pre_digest(babe_pre_digest)); digest.push(<DigestItem as CompatibleDigestItem>::babe_pre_digest(babe_pre_digest));
let new_block = futures::executor::block_on(async move { let new_block = futures::executor::block_on(async move {
let proposer = proposer_factory.init(&parent_header).await; let proposer = proposer_factory.init(&parent_header).await;
proposer.unwrap().propose( proposer
inherent_data, .unwrap()
digest, .propose(inherent_data, digest, std::time::Duration::from_secs(1), None)
std::time::Duration::from_secs(1), .await
None, })
).await .expect("Error making test block")
}).expect("Error making test block").block; .block;
let (new_header, new_body) = new_block.deconstruct(); let (new_header, new_body) = new_block.deconstruct();
let pre_hash = new_header.hash(); let pre_hash = new_header.hash();
@@ -760,10 +755,12 @@ mod tests {
sp_consensus_babe::AuthorityId::ID, sp_consensus_babe::AuthorityId::ID,
&alice.to_public_crypto_pair(), &alice.to_public_crypto_pair(),
&to_sign, &to_sign,
).unwrap().unwrap().try_into().unwrap(); )
let item = <DigestItem as CompatibleDigestItem>::babe_seal( .unwrap()
signature, .unwrap()
); .try_into()
.unwrap();
let item = <DigestItem as CompatibleDigestItem>::babe_seal(signature);
slot += 1; slot += 1;
let mut params = BlockImportParams::new(BlockOrigin::File, new_header); let mut params = BlockImportParams::new(BlockOrigin::File, new_header);
@@ -811,19 +808,13 @@ mod tests {
let raw_payload = SignedPayload::from_raw( let raw_payload = SignedPayload::from_raw(
function, function,
extra, extra,
(spec_version, transaction_version, genesis_hash, genesis_hash, (), (), ()) (spec_version, transaction_version, genesis_hash, genesis_hash, (), (), ()),
); );
let signature = raw_payload.using_encoded(|payload| { let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
signer.sign(payload)
});
let (function, extra, _) = raw_payload.deconstruct(); let (function, extra, _) = raw_payload.deconstruct();
index += 1; index += 1;
UncheckedExtrinsic::new_signed( UncheckedExtrinsic::new_signed(function, from.into(), signature.into(), extra)
function, .into()
from.into(),
signature.into(),
extra,
).into()
}, },
); );
} }
@@ -834,18 +825,25 @@ mod tests {
sc_service_test::consensus( sc_service_test::consensus(
crate::chain_spec::tests::integration_test_config_with_two_authorities(), crate::chain_spec::tests::integration_test_config_with_two_authorities(),
|config| { |config| {
let NewFullBase { task_manager, client, network, transaction_pool, .. } let NewFullBase { task_manager, client, network, transaction_pool, .. } =
= new_full_base(config,|_, _| ())?; new_full_base(config, |_, _| ())?;
Ok(sc_service_test::TestNetComponents::new(task_manager, client, network, transaction_pool)) Ok(sc_service_test::TestNetComponents::new(
task_manager,
client,
network,
transaction_pool,
))
}, },
|config| { |config| {
let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?; let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?;
Ok(sc_service_test::TestNetComponents::new(keep_alive, client, network, transaction_pool)) Ok(sc_service_test::TestNetComponents::new(
keep_alive,
client,
network,
transaction_pool,
))
}, },
vec![ vec!["//Alice".into(), "//Bob".into()],
"//Alice".into(),
"//Bob".into(),
],
) )
} }
} }
+12 -10
View File
@@ -18,11 +18,18 @@
#![cfg(unix)] #![cfg(unix)]
use std::{process::{Child, ExitStatus}, thread, time::Duration, path::Path};
use assert_cmd::cargo::cargo_bin; use assert_cmd::cargo::cargo_bin;
use std::{convert::TryInto, process::Command}; use nix::{
use nix::sys::signal::{kill, Signal::SIGINT}; sys::signal::{kill, Signal::SIGINT},
use nix::unistd::Pid; unistd::Pid,
};
use std::{
convert::TryInto,
path::Path,
process::{Child, Command, ExitStatus},
thread,
time::Duration,
};
/// Wait for the given `child` the given number of `secs`. /// Wait for the given `child` the given number of `secs`.
/// ///
@@ -50,12 +57,7 @@ pub fn wait_for(child: &mut Child, secs: usize) -> Option<ExitStatus> {
pub fn run_dev_node_for_a_while(base_path: &Path) { pub fn run_dev_node_for_a_while(base_path: &Path) {
let mut cmd = Command::new(cargo_bin("substrate")); let mut cmd = Command::new(cargo_bin("substrate"));
let mut cmd = cmd let mut cmd = cmd.args(&["--dev"]).arg("-d").arg(base_path).spawn().unwrap();
.args(&["--dev"])
.arg("-d")
.arg(base_path)
.spawn()
.unwrap();
// Let it produce some blocks. // Let it produce some blocks.
thread::sleep(Duration::from_secs(30)); thread::sleep(Duration::from_secs(30));
@@ -19,9 +19,9 @@
#![cfg(unix)] #![cfg(unix)]
use assert_cmd::cargo::cargo_bin; use assert_cmd::cargo::cargo_bin;
use std::{process::Command, fs, path::PathBuf};
use tempfile::{tempdir, TempDir};
use regex::Regex; use regex::Regex;
use std::{fs, path::PathBuf, process::Command};
use tempfile::{tempdir, TempDir};
pub mod common; pub mod common;
@@ -63,26 +63,23 @@ impl<'a> ExportImportRevertExecutor<'a> {
fn new( fn new(
base_path: &'a TempDir, base_path: &'a TempDir,
exported_blocks_file: &'a PathBuf, exported_blocks_file: &'a PathBuf,
db_path: &'a PathBuf db_path: &'a PathBuf,
) -> Self { ) -> Self {
Self { Self { base_path, exported_blocks_file, db_path, num_exported_blocks: None }
base_path,
exported_blocks_file,
db_path,
num_exported_blocks: None,
}
} }
/// Helper method to run a command. Returns a string corresponding to what has been logged. /// Helper method to run a command. Returns a string corresponding to what has been logged.
fn run_block_command(&self, fn run_block_command(
&self,
sub_command: SubCommand, sub_command: SubCommand,
format_opt: FormatOpt, format_opt: FormatOpt,
expected_to_fail: bool expected_to_fail: bool,
) -> String { ) -> String {
let sub_command_str = sub_command.to_string(); let sub_command_str = sub_command.to_string();
// Adding "--binary" if need be. // Adding "--binary" if need be.
let arguments: Vec<&str> = match format_opt { let arguments: Vec<&str> = match format_opt {
FormatOpt::Binary => vec![&sub_command_str, "--dev", "--pruning", "archive", "--binary", "-d"], FormatOpt::Binary =>
vec![&sub_command_str, "--dev", "--pruning", "archive", "--binary", "-d"],
FormatOpt::Json => vec![&sub_command_str, "--dev", "--pruning", "archive", "-d"], FormatOpt::Json => vec![&sub_command_str, "--dev", "--pruning", "archive", "-d"],
}; };
@@ -94,7 +91,7 @@ impl<'a> ExportImportRevertExecutor<'a> {
SubCommand::ImportBlocks => { SubCommand::ImportBlocks => {
tmp = tempdir().unwrap(); tmp = tempdir().unwrap();
tmp.path() tmp.path()
} },
}; };
// Running the command and capturing the output. // Running the command and capturing the output.
@@ -144,16 +141,13 @@ impl<'a> ExportImportRevertExecutor<'a> {
if !expected_to_fail { if !expected_to_fail {
// Using regex to find out how much block we imported, // Using regex to find out how much block we imported,
// and what's the best current block. // and what's the best current block.
let re = Regex::new(r"Imported (?P<imported>\d*) blocks. Best: #(?P<best>\d*)").unwrap(); let re =
Regex::new(r"Imported (?P<imported>\d*) blocks. Best: #(?P<best>\d*)").unwrap();
let caps = re.captures(&log).expect("capture should have succeeded"); let caps = re.captures(&log).expect("capture should have succeeded");
let imported = caps["imported"].parse::<u64>().unwrap(); let imported = caps["imported"].parse::<u64>().unwrap();
let best = caps["best"].parse::<u64>().unwrap(); let best = caps["best"].parse::<u64>().unwrap();
assert_eq!( assert_eq!(imported, best, "numbers of blocks imported and best number differs");
imported,
best,
"numbers of blocks imported and best number differs"
);
assert_eq!( assert_eq!(
best, best,
self.num_exported_blocks.expect("number of exported blocks cannot be None; qed"), self.num_exported_blocks.expect("number of exported blocks cannot be None; qed"),
@@ -195,11 +189,7 @@ fn export_import_revert() {
common::run_dev_node_for_a_while(base_path.path()); common::run_dev_node_for_a_while(base_path.path());
let mut executor = ExportImportRevertExecutor::new( let mut executor = ExportImportRevertExecutor::new(&base_path, &exported_blocks_file, &db_path);
&base_path,
&exported_blocks_file,
&db_path,
);
// Binary and binary should work. // Binary and binary should work.
executor.run(FormatOpt::Binary, FormatOpt::Binary, false); executor.run(FormatOpt::Binary, FormatOpt::Binary, false);
@@ -25,8 +25,13 @@ pub mod common;
#[test] #[test]
#[cfg(unix)] #[cfg(unix)]
fn running_the_node_works_and_can_be_interrupted() { fn running_the_node_works_and_can_be_interrupted() {
use nix::sys::signal::{kill, Signal::{self, SIGINT, SIGTERM}}; use nix::{
use nix::unistd::Pid; sys::signal::{
kill,
Signal::{self, SIGINT, SIGTERM},
},
unistd::Pid,
};
fn run_command_and_kill(signal: Signal) { fn run_command_and_kill(signal: Signal) {
let base_path = tempdir().expect("could not create a temp dir"); let base_path = tempdir().expect("could not create a temp dir");
+13 -22
View File
@@ -17,10 +17,11 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use assert_cmd::cargo::cargo_bin; use assert_cmd::cargo::cargo_bin;
use nix::sys::signal::{kill, Signal::SIGINT}; use nix::{
use nix::unistd::Pid; sys::signal::{kill, Signal::SIGINT},
use std::convert::TryInto; unistd::Pid,
use std::process; };
use std::{convert::TryInto, process};
pub mod common; pub mod common;
pub mod websocket_server; pub mod websocket_server;
@@ -45,27 +46,22 @@ async fn telemetry_works() {
Event::ConnectionOpen { address } => { Event::ConnectionOpen { address } => {
println!("New connection from {:?}", address); println!("New connection from {:?}", address);
server.accept(); server.accept();
} },
// Received a message from a connection. // Received a message from a connection.
Event::BinaryFrame { message, .. } => { Event::BinaryFrame { message, .. } => {
let json: serde_json::Value = serde_json::from_slice(&message).unwrap(); let json: serde_json::Value = serde_json::from_slice(&message).unwrap();
let object = json let object =
.as_object() json.as_object().unwrap().get("payload").unwrap().as_object().unwrap();
.unwrap()
.get("payload")
.unwrap()
.as_object()
.unwrap();
if matches!(object.get("best"), Some(serde_json::Value::String(_))) { if matches!(object.get("best"), Some(serde_json::Value::String(_))) {
break; break
} }
} },
Event::TextFrame { .. } => panic!("Got a TextFrame over the socket, this is a bug"), Event::TextFrame { .. } => panic!("Got a TextFrame over the socket, this is a bug"),
// Connection has been closed. // Connection has been closed.
Event::ConnectionError { .. } => {} Event::ConnectionError { .. } => {},
} }
} }
}); });
@@ -83,16 +79,11 @@ async fn telemetry_works() {
server_task.await; server_task.await;
assert!( assert!(substrate.try_wait().unwrap().is_none(), "the process should still be running");
substrate.try_wait().unwrap().is_none(),
"the process should still be running"
);
// Stop the process // Stop the process
kill(Pid::from_raw(substrate.id().try_into().unwrap()), SIGINT).unwrap(); kill(Pid::from_raw(substrate.id().try_into().unwrap()), SIGINT).unwrap();
assert!(common::wait_for(&mut substrate, 40) assert!(common::wait_for(&mut substrate, 40).map(|x| x.success()).unwrap_or_default());
.map(|x| x.success())
.unwrap_or_default());
let output = substrate.wait_with_output().unwrap(); let output = substrate.wait_with_output().unwrap();
@@ -19,15 +19,19 @@
#![cfg(unix)] #![cfg(unix)]
use assert_cmd::cargo::cargo_bin; use assert_cmd::cargo::cargo_bin;
use nix::sys::signal::{kill, Signal::SIGINT}; use nix::{
use nix::unistd::Pid; sys::signal::{kill, Signal::SIGINT},
unistd::Pid,
};
use regex::Regex; use regex::Regex;
use std::convert::TryInto; use std::{
use std::io::Read; convert::TryInto,
use std::path::PathBuf; io::Read,
use std::process::{Command, Stdio}; path::PathBuf,
use std::thread; process::{Command, Stdio},
use std::time::Duration; thread,
time::Duration,
};
pub mod common; pub mod common;
@@ -44,29 +48,18 @@ fn temp_base_path_works() {
// Let it produce some blocks. // Let it produce some blocks.
thread::sleep(Duration::from_secs(30)); thread::sleep(Duration::from_secs(30));
assert!( assert!(cmd.try_wait().unwrap().is_none(), "the process should still be running");
cmd.try_wait().unwrap().is_none(),
"the process should still be running"
);
// Stop the process // Stop the process
kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap(); kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap();
assert!(common::wait_for(&mut cmd, 40) assert!(common::wait_for(&mut cmd, 40).map(|x| x.success()).unwrap_or_default());
.map(|x| x.success())
.unwrap_or_default());
// Ensure the database has been deleted // Ensure the database has been deleted
let mut stderr = String::new(); let mut stderr = String::new();
cmd.stderr.unwrap().read_to_string(&mut stderr).unwrap(); cmd.stderr.unwrap().read_to_string(&mut stderr).unwrap();
let re = Regex::new(r"Database: .+ at (\S+)").unwrap(); let re = Regex::new(r"Database: .+ at (\S+)").unwrap();
let db_path = PathBuf::from( let db_path =
re.captures(stderr.as_str()) PathBuf::from(re.captures(stderr.as_str()).unwrap().get(1).unwrap().as_str().to_string());
.unwrap()
.get(1)
.unwrap()
.as_str()
.to_string(),
);
assert!(!db_path.exists()); assert!(!db_path.exists());
} }
+9 -25
View File
@@ -22,61 +22,45 @@ use regex::Regex;
use std::process::Command; use std::process::Command;
fn expected_regex() -> Regex { fn expected_regex() -> Regex {
Regex::new(r"^substrate (\d+\.\d+\.\d+(?:-.+?)?)-([a-f\d]+|unknown)-(.+?)-(.+?)(?:-(.+))?$").unwrap() Regex::new(r"^substrate (\d+\.\d+\.\d+(?:-.+?)?)-([a-f\d]+|unknown)-(.+?)-(.+?)(?:-(.+))?$")
.unwrap()
} }
#[test] #[test]
fn version_is_full() { fn version_is_full() {
let expected = expected_regex(); let expected = expected_regex();
let output = Command::new(cargo_bin("substrate")) let output = Command::new(cargo_bin("substrate")).args(&["--version"]).output().unwrap();
.args(&["--version"])
.output()
.unwrap();
assert!( assert!(output.status.success(), "command returned with non-success exit code");
output.status.success(),
"command returned with non-success exit code"
);
let output = String::from_utf8_lossy(&output.stdout).trim().to_owned(); let output = String::from_utf8_lossy(&output.stdout).trim().to_owned();
let captures = expected let captures = expected.captures(output.as_str()).expect("could not parse version in output");
.captures(output.as_str())
.expect("could not parse version in output");
assert_eq!(&captures[1], env!("CARGO_PKG_VERSION")); assert_eq!(&captures[1], env!("CARGO_PKG_VERSION"));
assert_eq!(&captures[3], TARGET_ARCH.as_str()); assert_eq!(&captures[3], TARGET_ARCH.as_str());
assert_eq!(&captures[4], TARGET_OS.as_str()); assert_eq!(&captures[4], TARGET_OS.as_str());
assert_eq!( assert_eq!(captures.get(5).map(|x| x.as_str()), TARGET_ENV.map(|x| x.as_str()));
captures.get(5).map(|x| x.as_str()),
TARGET_ENV.map(|x| x.as_str())
);
} }
#[test] #[test]
fn test_regex_matches_properly() { fn test_regex_matches_properly() {
let expected = expected_regex(); let expected = expected_regex();
let captures = expected let captures = expected.captures("substrate 2.0.0-da487d19d-x86_64-linux-gnu").unwrap();
.captures("substrate 2.0.0-da487d19d-x86_64-linux-gnu")
.unwrap();
assert_eq!(&captures[1], "2.0.0"); assert_eq!(&captures[1], "2.0.0");
assert_eq!(&captures[2], "da487d19d"); assert_eq!(&captures[2], "da487d19d");
assert_eq!(&captures[3], "x86_64"); assert_eq!(&captures[3], "x86_64");
assert_eq!(&captures[4], "linux"); assert_eq!(&captures[4], "linux");
assert_eq!(captures.get(5).map(|x| x.as_str()), Some("gnu")); assert_eq!(captures.get(5).map(|x| x.as_str()), Some("gnu"));
let captures = expected let captures = expected.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux-gnu").unwrap();
.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux-gnu")
.unwrap();
assert_eq!(&captures[1], "2.0.0-alpha.5"); assert_eq!(&captures[1], "2.0.0-alpha.5");
assert_eq!(&captures[2], "da487d19d"); assert_eq!(&captures[2], "da487d19d");
assert_eq!(&captures[3], "x86_64"); assert_eq!(&captures[3], "x86_64");
assert_eq!(&captures[4], "linux"); assert_eq!(&captures[4], "linux");
assert_eq!(captures.get(5).map(|x| x.as_str()), Some("gnu")); assert_eq!(captures.get(5).map(|x| x.as_str()), Some("gnu"));
let captures = expected let captures = expected.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux").unwrap();
.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux")
.unwrap();
assert_eq!(&captures[1], "2.0.0-alpha.5"); assert_eq!(&captures[1], "2.0.0-alpha.5");
assert_eq!(&captures[2], "da487d19d"); assert_eq!(&captures[2], "da487d19d");
assert_eq!(&captures[3], "x86_64"); assert_eq!(&captures[3], "x86_64");
@@ -116,7 +116,6 @@ impl WsServer {
/// # Panic /// # Panic
/// ///
/// Panics if no connection is pending. /// Panics if no connection is pending.
///
pub fn accept(&mut self) { pub fn accept(&mut self) {
let pending_incoming = self.pending_incoming.take().expect("no pending socket"); let pending_incoming = self.pending_incoming.take().expect("no pending socket");
@@ -129,15 +128,10 @@ impl WsServer {
}; };
match server match server
.send_response(&{ .send_response(&{ Response::Accept { key: &websocket_key, protocol: None } })
Response::Accept {
key: &websocket_key,
protocol: None,
}
})
.await .await
{ {
Ok(()) => {} Ok(()) => {},
Err(err) => return Err(Box::new(err) as Box<_>), Err(err) => return Err(Box::new(err) as Box<_>),
}; };
@@ -153,7 +147,6 @@ impl WsServer {
/// # Panic /// # Panic
/// ///
/// Panics if no connection is pending. /// Panics if no connection is pending.
///
pub fn reject(&mut self) { pub fn reject(&mut self) {
let _ = self.pending_incoming.take().expect("no pending socket"); let _ = self.pending_incoming.take().expect("no pending socket");
} }
+100 -92
View File
@@ -16,29 +16,33 @@
// limitations under the License. // limitations under the License.
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use criterion::{BatchSize, Criterion, criterion_group, criterion_main}; use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use frame_support::Hashable;
use node_executor::Executor; use node_executor::Executor;
use node_primitives::{BlockNumber, Hash}; use node_primitives::{BlockNumber, Hash};
use node_runtime::{ use node_runtime::{
Block, BuildStorage, Call, CheckedExtrinsic, GenesisConfig, Header, UncheckedExtrinsic, constants::currency::*, Block, BuildStorage, Call, CheckedExtrinsic, GenesisConfig, Header,
UncheckedExtrinsic,
}; };
use node_runtime::constants::currency::*;
use node_testing::keyring::*; use node_testing::keyring::*;
use sp_core::{NativeOrEncoded, NeverNativeValue}; use sc_executor::{Externalities, NativeExecutor, RuntimeInfo, WasmExecutionMethod};
use sp_core::storage::well_known_keys; use sp_core::{
use sp_core::traits::{CodeExecutor, RuntimeCode}; storage::well_known_keys,
use frame_support::Hashable; traits::{CodeExecutor, RuntimeCode},
use sp_state_machine::TestExternalities as CoreTestExternalities; NativeOrEncoded, NeverNativeValue,
use sc_executor::{NativeExecutor, RuntimeInfo, WasmExecutionMethod, Externalities}; };
use sp_runtime::traits::BlakeTwo256; use sp_runtime::traits::BlakeTwo256;
use sp_state_machine::TestExternalities as CoreTestExternalities;
criterion_group!(benches, bench_execute_block); criterion_group!(benches, bench_execute_block);
criterion_main!(benches); criterion_main!(benches);
/// The wasm runtime code. /// The wasm runtime code.
pub fn compact_code_unwrap() -> &'static [u8] { pub fn compact_code_unwrap() -> &'static [u8] {
node_runtime::WASM_BINARY.expect("Development wasm binary is not available. \ node_runtime::WASM_BINARY.expect(
Testing is only supported with the flag disabled.") "Development wasm binary is not available. \
Testing is only supported with the flag disabled.",
)
} }
const GENESIS_HASH: [u8; 32] = [69u8; 32]; const GENESIS_HASH: [u8; 32] = [69u8; 32];
@@ -66,7 +70,9 @@ fn new_test_ext(genesis_config: &GenesisConfig) -> TestExternalities<BlakeTwo256
compact_code_unwrap(), compact_code_unwrap(),
genesis_config.build_storage().unwrap(), genesis_config.build_storage().unwrap(),
); );
test_ext.ext().place_storage(well_known_keys::HEAP_PAGES.to_vec(), Some(HEAP_PAGES.encode())); test_ext
.ext()
.place_storage(well_known_keys::HEAP_PAGES.to_vec(), Some(HEAP_PAGES.encode()));
test_ext test_ext
} }
@@ -77,16 +83,16 @@ fn construct_block<E: Externalities>(
parent_hash: Hash, parent_hash: Hash,
extrinsics: Vec<CheckedExtrinsic>, extrinsics: Vec<CheckedExtrinsic>,
) -> (Vec<u8>, Hash) { ) -> (Vec<u8>, Hash) {
use sp_trie::{TrieConfiguration, trie_types::Layout}; use sp_trie::{trie_types::Layout, TrieConfiguration};
// sign extrinsics. // sign extrinsics.
let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>(); let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>();
// calculate the header fields that we can. // calculate the header fields that we can.
let extrinsics_root = Layout::<BlakeTwo256>::ordered_trie_root( let extrinsics_root =
extrinsics.iter().map(Encode::encode) Layout::<BlakeTwo256>::ordered_trie_root(extrinsics.iter().map(Encode::encode))
).to_fixed_bytes() .to_fixed_bytes()
.into(); .into();
let header = Header { let header = Header {
parent_hash, parent_hash,
@@ -103,34 +109,44 @@ fn construct_block<E: Externalities>(
}; };
// execute the block to get the real header. // execute the block to get the real header.
executor.call::<NeverNativeValue, fn() -> _>( executor
ext, .call::<NeverNativeValue, fn() -> _>(
&runtime_code,
"Core_initialize_block",
&header.encode(),
true,
None,
).0.unwrap();
for i in extrinsics.iter() {
executor.call::<NeverNativeValue, fn() -> _>(
ext, ext,
&runtime_code, &runtime_code,
"BlockBuilder_apply_extrinsic", "Core_initialize_block",
&i.encode(), &header.encode(),
true, true,
None, None,
).0.unwrap(); )
.0
.unwrap();
for i in extrinsics.iter() {
executor
.call::<NeverNativeValue, fn() -> _>(
ext,
&runtime_code,
"BlockBuilder_apply_extrinsic",
&i.encode(),
true,
None,
)
.0
.unwrap();
} }
let header = match executor.call::<NeverNativeValue, fn() -> _>( let header = match executor
ext, .call::<NeverNativeValue, fn() -> _>(
&runtime_code, ext,
"BlockBuilder_finalize_block", &runtime_code,
&[0u8;0], "BlockBuilder_finalize_block",
true, &[0u8; 0],
None, true,
).0.unwrap() { None,
)
.0
.unwrap()
{
NativeOrEncoded::Native(_) => unreachable!(), NativeOrEncoded::Native(_) => unreachable!(),
NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(),
}; };
@@ -139,29 +155,21 @@ fn construct_block<E: Externalities>(
(Block { header, extrinsics }.encode(), hash.into()) (Block { header, extrinsics }.encode(), hash.into())
} }
fn test_blocks(genesis_config: &GenesisConfig, executor: &NativeExecutor<Executor>) fn test_blocks(
-> Vec<(Vec<u8>, Hash)> genesis_config: &GenesisConfig,
{ executor: &NativeExecutor<Executor>,
) -> Vec<(Vec<u8>, Hash)> {
let mut test_ext = new_test_ext(genesis_config); let mut test_ext = new_test_ext(genesis_config);
let mut block1_extrinsics = vec![ let mut block1_extrinsics = vec![CheckedExtrinsic {
CheckedExtrinsic { signed: None,
signed: None, function: Call::Timestamp(pallet_timestamp::Call::set(0)),
function: Call::Timestamp(pallet_timestamp::Call::set(0)), }];
}, block1_extrinsics.extend((0..20).map(|i| CheckedExtrinsic {
]; signed: Some((alice(), signed_extra(i, 0))),
block1_extrinsics.extend((0..20).map(|i| { function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 1 * DOLLARS)),
CheckedExtrinsic {
signed: Some((alice(), signed_extra(i, 0))),
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 1 * DOLLARS)),
}
})); }));
let block1 = construct_block( let block1 =
executor, construct_block(executor, &mut test_ext.ext(), 1, GENESIS_HASH.into(), block1_extrinsics);
&mut test_ext.ext(),
1,
GENESIS_HASH.into(),
block1_extrinsics,
);
vec![block1] vec![block1]
} }
@@ -176,47 +184,47 @@ fn bench_execute_block(c: &mut Criterion) {
]; ];
for strategy in execution_methods { for strategy in execution_methods {
group.bench_function( group.bench_function(format!("{:?}", strategy), |b| {
format!("{:?}", strategy), let genesis_config = node_testing::genesis::config(false, Some(compact_code_unwrap()));
|b| { let (use_native, wasm_method) = match strategy {
let genesis_config = node_testing::genesis::config(false, Some(compact_code_unwrap())); ExecutionMethod::Native => (true, WasmExecutionMethod::Interpreted),
let (use_native, wasm_method) = match strategy { ExecutionMethod::Wasm(wasm_method) => (false, wasm_method),
ExecutionMethod::Native => (true, WasmExecutionMethod::Interpreted), };
ExecutionMethod::Wasm(wasm_method) => (false, wasm_method),
};
let executor = NativeExecutor::new(wasm_method, None, 8); let executor = NativeExecutor::new(wasm_method, None, 8);
let runtime_code = RuntimeCode { let runtime_code = RuntimeCode {
code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()), code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()),
hash: vec![1, 2, 3], hash: vec![1, 2, 3],
heap_pages: None, heap_pages: None,
}; };
// Get the runtime version to initialize the runtimes cache. // Get the runtime version to initialize the runtimes cache.
{ {
let mut test_ext = new_test_ext(&genesis_config); let mut test_ext = new_test_ext(&genesis_config);
executor.runtime_version(&mut test_ext.ext(), &runtime_code).unwrap(); executor.runtime_version(&mut test_ext.ext(), &runtime_code).unwrap();
} }
let blocks = test_blocks(&genesis_config, &executor); let blocks = test_blocks(&genesis_config, &executor);
b.iter_batched_ref( b.iter_batched_ref(
|| new_test_ext(&genesis_config), || new_test_ext(&genesis_config),
|test_ext| { |test_ext| {
for block in blocks.iter() { for block in blocks.iter() {
executor.call::<NeverNativeValue, fn() -> _>( executor
.call::<NeverNativeValue, fn() -> _>(
&mut test_ext.ext(), &mut test_ext.ext(),
&runtime_code, &runtime_code,
"Core_execute_block", "Core_execute_block",
&block.0, &block.0,
use_native, use_native,
None, None,
).0.unwrap(); )
} .0
}, .unwrap();
BatchSize::LargeInput, }
); },
}, BatchSize::LargeInput,
); );
});
} }
} }
+1 -1
View File
@@ -18,8 +18,8 @@
//! A `CodeExecutor` specialization which uses natively compiled runtime when the wasm to be //! A `CodeExecutor` specialization which uses natively compiled runtime when the wasm to be
//! executed is equivalent to the natively compiled code. //! executed is equivalent to the natively compiled code.
pub use sc_executor::NativeExecutor;
use sc_executor::native_executor_instance; use sc_executor::native_executor_instance;
pub use sc_executor::NativeExecutor;
// Declare an instance of the native executor named `Executor`. Include the wasm binary as the // Declare an instance of the native executor named `Executor`. Include the wasm binary as the
// equivalent wasm code. // equivalent wasm code.
+172 -134
View File
@@ -15,30 +15,28 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use codec::{Encode, Decode, Joiner}; use codec::{Decode, Encode, Joiner};
use frame_support::{ use frame_support::{
traits::Currency, traits::Currency,
weights::{GetDispatchInfo, DispatchInfo, DispatchClass}, weights::{DispatchClass, DispatchInfo, GetDispatchInfo},
}; };
use sp_core::{NeverNativeValue, traits::Externalities, storage::well_known_keys}; use frame_system::{self, AccountInfo, EventRecord, Phase};
use sp_core::{storage::well_known_keys, traits::Externalities, NeverNativeValue};
use sp_runtime::{ use sp_runtime::{
ApplyExtrinsicResult, traits::Hash as HashT, transaction_validity::InvalidTransaction, ApplyExtrinsicResult,
traits::Hash as HashT,
transaction_validity::InvalidTransaction,
}; };
use frame_system::{self, EventRecord, Phase, AccountInfo};
use node_runtime::{
Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances,
System, TransactionPayment, Event,
constants::{time::SLOT_DURATION, currency::*},
};
use node_primitives::{Balance, Hash}; use node_primitives::{Balance, Hash};
use wat; use node_runtime::{
constants::{currency::*, time::SLOT_DURATION},
Balances, Block, Call, CheckedExtrinsic, Event, Header, Runtime, System, TransactionPayment,
UncheckedExtrinsic,
};
use node_testing::keyring::*; use node_testing::keyring::*;
use wat;
pub mod common; pub mod common;
use self::common::{*, sign}; use self::common::{sign, *};
/// The wasm runtime binary which hasn't undergone the compacting process. /// The wasm runtime binary which hasn't undergone the compacting process.
/// ///
@@ -46,8 +44,10 @@ use self::common::{*, sign};
/// have to execute provided wasm code instead of the native equivalent. This trick is used to /// have to execute provided wasm code instead of the native equivalent. This trick is used to
/// test code paths that differ between native and wasm versions. /// test code paths that differ between native and wasm versions.
pub fn bloaty_code_unwrap() -> &'static [u8] { pub fn bloaty_code_unwrap() -> &'static [u8] {
node_runtime::WASM_BINARY_BLOATY.expect("Development wasm binary is not available. \ node_runtime::WASM_BINARY_BLOATY.expect(
Testing is only supported with the flag disabled.") "Development wasm binary is not available. \
Testing is only supported with the flag disabled.",
)
} }
/// Default transfer fee. This will use the same logic that is implemented in transaction-payment module. /// Default transfer fee. This will use the same logic that is implemented in transaction-payment module.
@@ -87,7 +87,10 @@ fn changes_trie_block() -> (Vec<u8>, Hash) {
}, },
CheckedExtrinsic { CheckedExtrinsic {
signed: Some((alice(), signed_extra(0, 0))), signed: Some((alice(), signed_extra(0, 0))),
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 69 * DOLLARS)), function: Call::Balances(pallet_balances::Call::transfer(
bob().into(),
69 * DOLLARS,
)),
}, },
], ],
(time / SLOT_DURATION).into(), (time / SLOT_DURATION).into(),
@@ -111,7 +114,10 @@ fn blocks() -> ((Vec<u8>, Hash), (Vec<u8>, Hash)) {
}, },
CheckedExtrinsic { CheckedExtrinsic {
signed: Some((alice(), signed_extra(0, 0))), signed: Some((alice(), signed_extra(0, 0))),
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 69 * DOLLARS)), function: Call::Balances(pallet_balances::Call::transfer(
bob().into(),
69 * DOLLARS,
)),
}, },
], ],
(time1 / SLOT_DURATION).into(), (time1 / SLOT_DURATION).into(),
@@ -128,12 +134,18 @@ fn blocks() -> ((Vec<u8>, Hash), (Vec<u8>, Hash)) {
}, },
CheckedExtrinsic { CheckedExtrinsic {
signed: Some((bob(), signed_extra(0, 0))), signed: Some((bob(), signed_extra(0, 0))),
function: Call::Balances(pallet_balances::Call::transfer(alice().into(), 5 * DOLLARS)), function: Call::Balances(pallet_balances::Call::transfer(
alice().into(),
5 * DOLLARS,
)),
}, },
CheckedExtrinsic { CheckedExtrinsic {
signed: Some((alice(), signed_extra(1, 0))), signed: Some((alice(), signed_extra(1, 0))),
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 15 * DOLLARS)), function: Call::Balances(pallet_balances::Call::transfer(
} bob().into(),
15 * DOLLARS,
)),
},
], ],
(time2 / SLOT_DURATION).into(), (time2 / SLOT_DURATION).into(),
); );
@@ -158,7 +170,7 @@ fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec<u8>, Hash) {
CheckedExtrinsic { CheckedExtrinsic {
signed: Some((alice(), signed_extra(nonce, 0))), signed: Some((alice(), signed_extra(nonce, 0))),
function: Call::System(frame_system::Call::remark(vec![0; size])), function: Call::System(frame_system::Call::remark(vec![0; size])),
} },
], ],
(time * 1000 / SLOT_DURATION).into(), (time * 1000 / SLOT_DURATION).into(),
) )
@@ -169,7 +181,7 @@ fn panic_execution_with_foreign_code_gives_error() {
let mut t = new_test_ext(bloaty_code_unwrap(), false); let mut t = new_test_ext(bloaty_code_unwrap(), false);
t.insert( t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(alice()), <frame_system::Account<Runtime>>::hashed_key_for(alice()),
(69u128, 0u32, 0u128, 0u128, 0u128).encode() (69u128, 0u32, 0u128, 0u128, 0u128).encode(),
); );
t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 69_u128.encode()); t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 69_u128.encode());
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]); t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
@@ -180,7 +192,8 @@ fn panic_execution_with_foreign_code_gives_error() {
&vec![].and(&from_block_number(1u32)), &vec![].and(&from_block_number(1u32)),
true, true,
None, None,
).0; )
.0;
assert!(r.is_ok()); assert!(r.is_ok());
let v = executor_call::<NeverNativeValue, fn() -> _>( let v = executor_call::<NeverNativeValue, fn() -> _>(
&mut t, &mut t,
@@ -188,7 +201,9 @@ fn panic_execution_with_foreign_code_gives_error() {
&vec![].and(&xt()), &vec![].and(&xt()),
true, true,
None, None,
).0.unwrap(); )
.0
.unwrap();
let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap(); let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap();
assert_eq!(r, Err(InvalidTransaction::Payment.into())); assert_eq!(r, Err(InvalidTransaction::Payment.into()));
} }
@@ -198,7 +213,7 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() {
let mut t = new_test_ext(compact_code_unwrap(), false); let mut t = new_test_ext(compact_code_unwrap(), false);
t.insert( t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(alice()), <frame_system::Account<Runtime>>::hashed_key_for(alice()),
(0u32, 0u32, 0u32, 69u128, 0u128, 0u128, 0u128).encode() (0u32, 0u32, 0u32, 69u128, 0u128, 0u128, 0u128).encode(),
); );
t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 69_u128.encode()); t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 69_u128.encode());
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]); t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
@@ -209,7 +224,8 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() {
&vec![].and(&from_block_number(1u32)), &vec![].and(&from_block_number(1u32)),
true, true,
None, None,
).0; )
.0;
assert!(r.is_ok()); assert!(r.is_ok());
let v = executor_call::<NeverNativeValue, fn() -> _>( let v = executor_call::<NeverNativeValue, fn() -> _>(
&mut t, &mut t,
@@ -217,7 +233,9 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() {
&vec![].and(&xt()), &vec![].and(&xt()),
true, true,
None, None,
).0.unwrap(); )
.0
.unwrap();
let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap(); let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap();
assert_eq!(r, Err(InvalidTransaction::Payment.into())); assert_eq!(r, Err(InvalidTransaction::Payment.into()));
} }
@@ -229,19 +247,21 @@ fn successful_execution_with_native_equivalent_code_gives_ok() {
<frame_system::Account<Runtime>>::hashed_key_for(alice()), <frame_system::Account<Runtime>>::hashed_key_for(alice()),
AccountInfo::<<Runtime as frame_system::Config>::Index, _> { AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
data: (111 * DOLLARS, 0u128, 0u128, 0u128), data: (111 * DOLLARS, 0u128, 0u128, 0u128),
.. Default::default() ..Default::default()
}.encode(), }
.encode(),
); );
t.insert( t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(bob()), <frame_system::Account<Runtime>>::hashed_key_for(bob()),
AccountInfo::<<Runtime as frame_system::Config>::Index, _> { AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
data: (0 * DOLLARS, 0u128, 0u128, 0u128), data: (0 * DOLLARS, 0u128, 0u128, 0u128),
.. Default::default() ..Default::default()
}.encode(), }
.encode(),
); );
t.insert( t.insert(
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), <pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
(111 * DOLLARS).encode() (111 * DOLLARS).encode(),
); );
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]); t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
@@ -251,7 +271,8 @@ fn successful_execution_with_native_equivalent_code_gives_ok() {
&vec![].and(&from_block_number(1u32)), &vec![].and(&from_block_number(1u32)),
true, true,
None, None,
).0; )
.0;
assert!(r.is_ok()); assert!(r.is_ok());
let fees = t.execute_with(|| transfer_fee(&xt())); let fees = t.execute_with(|| transfer_fee(&xt()));
@@ -262,7 +283,8 @@ fn successful_execution_with_native_equivalent_code_gives_ok() {
&vec![].and(&xt()), &vec![].and(&xt()),
true, true,
None, None,
).0; )
.0;
assert!(r.is_ok()); assert!(r.is_ok());
t.execute_with(|| { t.execute_with(|| {
@@ -278,19 +300,21 @@ fn successful_execution_with_foreign_code_gives_ok() {
<frame_system::Account<Runtime>>::hashed_key_for(alice()), <frame_system::Account<Runtime>>::hashed_key_for(alice()),
AccountInfo::<<Runtime as frame_system::Config>::Index, _> { AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
data: (111 * DOLLARS, 0u128, 0u128, 0u128), data: (111 * DOLLARS, 0u128, 0u128, 0u128),
.. Default::default() ..Default::default()
}.encode(), }
.encode(),
); );
t.insert( t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(bob()), <frame_system::Account<Runtime>>::hashed_key_for(bob()),
AccountInfo::<<Runtime as frame_system::Config>::Index, _> { AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
data: (0 * DOLLARS, 0u128, 0u128, 0u128), data: (0 * DOLLARS, 0u128, 0u128, 0u128),
.. Default::default() ..Default::default()
}.encode(), }
.encode(),
); );
t.insert( t.insert(
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), <pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
(111 * DOLLARS).encode() (111 * DOLLARS).encode(),
); );
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]); t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
@@ -300,7 +324,8 @@ fn successful_execution_with_foreign_code_gives_ok() {
&vec![].and(&from_block_number(1u32)), &vec![].and(&from_block_number(1u32)),
true, true,
None, None,
).0; )
.0;
assert!(r.is_ok()); assert!(r.is_ok());
let fees = t.execute_with(|| transfer_fee(&xt())); let fees = t.execute_with(|| transfer_fee(&xt()));
@@ -311,7 +336,8 @@ fn successful_execution_with_foreign_code_gives_ok() {
&vec![].and(&xt()), &vec![].and(&xt()),
true, true,
None, None,
).0; )
.0;
assert!(r.is_ok()); assert!(r.is_ok());
t.execute_with(|| { t.execute_with(|| {
@@ -330,7 +356,9 @@ fn full_native_block_import_works() {
let mut fees = t.execute_with(|| transfer_fee(&xt())); let mut fees = t.execute_with(|| transfer_fee(&xt()));
let transfer_weight = default_transfer_call().get_dispatch_info().weight; let transfer_weight = default_transfer_call().get_dispatch_info().weight;
let timestamp_weight = pallet_timestamp::Call::set::<Runtime>(Default::default()).get_dispatch_info().weight; let timestamp_weight = pallet_timestamp::Call::set::<Runtime>(Default::default())
.get_dispatch_info()
.weight;
executor_call::<NeverNativeValue, fn() -> _>( executor_call::<NeverNativeValue, fn() -> _>(
&mut t, &mut t,
@@ -338,7 +366,9 @@ fn full_native_block_import_works() {
&block1.0, &block1.0,
true, true,
None, None,
).0.unwrap(); )
.0
.unwrap();
t.execute_with(|| { t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
@@ -347,9 +377,11 @@ fn full_native_block_import_works() {
let events = vec![ let events = vec![
EventRecord { EventRecord {
phase: Phase::ApplyExtrinsic(0), phase: Phase::ApplyExtrinsic(0),
event: Event::System(frame_system::Event::ExtrinsicSuccess( event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, ..Default::default() } weight: timestamp_weight,
)), class: DispatchClass::Mandatory,
..Default::default()
})),
topics: vec![], topics: vec![],
}, },
EventRecord { EventRecord {
@@ -368,9 +400,10 @@ fn full_native_block_import_works() {
}, },
EventRecord { EventRecord {
phase: Phase::ApplyExtrinsic(1), phase: Phase::ApplyExtrinsic(1),
event: Event::System(frame_system::Event::ExtrinsicSuccess( event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
DispatchInfo { weight: transfer_weight, ..Default::default() } weight: transfer_weight,
)), ..Default::default()
})),
topics: vec![], topics: vec![],
}, },
]; ];
@@ -385,34 +418,33 @@ fn full_native_block_import_works() {
&block2.0, &block2.0,
true, true,
None, None,
).0.unwrap(); )
.0
.unwrap();
t.execute_with(|| { t.execute_with(|| {
assert_eq!( assert_eq!(
Balances::total_balance(&alice()), Balances::total_balance(&alice()),
alice_last_known_balance - 10 * DOLLARS - fees, alice_last_known_balance - 10 * DOLLARS - fees,
); );
assert_eq!( assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - fees,);
Balances::total_balance(&bob()),
179 * DOLLARS - fees,
);
let events = vec![ let events = vec![
EventRecord { EventRecord {
phase: Phase::ApplyExtrinsic(0), phase: Phase::ApplyExtrinsic(0),
event: Event::System(frame_system::Event::ExtrinsicSuccess( event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, ..Default::default() } weight: timestamp_weight,
)), class: DispatchClass::Mandatory,
..Default::default()
})),
topics: vec![], topics: vec![],
}, },
EventRecord { EventRecord {
phase: Phase::ApplyExtrinsic(1), phase: Phase::ApplyExtrinsic(1),
event: Event::Balances( event: Event::Balances(pallet_balances::Event::Transfer(
pallet_balances::Event::Transfer( bob().into(),
bob().into(), alice().into(),
alice().into(), 5 * DOLLARS,
5 * DOLLARS, )),
)
),
topics: vec![], topics: vec![],
}, },
EventRecord { EventRecord {
@@ -422,20 +454,19 @@ fn full_native_block_import_works() {
}, },
EventRecord { EventRecord {
phase: Phase::ApplyExtrinsic(1), phase: Phase::ApplyExtrinsic(1),
event: Event::System(frame_system::Event::ExtrinsicSuccess( event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
DispatchInfo { weight: transfer_weight, ..Default::default() } weight: transfer_weight,
)), ..Default::default()
})),
topics: vec![], topics: vec![],
}, },
EventRecord { EventRecord {
phase: Phase::ApplyExtrinsic(2), phase: Phase::ApplyExtrinsic(2),
event: Event::Balances( event: Event::Balances(pallet_balances::Event::Transfer(
pallet_balances::Event::Transfer( alice().into(),
alice().into(), bob().into(),
bob().into(), 15 * DOLLARS,
15 * DOLLARS, )),
)
),
topics: vec![], topics: vec![],
}, },
EventRecord { EventRecord {
@@ -445,9 +476,10 @@ fn full_native_block_import_works() {
}, },
EventRecord { EventRecord {
phase: Phase::ApplyExtrinsic(2), phase: Phase::ApplyExtrinsic(2),
event: Event::System(frame_system::Event::ExtrinsicSuccess( event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
DispatchInfo { weight: transfer_weight, ..Default::default() } weight: transfer_weight,
)), ..Default::default()
})),
topics: vec![], topics: vec![],
}, },
]; ];
@@ -470,7 +502,9 @@ fn full_wasm_block_import_works() {
&block1.0, &block1.0,
false, false,
None, None,
).0.unwrap(); )
.0
.unwrap();
t.execute_with(|| { t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
@@ -486,17 +520,16 @@ fn full_wasm_block_import_works() {
&block2.0, &block2.0,
false, false,
None, None,
).0.unwrap(); )
.0
.unwrap();
t.execute_with(|| { t.execute_with(|| {
assert_eq!( assert_eq!(
Balances::total_balance(&alice()), Balances::total_balance(&alice()),
alice_last_known_balance - 10 * DOLLARS - fees, alice_last_known_balance - 10 * DOLLARS - fees,
); );
assert_eq!( assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * fees,);
Balances::total_balance(&bob()),
179 * DOLLARS - 1 * fees,
);
}); });
} }
@@ -600,11 +633,7 @@ fn deploying_wasm_contract_should_work() {
let transfer_code = wat::parse_str(CODE_TRANSFER).unwrap(); let transfer_code = wat::parse_str(CODE_TRANSFER).unwrap();
let transfer_ch = <Runtime as frame_system::Config>::Hashing::hash(&transfer_code); let transfer_ch = <Runtime as frame_system::Config>::Hashing::hash(&transfer_code);
let addr = pallet_contracts::Pallet::<Runtime>::contract_address( let addr = pallet_contracts::Pallet::<Runtime>::contract_address(&charlie(), &transfer_ch, &[]);
&charlie(),
&transfer_ch,
&[],
);
let subsistence = pallet_contracts::Pallet::<Runtime>::subsistence_threshold(); let subsistence = pallet_contracts::Pallet::<Runtime>::subsistence_threshold();
@@ -627,19 +656,17 @@ fn deploying_wasm_contract_should_work() {
transfer_code, transfer_code,
Vec::new(), Vec::new(),
Vec::new(), Vec::new(),
) ),
), ),
}, },
CheckedExtrinsic { CheckedExtrinsic {
signed: Some((charlie(), signed_extra(1, 0))), signed: Some((charlie(), signed_extra(1, 0))),
function: Call::Contracts( function: Call::Contracts(pallet_contracts::Call::call::<Runtime>(
pallet_contracts::Call::call::<Runtime>( sp_runtime::MultiAddress::Id(addr.clone()),
sp_runtime::MultiAddress::Id(addr.clone()), 10,
10, 500_000_000,
500_000_000, vec![0x00, 0x01, 0x02, 0x03],
vec![0x00, 0x01, 0x02, 0x03] )),
)
),
}, },
], ],
(time / SLOT_DURATION).into(), (time / SLOT_DURATION).into(),
@@ -647,20 +674,14 @@ fn deploying_wasm_contract_should_work() {
let mut t = new_test_ext(compact_code_unwrap(), false); let mut t = new_test_ext(compact_code_unwrap(), false);
executor_call::<NeverNativeValue, fn() -> _>( executor_call::<NeverNativeValue, fn() -> _>(&mut t, "Core_execute_block", &b.0, false, None)
&mut t, .0
"Core_execute_block", .unwrap();
&b.0,
false,
None,
).0.unwrap();
t.execute_with(|| { t.execute_with(|| {
// Verify that the contract does exist by querying some of its storage items // Verify that the contract does exist by querying some of its storage items
// It does not matter that the storage item itself does not exist. // It does not matter that the storage item itself does not exist.
assert!( assert!(&pallet_contracts::Pallet::<Runtime>::get_storage(addr, Default::default()).is_ok());
&pallet_contracts::Pallet::<Runtime>::get_storage(addr, Default::default()).is_ok()
);
}); });
} }
@@ -676,7 +697,8 @@ fn wasm_big_block_import_fails() {
&block_with_size(42, 0, 120_000).0, &block_with_size(42, 0, 120_000).0,
false, false,
None, None,
).0; )
.0;
assert!(result.is_err()); // Err(Wasmi(Trap(Trap { kind: Host(AllocatorOutOfSpace) }))) assert!(result.is_err()); // Err(Wasmi(Trap(Trap { kind: Host(AllocatorOutOfSpace) })))
} }
@@ -690,7 +712,9 @@ fn native_big_block_import_succeeds() {
&block_with_size(42, 0, 120_000).0, &block_with_size(42, 0, 120_000).0,
true, true,
None, None,
).0.unwrap(); )
.0
.unwrap();
} }
#[test] #[test]
@@ -700,15 +724,15 @@ fn native_big_block_import_fails_on_fallback() {
// We set the heap pages to 8 because we know that should give an OOM in WASM with the given block. // We set the heap pages to 8 because we know that should give an OOM in WASM with the given block.
set_heap_pages(&mut t.ext(), 8); set_heap_pages(&mut t.ext(), 8);
assert!( assert!(executor_call::<NeverNativeValue, fn() -> _>(
executor_call::<NeverNativeValue, fn() -> _>( &mut t,
&mut t, "Core_execute_block",
"Core_execute_block", &block_with_size(42, 0, 120_000).0,
&block_with_size(42, 0, 120_000).0, false,
false, None,
None, )
).0.is_err() .0
); .is_err());
} }
#[test] #[test]
@@ -718,8 +742,9 @@ fn panic_execution_gives_error() {
<frame_system::Account<Runtime>>::hashed_key_for(alice()), <frame_system::Account<Runtime>>::hashed_key_for(alice()),
AccountInfo::<<Runtime as frame_system::Config>::Index, _> { AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
data: (0 * DOLLARS, 0u128, 0u128, 0u128), data: (0 * DOLLARS, 0u128, 0u128, 0u128),
.. Default::default() ..Default::default()
}.encode(), }
.encode(),
); );
t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 0_u128.encode()); t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 0_u128.encode());
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]); t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
@@ -730,7 +755,8 @@ fn panic_execution_gives_error() {
&vec![].and(&from_block_number(1u32)), &vec![].and(&from_block_number(1u32)),
false, false,
None, None,
).0; )
.0;
assert!(r.is_ok()); assert!(r.is_ok());
let r = executor_call::<NeverNativeValue, fn() -> _>( let r = executor_call::<NeverNativeValue, fn() -> _>(
&mut t, &mut t,
@@ -738,7 +764,10 @@ fn panic_execution_gives_error() {
&vec![].and(&xt()), &vec![].and(&xt()),
false, false,
None, None,
).0.unwrap().into_encoded(); )
.0
.unwrap()
.into_encoded();
let r = ApplyExtrinsicResult::decode(&mut &r[..]).unwrap(); let r = ApplyExtrinsicResult::decode(&mut &r[..]).unwrap();
assert_eq!(r, Err(InvalidTransaction::Payment.into())); assert_eq!(r, Err(InvalidTransaction::Payment.into()));
} }
@@ -750,19 +779,21 @@ fn successful_execution_gives_ok() {
<frame_system::Account<Runtime>>::hashed_key_for(alice()), <frame_system::Account<Runtime>>::hashed_key_for(alice()),
AccountInfo::<<Runtime as frame_system::Config>::Index, _> { AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
data: (111 * DOLLARS, 0u128, 0u128, 0u128), data: (111 * DOLLARS, 0u128, 0u128, 0u128),
.. Default::default() ..Default::default()
}.encode(), }
.encode(),
); );
t.insert( t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(bob()), <frame_system::Account<Runtime>>::hashed_key_for(bob()),
AccountInfo::<<Runtime as frame_system::Config>::Index, _> { AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
data: (0 * DOLLARS, 0u128, 0u128, 0u128), data: (0 * DOLLARS, 0u128, 0u128, 0u128),
.. Default::default() ..Default::default()
}.encode(), }
.encode(),
); );
t.insert( t.insert(
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), <pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
(111 * DOLLARS).encode() (111 * DOLLARS).encode(),
); );
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]); t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
@@ -772,7 +803,8 @@ fn successful_execution_gives_ok() {
&vec![].and(&from_block_number(1u32)), &vec![].and(&from_block_number(1u32)),
false, false,
None, None,
).0; )
.0;
assert!(r.is_ok()); assert!(r.is_ok());
t.execute_with(|| { t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 111 * DOLLARS); assert_eq!(Balances::total_balance(&alice()), 111 * DOLLARS);
@@ -786,7 +818,10 @@ fn successful_execution_gives_ok() {
&vec![].and(&xt()), &vec![].and(&xt()),
false, false,
None, None,
).0.unwrap().into_encoded(); )
.0
.unwrap()
.into_encoded();
ApplyExtrinsicResult::decode(&mut &r[..]) ApplyExtrinsicResult::decode(&mut &r[..])
.unwrap() .unwrap()
.expect("Extrinsic could not be applied") .expect("Extrinsic could not be applied")
@@ -811,7 +846,9 @@ fn full_native_block_import_works_with_changes_trie() {
&block.encode(), &block.encode(),
true, true,
None, None,
).0.unwrap(); )
.0
.unwrap();
assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some()); assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some());
} }
@@ -827,7 +864,9 @@ fn full_wasm_block_import_works_with_changes_trie() {
&block1.0, &block1.0,
false, false,
None, None,
).0.unwrap(); )
.0
.unwrap();
assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some()); assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some());
} }
@@ -835,8 +874,7 @@ fn full_wasm_block_import_works_with_changes_trie() {
#[test] #[test]
fn should_import_block_with_test_client() { fn should_import_block_with_test_client() {
use node_testing::client::{ use node_testing::client::{
ClientBlockImportExt, TestClientBuilderExt, TestClientBuilder, sp_consensus::BlockOrigin, ClientBlockImportExt, TestClientBuilder, TestClientBuilderExt,
sp_consensus::BlockOrigin,
}; };
let mut client = TestClientBuilder::new().build(); let mut client = TestClientBuilder::new().build();
+50 -45
View File
@@ -15,34 +15,32 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use codec::{Encode, Decode}; use codec::{Decode, Encode};
use frame_system::offchain::AppCrypto;
use frame_support::Hashable; use frame_support::Hashable;
use sp_state_machine::TestExternalities as CoreTestExternalities; use frame_system::offchain::AppCrypto;
use sp_consensus_babe::{BABE_ENGINE_ID, Slot, digests::{PreDigest, SecondaryPlainPreDigest}}; use sc_executor::{error::Result, NativeExecutor, WasmExecutionMethod};
use sp_consensus_babe::{
digests::{PreDigest, SecondaryPlainPreDigest},
Slot, BABE_ENGINE_ID,
};
use sp_core::{ use sp_core::{
NeverNativeValue, NativeOrEncoded,
crypto::KeyTypeId, crypto::KeyTypeId,
sr25519::Signature, sr25519::Signature,
traits::{CodeExecutor, RuntimeCode}, traits::{CodeExecutor, RuntimeCode},
NativeOrEncoded, NeverNativeValue,
}; };
use sp_runtime::{ use sp_runtime::{
ApplyExtrinsicResult, traits::{BlakeTwo256, Header as HeaderT},
MultiSigner, ApplyExtrinsicResult, Digest, DigestItem, MultiSignature, MultiSigner,
MultiSignature,
Digest,
DigestItem,
traits::{Header as HeaderT, BlakeTwo256},
}; };
use sc_executor::{NativeExecutor, WasmExecutionMethod}; use sp_state_machine::TestExternalities as CoreTestExternalities;
use sc_executor::error::Result;
use node_executor::Executor; use node_executor::Executor;
use node_primitives::{BlockNumber, Hash};
use node_runtime::{ use node_runtime::{
Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Runtime, BuildStorage, constants::currency::*, Block, BuildStorage, CheckedExtrinsic, Header, Runtime,
constants::currency::*, UncheckedExtrinsic,
}; };
use node_primitives::{Hash, BlockNumber};
use node_testing::keyring::*; use node_testing::keyring::*;
use sp_externalities::Externalities; use sp_externalities::Externalities;
@@ -50,8 +48,8 @@ pub const TEST_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"test");
pub mod sr25519 { pub mod sr25519 {
mod app_sr25519 { mod app_sr25519 {
use sp_application_crypto::{app_crypto, sr25519};
use super::super::TEST_KEY_TYPE_ID; use super::super::TEST_KEY_TYPE_ID;
use sp_application_crypto::{app_crypto, sr25519};
app_crypto!(sr25519, TEST_KEY_TYPE_ID); app_crypto!(sr25519, TEST_KEY_TYPE_ID);
} }
@@ -72,8 +70,10 @@ impl AppCrypto<MultiSigner, MultiSignature> for TestAuthorityId {
/// as canonical. This is why `native_executor_instance` also uses the compact version of the /// as canonical. This is why `native_executor_instance` also uses the compact version of the
/// runtime. /// runtime.
pub fn compact_code_unwrap() -> &'static [u8] { pub fn compact_code_unwrap() -> &'static [u8] {
node_runtime::WASM_BINARY.expect("Development wasm binary is not available. \ node_runtime::WASM_BINARY.expect(
Testing is only supported with the flag disabled.") "Development wasm binary is not available. \
Testing is only supported with the flag disabled.",
)
} }
pub const GENESIS_HASH: [u8; 32] = [69u8; 32]; pub const GENESIS_HASH: [u8; 32] = [69u8; 32];
@@ -101,8 +101,9 @@ pub fn executor() -> NativeExecutor<Executor> {
} }
pub fn executor_call< pub fn executor_call<
R:Decode + Encode + PartialEq, R: Decode + Encode + PartialEq,
NC: FnOnce() -> std::result::Result<R, Box<dyn std::error::Error + Send + Sync>> + std::panic::UnwindSafe NC: FnOnce() -> std::result::Result<R, Box<dyn std::error::Error + Send + Sync>>
+ std::panic::UnwindSafe,
>( >(
t: &mut TestExternalities<BlakeTwo256>, t: &mut TestExternalities<BlakeTwo256>,
method: &str, method: &str,
@@ -120,20 +121,15 @@ pub fn executor_call<
heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()), heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()),
}; };
executor().call::<R, NC>( executor().call::<R, NC>(&mut t, &runtime_code, method, data, use_native, native_call)
&mut t,
&runtime_code,
method,
data,
use_native,
native_call,
)
} }
pub fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities<BlakeTwo256> { pub fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities<BlakeTwo256> {
let mut ext = TestExternalities::new_with_code( let mut ext = TestExternalities::new_with_code(
code, code,
node_testing::genesis::config(support_changes_trie, Some(code)).build_storage().unwrap(), node_testing::genesis::config(support_changes_trie, Some(code))
.build_storage()
.unwrap(),
); );
ext.changes_trie_storage().insert(0, GENESIS_HASH.into(), Default::default()); ext.changes_trie_storage().insert(0, GENESIS_HASH.into(), Default::default());
ext ext
@@ -150,7 +146,7 @@ pub fn construct_block(
extrinsics: Vec<CheckedExtrinsic>, extrinsics: Vec<CheckedExtrinsic>,
babe_slot: Slot, babe_slot: Slot,
) -> (Vec<u8>, Hash) { ) -> (Vec<u8>, Hash) {
use sp_trie::{TrieConfiguration, trie_types::Layout}; use sp_trie::{trie_types::Layout, TrieConfiguration};
// sign extrinsics. // sign extrinsics.
let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>(); let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>();
@@ -167,15 +163,14 @@ pub fn construct_block(
extrinsics_root, extrinsics_root,
state_root: Default::default(), state_root: Default::default(),
digest: Digest { digest: Digest {
logs: vec![ logs: vec![DigestItem::PreRuntime(
DigestItem::PreRuntime( BABE_ENGINE_ID,
BABE_ENGINE_ID, PreDigest::SecondaryPlain(SecondaryPlainPreDigest {
PreDigest::SecondaryPlain(SecondaryPlainPreDigest { slot: babe_slot,
slot: babe_slot, authority_index: 42,
authority_index: 42, })
}).encode() .encode(),
), )],
],
}, },
}; };
@@ -186,7 +181,9 @@ pub fn construct_block(
&header.encode(), &header.encode(),
true, true,
None, None,
).0.unwrap(); )
.0
.unwrap();
for extrinsic in extrinsics.iter() { for extrinsic in extrinsics.iter() {
// Try to apply the `extrinsic`. It should be valid, in the sense that it passes // Try to apply the `extrinsic`. It should be valid, in the sense that it passes
@@ -197,8 +194,13 @@ pub fn construct_block(
&extrinsic.encode(), &extrinsic.encode(),
true, true,
None, None,
).0.expect("application of an extrinsic failed").into_encoded(); )
match ApplyExtrinsicResult::decode(&mut &r[..]).expect("apply result deserialization failed") { .0
.expect("application of an extrinsic failed")
.into_encoded();
match ApplyExtrinsicResult::decode(&mut &r[..])
.expect("apply result deserialization failed")
{
Ok(_) => {}, Ok(_) => {},
Err(e) => panic!("Applying extrinsic failed: {:?}", e), Err(e) => panic!("Applying extrinsic failed: {:?}", e),
} }
@@ -207,10 +209,13 @@ pub fn construct_block(
let header = match executor_call::<NeverNativeValue, fn() -> _>( let header = match executor_call::<NeverNativeValue, fn() -> _>(
env, env,
"BlockBuilder_finalize_block", "BlockBuilder_finalize_block",
&[0u8;0], &[0u8; 0],
true, true,
None, None,
).0.unwrap() { )
.0
.unwrap()
{
NativeOrEncoded::Native(_) => unreachable!(), NativeOrEncoded::Native(_) => unreachable!(),
NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(),
}; };
+47 -28
View File
@@ -18,20 +18,21 @@
use codec::{Encode, Joiner}; use codec::{Encode, Joiner};
use frame_support::{ use frame_support::{
traits::Currency, traits::Currency,
weights::{GetDispatchInfo, constants::ExtrinsicBaseWeight, IdentityFee, WeightToFeePolynomial}, weights::{
}; constants::ExtrinsicBaseWeight, GetDispatchInfo, IdentityFee, WeightToFeePolynomial,
use sp_core::NeverNativeValue; },
use sp_runtime::{Perbill, traits::One};
use node_runtime::{
CheckedExtrinsic, Call, Runtime, Balances, TransactionPayment, Multiplier,
TransactionByteFee,
constants::{time::SLOT_DURATION, currency::*},
}; };
use node_primitives::Balance; use node_primitives::Balance;
use node_runtime::{
constants::{currency::*, time::SLOT_DURATION},
Balances, Call, CheckedExtrinsic, Multiplier, Runtime, TransactionByteFee, TransactionPayment,
};
use node_testing::keyring::*; use node_testing::keyring::*;
use sp_core::NeverNativeValue;
use sp_runtime::{traits::One, Perbill};
pub mod common; pub mod common;
use self::common::{*, sign}; use self::common::{sign, *};
#[test] #[test]
fn fee_multiplier_increases_and_decreases_on_big_weight() { fn fee_multiplier_increases_and_decreases_on_big_weight() {
@@ -60,7 +61,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
CheckedExtrinsic { CheckedExtrinsic {
signed: Some((charlie(), signed_extra(0, 0))), signed: Some((charlie(), signed_extra(0, 0))),
function: Call::System(frame_system::Call::fill_block(Perbill::from_percent(60))), function: Call::System(frame_system::Call::fill_block(Perbill::from_percent(60))),
} },
], ],
(time1 / SLOT_DURATION).into(), (time1 / SLOT_DURATION).into(),
); );
@@ -79,7 +80,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
CheckedExtrinsic { CheckedExtrinsic {
signed: Some((charlie(), signed_extra(1, 0))), signed: Some((charlie(), signed_extra(1, 0))),
function: Call::System(frame_system::Call::remark(vec![0; 1])), function: Call::System(frame_system::Call::remark(vec![0; 1])),
} },
], ],
(time2 / SLOT_DURATION).into(), (time2 / SLOT_DURATION).into(),
); );
@@ -97,7 +98,9 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
&block1.0, &block1.0,
true, true,
None, None,
).0.unwrap(); )
.0
.unwrap();
// weight multiplier is increased for next block. // weight multiplier is increased for next block.
t.execute_with(|| { t.execute_with(|| {
@@ -114,7 +117,9 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
&block2.0, &block2.0,
true, true,
None, None,
).0.unwrap(); )
.0
.unwrap();
// weight multiplier is increased for next block. // weight multiplier is increased for next block.
t.execute_with(|| { t.execute_with(|| {
@@ -131,7 +136,8 @@ fn new_account_info(free_dollars: u128) -> Vec<u8> {
providers: 0, providers: 0,
sufficients: 0, sufficients: 0,
data: (free_dollars * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS), data: (free_dollars * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS),
}.encode() }
.encode()
} }
#[test] #[test]
@@ -148,7 +154,7 @@ fn transaction_fee_is_correct() {
t.insert(<frame_system::Account<Runtime>>::hashed_key_for(bob()), new_account_info(10)); t.insert(<frame_system::Account<Runtime>>::hashed_key_for(bob()), new_account_info(10));
t.insert( t.insert(
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), <pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
(110 * DOLLARS).encode() (110 * DOLLARS).encode(),
); );
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]); t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
@@ -164,7 +170,8 @@ fn transaction_fee_is_correct() {
&vec![].and(&from_block_number(1u32)), &vec![].and(&from_block_number(1u32)),
true, true,
None, None,
).0; )
.0;
assert!(r.is_ok()); assert!(r.is_ok());
let r = executor_call::<NeverNativeValue, fn() -> _>( let r = executor_call::<NeverNativeValue, fn() -> _>(
@@ -173,7 +180,8 @@ fn transaction_fee_is_correct() {
&vec![].and(&xt.clone()), &vec![].and(&xt.clone()),
true, true,
None, None,
).0; )
.0;
assert!(r.is_ok()); assert!(r.is_ok());
t.execute_with(|| { t.execute_with(|| {
@@ -228,15 +236,20 @@ fn block_weight_capacity_report() {
loop { loop {
let num_transfers = block_number * factor; let num_transfers = block_number * factor;
let mut xts = (0..num_transfers).map(|i| CheckedExtrinsic { let mut xts = (0..num_transfers)
signed: Some((charlie(), signed_extra(nonce + i as Index, 0))), .map(|i| CheckedExtrinsic {
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 0)), signed: Some((charlie(), signed_extra(nonce + i as Index, 0))),
}).collect::<Vec<CheckedExtrinsic>>(); function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 0)),
})
.collect::<Vec<CheckedExtrinsic>>();
xts.insert(0, CheckedExtrinsic { xts.insert(
signed: None, 0,
function: Call::Timestamp(pallet_timestamp::Call::set(time * 1000)), CheckedExtrinsic {
}); signed: None,
function: Call::Timestamp(pallet_timestamp::Call::set(time * 1000)),
},
);
// NOTE: this is super slow. Can probably be improved. // NOTE: this is super slow. Can probably be improved.
let block = construct_block( let block = construct_block(
@@ -262,7 +275,8 @@ fn block_weight_capacity_report() {
&block.0, &block.0,
true, true,
None, None,
).0; )
.0;
println!(" || Result = {:?}", r); println!(" || Result = {:?}", r);
assert!(r.is_ok()); assert!(r.is_ok());
@@ -307,7 +321,11 @@ fn block_length_capacity_report() {
}, },
CheckedExtrinsic { CheckedExtrinsic {
signed: Some((charlie(), signed_extra(nonce, 0))), signed: Some((charlie(), signed_extra(nonce, 0))),
function: Call::System(frame_system::Call::remark(vec![0u8; (block_number * factor) as usize])), function: Call::System(frame_system::Call::remark(vec![
0u8;
(block_number * factor)
as usize
])),
}, },
], ],
(time * 1000 / SLOT_DURATION).into(), (time * 1000 / SLOT_DURATION).into(),
@@ -327,7 +345,8 @@ fn block_length_capacity_report() {
&block.0, &block.0,
true, true,
None, None,
).0; )
.0;
println!(" || Result = {:?}", r); println!(" || Result = {:?}", r);
assert!(r.is_ok()); assert!(r.is_ok());
@@ -15,26 +15,13 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::sync::Arc;
use node_runtime::{
Executive, Indices, Runtime, UncheckedExtrinsic,
};
use sp_application_crypto::AppKey;
use sp_core::{
offchain::{
TransactionPoolExt,
testing::TestTransactionPoolExt,
},
};
use sp_keystore::{KeystoreExt, SyncCryptoStore, testing::KeyStore};
use frame_system::{
offchain::{
Signer,
SubmitTransaction,
SendSignedTransaction,
}
};
use codec::Decode; use codec::Decode;
use frame_system::offchain::{SendSignedTransaction, Signer, SubmitTransaction};
use node_runtime::{Executive, Indices, Runtime, UncheckedExtrinsic};
use sp_application_crypto::AppKey;
use sp_core::offchain::{testing::TestTransactionPoolExt, TransactionPoolExt};
use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStore};
use std::sync::Arc;
pub mod common; pub mod common;
use self::common::*; use self::common::*;
@@ -56,8 +43,10 @@ fn should_submit_unsigned_transaction() {
}; };
let call = pallet_im_online::Call::heartbeat(heartbeat_data, signature); let call = pallet_im_online::Call::heartbeat(heartbeat_data, signature);
SubmitTransaction::<Runtime, pallet_im_online::Call<Runtime>>::submit_unsigned_transaction(call.into()) SubmitTransaction::<Runtime, pallet_im_online::Call<Runtime>>::submit_unsigned_transaction(
.unwrap(); call.into(),
)
.unwrap();
assert_eq!(state.read().transactions.len(), 1) assert_eq!(state.read().transactions.len(), 1)
}); });
@@ -75,23 +64,26 @@ fn should_submit_signed_transaction() {
SyncCryptoStore::sr25519_generate_new( SyncCryptoStore::sr25519_generate_new(
&keystore, &keystore,
sr25519::AuthorityId::ID, sr25519::AuthorityId::ID,
Some(&format!("{}/hunter1", PHRASE)) Some(&format!("{}/hunter1", PHRASE)),
).unwrap(); )
.unwrap();
SyncCryptoStore::sr25519_generate_new( SyncCryptoStore::sr25519_generate_new(
&keystore, &keystore,
sr25519::AuthorityId::ID, sr25519::AuthorityId::ID,
Some(&format!("{}/hunter2", PHRASE)) Some(&format!("{}/hunter2", PHRASE)),
).unwrap(); )
.unwrap();
SyncCryptoStore::sr25519_generate_new( SyncCryptoStore::sr25519_generate_new(
&keystore, &keystore,
sr25519::AuthorityId::ID, sr25519::AuthorityId::ID,
Some(&format!("{}/hunter3", PHRASE)) Some(&format!("{}/hunter3", PHRASE)),
).unwrap(); )
.unwrap();
t.register_extension(KeystoreExt(Arc::new(keystore))); t.register_extension(KeystoreExt(Arc::new(keystore)));
t.execute_with(|| { t.execute_with(|| {
let results = Signer::<Runtime, TestAuthorityId>::all_accounts() let results =
.send_signed_transaction(|_| { Signer::<Runtime, TestAuthorityId>::all_accounts().send_signed_transaction(|_| {
pallet_balances::Call::transfer(Default::default(), Default::default()) pallet_balances::Call::transfer(Default::default(), Default::default())
}); });
@@ -112,18 +104,20 @@ fn should_submit_signed_twice_from_the_same_account() {
SyncCryptoStore::sr25519_generate_new( SyncCryptoStore::sr25519_generate_new(
&keystore, &keystore,
sr25519::AuthorityId::ID, sr25519::AuthorityId::ID,
Some(&format!("{}/hunter1", PHRASE)) Some(&format!("{}/hunter1", PHRASE)),
).unwrap(); )
.unwrap();
SyncCryptoStore::sr25519_generate_new( SyncCryptoStore::sr25519_generate_new(
&keystore, &keystore,
sr25519::AuthorityId::ID, sr25519::AuthorityId::ID,
Some(&format!("{}/hunter2", PHRASE)) Some(&format!("{}/hunter2", PHRASE)),
).unwrap(); )
.unwrap();
t.register_extension(KeystoreExt(Arc::new(keystore))); t.register_extension(KeystoreExt(Arc::new(keystore)));
t.execute_with(|| { t.execute_with(|| {
let result = Signer::<Runtime, TestAuthorityId>::any_account() let result =
.send_signed_transaction(|_| { Signer::<Runtime, TestAuthorityId>::any_account().send_signed_transaction(|_| {
pallet_balances::Call::transfer(Default::default(), Default::default()) pallet_balances::Call::transfer(Default::default(), Default::default())
}); });
@@ -131,8 +125,8 @@ fn should_submit_signed_twice_from_the_same_account() {
assert_eq!(state.read().transactions.len(), 1); assert_eq!(state.read().transactions.len(), 1);
// submit another one from the same account. The nonce should be incremented. // submit another one from the same account. The nonce should be incremented.
let result = Signer::<Runtime, TestAuthorityId>::any_account() let result =
.send_signed_transaction(|_| { Signer::<Runtime, TestAuthorityId>::any_account().send_signed_transaction(|_| {
pallet_balances::Call::transfer(Default::default(), Default::default()) pallet_balances::Call::transfer(Default::default(), Default::default())
}); });
@@ -147,10 +141,7 @@ fn should_submit_signed_twice_from_the_same_account() {
} }
let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap());
let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap()); let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap());
assert!( assert!(nonce1 != nonce2, "Transactions should have different nonces. Got: {:?}", nonce1);
nonce1 != nonce2,
"Transactions should have different nonces. Got: {:?}", nonce1
);
}); });
} }
@@ -161,14 +152,12 @@ fn should_submit_signed_twice_from_all_accounts() {
t.register_extension(TransactionPoolExt::new(pool)); t.register_extension(TransactionPoolExt::new(pool));
let keystore = KeyStore::new(); let keystore = KeyStore::new();
keystore.sr25519_generate_new( keystore
sr25519::AuthorityId::ID, .sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE)))
Some(&format!("{}/hunter1", PHRASE)) .unwrap();
).unwrap(); keystore
keystore.sr25519_generate_new( .sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter2", PHRASE)))
sr25519::AuthorityId::ID, .unwrap();
Some(&format!("{}/hunter2", PHRASE))
).unwrap();
t.register_extension(KeystoreExt(Arc::new(keystore))); t.register_extension(KeystoreExt(Arc::new(keystore)));
t.execute_with(|| { t.execute_with(|| {
@@ -217,8 +206,10 @@ fn should_submit_signed_twice_from_all_accounts() {
#[test] #[test]
fn submitted_transaction_should_be_valid() { fn submitted_transaction_should_be_valid() {
use codec::Encode; use codec::Encode;
use sp_runtime::transaction_validity::{TransactionSource, TransactionTag}; use sp_runtime::{
use sp_runtime::traits::StaticLookup; traits::StaticLookup,
transaction_validity::{TransactionSource, TransactionTag},
};
let mut t = new_test_ext(compact_code_unwrap(), false); let mut t = new_test_ext(compact_code_unwrap(), false);
let (pool, state) = TestTransactionPoolExt::new(); let (pool, state) = TestTransactionPoolExt::new();
@@ -227,13 +218,15 @@ fn submitted_transaction_should_be_valid() {
let keystore = KeyStore::new(); let keystore = KeyStore::new();
SyncCryptoStore::sr25519_generate_new( SyncCryptoStore::sr25519_generate_new(
&keystore, &keystore,
sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE)) sr25519::AuthorityId::ID,
).unwrap(); Some(&format!("{}/hunter1", PHRASE)),
)
.unwrap();
t.register_extension(KeystoreExt(Arc::new(keystore))); t.register_extension(KeystoreExt(Arc::new(keystore)));
t.execute_with(|| { t.execute_with(|| {
let results = Signer::<Runtime, TestAuthorityId>::all_accounts() let results =
.send_signed_transaction(|_| { Signer::<Runtime, TestAuthorityId>::all_accounts().send_signed_transaction(|_| {
pallet_balances::Call::transfer(Default::default(), Default::default()) pallet_balances::Call::transfer(Default::default(), Default::default())
}); });
let len = results.len(); let len = results.len();
@@ -252,7 +245,7 @@ fn submitted_transaction_should_be_valid() {
let author = extrinsic.signature.clone().unwrap().0; let author = extrinsic.signature.clone().unwrap().0;
let address = Indices::lookup(author).unwrap(); let address = Indices::lookup(author).unwrap();
let data = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() }; let data = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() };
let account = frame_system::AccountInfo { data, .. Default::default() }; let account = frame_system::AccountInfo { data, ..Default::default() };
<frame_system::Account<Runtime>>::insert(&address, account); <frame_system::Account<Runtime>>::insert(&address, account);
// check validity // check validity
@@ -260,7 +253,8 @@ fn submitted_transaction_should_be_valid() {
source, source,
extrinsic, extrinsic,
frame_system::BlockHash::<Runtime>::get(0), frame_system::BlockHash::<Runtime>::get(0),
).unwrap(); )
.unwrap();
// We ignore res.priority since this number can change based on updates to weights and such. // We ignore res.priority since this number can change based on updates to weights and such.
assert_eq!(res.requires, Vec::<TransactionTag>::new()); assert_eq!(res.requires, Vec::<TransactionTag>::new());
+1 -1
View File
@@ -18,8 +18,8 @@
//! Structs to easily compose inspect sub-command for CLI. //! Structs to easily compose inspect sub-command for CLI.
use std::fmt::Debug;
use sc_cli::{ImportParams, SharedParams}; use sc_cli::{ImportParams, SharedParams};
use std::fmt::Debug;
use structopt::StructOpt; use structopt::StructOpt;
/// The `inspect` command used to print decoded chain data. /// The `inspect` command used to print decoded chain data.
+6 -4
View File
@@ -18,8 +18,10 @@
//! Command ran by the CLI //! Command ran by the CLI
use crate::cli::{InspectCmd, InspectSubCmd}; use crate::{
use crate::Inspector; cli::{InspectCmd, InspectSubCmd},
Inspector,
};
use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams};
use sc_service::{new_full_client, Configuration, NativeExecutionDispatch}; use sc_service::{new_full_client, Configuration, NativeExecutionDispatch};
use sp_runtime::traits::Block; use sp_runtime::traits::Block;
@@ -43,13 +45,13 @@ impl InspectCmd {
let res = inspect.block(input).map_err(|e| format!("{}", e))?; let res = inspect.block(input).map_err(|e| format!("{}", e))?;
println!("{}", res); println!("{}", res);
Ok(()) Ok(())
} },
InspectSubCmd::Extrinsic { input } => { InspectSubCmd::Extrinsic { input } => {
let input = input.parse()?; let input = input.parse()?;
let res = inspect.extrinsic(input).map_err(|e| format!("{}", e))?; let res = inspect.extrinsic(input).map_err(|e| format!("{}", e))?;
println!("{}", res); println!("{}", res);
Ok(()) Ok(())
} },
} }
} }
} }
+62 -73
View File
@@ -27,33 +27,27 @@
pub mod cli; pub mod cli;
pub mod command; pub mod command;
use std::{ use codec::{Decode, Encode};
fmt,
fmt::Debug,
marker::PhantomData,
str::FromStr,
};
use codec::{Encode, Decode};
use sc_client_api::BlockBackend; use sc_client_api::BlockBackend;
use sp_blockchain::HeaderBackend; use sp_blockchain::HeaderBackend;
use sp_core::hexdisplay::HexDisplay; use sp_core::hexdisplay::HexDisplay;
use sp_runtime::{ use sp_runtime::{
generic::BlockId, generic::BlockId,
traits::{Block, HashFor, NumberFor, Hash} traits::{Block, Hash, HashFor, NumberFor},
}; };
use std::{fmt, fmt::Debug, marker::PhantomData, str::FromStr};
/// A helper type for a generic block input. /// A helper type for a generic block input.
pub type BlockAddressFor<TBlock> = BlockAddress< pub type BlockAddressFor<TBlock> =
<HashFor<TBlock> as Hash>::Output, BlockAddress<<HashFor<TBlock> as Hash>::Output, NumberFor<TBlock>>;
NumberFor<TBlock>
>;
/// A Pretty formatter implementation. /// A Pretty formatter implementation.
pub trait PrettyPrinter<TBlock: Block> { pub trait PrettyPrinter<TBlock: Block> {
/// Nicely format block. /// Nicely format block.
fn fmt_block(&self, fmt: &mut fmt::Formatter, block: &TBlock) -> fmt::Result; fn fmt_block(&self, fmt: &mut fmt::Formatter, block: &TBlock) -> fmt::Result;
/// Nicely format extrinsic. /// Nicely format extrinsic.
fn fmt_extrinsic(&self, fmt: &mut fmt::Formatter, extrinsic: &TBlock::Extrinsic) -> fmt::Result; fn fmt_extrinsic(&self, fmt: &mut fmt::Formatter, extrinsic: &TBlock::Extrinsic)
-> fmt::Result;
} }
/// Default dummy debug printer. /// Default dummy debug printer.
@@ -72,7 +66,11 @@ impl<TBlock: Block> PrettyPrinter<TBlock> for DebugPrinter {
Ok(()) Ok(())
} }
fn fmt_extrinsic(&self, fmt: &mut fmt::Formatter, extrinsic: &TBlock::Extrinsic) -> fmt::Result { fn fmt_extrinsic(
&self,
fmt: &mut fmt::Formatter,
extrinsic: &TBlock::Extrinsic,
) -> fmt::Result {
writeln!(fmt, " {:#?}", extrinsic)?; writeln!(fmt, " {:#?}", extrinsic)?;
writeln!(fmt, " Bytes: {:?}", HexDisplay::from(&extrinsic.encode()))?; writeln!(fmt, " Bytes: {:?}", HexDisplay::from(&extrinsic.encode()))?;
Ok(()) Ok(())
@@ -101,15 +99,14 @@ impl std::error::Error for Error {
} }
/// A helper trait to access block headers and bodies. /// A helper trait to access block headers and bodies.
pub trait ChainAccess<TBlock: Block>: pub trait ChainAccess<TBlock: Block>: HeaderBackend<TBlock> + BlockBackend<TBlock> {}
HeaderBackend<TBlock> +
BlockBackend<TBlock>
{}
impl<T, TBlock> ChainAccess<TBlock> for T where impl<T, TBlock> ChainAccess<TBlock> for T
where
TBlock: Block, TBlock: Block,
T: sp_blockchain::HeaderBackend<TBlock> + sc_client_api::BlockBackend<TBlock>, T: sp_blockchain::HeaderBackend<TBlock> + sc_client_api::BlockBackend<TBlock>,
{} {
}
/// Blockchain inspector. /// Blockchain inspector.
pub struct Inspector<TBlock: Block, TPrinter: PrettyPrinter<TBlock> = DebugPrinter> { pub struct Inspector<TBlock: Block, TPrinter: PrettyPrinter<TBlock> = DebugPrinter> {
@@ -120,22 +117,16 @@ pub struct Inspector<TBlock: Block, TPrinter: PrettyPrinter<TBlock> = DebugPrint
impl<TBlock: Block, TPrinter: PrettyPrinter<TBlock>> Inspector<TBlock, TPrinter> { impl<TBlock: Block, TPrinter: PrettyPrinter<TBlock>> Inspector<TBlock, TPrinter> {
/// Create new instance of the inspector with default printer. /// Create new instance of the inspector with default printer.
pub fn new( pub fn new(chain: impl ChainAccess<TBlock> + 'static) -> Self
chain: impl ChainAccess<TBlock> + 'static, where
) -> Self where TPrinter: Default { TPrinter: Default,
{
Self::with_printer(chain, Default::default()) Self::with_printer(chain, Default::default())
} }
/// Customize pretty-printing of the data. /// Customize pretty-printing of the data.
pub fn with_printer( pub fn with_printer(chain: impl ChainAccess<TBlock> + 'static, printer: TPrinter) -> Self {
chain: impl ChainAccess<TBlock> + 'static, Inspector { chain: Box::new(chain) as _, printer, _block: Default::default() }
printer: TPrinter,
) -> Self {
Inspector {
chain: Box::new(chain) as _,
printer,
_block: Default::default(),
}
} }
/// Get a pretty-printed block. /// Get a pretty-printed block.
@@ -153,25 +144,27 @@ impl<TBlock: Block, TPrinter: PrettyPrinter<TBlock>> Inspector<TBlock, TPrinter>
fn get_block(&self, input: BlockAddressFor<TBlock>) -> Result<TBlock, Error> { fn get_block(&self, input: BlockAddressFor<TBlock>) -> Result<TBlock, Error> {
Ok(match input { Ok(match input {
BlockAddress::Bytes(bytes) => { BlockAddress::Bytes(bytes) => TBlock::decode(&mut &*bytes)?,
TBlock::decode(&mut &*bytes)?
},
BlockAddress::Number(number) => { BlockAddress::Number(number) => {
let id = BlockId::number(number); let id = BlockId::number(number);
let not_found = format!("Could not find block {:?}", id); let not_found = format!("Could not find block {:?}", id);
let body = self.chain.block_body(&id)? let body = self
.ok_or_else(|| Error::NotFound(not_found.clone()))?; .chain
let header = self.chain.header(id)? .block_body(&id)?
.ok_or_else(|| Error::NotFound(not_found.clone()))?; .ok_or_else(|| Error::NotFound(not_found.clone()))?;
let header =
self.chain.header(id)?.ok_or_else(|| Error::NotFound(not_found.clone()))?;
TBlock::new(header, body) TBlock::new(header, body)
}, },
BlockAddress::Hash(hash) => { BlockAddress::Hash(hash) => {
let id = BlockId::hash(hash); let id = BlockId::hash(hash);
let not_found = format!("Could not find block {:?}", id); let not_found = format!("Could not find block {:?}", id);
let body = self.chain.block_body(&id)? let body = self
.ok_or_else(|| Error::NotFound(not_found.clone()))?; .chain
let header = self.chain.header(id)? .block_body(&id)?
.ok_or_else(|| Error::NotFound(not_found.clone()))?; .ok_or_else(|| Error::NotFound(not_found.clone()))?;
let header =
self.chain.header(id)?.ok_or_else(|| Error::NotFound(not_found.clone()))?;
TBlock::new(header, body) TBlock::new(header, body)
}, },
}) })
@@ -192,16 +185,14 @@ impl<TBlock: Block, TPrinter: PrettyPrinter<TBlock>> Inspector<TBlock, TPrinter>
let ext = match input { let ext = match input {
ExtrinsicAddress::Block(block, index) => { ExtrinsicAddress::Block(block, index) => {
let block = self.get_block(block)?; let block = self.get_block(block)?;
block.extrinsics() block.extrinsics().get(index).cloned().ok_or_else(|| {
.get(index) Error::NotFound(format!(
.cloned() "Could not find extrinsic {} in block {:?}",
.ok_or_else(|| Error::NotFound(format!( index, block
"Could not find extrinsic {} in block {:?}", index, block ))
)))? })?
}, },
ExtrinsicAddress::Bytes(bytes) => { ExtrinsicAddress::Bytes(bytes) => TBlock::Extrinsic::decode(&mut &*bytes)?,
TBlock::Extrinsic::decode(&mut &*bytes)?
}
}; };
Ok(format!("{}", ExtrinsicPrinter(ext, &self.printer))) Ok(format!("{}", ExtrinsicPrinter(ext, &self.printer)))
@@ -234,12 +225,12 @@ impl<Hash: FromStr, Number: FromStr> FromStr for BlockAddress<Hash, Number> {
} }
// then assume it's bytes (hex-encoded) // then assume it's bytes (hex-encoded)
sp_core::bytes::from_hex(s) sp_core::bytes::from_hex(s).map(Self::Bytes).map_err(|e| {
.map(Self::Bytes) format!(
.map_err(|e| format!(
"Given string does not look like hash or number. It could not be parsed as bytes either: {}", "Given string does not look like hash or number. It could not be parsed as bytes either: {}",
e e
)) )
})
} }
} }
@@ -263,11 +254,13 @@ impl<Hash: FromStr + Debug, Number: FromStr + Debug> FromStr for ExtrinsicAddres
// split by a bunch of different characters // split by a bunch of different characters
let mut it = s.split(|c| c == '.' || c == ':' || c == ' '); let mut it = s.split(|c| c == '.' || c == ':' || c == ' ');
let block = it.next() let block = it
.next()
.expect("First element of split iterator is never empty; qed") .expect("First element of split iterator is never empty; qed")
.parse()?; .parse()?;
let index = it.next() let index = it
.next()
.ok_or_else(|| format!("Extrinsic index missing: example \"5:0\""))? .ok_or_else(|| format!("Extrinsic index missing: example \"5:0\""))?
.parse() .parse()
.map_err(|e| format!("Invalid index format: {}", e))?; .map_err(|e| format!("Invalid index format: {}", e))?;
@@ -290,10 +283,10 @@ mod tests {
let b2 = BlockAddress::from_str("0"); let b2 = BlockAddress::from_str("0");
let b3 = BlockAddress::from_str("0x0012345f"); let b3 = BlockAddress::from_str("0x0012345f");
assert_eq!(
assert_eq!(b0, Ok(BlockAddress::Hash( b0,
"3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap() Ok(BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()))
))); );
assert_eq!(b1, Ok(BlockAddress::Number(1234))); assert_eq!(b1, Ok(BlockAddress::Number(1234)));
assert_eq!(b2, Ok(BlockAddress::Number(0))); assert_eq!(b2, Ok(BlockAddress::Number(0)));
assert_eq!(b3, Ok(BlockAddress::Bytes(vec![0, 0x12, 0x34, 0x5f]))); assert_eq!(b3, Ok(BlockAddress::Bytes(vec![0, 0x12, 0x34, 0x5f])));
@@ -310,20 +303,16 @@ mod tests {
let b2 = ExtrinsicAddress::from_str("0 0"); let b2 = ExtrinsicAddress::from_str("0 0");
let b3 = ExtrinsicAddress::from_str("0x0012345f"); let b3 = ExtrinsicAddress::from_str("0x0012345f");
assert_eq!(e0, Err("Extrinsic index missing: example \"5:0\"".into())); assert_eq!(e0, Err("Extrinsic index missing: example \"5:0\"".into()));
assert_eq!(b0, Ok(ExtrinsicAddress::Block( assert_eq!(
BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()), b0,
5 Ok(ExtrinsicAddress::Block(
))); BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()),
assert_eq!(b1, Ok(ExtrinsicAddress::Block( 5
BlockAddress::Number(1234), ))
0 );
))); assert_eq!(b1, Ok(ExtrinsicAddress::Block(BlockAddress::Number(1234), 0)));
assert_eq!(b2, Ok(ExtrinsicAddress::Block( assert_eq!(b2, Ok(ExtrinsicAddress::Block(BlockAddress::Number(0), 0)));
BlockAddress::Number(0),
0
)));
assert_eq!(b3, Ok(ExtrinsicAddress::Bytes(vec![0, 0x12, 0x34, 0x5f]))); assert_eq!(b3, Ok(ExtrinsicAddress::Bytes(vec![0, 0x12, 0x34, 0x5f])));
} }
} }
+3 -2
View File
@@ -18,11 +18,12 @@
//! Low-level types used throughout the Substrate code. //! Low-level types used throughout the Substrate code.
#![warn(missing_docs)] #![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
use sp_runtime::{ use sp_runtime::{
generic, traits::{Verify, BlakeTwo256, IdentifyAccount}, OpaqueExtrinsic, MultiSignature generic,
traits::{BlakeTwo256, IdentifyAccount, Verify},
MultiSignature, OpaqueExtrinsic,
}; };
/// An index to a block. /// An index to a block.
+9 -14
View File
@@ -24,15 +24,9 @@
use futures::Future; use futures::Future;
use hyper::rt; use hyper::rt;
use jsonrpc_core_client::{transports::http, RpcError};
use node_primitives::Hash; use node_primitives::Hash;
use sc_rpc::author::{ use sc_rpc::author::{hash::ExtrinsicOrHash, AuthorClient};
AuthorClient,
hash::ExtrinsicOrHash,
};
use jsonrpc_core_client::{
transports::http,
RpcError,
};
fn main() { fn main() {
sp_tracing::try_init_simple(); sp_tracing::try_init_simple();
@@ -41,9 +35,7 @@ fn main() {
let uri = "http://localhost:9933"; let uri = "http://localhost:9933";
http::connect(uri) http::connect(uri)
.and_then(|client: AuthorClient<Hash, Hash>| { .and_then(|client: AuthorClient<Hash, Hash>| remove_all_extrinsics(client))
remove_all_extrinsics(client)
})
.map_err(|e| { .map_err(|e| {
println!("Error: {:?}", e); println!("Error: {:?}", e);
}) })
@@ -58,11 +50,14 @@ fn main() {
/// ///
/// As the result of running the code the entire content of the transaction pool is going /// As the result of running the code the entire content of the transaction pool is going
/// to be removed and the extrinsics are going to be temporarily banned. /// to be removed and the extrinsics are going to be temporarily banned.
fn remove_all_extrinsics(client: AuthorClient<Hash, Hash>) -> impl Future<Item=(), Error=RpcError> { fn remove_all_extrinsics(
client.pending_extrinsics() client: AuthorClient<Hash, Hash>,
) -> impl Future<Item = (), Error = RpcError> {
client
.pending_extrinsics()
.and_then(move |pending| { .and_then(move |pending| {
client.remove_extrinsic( client.remove_extrinsic(
pending.into_iter().map(|tx| ExtrinsicOrHash::Extrinsic(tx.into())).collect() pending.into_iter().map(|tx| ExtrinsicOrHash::Extrinsic(tx.into())).collect(),
) )
}) })
.map(|removed| { .map(|removed| {
+58 -85
View File
@@ -32,24 +32,24 @@
use std::sync::Arc; use std::sync::Arc;
use sp_keystore::SyncCryptoStorePtr; use node_primitives::{AccountId, Balance, Block, BlockNumber, Hash, Index};
use node_primitives::{Block, BlockNumber, AccountId, Index, Balance, Hash}; use sc_client_api::AuxStore;
use sc_consensus_babe::{Config, Epoch}; use sc_consensus_babe::{Config, Epoch};
use sc_consensus_babe_rpc::BabeRpcHandler; use sc_consensus_babe_rpc::BabeRpcHandler;
use sc_consensus_epochs::SharedEpochChanges; use sc_consensus_epochs::SharedEpochChanges;
use sc_finality_grandpa::{ use sc_finality_grandpa::{
SharedVoterState, SharedAuthoritySet, FinalityProofProvider, GrandpaJustificationStream FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState,
}; };
use sc_finality_grandpa_rpc::GrandpaRpcHandler; use sc_finality_grandpa_rpc::GrandpaRpcHandler;
use sc_rpc::SubscriptionTaskExecutor;
pub use sc_rpc_api::DenyUnsafe; pub use sc_rpc_api::DenyUnsafe;
use sc_transaction_pool_api::TransactionPool;
use sp_api::ProvideRuntimeApi; use sp_api::ProvideRuntimeApi;
use sp_block_builder::BlockBuilder; use sp_block_builder::BlockBuilder;
use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend}; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
use sp_consensus::SelectChain; use sp_consensus::SelectChain;
use sp_consensus_babe::BabeApi; use sp_consensus_babe::BabeApi;
use sc_rpc::SubscriptionTaskExecutor; use sp_keystore::SyncCryptoStorePtr;
use sc_transaction_pool_api::TransactionPool;
use sc_client_api::AuxStore;
/// Light client extra dependencies. /// Light client extra dependencies.
pub struct LightDeps<C, F, P> { pub struct LightDeps<C, F, P> {
@@ -111,9 +111,15 @@ pub type IoHandler = jsonrpc_core::IoHandler<sc_rpc::Metadata>;
/// Instantiate all Full RPC extensions. /// Instantiate all Full RPC extensions.
pub fn create_full<C, P, SC, B>( pub fn create_full<C, P, SC, B>(
deps: FullDeps<C, P, SC, B>, deps: FullDeps<C, P, SC, B>,
) -> jsonrpc_core::IoHandler<sc_rpc_api::Metadata> where ) -> jsonrpc_core::IoHandler<sc_rpc_api::Metadata>
C: ProvideRuntimeApi<Block> + HeaderBackend<Block> + AuxStore + where
HeaderMetadata<Block, Error=BlockChainError> + Sync + Send + 'static, C: ProvideRuntimeApi<Block>
+ HeaderBackend<Block>
+ AuxStore
+ HeaderMetadata<Block, Error = BlockChainError>
+ Sync
+ Send
+ 'static,
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>, C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
C::Api: pallet_contracts_rpc::ContractsRuntimeApi<Block, AccountId, Balance, BlockNumber, Hash>, C::Api: pallet_contracts_rpc::ContractsRuntimeApi<Block, AccountId, Balance, BlockNumber, Hash>,
C::Api: pallet_mmr_rpc::MmrRuntimeApi<Block, <Block as sp_runtime::traits::Block>::Hash>, C::Api: pallet_mmr_rpc::MmrRuntimeApi<Block, <Block as sp_runtime::traits::Block>::Hash>,
@@ -121,31 +127,19 @@ pub fn create_full<C, P, SC, B>(
C::Api: BabeApi<Block>, C::Api: BabeApi<Block>,
C::Api: BlockBuilder<Block>, C::Api: BlockBuilder<Block>,
P: TransactionPool + 'static, P: TransactionPool + 'static,
SC: SelectChain<Block> +'static, SC: SelectChain<Block> + 'static,
B: sc_client_api::Backend<Block> + Send + Sync + 'static, B: sc_client_api::Backend<Block> + Send + Sync + 'static,
B::State: sc_client_api::backend::StateBackend<sp_runtime::traits::HashFor<Block>>, B::State: sc_client_api::backend::StateBackend<sp_runtime::traits::HashFor<Block>>,
{ {
use substrate_frame_rpc_system::{FullSystem, SystemApi};
use pallet_contracts_rpc::{Contracts, ContractsApi}; use pallet_contracts_rpc::{Contracts, ContractsApi};
use pallet_mmr_rpc::{MmrApi, Mmr}; use pallet_mmr_rpc::{Mmr, MmrApi};
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
use substrate_frame_rpc_system::{FullSystem, SystemApi};
let mut io = jsonrpc_core::IoHandler::default(); let mut io = jsonrpc_core::IoHandler::default();
let FullDeps { let FullDeps { client, pool, select_chain, chain_spec, deny_unsafe, babe, grandpa } = deps;
client,
pool,
select_chain,
chain_spec,
deny_unsafe,
babe,
grandpa,
} = deps;
let BabeDeps { let BabeDeps { keystore, babe_config, shared_epoch_changes } = babe;
keystore,
babe_config,
shared_epoch_changes,
} = babe;
let GrandpaDeps { let GrandpaDeps {
shared_voter_state, shared_voter_state,
shared_authority_set, shared_authority_set,
@@ -154,64 +148,45 @@ pub fn create_full<C, P, SC, B>(
finality_provider, finality_provider,
} = grandpa; } = grandpa;
io.extend_with( io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe)));
SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))
);
// Making synchronous calls in light client freezes the browser currently, // Making synchronous calls in light client freezes the browser currently,
// more context: https://github.com/paritytech/substrate/pull/3480 // more context: https://github.com/paritytech/substrate/pull/3480
// These RPCs should use an asynchronous caller instead. // These RPCs should use an asynchronous caller instead.
io.extend_with( io.extend_with(ContractsApi::to_delegate(Contracts::new(client.clone())));
ContractsApi::to_delegate(Contracts::new(client.clone())) io.extend_with(MmrApi::to_delegate(Mmr::new(client.clone())));
); io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone())));
io.extend_with( io.extend_with(sc_consensus_babe_rpc::BabeApi::to_delegate(BabeRpcHandler::new(
MmrApi::to_delegate(Mmr::new(client.clone())) client.clone(),
); shared_epoch_changes.clone(),
io.extend_with( keystore,
TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone())) babe_config,
); select_chain,
io.extend_with( deny_unsafe,
sc_consensus_babe_rpc::BabeApi::to_delegate( )));
BabeRpcHandler::new( io.extend_with(sc_finality_grandpa_rpc::GrandpaApi::to_delegate(GrandpaRpcHandler::new(
client.clone(), shared_authority_set.clone(),
shared_epoch_changes.clone(), shared_voter_state,
keystore, justification_stream,
babe_config, subscription_executor,
select_chain, finality_provider,
deny_unsafe, )));
),
)
);
io.extend_with(
sc_finality_grandpa_rpc::GrandpaApi::to_delegate(
GrandpaRpcHandler::new(
shared_authority_set.clone(),
shared_voter_state,
justification_stream,
subscription_executor,
finality_provider,
)
)
);
io.extend_with( io.extend_with(sc_sync_state_rpc::SyncStateRpcApi::to_delegate(
sc_sync_state_rpc::SyncStateRpcApi::to_delegate( sc_sync_state_rpc::SyncStateRpcHandler::new(
sc_sync_state_rpc::SyncStateRpcHandler::new( chain_spec,
chain_spec, client,
client, shared_authority_set,
shared_authority_set, shared_epoch_changes,
shared_epoch_changes, deny_unsafe,
deny_unsafe, ),
) ));
)
);
io io
} }
/// Instantiate all Light RPC extensions. /// Instantiate all Light RPC extensions.
pub fn create_light<C, P, M, F>( pub fn create_light<C, P, M, F>(deps: LightDeps<C, F, P>) -> jsonrpc_core::IoHandler<M>
deps: LightDeps<C, F, P>, where
) -> jsonrpc_core::IoHandler<M> where
C: sp_blockchain::HeaderBackend<Block>, C: sp_blockchain::HeaderBackend<Block>,
C: Send + Sync + 'static, C: Send + Sync + 'static,
F: sc_client_api::light::Fetcher<Block> + 'static, F: sc_client_api::light::Fetcher<Block> + 'static,
@@ -220,16 +195,14 @@ pub fn create_light<C, P, M, F>(
{ {
use substrate_frame_rpc_system::{LightSystem, SystemApi}; use substrate_frame_rpc_system::{LightSystem, SystemApi};
let LightDeps { let LightDeps { client, pool, remote_blockchain, fetcher } = deps;
client,
pool,
remote_blockchain,
fetcher
} = deps;
let mut io = jsonrpc_core::IoHandler::default(); let mut io = jsonrpc_core::IoHandler::default();
io.extend_with( io.extend_with(SystemApi::<Hash, AccountId, Index>::to_delegate(LightSystem::new(
SystemApi::<Hash, AccountId, Index>::to_delegate(LightSystem::new(client, remote_blockchain, fetcher, pool)) client,
); remote_blockchain,
fetcher,
pool,
)));
io io
} }
+2 -2
View File
@@ -22,7 +22,7 @@ pub mod currency {
use node_primitives::Balance; use node_primitives::Balance;
pub const MILLICENTS: Balance = 1_000_000_000; pub const MILLICENTS: Balance = 1_000_000_000;
pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent. pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent.
pub const DOLLARS: Balance = 100 * CENTS; pub const DOLLARS: Balance = 100 * CENTS;
pub const fn deposit(items: u32, bytes: u32) -> Balance { pub const fn deposit(items: u32, bytes: u32) -> Balance {
@@ -32,7 +32,7 @@ pub mod currency {
/// Time. /// Time.
pub mod time { pub mod time {
use node_primitives::{Moment, BlockNumber}; use node_primitives::{BlockNumber, Moment};
/// Since BABE is probabilistic this is the average expected block time that /// Since BABE is probabilistic this is the average expected block time that
/// we are targeting. Blocks will be produced at a minimum duration defined /// we are targeting. Blocks will be produced at a minimum duration defined
+44 -35
View File
@@ -17,8 +17,8 @@
//! Some configurable implementations as associated type for the substrate runtime. //! Some configurable implementations as associated type for the substrate runtime.
use frame_support::traits::{OnUnbalanced, Currency}; use crate::{Authorship, Balances, NegativeImbalance};
use crate::{Balances, Authorship, NegativeImbalance}; use frame_support::traits::{Currency, OnUnbalanced};
pub struct Author; pub struct Author;
impl OnUnbalanced<NegativeImbalance> for Author { impl OnUnbalanced<NegativeImbalance> for Author {
@@ -29,19 +29,24 @@ impl OnUnbalanced<NegativeImbalance> for Author {
#[cfg(test)] #[cfg(test)]
mod multiplier_tests { mod multiplier_tests {
use sp_runtime::{assert_eq_error_rate, FixedPointNumber, traits::{Convert, One, Zero}};
use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment};
use sp_runtime::{
assert_eq_error_rate,
traits::{Convert, One, Zero},
FixedPointNumber,
};
use crate::{ use crate::{
constants::{currency::*, time::*}, constants::{currency::*, time::*},
TransactionPayment, Runtime, TargetBlockFullness, AdjustmentVariable, MinimumMultiplier, Runtime, RuntimeBlockWeights as BlockWeights,
AdjustmentVariable, System, MinimumMultiplier, System, TargetBlockFullness, TransactionPayment,
RuntimeBlockWeights as BlockWeights,
}; };
use frame_support::weights::{Weight, WeightToFeePolynomial, DispatchClass}; use frame_support::weights::{DispatchClass, Weight, WeightToFeePolynomial};
fn max_normal() -> Weight { fn max_normal() -> Weight {
BlockWeights::get().get(DispatchClass::Normal).max_total BlockWeights::get()
.get(DispatchClass::Normal)
.max_total
.unwrap_or_else(|| BlockWeights::get().max_block) .unwrap_or_else(|| BlockWeights::get().max_block)
} }
@@ -64,7 +69,7 @@ mod multiplier_tests {
} }
// update based on reference impl. // update based on reference impl.
fn truth_value_update(block_weight: Weight, previous: Multiplier) -> Multiplier { fn truth_value_update(block_weight: Weight, previous: Multiplier) -> Multiplier {
let accuracy = Multiplier::accuracy() as f64; let accuracy = Multiplier::accuracy() as f64;
let previous_float = previous.into_inner() as f64 / accuracy; let previous_float = previous.into_inner() as f64 / accuracy;
// bump if it is zero. // bump if it is zero.
@@ -81,15 +86,20 @@ mod multiplier_tests {
// Current saturation in terms of weight // Current saturation in terms of weight
let s = block_weight; let s = block_weight;
let t1 = v * (s/m - ss/m); let t1 = v * (s / m - ss / m);
let t2 = v.powi(2) * (s/m - ss/m).powi(2) / 2.0; let t2 = v.powi(2) * (s / m - ss / m).powi(2) / 2.0;
let next_float = previous_float * (1.0 + t1 + t2); let next_float = previous_float * (1.0 + t1 + t2);
Multiplier::from_float(next_float) Multiplier::from_float(next_float)
} }
fn run_with_system_weight<F>(w: Weight, assertions: F) where F: Fn() -> () { fn run_with_system_weight<F>(w: Weight, assertions: F)
let mut t: sp_io::TestExternalities = where
frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap().into(); F: Fn() -> (),
{
let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default()
.build_storage::<Runtime>()
.unwrap()
.into();
t.execute_with(|| { t.execute_with(|| {
System::set_block_consumed_resources(w, 0); System::set_block_consumed_resources(w, 0);
assertions() assertions()
@@ -157,7 +167,9 @@ mod multiplier_tests {
loop { loop {
let next = runtime_multiplier_update(fm); let next = runtime_multiplier_update(fm);
fm = next; fm = next;
if fm == min_multiplier() { break; } if fm == min_multiplier() {
break
}
iterations += 1; iterations += 1;
} }
assert!(iterations > 533_333); assert!(iterations > 533_333);
@@ -198,7 +210,9 @@ mod multiplier_tests {
loop { loop {
let next = runtime_multiplier_update(fm); let next = runtime_multiplier_update(fm);
// if no change, panic. This should never happen in this case. // if no change, panic. This should never happen in this case.
if fm == next { panic!("The fee should ever increase"); } if fm == next {
panic!("The fee should ever increase");
}
fm = next; fm = next;
iterations += 1; iterations += 1;
let fee = let fee =
@@ -225,7 +239,7 @@ mod multiplier_tests {
let next = runtime_multiplier_update(fm); let next = runtime_multiplier_update(fm);
assert_eq_error_rate!( assert_eq_error_rate!(
next, next,
truth_value_update(target() / 4 , fm), truth_value_update(target() / 4, fm),
Multiplier::from_inner(100), Multiplier::from_inner(100),
); );
@@ -237,12 +251,11 @@ mod multiplier_tests {
let next = runtime_multiplier_update(fm); let next = runtime_multiplier_update(fm);
assert_eq_error_rate!( assert_eq_error_rate!(
next, next,
truth_value_update(target() / 2 , fm), truth_value_update(target() / 2, fm),
Multiplier::from_inner(100), Multiplier::from_inner(100),
); );
// Light block. Multiplier is reduced a little. // Light block. Multiplier is reduced a little.
assert!(next < fm); assert!(next < fm);
}); });
run_with_system_weight(target(), || { run_with_system_weight(target(), || {
let next = runtime_multiplier_update(fm); let next = runtime_multiplier_update(fm);
@@ -259,7 +272,7 @@ mod multiplier_tests {
let next = runtime_multiplier_update(fm); let next = runtime_multiplier_update(fm);
assert_eq_error_rate!( assert_eq_error_rate!(
next, next,
truth_value_update(target() * 2 , fm), truth_value_update(target() * 2, fm),
Multiplier::from_inner(100), Multiplier::from_inner(100),
); );
@@ -326,28 +339,24 @@ mod multiplier_tests {
BlockWeights::get().max_block, BlockWeights::get().max_block,
Weight::max_value() / 2, Weight::max_value() / 2,
Weight::max_value(), Weight::max_value(),
].into_iter().for_each(|i| { ]
.into_iter()
.for_each(|i| {
run_with_system_weight(i, || { run_with_system_weight(i, || {
let next = runtime_multiplier_update(Multiplier::one()); let next = runtime_multiplier_update(Multiplier::one());
let truth = truth_value_update(i, Multiplier::one()); let truth = truth_value_update(i, Multiplier::one());
assert_eq_error_rate!( assert_eq_error_rate!(truth, next, Multiplier::from_inner(50_000_000));
truth,
next,
Multiplier::from_inner(50_000_000)
);
}); });
}); });
// Some values that are all above the target and will cause an increase. // Some values that are all above the target and will cause an increase.
let t = target(); let t = target();
vec![t + 100, t * 2, t * 4] vec![t + 100, t * 2, t * 4].into_iter().for_each(|i| {
.into_iter() run_with_system_weight(i, || {
.for_each(|i| { let fm = runtime_multiplier_update(max_fm);
run_with_system_weight(i, || { // won't grow. The convert saturates everything.
let fm = runtime_multiplier_update(max_fm); assert_eq!(fm, max_fm);
// won't grow. The convert saturates everything. })
assert_eq!(fm, max_fm); });
})
});
} }
} }
+100 -93
View File
@@ -22,67 +22,67 @@
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit = "256"] #![recursion_limit = "256"]
use codec::{Decode, Encode, MaxEncodedLen};
use sp_std::prelude::*;
use frame_support::{ use frame_support::{
construct_runtime, parameter_types, RuntimeDebug, construct_runtime, parameter_types,
weights::{
Weight, IdentityFee,
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
DispatchClass,
},
traits::{ traits::{
Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, LockIdentifier, AllowAll, Currency, DenyAll, Imbalance, InstanceFilter, KeyOwnerProofSystem,
U128CurrencyToVote, AllowAll, DenyAll, LockIdentifier, OnUnbalanced, U128CurrencyToVote,
}, },
weights::{
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
DispatchClass, IdentityFee, Weight,
},
PalletId, RuntimeDebug,
}; };
use frame_system::{ use frame_system::{
EnsureRoot, EnsureOneOf, limits::{BlockLength, BlockWeights},
limits::{BlockWeights, BlockLength} EnsureOneOf, EnsureRoot,
}; };
use frame_support::{traits::InstanceFilter, PalletId}; pub use node_primitives::{AccountId, Signature};
use codec::{Encode, Decode, MaxEncodedLen}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment};
use pallet_contracts::weights::WeightInfo;
use pallet_election_provider_multi_phase::FallbackStrategy;
use pallet_grandpa::{
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
};
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use pallet_session::historical as pallet_session_historical;
pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment};
use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
use sp_api::impl_runtime_apis;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use sp_core::{ use sp_core::{
crypto::KeyTypeId, crypto::KeyTypeId,
u32_trait::{_1, _2, _3, _4, _5}, u32_trait::{_1, _2, _3, _4, _5},
OpaqueMetadata, OpaqueMetadata,
}; };
pub use node_primitives::{AccountId, Signature}; use sp_inherents::{CheckInherentsResult, InherentData};
use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment};
use sp_api::impl_runtime_apis;
use sp_runtime::{ use sp_runtime::{
Permill, Perbill, Perquintill, Percent, ApplyExtrinsicResult, impl_opaque_keys, generic, create_runtime_str,
create_runtime_str, FixedPointNumber, curve::PiecewiseLinear,
generic, impl_opaque_keys,
traits::{
self, BlakeTwo256, Block as BlockT, ConvertInto, NumberFor, OpaqueKeys,
SaturatedConversion, StaticLookup,
},
transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity},
ApplyExtrinsicResult, FixedPointNumber, Perbill, Percent, Permill, Perquintill,
}; };
use sp_runtime::curve::PiecewiseLinear; use sp_std::prelude::*;
use sp_runtime::transaction_validity::{TransactionValidity, TransactionSource, TransactionPriority};
use sp_runtime::traits::{
self, BlakeTwo256, Block as BlockT, StaticLookup, SaturatedConversion, ConvertInto, OpaqueKeys,
NumberFor,
};
use sp_version::RuntimeVersion;
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
use sp_version::NativeVersion; use sp_version::NativeVersion;
use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; use sp_version::RuntimeVersion;
use pallet_grandpa::fg_primitives;
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
pub use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment, CurrencyAdapter};
use pallet_session::{historical as pallet_session_historical};
use sp_inherents::{InherentData, CheckInherentsResult};
use static_assertions::const_assert; use static_assertions::const_assert;
use pallet_contracts::weights::WeightInfo;
use pallet_election_provider_multi_phase::FallbackStrategy;
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
#[cfg(any(feature = "std", test))]
pub use pallet_balances::Call as BalancesCall;
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
pub use frame_system::Call as SystemCall; pub use frame_system::Call as SystemCall;
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
pub use pallet_balances::Call as BalancesCall;
#[cfg(any(feature = "std", test))]
pub use pallet_staking::StakerStatus; pub use pallet_staking::StakerStatus;
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
/// Implementations of some helper traits passed into runtime modules as associated types. /// Implementations of some helper traits passed into runtime modules as associated types.
pub mod impls; pub mod impls;
@@ -90,7 +90,7 @@ use impls::Author;
/// Constant values used within the runtime. /// Constant values used within the runtime.
pub mod constants; pub mod constants;
use constants::{time::*, currency::*}; use constants::{currency::*, time::*};
use sp_runtime::generic::Era; use sp_runtime::generic::Era;
// Make the WASM binary available. // Make the WASM binary available.
@@ -100,9 +100,11 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
/// Wasm binary unwrapped. If built with `SKIP_WASM_BUILD`, the function panics. /// Wasm binary unwrapped. If built with `SKIP_WASM_BUILD`, the function panics.
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn wasm_binary_unwrap() -> &'static [u8] { pub fn wasm_binary_unwrap() -> &'static [u8] {
WASM_BINARY.expect("Development wasm binary is not available. This means the client is \ WASM_BINARY.expect(
"Development wasm binary is not available. This means the client is \
built with `SKIP_WASM_BUILD` flag and it is only usable for \ built with `SKIP_WASM_BUILD` flag and it is only usable for \
production chains. Please rebuild with the flag disabled.") production chains. Please rebuild with the flag disabled.",
)
} }
/// Runtime version. /// Runtime version.
@@ -125,23 +127,20 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration = pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration =
sp_consensus_babe::BabeEpochConfiguration { sp_consensus_babe::BabeEpochConfiguration {
c: PRIMARY_PROBABILITY, c: PRIMARY_PROBABILITY,
allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots,
}; };
/// Native version. /// Native version.
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
pub fn native_version() -> NativeVersion { pub fn native_version() -> NativeVersion {
NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
runtime_version: VERSION,
can_author_with: Default::default(),
}
} }
type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance; type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
pub struct DealWithFees; pub struct DealWithFees;
impl OnUnbalanced<NegativeImbalance> for DealWithFees { impl OnUnbalanced<NegativeImbalance> for DealWithFees {
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item=NegativeImbalance>) { fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
if let Some(fees) = fees_then_tips.next() { if let Some(fees) = fees_then_tips.next() {
// for fees, 80% to treasury, 20% to author // for fees, 80% to treasury, 20% to author
let mut split = fees.ration(80, 20); let mut split = fees.ration(80, 20);
@@ -256,14 +255,20 @@ parameter_types! {
} }
/// The type used to represent the kinds of proxying allowed. /// The type used to represent the kinds of proxying allowed.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, MaxEncodedLen)] #[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, MaxEncodedLen,
)]
pub enum ProxyType { pub enum ProxyType {
Any, Any,
NonTransfer, NonTransfer,
Governance, Governance,
Staking, Staking,
} }
impl Default for ProxyType { fn default() -> Self { Self::Any } } impl Default for ProxyType {
fn default() -> Self {
Self::Any
}
}
impl InstanceFilter<Call> for ProxyType { impl InstanceFilter<Call> for ProxyType {
fn filter(&self, c: &Call) -> bool { fn filter(&self, c: &Call) -> bool {
match self { match self {
@@ -271,19 +276,16 @@ impl InstanceFilter<Call> for ProxyType {
ProxyType::NonTransfer => !matches!( ProxyType::NonTransfer => !matches!(
c, c,
Call::Balances(..) | Call::Balances(..) |
Call::Assets(..) | Call::Assets(..) | Call::Uniques(..) |
Call::Uniques(..) | Call::Vesting(pallet_vesting::Call::vested_transfer(..)) |
Call::Vesting(pallet_vesting::Call::vested_transfer(..)) | Call::Indices(pallet_indices::Call::transfer(..))
Call::Indices(pallet_indices::Call::transfer(..))
), ),
ProxyType::Governance => matches!( ProxyType::Governance => matches!(
c, c,
Call::Democracy(..) | Call::Democracy(..) |
Call::Council(..) | Call::Council(..) | Call::Society(..) |
Call::Society(..) | Call::TechnicalCommittee(..) |
Call::TechnicalCommittee(..) | Call::Elections(..) | Call::Treasury(..)
Call::Elections(..) |
Call::Treasury(..)
), ),
ProxyType::Staking => matches!(c, Call::Staking(..)), ProxyType::Staking => matches!(c, Call::Staking(..)),
} }
@@ -500,15 +502,16 @@ impl pallet_staking::Config for Runtime {
type SlashCancelOrigin = EnsureOneOf< type SlashCancelOrigin = EnsureOneOf<
AccountId, AccountId,
EnsureRoot<AccountId>, EnsureRoot<AccountId>,
pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective> pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>,
>; >;
type SessionInterface = Self; type SessionInterface = Self;
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>; type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
type NextNewSession = Session; type NextNewSession = Session;
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type ElectionProvider = ElectionProviderMultiPhase; type ElectionProvider = ElectionProviderMultiPhase;
type GenesisElectionProvider = type GenesisElectionProvider = onchain::OnChainSequentialPhragmen<
onchain::OnChainSequentialPhragmen<pallet_election_provider_multi_phase::OnChainConfig<Self>>; pallet_election_provider_multi_phase::OnChainConfig<Self>,
>;
type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>; type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
} }
@@ -618,20 +621,26 @@ impl pallet_democracy::Config for Runtime {
type VotingPeriod = VotingPeriod; type VotingPeriod = VotingPeriod;
type MinimumDeposit = MinimumDeposit; type MinimumDeposit = MinimumDeposit;
/// A straight majority of the council can decide what their next motion is. /// A straight majority of the council can decide what their next motion is.
type ExternalOrigin = pallet_collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilCollective>; type ExternalOrigin =
pallet_collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilCollective>;
/// A super-majority can have the next scheduled referendum be a straight majority-carries vote. /// A super-majority can have the next scheduled referendum be a straight majority-carries vote.
type ExternalMajorityOrigin = pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>; type ExternalMajorityOrigin =
pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>;
/// A unanimous council can have the next scheduled referendum be a straight default-carries /// A unanimous council can have the next scheduled referendum be a straight default-carries
/// (NTB) vote. /// (NTB) vote.
type ExternalDefaultOrigin = pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, CouncilCollective>; type ExternalDefaultOrigin =
pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, CouncilCollective>;
/// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote /// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote
/// be tabled immediately and with a shorter voting/enactment period. /// be tabled immediately and with a shorter voting/enactment period.
type FastTrackOrigin = pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalCollective>; type FastTrackOrigin =
type InstantOrigin = pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, TechnicalCollective>; pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalCollective>;
type InstantOrigin =
pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, TechnicalCollective>;
type InstantAllowed = InstantAllowed; type InstantAllowed = InstantAllowed;
type FastTrackVotingPeriod = FastTrackVotingPeriod; type FastTrackVotingPeriod = FastTrackVotingPeriod;
// To cancel a proposal which has been passed, 2/3 of the council must agree to it. // 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>; type CancellationOrigin =
pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilCollective>;
// To cancel a proposal before it has been passed, the technical committee must be unanimous or // To cancel a proposal before it has been passed, the technical committee must be unanimous or
// Root must agree. // Root must agree.
type CancelProposalOrigin = EnsureOneOf< type CancelProposalOrigin = EnsureOneOf<
@@ -728,7 +737,7 @@ impl pallet_collective::Config<TechnicalCollective> for Runtime {
type EnsureRootOrHalfCouncil = EnsureOneOf< type EnsureRootOrHalfCouncil = EnsureOneOf<
AccountId, AccountId,
EnsureRoot<AccountId>, EnsureRoot<AccountId>,
pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective> pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>,
>; >;
impl pallet_membership::Config<pallet_membership::Instance1> for Runtime { impl pallet_membership::Config<pallet_membership::Instance1> for Runtime {
type Event = Event; type Event = Event;
@@ -768,12 +777,12 @@ impl pallet_treasury::Config for Runtime {
type ApproveOrigin = EnsureOneOf< type ApproveOrigin = EnsureOneOf<
AccountId, AccountId,
EnsureRoot<AccountId>, EnsureRoot<AccountId>,
pallet_collective::EnsureProportionAtLeast<_3, _5, AccountId, CouncilCollective> pallet_collective::EnsureProportionAtLeast<_3, _5, AccountId, CouncilCollective>,
>; >;
type RejectOrigin = EnsureOneOf< type RejectOrigin = EnsureOneOf<
AccountId, AccountId,
EnsureRoot<AccountId>, EnsureRoot<AccountId>,
pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective> pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>,
>; >;
type Event = Event; type Event = Event;
type OnSlash = (); type OnSlash = ();
@@ -876,8 +885,8 @@ parameter_types! {
} }
impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
where where
Call: From<LocalCall>, Call: From<LocalCall>,
{ {
fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>( fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
call: Call, call: Call,
@@ -887,10 +896,8 @@ impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for R
) -> Option<(Call, <UncheckedExtrinsic as traits::Extrinsic>::SignaturePayload)> { ) -> Option<(Call, <UncheckedExtrinsic as traits::Extrinsic>::SignaturePayload)> {
let tip = 0; let tip = 0;
// take the biggest period possible. // take the biggest period possible.
let period = BlockHashCount::get() let period =
.checked_next_power_of_two() BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64;
.map(|c| c / 2)
.unwrap_or(2) as u64;
let current_block = System::block_number() let current_block = System::block_number()
.saturated_into::<u64>() .saturated_into::<u64>()
// The `System::block_number` is initialized with `n+1`, // The `System::block_number` is initialized with `n+1`,
@@ -911,10 +918,7 @@ impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for R
log::warn!("Unable to create signed payload: {:?}", e); log::warn!("Unable to create signed payload: {:?}", e);
}) })
.ok()?; .ok()?;
let signature = raw_payload let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?;
.using_encoded(|payload| {
C::sign(payload, public)
})?;
let address = Indices::unlookup(account); let address = Indices::unlookup(account);
let (call, extra, _) = raw_payload.deconstruct(); let (call, extra, _) = raw_payload.deconstruct();
Some((call, (address, signature.into(), extra))) Some((call, (address, signature.into(), extra)))
@@ -926,7 +930,8 @@ impl frame_system::offchain::SigningTypes for Runtime {
type Signature = Signature; type Signature = Signature;
} }
impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime where impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime
where
Call: From<C>, Call: From<C>,
{ {
type Extrinsic = UncheckedExtrinsic; type Extrinsic = UncheckedExtrinsic;
@@ -965,8 +970,11 @@ impl pallet_grandpa::Config for Runtime {
GrandpaId, GrandpaId,
)>>::IdentificationTuple; )>>::IdentificationTuple;
type HandleEquivocation = type HandleEquivocation = pallet_grandpa::EquivocationHandler<
pallet_grandpa::EquivocationHandler<Self::KeyOwnerIdentification, Offences, ReportLongevity>; Self::KeyOwnerIdentification,
Offences,
ReportLongevity,
>;
type WeightInfo = (); type WeightInfo = ();
} }
@@ -1036,7 +1044,8 @@ impl pallet_society::Config for Runtime {
type MembershipChanged = (); type MembershipChanged = ();
type RotationPeriod = RotationPeriod; type RotationPeriod = RotationPeriod;
type MaxLockDuration = MaxLockDuration; type MaxLockDuration = MaxLockDuration;
type FounderSetOrigin = pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; type FounderSetOrigin =
pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>;
type SuspensionJudgementOrigin = pallet_society::EnsureFounder<Runtime>; type SuspensionJudgementOrigin = pallet_society::EnsureFounder<Runtime>;
type MaxCandidateIntake = MaxCandidateIntake; type MaxCandidateIntake = MaxCandidateIntake;
type ChallengePeriod = ChallengePeriod; type ChallengePeriod = ChallengePeriod;
@@ -1261,11 +1270,7 @@ mod mmr {
use super::Runtime; use super::Runtime;
pub use pallet_mmr::primitives::*; pub use pallet_mmr::primitives::*;
pub type Leaf = < pub type Leaf = <<Runtime as pallet_mmr::Config>::LeafData as LeafDataProvider>::LeafData;
<Runtime as pallet_mmr::Config>::LeafData
as
LeafDataProvider
>::LeafData;
pub type Hash = <Runtime as pallet_mmr::Config>::Hash; pub type Hash = <Runtime as pallet_mmr::Config>::Hash;
pub type Hashing = <Runtime as pallet_mmr::Config>::Hashing; pub type Hashing = <Runtime as pallet_mmr::Config>::Hashing;
} }
@@ -1613,9 +1618,11 @@ mod tests {
#[test] #[test]
fn validate_transaction_submitter_bounds() { fn validate_transaction_submitter_bounds() {
fn is_submit_signed_transaction<T>() where fn is_submit_signed_transaction<T>()
where
T: CreateSignedTransaction<Call>, T: CreateSignedTransaction<Call>,
{} {
}
is_submit_signed_transaction::<Runtime>(); is_submit_signed_transaction::<Runtime>();
} }
@@ -19,12 +19,12 @@
//! Basic example of end to end runtime tests. //! Basic example of end to end runtime tests.
use test_runner::{ChainInfo, SignatureVerificationOverride};
use grandpa::GrandpaBlockImport; use grandpa::GrandpaBlockImport;
use sc_service::{TFullBackend, TFullClient};
use sc_consensus_babe::BabeBlockImport; use sc_consensus_babe::BabeBlockImport;
use sc_consensus_manual_seal::consensus::babe::SlotTimestampProvider; use sc_consensus_manual_seal::consensus::babe::SlotTimestampProvider;
use sc_service::{TFullBackend, TFullClient};
use sp_runtime::generic::Era; use sp_runtime::generic::Era;
use test_runner::{ChainInfo, SignatureVerificationOverride};
type BlockImport<B, BE, C, SC> = BabeBlockImport<B, C, GrandpaBlockImport<BE, B, C, SC>>; type BlockImport<B, BE, C, SC> = BabeBlockImport<B, C, GrandpaBlockImport<BE, B, C, SC>>;
@@ -54,15 +54,20 @@ impl ChainInfo for NodeTemplateChainInfo {
Self::SelectChain, Self::SelectChain,
>; >;
type SignedExtras = node_runtime::SignedExtra; type SignedExtras = node_runtime::SignedExtra;
type InherentDataProviders = (SlotTimestampProvider, sp_consensus_babe::inherents::InherentDataProvider); type InherentDataProviders =
(SlotTimestampProvider, sp_consensus_babe::inherents::InherentDataProvider);
fn signed_extras(from: <Self::Runtime as frame_system::Config>::AccountId) -> Self::SignedExtras { fn signed_extras(
from: <Self::Runtime as frame_system::Config>::AccountId,
) -> Self::SignedExtras {
( (
frame_system::CheckSpecVersion::<Self::Runtime>::new(), frame_system::CheckSpecVersion::<Self::Runtime>::new(),
frame_system::CheckTxVersion::<Self::Runtime>::new(), frame_system::CheckTxVersion::<Self::Runtime>::new(),
frame_system::CheckGenesis::<Self::Runtime>::new(), frame_system::CheckGenesis::<Self::Runtime>::new(),
frame_system::CheckMortality::<Self::Runtime>::from(Era::Immortal), frame_system::CheckMortality::<Self::Runtime>::from(Era::Immortal),
frame_system::CheckNonce::<Self::Runtime>::from(frame_system::Pallet::<Self::Runtime>::account_nonce(from)), frame_system::CheckNonce::<Self::Runtime>::from(
frame_system::Pallet::<Self::Runtime>::account_nonce(from),
),
frame_system::CheckWeight::<Self::Runtime>::new(), frame_system::CheckWeight::<Self::Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<Self::Runtime>::from(0), pallet_transaction_payment::ChargeTransactionPayment::<Self::Runtime>::from(0),
) )
@@ -72,32 +77,43 @@ impl ChainInfo for NodeTemplateChainInfo {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use test_runner::{Node, client_parts, ConfigOrChainSpec, build_runtime, task_executor};
use sp_keyring::sr25519::Keyring::Alice;
use node_cli::chain_spec::development_config; use node_cli::chain_spec::development_config;
use sp_keyring::sr25519::Keyring::Alice;
use sp_runtime::{traits::IdentifyAccount, MultiSigner}; use sp_runtime::{traits::IdentifyAccount, MultiSigner};
use test_runner::{build_runtime, client_parts, task_executor, ConfigOrChainSpec, Node};
#[test] #[test]
fn test_runner() { fn test_runner() {
let mut tokio_runtime = build_runtime().unwrap(); let mut tokio_runtime = build_runtime().unwrap();
let task_executor = task_executor(tokio_runtime.handle().clone()); let task_executor = task_executor(tokio_runtime.handle().clone());
let (rpc, task_manager, client, pool, command_sink, backend) = let (rpc, task_manager, client, pool, command_sink, backend) = client_parts::<
client_parts::<NodeTemplateChainInfo>( NodeTemplateChainInfo,
ConfigOrChainSpec::ChainSpec(Box::new(development_config()), task_executor) >(
).unwrap(); ConfigOrChainSpec::ChainSpec(Box::new(development_config()), task_executor),
let node = Node::<NodeTemplateChainInfo>::new(rpc, task_manager, client, pool, command_sink, backend); )
.unwrap();
let node = Node::<NodeTemplateChainInfo>::new(
rpc,
task_manager,
client,
pool,
command_sink,
backend,
);
tokio_runtime.block_on(async { tokio_runtime.block_on(async {
// seals blocks // seals blocks
node.seal_blocks(1).await; node.seal_blocks(1).await;
// submit extrinsics // submit extrinsics
let alice = MultiSigner::from(Alice.public()).into_account(); let alice = MultiSigner::from(Alice.public()).into_account();
let _hash = node.submit_extrinsic(frame_system::Call::remark((b"hello world").to_vec()), alice) let _hash = node
.submit_extrinsic(frame_system::Call::remark((b"hello world").to_vec()), alice)
.await .await
.unwrap(); .unwrap();
// look ma, I can read state. // look ma, I can read state.
let _events = node.with_state(|| frame_system::Pallet::<node_runtime::Runtime>::events()); let _events =
node.with_state(|| frame_system::Pallet::<node_runtime::Runtime>::events());
// get access to the underlying client. // get access to the underlying client.
let _client = node.client(); let _client = node.client();
}) })
+122 -148
View File
@@ -22,44 +22,42 @@
//! can pregenerate seed database and `clone` it for every iteration of your benchmarks //! can pregenerate seed database and `clone` it for every iteration of your benchmarks
//! or tests to get consistent, smooth benchmark experience! //! or tests to get consistent, smooth benchmark experience!
use std::{sync::Arc, path::{Path, PathBuf}, collections::BTreeMap}; use std::{
collections::BTreeMap,
use node_primitives::Block; path::{Path, PathBuf},
use crate::client::{Client, Backend}; sync::Arc,
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, use crate::{
OpaqueExtrinsic, client::{Backend, Client},
traits::{Block as BlockT, Verify, Zero, IdentifyAccount}, keyring::*,
}; };
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use futures::executor;
use node_primitives::Block;
use node_runtime::{ use node_runtime::{
Call, constants::currency::DOLLARS, AccountId, BalancesCall, Call, CheckedExtrinsic, MinimumPeriod,
CheckedExtrinsic, Signature, SystemCall, UncheckedExtrinsic,
constants::currency::DOLLARS,
UncheckedExtrinsic,
MinimumPeriod,
SystemCall,
BalancesCall,
AccountId,
Signature,
};
use sp_core::{ExecutionContext, blake2_256, traits::SpawnNamed, Pair, Public, sr25519, ed25519};
use sp_api::ProvideRuntimeApi;
use sp_block_builder::BlockBuilder;
use sp_inherents::InherentData;
use sc_client_api::{
ExecutionStrategy, BlockBackend,
execution_extensions::{ExecutionExtensions, ExecutionStrategies},
}; };
use sc_block_builder::BlockBuilderProvider; use sc_block_builder::BlockBuilderProvider;
use futures::executor; use sc_client_api::{
execution_extensions::{ExecutionExtensions, ExecutionStrategies},
BlockBackend, ExecutionStrategy,
};
use sc_client_db::PruningMode;
use sc_executor::{NativeExecutor, WasmExecutionMethod};
use sp_api::ProvideRuntimeApi;
use sp_block_builder::BlockBuilder;
use sp_consensus::{
BlockImport, BlockImportParams, BlockOrigin, ForkChoiceStrategy, ImportResult, ImportedAux,
};
use sp_core::{blake2_256, ed25519, sr25519, traits::SpawnNamed, ExecutionContext, Pair, Public};
use sp_inherents::InherentData;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, IdentifyAccount, Verify, Zero},
OpaqueExtrinsic,
};
/// Keyring full of accounts for benching. /// Keyring full of accounts for benching.
/// ///
@@ -92,19 +90,21 @@ impl BenchPair {
/// ///
/// Will panic if cache drop is impossbile. /// Will panic if cache drop is impossbile.
pub fn drop_system_cache() { pub fn drop_system_cache() {
#[cfg(target_os = "windows")] { #[cfg(target_os = "windows")]
{
log::warn!( log::warn!(
target: "bench-logistics", target: "bench-logistics",
"Clearing system cache on windows is not supported. Benchmark might totally be wrong.", "Clearing system cache on windows is not supported. Benchmark might totally be wrong.",
); );
return; return
} }
std::process::Command::new("sync") std::process::Command::new("sync")
.output() .output()
.expect("Failed to execute system cache clear"); .expect("Failed to execute system cache clear");
#[cfg(target_os = "linux")] { #[cfg(target_os = "linux")]
{
log::trace!(target: "bench-logistics", "Clearing system cache..."); log::trace!(target: "bench-logistics", "Clearing system cache...");
std::process::Command::new("echo") std::process::Command::new("echo")
.args(&["3", ">", "/proc/sys/vm/drop_caches", "2>", "/dev/null"]) .args(&["3", ">", "/proc/sys/vm/drop_caches", "2>", "/dev/null"])
@@ -133,7 +133,8 @@ pub fn drop_system_cache() {
log::trace!(target: "bench-logistics", "Clearing system cache done!"); log::trace!(target: "bench-logistics", "Clearing system cache done!");
} }
#[cfg(target_os = "macos")] { #[cfg(target_os = "macos")]
{
log::trace!(target: "bench-logistics", "Clearing system cache..."); log::trace!(target: "bench-logistics", "Clearing system cache...");
if let Err(err) = std::process::Command::new("purge").output() { if let Err(err) = std::process::Command::new("purge").output() {
log::error!("purge error {:?}: ", err); log::error!("purge error {:?}: ", err);
@@ -169,15 +170,10 @@ impl Clone for BenchDb {
); );
let seed_db_files = std::fs::read_dir(seed_dir) let seed_db_files = std::fs::read_dir(seed_dir)
.expect("failed to list file in seed dir") .expect("failed to list file in seed dir")
.map(|f_result| .map(|f_result| f_result.expect("failed to read file in seed db").path())
f_result.expect("failed to read file in seed db") .collect::<Vec<PathBuf>>();
.path() fs_extra::copy_items(&seed_db_files, dir.path(), &fs_extra::dir::CopyOptions::new())
).collect::<Vec<PathBuf>>(); .expect("Copy of seed database is ok");
fs_extra::copy_items(
&seed_db_files,
dir.path(),
&fs_extra::dir::CopyOptions::new(),
).expect("Copy of seed database is ok");
// We clear system cache after db clone but before any warmups. // We clear system cache after db clone but before any warmups.
// This populates system cache with some data unrelated to actual // This populates system cache with some data unrelated to actual
@@ -204,10 +200,7 @@ pub enum BlockType {
impl BlockType { impl BlockType {
/// Create block content description with specified number of transactions. /// Create block content description with specified number of transactions.
pub fn to_content(self, size: Option<usize>) -> BlockContent { pub fn to_content(self, size: Option<usize>) -> BlockContent {
BlockContent { BlockContent { block_type: self, size }
block_type: self,
size,
}
} }
} }
@@ -230,13 +223,8 @@ pub enum DatabaseType {
impl DatabaseType { impl DatabaseType {
fn into_settings(self, path: PathBuf) -> sc_client_db::DatabaseSettingsSrc { fn into_settings(self, path: PathBuf) -> sc_client_db::DatabaseSettingsSrc {
match self { match self {
Self::RocksDb => sc_client_db::DatabaseSettingsSrc::RocksDb { Self::RocksDb => sc_client_db::DatabaseSettingsSrc::RocksDb { path, cache_size: 512 },
path, Self::ParityDb => sc_client_db::DatabaseSettingsSrc::ParityDb { path },
cache_size: 512,
},
Self::ParityDb => sc_client_db::DatabaseSettingsSrc::ParityDb {
path,
}
} }
} }
} }
@@ -251,10 +239,7 @@ pub struct TaskExecutor {
impl TaskExecutor { impl TaskExecutor {
fn new() -> Self { fn new() -> Self {
Self { Self { pool: executor::ThreadPool::new().expect("Failed to create task executor") }
pool: executor::ThreadPool::new()
.expect("Failed to create task executor")
}
} }
} }
@@ -279,21 +264,17 @@ pub struct BlockContentIterator<'a> {
impl<'a> BlockContentIterator<'a> { impl<'a> BlockContentIterator<'a> {
fn new(content: BlockContent, keyring: &'a BenchKeyring, client: &Client) -> Self { fn new(content: BlockContent, keyring: &'a BenchKeyring, client: &Client) -> Self {
let runtime_version = client.runtime_version_at(&BlockId::number(0)) let runtime_version = client
.runtime_version_at(&BlockId::number(0))
.expect("There should be runtime version at 0"); .expect("There should be runtime version at 0");
let genesis_hash = client.block_hash(Zero::zero()) let genesis_hash = client
.block_hash(Zero::zero())
.expect("Database error?") .expect("Database error?")
.expect("Genesis block always exists; qed") .expect("Genesis block always exists; qed")
.into(); .into();
BlockContentIterator { BlockContentIterator { iteration: 0, content, keyring, runtime_version, genesis_hash }
iteration: 0,
content,
keyring,
runtime_version,
genesis_hash,
}
} }
} }
@@ -302,41 +283,36 @@ impl<'a> Iterator for BlockContentIterator<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.content.size.map(|size| size <= self.iteration).unwrap_or(false) { if self.content.size.map(|size| size <= self.iteration).unwrap_or(false) {
return None; return None
} }
let sender = self.keyring.at(self.iteration); let sender = self.keyring.at(self.iteration);
let receiver = get_account_id_from_seed::<sr25519::Public>( let receiver = get_account_id_from_seed::<sr25519::Public>(&format!(
&format!("random-user//{}", self.iteration) "random-user//{}",
); self.iteration
));
let signed = self.keyring.sign( let signed = self.keyring.sign(
CheckedExtrinsic { CheckedExtrinsic {
signed: Some((sender, signed_extra(0, node_runtime::ExistentialDeposit::get() + 1))), signed: Some((
sender,
signed_extra(0, node_runtime::ExistentialDeposit::get() + 1),
)),
function: match self.content.block_type { function: match self.content.block_type {
BlockType::RandomTransfersKeepAlive => { BlockType::RandomTransfersKeepAlive =>
Call::Balances( Call::Balances(BalancesCall::transfer_keep_alive(
BalancesCall::transfer_keep_alive( sp_runtime::MultiAddress::Id(receiver),
sp_runtime::MultiAddress::Id(receiver), node_runtime::ExistentialDeposit::get() + 1,
node_runtime::ExistentialDeposit::get() + 1, )),
)
)
},
BlockType::RandomTransfersReaping => { BlockType::RandomTransfersReaping => {
Call::Balances( Call::Balances(BalancesCall::transfer(
BalancesCall::transfer( sp_runtime::MultiAddress::Id(receiver),
sp_runtime::MultiAddress::Id(receiver), // Transfer so that ending balance would be 1 less than existential deposit
// Transfer so that ending balance would be 1 less than existential deposit // so that we kill the sender account.
// so that we kill the sender account. 100 * DOLLARS - (node_runtime::ExistentialDeposit::get() - 1),
100*DOLLARS - (node_runtime::ExistentialDeposit::get() - 1), ))
)
)
},
BlockType::Noop => {
Call::System(
SystemCall::remark(Vec::new())
)
}, },
BlockType::Noop => Call::System(SystemCall::remark(Vec::new())),
}, },
}, },
self.runtime_version.spec_version, self.runtime_version.spec_version,
@@ -346,8 +322,7 @@ impl<'a> Iterator for BlockContentIterator<'a> {
let encoded = Encode::encode(&signed); let encoded = Encode::encode(&signed);
let opaque = OpaqueExtrinsic::decode(&mut &encoded[..]) let opaque = OpaqueExtrinsic::decode(&mut &encoded[..]).expect("Failed to decode opaque");
.expect("Failed to decode opaque");
self.iteration += 1; self.iteration += 1;
@@ -373,12 +348,8 @@ impl BenchDb {
"Created seed db at {}", "Created seed db at {}",
dir.path().to_string_lossy(), dir.path().to_string_lossy(),
); );
let (_client, _backend, _task_executor) = Self::bench_client( let (_client, _backend, _task_executor) =
database_type, Self::bench_client(database_type, dir.path(), Profile::Native, &keyring);
dir.path(),
Profile::Native,
&keyring,
);
let directory_guard = Guard(dir); let directory_guard = Guard(dir);
BenchDb { keyring, directory_guard, database_type } BenchDb { keyring, directory_guard, database_type }
@@ -408,7 +379,7 @@ impl BenchDb {
keyring: &BenchKeyring, keyring: &BenchKeyring,
) -> (Client, std::sync::Arc<Backend>, TaskExecutor) { ) -> (Client, std::sync::Arc<Backend>, TaskExecutor) {
let db_config = sc_client_db::DatabaseSettings { let db_config = sc_client_db::DatabaseSettings {
state_cache_size: 16*1024*1024, state_cache_size: 16 * 1024 * 1024,
state_cache_child_ratio: Some((0, 100)), state_cache_child_ratio: Some((0, 100)),
state_pruning: PruningMode::ArchiveAll, state_pruning: PruningMode::ArchiveAll,
source: database_type.into_settings(dir.into()), source: database_type.into_settings(dir.into()),
@@ -429,7 +400,8 @@ impl BenchDb {
None, None,
None, None,
Default::default(), Default::default(),
).expect("Should not fail"); )
.expect("Should not fail");
(client, backend, task_executor) (client, backend, task_executor)
} }
@@ -445,12 +417,14 @@ impl BenchDb {
.put_data(sp_timestamp::INHERENT_IDENTIFIER, &timestamp) .put_data(sp_timestamp::INHERENT_IDENTIFIER, &timestamp)
.expect("Put timestamp failed"); .expect("Put timestamp failed");
client.runtime_api() client
.runtime_api()
.inherent_extrinsics_with_context( .inherent_extrinsics_with_context(
&BlockId::number(0), &BlockId::number(0),
ExecutionContext::BlockConstruction, ExecutionContext::BlockConstruction,
inherent_data, inherent_data,
).expect("Get inherents failed") )
.expect("Get inherents failed")
} }
/// Iterate over some block content with transaction signed using this database keyring. /// Iterate over some block content with transaction signed using this database keyring.
@@ -474,9 +448,7 @@ impl BenchDb {
pub fn generate_block(&mut self, content: BlockContent) -> Block { pub fn generate_block(&mut self, content: BlockContent) -> Block {
let client = self.client(); let client = self.client();
let mut block = client let mut block = client.new_block(Default::default()).expect("Block creation failed");
.new_block(Default::default())
.expect("Block creation failed");
for extrinsic in self.generate_inherents(&client) { for extrinsic in self.generate_inherents(&client) {
block.push(extrinsic).expect("Push inherent failed"); block.push(extrinsic).expect("Push inherent failed");
@@ -486,14 +458,12 @@ impl BenchDb {
for opaque in self.block_content(content, &client) { for opaque in self.block_content(content, &client) {
match block.push(opaque) { match block.push(opaque) {
Err(sp_blockchain::Error::ApplyExtrinsicFailed( Err(sp_blockchain::Error::ApplyExtrinsicFailed(
sp_blockchain::ApplyExtrinsicFailed::Validity(e) sp_blockchain::ApplyExtrinsicFailed::Validity(e),
)) if e.exhausted_resources() => { )) if e.exhausted_resources() => break,
break;
},
Err(err) => panic!("Error pushing transaction: {:?}", err), Err(err) => panic!("Error pushing transaction: {:?}", err),
Ok(_) => {}, Ok(_) => {},
} }
}; }
let block = block.build().expect("Block build failed").block; let block = block.build().expect("Block build failed").block;
@@ -514,12 +484,8 @@ impl BenchDb {
/// Clone this database and create context for testing/benchmarking. /// Clone this database and create context for testing/benchmarking.
pub fn create_context(&self, profile: Profile) -> BenchContext { pub fn create_context(&self, profile: Profile) -> BenchContext {
let BenchDb { directory_guard, keyring, database_type } = self.clone(); let BenchDb { directory_guard, keyring, database_type } = self.clone();
let (client, backend, task_executor) = Self::bench_client( let (client, backend, task_executor) =
database_type, Self::bench_client(database_type, directory_guard.path(), profile, &keyring);
directory_guard.path(),
profile,
&keyring
);
BenchContext { BenchContext {
client: Arc::new(client), client: Arc::new(client),
@@ -549,7 +515,8 @@ impl BenchKeyring {
let seed = format!("//endowed-user/{}", n); let seed = format!("//endowed-user/{}", n);
let (account_id, pair) = match key_types { let (account_id, pair) = match key_types {
KeyTypes::Sr25519 => { KeyTypes::Sr25519 => {
let pair = sr25519::Pair::from_string(&seed, None).expect("failed to generate pair"); let pair =
sr25519::Pair::from_string(&seed, None).expect("failed to generate pair");
let account_id = AccountPublic::from(pair.public()).into_account(); let account_id = AccountPublic::from(pair.public()).into_account();
(account_id, BenchPair::Sr25519(pair)) (account_id, BenchPair::Sr25519(pair))
}, },
@@ -581,28 +548,34 @@ impl BenchKeyring {
xt: CheckedExtrinsic, xt: CheckedExtrinsic,
spec_version: u32, spec_version: u32,
tx_version: u32, tx_version: u32,
genesis_hash: [u8; 32] genesis_hash: [u8; 32],
) -> UncheckedExtrinsic { ) -> UncheckedExtrinsic {
match xt.signed { match xt.signed {
Some((signed, extra)) => { Some((signed, extra)) => {
let payload = (xt.function, extra.clone(), spec_version, tx_version, genesis_hash, genesis_hash); let payload = (
xt.function,
extra.clone(),
spec_version,
tx_version,
genesis_hash,
genesis_hash,
);
let key = self.accounts.get(&signed).expect("Account id not found in keyring"); let key = self.accounts.get(&signed).expect("Account id not found in keyring");
let signature = payload.using_encoded(|b| { let signature = payload
if b.len() > 256 { .using_encoded(|b| {
key.sign(&sp_io::hashing::blake2_256(b)) if b.len() > 256 {
} else { key.sign(&sp_io::hashing::blake2_256(b))
key.sign(b) } else {
} key.sign(b)
}).into(); }
})
.into();
UncheckedExtrinsic { UncheckedExtrinsic {
signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)),
function: payload.0, function: payload.0,
} }
}
None => UncheckedExtrinsic {
signature: None,
function: xt.function,
}, },
None => UncheckedExtrinsic { signature: None, function: xt.function },
} }
} }
@@ -641,7 +614,7 @@ impl Profile {
block_construction: ExecutionStrategy::NativeElseWasm, block_construction: ExecutionStrategy::NativeElseWasm,
offchain_worker: ExecutionStrategy::NativeElseWasm, offchain_worker: ExecutionStrategy::NativeElseWasm,
other: ExecutionStrategy::NativeElseWasm, other: ExecutionStrategy::NativeElseWasm,
} },
} }
} }
} }
@@ -676,7 +649,7 @@ fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public
fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
where where
AccountPublic: From<<TPublic::Pair as Pair>::Public> AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{ {
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account() AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
} }
@@ -684,24 +657,25 @@ where
impl BenchContext { impl BenchContext {
/// Import some block. /// Import some block.
pub fn import_block(&mut self, block: Block) { pub fn import_block(&mut self, block: Block) {
let mut import_params = BlockImportParams::new(BlockOrigin::NetworkBroadcast, block.header.clone()); let mut import_params =
BlockImportParams::new(BlockOrigin::NetworkBroadcast, block.header.clone());
import_params.body = Some(block.extrinsics().to_vec()); import_params.body = Some(block.extrinsics().to_vec());
import_params.fork_choice = Some(ForkChoiceStrategy::LongestChain); import_params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
assert_eq!(self.client.chain_info().best_number, 0); assert_eq!(self.client.chain_info().best_number, 0);
assert_eq!( assert_eq!(
futures::executor::block_on(self.client.import_block(import_params, Default::default())) futures::executor::block_on(
.expect("Failed to import block"), self.client.import_block(import_params, Default::default())
ImportResult::Imported(
ImportedAux {
header_only: false,
clear_justification_requests: false,
needs_justification: false,
bad_justification: false,
is_new_best: true,
}
) )
.expect("Failed to import block"),
ImportResult::Imported(ImportedAux {
header_only: false,
clear_justification_requests: false,
needs_justification: false,
bad_justification: false,
is_new_best: true,
})
); );
assert_eq!(self.client.chain_info().best_number, 1); assert_eq!(self.client.chain_info().best_number, 1);
+10 -10
View File
@@ -18,8 +18,8 @@
//! Utilities to build a `TestClient` for `node-runtime`. //! Utilities to build a `TestClient` for `node-runtime`.
use sp_runtime::BuildStorage;
use sc_service::client; use sc_service::client;
use sp_runtime::BuildStorage;
/// Re-export test-client utilities. /// Re-export test-client utilities.
pub use substrate_test_client::*; pub use substrate_test_client::*;
@@ -61,13 +61,15 @@ pub trait TestClientBuilderExt: Sized {
fn build(self) -> Client; fn build(self) -> Client;
} }
impl TestClientBuilderExt for substrate_test_client::TestClientBuilder< impl TestClientBuilderExt
node_primitives::Block, for substrate_test_client::TestClientBuilder<
client::LocalCallExecutor<node_primitives::Block, Backend, Executor>, node_primitives::Block,
Backend, client::LocalCallExecutor<node_primitives::Block, Backend, Executor>,
GenesisParameters, Backend,
> { GenesisParameters,
fn new() -> Self{ >
{
fn new() -> Self {
Self::default() Self::default()
} }
@@ -75,5 +77,3 @@ impl TestClientBuilderExt for substrate_test_client::TestClientBuilder<
self.build_with_native_executor(None).0 self.build_with_native_executor(None).0
} }
} }
+25 -46
View File
@@ -19,14 +19,13 @@
//! Genesis Configuration. //! Genesis Configuration.
use crate::keyring::*; use crate::keyring::*;
use sp_keyring::{Ed25519Keyring, Sr25519Keyring};
use node_runtime::{ use node_runtime::{
GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, SystemConfig, constants::currency::*, wasm_binary_unwrap, AccountId, BabeConfig, BalancesConfig,
GrandpaConfig, IndicesConfig, SocietyConfig, wasm_binary_unwrap, GenesisConfig, GrandpaConfig, IndicesConfig, SessionConfig, SocietyConfig, StakerStatus,
AccountId, StakerStatus, BabeConfig, BABE_GENESIS_EPOCH_CONFIG, StakingConfig, SystemConfig, BABE_GENESIS_EPOCH_CONFIG,
}; };
use node_runtime::constants::currency::*;
use sp_core::ChangesTrieConfiguration; use sp_core::ChangesTrieConfiguration;
use sp_keyring::{Ed25519Keyring, Sr25519Keyring};
use sp_runtime::Perbill; use sp_runtime::Perbill;
/// Create genesis runtime configuration for tests. /// Create genesis runtime configuration for tests.
@@ -41,7 +40,6 @@ pub fn config_endowed(
code: Option<&[u8]>, code: Option<&[u8]>,
extra_endowed: Vec<AccountId>, extra_endowed: Vec<AccountId>,
) -> GenesisConfig { ) -> GenesisConfig {
let mut endowed = vec![ let mut endowed = vec![
(alice(), 111 * DOLLARS), (alice(), 111 * DOLLARS),
(bob(), 100 * DOLLARS), (bob(), 100 * DOLLARS),
@@ -51,59 +49,44 @@ pub fn config_endowed(
(ferdie(), 100 * DOLLARS), (ferdie(), 100 * DOLLARS),
]; ];
endowed.extend( endowed.extend(extra_endowed.into_iter().map(|endowed| (endowed, 100 * DOLLARS)));
extra_endowed.into_iter().map(|endowed| (endowed, 100*DOLLARS))
);
GenesisConfig { GenesisConfig {
system: SystemConfig { system: SystemConfig {
changes_trie_config: if support_changes_trie { Some(ChangesTrieConfiguration { changes_trie_config: if support_changes_trie {
digest_interval: 2, Some(ChangesTrieConfiguration { digest_interval: 2, digest_levels: 2 })
digest_levels: 2, } else {
}) } else { None }, None
},
code: code.map(|x| x.to_vec()).unwrap_or_else(|| wasm_binary_unwrap().to_vec()), code: code.map(|x| x.to_vec()).unwrap_or_else(|| wasm_binary_unwrap().to_vec()),
}, },
indices: IndicesConfig { indices: IndicesConfig { indices: vec![] },
indices: vec![], balances: BalancesConfig { balances: endowed },
},
balances: BalancesConfig {
balances: endowed,
},
session: SessionConfig { session: SessionConfig {
keys: vec![ keys: vec![
(dave(), alice(), to_session_keys( (dave(), alice(), to_session_keys(&Ed25519Keyring::Alice, &Sr25519Keyring::Alice)),
&Ed25519Keyring::Alice, (eve(), bob(), to_session_keys(&Ed25519Keyring::Bob, &Sr25519Keyring::Bob)),
&Sr25519Keyring::Alice, (
)), ferdie(),
(eve(), bob(), to_session_keys( charlie(),
&Ed25519Keyring::Bob, to_session_keys(&Ed25519Keyring::Charlie, &Sr25519Keyring::Charlie),
&Sr25519Keyring::Bob, ),
)), ],
(ferdie(), charlie(), to_session_keys(
&Ed25519Keyring::Charlie,
&Sr25519Keyring::Charlie,
)),
]
}, },
staking: StakingConfig { staking: StakingConfig {
stakers: vec![ stakers: vec![
(dave(), alice(), 111 * DOLLARS, StakerStatus::Validator), (dave(), alice(), 111 * DOLLARS, StakerStatus::Validator),
(eve(), bob(), 100 * DOLLARS, StakerStatus::Validator), (eve(), bob(), 100 * DOLLARS, StakerStatus::Validator),
(ferdie(), charlie(), 100 * DOLLARS, StakerStatus::Validator) (ferdie(), charlie(), 100 * DOLLARS, StakerStatus::Validator),
], ],
validator_count: 3, validator_count: 3,
minimum_validator_count: 0, minimum_validator_count: 0,
slash_reward_fraction: Perbill::from_percent(10), slash_reward_fraction: Perbill::from_percent(10),
invulnerables: vec![alice(), bob(), charlie()], invulnerables: vec![alice(), bob(), charlie()],
.. Default::default() ..Default::default()
},
babe: BabeConfig {
authorities: vec![],
epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG),
},
grandpa: GrandpaConfig {
authorities: vec![],
}, },
babe: BabeConfig { authorities: vec![], epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG) },
grandpa: GrandpaConfig { authorities: vec![] },
im_online: Default::default(), im_online: Default::default(),
authority_discovery: Default::default(), authority_discovery: Default::default(),
democracy: Default::default(), democracy: Default::default(),
@@ -113,11 +96,7 @@ pub fn config_endowed(
elections: Default::default(), elections: Default::default(),
sudo: Default::default(), sudo: Default::default(),
treasury: Default::default(), treasury: Default::default(),
society: SocietyConfig { society: SocietyConfig { members: vec![alice(), bob()], pot: 0, max_members: 999 },
members: vec![alice(), bob()],
pot: 0,
max_members: 999,
},
vesting: Default::default(), vesting: Default::default(),
gilt: Default::default(), gilt: Default::default(),
transaction_storage: Default::default(), transaction_storage: Default::default(),
+22 -17
View File
@@ -18,11 +18,11 @@
//! Test accounts. //! Test accounts.
use sp_keyring::{AccountKeyring, Sr25519Keyring, Ed25519Keyring};
use node_primitives::{AccountId, Balance, Index};
use node_runtime::{CheckedExtrinsic, UncheckedExtrinsic, SessionKeys, SignedExtra};
use sp_runtime::generic::Era;
use codec::Encode; use codec::Encode;
use node_primitives::{AccountId, Balance, Index};
use node_runtime::{CheckedExtrinsic, SessionKeys, SignedExtra, UncheckedExtrinsic};
use sp_keyring::{AccountKeyring, Ed25519Keyring, Sr25519Keyring};
use sp_runtime::generic::Era;
/// Alice's account id. /// Alice's account id.
pub fn alice() -> AccountId { pub fn alice() -> AccountId {
@@ -81,26 +81,31 @@ pub fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra {
} }
/// Sign given `CheckedExtrinsic`. /// Sign given `CheckedExtrinsic`.
pub fn sign(xt: CheckedExtrinsic, spec_version: u32, tx_version: u32, genesis_hash: [u8; 32]) -> UncheckedExtrinsic { pub fn sign(
xt: CheckedExtrinsic,
spec_version: u32,
tx_version: u32,
genesis_hash: [u8; 32],
) -> UncheckedExtrinsic {
match xt.signed { match xt.signed {
Some((signed, extra)) => { Some((signed, extra)) => {
let payload = (xt.function, extra.clone(), spec_version, tx_version, genesis_hash, genesis_hash); let payload =
(xt.function, extra.clone(), spec_version, tx_version, genesis_hash, genesis_hash);
let key = AccountKeyring::from_account_id(&signed).unwrap(); let key = AccountKeyring::from_account_id(&signed).unwrap();
let signature = payload.using_encoded(|b| { let signature = payload
if b.len() > 256 { .using_encoded(|b| {
key.sign(&sp_io::hashing::blake2_256(b)) if b.len() > 256 {
} else { key.sign(&sp_io::hashing::blake2_256(b))
key.sign(b) } else {
} key.sign(b)
}).into(); }
})
.into();
UncheckedExtrinsic { UncheckedExtrinsic {
signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)),
function: payload.0, function: payload.0,
} }
}
None => UncheckedExtrinsic {
signature: None,
function: xt.function,
}, },
None => UncheckedExtrinsic { signature: None, function: xt.function },
} }
} }
+1 -1
View File
@@ -20,7 +20,7 @@
#![warn(missing_docs)] #![warn(missing_docs)]
pub mod bench;
pub mod client; pub mod client;
pub mod genesis; pub mod genesis;
pub mod keyring; pub mod keyring;
pub mod bench;
@@ -16,19 +16,23 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use std::{fs, path::{Path, PathBuf}, sync::Arc}; use std::{
fs,
path::{Path, PathBuf},
sync::Arc,
};
use ansi_term::Style; use ansi_term::Style;
use rand::{Rng, distributions::Alphanumeric, rngs::OsRng}; use rand::{distributions::Alphanumeric, rngs::OsRng, Rng};
use structopt::StructOpt; use structopt::StructOpt;
use sc_keystore::LocalKeystore;
use node_cli::chain_spec::{self, AccountId}; use node_cli::chain_spec::{self, AccountId};
use sc_keystore::LocalKeystore;
use sp_core::{ use sp_core::{
sr25519,
crypto::{Public, Ss58Codec}, crypto::{Public, Ss58Codec},
sr25519,
}; };
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore}; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
/// A utility to easily create a testnet chain spec definition with a given set /// A utility to easily create a testnet chain spec definition with a given set
/// of authorities and endowed accounts and/or generate random accounts. /// of authorities and endowed accounts and/or generate random accounts.
@@ -86,10 +90,8 @@ impl ChainSpecBuilder {
/// Returns the path where the chain spec should be saved. /// Returns the path where the chain spec should be saved.
fn chain_spec_path(&self) -> &Path { fn chain_spec_path(&self) -> &Path {
match self { match self {
ChainSpecBuilder::New { chain_spec_path, .. } => ChainSpecBuilder::New { chain_spec_path, .. } => chain_spec_path.as_path(),
chain_spec_path.as_path(), ChainSpecBuilder::Generate { chain_spec_path, .. } => chain_spec_path.as_path(),
ChainSpecBuilder::Generate { chain_spec_path, .. } =>
chain_spec_path.as_path(),
} }
} }
} }
@@ -125,11 +127,15 @@ fn generate_chain_spec(
.map_err(|err| format!("Failed to parse account address: {:?}", err)) .map_err(|err| format!("Failed to parse account address: {:?}", err))
}; };
let nominator_accounts = let nominator_accounts = nominator_accounts
nominator_accounts.into_iter().map(parse_account).collect::<Result<Vec<_>, String>>()?; .into_iter()
.map(parse_account)
.collect::<Result<Vec<_>, String>>()?;
let endowed_accounts = let endowed_accounts = endowed_accounts
endowed_accounts.into_iter().map(parse_account).collect::<Result<Vec<_>, String>>()?; .into_iter()
.map(parse_account)
.collect::<Result<Vec<_>, String>>()?;
let sudo_account = parse_account(sudo_account)?; let sudo_account = parse_account(sudo_account)?;
@@ -137,7 +143,14 @@ fn generate_chain_spec(
"Custom", "Custom",
"custom", "custom",
sc_chain_spec::ChainType::Live, sc_chain_spec::ChainType::Live,
move || genesis_constructor(&authority_seeds, &nominator_accounts, &endowed_accounts, &sudo_account), move || {
genesis_constructor(
&authority_seeds,
&nominator_accounts,
&endowed_accounts,
&sudo_account,
)
},
vec![], vec![],
None, None,
None, None,
@@ -148,42 +161,26 @@ fn generate_chain_spec(
chain_spec.as_json(false).map_err(|err| err) chain_spec.as_json(false).map_err(|err| err)
} }
fn generate_authority_keys_and_store( fn generate_authority_keys_and_store(seeds: &[String], keystore_path: &Path) -> Result<(), String> {
seeds: &[String],
keystore_path: &Path,
) -> Result<(), String> {
for (n, seed) in seeds.into_iter().enumerate() { for (n, seed) in seeds.into_iter().enumerate() {
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open( let keystore: SyncCryptoStorePtr = Arc::new(
keystore_path.join(format!("auth-{}", n)), LocalKeystore::open(keystore_path.join(format!("auth-{}", n)), None)
None, .map_err(|err| err.to_string())?,
).map_err(|err| err.to_string())?); );
let (_, _, grandpa, babe, im_online, authority_discovery) = let (_, _, grandpa, babe, im_online, authority_discovery) =
chain_spec::authority_keys_from_seed(seed); chain_spec::authority_keys_from_seed(seed);
let insert_key = |key_type, public| { let insert_key = |key_type, public| {
SyncCryptoStore::insert_unknown( SyncCryptoStore::insert_unknown(&*keystore, key_type, &format!("//{}", seed), public)
&*keystore, .map_err(|_| format!("Failed to insert key: {}", grandpa))
key_type,
&format!("//{}", seed),
public,
).map_err(|_| format!("Failed to insert key: {}", grandpa))
}; };
insert_key( insert_key(sp_core::crypto::key_types::BABE, babe.as_slice())?;
sp_core::crypto::key_types::BABE,
babe.as_slice(),
)?;
insert_key( insert_key(sp_core::crypto::key_types::GRANDPA, grandpa.as_slice())?;
sp_core::crypto::key_types::GRANDPA,
grandpa.as_slice(),
)?;
insert_key( insert_key(sp_core::crypto::key_types::IM_ONLINE, im_online.as_slice())?;
sp_core::crypto::key_types::IM_ONLINE,
im_online.as_slice(),
)?;
insert_key( insert_key(
sp_core::crypto::key_types::AUTHORITY_DISCOVERY, sp_core::crypto::key_types::AUTHORITY_DISCOVERY,
@@ -206,10 +203,7 @@ fn print_seeds(
println!("{}", header.paint("Authority seeds")); println!("{}", header.paint("Authority seeds"));
for (n, seed) in authority_seeds.iter().enumerate() { for (n, seed) in authority_seeds.iter().enumerate() {
println!("{} //{}", println!("{} //{}", entry.paint(format!("auth-{}:", n)), seed,);
entry.paint(format!("auth-{}:", n)),
seed,
);
} }
println!("{}", header.paint("Nominator seeds")); println!("{}", header.paint("Nominator seeds"));
@@ -223,10 +217,7 @@ fn print_seeds(
if !endowed_seeds.is_empty() { if !endowed_seeds.is_empty() {
println!("{}", header.paint("Endowed seeds")); println!("{}", header.paint("Endowed seeds"));
for (n, seed) in endowed_seeds.iter().enumerate() { for (n, seed) in endowed_seeds.iter().enumerate() {
println!("{} //{}", println!("{} //{}", entry.paint(format!("endowed-{}:", n)), seed,);
entry.paint(format!("endowed-{}:", n)),
seed,
);
} }
println!(); println!();
@@ -260,10 +251,7 @@ fn main() -> Result<(), String> {
print_seeds(&authority_seeds, &nominator_seeds, &endowed_seeds, &sudo_seed); print_seeds(&authority_seeds, &nominator_seeds, &endowed_seeds, &sudo_seed);
if let Some(keystore_path) = keystore_path { if let Some(keystore_path) = keystore_path {
generate_authority_keys_and_store( generate_authority_keys_and_store(&authority_seeds, &keystore_path)?;
&authority_seeds,
&keystore_path,
)?;
} }
let nominator_accounts = nominator_seeds let nominator_accounts = nominator_seeds
@@ -284,7 +272,7 @@ fn main() -> Result<(), String> {
chain_spec::get_account_id_from_seed::<sr25519::Public>(&sudo_seed).to_ss58check(); chain_spec::get_account_id_from_seed::<sr25519::Public>(&sudo_seed).to_ss58check();
(authority_seeds, nominator_accounts, endowed_accounts, sudo_account) (authority_seeds, nominator_accounts, endowed_accounts, sudo_account)
} },
ChainSpecBuilder::New { ChainSpecBuilder::New {
authority_seeds, authority_seeds,
nominator_accounts, nominator_accounts,
@@ -294,12 +282,8 @@ fn main() -> Result<(), String> {
} => (authority_seeds, nominator_accounts, endowed_accounts, sudo_account), } => (authority_seeds, nominator_accounts, endowed_accounts, sudo_account),
}; };
let json = generate_chain_spec( let json =
authority_seeds, generate_chain_spec(authority_seeds, nominator_accounts, endowed_accounts, sudo_account)?;
nominator_accounts,
endowed_accounts,
sudo_account,
)?;
fs::write(chain_spec_path, json).map_err(|err| err.to_string()) fs::write(chain_spec_path, json).map_err(|err| err.to_string())
} }
+4 -4
View File
@@ -16,17 +16,17 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use structopt::StructOpt;
use sc_cli::{ use sc_cli::{
Error, VanityCmd, SignCmd, VerifyCmd, GenerateNodeKeyCmd, GenerateCmd, InspectKeyCmd, Error, GenerateCmd, GenerateNodeKeyCmd, InspectKeyCmd, InspectNodeKeyCmd, SignCmd, VanityCmd,
InspectNodeKeyCmd VerifyCmd,
}; };
use structopt::StructOpt;
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
#[structopt( #[structopt(
name = "subkey", name = "subkey",
author = "Parity Team <admin@parity.io>", author = "Parity Team <admin@parity.io>",
about = "Utility for generating and restoring with Substrate keys", about = "Utility for generating and restoring with Substrate keys"
)] )]
pub enum Subkey { pub enum Subkey {
/// Generate a random node libp2p key, save it to file or print it to stdout /// Generate a random node libp2p key, save it to file or print it to stdout
+1 -1
View File
@@ -26,5 +26,5 @@ pub enum Error {
AllocatorOutOfSpace, AllocatorOutOfSpace,
/// Some other error occurred. /// Some other error occurred.
#[error("Other: {0}")] #[error("Other: {0}")]
Other(&'static str) Other(&'static str),
} }
+22 -16
View File
@@ -68,8 +68,12 @@
//! sizes. //! sizes.
use crate::Error; use crate::Error;
use std::{mem, convert::{TryFrom, TryInto}, ops::{Range, Index, IndexMut}};
use sp_wasm_interface::{Pointer, WordSize}; use sp_wasm_interface::{Pointer, WordSize};
use std::{
convert::{TryFrom, TryInto},
mem,
ops::{Index, IndexMut, Range},
};
/// The minimal alignment guaranteed by this allocator. /// The minimal alignment guaranteed by this allocator.
/// ///
@@ -139,7 +143,7 @@ impl Order {
fn from_size(size: u32) -> Result<Self, Error> { fn from_size(size: u32) -> Result<Self, Error> {
let clamped_size = if size > MAX_POSSIBLE_ALLOCATION { let clamped_size = if size > MAX_POSSIBLE_ALLOCATION {
log::warn!(target: LOG_TARGET, "going to fail due to allocating {:?}", size); log::warn!(target: LOG_TARGET, "going to fail due to allocating {:?}", size);
return Err(Error::RequestedAllocationTooLarge); return Err(Error::RequestedAllocationTooLarge)
} else if size < MIN_POSSIBLE_ALLOCATION { } else if size < MIN_POSSIBLE_ALLOCATION {
MIN_POSSIBLE_ALLOCATION MIN_POSSIBLE_ALLOCATION
} else { } else {
@@ -216,7 +220,6 @@ impl Link {
/// ``` /// ```
/// ///
/// ## Occupied header /// ## Occupied header
///
/// ```ignore /// ```ignore
/// 64 32 0 /// 64 32 0
// +--------------+-------------------+ // +--------------+-------------------+
@@ -290,9 +293,7 @@ struct FreeLists {
impl FreeLists { impl FreeLists {
/// Creates the free empty lists. /// Creates the free empty lists.
fn new() -> Self { fn new() -> Self {
Self { Self { heads: [Link::Nil; N_ORDERS] }
heads: [Link::Nil; N_ORDERS]
}
} }
/// Replaces a given link for the specified order and returns the old one. /// Replaces a given link for the specified order and returns the old one.
@@ -397,15 +398,11 @@ impl FreeingBumpHeapAllocator {
self.free_lists[order] = next_free; self.free_lists[order] = next_free;
header_ptr header_ptr
} },
Link::Nil => { Link::Nil => {
// Corresponding free list is empty. Allocate a new item. // Corresponding free list is empty. Allocate a new item.
Self::bump( Self::bump(&mut self.bumper, order.size() + HEADER_SIZE, mem.size())?
&mut self.bumper, },
order.size() + HEADER_SIZE,
mem.size(),
)?
}
}; };
// Write the order in the occupied header. // Write the order in the occupied header.
@@ -440,7 +437,11 @@ impl FreeingBumpHeapAllocator {
/// ///
/// - `mem` - a slice representing the linear memory on which this allocator operates. /// - `mem` - a slice representing the linear memory on which this allocator operates.
/// - `ptr` - pointer to the allocated chunk /// - `ptr` - pointer to the allocated chunk
pub fn deallocate<M: Memory + ?Sized>(&mut self, mem: &mut M, ptr: Pointer<u8>) -> Result<(), Error> { pub fn deallocate<M: Memory + ?Sized>(
&mut self,
mem: &mut M,
ptr: Pointer<u8>,
) -> Result<(), Error> {
if self.poisoned { if self.poisoned {
return Err(error("the allocator has been poisoned")) return Err(error("the allocator has been poisoned"))
} }
@@ -480,8 +481,13 @@ impl FreeingBumpHeapAllocator {
/// the operation would exhaust the heap. /// the operation would exhaust the heap.
fn bump(bumper: &mut u32, size: u32, heap_end: u32) -> Result<u32, Error> { fn bump(bumper: &mut u32, size: u32, heap_end: u32) -> Result<u32, Error> {
if *bumper + size > heap_end { if *bumper + size > heap_end {
log::error!(target: LOG_TARGET, "running out of space with current bumper {}, mem size {}", bumper, heap_end); log::error!(
return Err(Error::AllocatorOutOfSpace); target: LOG_TARGET,
"running out of space with current bumper {}, mem size {}",
bumper,
heap_end
);
return Err(Error::AllocatorOutOfSpace)
} }
let res = *bumper; let res = *bumper;
+1 -1
View File
@@ -25,5 +25,5 @@
mod error; mod error;
mod freeing_bump; mod freeing_bump;
pub use freeing_bump::FreeingBumpHeapAllocator;
pub use error::Error; pub use error::Error;
pub use freeing_bump::FreeingBumpHeapAllocator;
+91 -73
View File
@@ -18,30 +18,32 @@
//! Substrate Client data backend //! Substrate Client data backend
use std::sync::Arc;
use std::collections::{HashMap, HashSet};
use sp_core::ChangesTrieConfigurationRange;
use sp_core::offchain::OffchainStorage;
use sp_runtime::{generic::BlockId, Justification, Justifications, Storage};
use sp_runtime::traits::{Block as BlockT, NumberFor, HashFor};
use sp_state_machine::{
ChangesTrieState, ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction,
StorageCollection, ChildStorageCollection, OffchainChangesCollection, IndexOperation,
};
use sp_storage::{StorageData, StorageKey, PrefixedStorageKey, ChildInfo};
use crate::{ use crate::{
blockchain::{ blockchain::{well_known_cache_keys, Backend as BlockchainBackend},
Backend as BlockchainBackend, well_known_cache_keys
},
light::RemoteBlockchain, light::RemoteBlockchain,
UsageInfo, UsageInfo,
}; };
use parking_lot::RwLock;
use sp_blockchain; use sp_blockchain;
use sp_consensus::BlockOrigin; use sp_consensus::BlockOrigin;
use parking_lot::RwLock; use sp_core::{offchain::OffchainStorage, ChangesTrieConfigurationRange};
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, HashFor, NumberFor},
Justification, Justifications, Storage,
};
use sp_state_machine::{
ChangesTrieState, ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction,
ChildStorageCollection, IndexOperation, OffchainChangesCollection, StorageCollection,
};
use sp_storage::{ChildInfo, PrefixedStorageKey, StorageData, StorageKey};
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
pub use sp_state_machine::Backend as StateBackend;
pub use sp_consensus::ImportedState; pub use sp_consensus::ImportedState;
pub use sp_state_machine::Backend as StateBackend;
use std::marker::PhantomData; use std::marker::PhantomData;
/// Extracts the state backend type for the given backend. /// Extracts the state backend type for the given backend.
@@ -90,16 +92,17 @@ pub fn apply_aux<'a, 'b: 'a, 'c: 'a, B, Block, D, I>(
insert: I, insert: I,
delete: D, delete: D,
) -> sp_blockchain::Result<()> ) -> sp_blockchain::Result<()>
where where
Block: BlockT, Block: BlockT,
B: Backend<Block>, B: Backend<Block>,
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>, I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
D: IntoIterator<Item=&'a &'b [u8]>, D: IntoIterator<Item = &'a &'b [u8]>,
{ {
operation.op.insert_aux( operation.op.insert_aux(
insert.into_iter() insert
.into_iter()
.map(|(k, v)| (k.to_vec(), Some(v.to_vec()))) .map(|(k, v)| (k.to_vec(), Some(v.to_vec())))
.chain(delete.into_iter().map(|k| (k.to_vec(), None))) .chain(delete.into_iter().map(|k| (k.to_vec(), None))),
) )
} }
@@ -165,7 +168,11 @@ pub trait BlockImportOperation<Block: BlockT> {
/// Set genesis state. If `commit` is `false` the state is saved in memory, but is not written /// Set genesis state. If `commit` is `false` the state is saved in memory, but is not written
/// to the database. /// to the database.
fn set_genesis_state(&mut self, storage: Storage, commit: bool) -> sp_blockchain::Result<Block::Hash>; fn set_genesis_state(
&mut self,
storage: Storage,
commit: bool,
) -> sp_blockchain::Result<Block::Hash>;
/// Inject storage data into the database replacing any existing data. /// Inject storage data into the database replacing any existing data.
fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result<Block::Hash>; fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result<Block::Hash>;
@@ -182,7 +189,7 @@ pub trait BlockImportOperation<Block: BlockT> {
&mut self, &mut self,
_offchain_update: OffchainChangesCollection, _offchain_update: OffchainChangesCollection,
) -> sp_blockchain::Result<()> { ) -> sp_blockchain::Result<()> {
Ok(()) Ok(())
} }
/// Inject changes trie data into the database. /// Inject changes trie data into the database.
@@ -195,7 +202,8 @@ pub trait BlockImportOperation<Block: BlockT> {
/// ///
/// Values are `None` if should be deleted. /// Values are `None` if should be deleted.
fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()> fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()>
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>; where
I: IntoIterator<Item = (Vec<u8>, Option<Vec<u8>>)>;
/// Mark a block as finalized. /// Mark a block as finalized.
fn mark_finalized( fn mark_finalized(
@@ -209,16 +217,17 @@ pub trait BlockImportOperation<Block: BlockT> {
fn mark_head(&mut self, id: BlockId<Block>) -> sp_blockchain::Result<()>; fn mark_head(&mut self, id: BlockId<Block>) -> sp_blockchain::Result<()>;
/// Add a transaction index operation. /// Add a transaction index operation.
fn update_transaction_index(&mut self, index: Vec<IndexOperation>) -> sp_blockchain::Result<()>; fn update_transaction_index(&mut self, index: Vec<IndexOperation>)
-> sp_blockchain::Result<()>;
} }
/// Interface for performing operations on the backend. /// Interface for performing operations on the backend.
pub trait LockImportRun<Block: BlockT, B: Backend<Block>> { pub trait LockImportRun<Block: BlockT, B: Backend<Block>> {
/// Lock the import lock, and run operations inside. /// Lock the import lock, and run operations inside.
fn lock_import_and_run<R, Err, F>(&self, f: F) -> Result<R, Err> fn lock_import_and_run<R, Err, F>(&self, f: F) -> Result<R, Err>
where where
F: FnOnce(&mut ClientImportOperation<Block, B>) -> Result<R, Err>, F: FnOnce(&mut ClientImportOperation<Block, B>) -> Result<R, Err>,
Err: From<sp_blockchain::Error>; Err: From<sp_blockchain::Error>;
} }
/// Finalize Facilities /// Finalize Facilities
@@ -270,9 +279,13 @@ pub trait AuxStore {
'a, 'a,
'b: 'a, 'b: 'a,
'c: 'a, 'c: 'a,
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>, I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
D: IntoIterator<Item=&'a &'b [u8]>, D: IntoIterator<Item = &'a &'b [u8]>,
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()>; >(
&self,
insert: I,
delete: D,
) -> sp_blockchain::Result<()>;
/// Query auxiliary data from key-value store. /// Query auxiliary data from key-value store.
fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>>; fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>>;
@@ -287,16 +300,10 @@ pub struct KeyIterator<'a, State, Block> {
_phantom: PhantomData<Block>, _phantom: PhantomData<Block>,
} }
impl <'a, State, Block> KeyIterator<'a, State, Block> { impl<'a, State, Block> KeyIterator<'a, State, Block> {
/// create a KeyIterator instance /// create a KeyIterator instance
pub fn new(state: State, prefix: Option<&'a StorageKey>, current_key: Vec<u8>) -> Self { pub fn new(state: State, prefix: Option<&'a StorageKey>, current_key: Vec<u8>) -> Self {
Self { Self { state, child_storage: None, prefix, current_key, _phantom: PhantomData }
state,
child_storage: None,
prefix,
current_key,
_phantom: PhantomData,
}
} }
/// Create a `KeyIterator` instance for a child storage. /// Create a `KeyIterator` instance for a child storage.
@@ -306,17 +313,12 @@ impl <'a, State, Block> KeyIterator<'a, State, Block> {
prefix: Option<&'a StorageKey>, prefix: Option<&'a StorageKey>,
current_key: Vec<u8>, current_key: Vec<u8>,
) -> Self { ) -> Self {
Self { Self { state, child_storage: Some(child_info), prefix, current_key, _phantom: PhantomData }
state,
child_storage: Some(child_info),
prefix,
current_key,
_phantom: PhantomData,
}
} }
} }
impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> where impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block>
where
Block: BlockT, Block: BlockT,
State: StateBackend<HashFor<Block>>, State: StateBackend<HashFor<Block>>,
{ {
@@ -327,11 +329,13 @@ impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> where
self.state.next_child_storage_key(child_info, &self.current_key) self.state.next_child_storage_key(child_info, &self.current_key)
} else { } else {
self.state.next_storage_key(&self.current_key) self.state.next_storage_key(&self.current_key)
}.ok().flatten()?; }
.ok()
.flatten()?;
// this terminates the iterator the first time it fails. // this terminates the iterator the first time it fails.
if let Some(prefix) = self.prefix { if let Some(prefix) = self.prefix {
if !next_key.starts_with(&prefix.0[..]) { if !next_key.starts_with(&prefix.0[..]) {
return None; return None
} }
} }
self.current_key = next_key.clone(); self.current_key = next_key.clone();
@@ -342,19 +346,31 @@ impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> where
/// Provides acess to storage primitives /// Provides acess to storage primitives
pub trait StorageProvider<Block: BlockT, B: Backend<Block>> { pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
/// Given a `BlockId` and a key, return the value under the key in that block. /// Given a `BlockId` and a key, return the value under the key in that block.
fn storage(&self, id: &BlockId<Block>, key: &StorageKey) -> sp_blockchain::Result<Option<StorageData>>; fn storage(
&self,
id: &BlockId<Block>,
key: &StorageKey,
) -> sp_blockchain::Result<Option<StorageData>>;
/// Given a `BlockId` and a key prefix, return the matching storage keys in that block. /// Given a `BlockId` and a key prefix, return the matching storage keys in that block.
fn storage_keys(&self, id: &BlockId<Block>, key_prefix: &StorageKey) -> sp_blockchain::Result<Vec<StorageKey>>; fn storage_keys(
&self,
id: &BlockId<Block>,
key_prefix: &StorageKey,
) -> sp_blockchain::Result<Vec<StorageKey>>;
/// Given a `BlockId` and a key, return the value under the hash in that block. /// Given a `BlockId` and a key, return the value under the hash in that block.
fn storage_hash(&self, id: &BlockId<Block>, key: &StorageKey) -> sp_blockchain::Result<Option<Block::Hash>>; fn storage_hash(
&self,
id: &BlockId<Block>,
key: &StorageKey,
) -> sp_blockchain::Result<Option<Block::Hash>>;
/// Given a `BlockId` and a key prefix, return the matching child storage keys and values in that block. /// Given a `BlockId` and a key prefix, return the matching child storage keys and values in that block.
fn storage_pairs( fn storage_pairs(
&self, &self,
id: &BlockId<Block>, id: &BlockId<Block>,
key_prefix: &StorageKey key_prefix: &StorageKey,
) -> sp_blockchain::Result<Vec<(StorageKey, StorageData)>>; ) -> sp_blockchain::Result<Vec<(StorageKey, StorageData)>>;
/// Given a `BlockId` and a key prefix, return a `KeyIterator` iterates matching storage keys in that block. /// Given a `BlockId` and a key prefix, return a `KeyIterator` iterates matching storage keys in that block.
@@ -362,7 +378,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
&self, &self,
id: &BlockId<Block>, id: &BlockId<Block>,
prefix: Option<&'a StorageKey>, prefix: Option<&'a StorageKey>,
start_key: Option<&StorageKey> start_key: Option<&StorageKey>,
) -> sp_blockchain::Result<KeyIterator<'a, B::State, Block>>; ) -> sp_blockchain::Result<KeyIterator<'a, B::State, Block>>;
/// Given a `BlockId`, a key and a child storage key, return the value under the key in that block. /// Given a `BlockId`, a key and a child storage key, return the value under the key in that block.
@@ -370,7 +386,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
&self, &self,
id: &BlockId<Block>, id: &BlockId<Block>,
child_info: &ChildInfo, child_info: &ChildInfo,
key: &StorageKey key: &StorageKey,
) -> sp_blockchain::Result<Option<StorageData>>; ) -> sp_blockchain::Result<Option<StorageData>>;
/// Given a `BlockId`, a key prefix, and a child storage key, return the matching child storage keys. /// Given a `BlockId`, a key prefix, and a child storage key, return the matching child storage keys.
@@ -378,7 +394,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
&self, &self,
id: &BlockId<Block>, id: &BlockId<Block>,
child_info: &ChildInfo, child_info: &ChildInfo,
key_prefix: &StorageKey key_prefix: &StorageKey,
) -> sp_blockchain::Result<Vec<StorageKey>>; ) -> sp_blockchain::Result<Vec<StorageKey>>;
/// Given a `BlockId` and a key `prefix` and a child storage key, /// Given a `BlockId` and a key `prefix` and a child storage key,
@@ -388,7 +404,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
id: &BlockId<Block>, id: &BlockId<Block>,
child_info: ChildInfo, child_info: ChildInfo,
prefix: Option<&'a StorageKey>, prefix: Option<&'a StorageKey>,
start_key: Option<&StorageKey> start_key: Option<&StorageKey>,
) -> sp_blockchain::Result<KeyIterator<'a, B::State, Block>>; ) -> sp_blockchain::Result<KeyIterator<'a, B::State, Block>>;
/// Given a `BlockId`, a key and a child storage key, return the hash under the key in that block. /// Given a `BlockId`, a key and a child storage key, return the hash under the key in that block.
@@ -396,7 +412,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
&self, &self,
id: &BlockId<Block>, id: &BlockId<Block>,
child_info: &ChildInfo, child_info: &ChildInfo,
key: &StorageKey key: &StorageKey,
) -> sp_blockchain::Result<Option<Block::Hash>>; ) -> sp_blockchain::Result<Option<Block::Hash>>;
/// Get longest range within [first; last] that is possible to use in `key_changes` /// Get longest range within [first; last] that is possible to use in `key_changes`
@@ -418,7 +434,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
first: NumberFor<Block>, first: NumberFor<Block>,
last: BlockId<Block>, last: BlockId<Block>,
storage_key: Option<&PrefixedStorageKey>, storage_key: Option<&PrefixedStorageKey>,
key: &StorageKey key: &StorageKey,
) -> sp_blockchain::Result<Vec<(NumberFor<Block>, u32)>>; ) -> sp_blockchain::Result<Vec<(NumberFor<Block>, u32)>>;
} }
@@ -511,20 +527,20 @@ pub trait Backend<Block: BlockT>: AuxStore + Send + Sync {
) -> sp_blockchain::Result<(NumberFor<Block>, HashSet<Block::Hash>)>; ) -> sp_blockchain::Result<(NumberFor<Block>, HashSet<Block::Hash>)>;
/// Discard non-best, unfinalized leaf block. /// Discard non-best, unfinalized leaf block.
fn remove_leaf_block( fn remove_leaf_block(&self, hash: &Block::Hash) -> sp_blockchain::Result<()>;
&self,
hash: &Block::Hash,
) -> sp_blockchain::Result<()>;
/// Insert auxiliary data into key-value store. /// Insert auxiliary data into key-value store.
fn insert_aux< fn insert_aux<
'a, 'a,
'b: 'a, 'b: 'a,
'c: 'a, 'c: 'a,
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>, I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
D: IntoIterator<Item=&'a &'b [u8]>, D: IntoIterator<Item = &'a &'b [u8]>,
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()> >(
{ &self,
insert: I,
delete: D,
) -> sp_blockchain::Result<()> {
AuxStore::insert_aux(self, insert, delete) AuxStore::insert_aux(self, insert, delete)
} }
/// Query auxiliary data from key-value store. /// Query auxiliary data from key-value store.
@@ -548,9 +564,10 @@ pub trait PrunableStateChangesTrieStorage<Block: BlockT>:
/// Get reference to StateChangesTrieStorage. /// Get reference to StateChangesTrieStorage.
fn storage(&self) -> &dyn StateChangesTrieStorage<HashFor<Block>, NumberFor<Block>>; fn storage(&self) -> &dyn StateChangesTrieStorage<HashFor<Block>, NumberFor<Block>>;
/// Get configuration at given block. /// Get configuration at given block.
fn configuration_at(&self, at: &BlockId<Block>) -> sp_blockchain::Result< fn configuration_at(
ChangesTrieConfigurationRange<NumberFor<Block>, Block::Hash> &self,
>; at: &BlockId<Block>,
) -> sp_blockchain::Result<ChangesTrieConfigurationRange<NumberFor<Block>, Block::Hash>>;
/// Get end block (inclusive) of oldest pruned max-level (or skewed) digest trie blocks range. /// Get end block (inclusive) of oldest pruned max-level (or skewed) digest trie blocks range.
/// It is guaranteed that we have no any changes tries before (and including) this block. /// It is guaranteed that we have no any changes tries before (and including) this block.
/// It is guaranteed that all existing changes tries after this block are not yet pruned (if created). /// It is guaranteed that all existing changes tries after this block are not yet pruned (if created).
@@ -584,7 +601,8 @@ pub fn changes_tries_state_at_block<'a, Block: BlockT>(
let config_range = storage.configuration_at(block)?; let config_range = storage.configuration_at(block)?;
match config_range.config { match config_range.config {
Some(config) => Ok(Some(ChangesTrieState::new(config, config_range.zero.0, storage.storage()))), Some(config) =>
Ok(Some(ChangesTrieState::new(config, config_range.zero.0, storage.storage()))),
None => Ok(None), None => Ok(None),
} }
} }
+26 -22
View File
@@ -18,20 +18,19 @@
//! A method call executor interface. //! A method call executor interface.
use std::{panic::UnwindSafe, result, cell::RefCell}; use codec::{Decode, Encode};
use codec::{Encode, Decode}; use sc_executor::{NativeVersion, RuntimeVersion};
use sp_runtime::{
generic::BlockId, traits::{Block as BlockT, HashFor},
};
use sp_state_machine::{
OverlayedChanges, ExecutionManager, ExecutionStrategy, StorageProof,
};
use sc_executor::{RuntimeVersion, NativeVersion};
use sp_externalities::Extensions;
use sp_core::NativeOrEncoded; use sp_core::NativeOrEncoded;
use sp_externalities::Extensions;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, HashFor},
};
use sp_state_machine::{ExecutionManager, ExecutionStrategy, OverlayedChanges, StorageProof};
use std::{cell::RefCell, panic::UnwindSafe, result};
use sp_api::{ProofRecorder, StorageTransactionCache};
use crate::execution_extensions::ExecutionExtensions; use crate::execution_extensions::ExecutionExtensions;
use sp_api::{ProofRecorder, StorageTransactionCache};
/// Executor Provider /// Executor Provider
pub trait ExecutorProvider<Block: BlockT> { pub trait ExecutorProvider<Block: BlockT> {
@@ -73,7 +72,7 @@ pub trait CallExecutor<B: BlockT> {
fn contextual_call< fn contextual_call<
EM: Fn( EM: Fn(
Result<NativeOrEncoded<R>, Self::Error>, Result<NativeOrEncoded<R>, Self::Error>,
Result<NativeOrEncoded<R>, Self::Error> Result<NativeOrEncoded<R>, Self::Error>,
) -> Result<NativeOrEncoded<R>, Self::Error>, ) -> Result<NativeOrEncoded<R>, Self::Error>,
R: Encode + Decode + PartialEq, R: Encode + Decode + PartialEq,
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe, NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
@@ -83,14 +82,18 @@ pub trait CallExecutor<B: BlockT> {
method: &str, method: &str,
call_data: &[u8], call_data: &[u8],
changes: &RefCell<OverlayedChanges>, changes: &RefCell<OverlayedChanges>,
storage_transaction_cache: Option<&RefCell< storage_transaction_cache: Option<
StorageTransactionCache<B, <Self::Backend as crate::backend::Backend<B>>::State>, &RefCell<
>>, StorageTransactionCache<B, <Self::Backend as crate::backend::Backend<B>>::State>,
>,
>,
execution_manager: ExecutionManager<EM>, execution_manager: ExecutionManager<EM>,
native_call: Option<NC>, native_call: Option<NC>,
proof_recorder: &Option<ProofRecorder<B>>, proof_recorder: &Option<ProofRecorder<B>>,
extensions: Option<Extensions>, extensions: Option<Extensions>,
) -> sp_blockchain::Result<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone; ) -> sp_blockchain::Result<NativeOrEncoded<R>>
where
ExecutionManager<EM>: Clone;
/// Extract RuntimeVersion of given block /// Extract RuntimeVersion of given block
/// ///
@@ -105,12 +108,13 @@ pub trait CallExecutor<B: BlockT> {
mut state: S, mut state: S,
overlay: &mut OverlayedChanges, overlay: &mut OverlayedChanges,
method: &str, method: &str,
call_data: &[u8] call_data: &[u8],
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error> { ) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error> {
let trie_state = state.as_trie_backend() let trie_state = state.as_trie_backend().ok_or_else(|| {
.ok_or_else(|| sp_blockchain::Error::from_state(Box::new(
sp_blockchain::Error::from_state(Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof) as Box<_>) sp_state_machine::ExecutionError::UnableToGenerateProof,
)?; ) as Box<_>)
})?;
self.prove_at_trie_state(trie_state, overlay, method, call_data) self.prove_at_trie_state(trie_state, overlay, method, call_data)
} }
@@ -122,7 +126,7 @@ pub trait CallExecutor<B: BlockT> {
trie_state: &sp_state_machine::TrieBackend<S, HashFor<B>>, trie_state: &sp_state_machine::TrieBackend<S, HashFor<B>>,
overlay: &mut OverlayedChanges, overlay: &mut OverlayedChanges,
method: &str, method: &str,
call_data: &[u8] call_data: &[u8],
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error>; ) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error>;
/// Get runtime version if supported. /// Get runtime version if supported.
+115 -107
View File
@@ -25,15 +25,15 @@
//! root hash. A correct proof implies that the claimed block is identical to the one //! root hash. A correct proof implies that the claimed block is identical to the one
//! we discarded. //! we discarded.
use hash_db;
use codec::Encode; use codec::Encode;
use hash_db;
use sp_trie; use sp_trie;
use sp_core::{H256, convert_hash}; use sp_core::{convert_hash, H256};
use sp_runtime::traits::{Header as HeaderT, AtLeast32Bit, Zero, One}; use sp_runtime::traits::{AtLeast32Bit, Header as HeaderT, One, Zero};
use sp_state_machine::{ use sp_state_machine::{
MemoryDB, TrieBackend, Backend as StateBackend, StorageProof, InMemoryBackend, prove_read_on_trie_backend, read_proof_check, read_proof_check_on_proving_backend,
prove_read_on_trie_backend, read_proof_check, read_proof_check_on_proving_backend Backend as StateBackend, InMemoryBackend, MemoryDB, StorageProof, TrieBackend,
}; };
use sp_blockchain::{Error as ClientError, Result as ClientResult}; use sp_blockchain::{Error as ClientError, Result as ClientResult};
@@ -49,17 +49,17 @@ pub fn size<N: From<u32>>() -> N {
/// Returns Some(cht_number) if CHT is need to be built when the block with given number is canonized. /// Returns Some(cht_number) if CHT is need to be built when the block with given number is canonized.
pub fn is_build_required<N>(cht_size: N, block_num: N) -> Option<N> pub fn is_build_required<N>(cht_size: N, block_num: N) -> Option<N>
where where
N: Clone + AtLeast32Bit, N: Clone + AtLeast32Bit,
{ {
let block_cht_num = block_to_cht_number(cht_size.clone(), block_num.clone())?; let block_cht_num = block_to_cht_number(cht_size.clone(), block_num.clone())?;
let two = N::one() + N::one(); let two = N::one() + N::one();
if block_cht_num < two { if block_cht_num < two {
return None; return None
} }
let cht_start = start_number(cht_size, block_cht_num.clone()); let cht_start = start_number(cht_size, block_cht_num.clone());
if cht_start != block_num { if cht_start != block_num {
return None; return None
} }
Some(block_cht_num - two) Some(block_cht_num - two)
@@ -67,13 +67,13 @@ pub fn is_build_required<N>(cht_size: N, block_num: N) -> Option<N>
/// Returns Some(max_cht_number) if CHT has ever been built given maximal canonical block number. /// Returns Some(max_cht_number) if CHT has ever been built given maximal canonical block number.
pub fn max_cht_number<N>(cht_size: N, max_canonical_block: N) -> Option<N> pub fn max_cht_number<N>(cht_size: N, max_canonical_block: N) -> Option<N>
where where
N: Clone + AtLeast32Bit, N: Clone + AtLeast32Bit,
{ {
let max_cht_number = block_to_cht_number(cht_size, max_canonical_block)?; let max_cht_number = block_to_cht_number(cht_size, max_canonical_block)?;
let two = N::one() + N::one(); let two = N::one() + N::one();
if max_cht_number < two { if max_cht_number < two {
return None; return None
} }
Some(max_cht_number - two) Some(max_cht_number - two)
} }
@@ -86,16 +86,16 @@ pub fn compute_root<Header, Hasher, I>(
cht_num: Header::Number, cht_num: Header::Number,
hashes: I, hashes: I,
) -> ClientResult<Hasher::Out> ) -> ClientResult<Hasher::Out>
where where
Header: HeaderT, Header: HeaderT,
Hasher: hash_db::Hasher, Hasher: hash_db::Hasher,
Hasher::Out: Ord, Hasher::Out: Ord,
I: IntoIterator<Item=ClientResult<Option<Header::Hash>>>, I: IntoIterator<Item = ClientResult<Option<Header::Hash>>>,
{ {
use sp_trie::TrieConfiguration; use sp_trie::TrieConfiguration;
Ok(sp_trie::trie_types::Layout::<Hasher>::trie_root( Ok(sp_trie::trie_types::Layout::<Hasher>::trie_root(build_pairs::<Header, I>(
build_pairs::<Header, I>(cht_size, cht_num, hashes)? cht_size, cht_num, hashes,
)) )?))
} }
/// Build CHT-based header proof. /// Build CHT-based header proof.
@@ -103,26 +103,28 @@ pub fn build_proof<Header, Hasher, BlocksI, HashesI>(
cht_size: Header::Number, cht_size: Header::Number,
cht_num: Header::Number, cht_num: Header::Number,
blocks: BlocksI, blocks: BlocksI,
hashes: HashesI hashes: HashesI,
) -> ClientResult<StorageProof> ) -> ClientResult<StorageProof>
where where
Header: HeaderT, Header: HeaderT,
Hasher: hash_db::Hasher, Hasher: hash_db::Hasher,
Hasher::Out: Ord + codec::Codec, Hasher::Out: Ord + codec::Codec,
BlocksI: IntoIterator<Item=Header::Number>, BlocksI: IntoIterator<Item = Header::Number>,
HashesI: IntoIterator<Item=ClientResult<Option<Header::Hash>>>, HashesI: IntoIterator<Item = ClientResult<Option<Header::Hash>>>,
{ {
let transaction = build_pairs::<Header, _>(cht_size, cht_num, hashes)? let transaction = build_pairs::<Header, _>(cht_size, cht_num, hashes)?
.into_iter() .into_iter()
.map(|(k, v)| (k, Some(v))) .map(|(k, v)| (k, Some(v)))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut storage = InMemoryBackend::<Hasher>::default().update(vec![(None, transaction)]); let mut storage = InMemoryBackend::<Hasher>::default().update(vec![(None, transaction)]);
let trie_storage = storage.as_trie_backend() let trie_storage = storage
.as_trie_backend()
.expect("InMemoryState::as_trie_backend always returns Some; qed"); .expect("InMemoryState::as_trie_backend always returns Some; qed");
prove_read_on_trie_backend( prove_read_on_trie_backend(
trie_storage, trie_storage,
blocks.into_iter().map(|number| encode_cht_key(number)), blocks.into_iter().map(|number| encode_cht_key(number)),
).map_err(ClientError::from_state) )
.map_err(ClientError::from_state)
} }
/// Check CHT-based header proof. /// Check CHT-based header proof.
@@ -132,25 +134,24 @@ pub fn check_proof<Header, Hasher>(
remote_hash: Header::Hash, remote_hash: Header::Hash,
remote_proof: StorageProof, remote_proof: StorageProof,
) -> ClientResult<()> ) -> ClientResult<()>
where where
Header: HeaderT, Header: HeaderT,
Hasher: hash_db::Hasher, Hasher: hash_db::Hasher,
Hasher::Out: Ord + codec::Codec, Hasher::Out: Ord + codec::Codec,
{ {
do_check_proof::<Header, Hasher, _>( do_check_proof::<Header, Hasher, _>(
local_root, local_root,
local_number, local_number,
remote_hash, remote_hash,
move |local_root, local_cht_key| move |local_root, local_cht_key| {
read_proof_check::<Hasher, _>( read_proof_check::<Hasher, _>(
local_root, local_root,
remote_proof, remote_proof,
::std::iter::once(local_cht_key), ::std::iter::once(local_cht_key),
) )
.map(|mut map| map .map(|mut map| map.remove(local_cht_key).expect("checked proof of local_cht_key; qed"))
.remove(local_cht_key) .map_err(ClientError::from_state)
.expect("checked proof of local_cht_key; qed")) },
.map_err(ClientError::from_state),
) )
} }
@@ -161,20 +162,19 @@ pub fn check_proof_on_proving_backend<Header, Hasher>(
remote_hash: Header::Hash, remote_hash: Header::Hash,
proving_backend: &TrieBackend<MemoryDB<Hasher>, Hasher>, proving_backend: &TrieBackend<MemoryDB<Hasher>, Hasher>,
) -> ClientResult<()> ) -> ClientResult<()>
where where
Header: HeaderT, Header: HeaderT,
Hasher: hash_db::Hasher, Hasher: hash_db::Hasher,
Hasher::Out: Ord + codec::Codec, Hasher::Out: Ord + codec::Codec,
{ {
do_check_proof::<Header, Hasher, _>( do_check_proof::<Header, Hasher, _>(
local_root, local_root,
local_number, local_number,
remote_hash, remote_hash,
|_, local_cht_key| |_, local_cht_key| {
read_proof_check_on_proving_backend::<Hasher>( read_proof_check_on_proving_backend::<Hasher>(proving_backend, local_cht_key)
proving_backend, .map_err(ClientError::from_state)
local_cht_key, },
).map_err(ClientError::from_state),
) )
} }
@@ -185,22 +185,22 @@ fn do_check_proof<Header, Hasher, F>(
remote_hash: Header::Hash, remote_hash: Header::Hash,
checker: F, checker: F,
) -> ClientResult<()> ) -> ClientResult<()>
where where
Header: HeaderT, Header: HeaderT,
Hasher: hash_db::Hasher, Hasher: hash_db::Hasher,
Hasher::Out: Ord, Hasher::Out: Ord,
F: FnOnce(Hasher::Out, &[u8]) -> ClientResult<Option<Vec<u8>>>, F: FnOnce(Hasher::Out, &[u8]) -> ClientResult<Option<Vec<u8>>>,
{ {
let root: Hasher::Out = convert_hash(&local_root); let root: Hasher::Out = convert_hash(&local_root);
let local_cht_key = encode_cht_key(local_number); let local_cht_key = encode_cht_key(local_number);
let local_cht_value = checker(root, &local_cht_key)?; let local_cht_value = checker(root, &local_cht_key)?;
let local_cht_value = local_cht_value.ok_or_else(|| ClientError::InvalidCHTProof)?; let local_cht_value = local_cht_value.ok_or_else(|| ClientError::InvalidCHTProof)?;
let local_hash = decode_cht_value(&local_cht_value).ok_or_else(|| ClientError::InvalidCHTProof)?; let local_hash =
decode_cht_value(&local_cht_value).ok_or_else(|| ClientError::InvalidCHTProof)?;
match &local_hash[..] == remote_hash.as_ref() { match &local_hash[..] == remote_hash.as_ref() {
true => Ok(()), true => Ok(()),
false => Err(ClientError::InvalidCHTProof.into()), false => Err(ClientError::InvalidCHTProof.into()),
} }
} }
/// Group ordered blocks by CHT number and call functor with blocks of each group. /// Group ordered blocks by CHT number and call functor with blocks of each group.
@@ -210,29 +210,31 @@ pub fn for_each_cht_group<Header, I, F, P>(
mut functor: F, mut functor: F,
mut functor_param: P, mut functor_param: P,
) -> ClientResult<()> ) -> ClientResult<()>
where where
Header: HeaderT, Header: HeaderT,
I: IntoIterator<Item=Header::Number>, I: IntoIterator<Item = Header::Number>,
F: FnMut(P, Header::Number, Vec<Header::Number>) -> ClientResult<P>, F: FnMut(P, Header::Number, Vec<Header::Number>) -> ClientResult<P>,
{ {
let mut current_cht_num = None; let mut current_cht_num = None;
let mut current_cht_blocks = Vec::new(); let mut current_cht_blocks = Vec::new();
for block in blocks { for block in blocks {
let new_cht_num = block_to_cht_number(cht_size, block).ok_or_else(|| ClientError::Backend(format!( let new_cht_num = block_to_cht_number(cht_size, block).ok_or_else(|| {
"Cannot compute CHT root for the block #{}", block)) ClientError::Backend(format!("Cannot compute CHT root for the block #{}", block))
)?; })?;
let advance_to_next_cht = current_cht_num.is_some() && current_cht_num != Some(new_cht_num); let advance_to_next_cht = current_cht_num.is_some() && current_cht_num != Some(new_cht_num);
if advance_to_next_cht { if advance_to_next_cht {
let current_cht_num = current_cht_num.expect("advance_to_next_cht is true; let current_cht_num = current_cht_num.expect(
it is true only when current_cht_num is Some; qed"); "advance_to_next_cht is true;
assert!(new_cht_num > current_cht_num, "for_each_cht_group only supports ordered iterators"); it is true only when current_cht_num is Some; qed",
);
assert!(
new_cht_num > current_cht_num,
"for_each_cht_group only supports ordered iterators"
);
functor_param = functor( functor_param =
functor_param, functor(functor_param, current_cht_num, std::mem::take(&mut current_cht_blocks))?;
current_cht_num,
std::mem::take(&mut current_cht_blocks),
)?;
} }
current_cht_blocks.push(block); current_cht_blocks.push(block);
@@ -240,11 +242,7 @@ pub fn for_each_cht_group<Header, I, F, P>(
} }
if let Some(current_cht_num) = current_cht_num { if let Some(current_cht_num) = current_cht_num {
functor( functor(functor_param, current_cht_num, std::mem::take(&mut current_cht_blocks))?;
functor_param,
current_cht_num,
std::mem::take(&mut current_cht_blocks),
)?;
} }
Ok(()) Ok(())
@@ -254,26 +252,22 @@ pub fn for_each_cht_group<Header, I, F, P>(
fn build_pairs<Header, I>( fn build_pairs<Header, I>(
cht_size: Header::Number, cht_size: Header::Number,
cht_num: Header::Number, cht_num: Header::Number,
hashes: I hashes: I,
) -> ClientResult<Vec<(Vec<u8>, Vec<u8>)>> ) -> ClientResult<Vec<(Vec<u8>, Vec<u8>)>>
where where
Header: HeaderT, Header: HeaderT,
I: IntoIterator<Item=ClientResult<Option<Header::Hash>>>, I: IntoIterator<Item = ClientResult<Option<Header::Hash>>>,
{ {
let start_num = start_number(cht_size, cht_num); let start_num = start_number(cht_size, cht_num);
let mut pairs = Vec::new(); let mut pairs = Vec::new();
let mut hash_index = Header::Number::zero(); let mut hash_index = Header::Number::zero();
for hash in hashes.into_iter() { for hash in hashes.into_iter() {
let hash = hash?.ok_or_else(|| ClientError::from( let hash =
ClientError::MissingHashRequiredForCHT hash?.ok_or_else(|| ClientError::from(ClientError::MissingHashRequiredForCHT))?;
))?; pairs.push((encode_cht_key(start_num + hash_index).to_vec(), encode_cht_value(hash)));
pairs.push((
encode_cht_key(start_num + hash_index).to_vec(),
encode_cht_value(hash)
));
hash_index += Header::Number::one(); hash_index += Header::Number::one();
if hash_index == cht_size { if hash_index == cht_size {
break; break
} }
} }
@@ -325,7 +319,6 @@ pub fn decode_cht_value(value: &[u8]) -> Option<H256> {
32 => Some(H256::from_slice(&value[0..32])), 32 => Some(H256::from_slice(&value[0..32])),
_ => None, _ => None,
} }
} }
#[cfg(test)] #[cfg(test)]
@@ -379,8 +372,12 @@ mod tests {
#[test] #[test]
fn build_pairs_fails_when_no_enough_blocks() { fn build_pairs_fails_when_no_enough_blocks() {
assert!(build_pairs::<Header, _>(SIZE as _, 0, assert!(build_pairs::<Header, _>(
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize / 2)).is_err()); SIZE as _,
0,
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize / 2)
)
.is_err());
} }
#[test] #[test]
@@ -391,9 +388,12 @@ mod tests {
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))) ::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
.take(SIZE as usize / 2) .take(SIZE as usize / 2)
.chain(::std::iter::once(Ok(None))) .chain(::std::iter::once(Ok(None)))
.chain(::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(2)))) .chain(
.take(SIZE as usize / 2 - 1)) ::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(2))))
).is_err()); .take(SIZE as usize / 2 - 1)
)
)
.is_err());
} }
#[test] #[test]
@@ -401,9 +401,9 @@ mod tests {
assert!(compute_root::<Header, BlakeTwo256, _>( assert!(compute_root::<Header, BlakeTwo256, _>(
SIZE as _, SIZE as _,
42, 42,
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))) ::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize)
.take(SIZE as usize) )
).is_ok()); .is_ok());
} }
#[test] #[test]
@@ -413,9 +413,9 @@ mod tests {
SIZE as _, SIZE as _,
0, 0,
vec![(SIZE * 1000) as u64], vec![(SIZE * 1000) as u64],
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))) ::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize)
.take(SIZE as usize) )
).is_err()); .is_err());
} }
#[test] #[test]
@@ -424,9 +424,9 @@ mod tests {
SIZE as _, SIZE as _,
0, 0,
vec![(SIZE / 2) as u64], vec![(SIZE / 2) as u64],
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))) ::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize)
.take(SIZE as usize) )
).is_ok()); .is_ok());
} }
#[test] #[test]
@@ -447,19 +447,27 @@ mod tests {
let _ = for_each_cht_group::<Header, _, _, _>( let _ = for_each_cht_group::<Header, _, _, _>(
cht_size, cht_size,
vec![ vec![
cht_size * 2 + 1, cht_size * 2 + 2, cht_size * 2 + 5, cht_size * 2 + 1,
cht_size * 4 + 1, cht_size * 4 + 7, cht_size * 2 + 2,
cht_size * 6 + 1 cht_size * 2 + 5,
], |_, cht_num, blocks| { cht_size * 4 + 1,
cht_size * 4 + 7,
cht_size * 6 + 1,
],
|_, cht_num, blocks| {
match cht_num { match cht_num {
2 => assert_eq!(blocks, vec![cht_size * 2 + 1, cht_size * 2 + 2, cht_size * 2 + 5]), 2 => assert_eq!(
blocks,
vec![cht_size * 2 + 1, cht_size * 2 + 2, cht_size * 2 + 5]
),
4 => assert_eq!(blocks, vec![cht_size * 4 + 1, cht_size * 4 + 7]), 4 => assert_eq!(blocks, vec![cht_size * 4 + 1, cht_size * 4 + 7]),
6 => assert_eq!(blocks, vec![cht_size * 6 + 1]), 6 => assert_eq!(blocks, vec![cht_size * 6 + 1]),
_ => unreachable!(), _ => unreachable!(),
} }
Ok(()) Ok(())
}, () },
(),
); );
} }
} }
+18 -23
View File
@@ -18,20 +18,19 @@
//! A set of APIs supported by the client along with their primitives. //! A set of APIs supported by the client along with their primitives.
use std::{fmt, collections::HashSet, sync::Arc, convert::TryFrom}; use sp_consensus::BlockOrigin;
use sp_core::storage::StorageKey; use sp_core::storage::StorageKey;
use sp_runtime::{ use sp_runtime::{
traits::{Block as BlockT, NumberFor},
generic::{BlockId, SignedBlock}, generic::{BlockId, SignedBlock},
traits::{Block as BlockT, NumberFor},
Justifications, Justifications,
}; };
use sp_consensus::BlockOrigin; use std::{collections::HashSet, convert::TryFrom, fmt, sync::Arc};
use crate::blockchain::Info; use crate::{blockchain::Info, notifications::StorageEventStream};
use crate::notifications::StorageEventStream;
use sp_utils::mpsc::TracingUnboundedReceiver;
use sp_blockchain;
use sc_transaction_pool_api::ChainEvent; use sc_transaction_pool_api::ChainEvent;
use sp_blockchain;
use sp_utils::mpsc::TracingUnboundedReceiver;
/// Type that implements `futures::Stream` of block import events. /// Type that implements `futures::Stream` of block import events.
pub type ImportNotifications<Block> = TracingUnboundedReceiver<BlockImportNotification<Block>>; pub type ImportNotifications<Block> = TracingUnboundedReceiver<BlockImportNotification<Block>>;
@@ -82,7 +81,7 @@ pub trait BlockBackend<Block: BlockT> {
/// Get block body by ID. Returns `None` if the body is not stored. /// Get block body by ID. Returns `None` if the body is not stored.
fn block_body( fn block_body(
&self, &self,
id: &BlockId<Block> id: &BlockId<Block>,
) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>>; ) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
/// Get all indexed transactions for a block, /// Get all indexed transactions for a block,
@@ -99,7 +98,8 @@ pub trait BlockBackend<Block: BlockT> {
fn block(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<SignedBlock<Block>>>; fn block(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<SignedBlock<Block>>>;
/// Get block status. /// Get block status.
fn block_status(&self, id: &BlockId<Block>) -> sp_blockchain::Result<sp_consensus::BlockStatus>; fn block_status(&self, id: &BlockId<Block>)
-> sp_blockchain::Result<sp_consensus::BlockStatus>;
/// Get block justifications for the block with the given id. /// Get block justifications for the block with the given id.
fn justifications(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<Justifications>>; fn justifications(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<Justifications>>;
@@ -107,14 +107,11 @@ pub trait BlockBackend<Block: BlockT> {
/// Get block hash by number. /// Get block hash by number.
fn block_hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>>; fn block_hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>>;
/// Get single indexed transaction by content hash. /// Get single indexed transaction by content hash.
/// ///
/// Note that this will only fetch transactions /// Note that this will only fetch transactions
/// that are indexed by the runtime with `storage_index_transaction`. /// that are indexed by the runtime with `storage_index_transaction`.
fn indexed_transaction( fn indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result<Option<Vec<u8>>>;
&self,
hash: &Block::Hash,
) -> sp_blockchain::Result<Option<Vec<u8>>>;
/// Check if transaction index exists. /// Check if transaction index exists.
fn has_indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result<bool> { fn has_indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result<bool> {
@@ -125,8 +122,11 @@ pub trait BlockBackend<Block: BlockT> {
/// Provide a list of potential uncle headers for a given block. /// Provide a list of potential uncle headers for a given block.
pub trait ProvideUncles<Block: BlockT> { pub trait ProvideUncles<Block: BlockT> {
/// Gets the uncles of the block with `target_hash` going back `max_generation` ancestors. /// Gets the uncles of the block with `target_hash` going back `max_generation` ancestors.
fn uncles(&self, target_hash: Block::Hash, max_generation: NumberFor<Block>) fn uncles(
-> sp_blockchain::Result<Vec<Block::Header>>; &self,
target_hash: Block::Hash,
max_generation: NumberFor<Block>,
) -> sp_blockchain::Result<Vec<Block::Header>>;
} }
/// Client info /// Client info
@@ -284,10 +284,7 @@ impl<B: BlockT> TryFrom<BlockImportNotification<B>> for ChainEvent<B> {
fn try_from(n: BlockImportNotification<B>) -> Result<Self, ()> { fn try_from(n: BlockImportNotification<B>) -> Result<Self, ()> {
if n.is_new_best { if n.is_new_best {
Ok(Self::NewBestBlock { Ok(Self::NewBestBlock { hash: n.hash, tree_route: n.tree_route })
hash: n.hash,
tree_route: n.tree_route,
})
} else { } else {
Err(()) Err(())
} }
@@ -296,8 +293,6 @@ impl<B: BlockT> TryFrom<BlockImportNotification<B>> for ChainEvent<B> {
impl<B: BlockT> From<FinalityNotification<B>> for ChainEvent<B> { impl<B: BlockT> From<FinalityNotification<B>> for ChainEvent<B> {
fn from(n: FinalityNotification<B>) -> Self { fn from(n: FinalityNotification<B>) -> Self {
Self::Finalized { Self::Finalized { hash: n.hash }
hash: n.hash,
}
} }
} }
@@ -22,22 +22,19 @@
//! strategy for the runtime calls and provide the right `Externalities` //! strategy for the runtime calls and provide the right `Externalities`
//! extensions to support APIs for particular execution context & capabilities. //! extensions to support APIs for particular execution context & capabilities.
use std::sync::{Weak, Arc};
use codec::Decode; use codec::Decode;
use sp_core::{
ExecutionContext,
offchain::{self, OffchainWorkerExt, TransactionPoolExt, OffchainDbExt},
};
use sp_keystore::{KeystoreExt, SyncCryptoStorePtr};
use sp_runtime::{
generic::BlockId,
traits,
};
use sp_state_machine::{ExecutionManager, DefaultHandler};
pub use sp_state_machine::ExecutionStrategy;
use sp_externalities::Extensions;
use parking_lot::RwLock; use parking_lot::RwLock;
use sc_transaction_pool_api::OffchainSubmitTransaction; use sc_transaction_pool_api::OffchainSubmitTransaction;
use sp_core::{
offchain::{self, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt},
ExecutionContext,
};
use sp_externalities::Extensions;
use sp_keystore::{KeystoreExt, SyncCryptoStorePtr};
use sp_runtime::{generic::BlockId, traits};
pub use sp_state_machine::ExecutionStrategy;
use sp_state_machine::{DefaultHandler, ExecutionManager};
use std::sync::{Arc, Weak};
/// Execution strategies settings. /// Execution strategies settings.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -151,7 +148,8 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
/// Register transaction pool extension. /// Register transaction pool extension.
pub fn register_transaction_pool<T>(&self, pool: &Arc<T>) pub fn register_transaction_pool<T>(&self, pool: &Arc<T>)
where T: OffchainSubmitTransaction<Block> + 'static where
T: OffchainSubmitTransaction<Block> + 'static,
{ {
*self.transaction_pool.write() = Some(Arc::downgrade(&pool) as _); *self.transaction_pool.write() = Some(Arc::downgrade(&pool) as _);
} }
@@ -171,14 +169,10 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
if capabilities.has(offchain::Capability::TransactionPool) { if capabilities.has(offchain::Capability::TransactionPool) {
if let Some(pool) = self.transaction_pool.read().as_ref().and_then(|x| x.upgrade()) { if let Some(pool) = self.transaction_pool.read().as_ref().and_then(|x| x.upgrade()) {
extensions.register( extensions
TransactionPoolExt( .register(TransactionPoolExt(
Box::new(TransactionPoolAdapter { Box::new(TransactionPoolAdapter { at: *at, pool }) as _,
at: *at, ));
pool,
}) as _
),
);
} }
} }
@@ -186,19 +180,18 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
capabilities.has(offchain::Capability::OffchainDbWrite) capabilities.has(offchain::Capability::OffchainDbWrite)
{ {
if let Some(offchain_db) = self.offchain_db.as_ref() { if let Some(offchain_db) = self.offchain_db.as_ref() {
extensions.register( extensions.register(OffchainDbExt::new(offchain::LimitedExternalities::new(
OffchainDbExt::new(offchain::LimitedExternalities::new( capabilities,
capabilities, offchain_db.create(),
offchain_db.create(), )));
))
);
} }
} }
if let ExecutionContext::OffchainCall(Some(ext)) = context { if let ExecutionContext::OffchainCall(Some(ext)) = context {
extensions.register( extensions.register(OffchainWorkerExt::new(offchain::LimitedExternalities::new(
OffchainWorkerExt::new(offchain::LimitedExternalities::new(capabilities, ext.0)), capabilities,
); ext.0,
)));
} }
extensions extensions
@@ -212,21 +205,14 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
&self, &self,
at: &BlockId<Block>, at: &BlockId<Block>,
context: ExecutionContext, context: ExecutionContext,
) -> ( ) -> (ExecutionManager<DefaultHandler<R, E>>, Extensions) {
ExecutionManager<DefaultHandler<R, E>>,
Extensions,
) {
let manager = match context { let manager = match context {
ExecutionContext::BlockConstruction => ExecutionContext::BlockConstruction => self.strategies.block_construction.get_manager(),
self.strategies.block_construction.get_manager(), ExecutionContext::Syncing => self.strategies.syncing.get_manager(),
ExecutionContext::Syncing => ExecutionContext::Importing => self.strategies.importing.get_manager(),
self.strategies.syncing.get_manager(),
ExecutionContext::Importing =>
self.strategies.importing.get_manager(),
ExecutionContext::OffchainCall(Some((_, capabilities))) if capabilities.has_all() => ExecutionContext::OffchainCall(Some((_, capabilities))) if capabilities.has_all() =>
self.strategies.offchain_worker.get_manager(), self.strategies.offchain_worker.get_manager(),
ExecutionContext::OffchainCall(_) => ExecutionContext::OffchainCall(_) => self.strategies.other.get_manager(),
self.strategies.other.get_manager(),
}; };
(manager, self.extensions(at, context)) (manager, self.extensions(at, context))
@@ -245,7 +231,7 @@ impl<Block: traits::Block> offchain::TransactionPool for TransactionPoolAdapter<
Ok(xt) => xt, Ok(xt) => xt,
Err(e) => { Err(e) => {
log::warn!("Unable to decode extrinsic: {:?}: {}", data, e); log::warn!("Unable to decode extrinsic: {:?}: {}", data, e);
return Err(()); return Err(())
}, },
}; };
+231 -137
View File
@@ -18,30 +18,31 @@
//! In memory client backend //! In memory client backend
use std::collections::{HashMap, HashSet};
use std::ptr;
use std::sync::Arc;
use parking_lot::RwLock; use parking_lot::RwLock;
use sp_core::{
storage::well_known_keys, offchain::storage::InMemOffchainStorage as OffchainStorage,
};
use sp_runtime::generic::BlockId;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Zero, NumberFor, HashFor};
use sp_runtime::{Justification, Justifications, Storage};
use sp_state_machine::{
ChangesTrieTransaction, InMemoryBackend, Backend as StateBackend, StorageCollection,
ChildStorageCollection, IndexOperation,
};
use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata}; use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata};
use sp_core::{
offchain::storage::InMemOffchainStorage as OffchainStorage, storage::well_known_keys,
};
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, HashFor, Header as HeaderT, NumberFor, Zero},
Justification, Justifications, Storage,
};
use sp_state_machine::{
Backend as StateBackend, ChangesTrieTransaction, ChildStorageCollection, InMemoryBackend,
IndexOperation, StorageCollection,
};
use std::{
collections::{HashMap, HashSet},
ptr,
sync::Arc,
};
use crate::{ use crate::{
backend::{self, NewBlockState, ProvideChtRoots}, backend::{self, NewBlockState, ProvideChtRoots},
blockchain::{ blockchain::{self, well_known_cache_keys::Id as CacheKeyId, BlockStatus, HeaderBackend},
self, BlockStatus, HeaderBackend, well_known_cache_keys::Id as CacheKeyId
},
UsageInfo,
light,
leaves::LeafSet, leaves::LeafSet,
light, UsageInfo,
}; };
struct PendingBlock<B: BlockT> { struct PendingBlock<B: BlockT> {
@@ -56,7 +57,11 @@ enum StoredBlock<B: BlockT> {
} }
impl<B: BlockT> StoredBlock<B> { impl<B: BlockT> StoredBlock<B> {
fn new(header: B::Header, body: Option<Vec<B::Extrinsic>>, just: Option<Justifications>) -> Self { fn new(
header: B::Header,
body: Option<Vec<B::Extrinsic>>,
just: Option<Justifications>,
) -> Self {
match body { match body {
Some(body) => StoredBlock::Full(B::new(header, body), just), Some(body) => StoredBlock::Full(B::new(header, body), just),
None => StoredBlock::Header(header, just), None => StoredBlock::Header(header, just),
@@ -72,7 +77,7 @@ impl<B: BlockT> StoredBlock<B> {
fn justifications(&self) -> Option<&Justifications> { fn justifications(&self) -> Option<&Justifications> {
match *self { match *self {
StoredBlock::Header(_, ref j) | StoredBlock::Full(_, ref j) => j.as_ref() StoredBlock::Header(_, ref j) | StoredBlock::Full(_, ref j) => j.as_ref(),
} }
} }
@@ -89,7 +94,7 @@ impl<B: BlockT> StoredBlock<B> {
StoredBlock::Full(block, just) => { StoredBlock::Full(block, just) => {
let (header, body) = block.deconstruct(); let (header, body) = block.deconstruct();
(header, Some(body), just) (header, Some(body), just)
} },
} }
} }
} }
@@ -123,9 +128,7 @@ impl<Block: BlockT> Default for Blockchain<Block> {
impl<Block: BlockT + Clone> Clone for Blockchain<Block> { impl<Block: BlockT + Clone> Clone for Blockchain<Block> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
let storage = Arc::new(RwLock::new(self.storage.read().clone())); let storage = Arc::new(RwLock::new(self.storage.read().clone()));
Blockchain { Blockchain { storage }
storage,
}
} }
} }
@@ -140,23 +143,20 @@ impl<Block: BlockT> Blockchain<Block> {
/// Create new in-memory blockchain storage. /// Create new in-memory blockchain storage.
pub fn new() -> Blockchain<Block> { pub fn new() -> Blockchain<Block> {
let storage = Arc::new(RwLock::new( let storage = Arc::new(RwLock::new(BlockchainStorage {
BlockchainStorage { blocks: HashMap::new(),
blocks: HashMap::new(), hashes: HashMap::new(),
hashes: HashMap::new(), best_hash: Default::default(),
best_hash: Default::default(), best_number: Zero::zero(),
best_number: Zero::zero(), finalized_hash: Default::default(),
finalized_hash: Default::default(), finalized_number: Zero::zero(),
finalized_number: Zero::zero(), genesis_hash: Default::default(),
genesis_hash: Default::default(), header_cht_roots: HashMap::new(),
header_cht_roots: HashMap::new(), changes_trie_cht_roots: HashMap::new(),
changes_trie_cht_roots: HashMap::new(), leaves: LeafSet::new(),
leaves: LeafSet::new(), aux: HashMap::new(),
aux: HashMap::new(), }));
})); Blockchain { storage }
Blockchain {
storage,
}
} }
/// Insert a block header and associated data. /// Insert a block header and associated data.
@@ -175,8 +175,12 @@ impl<Block: BlockT> Blockchain<Block> {
{ {
let mut storage = self.storage.write(); let mut storage = self.storage.write();
storage.leaves.import(hash.clone(), number.clone(), header.parent_hash().clone()); storage
storage.blocks.insert(hash.clone(), StoredBlock::new(header, body, justifications)); .leaves
.import(hash.clone(), number.clone(), header.parent_hash().clone());
storage
.blocks
.insert(hash.clone(), StoredBlock::new(header, body, justifications));
if let NewBlockState::Final = new_state { if let NewBlockState::Final = new_state {
storage.finalized_hash = hash; storage.finalized_hash = hash;
@@ -200,7 +204,7 @@ impl<Block: BlockT> Blockchain<Block> {
pub fn equals_to(&self, other: &Self) -> bool { pub fn equals_to(&self, other: &Self) -> bool {
// Check ptr equality first to avoid double read locks. // Check ptr equality first to avoid double read locks.
if ptr::eq(self, other) { if ptr::eq(self, other) {
return true; return true
} }
self.canon_equals_to(other) && self.storage.read().blocks == other.storage.read().blocks self.canon_equals_to(other) && self.storage.read().blocks == other.storage.read().blocks
} }
@@ -209,14 +213,14 @@ impl<Block: BlockT> Blockchain<Block> {
pub fn canon_equals_to(&self, other: &Self) -> bool { pub fn canon_equals_to(&self, other: &Self) -> bool {
// Check ptr equality first to avoid double read locks. // Check ptr equality first to avoid double read locks.
if ptr::eq(self, other) { if ptr::eq(self, other) {
return true; return true
} }
let this = self.storage.read(); let this = self.storage.read();
let other = other.storage.read(); let other = other.storage.read();
this.hashes == other.hashes this.hashes == other.hashes &&
&& this.best_hash == other.best_hash this.best_hash == other.best_hash &&
&& this.best_number == other.best_number this.best_number == other.best_number &&
&& this.genesis_hash == other.genesis_hash this.genesis_hash == other.genesis_hash
} }
/// Insert header CHT root. /// Insert header CHT root.
@@ -226,7 +230,8 @@ impl<Block: BlockT> Blockchain<Block> {
/// Set an existing block as head. /// Set an existing block as head.
pub fn set_head(&self, id: BlockId<Block>) -> sp_blockchain::Result<()> { pub fn set_head(&self, id: BlockId<Block>) -> sp_blockchain::Result<()> {
let header = self.header(id)? let header = self
.header(id)?
.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", id)))?; .ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", id)))?;
self.apply_head(&header) self.apply_head(&header)
@@ -270,7 +275,11 @@ impl<Block: BlockT> Blockchain<Block> {
Ok(()) Ok(())
} }
fn finalize_header(&self, id: BlockId<Block>, justification: Option<Justification>) -> sp_blockchain::Result<()> { fn finalize_header(
&self,
id: BlockId<Block>,
justification: Option<Justification>,
) -> sp_blockchain::Result<()> {
let hash = match self.header(id)? { let hash = match self.header(id)? {
Some(h) => h.hash(), Some(h) => h.hash(),
None => return Err(sp_blockchain::Error::UnknownBlock(format!("{}", id))), None => return Err(sp_blockchain::Error::UnknownBlock(format!("{}", id))),
@@ -280,11 +289,13 @@ impl<Block: BlockT> Blockchain<Block> {
storage.finalized_hash = hash; storage.finalized_hash = hash;
if justification.is_some() { if justification.is_some() {
let block = storage.blocks.get_mut(&hash) let block = storage
.blocks
.get_mut(&hash)
.expect("hash was fetched from a block in the db; qed"); .expect("hash was fetched from a block in the db; qed");
let block_justifications = match block { let block_justifications = match block {
StoredBlock::Header(_, ref mut j) | StoredBlock::Full(_, ref mut j) => j StoredBlock::Header(_, ref mut j) | StoredBlock::Full(_, ref mut j) => j,
}; };
*block_justifications = justification.map(Justifications::from); *block_justifications = justification.map(Justifications::from);
@@ -293,9 +304,11 @@ impl<Block: BlockT> Blockchain<Block> {
Ok(()) Ok(())
} }
fn append_justification(&self, id: BlockId<Block>, justification: Justification) fn append_justification(
-> sp_blockchain::Result<()> &self,
{ id: BlockId<Block>,
justification: Justification,
) -> sp_blockchain::Result<()> {
let hash = self.expect_block_hash_from_id(&id)?; let hash = self.expect_block_hash_from_id(&id)?;
let mut storage = self.storage.write(); let mut storage = self.storage.write();
@@ -305,14 +318,14 @@ impl<Block: BlockT> Blockchain<Block> {
.expect("hash was fetched from a block in the db; qed"); .expect("hash was fetched from a block in the db; qed");
let block_justifications = match block { let block_justifications = match block {
StoredBlock::Header(_, ref mut j) | StoredBlock::Full(_, ref mut j) => j StoredBlock::Header(_, ref mut j) | StoredBlock::Full(_, ref mut j) => j,
}; };
if let Some(stored_justifications) = block_justifications { if let Some(stored_justifications) = block_justifications {
if !stored_justifications.append(justification) { if !stored_justifications.append(justification) {
return Err(sp_blockchain::Error::BadJustification( return Err(sp_blockchain::Error::BadJustification(
"Duplicate consensus engine ID".into() "Duplicate consensus engine ID".into(),
)); ))
} }
} else { } else {
*block_justifications = Some(Justifications::from(justification)); *block_justifications = Some(Justifications::from(justification));
@@ -333,10 +346,13 @@ impl<Block: BlockT> Blockchain<Block> {
} }
impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> { impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
fn header(&self, id: BlockId<Block>) -> sp_blockchain::Result<Option<<Block as BlockT>::Header>> { fn header(
Ok(self.id(id).and_then(|hash| { &self,
self.storage.read().blocks.get(&hash).map(|b| b.header().clone()) id: BlockId<Block>,
})) ) -> sp_blockchain::Result<Option<<Block as BlockT>::Header>> {
Ok(self
.id(id)
.and_then(|hash| self.storage.read().blocks.get(&hash).map(|b| b.header().clone())))
} }
fn info(&self) -> blockchain::Info<Block> { fn info(&self) -> blockchain::Info<Block> {
@@ -352,7 +368,7 @@ impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
} else { } else {
None None
}, },
number_leaves: storage.leaves.count() number_leaves: storage.leaves.count(),
} }
} }
@@ -367,7 +383,10 @@ impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
Ok(self.storage.read().blocks.get(&hash).map(|b| *b.header().number())) Ok(self.storage.read().blocks.get(&hash).map(|b| *b.header().number()))
} }
fn hash(&self, number: <<Block as BlockT>::Header as HeaderT>::Number) -> sp_blockchain::Result<Option<Block::Hash>> { fn hash(
&self,
number: <<Block as BlockT>::Header as HeaderT>::Number,
) -> sp_blockchain::Result<Option<Block::Hash>> {
Ok(self.id(BlockId::Number(number))) Ok(self.id(BlockId::Number(number)))
} }
} }
@@ -375,9 +394,15 @@ impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
impl<Block: BlockT> HeaderMetadata<Block> for Blockchain<Block> { impl<Block: BlockT> HeaderMetadata<Block> for Blockchain<Block> {
type Error = sp_blockchain::Error; type Error = sp_blockchain::Error;
fn header_metadata(&self, hash: Block::Hash) -> Result<CachedHeaderMetadata<Block>, Self::Error> { fn header_metadata(
self.header(BlockId::hash(hash))?.map(|header| CachedHeaderMetadata::from(&header)) &self,
.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("header not found: {}", hash))) hash: Block::Hash,
) -> Result<CachedHeaderMetadata<Block>, Self::Error> {
self.header(BlockId::hash(hash))?
.map(|header| CachedHeaderMetadata::from(&header))
.ok_or_else(|| {
sp_blockchain::Error::UnknownBlock(format!("header not found: {}", hash))
})
} }
fn insert_header_metadata(&self, _hash: Block::Hash, _metadata: CachedHeaderMetadata<Block>) { fn insert_header_metadata(&self, _hash: Block::Hash, _metadata: CachedHeaderMetadata<Block>) {
@@ -389,17 +414,27 @@ impl<Block: BlockT> HeaderMetadata<Block> for Blockchain<Block> {
} }
impl<Block: BlockT> blockchain::Backend<Block> for Blockchain<Block> { impl<Block: BlockT> blockchain::Backend<Block> for Blockchain<Block> {
fn body(&self, id: BlockId<Block>) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> { fn body(
&self,
id: BlockId<Block>,
) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
Ok(self.id(id).and_then(|hash| { Ok(self.id(id).and_then(|hash| {
self.storage.read().blocks.get(&hash) self.storage
.read()
.blocks
.get(&hash)
.and_then(|b| b.extrinsics().map(|x| x.to_vec())) .and_then(|b| b.extrinsics().map(|x| x.to_vec()))
})) }))
} }
fn justifications(&self, id: BlockId<Block>) -> sp_blockchain::Result<Option<Justifications>> { fn justifications(&self, id: BlockId<Block>) -> sp_blockchain::Result<Option<Justifications>> {
Ok(self.id(id).and_then(|hash| self.storage.read().blocks.get(&hash).and_then(|b| Ok(self.id(id).and_then(|hash| {
b.justifications().map(|x| x.clone())) self.storage
)) .read()
.blocks
.get(&hash)
.and_then(|b| b.justifications().map(|x| x.clone()))
}))
} }
fn last_finalized(&self) -> sp_blockchain::Result<Block::Hash> { fn last_finalized(&self) -> sp_blockchain::Result<Block::Hash> {
@@ -418,16 +453,13 @@ impl<Block: BlockT> blockchain::Backend<Block> for Blockchain<Block> {
unimplemented!() unimplemented!()
} }
fn indexed_transaction( fn indexed_transaction(&self, _hash: &Block::Hash) -> sp_blockchain::Result<Option<Vec<u8>>> {
&self,
_hash: &Block::Hash,
) -> sp_blockchain::Result<Option<Vec<u8>>> {
unimplemented!("Not supported by the in-mem backend.") unimplemented!("Not supported by the in-mem backend.")
} }
fn block_indexed_body( fn block_indexed_body(
&self, &self,
_id: BlockId<Block> _id: BlockId<Block>,
) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>> { ) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>> {
unimplemented!("Not supported by the in-mem backend.") unimplemented!("Not supported by the in-mem backend.")
} }
@@ -444,9 +476,13 @@ impl<Block: BlockT> backend::AuxStore for Blockchain<Block> {
'a, 'a,
'b: 'a, 'b: 'a,
'c: 'a, 'c: 'a,
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>, I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
D: IntoIterator<Item=&'a &'b [u8]>, D: IntoIterator<Item = &'a &'b [u8]>,
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()> { >(
&self,
insert: I,
delete: D,
) -> sp_blockchain::Result<()> {
let mut storage = self.storage.write(); let mut storage = self.storage.write();
for (k, v) in insert { for (k, v) in insert {
storage.aux.insert(k.to_vec(), v.to_vec()); storage.aux.insert(k.to_vec(), v.to_vec());
@@ -463,8 +499,8 @@ impl<Block: BlockT> backend::AuxStore for Blockchain<Block> {
} }
impl<Block: BlockT> light::Storage<Block> for Blockchain<Block> impl<Block: BlockT> light::Storage<Block> for Blockchain<Block>
where where
Block::Hash: From<[u8; 32]>, Block::Hash: From<[u8; 32]>,
{ {
fn import_header( fn import_header(
&self, &self,
@@ -507,8 +543,14 @@ impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
_cht_size: NumberFor<Block>, _cht_size: NumberFor<Block>,
block: NumberFor<Block>, block: NumberFor<Block>,
) -> sp_blockchain::Result<Option<Block::Hash>> { ) -> sp_blockchain::Result<Option<Block::Hash>> {
self.storage.read().header_cht_roots.get(&block).cloned() self.storage
.ok_or_else(|| sp_blockchain::Error::Backend(format!("Header CHT for block {} not exists", block))) .read()
.header_cht_roots
.get(&block)
.cloned()
.ok_or_else(|| {
sp_blockchain::Error::Backend(format!("Header CHT for block {} not exists", block))
})
.map(Some) .map(Some)
} }
@@ -517,8 +559,17 @@ impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
_cht_size: NumberFor<Block>, _cht_size: NumberFor<Block>,
block: NumberFor<Block>, block: NumberFor<Block>,
) -> sp_blockchain::Result<Option<Block::Hash>> { ) -> sp_blockchain::Result<Option<Block::Hash>> {
self.storage.read().changes_trie_cht_roots.get(&block).cloned() self.storage
.ok_or_else(|| sp_blockchain::Error::Backend(format!("Changes trie CHT for block {} not exists", block))) .read()
.changes_trie_cht_roots
.get(&block)
.cloned()
.ok_or_else(|| {
sp_blockchain::Error::Backend(format!(
"Changes trie CHT for block {} not exists",
block
))
})
.map(Some) .map(Some)
} }
} }
@@ -527,25 +578,30 @@ impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
pub struct BlockImportOperation<Block: BlockT> { pub struct BlockImportOperation<Block: BlockT> {
pending_block: Option<PendingBlock<Block>>, pending_block: Option<PendingBlock<Block>>,
old_state: InMemoryBackend<HashFor<Block>>, old_state: InMemoryBackend<HashFor<Block>>,
new_state: Option<<InMemoryBackend<HashFor<Block>> as StateBackend<HashFor<Block>>>::Transaction>, new_state:
Option<<InMemoryBackend<HashFor<Block>> as StateBackend<HashFor<Block>>>::Transaction>,
aux: Vec<(Vec<u8>, Option<Vec<u8>>)>, aux: Vec<(Vec<u8>, Option<Vec<u8>>)>,
finalized_blocks: Vec<(BlockId<Block>, Option<Justification>)>, finalized_blocks: Vec<(BlockId<Block>, Option<Justification>)>,
set_head: Option<BlockId<Block>>, set_head: Option<BlockId<Block>>,
} }
impl<Block: BlockT> BlockImportOperation<Block> where impl<Block: BlockT> BlockImportOperation<Block>
where
Block::Hash: Ord, Block::Hash: Ord,
{ {
fn apply_storage(&mut self, storage: Storage, commit: bool) -> sp_blockchain::Result<Block::Hash> { fn apply_storage(
&mut self,
storage: Storage,
commit: bool,
) -> sp_blockchain::Result<Block::Hash> {
check_genesis_storage(&storage)?; check_genesis_storage(&storage)?;
let child_delta = storage.children_default.iter() let child_delta = storage.children_default.iter().map(|(_storage_key, child_content)| {
.map(|(_storage_key, child_content)| (
( &child_content.child_info,
&child_content.child_info, child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))),
child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))) )
) });
);
let (root, transaction) = self.old_state.full_storage_root( let (root, transaction) = self.old_state.full_storage_root(
storage.top.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))), storage.top.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))),
@@ -559,7 +615,8 @@ impl<Block: BlockT> BlockImportOperation<Block> where
} }
} }
impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperation<Block> where impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperation<Block>
where
Block::Hash: Ord, Block::Hash: Ord,
{ {
type State = InMemoryBackend<HashFor<Block>>; type State = InMemoryBackend<HashFor<Block>>;
@@ -577,10 +634,8 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
state: NewBlockState, state: NewBlockState,
) -> sp_blockchain::Result<()> { ) -> sp_blockchain::Result<()> {
assert!(self.pending_block.is_none(), "Only one block per operation is allowed"); assert!(self.pending_block.is_none(), "Only one block per operation is allowed");
self.pending_block = Some(PendingBlock { self.pending_block =
block: StoredBlock::new(header, body, justifications), Some(PendingBlock { block: StoredBlock::new(header, body, justifications), state });
state,
});
Ok(()) Ok(())
} }
@@ -601,7 +656,11 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
Ok(()) Ok(())
} }
fn set_genesis_state(&mut self, storage: Storage, commit: bool) -> sp_blockchain::Result<Block::Hash> { fn set_genesis_state(
&mut self,
storage: Storage,
commit: bool,
) -> sp_blockchain::Result<Block::Hash> {
self.apply_storage(storage, commit) self.apply_storage(storage, commit)
} }
@@ -610,7 +669,8 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
} }
fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()> fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()>
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)> where
I: IntoIterator<Item = (Vec<u8>, Option<Vec<u8>>)>,
{ {
self.aux.append(&mut ops.into_iter().collect()); self.aux.append(&mut ops.into_iter().collect());
Ok(()) Ok(())
@@ -639,7 +699,10 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
Ok(()) Ok(())
} }
fn update_transaction_index(&mut self, _index: Vec<IndexOperation>) -> sp_blockchain::Result<()> { fn update_transaction_index(
&mut self,
_index: Vec<IndexOperation>,
) -> sp_blockchain::Result<()> {
Ok(()) Ok(())
} }
} }
@@ -648,13 +711,19 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
/// ///
/// > **Warning**: Doesn't support all the features necessary for a proper database. Only use this /// > **Warning**: Doesn't support all the features necessary for a proper database. Only use this
/// > struct for testing purposes. Do **NOT** use in production. /// > struct for testing purposes. Do **NOT** use in production.
pub struct Backend<Block: BlockT> where Block::Hash: Ord { pub struct Backend<Block: BlockT>
where
Block::Hash: Ord,
{
states: RwLock<HashMap<Block::Hash, InMemoryBackend<HashFor<Block>>>>, states: RwLock<HashMap<Block::Hash, InMemoryBackend<HashFor<Block>>>>,
blockchain: Blockchain<Block>, blockchain: Blockchain<Block>,
import_lock: RwLock<()>, import_lock: RwLock<()>,
} }
impl<Block: BlockT> Backend<Block> where Block::Hash: Ord { impl<Block: BlockT> Backend<Block>
where
Block::Hash: Ord,
{
/// Create a new instance of in-mem backend. /// Create a new instance of in-mem backend.
pub fn new() -> Self { pub fn new() -> Self {
Backend { Backend {
@@ -665,14 +734,21 @@ impl<Block: BlockT> Backend<Block> where Block::Hash: Ord {
} }
} }
impl<Block: BlockT> backend::AuxStore for Backend<Block> where Block::Hash: Ord { impl<Block: BlockT> backend::AuxStore for Backend<Block>
where
Block::Hash: Ord,
{
fn insert_aux< fn insert_aux<
'a, 'a,
'b: 'a, 'b: 'a,
'c: 'a, 'c: 'a,
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>, I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
D: IntoIterator<Item=&'a &'b [u8]>, D: IntoIterator<Item = &'a &'b [u8]>,
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()> { >(
&self,
insert: I,
delete: D,
) -> sp_blockchain::Result<()> {
self.blockchain.insert_aux(insert, delete) self.blockchain.insert_aux(insert, delete)
} }
@@ -681,7 +757,10 @@ impl<Block: BlockT> backend::AuxStore for Backend<Block> where Block::Hash: Ord
} }
} }
impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash: Ord { impl<Block: BlockT> backend::Backend<Block> for Backend<Block>
where
Block::Hash: Ord,
{
type BlockImportOperation = BlockImportOperation<Block>; type BlockImportOperation = BlockImportOperation<Block>;
type Blockchain = Blockchain<Block>; type Blockchain = Blockchain<Block>;
type State = InMemoryBackend<HashFor<Block>>; type State = InMemoryBackend<HashFor<Block>>;
@@ -708,10 +787,7 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
Ok(()) Ok(())
} }
fn commit_operation( fn commit_operation(&self, operation: Self::BlockImportOperation) -> sp_blockchain::Result<()> {
&self,
operation: Self::BlockImportOperation,
) -> sp_blockchain::Result<()> {
if !operation.finalized_blocks.is_empty() { if !operation.finalized_blocks.is_empty() {
for (block, justification) in operation.finalized_blocks { for (block, justification) in operation.finalized_blocks {
self.blockchain.finalize_header(block, justification)?; self.blockchain.finalize_header(block, justification)?;
@@ -779,13 +855,13 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
fn state_at(&self, block: BlockId<Block>) -> sp_blockchain::Result<Self::State> { fn state_at(&self, block: BlockId<Block>) -> sp_blockchain::Result<Self::State> {
match block { match block {
BlockId::Hash(h) if h == Default::default() => { BlockId::Hash(h) if h == Default::default() => return Ok(Self::State::default()),
return Ok(Self::State::default());
},
_ => {}, _ => {},
} }
self.blockchain.id(block).and_then(|id| self.states.read().get(&id).cloned()) self.blockchain
.id(block)
.and_then(|id| self.states.read().get(&id).cloned())
.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", block))) .ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", block)))
} }
@@ -797,10 +873,7 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
Ok((Zero::zero(), HashSet::new())) Ok((Zero::zero(), HashSet::new()))
} }
fn remove_leaf_block( fn remove_leaf_block(&self, _hash: &Block::Hash) -> sp_blockchain::Result<()> {
&self,
_hash: &Block::Hash,
) -> sp_blockchain::Result<()> {
Ok(()) Ok(())
} }
@@ -811,9 +884,13 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
impl<Block: BlockT> backend::LocalBackend<Block> for Backend<Block> where Block::Hash: Ord {} impl<Block: BlockT> backend::LocalBackend<Block> for Backend<Block> where Block::Hash: Ord {}
impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block> where Block::Hash: Ord { impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block>
where
Block::Hash: Ord,
{
fn is_local_state_available(&self, block: &BlockId<Block>) -> bool { fn is_local_state_available(&self, block: &BlockId<Block>) -> bool {
self.blockchain.expect_block_number_from_id(block) self.blockchain
.expect_block_number_from_id(block)
.map(|num| num.is_zero()) .map(|num| num.is_zero())
.unwrap_or(false) .unwrap_or(false)
} }
@@ -826,12 +903,15 @@ impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block> where Block
/// Check that genesis storage is valid. /// Check that genesis storage is valid.
pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> { pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
if storage.top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) { if storage.top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) {
return Err(sp_blockchain::Error::InvalidState.into()); return Err(sp_blockchain::Error::InvalidState.into())
} }
if storage.children_default.keys() if storage
.any(|child_key| !well_known_keys::is_child_storage_key(&child_key)) { .children_default
return Err(sp_blockchain::Error::InvalidState.into()); .keys()
.any(|child_key| !well_known_keys::is_child_storage_key(&child_key))
{
return Err(sp_blockchain::Error::InvalidState.into())
} }
Ok(()) Ok(())
@@ -839,10 +919,10 @@ pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{NewBlockState, in_mem::Blockchain}; use crate::{in_mem::Blockchain, NewBlockState};
use sp_api::{BlockId, HeaderT}; use sp_api::{BlockId, HeaderT};
use sp_runtime::{ConsensusEngineId, Justifications};
use sp_blockchain::Backend; use sp_blockchain::Backend;
use sp_runtime::{ConsensusEngineId, Justifications};
use substrate_test_runtime::{Block, Header, H256}; use substrate_test_runtime::{Block, Header, H256};
pub const ID1: ConsensusEngineId = *b"TST1"; pub const ID1: ConsensusEngineId = *b"TST1";
@@ -853,7 +933,13 @@ mod tests {
0 => Default::default(), 0 => Default::default(),
_ => header(number - 1).hash(), _ => header(number - 1).hash(),
}; };
Header::new(number, H256::from_low_u64_be(0), H256::from_low_u64_be(0), parent_hash, Default::default()) Header::new(
number,
H256::from_low_u64_be(0),
H256::from_low_u64_be(0),
parent_hash,
Default::default(),
)
} }
fn test_blockchain() -> Blockchain<Block> { fn test_blockchain() -> Blockchain<Block> {
@@ -862,10 +948,18 @@ mod tests {
let just1 = Some(Justifications::from((ID1, vec![1]))); let just1 = Some(Justifications::from((ID1, vec![1])));
let just2 = None; let just2 = None;
let just3 = Some(Justifications::from((ID1, vec![3]))); let just3 = Some(Justifications::from((ID1, vec![3])));
blockchain.insert(header(0).hash(), header(0), just0, None, NewBlockState::Final).unwrap(); blockchain
blockchain.insert(header(1).hash(), header(1), just1, None, NewBlockState::Final).unwrap(); .insert(header(0).hash(), header(0), just0, None, NewBlockState::Final)
blockchain.insert(header(2).hash(), header(2), just2, None, NewBlockState::Best).unwrap(); .unwrap();
blockchain.insert(header(3).hash(), header(3), just3, None, NewBlockState::Final).unwrap(); blockchain
.insert(header(1).hash(), header(1), just1, None, NewBlockState::Final)
.unwrap();
blockchain
.insert(header(2).hash(), header(2), just2, None, NewBlockState::Best)
.unwrap();
blockchain
.insert(header(3).hash(), header(3), just3, None, NewBlockState::Final)
.unwrap();
blockchain blockchain
} }
+41 -38
View File
@@ -18,12 +18,11 @@
//! Helper for managing the set of available leaves in the chain for DB implementations. //! Helper for managing the set of available leaves in the chain for DB implementations.
use std::collections::BTreeMap; use codec::{Decode, Encode};
use std::cmp::Reverse; use sp_blockchain::{Error, Result};
use sp_database::{Database, Transaction}; use sp_database::{Database, Transaction};
use sp_runtime::traits::AtLeast32Bit; use sp_runtime::traits::AtLeast32Bit;
use codec::{Encode, Decode}; use std::{cmp::Reverse, collections::BTreeMap};
use sp_blockchain::{Error, Result};
type DbHash = sp_core::H256; type DbHash = sp_core::H256;
@@ -57,7 +56,7 @@ impl<H, N: Ord> FinalizationDisplaced<H, N> {
} }
/// Iterate over all displaced leaves. /// Iterate over all displaced leaves.
pub fn leaves(&self) -> impl IntoIterator<Item=&H> { pub fn leaves(&self) -> impl IntoIterator<Item = &H> {
self.leaves.values().flatten() self.leaves.values().flatten()
} }
} }
@@ -72,17 +71,14 @@ pub struct LeafSet<H, N> {
pending_removed: Vec<H>, pending_removed: Vec<H>,
} }
impl<H, N> LeafSet<H, N> where impl<H, N> LeafSet<H, N>
where
H: Clone + PartialEq + Decode + Encode, H: Clone + PartialEq + Decode + Encode,
N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode, N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode,
{ {
/// Construct a new, blank leaf set. /// Construct a new, blank leaf set.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self { storage: BTreeMap::new(), pending_added: Vec::new(), pending_removed: Vec::new() }
storage: BTreeMap::new(),
pending_added: Vec::new(),
pending_removed: Vec::new(),
}
} }
/// Read the leaf list from the DB, using given prefix for keys. /// Read the leaf list from the DB, using given prefix for keys.
@@ -98,14 +94,10 @@ impl<H, N> LeafSet<H, N> where
for (number, hashes) in vals.into_iter() { for (number, hashes) in vals.into_iter() {
storage.insert(Reverse(number), hashes); storage.insert(Reverse(number), hashes);
} }
} },
None => {}, None => {},
} }
Ok(Self { Ok(Self { storage, pending_added: Vec::new(), pending_removed: Vec::new() })
storage,
pending_added: Vec::new(),
pending_removed: Vec::new(),
})
} }
/// update the leaf list on import. returns a displaced leaf if there was one. /// update the leaf list on import. returns a displaced leaf if there was one.
@@ -119,10 +111,7 @@ impl<H, N> LeafSet<H, N> where
self.pending_removed.push(parent_hash.clone()); self.pending_removed.push(parent_hash.clone());
Some(ImportDisplaced { Some(ImportDisplaced {
new_hash: hash.clone(), new_hash: hash.clone(),
displaced: LeafSetItem { displaced: LeafSetItem { hash: parent_hash, number: new_number },
hash: parent_hash,
number: new_number,
},
}) })
} else { } else {
None None
@@ -144,16 +133,15 @@ impl<H, N> LeafSet<H, N> where
/// will be pruned soon afterwards anyway. /// will be pruned soon afterwards anyway.
pub fn finalize_height(&mut self, number: N) -> FinalizationDisplaced<H, N> { pub fn finalize_height(&mut self, number: N) -> FinalizationDisplaced<H, N> {
let boundary = if number == N::zero() { let boundary = if number == N::zero() {
return FinalizationDisplaced { leaves: BTreeMap::new() }; return FinalizationDisplaced { leaves: BTreeMap::new() }
} else { } else {
number - N::one() number - N::one()
}; };
let below_boundary = self.storage.split_off(&Reverse(boundary)); let below_boundary = self.storage.split_off(&Reverse(boundary));
self.pending_removed.extend(below_boundary.values().flat_map(|h| h.iter()).cloned()); self.pending_removed
FinalizationDisplaced { .extend(below_boundary.values().flat_map(|h| h.iter()).cloned());
leaves: below_boundary, FinalizationDisplaced { leaves: below_boundary }
}
} }
/// Undo all pending operations. /// Undo all pending operations.
@@ -169,7 +157,9 @@ impl<H, N> LeafSet<H, N> where
/// Revert to the given block height by dropping all leaves in the leaf set /// Revert to the given block height by dropping all leaves in the leaf set
/// with a block number higher than the target. /// with a block number higher than the target.
pub fn revert(&mut self, best_hash: H, best_number: N) { pub fn revert(&mut self, best_hash: H, best_number: N) {
let items = self.storage.iter() let items = self
.storage
.iter()
.flat_map(|(number, hashes)| hashes.iter().map(move |h| (h.clone(), number.clone()))) .flat_map(|(number, hashes)| hashes.iter().map(move |h| (h.clone(), number.clone())))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@@ -185,7 +175,8 @@ impl<H, N> LeafSet<H, N> where
} }
let best_number = Reverse(best_number); let best_number = Reverse(best_number);
let leaves_contains_best = self.storage let leaves_contains_best = self
.storage
.get(&best_number) .get(&best_number)
.map_or(false, |hashes| hashes.contains(&best_hash)); .map_or(false, |hashes| hashes.contains(&best_hash));
@@ -209,7 +200,12 @@ impl<H, N> LeafSet<H, N> where
} }
/// Write the leaf list to the database transaction. /// Write the leaf list to the database transaction.
pub fn prepare_transaction(&mut self, tx: &mut Transaction<DbHash>, column: u32, prefix: &[u8]) { pub fn prepare_transaction(
&mut self,
tx: &mut Transaction<DbHash>,
column: u32,
prefix: &[u8],
) {
let leaves: Vec<_> = self.storage.iter().map(|(n, h)| (n.0.clone(), h.clone())).collect(); let leaves: Vec<_> = self.storage.iter().map(|(n, h)| (n.0.clone(), h.clone())).collect();
tx.set_from_vec(column, prefix, leaves.encode()); tx.set_from_vec(column, prefix, leaves.encode());
self.pending_added.clear(); self.pending_added.clear();
@@ -218,7 +214,9 @@ impl<H, N> LeafSet<H, N> where
/// Check if given block is a leaf. /// Check if given block is a leaf.
pub fn contains(&self, number: N, hash: H) -> bool { pub fn contains(&self, number: N, hash: H) -> bool {
self.storage.get(&Reverse(number)).map_or(false, |hashes| hashes.contains(&hash)) self.storage
.get(&Reverse(number))
.map_or(false, |hashes| hashes.contains(&hash))
} }
fn insert_leaf(&mut self, number: Reverse<N>, hash: H) { fn insert_leaf(&mut self, number: Reverse<N>, hash: H) {
@@ -230,14 +228,18 @@ impl<H, N> LeafSet<H, N> where
let mut empty = false; let mut empty = false;
let removed = self.storage.get_mut(number).map_or(false, |leaves| { let removed = self.storage.get_mut(number).map_or(false, |leaves| {
let mut found = false; let mut found = false;
leaves.retain(|h| if h == hash { leaves.retain(|h| {
found = true; if h == hash {
false found = true;
} else { false
true } else {
true
}
}); });
if leaves.is_empty() { empty = true } if leaves.is_empty() {
empty = true
}
found found
}); });
@@ -255,7 +257,8 @@ pub struct Undo<'a, H: 'a, N: 'a> {
inner: &'a mut LeafSet<H, N>, inner: &'a mut LeafSet<H, N>,
} }
impl<'a, H: 'a, N: 'a> Undo<'a, H, N> where impl<'a, H: 'a, N: 'a> Undo<'a, H, N>
where
H: Clone + PartialEq + Decode + Encode, H: Clone + PartialEq + Decode + Encode,
N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode, N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode,
{ {
@@ -329,7 +332,7 @@ mod tests {
fn two_leaves_same_height_can_be_included() { fn two_leaves_same_height_can_be_included() {
let mut set = LeafSet::new(); let mut set = LeafSet::new();
set.import(1_1u32, 10u32,0u32); set.import(1_1u32, 10u32, 0u32);
set.import(1_2, 10, 0); set.import(1_2, 10, 0);
assert!(set.storage.contains_key(&Reverse(10))); assert!(set.storage.contains_key(&Reverse(10)));
+15 -12
View File
@@ -21,30 +21,28 @@
pub mod backend; pub mod backend;
pub mod call_executor; pub mod call_executor;
pub mod client;
pub mod cht; pub mod cht;
pub mod client;
pub mod execution_extensions; pub mod execution_extensions;
pub mod in_mem; pub mod in_mem;
pub mod light;
pub mod leaves; pub mod leaves;
pub mod light;
pub mod notifications; pub mod notifications;
pub mod proof_provider; pub mod proof_provider;
pub use sp_blockchain as blockchain;
pub use backend::*; pub use backend::*;
pub use notifications::*;
pub use call_executor::*; pub use call_executor::*;
pub use client::*; pub use client::*;
pub use light::*; pub use light::*;
pub use notifications::*; pub use notifications::*;
pub use proof_provider::*; pub use proof_provider::*;
pub use sp_blockchain as blockchain;
pub use sp_blockchain::HeaderBackend; pub use sp_blockchain::HeaderBackend;
pub use sp_state_machine::{StorageProof, ExecutionStrategy}; pub use sp_state_machine::{ExecutionStrategy, StorageProof};
pub use sp_storage::{StorageData, StorageKey, PrefixedStorageKey, ChildInfo}; pub use sp_storage::{ChildInfo, PrefixedStorageKey, StorageData, StorageKey};
/// Usage Information Provider interface /// Usage Information Provider interface
///
pub trait UsageProvider<Block: sp_runtime::traits::Block> { pub trait UsageProvider<Block: sp_runtime::traits::Block> {
/// Get usage info about current client. /// Get usage info about current client.
fn usage_info(&self) -> ClientInfo<Block>; fn usage_info(&self) -> ClientInfo<Block>;
@@ -52,7 +50,7 @@ pub trait UsageProvider<Block: sp_runtime::traits::Block> {
/// Utility methods for the client. /// Utility methods for the client.
pub mod utils { pub mod utils {
use sp_blockchain::{HeaderBackend, HeaderMetadata, Error}; use sp_blockchain::{Error, HeaderBackend, HeaderMetadata};
use sp_runtime::traits::Block as BlockT; use sp_runtime::traits::Block as BlockT;
use std::borrow::Borrow; use std::borrow::Borrow;
@@ -66,19 +64,24 @@ pub mod utils {
client: &'a T, client: &'a T,
current: Option<(Block::Hash, Block::Hash)>, current: Option<(Block::Hash, Block::Hash)>,
) -> impl Fn(&Block::Hash, &Block::Hash) -> Result<bool, Error> + 'a ) -> impl Fn(&Block::Hash, &Block::Hash) -> Result<bool, Error> + 'a
where T: HeaderBackend<Block> + HeaderMetadata<Block, Error = Error>, where
T: HeaderBackend<Block> + HeaderMetadata<Block, Error = Error>,
{ {
move |base, hash| { move |base, hash| {
if base == hash { return Ok(false); } if base == hash {
return Ok(false)
}
let current = current.as_ref().map(|(c, p)| (c.borrow(), p.borrow())); let current = current.as_ref().map(|(c, p)| (c.borrow(), p.borrow()));
let mut hash = hash; let mut hash = hash;
if let Some((current_hash, current_parent_hash)) = current { if let Some((current_hash, current_parent_hash)) = current {
if base == current_hash { return Ok(false); } if base == current_hash {
return Ok(false)
}
if hash == current_hash { if hash == current_hash {
if base == current_parent_hash { if base == current_parent_hash {
return Ok(true); return Ok(true)
} else { } else {
hash = current_parent_hash; hash = current_parent_hash;
} }
+69 -62
View File
@@ -18,23 +18,26 @@
//! Substrate light client interfaces //! Substrate light client interfaces
use std::sync::Arc; use std::{
use std::collections::{BTreeMap, HashMap}; collections::{BTreeMap, HashMap},
use std::future::Future; future::Future,
sync::Arc,
};
use sp_runtime::{ use crate::{
traits::{ backend::{AuxStore, NewBlockState},
Block as BlockT, Header as HeaderT, NumberFor, ProvideChtRoots, UsageInfo,
},
generic::BlockId
}; };
use sp_core::{ChangesTrieConfigurationRange, storage::PrefixedStorageKey};
use sp_state_machine::StorageProof;
use sp_blockchain::{ use sp_blockchain::{
HeaderMetadata, well_known_cache_keys, HeaderBackend, Cache as BlockchainCache, well_known_cache_keys, Cache as BlockchainCache, Error as ClientError, HeaderBackend,
Error as ClientError, Result as ClientResult, HeaderMetadata, Result as ClientResult,
}; };
use crate::{backend::{AuxStore, NewBlockState}, UsageInfo, ProvideChtRoots}; use sp_core::{storage::PrefixedStorageKey, ChangesTrieConfigurationRange};
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, Header as HeaderT, NumberFor},
};
use sp_state_machine::StorageProof;
/// Remote call request. /// Remote call request.
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -142,48 +145,48 @@ pub struct RemoteBodyRequest<Header: HeaderT> {
/// is correct (see FetchedDataChecker) and return already checked data. /// is correct (see FetchedDataChecker) and return already checked data.
pub trait Fetcher<Block: BlockT>: Send + Sync { pub trait Fetcher<Block: BlockT>: Send + Sync {
/// Remote header future. /// Remote header future.
type RemoteHeaderResult: Future<Output = Result< type RemoteHeaderResult: Future<Output = Result<Block::Header, ClientError>>
Block::Header, + Unpin
ClientError, + Send
>> + Unpin + Send + 'static; + 'static;
/// Remote storage read future. /// Remote storage read future.
type RemoteReadResult: Future<Output = Result< type RemoteReadResult: Future<Output = Result<HashMap<Vec<u8>, Option<Vec<u8>>>, ClientError>>
HashMap<Vec<u8>, Option<Vec<u8>>>, + Unpin
ClientError, + Send
>> + Unpin + Send + 'static; + 'static;
/// Remote call result future. /// Remote call result future.
type RemoteCallResult: Future<Output = Result< type RemoteCallResult: Future<Output = Result<Vec<u8>, ClientError>> + Unpin + Send + 'static;
Vec<u8>,
ClientError,
>> + Unpin + Send + 'static;
/// Remote changes result future. /// Remote changes result future.
type RemoteChangesResult: Future<Output = Result< type RemoteChangesResult: Future<Output = Result<Vec<(NumberFor<Block>, u32)>, ClientError>>
Vec<(NumberFor<Block>, u32)>, + Unpin
ClientError, + Send
>> + Unpin + Send + 'static; + 'static;
/// Remote block body result future. /// Remote block body result future.
type RemoteBodyResult: Future<Output = Result< type RemoteBodyResult: Future<Output = Result<Vec<Block::Extrinsic>, ClientError>>
Vec<Block::Extrinsic>, + Unpin
ClientError, + Send
>> + Unpin + Send + 'static; + 'static;
/// Fetch remote header. /// Fetch remote header.
fn remote_header(&self, request: RemoteHeaderRequest<Block::Header>) -> Self::RemoteHeaderResult; fn remote_header(
/// Fetch remote storage value.
fn remote_read(
&self, &self,
request: RemoteReadRequest<Block::Header> request: RemoteHeaderRequest<Block::Header>,
) -> Self::RemoteReadResult; ) -> Self::RemoteHeaderResult;
/// Fetch remote storage value.
fn remote_read(&self, request: RemoteReadRequest<Block::Header>) -> Self::RemoteReadResult;
/// Fetch remote storage child value. /// Fetch remote storage child value.
fn remote_read_child( fn remote_read_child(
&self, &self,
request: RemoteReadChildRequest<Block::Header> request: RemoteReadChildRequest<Block::Header>,
) -> Self::RemoteReadResult; ) -> Self::RemoteReadResult;
/// Fetch remote call result. /// Fetch remote call result.
fn remote_call(&self, request: RemoteCallRequest<Block::Header>) -> Self::RemoteCallResult; fn remote_call(&self, request: RemoteCallRequest<Block::Header>) -> Self::RemoteCallResult;
/// Fetch remote changes ((block number, extrinsic index)) where given key has been changed /// Fetch remote changes ((block number, extrinsic index)) where given key has been changed
/// at a given blocks range. /// at a given blocks range.
fn remote_changes(&self, request: RemoteChangesRequest<Block::Header>) -> Self::RemoteChangesResult; fn remote_changes(
&self,
request: RemoteChangesRequest<Block::Header>,
) -> Self::RemoteChangesResult;
/// Fetch remote block body /// Fetch remote block body
fn remote_body(&self, request: RemoteBodyRequest<Block::Header>) -> Self::RemoteBodyResult; fn remote_body(&self, request: RemoteBodyRequest<Block::Header>) -> Self::RemoteBodyResult;
} }
@@ -222,20 +225,22 @@ pub trait FetchChecker<Block: BlockT>: Send + Sync {
fn check_changes_proof( fn check_changes_proof(
&self, &self,
request: &RemoteChangesRequest<Block::Header>, request: &RemoteChangesRequest<Block::Header>,
proof: ChangesProof<Block::Header> proof: ChangesProof<Block::Header>,
) -> ClientResult<Vec<(NumberFor<Block>, u32)>>; ) -> ClientResult<Vec<(NumberFor<Block>, u32)>>;
/// Check remote body proof. /// Check remote body proof.
fn check_body_proof( fn check_body_proof(
&self, &self,
request: &RemoteBodyRequest<Block::Header>, request: &RemoteBodyRequest<Block::Header>,
body: Vec<Block::Extrinsic> body: Vec<Block::Extrinsic>,
) -> ClientResult<Vec<Block::Extrinsic>>; ) -> ClientResult<Vec<Block::Extrinsic>>;
} }
/// Light client blockchain storage. /// Light client blockchain storage.
pub trait Storage<Block: BlockT>: AuxStore + HeaderBackend<Block> pub trait Storage<Block: BlockT>:
+ HeaderMetadata<Block, Error=ClientError> + ProvideChtRoots<Block> AuxStore
+ HeaderBackend<Block>
+ HeaderMetadata<Block, Error = ClientError>
+ ProvideChtRoots<Block>
{ {
/// Store new header. Should refuse to revert any finalized blocks. /// Store new header. Should refuse to revert any finalized blocks.
/// ///
@@ -280,10 +285,10 @@ pub enum LocalOrRemote<Data, Request> {
/// locally, or fetches required data from remote node. /// locally, or fetches required data from remote node.
pub trait RemoteBlockchain<Block: BlockT>: Send + Sync { pub trait RemoteBlockchain<Block: BlockT>: Send + Sync {
/// Get block header. /// Get block header.
fn header(&self, id: BlockId<Block>) -> ClientResult<LocalOrRemote< fn header(
Block::Header, &self,
RemoteHeaderRequest<Block::Header>, id: BlockId<Block>,
>>; ) -> ClientResult<LocalOrRemote<Block::Header, RemoteHeaderRequest<Block::Header>>>;
} }
/// Returns future that resolves header either locally, or remotely. /// Returns future that resolves header either locally, or remotely.
@@ -295,11 +300,8 @@ pub fn future_header<Block: BlockT, F: Fetcher<Block>>(
use futures::future::{ready, Either, FutureExt}; use futures::future::{ready, Either, FutureExt};
match blockchain.header(id) { match blockchain.header(id) {
Ok(LocalOrRemote::Remote(request)) => Either::Left( Ok(LocalOrRemote::Remote(request)) =>
fetcher Either::Left(fetcher.remote_header(request).then(|header| ready(header.map(Some)))),
.remote_header(request)
.then(|header| ready(header.map(Some)))
),
Ok(LocalOrRemote::Unknown) => Either::Right(ready(Ok(None))), Ok(LocalOrRemote::Unknown) => Either::Right(ready(Ok(None))),
Ok(LocalOrRemote::Local(local_header)) => Either::Right(ready(Ok(Some(local_header)))), Ok(LocalOrRemote::Local(local_header)) => Either::Right(ready(Ok(Some(local_header)))),
Err(err) => Either::Right(ready(Err(err))), Err(err) => Either::Right(ready(Err(err))),
@@ -308,11 +310,11 @@ pub fn future_header<Block: BlockT, F: Fetcher<Block>>(
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use super::*;
use futures::future::Ready; use futures::future::Ready;
use parking_lot::Mutex; use parking_lot::Mutex;
use sp_blockchain::Error as ClientError; use sp_blockchain::Error as ClientError;
use sp_test_primitives::{Block, Header, Extrinsic}; use sp_test_primitives::{Block, Extrinsic, Header};
use super::*;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
#[error("Not implemented on test node")] #[error("Not implemented on test node")]
@@ -322,12 +324,11 @@ pub mod tests {
fn into(self) -> ClientError { fn into(self) -> ClientError {
ClientError::Application(Box::new(self)) ClientError::Application(Box::new(self))
} }
} }
pub type OkCallFetcher = Mutex<Vec<u8>>; pub type OkCallFetcher = Mutex<Vec<u8>>;
fn not_implemented_in_tests<T>() -> Ready<Result<T, ClientError>> fn not_implemented_in_tests<T>() -> Ready<Result<T, ClientError>> {
{
futures::future::ready(Err(MockError.into())) futures::future::ready(Err(MockError.into()))
} }
@@ -346,7 +347,10 @@ pub mod tests {
not_implemented_in_tests() not_implemented_in_tests()
} }
fn remote_read_child(&self, _request: RemoteReadChildRequest<Header>) -> Self::RemoteReadResult { fn remote_read_child(
&self,
_request: RemoteReadChildRequest<Header>,
) -> Self::RemoteReadResult {
not_implemented_in_tests() not_implemented_in_tests()
} }
@@ -354,7 +358,10 @@ pub mod tests {
futures::future::ready(Ok((*self.lock()).clone())) futures::future::ready(Ok((*self.lock()).clone()))
} }
fn remote_changes(&self, _request: RemoteChangesRequest<Header>) -> Self::RemoteChangesResult { fn remote_changes(
&self,
_request: RemoteChangesRequest<Header>,
) -> Self::RemoteChangesResult {
not_implemented_in_tests() not_implemented_in_tests()
} }
+154 -130
View File
@@ -19,15 +19,15 @@
//! Storage notifications //! Storage notifications
use std::{ use std::{
collections::{HashSet, HashMap}, collections::{HashMap, HashSet},
sync::Arc, sync::Arc,
}; };
use fnv::{FnvHashSet, FnvHashMap}; use fnv::{FnvHashMap, FnvHashSet};
use sp_core::storage::{StorageKey, StorageData}; use prometheus_endpoint::{register, CounterVec, Opts, Registry, U64};
use sp_core::storage::{StorageData, StorageKey};
use sp_runtime::traits::Block as BlockT; use sp_runtime::traits::Block as BlockT;
use sp_utils::mpsc::{TracingUnboundedSender, TracingUnboundedReceiver, tracing_unbounded}; use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
use prometheus_endpoint::{Registry, CounterVec, Opts, U64, register};
/// Storage change set /// Storage change set
#[derive(Debug)] #[derive(Debug)]
@@ -40,29 +40,34 @@ pub struct StorageChangeSet {
impl StorageChangeSet { impl StorageChangeSet {
/// Convert the change set into iterator over storage items. /// Convert the change set into iterator over storage items.
pub fn iter<'a>(&'a self) pub fn iter<'a>(
-> impl Iterator<Item=(Option<&'a StorageKey>, &'a StorageKey, Option<&'a StorageData>)> + 'a { &'a self,
let top = self.changes ) -> impl Iterator<Item = (Option<&'a StorageKey>, &'a StorageKey, Option<&'a StorageData>)> + 'a
{
let top = self
.changes
.iter() .iter()
.filter(move |&(key, _)| match self.filter { .filter(move |&(key, _)| match self.filter {
Some(ref filter) => filter.contains(key), Some(ref filter) => filter.contains(key),
None => true, None => true,
}) })
.map(move |(k,v)| (None, k, v.as_ref())); .map(move |(k, v)| (None, k, v.as_ref()));
let children = self.child_changes let children = self
.child_changes
.iter() .iter()
.filter_map(move |(sk, changes)| .filter_map(move |(sk, changes)| {
self.child_filters.as_ref().and_then(|cf| self.child_filters.as_ref().and_then(|cf| {
cf.get(sk).map(|filter| changes cf.get(sk).map(|filter| {
changes
.iter() .iter()
.filter(move |&(key, _)| match filter { .filter(move |&(key, _)| match filter {
Some(ref filter) => filter.contains(key), Some(ref filter) => filter.contains(key),
None => true, None => true,
}) })
.map(move |(k,v)| (Some(sk), k, v.as_ref())) .map(move |(k, v)| (Some(sk), k, v.as_ref()))
) })
) })
) })
.flatten(); .flatten();
top.chain(children) top.chain(children)
} }
@@ -82,15 +87,18 @@ pub struct StorageNotifications<Block: BlockT> {
next_id: SubscriberId, next_id: SubscriberId,
wildcard_listeners: FnvHashSet<SubscriberId>, wildcard_listeners: FnvHashSet<SubscriberId>,
listeners: HashMap<StorageKey, FnvHashSet<SubscriberId>>, listeners: HashMap<StorageKey, FnvHashSet<SubscriberId>>,
child_listeners: HashMap<StorageKey, ( child_listeners: HashMap<
HashMap<StorageKey, FnvHashSet<SubscriberId>>, StorageKey,
FnvHashSet<SubscriberId> (HashMap<StorageKey, FnvHashSet<SubscriberId>>, FnvHashSet<SubscriberId>),
)>, >,
sinks: FnvHashMap<SubscriberId, ( sinks: FnvHashMap<
TracingUnboundedSender<(Block::Hash, StorageChangeSet)>, SubscriberId,
Option<HashSet<StorageKey>>, (
Option<HashMap<StorageKey, Option<HashSet<StorageKey>>>>, TracingUnboundedSender<(Block::Hash, StorageChangeSet)>,
)>, Option<HashSet<StorageKey>>,
Option<HashMap<StorageKey, Option<HashSet<StorageKey>>>>,
),
>,
} }
impl<Block: BlockT> Default for StorageNotifications<Block> { impl<Block: BlockT> Default for StorageNotifications<Block> {
@@ -110,16 +118,17 @@ impl<Block: BlockT> StorageNotifications<Block> {
/// Initialize a new StorageNotifications /// Initialize a new StorageNotifications
/// optionally pass a prometheus registry to send subscriber metrics to /// optionally pass a prometheus registry to send subscriber metrics to
pub fn new(prometheus_registry: Option<Registry>) -> Self { pub fn new(prometheus_registry: Option<Registry>) -> Self {
let metrics = prometheus_registry.and_then(|r| let metrics = prometheus_registry.and_then(|r| {
CounterVec::new( CounterVec::new(
Opts::new( Opts::new(
"storage_notification_subscribers", "storage_notification_subscribers",
"Number of subscribers in storage notification sytem" "Number of subscribers in storage notification sytem",
), ),
&["action"], //added | removed &["action"], // added | removed
).and_then(|g| register(g, &r)) )
.and_then(|g| register(g, &r))
.ok() .ok()
); });
StorageNotifications { StorageNotifications {
metrics, metrics,
@@ -137,17 +146,16 @@ impl<Block: BlockT> StorageNotifications<Block> {
pub fn trigger( pub fn trigger(
&mut self, &mut self,
hash: &Block::Hash, hash: &Block::Hash,
changeset: impl Iterator<Item=(Vec<u8>, Option<Vec<u8>>)>, changeset: impl Iterator<Item = (Vec<u8>, Option<Vec<u8>>)>,
child_changeset: impl Iterator< child_changeset: impl Iterator<
Item=(Vec<u8>, impl Iterator<Item=(Vec<u8>, Option<Vec<u8>>)>) Item = (Vec<u8>, impl Iterator<Item = (Vec<u8>, Option<Vec<u8>>)>),
>, >,
) { ) {
let has_wildcard = !self.wildcard_listeners.is_empty(); let has_wildcard = !self.wildcard_listeners.is_empty();
// early exit if no listeners // early exit if no listeners
if !has_wildcard && self.listeners.is_empty() && self.child_listeners.is_empty() { if !has_wildcard && self.listeners.is_empty() && self.child_listeners.is_empty() {
return; return
} }
let mut subscribers = self.wildcard_listeners.clone(); let mut subscribers = self.wildcard_listeners.clone();
@@ -193,24 +201,29 @@ impl<Block: BlockT> StorageNotifications<Block> {
// Don't send empty notifications // Don't send empty notifications
if changes.is_empty() && child_changes.is_empty() { if changes.is_empty() && child_changes.is_empty() {
return; return
} }
let changes = Arc::new(changes); let changes = Arc::new(changes);
let child_changes = Arc::new(child_changes); let child_changes = Arc::new(child_changes);
// Trigger the events // Trigger the events
let to_remove = self.sinks let to_remove = self
.sinks
.iter() .iter()
.filter_map(|(subscriber, &(ref sink, ref filter, ref child_filters))| { .filter_map(|(subscriber, &(ref sink, ref filter, ref child_filters))| {
let should_remove = { let should_remove = {
if subscribers.contains(subscriber) { if subscribers.contains(subscriber) {
sink.unbounded_send((hash.clone(), StorageChangeSet { sink.unbounded_send((
changes: changes.clone(), hash.clone(),
child_changes: child_changes.clone(), StorageChangeSet {
filter: filter.clone(), changes: changes.clone(),
child_filters: child_filters.clone(), child_changes: child_changes.clone(),
})).is_err() filter: filter.clone(),
child_filters: child_filters.clone(),
},
))
.is_err()
} else { } else {
sink.is_closed() sink.is_closed()
} }
@@ -221,7 +234,8 @@ impl<Block: BlockT> StorageNotifications<Block> {
} else { } else {
None None
} }
}).collect::<Vec<_>>(); })
.collect::<Vec<_>>();
for sub_id in to_remove { for sub_id in to_remove {
self.remove_subscriber(sub_id); self.remove_subscriber(sub_id);
@@ -233,13 +247,12 @@ impl<Block: BlockT> StorageNotifications<Block> {
filters: &Option<HashSet<StorageKey>>, filters: &Option<HashSet<StorageKey>>,
listeners: &mut HashMap<StorageKey, FnvHashSet<SubscriberId>>, listeners: &mut HashMap<StorageKey, FnvHashSet<SubscriberId>>,
wildcards: &mut FnvHashSet<SubscriberId>, wildcards: &mut FnvHashSet<SubscriberId>,
){ ) {
match filters { match filters {
None => { None => {
wildcards.remove(subscriber); wildcards.remove(subscriber);
}, },
Some(filters) => { Some(filters) =>
for key in filters.iter() { for key in filters.iter() {
let remove_key = match listeners.get_mut(key) { let remove_key = match listeners.get_mut(key) {
Some(ref mut set) => { Some(ref mut set) => {
@@ -252,8 +265,7 @@ impl<Block: BlockT> StorageNotifications<Block> {
if remove_key { if remove_key {
listeners.remove(key); listeners.remove(key);
} }
} },
}
} }
} }
@@ -267,7 +279,6 @@ impl<Block: BlockT> StorageNotifications<Block> {
); );
if let Some(child_filters) = child_filters.as_ref() { if let Some(child_filters) = child_filters.as_ref() {
for (c_key, filters) in child_filters { for (c_key, filters) in child_filters {
if let Some((listeners, wildcards)) = self.child_listeners.get_mut(&c_key) { if let Some((listeners, wildcards)) = self.child_listeners.get_mut(&c_key) {
Self::remove_subscriber_from( Self::remove_subscriber_from(
&subscriber, &subscriber,
@@ -293,20 +304,24 @@ impl<Block: BlockT> StorageNotifications<Block> {
filter_keys: &Option<impl AsRef<[StorageKey]>>, filter_keys: &Option<impl AsRef<[StorageKey]>>,
listeners: &mut HashMap<StorageKey, FnvHashSet<SubscriberId>>, listeners: &mut HashMap<StorageKey, FnvHashSet<SubscriberId>>,
wildcards: &mut FnvHashSet<SubscriberId>, wildcards: &mut FnvHashSet<SubscriberId>,
) -> Option<HashSet<StorageKey>> ) -> Option<HashSet<StorageKey>> {
{
match filter_keys { match filter_keys {
None => { None => {
wildcards.insert(current_id); wildcards.insert(current_id);
None None
}, },
Some(keys) => Some(keys.as_ref().iter().map(|key| { Some(keys) => Some(
listeners keys.as_ref()
.entry(key.clone()) .iter()
.or_insert_with(Default::default) .map(|key| {
.insert(current_id); listeners
key.clone() .entry(key.clone())
}).collect()) .or_insert_with(Default::default)
.insert(current_id);
key.clone()
})
.collect(),
),
} }
} }
@@ -327,21 +342,20 @@ impl<Block: BlockT> StorageNotifications<Block> {
&mut self.wildcard_listeners, &mut self.wildcard_listeners,
); );
let child_keys = filter_child_keys.map(|filter_child_keys| { let child_keys = filter_child_keys.map(|filter_child_keys| {
filter_child_keys.iter().map(|(c_key, o_keys)| { filter_child_keys
let (c_listeners, c_wildcards) = self.child_listeners .iter()
.entry(c_key.clone()) .map(|(c_key, o_keys)| {
.or_insert_with(Default::default); let (c_listeners, c_wildcards) =
self.child_listeners.entry(c_key.clone()).or_insert_with(Default::default);
(c_key.clone(), Self::listen_from( (
current_id, c_key.clone(),
o_keys, Self::listen_from(current_id, o_keys, &mut *c_listeners, &mut *c_wildcards),
&mut *c_listeners, )
&mut *c_wildcards, })
)) .collect()
}).collect()
}); });
// insert sink // insert sink
let (tx, rx) = tracing_unbounded("mpsc_storage_notification_items"); let (tx, rx) = tracing_unbounded("mpsc_storage_notification_items");
self.sinks.insert(current_id, (tx, keys, child_keys)); self.sinks.insert(current_id, (tx, keys, child_keys));
@@ -356,8 +370,8 @@ impl<Block: BlockT> StorageNotifications<Block> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use sp_runtime::testing::{H256 as Hash, Block as RawBlock, ExtrinsicWrapper};
use super::*; use super::*;
use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash};
use std::iter::{empty, Empty}; use std::iter::{empty, Empty};
type TestChangeSet = ( type TestChangeSet = (
@@ -369,10 +383,12 @@ mod tests {
impl From<TestChangeSet> for StorageChangeSet { impl From<TestChangeSet> for StorageChangeSet {
fn from(changes: TestChangeSet) -> Self { fn from(changes: TestChangeSet) -> Self {
// warning hardcoded child trie wildcard to test upon // warning hardcoded child trie wildcard to test upon
let child_filters = Some([ let child_filters = Some(
(StorageKey(vec![4]), None), [(StorageKey(vec![4]), None), (StorageKey(vec![5]), None)]
(StorageKey(vec![5]), None), .iter()
].iter().cloned().collect()); .cloned()
.collect(),
);
StorageChangeSet { StorageChangeSet {
changes: Arc::new(changes.0), changes: Arc::new(changes.0),
child_changes: Arc::new(changes.1), child_changes: Arc::new(changes.1),
@@ -396,34 +412,40 @@ mod tests {
// given // given
let mut notifications = StorageNotifications::<Block>::default(); let mut notifications = StorageNotifications::<Block>::default();
let child_filter = [(StorageKey(vec![4]), None)]; let child_filter = [(StorageKey(vec![4]), None)];
let mut recv = futures::executor::block_on_stream( let mut recv =
notifications.listen(None, Some(&child_filter[..])) futures::executor::block_on_stream(notifications.listen(None, Some(&child_filter[..])));
);
// when // when
let changeset = vec![ let changeset = vec![(vec![2], Some(vec![3])), (vec![3], None)];
(vec![2], Some(vec![3])), let c_changeset_1 = vec![(vec![5], Some(vec![4])), (vec![6], None)];
(vec![3], None),
];
let c_changeset_1 = vec![
(vec![5], Some(vec![4])),
(vec![6], None),
];
let c_changeset = vec![(vec![4], c_changeset_1)]; let c_changeset = vec![(vec![4], c_changeset_1)];
notifications.trigger( notifications.trigger(
&Hash::from_low_u64_be(1), &Hash::from_low_u64_be(1),
changeset.into_iter(), changeset.into_iter(),
c_changeset.into_iter().map(|(a,b)| (a, b.into_iter())), c_changeset.into_iter().map(|(a, b)| (a, b.into_iter())),
); );
// then // then
assert_eq!(recv.next().unwrap(), (Hash::from_low_u64_be(1), (vec![ assert_eq!(
(StorageKey(vec![2]), Some(StorageData(vec![3]))), recv.next().unwrap(),
(StorageKey(vec![3]), None), (
], vec![(StorageKey(vec![4]), vec![ Hash::from_low_u64_be(1),
(StorageKey(vec![5]), Some(StorageData(vec![4]))), (
(StorageKey(vec![6]), None), vec![
])]).into())); (StorageKey(vec![2]), Some(StorageData(vec![3]))),
(StorageKey(vec![3]), None),
],
vec![(
StorageKey(vec![4]),
vec![
(StorageKey(vec![5]), Some(StorageData(vec![4]))),
(StorageKey(vec![6]), None),
]
)]
)
.into()
)
);
} }
#[test] #[test]
@@ -432,44 +454,52 @@ mod tests {
let mut notifications = StorageNotifications::<Block>::default(); let mut notifications = StorageNotifications::<Block>::default();
let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))]; let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))];
let mut recv1 = futures::executor::block_on_stream( let mut recv1 = futures::executor::block_on_stream(
notifications.listen(Some(&[StorageKey(vec![1])]), None) notifications.listen(Some(&[StorageKey(vec![1])]), None),
); );
let mut recv2 = futures::executor::block_on_stream( let mut recv2 = futures::executor::block_on_stream(
notifications.listen(Some(&[StorageKey(vec![2])]), None) notifications.listen(Some(&[StorageKey(vec![2])]), None),
); );
let mut recv3 = futures::executor::block_on_stream( let mut recv3 = futures::executor::block_on_stream(
notifications.listen(Some(&[]), Some(&child_filter)) notifications.listen(Some(&[]), Some(&child_filter)),
); );
// when // when
let changeset = vec![ let changeset = vec![(vec![2], Some(vec![3])), (vec![1], None)];
(vec![2], Some(vec![3])), let c_changeset_1 = vec![(vec![5], Some(vec![4])), (vec![6], None)];
(vec![1], None),
];
let c_changeset_1 = vec![
(vec![5], Some(vec![4])),
(vec![6], None),
];
let c_changeset = vec![(vec![4], c_changeset_1)]; let c_changeset = vec![(vec![4], c_changeset_1)];
notifications.trigger( notifications.trigger(
&Hash::from_low_u64_be(1), &Hash::from_low_u64_be(1),
changeset.into_iter(), changeset.into_iter(),
c_changeset.into_iter().map(|(a,b)| (a, b.into_iter())), c_changeset.into_iter().map(|(a, b)| (a, b.into_iter())),
); );
// then // then
assert_eq!(recv1.next().unwrap(), (Hash::from_low_u64_be(1), (vec![ assert_eq!(
(StorageKey(vec![1]), None), recv1.next().unwrap(),
], vec![]).into())); (Hash::from_low_u64_be(1), (vec![(StorageKey(vec![1]), None),], vec![]).into())
assert_eq!(recv2.next().unwrap(), (Hash::from_low_u64_be(1), (vec![ );
(StorageKey(vec![2]), Some(StorageData(vec![3]))), assert_eq!(
], vec![]).into())); recv2.next().unwrap(),
assert_eq!(recv3.next().unwrap(), (Hash::from_low_u64_be(1), (vec![], (
vec![ Hash::from_low_u64_be(1),
(StorageKey(vec![4]), vec![(StorageKey(vec![5]), Some(StorageData(vec![4])))]), (vec![(StorageKey(vec![2]), Some(StorageData(vec![3]))),], vec![]).into()
]).into())); )
);
assert_eq!(
recv3.next().unwrap(),
(
Hash::from_low_u64_be(1),
(
vec![],
vec![(
StorageKey(vec![4]),
vec![(StorageKey(vec![5]), Some(StorageData(vec![4])))]
),]
)
.into()
)
);
} }
#[test] #[test]
@@ -479,27 +509,21 @@ mod tests {
{ {
let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))]; let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))];
let _recv1 = futures::executor::block_on_stream( let _recv1 = futures::executor::block_on_stream(
notifications.listen(Some(&[StorageKey(vec![1])]), None) notifications.listen(Some(&[StorageKey(vec![1])]), None),
); );
let _recv2 = futures::executor::block_on_stream( let _recv2 = futures::executor::block_on_stream(
notifications.listen(Some(&[StorageKey(vec![2])]), None) notifications.listen(Some(&[StorageKey(vec![2])]), None),
);
let _recv3 = futures::executor::block_on_stream(
notifications.listen(None, None)
);
let _recv4 = futures::executor::block_on_stream(
notifications.listen(None, Some(&child_filter))
); );
let _recv3 = futures::executor::block_on_stream(notifications.listen(None, None));
let _recv4 =
futures::executor::block_on_stream(notifications.listen(None, Some(&child_filter)));
assert_eq!(notifications.listeners.len(), 2); assert_eq!(notifications.listeners.len(), 2);
assert_eq!(notifications.wildcard_listeners.len(), 2); assert_eq!(notifications.wildcard_listeners.len(), 2);
assert_eq!(notifications.child_listeners.len(), 1); assert_eq!(notifications.child_listeners.len(), 1);
} }
// when // when
let changeset = vec![ let changeset = vec![(vec![2], Some(vec![3])), (vec![1], None)];
(vec![2], Some(vec![3])),
(vec![1], None),
];
let c_changeset = empty::<(_, Empty<_>)>(); let c_changeset = empty::<(_, Empty<_>)>();
notifications.trigger(&Hash::from_low_u64_be(1), changeset.into_iter(), c_changeset); notifications.trigger(&Hash::from_low_u64_be(1), changeset.into_iter(), c_changeset);
+9 -9
View File
@@ -17,12 +17,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Proof utilities //! Proof utilities
use sp_runtime::{ use crate::{ChangesProof, StorageProof};
generic::BlockId, use sp_runtime::{generic::BlockId, traits::Block as BlockT};
traits::{Block as BlockT}, use sp_storage::{ChildInfo, PrefixedStorageKey, StorageKey};
};
use crate::{StorageProof, ChangesProof};
use sp_storage::{ChildInfo, StorageKey, PrefixedStorageKey};
/// Interface for providing block proving utilities. /// Interface for providing block proving utilities.
pub trait ProofProvider<Block: BlockT> { pub trait ProofProvider<Block: BlockT> {
@@ -30,7 +27,7 @@ pub trait ProofProvider<Block: BlockT> {
fn read_proof( fn read_proof(
&self, &self,
id: &BlockId<Block>, id: &BlockId<Block>,
keys: &mut dyn Iterator<Item=&[u8]>, keys: &mut dyn Iterator<Item = &[u8]>,
) -> sp_blockchain::Result<StorageProof>; ) -> sp_blockchain::Result<StorageProof>;
/// Reads child storage value at a given block + storage_key + key, returning /// Reads child storage value at a given block + storage_key + key, returning
@@ -39,7 +36,7 @@ pub trait ProofProvider<Block: BlockT> {
&self, &self,
id: &BlockId<Block>, id: &BlockId<Block>,
child_info: &ChildInfo, child_info: &ChildInfo,
keys: &mut dyn Iterator<Item=&[u8]>, keys: &mut dyn Iterator<Item = &[u8]>,
) -> sp_blockchain::Result<StorageProof>; ) -> sp_blockchain::Result<StorageProof>;
/// Execute a call to a contract on top of state in a block of given hash /// Execute a call to a contract on top of state in a block of given hash
@@ -53,7 +50,10 @@ pub trait ProofProvider<Block: BlockT> {
call_data: &[u8], call_data: &[u8],
) -> sp_blockchain::Result<(Vec<u8>, StorageProof)>; ) -> sp_blockchain::Result<(Vec<u8>, StorageProof)>;
/// Reads given header and generates CHT-based header proof. /// Reads given header and generates CHT-based header proof.
fn header_proof(&self, id: &BlockId<Block>) -> sp_blockchain::Result<(Block::Header, StorageProof)>; fn header_proof(
&self,
id: &BlockId<Block>,
) -> sp_blockchain::Result<(Block::Header, StorageProof)>;
/// Get proof for computation of (block, extrinsic) pairs where key has been changed at given blocks range. /// Get proof for computation of (block, extrinsic) pairs where key has been changed at given blocks range.
/// `min` is the hash of the first block, which changes trie root is known to the requester - when we're using /// `min` is the hash of the first block, which changes trie root is known to the requester - when we're using
@@ -16,13 +16,13 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use futures::stream::Stream; use futures::{future::FutureExt, ready, stream::Stream};
use futures::future::FutureExt;
use futures::ready;
use futures_timer::Delay; use futures_timer::Delay;
use std::pin::Pin; use std::{
use std::task::{Context, Poll}; pin::Pin,
use std::time::Duration; task::{Context, Poll},
time::Duration,
};
/// Exponentially increasing interval /// Exponentially increasing interval
/// ///
@@ -37,11 +37,7 @@ impl ExpIncInterval {
/// Create a new [`ExpIncInterval`]. /// Create a new [`ExpIncInterval`].
pub fn new(start: Duration, max: Duration) -> Self { pub fn new(start: Duration, max: Duration) -> Self {
let delay = Delay::new(start); let delay = Delay::new(start);
Self { Self { max, next: start * 2, delay }
max,
next: start * 2,
delay,
}
} }
/// Fast forward the exponentially increasing interval to the configured maximum. /// Fast forward the exponentially increasing interval to the configured maximum.
+12 -14
View File
@@ -26,18 +26,23 @@
//! //!
//! See [`Worker`] and [`Service`] for more documentation. //! See [`Worker`] and [`Service`] for more documentation.
pub use crate::{service::Service, worker::{NetworkProvider, Worker, Role}}; pub use crate::{
service::Service,
worker::{NetworkProvider, Role, Worker},
};
use std::{sync::Arc, time::Duration}; use std::{sync::Arc, time::Duration};
use futures::channel::{mpsc, oneshot}; use futures::{
use futures::Stream; channel::{mpsc, oneshot},
Stream,
};
use sc_client_api::blockchain::HeaderBackend; use sc_client_api::blockchain::HeaderBackend;
use sc_network::{DhtEvent, Multiaddr, PeerId}; use sc_network::{DhtEvent, Multiaddr, PeerId};
use sp_api::ProvideRuntimeApi;
use sp_authority_discovery::{AuthorityDiscoveryApi, AuthorityId}; use sp_authority_discovery::{AuthorityDiscoveryApi, AuthorityId};
use sp_runtime::traits::Block as BlockT; use sp_runtime::traits::Block as BlockT;
use sp_api::ProvideRuntimeApi;
mod error; mod error;
mod interval; mod interval;
@@ -141,15 +146,8 @@ where
{ {
let (to_worker, from_service) = mpsc::channel(0); let (to_worker, from_service) = mpsc::channel(0);
let worker = Worker::new( let worker =
from_service, Worker::new(from_service, client, network, dht_event_rx, role, prometheus_registry, config);
client,
network,
dht_event_rx,
role,
prometheus_registry,
config,
);
let service = Service::new(to_worker); let service = Service::new(to_worker);
(worker, service) (worker, service)
@@ -160,5 +158,5 @@ pub(crate) enum ServicetoWorkerMsg {
/// See [`Service::get_addresses_by_authority_id`]. /// See [`Service::get_addresses_by_authority_id`].
GetAddressesByAuthorityId(AuthorityId, oneshot::Sender<Option<Vec<Multiaddr>>>), GetAddressesByAuthorityId(AuthorityId, oneshot::Sender<Option<Vec<Multiaddr>>>),
/// See [`Service::get_authority_id_by_peer_id`]. /// See [`Service::get_authority_id_by_peer_id`].
GetAuthorityIdByPeerId(PeerId, oneshot::Sender<Option<AuthorityId>>) GetAuthorityIdByPeerId(PeerId, oneshot::Sender<Option<AuthorityId>>),
} }
@@ -20,8 +20,10 @@ use std::fmt::Debug;
use crate::ServicetoWorkerMsg; use crate::ServicetoWorkerMsg;
use futures::channel::{mpsc, oneshot}; use futures::{
use futures::SinkExt; channel::{mpsc, oneshot},
SinkExt,
};
use sc_network::{Multiaddr, PeerId}; use sc_network::{Multiaddr, PeerId};
use sp_authority_discovery::AuthorityId; use sp_authority_discovery::AuthorityId;
@@ -42,9 +44,7 @@ impl Debug for Service {
/// [`crate::Worker`]'s local address cache for a given [`AuthorityId`]. /// [`crate::Worker`]'s local address cache for a given [`AuthorityId`].
impl Service { impl Service {
pub(crate) fn new(to_worker: mpsc::Sender<ServicetoWorkerMsg>) -> Self { pub(crate) fn new(to_worker: mpsc::Sender<ServicetoWorkerMsg>) -> Self {
Self { Self { to_worker }
to_worker,
}
} }
/// Get the addresses for the given [`AuthorityId`] from the local address /// Get the addresses for the given [`AuthorityId`] from the local address
@@ -59,7 +59,10 @@ impl Service {
/// enforced today, given that there are still authorities out there /// enforced today, given that there are still authorities out there
/// publishing the addresses of their sentry nodes on the DHT. In the future /// publishing the addresses of their sentry nodes on the DHT. In the future
/// this guarantee can be provided. /// this guarantee can be provided.
pub async fn get_addresses_by_authority_id(&mut self, authority: AuthorityId) -> Option<Vec<Multiaddr>> { pub async fn get_addresses_by_authority_id(
&mut self,
authority: AuthorityId,
) -> Option<Vec<Multiaddr>> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.to_worker self.to_worker
@@ -16,15 +16,24 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::{new_worker_and_service, worker::{tests::{TestApi, TestNetwork}, Role}}; use crate::{
new_worker_and_service,
worker::{
tests::{TestApi, TestNetwork},
Role,
},
};
use std::sync::Arc;
use futures::{channel::mpsc::channel, executor::LocalPool, task::LocalSpawn}; use futures::{channel::mpsc::channel, executor::LocalPool, task::LocalSpawn};
use libp2p::core::{multiaddr::{Multiaddr, Protocol}, PeerId}; use libp2p::core::{
multiaddr::{Multiaddr, Protocol},
PeerId,
};
use std::sync::Arc;
use sp_authority_discovery::AuthorityId; use sp_authority_discovery::AuthorityId;
use sp_core::crypto::key_types; use sp_core::crypto::key_types;
use sp_keystore::{CryptoStore, testing::KeyStore}; use sp_keystore::{testing::KeyStore, CryptoStore};
#[test] #[test]
fn get_addresses_and_authority_id() { fn get_addresses_and_authority_id() {
@@ -44,13 +53,12 @@ fn get_addresses_and_authority_id() {
}); });
let remote_peer_id = PeerId::random(); let remote_peer_id = PeerId::random();
let remote_addr = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333".parse::<Multiaddr>() let remote_addr = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333"
.parse::<Multiaddr>()
.unwrap() .unwrap()
.with(Protocol::P2p(remote_peer_id.clone().into())); .with(Protocol::P2p(remote_peer_id.clone().into()));
let test_api = Arc::new(TestApi { let test_api = Arc::new(TestApi { authorities: vec![] });
authorities: vec![],
});
let (mut worker, mut service) = new_worker_and_service( let (mut worker, mut service) = new_worker_and_service(
test_api, test_api,
+125 -145
View File
@@ -16,43 +16,49 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::{error::{Error, Result}, interval::ExpIncInterval, ServicetoWorkerMsg}; use crate::{
error::{Error, Result},
interval::ExpIncInterval,
ServicetoWorkerMsg,
};
use std::collections::{HashMap, HashSet}; use std::{
use std::convert::TryInto; collections::{HashMap, HashSet},
use std::marker::PhantomData; convert::TryInto,
use std::sync::Arc; marker::PhantomData,
use std::time::Duration; sync::Arc,
time::Duration,
};
use futures::channel::mpsc; use futures::{channel::mpsc, future, stream::Fuse, FutureExt, Stream, StreamExt};
use futures::{future, FutureExt, Stream, StreamExt, stream::Fuse};
use addr_cache::AddrCache; use addr_cache::AddrCache;
use async_trait::async_trait; use async_trait::async_trait;
use codec::Decode; use codec::Decode;
use ip_network::IpNetwork; use ip_network::IpNetwork;
use libp2p::{core::multiaddr, multihash::{Multihash, Hasher}}; use libp2p::{
core::multiaddr,
multihash::{Hasher, Multihash},
};
use log::{debug, error, log_enabled}; use log::{debug, error, log_enabled};
use prometheus_endpoint::{Counter, CounterVec, Gauge, Opts, U64, register}; use prometheus_endpoint::{register, Counter, CounterVec, Gauge, Opts, U64};
use prost::Message; use prost::Message;
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
use sc_client_api::blockchain::HeaderBackend; use sc_client_api::blockchain::HeaderBackend;
use sc_network::{ use sc_network::{DhtEvent, ExHashT, Multiaddr, NetworkStateInfo, PeerId};
DhtEvent, use sp_api::ProvideRuntimeApi;
ExHashT, use sp_authority_discovery::{
Multiaddr, AuthorityDiscoveryApi, AuthorityId, AuthorityPair, AuthoritySignature,
NetworkStateInfo,
PeerId,
}; };
use sp_authority_discovery::{AuthorityDiscoveryApi, AuthorityId, AuthoritySignature, AuthorityPair};
use sp_core::crypto::{key_types, CryptoTypePublicPair, Pair}; use sp_core::crypto::{key_types, CryptoTypePublicPair, Pair};
use sp_keystore::CryptoStore; use sp_keystore::CryptoStore;
use sp_runtime::{traits::Block as BlockT, generic::BlockId}; use sp_runtime::{generic::BlockId, traits::Block as BlockT};
use sp_api::ProvideRuntimeApi;
mod addr_cache; mod addr_cache;
/// Dht payload schemas generated from Protobuf definitions via Prost crate in build.rs. /// Dht payload schemas generated from Protobuf definitions via Prost crate in build.rs.
mod schema { include!(concat!(env!("OUT_DIR"), "/authority_discovery.rs")); } mod schema {
include!(concat!(env!("OUT_DIR"), "/authority_discovery.rs"));
}
#[cfg(test)] #[cfg(test)]
pub mod tests; pub mod tests;
@@ -72,7 +78,6 @@ pub enum Role {
Discover, Discover,
} }
/// An authority discovery [`Worker`] can publish the local node's addresses as well as discover /// An authority discovery [`Worker`] can publish the local node's addresses as well as discover
/// those of other nodes via a Kademlia DHT. /// those of other nodes via a Kademlia DHT.
/// ///
@@ -141,8 +146,7 @@ where
Block: BlockT + Unpin + 'static, Block: BlockT + Unpin + 'static,
Network: NetworkProvider, Network: NetworkProvider,
Client: ProvideRuntimeApi<Block> + Send + Sync + 'static + HeaderBackend<Block>, Client: ProvideRuntimeApi<Block> + Send + Sync + 'static + HeaderBackend<Block>,
<Client as ProvideRuntimeApi<Block>>::Api: <Client as ProvideRuntimeApi<Block>>::Api: AuthorityDiscoveryApi<Block>,
AuthorityDiscoveryApi<Block>,
DhtEventStream: Stream<Item = DhtEvent> + Unpin, DhtEventStream: Stream<Item = DhtEvent> + Unpin,
{ {
/// Construct a [`Worker`]. /// Construct a [`Worker`].
@@ -161,33 +165,24 @@ where
// thus timely retries are not needed. For this reasoning use an exponentially increasing // thus timely retries are not needed. For this reasoning use an exponentially increasing
// interval for `publish_interval`, `query_interval` and `priority_group_set_interval` // interval for `publish_interval`, `query_interval` and `priority_group_set_interval`
// instead of a constant interval. // instead of a constant interval.
let publish_interval = ExpIncInterval::new( let publish_interval =
Duration::from_secs(2), ExpIncInterval::new(Duration::from_secs(2), config.max_publish_interval);
config.max_publish_interval, let query_interval = ExpIncInterval::new(Duration::from_secs(2), config.max_query_interval);
);
let query_interval = ExpIncInterval::new(
Duration::from_secs(2),
config.max_query_interval,
);
// An `ExpIncInterval` is overkill here because the interval is constant, but consistency // An `ExpIncInterval` is overkill here because the interval is constant, but consistency
// is more simple. // is more simple.
let publish_if_changed_interval = ExpIncInterval::new( let publish_if_changed_interval =
config.keystore_refresh_interval, ExpIncInterval::new(config.keystore_refresh_interval, config.keystore_refresh_interval);
config.keystore_refresh_interval
);
let addr_cache = AddrCache::new(); let addr_cache = AddrCache::new();
let metrics = match prometheus_registry { let metrics = match prometheus_registry {
Some(registry) => { Some(registry) => match Metrics::register(&registry) {
match Metrics::register(&registry) { Ok(metrics) => Some(metrics),
Ok(metrics) => Some(metrics), Err(e) => {
Err(e) => { error!(target: LOG_TARGET, "Failed to register metrics: {:?}", e);
error!(target: LOG_TARGET, "Failed to register metrics: {:?}", e); None
None },
},
}
}, },
None => None, None => None,
}; };
@@ -262,23 +257,23 @@ where
let _ = sender.send( let _ = sender.send(
self.addr_cache.get_addresses_by_authority_id(&authority).map(Clone::clone), self.addr_cache.get_addresses_by_authority_id(&authority).map(Clone::clone),
); );
} },
ServicetoWorkerMsg::GetAuthorityIdByPeerId(peer_id, sender) => { ServicetoWorkerMsg::GetAuthorityIdByPeerId(peer_id, sender) => {
let _ = sender.send( let _ = sender
self.addr_cache.get_authority_id_by_peer_id(&peer_id).map(Clone::clone), .send(self.addr_cache.get_authority_id_by_peer_id(&peer_id).map(Clone::clone));
); },
}
} }
} }
fn addresses_to_publish(&self) -> impl Iterator<Item = Multiaddr> { fn addresses_to_publish(&self) -> impl Iterator<Item = Multiaddr> {
let peer_id: Multihash = self.network.local_peer_id().into(); let peer_id: Multihash = self.network.local_peer_id().into();
let publish_non_global_ips = self.publish_non_global_ips; let publish_non_global_ips = self.publish_non_global_ips;
self.network.external_addresses() self.network
.external_addresses()
.into_iter() .into_iter()
.filter(move |a| { .filter(move |a| {
if publish_non_global_ips { if publish_non_global_ips {
return true; return true
} }
a.iter().all(|p| match p { a.iter().all(|p| match p {
@@ -321,9 +316,9 @@ where
if let Some(metrics) = &self.metrics { if let Some(metrics) = &self.metrics {
metrics.publish.inc(); metrics.publish.inc();
metrics.amount_addresses_last_published.set( metrics
addresses.len().try_into().unwrap_or(std::u64::MAX), .amount_addresses_last_published
); .set(addresses.len().try_into().unwrap_or(std::u64::MAX));
} }
let mut serialized_addresses = vec![]; let mut serialized_addresses = vec![];
@@ -332,30 +327,26 @@ where
.map_err(Error::EncodingProto)?; .map_err(Error::EncodingProto)?;
let keys_vec = keys.iter().cloned().collect::<Vec<_>>(); let keys_vec = keys.iter().cloned().collect::<Vec<_>>();
let signatures = key_store.sign_with_all( let signatures = key_store
key_types::AUTHORITY_DISCOVERY, .sign_with_all(
keys_vec.clone(), key_types::AUTHORITY_DISCOVERY,
serialized_addresses.as_slice(), keys_vec.clone(),
).await.map_err(|_| Error::Signing)?; serialized_addresses.as_slice(),
)
.await
.map_err(|_| Error::Signing)?;
for (sign_result, key) in signatures.into_iter().zip(keys_vec.iter()) { for (sign_result, key) in signatures.into_iter().zip(keys_vec.iter()) {
let mut signed_addresses = vec![]; let mut signed_addresses = vec![];
// Verify that all signatures exist for all provided keys. // Verify that all signatures exist for all provided keys.
let signature = sign_result.ok() let signature =
.flatten() sign_result.ok().flatten().ok_or_else(|| Error::MissingSignature(key.clone()))?;
.ok_or_else(|| Error::MissingSignature(key.clone()))?; schema::SignedAuthorityAddresses { addresses: serialized_addresses.clone(), signature }
schema::SignedAuthorityAddresses { .encode(&mut signed_addresses)
addresses: serialized_addresses.clone(),
signature,
}
.encode(&mut signed_addresses)
.map_err(Error::EncodingProto)?; .map_err(Error::EncodingProto)?;
self.network.put_value( self.network.put_value(hash_authority_id(key.1.as_ref()), signed_addresses);
hash_authority_id(key.1.as_ref()),
signed_addresses,
);
} }
self.latest_published_keys = keys; self.latest_published_keys = keys;
@@ -367,11 +358,11 @@ where
let id = BlockId::hash(self.client.info().best_hash); let id = BlockId::hash(self.client.info().best_hash);
let local_keys = match &self.role { let local_keys = match &self.role {
Role::PublishAndDiscover(key_store) => { Role::PublishAndDiscover(key_store) => key_store
key_store.sr25519_public_keys( .sr25519_public_keys(key_types::AUTHORITY_DISCOVERY)
key_types::AUTHORITY_DISCOVERY .await
).await.into_iter().collect::<HashSet<_>>() .into_iter()
}, .collect::<HashSet<_>>(),
Role::Discover => HashSet::new(), Role::Discover => HashSet::new(),
}; };
@@ -393,9 +384,9 @@ where
self.in_flight_lookups.clear(); self.in_flight_lookups.clear();
if let Some(metrics) = &self.metrics { if let Some(metrics) = &self.metrics {
metrics.requests_pending.set( metrics
self.pending_lookups.len().try_into().unwrap_or(std::u64::MAX), .requests_pending
); .set(self.pending_lookups.len().try_into().unwrap_or(std::u64::MAX));
} }
Ok(()) Ok(())
@@ -408,15 +399,14 @@ where
None => return, None => return,
}; };
let hash = hash_authority_id(authority_id.as_ref()); let hash = hash_authority_id(authority_id.as_ref());
self.network self.network.get_value(&hash);
.get_value(&hash);
self.in_flight_lookups.insert(hash, authority_id); self.in_flight_lookups.insert(hash, authority_id);
if let Some(metrics) = &self.metrics { if let Some(metrics) = &self.metrics {
metrics.requests.inc(); metrics.requests.inc();
metrics.requests_pending.set( metrics
self.pending_lookups.len().try_into().unwrap_or(std::u64::MAX), .requests_pending
); .set(self.pending_lookups.len().try_into().unwrap_or(std::u64::MAX));
} }
} }
} }
@@ -431,10 +421,7 @@ where
if log_enabled!(log::Level::Debug) { if log_enabled!(log::Level::Debug) {
let hashes: Vec<_> = v.iter().map(|(hash, _value)| hash.clone()).collect(); let hashes: Vec<_> = v.iter().map(|(hash, _value)| hash.clone()).collect();
debug!( debug!(target: LOG_TARGET, "Value for hash '{:?}' found on Dht.", hashes,);
target: LOG_TARGET,
"Value for hash '{:?}' found on Dht.", hashes,
);
} }
if let Err(e) = self.handle_dht_value_found_event(v) { if let Err(e) = self.handle_dht_value_found_event(v) {
@@ -442,22 +429,16 @@ where
metrics.handle_value_found_event_failure.inc(); metrics.handle_value_found_event_failure.inc();
} }
debug!( debug!(target: LOG_TARGET, "Failed to handle Dht value found event: {:?}", e,);
target: LOG_TARGET,
"Failed to handle Dht value found event: {:?}", e,
);
} }
} },
DhtEvent::ValueNotFound(hash) => { DhtEvent::ValueNotFound(hash) => {
if let Some(metrics) = &self.metrics { if let Some(metrics) = &self.metrics {
metrics.dht_event_received.with_label_values(&["value_not_found"]).inc(); metrics.dht_event_received.with_label_values(&["value_not_found"]).inc();
} }
if self.in_flight_lookups.remove(&hash).is_some() { if self.in_flight_lookups.remove(&hash).is_some() {
debug!( debug!(target: LOG_TARGET, "Value for hash '{:?}' not found on Dht.", hash)
target: LOG_TARGET,
"Value for hash '{:?}' not found on Dht.", hash
)
} else { } else {
debug!( debug!(
target: LOG_TARGET, target: LOG_TARGET,
@@ -475,21 +456,15 @@ where
metrics.dht_event_received.with_label_values(&["value_put"]).inc(); metrics.dht_event_received.with_label_values(&["value_put"]).inc();
} }
debug!( debug!(target: LOG_TARGET, "Successfully put hash '{:?}' on Dht.", hash,)
target: LOG_TARGET,
"Successfully put hash '{:?}' on Dht.", hash,
)
}, },
DhtEvent::ValuePutFailed(hash) => { DhtEvent::ValuePutFailed(hash) => {
if let Some(metrics) = &self.metrics { if let Some(metrics) = &self.metrics {
metrics.dht_event_received.with_label_values(&["value_put_failed"]).inc(); metrics.dht_event_received.with_label_values(&["value_put_failed"]).inc();
} }
debug!( debug!(target: LOG_TARGET, "Failed to put hash '{:?}' on Dht.", hash)
target: LOG_TARGET, },
"Failed to put hash '{:?}' on Dht.", hash
)
}
} }
} }
@@ -498,34 +473,36 @@ where
values: Vec<(libp2p::kad::record::Key, Vec<u8>)>, values: Vec<(libp2p::kad::record::Key, Vec<u8>)>,
) -> Result<()> { ) -> Result<()> {
// Ensure `values` is not empty and all its keys equal. // Ensure `values` is not empty and all its keys equal.
let remote_key = values.iter().fold(Ok(None), |acc, (key, _)| { let remote_key = values
match acc { .iter()
.fold(Ok(None), |acc, (key, _)| match acc {
Ok(None) => Ok(Some(key.clone())), Ok(None) => Ok(Some(key.clone())),
Ok(Some(ref prev_key)) if prev_key != key => Err( Ok(Some(ref prev_key)) if prev_key != key =>
Error::ReceivingDhtValueFoundEventWithDifferentKeys Err(Error::ReceivingDhtValueFoundEventWithDifferentKeys),
),
x @ Ok(_) => x, x @ Ok(_) => x,
Err(e) => Err(e), Err(e) => Err(e),
} })?
})?.ok_or(Error::ReceivingDhtValueFoundEventWithNoRecords)?; .ok_or(Error::ReceivingDhtValueFoundEventWithNoRecords)?;
let authority_id: AuthorityId = self.in_flight_lookups let authority_id: AuthorityId = self
.in_flight_lookups
.remove(&remote_key) .remove(&remote_key)
.ok_or(Error::ReceivingUnexpectedRecord)?; .ok_or(Error::ReceivingUnexpectedRecord)?;
let local_peer_id = self.network.local_peer_id(); let local_peer_id = self.network.local_peer_id();
let remote_addresses: Vec<Multiaddr> = values.into_iter() let remote_addresses: Vec<Multiaddr> = values
.into_iter()
.map(|(_k, v)| { .map(|(_k, v)| {
let schema::SignedAuthorityAddresses { signature, addresses } = let schema::SignedAuthorityAddresses { signature, addresses } =
schema::SignedAuthorityAddresses::decode(v.as_slice()) schema::SignedAuthorityAddresses::decode(v.as_slice())
.map_err(Error::DecodingProto)?; .map_err(Error::DecodingProto)?;
let signature = AuthoritySignature::decode(&mut &signature[..]) let signature = AuthoritySignature::decode(&mut &signature[..])
.map_err(Error::EncodingDecodingScale)?; .map_err(Error::EncodingDecodingScale)?;
if !AuthorityPair::verify(&signature, &addresses, &authority_id) { if !AuthorityPair::verify(&signature, &addresses, &authority_id) {
return Err(Error::VerifyingDhtPayload); return Err(Error::VerifyingDhtPayload)
} }
let addresses = schema::AuthorityAddresses::decode(addresses.as_slice()) let addresses = schema::AuthorityAddresses::decode(addresses.as_slice())
@@ -542,40 +519,41 @@ where
.into_iter() .into_iter()
.flatten() .flatten()
// Ignore [`Multiaddr`]s without [`PeerId`] and own addresses. // Ignore [`Multiaddr`]s without [`PeerId`] and own addresses.
.filter(|addr| addr.iter().any(|protocol| { .filter(|addr| {
// Parse to PeerId first as Multihashes of old and new PeerId addr.iter().any(|protocol| {
// representation don't equal. // Parse to PeerId first as Multihashes of old and new PeerId
// // representation don't equal.
// See https://github.com/libp2p/rust-libp2p/issues/555 for //
// details. // See https://github.com/libp2p/rust-libp2p/issues/555 for
if let multiaddr::Protocol::P2p(hash) = protocol { // details.
let peer_id = match PeerId::from_multihash(hash) { if let multiaddr::Protocol::P2p(hash) = protocol {
Ok(peer_id) => peer_id, let peer_id = match PeerId::from_multihash(hash) {
Err(_) => return false, // Discard address. Ok(peer_id) => peer_id,
}; Err(_) => return false, // Discard address.
};
// Discard if equal to local peer id, keep if it differs. // Discard if equal to local peer id, keep if it differs.
return !(peer_id == local_peer_id); return !(peer_id == local_peer_id)
} }
false // `protocol` is not a [`Protocol::P2p`], let's keep looking. false // `protocol` is not a [`Protocol::P2p`], let's keep looking.
})) })
})
.take(MAX_ADDRESSES_PER_AUTHORITY) .take(MAX_ADDRESSES_PER_AUTHORITY)
.collect(); .collect();
if !remote_addresses.is_empty() { if !remote_addresses.is_empty() {
self.addr_cache.insert(authority_id, remote_addresses); self.addr_cache.insert(authority_id, remote_addresses);
if let Some(metrics) = &self.metrics { if let Some(metrics) = &self.metrics {
metrics.known_authorities_count.set( metrics
self.addr_cache.num_ids().try_into().unwrap_or(std::u64::MAX) .known_authorities_count
); .set(self.addr_cache.num_ids().try_into().unwrap_or(std::u64::MAX));
} }
} }
Ok(()) Ok(())
} }
/// Retrieve our public keys within the current and next authority set. /// Retrieve our public keys within the current and next authority set.
//
// A node might have multiple authority discovery keys within its keystore, e.g. an old one and // A node might have multiple authority discovery keys within its keystore, e.g. an old one and
// one for the upcoming session. In addition it could be participating in the current and (/ or) // one for the upcoming session. In addition it could be participating in the current and (/ or)
// next authority set with two keys. The function does not return all of the local authority // next authority set with two keys. The function does not return all of the local authority
@@ -591,14 +569,16 @@ where
.collect::<HashSet<_>>(); .collect::<HashSet<_>>();
let id = BlockId::hash(client.info().best_hash); let id = BlockId::hash(client.info().best_hash);
let authorities = client.runtime_api() let authorities = client
.runtime_api()
.authorities(&id) .authorities(&id)
.map_err(|e| Error::CallingRuntime(e.into()))? .map_err(|e| Error::CallingRuntime(e.into()))?
.into_iter() .into_iter()
.map(std::convert::Into::into) .map(std::convert::Into::into)
.collect::<HashSet<_>>(); .collect::<HashSet<_>>();
let intersection = local_pub_keys.intersection(&authorities) let intersection = local_pub_keys
.intersection(&authorities)
.cloned() .cloned()
.map(std::convert::Into::into) .map(std::convert::Into::into)
.collect(); .collect();
@@ -655,7 +635,7 @@ impl Metrics {
publish: register( publish: register(
Counter::new( Counter::new(
"authority_discovery_times_published_total", "authority_discovery_times_published_total",
"Number of times authority discovery has published external addresses." "Number of times authority discovery has published external addresses.",
)?, )?,
registry, registry,
)?, )?,
@@ -663,7 +643,7 @@ impl Metrics {
Gauge::new( Gauge::new(
"authority_discovery_amount_external_addresses_last_published", "authority_discovery_amount_external_addresses_last_published",
"Number of external addresses published when authority discovery last \ "Number of external addresses published when authority discovery last \
published addresses." published addresses.",
)?, )?,
registry, registry,
)?, )?,
@@ -671,14 +651,14 @@ impl Metrics {
Counter::new( Counter::new(
"authority_discovery_authority_addresses_requested_total", "authority_discovery_authority_addresses_requested_total",
"Number of times authority discovery has requested external addresses of a \ "Number of times authority discovery has requested external addresses of a \
single authority." single authority.",
)?, )?,
registry, registry,
)?, )?,
requests_pending: register( requests_pending: register(
Gauge::new( Gauge::new(
"authority_discovery_authority_address_requests_pending", "authority_discovery_authority_address_requests_pending",
"Number of pending authority address requests." "Number of pending authority address requests.",
)?, )?,
registry, registry,
)?, )?,
@@ -686,7 +666,7 @@ impl Metrics {
CounterVec::new( CounterVec::new(
Opts::new( Opts::new(
"authority_discovery_dht_event_received", "authority_discovery_dht_event_received",
"Number of dht events received by authority discovery." "Number of dht events received by authority discovery.",
), ),
&["name"], &["name"],
)?, )?,
@@ -695,14 +675,14 @@ impl Metrics {
handle_value_found_event_failure: register( handle_value_found_event_failure: register(
Counter::new( Counter::new(
"authority_discovery_handle_value_found_event_failure", "authority_discovery_handle_value_found_event_failure",
"Number of times handling a dht value found event failed." "Number of times handling a dht value found event failed.",
)?, )?,
registry, registry,
)?, )?,
known_authorities_count: register( known_authorities_count: register(
Gauge::new( Gauge::new(
"authority_discovery_known_authorities_count", "authority_discovery_known_authorities_count",
"Number of authorities known by authority discovery." "Number of authorities known by authority discovery.",
)?, )?,
registry, registry,
)?, )?,
@@ -19,8 +19,8 @@
use libp2p::core::multiaddr::{Multiaddr, Protocol}; use libp2p::core::multiaddr::{Multiaddr, Protocol};
use std::collections::HashMap; use std::collections::HashMap;
use sp_authority_discovery::AuthorityId;
use sc_network::PeerId; use sc_network::PeerId;
use sp_authority_discovery::AuthorityId;
/// Cache for [`AuthorityId`] -> [`Vec<Multiaddr>`] and [`PeerId`] -> [`AuthorityId`] mappings. /// Cache for [`AuthorityId`] -> [`Vec<Multiaddr>`] and [`PeerId`] -> [`AuthorityId`] mappings.
pub(super) struct AddrCache { pub(super) struct AddrCache {
@@ -45,27 +45,34 @@ impl AddrCache {
addresses.sort_unstable_by(|a, b| a.as_ref().cmp(b.as_ref())); addresses.sort_unstable_by(|a, b| a.as_ref().cmp(b.as_ref()));
// Insert into `self.peer_id_to_authority_id`. // Insert into `self.peer_id_to_authority_id`.
let peer_ids = addresses.iter() let peer_ids = addresses
.iter()
.map(|a| peer_id_from_multiaddr(a)) .map(|a| peer_id_from_multiaddr(a))
.filter_map(|peer_id| peer_id); .filter_map(|peer_id| peer_id);
for peer_id in peer_ids.clone() { for peer_id in peer_ids.clone() {
let former_auth = match self.peer_id_to_authority_id.insert(peer_id, authority_id.clone()) { let former_auth =
Some(a) if a != authority_id => a, match self.peer_id_to_authority_id.insert(peer_id, authority_id.clone()) {
_ => continue, Some(a) if a != authority_id => a,
}; _ => continue,
};
// PeerId was associated to a different authority id before. // PeerId was associated to a different authority id before.
// Remove corresponding authority from `self.authority_id_to_addresses`. // Remove corresponding authority from `self.authority_id_to_addresses`.
let former_auth_addrs = match self.authority_id_to_addresses.get_mut(&former_auth) { let former_auth_addrs = match self.authority_id_to_addresses.get_mut(&former_auth) {
Some(a) => a, Some(a) => a,
None => { debug_assert!(false); continue } None => {
debug_assert!(false);
continue
},
}; };
former_auth_addrs.retain(|a| peer_id_from_multiaddr(a).map_or(true, |p| p != peer_id)); former_auth_addrs.retain(|a| peer_id_from_multiaddr(a).map_or(true, |p| p != peer_id));
} }
// Insert into `self.authority_id_to_addresses`. // Insert into `self.authority_id_to_addresses`.
for former_addr in for former_addr in self
self.authority_id_to_addresses.insert(authority_id.clone(), addresses.clone()).unwrap_or_default() .authority_id_to_addresses
.insert(authority_id.clone(), addresses.clone())
.unwrap_or_default()
{ {
// Must remove from `self.peer_id_to_authority_id` any PeerId formerly associated // Must remove from `self.peer_id_to_authority_id` any PeerId formerly associated
// to that authority but that can't be found in its new addresses. // to that authority but that can't be found in its new addresses.
@@ -87,7 +94,10 @@ impl AddrCache {
} }
/// Returns the addresses for the given [`AuthorityId`]. /// Returns the addresses for the given [`AuthorityId`].
pub fn get_addresses_by_authority_id(&self, authority_id: &AuthorityId) -> Option<&Vec<Multiaddr>> { pub fn get_addresses_by_authority_id(
&self,
authority_id: &AuthorityId,
) -> Option<&Vec<Multiaddr>> {
self.authority_id_to_addresses.get(&authority_id) self.authority_id_to_addresses.get(&authority_id)
} }
@@ -100,7 +110,9 @@ impl AddrCache {
/// [`AuthorityId`]s. /// [`AuthorityId`]s.
pub fn retain_ids(&mut self, authority_ids: &Vec<AuthorityId>) { pub fn retain_ids(&mut self, authority_ids: &Vec<AuthorityId>) {
// The below logic could be replaced by `BtreeMap::drain_filter` once it stabilized. // The below logic could be replaced by `BtreeMap::drain_filter` once it stabilized.
let authority_ids_to_remove = self.authority_id_to_addresses.iter() let authority_ids_to_remove = self
.authority_id_to_addresses
.iter()
.filter(|(id, _addresses)| !authority_ids.contains(id)) .filter(|(id, _addresses)| !authority_ids.contains(id))
.map(|entry| entry.0) .map(|entry| entry.0)
.cloned() .cloned()
@@ -111,7 +123,8 @@ impl AddrCache {
let addresses = self.authority_id_to_addresses.remove(&authority_id_to_remove); let addresses = self.authority_id_to_addresses.remove(&authority_id_to_remove);
// Remove other entries from `self.peer_id_to_authority_id`. // Remove other entries from `self.peer_id_to_authority_id`.
let peer_ids = addresses.iter() let peer_ids = addresses
.iter()
.flatten() .flatten()
.map(|a| peer_id_from_multiaddr(a)) .map(|a| peer_id_from_multiaddr(a))
.filter_map(|peer_id| peer_id); .filter_map(|peer_id| peer_id);
@@ -125,10 +138,12 @@ impl AddrCache {
} }
fn peer_id_from_multiaddr(addr: &Multiaddr) -> Option<PeerId> { fn peer_id_from_multiaddr(addr: &Multiaddr) -> Option<PeerId> {
addr.iter().last().and_then(|protocol| if let Protocol::P2p(multihash) = protocol { addr.iter().last().and_then(|protocol| {
PeerId::from_multihash(multihash).ok() if let Protocol::P2p(multihash) = protocol {
} else { PeerId::from_multihash(multihash).ok()
None } else {
None
}
}) })
} }
@@ -159,9 +174,11 @@ mod tests {
fn arbitrary(g: &mut Gen) -> Self { fn arbitrary(g: &mut Gen) -> Self {
let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>(); let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>();
let peer_id = PeerId::from_multihash( let peer_id = PeerId::from_multihash(
Multihash::wrap(multihash::Code::Sha2_256.into(), &seed).unwrap() Multihash::wrap(multihash::Code::Sha2_256.into(), &seed).unwrap(),
).unwrap(); )
let multiaddr = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333".parse::<Multiaddr>() .unwrap();
let multiaddr = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333"
.parse::<Multiaddr>()
.unwrap() .unwrap()
.with(Protocol::P2p(peer_id.into())); .with(Protocol::P2p(peer_id.into()));
@@ -176,12 +193,15 @@ mod tests {
fn arbitrary(g: &mut Gen) -> Self { fn arbitrary(g: &mut Gen) -> Self {
let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>(); let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>();
let peer_id = PeerId::from_multihash( let peer_id = PeerId::from_multihash(
Multihash::wrap(multihash::Code::Sha2_256.into(), &seed).unwrap() Multihash::wrap(multihash::Code::Sha2_256.into(), &seed).unwrap(),
).unwrap(); )
let multiaddr1 = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333".parse::<Multiaddr>() .unwrap();
let multiaddr1 = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333"
.parse::<Multiaddr>()
.unwrap() .unwrap()
.with(Protocol::P2p(peer_id.clone().into())); .with(Protocol::P2p(peer_id.clone().into()));
let multiaddr2 = "/ip6/2002:db8:0:0:0:0:0:2/tcp/30133".parse::<Multiaddr>() let multiaddr2 = "/ip6/2002:db8:0:0:0:0:0:2/tcp/30133"
.parse::<Multiaddr>()
.unwrap() .unwrap()
.with(Protocol::P2p(peer_id.into())); .with(Protocol::P2p(peer_id.into()));
TestMultiaddrsSamePeerCombo(multiaddr1, multiaddr2) TestMultiaddrsSamePeerCombo(multiaddr1, multiaddr2)
@@ -219,11 +239,13 @@ mod tests {
cache.retain_ids(&vec![first.0, second.0]); cache.retain_ids(&vec![first.0, second.0]);
assert_eq!( assert_eq!(
None, cache.get_addresses_by_authority_id(&third.0), None,
cache.get_addresses_by_authority_id(&third.0),
"Expect `get_addresses_by_authority_id` to not return `None` for third authority." "Expect `get_addresses_by_authority_id` to not return `None` for third authority."
); );
assert_eq!( assert_eq!(
None, cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&third.1).unwrap()), None,
cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&third.1).unwrap()),
"Expect `get_authority_id_by_peer_id` to return `None` for third authority." "Expect `get_authority_id_by_peer_id` to return `None` for third authority."
); );
@@ -253,7 +275,10 @@ mod tests {
let mut cache = AddrCache::new(); let mut cache = AddrCache::new();
cache.insert(authority1.clone(), vec![multiaddr1.clone()]); cache.insert(authority1.clone(), vec![multiaddr1.clone()]);
cache.insert(authority1.clone(), vec![multiaddr2.clone(), multiaddr3.clone(), multiaddr4.clone()]); cache.insert(
authority1.clone(),
vec![multiaddr2.clone(), multiaddr3.clone(), multiaddr4.clone()],
);
assert_eq!( assert_eq!(
None, None,
@@ -18,21 +18,26 @@
use crate::worker::schema; use crate::worker::schema;
use std::{sync::{Arc, Mutex}, task::Poll}; use std::{
sync::{Arc, Mutex},
task::Poll,
};
use async_trait::async_trait; use async_trait::async_trait;
use futures::channel::mpsc::{self, channel}; use futures::{
use futures::executor::{block_on, LocalPool}; channel::mpsc::{self, channel},
use futures::future::FutureExt; executor::{block_on, LocalPool},
use futures::sink::SinkExt; future::FutureExt,
use futures::task::LocalSpawn; sink::SinkExt,
use libp2p::{kad, core::multiaddr, PeerId}; task::LocalSpawn,
};
use libp2p::{core::multiaddr, kad, PeerId};
use prometheus_endpoint::prometheus::default_registry; use prometheus_endpoint::prometheus::default_registry;
use sp_api::{ProvideRuntimeApi, ApiRef}; use sp_api::{ApiRef, ProvideRuntimeApi};
use sp_core::crypto::Public; use sp_core::crypto::Public;
use sp_keystore::{testing::KeyStore, CryptoStore}; use sp_keystore::{testing::KeyStore, CryptoStore};
use sp_runtime::traits::{Zero, Block as BlockT, NumberFor}; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero};
use substrate_test_runtime_client::runtime::Block; use substrate_test_runtime_client::runtime::Block;
use super::*; use super::*;
@@ -46,9 +51,7 @@ impl ProvideRuntimeApi<Block> for TestApi {
type Api = RuntimeApi; type Api = RuntimeApi;
fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> { fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> {
RuntimeApi { RuntimeApi { authorities: self.authorities.clone() }.into()
authorities: self.authorities.clone(),
}.into()
} }
} }
@@ -135,10 +138,7 @@ impl Default for TestNetwork {
let (tx, rx) = mpsc::unbounded(); let (tx, rx) = mpsc::unbounded();
TestNetwork { TestNetwork {
peer_id: PeerId::random(), peer_id: PeerId::random(),
external_addresses: vec![ external_addresses: vec!["/ip6/2001:db8::/tcp/30333".parse().unwrap()],
"/ip6/2001:db8::/tcp/30333"
.parse().unwrap(),
],
put_value_call: Default::default(), put_value_call: Default::default(),
get_value_call: Default::default(), get_value_call: Default::default(),
event_sender: tx, event_sender: tx,
@@ -151,11 +151,17 @@ impl Default for TestNetwork {
impl NetworkProvider for TestNetwork { impl NetworkProvider for TestNetwork {
fn put_value(&self, key: kad::record::Key, value: Vec<u8>) { fn put_value(&self, key: kad::record::Key, value: Vec<u8>) {
self.put_value_call.lock().unwrap().push((key.clone(), value.clone())); self.put_value_call.lock().unwrap().push((key.clone(), value.clone()));
self.event_sender.clone().unbounded_send(TestNetworkEvent::PutCalled(key, value)).unwrap(); self.event_sender
.clone()
.unbounded_send(TestNetworkEvent::PutCalled(key, value))
.unwrap();
} }
fn get_value(&self, key: &kad::record::Key) { fn get_value(&self, key: &kad::record::Key) {
self.get_value_call.lock().unwrap().push(key.clone()); self.get_value_call.lock().unwrap().push(key.clone());
self.event_sender.clone().unbounded_send(TestNetworkEvent::GetCalled(key.clone())).unwrap(); self.event_sender
.clone()
.unbounded_send(TestNetworkEvent::GetCalled(key.clone()))
.unwrap();
} }
} }
@@ -175,9 +181,8 @@ async fn build_dht_event(
key_store: &KeyStore, key_store: &KeyStore,
) -> (libp2p::kad::record::Key, Vec<u8>) { ) -> (libp2p::kad::record::Key, Vec<u8>) {
let mut serialized_addresses = vec![]; let mut serialized_addresses = vec![];
schema::AuthorityAddresses { schema::AuthorityAddresses { addresses: addresses.into_iter().map(|a| a.to_vec()).collect() }
addresses: addresses.into_iter().map(|a| a.to_vec()).collect() .encode(&mut serialized_addresses)
}.encode(&mut serialized_addresses)
.map_err(Error::EncodingProto) .map_err(Error::EncodingProto)
.unwrap(); .unwrap();
@@ -192,11 +197,9 @@ async fn build_dht_event(
.unwrap(); .unwrap();
let mut signed_addresses = vec![]; let mut signed_addresses = vec![];
schema::SignedAuthorityAddresses { schema::SignedAuthorityAddresses { addresses: serialized_addresses.clone(), signature }
addresses: serialized_addresses.clone(), .encode(&mut signed_addresses)
signature, .unwrap();
}
.encode(&mut signed_addresses).unwrap();
let key = hash_authority_id(&public_key.to_raw_vec()); let key = hash_authority_id(&public_key.to_raw_vec());
let value = signed_addresses; let value = signed_addresses;
@@ -208,9 +211,7 @@ fn new_registers_metrics() {
let (_dht_event_tx, dht_event_rx) = mpsc::channel(1000); let (_dht_event_tx, dht_event_rx) = mpsc::channel(1000);
let network: Arc<TestNetwork> = Arc::new(Default::default()); let network: Arc<TestNetwork> = Arc::new(Default::default());
let key_store = KeyStore::new(); let key_store = KeyStore::new();
let test_api = Arc::new(TestApi { let test_api = Arc::new(TestApi { authorities: vec![] });
authorities: vec![],
});
let registry = prometheus_endpoint::Registry::new(); let registry = prometheus_endpoint::Registry::new();
@@ -275,65 +276,67 @@ fn publish_discover_cycle() {
let key_store = KeyStore::new(); let key_store = KeyStore::new();
let _ = pool.spawner().spawn_local_obj(async move { let _ = pool.spawner().spawn_local_obj(
let node_a_public = key_store async move {
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None) let node_a_public = key_store
.await .sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)
.unwrap(); .await
let test_api = Arc::new(TestApi { .unwrap();
authorities: vec![node_a_public.into()], let test_api = Arc::new(TestApi { authorities: vec![node_a_public.into()] });
});
let (_to_worker, from_service) = mpsc::channel(0); let (_to_worker, from_service) = mpsc::channel(0);
let mut worker = Worker::new( let mut worker = Worker::new(
from_service, from_service,
test_api, test_api,
network.clone(), network.clone(),
Box::pin(dht_event_rx), Box::pin(dht_event_rx),
Role::PublishAndDiscover(key_store.into()), Role::PublishAndDiscover(key_store.into()),
None, None,
Default::default(), Default::default(),
); );
worker.publish_ext_addresses(false).await.unwrap(); worker.publish_ext_addresses(false).await.unwrap();
// Expect authority discovery to put a new record onto the dht. // Expect authority discovery to put a new record onto the dht.
assert_eq!(network.put_value_call.lock().unwrap().len(), 1); assert_eq!(network.put_value_call.lock().unwrap().len(), 1);
let dht_event = { let dht_event = {
let (key, value) = network.put_value_call.lock().unwrap().pop().unwrap(); let (key, value) = network.put_value_call.lock().unwrap().pop().unwrap();
sc_network::DhtEvent::ValueFound(vec![(key, value)]) sc_network::DhtEvent::ValueFound(vec![(key, value)])
}; };
// Node B discovering node A's address. // Node B discovering node A's address.
let (mut dht_event_tx, dht_event_rx) = channel(1000); let (mut dht_event_tx, dht_event_rx) = channel(1000);
let test_api = Arc::new(TestApi { let test_api = Arc::new(TestApi {
// Make sure node B identifies node A as an authority. // Make sure node B identifies node A as an authority.
authorities: vec![node_a_public.into()], authorities: vec![node_a_public.into()],
}); });
let network: Arc<TestNetwork> = Arc::new(Default::default()); let network: Arc<TestNetwork> = Arc::new(Default::default());
let key_store = KeyStore::new(); let key_store = KeyStore::new();
let (_to_worker, from_service) = mpsc::channel(0); let (_to_worker, from_service) = mpsc::channel(0);
let mut worker = Worker::new( let mut worker = Worker::new(
from_service, from_service,
test_api, test_api,
network.clone(), network.clone(),
Box::pin(dht_event_rx), Box::pin(dht_event_rx),
Role::PublishAndDiscover(key_store.into()), Role::PublishAndDiscover(key_store.into()),
None, None,
Default::default(), Default::default(),
); );
dht_event_tx.try_send(dht_event.clone()).unwrap(); dht_event_tx.try_send(dht_event.clone()).unwrap();
worker.refill_pending_lookups_queue().await.unwrap(); worker.refill_pending_lookups_queue().await.unwrap();
worker.start_new_lookups(); worker.start_new_lookups();
// Make authority discovery handle the event. // Make authority discovery handle the event.
worker.handle_dht_event(dht_event).await; worker.handle_dht_event(dht_event).await;
}.boxed_local().into()); }
.boxed_local()
.into(),
);
pool.run(); pool.run();
} }
@@ -345,9 +348,7 @@ fn terminate_when_event_stream_terminates() {
let (dht_event_tx, dht_event_rx) = channel(1000); let (dht_event_tx, dht_event_rx) = channel(1000);
let network: Arc<TestNetwork> = Arc::new(Default::default()); let network: Arc<TestNetwork> = Arc::new(Default::default());
let key_store = KeyStore::new(); let key_store = KeyStore::new();
let test_api = Arc::new(TestApi { let test_api = Arc::new(TestApi { authorities: vec![] });
authorities: vec![],
});
let (to_worker, from_service) = mpsc::channel(0); let (to_worker, from_service) = mpsc::channel(0);
let worker = Worker::new( let worker = Worker::new(
@@ -358,7 +359,8 @@ fn terminate_when_event_stream_terminates() {
Role::PublishAndDiscover(key_store.into()), Role::PublishAndDiscover(key_store.into()),
None, None,
Default::default(), Default::default(),
).run(); )
.run();
futures::pin_mut!(worker); futures::pin_mut!(worker);
block_on(async { block_on(async {
@@ -367,7 +369,8 @@ fn terminate_when_event_stream_terminates() {
// Drop sender side of service channel. // Drop sender side of service channel.
drop(to_worker); drop(to_worker);
assert_eq!( assert_eq!(
Poll::Pending, futures::poll!(&mut worker), Poll::Pending,
futures::poll!(&mut worker),
"Expect the authority discovery module not to terminate once the \ "Expect the authority discovery module not to terminate once the \
sender side of the service channel is closed.", sender side of the service channel is closed.",
); );
@@ -377,7 +380,8 @@ fn terminate_when_event_stream_terminates() {
drop(dht_event_tx); drop(dht_event_tx);
assert_eq!( assert_eq!(
Poll::Ready(()), futures::poll!(&mut worker), Poll::Ready(()),
futures::poll!(&mut worker),
"Expect the authority discovery module to terminate once the \ "Expect the authority discovery module to terminate once the \
sending side of the dht event channel is closed.", sending side of the dht event channel is closed.",
); );
@@ -390,14 +394,13 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() {
let peer_id = PeerId::random(); let peer_id = PeerId::random();
let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap(); let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
address.with(multiaddr::Protocol::P2p( address.with(multiaddr::Protocol::P2p(peer_id.into()))
peer_id.into(),
))
}; };
let remote_key_store = KeyStore::new(); let remote_key_store = KeyStore::new();
let remote_public_key: AuthorityId = block_on( let remote_public_key: AuthorityId =
remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None), block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
).unwrap().into(); .unwrap()
.into();
let (mut dht_event_tx, dht_event_rx) = channel(1); let (mut dht_event_tx, dht_event_rx) = channel(1);
let (network, mut network_events) = { let (network, mut network_events) = {
@@ -407,9 +410,7 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() {
}; };
let key_store = KeyStore::new(); let key_store = KeyStore::new();
let test_api = Arc::new(TestApi { let test_api = Arc::new(TestApi { authorities: vec![remote_public_key.clone()] });
authorities: vec![remote_public_key.clone()],
});
let mut pool = LocalPool::new(); let mut pool = LocalPool::new();
let (mut to_worker, from_service) = mpsc::channel(1); let (mut to_worker, from_service) = mpsc::channel(1);
@@ -427,30 +428,35 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() {
// //
// As this is a local pool, only one future at a time will have the CPU and // As this is a local pool, only one future at a time will have the CPU and
// can make progress until the future returns `Pending`. // can make progress until the future returns `Pending`.
let _ = pool.spawner().spawn_local_obj(async move { let _ = pool.spawner().spawn_local_obj(
// Refilling `pending_lookups` only happens every X minutes. Fast async move {
// forward by calling `refill_pending_lookups_queue` directly. // Refilling `pending_lookups` only happens every X minutes. Fast
worker.refill_pending_lookups_queue().await.unwrap(); // forward by calling `refill_pending_lookups_queue` directly.
worker.run().await worker.refill_pending_lookups_queue().await.unwrap();
}.boxed_local().into()); worker.run().await
}
.boxed_local()
.into(),
);
pool.run_until(async { pool.run_until(async {
// Assert worker to trigger a lookup for the one and only authority. // Assert worker to trigger a lookup for the one and only authority.
assert!(matches!( assert!(matches!(network_events.next().await, Some(TestNetworkEvent::GetCalled(_))));
network_events.next().await,
Some(TestNetworkEvent::GetCalled(_))
));
// Send an event that should generate an error // Send an event that should generate an error
dht_event_tx.send(DhtEvent::ValueFound(Default::default())).await dht_event_tx
.send(DhtEvent::ValueFound(Default::default()))
.await
.expect("Channel has capacity of 1."); .expect("Channel has capacity of 1.");
// Make previously triggered lookup succeed. // Make previously triggered lookup succeed.
let dht_event = { let dht_event = {
let (key, value) = build_dht_event( let (key, value) = build_dht_event(
vec![remote_multiaddr.clone()], vec![remote_multiaddr.clone()],
remote_public_key.clone(), &remote_key_store, remote_public_key.clone(),
).await; &remote_key_store,
)
.await;
sc_network::DhtEvent::ValueFound(vec![(key, value)]) sc_network::DhtEvent::ValueFound(vec![(key, value)])
}; };
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
@@ -458,10 +464,10 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() {
// Expect authority discovery to function normally, now knowing the // Expect authority discovery to function normally, now knowing the
// address for the remote node. // address for the remote node.
let (sender, addresses) = futures::channel::oneshot::channel(); let (sender, addresses) = futures::channel::oneshot::channel();
to_worker.send(ServicetoWorkerMsg::GetAddressesByAuthorityId( to_worker
remote_public_key, .send(ServicetoWorkerMsg::GetAddressesByAuthorityId(remote_public_key, sender))
sender, .await
)).await.expect("Channel has capacity of 1."); .expect("Channel has capacity of 1.");
assert_eq!(Some(vec![remote_multiaddr]), addresses.await.unwrap()); assert_eq!(Some(vec![remote_multiaddr]), addresses.await.unwrap());
}); });
} }
@@ -469,23 +475,19 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() {
#[test] #[test]
fn limit_number_of_addresses_added_to_cache_per_authority() { fn limit_number_of_addresses_added_to_cache_per_authority() {
let remote_key_store = KeyStore::new(); let remote_key_store = KeyStore::new();
let remote_public = block_on(remote_key_store let remote_public =
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)) block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
.unwrap(); .unwrap();
let addresses = (0..100).map(|_| { let addresses = (0..100)
let peer_id = PeerId::random(); .map(|_| {
let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap(); let peer_id = PeerId::random();
address.with(multiaddr::Protocol::P2p( let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
peer_id.into(), address.with(multiaddr::Protocol::P2p(peer_id.into()))
)) })
}).collect(); .collect();
let dht_event = block_on(build_dht_event( let dht_event = block_on(build_dht_event(addresses, remote_public.into(), &remote_key_store));
addresses,
remote_public.into(),
&remote_key_store,
));
let (_dht_event_tx, dht_event_rx) = channel(1); let (_dht_event_tx, dht_event_rx) = channel(1);
@@ -506,16 +508,20 @@ fn limit_number_of_addresses_added_to_cache_per_authority() {
worker.handle_dht_value_found_event(vec![dht_event]).unwrap(); worker.handle_dht_value_found_event(vec![dht_event]).unwrap();
assert_eq!( assert_eq!(
MAX_ADDRESSES_PER_AUTHORITY, MAX_ADDRESSES_PER_AUTHORITY,
worker.addr_cache.get_addresses_by_authority_id(&remote_public.into()).unwrap().len(), worker
.addr_cache
.get_addresses_by_authority_id(&remote_public.into())
.unwrap()
.len(),
); );
} }
#[test] #[test]
fn do_not_cache_addresses_without_peer_id() { fn do_not_cache_addresses_without_peer_id() {
let remote_key_store = KeyStore::new(); let remote_key_store = KeyStore::new();
let remote_public = block_on(remote_key_store let remote_public =
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)) block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
.unwrap(); .unwrap();
let multiaddr_with_peer_id = { let multiaddr_with_peer_id = {
let peer_id = PeerId::random(); let peer_id = PeerId::random();
@@ -524,21 +530,17 @@ fn do_not_cache_addresses_without_peer_id() {
address.with(multiaddr::Protocol::P2p(peer_id.into())) address.with(multiaddr::Protocol::P2p(peer_id.into()))
}; };
let multiaddr_without_peer_id: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap(); let multiaddr_without_peer_id: Multiaddr =
"/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
let dht_event = block_on(build_dht_event( let dht_event = block_on(build_dht_event(
vec![ vec![multiaddr_with_peer_id.clone(), multiaddr_without_peer_id],
multiaddr_with_peer_id.clone(),
multiaddr_without_peer_id,
],
remote_public.into(), remote_public.into(),
&remote_key_store, &remote_key_store,
)); ));
let (_dht_event_tx, dht_event_rx) = channel(1); let (_dht_event_tx, dht_event_rx) = channel(1);
let local_test_api = Arc::new(TestApi { let local_test_api = Arc::new(TestApi { authorities: vec![remote_public.into()] });
authorities: vec![remote_public.into()],
});
let local_network: Arc<TestNetwork> = Arc::new(Default::default()); let local_network: Arc<TestNetwork> = Arc::new(Default::default());
let local_key_store = KeyStore::new(); let local_key_store = KeyStore::new();
@@ -578,9 +580,7 @@ fn addresses_to_publish_adds_p2p() {
let (_to_worker, from_service) = mpsc::channel(0); let (_to_worker, from_service) = mpsc::channel(0);
let worker = Worker::new( let worker = Worker::new(
from_service, from_service,
Arc::new(TestApi { Arc::new(TestApi { authorities: vec![] }),
authorities: vec![],
}),
network.clone(), network.clone(),
Box::pin(dht_event_rx), Box::pin(dht_event_rx),
Role::PublishAndDiscover(Arc::new(KeyStore::new())), Role::PublishAndDiscover(Arc::new(KeyStore::new())),
@@ -605,17 +605,16 @@ fn addresses_to_publish_respects_existing_p2p_protocol() {
let network: Arc<TestNetwork> = Arc::new(TestNetwork { let network: Arc<TestNetwork> = Arc::new(TestNetwork {
external_addresses: vec![ external_addresses: vec![
"/ip6/2001:db8::/tcp/30333/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC" "/ip6/2001:db8::/tcp/30333/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"
.parse().unwrap(), .parse()
.unwrap(),
], ],
.. Default::default() ..Default::default()
}); });
let (_to_worker, from_service) = mpsc::channel(0); let (_to_worker, from_service) = mpsc::channel(0);
let worker = Worker::new( let worker = Worker::new(
from_service, from_service,
Arc::new(TestApi { Arc::new(TestApi { authorities: vec![] }),
authorities: vec![],
}),
network.clone(), network.clone(),
Box::pin(dht_event_rx), Box::pin(dht_event_rx),
Role::PublishAndDiscover(Arc::new(KeyStore::new())), Role::PublishAndDiscover(Arc::new(KeyStore::new())),
@@ -624,7 +623,8 @@ fn addresses_to_publish_respects_existing_p2p_protocol() {
); );
assert_eq!( assert_eq!(
network.external_addresses, worker.addresses_to_publish().collect::<Vec<_>>(), network.external_addresses,
worker.addresses_to_publish().collect::<Vec<_>>(),
"Expected Multiaddr from `TestNetwork` to not be altered.", "Expected Multiaddr from `TestNetwork` to not be altered.",
); );
} }
@@ -635,21 +635,21 @@ fn lookup_throttling() {
let peer_id = PeerId::random(); let peer_id = PeerId::random();
let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap(); let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
address.with(multiaddr::Protocol::P2p( address.with(multiaddr::Protocol::P2p(peer_id.into()))
peer_id.into(),
))
}; };
let remote_key_store = KeyStore::new(); let remote_key_store = KeyStore::new();
let remote_public_keys: Vec<AuthorityId> = (0..20).map(|_| { let remote_public_keys: Vec<AuthorityId> = (0..20)
block_on(remote_key_store .map(|_| {
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)) block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
.unwrap().into() .unwrap()
}).collect(); .into()
let remote_hash_to_key = remote_public_keys.iter() })
.collect();
let remote_hash_to_key = remote_public_keys
.iter()
.map(|k| (hash_authority_id(k.as_ref()), k.clone())) .map(|k| (hash_authority_id(k.as_ref()), k.clone()))
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();
let (mut dht_event_tx, dht_event_rx) = channel(1); let (mut dht_event_tx, dht_event_rx) = channel(1);
let (_to_worker, from_service) = mpsc::channel(0); let (_to_worker, from_service) = mpsc::channel(0);
let mut network = TestNetwork::default(); let mut network = TestNetwork::default();
@@ -668,56 +668,61 @@ fn lookup_throttling() {
let mut pool = LocalPool::new(); let mut pool = LocalPool::new();
let metrics = worker.metrics.clone().unwrap(); let metrics = worker.metrics.clone().unwrap();
let _ = pool.spawner().spawn_local_obj(async move { let _ = pool.spawner().spawn_local_obj(
// Refilling `pending_lookups` only happens every X minutes. Fast async move {
// forward by calling `refill_pending_lookups_queue` directly. // Refilling `pending_lookups` only happens every X minutes. Fast
worker.refill_pending_lookups_queue().await.unwrap(); // forward by calling `refill_pending_lookups_queue` directly.
worker.run().await worker.refill_pending_lookups_queue().await.unwrap();
}.boxed_local().into()); worker.run().await
pool.run_until(async {
// Assert worker to trigger MAX_IN_FLIGHT_LOOKUPS lookups.
for _ in 0..MAX_IN_FLIGHT_LOOKUPS {
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
} }
assert_eq!( .boxed_local()
metrics.requests_pending.get(), .into(),
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS) as u64 );
);
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS);
// Make first lookup succeed. pool.run_until(
let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap(); async {
let remote_key: AuthorityId = remote_hash_to_key.get(&remote_hash).unwrap().clone(); // Assert worker to trigger MAX_IN_FLIGHT_LOOKUPS lookups.
let dht_event = { for _ in 0..MAX_IN_FLIGHT_LOOKUPS {
let (key, value) = build_dht_event( assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
vec![remote_multiaddr.clone()], }
remote_key, assert_eq!(
&remote_key_store metrics.requests_pending.get(),
).await; (remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS) as u64
sc_network::DhtEvent::ValueFound(vec![(key, value)]) );
}; assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS);
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
// Assert worker to trigger another lookup. // Make first lookup succeed.
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_)))); let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap();
assert_eq!( let remote_key: AuthorityId = remote_hash_to_key.get(&remote_hash).unwrap().clone();
metrics.requests_pending.get(), let dht_event = {
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS - 1) as u64 let (key, value) =
); build_dht_event(vec![remote_multiaddr.clone()], remote_key, &remote_key_store)
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS); .await;
sc_network::DhtEvent::ValueFound(vec![(key, value)])
};
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
// Make second one fail. // Assert worker to trigger another lookup.
let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap(); assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
let dht_event = sc_network::DhtEvent::ValueNotFound(remote_hash); assert_eq!(
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); metrics.requests_pending.get(),
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS - 1) as u64
);
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS);
// Assert worker to trigger another lookup. // Make second one fail.
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_)))); let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap();
assert_eq!( let dht_event = sc_network::DhtEvent::ValueNotFound(remote_hash);
metrics.requests_pending.get(), dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS - 2) as u64
); // Assert worker to trigger another lookup.
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS); assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
}.boxed_local()); assert_eq!(
metrics.requests_pending.get(),
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS - 2) as u64
);
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS);
}
.boxed_local(),
);
} }
@@ -20,24 +20,30 @@
// FIXME #1021 move this into sp-consensus // FIXME #1021 move this into sp-consensus
use std::{pin::Pin, time, sync::Arc};
use sc_client_api::backend;
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use sp_consensus::{evaluation, Proposal, ProofRecording, DisableProofRecording, EnableProofRecording}; use futures::{
channel::oneshot,
future,
future::{Future, FutureExt},
select,
};
use log::{debug, error, info, trace, warn};
use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider};
use sc_client_api::backend;
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_INFO};
use sc_transaction_pool_api::{InPoolTransaction, TransactionPool};
use sp_api::{ApiExt, ProvideRuntimeApi};
use sp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed, HeaderBackend};
use sp_consensus::{
evaluation, DisableProofRecording, EnableProofRecording, ProofRecording, Proposal,
};
use sp_core::traits::SpawnNamed; use sp_core::traits::SpawnNamed;
use sp_inherents::InherentData; use sp_inherents::InherentData;
use log::{error, info, debug, trace, warn};
use sp_runtime::{ use sp_runtime::{
generic::BlockId, generic::BlockId,
traits::{Block as BlockT, Hash as HashT, Header as HeaderT, DigestFor, BlakeTwo256}, traits::{BlakeTwo256, Block as BlockT, DigestFor, Hash as HashT, Header as HeaderT},
}; };
use sc_transaction_pool_api::{TransactionPool, InPoolTransaction}; use std::{marker::PhantomData, pin::Pin, sync::Arc, time};
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_INFO};
use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider};
use sp_api::{ProvideRuntimeApi, ApiExt};
use futures::{future, future::{Future, FutureExt}, channel::oneshot, select};
use sp_blockchain::{HeaderBackend, ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed};
use std::marker::PhantomData;
use prometheus_endpoint::Registry as PrometheusRegistry; use prometheus_endpoint::Registry as PrometheusRegistry;
use sc_proposer_metrics::MetricsLink as PrometheusMetrics; use sc_proposer_metrics::MetricsLink as PrometheusMetrics;
@@ -141,14 +147,18 @@ impl<A, B, C, PR> ProposerFactory<A, B, C, PR> {
} }
impl<B, Block, C, A, PR> ProposerFactory<A, B, C, PR> impl<B, Block, C, A, PR> ProposerFactory<A, B, C, PR>
where where
A: TransactionPool<Block = Block> + 'static, A: TransactionPool<Block = Block> + 'static,
B: backend::Backend<Block> + Send + Sync + 'static, B: backend::Backend<Block> + Send + Sync + 'static,
Block: BlockT, Block: BlockT,
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block> C: BlockBuilderProvider<B, Block, C>
+ Send + Sync + 'static, + HeaderBackend<Block>
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + ProvideRuntimeApi<Block>
+ BlockBuilderApi<Block>, + Send
+ Sync
+ 'static,
C::Api:
ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + BlockBuilderApi<Block>,
{ {
fn init_with_now( fn init_with_now(
&mut self, &mut self,
@@ -180,26 +190,26 @@ impl<B, Block, C, A, PR> ProposerFactory<A, B, C, PR>
} }
} }
impl<A, B, Block, C, PR> sp_consensus::Environment<Block> for impl<A, B, Block, C, PR> sp_consensus::Environment<Block> for ProposerFactory<A, B, C, PR>
ProposerFactory<A, B, C, PR> where
where A: TransactionPool<Block = Block> + 'static,
A: TransactionPool<Block = Block> + 'static, B: backend::Backend<Block> + Send + Sync + 'static,
B: backend::Backend<Block> + Send + Sync + 'static, Block: BlockT,
Block: BlockT, C: BlockBuilderProvider<B, Block, C>
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block> + HeaderBackend<Block>
+ Send + Sync + 'static, + ProvideRuntimeApi<Block>
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + Send
+ BlockBuilderApi<Block>, + Sync
PR: ProofRecording, + 'static,
C::Api:
ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + BlockBuilderApi<Block>,
PR: ProofRecording,
{ {
type CreateProposer = future::Ready<Result<Self::Proposer, Self::Error>>; type CreateProposer = future::Ready<Result<Self::Proposer, Self::Error>>;
type Proposer = Proposer<B, Block, C, A, PR>; type Proposer = Proposer<B, Block, C, A, PR>;
type Error = sp_blockchain::Error; type Error = sp_blockchain::Error;
fn init( fn init(&mut self, parent_header: &<Block as BlockT>::Header) -> Self::CreateProposer {
&mut self,
parent_header: &<Block as BlockT>::Header,
) -> Self::CreateProposer {
future::ready(Ok(self.init_with_now(parent_header, Box::new(time::Instant::now)))) future::ready(Ok(self.init_with_now(parent_header, Box::new(time::Instant::now))))
} }
} }
@@ -220,22 +230,28 @@ pub struct Proposer<B, Block: BlockT, C, A: TransactionPool, PR> {
_phantom: PhantomData<(B, PR)>, _phantom: PhantomData<(B, PR)>,
} }
impl<A, B, Block, C, PR> sp_consensus::Proposer<Block> for impl<A, B, Block, C, PR> sp_consensus::Proposer<Block> for Proposer<B, Block, C, A, PR>
Proposer<B, Block, C, A, PR> where
where A: TransactionPool<Block = Block> + 'static,
A: TransactionPool<Block = Block> + 'static, B: backend::Backend<Block> + Send + Sync + 'static,
B: backend::Backend<Block> + Send + Sync + 'static, Block: BlockT,
Block: BlockT, C: BlockBuilderProvider<B, Block, C>
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block> + HeaderBackend<Block>
+ Send + Sync + 'static, + ProvideRuntimeApi<Block>
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + Send
+ BlockBuilderApi<Block>, + Sync
PR: ProofRecording, + 'static,
C::Api:
ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + BlockBuilderApi<Block>,
PR: ProofRecording,
{ {
type Transaction = backend::TransactionFor<B, Block>; type Transaction = backend::TransactionFor<B, Block>;
type Proposal = Pin<Box<dyn Future< type Proposal = Pin<
Output = Result<Proposal<Block, Self::Transaction, PR::Proof>, Self::Error> Box<
> + Send>>; dyn Future<Output = Result<Proposal<Block, Self::Transaction, PR::Proof>, Self::Error>>
+ Send,
>,
>;
type Error = sp_blockchain::Error; type Error = sp_blockchain::Error;
type ProofRecording = PR; type ProofRecording = PR;
type Proof = PR::Proof; type Proof = PR::Proof;
@@ -250,36 +266,38 @@ impl<A, B, Block, C, PR> sp_consensus::Proposer<Block> for
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
let spawn_handle = self.spawn_handle.clone(); let spawn_handle = self.spawn_handle.clone();
spawn_handle.spawn_blocking("basic-authorship-proposer", Box::pin(async move { spawn_handle.spawn_blocking(
// leave some time for evaluation and block finalization (33%) "basic-authorship-proposer",
let deadline = (self.now)() + max_duration - max_duration / 3; Box::pin(async move {
let res = self.propose_with( // leave some time for evaluation and block finalization (33%)
inherent_data, let deadline = (self.now)() + max_duration - max_duration / 3;
inherent_digests, let res = self
deadline, .propose_with(inherent_data, inherent_digests, deadline, block_size_limit)
block_size_limit, .await;
).await; if tx.send(res).is_err() {
if tx.send(res).is_err() { trace!("Could not send block production result to proposer!");
trace!("Could not send block production result to proposer!"); }
} }),
})); );
async move { async move { rx.await? }.boxed()
rx.await?
}.boxed()
} }
} }
impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR> impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
where where
A: TransactionPool<Block = Block>, A: TransactionPool<Block = Block>,
B: backend::Backend<Block> + Send + Sync + 'static, B: backend::Backend<Block> + Send + Sync + 'static,
Block: BlockT, Block: BlockT,
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block> C: BlockBuilderProvider<B, Block, C>
+ Send + Sync + 'static, + HeaderBackend<Block>
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + ProvideRuntimeApi<Block>
+ BlockBuilderApi<Block>, + Send
PR: ProofRecording, + Sync
+ 'static,
C::Api:
ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + BlockBuilderApi<Block>,
PR: ProofRecording,
{ {
async fn propose_with( async fn propose_with(
self, self,
@@ -287,30 +305,30 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
inherent_digests: DigestFor<Block>, inherent_digests: DigestFor<Block>,
deadline: time::Instant, deadline: time::Instant,
block_size_limit: Option<usize>, block_size_limit: Option<usize>,
) -> Result<Proposal<Block, backend::TransactionFor<B, Block>, PR::Proof>, sp_blockchain::Error> { ) -> Result<Proposal<Block, backend::TransactionFor<B, Block>, PR::Proof>, sp_blockchain::Error>
{
/// If the block is full we will attempt to push at most /// If the block is full we will attempt to push at most
/// this number of transactions before quitting for real. /// this number of transactions before quitting for real.
/// It allows us to increase block utilization. /// It allows us to increase block utilization.
const MAX_SKIPPED_TRANSACTIONS: usize = 8; const MAX_SKIPPED_TRANSACTIONS: usize = 8;
let mut block_builder = self.client.new_block_at( let mut block_builder =
&self.parent_id, self.client.new_block_at(&self.parent_id, inherent_digests, PR::ENABLED)?;
inherent_digests,
PR::ENABLED,
)?;
for inherent in block_builder.create_inherents(inherent_data)? { for inherent in block_builder.create_inherents(inherent_data)? {
match block_builder.push(inherent) { match block_builder.push(inherent) {
Err(ApplyExtrinsicFailed(Validity(e))) if e.exhausted_resources() => Err(ApplyExtrinsicFailed(Validity(e))) if e.exhausted_resources() =>
warn!("⚠️ Dropping non-mandatory inherent from overweight block."), warn!("⚠️ Dropping non-mandatory inherent from overweight block."),
Err(ApplyExtrinsicFailed(Validity(e))) if e.was_mandatory() => { Err(ApplyExtrinsicFailed(Validity(e))) if e.was_mandatory() => {
error!("❌️ Mandatory inherent extrinsic returned error. Block cannot be produced."); error!(
"❌️ Mandatory inherent extrinsic returned error. Block cannot be produced."
);
Err(ApplyExtrinsicFailed(Validity(e)))? Err(ApplyExtrinsicFailed(Validity(e)))?
} },
Err(e) => { Err(e) => {
warn!("❗️ Inherent extrinsic returned unexpected error: {}. Dropping.", e); warn!("❗️ Inherent extrinsic returned unexpected error: {}. Dropping.", e);
} },
Ok(_) => {} Ok(_) => {},
} }
} }
@@ -320,9 +338,8 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
let mut unqueue_invalid = Vec::new(); let mut unqueue_invalid = Vec::new();
let mut t1 = self.transaction_pool.ready_at(self.parent_number).fuse(); let mut t1 = self.transaction_pool.ready_at(self.parent_number).fuse();
let mut t2 = futures_timer::Delay::new( let mut t2 =
deadline.saturating_duration_since((self.now)()) / 8, futures_timer::Delay::new(deadline.saturating_duration_since((self.now)()) / 8).fuse();
).fuse();
let pending_iterator = select! { let pending_iterator = select! {
res = t1 => res, res = t1 => res,
@@ -349,15 +366,14 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
"Consensus deadline reached when pushing block transactions, \ "Consensus deadline reached when pushing block transactions, \
proceeding with proposing." proceeding with proposing."
); );
break; break
} }
let pending_tx_data = pending_tx.data().clone(); let pending_tx_data = pending_tx.data().clone();
let pending_tx_hash = pending_tx.hash().clone(); let pending_tx_hash = pending_tx.hash().clone();
let block_size = block_builder.estimate_block_size( let block_size =
self.include_proof_in_block_size_estimation, block_builder.estimate_block_size(self.include_proof_in_block_size_estimation);
);
if block_size + pending_tx_data.encoded_size() > block_size_limit { if block_size + pending_tx_data.encoded_size() > block_size_limit {
if skipped < MAX_SKIPPED_TRANSACTIONS { if skipped < MAX_SKIPPED_TRANSACTIONS {
skipped += 1; skipped += 1;
@@ -366,11 +382,11 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
but will try {} more transactions before quitting.", but will try {} more transactions before quitting.",
MAX_SKIPPED_TRANSACTIONS - skipped, MAX_SKIPPED_TRANSACTIONS - skipped,
); );
continue; continue
} else { } else {
debug!("Reached block size limit, proceeding with proposing."); debug!("Reached block size limit, proceeding with proposing.");
hit_block_size_limit = true; hit_block_size_limit = true;
break; break
} }
} }
@@ -379,9 +395,8 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
Ok(()) => { Ok(()) => {
transaction_pushed = true; transaction_pushed = true;
debug!("[{:?}] Pushed to the block.", pending_tx_hash); debug!("[{:?}] Pushed to the block.", pending_tx_hash);
} },
Err(ApplyExtrinsicFailed(Validity(e))) Err(ApplyExtrinsicFailed(Validity(e))) if e.exhausted_resources() => {
if e.exhausted_resources() => {
if skipped < MAX_SKIPPED_TRANSACTIONS { if skipped < MAX_SKIPPED_TRANSACTIONS {
skipped += 1; skipped += 1;
debug!( debug!(
@@ -390,20 +405,20 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
); );
} else { } else {
debug!("Block is full, proceed with proposing."); debug!("Block is full, proceed with proposing.");
break; break
} }
} },
Err(e) if skipped > 0 => { Err(e) if skipped > 0 => {
trace!( trace!(
"[{:?}] Ignoring invalid transaction when skipping: {}", "[{:?}] Ignoring invalid transaction when skipping: {}",
pending_tx_hash, pending_tx_hash,
e e
); );
} },
Err(e) => { Err(e) => {
debug!("[{:?}] Invalid transaction: {}", pending_tx_hash, e); debug!("[{:?}] Invalid transaction: {}", pending_tx_hash, e);
unqueue_invalid.push(pending_tx_hash); unqueue_invalid.push(pending_tx_hash);
} },
} }
} }
@@ -418,12 +433,10 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
let (block, storage_changes, proof) = block_builder.build()?.into_inner(); let (block, storage_changes, proof) = block_builder.build()?.into_inner();
self.metrics.report( self.metrics.report(|metrics| {
|metrics| { metrics.number_of_transactions.set(block.extrinsics().len() as u64);
metrics.number_of_transactions.set(block.extrinsics().len() as u64); metrics.block_constructed.observe(block_timer.elapsed().as_secs_f64());
metrics.block_constructed.observe(block_timer.elapsed().as_secs_f64()); });
}
);
info!( info!(
"🎁 Prepared block for proposing at {} [hash: {:?}; parent_hash: {}; extrinsics ({}): [{}]]", "🎁 Prepared block for proposing at {} [hash: {:?}; parent_hash: {}; extrinsics ({}): [{}]]",
@@ -449,16 +462,14 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
error!("Failed to verify block encoding/decoding"); error!("Failed to verify block encoding/decoding");
} }
if let Err(err) = evaluation::evaluate_initial( if let Err(err) =
&block, evaluation::evaluate_initial(&block, &self.parent_hash, self.parent_number)
&self.parent_hash, {
self.parent_number,
) {
error!("Failed to evaluate authored block: {:?}", err); error!("Failed to evaluate authored block: {:?}", err);
} }
let proof = PR::into_proof(proof) let proof =
.map_err(|e| sp_blockchain::Error::Application(Box::new(e)))?; PR::into_proof(proof).map_err(|e| sp_blockchain::Error::Application(Box::new(e)))?;
Ok(Proposal { block, proof, storage_changes }) Ok(Proposal { block, proof, storage_changes })
} }
} }
@@ -467,19 +478,20 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
mod tests { mod tests {
use super::*; use super::*;
use futures::executor::block_on;
use parking_lot::Mutex; use parking_lot::Mutex;
use sp_consensus::{BlockOrigin, Proposer}; use sc_client_api::Backend;
use substrate_test_runtime_client::{
prelude::*, TestClientBuilder, runtime::{Extrinsic, Transfer}, TestClientBuilderExt,
};
use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool, TransactionSource};
use sc_transaction_pool::BasicPool; use sc_transaction_pool::BasicPool;
use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool, TransactionSource};
use sp_api::Core; use sp_api::Core;
use sp_blockchain::HeaderBackend; use sp_blockchain::HeaderBackend;
use sp_consensus::{BlockOrigin, Environment, Proposer};
use sp_runtime::traits::NumberFor; use sp_runtime::traits::NumberFor;
use sc_client_api::Backend; use substrate_test_runtime_client::{
use futures::executor::block_on; prelude::*,
use sp_consensus::Environment; runtime::{Extrinsic, Transfer},
TestClientBuilder, TestClientBuilderExt,
};
const SOURCE: TransactionSource = TransactionSource::External; const SOURCE: TransactionSource = TransactionSource::External;
@@ -489,16 +501,15 @@ mod tests {
nonce, nonce,
from: AccountKeyring::Alice.into(), from: AccountKeyring::Alice.into(),
to: Default::default(), to: Default::default(),
}.into_signed_tx() }
.into_signed_tx()
} }
fn chain_event<B: BlockT>(header: B::Header) -> ChainEvent<B> fn chain_event<B: BlockT>(header: B::Header) -> ChainEvent<B>
where NumberFor<B>: From<u64> where
NumberFor<B>: From<u64>,
{ {
ChainEvent::NewBestBlock { ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }
hash: header.hash(),
tree_route: None,
}
} }
#[test] #[test]
@@ -514,25 +525,20 @@ mod tests {
client.clone(), client.clone(),
); );
block_on( block_on(txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0), extrinsic(1)]))
txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0), extrinsic(1)]) .unwrap();
).unwrap();
block_on( block_on(
txpool.maintain(chain_event( txpool.maintain(chain_event(
client.header(&BlockId::Number(0u64)) client
.header(&BlockId::Number(0u64))
.expect("header get error") .expect("header get error")
.expect("there should be header") .expect("there should be header"),
)) )),
); );
let mut proposer_factory = ProposerFactory::new( let mut proposer_factory =
spawner.clone(), ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
client.clone(),
txpool.clone(),
None,
None,
);
let cell = Mutex::new((false, time::Instant::now())); let cell = Mutex::new((false, time::Instant::now()));
let proposer = proposer_factory.init_with_now( let proposer = proposer_factory.init_with_now(
@@ -541,20 +547,21 @@ mod tests {
let mut value = cell.lock(); let mut value = cell.lock();
if !value.0 { if !value.0 {
value.0 = true; value.0 = true;
return value.1; return value.1
} }
let old = value.1; let old = value.1;
let new = old + time::Duration::from_secs(2); let new = old + time::Duration::from_secs(2);
*value = (true, new); *value = (true, new);
old old
}) }),
); );
// when // when
let deadline = time::Duration::from_secs(3); let deadline = time::Duration::from_secs(3);
let block = block_on( let block =
proposer.propose(Default::default(), Default::default(), deadline, None) block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
).map(|r| r.block).unwrap(); .map(|r| r.block)
.unwrap();
// then // then
// block should have some extrinsics although we have some more in the pool. // block should have some extrinsics although we have some more in the pool.
@@ -574,13 +581,8 @@ mod tests {
client.clone(), client.clone(),
); );
let mut proposer_factory = ProposerFactory::new( let mut proposer_factory =
spawner.clone(), ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
client.clone(),
txpool.clone(),
None,
None,
);
let cell = Mutex::new((false, time::Instant::now())); let cell = Mutex::new((false, time::Instant::now()));
let proposer = proposer_factory.init_with_now( let proposer = proposer_factory.init_with_now(
@@ -589,18 +591,18 @@ mod tests {
let mut value = cell.lock(); let mut value = cell.lock();
if !value.0 { if !value.0 {
value.0 = true; value.0 = true;
return value.1; return value.1
} }
let new = value.1 + time::Duration::from_secs(160); let new = value.1 + time::Duration::from_secs(160);
*value = (true, new); *value = (true, new);
new new
}) }),
); );
let deadline = time::Duration::from_secs(1); let deadline = time::Duration::from_secs(1);
block_on( block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
proposer.propose(Default::default(), Default::default(), deadline, None) .map(|r| r.block)
).map(|r| r.block).unwrap(); .unwrap();
} }
#[test] #[test]
@@ -619,25 +621,19 @@ mod tests {
let genesis_hash = client.info().best_hash; let genesis_hash = client.info().best_hash;
let block_id = BlockId::Hash(genesis_hash); let block_id = BlockId::Hash(genesis_hash);
block_on( block_on(txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0)])).unwrap();
txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0)]),
).unwrap();
block_on( block_on(
txpool.maintain(chain_event( txpool.maintain(chain_event(
client.header(&BlockId::Number(0u64)) client
.header(&BlockId::Number(0u64))
.expect("header get error") .expect("header get error")
.expect("there should be header"), .expect("there should be header"),
)) )),
); );
let mut proposer_factory = ProposerFactory::new( let mut proposer_factory =
spawner.clone(), ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
client.clone(),
txpool.clone(),
None,
None,
);
let proposer = proposer_factory.init_with_now( let proposer = proposer_factory.init_with_now(
&client.header(&block_id).unwrap().unwrap(), &client.header(&block_id).unwrap().unwrap(),
@@ -645,9 +641,9 @@ mod tests {
); );
let deadline = time::Duration::from_secs(9); let deadline = time::Duration::from_secs(9);
let proposal = block_on( let proposal =
proposer.propose(Default::default(), Default::default(), deadline, None), block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
).unwrap(); .unwrap();
assert_eq!(proposal.block.extrinsics().len(), 1); assert_eq!(proposal.block.extrinsics().len(), 1);
@@ -655,16 +651,13 @@ mod tests {
api.execute_block(&block_id, proposal.block).unwrap(); api.execute_block(&block_id, proposal.block).unwrap();
let state = backend.state_at(block_id).unwrap(); let state = backend.state_at(block_id).unwrap();
let changes_trie_state = backend::changes_tries_state_at_block( let changes_trie_state =
&block_id, backend::changes_tries_state_at_block(&block_id, backend.changes_trie_storage())
backend.changes_trie_storage(), .unwrap();
).unwrap();
let storage_changes = api.into_storage_changes( let storage_changes = api
&state, .into_storage_changes(&state, changes_trie_state.as_ref(), genesis_hash)
changes_trie_state.as_ref(), .unwrap();
genesis_hash,
).unwrap();
assert_eq!( assert_eq!(
proposal.storage_changes.transaction_storage_root, proposal.storage_changes.transaction_storage_root,
@@ -685,8 +678,10 @@ mod tests {
client.clone(), client.clone(),
); );
block_on( block_on(txpool.submit_at(
txpool.submit_at(&BlockId::number(0), SOURCE, vec![ &BlockId::number(0),
SOURCE,
vec![
extrinsic(0), extrinsic(0),
extrinsic(1), extrinsic(1),
Transfer { Transfer {
@@ -704,22 +699,16 @@ mod tests {
}.into_resources_exhausting_tx(), }.into_resources_exhausting_tx(),
extrinsic(5), extrinsic(5),
extrinsic(6), extrinsic(6),
]) ],
).unwrap(); ))
.unwrap();
let mut proposer_factory = ProposerFactory::new( let mut proposer_factory =
spawner.clone(), ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
client.clone(), let mut propose_block = |client: &TestClient,
txpool.clone(), number,
None, expected_block_extrinsics,
None, expected_pool_transactions| {
);
let mut propose_block = |
client: &TestClient,
number,
expected_block_extrinsics,
expected_pool_transactions,
| {
let proposer = proposer_factory.init_with_now( let proposer = proposer_factory.init_with_now(
&client.header(&BlockId::number(number)).unwrap().unwrap(), &client.header(&BlockId::number(number)).unwrap().unwrap(),
Box::new(move || time::Instant::now()), Box::new(move || time::Instant::now()),
@@ -727,9 +716,10 @@ mod tests {
// when // when
let deadline = time::Duration::from_secs(9); let deadline = time::Duration::from_secs(9);
let block = block_on( let block =
proposer.propose(Default::default(), Default::default(), deadline, None) block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
).map(|r| r.block).unwrap(); .map(|r| r.block)
.unwrap();
// then // then
// block should have some extrinsics although we have some more in the pool. // block should have some extrinsics although we have some more in the pool.
@@ -741,10 +731,11 @@ mod tests {
block_on( block_on(
txpool.maintain(chain_event( txpool.maintain(chain_event(
client.header(&BlockId::Number(0u64)) client
.header(&BlockId::Number(0u64))
.expect("header get error") .expect("header get error")
.expect("there should be header") .expect("there should be header"),
)) )),
); );
// let's create one block and import it // let's create one block and import it
@@ -753,10 +744,11 @@ mod tests {
block_on( block_on(
txpool.maintain(chain_event( txpool.maintain(chain_event(
client.header(&BlockId::Number(1)) client
.header(&BlockId::Number(1))
.expect("header get error") .expect("header get error")
.expect("there should be header") .expect("there should be header"),
)) )),
); );
// now let's make sure that we can still make some progress // now let's make sure that we can still make some progress
@@ -775,7 +767,8 @@ mod tests {
spawner.clone(), spawner.clone(),
client.clone(), client.clone(),
); );
let genesis_header = client.header(&BlockId::Number(0u64)) let genesis_header = client
.header(&BlockId::Number(0u64))
.expect("header get error") .expect("header get error")
.expect("there should be header"); .expect("there should be header");
@@ -784,40 +777,43 @@ mod tests {
.map(|v| Extrinsic::IncludeData(vec![v as u8; 10])) .map(|v| Extrinsic::IncludeData(vec![v as u8; 10]))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let block_limit = genesis_header.encoded_size() let block_limit = genesis_header.encoded_size() +
+ extrinsics.iter().take(extrinsics_num - 1).map(Encode::encoded_size).sum::<usize>() extrinsics
+ Vec::<Extrinsic>::new().encoded_size(); .iter()
.take(extrinsics_num - 1)
.map(Encode::encoded_size)
.sum::<usize>() +
Vec::<Extrinsic>::new().encoded_size();
block_on( block_on(txpool.submit_at(&BlockId::number(0), SOURCE, extrinsics)).unwrap();
txpool.submit_at(&BlockId::number(0), SOURCE, extrinsics)
).unwrap();
block_on(txpool.maintain(chain_event(genesis_header.clone()))); block_on(txpool.maintain(chain_event(genesis_header.clone())));
let mut proposer_factory = ProposerFactory::new( let mut proposer_factory =
spawner.clone(), ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
client.clone(),
txpool.clone(),
None,
None,
);
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap(); let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
// Give it enough time // Give it enough time
let deadline = time::Duration::from_secs(300); let deadline = time::Duration::from_secs(300);
let block = block_on( let block = block_on(proposer.propose(
proposer.propose(Default::default(), Default::default(), deadline, Some(block_limit)) Default::default(),
).map(|r| r.block).unwrap(); Default::default(),
deadline,
Some(block_limit),
))
.map(|r| r.block)
.unwrap();
// Based on the block limit, one transaction shouldn't be included. // Based on the block limit, one transaction shouldn't be included.
assert_eq!(block.extrinsics().len(), extrinsics_num - 1); assert_eq!(block.extrinsics().len(), extrinsics_num - 1);
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap(); let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
let block = block_on( let block =
proposer.propose(Default::default(), Default::default(), deadline, None, block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
)).map(|r| r.block).unwrap(); .map(|r| r.block)
.unwrap();
// Without a block limit we should include all of them // Without a block limit we should include all of them
assert_eq!(block.extrinsics().len(), extrinsics_num); assert_eq!(block.extrinsics().len(), extrinsics_num);
@@ -833,9 +829,14 @@ mod tests {
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap(); let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
// Give it enough time // Give it enough time
let block = block_on( let block = block_on(proposer.propose(
proposer.propose(Default::default(), Default::default(), deadline, Some(block_limit)) Default::default(),
).map(|r| r.block).unwrap(); Default::default(),
deadline,
Some(block_limit),
))
.map(|r| r.block)
.unwrap();
// The block limit didn't changed, but we now include the proof in the estimation of the // The block limit didn't changed, but we now include the proof in the estimation of the
// block size and thus, one less transaction should fit into the limit. // block size and thus, one less transaction should fit into the limit.
+7 -8
View File
@@ -41,12 +41,12 @@
//! # ); //! # );
//! // The first step is to create a `ProposerFactory`. //! // The first step is to create a `ProposerFactory`.
//! let mut proposer_factory = ProposerFactory::new( //! let mut proposer_factory = ProposerFactory::new(
//! spawner, //! spawner,
//! client.clone(), //! client.clone(),
//! txpool.clone(), //! txpool.clone(),
//! None, //! None,
//! None, //! None,
//! ); //! );
//! //!
//! // From this factory, we create a `Proposer`. //! // From this factory, we create a `Proposer`.
//! let proposer = proposer_factory.init( //! let proposer = proposer_factory.init(
@@ -69,8 +69,7 @@
//! let block = futures::executor::block_on(future).unwrap(); //! let block = futures::executor::block_on(future).unwrap();
//! println!("Generated block: {:?}", block.block); //! println!("Generated block: {:?}", block.block);
//! ``` //! ```
//!
mod basic_authorship; mod basic_authorship;
pub use crate::basic_authorship::{ProposerFactory, Proposer, DEFAULT_BLOCK_SIZE_LIMIT}; pub use crate::basic_authorship::{Proposer, ProposerFactory, DEFAULT_BLOCK_SIZE_LIMIT};
+47 -44
View File
@@ -28,14 +28,14 @@
use codec::Encode; use codec::Encode;
use sp_runtime::{ use sp_api::{
generic::BlockId, ApiExt, ApiRef, Core, ProvideRuntimeApi, StorageChanges, StorageProof, TransactionOutcome,
traits::{Header as HeaderT, Hash, Block as BlockT, HashFor, DigestFor, NumberFor, One},
}; };
use sp_blockchain::{ApplyExtrinsicFailed, Error}; use sp_blockchain::{ApplyExtrinsicFailed, Error};
use sp_core::ExecutionContext; use sp_core::ExecutionContext;
use sp_api::{ use sp_runtime::{
Core, ApiExt, ApiRef, ProvideRuntimeApi, StorageChanges, StorageProof, TransactionOutcome, generic::BlockId,
traits::{Block as BlockT, DigestFor, Hash, HashFor, Header as HeaderT, NumberFor, One},
}; };
pub use sp_block_builder::BlockBuilder as BlockBuilderApi; pub use sp_block_builder::BlockBuilder as BlockBuilderApi;
@@ -94,7 +94,9 @@ pub struct BuiltBlock<Block: BlockT, StateBackend: backend::StateBackend<HashFor
pub proof: Option<StorageProof>, pub proof: Option<StorageProof>,
} }
impl<Block: BlockT, StateBackend: backend::StateBackend<HashFor<Block>>> BuiltBlock<Block, StateBackend> { impl<Block: BlockT, StateBackend: backend::StateBackend<HashFor<Block>>>
BuiltBlock<Block, StateBackend>
{
/// Convert into the inner values. /// Convert into the inner values.
pub fn into_inner(self) -> (Block, StorageChanges<StateBackend, Block>, Option<StorageProof>) { pub fn into_inner(self) -> (Block, StorageChanges<StateBackend, Block>, Option<StorageProof>) {
(self.block, self.storage_changes, self.proof) (self.block, self.storage_changes, self.proof)
@@ -103,11 +105,11 @@ impl<Block: BlockT, StateBackend: backend::StateBackend<HashFor<Block>>> BuiltBl
/// Block builder provider /// Block builder provider
pub trait BlockBuilderProvider<B, Block, RA> pub trait BlockBuilderProvider<B, Block, RA>
where where
Block: BlockT, Block: BlockT,
B: backend::Backend<Block>, B: backend::Backend<Block>,
Self: Sized, Self: Sized,
RA: ProvideRuntimeApi<Block>, RA: ProvideRuntimeApi<Block>,
{ {
/// Create a new block, built on top of `parent`. /// Create a new block, built on top of `parent`.
/// ///
@@ -143,7 +145,8 @@ impl<'a, Block, A, B> BlockBuilder<'a, Block, A, B>
where where
Block: BlockT, Block: BlockT,
A: ProvideRuntimeApi<Block> + 'a, A: ProvideRuntimeApi<Block> + 'a,
A::Api: BlockBuilderApi<Block> + ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>, A::Api:
BlockBuilderApi<Block> + ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>,
B: backend::Backend<Block>, B: backend::Backend<Block>,
{ {
/// Create a new instance of builder based on the given `parent_hash` and `parent_number`. /// Create a new instance of builder based on the given `parent_hash` and `parent_number`.
@@ -177,9 +180,7 @@ where
let block_id = BlockId::Hash(parent_hash); let block_id = BlockId::Hash(parent_hash);
api.initialize_block_with_context( api.initialize_block_with_context(&block_id, ExecutionContext::BlockConstruction, &header)?;
&block_id, ExecutionContext::BlockConstruction, &header,
)?;
Ok(Self { Ok(Self {
parent_hash, parent_hash,
@@ -207,12 +208,10 @@ where
Ok(Ok(_)) => { Ok(Ok(_)) => {
extrinsics.push(xt); extrinsics.push(xt);
TransactionOutcome::Commit(Ok(())) TransactionOutcome::Commit(Ok(()))
}
Ok(Err(tx_validity)) => {
TransactionOutcome::Rollback(
Err(ApplyExtrinsicFailed::Validity(tx_validity).into()),
)
}, },
Ok(Err(tx_validity)) => TransactionOutcome::Rollback(Err(
ApplyExtrinsicFailed::Validity(tx_validity).into(),
)),
Err(e) => TransactionOutcome::Rollback(Err(Error::from(e))), Err(e) => TransactionOutcome::Rollback(Err(Error::from(e))),
} }
}) })
@@ -224,9 +223,9 @@ where
/// supplied by `self.api`, combined as [`BuiltBlock`]. /// supplied by `self.api`, combined as [`BuiltBlock`].
/// The storage proof will be `Some(_)` when proof recording was enabled. /// The storage proof will be `Some(_)` when proof recording was enabled.
pub fn build(mut self) -> Result<BuiltBlock<Block, backend::StateBackendFor<B, Block>>, Error> { pub fn build(mut self) -> Result<BuiltBlock<Block, backend::StateBackendFor<B, Block>>, Error> {
let header = self.api.finalize_block_with_context( let header = self
&self.block_id, ExecutionContext::BlockConstruction .api
)?; .finalize_block_with_context(&self.block_id, ExecutionContext::BlockConstruction)?;
debug_assert_eq!( debug_assert_eq!(
header.extrinsics_root().clone(), header.extrinsics_root().clone(),
@@ -244,11 +243,10 @@ where
)?; )?;
let parent_hash = self.parent_hash; let parent_hash = self.parent_hash;
let storage_changes = self.api.into_storage_changes( let storage_changes = self
&state, .api
changes_trie_state.as_ref(), .into_storage_changes(&state, changes_trie_state.as_ref(), parent_hash)
parent_hash, .map_err(|e| sp_blockchain::Error::StorageChanges(e))?;
).map_err(|e| sp_blockchain::Error::StorageChanges(e))?;
Ok(BuiltBlock { Ok(BuiltBlock {
block: <Block as BlockT>::new(header, self.extrinsics), block: <Block as BlockT>::new(header, self.extrinsics),
@@ -265,15 +263,17 @@ where
inherent_data: sp_inherents::InherentData, inherent_data: sp_inherents::InherentData,
) -> Result<Vec<Block::Extrinsic>, Error> { ) -> Result<Vec<Block::Extrinsic>, Error> {
let block_id = self.block_id; let block_id = self.block_id;
self.api.execute_in_transaction(move |api| { self.api
// `create_inherents` should not change any state, to ensure this we always rollback .execute_in_transaction(move |api| {
// the transaction. // `create_inherents` should not change any state, to ensure this we always rollback
TransactionOutcome::Rollback(api.inherent_extrinsics_with_context( // the transaction.
&block_id, TransactionOutcome::Rollback(api.inherent_extrinsics_with_context(
ExecutionContext::BlockConstruction, &block_id,
inherent_data ExecutionContext::BlockConstruction,
)) inherent_data,
}).map_err(|e| Error::Application(Box::new(e))) ))
})
.map_err(|e| Error::Application(Box::new(e)))
} }
/// Estimate the size of the block in the current state. /// Estimate the size of the block in the current state.
@@ -312,19 +312,22 @@ mod tests {
RecordProof::Yes, RecordProof::Yes,
Default::default(), Default::default(),
&*backend, &*backend,
).unwrap().build().unwrap(); )
.unwrap()
.build()
.unwrap();
let proof = block.proof.expect("Proof is build on request"); let proof = block.proof.expect("Proof is build on request");
let backend = sp_state_machine::create_proof_check_backend::<Blake2Hasher>( let backend = sp_state_machine::create_proof_check_backend::<Blake2Hasher>(
block.storage_changes.transaction_storage_root, block.storage_changes.transaction_storage_root,
proof, proof,
).unwrap(); )
.unwrap();
assert!( assert!(backend
backend.storage(&sp_core::storage::well_known_keys::CODE) .storage(&sp_core::storage::well_known_keys::CODE)
.unwrap_err() .unwrap_err()
.contains("Database missing expected key"), .contains("Database missing expected key"),);
);
} }
} }
+35 -38
View File
@@ -17,9 +17,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{DeriveInput, Ident, Error};
use proc_macro_crate::{crate_name, FoundCrate}; use proc_macro_crate::{crate_name, FoundCrate};
use quote::quote;
use syn::{DeriveInput, Error, Ident};
const CRATE_NAME: &str = "sc-chain-spec"; const CRATE_NAME: &str = "sc-chain-spec";
const ATTRIBUTE_NAME: &str = "forks"; const ATTRIBUTE_NAME: &str = "forks";
@@ -31,14 +31,18 @@ const ATTRIBUTE_NAME: &str = "forks";
pub fn extension_derive(ast: &DeriveInput) -> proc_macro::TokenStream { pub fn extension_derive(ast: &DeriveInput) -> proc_macro::TokenStream {
derive(ast, |crate_name, name, generics: &syn::Generics, field_names, field_types, fields| { derive(ast, |crate_name, name, generics: &syn::Generics, field_names, field_types, fields| {
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let forks = fields.named.iter().find_map(|f| { let forks = fields
if f.attrs.iter().any(|attr| attr.path.is_ident(ATTRIBUTE_NAME)) { .named
let typ = &f.ty; .iter()
Some(quote! { #typ }) .find_map(|f| {
} else { if f.attrs.iter().any(|attr| attr.path.is_ident(ATTRIBUTE_NAME)) {
None let typ = &f.ty;
} Some(quote! { #typ })
}).unwrap_or_else(|| quote! { #crate_name::NoExtension }); } else {
None
}
})
.unwrap_or_else(|| quote! { #crate_name::NoExtension });
quote! { quote! {
impl #impl_generics #crate_name::Extension for #name #ty_generics #where_clause { impl #impl_generics #crate_name::Extension for #name #ty_generics #where_clause {
@@ -80,13 +84,12 @@ pub fn group_derive(ast: &DeriveInput) -> proc_macro::TokenStream {
Ok(FoundCrate::Itself) => Ident::new("serde", Span::call_site()), Ok(FoundCrate::Itself) => Ident::new("serde", Span::call_site()),
Ok(FoundCrate::Name(name)) => Ident::new(&name, Span::call_site()), Ok(FoundCrate::Name(name)) => Ident::new(&name, Span::call_site()),
Err(e) => { Err(e) => {
let err = Error::new( let err =
Span::call_site(), Error::new(Span::call_site(), &format!("Could not find `serde` crate: {}", e))
&format!("Could not find `serde` crate: {}", e), .to_compile_error();
).to_compile_error();
return quote!( #err ).into(); return quote!( #err ).into()
} },
}; };
quote! { quote! {
@@ -131,14 +134,20 @@ pub fn group_derive(ast: &DeriveInput) -> proc_macro::TokenStream {
pub fn derive( pub fn derive(
ast: &DeriveInput, ast: &DeriveInput,
derive: impl Fn( derive: impl Fn(
&Ident, &Ident, &syn::Generics, Vec<&Ident>, Vec<&syn::Type>, &syn::FieldsNamed, &Ident,
&Ident,
&syn::Generics,
Vec<&Ident>,
Vec<&syn::Type>,
&syn::FieldsNamed,
) -> TokenStream, ) -> TokenStream,
) -> proc_macro::TokenStream { ) -> proc_macro::TokenStream {
let err = || { let err = || {
let err = Error::new( let err = Error::new(
Span::call_site(), Span::call_site(),
"ChainSpecGroup is only available for structs with named fields." "ChainSpecGroup is only available for structs with named fields.",
).to_compile_error(); )
.to_compile_error();
quote!( #err ).into() quote!( #err ).into()
}; };
@@ -168,47 +177,35 @@ pub fn derive(
derive(&crate_name, name, &ast.generics, field_names, field_types, fields).into() derive(&crate_name, name, &ast.generics, field_names, field_types, fields).into()
} }
fn generate_fork_fields( fn generate_fork_fields(crate_name: &Ident, names: &[&Ident], types: &[&syn::Type]) -> TokenStream {
crate_name: &Ident,
names: &[&Ident],
types: &[&syn::Type],
) -> TokenStream {
let crate_name = std::iter::repeat(crate_name); let crate_name = std::iter::repeat(crate_name);
quote! { quote! {
#( pub #names: Option<<#types as #crate_name::Group>::Fork>, )* #( pub #names: Option<<#types as #crate_name::Group>::Fork>, )*
} }
} }
fn generate_base_to_fork( fn generate_base_to_fork(fork_name: &Ident, names: &[&Ident]) -> TokenStream {
fork_name: &Ident,
names: &[&Ident],
) -> TokenStream {
let names2 = names.to_vec(); let names2 = names.to_vec();
quote!{ quote! {
#fork_name { #fork_name {
#( #names: Some(self.#names2.to_fork()), )* #( #names: Some(self.#names2.to_fork()), )*
} }
} }
} }
fn generate_combine_with( fn generate_combine_with(names: &[&Ident]) -> TokenStream {
names: &[&Ident],
) -> TokenStream {
let names2 = names.to_vec(); let names2 = names.to_vec();
quote!{ quote! {
#( self.#names.combine_with(other.#names2); )* #( self.#names.combine_with(other.#names2); )*
} }
} }
fn generate_fork_to_base( fn generate_fork_to_base(fork: &Ident, names: &[&Ident]) -> TokenStream {
fork: &Ident,
names: &[&Ident],
) -> TokenStream {
let names2 = names.to_vec(); let names2 = names.to_vec();
quote!{ quote! {
Some(#fork { Some(#fork {
#( #names: self.#names2?.to_base()?, )* #( #names: self.#names2?.to_base()?, )*
}) })
+94 -96
View File
@@ -19,15 +19,20 @@
//! Substrate chain configurations. //! Substrate chain configurations.
#![warn(missing_docs)] #![warn(missing_docs)]
use std::{borrow::Cow, fs::File, path::PathBuf, sync::Arc, collections::HashMap}; use crate::{extension::GetExtension, ChainType, Properties, RuntimeGenesis};
use serde::{Serialize, Deserialize};
use sp_core::{storage::{StorageKey, StorageData, ChildInfo, Storage, StorageChild}, Bytes};
use sp_runtime::BuildStorage;
use serde_json as json;
use crate::{RuntimeGenesis, ChainType, extension::GetExtension, Properties};
use sc_network::config::MultiaddrWithPeerId; use sc_network::config::MultiaddrWithPeerId;
use sc_telemetry::TelemetryEndpoints; use sc_telemetry::TelemetryEndpoints;
use sp_runtime::traits::{Block as BlockT, NumberFor}; use serde::{Deserialize, Serialize};
use serde_json as json;
use sp_core::{
storage::{ChildInfo, Storage, StorageChild, StorageData, StorageKey},
Bytes,
};
use sp_runtime::{
traits::{Block as BlockT, NumberFor},
BuildStorage,
};
use std::{borrow::Cow, collections::HashMap, fs::File, path::PathBuf, sync::Arc};
enum GenesisSource<G> { enum GenesisSource<G> {
File(PathBuf), File(PathBuf),
@@ -56,8 +61,8 @@ impl<G: RuntimeGenesis> GenesisSource<G> {
match self { match self {
Self::File(path) => { Self::File(path) => {
let file = File::open(path) let file =
.map_err(|e| format!("Error opening spec file: {}", e))?; File::open(path).map_err(|e| format!("Error opening spec file: {}", e))?;
let genesis: GenesisContainer<G> = json::from_reader(file) let genesis: GenesisContainer<G> = json::from_reader(file)
.map_err(|e| format!("Error parsing spec file: {}", e))?; .map_err(|e| format!("Error parsing spec file: {}", e))?;
Ok(genesis.genesis) Ok(genesis.genesis)
@@ -69,22 +74,25 @@ impl<G: RuntimeGenesis> GenesisSource<G> {
}, },
Self::Factory(f) => Ok(Genesis::Runtime(f())), Self::Factory(f) => Ok(Genesis::Runtime(f())),
Self::Storage(storage) => { Self::Storage(storage) => {
let top = storage.top let top = storage
.top
.iter() .iter()
.map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone()))) .map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone())))
.collect(); .collect();
let children_default = storage.children_default let children_default = storage
.children_default
.iter() .iter()
.map(|(k, child)| .map(|(k, child)| {
( (
StorageKey(k.clone()), StorageKey(k.clone()),
child.data child
.data
.iter() .iter()
.map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone()))) .map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone())))
.collect() .collect(),
) )
) })
.collect(); .collect();
Ok(Genesis::Raw(RawGenesis { top, children_default })) Ok(Genesis::Raw(RawGenesis { top, children_default }))
@@ -99,24 +107,24 @@ impl<G: RuntimeGenesis, E> BuildStorage for ChainSpec<G, E> {
Genesis::Runtime(gc) => gc.build_storage(), Genesis::Runtime(gc) => gc.build_storage(),
Genesis::Raw(RawGenesis { top: map, children_default: children_map }) => Ok(Storage { Genesis::Raw(RawGenesis { top: map, children_default: children_map }) => Ok(Storage {
top: map.into_iter().map(|(k, v)| (k.0, v.0)).collect(), top: map.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
children_default: children_map.into_iter().map(|(storage_key, child_content)| { children_default: children_map
let child_info = ChildInfo::new_default(storage_key.0.as_slice()); .into_iter()
( .map(|(storage_key, child_content)| {
storage_key.0, let child_info = ChildInfo::new_default(storage_key.0.as_slice());
StorageChild { (
data: child_content.into_iter().map(|(k, v)| (k.0, v.0)).collect(), storage_key.0,
child_info, StorageChild {
}, data: child_content.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
) child_info,
}).collect(), },
)
})
.collect(),
}), }),
} }
} }
fn assimilate_storage( fn assimilate_storage(&self, _: &mut Storage) -> Result<(), String> {
&self,
_: &mut Storage,
) -> Result<(), String> {
Err("`assimilate_storage` not implemented for `ChainSpec`.".into()) Err("`assimilate_storage` not implemented for `ChainSpec`.".into())
} }
} }
@@ -181,10 +189,7 @@ pub struct ChainSpec<G, E = NoExtension> {
impl<G, E: Clone> Clone for ChainSpec<G, E> { impl<G, E: Clone> Clone for ChainSpec<G, E> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
ChainSpec { ChainSpec { client_spec: self.client_spec.clone(), genesis: self.genesis.clone() }
client_spec: self.client_spec.clone(),
genesis: self.genesis.clone(),
}
} }
} }
@@ -258,10 +263,7 @@ impl<G, E> ChainSpec<G, E> {
code_substitutes: HashMap::new(), code_substitutes: HashMap::new(),
}; };
ChainSpec { ChainSpec { client_spec, genesis: GenesisSource::Factory(Arc::new(constructor)) }
client_spec,
genesis: GenesisSource::Factory(Arc::new(constructor)),
}
} }
/// Type of the chain. /// Type of the chain.
@@ -281,22 +283,15 @@ impl<G, E: serde::de::DeserializeOwned> ChainSpec<G, E> {
let json = json.into(); let json = json.into();
let client_spec = json::from_slice(json.as_ref()) let client_spec = json::from_slice(json.as_ref())
.map_err(|e| format!("Error parsing spec file: {}", e))?; .map_err(|e| format!("Error parsing spec file: {}", e))?;
Ok(ChainSpec { Ok(ChainSpec { client_spec, genesis: GenesisSource::Binary(json) })
client_spec,
genesis: GenesisSource::Binary(json),
})
} }
/// Parse json file into a `ChainSpec` /// Parse json file into a `ChainSpec`
pub fn from_json_file(path: PathBuf) -> Result<Self, String> { pub fn from_json_file(path: PathBuf) -> Result<Self, String> {
let file = File::open(&path) let file = File::open(&path).map_err(|e| format!("Error opening spec file: {}", e))?;
.map_err(|e| format!("Error opening spec file: {}", e))?; let client_spec =
let client_spec = json::from_reader(file) json::from_reader(file).map_err(|e| format!("Error parsing spec file: {}", e))?;
.map_err(|e| format!("Error parsing spec file: {}", e))?; Ok(ChainSpec { client_spec, genesis: GenesisSource::File(path) })
Ok(ChainSpec {
client_spec,
genesis: GenesisSource::File(path),
})
} }
} }
@@ -312,33 +307,34 @@ impl<G: RuntimeGenesis, E: serde::Serialize + Clone + 'static> ChainSpec<G, E> {
let genesis = match (raw, self.genesis.resolve()?) { let genesis = match (raw, self.genesis.resolve()?) {
(true, Genesis::Runtime(g)) => { (true, Genesis::Runtime(g)) => {
let storage = g.build_storage()?; let storage = g.build_storage()?;
let top = storage.top.into_iter() let top =
.map(|(k, v)| (StorageKey(k), StorageData(v))) storage.top.into_iter().map(|(k, v)| (StorageKey(k), StorageData(v))).collect();
.collect(); let children_default = storage
let children_default = storage.children_default.into_iter() .children_default
.map(|(sk, child)| ( .into_iter()
StorageKey(sk), .map(|(sk, child)| {
child.data.into_iter() (
.map(|(k, v)| (StorageKey(k), StorageData(v))) StorageKey(sk),
.collect(), child
)) .data
.into_iter()
.map(|(k, v)| (StorageKey(k), StorageData(v)))
.collect(),
)
})
.collect(); .collect();
Genesis::Raw(RawGenesis { top, children_default }) Genesis::Raw(RawGenesis { top, children_default })
}, },
(_, genesis) => genesis, (_, genesis) => genesis,
}; };
Ok(JsonContainer { Ok(JsonContainer { client_spec: self.client_spec.clone(), genesis })
client_spec: self.client_spec.clone(),
genesis,
})
} }
/// Dump to json string. /// Dump to json string.
pub fn as_json(&self, raw: bool) -> Result<String, String> { pub fn as_json(&self, raw: bool) -> Result<String, String> {
let container = self.json_container(raw)?; let container = self.json_container(raw)?;
json::to_string_pretty(&container) json::to_string_pretty(&container).map_err(|e| format!("Error generating spec json: {}", e))
.map_err(|e| format!("Error generating spec json: {}", e))
} }
} }
@@ -404,7 +400,11 @@ where
} }
fn code_substitutes(&self) -> std::collections::HashMap<String, Vec<u8>> { fn code_substitutes(&self) -> std::collections::HashMap<String, Vec<u8>> {
self.client_spec.code_substitutes.iter().map(|(h, c)| (h.clone(), c.0.clone())).collect() self.client_spec
.code_substitutes
.iter()
.map(|(h, c)| (h.clone(), c.0.clone()))
.collect()
} }
} }
@@ -417,7 +417,8 @@ pub struct LightSyncState<Block: BlockT> {
/// The babe weight of the finalized block. /// The babe weight of the finalized block.
pub babe_finalized_block_weight: sp_consensus_babe::BabeBlockWeight, pub babe_finalized_block_weight: sp_consensus_babe::BabeBlockWeight,
/// The authority set for grandpa. /// The authority set for grandpa.
pub grandpa_authority_set: sc_finality_grandpa::AuthoritySet<<Block as BlockT>::Hash, NumberFor<Block>>, pub grandpa_authority_set:
sc_finality_grandpa::AuthoritySet<<Block as BlockT>::Hash, NumberFor<Block>>,
} }
impl<Block: BlockT> LightSyncState<Block> { impl<Block: BlockT> LightSyncState<Block> {
@@ -427,25 +428,25 @@ impl<Block: BlockT> LightSyncState<Block> {
SerializableLightSyncState { SerializableLightSyncState {
finalized_block_header: StorageData(self.finalized_block_header.encode()), finalized_block_header: StorageData(self.finalized_block_header.encode()),
babe_epoch_changes: babe_epoch_changes: StorageData(self.babe_epoch_changes.encode()),
StorageData(self.babe_epoch_changes.encode()), babe_finalized_block_weight: self.babe_finalized_block_weight,
babe_finalized_block_weight: grandpa_authority_set: StorageData(self.grandpa_authority_set.encode()),
self.babe_finalized_block_weight,
grandpa_authority_set:
StorageData(self.grandpa_authority_set.encode()),
} }
} }
/// Convert from a `SerializableLightSyncState`. /// Convert from a `SerializableLightSyncState`.
pub fn from_serializable(serialized: &SerializableLightSyncState) -> Result<Self, codec::Error> { pub fn from_serializable(
serialized: &SerializableLightSyncState,
) -> Result<Self, codec::Error> {
Ok(Self { Ok(Self {
finalized_block_header: codec::Decode::decode(&mut &serialized.finalized_block_header.0[..])?, finalized_block_header: codec::Decode::decode(
babe_epoch_changes: &mut &serialized.finalized_block_header.0[..],
codec::Decode::decode(&mut &serialized.babe_epoch_changes.0[..])?, )?,
babe_finalized_block_weight: babe_epoch_changes: codec::Decode::decode(&mut &serialized.babe_epoch_changes.0[..])?,
serialized.babe_finalized_block_weight, babe_finalized_block_weight: serialized.babe_finalized_block_weight,
grandpa_authority_set: grandpa_authority_set: codec::Decode::decode(
codec::Decode::decode(&mut &serialized.grandpa_authority_set.0[..])?, &mut &serialized.grandpa_authority_set.0[..],
)?,
}) })
} }
} }
@@ -469,12 +470,9 @@ mod tests {
struct Genesis(HashMap<String, String>); struct Genesis(HashMap<String, String>);
impl BuildStorage for Genesis { impl BuildStorage for Genesis {
fn assimilate_storage( fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> {
&self,
storage: &mut Storage,
) -> Result<(), String> {
storage.top.extend( storage.top.extend(
self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes())) self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes())),
); );
Ok(()) Ok(())
} }
@@ -485,11 +483,10 @@ mod tests {
#[test] #[test]
fn should_deserialize_example_chain_spec() { fn should_deserialize_example_chain_spec() {
let spec1 = TestSpec::from_json_bytes(Cow::Owned( let spec1 = TestSpec::from_json_bytes(Cow::Owned(
include_bytes!("../res/chain_spec.json").to_vec() include_bytes!("../res/chain_spec.json").to_vec(),
)).unwrap(); ))
let spec2 = TestSpec::from_json_file( .unwrap();
PathBuf::from("./res/chain_spec.json") let spec2 = TestSpec::from_json_file(PathBuf::from("./res/chain_spec.json")).unwrap();
).unwrap();
assert_eq!(spec1.as_json(false), spec2.as_json(false)); assert_eq!(spec1.as_json(false), spec2.as_json(false));
assert_eq!(spec2.chain_type(), ChainType::Live) assert_eq!(spec2.chain_type(), ChainType::Live)
@@ -506,8 +503,9 @@ mod tests {
#[test] #[test]
fn should_deserialize_chain_spec_with_extensions() { fn should_deserialize_chain_spec_with_extensions() {
let spec = TestSpec2::from_json_bytes(Cow::Owned( let spec = TestSpec2::from_json_bytes(Cow::Owned(
include_bytes!("../res/chain_spec2.json").to_vec() include_bytes!("../res/chain_spec2.json").to_vec(),
)).unwrap(); ))
.unwrap();
assert_eq!(spec.extensions().my_property, "Test Extension"); assert_eq!(spec.extensions().my_property, "Test Extension");
} }
+70 -58
View File
@@ -18,19 +18,21 @@
//! Chain Spec extensions helpers. //! Chain Spec extensions helpers.
use std::fmt::Debug; use std::{
use std::any::{TypeId, Any}; any::{Any, TypeId},
fmt::Debug,
};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use serde::{Serialize, Deserialize, de::DeserializeOwned}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
/// A `ChainSpec` extension. /// A `ChainSpec` extension.
/// ///
/// This trait is implemented automatically by `ChainSpecGroup` macro. /// This trait is implemented automatically by `ChainSpecGroup` macro.
pub trait Group: Clone + Sized { pub trait Group: Clone + Sized {
/// An associated type containing fork definition. /// An associated type containing fork definition.
type Fork: Fork<Base=Self>; type Fork: Fork<Base = Self>;
/// Convert to fork type. /// Convert to fork type.
fn to_fork(self) -> Self::Fork; fn to_fork(self) -> Self::Fork;
@@ -45,7 +47,7 @@ pub trait Group: Clone + Sized {
/// a complete set of parameters /// a complete set of parameters
pub trait Fork: Serialize + DeserializeOwned + Clone + Sized { pub trait Fork: Serialize + DeserializeOwned + Clone + Sized {
/// A base `Group` type. /// A base `Group` type.
type Base: Group<Fork=Self>; type Base: Group<Fork = Self>;
/// Combine with another struct. /// Combine with another struct.
/// ///
@@ -128,7 +130,8 @@ pub trait Extension: Serialize + DeserializeOwned + Clone {
fn get_any(&self, t: TypeId) -> &dyn Any; fn get_any(&self, t: TypeId) -> &dyn Any;
/// Get forkable extensions of specific type. /// Get forkable extensions of specific type.
fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>> where fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>>
where
BlockNumber: Ord + Clone + 'static, BlockNumber: Ord + Clone + 'static,
T: Group + 'static, T: Group + 'static,
<Self::Forks as IsForks>::Extension: Extension, <Self::Forks as IsForks>::Extension: Extension,
@@ -142,8 +145,12 @@ pub trait Extension: Serialize + DeserializeOwned + Clone {
impl Extension for crate::NoExtension { impl Extension for crate::NoExtension {
type Forks = Self; type Forks = Self;
fn get<T: 'static>(&self) -> Option<&T> { None } fn get<T: 'static>(&self) -> Option<&T> {
fn get_any(&self, _t: TypeId) -> &dyn Any { self } None
}
fn get_any(&self, _t: TypeId) -> &dyn Any {
self
}
} }
pub trait IsForks { pub trait IsForks {
@@ -166,14 +173,12 @@ pub struct Forks<BlockNumber: Ord, T: Group> {
impl<B: Ord, T: Group + Default> Default for Forks<B, T> { impl<B: Ord, T: Group + Default> Default for Forks<B, T> {
fn default() -> Self { fn default() -> Self {
Self { Self { base: Default::default(), forks: Default::default() }
base: Default::default(),
forks: Default::default(),
}
} }
} }
impl<B: Ord, T: Group> Forks<B, T> where impl<B: Ord, T: Group> Forks<B, T>
where
T::Fork: Debug, T::Fork: Debug,
{ {
/// Create new fork definition given the base and the forks. /// Create new fork definition given the base and the forks.
@@ -195,7 +200,8 @@ impl<B: Ord, T: Group> Forks<B, T> where
} }
} }
impl<B, T> IsForks for Forks<B, T> where impl<B, T> IsForks for Forks<B, T>
where
B: Ord + 'static, B: Ord + 'static,
T: Group + 'static, T: Group + 'static,
{ {
@@ -203,29 +209,31 @@ impl<B, T> IsForks for Forks<B, T> where
type Extension = T; type Extension = T;
} }
impl<B: Ord + Clone, T: Group + Extension> Forks<B, T> where impl<B: Ord + Clone, T: Group + Extension> Forks<B, T>
where
T::Fork: Extension, T::Fork: Extension,
{ {
/// Get forks definition for a subset of this extension. /// Get forks definition for a subset of this extension.
/// ///
/// Returns the `Forks` struct, but limited to a particular type /// Returns the `Forks` struct, but limited to a particular type
/// within the extension. /// within the extension.
pub fn for_type<X>(&self) -> Option<Forks<B, X>> where pub fn for_type<X>(&self) -> Option<Forks<B, X>>
where
X: Group + 'static, X: Group + 'static,
{ {
let base = self.base.get::<X>()?.clone(); let base = self.base.get::<X>()?.clone();
let forks = self.forks.iter().filter_map(|(k, v)| { let forks = self
Some((k.clone(), v.get::<Option<X::Fork>>()?.clone()?)) .forks
}).collect(); .iter()
.filter_map(|(k, v)| Some((k.clone(), v.get::<Option<X::Fork>>()?.clone()?)))
.collect();
Some(Forks { Some(Forks { base, forks })
base,
forks,
})
} }
} }
impl<B, E> Extension for Forks<B, E> where impl<B, E> Extension for Forks<B, E>
where
B: Serialize + DeserializeOwned + Ord + Clone + 'static, B: Serialize + DeserializeOwned + Ord + Clone + 'static,
E: Extension + Group + 'static, E: Extension + Group + 'static,
{ {
@@ -245,7 +253,8 @@ impl<B, E> Extension for Forks<B, E> where
} }
} }
fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>> where fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>>
where
BlockNumber: Ord + Clone + 'static, BlockNumber: Ord + Clone + 'static,
T: Group + 'static, T: Group + 'static,
<Self::Forks as IsForks>::Extension: Extension, <Self::Forks as IsForks>::Extension: Extension,
@@ -266,7 +275,7 @@ pub trait GetExtension {
fn get_any(&self, t: TypeId) -> &dyn Any; fn get_any(&self, t: TypeId) -> &dyn Any;
} }
impl <E: Extension> GetExtension for E { impl<E: Extension> GetExtension for E {
fn get_any(&self, t: TypeId) -> &dyn Any { fn get_any(&self, t: TypeId) -> &dyn Any {
Extension::get_any(self, t) Extension::get_any(self, t)
} }
@@ -281,7 +290,7 @@ pub fn get_extension<T: 'static>(e: &dyn GetExtension) -> Option<&T> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use sc_chain_spec_derive::{ChainSpecGroup, ChainSpecExtension}; use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
// Make the proc macro work for tests and doc tests. // Make the proc macro work for tests and doc tests.
use crate as sc_chain_spec; use crate as sc_chain_spec;
@@ -297,7 +306,9 @@ mod tests {
pub test: u8, pub test: u8,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] #[derive(
Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension,
)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Extensions { pub struct Extensions {
pub ext1: Extension1, pub ext1: Extension1,
@@ -315,11 +326,12 @@ mod tests {
#[test] #[test]
fn forks_should_work_correctly() { fn forks_should_work_correctly() {
use super::Extension as _ ; use super::Extension as _;
// We first need to deserialize into a `Value` because of the following bug: // We first need to deserialize into a `Value` because of the following bug:
// https://github.com/serde-rs/json/issues/505 // https://github.com/serde-rs/json/issues/505
let ext_val: serde_json::Value = serde_json::from_str(r#" let ext_val: serde_json::Value = serde_json::from_str(
r#"
{ {
"test": 11, "test": 11,
"forkable": { "forkable": {
@@ -342,40 +354,40 @@ mod tests {
} }
} }
} }
"#).unwrap(); "#,
)
.unwrap();
let ext: Ext2 = serde_json::from_value(ext_val).unwrap(); let ext: Ext2 = serde_json::from_value(ext_val).unwrap();
assert_eq!(ext.get::<Extension1>(), Some(&Extension1 { assert_eq!(ext.get::<Extension1>(), Some(&Extension1 { test: 11 }));
test: 11
}));
// get forks definition // get forks definition
let forks = ext.get::<Forks<u64, Extensions>>().unwrap(); let forks = ext.get::<Forks<u64, Extensions>>().unwrap();
assert_eq!(forks.at_block(0), Extensions { assert_eq!(
ext1: Extension1 { test: 15 }, forks.at_block(0),
ext2: Extension2 { test: 123 }, Extensions { ext1: Extension1 { test: 15 }, ext2: Extension2 { test: 123 } }
}); );
assert_eq!(forks.at_block(1), Extensions { assert_eq!(
ext1: Extension1 { test: 5 }, forks.at_block(1),
ext2: Extension2 { test: 123 }, Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 123 } }
}); );
assert_eq!(forks.at_block(2), Extensions { assert_eq!(
ext1: Extension1 { test: 5 }, forks.at_block(2),
ext2: Extension2 { test: 5 }, Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 5 } }
}); );
assert_eq!(forks.at_block(4), Extensions { assert_eq!(
ext1: Extension1 { test: 5 }, forks.at_block(4),
ext2: Extension2 { test: 5 }, Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 5 } }
}); );
assert_eq!(forks.at_block(5), Extensions { assert_eq!(
ext1: Extension1 { test: 5 }, forks.at_block(5),
ext2: Extension2 { test: 1 }, Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 1 } }
}); );
assert_eq!(forks.at_block(10), Extensions { assert_eq!(
ext1: Extension1 { test: 5 }, forks.at_block(10),
ext2: Extension2 { test: 1 }, Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 1 } }
}); );
assert!(forks.at_block(10).get::<Extension2>().is_some()); assert!(forks.at_block(10).get::<Extension2>().is_some());
// filter forks for `Extension2` // filter forks for `Extension2`
+16 -16
View File
@@ -35,7 +35,7 @@
//! //!
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecExtension)] //! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecExtension)]
//! pub struct MyExtension { //! pub struct MyExtension {
//! pub known_blocks: HashMap<u64, String>, //! pub known_blocks: HashMap<u64, String>,
//! } //! }
//! //!
//! pub type MyChainSpec<G> = GenericChainSpec<G, MyExtension>; //! pub type MyChainSpec<G> = GenericChainSpec<G, MyExtension>;
@@ -53,19 +53,19 @@
//! //!
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)] //! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)]
//! pub struct ClientParams { //! pub struct ClientParams {
//! max_block_size: usize, //! max_block_size: usize,
//! max_extrinsic_size: usize, //! max_extrinsic_size: usize,
//! } //! }
//! //!
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)] //! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)]
//! pub struct PoolParams { //! pub struct PoolParams {
//! max_transaction_size: usize, //! max_transaction_size: usize,
//! } //! }
//! //!
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup, ChainSpecExtension)] //! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup, ChainSpecExtension)]
//! pub struct Extension { //! pub struct Extension {
//! pub client: ClientParams, //! pub client: ClientParams,
//! pub pool: PoolParams, //! pub pool: PoolParams,
//! } //! }
//! //!
//! pub type BlockNumber = u64; //! pub type BlockNumber = u64;
@@ -88,20 +88,20 @@
//! //!
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)] //! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
//! pub struct ClientParams { //! pub struct ClientParams {
//! max_block_size: usize, //! max_block_size: usize,
//! max_extrinsic_size: usize, //! max_extrinsic_size: usize,
//! } //! }
//! //!
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)] //! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
//! pub struct PoolParams { //! pub struct PoolParams {
//! max_transaction_size: usize, //! max_transaction_size: usize,
//! } //! }
//! //!
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecExtension)] //! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecExtension)]
//! pub struct Extension { //! pub struct Extension {
//! pub client: ClientParams, //! pub client: ClientParams,
//! #[forks] //! #[forks]
//! pub pool: Forks<u64, PoolParams>, //! pub pool: Forks<u64, PoolParams>,
//! } //! }
//! //!
//! pub type MyChainSpec<G> = GenericChainSpec<G, Extension>; //! pub type MyChainSpec<G> = GenericChainSpec<G, Extension>;
@@ -111,16 +111,16 @@ mod chain_spec;
mod extension; mod extension;
pub use chain_spec::{ pub use chain_spec::{
ChainSpec as GenericChainSpec, NoExtension, LightSyncState, SerializableLightSyncState, ChainSpec as GenericChainSpec, LightSyncState, NoExtension, SerializableLightSyncState,
}; };
pub use extension::{Group, Fork, Forks, Extension, GetExtension, get_extension}; pub use extension::{get_extension, Extension, Fork, Forks, GetExtension, Group};
pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup}; pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
use serde::{Serialize, de::DeserializeOwned};
use sp_runtime::BuildStorage;
use sc_network::config::MultiaddrWithPeerId; use sc_network::config::MultiaddrWithPeerId;
use sc_telemetry::TelemetryEndpoints; use sc_telemetry::TelemetryEndpoints;
use serde::{de::DeserializeOwned, Serialize};
use sp_core::storage::Storage; use sp_core::storage::Storage;
use sp_runtime::BuildStorage;
/// The type of a chain. /// The type of a chain.
/// ///
+6 -11
View File
@@ -74,9 +74,8 @@ impl WasmExecutionMethod {
impl Into<sc_service::config::WasmExecutionMethod> for WasmExecutionMethod { impl Into<sc_service::config::WasmExecutionMethod> for WasmExecutionMethod {
fn into(self) -> sc_service::config::WasmExecutionMethod { fn into(self) -> sc_service::config::WasmExecutionMethod {
match self { match self {
WasmExecutionMethod::Interpreted => { WasmExecutionMethod::Interpreted =>
sc_service::config::WasmExecutionMethod::Interpreted sc_service::config::WasmExecutionMethod::Interpreted,
}
#[cfg(feature = "wasmtime")] #[cfg(feature = "wasmtime")]
WasmExecutionMethod::Compiled => sc_service::config::WasmExecutionMethod::Compiled, WasmExecutionMethod::Compiled => sc_service::config::WasmExecutionMethod::Compiled,
#[cfg(not(feature = "wasmtime"))] #[cfg(not(feature = "wasmtime"))]
@@ -250,14 +249,10 @@ impl Into<sc_network::config::SyncMode> for SyncMode {
fn into(self) -> sc_network::config::SyncMode { fn into(self) -> sc_network::config::SyncMode {
match self { match self {
SyncMode::Full => sc_network::config::SyncMode::Full, SyncMode::Full => sc_network::config::SyncMode::Full,
SyncMode::Fast => sc_network::config::SyncMode::Fast { SyncMode::Fast =>
skip_proofs: false, sc_network::config::SyncMode::Fast { skip_proofs: false, storage_chain_mode: false },
storage_chain_mode: false, SyncMode::FastUnsafe =>
}, sc_network::config::SyncMode::Fast { skip_proofs: true, storage_chain_mode: false },
SyncMode::FastUnsafe => sc_network::config::SyncMode::Fast {
skip_proofs: true,
storage_chain_mode: false,
},
} }
} }
} }
@@ -16,15 +16,19 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error; use crate::{
use crate::params::NodeKeyParams; error,
use crate::params::SharedParams; params::{NodeKeyParams, SharedParams},
use crate::CliConfiguration; CliConfiguration,
};
use log::info; use log::info;
use sc_network::config::build_multiaddr; use sc_network::config::build_multiaddr;
use sc_service::{config::{MultiaddrWithPeerId, NetworkConfiguration}, ChainSpec}; use sc_service::{
use structopt::StructOpt; config::{MultiaddrWithPeerId, NetworkConfiguration},
ChainSpec,
};
use std::io::Write; use std::io::Write;
use structopt::StructOpt;
/// The `build-spec` command used to build a specification. /// The `build-spec` command used to build a specification.
#[derive(Debug, StructOpt, Clone)] #[derive(Debug, StructOpt, Clone)]
@@ -17,7 +17,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::{ use crate::{
CliConfiguration, error, params::{ImportParams, SharedParams, BlockNumberOrHash}, error,
params::{BlockNumberOrHash, ImportParams, SharedParams},
CliConfiguration,
}; };
use sc_client_api::{BlockBackend, UsageProvider}; use sc_client_api::{BlockBackend, UsageProvider};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
@@ -48,11 +50,7 @@ pub struct CheckBlockCmd {
impl CheckBlockCmd { impl CheckBlockCmd {
/// Run the check-block command /// Run the check-block command
pub async fn run<B, C, IQ>( pub async fn run<B, C, IQ>(&self, client: Arc<C>, import_queue: IQ) -> error::Result<()>
&self,
client: Arc<C>,
import_queue: IQ,
) -> error::Result<()>
where where
B: BlockT + for<'de> serde::Deserialize<'de>, B: BlockT + for<'de> serde::Deserialize<'de>,
C: BlockBackend<B> + UsageProvider<B> + Send + Sync + 'static, C: BlockBackend<B> + UsageProvider<B> + Send + Sync + 'static,
@@ -16,21 +16,16 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error; use crate::{
use crate::params::{GenericNumber, DatabaseParams, PruningParams, SharedParams}; error,
use crate::CliConfiguration; params::{DatabaseParams, GenericNumber, PruningParams, SharedParams},
use log::info; CliConfiguration,
use sc_service::{
config::DatabaseConfig, chain_ops::export_blocks,
}; };
use log::info;
use sc_client_api::{BlockBackend, UsageProvider}; use sc_client_api::{BlockBackend, UsageProvider};
use sc_service::{chain_ops::export_blocks, config::DatabaseConfig};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use std::fmt::Debug; use std::{fmt::Debug, fs, io, path::PathBuf, str::FromStr, sync::Arc};
use std::fs;
use std::io;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use structopt::StructOpt; use structopt::StructOpt;
/// The `export-blocks` command used to export blocks. /// The `export-blocks` command used to export blocks.
@@ -95,9 +90,7 @@ impl ExportBlocksCmd {
None => Box::new(io::stdout()), None => Box::new(io::stdout()),
}; };
export_blocks(client, file, from.into(), to, binary) export_blocks(client, file, from.into(), to, binary).await.map_err(Into::into)
.await
.map_err(Into::into)
} }
} }
@@ -17,13 +17,15 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::{ use crate::{
CliConfiguration, error, params::{PruningParams, SharedParams, BlockNumberOrHash}, error,
params::{BlockNumberOrHash, PruningParams, SharedParams},
CliConfiguration,
}; };
use log::info; use log::info;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use std::{fmt::Debug, str::FromStr, io::Write, sync::Arc};
use structopt::StructOpt;
use sc_client_api::{StorageProvider, UsageProvider}; use sc_client_api::{StorageProvider, UsageProvider};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use std::{fmt::Debug, io::Write, str::FromStr, sync::Arc};
use structopt::StructOpt;
/// The `export-state` command used to export the state of a given block into /// The `export-state` command used to export the state of a given block into
/// a chain spec. /// a chain spec.
+9 -10
View File
@@ -16,12 +16,12 @@
// limitations under the License. // limitations under the License.
//! Implementation of the `generate` subcommand //! Implementation of the `generate` subcommand
use bip39::{MnemonicType, Mnemonic, Language};
use structopt::StructOpt;
use crate::{ use crate::{
utils::print_from_uri, KeystoreParams, Error, utils::print_from_uri, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams,
with_crypto_scheme, NetworkSchemeFlag, OutputTypeFlag, CryptoSchemeFlag, NetworkSchemeFlag, OutputTypeFlag,
}; };
use bip39::{Language, Mnemonic, MnemonicType};
use structopt::StructOpt;
/// The `generate` command /// The `generate` command
#[derive(Debug, StructOpt, Clone)] #[derive(Debug, StructOpt, Clone)]
@@ -52,12 +52,11 @@ impl GenerateCmd {
/// Run the command /// Run the command
pub fn run(&self) -> Result<(), Error> { pub fn run(&self) -> Result<(), Error> {
let words = match self.words { let words = match self.words {
Some(words) => { Some(words) => MnemonicType::for_word_count(words).map_err(|_| {
MnemonicType::for_word_count(words) Error::Input(
.map_err(|_| { "Invalid number of words given for phrase: must be 12/15/18/21/24".into(),
Error::Input("Invalid number of words given for phrase: must be 12/15/18/21/24".into()) )
})? })?,
},
None => MnemonicType::Words12, None => MnemonicType::Words12,
}; };
let mnemonic = Mnemonic::new(words, Language::English); let mnemonic = Mnemonic::new(words, Language::English);
@@ -18,9 +18,9 @@
//! Implementation of the `generate-node-key` subcommand //! Implementation of the `generate-node-key` subcommand
use crate::Error; use crate::Error;
use structopt::StructOpt;
use std::{path::PathBuf, fs};
use libp2p::identity::{ed25519 as libp2p_ed25519, PublicKey}; use libp2p::identity::{ed25519 as libp2p_ed25519, PublicKey};
use std::{fs, path::PathBuf};
use structopt::StructOpt;
/// The `generate-node-key` command /// The `generate-node-key` command
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
@@ -59,15 +59,14 @@ impl GenerateNodeKeyCmd {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use tempfile::Builder;
use std::io::Read; use std::io::Read;
use tempfile::Builder;
#[test] #[test]
fn generate_node_key() { fn generate_node_key() {
let mut file = Builder::new().prefix("keyfile").tempfile().unwrap(); let mut file = Builder::new().prefix("keyfile").tempfile().unwrap();
let file_path = file.path().display().to_string(); let file_path = file.path().display().to_string();
let generate = let generate = GenerateNodeKeyCmd::from_iter(&["generate-node-key", "--file", &file_path]);
GenerateNodeKeyCmd::from_iter(&["generate-node-key", "--file", &file_path]);
assert!(generate.run().is_ok()); assert!(generate.run().is_ok());
let mut buf = String::new(); let mut buf = String::new();
assert!(file.read_to_string(&mut buf).is_ok()); assert!(file.read_to_string(&mut buf).is_ok());
@@ -16,19 +16,22 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error; use crate::{
use crate::params::ImportParams; error,
use crate::params::SharedParams; params::{ImportParams, SharedParams},
use crate::CliConfiguration; CliConfiguration,
};
use sc_client_api::UsageProvider;
use sc_service::chain_ops::import_blocks; use sc_service::chain_ops::import_blocks;
use sp_runtime::traits::Block as BlockT; use sp_runtime::traits::Block as BlockT;
use std::fmt::Debug; use std::{
use std::fs; fmt::Debug,
use std::io::{self, Read, Seek}; fs,
use std::path::PathBuf; io::{self, Read, Seek},
use std::sync::Arc; path::PathBuf,
sync::Arc,
};
use structopt::StructOpt; use structopt::StructOpt;
use sc_client_api::UsageProvider;
/// The `import-blocks` command used to import blocks. /// The `import-blocks` command used to import blocks.
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
@@ -63,11 +66,7 @@ impl<T: Read + Seek> ReadPlusSeek for T {}
impl ImportBlocksCmd { impl ImportBlocksCmd {
/// Run the import-blocks command /// Run the import-blocks command
pub async fn run<B, C, IQ>( pub async fn run<B, C, IQ>(&self, client: Arc<C>, import_queue: IQ) -> error::Result<()>
&self,
client: Arc<C>,
import_queue: IQ,
) -> error::Result<()>
where where
C: UsageProvider<B> + Send + Sync + 'static, C: UsageProvider<B> + Send + Sync + 'static,
B: BlockT + for<'de> serde::Deserialize<'de>, B: BlockT + for<'de> serde::Deserialize<'de>,
@@ -79,7 +78,7 @@ impl ImportBlocksCmd {
let mut buffer = Vec::new(); let mut buffer = Vec::new();
io::stdin().read_to_end(&mut buffer)?; io::stdin().read_to_end(&mut buffer)?;
Box::new(io::Cursor::new(buffer)) Box::new(io::Cursor::new(buffer))
} },
}; };
import_blocks(client, import_queue, file, false, self.binary) import_blocks(client, import_queue, file, false, self.binary)
+37 -38
View File
@@ -18,22 +18,18 @@
//! Implementation of the `insert` subcommand //! Implementation of the `insert` subcommand
use crate::{ use crate::{
Error, KeystoreParams, CryptoSchemeFlag, SharedParams, utils, with_crypto_scheme, utils, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, SharedParams, SubstrateCli,
SubstrateCli,
}; };
use std::{sync::Arc, convert::TryFrom};
use structopt::StructOpt;
use sp_core::{crypto::KeyTypeId, crypto::SecretString};
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
use sc_keystore::LocalKeystore; use sc_keystore::LocalKeystore;
use sc_service::config::{KeystoreConfig, BasePath}; use sc_service::config::{BasePath, KeystoreConfig};
use sp_core::crypto::{KeyTypeId, SecretString};
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
use std::{convert::TryFrom, sync::Arc};
use structopt::StructOpt;
/// The `insert` command /// The `insert` command
#[derive(Debug, StructOpt, Clone)] #[derive(Debug, StructOpt, Clone)]
#[structopt( #[structopt(name = "insert", about = "Insert a key to the keystore of a node.")]
name = "insert",
about = "Insert a key to the keystore of a node."
)]
pub struct InsertKeyCmd { pub struct InsertKeyCmd {
/// The secret key URI. /// The secret key URI.
/// If the value is a file, the file content is used as URI. /// If the value is a file, the file content is used as URI.
@@ -62,7 +58,8 @@ impl InsertKeyCmd {
/// Run the command /// Run the command
pub fn run<C: SubstrateCli>(&self, cli: &C) -> Result<(), Error> { pub fn run<C: SubstrateCli>(&self, cli: &C) -> Result<(), Error> {
let suri = utils::read_uri(self.suri.as_ref())?; let suri = utils::read_uri(self.suri.as_ref())?;
let base_path = self.shared_params let base_path = self
.shared_params
.base_path() .base_path()
.unwrap_or_else(|| BasePath::from_project("", "", &C::executable_name())); .unwrap_or_else(|| BasePath::from_project("", "", &C::executable_name()));
let chain_id = self.shared_params.chain_id(self.shared_params.is_dev()); let chain_id = self.shared_params.chain_id(self.shared_params.is_dev());
@@ -78,10 +75,11 @@ impl InsertKeyCmd {
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(path, password)?); let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(path, password)?);
(keystore, public) (keystore, public)
}, },
_ => unreachable!("keystore_config always returns path and password; qed") _ => unreachable!("keystore_config always returns path and password; qed"),
}; };
let key_type = KeyTypeId::try_from(self.key_type.as_str()).map_err(|_| Error::KeyTypeInvalid)?; let key_type =
KeyTypeId::try_from(self.key_type.as_str()).map_err(|_| Error::KeyTypeInvalid)?;
SyncCryptoStore::insert_unknown(&*keystore, key_type, &suri, &public[..]) SyncCryptoStore::insert_unknown(&*keystore, key_type, &suri, &public[..])
.map_err(|_| Error::KeyStoreOperation)?; .map_err(|_| Error::KeyStoreOperation)?;
@@ -98,10 +96,10 @@ fn to_vec<P: sp_core::Pair>(uri: &str, pass: Option<SecretString>) -> Result<Vec
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use sc_service::{ChainSpec, ChainType, GenericChainSpec, NoExtension};
use sp_core::{sr25519::Pair, Pair as _, Public};
use structopt::StructOpt; use structopt::StructOpt;
use tempfile::TempDir; use tempfile::TempDir;
use sp_core::{sr25519::Pair, Pair as _, Public};
use sc_service::{ChainSpec, GenericChainSpec, ChainType, NoExtension};
struct Cli; struct Cli;
@@ -135,21 +133,17 @@ mod tests {
} }
fn load_spec(&self, _: &str) -> std::result::Result<Box<dyn ChainSpec>, String> { fn load_spec(&self, _: &str) -> std::result::Result<Box<dyn ChainSpec>, String> {
Ok( Ok(Box::new(GenericChainSpec::from_genesis(
Box::new( "test",
GenericChainSpec::from_genesis( "test_id",
"test", ChainType::Development,
"test_id", || unimplemented!("Not required in tests"),
ChainType::Development, Vec::new(),
|| unimplemented!("Not required in tests"), None,
Vec::new(), None,
None, None,
None, NoExtension::None,
None, )))
NoExtension::None,
),
),
)
} }
} }
@@ -159,15 +153,20 @@ mod tests {
let path_str = format!("{}", path.path().display()); let path_str = format!("{}", path.path().display());
let (key, uri, _) = Pair::generate_with_phrase(None); let (key, uri, _) = Pair::generate_with_phrase(None);
let inspect = InsertKeyCmd::from_iter( let inspect = InsertKeyCmd::from_iter(&[
&["insert-key", "-d", &path_str, "--key-type", "test", "--suri", &uri], "insert-key",
); "-d",
&path_str,
"--key-type",
"test",
"--suri",
&uri,
]);
assert!(inspect.run(&Cli).is_ok()); assert!(inspect.run(&Cli).is_ok());
let keystore = LocalKeystore::open( let keystore =
path.path().join("chains").join("test_id").join("keystore"), LocalKeystore::open(path.path().join("chains").join("test_id").join("keystore"), None)
None, .unwrap();
).unwrap();
assert!(keystore.has_keys(&[(key.public().to_raw_vec(), KeyTypeId(*b"test"))])); assert!(keystore.has_keys(&[(key.public().to_raw_vec(), KeyTypeId(*b"test"))]));
} }
} }
@@ -18,8 +18,8 @@
//! Implementation of the `inspect` subcommand //! Implementation of the `inspect` subcommand
use crate::{ use crate::{
utils::{self, print_from_uri, print_from_public}, KeystoreParams, utils::{self, print_from_public, print_from_uri},
with_crypto_scheme, NetworkSchemeFlag, OutputTypeFlag, CryptoSchemeFlag, Error, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, NetworkSchemeFlag, OutputTypeFlag,
}; };
use structopt::StructOpt; use structopt::StructOpt;
/// The `inspect` command /// The `inspect` command
@@ -103,8 +103,7 @@ mod tests {
"remember fiber forum demise paper uniform squirrel feel access exclude casual effort"; "remember fiber forum demise paper uniform squirrel feel access exclude casual effort";
let seed = "0xad1fb77243b536b90cfe5f0d351ab1b1ac40e3890b41dc64f766ee56340cfca5"; let seed = "0xad1fb77243b536b90cfe5f0d351ab1b1ac40e3890b41dc64f766ee56340cfca5";
let inspect = let inspect = InspectKeyCmd::from_iter(&["inspect-key", words, "--password", "12345"]);
InspectKeyCmd::from_iter(&["inspect-key", words, "--password", "12345"]);
assert!(inspect.run().is_ok()); assert!(inspect.run().is_ok());
let inspect = InspectKeyCmd::from_iter(&["inspect-key", seed]); let inspect = InspectKeyCmd::from_iter(&["inspect-key", seed]);
@@ -18,9 +18,8 @@
//! Implementation of the `inspect-node-key` subcommand //! Implementation of the `inspect-node-key` subcommand
use crate::{Error, NetworkSchemeFlag}; use crate::{Error, NetworkSchemeFlag};
use std::fs; use libp2p::identity::{ed25519, PublicKey};
use libp2p::identity::{PublicKey, ed25519}; use std::{fs, path::PathBuf};
use std::path::PathBuf;
use structopt::StructOpt; use structopt::StructOpt;
/// The `inspect-node-key` command /// The `inspect-node-key` command
@@ -42,10 +41,10 @@ pub struct InspectNodeKeyCmd {
impl InspectNodeKeyCmd { impl InspectNodeKeyCmd {
/// runs the command /// runs the command
pub fn run(&self) -> Result<(), Error> { pub fn run(&self) -> Result<(), Error> {
let mut file_content = hex::decode(fs::read(&self.file)?) let mut file_content =
.map_err(|_| "failed to decode secret as hex")?; hex::decode(fs::read(&self.file)?).map_err(|_| "failed to decode secret as hex")?;
let secret = ed25519::SecretKey::from_bytes(&mut file_content) let secret =
.map_err(|_| "Bad node key file")?; ed25519::SecretKey::from_bytes(&mut file_content).map_err(|_| "Bad node key file")?;
let keypair = ed25519::Keypair::from(secret); let keypair = ed25519::Keypair::from(secret);
let peer_id = PublicKey::Ed25519(keypair.public()).into_peer_id(); let peer_id = PublicKey::Ed25519(keypair.public()).into_peer_id();
@@ -58,8 +57,7 @@ impl InspectNodeKeyCmd {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::{super::GenerateNodeKeyCmd, *};
use super::super::GenerateNodeKeyCmd;
#[test] #[test]
fn inspect_node_key() { fn inspect_node_key() {
+2 -5
View File
@@ -21,11 +21,8 @@ use crate::{Error, SubstrateCli};
use structopt::StructOpt; use structopt::StructOpt;
use super::{ use super::{
insert_key::InsertKeyCmd, generate::GenerateCmd, generate_node_key::GenerateNodeKeyCmd, insert_key::InsertKeyCmd,
inspect_key::InspectKeyCmd, inspect_key::InspectKeyCmd, inspect_node_key::InspectNodeKeyCmd,
generate::GenerateCmd,
inspect_node_key::InspectNodeKeyCmd,
generate_node_key::GenerateNodeKeyCmd,
}; };
/// Key utilities for the cli. /// Key utilities for the cli.

Some files were not shown because too many files have changed in this diff Show More