mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 17:31:05 +00:00
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:
@@ -233,6 +233,14 @@ cargo-deny:
|
||||
# FIXME: Temorarily allow to fail.
|
||||
allow_failure: true
|
||||
|
||||
cargo-fmt:
|
||||
stage: test
|
||||
<<: *docker-env
|
||||
<<: *test-refs
|
||||
script:
|
||||
- cargo +nightly fmt --all -- --check
|
||||
allow_failure: true
|
||||
|
||||
cargo-check-benches:
|
||||
stage: test
|
||||
<<: *docker-env
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
// {{arg}}
|
||||
{{/each}}
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use sp_core::{Pair, Public, sr25519};
|
||||
use node_template_runtime::{
|
||||
AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig,
|
||||
SudoConfig, SystemConfig, WASM_BINARY, Signature
|
||||
AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,
|
||||
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 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.
|
||||
// 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;
|
||||
|
||||
/// Generate an account ID from seed.
|
||||
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId where
|
||||
AccountPublic: From<<TPublic::Pair as Pair>::Public>
|
||||
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
|
||||
where
|
||||
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
|
||||
{
|
||||
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
|
||||
}
|
||||
|
||||
/// Generate an Aura authority key.
|
||||
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> {
|
||||
@@ -47,23 +45,23 @@ pub fn development_config() -> Result<ChainSpec, String> {
|
||||
// ID
|
||||
"dev",
|
||||
ChainType::Development,
|
||||
move || testnet_genesis(
|
||||
wasm_binary,
|
||||
// Initial PoA authorities
|
||||
vec![
|
||||
authority_keys_from_seed("Alice"),
|
||||
],
|
||||
// Sudo account
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
// Pre-funded accounts
|
||||
vec![
|
||||
move || {
|
||||
testnet_genesis(
|
||||
wasm_binary,
|
||||
// Initial PoA authorities
|
||||
vec![authority_keys_from_seed("Alice")],
|
||||
// Sudo account
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||
],
|
||||
true,
|
||||
),
|
||||
// Pre-funded accounts
|
||||
vec![
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||
],
|
||||
true,
|
||||
)
|
||||
},
|
||||
// Bootnodes
|
||||
vec![],
|
||||
// Telemetry
|
||||
@@ -86,32 +84,31 @@ pub fn local_testnet_config() -> Result<ChainSpec, String> {
|
||||
// ID
|
||||
"local_testnet",
|
||||
ChainType::Local,
|
||||
move || testnet_genesis(
|
||||
wasm_binary,
|
||||
// Initial PoA authorities
|
||||
vec![
|
||||
authority_keys_from_seed("Alice"),
|
||||
authority_keys_from_seed("Bob"),
|
||||
],
|
||||
// Sudo account
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
// Pre-funded accounts
|
||||
vec![
|
||||
move || {
|
||||
testnet_genesis(
|
||||
wasm_binary,
|
||||
// Initial PoA authorities
|
||||
vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")],
|
||||
// Sudo account
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Charlie"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Dave"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Eve"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
|
||||
],
|
||||
true,
|
||||
),
|
||||
// Pre-funded accounts
|
||||
vec![
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Charlie"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Dave"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Eve"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
|
||||
],
|
||||
true,
|
||||
)
|
||||
},
|
||||
// Bootnodes
|
||||
vec![],
|
||||
// Telemetry
|
||||
@@ -141,7 +138,7 @@ fn testnet_genesis(
|
||||
},
|
||||
balances: BalancesConfig {
|
||||
// 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 {
|
||||
authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use structopt::StructOpt;
|
||||
use sc_cli::RunCmd;
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
pub struct Cli {
|
||||
|
||||
@@ -15,11 +15,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{chain_spec, service};
|
||||
use crate::cli::{Cli, Subcommand};
|
||||
use sc_cli::{SubstrateCli, RuntimeVersion, Role, ChainSpec};
|
||||
use sc_service::PartialComponents;
|
||||
use crate::{
|
||||
chain_spec,
|
||||
cli::{Cli, Subcommand},
|
||||
service,
|
||||
};
|
||||
use node_template_runtime::Block;
|
||||
use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli};
|
||||
use sc_service::PartialComponents;
|
||||
|
||||
impl SubstrateCli for Cli {
|
||||
fn impl_name() -> String {
|
||||
@@ -50,9 +53,8 @@ impl SubstrateCli for Cli {
|
||||
Ok(match id {
|
||||
"dev" => Box::new(chain_spec::development_config()?),
|
||||
"" | "local" => Box::new(chain_spec::local_testnet_config()?),
|
||||
path => Box::new(chain_spec::ChainSpec::from_json_file(
|
||||
std::path::PathBuf::from(path),
|
||||
)?),
|
||||
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)) => {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
runner.async_run(|config| {
|
||||
let PartialComponents { client, task_manager, import_queue, ..}
|
||||
= service::new_partial(&config)?;
|
||||
let PartialComponents { client, task_manager, import_queue, .. } =
|
||||
service::new_partial(&config)?;
|
||||
Ok((cmd.run(client, import_queue), task_manager))
|
||||
})
|
||||
},
|
||||
Some(Subcommand::ExportBlocks(cmd)) => {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
runner.async_run(|config| {
|
||||
let PartialComponents { client, task_manager, ..}
|
||||
= service::new_partial(&config)?;
|
||||
let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?;
|
||||
Ok((cmd.run(client, config.database), task_manager))
|
||||
})
|
||||
},
|
||||
Some(Subcommand::ExportState(cmd)) => {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
runner.async_run(|config| {
|
||||
let PartialComponents { client, task_manager, ..}
|
||||
= service::new_partial(&config)?;
|
||||
let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?;
|
||||
Ok((cmd.run(client, config.chain_spec), task_manager))
|
||||
})
|
||||
},
|
||||
Some(Subcommand::ImportBlocks(cmd)) => {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
runner.async_run(|config| {
|
||||
let PartialComponents { client, task_manager, import_queue, ..}
|
||||
= service::new_partial(&config)?;
|
||||
let PartialComponents { client, task_manager, import_queue, .. } =
|
||||
service::new_partial(&config)?;
|
||||
Ok((cmd.run(client, import_queue), task_manager))
|
||||
})
|
||||
},
|
||||
@@ -110,29 +110,30 @@ pub fn run() -> sc_cli::Result<()> {
|
||||
Some(Subcommand::Revert(cmd)) => {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
runner.async_run(|config| {
|
||||
let PartialComponents { client, task_manager, backend, ..}
|
||||
= service::new_partial(&config)?;
|
||||
let PartialComponents { client, task_manager, backend, .. } =
|
||||
service::new_partial(&config)?;
|
||||
Ok((cmd.run(client, backend), task_manager))
|
||||
})
|
||||
},
|
||||
Some(Subcommand::Benchmark(cmd)) => {
|
||||
Some(Subcommand::Benchmark(cmd)) =>
|
||||
if cfg!(feature = "runtime-benchmarks") {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
|
||||
runner.sync_run(|config| cmd.run::<Block, service::Executor>(config))
|
||||
} else {
|
||||
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 => {
|
||||
let runner = cli.create_runner(&cli.run)?;
|
||||
runner.run_node_until_exit(|config| async move {
|
||||
match config.role {
|
||||
Role::Light => service::new_light(config),
|
||||
_ => service::new_full(config),
|
||||
}.map_err(sc_cli::Error::Service)
|
||||
}
|
||||
.map_err(sc_cli::Error::Service)
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
pub mod chain_spec;
|
||||
pub mod service;
|
||||
pub mod rpc;
|
||||
pub mod service;
|
||||
|
||||
@@ -8,12 +8,11 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
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;
|
||||
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.
|
||||
pub struct FullDeps<C, P> {
|
||||
@@ -26,34 +25,25 @@ pub struct FullDeps<C, P> {
|
||||
}
|
||||
|
||||
/// Instantiate all full RPC extensions.
|
||||
pub fn create_full<C, P>(
|
||||
deps: FullDeps<C, P>,
|
||||
) -> jsonrpc_core::IoHandler<sc_rpc::Metadata> where
|
||||
pub fn create_full<C, P>(deps: FullDeps<C, P>) -> jsonrpc_core::IoHandler<sc_rpc::Metadata>
|
||||
where
|
||||
C: ProvideRuntimeApi<Block>,
|
||||
C: HeaderBackend<Block> + HeaderMetadata<Block, Error=BlockChainError> + 'static,
|
||||
C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError> + 'static,
|
||||
C: Send + Sync + 'static,
|
||||
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
|
||||
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
|
||||
C::Api: BlockBuilder<Block>,
|
||||
P: TransactionPool + 'static,
|
||||
{
|
||||
use substrate_frame_rpc_system::{FullSystem, SystemApi};
|
||||
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
|
||||
use substrate_frame_rpc_system::{FullSystem, SystemApi};
|
||||
|
||||
let mut io = jsonrpc_core::IoHandler::default();
|
||||
let FullDeps {
|
||||
client,
|
||||
pool,
|
||||
deny_unsafe,
|
||||
} = deps;
|
||||
let FullDeps { client, pool, deny_unsafe } = deps;
|
||||
|
||||
io.extend_with(
|
||||
SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))
|
||||
);
|
||||
io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe)));
|
||||
|
||||
io.extend_with(
|
||||
TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone()))
|
||||
);
|
||||
io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone())));
|
||||
|
||||
// Extend this RPC with a custom API by using the following syntax.
|
||||
// `YourRpcStruct` should have a reference to a client, which is needed
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
//! 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 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;
|
||||
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_keystore::LocalKeystore;
|
||||
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
|
||||
use sc_telemetry::{Telemetry, TelemetryWorker};
|
||||
use sp_consensus::SlotData;
|
||||
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
// Our 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 FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
|
||||
|
||||
pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponents<
|
||||
FullClient, FullBackend, FullSelectChain,
|
||||
sp_consensus::DefaultImportQueue<Block, FullClient>,
|
||||
sc_transaction_pool::FullPool<Block, FullClient>,
|
||||
(
|
||||
sc_finality_grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, FullSelectChain>,
|
||||
sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
|
||||
Option<Telemetry>,
|
||||
)
|
||||
>, ServiceError> {
|
||||
pub fn new_partial(
|
||||
config: &Configuration,
|
||||
) -> Result<
|
||||
sc_service::PartialComponents<
|
||||
FullClient,
|
||||
FullBackend,
|
||||
FullSelectChain,
|
||||
sp_consensus::DefaultImportQueue<Block, FullClient>,
|
||||
sc_transaction_pool::FullPool<Block, FullClient>,
|
||||
(
|
||||
sc_finality_grandpa::GrandpaBlockImport<
|
||||
FullBackend,
|
||||
Block,
|
||||
FullClient,
|
||||
FullSelectChain,
|
||||
>,
|
||||
sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
|
||||
Option<Telemetry>,
|
||||
),
|
||||
>,
|
||||
ServiceError,
|
||||
> {
|
||||
if config.keystore_remote.is_some() {
|
||||
return Err(ServiceError::Other(
|
||||
format!("Remote Keystores are not supported.")))
|
||||
return Err(ServiceError::Other(format!("Remote Keystores are not supported.")))
|
||||
}
|
||||
|
||||
let telemetry = config.telemetry_endpoints.clone()
|
||||
let telemetry = config
|
||||
.telemetry_endpoints
|
||||
.clone()
|
||||
.filter(|x| !x.is_empty())
|
||||
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
|
||||
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 telemetry = telemetry
|
||||
.map(|(worker, telemetry)| {
|
||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||
telemetry
|
||||
});
|
||||
let telemetry = telemetry.map(|(worker, telemetry)| {
|
||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||
telemetry
|
||||
});
|
||||
|
||||
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 import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(
|
||||
ImportQueueParams {
|
||||
let import_queue =
|
||||
sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
|
||||
block_import: grandpa_block_import.clone(),
|
||||
justification_import: Some(Box::new(grandpa_block_import.clone())),
|
||||
client: client.clone(),
|
||||
@@ -98,12 +110,13 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen
|
||||
Ok((timestamp, slot))
|
||||
},
|
||||
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(),
|
||||
check_for_equivocation: Default::default(),
|
||||
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
||||
},
|
||||
)?;
|
||||
})?;
|
||||
|
||||
Ok(sc_service::PartialComponents {
|
||||
client,
|
||||
@@ -140,10 +153,11 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
||||
if let Some(url) = &config.keystore_remote {
|
||||
match remote_keystore(url) {
|
||||
Ok(k) => keystore_container.set_remote_keystore(k),
|
||||
Err(e) => {
|
||||
return Err(ServiceError::Other(
|
||||
format!("Error hooking up remote keystore for {}: {}", url, e)))
|
||||
}
|
||||
Err(e) =>
|
||||
return Err(ServiceError::Other(format!(
|
||||
"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 {
|
||||
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();
|
||||
|
||||
Box::new(move |deny_unsafe, _| {
|
||||
let deps = crate::rpc::FullDeps {
|
||||
client: client.clone(),
|
||||
pool: pool.clone(),
|
||||
deny_unsafe,
|
||||
};
|
||||
let deps =
|
||||
crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe };
|
||||
|
||||
crate::rpc::create_full(deps)
|
||||
})
|
||||
};
|
||||
|
||||
let _rpc_handlers = sc_service::spawn_tasks(
|
||||
sc_service::SpawnTasksParams {
|
||||
network: network.clone(),
|
||||
client: client.clone(),
|
||||
keystore: keystore_container.sync_keystore(),
|
||||
task_manager: &mut task_manager,
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
rpc_extensions_builder,
|
||||
on_demand: None,
|
||||
remote_blockchain: None,
|
||||
backend,
|
||||
system_rpc_tx,
|
||||
config,
|
||||
telemetry: telemetry.as_mut(),
|
||||
},
|
||||
)?;
|
||||
let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||
network: network.clone(),
|
||||
client: client.clone(),
|
||||
keystore: keystore_container.sync_keystore(),
|
||||
task_manager: &mut task_manager,
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
rpc_extensions_builder,
|
||||
on_demand: None,
|
||||
remote_blockchain: None,
|
||||
backend,
|
||||
system_rpc_tx,
|
||||
config,
|
||||
telemetry: telemetry.as_mut(),
|
||||
})?;
|
||||
|
||||
if role.is_authority() {
|
||||
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
|
||||
// need a keystore, regardless of which protocol we use below.
|
||||
let keystore = if role.is_authority() {
|
||||
Some(keystore_container.sync_keystore())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let keystore =
|
||||
if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None };
|
||||
|
||||
let grandpa_config = sc_finality_grandpa::Config {
|
||||
// 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.
|
||||
task_manager.spawn_essential_handle().spawn_blocking(
|
||||
"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.
|
||||
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())
|
||||
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
|
||||
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()),
|
||||
)?;
|
||||
|
||||
let mut telemetry = telemetry
|
||||
.map(|(worker, telemetry)| {
|
||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||
telemetry
|
||||
});
|
||||
let mut telemetry = telemetry.map(|(worker, telemetry)| {
|
||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||
telemetry
|
||||
});
|
||||
|
||||
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 import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(
|
||||
ImportQueueParams {
|
||||
let import_queue =
|
||||
sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
|
||||
block_import: grandpa_block_import.clone(),
|
||||
justification_import: Some(Box::new(grandpa_block_import.clone())),
|
||||
client: client.clone(),
|
||||
@@ -368,8 +378,7 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
||||
registry: config.prometheus_registry(),
|
||||
check_for_equivocation: Default::default(),
|
||||
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
||||
},
|
||||
)?;
|
||||
})?;
|
||||
|
||||
let (network, system_rpc_tx, network_starter) =
|
||||
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 {
|
||||
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 frame_system::RawOrigin;
|
||||
use frame_benchmarking::{benchmarks, whitelisted_caller, impl_benchmark_test_suite};
|
||||
#[allow(unused)]
|
||||
use crate::Pallet as Template;
|
||||
use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller};
|
||||
use frame_system::RawOrigin;
|
||||
|
||||
benchmarks! {
|
||||
do_something {
|
||||
@@ -17,8 +17,4 @@ benchmarks! {
|
||||
}
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(
|
||||
Template,
|
||||
crate::mock::new_test_ext(),
|
||||
crate::mock::Test,
|
||||
);
|
||||
impl_benchmark_test_suite!(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.
|
||||
/// Learn more about FRAME and the core library of Substrate FRAME pallets:
|
||||
/// <https://substrate.dev/docs/en/knowledgebase/runtime/frame>
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -63,7 +62,7 @@ pub mod pallet {
|
||||
// These functions materialize as "extrinsics", which are often compared to transactions.
|
||||
// Dispatchable functions must be annotated with a weight and must return a DispatchResult.
|
||||
#[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
|
||||
/// storage and emits an event. This function must be dispatched by a signed extrinsic.
|
||||
#[pallet::weight(10_000 + T::DbWeight::get().writes(1))]
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use crate as pallet_template;
|
||||
use sp_core::H256;
|
||||
use frame_support::parameter_types;
|
||||
use sp_runtime::{
|
||||
traits::{BlakeTwo256, IdentityLookup}, testing::Header,
|
||||
};
|
||||
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 Block = frame_system::mocking::MockBlock<Test>;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{Error, mock::*};
|
||||
use frame_support::{assert_ok, assert_noop};
|
||||
use crate::{mock::*, Error};
|
||||
use frame_support::{assert_noop, assert_ok};
|
||||
|
||||
#[test]
|
||||
fn it_works_for_default_value() {
|
||||
@@ -15,9 +15,6 @@ fn it_works_for_default_value() {
|
||||
fn correct_error_for_none_value() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Ensure the expected error is thrown when no value is present.
|
||||
assert_noop!(
|
||||
TemplateModule::cause_error(Origin::signed(1)),
|
||||
Error::<Test>::NoneValue
|
||||
);
|
||||
assert_noop!(TemplateModule::cause_error(Origin::signed(1)), Error::<Test>::NoneValue);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,43 +1,44 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
// `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.
|
||||
#[cfg(feature = "std")]
|
||||
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
|
||||
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 pallet_grandpa::{
|
||||
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
|
||||
};
|
||||
use sp_api::impl_runtime_apis;
|
||||
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
||||
use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
|
||||
use pallet_grandpa::fg_primitives;
|
||||
use sp_version::RuntimeVersion;
|
||||
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
|
||||
use sp_runtime::{
|
||||
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")]
|
||||
use sp_version::NativeVersion;
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
// 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::{
|
||||
construct_runtime, parameter_types, StorageValue,
|
||||
construct_runtime, parameter_types,
|
||||
traits::{KeyOwnerProofSystem, Randomness, StorageInfo},
|
||||
weights::{
|
||||
Weight, IdentityFee,
|
||||
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;
|
||||
#[cfg(any(feature = "std", test))]
|
||||
pub use sp_runtime::BuildStorage;
|
||||
pub use sp_runtime::{Perbill, Permill};
|
||||
|
||||
/// Import the template pallet.
|
||||
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.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn native_version() -> NativeVersion {
|
||||
NativeVersion {
|
||||
runtime_version: VERSION,
|
||||
can_author_with: Default::default(),
|
||||
}
|
||||
NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
|
||||
}
|
||||
|
||||
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
|
||||
@@ -306,7 +304,7 @@ pub type SignedExtra = (
|
||||
frame_system::CheckEra<Runtime>,
|
||||
frame_system::CheckNonce<Runtime>,
|
||||
frame_system::CheckWeight<Runtime>,
|
||||
pallet_transaction_payment::ChargeTransactionPayment<Runtime>
|
||||
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
|
||||
);
|
||||
/// Unchecked extrinsic type as expected by this runtime.
|
||||
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
|
||||
|
||||
@@ -24,36 +24,22 @@
|
||||
//! DO NOT depend on user input). Thus transaction generation should be
|
||||
//! based on randomized data.
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
};
|
||||
use futures::Future;
|
||||
use std::{borrow::Cow, collections::HashMap, pin::Pin, sync::Arc};
|
||||
|
||||
use node_primitives::Block;
|
||||
use node_testing::bench::{BenchDb, Profile, BlockType, KeyTypes, DatabaseType};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::NumberFor,
|
||||
OpaqueExtrinsic,
|
||||
};
|
||||
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile};
|
||||
use sc_transaction_pool_api::{
|
||||
ImportNotificationStream,
|
||||
PoolFuture,
|
||||
PoolStatus,
|
||||
TransactionFor,
|
||||
TransactionSource,
|
||||
TransactionStatusStreamFor,
|
||||
TxHash,
|
||||
ImportNotificationStream, PoolFuture, PoolStatus, TransactionFor, TransactionSource,
|
||||
TransactionStatusStreamFor, TxHash,
|
||||
};
|
||||
use sp_consensus::{Environment, Proposer};
|
||||
use sp_inherents::InherentDataProvider;
|
||||
use sp_runtime::{generic::BlockId, traits::NumberFor, OpaqueExtrinsic};
|
||||
|
||||
use crate::{
|
||||
common::SizeType,
|
||||
core::{self, Path, Mode},
|
||||
core::{self, Mode, Path},
|
||||
};
|
||||
|
||||
pub struct ConstructionBenchmarkDescription {
|
||||
@@ -72,7 +58,6 @@ pub struct ConstructionBenchmark {
|
||||
|
||||
impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
|
||||
fn path(&self) -> Path {
|
||||
|
||||
let mut path = Path::new(&["node", "proposer"]);
|
||||
|
||||
match self.profile {
|
||||
@@ -104,11 +89,7 @@ impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
|
||||
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
|
||||
let mut extrinsics: Vec<Arc<PoolTransaction>> = Vec::new();
|
||||
|
||||
let mut bench_db = BenchDb::with_key_types(
|
||||
self.database_type,
|
||||
50_000,
|
||||
self.key_types
|
||||
);
|
||||
let mut bench_db = BenchDb::with_key_types(self.database_type, 50_000, self.key_types);
|
||||
|
||||
let client = bench_db.client();
|
||||
|
||||
@@ -127,11 +108,9 @@ impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
format!(
|
||||
"Block construction ({:?}/{}, {:?}, {:?} backend)",
|
||||
self.block_type,
|
||||
self.size,
|
||||
self.profile,
|
||||
self.database_type,
|
||||
).into()
|
||||
self.block_type, self.size, self.profile, self.database_type,
|
||||
)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +118,9 @@ impl core::Benchmark for ConstructionBenchmark {
|
||||
fn run(&mut self, mode: Mode) -> std::time::Duration {
|
||||
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")
|
||||
.spec_version;
|
||||
|
||||
@@ -158,20 +139,25 @@ impl core::Benchmark for ConstructionBenchmark {
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
let proposer = futures::executor::block_on(proposer_factory.init(
|
||||
&context.client.header(&BlockId::number(0))
|
||||
.expect("Database error querying block #0")
|
||||
.expect("Block #0 should exist"),
|
||||
)).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,
|
||||
let proposer = futures::executor::block_on(
|
||||
proposer_factory.init(
|
||||
&context
|
||||
.client
|
||||
.header(&BlockId::number(0))
|
||||
.expect("Database error querying block #0")
|
||||
.expect("Block #0 should exist"),
|
||||
),
|
||||
).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();
|
||||
|
||||
@@ -191,10 +177,7 @@ pub struct PoolTransaction {
|
||||
|
||||
impl From<OpaqueExtrinsic> for PoolTransaction {
|
||||
fn from(e: OpaqueExtrinsic) -> Self {
|
||||
PoolTransaction {
|
||||
data: e,
|
||||
hash: node_primitives::Hash::zero(),
|
||||
}
|
||||
PoolTransaction { data: e, hash: node_primitives::Hash::zero() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,15 +193,25 @@ impl sc_transaction_pool_api::InPoolTransaction for PoolTransaction {
|
||||
&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)]
|
||||
@@ -236,7 +229,7 @@ impl sc_transaction_pool_api::TransactionPool for Transactions {
|
||||
_at: &BlockId<Self::Block>,
|
||||
_source: TransactionSource,
|
||||
_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!()
|
||||
}
|
||||
|
||||
@@ -259,14 +252,21 @@ impl sc_transaction_pool_api::TransactionPool for Transactions {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn ready_at(&self, _at: NumberFor<Self::Block>)
|
||||
-> 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());
|
||||
fn ready_at(
|
||||
&self,
|
||||
_at: NumberFor<Self::Block>,
|
||||
) -> 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))
|
||||
}
|
||||
|
||||
fn ready(&self) -> Box<dyn Iterator<Item=Arc<Self::InPoolTransaction>> + Send> {
|
||||
fn ready(&self) -> Box<dyn Iterator<Item = Arc<Self::InPoolTransaction>> + Send> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use std::{fmt, borrow::{Cow, ToOwned}};
|
||||
use serde::Serialize;
|
||||
use std::{
|
||||
borrow::{Cow, ToOwned},
|
||||
fmt,
|
||||
};
|
||||
|
||||
pub struct Path(Vec<String>);
|
||||
|
||||
@@ -33,7 +36,11 @@ impl Path {
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -115,10 +122,7 @@ impl fmt::Display for BenchmarkOutput {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_benchmark(
|
||||
benchmark: Box<dyn BenchmarkDescription>,
|
||||
mode: Mode,
|
||||
) -> BenchmarkOutput {
|
||||
pub fn run_benchmark(benchmark: Box<dyn BenchmarkDescription>, mode: Mode) -> BenchmarkOutput {
|
||||
let name = benchmark.name().to_owned();
|
||||
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 average = (durations.iter().skip(10).take(30).sum::<u128>() / 30) as u64;
|
||||
|
||||
BenchmarkOutput {
|
||||
name: name.into(),
|
||||
raw_average,
|
||||
average,
|
||||
}
|
||||
BenchmarkOutput { name: name.into(), raw_average, average }
|
||||
}
|
||||
|
||||
macro_rules! matrix(
|
||||
|
||||
@@ -30,14 +30,15 @@ use crate::simple_trie::SimpleTrie;
|
||||
/// return root.
|
||||
pub fn generate_trie(
|
||||
db: Arc<dyn KeyValueDB>,
|
||||
key_values: impl IntoIterator<Item=(Vec<u8>, Vec<u8>)>,
|
||||
key_values: impl IntoIterator<Item = (Vec<u8>, Vec<u8>)>,
|
||||
) -> Hash {
|
||||
let mut root = Hash::default();
|
||||
|
||||
let (db, overlay) = {
|
||||
let mut overlay = HashMap::new();
|
||||
overlay.insert(
|
||||
hex::decode("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").expect("null key is valid"),
|
||||
hex::decode("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314")
|
||||
.expect("null key is valid"),
|
||||
Some(vec![0]),
|
||||
);
|
||||
let mut trie = SimpleTrie { db, overlay: &mut overlay };
|
||||
@@ -50,7 +51,7 @@ pub fn generate_trie(
|
||||
|
||||
trie_db.commit();
|
||||
}
|
||||
( trie.db, overlay )
|
||||
(trie.db, overlay)
|
||||
};
|
||||
|
||||
let mut transaction = db.transaction();
|
||||
|
||||
@@ -32,15 +32,15 @@
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use node_testing::bench::{BenchDb, Profile, BlockType, KeyTypes, DatabaseType};
|
||||
use node_primitives::Block;
|
||||
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile};
|
||||
use sc_client_api::backend::Backend;
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_state_machine::InspectState;
|
||||
|
||||
use crate::{
|
||||
common::SizeType,
|
||||
core::{self, Path, Mode},
|
||||
core::{self, Mode, Path},
|
||||
};
|
||||
|
||||
pub struct ImportBenchmarkDescription {
|
||||
@@ -60,7 +60,6 @@ pub struct ImportBenchmark {
|
||||
|
||||
impl core::BenchmarkDescription for ImportBenchmarkDescription {
|
||||
fn path(&self) -> Path {
|
||||
|
||||
let mut path = Path::new(&["node", "import"]);
|
||||
|
||||
match self.profile {
|
||||
@@ -91,11 +90,7 @@ impl core::BenchmarkDescription for ImportBenchmarkDescription {
|
||||
|
||||
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
|
||||
let profile = self.profile;
|
||||
let mut bench_db = BenchDb::with_key_types(
|
||||
self.database_type,
|
||||
50_000,
|
||||
self.key_types
|
||||
);
|
||||
let mut bench_db = BenchDb::with_key_types(self.database_type, 50_000, self.key_types);
|
||||
let block = bench_db.generate_block(self.block_type.to_content(self.size.transactions()));
|
||||
Box::new(ImportBenchmark {
|
||||
database: bench_db,
|
||||
@@ -108,11 +103,9 @@ impl core::BenchmarkDescription for ImportBenchmarkDescription {
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
format!(
|
||||
"Block import ({:?}/{}, {:?}, {:?} backend)",
|
||||
self.block_type,
|
||||
self.size,
|
||||
self.profile,
|
||||
self.database_type,
|
||||
).into()
|
||||
self.block_type, self.size, self.profile, self.database_type,
|
||||
)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +113,9 @@ impl core::Benchmark for ImportBenchmark {
|
||||
fn run(&mut self, mode: Mode) -> std::time::Duration {
|
||||
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")
|
||||
.spec_version;
|
||||
|
||||
@@ -133,7 +128,8 @@ impl core::Benchmark for ImportBenchmark {
|
||||
let elapsed = start.elapsed();
|
||||
|
||||
// Sanity checks.
|
||||
context.client
|
||||
context
|
||||
.client
|
||||
.state_at(&BlockId::number(1))
|
||||
.expect("state_at failed for block#1")
|
||||
.inspect_state(|| {
|
||||
@@ -155,19 +151,17 @@ impl core::Benchmark for ImportBenchmark {
|
||||
BlockType::Noop => {
|
||||
assert_eq!(
|
||||
node_runtime::System::events().len(),
|
||||
|
||||
// should be 2 per signed extrinsic + 1 per unsigned
|
||||
// we have 1 unsigned and the rest are signed in the block
|
||||
// those 2 events per signed are:
|
||||
// - deposit event for charging transaction fee
|
||||
// - extrinsic success
|
||||
(self.block.extrinsics.len() - 1) * 2 + 1,
|
||||
(self.block.extrinsics.len() - 1) * 2 + 1,
|
||||
);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
if mode == Mode::Profile {
|
||||
std::thread::park_timeout(std::time::Duration::from_secs(1));
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
|
||||
mod common;
|
||||
mod construct;
|
||||
#[macro_use] mod core;
|
||||
mod import;
|
||||
#[macro_use]
|
||||
mod core;
|
||||
mod generator;
|
||||
mod import;
|
||||
mod simple_trie;
|
||||
mod state_sizes;
|
||||
mod tempdb;
|
||||
@@ -29,15 +30,15 @@ mod txpool;
|
||||
|
||||
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::{
|
||||
common::SizeType,
|
||||
core::{run_benchmark, Mode as BenchmarkMode},
|
||||
tempdb::DatabaseType,
|
||||
import::ImportBenchmarkDescription,
|
||||
trie::{TrieReadBenchmarkDescription, TrieWriteBenchmarkDescription, DatabaseSize},
|
||||
construct::ConstructionBenchmarkDescription,
|
||||
core::{run_benchmark, Mode as BenchmarkMode},
|
||||
import::ImportBenchmarkDescription,
|
||||
tempdb::DatabaseType,
|
||||
trie::{DatabaseSize, TrieReadBenchmarkDescription, TrieWriteBenchmarkDescription},
|
||||
txpool::PoolBenchmarkDescription,
|
||||
};
|
||||
|
||||
@@ -92,14 +93,25 @@ fn main() {
|
||||
SizeType::Large,
|
||||
SizeType::Full,
|
||||
SizeType::Custom(opt.transactions.unwrap_or(0)),
|
||||
].iter() {
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
for block_type in [
|
||||
BlockType::RandomTransfersKeepAlive,
|
||||
BlockType::RandomTransfersReaping,
|
||||
BlockType::Noop,
|
||||
].iter() {
|
||||
for database_type in [BenchDataBaseType::RocksDb, BenchDataBaseType::ParityDb].iter() {
|
||||
import_benchmarks.push((profile, size.clone(), block_type.clone(), database_type));
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
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())
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
let mut results = Vec::new();
|
||||
@@ -183,7 +195,8 @@ fn main() {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use hash_db::{AsHashDB, HashDB, Hasher as _, Prefix};
|
||||
use kvdb::KeyValueDB;
|
||||
use node_primitives::Hash;
|
||||
use sp_trie::DBValue;
|
||||
use hash_db::{HashDB, AsHashDB, Prefix, Hasher as _};
|
||||
|
||||
pub type Hasher = sp_core::Blake2Hasher;
|
||||
|
||||
@@ -32,7 +32,9 @@ pub struct 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) {
|
||||
&mut *self
|
||||
@@ -43,7 +45,7 @@ impl<'a> HashDB<Hasher, DBValue> for SimpleTrie<'a> {
|
||||
fn get(&self, key: &Hash, prefix: Prefix) -> Option<DBValue> {
|
||||
let key = sp_trie::prefixed_key::<Hasher>(key, prefix);
|
||||
if let Some(value) = self.overlay.get(&key) {
|
||||
return value.clone();
|
||||
return value.clone()
|
||||
}
|
||||
self.db.get(0, &key).expect("Database backend error")
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/// Kusama value size distribution
|
||||
pub const KUSAMA_STATE_DISTRIBUTION: &'static[(u32, u32)] = &[
|
||||
pub const KUSAMA_STATE_DISTRIBUTION: &'static [(u32, u32)] = &[
|
||||
(32, 35),
|
||||
(33, 20035),
|
||||
(34, 5369),
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// 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 kvdb::{KeyValueDB, DBTransaction};
|
||||
use kvdb_rocksdb::{DatabaseConfig, Database};
|
||||
|
||||
#[derive(Debug, Clone, Copy, derive_more::Display)]
|
||||
pub enum DatabaseType {
|
||||
@@ -44,13 +44,14 @@ impl KeyValueDB for ParityDbWrapper {
|
||||
|
||||
/// Write a transaction of changes to the buffer.
|
||||
fn write(&self, transaction: DBTransaction) -> io::Result<()> {
|
||||
self.0.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())),
|
||||
self.0
|
||||
.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::Delete { col, key } => (*col as u8, &key[key.len() - 32..], None),
|
||||
kvdb::DBOp::DeletePrefix { col: _, prefix: _ } => unimplemented!()
|
||||
})
|
||||
).expect("db error");
|
||||
kvdb::DBOp::DeletePrefix { col: _, prefix: _ } => unimplemented!(),
|
||||
}))
|
||||
.expect("db error");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -90,21 +91,19 @@ impl TempDatabase {
|
||||
match db_type {
|
||||
DatabaseType::RocksDb => {
|
||||
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)
|
||||
},
|
||||
DatabaseType::ParityDb => {
|
||||
Arc::new(ParityDbWrapper({
|
||||
let mut options = parity_db::Options::with_columns(self.0.path(), 1);
|
||||
let mut column_options = &mut options.columns[0];
|
||||
column_options.ref_counted = true;
|
||||
column_options.preimage = true;
|
||||
column_options.uniform = true;
|
||||
parity_db::Db::open(&options).expect("db open error")
|
||||
}))
|
||||
}
|
||||
DatabaseType::ParityDb => Arc::new(ParityDbWrapper({
|
||||
let mut options = parity_db::Options::with_columns(self.0.path(), 1);
|
||||
let mut column_options = &mut options.columns[0];
|
||||
column_options.ref_counted = true;
|
||||
column_options.preimage = true;
|
||||
column_options.uniform = true;
|
||||
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)
|
||||
.expect("failed to list file in seed dir")
|
||||
.map(|f_result|
|
||||
f_result.expect("failed to read file in seed db")
|
||||
.path()
|
||||
).collect::<Vec<PathBuf>>();
|
||||
fs_extra::copy_items(
|
||||
&self_db_files,
|
||||
new_dir.path(),
|
||||
&fs_extra::dir::CopyOptions::new(),
|
||||
).expect("Copy of seed database is ok");
|
||||
.map(|f_result| f_result.expect("failed to read file in seed db").path())
|
||||
.collect::<Vec<PathBuf>>();
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
|
||||
//! Trie benchmark (integrated).
|
||||
|
||||
use std::{borrow::Cow, collections::HashMap, sync::Arc};
|
||||
use hash_db::Prefix;
|
||||
use kvdb::KeyValueDB;
|
||||
use lazy_static::lazy_static;
|
||||
use rand::Rng;
|
||||
use hash_db::Prefix;
|
||||
use sp_state_machine::Backend as _;
|
||||
use sp_trie::{trie_types::TrieDBMut, TrieMut as _};
|
||||
use std::{borrow::Cow, collections::HashMap, sync::Arc};
|
||||
|
||||
use node_primitives::Hash;
|
||||
|
||||
@@ -32,7 +32,7 @@ use crate::{
|
||||
core::{self, Mode, Path},
|
||||
generator::generate_trie,
|
||||
simple_trie::SimpleTrie,
|
||||
tempdb::{TempDatabase, DatabaseType},
|
||||
tempdb::{DatabaseType, TempDatabase},
|
||||
};
|
||||
|
||||
pub const SAMPLE_SIZE: usize = 100;
|
||||
@@ -142,10 +142,7 @@ impl core::BenchmarkDescription for TrieReadBenchmarkDescription {
|
||||
assert_eq!(warmup_keys.len(), SAMPLE_SIZE);
|
||||
assert_eq!(query_keys.len(), SAMPLE_SIZE);
|
||||
|
||||
let root = generate_trie(
|
||||
database.open(self.database_type),
|
||||
key_values,
|
||||
);
|
||||
let root = generate_trie(database.open(self.database_type), key_values);
|
||||
|
||||
Box::new(TrieReadBenchmark {
|
||||
database,
|
||||
@@ -162,7 +159,8 @@ impl core::BenchmarkDescription for TrieReadBenchmarkDescription {
|
||||
self.database_size,
|
||||
pretty_print(self.database_size.keys()),
|
||||
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>> =
|
||||
Arc::new(Storage(db.open(self.database_type)));
|
||||
|
||||
let trie_backend = sp_state_machine::TrieBackend::new(
|
||||
storage,
|
||||
self.root,
|
||||
);
|
||||
let trie_backend = sp_state_machine::TrieBackend::new(storage, self.root);
|
||||
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("Warmup key should exist");
|
||||
|
||||
@@ -218,7 +214,6 @@ pub struct TrieWriteBenchmarkDescription {
|
||||
pub database_type: DatabaseType,
|
||||
}
|
||||
|
||||
|
||||
impl core::BenchmarkDescription for TrieWriteBenchmarkDescription {
|
||||
fn path(&self) -> Path {
|
||||
let mut path = Path::new(&["trie", "write"]);
|
||||
@@ -253,10 +248,7 @@ impl core::BenchmarkDescription for TrieWriteBenchmarkDescription {
|
||||
|
||||
assert_eq!(warmup_keys.len(), SAMPLE_SIZE);
|
||||
|
||||
let root = generate_trie(
|
||||
database.open(self.database_type),
|
||||
key_values,
|
||||
);
|
||||
let root = generate_trie(database.open(self.database_type), key_values);
|
||||
|
||||
Box::new(TrieWriteBenchmark {
|
||||
database,
|
||||
@@ -272,7 +264,8 @@ impl core::BenchmarkDescription for TrieWriteBenchmarkDescription {
|
||||
self.database_size,
|
||||
pretty_print(self.database_size.keys()),
|
||||
self.database_type,
|
||||
).into()
|
||||
)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,15 +285,13 @@ impl core::Benchmark for TrieWriteBenchmark {
|
||||
let mut new_root = self.root.clone();
|
||||
|
||||
let mut overlay = HashMap::new();
|
||||
let mut trie = SimpleTrie {
|
||||
db: kvdb.clone(),
|
||||
overlay: &mut overlay,
|
||||
};
|
||||
let mut trie_db_mut = TrieDBMut::from_existing(&mut trie, &mut new_root)
|
||||
.expect("Failed to create TrieDBMut");
|
||||
let mut trie = SimpleTrie { db: kvdb.clone(), overlay: &mut overlay };
|
||||
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() {
|
||||
let value = trie_db_mut.get(&warmup_key[..])
|
||||
let value = trie_db_mut
|
||||
.get(&warmup_key[..])
|
||||
.expect("Failed to get key: db error")
|
||||
.expect("Warmup key should exist");
|
||||
|
||||
@@ -367,7 +358,9 @@ impl SizePool {
|
||||
|
||||
fn value<R: Rng>(&self, rng: &mut R) -> Vec<u8> {
|
||||
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;
|
||||
random_vec(rng, size)
|
||||
}
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
|
||||
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 sp_runtime::generic::BlockId;
|
||||
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 database_type: DatabaseType,
|
||||
@@ -46,11 +46,7 @@ impl core::BenchmarkDescription for PoolBenchmarkDescription {
|
||||
|
||||
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
|
||||
Box::new(PoolBenchmark {
|
||||
database: BenchDb::with_key_types(
|
||||
self.database_type,
|
||||
50_000,
|
||||
KeyTypes::Sr25519,
|
||||
),
|
||||
database: BenchDb::with_key_types(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 {
|
||||
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")
|
||||
.spec_version;
|
||||
|
||||
@@ -80,22 +78,20 @@ impl core::Benchmark for PoolBenchmark {
|
||||
context.client.clone(),
|
||||
);
|
||||
|
||||
let generated_transactions = self.database.block_content(
|
||||
BlockType::RandomTransfersKeepAlive.to_content(Some(100)),
|
||||
&context.client,
|
||||
).into_iter().collect::<Vec<_>>();
|
||||
let generated_transactions = self
|
||||
.database
|
||||
.block_content(
|
||||
BlockType::RandomTransfersKeepAlive.to_content(Some(100)),
|
||||
&context.client,
|
||||
)
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
let submissions = generated_transactions.into_iter().map(|tx| {
|
||||
txpool.submit_one(
|
||||
&BlockId::Number(0),
|
||||
TransactionSource::External,
|
||||
tx,
|
||||
)
|
||||
});
|
||||
futures::executor::block_on(
|
||||
futures::future::join_all(submissions)
|
||||
);
|
||||
let submissions = generated_transactions
|
||||
.into_iter()
|
||||
.map(|tx| txpool.submit_one(&BlockId::Number(0), TransactionSource::External, tx));
|
||||
futures::executor::block_on(futures::future::join_all(submissions));
|
||||
let elapsed = start.elapsed();
|
||||
|
||||
if mode == Mode::Profile {
|
||||
|
||||
@@ -28,11 +28,11 @@
|
||||
//! flag and open a browser to the url that `wasm-pack test` outputs.
|
||||
//! For more infomation see <https://rustwasm.github.io/docs/wasm-pack/>.
|
||||
|
||||
use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use wasm_bindgen::JsValue;
|
||||
use jsonrpc_core::types::{MethodCall, Success, Version, Params, Id};
|
||||
use jsonrpc_core::types::{Id, MethodCall, Params, Success, Version};
|
||||
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);
|
||||
|
||||
@@ -41,8 +41,9 @@ fn rpc_call(method: &str) -> String {
|
||||
jsonrpc: Some(Version::V2),
|
||||
method: method.into(),
|
||||
params: Params::None,
|
||||
id: Id::Num(1)
|
||||
}).unwrap()
|
||||
id: Id::Num(1),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
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]
|
||||
async fn runs() {
|
||||
let mut client = node_cli::start_client(None, "info".into())
|
||||
.unwrap();
|
||||
let mut client = node_cli::start_client(None, "info".into()).unwrap();
|
||||
|
||||
// Check that the node handles rpc calls.
|
||||
// TODO: Re-add the code that checks if the node is syncing.
|
||||
let chain_name: String = deserialize_rpc_result(
|
||||
JsFuture::from(client.rpc_send(&rpc_call("system_chain")))
|
||||
.await
|
||||
.unwrap()
|
||||
JsFuture::from(client.rpc_send(&rpc_call("system_chain"))).await.unwrap(),
|
||||
);
|
||||
assert_eq!(chain_name, "Development");
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ fn main() {
|
||||
mod cli {
|
||||
include!("src/cli.rs");
|
||||
|
||||
use std::{fs, env, path::Path};
|
||||
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};
|
||||
|
||||
pub fn main() {
|
||||
@@ -51,9 +51,12 @@ mod cli {
|
||||
Some(dir) => dir,
|
||||
};
|
||||
let path = Path::new(&outdir)
|
||||
.parent().unwrap()
|
||||
.parent().unwrap()
|
||||
.parent().unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join("completion-scripts");
|
||||
|
||||
fs::create_dir(&path).ok();
|
||||
|
||||
@@ -17,18 +17,14 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::chain_spec::ChainSpec;
|
||||
use browser_utils::{browser_configuration, init_logging, set_console_error_panic_hook, Client};
|
||||
use log::info;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use browser_utils::{
|
||||
Client,
|
||||
browser_configuration, init_logging, set_console_error_panic_hook,
|
||||
};
|
||||
|
||||
/// Starts the client.
|
||||
#[wasm_bindgen]
|
||||
pub fn start_client(chain_spec: Option<String>, log_level: String) -> Result<Client, JsValue> {
|
||||
start_inner(chain_spec, log_level)
|
||||
.map_err(|err| JsValue::from_str(&err.to_string()))
|
||||
start_inner(chain_spec, log_level).map_err(|err| JsValue::from_str(&err.to_string()))
|
||||
}
|
||||
|
||||
fn start_inner(
|
||||
@@ -53,10 +49,9 @@ fn start_inner(
|
||||
info!("👤 Role: {:?}", config.role);
|
||||
|
||||
// Create the service. This is the most heavy initialization step.
|
||||
let (task_manager, rpc_handlers) =
|
||||
crate::service::new_light_base(config)
|
||||
.map(|(components, rpc_handlers, _, _, _)| (components, rpc_handlers))
|
||||
.map_err(|e| format!("{:?}", e))?;
|
||||
let (task_manager, rpc_handlers) = crate::service::new_light_base(config)
|
||||
.map(|(components, rpc_handlers, _, _, _)| (components, rpc_handlers))
|
||||
.map_err(|e| format!("{:?}", e))?;
|
||||
|
||||
Ok(browser_utils::start_client(task_manager, rpc_handlers))
|
||||
}
|
||||
|
||||
@@ -18,25 +18,26 @@
|
||||
|
||||
//! Substrate chain configurations.
|
||||
|
||||
use sc_chain_spec::ChainSpecExtension;
|
||||
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 grandpa_primitives::AuthorityId as GrandpaId;
|
||||
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 grandpa_primitives::{AuthorityId as GrandpaId};
|
||||
use sp_consensus_babe::{AuthorityId as BabeId};
|
||||
use pallet_im_online::sr25519::{AuthorityId as ImOnlineId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
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_runtime::GenesisConfig;
|
||||
@@ -59,10 +60,7 @@ pub struct Extensions {
|
||||
}
|
||||
|
||||
/// Specialized `ChainSpec`.
|
||||
pub type ChainSpec = sc_service::GenericChainSpec<
|
||||
GenesisConfig,
|
||||
Extensions,
|
||||
>;
|
||||
pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig, Extensions>;
|
||||
/// Flaming Fir testnet generator
|
||||
pub fn flaming_fir_config() -> Result<ChainSpec, String> {
|
||||
ChainSpec::from_json_bytes(&include_bytes!("../res/flaming-fir.json")[..])
|
||||
@@ -84,65 +82,94 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
||||
// and
|
||||
// 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![(
|
||||
// 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy
|
||||
hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].into(),
|
||||
// 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq
|
||||
hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].into(),
|
||||
// 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC
|
||||
hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"].unchecked_into(),
|
||||
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
|
||||
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"].unchecked_into(),
|
||||
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
|
||||
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"].unchecked_into(),
|
||||
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
|
||||
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"].unchecked_into(),
|
||||
),(
|
||||
// 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2
|
||||
hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].into(),
|
||||
// 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF
|
||||
hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].into(),
|
||||
// 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE
|
||||
hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"].unchecked_into(),
|
||||
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
|
||||
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"].unchecked_into(),
|
||||
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
|
||||
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"].unchecked_into(),
|
||||
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
|
||||
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"].unchecked_into(),
|
||||
),(
|
||||
// 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp
|
||||
hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].into(),
|
||||
// 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9
|
||||
hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].into(),
|
||||
// 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d
|
||||
hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"].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(),
|
||||
)];
|
||||
let initial_authorities: Vec<(
|
||||
AccountId,
|
||||
AccountId,
|
||||
GrandpaId,
|
||||
BabeId,
|
||||
ImOnlineId,
|
||||
AuthorityDiscoveryId,
|
||||
)> = vec![
|
||||
(
|
||||
// 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy
|
||||
hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].into(),
|
||||
// 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq
|
||||
hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].into(),
|
||||
// 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC
|
||||
hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"]
|
||||
.unchecked_into(),
|
||||
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
|
||||
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"]
|
||||
.unchecked_into(),
|
||||
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
|
||||
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"]
|
||||
.unchecked_into(),
|
||||
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
|
||||
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"]
|
||||
.unchecked_into(),
|
||||
),
|
||||
(
|
||||
// 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2
|
||||
hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].into(),
|
||||
// 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF
|
||||
hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].into(),
|
||||
// 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE
|
||||
hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"]
|
||||
.unchecked_into(),
|
||||
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
|
||||
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"]
|
||||
.unchecked_into(),
|
||||
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
|
||||
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"]
|
||||
.unchecked_into(),
|
||||
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
|
||||
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"]
|
||||
.unchecked_into(),
|
||||
),
|
||||
(
|
||||
// 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp
|
||||
hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].into(),
|
||||
// 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9
|
||||
hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].into(),
|
||||
// 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d
|
||||
hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"]
|
||||
.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
|
||||
let root_key: AccountId = hex![
|
||||
// 5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo
|
||||
"9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809"
|
||||
].into();
|
||||
]
|
||||
.into();
|
||||
|
||||
let endowed_accounts: Vec<AccountId> = vec![root_key.clone()];
|
||||
|
||||
@@ -158,8 +185,10 @@ pub fn staging_testnet_config() -> ChainSpec {
|
||||
ChainType::Live,
|
||||
staging_testnet_config_genesis,
|
||||
boot_nodes,
|
||||
Some(TelemetryEndpoints::new(vec![(STAGING_TELEMETRY_URL.to_string(), 0)])
|
||||
.expect("Staging telemetry url is valid; qed")),
|
||||
Some(
|
||||
TelemetryEndpoints::new(vec![(STAGING_TELEMETRY_URL.to_string(), 0)])
|
||||
.expect("Staging telemetry url is valid; qed"),
|
||||
),
|
||||
None,
|
||||
None,
|
||||
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
|
||||
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId where
|
||||
AccountPublic: From<<TPublic::Pair as Pair>::Public>
|
||||
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
|
||||
where
|
||||
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
|
||||
{
|
||||
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
|
||||
}
|
||||
|
||||
/// Helper function to generate stash, controller and session key from seed
|
||||
pub fn authority_keys_from_seed(seed: &str) -> (
|
||||
AccountId,
|
||||
AccountId,
|
||||
GrandpaId,
|
||||
BabeId,
|
||||
ImOnlineId,
|
||||
AuthorityDiscoveryId,
|
||||
) {
|
||||
pub fn authority_keys_from_seed(
|
||||
seed: &str,
|
||||
) -> (AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId) {
|
||||
(
|
||||
get_account_id_from_seed::<sr25519::Public>(&format!("{}//stash", seed)),
|
||||
get_account_id_from_seed::<sr25519::Public>(seed),
|
||||
@@ -230,11 +255,15 @@ pub fn testnet_genesis(
|
||||
]
|
||||
});
|
||||
// endow all authorities and nominators.
|
||||
initial_authorities.iter().map(|x| &x.0).chain(initial_nominators.iter()).for_each(|x| {
|
||||
if !endowed_accounts.contains(&x) {
|
||||
endowed_accounts.push(x.clone())
|
||||
}
|
||||
});
|
||||
initial_authorities
|
||||
.iter()
|
||||
.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.
|
||||
let mut rng = rand::thread_rng();
|
||||
@@ -266,22 +295,20 @@ pub fn testnet_genesis(
|
||||
changes_trie_config: Default::default(),
|
||||
},
|
||||
balances: BalancesConfig {
|
||||
balances: endowed_accounts.iter().cloned()
|
||||
.map(|x| (x, ENDOWMENT))
|
||||
.collect()
|
||||
},
|
||||
indices: IndicesConfig {
|
||||
indices: vec![],
|
||||
balances: endowed_accounts.iter().cloned().map(|x| (x, ENDOWMENT)).collect(),
|
||||
},
|
||||
indices: IndicesConfig { indices: vec![] },
|
||||
session: SessionConfig {
|
||||
keys: initial_authorities.iter().map(|x| {
|
||||
(x.0.clone(), x.0.clone(), session_keys(
|
||||
x.2.clone(),
|
||||
x.3.clone(),
|
||||
x.4.clone(),
|
||||
x.5.clone(),
|
||||
))
|
||||
}).collect::<Vec<_>>(),
|
||||
keys: initial_authorities
|
||||
.iter()
|
||||
.map(|x| {
|
||||
(
|
||||
x.0.clone(),
|
||||
x.0.clone(),
|
||||
session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
},
|
||||
staking: StakingConfig {
|
||||
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(),
|
||||
slash_reward_fraction: Perbill::from_percent(10),
|
||||
stakers,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
},
|
||||
democracy: DemocracyConfig::default(),
|
||||
elections: ElectionsConfig {
|
||||
members: endowed_accounts.iter()
|
||||
.take((num_endowed_accounts + 1) / 2)
|
||||
.cloned()
|
||||
.map(|member| (member, STASH))
|
||||
.collect(),
|
||||
members: endowed_accounts
|
||||
.iter()
|
||||
.take((num_endowed_accounts + 1) / 2)
|
||||
.cloned()
|
||||
.map(|member| (member, STASH))
|
||||
.collect(),
|
||||
},
|
||||
council: CouncilConfig::default(),
|
||||
technical_committee: TechnicalCommitteeConfig {
|
||||
members: endowed_accounts.iter()
|
||||
.take((num_endowed_accounts + 1) / 2)
|
||||
.cloned()
|
||||
.collect(),
|
||||
members: endowed_accounts
|
||||
.iter()
|
||||
.take((num_endowed_accounts + 1) / 2)
|
||||
.cloned()
|
||||
.collect(),
|
||||
phantom: Default::default(),
|
||||
},
|
||||
sudo: SudoConfig {
|
||||
key: root_key,
|
||||
},
|
||||
sudo: SudoConfig { key: root_key },
|
||||
babe: BabeConfig {
|
||||
authorities: vec![],
|
||||
epoch_config: Some(node_runtime::BABE_GENESIS_EPOCH_CONFIG),
|
||||
},
|
||||
im_online: ImOnlineConfig {
|
||||
keys: vec![],
|
||||
},
|
||||
authority_discovery: AuthorityDiscoveryConfig {
|
||||
keys: vec![],
|
||||
},
|
||||
grandpa: GrandpaConfig {
|
||||
authorities: vec![],
|
||||
},
|
||||
im_online: ImOnlineConfig { keys: vec![] },
|
||||
authority_discovery: AuthorityDiscoveryConfig { keys: vec![] },
|
||||
grandpa: GrandpaConfig { authorities: vec![] },
|
||||
technical_membership: Default::default(),
|
||||
treasury: Default::default(),
|
||||
society: SocietyConfig {
|
||||
members: endowed_accounts.iter()
|
||||
.take((num_endowed_accounts + 1) / 2)
|
||||
.cloned()
|
||||
.collect(),
|
||||
members: endowed_accounts
|
||||
.iter()
|
||||
.take((num_endowed_accounts + 1) / 2)
|
||||
.cloned()
|
||||
.collect(),
|
||||
pot: 0,
|
||||
max_members: 999,
|
||||
},
|
||||
@@ -341,9 +363,7 @@ pub fn testnet_genesis(
|
||||
|
||||
fn development_config_genesis() -> GenesisConfig {
|
||||
testnet_genesis(
|
||||
vec![
|
||||
authority_keys_from_seed("Alice"),
|
||||
],
|
||||
vec![authority_keys_from_seed("Alice")],
|
||||
vec![],
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
None,
|
||||
@@ -367,10 +387,7 @@ pub fn development_config() -> ChainSpec {
|
||||
|
||||
fn local_testnet_genesis() -> GenesisConfig {
|
||||
testnet_genesis(
|
||||
vec![
|
||||
authority_keys_from_seed("Alice"),
|
||||
authority_keys_from_seed("Bob"),
|
||||
],
|
||||
vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")],
|
||||
vec![],
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
None,
|
||||
@@ -401,9 +418,7 @@ pub(crate) mod tests {
|
||||
|
||||
fn local_testnet_genesis_instant_single() -> GenesisConfig {
|
||||
testnet_genesis(
|
||||
vec![
|
||||
authority_keys_from_seed("Alice"),
|
||||
],
|
||||
vec![authority_keys_from_seed("Alice")],
|
||||
vec![],
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
None,
|
||||
@@ -446,14 +461,24 @@ pub(crate) mod tests {
|
||||
sc_service_test::connectivity(
|
||||
integration_test_config_with_two_authorities(),
|
||||
|config| {
|
||||
let NewFullBase { task_manager, client, network, transaction_pool, .. }
|
||||
= new_full_base(config,|_, _| ())?;
|
||||
Ok(sc_service_test::TestNetComponents::new(task_manager, client, network, transaction_pool))
|
||||
let NewFullBase { task_manager, client, network, transaction_pool, .. } =
|
||||
new_full_base(config, |_, _| ())?;
|
||||
Ok(sc_service_test::TestNetComponents::new(
|
||||
task_manager,
|
||||
client,
|
||||
network,
|
||||
transaction_pool,
|
||||
))
|
||||
},
|
||||
|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,
|
||||
))
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// 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;
|
||||
|
||||
/// An overarching CLI command definition.
|
||||
|
||||
@@ -16,12 +16,11 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// 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_runtime::{Block, RuntimeApi};
|
||||
use sc_cli::{Result, SubstrateCli, RuntimeVersion, Role, ChainSpec};
|
||||
use sc_cli::{ChainSpec, Result, Role, RuntimeVersion, SubstrateCli};
|
||||
use sc_service::PartialComponents;
|
||||
use crate::service::new_partial;
|
||||
|
||||
impl SubstrateCli for Cli {
|
||||
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> {
|
||||
let spec =
|
||||
match id {
|
||||
"" => return Err("Please specify which chain you want to run, e.g. --dev or --chain=local".into()),
|
||||
"dev" => Box::new(chain_spec::development_config()),
|
||||
"local" => Box::new(chain_spec::local_testnet_config()),
|
||||
"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),
|
||||
)?),
|
||||
};
|
||||
let spec = match id {
|
||||
"" =>
|
||||
return Err(
|
||||
"Please specify which chain you want to run, e.g. --dev or --chain=local"
|
||||
.into(),
|
||||
),
|
||||
"dev" => Box::new(chain_spec::development_config()),
|
||||
"local" => Box::new(chain_spec::local_testnet_config()),
|
||||
"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)
|
||||
}
|
||||
|
||||
@@ -79,24 +80,25 @@ pub fn run() -> Result<()> {
|
||||
match config.role {
|
||||
Role::Light => service::new_light(config),
|
||||
_ => service::new_full(config),
|
||||
}.map_err(sc_cli::Error::Service)
|
||||
}
|
||||
.map_err(sc_cli::Error::Service)
|
||||
})
|
||||
}
|
||||
},
|
||||
Some(Subcommand::Inspect(cmd)) => {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
|
||||
runner.sync_run(|config| cmd.run::<Block, RuntimeApi, Executor>(config))
|
||||
}
|
||||
Some(Subcommand::Benchmark(cmd)) => {
|
||||
},
|
||||
Some(Subcommand::Benchmark(cmd)) =>
|
||||
if cfg!(feature = "runtime-benchmarks") {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
|
||||
runner.sync_run(|config| cmd.run::<Block, Executor>(config))
|
||||
} else {
|
||||
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::Sign(cmd)) => cmd.run(),
|
||||
Some(Subcommand::Verify(cmd)) => cmd.run(),
|
||||
@@ -108,32 +110,30 @@ pub fn run() -> Result<()> {
|
||||
Some(Subcommand::CheckBlock(cmd)) => {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
runner.async_run(|config| {
|
||||
let PartialComponents { client, task_manager, import_queue, ..}
|
||||
= new_partial(&config)?;
|
||||
let PartialComponents { client, task_manager, import_queue, .. } =
|
||||
new_partial(&config)?;
|
||||
Ok((cmd.run(client, import_queue), task_manager))
|
||||
})
|
||||
},
|
||||
Some(Subcommand::ExportBlocks(cmd)) => {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
runner.async_run(|config| {
|
||||
let PartialComponents { client, task_manager, ..}
|
||||
= new_partial(&config)?;
|
||||
let PartialComponents { client, task_manager, .. } = new_partial(&config)?;
|
||||
Ok((cmd.run(client, config.database), task_manager))
|
||||
})
|
||||
},
|
||||
Some(Subcommand::ExportState(cmd)) => {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
runner.async_run(|config| {
|
||||
let PartialComponents { client, task_manager, ..}
|
||||
= new_partial(&config)?;
|
||||
let PartialComponents { client, task_manager, .. } = new_partial(&config)?;
|
||||
Ok((cmd.run(client, config.chain_spec), task_manager))
|
||||
})
|
||||
},
|
||||
Some(Subcommand::ImportBlocks(cmd)) => {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
runner.async_run(|config| {
|
||||
let PartialComponents { client, task_manager, import_queue, ..}
|
||||
= new_partial(&config)?;
|
||||
let PartialComponents { client, task_manager, import_queue, .. } =
|
||||
new_partial(&config)?;
|
||||
Ok((cmd.run(client, import_queue), task_manager))
|
||||
})
|
||||
},
|
||||
@@ -144,8 +144,7 @@ pub fn run() -> Result<()> {
|
||||
Some(Subcommand::Revert(cmd)) => {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
runner.async_run(|config| {
|
||||
let PartialComponents { client, task_manager, backend, ..}
|
||||
= new_partial(&config)?;
|
||||
let PartialComponents { client, task_manager, backend, .. } = new_partial(&config)?;
|
||||
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
|
||||
// manager to do `async_run`.
|
||||
let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry);
|
||||
let task_manager = sc_service::TaskManager::new(
|
||||
config.task_executor.clone(),
|
||||
registry,
|
||||
).map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?;
|
||||
let task_manager =
|
||||
sc_service::TaskManager::new(config.task_executor.clone(), registry)
|
||||
.map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?;
|
||||
|
||||
Ok((cmd.run::<Block, Executor>(config), task_manager))
|
||||
})
|
||||
},
|
||||
#[cfg(not(feature = "try-runtime"))]
|
||||
Some(Subcommand::TryRuntime) => {
|
||||
Err("TryRuntime wasn't enabled when building the node. \
|
||||
You can enable it with `--features try-runtime`.".into())
|
||||
},
|
||||
Some(Subcommand::TryRuntime) => Err("TryRuntime wasn't enabled when building the node. \
|
||||
You can enable it with `--features try-runtime`."
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,20 +20,17 @@
|
||||
|
||||
//! Service implementation. Specialized wrapper over substrate service.
|
||||
|
||||
use std::sync::Arc;
|
||||
use sc_consensus_babe;
|
||||
use futures::prelude::*;
|
||||
use node_executor::Executor;
|
||||
use node_primitives::Block;
|
||||
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 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_consensus_babe::SlotProportion;
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use std::sync::Arc;
|
||||
|
||||
type FullClient = sc_service::TFullClient<Block, RuntimeApi, Executor>;
|
||||
type FullBackend = sc_service::TFullBackend<Block>;
|
||||
@@ -44,25 +41,29 @@ type LightClient = sc_service::TLightClient<Block, RuntimeApi, Executor>;
|
||||
|
||||
pub fn new_partial(
|
||||
config: &Configuration,
|
||||
) -> Result<sc_service::PartialComponents<
|
||||
FullClient, FullBackend, FullSelectChain,
|
||||
sp_consensus::DefaultImportQueue<Block, FullClient>,
|
||||
sc_transaction_pool::FullPool<Block, FullClient>,
|
||||
(
|
||||
impl Fn(
|
||||
node_rpc::DenyUnsafe,
|
||||
sc_rpc::SubscriptionTaskExecutor,
|
||||
) -> node_rpc::IoHandler,
|
||||
) -> Result<
|
||||
sc_service::PartialComponents<
|
||||
FullClient,
|
||||
FullBackend,
|
||||
FullSelectChain,
|
||||
sp_consensus::DefaultImportQueue<Block, FullClient>,
|
||||
sc_transaction_pool::FullPool<Block, FullClient>,
|
||||
(
|
||||
sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>,
|
||||
grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
|
||||
sc_consensus_babe::BabeLink<Block>,
|
||||
impl Fn(node_rpc::DenyUnsafe, sc_rpc::SubscriptionTaskExecutor) -> node_rpc::IoHandler,
|
||||
(
|
||||
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> {
|
||||
let telemetry = config.telemetry_endpoints.clone()
|
||||
>,
|
||||
ServiceError,
|
||||
> {
|
||||
let telemetry = config
|
||||
.telemetry_endpoints
|
||||
.clone()
|
||||
.filter(|x| !x.is_empty())
|
||||
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
|
||||
let worker = TelemetryWorker::new(16)?;
|
||||
@@ -78,11 +79,10 @@ pub fn new_partial(
|
||||
)?;
|
||||
let client = Arc::new(client);
|
||||
|
||||
let telemetry = telemetry
|
||||
.map(|(worker, telemetry)| {
|
||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||
telemetry
|
||||
});
|
||||
let telemetry = telemetry.map(|(worker, telemetry)| {
|
||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||
telemetry
|
||||
});
|
||||
|
||||
let select_chain = sc_consensus::LongestChain::new(backend.clone());
|
||||
|
||||
@@ -115,21 +115,19 @@ pub fn new_partial(
|
||||
Some(Box::new(justification_import)),
|
||||
client.clone(),
|
||||
select_chain.clone(),
|
||||
move |_, ()| {
|
||||
async move {
|
||||
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
move |_, ()| async move {
|
||||
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
|
||||
let slot =
|
||||
sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
|
||||
*timestamp,
|
||||
slot_duration,
|
||||
);
|
||||
let slot =
|
||||
sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
|
||||
*timestamp,
|
||||
slot_duration,
|
||||
);
|
||||
|
||||
let uncles =
|
||||
sp_authorship::InherentDataProvider::<<Block as BlockT>::Header>::check_inherents();
|
||||
let uncles =
|
||||
sp_authorship::InherentDataProvider::<<Block as BlockT>::Header>::check_inherents();
|
||||
|
||||
Ok((timestamp, slot, uncles))
|
||||
}
|
||||
Ok((timestamp, slot, uncles))
|
||||
},
|
||||
&task_manager.spawn_essential_handle(),
|
||||
config.prometheus_registry(),
|
||||
@@ -213,7 +211,7 @@ pub fn new_full_base(
|
||||
with_startup_data: impl FnOnce(
|
||||
&sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>,
|
||||
&sc_consensus_babe::BabeLink<Block>,
|
||||
)
|
||||
),
|
||||
) -> Result<NewFullBase, ServiceError> {
|
||||
let sc_service::PartialComponents {
|
||||
client,
|
||||
@@ -238,7 +236,7 @@ pub fn new_full_base(
|
||||
task_manager.spawn_handle(),
|
||||
backend.clone(),
|
||||
import_setup.1.shared_authority_set().clone(),
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
let (network, system_rpc_tx, network_starter) =
|
||||
@@ -254,7 +252,10 @@ pub fn new_full_base(
|
||||
|
||||
if config.offchain_worker.enabled {
|
||||
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 prometheus_registry = config.prometheus_registry().cloned();
|
||||
|
||||
let _rpc_handlers = sc_service::spawn_tasks(
|
||||
sc_service::SpawnTasksParams {
|
||||
config,
|
||||
backend: backend.clone(),
|
||||
client: client.clone(),
|
||||
keystore: keystore_container.sync_keystore(),
|
||||
network: network.clone(),
|
||||
rpc_extensions_builder: Box::new(rpc_extensions_builder),
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
task_manager: &mut task_manager,
|
||||
on_demand: None,
|
||||
remote_blockchain: None,
|
||||
system_rpc_tx,
|
||||
telemetry: telemetry.as_mut(),
|
||||
},
|
||||
)?;
|
||||
let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||
config,
|
||||
backend: backend.clone(),
|
||||
client: client.clone(),
|
||||
keystore: keystore_container.sync_keystore(),
|
||||
network: network.clone(),
|
||||
rpc_extensions_builder: Box::new(rpc_extensions_builder),
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
task_manager: &mut task_manager,
|
||||
on_demand: None,
|
||||
remote_blockchain: None,
|
||||
system_rpc_tx,
|
||||
telemetry: telemetry.as_mut(),
|
||||
})?;
|
||||
|
||||
let (block_import, grandpa_link, babe_link) = import_setup;
|
||||
|
||||
@@ -343,36 +342,37 @@ pub fn new_full_base(
|
||||
|
||||
// Spawn authority discovery module.
|
||||
if role.is_authority() {
|
||||
let authority_discovery_role = sc_authority_discovery::Role::PublishAndDiscover(
|
||||
keystore_container.keystore(),
|
||||
);
|
||||
let dht_event_stream = network.event_stream("authority-discovery")
|
||||
.filter_map(|e| async move { match e {
|
||||
Event::Dht(e) => Some(e),
|
||||
_ => None,
|
||||
}});
|
||||
let (authority_discovery_worker, _service) = sc_authority_discovery::new_worker_and_service_with_config(
|
||||
sc_authority_discovery::WorkerConfig {
|
||||
publish_non_global_ips: auth_disc_publish_non_global_ips,
|
||||
..Default::default()
|
||||
},
|
||||
client.clone(),
|
||||
network.clone(),
|
||||
Box::pin(dht_event_stream),
|
||||
authority_discovery_role,
|
||||
prometheus_registry.clone(),
|
||||
);
|
||||
let authority_discovery_role =
|
||||
sc_authority_discovery::Role::PublishAndDiscover(keystore_container.keystore());
|
||||
let dht_event_stream =
|
||||
network.event_stream("authority-discovery").filter_map(|e| async move {
|
||||
match e {
|
||||
Event::Dht(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
let (authority_discovery_worker, _service) =
|
||||
sc_authority_discovery::new_worker_and_service_with_config(
|
||||
sc_authority_discovery::WorkerConfig {
|
||||
publish_non_global_ips: auth_disc_publish_non_global_ips,
|
||||
..Default::default()
|
||||
},
|
||||
client.clone(),
|
||||
network.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
|
||||
// need a keystore, regardless of which protocol we use below.
|
||||
let keystore = if role.is_authority() {
|
||||
Some(keystore_container.sync_keystore())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let keystore =
|
||||
if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None };
|
||||
|
||||
let config = grandpa::Config {
|
||||
// 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.
|
||||
// if it fails we take down the service with it.
|
||||
task_manager.spawn_essential_handle().spawn_blocking(
|
||||
"grandpa-voter",
|
||||
grandpa::run_grandpa_voter(grandpa_config)?
|
||||
);
|
||||
task_manager
|
||||
.spawn_essential_handle()
|
||||
.spawn_blocking("grandpa-voter", grandpa::run_grandpa_voter(grandpa_config)?);
|
||||
}
|
||||
|
||||
network_starter.start_network();
|
||||
Ok(NewFullBase {
|
||||
task_manager,
|
||||
client,
|
||||
network,
|
||||
transaction_pool,
|
||||
})
|
||||
Ok(NewFullBase { task_manager, client, network, transaction_pool })
|
||||
}
|
||||
|
||||
/// Builds a new service for a full client.
|
||||
pub fn new_full(
|
||||
config: Configuration,
|
||||
) -> Result<TaskManager, ServiceError> {
|
||||
new_full_base(config, |_, _| ()).map(|NewFullBase { task_manager, .. }| {
|
||||
task_manager
|
||||
})
|
||||
pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
|
||||
new_full_base(config, |_, _| ()).map(|NewFullBase { task_manager, .. }| task_manager)
|
||||
}
|
||||
|
||||
pub fn new_light_base(
|
||||
mut config: Configuration,
|
||||
) -> Result<(
|
||||
TaskManager,
|
||||
RpcHandlers,
|
||||
Arc<LightClient>,
|
||||
Arc<NetworkService<Block, <Block as BlockT>::Hash>>,
|
||||
Arc<sc_transaction_pool::LightPool<Block, LightClient, sc_network::config::OnDemand<Block>>>
|
||||
), ServiceError> {
|
||||
let telemetry = config.telemetry_endpoints.clone()
|
||||
) -> Result<
|
||||
(
|
||||
TaskManager,
|
||||
RpcHandlers,
|
||||
Arc<LightClient>,
|
||||
Arc<NetworkService<Block, <Block as BlockT>::Hash>>,
|
||||
Arc<
|
||||
sc_transaction_pool::LightPool<Block, LightClient, sc_network::config::OnDemand<Block>>,
|
||||
>,
|
||||
),
|
||||
ServiceError,
|
||||
> {
|
||||
let telemetry = config
|
||||
.telemetry_endpoints
|
||||
.clone()
|
||||
.filter(|x| !x.is_empty())
|
||||
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
|
||||
#[cfg(feature = "browser")]
|
||||
let transport = Some(
|
||||
sc_telemetry::ExtTransport::new(libp2p_wasm_ext::ffi::websocket_transport())
|
||||
);
|
||||
let transport = Some(sc_telemetry::ExtTransport::new(libp2p_wasm_ext::ffi::websocket_transport()));
|
||||
#[cfg(not(feature = "browser"))]
|
||||
let transport = None;
|
||||
|
||||
@@ -459,11 +454,10 @@ pub fn new_light_base(
|
||||
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
|
||||
)?;
|
||||
|
||||
let mut telemetry = telemetry
|
||||
.map(|(worker, telemetry)| {
|
||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||
telemetry
|
||||
});
|
||||
let mut telemetry = telemetry.map(|(worker, telemetry)| {
|
||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||
telemetry
|
||||
});
|
||||
|
||||
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_handlers =
|
||||
sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||
on_demand: Some(on_demand),
|
||||
remote_blockchain: Some(backend.remote_blockchain()),
|
||||
rpc_extensions_builder: Box::new(sc_service::NoopRpcExtensionBuilder(rpc_extensions)),
|
||||
client: client.clone(),
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
keystore: keystore_container.sync_keystore(),
|
||||
config, backend, system_rpc_tx,
|
||||
network: network.clone(),
|
||||
task_manager: &mut task_manager,
|
||||
telemetry: telemetry.as_mut(),
|
||||
})?;
|
||||
let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||
on_demand: Some(on_demand),
|
||||
remote_blockchain: Some(backend.remote_blockchain()),
|
||||
rpc_extensions_builder: Box::new(sc_service::NoopRpcExtensionBuilder(rpc_extensions)),
|
||||
client: client.clone(),
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
keystore: keystore_container.sync_keystore(),
|
||||
config,
|
||||
backend,
|
||||
system_rpc_tx,
|
||||
network: network.clone(),
|
||||
task_manager: &mut task_manager,
|
||||
telemetry: telemetry.as_mut(),
|
||||
})?;
|
||||
|
||||
network_starter.start_network();
|
||||
Ok((
|
||||
task_manager,
|
||||
rpc_handlers,
|
||||
client,
|
||||
network,
|
||||
transaction_pool,
|
||||
))
|
||||
Ok((task_manager, rpc_handlers, client, network, transaction_pool))
|
||||
}
|
||||
|
||||
/// Builds a new service for a light client.
|
||||
pub fn new_light(
|
||||
config: Configuration,
|
||||
) -> Result<TaskManager, ServiceError> {
|
||||
new_light_base(config).map(|(task_manager, _, _, _, _)| {
|
||||
task_manager
|
||||
})
|
||||
pub fn new_light(config: Configuration) -> Result<TaskManager, ServiceError> {
|
||||
new_light_base(config).map(|(task_manager, _, _, _, _)| task_manager)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{sync::Arc, borrow::Cow, convert::TryInto};
|
||||
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 crate::service::{new_full_base, new_light_base, NewFullBase};
|
||||
use codec::Encode;
|
||||
use sp_core::{
|
||||
crypto::Pair as CryptoPair,
|
||||
H256,
|
||||
Public
|
||||
use node_primitives::{Block, DigestItem, Signature};
|
||||
use node_runtime::{
|
||||
constants::{currency::CENTS, time::SLOT_DURATION},
|
||||
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::{
|
||||
generic::{BlockId, Era, Digest, SignedPayload},
|
||||
traits::{Block as BlockT, Header as HeaderT},
|
||||
traits::Verify,
|
||||
generic::{BlockId, Digest, Era, SignedPayload},
|
||||
key_types::BABE,
|
||||
traits::{Block as BlockT, Header as HeaderT, IdentifyAccount, Verify},
|
||||
RuntimeAppPublic,
|
||||
};
|
||||
use sp_timestamp;
|
||||
use sp_keyring::AccountKeyring;
|
||||
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;
|
||||
use std::{borrow::Cow, convert::TryInto, sync::Arc};
|
||||
|
||||
type AccountPublic = <Signature as Verify>::Signer;
|
||||
|
||||
@@ -641,10 +624,12 @@ mod tests {
|
||||
#[ignore]
|
||||
fn test_sync() {
|
||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||
let keystore: SyncCryptoStorePtr = 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"))
|
||||
.expect("Creates authority pair").into();
|
||||
let keystore: SyncCryptoStorePtr =
|
||||
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"))
|
||||
.expect("Creates authority pair")
|
||||
.into();
|
||||
|
||||
let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority();
|
||||
|
||||
@@ -660,25 +645,31 @@ mod tests {
|
||||
chain_spec,
|
||||
|config| {
|
||||
let mut setup_handles = None;
|
||||
let NewFullBase {
|
||||
task_manager, client, network, transaction_pool, ..
|
||||
} = new_full_base(config,
|
||||
|
|
||||
block_import: &sc_consensus_babe::BabeBlockImport<Block, _, _>,
|
||||
babe_link: &sc_consensus_babe::BabeLink<Block>,
|
||||
| {
|
||||
setup_handles = Some((block_import.clone(), babe_link.clone()));
|
||||
}
|
||||
)?;
|
||||
let NewFullBase { task_manager, client, network, transaction_pool, .. } =
|
||||
new_full_base(
|
||||
config,
|
||||
|block_import: &sc_consensus_babe::BabeBlockImport<Block, _, _>,
|
||||
babe_link: &sc_consensus_babe::BabeLink<Block>| {
|
||||
setup_handles = Some((block_import.clone(), babe_link.clone()));
|
||||
},
|
||||
)?;
|
||||
|
||||
let node = sc_service_test::TestNetComponents::new(
|
||||
task_manager, client, network, transaction_pool
|
||||
task_manager,
|
||||
client,
|
||||
network,
|
||||
transaction_pool,
|
||||
);
|
||||
Ok((node, setup_handles.unwrap()))
|
||||
},
|
||||
|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)| {
|
||||
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_number = *parent_header.number();
|
||||
|
||||
futures::executor::block_on(
|
||||
service.transaction_pool().maintain(
|
||||
ChainEvent::NewBestBlock {
|
||||
hash: parent_header.hash(),
|
||||
tree_route: None,
|
||||
},
|
||||
)
|
||||
);
|
||||
futures::executor::block_on(service.transaction_pool().maintain(
|
||||
ChainEvent::NewBestBlock { hash: parent_header.hash(), tree_route: None },
|
||||
));
|
||||
|
||||
let mut proposer_factory = sc_basic_authorship::ProposerFactory::new(
|
||||
service.spawn_handle(),
|
||||
@@ -708,23 +694,30 @@ mod tests {
|
||||
// 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.
|
||||
let (babe_pre_digest, epoch_descriptor) = loop {
|
||||
let epoch_descriptor = babe_link.epoch_changes().shared_data().epoch_descriptor_for_child_of(
|
||||
descendent_query(&*service.client()),
|
||||
&parent_hash,
|
||||
parent_number,
|
||||
slot.into(),
|
||||
).unwrap().unwrap();
|
||||
let epoch_descriptor = babe_link
|
||||
.epoch_changes()
|
||||
.shared_data()
|
||||
.epoch_descriptor_for_child_of(
|
||||
descendent_query(&*service.client()),
|
||||
&parent_hash,
|
||||
parent_number,
|
||||
slot.into(),
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let epoch = babe_link.epoch_changes().shared_data().epoch_data(
|
||||
&epoch_descriptor,
|
||||
|slot| sc_consensus_babe::Epoch::genesis(&babe_link.config(), slot),
|
||||
).unwrap();
|
||||
let epoch = babe_link
|
||||
.epoch_changes()
|
||||
.shared_data()
|
||||
.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(
|
||||
slot.into(),
|
||||
&epoch,
|
||||
&keystore,
|
||||
).map(|(digest, _)| digest) {
|
||||
if let Some(babe_pre_digest) =
|
||||
sc_consensus_babe::authorship::claim_slot(slot.into(), &epoch, &keystore)
|
||||
.map(|(digest, _)| digest)
|
||||
{
|
||||
break (babe_pre_digest, epoch_descriptor)
|
||||
}
|
||||
|
||||
@@ -736,19 +729,21 @@ mod tests {
|
||||
std::time::Duration::from_millis(SLOT_DURATION * 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));
|
||||
|
||||
let new_block = futures::executor::block_on(async move {
|
||||
let proposer = proposer_factory.init(&parent_header).await;
|
||||
proposer.unwrap().propose(
|
||||
inherent_data,
|
||||
digest,
|
||||
std::time::Duration::from_secs(1),
|
||||
None,
|
||||
).await
|
||||
}).expect("Error making test block").block;
|
||||
proposer
|
||||
.unwrap()
|
||||
.propose(inherent_data, digest, std::time::Duration::from_secs(1), None)
|
||||
.await
|
||||
})
|
||||
.expect("Error making test block")
|
||||
.block;
|
||||
|
||||
let (new_header, new_body) = new_block.deconstruct();
|
||||
let pre_hash = new_header.hash();
|
||||
@@ -760,10 +755,12 @@ mod tests {
|
||||
sp_consensus_babe::AuthorityId::ID,
|
||||
&alice.to_public_crypto_pair(),
|
||||
&to_sign,
|
||||
).unwrap().unwrap().try_into().unwrap();
|
||||
let item = <DigestItem as CompatibleDigestItem>::babe_seal(
|
||||
signature,
|
||||
);
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let item = <DigestItem as CompatibleDigestItem>::babe_seal(signature);
|
||||
slot += 1;
|
||||
|
||||
let mut params = BlockImportParams::new(BlockOrigin::File, new_header);
|
||||
@@ -811,19 +808,13 @@ mod tests {
|
||||
let raw_payload = SignedPayload::from_raw(
|
||||
function,
|
||||
extra,
|
||||
(spec_version, transaction_version, genesis_hash, genesis_hash, (), (), ())
|
||||
(spec_version, transaction_version, genesis_hash, genesis_hash, (), (), ()),
|
||||
);
|
||||
let signature = raw_payload.using_encoded(|payload| {
|
||||
signer.sign(payload)
|
||||
});
|
||||
let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
|
||||
let (function, extra, _) = raw_payload.deconstruct();
|
||||
index += 1;
|
||||
UncheckedExtrinsic::new_signed(
|
||||
function,
|
||||
from.into(),
|
||||
signature.into(),
|
||||
extra,
|
||||
).into()
|
||||
UncheckedExtrinsic::new_signed(function, from.into(), signature.into(), extra)
|
||||
.into()
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -834,18 +825,25 @@ mod tests {
|
||||
sc_service_test::consensus(
|
||||
crate::chain_spec::tests::integration_test_config_with_two_authorities(),
|
||||
|config| {
|
||||
let NewFullBase { task_manager, client, network, transaction_pool, .. }
|
||||
= new_full_base(config,|_, _| ())?;
|
||||
Ok(sc_service_test::TestNetComponents::new(task_manager, client, network, transaction_pool))
|
||||
let NewFullBase { task_manager, client, network, transaction_pool, .. } =
|
||||
new_full_base(config, |_, _| ())?;
|
||||
Ok(sc_service_test::TestNetComponents::new(
|
||||
task_manager,
|
||||
client,
|
||||
network,
|
||||
transaction_pool,
|
||||
))
|
||||
},
|
||||
|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![
|
||||
"//Alice".into(),
|
||||
"//Bob".into(),
|
||||
],
|
||||
vec!["//Alice".into(), "//Bob".into()],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,18 @@
|
||||
|
||||
#![cfg(unix)]
|
||||
|
||||
use std::{process::{Child, ExitStatus}, thread, time::Duration, path::Path};
|
||||
use assert_cmd::cargo::cargo_bin;
|
||||
use std::{convert::TryInto, process::Command};
|
||||
use nix::sys::signal::{kill, Signal::SIGINT};
|
||||
use nix::unistd::Pid;
|
||||
use nix::{
|
||||
sys::signal::{kill, Signal::SIGINT},
|
||||
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`.
|
||||
///
|
||||
@@ -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) {
|
||||
let mut cmd = Command::new(cargo_bin("substrate"));
|
||||
|
||||
let mut cmd = cmd
|
||||
.args(&["--dev"])
|
||||
.arg("-d")
|
||||
.arg(base_path)
|
||||
.spawn()
|
||||
.unwrap();
|
||||
let mut cmd = cmd.args(&["--dev"]).arg("-d").arg(base_path).spawn().unwrap();
|
||||
|
||||
// Let it produce some blocks.
|
||||
thread::sleep(Duration::from_secs(30));
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
#![cfg(unix)]
|
||||
|
||||
use assert_cmd::cargo::cargo_bin;
|
||||
use std::{process::Command, fs, path::PathBuf};
|
||||
use tempfile::{tempdir, TempDir};
|
||||
use regex::Regex;
|
||||
use std::{fs, path::PathBuf, process::Command};
|
||||
use tempfile::{tempdir, TempDir};
|
||||
|
||||
pub mod common;
|
||||
|
||||
@@ -63,26 +63,23 @@ impl<'a> ExportImportRevertExecutor<'a> {
|
||||
fn new(
|
||||
base_path: &'a TempDir,
|
||||
exported_blocks_file: &'a PathBuf,
|
||||
db_path: &'a PathBuf
|
||||
db_path: &'a PathBuf,
|
||||
) -> Self {
|
||||
Self {
|
||||
base_path,
|
||||
exported_blocks_file,
|
||||
db_path,
|
||||
num_exported_blocks: None,
|
||||
}
|
||||
Self { 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.
|
||||
fn run_block_command(&self,
|
||||
fn run_block_command(
|
||||
&self,
|
||||
sub_command: SubCommand,
|
||||
format_opt: FormatOpt,
|
||||
expected_to_fail: bool
|
||||
expected_to_fail: bool,
|
||||
) -> String {
|
||||
let sub_command_str = sub_command.to_string();
|
||||
// Adding "--binary" if need be.
|
||||
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"],
|
||||
};
|
||||
|
||||
@@ -94,7 +91,7 @@ impl<'a> ExportImportRevertExecutor<'a> {
|
||||
SubCommand::ImportBlocks => {
|
||||
tmp = tempdir().unwrap();
|
||||
tmp.path()
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Running the command and capturing the output.
|
||||
@@ -144,16 +141,13 @@ impl<'a> ExportImportRevertExecutor<'a> {
|
||||
if !expected_to_fail {
|
||||
// Using regex to find out how much block we imported,
|
||||
// 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 imported = caps["imported"].parse::<u64>().unwrap();
|
||||
let best = caps["best"].parse::<u64>().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
imported,
|
||||
best,
|
||||
"numbers of blocks imported and best number differs"
|
||||
);
|
||||
assert_eq!(imported, best, "numbers of blocks imported and best number differs");
|
||||
assert_eq!(
|
||||
best,
|
||||
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());
|
||||
|
||||
let mut executor = ExportImportRevertExecutor::new(
|
||||
&base_path,
|
||||
&exported_blocks_file,
|
||||
&db_path,
|
||||
);
|
||||
let mut executor = ExportImportRevertExecutor::new(&base_path, &exported_blocks_file, &db_path);
|
||||
|
||||
// Binary and binary should work.
|
||||
executor.run(FormatOpt::Binary, FormatOpt::Binary, false);
|
||||
|
||||
@@ -25,8 +25,13 @@ pub mod common;
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn running_the_node_works_and_can_be_interrupted() {
|
||||
use nix::sys::signal::{kill, Signal::{self, SIGINT, SIGTERM}};
|
||||
use nix::unistd::Pid;
|
||||
use nix::{
|
||||
sys::signal::{
|
||||
kill,
|
||||
Signal::{self, SIGINT, SIGTERM},
|
||||
},
|
||||
unistd::Pid,
|
||||
};
|
||||
|
||||
fn run_command_and_kill(signal: Signal) {
|
||||
let base_path = tempdir().expect("could not create a temp dir");
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use assert_cmd::cargo::cargo_bin;
|
||||
use nix::sys::signal::{kill, Signal::SIGINT};
|
||||
use nix::unistd::Pid;
|
||||
use std::convert::TryInto;
|
||||
use std::process;
|
||||
use nix::{
|
||||
sys::signal::{kill, Signal::SIGINT},
|
||||
unistd::Pid,
|
||||
};
|
||||
use std::{convert::TryInto, process};
|
||||
|
||||
pub mod common;
|
||||
pub mod websocket_server;
|
||||
@@ -45,27 +46,22 @@ async fn telemetry_works() {
|
||||
Event::ConnectionOpen { address } => {
|
||||
println!("New connection from {:?}", address);
|
||||
server.accept();
|
||||
}
|
||||
},
|
||||
|
||||
// Received a message from a connection.
|
||||
Event::BinaryFrame { message, .. } => {
|
||||
let json: serde_json::Value = serde_json::from_slice(&message).unwrap();
|
||||
let object = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("payload")
|
||||
.unwrap()
|
||||
.as_object()
|
||||
.unwrap();
|
||||
let object =
|
||||
json.as_object().unwrap().get("payload").unwrap().as_object().unwrap();
|
||||
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"),
|
||||
|
||||
// Connection has been closed.
|
||||
Event::ConnectionError { .. } => {}
|
||||
Event::ConnectionError { .. } => {},
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -83,16 +79,11 @@ async fn telemetry_works() {
|
||||
|
||||
server_task.await;
|
||||
|
||||
assert!(
|
||||
substrate.try_wait().unwrap().is_none(),
|
||||
"the process should still be running"
|
||||
);
|
||||
assert!(substrate.try_wait().unwrap().is_none(), "the process should still be running");
|
||||
|
||||
// Stop the process
|
||||
kill(Pid::from_raw(substrate.id().try_into().unwrap()), SIGINT).unwrap();
|
||||
assert!(common::wait_for(&mut substrate, 40)
|
||||
.map(|x| x.success())
|
||||
.unwrap_or_default());
|
||||
assert!(common::wait_for(&mut substrate, 40).map(|x| x.success()).unwrap_or_default());
|
||||
|
||||
let output = substrate.wait_with_output().unwrap();
|
||||
|
||||
|
||||
@@ -19,15 +19,19 @@
|
||||
#![cfg(unix)]
|
||||
|
||||
use assert_cmd::cargo::cargo_bin;
|
||||
use nix::sys::signal::{kill, Signal::SIGINT};
|
||||
use nix::unistd::Pid;
|
||||
use nix::{
|
||||
sys::signal::{kill, Signal::SIGINT},
|
||||
unistd::Pid,
|
||||
};
|
||||
use regex::Regex;
|
||||
use std::convert::TryInto;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
io::Read,
|
||||
path::PathBuf,
|
||||
process::{Command, Stdio},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
pub mod common;
|
||||
|
||||
@@ -44,29 +48,18 @@ fn temp_base_path_works() {
|
||||
|
||||
// Let it produce some blocks.
|
||||
thread::sleep(Duration::from_secs(30));
|
||||
assert!(
|
||||
cmd.try_wait().unwrap().is_none(),
|
||||
"the process should still be running"
|
||||
);
|
||||
assert!(cmd.try_wait().unwrap().is_none(), "the process should still be running");
|
||||
|
||||
// Stop the process
|
||||
kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap();
|
||||
assert!(common::wait_for(&mut cmd, 40)
|
||||
.map(|x| x.success())
|
||||
.unwrap_or_default());
|
||||
assert!(common::wait_for(&mut cmd, 40).map(|x| x.success()).unwrap_or_default());
|
||||
|
||||
// Ensure the database has been deleted
|
||||
let mut stderr = String::new();
|
||||
cmd.stderr.unwrap().read_to_string(&mut stderr).unwrap();
|
||||
let re = Regex::new(r"Database: .+ at (\S+)").unwrap();
|
||||
let db_path = PathBuf::from(
|
||||
re.captures(stderr.as_str())
|
||||
.unwrap()
|
||||
.get(1)
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.to_string(),
|
||||
);
|
||||
let db_path =
|
||||
PathBuf::from(re.captures(stderr.as_str()).unwrap().get(1).unwrap().as_str().to_string());
|
||||
|
||||
assert!(!db_path.exists());
|
||||
}
|
||||
|
||||
@@ -22,61 +22,45 @@ use regex::Regex;
|
||||
use std::process::Command;
|
||||
|
||||
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]
|
||||
fn version_is_full() {
|
||||
let expected = expected_regex();
|
||||
let output = Command::new(cargo_bin("substrate"))
|
||||
.args(&["--version"])
|
||||
.output()
|
||||
.unwrap();
|
||||
let output = Command::new(cargo_bin("substrate")).args(&["--version"]).output().unwrap();
|
||||
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"command returned with non-success exit code"
|
||||
);
|
||||
assert!(output.status.success(), "command returned with non-success exit code");
|
||||
|
||||
let output = String::from_utf8_lossy(&output.stdout).trim().to_owned();
|
||||
let captures = expected
|
||||
.captures(output.as_str())
|
||||
.expect("could not parse version in output");
|
||||
let captures = expected.captures(output.as_str()).expect("could not parse version in output");
|
||||
|
||||
assert_eq!(&captures[1], env!("CARGO_PKG_VERSION"));
|
||||
assert_eq!(&captures[3], TARGET_ARCH.as_str());
|
||||
assert_eq!(&captures[4], TARGET_OS.as_str());
|
||||
assert_eq!(
|
||||
captures.get(5).map(|x| x.as_str()),
|
||||
TARGET_ENV.map(|x| x.as_str())
|
||||
);
|
||||
assert_eq!(captures.get(5).map(|x| x.as_str()), TARGET_ENV.map(|x| x.as_str()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_regex_matches_properly() {
|
||||
let expected = expected_regex();
|
||||
|
||||
let captures = expected
|
||||
.captures("substrate 2.0.0-da487d19d-x86_64-linux-gnu")
|
||||
.unwrap();
|
||||
let captures = expected.captures("substrate 2.0.0-da487d19d-x86_64-linux-gnu").unwrap();
|
||||
assert_eq!(&captures[1], "2.0.0");
|
||||
assert_eq!(&captures[2], "da487d19d");
|
||||
assert_eq!(&captures[3], "x86_64");
|
||||
assert_eq!(&captures[4], "linux");
|
||||
assert_eq!(captures.get(5).map(|x| x.as_str()), Some("gnu"));
|
||||
|
||||
let captures = expected
|
||||
.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux-gnu")
|
||||
.unwrap();
|
||||
let captures = expected.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[2], "da487d19d");
|
||||
assert_eq!(&captures[3], "x86_64");
|
||||
assert_eq!(&captures[4], "linux");
|
||||
assert_eq!(captures.get(5).map(|x| x.as_str()), Some("gnu"));
|
||||
|
||||
let captures = expected
|
||||
.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux")
|
||||
.unwrap();
|
||||
let captures = expected.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux").unwrap();
|
||||
assert_eq!(&captures[1], "2.0.0-alpha.5");
|
||||
assert_eq!(&captures[2], "da487d19d");
|
||||
assert_eq!(&captures[3], "x86_64");
|
||||
|
||||
@@ -116,7 +116,6 @@ impl WsServer {
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if no connection is pending.
|
||||
///
|
||||
pub fn accept(&mut self) {
|
||||
let pending_incoming = self.pending_incoming.take().expect("no pending socket");
|
||||
|
||||
@@ -129,15 +128,10 @@ impl WsServer {
|
||||
};
|
||||
|
||||
match server
|
||||
.send_response(&{
|
||||
Response::Accept {
|
||||
key: &websocket_key,
|
||||
protocol: None,
|
||||
}
|
||||
})
|
||||
.send_response(&{ Response::Accept { key: &websocket_key, protocol: None } })
|
||||
.await
|
||||
{
|
||||
Ok(()) => {}
|
||||
Ok(()) => {},
|
||||
Err(err) => return Err(Box::new(err) as Box<_>),
|
||||
};
|
||||
|
||||
@@ -153,7 +147,6 @@ impl WsServer {
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if no connection is pending.
|
||||
///
|
||||
pub fn reject(&mut self) {
|
||||
let _ = self.pending_incoming.take().expect("no pending socket");
|
||||
}
|
||||
|
||||
@@ -16,29 +16,33 @@
|
||||
// limitations under the License.
|
||||
|
||||
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_primitives::{BlockNumber, Hash};
|
||||
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 sp_core::{NativeOrEncoded, NeverNativeValue};
|
||||
use sp_core::storage::well_known_keys;
|
||||
use sp_core::traits::{CodeExecutor, RuntimeCode};
|
||||
use frame_support::Hashable;
|
||||
use sp_state_machine::TestExternalities as CoreTestExternalities;
|
||||
use sc_executor::{NativeExecutor, RuntimeInfo, WasmExecutionMethod, Externalities};
|
||||
use sc_executor::{Externalities, NativeExecutor, RuntimeInfo, WasmExecutionMethod};
|
||||
use sp_core::{
|
||||
storage::well_known_keys,
|
||||
traits::{CodeExecutor, RuntimeCode},
|
||||
NativeOrEncoded, NeverNativeValue,
|
||||
};
|
||||
use sp_runtime::traits::BlakeTwo256;
|
||||
use sp_state_machine::TestExternalities as CoreTestExternalities;
|
||||
|
||||
criterion_group!(benches, bench_execute_block);
|
||||
criterion_main!(benches);
|
||||
|
||||
/// The wasm runtime code.
|
||||
pub fn compact_code_unwrap() -> &'static [u8] {
|
||||
node_runtime::WASM_BINARY.expect("Development wasm binary is not available. \
|
||||
Testing is only supported with the flag disabled.")
|
||||
node_runtime::WASM_BINARY.expect(
|
||||
"Development wasm binary is not available. \
|
||||
Testing is only supported with the flag disabled.",
|
||||
)
|
||||
}
|
||||
|
||||
const GENESIS_HASH: [u8; 32] = [69u8; 32];
|
||||
@@ -66,7 +70,9 @@ fn new_test_ext(genesis_config: &GenesisConfig) -> TestExternalities<BlakeTwo256
|
||||
compact_code_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
|
||||
}
|
||||
|
||||
@@ -77,16 +83,16 @@ fn construct_block<E: Externalities>(
|
||||
parent_hash: Hash,
|
||||
extrinsics: Vec<CheckedExtrinsic>,
|
||||
) -> (Vec<u8>, Hash) {
|
||||
use sp_trie::{TrieConfiguration, trie_types::Layout};
|
||||
use sp_trie::{trie_types::Layout, TrieConfiguration};
|
||||
|
||||
// sign extrinsics.
|
||||
let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>();
|
||||
|
||||
// calculate the header fields that we can.
|
||||
let extrinsics_root = Layout::<BlakeTwo256>::ordered_trie_root(
|
||||
extrinsics.iter().map(Encode::encode)
|
||||
).to_fixed_bytes()
|
||||
.into();
|
||||
let extrinsics_root =
|
||||
Layout::<BlakeTwo256>::ordered_trie_root(extrinsics.iter().map(Encode::encode))
|
||||
.to_fixed_bytes()
|
||||
.into();
|
||||
|
||||
let header = Header {
|
||||
parent_hash,
|
||||
@@ -103,34 +109,44 @@ fn construct_block<E: Externalities>(
|
||||
};
|
||||
|
||||
// execute the block to get the real header.
|
||||
executor.call::<NeverNativeValue, fn() -> _>(
|
||||
ext,
|
||||
&runtime_code,
|
||||
"Core_initialize_block",
|
||||
&header.encode(),
|
||||
true,
|
||||
None,
|
||||
).0.unwrap();
|
||||
|
||||
for i in extrinsics.iter() {
|
||||
executor.call::<NeverNativeValue, fn() -> _>(
|
||||
executor
|
||||
.call::<NeverNativeValue, fn() -> _>(
|
||||
ext,
|
||||
&runtime_code,
|
||||
"BlockBuilder_apply_extrinsic",
|
||||
&i.encode(),
|
||||
"Core_initialize_block",
|
||||
&header.encode(),
|
||||
true,
|
||||
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() -> _>(
|
||||
ext,
|
||||
&runtime_code,
|
||||
"BlockBuilder_finalize_block",
|
||||
&[0u8;0],
|
||||
true,
|
||||
None,
|
||||
).0.unwrap() {
|
||||
let header = match executor
|
||||
.call::<NeverNativeValue, fn() -> _>(
|
||||
ext,
|
||||
&runtime_code,
|
||||
"BlockBuilder_finalize_block",
|
||||
&[0u8; 0],
|
||||
true,
|
||||
None,
|
||||
)
|
||||
.0
|
||||
.unwrap()
|
||||
{
|
||||
NativeOrEncoded::Native(_) => unreachable!(),
|
||||
NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(),
|
||||
};
|
||||
@@ -139,29 +155,21 @@ fn construct_block<E: Externalities>(
|
||||
(Block { header, extrinsics }.encode(), hash.into())
|
||||
}
|
||||
|
||||
fn test_blocks(genesis_config: &GenesisConfig, executor: &NativeExecutor<Executor>)
|
||||
-> Vec<(Vec<u8>, Hash)>
|
||||
{
|
||||
fn test_blocks(
|
||||
genesis_config: &GenesisConfig,
|
||||
executor: &NativeExecutor<Executor>,
|
||||
) -> Vec<(Vec<u8>, Hash)> {
|
||||
let mut test_ext = new_test_ext(genesis_config);
|
||||
let mut block1_extrinsics = vec![
|
||||
CheckedExtrinsic {
|
||||
signed: None,
|
||||
function: Call::Timestamp(pallet_timestamp::Call::set(0)),
|
||||
},
|
||||
];
|
||||
block1_extrinsics.extend((0..20).map(|i| {
|
||||
CheckedExtrinsic {
|
||||
signed: Some((alice(), signed_extra(i, 0))),
|
||||
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 1 * DOLLARS)),
|
||||
}
|
||||
let mut block1_extrinsics = vec![CheckedExtrinsic {
|
||||
signed: None,
|
||||
function: Call::Timestamp(pallet_timestamp::Call::set(0)),
|
||||
}];
|
||||
block1_extrinsics.extend((0..20).map(|i| CheckedExtrinsic {
|
||||
signed: Some((alice(), signed_extra(i, 0))),
|
||||
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 1 * DOLLARS)),
|
||||
}));
|
||||
let block1 = construct_block(
|
||||
executor,
|
||||
&mut test_ext.ext(),
|
||||
1,
|
||||
GENESIS_HASH.into(),
|
||||
block1_extrinsics,
|
||||
);
|
||||
let block1 =
|
||||
construct_block(executor, &mut test_ext.ext(), 1, GENESIS_HASH.into(), block1_extrinsics);
|
||||
|
||||
vec![block1]
|
||||
}
|
||||
@@ -176,47 +184,47 @@ fn bench_execute_block(c: &mut Criterion) {
|
||||
];
|
||||
|
||||
for strategy in execution_methods {
|
||||
group.bench_function(
|
||||
format!("{:?}", strategy),
|
||||
|b| {
|
||||
let genesis_config = node_testing::genesis::config(false, Some(compact_code_unwrap()));
|
||||
let (use_native, wasm_method) = match strategy {
|
||||
ExecutionMethod::Native => (true, WasmExecutionMethod::Interpreted),
|
||||
ExecutionMethod::Wasm(wasm_method) => (false, wasm_method),
|
||||
};
|
||||
group.bench_function(format!("{:?}", strategy), |b| {
|
||||
let genesis_config = node_testing::genesis::config(false, Some(compact_code_unwrap()));
|
||||
let (use_native, wasm_method) = match strategy {
|
||||
ExecutionMethod::Native => (true, WasmExecutionMethod::Interpreted),
|
||||
ExecutionMethod::Wasm(wasm_method) => (false, wasm_method),
|
||||
};
|
||||
|
||||
let executor = NativeExecutor::new(wasm_method, None, 8);
|
||||
let runtime_code = RuntimeCode {
|
||||
code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()),
|
||||
hash: vec![1, 2, 3],
|
||||
heap_pages: None,
|
||||
};
|
||||
let executor = NativeExecutor::new(wasm_method, None, 8);
|
||||
let runtime_code = RuntimeCode {
|
||||
code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()),
|
||||
hash: vec![1, 2, 3],
|
||||
heap_pages: None,
|
||||
};
|
||||
|
||||
// Get the runtime version to initialize the runtimes cache.
|
||||
{
|
||||
let mut test_ext = new_test_ext(&genesis_config);
|
||||
executor.runtime_version(&mut test_ext.ext(), &runtime_code).unwrap();
|
||||
}
|
||||
// Get the runtime version to initialize the runtimes cache.
|
||||
{
|
||||
let mut test_ext = new_test_ext(&genesis_config);
|
||||
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(
|
||||
|| new_test_ext(&genesis_config),
|
||||
|test_ext| {
|
||||
for block in blocks.iter() {
|
||||
executor.call::<NeverNativeValue, fn() -> _>(
|
||||
b.iter_batched_ref(
|
||||
|| new_test_ext(&genesis_config),
|
||||
|test_ext| {
|
||||
for block in blocks.iter() {
|
||||
executor
|
||||
.call::<NeverNativeValue, fn() -> _>(
|
||||
&mut test_ext.ext(),
|
||||
&runtime_code,
|
||||
"Core_execute_block",
|
||||
&block.0,
|
||||
use_native,
|
||||
None,
|
||||
).0.unwrap();
|
||||
}
|
||||
},
|
||||
BatchSize::LargeInput,
|
||||
);
|
||||
},
|
||||
);
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
}
|
||||
},
|
||||
BatchSize::LargeInput,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
//! A `CodeExecutor` specialization which uses natively compiled runtime when the wasm to be
|
||||
//! executed is equivalent to the natively compiled code.
|
||||
|
||||
pub use sc_executor::NativeExecutor;
|
||||
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
|
||||
// equivalent wasm code.
|
||||
|
||||
@@ -15,30 +15,28 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use codec::{Encode, Decode, Joiner};
|
||||
use codec::{Decode, Encode, Joiner};
|
||||
use frame_support::{
|
||||
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::{
|
||||
ApplyExtrinsicResult,
|
||||
traits::Hash as HashT,
|
||||
transaction_validity::InvalidTransaction,
|
||||
traits::Hash as HashT, transaction_validity::InvalidTransaction, ApplyExtrinsicResult,
|
||||
};
|
||||
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 wat;
|
||||
use node_runtime::{
|
||||
constants::{currency::*, time::SLOT_DURATION},
|
||||
Balances, Block, Call, CheckedExtrinsic, Event, Header, Runtime, System, TransactionPayment,
|
||||
UncheckedExtrinsic,
|
||||
};
|
||||
use node_testing::keyring::*;
|
||||
use wat;
|
||||
|
||||
pub mod common;
|
||||
use self::common::{*, sign};
|
||||
use self::common::{sign, *};
|
||||
|
||||
/// 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
|
||||
/// test code paths that differ between native and wasm versions.
|
||||
pub fn bloaty_code_unwrap() -> &'static [u8] {
|
||||
node_runtime::WASM_BINARY_BLOATY.expect("Development wasm binary is not available. \
|
||||
Testing is only supported with the flag disabled.")
|
||||
node_runtime::WASM_BINARY_BLOATY.expect(
|
||||
"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.
|
||||
@@ -87,7 +87,10 @@ fn changes_trie_block() -> (Vec<u8>, Hash) {
|
||||
},
|
||||
CheckedExtrinsic {
|
||||
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(),
|
||||
@@ -111,7 +114,10 @@ fn blocks() -> ((Vec<u8>, Hash), (Vec<u8>, Hash)) {
|
||||
},
|
||||
CheckedExtrinsic {
|
||||
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(),
|
||||
@@ -128,12 +134,18 @@ fn blocks() -> ((Vec<u8>, Hash), (Vec<u8>, Hash)) {
|
||||
},
|
||||
CheckedExtrinsic {
|
||||
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 {
|
||||
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(),
|
||||
);
|
||||
@@ -158,7 +170,7 @@ fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec<u8>, Hash) {
|
||||
CheckedExtrinsic {
|
||||
signed: Some((alice(), signed_extra(nonce, 0))),
|
||||
function: Call::System(frame_system::Call::remark(vec![0; size])),
|
||||
}
|
||||
},
|
||||
],
|
||||
(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);
|
||||
t.insert(
|
||||
<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(<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)),
|
||||
true,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
assert!(r.is_ok());
|
||||
let v = executor_call::<NeverNativeValue, fn() -> _>(
|
||||
&mut t,
|
||||
@@ -188,7 +201,9 @@ fn panic_execution_with_foreign_code_gives_error() {
|
||||
&vec![].and(&xt()),
|
||||
true,
|
||||
None,
|
||||
).0.unwrap();
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap();
|
||||
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);
|
||||
t.insert(
|
||||
<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(<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)),
|
||||
true,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
assert!(r.is_ok());
|
||||
let v = executor_call::<NeverNativeValue, fn() -> _>(
|
||||
&mut t,
|
||||
@@ -217,7 +233,9 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() {
|
||||
&vec![].and(&xt()),
|
||||
true,
|
||||
None,
|
||||
).0.unwrap();
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap();
|
||||
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()),
|
||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||
data: (111 * DOLLARS, 0u128, 0u128, 0u128),
|
||||
.. Default::default()
|
||||
}.encode(),
|
||||
..Default::default()
|
||||
}
|
||||
.encode(),
|
||||
);
|
||||
t.insert(
|
||||
<frame_system::Account<Runtime>>::hashed_key_for(bob()),
|
||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
|
||||
.. Default::default()
|
||||
}.encode(),
|
||||
..Default::default()
|
||||
}
|
||||
.encode(),
|
||||
);
|
||||
t.insert(
|
||||
<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]);
|
||||
|
||||
@@ -251,7 +271,8 @@ fn successful_execution_with_native_equivalent_code_gives_ok() {
|
||||
&vec![].and(&from_block_number(1u32)),
|
||||
true,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
assert!(r.is_ok());
|
||||
|
||||
let fees = t.execute_with(|| transfer_fee(&xt()));
|
||||
@@ -262,7 +283,8 @@ fn successful_execution_with_native_equivalent_code_gives_ok() {
|
||||
&vec![].and(&xt()),
|
||||
true,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
assert!(r.is_ok());
|
||||
|
||||
t.execute_with(|| {
|
||||
@@ -278,19 +300,21 @@ fn successful_execution_with_foreign_code_gives_ok() {
|
||||
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||
data: (111 * DOLLARS, 0u128, 0u128, 0u128),
|
||||
.. Default::default()
|
||||
}.encode(),
|
||||
..Default::default()
|
||||
}
|
||||
.encode(),
|
||||
);
|
||||
t.insert(
|
||||
<frame_system::Account<Runtime>>::hashed_key_for(bob()),
|
||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
|
||||
.. Default::default()
|
||||
}.encode(),
|
||||
..Default::default()
|
||||
}
|
||||
.encode(),
|
||||
);
|
||||
t.insert(
|
||||
<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]);
|
||||
|
||||
@@ -300,7 +324,8 @@ fn successful_execution_with_foreign_code_gives_ok() {
|
||||
&vec![].and(&from_block_number(1u32)),
|
||||
true,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
assert!(r.is_ok());
|
||||
|
||||
let fees = t.execute_with(|| transfer_fee(&xt()));
|
||||
@@ -311,7 +336,8 @@ fn successful_execution_with_foreign_code_gives_ok() {
|
||||
&vec![].and(&xt()),
|
||||
true,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
assert!(r.is_ok());
|
||||
|
||||
t.execute_with(|| {
|
||||
@@ -330,7 +356,9 @@ fn full_native_block_import_works() {
|
||||
let mut fees = t.execute_with(|| transfer_fee(&xt()));
|
||||
|
||||
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() -> _>(
|
||||
&mut t,
|
||||
@@ -338,7 +366,9 @@ fn full_native_block_import_works() {
|
||||
&block1.0,
|
||||
true,
|
||||
None,
|
||||
).0.unwrap();
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
|
||||
t.execute_with(|| {
|
||||
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
|
||||
@@ -347,9 +377,11 @@ fn full_native_block_import_works() {
|
||||
let events = vec![
|
||||
EventRecord {
|
||||
phase: Phase::ApplyExtrinsic(0),
|
||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(
|
||||
DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, ..Default::default() }
|
||||
)),
|
||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
|
||||
weight: timestamp_weight,
|
||||
class: DispatchClass::Mandatory,
|
||||
..Default::default()
|
||||
})),
|
||||
topics: vec![],
|
||||
},
|
||||
EventRecord {
|
||||
@@ -368,9 +400,10 @@ fn full_native_block_import_works() {
|
||||
},
|
||||
EventRecord {
|
||||
phase: Phase::ApplyExtrinsic(1),
|
||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(
|
||||
DispatchInfo { weight: transfer_weight, ..Default::default() }
|
||||
)),
|
||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
|
||||
weight: transfer_weight,
|
||||
..Default::default()
|
||||
})),
|
||||
topics: vec![],
|
||||
},
|
||||
];
|
||||
@@ -385,34 +418,33 @@ fn full_native_block_import_works() {
|
||||
&block2.0,
|
||||
true,
|
||||
None,
|
||||
).0.unwrap();
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
|
||||
t.execute_with(|| {
|
||||
assert_eq!(
|
||||
Balances::total_balance(&alice()),
|
||||
alice_last_known_balance - 10 * DOLLARS - fees,
|
||||
);
|
||||
assert_eq!(
|
||||
Balances::total_balance(&bob()),
|
||||
179 * DOLLARS - fees,
|
||||
);
|
||||
assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - fees,);
|
||||
let events = vec![
|
||||
EventRecord {
|
||||
phase: Phase::ApplyExtrinsic(0),
|
||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(
|
||||
DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, ..Default::default() }
|
||||
)),
|
||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
|
||||
weight: timestamp_weight,
|
||||
class: DispatchClass::Mandatory,
|
||||
..Default::default()
|
||||
})),
|
||||
topics: vec![],
|
||||
},
|
||||
EventRecord {
|
||||
phase: Phase::ApplyExtrinsic(1),
|
||||
event: Event::Balances(
|
||||
pallet_balances::Event::Transfer(
|
||||
bob().into(),
|
||||
alice().into(),
|
||||
5 * DOLLARS,
|
||||
)
|
||||
),
|
||||
event: Event::Balances(pallet_balances::Event::Transfer(
|
||||
bob().into(),
|
||||
alice().into(),
|
||||
5 * DOLLARS,
|
||||
)),
|
||||
topics: vec![],
|
||||
},
|
||||
EventRecord {
|
||||
@@ -422,20 +454,19 @@ fn full_native_block_import_works() {
|
||||
},
|
||||
EventRecord {
|
||||
phase: Phase::ApplyExtrinsic(1),
|
||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(
|
||||
DispatchInfo { weight: transfer_weight, ..Default::default() }
|
||||
)),
|
||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
|
||||
weight: transfer_weight,
|
||||
..Default::default()
|
||||
})),
|
||||
topics: vec![],
|
||||
},
|
||||
EventRecord {
|
||||
phase: Phase::ApplyExtrinsic(2),
|
||||
event: Event::Balances(
|
||||
pallet_balances::Event::Transfer(
|
||||
alice().into(),
|
||||
bob().into(),
|
||||
15 * DOLLARS,
|
||||
)
|
||||
),
|
||||
event: Event::Balances(pallet_balances::Event::Transfer(
|
||||
alice().into(),
|
||||
bob().into(),
|
||||
15 * DOLLARS,
|
||||
)),
|
||||
topics: vec![],
|
||||
},
|
||||
EventRecord {
|
||||
@@ -445,9 +476,10 @@ fn full_native_block_import_works() {
|
||||
},
|
||||
EventRecord {
|
||||
phase: Phase::ApplyExtrinsic(2),
|
||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(
|
||||
DispatchInfo { weight: transfer_weight, ..Default::default() }
|
||||
)),
|
||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
|
||||
weight: transfer_weight,
|
||||
..Default::default()
|
||||
})),
|
||||
topics: vec![],
|
||||
},
|
||||
];
|
||||
@@ -470,7 +502,9 @@ fn full_wasm_block_import_works() {
|
||||
&block1.0,
|
||||
false,
|
||||
None,
|
||||
).0.unwrap();
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
|
||||
t.execute_with(|| {
|
||||
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
|
||||
@@ -486,17 +520,16 @@ fn full_wasm_block_import_works() {
|
||||
&block2.0,
|
||||
false,
|
||||
None,
|
||||
).0.unwrap();
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
|
||||
t.execute_with(|| {
|
||||
assert_eq!(
|
||||
Balances::total_balance(&alice()),
|
||||
alice_last_known_balance - 10 * DOLLARS - fees,
|
||||
);
|
||||
assert_eq!(
|
||||
Balances::total_balance(&bob()),
|
||||
179 * DOLLARS - 1 * fees,
|
||||
);
|
||||
assert_eq!(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_ch = <Runtime as frame_system::Config>::Hashing::hash(&transfer_code);
|
||||
|
||||
let addr = pallet_contracts::Pallet::<Runtime>::contract_address(
|
||||
&charlie(),
|
||||
&transfer_ch,
|
||||
&[],
|
||||
);
|
||||
let addr = pallet_contracts::Pallet::<Runtime>::contract_address(&charlie(), &transfer_ch, &[]);
|
||||
|
||||
let subsistence = pallet_contracts::Pallet::<Runtime>::subsistence_threshold();
|
||||
|
||||
@@ -627,19 +656,17 @@ fn deploying_wasm_contract_should_work() {
|
||||
transfer_code,
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
)
|
||||
),
|
||||
),
|
||||
},
|
||||
CheckedExtrinsic {
|
||||
signed: Some((charlie(), signed_extra(1, 0))),
|
||||
function: Call::Contracts(
|
||||
pallet_contracts::Call::call::<Runtime>(
|
||||
sp_runtime::MultiAddress::Id(addr.clone()),
|
||||
10,
|
||||
500_000_000,
|
||||
vec![0x00, 0x01, 0x02, 0x03]
|
||||
)
|
||||
),
|
||||
function: Call::Contracts(pallet_contracts::Call::call::<Runtime>(
|
||||
sp_runtime::MultiAddress::Id(addr.clone()),
|
||||
10,
|
||||
500_000_000,
|
||||
vec![0x00, 0x01, 0x02, 0x03],
|
||||
)),
|
||||
},
|
||||
],
|
||||
(time / SLOT_DURATION).into(),
|
||||
@@ -647,20 +674,14 @@ fn deploying_wasm_contract_should_work() {
|
||||
|
||||
let mut t = new_test_ext(compact_code_unwrap(), false);
|
||||
|
||||
executor_call::<NeverNativeValue, fn() -> _>(
|
||||
&mut t,
|
||||
"Core_execute_block",
|
||||
&b.0,
|
||||
false,
|
||||
None,
|
||||
).0.unwrap();
|
||||
executor_call::<NeverNativeValue, fn() -> _>(&mut t, "Core_execute_block", &b.0, false, None)
|
||||
.0
|
||||
.unwrap();
|
||||
|
||||
t.execute_with(|| {
|
||||
// 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.
|
||||
assert!(
|
||||
&pallet_contracts::Pallet::<Runtime>::get_storage(addr, Default::default()).is_ok()
|
||||
);
|
||||
assert!(&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,
|
||||
false,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
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,
|
||||
true,
|
||||
None,
|
||||
).0.unwrap();
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[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.
|
||||
set_heap_pages(&mut t.ext(), 8);
|
||||
|
||||
assert!(
|
||||
executor_call::<NeverNativeValue, fn() -> _>(
|
||||
&mut t,
|
||||
"Core_execute_block",
|
||||
&block_with_size(42, 0, 120_000).0,
|
||||
false,
|
||||
None,
|
||||
).0.is_err()
|
||||
);
|
||||
assert!(executor_call::<NeverNativeValue, fn() -> _>(
|
||||
&mut t,
|
||||
"Core_execute_block",
|
||||
&block_with_size(42, 0, 120_000).0,
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.0
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -718,8 +742,9 @@ fn panic_execution_gives_error() {
|
||||
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
|
||||
.. Default::default()
|
||||
}.encode(),
|
||||
..Default::default()
|
||||
}
|
||||
.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]);
|
||||
@@ -730,7 +755,8 @@ fn panic_execution_gives_error() {
|
||||
&vec![].and(&from_block_number(1u32)),
|
||||
false,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
assert!(r.is_ok());
|
||||
let r = executor_call::<NeverNativeValue, fn() -> _>(
|
||||
&mut t,
|
||||
@@ -738,7 +764,10 @@ fn panic_execution_gives_error() {
|
||||
&vec![].and(&xt()),
|
||||
false,
|
||||
None,
|
||||
).0.unwrap().into_encoded();
|
||||
)
|
||||
.0
|
||||
.unwrap()
|
||||
.into_encoded();
|
||||
let r = ApplyExtrinsicResult::decode(&mut &r[..]).unwrap();
|
||||
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
|
||||
}
|
||||
@@ -750,19 +779,21 @@ fn successful_execution_gives_ok() {
|
||||
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||
data: (111 * DOLLARS, 0u128, 0u128, 0u128),
|
||||
.. Default::default()
|
||||
}.encode(),
|
||||
..Default::default()
|
||||
}
|
||||
.encode(),
|
||||
);
|
||||
t.insert(
|
||||
<frame_system::Account<Runtime>>::hashed_key_for(bob()),
|
||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
|
||||
.. Default::default()
|
||||
}.encode(),
|
||||
..Default::default()
|
||||
}
|
||||
.encode(),
|
||||
);
|
||||
t.insert(
|
||||
<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]);
|
||||
|
||||
@@ -772,7 +803,8 @@ fn successful_execution_gives_ok() {
|
||||
&vec![].and(&from_block_number(1u32)),
|
||||
false,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
assert!(r.is_ok());
|
||||
t.execute_with(|| {
|
||||
assert_eq!(Balances::total_balance(&alice()), 111 * DOLLARS);
|
||||
@@ -786,7 +818,10 @@ fn successful_execution_gives_ok() {
|
||||
&vec![].and(&xt()),
|
||||
false,
|
||||
None,
|
||||
).0.unwrap().into_encoded();
|
||||
)
|
||||
.0
|
||||
.unwrap()
|
||||
.into_encoded();
|
||||
ApplyExtrinsicResult::decode(&mut &r[..])
|
||||
.unwrap()
|
||||
.expect("Extrinsic could not be applied")
|
||||
@@ -811,7 +846,9 @@ fn full_native_block_import_works_with_changes_trie() {
|
||||
&block.encode(),
|
||||
true,
|
||||
None,
|
||||
).0.unwrap();
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
|
||||
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,
|
||||
false,
|
||||
None,
|
||||
).0.unwrap();
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
|
||||
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]
|
||||
fn should_import_block_with_test_client() {
|
||||
use node_testing::client::{
|
||||
ClientBlockImportExt, TestClientBuilderExt, TestClientBuilder,
|
||||
sp_consensus::BlockOrigin,
|
||||
sp_consensus::BlockOrigin, ClientBlockImportExt, TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
|
||||
let mut client = TestClientBuilder::new().build();
|
||||
|
||||
@@ -15,34 +15,32 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
use frame_system::offchain::AppCrypto;
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::Hashable;
|
||||
use sp_state_machine::TestExternalities as CoreTestExternalities;
|
||||
use sp_consensus_babe::{BABE_ENGINE_ID, Slot, digests::{PreDigest, SecondaryPlainPreDigest}};
|
||||
use frame_system::offchain::AppCrypto;
|
||||
use sc_executor::{error::Result, NativeExecutor, WasmExecutionMethod};
|
||||
use sp_consensus_babe::{
|
||||
digests::{PreDigest, SecondaryPlainPreDigest},
|
||||
Slot, BABE_ENGINE_ID,
|
||||
};
|
||||
use sp_core::{
|
||||
NeverNativeValue, NativeOrEncoded,
|
||||
crypto::KeyTypeId,
|
||||
sr25519::Signature,
|
||||
traits::{CodeExecutor, RuntimeCode},
|
||||
NativeOrEncoded, NeverNativeValue,
|
||||
};
|
||||
use sp_runtime::{
|
||||
ApplyExtrinsicResult,
|
||||
MultiSigner,
|
||||
MultiSignature,
|
||||
Digest,
|
||||
DigestItem,
|
||||
traits::{Header as HeaderT, BlakeTwo256},
|
||||
traits::{BlakeTwo256, Header as HeaderT},
|
||||
ApplyExtrinsicResult, Digest, DigestItem, MultiSignature, MultiSigner,
|
||||
};
|
||||
use sc_executor::{NativeExecutor, WasmExecutionMethod};
|
||||
use sc_executor::error::Result;
|
||||
use sp_state_machine::TestExternalities as CoreTestExternalities;
|
||||
|
||||
use node_executor::Executor;
|
||||
use node_primitives::{BlockNumber, Hash};
|
||||
use node_runtime::{
|
||||
Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Runtime, BuildStorage,
|
||||
constants::currency::*,
|
||||
constants::currency::*, Block, BuildStorage, CheckedExtrinsic, Header, Runtime,
|
||||
UncheckedExtrinsic,
|
||||
};
|
||||
use node_primitives::{Hash, BlockNumber};
|
||||
use node_testing::keyring::*;
|
||||
use sp_externalities::Externalities;
|
||||
|
||||
@@ -50,8 +48,8 @@ pub const TEST_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"test");
|
||||
|
||||
pub mod sr25519 {
|
||||
mod app_sr25519 {
|
||||
use sp_application_crypto::{app_crypto, sr25519};
|
||||
use super::super::TEST_KEY_TYPE_ID;
|
||||
use sp_application_crypto::{app_crypto, sr25519};
|
||||
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
|
||||
/// runtime.
|
||||
pub fn compact_code_unwrap() -> &'static [u8] {
|
||||
node_runtime::WASM_BINARY.expect("Development wasm binary is not available. \
|
||||
Testing is only supported with the flag disabled.")
|
||||
node_runtime::WASM_BINARY.expect(
|
||||
"Development wasm binary is not available. \
|
||||
Testing is only supported with the flag disabled.",
|
||||
)
|
||||
}
|
||||
|
||||
pub const GENESIS_HASH: [u8; 32] = [69u8; 32];
|
||||
@@ -101,8 +101,9 @@ pub fn executor() -> NativeExecutor<Executor> {
|
||||
}
|
||||
|
||||
pub fn executor_call<
|
||||
R:Decode + Encode + PartialEq,
|
||||
NC: FnOnce() -> std::result::Result<R, Box<dyn std::error::Error + Send + Sync>> + std::panic::UnwindSafe
|
||||
R: Decode + Encode + PartialEq,
|
||||
NC: FnOnce() -> std::result::Result<R, Box<dyn std::error::Error + Send + Sync>>
|
||||
+ std::panic::UnwindSafe,
|
||||
>(
|
||||
t: &mut TestExternalities<BlakeTwo256>,
|
||||
method: &str,
|
||||
@@ -120,20 +121,15 @@ pub fn executor_call<
|
||||
heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()),
|
||||
};
|
||||
|
||||
executor().call::<R, NC>(
|
||||
&mut t,
|
||||
&runtime_code,
|
||||
method,
|
||||
data,
|
||||
use_native,
|
||||
native_call,
|
||||
)
|
||||
executor().call::<R, NC>(&mut t, &runtime_code, method, data, use_native, native_call)
|
||||
}
|
||||
|
||||
pub fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities<BlakeTwo256> {
|
||||
let mut ext = TestExternalities::new_with_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
|
||||
@@ -150,7 +146,7 @@ pub fn construct_block(
|
||||
extrinsics: Vec<CheckedExtrinsic>,
|
||||
babe_slot: Slot,
|
||||
) -> (Vec<u8>, Hash) {
|
||||
use sp_trie::{TrieConfiguration, trie_types::Layout};
|
||||
use sp_trie::{trie_types::Layout, TrieConfiguration};
|
||||
|
||||
// sign extrinsics.
|
||||
let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>();
|
||||
@@ -167,15 +163,14 @@ pub fn construct_block(
|
||||
extrinsics_root,
|
||||
state_root: Default::default(),
|
||||
digest: Digest {
|
||||
logs: vec![
|
||||
DigestItem::PreRuntime(
|
||||
BABE_ENGINE_ID,
|
||||
PreDigest::SecondaryPlain(SecondaryPlainPreDigest {
|
||||
slot: babe_slot,
|
||||
authority_index: 42,
|
||||
}).encode()
|
||||
),
|
||||
],
|
||||
logs: vec![DigestItem::PreRuntime(
|
||||
BABE_ENGINE_ID,
|
||||
PreDigest::SecondaryPlain(SecondaryPlainPreDigest {
|
||||
slot: babe_slot,
|
||||
authority_index: 42,
|
||||
})
|
||||
.encode(),
|
||||
)],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -186,7 +181,9 @@ pub fn construct_block(
|
||||
&header.encode(),
|
||||
true,
|
||||
None,
|
||||
).0.unwrap();
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
|
||||
for extrinsic in extrinsics.iter() {
|
||||
// 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(),
|
||||
true,
|
||||
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(_) => {},
|
||||
Err(e) => panic!("Applying extrinsic failed: {:?}", e),
|
||||
}
|
||||
@@ -207,10 +209,13 @@ pub fn construct_block(
|
||||
let header = match executor_call::<NeverNativeValue, fn() -> _>(
|
||||
env,
|
||||
"BlockBuilder_finalize_block",
|
||||
&[0u8;0],
|
||||
&[0u8; 0],
|
||||
true,
|
||||
None,
|
||||
).0.unwrap() {
|
||||
)
|
||||
.0
|
||||
.unwrap()
|
||||
{
|
||||
NativeOrEncoded::Native(_) => unreachable!(),
|
||||
NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(),
|
||||
};
|
||||
|
||||
@@ -18,20 +18,21 @@
|
||||
use codec::{Encode, Joiner};
|
||||
use frame_support::{
|
||||
traits::Currency,
|
||||
weights::{GetDispatchInfo, constants::ExtrinsicBaseWeight, 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::*},
|
||||
weights::{
|
||||
constants::ExtrinsicBaseWeight, GetDispatchInfo, IdentityFee, WeightToFeePolynomial,
|
||||
},
|
||||
};
|
||||
use node_primitives::Balance;
|
||||
use node_runtime::{
|
||||
constants::{currency::*, time::SLOT_DURATION},
|
||||
Balances, Call, CheckedExtrinsic, Multiplier, Runtime, TransactionByteFee, TransactionPayment,
|
||||
};
|
||||
use node_testing::keyring::*;
|
||||
use sp_core::NeverNativeValue;
|
||||
use sp_runtime::{traits::One, Perbill};
|
||||
|
||||
pub mod common;
|
||||
use self::common::{*, sign};
|
||||
use self::common::{sign, *};
|
||||
|
||||
#[test]
|
||||
fn fee_multiplier_increases_and_decreases_on_big_weight() {
|
||||
@@ -60,7 +61,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
|
||||
CheckedExtrinsic {
|
||||
signed: Some((charlie(), signed_extra(0, 0))),
|
||||
function: Call::System(frame_system::Call::fill_block(Perbill::from_percent(60))),
|
||||
}
|
||||
},
|
||||
],
|
||||
(time1 / SLOT_DURATION).into(),
|
||||
);
|
||||
@@ -79,7 +80,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
|
||||
CheckedExtrinsic {
|
||||
signed: Some((charlie(), signed_extra(1, 0))),
|
||||
function: Call::System(frame_system::Call::remark(vec![0; 1])),
|
||||
}
|
||||
},
|
||||
],
|
||||
(time2 / SLOT_DURATION).into(),
|
||||
);
|
||||
@@ -97,7 +98,9 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
|
||||
&block1.0,
|
||||
true,
|
||||
None,
|
||||
).0.unwrap();
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
|
||||
// weight multiplier is increased for next block.
|
||||
t.execute_with(|| {
|
||||
@@ -114,7 +117,9 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
|
||||
&block2.0,
|
||||
true,
|
||||
None,
|
||||
).0.unwrap();
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
|
||||
// weight multiplier is increased for next block.
|
||||
t.execute_with(|| {
|
||||
@@ -131,7 +136,8 @@ fn new_account_info(free_dollars: u128) -> Vec<u8> {
|
||||
providers: 0,
|
||||
sufficients: 0,
|
||||
data: (free_dollars * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS),
|
||||
}.encode()
|
||||
}
|
||||
.encode()
|
||||
}
|
||||
|
||||
#[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(
|
||||
<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]);
|
||||
|
||||
@@ -164,7 +170,8 @@ fn transaction_fee_is_correct() {
|
||||
&vec![].and(&from_block_number(1u32)),
|
||||
true,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
|
||||
assert!(r.is_ok());
|
||||
let r = executor_call::<NeverNativeValue, fn() -> _>(
|
||||
@@ -173,7 +180,8 @@ fn transaction_fee_is_correct() {
|
||||
&vec![].and(&xt.clone()),
|
||||
true,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
assert!(r.is_ok());
|
||||
|
||||
t.execute_with(|| {
|
||||
@@ -228,15 +236,20 @@ fn block_weight_capacity_report() {
|
||||
|
||||
loop {
|
||||
let num_transfers = block_number * factor;
|
||||
let mut xts = (0..num_transfers).map(|i| CheckedExtrinsic {
|
||||
signed: Some((charlie(), signed_extra(nonce + i as Index, 0))),
|
||||
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 0)),
|
||||
}).collect::<Vec<CheckedExtrinsic>>();
|
||||
let mut xts = (0..num_transfers)
|
||||
.map(|i| CheckedExtrinsic {
|
||||
signed: Some((charlie(), signed_extra(nonce + i as Index, 0))),
|
||||
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 0)),
|
||||
})
|
||||
.collect::<Vec<CheckedExtrinsic>>();
|
||||
|
||||
xts.insert(0, CheckedExtrinsic {
|
||||
signed: None,
|
||||
function: Call::Timestamp(pallet_timestamp::Call::set(time * 1000)),
|
||||
});
|
||||
xts.insert(
|
||||
0,
|
||||
CheckedExtrinsic {
|
||||
signed: None,
|
||||
function: Call::Timestamp(pallet_timestamp::Call::set(time * 1000)),
|
||||
},
|
||||
);
|
||||
|
||||
// NOTE: this is super slow. Can probably be improved.
|
||||
let block = construct_block(
|
||||
@@ -262,7 +275,8 @@ fn block_weight_capacity_report() {
|
||||
&block.0,
|
||||
true,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
|
||||
println!(" || Result = {:?}", r);
|
||||
assert!(r.is_ok());
|
||||
@@ -307,7 +321,11 @@ fn block_length_capacity_report() {
|
||||
},
|
||||
CheckedExtrinsic {
|
||||
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(),
|
||||
@@ -327,7 +345,8 @@ fn block_length_capacity_report() {
|
||||
&block.0,
|
||||
true,
|
||||
None,
|
||||
).0;
|
||||
)
|
||||
.0;
|
||||
|
||||
println!(" || Result = {:?}", r);
|
||||
assert!(r.is_ok());
|
||||
|
||||
@@ -15,26 +15,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// 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 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;
|
||||
use self::common::*;
|
||||
@@ -56,8 +43,10 @@ fn should_submit_unsigned_transaction() {
|
||||
};
|
||||
|
||||
let call = pallet_im_online::Call::heartbeat(heartbeat_data, signature);
|
||||
SubmitTransaction::<Runtime, pallet_im_online::Call<Runtime>>::submit_unsigned_transaction(call.into())
|
||||
.unwrap();
|
||||
SubmitTransaction::<Runtime, pallet_im_online::Call<Runtime>>::submit_unsigned_transaction(
|
||||
call.into(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(state.read().transactions.len(), 1)
|
||||
});
|
||||
@@ -75,23 +64,26 @@ fn should_submit_signed_transaction() {
|
||||
SyncCryptoStore::sr25519_generate_new(
|
||||
&keystore,
|
||||
sr25519::AuthorityId::ID,
|
||||
Some(&format!("{}/hunter1", PHRASE))
|
||||
).unwrap();
|
||||
Some(&format!("{}/hunter1", PHRASE)),
|
||||
)
|
||||
.unwrap();
|
||||
SyncCryptoStore::sr25519_generate_new(
|
||||
&keystore,
|
||||
sr25519::AuthorityId::ID,
|
||||
Some(&format!("{}/hunter2", PHRASE))
|
||||
).unwrap();
|
||||
Some(&format!("{}/hunter2", PHRASE)),
|
||||
)
|
||||
.unwrap();
|
||||
SyncCryptoStore::sr25519_generate_new(
|
||||
&keystore,
|
||||
sr25519::AuthorityId::ID,
|
||||
Some(&format!("{}/hunter3", PHRASE))
|
||||
).unwrap();
|
||||
Some(&format!("{}/hunter3", PHRASE)),
|
||||
)
|
||||
.unwrap();
|
||||
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
||||
|
||||
t.execute_with(|| {
|
||||
let results = Signer::<Runtime, TestAuthorityId>::all_accounts()
|
||||
.send_signed_transaction(|_| {
|
||||
let results =
|
||||
Signer::<Runtime, TestAuthorityId>::all_accounts().send_signed_transaction(|_| {
|
||||
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(
|
||||
&keystore,
|
||||
sr25519::AuthorityId::ID,
|
||||
Some(&format!("{}/hunter1", PHRASE))
|
||||
).unwrap();
|
||||
Some(&format!("{}/hunter1", PHRASE)),
|
||||
)
|
||||
.unwrap();
|
||||
SyncCryptoStore::sr25519_generate_new(
|
||||
&keystore,
|
||||
sr25519::AuthorityId::ID,
|
||||
Some(&format!("{}/hunter2", PHRASE))
|
||||
).unwrap();
|
||||
Some(&format!("{}/hunter2", PHRASE)),
|
||||
)
|
||||
.unwrap();
|
||||
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
||||
|
||||
t.execute_with(|| {
|
||||
let result = Signer::<Runtime, TestAuthorityId>::any_account()
|
||||
.send_signed_transaction(|_| {
|
||||
let result =
|
||||
Signer::<Runtime, TestAuthorityId>::any_account().send_signed_transaction(|_| {
|
||||
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);
|
||||
|
||||
// submit another one from the same account. The nonce should be incremented.
|
||||
let result = Signer::<Runtime, TestAuthorityId>::any_account()
|
||||
.send_signed_transaction(|_| {
|
||||
let result =
|
||||
Signer::<Runtime, TestAuthorityId>::any_account().send_signed_transaction(|_| {
|
||||
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 nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap());
|
||||
assert!(
|
||||
nonce1 != nonce2,
|
||||
"Transactions should have different nonces. Got: {:?}", nonce1
|
||||
);
|
||||
assert!(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));
|
||||
|
||||
let keystore = KeyStore::new();
|
||||
keystore.sr25519_generate_new(
|
||||
sr25519::AuthorityId::ID,
|
||||
Some(&format!("{}/hunter1", PHRASE))
|
||||
).unwrap();
|
||||
keystore.sr25519_generate_new(
|
||||
sr25519::AuthorityId::ID,
|
||||
Some(&format!("{}/hunter2", PHRASE))
|
||||
).unwrap();
|
||||
keystore
|
||||
.sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE)))
|
||||
.unwrap();
|
||||
keystore
|
||||
.sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter2", PHRASE)))
|
||||
.unwrap();
|
||||
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
||||
|
||||
t.execute_with(|| {
|
||||
@@ -217,8 +206,10 @@ fn should_submit_signed_twice_from_all_accounts() {
|
||||
#[test]
|
||||
fn submitted_transaction_should_be_valid() {
|
||||
use codec::Encode;
|
||||
use sp_runtime::transaction_validity::{TransactionSource, TransactionTag};
|
||||
use sp_runtime::traits::StaticLookup;
|
||||
use sp_runtime::{
|
||||
traits::StaticLookup,
|
||||
transaction_validity::{TransactionSource, TransactionTag},
|
||||
};
|
||||
|
||||
let mut t = new_test_ext(compact_code_unwrap(), false);
|
||||
let (pool, state) = TestTransactionPoolExt::new();
|
||||
@@ -227,13 +218,15 @@ fn submitted_transaction_should_be_valid() {
|
||||
let keystore = KeyStore::new();
|
||||
SyncCryptoStore::sr25519_generate_new(
|
||||
&keystore,
|
||||
sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE))
|
||||
).unwrap();
|
||||
sr25519::AuthorityId::ID,
|
||||
Some(&format!("{}/hunter1", PHRASE)),
|
||||
)
|
||||
.unwrap();
|
||||
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
||||
|
||||
t.execute_with(|| {
|
||||
let results = Signer::<Runtime, TestAuthorityId>::all_accounts()
|
||||
.send_signed_transaction(|_| {
|
||||
let results =
|
||||
Signer::<Runtime, TestAuthorityId>::all_accounts().send_signed_transaction(|_| {
|
||||
pallet_balances::Call::transfer(Default::default(), Default::default())
|
||||
});
|
||||
let len = results.len();
|
||||
@@ -252,7 +245,7 @@ fn submitted_transaction_should_be_valid() {
|
||||
let author = extrinsic.signature.clone().unwrap().0;
|
||||
let address = Indices::lookup(author).unwrap();
|
||||
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);
|
||||
|
||||
// check validity
|
||||
@@ -260,7 +253,8 @@ fn submitted_transaction_should_be_valid() {
|
||||
source,
|
||||
extrinsic,
|
||||
frame_system::BlockHash::<Runtime>::get(0),
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// We ignore res.priority since this number can change based on updates to weights and such.
|
||||
assert_eq!(res.requires, Vec::<TransactionTag>::new());
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
//! Structs to easily compose inspect sub-command for CLI.
|
||||
|
||||
use std::fmt::Debug;
|
||||
use sc_cli::{ImportParams, SharedParams};
|
||||
use std::fmt::Debug;
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// The `inspect` command used to print decoded chain data.
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
|
||||
//! Command ran by the CLI
|
||||
|
||||
use crate::cli::{InspectCmd, InspectSubCmd};
|
||||
use crate::Inspector;
|
||||
use crate::{
|
||||
cli::{InspectCmd, InspectSubCmd},
|
||||
Inspector,
|
||||
};
|
||||
use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams};
|
||||
use sc_service::{new_full_client, Configuration, NativeExecutionDispatch};
|
||||
use sp_runtime::traits::Block;
|
||||
@@ -43,13 +45,13 @@ impl InspectCmd {
|
||||
let res = inspect.block(input).map_err(|e| format!("{}", e))?;
|
||||
println!("{}", res);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
InspectSubCmd::Extrinsic { input } => {
|
||||
let input = input.parse()?;
|
||||
let res = inspect.extrinsic(input).map_err(|e| format!("{}", e))?;
|
||||
println!("{}", res);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,33 +27,27 @@
|
||||
pub mod cli;
|
||||
pub mod command;
|
||||
|
||||
use std::{
|
||||
fmt,
|
||||
fmt::Debug,
|
||||
marker::PhantomData,
|
||||
str::FromStr,
|
||||
};
|
||||
use codec::{Encode, Decode};
|
||||
use codec::{Decode, Encode};
|
||||
use sc_client_api::BlockBackend;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_core::hexdisplay::HexDisplay;
|
||||
use sp_runtime::{
|
||||
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.
|
||||
pub type BlockAddressFor<TBlock> = BlockAddress<
|
||||
<HashFor<TBlock> as Hash>::Output,
|
||||
NumberFor<TBlock>
|
||||
>;
|
||||
pub type BlockAddressFor<TBlock> =
|
||||
BlockAddress<<HashFor<TBlock> as Hash>::Output, NumberFor<TBlock>>;
|
||||
|
||||
/// A Pretty formatter implementation.
|
||||
pub trait PrettyPrinter<TBlock: Block> {
|
||||
/// Nicely format block.
|
||||
fn fmt_block(&self, fmt: &mut fmt::Formatter, block: &TBlock) -> fmt::Result;
|
||||
/// 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.
|
||||
@@ -72,7 +66,11 @@ impl<TBlock: Block> PrettyPrinter<TBlock> for DebugPrinter {
|
||||
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, " Bytes: {:?}", HexDisplay::from(&extrinsic.encode()))?;
|
||||
Ok(())
|
||||
@@ -101,15 +99,14 @@ impl std::error::Error for Error {
|
||||
}
|
||||
|
||||
/// A helper trait to access block headers and bodies.
|
||||
pub trait ChainAccess<TBlock: Block>:
|
||||
HeaderBackend<TBlock> +
|
||||
BlockBackend<TBlock>
|
||||
{}
|
||||
pub trait ChainAccess<TBlock: Block>: HeaderBackend<TBlock> + BlockBackend<TBlock> {}
|
||||
|
||||
impl<T, TBlock> ChainAccess<TBlock> for T where
|
||||
impl<T, TBlock> ChainAccess<TBlock> for T
|
||||
where
|
||||
TBlock: Block,
|
||||
T: sp_blockchain::HeaderBackend<TBlock> + sc_client_api::BlockBackend<TBlock>,
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
/// Blockchain inspector.
|
||||
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> {
|
||||
/// Create new instance of the inspector with default printer.
|
||||
pub fn new(
|
||||
chain: impl ChainAccess<TBlock> + 'static,
|
||||
) -> Self where TPrinter: Default {
|
||||
pub fn new(chain: impl ChainAccess<TBlock> + 'static) -> Self
|
||||
where
|
||||
TPrinter: Default,
|
||||
{
|
||||
Self::with_printer(chain, Default::default())
|
||||
}
|
||||
|
||||
/// Customize pretty-printing of the data.
|
||||
pub fn with_printer(
|
||||
chain: impl ChainAccess<TBlock> + 'static,
|
||||
printer: TPrinter,
|
||||
) -> Self {
|
||||
Inspector {
|
||||
chain: Box::new(chain) as _,
|
||||
printer,
|
||||
_block: Default::default(),
|
||||
}
|
||||
pub fn with_printer(chain: impl ChainAccess<TBlock> + 'static, printer: TPrinter) -> Self {
|
||||
Inspector { chain: Box::new(chain) as _, printer, _block: Default::default() }
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
Ok(match input {
|
||||
BlockAddress::Bytes(bytes) => {
|
||||
TBlock::decode(&mut &*bytes)?
|
||||
},
|
||||
BlockAddress::Bytes(bytes) => TBlock::decode(&mut &*bytes)?,
|
||||
BlockAddress::Number(number) => {
|
||||
let id = BlockId::number(number);
|
||||
let not_found = format!("Could not find block {:?}", id);
|
||||
let body = self.chain.block_body(&id)?
|
||||
.ok_or_else(|| Error::NotFound(not_found.clone()))?;
|
||||
let header = self.chain.header(id)?
|
||||
let body = self
|
||||
.chain
|
||||
.block_body(&id)?
|
||||
.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)
|
||||
},
|
||||
BlockAddress::Hash(hash) => {
|
||||
let id = BlockId::hash(hash);
|
||||
let not_found = format!("Could not find block {:?}", id);
|
||||
let body = self.chain.block_body(&id)?
|
||||
.ok_or_else(|| Error::NotFound(not_found.clone()))?;
|
||||
let header = self.chain.header(id)?
|
||||
let body = self
|
||||
.chain
|
||||
.block_body(&id)?
|
||||
.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)
|
||||
},
|
||||
})
|
||||
@@ -192,16 +185,14 @@ impl<TBlock: Block, TPrinter: PrettyPrinter<TBlock>> Inspector<TBlock, TPrinter>
|
||||
let ext = match input {
|
||||
ExtrinsicAddress::Block(block, index) => {
|
||||
let block = self.get_block(block)?;
|
||||
block.extrinsics()
|
||||
.get(index)
|
||||
.cloned()
|
||||
.ok_or_else(|| Error::NotFound(format!(
|
||||
"Could not find extrinsic {} in block {:?}", index, block
|
||||
)))?
|
||||
block.extrinsics().get(index).cloned().ok_or_else(|| {
|
||||
Error::NotFound(format!(
|
||||
"Could not find extrinsic {} in block {:?}",
|
||||
index, block
|
||||
))
|
||||
})?
|
||||
},
|
||||
ExtrinsicAddress::Bytes(bytes) => {
|
||||
TBlock::Extrinsic::decode(&mut &*bytes)?
|
||||
}
|
||||
ExtrinsicAddress::Bytes(bytes) => TBlock::Extrinsic::decode(&mut &*bytes)?,
|
||||
};
|
||||
|
||||
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)
|
||||
sp_core::bytes::from_hex(s)
|
||||
.map(Self::Bytes)
|
||||
.map_err(|e| format!(
|
||||
sp_core::bytes::from_hex(s).map(Self::Bytes).map_err(|e| {
|
||||
format!(
|
||||
"Given string does not look like hash or number. It could not be parsed as bytes either: {}",
|
||||
e
|
||||
))
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,11 +254,13 @@ impl<Hash: FromStr + Debug, Number: FromStr + Debug> FromStr for ExtrinsicAddres
|
||||
|
||||
// split by a bunch of different characters
|
||||
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")
|
||||
.parse()?;
|
||||
|
||||
let index = it.next()
|
||||
let index = it
|
||||
.next()
|
||||
.ok_or_else(|| format!("Extrinsic index missing: example \"5:0\""))?
|
||||
.parse()
|
||||
.map_err(|e| format!("Invalid index format: {}", e))?;
|
||||
@@ -290,10 +283,10 @@ mod tests {
|
||||
let b2 = BlockAddress::from_str("0");
|
||||
let b3 = BlockAddress::from_str("0x0012345f");
|
||||
|
||||
|
||||
assert_eq!(b0, Ok(BlockAddress::Hash(
|
||||
"3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()
|
||||
)));
|
||||
assert_eq!(
|
||||
b0,
|
||||
Ok(BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()))
|
||||
);
|
||||
assert_eq!(b1, Ok(BlockAddress::Number(1234)));
|
||||
assert_eq!(b2, Ok(BlockAddress::Number(0)));
|
||||
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 b3 = ExtrinsicAddress::from_str("0x0012345f");
|
||||
|
||||
|
||||
assert_eq!(e0, Err("Extrinsic index missing: example \"5:0\"".into()));
|
||||
assert_eq!(b0, Ok(ExtrinsicAddress::Block(
|
||||
BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()),
|
||||
5
|
||||
)));
|
||||
assert_eq!(b1, Ok(ExtrinsicAddress::Block(
|
||||
BlockAddress::Number(1234),
|
||||
0
|
||||
)));
|
||||
assert_eq!(b2, Ok(ExtrinsicAddress::Block(
|
||||
BlockAddress::Number(0),
|
||||
0
|
||||
)));
|
||||
assert_eq!(
|
||||
b0,
|
||||
Ok(ExtrinsicAddress::Block(
|
||||
BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()),
|
||||
5
|
||||
))
|
||||
);
|
||||
assert_eq!(b1, Ok(ExtrinsicAddress::Block(BlockAddress::Number(1234), 0)));
|
||||
assert_eq!(b2, Ok(ExtrinsicAddress::Block(BlockAddress::Number(0), 0)));
|
||||
assert_eq!(b3, Ok(ExtrinsicAddress::Bytes(vec![0, 0x12, 0x34, 0x5f])));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
//! Low-level types used throughout the Substrate code.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use sp_runtime::{
|
||||
generic, traits::{Verify, BlakeTwo256, IdentifyAccount}, OpaqueExtrinsic, MultiSignature
|
||||
generic,
|
||||
traits::{BlakeTwo256, IdentifyAccount, Verify},
|
||||
MultiSignature, OpaqueExtrinsic,
|
||||
};
|
||||
|
||||
/// An index to a block.
|
||||
|
||||
@@ -24,15 +24,9 @@
|
||||
|
||||
use futures::Future;
|
||||
use hyper::rt;
|
||||
use jsonrpc_core_client::{transports::http, RpcError};
|
||||
use node_primitives::Hash;
|
||||
use sc_rpc::author::{
|
||||
AuthorClient,
|
||||
hash::ExtrinsicOrHash,
|
||||
};
|
||||
use jsonrpc_core_client::{
|
||||
transports::http,
|
||||
RpcError,
|
||||
};
|
||||
use sc_rpc::author::{hash::ExtrinsicOrHash, AuthorClient};
|
||||
|
||||
fn main() {
|
||||
sp_tracing::try_init_simple();
|
||||
@@ -41,9 +35,7 @@ fn main() {
|
||||
let uri = "http://localhost:9933";
|
||||
|
||||
http::connect(uri)
|
||||
.and_then(|client: AuthorClient<Hash, Hash>| {
|
||||
remove_all_extrinsics(client)
|
||||
})
|
||||
.and_then(|client: AuthorClient<Hash, Hash>| remove_all_extrinsics(client))
|
||||
.map_err(|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
|
||||
/// 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> {
|
||||
client.pending_extrinsics()
|
||||
fn remove_all_extrinsics(
|
||||
client: AuthorClient<Hash, Hash>,
|
||||
) -> impl Future<Item = (), Error = RpcError> {
|
||||
client
|
||||
.pending_extrinsics()
|
||||
.and_then(move |pending| {
|
||||
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| {
|
||||
|
||||
@@ -32,24 +32,24 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use sp_keystore::SyncCryptoStorePtr;
|
||||
use node_primitives::{Block, BlockNumber, AccountId, Index, Balance, Hash};
|
||||
use node_primitives::{AccountId, Balance, Block, BlockNumber, Hash, Index};
|
||||
use sc_client_api::AuxStore;
|
||||
use sc_consensus_babe::{Config, Epoch};
|
||||
use sc_consensus_babe_rpc::BabeRpcHandler;
|
||||
use sc_consensus_epochs::SharedEpochChanges;
|
||||
use sc_finality_grandpa::{
|
||||
SharedVoterState, SharedAuthoritySet, FinalityProofProvider, GrandpaJustificationStream
|
||||
FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState,
|
||||
};
|
||||
use sc_finality_grandpa_rpc::GrandpaRpcHandler;
|
||||
use sc_rpc::SubscriptionTaskExecutor;
|
||||
pub use sc_rpc_api::DenyUnsafe;
|
||||
use sc_transaction_pool_api::TransactionPool;
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
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_babe::BabeApi;
|
||||
use sc_rpc::SubscriptionTaskExecutor;
|
||||
use sc_transaction_pool_api::TransactionPool;
|
||||
use sc_client_api::AuxStore;
|
||||
use sp_keystore::SyncCryptoStorePtr;
|
||||
|
||||
/// Light client extra dependencies.
|
||||
pub struct LightDeps<C, F, P> {
|
||||
@@ -111,9 +111,15 @@ pub type IoHandler = jsonrpc_core::IoHandler<sc_rpc::Metadata>;
|
||||
/// Instantiate all Full RPC extensions.
|
||||
pub fn create_full<C, P, SC, B>(
|
||||
deps: FullDeps<C, P, SC, B>,
|
||||
) -> jsonrpc_core::IoHandler<sc_rpc_api::Metadata> where
|
||||
C: ProvideRuntimeApi<Block> + HeaderBackend<Block> + AuxStore +
|
||||
HeaderMetadata<Block, Error=BlockChainError> + Sync + Send + 'static,
|
||||
) -> jsonrpc_core::IoHandler<sc_rpc_api::Metadata>
|
||||
where
|
||||
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: pallet_contracts_rpc::ContractsRuntimeApi<Block, AccountId, Balance, BlockNumber, 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: BlockBuilder<Block>,
|
||||
P: TransactionPool + 'static,
|
||||
SC: SelectChain<Block> +'static,
|
||||
SC: SelectChain<Block> + 'static,
|
||||
B: sc_client_api::Backend<Block> + Send + Sync + 'static,
|
||||
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_mmr_rpc::{MmrApi, Mmr};
|
||||
use pallet_mmr_rpc::{Mmr, MmrApi};
|
||||
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
|
||||
use substrate_frame_rpc_system::{FullSystem, SystemApi};
|
||||
|
||||
let mut io = jsonrpc_core::IoHandler::default();
|
||||
let FullDeps {
|
||||
client,
|
||||
pool,
|
||||
select_chain,
|
||||
chain_spec,
|
||||
deny_unsafe,
|
||||
babe,
|
||||
grandpa,
|
||||
} = deps;
|
||||
let FullDeps { client, pool, select_chain, chain_spec, deny_unsafe, babe, grandpa } = deps;
|
||||
|
||||
let BabeDeps {
|
||||
keystore,
|
||||
babe_config,
|
||||
shared_epoch_changes,
|
||||
} = babe;
|
||||
let BabeDeps { keystore, babe_config, shared_epoch_changes } = babe;
|
||||
let GrandpaDeps {
|
||||
shared_voter_state,
|
||||
shared_authority_set,
|
||||
@@ -154,64 +148,45 @@ pub fn create_full<C, P, SC, B>(
|
||||
finality_provider,
|
||||
} = grandpa;
|
||||
|
||||
io.extend_with(
|
||||
SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))
|
||||
);
|
||||
io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe)));
|
||||
// Making synchronous calls in light client freezes the browser currently,
|
||||
// more context: https://github.com/paritytech/substrate/pull/3480
|
||||
// These RPCs should use an asynchronous caller instead.
|
||||
io.extend_with(
|
||||
ContractsApi::to_delegate(Contracts::new(client.clone()))
|
||||
);
|
||||
io.extend_with(
|
||||
MmrApi::to_delegate(Mmr::new(client.clone()))
|
||||
);
|
||||
io.extend_with(
|
||||
TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone()))
|
||||
);
|
||||
io.extend_with(
|
||||
sc_consensus_babe_rpc::BabeApi::to_delegate(
|
||||
BabeRpcHandler::new(
|
||||
client.clone(),
|
||||
shared_epoch_changes.clone(),
|
||||
keystore,
|
||||
babe_config,
|
||||
select_chain,
|
||||
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(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(sc_consensus_babe_rpc::BabeApi::to_delegate(BabeRpcHandler::new(
|
||||
client.clone(),
|
||||
shared_epoch_changes.clone(),
|
||||
keystore,
|
||||
babe_config,
|
||||
select_chain,
|
||||
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(
|
||||
sc_sync_state_rpc::SyncStateRpcApi::to_delegate(
|
||||
sc_sync_state_rpc::SyncStateRpcHandler::new(
|
||||
chain_spec,
|
||||
client,
|
||||
shared_authority_set,
|
||||
shared_epoch_changes,
|
||||
deny_unsafe,
|
||||
)
|
||||
)
|
||||
);
|
||||
io.extend_with(sc_sync_state_rpc::SyncStateRpcApi::to_delegate(
|
||||
sc_sync_state_rpc::SyncStateRpcHandler::new(
|
||||
chain_spec,
|
||||
client,
|
||||
shared_authority_set,
|
||||
shared_epoch_changes,
|
||||
deny_unsafe,
|
||||
),
|
||||
));
|
||||
|
||||
io
|
||||
}
|
||||
|
||||
/// Instantiate all Light RPC extensions.
|
||||
pub fn create_light<C, P, M, F>(
|
||||
deps: LightDeps<C, F, P>,
|
||||
) -> jsonrpc_core::IoHandler<M> where
|
||||
pub fn create_light<C, P, M, F>(deps: LightDeps<C, F, P>) -> jsonrpc_core::IoHandler<M>
|
||||
where
|
||||
C: sp_blockchain::HeaderBackend<Block>,
|
||||
C: Send + Sync + '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};
|
||||
|
||||
let LightDeps {
|
||||
client,
|
||||
pool,
|
||||
remote_blockchain,
|
||||
fetcher
|
||||
} = deps;
|
||||
let LightDeps { client, pool, remote_blockchain, fetcher } = deps;
|
||||
let mut io = jsonrpc_core::IoHandler::default();
|
||||
io.extend_with(
|
||||
SystemApi::<Hash, AccountId, Index>::to_delegate(LightSystem::new(client, remote_blockchain, fetcher, pool))
|
||||
);
|
||||
io.extend_with(SystemApi::<Hash, AccountId, Index>::to_delegate(LightSystem::new(
|
||||
client,
|
||||
remote_blockchain,
|
||||
fetcher,
|
||||
pool,
|
||||
)));
|
||||
|
||||
io
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ pub mod currency {
|
||||
use node_primitives::Balance;
|
||||
|
||||
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 fn deposit(items: u32, bytes: u32) -> Balance {
|
||||
@@ -32,7 +32,7 @@ pub mod currency {
|
||||
|
||||
/// 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
|
||||
/// we are targeting. Blocks will be produced at a minimum duration defined
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
//! Some configurable implementations as associated type for the substrate runtime.
|
||||
|
||||
use frame_support::traits::{OnUnbalanced, Currency};
|
||||
use crate::{Balances, Authorship, NegativeImbalance};
|
||||
use crate::{Authorship, Balances, NegativeImbalance};
|
||||
use frame_support::traits::{Currency, OnUnbalanced};
|
||||
|
||||
pub struct Author;
|
||||
impl OnUnbalanced<NegativeImbalance> for Author {
|
||||
@@ -29,19 +29,24 @@ impl OnUnbalanced<NegativeImbalance> for Author {
|
||||
|
||||
#[cfg(test)]
|
||||
mod multiplier_tests {
|
||||
use sp_runtime::{assert_eq_error_rate, FixedPointNumber, traits::{Convert, One, Zero}};
|
||||
use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment};
|
||||
use sp_runtime::{
|
||||
assert_eq_error_rate,
|
||||
traits::{Convert, One, Zero},
|
||||
FixedPointNumber,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
constants::{currency::*, time::*},
|
||||
TransactionPayment, Runtime, TargetBlockFullness,
|
||||
AdjustmentVariable, System, MinimumMultiplier,
|
||||
RuntimeBlockWeights as BlockWeights,
|
||||
AdjustmentVariable, MinimumMultiplier, Runtime, RuntimeBlockWeights as BlockWeights,
|
||||
System, TargetBlockFullness, TransactionPayment,
|
||||
};
|
||||
use frame_support::weights::{Weight, WeightToFeePolynomial, DispatchClass};
|
||||
use frame_support::weights::{DispatchClass, Weight, WeightToFeePolynomial};
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -64,7 +69,7 @@ mod multiplier_tests {
|
||||
}
|
||||
|
||||
// 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 previous_float = previous.into_inner() as f64 / accuracy;
|
||||
// bump if it is zero.
|
||||
@@ -81,15 +86,20 @@ mod multiplier_tests {
|
||||
// Current saturation in terms of weight
|
||||
let s = block_weight;
|
||||
|
||||
let t1 = v * (s/m - ss/m);
|
||||
let t2 = v.powi(2) * (s/m - ss/m).powi(2) / 2.0;
|
||||
let t1 = v * (s / m - ss / m);
|
||||
let t2 = v.powi(2) * (s / m - ss / m).powi(2) / 2.0;
|
||||
let next_float = previous_float * (1.0 + t1 + t2);
|
||||
Multiplier::from_float(next_float)
|
||||
}
|
||||
|
||||
fn run_with_system_weight<F>(w: Weight, assertions: F) where F: Fn() -> () {
|
||||
let mut t: sp_io::TestExternalities =
|
||||
frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap().into();
|
||||
fn run_with_system_weight<F>(w: Weight, assertions: F)
|
||||
where
|
||||
F: Fn() -> (),
|
||||
{
|
||||
let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default()
|
||||
.build_storage::<Runtime>()
|
||||
.unwrap()
|
||||
.into();
|
||||
t.execute_with(|| {
|
||||
System::set_block_consumed_resources(w, 0);
|
||||
assertions()
|
||||
@@ -157,7 +167,9 @@ mod multiplier_tests {
|
||||
loop {
|
||||
let next = runtime_multiplier_update(fm);
|
||||
fm = next;
|
||||
if fm == min_multiplier() { break; }
|
||||
if fm == min_multiplier() {
|
||||
break
|
||||
}
|
||||
iterations += 1;
|
||||
}
|
||||
assert!(iterations > 533_333);
|
||||
@@ -198,7 +210,9 @@ mod multiplier_tests {
|
||||
loop {
|
||||
let next = runtime_multiplier_update(fm);
|
||||
// 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;
|
||||
iterations += 1;
|
||||
let fee =
|
||||
@@ -225,7 +239,7 @@ mod multiplier_tests {
|
||||
let next = runtime_multiplier_update(fm);
|
||||
assert_eq_error_rate!(
|
||||
next,
|
||||
truth_value_update(target() / 4 , fm),
|
||||
truth_value_update(target() / 4, fm),
|
||||
Multiplier::from_inner(100),
|
||||
);
|
||||
|
||||
@@ -237,12 +251,11 @@ mod multiplier_tests {
|
||||
let next = runtime_multiplier_update(fm);
|
||||
assert_eq_error_rate!(
|
||||
next,
|
||||
truth_value_update(target() / 2 , fm),
|
||||
truth_value_update(target() / 2, fm),
|
||||
Multiplier::from_inner(100),
|
||||
);
|
||||
// Light block. Multiplier is reduced a little.
|
||||
assert!(next < fm);
|
||||
|
||||
});
|
||||
run_with_system_weight(target(), || {
|
||||
let next = runtime_multiplier_update(fm);
|
||||
@@ -259,7 +272,7 @@ mod multiplier_tests {
|
||||
let next = runtime_multiplier_update(fm);
|
||||
assert_eq_error_rate!(
|
||||
next,
|
||||
truth_value_update(target() * 2 , fm),
|
||||
truth_value_update(target() * 2, fm),
|
||||
Multiplier::from_inner(100),
|
||||
);
|
||||
|
||||
@@ -326,28 +339,24 @@ mod multiplier_tests {
|
||||
BlockWeights::get().max_block,
|
||||
Weight::max_value() / 2,
|
||||
Weight::max_value(),
|
||||
].into_iter().for_each(|i| {
|
||||
]
|
||||
.into_iter()
|
||||
.for_each(|i| {
|
||||
run_with_system_weight(i, || {
|
||||
let next = runtime_multiplier_update(Multiplier::one());
|
||||
let truth = truth_value_update(i, Multiplier::one());
|
||||
assert_eq_error_rate!(
|
||||
truth,
|
||||
next,
|
||||
Multiplier::from_inner(50_000_000)
|
||||
);
|
||||
assert_eq_error_rate!(truth, next, Multiplier::from_inner(50_000_000));
|
||||
});
|
||||
});
|
||||
|
||||
// Some values that are all above the target and will cause an increase.
|
||||
let t = target();
|
||||
vec![t + 100, t * 2, t * 4]
|
||||
.into_iter()
|
||||
.for_each(|i| {
|
||||
run_with_system_weight(i, || {
|
||||
let fm = runtime_multiplier_update(max_fm);
|
||||
// won't grow. The convert saturates everything.
|
||||
assert_eq!(fm, max_fm);
|
||||
})
|
||||
});
|
||||
vec![t + 100, t * 2, t * 4].into_iter().for_each(|i| {
|
||||
run_with_system_weight(i, || {
|
||||
let fm = runtime_multiplier_update(max_fm);
|
||||
// won't grow. The convert saturates everything.
|
||||
assert_eq!(fm, max_fm);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,67 +22,67 @@
|
||||
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use frame_support::{
|
||||
construct_runtime, parameter_types, RuntimeDebug,
|
||||
weights::{
|
||||
Weight, IdentityFee,
|
||||
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
|
||||
DispatchClass,
|
||||
},
|
||||
construct_runtime, parameter_types,
|
||||
traits::{
|
||||
Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, LockIdentifier,
|
||||
U128CurrencyToVote, AllowAll, DenyAll,
|
||||
AllowAll, Currency, DenyAll, Imbalance, InstanceFilter, KeyOwnerProofSystem,
|
||||
LockIdentifier, OnUnbalanced, U128CurrencyToVote,
|
||||
},
|
||||
weights::{
|
||||
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
|
||||
DispatchClass, IdentityFee, Weight,
|
||||
},
|
||||
PalletId, RuntimeDebug,
|
||||
};
|
||||
use frame_system::{
|
||||
EnsureRoot, EnsureOneOf,
|
||||
limits::{BlockWeights, BlockLength}
|
||||
limits::{BlockLength, BlockWeights},
|
||||
EnsureOneOf, EnsureRoot,
|
||||
};
|
||||
use frame_support::{traits::InstanceFilter, PalletId};
|
||||
use codec::{Encode, Decode, MaxEncodedLen};
|
||||
pub use node_primitives::{AccountId, Signature};
|
||||
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::{
|
||||
crypto::KeyTypeId,
|
||||
u32_trait::{_1, _2, _3, _4, _5},
|
||||
OpaqueMetadata,
|
||||
};
|
||||
pub use node_primitives::{AccountId, Signature};
|
||||
use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment};
|
||||
use sp_api::impl_runtime_apis;
|
||||
use sp_inherents::{CheckInherentsResult, InherentData};
|
||||
use sp_runtime::{
|
||||
Permill, Perbill, Perquintill, Percent, ApplyExtrinsicResult, impl_opaque_keys, generic,
|
||||
create_runtime_str, FixedPointNumber,
|
||||
create_runtime_str,
|
||||
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_runtime::transaction_validity::{TransactionValidity, TransactionSource, TransactionPriority};
|
||||
use sp_runtime::traits::{
|
||||
self, BlakeTwo256, Block as BlockT, StaticLookup, SaturatedConversion, ConvertInto, OpaqueKeys,
|
||||
NumberFor,
|
||||
};
|
||||
use sp_version::RuntimeVersion;
|
||||
use sp_std::prelude::*;
|
||||
#[cfg(any(feature = "std", test))]
|
||||
use sp_version::NativeVersion;
|
||||
use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
|
||||
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 sp_version::RuntimeVersion;
|
||||
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))]
|
||||
pub use frame_system::Call as SystemCall;
|
||||
#[cfg(any(feature = "std", test))]
|
||||
pub use pallet_balances::Call as BalancesCall;
|
||||
#[cfg(any(feature = "std", test))]
|
||||
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.
|
||||
pub mod impls;
|
||||
@@ -90,7 +90,7 @@ use impls::Author;
|
||||
|
||||
/// Constant values used within the runtime.
|
||||
pub mod constants;
|
||||
use constants::{time::*, currency::*};
|
||||
use constants::{currency::*, time::*};
|
||||
use sp_runtime::generic::Era;
|
||||
|
||||
// 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.
|
||||
#[cfg(feature = "std")]
|
||||
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 \
|
||||
production chains. Please rebuild with the flag disabled.")
|
||||
production chains. Please rebuild with the flag disabled.",
|
||||
)
|
||||
}
|
||||
|
||||
/// Runtime version.
|
||||
@@ -125,23 +127,20 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration =
|
||||
sp_consensus_babe::BabeEpochConfiguration {
|
||||
c: PRIMARY_PROBABILITY,
|
||||
allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots
|
||||
allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots,
|
||||
};
|
||||
|
||||
/// Native version.
|
||||
#[cfg(any(feature = "std", test))]
|
||||
pub fn native_version() -> NativeVersion {
|
||||
NativeVersion {
|
||||
runtime_version: VERSION,
|
||||
can_author_with: Default::default(),
|
||||
}
|
||||
NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
|
||||
}
|
||||
|
||||
type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
|
||||
|
||||
pub struct 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() {
|
||||
// for fees, 80% to treasury, 20% to author
|
||||
let mut split = fees.ration(80, 20);
|
||||
@@ -256,14 +255,20 @@ parameter_types! {
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
Any,
|
||||
NonTransfer,
|
||||
Governance,
|
||||
Staking,
|
||||
}
|
||||
impl Default for ProxyType { fn default() -> Self { Self::Any } }
|
||||
impl Default for ProxyType {
|
||||
fn default() -> Self {
|
||||
Self::Any
|
||||
}
|
||||
}
|
||||
impl InstanceFilter<Call> for ProxyType {
|
||||
fn filter(&self, c: &Call) -> bool {
|
||||
match self {
|
||||
@@ -271,19 +276,16 @@ impl InstanceFilter<Call> for ProxyType {
|
||||
ProxyType::NonTransfer => !matches!(
|
||||
c,
|
||||
Call::Balances(..) |
|
||||
Call::Assets(..) |
|
||||
Call::Uniques(..) |
|
||||
Call::Vesting(pallet_vesting::Call::vested_transfer(..)) |
|
||||
Call::Indices(pallet_indices::Call::transfer(..))
|
||||
Call::Assets(..) | Call::Uniques(..) |
|
||||
Call::Vesting(pallet_vesting::Call::vested_transfer(..)) |
|
||||
Call::Indices(pallet_indices::Call::transfer(..))
|
||||
),
|
||||
ProxyType::Governance => matches!(
|
||||
c,
|
||||
Call::Democracy(..) |
|
||||
Call::Council(..) |
|
||||
Call::Society(..) |
|
||||
Call::TechnicalCommittee(..) |
|
||||
Call::Elections(..) |
|
||||
Call::Treasury(..)
|
||||
Call::Council(..) | Call::Society(..) |
|
||||
Call::TechnicalCommittee(..) |
|
||||
Call::Elections(..) | Call::Treasury(..)
|
||||
),
|
||||
ProxyType::Staking => matches!(c, Call::Staking(..)),
|
||||
}
|
||||
@@ -500,15 +502,16 @@ impl pallet_staking::Config for Runtime {
|
||||
type SlashCancelOrigin = EnsureOneOf<
|
||||
AccountId,
|
||||
EnsureRoot<AccountId>,
|
||||
pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>
|
||||
pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>,
|
||||
>;
|
||||
type SessionInterface = Self;
|
||||
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
|
||||
type NextNewSession = Session;
|
||||
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
|
||||
type ElectionProvider = ElectionProviderMultiPhase;
|
||||
type GenesisElectionProvider =
|
||||
onchain::OnChainSequentialPhragmen<pallet_election_provider_multi_phase::OnChainConfig<Self>>;
|
||||
type GenesisElectionProvider = onchain::OnChainSequentialPhragmen<
|
||||
pallet_election_provider_multi_phase::OnChainConfig<Self>,
|
||||
>;
|
||||
type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
|
||||
}
|
||||
|
||||
@@ -618,20 +621,26 @@ impl pallet_democracy::Config for Runtime {
|
||||
type VotingPeriod = VotingPeriod;
|
||||
type MinimumDeposit = MinimumDeposit;
|
||||
/// A straight majority of the council can decide what their next motion is.
|
||||
type ExternalOrigin = pallet_collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilCollective>;
|
||||
type ExternalOrigin =
|
||||
pallet_collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilCollective>;
|
||||
/// 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
|
||||
/// (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
|
||||
/// be tabled immediately and with a shorter voting/enactment period.
|
||||
type FastTrackOrigin = pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalCollective>;
|
||||
type InstantOrigin = pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, TechnicalCollective>;
|
||||
type FastTrackOrigin =
|
||||
pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalCollective>;
|
||||
type InstantOrigin =
|
||||
pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, TechnicalCollective>;
|
||||
type InstantAllowed = InstantAllowed;
|
||||
type FastTrackVotingPeriod = FastTrackVotingPeriod;
|
||||
// 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
|
||||
// Root must agree.
|
||||
type CancelProposalOrigin = EnsureOneOf<
|
||||
@@ -728,7 +737,7 @@ impl pallet_collective::Config<TechnicalCollective> for Runtime {
|
||||
type EnsureRootOrHalfCouncil = EnsureOneOf<
|
||||
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 {
|
||||
type Event = Event;
|
||||
@@ -768,12 +777,12 @@ impl pallet_treasury::Config for Runtime {
|
||||
type ApproveOrigin = EnsureOneOf<
|
||||
AccountId,
|
||||
EnsureRoot<AccountId>,
|
||||
pallet_collective::EnsureProportionAtLeast<_3, _5, AccountId, CouncilCollective>
|
||||
pallet_collective::EnsureProportionAtLeast<_3, _5, AccountId, CouncilCollective>,
|
||||
>;
|
||||
type RejectOrigin = EnsureOneOf<
|
||||
AccountId,
|
||||
EnsureRoot<AccountId>,
|
||||
pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>
|
||||
pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>,
|
||||
>;
|
||||
type Event = Event;
|
||||
type OnSlash = ();
|
||||
@@ -876,8 +885,8 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
|
||||
where
|
||||
Call: From<LocalCall>,
|
||||
where
|
||||
Call: From<LocalCall>,
|
||||
{
|
||||
fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
|
||||
call: Call,
|
||||
@@ -887,10 +896,8 @@ impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for R
|
||||
) -> Option<(Call, <UncheckedExtrinsic as traits::Extrinsic>::SignaturePayload)> {
|
||||
let tip = 0;
|
||||
// take the biggest period possible.
|
||||
let period = BlockHashCount::get()
|
||||
.checked_next_power_of_two()
|
||||
.map(|c| c / 2)
|
||||
.unwrap_or(2) as u64;
|
||||
let period =
|
||||
BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64;
|
||||
let current_block = System::block_number()
|
||||
.saturated_into::<u64>()
|
||||
// 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);
|
||||
})
|
||||
.ok()?;
|
||||
let signature = raw_payload
|
||||
.using_encoded(|payload| {
|
||||
C::sign(payload, public)
|
||||
})?;
|
||||
let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?;
|
||||
let address = Indices::unlookup(account);
|
||||
let (call, extra, _) = raw_payload.deconstruct();
|
||||
Some((call, (address, signature.into(), extra)))
|
||||
@@ -926,7 +930,8 @@ impl frame_system::offchain::SigningTypes for Runtime {
|
||||
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>,
|
||||
{
|
||||
type Extrinsic = UncheckedExtrinsic;
|
||||
@@ -965,8 +970,11 @@ impl pallet_grandpa::Config for Runtime {
|
||||
GrandpaId,
|
||||
)>>::IdentificationTuple;
|
||||
|
||||
type HandleEquivocation =
|
||||
pallet_grandpa::EquivocationHandler<Self::KeyOwnerIdentification, Offences, ReportLongevity>;
|
||||
type HandleEquivocation = pallet_grandpa::EquivocationHandler<
|
||||
Self::KeyOwnerIdentification,
|
||||
Offences,
|
||||
ReportLongevity,
|
||||
>;
|
||||
|
||||
type WeightInfo = ();
|
||||
}
|
||||
@@ -1036,7 +1044,8 @@ impl pallet_society::Config for Runtime {
|
||||
type MembershipChanged = ();
|
||||
type RotationPeriod = RotationPeriod;
|
||||
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 MaxCandidateIntake = MaxCandidateIntake;
|
||||
type ChallengePeriod = ChallengePeriod;
|
||||
@@ -1261,11 +1270,7 @@ mod mmr {
|
||||
use super::Runtime;
|
||||
pub use pallet_mmr::primitives::*;
|
||||
|
||||
pub type Leaf = <
|
||||
<Runtime as pallet_mmr::Config>::LeafData
|
||||
as
|
||||
LeafDataProvider
|
||||
>::LeafData;
|
||||
pub type Leaf = <<Runtime as pallet_mmr::Config>::LeafData as LeafDataProvider>::LeafData;
|
||||
pub type Hash = <Runtime as pallet_mmr::Config>::Hash;
|
||||
pub type Hashing = <Runtime as pallet_mmr::Config>::Hashing;
|
||||
}
|
||||
@@ -1613,9 +1618,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn validate_transaction_submitter_bounds() {
|
||||
fn is_submit_signed_transaction<T>() where
|
||||
fn is_submit_signed_transaction<T>()
|
||||
where
|
||||
T: CreateSignedTransaction<Call>,
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
is_submit_signed_transaction::<Runtime>();
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
|
||||
//! Basic example of end to end runtime tests.
|
||||
|
||||
use test_runner::{ChainInfo, SignatureVerificationOverride};
|
||||
use grandpa::GrandpaBlockImport;
|
||||
use sc_service::{TFullBackend, TFullClient};
|
||||
use sc_consensus_babe::BabeBlockImport;
|
||||
use sc_consensus_manual_seal::consensus::babe::SlotTimestampProvider;
|
||||
use sc_service::{TFullBackend, TFullClient};
|
||||
use sp_runtime::generic::Era;
|
||||
use test_runner::{ChainInfo, SignatureVerificationOverride};
|
||||
|
||||
type BlockImport<B, BE, C, SC> = BabeBlockImport<B, C, GrandpaBlockImport<BE, B, C, SC>>;
|
||||
|
||||
@@ -54,15 +54,20 @@ impl ChainInfo for NodeTemplateChainInfo {
|
||||
Self::SelectChain,
|
||||
>;
|
||||
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::CheckTxVersion::<Self::Runtime>::new(),
|
||||
frame_system::CheckGenesis::<Self::Runtime>::new(),
|
||||
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(),
|
||||
pallet_transaction_payment::ChargeTransactionPayment::<Self::Runtime>::from(0),
|
||||
)
|
||||
@@ -72,32 +77,43 @@ impl ChainInfo for NodeTemplateChainInfo {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
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 sp_keyring::sr25519::Keyring::Alice;
|
||||
use sp_runtime::{traits::IdentifyAccount, MultiSigner};
|
||||
use test_runner::{build_runtime, client_parts, task_executor, ConfigOrChainSpec, Node};
|
||||
|
||||
#[test]
|
||||
fn test_runner() {
|
||||
let mut tokio_runtime = build_runtime().unwrap();
|
||||
let task_executor = task_executor(tokio_runtime.handle().clone());
|
||||
let (rpc, task_manager, client, pool, command_sink, backend) =
|
||||
client_parts::<NodeTemplateChainInfo>(
|
||||
ConfigOrChainSpec::ChainSpec(Box::new(development_config()), task_executor)
|
||||
).unwrap();
|
||||
let node = Node::<NodeTemplateChainInfo>::new(rpc, task_manager, client, pool, command_sink, backend);
|
||||
let (rpc, task_manager, client, pool, command_sink, backend) = client_parts::<
|
||||
NodeTemplateChainInfo,
|
||||
>(
|
||||
ConfigOrChainSpec::ChainSpec(Box::new(development_config()), task_executor),
|
||||
)
|
||||
.unwrap();
|
||||
let node = Node::<NodeTemplateChainInfo>::new(
|
||||
rpc,
|
||||
task_manager,
|
||||
client,
|
||||
pool,
|
||||
command_sink,
|
||||
backend,
|
||||
);
|
||||
|
||||
tokio_runtime.block_on(async {
|
||||
// seals blocks
|
||||
node.seal_blocks(1).await;
|
||||
// submit extrinsics
|
||||
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
|
||||
.unwrap();
|
||||
|
||||
// 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.
|
||||
let _client = node.client();
|
||||
})
|
||||
|
||||
@@ -22,44 +22,42 @@
|
||||
//! can pregenerate seed database and `clone` it for every iteration of your benchmarks
|
||||
//! or tests to get consistent, smooth benchmark experience!
|
||||
|
||||
use std::{sync::Arc, path::{Path, PathBuf}, collections::BTreeMap};
|
||||
|
||||
use node_primitives::Block;
|
||||
use crate::client::{Client, Backend};
|
||||
use crate::keyring::*;
|
||||
use sc_client_db::PruningMode;
|
||||
use sc_executor::{NativeExecutor, WasmExecutionMethod};
|
||||
use sp_consensus::{
|
||||
BlockOrigin, BlockImport, BlockImportParams,
|
||||
ForkChoiceStrategy, ImportResult, ImportedAux
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
OpaqueExtrinsic,
|
||||
traits::{Block as BlockT, Verify, Zero, IdentifyAccount},
|
||||
|
||||
use crate::{
|
||||
client::{Backend, Client},
|
||||
keyring::*,
|
||||
};
|
||||
use codec::{Decode, Encode};
|
||||
use futures::executor;
|
||||
use node_primitives::Block;
|
||||
use node_runtime::{
|
||||
Call,
|
||||
CheckedExtrinsic,
|
||||
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},
|
||||
constants::currency::DOLLARS, AccountId, BalancesCall, Call, CheckedExtrinsic, MinimumPeriod,
|
||||
Signature, SystemCall, UncheckedExtrinsic,
|
||||
};
|
||||
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.
|
||||
///
|
||||
@@ -92,19 +90,21 @@ impl BenchPair {
|
||||
///
|
||||
/// Will panic if cache drop is impossbile.
|
||||
pub fn drop_system_cache() {
|
||||
#[cfg(target_os = "windows")] {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
log::warn!(
|
||||
target: "bench-logistics",
|
||||
"Clearing system cache on windows is not supported. Benchmark might totally be wrong.",
|
||||
);
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
std::process::Command::new("sync")
|
||||
.output()
|
||||
.expect("Failed to execute system cache clear");
|
||||
|
||||
#[cfg(target_os = "linux")] {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
log::trace!(target: "bench-logistics", "Clearing system cache...");
|
||||
std::process::Command::new("echo")
|
||||
.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!");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")] {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
log::trace!(target: "bench-logistics", "Clearing system cache...");
|
||||
if let Err(err) = std::process::Command::new("purge").output() {
|
||||
log::error!("purge error {:?}: ", err);
|
||||
@@ -169,15 +170,10 @@ impl Clone for BenchDb {
|
||||
);
|
||||
let seed_db_files = std::fs::read_dir(seed_dir)
|
||||
.expect("failed to list file in seed dir")
|
||||
.map(|f_result|
|
||||
f_result.expect("failed to read file in seed db")
|
||||
.path()
|
||||
).collect::<Vec<PathBuf>>();
|
||||
fs_extra::copy_items(
|
||||
&seed_db_files,
|
||||
dir.path(),
|
||||
&fs_extra::dir::CopyOptions::new(),
|
||||
).expect("Copy of seed database is ok");
|
||||
.map(|f_result| f_result.expect("failed to read file in seed db").path())
|
||||
.collect::<Vec<PathBuf>>();
|
||||
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.
|
||||
// This populates system cache with some data unrelated to actual
|
||||
@@ -204,10 +200,7 @@ pub enum BlockType {
|
||||
impl BlockType {
|
||||
/// Create block content description with specified number of transactions.
|
||||
pub fn to_content(self, size: Option<usize>) -> BlockContent {
|
||||
BlockContent {
|
||||
block_type: self,
|
||||
size,
|
||||
}
|
||||
BlockContent { block_type: self, size }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,13 +223,8 @@ pub enum DatabaseType {
|
||||
impl DatabaseType {
|
||||
fn into_settings(self, path: PathBuf) -> sc_client_db::DatabaseSettingsSrc {
|
||||
match self {
|
||||
Self::RocksDb => sc_client_db::DatabaseSettingsSrc::RocksDb {
|
||||
path,
|
||||
cache_size: 512,
|
||||
},
|
||||
Self::ParityDb => sc_client_db::DatabaseSettingsSrc::ParityDb {
|
||||
path,
|
||||
}
|
||||
Self::RocksDb => sc_client_db::DatabaseSettingsSrc::RocksDb { path, cache_size: 512 },
|
||||
Self::ParityDb => sc_client_db::DatabaseSettingsSrc::ParityDb { path },
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,10 +239,7 @@ pub struct TaskExecutor {
|
||||
|
||||
impl TaskExecutor {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
pool: executor::ThreadPool::new()
|
||||
.expect("Failed to create task executor")
|
||||
}
|
||||
Self { pool: executor::ThreadPool::new().expect("Failed to create task executor") }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,21 +264,17 @@ pub struct BlockContentIterator<'a> {
|
||||
|
||||
impl<'a> BlockContentIterator<'a> {
|
||||
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");
|
||||
|
||||
let genesis_hash = client.block_hash(Zero::zero())
|
||||
let genesis_hash = client
|
||||
.block_hash(Zero::zero())
|
||||
.expect("Database error?")
|
||||
.expect("Genesis block always exists; qed")
|
||||
.into();
|
||||
|
||||
BlockContentIterator {
|
||||
iteration: 0,
|
||||
content,
|
||||
keyring,
|
||||
runtime_version,
|
||||
genesis_hash,
|
||||
}
|
||||
BlockContentIterator { 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> {
|
||||
if self.content.size.map(|size| size <= self.iteration).unwrap_or(false) {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
let sender = self.keyring.at(self.iteration);
|
||||
let receiver = get_account_id_from_seed::<sr25519::Public>(
|
||||
&format!("random-user//{}", self.iteration)
|
||||
);
|
||||
let receiver = get_account_id_from_seed::<sr25519::Public>(&format!(
|
||||
"random-user//{}",
|
||||
self.iteration
|
||||
));
|
||||
|
||||
let signed = self.keyring.sign(
|
||||
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 {
|
||||
BlockType::RandomTransfersKeepAlive => {
|
||||
Call::Balances(
|
||||
BalancesCall::transfer_keep_alive(
|
||||
sp_runtime::MultiAddress::Id(receiver),
|
||||
node_runtime::ExistentialDeposit::get() + 1,
|
||||
)
|
||||
)
|
||||
},
|
||||
BlockType::RandomTransfersKeepAlive =>
|
||||
Call::Balances(BalancesCall::transfer_keep_alive(
|
||||
sp_runtime::MultiAddress::Id(receiver),
|
||||
node_runtime::ExistentialDeposit::get() + 1,
|
||||
)),
|
||||
BlockType::RandomTransfersReaping => {
|
||||
Call::Balances(
|
||||
BalancesCall::transfer(
|
||||
sp_runtime::MultiAddress::Id(receiver),
|
||||
// Transfer so that ending balance would be 1 less than existential deposit
|
||||
// so that we kill the sender account.
|
||||
100*DOLLARS - (node_runtime::ExistentialDeposit::get() - 1),
|
||||
)
|
||||
)
|
||||
},
|
||||
BlockType::Noop => {
|
||||
Call::System(
|
||||
SystemCall::remark(Vec::new())
|
||||
)
|
||||
Call::Balances(BalancesCall::transfer(
|
||||
sp_runtime::MultiAddress::Id(receiver),
|
||||
// Transfer so that ending balance would be 1 less than existential deposit
|
||||
// so that we kill the sender account.
|
||||
100 * DOLLARS - (node_runtime::ExistentialDeposit::get() - 1),
|
||||
))
|
||||
},
|
||||
BlockType::Noop => Call::System(SystemCall::remark(Vec::new())),
|
||||
},
|
||||
},
|
||||
self.runtime_version.spec_version,
|
||||
@@ -346,8 +322,7 @@ impl<'a> Iterator for BlockContentIterator<'a> {
|
||||
|
||||
let encoded = Encode::encode(&signed);
|
||||
|
||||
let opaque = OpaqueExtrinsic::decode(&mut &encoded[..])
|
||||
.expect("Failed to decode opaque");
|
||||
let opaque = OpaqueExtrinsic::decode(&mut &encoded[..]).expect("Failed to decode opaque");
|
||||
|
||||
self.iteration += 1;
|
||||
|
||||
@@ -373,12 +348,8 @@ impl BenchDb {
|
||||
"Created seed db at {}",
|
||||
dir.path().to_string_lossy(),
|
||||
);
|
||||
let (_client, _backend, _task_executor) = Self::bench_client(
|
||||
database_type,
|
||||
dir.path(),
|
||||
Profile::Native,
|
||||
&keyring,
|
||||
);
|
||||
let (_client, _backend, _task_executor) =
|
||||
Self::bench_client(database_type, dir.path(), Profile::Native, &keyring);
|
||||
let directory_guard = Guard(dir);
|
||||
|
||||
BenchDb { keyring, directory_guard, database_type }
|
||||
@@ -408,7 +379,7 @@ impl BenchDb {
|
||||
keyring: &BenchKeyring,
|
||||
) -> (Client, std::sync::Arc<Backend>, TaskExecutor) {
|
||||
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_pruning: PruningMode::ArchiveAll,
|
||||
source: database_type.into_settings(dir.into()),
|
||||
@@ -429,7 +400,8 @@ impl BenchDb {
|
||||
None,
|
||||
None,
|
||||
Default::default(),
|
||||
).expect("Should not fail");
|
||||
)
|
||||
.expect("Should not fail");
|
||||
|
||||
(client, backend, task_executor)
|
||||
}
|
||||
@@ -445,12 +417,14 @@ impl BenchDb {
|
||||
.put_data(sp_timestamp::INHERENT_IDENTIFIER, ×tamp)
|
||||
.expect("Put timestamp failed");
|
||||
|
||||
client.runtime_api()
|
||||
client
|
||||
.runtime_api()
|
||||
.inherent_extrinsics_with_context(
|
||||
&BlockId::number(0),
|
||||
ExecutionContext::BlockConstruction,
|
||||
inherent_data,
|
||||
).expect("Get inherents failed")
|
||||
)
|
||||
.expect("Get inherents failed")
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
let client = self.client();
|
||||
|
||||
let mut block = client
|
||||
.new_block(Default::default())
|
||||
.expect("Block creation failed");
|
||||
let mut block = client.new_block(Default::default()).expect("Block creation failed");
|
||||
|
||||
for extrinsic in self.generate_inherents(&client) {
|
||||
block.push(extrinsic).expect("Push inherent failed");
|
||||
@@ -486,14 +458,12 @@ impl BenchDb {
|
||||
for opaque in self.block_content(content, &client) {
|
||||
match block.push(opaque) {
|
||||
Err(sp_blockchain::Error::ApplyExtrinsicFailed(
|
||||
sp_blockchain::ApplyExtrinsicFailed::Validity(e)
|
||||
)) if e.exhausted_resources() => {
|
||||
break;
|
||||
},
|
||||
sp_blockchain::ApplyExtrinsicFailed::Validity(e),
|
||||
)) if e.exhausted_resources() => break,
|
||||
Err(err) => panic!("Error pushing transaction: {:?}", err),
|
||||
Ok(_) => {},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let block = block.build().expect("Block build failed").block;
|
||||
|
||||
@@ -514,12 +484,8 @@ impl BenchDb {
|
||||
/// Clone this database and create context for testing/benchmarking.
|
||||
pub fn create_context(&self, profile: Profile) -> BenchContext {
|
||||
let BenchDb { directory_guard, keyring, database_type } = self.clone();
|
||||
let (client, backend, task_executor) = Self::bench_client(
|
||||
database_type,
|
||||
directory_guard.path(),
|
||||
profile,
|
||||
&keyring
|
||||
);
|
||||
let (client, backend, task_executor) =
|
||||
Self::bench_client(database_type, directory_guard.path(), profile, &keyring);
|
||||
|
||||
BenchContext {
|
||||
client: Arc::new(client),
|
||||
@@ -549,7 +515,8 @@ impl BenchKeyring {
|
||||
let seed = format!("//endowed-user/{}", n);
|
||||
let (account_id, pair) = match key_types {
|
||||
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();
|
||||
(account_id, BenchPair::Sr25519(pair))
|
||||
},
|
||||
@@ -581,28 +548,34 @@ impl BenchKeyring {
|
||||
xt: CheckedExtrinsic,
|
||||
spec_version: u32,
|
||||
tx_version: u32,
|
||||
genesis_hash: [u8; 32]
|
||||
genesis_hash: [u8; 32],
|
||||
) -> UncheckedExtrinsic {
|
||||
match xt.signed {
|
||||
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 signature = payload.using_encoded(|b| {
|
||||
if b.len() > 256 {
|
||||
key.sign(&sp_io::hashing::blake2_256(b))
|
||||
} else {
|
||||
key.sign(b)
|
||||
}
|
||||
}).into();
|
||||
let signature = payload
|
||||
.using_encoded(|b| {
|
||||
if b.len() > 256 {
|
||||
key.sign(&sp_io::hashing::blake2_256(b))
|
||||
} else {
|
||||
key.sign(b)
|
||||
}
|
||||
})
|
||||
.into();
|
||||
UncheckedExtrinsic {
|
||||
signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)),
|
||||
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,
|
||||
offchain_worker: 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
|
||||
where
|
||||
AccountPublic: From<<TPublic::Pair as Pair>::Public>
|
||||
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
|
||||
{
|
||||
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
|
||||
}
|
||||
@@ -684,24 +657,25 @@ where
|
||||
impl BenchContext {
|
||||
/// Import some 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.fork_choice = Some(ForkChoiceStrategy::LongestChain);
|
||||
|
||||
assert_eq!(self.client.chain_info().best_number, 0);
|
||||
|
||||
assert_eq!(
|
||||
futures::executor::block_on(self.client.import_block(import_params, Default::default()))
|
||||
.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,
|
||||
}
|
||||
futures::executor::block_on(
|
||||
self.client.import_block(import_params, Default::default())
|
||||
)
|
||||
.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);
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
//! Utilities to build a `TestClient` for `node-runtime`.
|
||||
|
||||
use sp_runtime::BuildStorage;
|
||||
use sc_service::client;
|
||||
use sp_runtime::BuildStorage;
|
||||
/// Re-export test-client utilities.
|
||||
pub use substrate_test_client::*;
|
||||
|
||||
@@ -61,13 +61,15 @@ pub trait TestClientBuilderExt: Sized {
|
||||
fn build(self) -> Client;
|
||||
}
|
||||
|
||||
impl TestClientBuilderExt for substrate_test_client::TestClientBuilder<
|
||||
node_primitives::Block,
|
||||
client::LocalCallExecutor<node_primitives::Block, Backend, Executor>,
|
||||
Backend,
|
||||
GenesisParameters,
|
||||
> {
|
||||
fn new() -> Self{
|
||||
impl TestClientBuilderExt
|
||||
for substrate_test_client::TestClientBuilder<
|
||||
node_primitives::Block,
|
||||
client::LocalCallExecutor<node_primitives::Block, Backend, Executor>,
|
||||
Backend,
|
||||
GenesisParameters,
|
||||
>
|
||||
{
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
@@ -75,5 +77,3 @@ impl TestClientBuilderExt for substrate_test_client::TestClientBuilder<
|
||||
self.build_with_native_executor(None).0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,14 +19,13 @@
|
||||
//! Genesis Configuration.
|
||||
|
||||
use crate::keyring::*;
|
||||
use sp_keyring::{Ed25519Keyring, Sr25519Keyring};
|
||||
use node_runtime::{
|
||||
GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, SystemConfig,
|
||||
GrandpaConfig, IndicesConfig, SocietyConfig, wasm_binary_unwrap,
|
||||
AccountId, StakerStatus, BabeConfig, BABE_GENESIS_EPOCH_CONFIG,
|
||||
constants::currency::*, wasm_binary_unwrap, AccountId, BabeConfig, BalancesConfig,
|
||||
GenesisConfig, GrandpaConfig, IndicesConfig, SessionConfig, SocietyConfig, StakerStatus,
|
||||
StakingConfig, SystemConfig, BABE_GENESIS_EPOCH_CONFIG,
|
||||
};
|
||||
use node_runtime::constants::currency::*;
|
||||
use sp_core::ChangesTrieConfiguration;
|
||||
use sp_keyring::{Ed25519Keyring, Sr25519Keyring};
|
||||
use sp_runtime::Perbill;
|
||||
|
||||
/// Create genesis runtime configuration for tests.
|
||||
@@ -41,7 +40,6 @@ pub fn config_endowed(
|
||||
code: Option<&[u8]>,
|
||||
extra_endowed: Vec<AccountId>,
|
||||
) -> GenesisConfig {
|
||||
|
||||
let mut endowed = vec![
|
||||
(alice(), 111 * DOLLARS),
|
||||
(bob(), 100 * DOLLARS),
|
||||
@@ -51,59 +49,44 @@ pub fn config_endowed(
|
||||
(ferdie(), 100 * DOLLARS),
|
||||
];
|
||||
|
||||
endowed.extend(
|
||||
extra_endowed.into_iter().map(|endowed| (endowed, 100*DOLLARS))
|
||||
);
|
||||
endowed.extend(extra_endowed.into_iter().map(|endowed| (endowed, 100 * DOLLARS)));
|
||||
|
||||
GenesisConfig {
|
||||
system: SystemConfig {
|
||||
changes_trie_config: if support_changes_trie { Some(ChangesTrieConfiguration {
|
||||
digest_interval: 2,
|
||||
digest_levels: 2,
|
||||
}) } else { None },
|
||||
changes_trie_config: if support_changes_trie {
|
||||
Some(ChangesTrieConfiguration { digest_interval: 2, digest_levels: 2 })
|
||||
} else {
|
||||
None
|
||||
},
|
||||
code: code.map(|x| x.to_vec()).unwrap_or_else(|| wasm_binary_unwrap().to_vec()),
|
||||
},
|
||||
indices: IndicesConfig {
|
||||
indices: vec![],
|
||||
},
|
||||
balances: BalancesConfig {
|
||||
balances: endowed,
|
||||
},
|
||||
indices: IndicesConfig { indices: vec![] },
|
||||
balances: BalancesConfig { balances: endowed },
|
||||
session: SessionConfig {
|
||||
keys: vec![
|
||||
(dave(), alice(), to_session_keys(
|
||||
&Ed25519Keyring::Alice,
|
||||
&Sr25519Keyring::Alice,
|
||||
)),
|
||||
(eve(), bob(), to_session_keys(
|
||||
&Ed25519Keyring::Bob,
|
||||
&Sr25519Keyring::Bob,
|
||||
)),
|
||||
(ferdie(), charlie(), to_session_keys(
|
||||
&Ed25519Keyring::Charlie,
|
||||
&Sr25519Keyring::Charlie,
|
||||
)),
|
||||
]
|
||||
(dave(), alice(), to_session_keys(&Ed25519Keyring::Alice, &Sr25519Keyring::Alice)),
|
||||
(eve(), bob(), to_session_keys(&Ed25519Keyring::Bob, &Sr25519Keyring::Bob)),
|
||||
(
|
||||
ferdie(),
|
||||
charlie(),
|
||||
to_session_keys(&Ed25519Keyring::Charlie, &Sr25519Keyring::Charlie),
|
||||
),
|
||||
],
|
||||
},
|
||||
staking: StakingConfig {
|
||||
stakers: vec![
|
||||
(dave(), alice(), 111 * DOLLARS, StakerStatus::Validator),
|
||||
(eve(), bob(), 100 * DOLLARS, StakerStatus::Validator),
|
||||
(ferdie(), charlie(), 100 * DOLLARS, StakerStatus::Validator)
|
||||
(ferdie(), charlie(), 100 * DOLLARS, StakerStatus::Validator),
|
||||
],
|
||||
validator_count: 3,
|
||||
minimum_validator_count: 0,
|
||||
slash_reward_fraction: Perbill::from_percent(10),
|
||||
invulnerables: vec![alice(), bob(), charlie()],
|
||||
.. Default::default()
|
||||
},
|
||||
babe: BabeConfig {
|
||||
authorities: vec![],
|
||||
epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG),
|
||||
},
|
||||
grandpa: GrandpaConfig {
|
||||
authorities: vec![],
|
||||
..Default::default()
|
||||
},
|
||||
babe: BabeConfig { authorities: vec![], epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG) },
|
||||
grandpa: GrandpaConfig { authorities: vec![] },
|
||||
im_online: Default::default(),
|
||||
authority_discovery: Default::default(),
|
||||
democracy: Default::default(),
|
||||
@@ -113,11 +96,7 @@ pub fn config_endowed(
|
||||
elections: Default::default(),
|
||||
sudo: Default::default(),
|
||||
treasury: Default::default(),
|
||||
society: SocietyConfig {
|
||||
members: vec![alice(), bob()],
|
||||
pot: 0,
|
||||
max_members: 999,
|
||||
},
|
||||
society: SocietyConfig { members: vec![alice(), bob()], pot: 0, max_members: 999 },
|
||||
vesting: Default::default(),
|
||||
gilt: Default::default(),
|
||||
transaction_storage: Default::default(),
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
//! 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 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.
|
||||
pub fn alice() -> AccountId {
|
||||
@@ -81,26 +81,31 @@ pub fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra {
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
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 signature = payload.using_encoded(|b| {
|
||||
if b.len() > 256 {
|
||||
key.sign(&sp_io::hashing::blake2_256(b))
|
||||
} else {
|
||||
key.sign(b)
|
||||
}
|
||||
}).into();
|
||||
let signature = payload
|
||||
.using_encoded(|b| {
|
||||
if b.len() > 256 {
|
||||
key.sign(&sp_io::hashing::blake2_256(b))
|
||||
} else {
|
||||
key.sign(b)
|
||||
}
|
||||
})
|
||||
.into();
|
||||
UncheckedExtrinsic {
|
||||
signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)),
|
||||
function: payload.0,
|
||||
}
|
||||
}
|
||||
None => UncheckedExtrinsic {
|
||||
signature: None,
|
||||
function: xt.function,
|
||||
},
|
||||
None => UncheckedExtrinsic { signature: None, function: xt.function },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
pub mod bench;
|
||||
pub mod client;
|
||||
pub mod genesis;
|
||||
pub mod keyring;
|
||||
pub mod bench;
|
||||
|
||||
@@ -16,19 +16,23 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// 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 rand::{Rng, distributions::Alphanumeric, rngs::OsRng};
|
||||
use rand::{distributions::Alphanumeric, rngs::OsRng, Rng};
|
||||
use structopt::StructOpt;
|
||||
|
||||
use sc_keystore::LocalKeystore;
|
||||
use node_cli::chain_spec::{self, AccountId};
|
||||
use sc_keystore::LocalKeystore;
|
||||
use sp_core::{
|
||||
sr25519,
|
||||
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
|
||||
/// 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.
|
||||
fn chain_spec_path(&self) -> &Path {
|
||||
match self {
|
||||
ChainSpecBuilder::New { chain_spec_path, .. } =>
|
||||
chain_spec_path.as_path(),
|
||||
ChainSpecBuilder::Generate { chain_spec_path, .. } =>
|
||||
chain_spec_path.as_path(),
|
||||
ChainSpecBuilder::New { 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))
|
||||
};
|
||||
|
||||
let nominator_accounts =
|
||||
nominator_accounts.into_iter().map(parse_account).collect::<Result<Vec<_>, String>>()?;
|
||||
let nominator_accounts = nominator_accounts
|
||||
.into_iter()
|
||||
.map(parse_account)
|
||||
.collect::<Result<Vec<_>, String>>()?;
|
||||
|
||||
let endowed_accounts =
|
||||
endowed_accounts.into_iter().map(parse_account).collect::<Result<Vec<_>, String>>()?;
|
||||
let endowed_accounts = endowed_accounts
|
||||
.into_iter()
|
||||
.map(parse_account)
|
||||
.collect::<Result<Vec<_>, String>>()?;
|
||||
|
||||
let sudo_account = parse_account(sudo_account)?;
|
||||
|
||||
@@ -137,7 +143,14 @@ fn generate_chain_spec(
|
||||
"Custom",
|
||||
"custom",
|
||||
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![],
|
||||
None,
|
||||
None,
|
||||
@@ -148,42 +161,26 @@ fn generate_chain_spec(
|
||||
chain_spec.as_json(false).map_err(|err| err)
|
||||
}
|
||||
|
||||
fn generate_authority_keys_and_store(
|
||||
seeds: &[String],
|
||||
keystore_path: &Path,
|
||||
) -> Result<(), String> {
|
||||
fn generate_authority_keys_and_store(seeds: &[String], keystore_path: &Path) -> Result<(), String> {
|
||||
for (n, seed) in seeds.into_iter().enumerate() {
|
||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(
|
||||
keystore_path.join(format!("auth-{}", n)),
|
||||
None,
|
||||
).map_err(|err| err.to_string())?);
|
||||
let keystore: SyncCryptoStorePtr = Arc::new(
|
||||
LocalKeystore::open(keystore_path.join(format!("auth-{}", n)), None)
|
||||
.map_err(|err| err.to_string())?,
|
||||
);
|
||||
|
||||
let (_, _, grandpa, babe, im_online, authority_discovery) =
|
||||
chain_spec::authority_keys_from_seed(seed);
|
||||
|
||||
let insert_key = |key_type, public| {
|
||||
SyncCryptoStore::insert_unknown(
|
||||
&*keystore,
|
||||
key_type,
|
||||
&format!("//{}", seed),
|
||||
public,
|
||||
).map_err(|_| format!("Failed to insert key: {}", grandpa))
|
||||
SyncCryptoStore::insert_unknown(&*keystore, key_type, &format!("//{}", seed), public)
|
||||
.map_err(|_| format!("Failed to insert key: {}", grandpa))
|
||||
};
|
||||
|
||||
insert_key(
|
||||
sp_core::crypto::key_types::BABE,
|
||||
babe.as_slice(),
|
||||
)?;
|
||||
insert_key(sp_core::crypto::key_types::BABE, babe.as_slice())?;
|
||||
|
||||
insert_key(
|
||||
sp_core::crypto::key_types::GRANDPA,
|
||||
grandpa.as_slice(),
|
||||
)?;
|
||||
insert_key(sp_core::crypto::key_types::GRANDPA, grandpa.as_slice())?;
|
||||
|
||||
insert_key(
|
||||
sp_core::crypto::key_types::IM_ONLINE,
|
||||
im_online.as_slice(),
|
||||
)?;
|
||||
insert_key(sp_core::crypto::key_types::IM_ONLINE, im_online.as_slice())?;
|
||||
|
||||
insert_key(
|
||||
sp_core::crypto::key_types::AUTHORITY_DISCOVERY,
|
||||
@@ -206,10 +203,7 @@ fn print_seeds(
|
||||
println!("{}", header.paint("Authority seeds"));
|
||||
|
||||
for (n, seed) in authority_seeds.iter().enumerate() {
|
||||
println!("{} //{}",
|
||||
entry.paint(format!("auth-{}:", n)),
|
||||
seed,
|
||||
);
|
||||
println!("{} //{}", entry.paint(format!("auth-{}:", n)), seed,);
|
||||
}
|
||||
|
||||
println!("{}", header.paint("Nominator seeds"));
|
||||
@@ -223,10 +217,7 @@ fn print_seeds(
|
||||
if !endowed_seeds.is_empty() {
|
||||
println!("{}", header.paint("Endowed seeds"));
|
||||
for (n, seed) in endowed_seeds.iter().enumerate() {
|
||||
println!("{} //{}",
|
||||
entry.paint(format!("endowed-{}:", n)),
|
||||
seed,
|
||||
);
|
||||
println!("{} //{}", entry.paint(format!("endowed-{}:", n)), seed,);
|
||||
}
|
||||
|
||||
println!();
|
||||
@@ -260,10 +251,7 @@ fn main() -> Result<(), String> {
|
||||
print_seeds(&authority_seeds, &nominator_seeds, &endowed_seeds, &sudo_seed);
|
||||
|
||||
if let Some(keystore_path) = keystore_path {
|
||||
generate_authority_keys_and_store(
|
||||
&authority_seeds,
|
||||
&keystore_path,
|
||||
)?;
|
||||
generate_authority_keys_and_store(&authority_seeds, &keystore_path)?;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
(authority_seeds, nominator_accounts, endowed_accounts, sudo_account)
|
||||
}
|
||||
},
|
||||
ChainSpecBuilder::New {
|
||||
authority_seeds,
|
||||
nominator_accounts,
|
||||
@@ -294,12 +282,8 @@ fn main() -> Result<(), String> {
|
||||
} => (authority_seeds, nominator_accounts, endowed_accounts, sudo_account),
|
||||
};
|
||||
|
||||
let json = generate_chain_spec(
|
||||
authority_seeds,
|
||||
nominator_accounts,
|
||||
endowed_accounts,
|
||||
sudo_account,
|
||||
)?;
|
||||
let json =
|
||||
generate_chain_spec(authority_seeds, nominator_accounts, endowed_accounts, sudo_account)?;
|
||||
|
||||
fs::write(chain_spec_path, json).map_err(|err| err.to_string())
|
||||
}
|
||||
|
||||
@@ -16,17 +16,17 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use structopt::StructOpt;
|
||||
use sc_cli::{
|
||||
Error, VanityCmd, SignCmd, VerifyCmd, GenerateNodeKeyCmd, GenerateCmd, InspectKeyCmd,
|
||||
InspectNodeKeyCmd
|
||||
Error, GenerateCmd, GenerateNodeKeyCmd, InspectKeyCmd, InspectNodeKeyCmd, SignCmd, VanityCmd,
|
||||
VerifyCmd,
|
||||
};
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(
|
||||
name = "subkey",
|
||||
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 {
|
||||
/// Generate a random node libp2p key, save it to file or print it to stdout
|
||||
|
||||
@@ -26,5 +26,5 @@ pub enum Error {
|
||||
AllocatorOutOfSpace,
|
||||
/// Some other error occurred.
|
||||
#[error("Other: {0}")]
|
||||
Other(&'static str)
|
||||
Other(&'static str),
|
||||
}
|
||||
|
||||
@@ -68,8 +68,12 @@
|
||||
//! sizes.
|
||||
|
||||
use crate::Error;
|
||||
use std::{mem, convert::{TryFrom, TryInto}, ops::{Range, Index, IndexMut}};
|
||||
use sp_wasm_interface::{Pointer, WordSize};
|
||||
use std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
mem,
|
||||
ops::{Index, IndexMut, Range},
|
||||
};
|
||||
|
||||
/// The minimal alignment guaranteed by this allocator.
|
||||
///
|
||||
@@ -139,7 +143,7 @@ impl Order {
|
||||
fn from_size(size: u32) -> Result<Self, Error> {
|
||||
let clamped_size = if size > MAX_POSSIBLE_ALLOCATION {
|
||||
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 {
|
||||
MIN_POSSIBLE_ALLOCATION
|
||||
} else {
|
||||
@@ -216,7 +220,6 @@ impl Link {
|
||||
/// ```
|
||||
///
|
||||
/// ## Occupied header
|
||||
///
|
||||
/// ```ignore
|
||||
/// 64 32 0
|
||||
// +--------------+-------------------+
|
||||
@@ -290,9 +293,7 @@ struct FreeLists {
|
||||
impl FreeLists {
|
||||
/// Creates the free empty lists.
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
heads: [Link::Nil; N_ORDERS]
|
||||
}
|
||||
Self { heads: [Link::Nil; N_ORDERS] }
|
||||
}
|
||||
|
||||
/// 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;
|
||||
|
||||
header_ptr
|
||||
}
|
||||
},
|
||||
Link::Nil => {
|
||||
// Corresponding free list is empty. Allocate a new item.
|
||||
Self::bump(
|
||||
&mut self.bumper,
|
||||
order.size() + HEADER_SIZE,
|
||||
mem.size(),
|
||||
)?
|
||||
}
|
||||
Self::bump(&mut self.bumper, order.size() + HEADER_SIZE, mem.size())?
|
||||
},
|
||||
};
|
||||
|
||||
// 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.
|
||||
/// - `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 {
|
||||
return Err(error("the allocator has been poisoned"))
|
||||
}
|
||||
@@ -480,8 +481,13 @@ impl FreeingBumpHeapAllocator {
|
||||
/// the operation would exhaust the heap.
|
||||
fn bump(bumper: &mut u32, size: u32, heap_end: u32) -> Result<u32, Error> {
|
||||
if *bumper + size > heap_end {
|
||||
log::error!(target: LOG_TARGET, "running out of space with current bumper {}, mem size {}", bumper, heap_end);
|
||||
return Err(Error::AllocatorOutOfSpace);
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
"running out of space with current bumper {}, mem size {}",
|
||||
bumper,
|
||||
heap_end
|
||||
);
|
||||
return Err(Error::AllocatorOutOfSpace)
|
||||
}
|
||||
|
||||
let res = *bumper;
|
||||
|
||||
@@ -25,5 +25,5 @@
|
||||
mod error;
|
||||
mod freeing_bump;
|
||||
|
||||
pub use freeing_bump::FreeingBumpHeapAllocator;
|
||||
pub use error::Error;
|
||||
pub use freeing_bump::FreeingBumpHeapAllocator;
|
||||
|
||||
@@ -18,30 +18,32 @@
|
||||
|
||||
//! 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::{
|
||||
blockchain::{
|
||||
Backend as BlockchainBackend, well_known_cache_keys
|
||||
},
|
||||
blockchain::{well_known_cache_keys, Backend as BlockchainBackend},
|
||||
light::RemoteBlockchain,
|
||||
UsageInfo,
|
||||
};
|
||||
use parking_lot::RwLock;
|
||||
use sp_blockchain;
|
||||
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_state_machine::Backend as StateBackend;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// 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,
|
||||
delete: D,
|
||||
) -> sp_blockchain::Result<()>
|
||||
where
|
||||
Block: BlockT,
|
||||
B: Backend<Block>,
|
||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
||||
where
|
||||
Block: BlockT,
|
||||
B: Backend<Block>,
|
||||
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||
{
|
||||
operation.op.insert_aux(
|
||||
insert.into_iter()
|
||||
insert
|
||||
.into_iter()
|
||||
.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
|
||||
/// 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.
|
||||
fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result<Block::Hash>;
|
||||
@@ -182,7 +189,7 @@ pub trait BlockImportOperation<Block: BlockT> {
|
||||
&mut self,
|
||||
_offchain_update: OffchainChangesCollection,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inject changes trie data into the database.
|
||||
@@ -195,7 +202,8 @@ pub trait BlockImportOperation<Block: BlockT> {
|
||||
///
|
||||
/// Values are `None` if should be deleted.
|
||||
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.
|
||||
fn mark_finalized(
|
||||
@@ -209,16 +217,17 @@ pub trait BlockImportOperation<Block: BlockT> {
|
||||
fn mark_head(&mut self, id: BlockId<Block>) -> sp_blockchain::Result<()>;
|
||||
|
||||
/// 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.
|
||||
pub trait LockImportRun<Block: BlockT, B: Backend<Block>> {
|
||||
/// Lock the import lock, and run operations inside.
|
||||
fn lock_import_and_run<R, Err, F>(&self, f: F) -> Result<R, Err>
|
||||
where
|
||||
F: FnOnce(&mut ClientImportOperation<Block, B>) -> Result<R, Err>,
|
||||
Err: From<sp_blockchain::Error>;
|
||||
where
|
||||
F: FnOnce(&mut ClientImportOperation<Block, B>) -> Result<R, Err>,
|
||||
Err: From<sp_blockchain::Error>;
|
||||
}
|
||||
|
||||
/// Finalize Facilities
|
||||
@@ -270,9 +279,13 @@ pub trait AuxStore {
|
||||
'a,
|
||||
'b: 'a,
|
||||
'c: 'a,
|
||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
||||
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()>;
|
||||
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||
>(
|
||||
&self,
|
||||
insert: I,
|
||||
delete: D,
|
||||
) -> sp_blockchain::Result<()>;
|
||||
|
||||
/// Query auxiliary data from key-value store.
|
||||
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>,
|
||||
}
|
||||
|
||||
impl <'a, State, Block> KeyIterator<'a, State, Block> {
|
||||
impl<'a, State, Block> KeyIterator<'a, State, Block> {
|
||||
/// create a KeyIterator instance
|
||||
pub fn new(state: State, prefix: Option<&'a StorageKey>, current_key: Vec<u8>) -> Self {
|
||||
Self {
|
||||
state,
|
||||
child_storage: None,
|
||||
prefix,
|
||||
current_key,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
Self { state, child_storage: None, prefix, current_key, _phantom: PhantomData }
|
||||
}
|
||||
|
||||
/// Create a `KeyIterator` instance for a child storage.
|
||||
@@ -306,17 +313,12 @@ impl <'a, State, Block> KeyIterator<'a, State, Block> {
|
||||
prefix: Option<&'a StorageKey>,
|
||||
current_key: Vec<u8>,
|
||||
) -> Self {
|
||||
Self {
|
||||
state,
|
||||
child_storage: Some(child_info),
|
||||
prefix,
|
||||
current_key,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
Self { 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,
|
||||
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)
|
||||
} else {
|
||||
self.state.next_storage_key(&self.current_key)
|
||||
}.ok().flatten()?;
|
||||
}
|
||||
.ok()
|
||||
.flatten()?;
|
||||
// this terminates the iterator the first time it fails.
|
||||
if let Some(prefix) = self.prefix {
|
||||
if !next_key.starts_with(&prefix.0[..]) {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
}
|
||||
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
|
||||
pub trait StorageProvider<Block: BlockT, B: Backend<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.
|
||||
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.
|
||||
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.
|
||||
fn storage_pairs(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
key_prefix: &StorageKey
|
||||
key_prefix: &StorageKey,
|
||||
) -> sp_blockchain::Result<Vec<(StorageKey, StorageData)>>;
|
||||
|
||||
/// 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,
|
||||
id: &BlockId<Block>,
|
||||
prefix: Option<&'a StorageKey>,
|
||||
start_key: Option<&StorageKey>
|
||||
start_key: Option<&StorageKey>,
|
||||
) -> 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.
|
||||
@@ -370,7 +386,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
child_info: &ChildInfo,
|
||||
key: &StorageKey
|
||||
key: &StorageKey,
|
||||
) -> sp_blockchain::Result<Option<StorageData>>;
|
||||
|
||||
/// 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,
|
||||
id: &BlockId<Block>,
|
||||
child_info: &ChildInfo,
|
||||
key_prefix: &StorageKey
|
||||
key_prefix: &StorageKey,
|
||||
) -> sp_blockchain::Result<Vec<StorageKey>>;
|
||||
|
||||
/// 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>,
|
||||
child_info: ChildInfo,
|
||||
prefix: Option<&'a StorageKey>,
|
||||
start_key: Option<&StorageKey>
|
||||
start_key: Option<&StorageKey>,
|
||||
) -> 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.
|
||||
@@ -396,7 +412,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
child_info: &ChildInfo,
|
||||
key: &StorageKey
|
||||
key: &StorageKey,
|
||||
) -> sp_blockchain::Result<Option<Block::Hash>>;
|
||||
|
||||
/// 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>,
|
||||
last: BlockId<Block>,
|
||||
storage_key: Option<&PrefixedStorageKey>,
|
||||
key: &StorageKey
|
||||
key: &StorageKey,
|
||||
) -> 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>)>;
|
||||
|
||||
/// Discard non-best, unfinalized leaf block.
|
||||
fn remove_leaf_block(
|
||||
&self,
|
||||
hash: &Block::Hash,
|
||||
) -> sp_blockchain::Result<()>;
|
||||
fn remove_leaf_block(&self, hash: &Block::Hash) -> sp_blockchain::Result<()>;
|
||||
|
||||
/// Insert auxiliary data into key-value store.
|
||||
fn insert_aux<
|
||||
'a,
|
||||
'b: 'a,
|
||||
'c: 'a,
|
||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
||||
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()>
|
||||
{
|
||||
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||
>(
|
||||
&self,
|
||||
insert: I,
|
||||
delete: D,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
AuxStore::insert_aux(self, insert, delete)
|
||||
}
|
||||
/// Query auxiliary data from key-value store.
|
||||
@@ -548,9 +564,10 @@ pub trait PrunableStateChangesTrieStorage<Block: BlockT>:
|
||||
/// Get reference to StateChangesTrieStorage.
|
||||
fn storage(&self) -> &dyn StateChangesTrieStorage<HashFor<Block>, NumberFor<Block>>;
|
||||
/// Get configuration at given block.
|
||||
fn configuration_at(&self, at: &BlockId<Block>) -> sp_blockchain::Result<
|
||||
ChangesTrieConfigurationRange<NumberFor<Block>, Block::Hash>
|
||||
>;
|
||||
fn configuration_at(
|
||||
&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.
|
||||
/// 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).
|
||||
@@ -584,7 +601,8 @@ pub fn changes_tries_state_at_block<'a, Block: BlockT>(
|
||||
|
||||
let config_range = storage.configuration_at(block)?;
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
|
||||
//! A method call executor interface.
|
||||
|
||||
use std::{panic::UnwindSafe, result, cell::RefCell};
|
||||
use codec::{Encode, Decode};
|
||||
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 codec::{Decode, Encode};
|
||||
use sc_executor::{NativeVersion, RuntimeVersion};
|
||||
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 sp_api::{ProofRecorder, StorageTransactionCache};
|
||||
|
||||
/// Executor Provider
|
||||
pub trait ExecutorProvider<Block: BlockT> {
|
||||
@@ -73,7 +72,7 @@ pub trait CallExecutor<B: BlockT> {
|
||||
fn contextual_call<
|
||||
EM: Fn(
|
||||
Result<NativeOrEncoded<R>, Self::Error>,
|
||||
Result<NativeOrEncoded<R>, Self::Error>
|
||||
Result<NativeOrEncoded<R>, Self::Error>,
|
||||
) -> Result<NativeOrEncoded<R>, Self::Error>,
|
||||
R: Encode + Decode + PartialEq,
|
||||
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
|
||||
@@ -83,14 +82,18 @@ pub trait CallExecutor<B: BlockT> {
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
changes: &RefCell<OverlayedChanges>,
|
||||
storage_transaction_cache: Option<&RefCell<
|
||||
StorageTransactionCache<B, <Self::Backend as crate::backend::Backend<B>>::State>,
|
||||
>>,
|
||||
storage_transaction_cache: Option<
|
||||
&RefCell<
|
||||
StorageTransactionCache<B, <Self::Backend as crate::backend::Backend<B>>::State>,
|
||||
>,
|
||||
>,
|
||||
execution_manager: ExecutionManager<EM>,
|
||||
native_call: Option<NC>,
|
||||
proof_recorder: &Option<ProofRecorder<B>>,
|
||||
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
|
||||
///
|
||||
@@ -105,12 +108,13 @@ pub trait CallExecutor<B: BlockT> {
|
||||
mut state: S,
|
||||
overlay: &mut OverlayedChanges,
|
||||
method: &str,
|
||||
call_data: &[u8]
|
||||
call_data: &[u8],
|
||||
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error> {
|
||||
let trie_state = state.as_trie_backend()
|
||||
.ok_or_else(||
|
||||
sp_blockchain::Error::from_state(Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof) as Box<_>)
|
||||
)?;
|
||||
let trie_state = state.as_trie_backend().ok_or_else(|| {
|
||||
sp_blockchain::Error::from_state(Box::new(
|
||||
sp_state_machine::ExecutionError::UnableToGenerateProof,
|
||||
) as Box<_>)
|
||||
})?;
|
||||
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>>,
|
||||
overlay: &mut OverlayedChanges,
|
||||
method: &str,
|
||||
call_data: &[u8]
|
||||
call_data: &[u8],
|
||||
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error>;
|
||||
|
||||
/// Get runtime version if supported.
|
||||
|
||||
+115
-107
@@ -25,15 +25,15 @@
|
||||
//! root hash. A correct proof implies that the claimed block is identical to the one
|
||||
//! we discarded.
|
||||
|
||||
use hash_db;
|
||||
use codec::Encode;
|
||||
use hash_db;
|
||||
use sp_trie;
|
||||
|
||||
use sp_core::{H256, convert_hash};
|
||||
use sp_runtime::traits::{Header as HeaderT, AtLeast32Bit, Zero, One};
|
||||
use sp_core::{convert_hash, H256};
|
||||
use sp_runtime::traits::{AtLeast32Bit, Header as HeaderT, One, Zero};
|
||||
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};
|
||||
@@ -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.
|
||||
pub fn is_build_required<N>(cht_size: N, block_num: N) -> Option<N>
|
||||
where
|
||||
N: Clone + AtLeast32Bit,
|
||||
where
|
||||
N: Clone + AtLeast32Bit,
|
||||
{
|
||||
let block_cht_num = block_to_cht_number(cht_size.clone(), block_num.clone())?;
|
||||
let two = N::one() + N::one();
|
||||
if block_cht_num < two {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
let cht_start = start_number(cht_size, block_cht_num.clone());
|
||||
if cht_start != block_num {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
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.
|
||||
pub fn max_cht_number<N>(cht_size: N, max_canonical_block: N) -> Option<N>
|
||||
where
|
||||
N: Clone + AtLeast32Bit,
|
||||
where
|
||||
N: Clone + AtLeast32Bit,
|
||||
{
|
||||
let max_cht_number = block_to_cht_number(cht_size, max_canonical_block)?;
|
||||
let two = N::one() + N::one();
|
||||
if max_cht_number < two {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
Some(max_cht_number - two)
|
||||
}
|
||||
@@ -86,16 +86,16 @@ pub fn compute_root<Header, Hasher, I>(
|
||||
cht_num: Header::Number,
|
||||
hashes: I,
|
||||
) -> ClientResult<Hasher::Out>
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord,
|
||||
I: IntoIterator<Item=ClientResult<Option<Header::Hash>>>,
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord,
|
||||
I: IntoIterator<Item = ClientResult<Option<Header::Hash>>>,
|
||||
{
|
||||
use sp_trie::TrieConfiguration;
|
||||
Ok(sp_trie::trie_types::Layout::<Hasher>::trie_root(
|
||||
build_pairs::<Header, I>(cht_size, cht_num, hashes)?
|
||||
))
|
||||
Ok(sp_trie::trie_types::Layout::<Hasher>::trie_root(build_pairs::<Header, I>(
|
||||
cht_size, cht_num, hashes,
|
||||
)?))
|
||||
}
|
||||
|
||||
/// Build CHT-based header proof.
|
||||
@@ -103,26 +103,28 @@ pub fn build_proof<Header, Hasher, BlocksI, HashesI>(
|
||||
cht_size: Header::Number,
|
||||
cht_num: Header::Number,
|
||||
blocks: BlocksI,
|
||||
hashes: HashesI
|
||||
hashes: HashesI,
|
||||
) -> ClientResult<StorageProof>
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + codec::Codec,
|
||||
BlocksI: IntoIterator<Item=Header::Number>,
|
||||
HashesI: IntoIterator<Item=ClientResult<Option<Header::Hash>>>,
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + codec::Codec,
|
||||
BlocksI: IntoIterator<Item = Header::Number>,
|
||||
HashesI: IntoIterator<Item = ClientResult<Option<Header::Hash>>>,
|
||||
{
|
||||
let transaction = build_pairs::<Header, _>(cht_size, cht_num, hashes)?
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, Some(v)))
|
||||
.collect::<Vec<_>>();
|
||||
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");
|
||||
prove_read_on_trie_backend(
|
||||
trie_storage,
|
||||
blocks.into_iter().map(|number| encode_cht_key(number)),
|
||||
).map_err(ClientError::from_state)
|
||||
)
|
||||
.map_err(ClientError::from_state)
|
||||
}
|
||||
|
||||
/// Check CHT-based header proof.
|
||||
@@ -132,25 +134,24 @@ pub fn check_proof<Header, Hasher>(
|
||||
remote_hash: Header::Hash,
|
||||
remote_proof: StorageProof,
|
||||
) -> ClientResult<()>
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + codec::Codec,
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + codec::Codec,
|
||||
{
|
||||
do_check_proof::<Header, Hasher, _>(
|
||||
local_root,
|
||||
local_number,
|
||||
remote_hash,
|
||||
move |local_root, local_cht_key|
|
||||
move |local_root, local_cht_key| {
|
||||
read_proof_check::<Hasher, _>(
|
||||
local_root,
|
||||
remote_proof,
|
||||
::std::iter::once(local_cht_key),
|
||||
)
|
||||
.map(|mut map| map
|
||||
.remove(local_cht_key)
|
||||
.expect("checked proof of local_cht_key; qed"))
|
||||
.map_err(ClientError::from_state),
|
||||
.map(|mut map| map.remove(local_cht_key).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,
|
||||
proving_backend: &TrieBackend<MemoryDB<Hasher>, Hasher>,
|
||||
) -> ClientResult<()>
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + codec::Codec,
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + codec::Codec,
|
||||
{
|
||||
do_check_proof::<Header, Hasher, _>(
|
||||
local_root,
|
||||
local_number,
|
||||
remote_hash,
|
||||
|_, local_cht_key|
|
||||
read_proof_check_on_proving_backend::<Hasher>(
|
||||
proving_backend,
|
||||
local_cht_key,
|
||||
).map_err(ClientError::from_state),
|
||||
|_, local_cht_key| {
|
||||
read_proof_check_on_proving_backend::<Hasher>(proving_backend, local_cht_key)
|
||||
.map_err(ClientError::from_state)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -185,22 +185,22 @@ fn do_check_proof<Header, Hasher, F>(
|
||||
remote_hash: Header::Hash,
|
||||
checker: F,
|
||||
) -> ClientResult<()>
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord,
|
||||
F: FnOnce(Hasher::Out, &[u8]) -> ClientResult<Option<Vec<u8>>>,
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord,
|
||||
F: FnOnce(Hasher::Out, &[u8]) -> ClientResult<Option<Vec<u8>>>,
|
||||
{
|
||||
let root: Hasher::Out = convert_hash(&local_root);
|
||||
let local_cht_key = encode_cht_key(local_number);
|
||||
let local_cht_value = checker(root, &local_cht_key)?;
|
||||
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() {
|
||||
true => Ok(()),
|
||||
false => Err(ClientError::InvalidCHTProof.into()),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// 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_param: P,
|
||||
) -> ClientResult<()>
|
||||
where
|
||||
Header: HeaderT,
|
||||
I: IntoIterator<Item=Header::Number>,
|
||||
F: FnMut(P, Header::Number, Vec<Header::Number>) -> ClientResult<P>,
|
||||
where
|
||||
Header: HeaderT,
|
||||
I: IntoIterator<Item = Header::Number>,
|
||||
F: FnMut(P, Header::Number, Vec<Header::Number>) -> ClientResult<P>,
|
||||
{
|
||||
let mut current_cht_num = None;
|
||||
let mut current_cht_blocks = Vec::new();
|
||||
for block in blocks {
|
||||
let new_cht_num = block_to_cht_number(cht_size, block).ok_or_else(|| ClientError::Backend(format!(
|
||||
"Cannot compute CHT root for the block #{}", block))
|
||||
)?;
|
||||
let new_cht_num = block_to_cht_number(cht_size, block).ok_or_else(|| {
|
||||
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);
|
||||
if advance_to_next_cht {
|
||||
let current_cht_num = current_cht_num.expect("advance_to_next_cht is true;
|
||||
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");
|
||||
let current_cht_num = current_cht_num.expect(
|
||||
"advance_to_next_cht is true;
|
||||
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,
|
||||
current_cht_num,
|
||||
std::mem::take(&mut current_cht_blocks),
|
||||
)?;
|
||||
functor_param =
|
||||
functor(functor_param, current_cht_num, std::mem::take(&mut current_cht_blocks))?;
|
||||
}
|
||||
|
||||
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 {
|
||||
functor(
|
||||
functor_param,
|
||||
current_cht_num,
|
||||
std::mem::take(&mut current_cht_blocks),
|
||||
)?;
|
||||
functor(functor_param, current_cht_num, std::mem::take(&mut current_cht_blocks))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -254,26 +252,22 @@ pub fn for_each_cht_group<Header, I, F, P>(
|
||||
fn build_pairs<Header, I>(
|
||||
cht_size: Header::Number,
|
||||
cht_num: Header::Number,
|
||||
hashes: I
|
||||
hashes: I,
|
||||
) -> ClientResult<Vec<(Vec<u8>, Vec<u8>)>>
|
||||
where
|
||||
Header: HeaderT,
|
||||
I: IntoIterator<Item=ClientResult<Option<Header::Hash>>>,
|
||||
where
|
||||
Header: HeaderT,
|
||||
I: IntoIterator<Item = ClientResult<Option<Header::Hash>>>,
|
||||
{
|
||||
let start_num = start_number(cht_size, cht_num);
|
||||
let mut pairs = Vec::new();
|
||||
let mut hash_index = Header::Number::zero();
|
||||
for hash in hashes.into_iter() {
|
||||
let hash = hash?.ok_or_else(|| ClientError::from(
|
||||
ClientError::MissingHashRequiredForCHT
|
||||
))?;
|
||||
pairs.push((
|
||||
encode_cht_key(start_num + hash_index).to_vec(),
|
||||
encode_cht_value(hash)
|
||||
));
|
||||
let hash =
|
||||
hash?.ok_or_else(|| ClientError::from(ClientError::MissingHashRequiredForCHT))?;
|
||||
pairs.push((encode_cht_key(start_num + hash_index).to_vec(), encode_cht_value(hash)));
|
||||
hash_index += Header::Number::one();
|
||||
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])),
|
||||
_ => None,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -379,8 +372,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn build_pairs_fails_when_no_enough_blocks() {
|
||||
assert!(build_pairs::<Header, _>(SIZE as _, 0,
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize / 2)).is_err());
|
||||
assert!(build_pairs::<Header, _>(
|
||||
SIZE as _,
|
||||
0,
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize / 2)
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -391,9 +388,12 @@ mod tests {
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
||||
.take(SIZE as usize / 2)
|
||||
.chain(::std::iter::once(Ok(None)))
|
||||
.chain(::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(2))))
|
||||
.take(SIZE as usize / 2 - 1))
|
||||
).is_err());
|
||||
.chain(
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(2))))
|
||||
.take(SIZE as usize / 2 - 1)
|
||||
)
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -401,9 +401,9 @@ mod tests {
|
||||
assert!(compute_root::<Header, BlakeTwo256, _>(
|
||||
SIZE as _,
|
||||
42,
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
||||
.take(SIZE as usize)
|
||||
).is_ok());
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize)
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -413,9 +413,9 @@ mod tests {
|
||||
SIZE as _,
|
||||
0,
|
||||
vec![(SIZE * 1000) as u64],
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
||||
.take(SIZE as usize)
|
||||
).is_err());
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize)
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -424,9 +424,9 @@ mod tests {
|
||||
SIZE as _,
|
||||
0,
|
||||
vec![(SIZE / 2) as u64],
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
||||
.take(SIZE as usize)
|
||||
).is_ok());
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize)
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -447,19 +447,27 @@ mod tests {
|
||||
let _ = for_each_cht_group::<Header, _, _, _>(
|
||||
cht_size,
|
||||
vec![
|
||||
cht_size * 2 + 1, cht_size * 2 + 2, cht_size * 2 + 5,
|
||||
cht_size * 4 + 1, cht_size * 4 + 7,
|
||||
cht_size * 6 + 1
|
||||
], |_, cht_num, blocks| {
|
||||
cht_size * 2 + 1,
|
||||
cht_size * 2 + 2,
|
||||
cht_size * 2 + 5,
|
||||
cht_size * 4 + 1,
|
||||
cht_size * 4 + 7,
|
||||
cht_size * 6 + 1,
|
||||
],
|
||||
|_, cht_num, blocks| {
|
||||
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]),
|
||||
6 => assert_eq!(blocks, vec![cht_size * 6 + 1]),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}, ()
|
||||
},
|
||||
(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
|
||||
//! 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_runtime::{
|
||||
traits::{Block as BlockT, NumberFor},
|
||||
generic::{BlockId, SignedBlock},
|
||||
traits::{Block as BlockT, NumberFor},
|
||||
Justifications,
|
||||
};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use std::{collections::HashSet, convert::TryFrom, fmt, sync::Arc};
|
||||
|
||||
use crate::blockchain::Info;
|
||||
use crate::notifications::StorageEventStream;
|
||||
use sp_utils::mpsc::TracingUnboundedReceiver;
|
||||
use sp_blockchain;
|
||||
use crate::{blockchain::Info, notifications::StorageEventStream};
|
||||
use sc_transaction_pool_api::ChainEvent;
|
||||
use sp_blockchain;
|
||||
use sp_utils::mpsc::TracingUnboundedReceiver;
|
||||
|
||||
/// Type that implements `futures::Stream` of block import events.
|
||||
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.
|
||||
fn block_body(
|
||||
&self,
|
||||
id: &BlockId<Block>
|
||||
id: &BlockId<Block>,
|
||||
) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
|
||||
|
||||
/// 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>>>;
|
||||
|
||||
/// 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.
|
||||
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.
|
||||
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
|
||||
/// that are indexed by the runtime with `storage_index_transaction`.
|
||||
fn indexed_transaction(
|
||||
&self,
|
||||
hash: &Block::Hash,
|
||||
) -> sp_blockchain::Result<Option<Vec<u8>>>;
|
||||
fn indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result<Option<Vec<u8>>>;
|
||||
|
||||
/// Check if transaction index exists.
|
||||
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.
|
||||
pub trait ProvideUncles<Block: BlockT> {
|
||||
/// 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>)
|
||||
-> sp_blockchain::Result<Vec<Block::Header>>;
|
||||
fn uncles(
|
||||
&self,
|
||||
target_hash: Block::Hash,
|
||||
max_generation: NumberFor<Block>,
|
||||
) -> sp_blockchain::Result<Vec<Block::Header>>;
|
||||
}
|
||||
|
||||
/// Client info
|
||||
@@ -284,10 +284,7 @@ impl<B: BlockT> TryFrom<BlockImportNotification<B>> for ChainEvent<B> {
|
||||
|
||||
fn try_from(n: BlockImportNotification<B>) -> Result<Self, ()> {
|
||||
if n.is_new_best {
|
||||
Ok(Self::NewBestBlock {
|
||||
hash: n.hash,
|
||||
tree_route: n.tree_route,
|
||||
})
|
||||
Ok(Self::NewBestBlock { hash: n.hash, tree_route: n.tree_route })
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
@@ -296,8 +293,6 @@ impl<B: BlockT> TryFrom<BlockImportNotification<B>> for ChainEvent<B> {
|
||||
|
||||
impl<B: BlockT> From<FinalityNotification<B>> for ChainEvent<B> {
|
||||
fn from(n: FinalityNotification<B>) -> Self {
|
||||
Self::Finalized {
|
||||
hash: n.hash,
|
||||
}
|
||||
Self::Finalized { hash: n.hash }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,22 +22,19 @@
|
||||
//! strategy for the runtime calls and provide the right `Externalities`
|
||||
//! extensions to support APIs for particular execution context & capabilities.
|
||||
|
||||
use std::sync::{Weak, Arc};
|
||||
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 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.
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -151,7 +148,8 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
||||
|
||||
/// Register transaction pool extension.
|
||||
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 _);
|
||||
}
|
||||
@@ -171,14 +169,10 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
||||
|
||||
if capabilities.has(offchain::Capability::TransactionPool) {
|
||||
if let Some(pool) = self.transaction_pool.read().as_ref().and_then(|x| x.upgrade()) {
|
||||
extensions.register(
|
||||
TransactionPoolExt(
|
||||
Box::new(TransactionPoolAdapter {
|
||||
at: *at,
|
||||
pool,
|
||||
}) as _
|
||||
),
|
||||
);
|
||||
extensions
|
||||
.register(TransactionPoolExt(
|
||||
Box::new(TransactionPoolAdapter { at: *at, pool }) as _,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,19 +180,18 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
||||
capabilities.has(offchain::Capability::OffchainDbWrite)
|
||||
{
|
||||
if let Some(offchain_db) = self.offchain_db.as_ref() {
|
||||
extensions.register(
|
||||
OffchainDbExt::new(offchain::LimitedExternalities::new(
|
||||
capabilities,
|
||||
offchain_db.create(),
|
||||
))
|
||||
);
|
||||
extensions.register(OffchainDbExt::new(offchain::LimitedExternalities::new(
|
||||
capabilities,
|
||||
offchain_db.create(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
if let ExecutionContext::OffchainCall(Some(ext)) = context {
|
||||
extensions.register(
|
||||
OffchainWorkerExt::new(offchain::LimitedExternalities::new(capabilities, ext.0)),
|
||||
);
|
||||
extensions.register(OffchainWorkerExt::new(offchain::LimitedExternalities::new(
|
||||
capabilities,
|
||||
ext.0,
|
||||
)));
|
||||
}
|
||||
|
||||
extensions
|
||||
@@ -212,21 +205,14 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
context: ExecutionContext,
|
||||
) -> (
|
||||
ExecutionManager<DefaultHandler<R, E>>,
|
||||
Extensions,
|
||||
) {
|
||||
) -> (ExecutionManager<DefaultHandler<R, E>>, Extensions) {
|
||||
let manager = match context {
|
||||
ExecutionContext::BlockConstruction =>
|
||||
self.strategies.block_construction.get_manager(),
|
||||
ExecutionContext::Syncing =>
|
||||
self.strategies.syncing.get_manager(),
|
||||
ExecutionContext::Importing =>
|
||||
self.strategies.importing.get_manager(),
|
||||
ExecutionContext::BlockConstruction => self.strategies.block_construction.get_manager(),
|
||||
ExecutionContext::Syncing => self.strategies.syncing.get_manager(),
|
||||
ExecutionContext::Importing => self.strategies.importing.get_manager(),
|
||||
ExecutionContext::OffchainCall(Some((_, capabilities))) if capabilities.has_all() =>
|
||||
self.strategies.offchain_worker.get_manager(),
|
||||
ExecutionContext::OffchainCall(_) =>
|
||||
self.strategies.other.get_manager(),
|
||||
ExecutionContext::OffchainCall(_) => self.strategies.other.get_manager(),
|
||||
};
|
||||
|
||||
(manager, self.extensions(at, context))
|
||||
@@ -245,7 +231,7 @@ impl<Block: traits::Block> offchain::TransactionPool for TransactionPoolAdapter<
|
||||
Ok(xt) => xt,
|
||||
Err(e) => {
|
||||
log::warn!("Unable to decode extrinsic: {:?}: {}", data, e);
|
||||
return Err(());
|
||||
return Err(())
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
+231
-137
@@ -18,30 +18,31 @@
|
||||
|
||||
//! In memory client backend
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
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_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::{
|
||||
backend::{self, NewBlockState, ProvideChtRoots},
|
||||
blockchain::{
|
||||
self, BlockStatus, HeaderBackend, well_known_cache_keys::Id as CacheKeyId
|
||||
},
|
||||
UsageInfo,
|
||||
light,
|
||||
blockchain::{self, well_known_cache_keys::Id as CacheKeyId, BlockStatus, HeaderBackend},
|
||||
leaves::LeafSet,
|
||||
light, UsageInfo,
|
||||
};
|
||||
|
||||
struct PendingBlock<B: BlockT> {
|
||||
@@ -56,7 +57,11 @@ enum StoredBlock<B: BlockT> {
|
||||
}
|
||||
|
||||
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 {
|
||||
Some(body) => StoredBlock::Full(B::new(header, body), just),
|
||||
None => StoredBlock::Header(header, just),
|
||||
@@ -72,7 +77,7 @@ impl<B: BlockT> StoredBlock<B> {
|
||||
|
||||
fn justifications(&self) -> Option<&Justifications> {
|
||||
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) => {
|
||||
let (header, body) = block.deconstruct();
|
||||
(header, Some(body), just)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,9 +128,7 @@ impl<Block: BlockT> Default for Blockchain<Block> {
|
||||
impl<Block: BlockT + Clone> Clone for Blockchain<Block> {
|
||||
fn clone(&self) -> Self {
|
||||
let storage = Arc::new(RwLock::new(self.storage.read().clone()));
|
||||
Blockchain {
|
||||
storage,
|
||||
}
|
||||
Blockchain { storage }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,23 +143,20 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
|
||||
/// Create new in-memory blockchain storage.
|
||||
pub fn new() -> Blockchain<Block> {
|
||||
let storage = Arc::new(RwLock::new(
|
||||
BlockchainStorage {
|
||||
blocks: HashMap::new(),
|
||||
hashes: HashMap::new(),
|
||||
best_hash: Default::default(),
|
||||
best_number: Zero::zero(),
|
||||
finalized_hash: Default::default(),
|
||||
finalized_number: Zero::zero(),
|
||||
genesis_hash: Default::default(),
|
||||
header_cht_roots: HashMap::new(),
|
||||
changes_trie_cht_roots: HashMap::new(),
|
||||
leaves: LeafSet::new(),
|
||||
aux: HashMap::new(),
|
||||
}));
|
||||
Blockchain {
|
||||
storage,
|
||||
}
|
||||
let storage = Arc::new(RwLock::new(BlockchainStorage {
|
||||
blocks: HashMap::new(),
|
||||
hashes: HashMap::new(),
|
||||
best_hash: Default::default(),
|
||||
best_number: Zero::zero(),
|
||||
finalized_hash: Default::default(),
|
||||
finalized_number: Zero::zero(),
|
||||
genesis_hash: Default::default(),
|
||||
header_cht_roots: HashMap::new(),
|
||||
changes_trie_cht_roots: HashMap::new(),
|
||||
leaves: LeafSet::new(),
|
||||
aux: HashMap::new(),
|
||||
}));
|
||||
Blockchain { storage }
|
||||
}
|
||||
|
||||
/// Insert a block header and associated data.
|
||||
@@ -175,8 +175,12 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
|
||||
{
|
||||
let mut storage = self.storage.write();
|
||||
storage.leaves.import(hash.clone(), number.clone(), header.parent_hash().clone());
|
||||
storage.blocks.insert(hash.clone(), StoredBlock::new(header, body, justifications));
|
||||
storage
|
||||
.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 {
|
||||
storage.finalized_hash = hash;
|
||||
@@ -200,7 +204,7 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
pub fn equals_to(&self, other: &Self) -> bool {
|
||||
// Check ptr equality first to avoid double read locks.
|
||||
if ptr::eq(self, other) {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
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 {
|
||||
// Check ptr equality first to avoid double read locks.
|
||||
if ptr::eq(self, other) {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
let this = self.storage.read();
|
||||
let other = other.storage.read();
|
||||
this.hashes == other.hashes
|
||||
&& this.best_hash == other.best_hash
|
||||
&& this.best_number == other.best_number
|
||||
&& this.genesis_hash == other.genesis_hash
|
||||
this.hashes == other.hashes &&
|
||||
this.best_hash == other.best_hash &&
|
||||
this.best_number == other.best_number &&
|
||||
this.genesis_hash == other.genesis_hash
|
||||
}
|
||||
|
||||
/// Insert header CHT root.
|
||||
@@ -226,7 +230,8 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
|
||||
/// Set an existing block as head.
|
||||
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)))?;
|
||||
|
||||
self.apply_head(&header)
|
||||
@@ -270,7 +275,11 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
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)? {
|
||||
Some(h) => h.hash(),
|
||||
None => return Err(sp_blockchain::Error::UnknownBlock(format!("{}", id))),
|
||||
@@ -280,11 +289,13 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
storage.finalized_hash = hash;
|
||||
|
||||
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");
|
||||
|
||||
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);
|
||||
@@ -293,9 +304,11 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn append_justification(&self, id: BlockId<Block>, justification: Justification)
|
||||
-> sp_blockchain::Result<()>
|
||||
{
|
||||
fn append_justification(
|
||||
&self,
|
||||
id: BlockId<Block>,
|
||||
justification: Justification,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
let hash = self.expect_block_hash_from_id(&id)?;
|
||||
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");
|
||||
|
||||
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 !stored_justifications.append(justification) {
|
||||
return Err(sp_blockchain::Error::BadJustification(
|
||||
"Duplicate consensus engine ID".into()
|
||||
));
|
||||
"Duplicate consensus engine ID".into(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
*block_justifications = Some(Justifications::from(justification));
|
||||
@@ -333,10 +346,13 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
}
|
||||
|
||||
impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
|
||||
fn header(&self, 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 header(
|
||||
&self,
|
||||
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> {
|
||||
@@ -352,7 +368,7 @@ impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
|
||||
} else {
|
||||
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()))
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
}
|
||||
@@ -375,9 +394,15 @@ impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
|
||||
impl<Block: BlockT> HeaderMetadata<Block> for Blockchain<Block> {
|
||||
type Error = sp_blockchain::Error;
|
||||
|
||||
fn header_metadata(&self, 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 header_metadata(
|
||||
&self,
|
||||
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>) {
|
||||
@@ -389,17 +414,27 @@ impl<Block: BlockT> HeaderMetadata<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| {
|
||||
self.storage.read().blocks.get(&hash)
|
||||
self.storage
|
||||
.read()
|
||||
.blocks
|
||||
.get(&hash)
|
||||
.and_then(|b| b.extrinsics().map(|x| x.to_vec()))
|
||||
}))
|
||||
}
|
||||
|
||||
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|
|
||||
b.justifications().map(|x| x.clone()))
|
||||
))
|
||||
Ok(self.id(id).and_then(|hash| {
|
||||
self.storage
|
||||
.read()
|
||||
.blocks
|
||||
.get(&hash)
|
||||
.and_then(|b| b.justifications().map(|x| x.clone()))
|
||||
}))
|
||||
}
|
||||
|
||||
fn last_finalized(&self) -> sp_blockchain::Result<Block::Hash> {
|
||||
@@ -418,16 +453,13 @@ impl<Block: BlockT> blockchain::Backend<Block> for Blockchain<Block> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn indexed_transaction(
|
||||
&self,
|
||||
_hash: &Block::Hash,
|
||||
) -> sp_blockchain::Result<Option<Vec<u8>>> {
|
||||
fn indexed_transaction(&self, _hash: &Block::Hash) -> sp_blockchain::Result<Option<Vec<u8>>> {
|
||||
unimplemented!("Not supported by the in-mem backend.")
|
||||
}
|
||||
|
||||
fn block_indexed_body(
|
||||
&self,
|
||||
_id: BlockId<Block>
|
||||
_id: BlockId<Block>,
|
||||
) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>> {
|
||||
unimplemented!("Not supported by the in-mem backend.")
|
||||
}
|
||||
@@ -444,9 +476,13 @@ impl<Block: BlockT> backend::AuxStore for Blockchain<Block> {
|
||||
'a,
|
||||
'b: 'a,
|
||||
'c: 'a,
|
||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
||||
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()> {
|
||||
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||
>(
|
||||
&self,
|
||||
insert: I,
|
||||
delete: D,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
let mut storage = self.storage.write();
|
||||
for (k, v) in insert {
|
||||
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>
|
||||
where
|
||||
Block::Hash: From<[u8; 32]>,
|
||||
where
|
||||
Block::Hash: From<[u8; 32]>,
|
||||
{
|
||||
fn import_header(
|
||||
&self,
|
||||
@@ -507,8 +543,14 @@ impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
|
||||
_cht_size: NumberFor<Block>,
|
||||
block: NumberFor<Block>,
|
||||
) -> sp_blockchain::Result<Option<Block::Hash>> {
|
||||
self.storage.read().header_cht_roots.get(&block).cloned()
|
||||
.ok_or_else(|| sp_blockchain::Error::Backend(format!("Header CHT for block {} not exists", block)))
|
||||
self.storage
|
||||
.read()
|
||||
.header_cht_roots
|
||||
.get(&block)
|
||||
.cloned()
|
||||
.ok_or_else(|| {
|
||||
sp_blockchain::Error::Backend(format!("Header CHT for block {} not exists", block))
|
||||
})
|
||||
.map(Some)
|
||||
}
|
||||
|
||||
@@ -517,8 +559,17 @@ impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
|
||||
_cht_size: NumberFor<Block>,
|
||||
block: NumberFor<Block>,
|
||||
) -> sp_blockchain::Result<Option<Block::Hash>> {
|
||||
self.storage.read().changes_trie_cht_roots.get(&block).cloned()
|
||||
.ok_or_else(|| sp_blockchain::Error::Backend(format!("Changes trie CHT for block {} not exists", block)))
|
||||
self.storage
|
||||
.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)
|
||||
}
|
||||
}
|
||||
@@ -527,25 +578,30 @@ impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
|
||||
pub struct BlockImportOperation<Block: BlockT> {
|
||||
pending_block: Option<PendingBlock<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>>)>,
|
||||
finalized_blocks: Vec<(BlockId<Block>, Option<Justification>)>,
|
||||
set_head: Option<BlockId<Block>>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> BlockImportOperation<Block> where
|
||||
impl<Block: BlockT> BlockImportOperation<Block>
|
||||
where
|
||||
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)?;
|
||||
|
||||
let child_delta = storage.children_default.iter()
|
||||
.map(|(_storage_key, child_content)|
|
||||
(
|
||||
&child_content.child_info,
|
||||
child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref())))
|
||||
)
|
||||
);
|
||||
let child_delta = storage.children_default.iter().map(|(_storage_key, child_content)| {
|
||||
(
|
||||
&child_content.child_info,
|
||||
child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))),
|
||||
)
|
||||
});
|
||||
|
||||
let (root, transaction) = self.old_state.full_storage_root(
|
||||
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,
|
||||
{
|
||||
type State = InMemoryBackend<HashFor<Block>>;
|
||||
@@ -577,10 +634,8 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
||||
state: NewBlockState,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
assert!(self.pending_block.is_none(), "Only one block per operation is allowed");
|
||||
self.pending_block = Some(PendingBlock {
|
||||
block: StoredBlock::new(header, body, justifications),
|
||||
state,
|
||||
});
|
||||
self.pending_block =
|
||||
Some(PendingBlock { block: StoredBlock::new(header, body, justifications), state });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -601,7 +656,11 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -610,7 +669,8 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
||||
}
|
||||
|
||||
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());
|
||||
Ok(())
|
||||
@@ -639,7 +699,10 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
||||
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(())
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
/// > 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>>>>,
|
||||
blockchain: Blockchain<Block>,
|
||||
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.
|
||||
pub fn new() -> Self {
|
||||
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<
|
||||
'a,
|
||||
'b: 'a,
|
||||
'c: 'a,
|
||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
||||
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()> {
|
||||
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||
>(
|
||||
&self,
|
||||
insert: I,
|
||||
delete: D,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
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 Blockchain = Blockchain<Block>;
|
||||
type State = InMemoryBackend<HashFor<Block>>;
|
||||
@@ -708,10 +787,7 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn commit_operation(
|
||||
&self,
|
||||
operation: Self::BlockImportOperation,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
fn commit_operation(&self, operation: Self::BlockImportOperation) -> sp_blockchain::Result<()> {
|
||||
if !operation.finalized_blocks.is_empty() {
|
||||
for (block, justification) in operation.finalized_blocks {
|
||||
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> {
|
||||
match block {
|
||||
BlockId::Hash(h) if h == Default::default() => {
|
||||
return Ok(Self::State::default());
|
||||
},
|
||||
BlockId::Hash(h) if h == Default::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)))
|
||||
}
|
||||
|
||||
@@ -797,10 +873,7 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
||||
Ok((Zero::zero(), HashSet::new()))
|
||||
}
|
||||
|
||||
fn remove_leaf_block(
|
||||
&self,
|
||||
_hash: &Block::Hash,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
fn remove_leaf_block(&self, _hash: &Block::Hash) -> sp_blockchain::Result<()> {
|
||||
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::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 {
|
||||
self.blockchain.expect_block_number_from_id(block)
|
||||
self.blockchain
|
||||
.expect_block_number_from_id(block)
|
||||
.map(|num| num.is_zero())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
@@ -826,12 +903,15 @@ impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block> where Block
|
||||
/// Check that genesis storage is valid.
|
||||
pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
|
||||
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()
|
||||
.any(|child_key| !well_known_keys::is_child_storage_key(&child_key)) {
|
||||
return Err(sp_blockchain::Error::InvalidState.into());
|
||||
if storage
|
||||
.children_default
|
||||
.keys()
|
||||
.any(|child_key| !well_known_keys::is_child_storage_key(&child_key))
|
||||
{
|
||||
return Err(sp_blockchain::Error::InvalidState.into())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -839,10 +919,10 @@ pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{NewBlockState, in_mem::Blockchain};
|
||||
use crate::{in_mem::Blockchain, NewBlockState};
|
||||
use sp_api::{BlockId, HeaderT};
|
||||
use sp_runtime::{ConsensusEngineId, Justifications};
|
||||
use sp_blockchain::Backend;
|
||||
use sp_runtime::{ConsensusEngineId, Justifications};
|
||||
use substrate_test_runtime::{Block, Header, H256};
|
||||
|
||||
pub const ID1: ConsensusEngineId = *b"TST1";
|
||||
@@ -853,7 +933,13 @@ mod tests {
|
||||
0 => Default::default(),
|
||||
_ => 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> {
|
||||
@@ -862,10 +948,18 @@ mod tests {
|
||||
let just1 = Some(Justifications::from((ID1, vec![1])));
|
||||
let just2 = None;
|
||||
let just3 = Some(Justifications::from((ID1, vec![3])));
|
||||
blockchain.insert(header(0).hash(), header(0), just0, 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
|
||||
.insert(header(0).hash(), header(0), just0, 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
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,11 @@
|
||||
|
||||
//! Helper for managing the set of available leaves in the chain for DB implementations.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::cmp::Reverse;
|
||||
use codec::{Decode, Encode};
|
||||
use sp_blockchain::{Error, Result};
|
||||
use sp_database::{Database, Transaction};
|
||||
use sp_runtime::traits::AtLeast32Bit;
|
||||
use codec::{Encode, Decode};
|
||||
use sp_blockchain::{Error, Result};
|
||||
use std::{cmp::Reverse, collections::BTreeMap};
|
||||
|
||||
type DbHash = sp_core::H256;
|
||||
|
||||
@@ -57,7 +56,7 @@ impl<H, N: Ord> FinalizationDisplaced<H, N> {
|
||||
}
|
||||
|
||||
/// 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()
|
||||
}
|
||||
}
|
||||
@@ -72,17 +71,14 @@ pub struct LeafSet<H, N> {
|
||||
pending_removed: Vec<H>,
|
||||
}
|
||||
|
||||
impl<H, N> LeafSet<H, N> where
|
||||
impl<H, N> LeafSet<H, N>
|
||||
where
|
||||
H: Clone + PartialEq + Decode + Encode,
|
||||
N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode,
|
||||
{
|
||||
/// Construct a new, blank leaf set.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
storage: BTreeMap::new(),
|
||||
pending_added: Vec::new(),
|
||||
pending_removed: Vec::new(),
|
||||
}
|
||||
Self { storage: BTreeMap::new(), pending_added: Vec::new(), pending_removed: Vec::new() }
|
||||
}
|
||||
|
||||
/// 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() {
|
||||
storage.insert(Reverse(number), hashes);
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
Ok(Self {
|
||||
storage,
|
||||
pending_added: Vec::new(),
|
||||
pending_removed: Vec::new(),
|
||||
})
|
||||
Ok(Self { storage, pending_added: Vec::new(), pending_removed: Vec::new() })
|
||||
}
|
||||
|
||||
/// 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());
|
||||
Some(ImportDisplaced {
|
||||
new_hash: hash.clone(),
|
||||
displaced: LeafSetItem {
|
||||
hash: parent_hash,
|
||||
number: new_number,
|
||||
},
|
||||
displaced: LeafSetItem { hash: parent_hash, number: new_number },
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -144,16 +133,15 @@ impl<H, N> LeafSet<H, N> where
|
||||
/// will be pruned soon afterwards anyway.
|
||||
pub fn finalize_height(&mut self, number: N) -> FinalizationDisplaced<H, N> {
|
||||
let boundary = if number == N::zero() {
|
||||
return FinalizationDisplaced { leaves: BTreeMap::new() };
|
||||
return FinalizationDisplaced { leaves: BTreeMap::new() }
|
||||
} else {
|
||||
number - N::one()
|
||||
};
|
||||
|
||||
let below_boundary = self.storage.split_off(&Reverse(boundary));
|
||||
self.pending_removed.extend(below_boundary.values().flat_map(|h| h.iter()).cloned());
|
||||
FinalizationDisplaced {
|
||||
leaves: below_boundary,
|
||||
}
|
||||
self.pending_removed
|
||||
.extend(below_boundary.values().flat_map(|h| h.iter()).cloned());
|
||||
FinalizationDisplaced { leaves: below_boundary }
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// with a block number higher than the target.
|
||||
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())))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -185,7 +175,8 @@ impl<H, N> LeafSet<H, N> where
|
||||
}
|
||||
|
||||
let best_number = Reverse(best_number);
|
||||
let leaves_contains_best = self.storage
|
||||
let leaves_contains_best = self
|
||||
.storage
|
||||
.get(&best_number)
|
||||
.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.
|
||||
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();
|
||||
tx.set_from_vec(column, prefix, leaves.encode());
|
||||
self.pending_added.clear();
|
||||
@@ -218,7 +214,9 @@ impl<H, N> LeafSet<H, N> where
|
||||
|
||||
/// Check if given block is a leaf.
|
||||
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) {
|
||||
@@ -230,14 +228,18 @@ impl<H, N> LeafSet<H, N> where
|
||||
let mut empty = false;
|
||||
let removed = self.storage.get_mut(number).map_or(false, |leaves| {
|
||||
let mut found = false;
|
||||
leaves.retain(|h| if h == hash {
|
||||
found = true;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
leaves.retain(|h| {
|
||||
if h == hash {
|
||||
found = true;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
if leaves.is_empty() { empty = true }
|
||||
if leaves.is_empty() {
|
||||
empty = true
|
||||
}
|
||||
|
||||
found
|
||||
});
|
||||
@@ -255,7 +257,8 @@ pub struct Undo<'a, H: 'a, N: 'a> {
|
||||
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,
|
||||
N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode,
|
||||
{
|
||||
@@ -329,7 +332,7 @@ mod tests {
|
||||
fn two_leaves_same_height_can_be_included() {
|
||||
let mut set = LeafSet::new();
|
||||
|
||||
set.import(1_1u32, 10u32,0u32);
|
||||
set.import(1_1u32, 10u32, 0u32);
|
||||
set.import(1_2, 10, 0);
|
||||
|
||||
assert!(set.storage.contains_key(&Reverse(10)));
|
||||
|
||||
@@ -21,30 +21,28 @@
|
||||
|
||||
pub mod backend;
|
||||
pub mod call_executor;
|
||||
pub mod client;
|
||||
pub mod cht;
|
||||
pub mod client;
|
||||
pub mod execution_extensions;
|
||||
pub mod in_mem;
|
||||
pub mod light;
|
||||
pub mod leaves;
|
||||
pub mod light;
|
||||
pub mod notifications;
|
||||
pub mod proof_provider;
|
||||
|
||||
pub use sp_blockchain as blockchain;
|
||||
pub use backend::*;
|
||||
pub use notifications::*;
|
||||
pub use call_executor::*;
|
||||
pub use client::*;
|
||||
pub use light::*;
|
||||
pub use notifications::*;
|
||||
pub use proof_provider::*;
|
||||
pub use sp_blockchain as blockchain;
|
||||
pub use sp_blockchain::HeaderBackend;
|
||||
|
||||
pub use sp_state_machine::{StorageProof, ExecutionStrategy};
|
||||
pub use sp_storage::{StorageData, StorageKey, PrefixedStorageKey, ChildInfo};
|
||||
pub use sp_state_machine::{ExecutionStrategy, StorageProof};
|
||||
pub use sp_storage::{ChildInfo, PrefixedStorageKey, StorageData, StorageKey};
|
||||
|
||||
/// Usage Information Provider interface
|
||||
///
|
||||
pub trait UsageProvider<Block: sp_runtime::traits::Block> {
|
||||
/// Get usage info about current client.
|
||||
fn usage_info(&self) -> ClientInfo<Block>;
|
||||
@@ -52,7 +50,7 @@ pub trait UsageProvider<Block: sp_runtime::traits::Block> {
|
||||
|
||||
/// Utility methods for the client.
|
||||
pub mod utils {
|
||||
use sp_blockchain::{HeaderBackend, HeaderMetadata, Error};
|
||||
use sp_blockchain::{Error, HeaderBackend, HeaderMetadata};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
@@ -66,19 +64,24 @@ pub mod utils {
|
||||
client: &'a T,
|
||||
current: Option<(Block::Hash, Block::Hash)>,
|
||||
) -> 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| {
|
||||
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 mut hash = hash;
|
||||
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 base == current_parent_hash {
|
||||
return Ok(true);
|
||||
return Ok(true)
|
||||
} else {
|
||||
hash = current_parent_hash;
|
||||
}
|
||||
|
||||
@@ -18,23 +18,26 @@
|
||||
|
||||
//! Substrate light client interfaces
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::future::Future;
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
future::Future,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use sp_runtime::{
|
||||
traits::{
|
||||
Block as BlockT, Header as HeaderT, NumberFor,
|
||||
},
|
||||
generic::BlockId
|
||||
use crate::{
|
||||
backend::{AuxStore, NewBlockState},
|
||||
ProvideChtRoots, UsageInfo,
|
||||
};
|
||||
use sp_core::{ChangesTrieConfigurationRange, storage::PrefixedStorageKey};
|
||||
use sp_state_machine::StorageProof;
|
||||
use sp_blockchain::{
|
||||
HeaderMetadata, well_known_cache_keys, HeaderBackend, Cache as BlockchainCache,
|
||||
Error as ClientError, Result as ClientResult,
|
||||
well_known_cache_keys, Cache as BlockchainCache, Error as ClientError, HeaderBackend,
|
||||
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.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
@@ -142,48 +145,48 @@ pub struct RemoteBodyRequest<Header: HeaderT> {
|
||||
/// is correct (see FetchedDataChecker) and return already checked data.
|
||||
pub trait Fetcher<Block: BlockT>: Send + Sync {
|
||||
/// Remote header future.
|
||||
type RemoteHeaderResult: Future<Output = Result<
|
||||
Block::Header,
|
||||
ClientError,
|
||||
>> + Unpin + Send + 'static;
|
||||
type RemoteHeaderResult: Future<Output = Result<Block::Header, ClientError>>
|
||||
+ Unpin
|
||||
+ Send
|
||||
+ 'static;
|
||||
/// Remote storage read future.
|
||||
type RemoteReadResult: Future<Output = Result<
|
||||
HashMap<Vec<u8>, Option<Vec<u8>>>,
|
||||
ClientError,
|
||||
>> + Unpin + Send + 'static;
|
||||
type RemoteReadResult: Future<Output = Result<HashMap<Vec<u8>, Option<Vec<u8>>>, ClientError>>
|
||||
+ Unpin
|
||||
+ Send
|
||||
+ 'static;
|
||||
/// Remote call result future.
|
||||
type RemoteCallResult: Future<Output = Result<
|
||||
Vec<u8>,
|
||||
ClientError,
|
||||
>> + Unpin + Send + 'static;
|
||||
type RemoteCallResult: Future<Output = Result<Vec<u8>, ClientError>> + Unpin + Send + 'static;
|
||||
/// Remote changes result future.
|
||||
type RemoteChangesResult: Future<Output = Result<
|
||||
Vec<(NumberFor<Block>, u32)>,
|
||||
ClientError,
|
||||
>> + Unpin + Send + 'static;
|
||||
type RemoteChangesResult: Future<Output = Result<Vec<(NumberFor<Block>, u32)>, ClientError>>
|
||||
+ Unpin
|
||||
+ Send
|
||||
+ 'static;
|
||||
/// Remote block body result future.
|
||||
type RemoteBodyResult: Future<Output = Result<
|
||||
Vec<Block::Extrinsic>,
|
||||
ClientError,
|
||||
>> + Unpin + Send + 'static;
|
||||
type RemoteBodyResult: Future<Output = Result<Vec<Block::Extrinsic>, ClientError>>
|
||||
+ Unpin
|
||||
+ Send
|
||||
+ 'static;
|
||||
|
||||
/// Fetch remote header.
|
||||
fn remote_header(&self, request: RemoteHeaderRequest<Block::Header>) -> Self::RemoteHeaderResult;
|
||||
/// Fetch remote storage value.
|
||||
fn remote_read(
|
||||
fn remote_header(
|
||||
&self,
|
||||
request: RemoteReadRequest<Block::Header>
|
||||
) -> Self::RemoteReadResult;
|
||||
request: RemoteHeaderRequest<Block::Header>,
|
||||
) -> Self::RemoteHeaderResult;
|
||||
/// Fetch remote storage value.
|
||||
fn remote_read(&self, request: RemoteReadRequest<Block::Header>) -> Self::RemoteReadResult;
|
||||
/// Fetch remote storage child value.
|
||||
fn remote_read_child(
|
||||
&self,
|
||||
request: RemoteReadChildRequest<Block::Header>
|
||||
request: RemoteReadChildRequest<Block::Header>,
|
||||
) -> Self::RemoteReadResult;
|
||||
/// Fetch remote call result.
|
||||
fn remote_call(&self, request: RemoteCallRequest<Block::Header>) -> Self::RemoteCallResult;
|
||||
/// Fetch remote changes ((block number, extrinsic index)) where given key has been changed
|
||||
/// 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
|
||||
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(
|
||||
&self,
|
||||
request: &RemoteChangesRequest<Block::Header>,
|
||||
proof: ChangesProof<Block::Header>
|
||||
proof: ChangesProof<Block::Header>,
|
||||
) -> ClientResult<Vec<(NumberFor<Block>, u32)>>;
|
||||
/// Check remote body proof.
|
||||
fn check_body_proof(
|
||||
&self,
|
||||
request: &RemoteBodyRequest<Block::Header>,
|
||||
body: Vec<Block::Extrinsic>
|
||||
body: Vec<Block::Extrinsic>,
|
||||
) -> ClientResult<Vec<Block::Extrinsic>>;
|
||||
}
|
||||
|
||||
|
||||
/// Light client blockchain storage.
|
||||
pub trait Storage<Block: BlockT>: AuxStore + HeaderBackend<Block>
|
||||
+ HeaderMetadata<Block, Error=ClientError> + ProvideChtRoots<Block>
|
||||
pub trait Storage<Block: BlockT>:
|
||||
AuxStore
|
||||
+ HeaderBackend<Block>
|
||||
+ HeaderMetadata<Block, Error = ClientError>
|
||||
+ ProvideChtRoots<Block>
|
||||
{
|
||||
/// 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.
|
||||
pub trait RemoteBlockchain<Block: BlockT>: Send + Sync {
|
||||
/// Get block header.
|
||||
fn header(&self, id: BlockId<Block>) -> ClientResult<LocalOrRemote<
|
||||
Block::Header,
|
||||
RemoteHeaderRequest<Block::Header>,
|
||||
>>;
|
||||
fn header(
|
||||
&self,
|
||||
id: BlockId<Block>,
|
||||
) -> ClientResult<LocalOrRemote<Block::Header, RemoteHeaderRequest<Block::Header>>>;
|
||||
}
|
||||
|
||||
/// 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};
|
||||
|
||||
match blockchain.header(id) {
|
||||
Ok(LocalOrRemote::Remote(request)) => Either::Left(
|
||||
fetcher
|
||||
.remote_header(request)
|
||||
.then(|header| ready(header.map(Some)))
|
||||
),
|
||||
Ok(LocalOrRemote::Remote(request)) =>
|
||||
Either::Left(fetcher.remote_header(request).then(|header| ready(header.map(Some)))),
|
||||
Ok(LocalOrRemote::Unknown) => Either::Right(ready(Ok(None))),
|
||||
Ok(LocalOrRemote::Local(local_header)) => Either::Right(ready(Ok(Some(local_header)))),
|
||||
Err(err) => Either::Right(ready(Err(err))),
|
||||
@@ -308,11 +310,11 @@ pub fn future_header<Block: BlockT, F: Fetcher<Block>>(
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use futures::future::Ready;
|
||||
use parking_lot::Mutex;
|
||||
use sp_blockchain::Error as ClientError;
|
||||
use sp_test_primitives::{Block, Header, Extrinsic};
|
||||
use super::*;
|
||||
use sp_test_primitives::{Block, Extrinsic, Header};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Not implemented on test node")]
|
||||
@@ -322,12 +324,11 @@ pub mod tests {
|
||||
fn into(self) -> ClientError {
|
||||
ClientError::Application(Box::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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()))
|
||||
}
|
||||
|
||||
@@ -346,7 +347,10 @@ pub mod 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()
|
||||
}
|
||||
|
||||
@@ -354,7 +358,10 @@ pub mod tests {
|
||||
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()
|
||||
}
|
||||
|
||||
|
||||
@@ -19,15 +19,15 @@
|
||||
//! Storage notifications
|
||||
|
||||
use std::{
|
||||
collections::{HashSet, HashMap},
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use fnv::{FnvHashSet, FnvHashMap};
|
||||
use sp_core::storage::{StorageKey, StorageData};
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use prometheus_endpoint::{register, CounterVec, Opts, Registry, U64};
|
||||
use sp_core::storage::{StorageData, StorageKey};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use sp_utils::mpsc::{TracingUnboundedSender, TracingUnboundedReceiver, tracing_unbounded};
|
||||
use prometheus_endpoint::{Registry, CounterVec, Opts, U64, register};
|
||||
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
|
||||
|
||||
/// Storage change set
|
||||
#[derive(Debug)]
|
||||
@@ -40,29 +40,34 @@ pub struct StorageChangeSet {
|
||||
|
||||
impl StorageChangeSet {
|
||||
/// Convert the change set into iterator over storage items.
|
||||
pub fn iter<'a>(&'a self)
|
||||
-> impl Iterator<Item=(Option<&'a StorageKey>, &'a StorageKey, Option<&'a StorageData>)> + 'a {
|
||||
let top = self.changes
|
||||
pub fn iter<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (Option<&'a StorageKey>, &'a StorageKey, Option<&'a StorageData>)> + 'a
|
||||
{
|
||||
let top = self
|
||||
.changes
|
||||
.iter()
|
||||
.filter(move |&(key, _)| match self.filter {
|
||||
Some(ref filter) => filter.contains(key),
|
||||
None => true,
|
||||
})
|
||||
.map(move |(k,v)| (None, k, v.as_ref()));
|
||||
let children = self.child_changes
|
||||
.map(move |(k, v)| (None, k, v.as_ref()));
|
||||
let children = self
|
||||
.child_changes
|
||||
.iter()
|
||||
.filter_map(move |(sk, changes)|
|
||||
self.child_filters.as_ref().and_then(|cf|
|
||||
cf.get(sk).map(|filter| changes
|
||||
.filter_map(move |(sk, changes)| {
|
||||
self.child_filters.as_ref().and_then(|cf| {
|
||||
cf.get(sk).map(|filter| {
|
||||
changes
|
||||
.iter()
|
||||
.filter(move |&(key, _)| match filter {
|
||||
Some(ref filter) => filter.contains(key),
|
||||
None => true,
|
||||
})
|
||||
.map(move |(k,v)| (Some(sk), k, v.as_ref()))
|
||||
)
|
||||
)
|
||||
)
|
||||
.map(move |(k, v)| (Some(sk), k, v.as_ref()))
|
||||
})
|
||||
})
|
||||
})
|
||||
.flatten();
|
||||
top.chain(children)
|
||||
}
|
||||
@@ -82,15 +87,18 @@ pub struct StorageNotifications<Block: BlockT> {
|
||||
next_id: SubscriberId,
|
||||
wildcard_listeners: FnvHashSet<SubscriberId>,
|
||||
listeners: HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
||||
child_listeners: HashMap<StorageKey, (
|
||||
HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
||||
FnvHashSet<SubscriberId>
|
||||
)>,
|
||||
sinks: FnvHashMap<SubscriberId, (
|
||||
TracingUnboundedSender<(Block::Hash, StorageChangeSet)>,
|
||||
Option<HashSet<StorageKey>>,
|
||||
Option<HashMap<StorageKey, Option<HashSet<StorageKey>>>>,
|
||||
)>,
|
||||
child_listeners: HashMap<
|
||||
StorageKey,
|
||||
(HashMap<StorageKey, FnvHashSet<SubscriberId>>, FnvHashSet<SubscriberId>),
|
||||
>,
|
||||
sinks: FnvHashMap<
|
||||
SubscriberId,
|
||||
(
|
||||
TracingUnboundedSender<(Block::Hash, StorageChangeSet)>,
|
||||
Option<HashSet<StorageKey>>,
|
||||
Option<HashMap<StorageKey, Option<HashSet<StorageKey>>>>,
|
||||
),
|
||||
>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> Default for StorageNotifications<Block> {
|
||||
@@ -110,16 +118,17 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
/// Initialize a new StorageNotifications
|
||||
/// optionally pass a prometheus registry to send subscriber metrics to
|
||||
pub fn new(prometheus_registry: Option<Registry>) -> Self {
|
||||
let metrics = prometheus_registry.and_then(|r|
|
||||
let metrics = prometheus_registry.and_then(|r| {
|
||||
CounterVec::new(
|
||||
Opts::new(
|
||||
"storage_notification_subscribers",
|
||||
"Number of subscribers in storage notification sytem"
|
||||
"Number of subscribers in storage notification sytem",
|
||||
),
|
||||
&["action"], //added | removed
|
||||
).and_then(|g| register(g, &r))
|
||||
&["action"], // added | removed
|
||||
)
|
||||
.and_then(|g| register(g, &r))
|
||||
.ok()
|
||||
);
|
||||
});
|
||||
|
||||
StorageNotifications {
|
||||
metrics,
|
||||
@@ -137,17 +146,16 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
pub fn trigger(
|
||||
&mut self,
|
||||
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<
|
||||
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();
|
||||
|
||||
// early exit if no listeners
|
||||
if !has_wildcard && self.listeners.is_empty() && self.child_listeners.is_empty() {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
let mut subscribers = self.wildcard_listeners.clone();
|
||||
@@ -193,24 +201,29 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
|
||||
// Don't send empty notifications
|
||||
if changes.is_empty() && child_changes.is_empty() {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
let changes = Arc::new(changes);
|
||||
let child_changes = Arc::new(child_changes);
|
||||
// Trigger the events
|
||||
|
||||
let to_remove = self.sinks
|
||||
let to_remove = self
|
||||
.sinks
|
||||
.iter()
|
||||
.filter_map(|(subscriber, &(ref sink, ref filter, ref child_filters))| {
|
||||
let should_remove = {
|
||||
if subscribers.contains(subscriber) {
|
||||
sink.unbounded_send((hash.clone(), StorageChangeSet {
|
||||
changes: changes.clone(),
|
||||
child_changes: child_changes.clone(),
|
||||
filter: filter.clone(),
|
||||
child_filters: child_filters.clone(),
|
||||
})).is_err()
|
||||
sink.unbounded_send((
|
||||
hash.clone(),
|
||||
StorageChangeSet {
|
||||
changes: changes.clone(),
|
||||
child_changes: child_changes.clone(),
|
||||
filter: filter.clone(),
|
||||
child_filters: child_filters.clone(),
|
||||
},
|
||||
))
|
||||
.is_err()
|
||||
} else {
|
||||
sink.is_closed()
|
||||
}
|
||||
@@ -221,7 +234,8 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect::<Vec<_>>();
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for sub_id in to_remove {
|
||||
self.remove_subscriber(sub_id);
|
||||
@@ -233,13 +247,12 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
filters: &Option<HashSet<StorageKey>>,
|
||||
listeners: &mut HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
||||
wildcards: &mut FnvHashSet<SubscriberId>,
|
||||
){
|
||||
) {
|
||||
match filters {
|
||||
None => {
|
||||
wildcards.remove(subscriber);
|
||||
},
|
||||
Some(filters) => {
|
||||
|
||||
Some(filters) =>
|
||||
for key in filters.iter() {
|
||||
let remove_key = match listeners.get_mut(key) {
|
||||
Some(ref mut set) => {
|
||||
@@ -252,8 +265,7 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
if remove_key {
|
||||
listeners.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +279,6 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
);
|
||||
if let Some(child_filters) = child_filters.as_ref() {
|
||||
for (c_key, filters) in child_filters {
|
||||
|
||||
if let Some((listeners, wildcards)) = self.child_listeners.get_mut(&c_key) {
|
||||
Self::remove_subscriber_from(
|
||||
&subscriber,
|
||||
@@ -293,20 +304,24 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
filter_keys: &Option<impl AsRef<[StorageKey]>>,
|
||||
listeners: &mut HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
||||
wildcards: &mut FnvHashSet<SubscriberId>,
|
||||
) -> Option<HashSet<StorageKey>>
|
||||
{
|
||||
) -> Option<HashSet<StorageKey>> {
|
||||
match filter_keys {
|
||||
None => {
|
||||
wildcards.insert(current_id);
|
||||
None
|
||||
},
|
||||
Some(keys) => Some(keys.as_ref().iter().map(|key| {
|
||||
listeners
|
||||
.entry(key.clone())
|
||||
.or_insert_with(Default::default)
|
||||
.insert(current_id);
|
||||
key.clone()
|
||||
}).collect())
|
||||
Some(keys) => Some(
|
||||
keys.as_ref()
|
||||
.iter()
|
||||
.map(|key| {
|
||||
listeners
|
||||
.entry(key.clone())
|
||||
.or_insert_with(Default::default)
|
||||
.insert(current_id);
|
||||
key.clone()
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,21 +342,20 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
&mut self.wildcard_listeners,
|
||||
);
|
||||
let child_keys = filter_child_keys.map(|filter_child_keys| {
|
||||
filter_child_keys.iter().map(|(c_key, o_keys)| {
|
||||
let (c_listeners, c_wildcards) = self.child_listeners
|
||||
.entry(c_key.clone())
|
||||
.or_insert_with(Default::default);
|
||||
filter_child_keys
|
||||
.iter()
|
||||
.map(|(c_key, o_keys)| {
|
||||
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,
|
||||
o_keys,
|
||||
&mut *c_listeners,
|
||||
&mut *c_wildcards,
|
||||
))
|
||||
}).collect()
|
||||
(
|
||||
c_key.clone(),
|
||||
Self::listen_from(current_id, o_keys, &mut *c_listeners, &mut *c_wildcards),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
|
||||
// insert sink
|
||||
let (tx, rx) = tracing_unbounded("mpsc_storage_notification_items");
|
||||
self.sinks.insert(current_id, (tx, keys, child_keys));
|
||||
@@ -356,8 +370,8 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use sp_runtime::testing::{H256 as Hash, Block as RawBlock, ExtrinsicWrapper};
|
||||
use super::*;
|
||||
use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash};
|
||||
use std::iter::{empty, Empty};
|
||||
|
||||
type TestChangeSet = (
|
||||
@@ -369,10 +383,12 @@ mod tests {
|
||||
impl From<TestChangeSet> for StorageChangeSet {
|
||||
fn from(changes: TestChangeSet) -> Self {
|
||||
// warning hardcoded child trie wildcard to test upon
|
||||
let child_filters = Some([
|
||||
(StorageKey(vec![4]), None),
|
||||
(StorageKey(vec![5]), None),
|
||||
].iter().cloned().collect());
|
||||
let child_filters = Some(
|
||||
[(StorageKey(vec![4]), None), (StorageKey(vec![5]), None)]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
);
|
||||
StorageChangeSet {
|
||||
changes: Arc::new(changes.0),
|
||||
child_changes: Arc::new(changes.1),
|
||||
@@ -396,34 +412,40 @@ mod tests {
|
||||
// given
|
||||
let mut notifications = StorageNotifications::<Block>::default();
|
||||
let child_filter = [(StorageKey(vec![4]), None)];
|
||||
let mut recv = futures::executor::block_on_stream(
|
||||
notifications.listen(None, Some(&child_filter[..]))
|
||||
);
|
||||
let mut recv =
|
||||
futures::executor::block_on_stream(notifications.listen(None, Some(&child_filter[..])));
|
||||
|
||||
// when
|
||||
let changeset = vec![
|
||||
(vec![2], Some(vec![3])),
|
||||
(vec![3], None),
|
||||
];
|
||||
let c_changeset_1 = vec![
|
||||
(vec![5], Some(vec![4])),
|
||||
(vec![6], None),
|
||||
];
|
||||
let changeset = vec![(vec![2], Some(vec![3])), (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)];
|
||||
notifications.trigger(
|
||||
&Hash::from_low_u64_be(1),
|
||||
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
|
||||
assert_eq!(recv.next().unwrap(), (Hash::from_low_u64_be(1), (vec![
|
||||
(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()));
|
||||
assert_eq!(
|
||||
recv.next().unwrap(),
|
||||
(
|
||||
Hash::from_low_u64_be(1),
|
||||
(
|
||||
vec![
|
||||
(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]
|
||||
@@ -432,44 +454,52 @@ mod tests {
|
||||
let mut notifications = StorageNotifications::<Block>::default();
|
||||
let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))];
|
||||
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(
|
||||
notifications.listen(Some(&[StorageKey(vec![2])]), None)
|
||||
notifications.listen(Some(&[StorageKey(vec![2])]), None),
|
||||
);
|
||||
let mut recv3 = futures::executor::block_on_stream(
|
||||
notifications.listen(Some(&[]), Some(&child_filter))
|
||||
notifications.listen(Some(&[]), Some(&child_filter)),
|
||||
);
|
||||
|
||||
// when
|
||||
let changeset = vec![
|
||||
(vec![2], Some(vec![3])),
|
||||
(vec![1], None),
|
||||
];
|
||||
let c_changeset_1 = vec![
|
||||
(vec![5], Some(vec![4])),
|
||||
(vec![6], None),
|
||||
];
|
||||
let changeset = vec![(vec![2], Some(vec![3])), (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)];
|
||||
notifications.trigger(
|
||||
&Hash::from_low_u64_be(1),
|
||||
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
|
||||
assert_eq!(recv1.next().unwrap(), (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]))),
|
||||
], vec![]).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()));
|
||||
|
||||
assert_eq!(
|
||||
recv1.next().unwrap(),
|
||||
(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]))),], vec![]).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]
|
||||
@@ -479,27 +509,21 @@ mod tests {
|
||||
{
|
||||
let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))];
|
||||
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(
|
||||
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))
|
||||
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)));
|
||||
assert_eq!(notifications.listeners.len(), 2);
|
||||
assert_eq!(notifications.wildcard_listeners.len(), 2);
|
||||
assert_eq!(notifications.child_listeners.len(), 1);
|
||||
}
|
||||
|
||||
// when
|
||||
let changeset = vec![
|
||||
(vec![2], Some(vec![3])),
|
||||
(vec![1], None),
|
||||
];
|
||||
let changeset = vec![(vec![2], Some(vec![3])), (vec![1], None)];
|
||||
let c_changeset = empty::<(_, Empty<_>)>();
|
||||
notifications.trigger(&Hash::from_low_u64_be(1), changeset.into_iter(), c_changeset);
|
||||
|
||||
|
||||
@@ -17,12 +17,9 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! Proof utilities
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT},
|
||||
};
|
||||
use crate::{StorageProof, ChangesProof};
|
||||
use sp_storage::{ChildInfo, StorageKey, PrefixedStorageKey};
|
||||
use crate::{ChangesProof, StorageProof};
|
||||
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
|
||||
use sp_storage::{ChildInfo, PrefixedStorageKey, StorageKey};
|
||||
|
||||
/// Interface for providing block proving utilities.
|
||||
pub trait ProofProvider<Block: BlockT> {
|
||||
@@ -30,7 +27,7 @@ pub trait ProofProvider<Block: BlockT> {
|
||||
fn read_proof(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
keys: &mut dyn Iterator<Item=&[u8]>,
|
||||
keys: &mut dyn Iterator<Item = &[u8]>,
|
||||
) -> sp_blockchain::Result<StorageProof>;
|
||||
|
||||
/// Reads child storage value at a given block + storage_key + key, returning
|
||||
@@ -39,7 +36,7 @@ pub trait ProofProvider<Block: BlockT> {
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
child_info: &ChildInfo,
|
||||
keys: &mut dyn Iterator<Item=&[u8]>,
|
||||
keys: &mut dyn Iterator<Item = &[u8]>,
|
||||
) -> sp_blockchain::Result<StorageProof>;
|
||||
|
||||
/// 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],
|
||||
) -> sp_blockchain::Result<(Vec<u8>, StorageProof)>;
|
||||
/// 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.
|
||||
/// `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
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use futures::stream::Stream;
|
||||
use futures::future::FutureExt;
|
||||
use futures::ready;
|
||||
use futures::{future::FutureExt, ready, stream::Stream};
|
||||
use futures_timer::Delay;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
/// Exponentially increasing interval
|
||||
///
|
||||
@@ -37,11 +37,7 @@ impl ExpIncInterval {
|
||||
/// Create a new [`ExpIncInterval`].
|
||||
pub fn new(start: Duration, max: Duration) -> Self {
|
||||
let delay = Delay::new(start);
|
||||
Self {
|
||||
max,
|
||||
next: start * 2,
|
||||
delay,
|
||||
}
|
||||
Self { max, next: start * 2, delay }
|
||||
}
|
||||
|
||||
/// Fast forward the exponentially increasing interval to the configured maximum.
|
||||
|
||||
@@ -26,18 +26,23 @@
|
||||
//!
|
||||
//! 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 futures::channel::{mpsc, oneshot};
|
||||
use futures::Stream;
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
Stream,
|
||||
};
|
||||
|
||||
use sc_client_api::blockchain::HeaderBackend;
|
||||
use sc_network::{DhtEvent, Multiaddr, PeerId};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_authority_discovery::{AuthorityDiscoveryApi, AuthorityId};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
|
||||
mod error;
|
||||
mod interval;
|
||||
@@ -141,15 +146,8 @@ where
|
||||
{
|
||||
let (to_worker, from_service) = mpsc::channel(0);
|
||||
|
||||
let worker = Worker::new(
|
||||
from_service,
|
||||
client,
|
||||
network,
|
||||
dht_event_rx,
|
||||
role,
|
||||
prometheus_registry,
|
||||
config,
|
||||
);
|
||||
let worker =
|
||||
Worker::new(from_service, client, network, dht_event_rx, role, prometheus_registry, config);
|
||||
let service = Service::new(to_worker);
|
||||
|
||||
(worker, service)
|
||||
@@ -160,5 +158,5 @@ pub(crate) enum ServicetoWorkerMsg {
|
||||
/// See [`Service::get_addresses_by_authority_id`].
|
||||
GetAddressesByAuthorityId(AuthorityId, oneshot::Sender<Option<Vec<Multiaddr>>>),
|
||||
/// 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 futures::channel::{mpsc, oneshot};
|
||||
use futures::SinkExt;
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
SinkExt,
|
||||
};
|
||||
|
||||
use sc_network::{Multiaddr, PeerId};
|
||||
use sp_authority_discovery::AuthorityId;
|
||||
@@ -42,9 +44,7 @@ impl Debug for Service {
|
||||
/// [`crate::Worker`]'s local address cache for a given [`AuthorityId`].
|
||||
impl Service {
|
||||
pub(crate) fn new(to_worker: mpsc::Sender<ServicetoWorkerMsg>) -> Self {
|
||||
Self {
|
||||
to_worker,
|
||||
}
|
||||
Self { to_worker }
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// publishing the addresses of their sentry nodes on the DHT. In the future
|
||||
/// 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();
|
||||
|
||||
self.to_worker
|
||||
|
||||
@@ -16,15 +16,24 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// 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 libp2p::core::{multiaddr::{Multiaddr, Protocol}, PeerId};
|
||||
use libp2p::core::{
|
||||
multiaddr::{Multiaddr, Protocol},
|
||||
PeerId,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
use sp_authority_discovery::AuthorityId;
|
||||
use sp_core::crypto::key_types;
|
||||
use sp_keystore::{CryptoStore, testing::KeyStore};
|
||||
use sp_keystore::{testing::KeyStore, CryptoStore};
|
||||
|
||||
#[test]
|
||||
fn get_addresses_and_authority_id() {
|
||||
@@ -44,13 +53,12 @@ fn get_addresses_and_authority_id() {
|
||||
});
|
||||
|
||||
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()
|
||||
.with(Protocol::P2p(remote_peer_id.clone().into()));
|
||||
|
||||
let test_api = Arc::new(TestApi {
|
||||
authorities: vec![],
|
||||
});
|
||||
let test_api = Arc::new(TestApi { authorities: vec![] });
|
||||
|
||||
let (mut worker, mut service) = new_worker_and_service(
|
||||
test_api,
|
||||
|
||||
@@ -16,43 +16,49 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// 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::convert::TryInto;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
convert::TryInto,
|
||||
marker::PhantomData,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use futures::channel::mpsc;
|
||||
use futures::{future, FutureExt, Stream, StreamExt, stream::Fuse};
|
||||
use futures::{channel::mpsc, future, stream::Fuse, FutureExt, Stream, StreamExt};
|
||||
|
||||
use addr_cache::AddrCache;
|
||||
use async_trait::async_trait;
|
||||
use codec::Decode;
|
||||
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 prometheus_endpoint::{Counter, CounterVec, Gauge, Opts, U64, register};
|
||||
use prometheus_endpoint::{register, Counter, CounterVec, Gauge, Opts, U64};
|
||||
use prost::Message;
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
use sc_client_api::blockchain::HeaderBackend;
|
||||
use sc_network::{
|
||||
DhtEvent,
|
||||
ExHashT,
|
||||
Multiaddr,
|
||||
NetworkStateInfo,
|
||||
PeerId,
|
||||
use sc_network::{DhtEvent, ExHashT, Multiaddr, NetworkStateInfo, PeerId};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_authority_discovery::{
|
||||
AuthorityDiscoveryApi, AuthorityId, AuthorityPair, AuthoritySignature,
|
||||
};
|
||||
use sp_authority_discovery::{AuthorityDiscoveryApi, AuthorityId, AuthoritySignature, AuthorityPair};
|
||||
use sp_core::crypto::{key_types, CryptoTypePublicPair, Pair};
|
||||
use sp_keystore::CryptoStore;
|
||||
use sp_runtime::{traits::Block as BlockT, generic::BlockId};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
|
||||
|
||||
mod addr_cache;
|
||||
/// 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)]
|
||||
pub mod tests;
|
||||
|
||||
@@ -72,7 +78,6 @@ pub enum Role {
|
||||
Discover,
|
||||
}
|
||||
|
||||
|
||||
/// An authority discovery [`Worker`] can publish the local node's addresses as well as discover
|
||||
/// those of other nodes via a Kademlia DHT.
|
||||
///
|
||||
@@ -141,8 +146,7 @@ where
|
||||
Block: BlockT + Unpin + 'static,
|
||||
Network: NetworkProvider,
|
||||
Client: ProvideRuntimeApi<Block> + Send + Sync + 'static + HeaderBackend<Block>,
|
||||
<Client as ProvideRuntimeApi<Block>>::Api:
|
||||
AuthorityDiscoveryApi<Block>,
|
||||
<Client as ProvideRuntimeApi<Block>>::Api: AuthorityDiscoveryApi<Block>,
|
||||
DhtEventStream: Stream<Item = DhtEvent> + Unpin,
|
||||
{
|
||||
/// Construct a [`Worker`].
|
||||
@@ -161,33 +165,24 @@ where
|
||||
// thus timely retries are not needed. For this reasoning use an exponentially increasing
|
||||
// interval for `publish_interval`, `query_interval` and `priority_group_set_interval`
|
||||
// instead of a constant interval.
|
||||
let publish_interval = ExpIncInterval::new(
|
||||
Duration::from_secs(2),
|
||||
config.max_publish_interval,
|
||||
);
|
||||
let query_interval = ExpIncInterval::new(
|
||||
Duration::from_secs(2),
|
||||
config.max_query_interval,
|
||||
);
|
||||
let publish_interval =
|
||||
ExpIncInterval::new(Duration::from_secs(2), config.max_publish_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
|
||||
// is more simple.
|
||||
let publish_if_changed_interval = ExpIncInterval::new(
|
||||
config.keystore_refresh_interval,
|
||||
config.keystore_refresh_interval
|
||||
);
|
||||
let publish_if_changed_interval =
|
||||
ExpIncInterval::new(config.keystore_refresh_interval, config.keystore_refresh_interval);
|
||||
|
||||
let addr_cache = AddrCache::new();
|
||||
|
||||
let metrics = match prometheus_registry {
|
||||
Some(registry) => {
|
||||
match Metrics::register(®istry) {
|
||||
Ok(metrics) => Some(metrics),
|
||||
Err(e) => {
|
||||
error!(target: LOG_TARGET, "Failed to register metrics: {:?}", e);
|
||||
None
|
||||
},
|
||||
}
|
||||
Some(registry) => match Metrics::register(®istry) {
|
||||
Ok(metrics) => Some(metrics),
|
||||
Err(e) => {
|
||||
error!(target: LOG_TARGET, "Failed to register metrics: {:?}", e);
|
||||
None
|
||||
},
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
@@ -262,23 +257,23 @@ where
|
||||
let _ = sender.send(
|
||||
self.addr_cache.get_addresses_by_authority_id(&authority).map(Clone::clone),
|
||||
);
|
||||
}
|
||||
},
|
||||
ServicetoWorkerMsg::GetAuthorityIdByPeerId(peer_id, sender) => {
|
||||
let _ = sender.send(
|
||||
self.addr_cache.get_authority_id_by_peer_id(&peer_id).map(Clone::clone),
|
||||
);
|
||||
}
|
||||
let _ = sender
|
||||
.send(self.addr_cache.get_authority_id_by_peer_id(&peer_id).map(Clone::clone));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn addresses_to_publish(&self) -> impl Iterator<Item = Multiaddr> {
|
||||
let peer_id: Multihash = self.network.local_peer_id().into();
|
||||
let publish_non_global_ips = self.publish_non_global_ips;
|
||||
self.network.external_addresses()
|
||||
self.network
|
||||
.external_addresses()
|
||||
.into_iter()
|
||||
.filter(move |a| {
|
||||
if publish_non_global_ips {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
a.iter().all(|p| match p {
|
||||
@@ -321,9 +316,9 @@ where
|
||||
|
||||
if let Some(metrics) = &self.metrics {
|
||||
metrics.publish.inc();
|
||||
metrics.amount_addresses_last_published.set(
|
||||
addresses.len().try_into().unwrap_or(std::u64::MAX),
|
||||
);
|
||||
metrics
|
||||
.amount_addresses_last_published
|
||||
.set(addresses.len().try_into().unwrap_or(std::u64::MAX));
|
||||
}
|
||||
|
||||
let mut serialized_addresses = vec![];
|
||||
@@ -332,30 +327,26 @@ where
|
||||
.map_err(Error::EncodingProto)?;
|
||||
|
||||
let keys_vec = keys.iter().cloned().collect::<Vec<_>>();
|
||||
let signatures = key_store.sign_with_all(
|
||||
key_types::AUTHORITY_DISCOVERY,
|
||||
keys_vec.clone(),
|
||||
serialized_addresses.as_slice(),
|
||||
).await.map_err(|_| Error::Signing)?;
|
||||
let signatures = key_store
|
||||
.sign_with_all(
|
||||
key_types::AUTHORITY_DISCOVERY,
|
||||
keys_vec.clone(),
|
||||
serialized_addresses.as_slice(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Error::Signing)?;
|
||||
|
||||
for (sign_result, key) in signatures.into_iter().zip(keys_vec.iter()) {
|
||||
let mut signed_addresses = vec![];
|
||||
|
||||
// Verify that all signatures exist for all provided keys.
|
||||
let signature = sign_result.ok()
|
||||
.flatten()
|
||||
.ok_or_else(|| Error::MissingSignature(key.clone()))?;
|
||||
schema::SignedAuthorityAddresses {
|
||||
addresses: serialized_addresses.clone(),
|
||||
signature,
|
||||
}
|
||||
.encode(&mut signed_addresses)
|
||||
let signature =
|
||||
sign_result.ok().flatten().ok_or_else(|| Error::MissingSignature(key.clone()))?;
|
||||
schema::SignedAuthorityAddresses { addresses: serialized_addresses.clone(), signature }
|
||||
.encode(&mut signed_addresses)
|
||||
.map_err(Error::EncodingProto)?;
|
||||
|
||||
self.network.put_value(
|
||||
hash_authority_id(key.1.as_ref()),
|
||||
signed_addresses,
|
||||
);
|
||||
self.network.put_value(hash_authority_id(key.1.as_ref()), signed_addresses);
|
||||
}
|
||||
|
||||
self.latest_published_keys = keys;
|
||||
@@ -367,11 +358,11 @@ where
|
||||
let id = BlockId::hash(self.client.info().best_hash);
|
||||
|
||||
let local_keys = match &self.role {
|
||||
Role::PublishAndDiscover(key_store) => {
|
||||
key_store.sr25519_public_keys(
|
||||
key_types::AUTHORITY_DISCOVERY
|
||||
).await.into_iter().collect::<HashSet<_>>()
|
||||
},
|
||||
Role::PublishAndDiscover(key_store) => key_store
|
||||
.sr25519_public_keys(key_types::AUTHORITY_DISCOVERY)
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<HashSet<_>>(),
|
||||
Role::Discover => HashSet::new(),
|
||||
};
|
||||
|
||||
@@ -393,9 +384,9 @@ where
|
||||
self.in_flight_lookups.clear();
|
||||
|
||||
if let Some(metrics) = &self.metrics {
|
||||
metrics.requests_pending.set(
|
||||
self.pending_lookups.len().try_into().unwrap_or(std::u64::MAX),
|
||||
);
|
||||
metrics
|
||||
.requests_pending
|
||||
.set(self.pending_lookups.len().try_into().unwrap_or(std::u64::MAX));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -408,15 +399,14 @@ where
|
||||
None => return,
|
||||
};
|
||||
let hash = hash_authority_id(authority_id.as_ref());
|
||||
self.network
|
||||
.get_value(&hash);
|
||||
self.network.get_value(&hash);
|
||||
self.in_flight_lookups.insert(hash, authority_id);
|
||||
|
||||
if let Some(metrics) = &self.metrics {
|
||||
metrics.requests.inc();
|
||||
metrics.requests_pending.set(
|
||||
self.pending_lookups.len().try_into().unwrap_or(std::u64::MAX),
|
||||
);
|
||||
metrics
|
||||
.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) {
|
||||
let hashes: Vec<_> = v.iter().map(|(hash, _value)| hash.clone()).collect();
|
||||
debug!(
|
||||
target: LOG_TARGET,
|
||||
"Value for hash '{:?}' found on Dht.", hashes,
|
||||
);
|
||||
debug!(target: LOG_TARGET, "Value for hash '{:?}' found on Dht.", hashes,);
|
||||
}
|
||||
|
||||
if let Err(e) = self.handle_dht_value_found_event(v) {
|
||||
@@ -442,22 +429,16 @@ where
|
||||
metrics.handle_value_found_event_failure.inc();
|
||||
}
|
||||
|
||||
debug!(
|
||||
target: LOG_TARGET,
|
||||
"Failed to handle Dht value found event: {:?}", e,
|
||||
);
|
||||
debug!(target: LOG_TARGET, "Failed to handle Dht value found event: {:?}", e,);
|
||||
}
|
||||
}
|
||||
},
|
||||
DhtEvent::ValueNotFound(hash) => {
|
||||
if let Some(metrics) = &self.metrics {
|
||||
metrics.dht_event_received.with_label_values(&["value_not_found"]).inc();
|
||||
}
|
||||
|
||||
if self.in_flight_lookups.remove(&hash).is_some() {
|
||||
debug!(
|
||||
target: LOG_TARGET,
|
||||
"Value for hash '{:?}' not found on Dht.", hash
|
||||
)
|
||||
debug!(target: LOG_TARGET, "Value for hash '{:?}' not found on Dht.", hash)
|
||||
} else {
|
||||
debug!(
|
||||
target: LOG_TARGET,
|
||||
@@ -475,21 +456,15 @@ where
|
||||
metrics.dht_event_received.with_label_values(&["value_put"]).inc();
|
||||
}
|
||||
|
||||
debug!(
|
||||
target: LOG_TARGET,
|
||||
"Successfully put hash '{:?}' on Dht.", hash,
|
||||
)
|
||||
debug!(target: LOG_TARGET, "Successfully put hash '{:?}' on Dht.", hash,)
|
||||
},
|
||||
DhtEvent::ValuePutFailed(hash) => {
|
||||
if let Some(metrics) = &self.metrics {
|
||||
metrics.dht_event_received.with_label_values(&["value_put_failed"]).inc();
|
||||
}
|
||||
|
||||
debug!(
|
||||
target: LOG_TARGET,
|
||||
"Failed to put hash '{:?}' on Dht.", hash
|
||||
)
|
||||
}
|
||||
debug!(target: LOG_TARGET, "Failed to put hash '{:?}' on Dht.", hash)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,34 +473,36 @@ where
|
||||
values: Vec<(libp2p::kad::record::Key, Vec<u8>)>,
|
||||
) -> Result<()> {
|
||||
// Ensure `values` is not empty and all its keys equal.
|
||||
let remote_key = values.iter().fold(Ok(None), |acc, (key, _)| {
|
||||
match acc {
|
||||
let remote_key = values
|
||||
.iter()
|
||||
.fold(Ok(None), |acc, (key, _)| match acc {
|
||||
Ok(None) => Ok(Some(key.clone())),
|
||||
Ok(Some(ref prev_key)) if prev_key != key => Err(
|
||||
Error::ReceivingDhtValueFoundEventWithDifferentKeys
|
||||
),
|
||||
Ok(Some(ref prev_key)) if prev_key != key =>
|
||||
Err(Error::ReceivingDhtValueFoundEventWithDifferentKeys),
|
||||
x @ Ok(_) => x,
|
||||
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)
|
||||
.ok_or(Error::ReceivingUnexpectedRecord)?;
|
||||
|
||||
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)| {
|
||||
let schema::SignedAuthorityAddresses { signature, addresses } =
|
||||
schema::SignedAuthorityAddresses::decode(v.as_slice())
|
||||
.map_err(Error::DecodingProto)?;
|
||||
.map_err(Error::DecodingProto)?;
|
||||
|
||||
let signature = AuthoritySignature::decode(&mut &signature[..])
|
||||
.map_err(Error::EncodingDecodingScale)?;
|
||||
|
||||
if !AuthorityPair::verify(&signature, &addresses, &authority_id) {
|
||||
return Err(Error::VerifyingDhtPayload);
|
||||
return Err(Error::VerifyingDhtPayload)
|
||||
}
|
||||
|
||||
let addresses = schema::AuthorityAddresses::decode(addresses.as_slice())
|
||||
@@ -542,40 +519,41 @@ where
|
||||
.into_iter()
|
||||
.flatten()
|
||||
// Ignore [`Multiaddr`]s without [`PeerId`] and own addresses.
|
||||
.filter(|addr| addr.iter().any(|protocol| {
|
||||
// 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.
|
||||
if let multiaddr::Protocol::P2p(hash) = protocol {
|
||||
let peer_id = match PeerId::from_multihash(hash) {
|
||||
Ok(peer_id) => peer_id,
|
||||
Err(_) => return false, // Discard address.
|
||||
};
|
||||
.filter(|addr| {
|
||||
addr.iter().any(|protocol| {
|
||||
// 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.
|
||||
if let multiaddr::Protocol::P2p(hash) = protocol {
|
||||
let peer_id = match PeerId::from_multihash(hash) {
|
||||
Ok(peer_id) => peer_id,
|
||||
Err(_) => return false, // Discard address.
|
||||
};
|
||||
|
||||
// Discard if equal to local peer id, keep if it differs.
|
||||
return !(peer_id == local_peer_id);
|
||||
}
|
||||
// Discard if equal to local peer id, keep if it differs.
|
||||
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)
|
||||
.collect();
|
||||
|
||||
if !remote_addresses.is_empty() {
|
||||
self.addr_cache.insert(authority_id, remote_addresses);
|
||||
if let Some(metrics) = &self.metrics {
|
||||
metrics.known_authorities_count.set(
|
||||
self.addr_cache.num_ids().try_into().unwrap_or(std::u64::MAX)
|
||||
);
|
||||
metrics
|
||||
.known_authorities_count
|
||||
.set(self.addr_cache.num_ids().try_into().unwrap_or(std::u64::MAX));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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
|
||||
// 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
|
||||
@@ -591,14 +569,16 @@ where
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let id = BlockId::hash(client.info().best_hash);
|
||||
let authorities = client.runtime_api()
|
||||
let authorities = client
|
||||
.runtime_api()
|
||||
.authorities(&id)
|
||||
.map_err(|e| Error::CallingRuntime(e.into()))?
|
||||
.into_iter()
|
||||
.map(std::convert::Into::into)
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let intersection = local_pub_keys.intersection(&authorities)
|
||||
let intersection = local_pub_keys
|
||||
.intersection(&authorities)
|
||||
.cloned()
|
||||
.map(std::convert::Into::into)
|
||||
.collect();
|
||||
@@ -655,7 +635,7 @@ impl Metrics {
|
||||
publish: register(
|
||||
Counter::new(
|
||||
"authority_discovery_times_published_total",
|
||||
"Number of times authority discovery has published external addresses."
|
||||
"Number of times authority discovery has published external addresses.",
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
@@ -663,7 +643,7 @@ impl Metrics {
|
||||
Gauge::new(
|
||||
"authority_discovery_amount_external_addresses_last_published",
|
||||
"Number of external addresses published when authority discovery last \
|
||||
published addresses."
|
||||
published addresses.",
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
@@ -671,14 +651,14 @@ impl Metrics {
|
||||
Counter::new(
|
||||
"authority_discovery_authority_addresses_requested_total",
|
||||
"Number of times authority discovery has requested external addresses of a \
|
||||
single authority."
|
||||
single authority.",
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
requests_pending: register(
|
||||
Gauge::new(
|
||||
"authority_discovery_authority_address_requests_pending",
|
||||
"Number of pending authority address requests."
|
||||
"Number of pending authority address requests.",
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
@@ -686,7 +666,7 @@ impl Metrics {
|
||||
CounterVec::new(
|
||||
Opts::new(
|
||||
"authority_discovery_dht_event_received",
|
||||
"Number of dht events received by authority discovery."
|
||||
"Number of dht events received by authority discovery.",
|
||||
),
|
||||
&["name"],
|
||||
)?,
|
||||
@@ -695,14 +675,14 @@ impl Metrics {
|
||||
handle_value_found_event_failure: register(
|
||||
Counter::new(
|
||||
"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,
|
||||
)?,
|
||||
known_authorities_count: register(
|
||||
Gauge::new(
|
||||
"authority_discovery_known_authorities_count",
|
||||
"Number of authorities known by authority discovery."
|
||||
"Number of authorities known by authority discovery.",
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
use libp2p::core::multiaddr::{Multiaddr, Protocol};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use sp_authority_discovery::AuthorityId;
|
||||
use sc_network::PeerId;
|
||||
use sp_authority_discovery::AuthorityId;
|
||||
|
||||
/// Cache for [`AuthorityId`] -> [`Vec<Multiaddr>`] and [`PeerId`] -> [`AuthorityId`] mappings.
|
||||
pub(super) struct AddrCache {
|
||||
@@ -45,27 +45,34 @@ impl AddrCache {
|
||||
addresses.sort_unstable_by(|a, b| a.as_ref().cmp(b.as_ref()));
|
||||
|
||||
// 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))
|
||||
.filter_map(|peer_id| peer_id);
|
||||
for peer_id in peer_ids.clone() {
|
||||
let former_auth = match self.peer_id_to_authority_id.insert(peer_id, authority_id.clone()) {
|
||||
Some(a) if a != authority_id => a,
|
||||
_ => continue,
|
||||
};
|
||||
let former_auth =
|
||||
match self.peer_id_to_authority_id.insert(peer_id, authority_id.clone()) {
|
||||
Some(a) if a != authority_id => a,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
// PeerId was associated to a different authority id before.
|
||||
// Remove corresponding authority from `self.authority_id_to_addresses`.
|
||||
let former_auth_addrs = match self.authority_id_to_addresses.get_mut(&former_auth) {
|
||||
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));
|
||||
}
|
||||
|
||||
// Insert into `self.authority_id_to_addresses`.
|
||||
for former_addr in
|
||||
self.authority_id_to_addresses.insert(authority_id.clone(), addresses.clone()).unwrap_or_default()
|
||||
for former_addr in self
|
||||
.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
|
||||
// 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`].
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -100,7 +110,9 @@ impl AddrCache {
|
||||
/// [`AuthorityId`]s.
|
||||
pub fn retain_ids(&mut self, authority_ids: &Vec<AuthorityId>) {
|
||||
// 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))
|
||||
.map(|entry| entry.0)
|
||||
.cloned()
|
||||
@@ -111,7 +123,8 @@ impl AddrCache {
|
||||
let addresses = self.authority_id_to_addresses.remove(&authority_id_to_remove);
|
||||
|
||||
// Remove other entries from `self.peer_id_to_authority_id`.
|
||||
let peer_ids = addresses.iter()
|
||||
let peer_ids = addresses
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|a| peer_id_from_multiaddr(a))
|
||||
.filter_map(|peer_id| peer_id);
|
||||
@@ -125,10 +138,12 @@ impl AddrCache {
|
||||
}
|
||||
|
||||
fn peer_id_from_multiaddr(addr: &Multiaddr) -> Option<PeerId> {
|
||||
addr.iter().last().and_then(|protocol| if let Protocol::P2p(multihash) = protocol {
|
||||
PeerId::from_multihash(multihash).ok()
|
||||
} else {
|
||||
None
|
||||
addr.iter().last().and_then(|protocol| {
|
||||
if let Protocol::P2p(multihash) = protocol {
|
||||
PeerId::from_multihash(multihash).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -159,9 +174,11 @@ mod tests {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>();
|
||||
let peer_id = PeerId::from_multihash(
|
||||
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>()
|
||||
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()
|
||||
.with(Protocol::P2p(peer_id.into()));
|
||||
|
||||
@@ -176,12 +193,15 @@ mod tests {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>();
|
||||
let peer_id = PeerId::from_multihash(
|
||||
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>()
|
||||
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()
|
||||
.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()
|
||||
.with(Protocol::P2p(peer_id.into()));
|
||||
TestMultiaddrsSamePeerCombo(multiaddr1, multiaddr2)
|
||||
@@ -219,11 +239,13 @@ mod tests {
|
||||
cache.retain_ids(&vec![first.0, second.0]);
|
||||
|
||||
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."
|
||||
);
|
||||
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."
|
||||
);
|
||||
|
||||
@@ -253,7 +275,10 @@ mod tests {
|
||||
let mut cache = AddrCache::new();
|
||||
|
||||
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!(
|
||||
None,
|
||||
|
||||
@@ -18,21 +18,26 @@
|
||||
|
||||
use crate::worker::schema;
|
||||
|
||||
use std::{sync::{Arc, Mutex}, task::Poll};
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
task::Poll,
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures::channel::mpsc::{self, channel};
|
||||
use futures::executor::{block_on, LocalPool};
|
||||
use futures::future::FutureExt;
|
||||
use futures::sink::SinkExt;
|
||||
use futures::task::LocalSpawn;
|
||||
use libp2p::{kad, core::multiaddr, PeerId};
|
||||
use futures::{
|
||||
channel::mpsc::{self, channel},
|
||||
executor::{block_on, LocalPool},
|
||||
future::FutureExt,
|
||||
sink::SinkExt,
|
||||
task::LocalSpawn,
|
||||
};
|
||||
use libp2p::{core::multiaddr, kad, PeerId};
|
||||
use prometheus_endpoint::prometheus::default_registry;
|
||||
|
||||
use sp_api::{ProvideRuntimeApi, ApiRef};
|
||||
use sp_api::{ApiRef, ProvideRuntimeApi};
|
||||
use sp_core::crypto::Public;
|
||||
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 super::*;
|
||||
@@ -46,9 +51,7 @@ impl ProvideRuntimeApi<Block> for TestApi {
|
||||
type Api = RuntimeApi;
|
||||
|
||||
fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> {
|
||||
RuntimeApi {
|
||||
authorities: self.authorities.clone(),
|
||||
}.into()
|
||||
RuntimeApi { authorities: self.authorities.clone() }.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,10 +138,7 @@ impl Default for TestNetwork {
|
||||
let (tx, rx) = mpsc::unbounded();
|
||||
TestNetwork {
|
||||
peer_id: PeerId::random(),
|
||||
external_addresses: vec![
|
||||
"/ip6/2001:db8::/tcp/30333"
|
||||
.parse().unwrap(),
|
||||
],
|
||||
external_addresses: vec!["/ip6/2001:db8::/tcp/30333".parse().unwrap()],
|
||||
put_value_call: Default::default(),
|
||||
get_value_call: Default::default(),
|
||||
event_sender: tx,
|
||||
@@ -151,11 +151,17 @@ impl Default for TestNetwork {
|
||||
impl NetworkProvider for TestNetwork {
|
||||
fn put_value(&self, key: kad::record::Key, value: Vec<u8>) {
|
||||
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) {
|
||||
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,
|
||||
) -> (libp2p::kad::record::Key, Vec<u8>) {
|
||||
let mut serialized_addresses = vec![];
|
||||
schema::AuthorityAddresses {
|
||||
addresses: addresses.into_iter().map(|a| a.to_vec()).collect()
|
||||
}.encode(&mut serialized_addresses)
|
||||
schema::AuthorityAddresses { addresses: addresses.into_iter().map(|a| a.to_vec()).collect() }
|
||||
.encode(&mut serialized_addresses)
|
||||
.map_err(Error::EncodingProto)
|
||||
.unwrap();
|
||||
|
||||
@@ -192,11 +197,9 @@ async fn build_dht_event(
|
||||
.unwrap();
|
||||
|
||||
let mut signed_addresses = vec![];
|
||||
schema::SignedAuthorityAddresses {
|
||||
addresses: serialized_addresses.clone(),
|
||||
signature,
|
||||
}
|
||||
.encode(&mut signed_addresses).unwrap();
|
||||
schema::SignedAuthorityAddresses { addresses: serialized_addresses.clone(), signature }
|
||||
.encode(&mut signed_addresses)
|
||||
.unwrap();
|
||||
|
||||
let key = hash_authority_id(&public_key.to_raw_vec());
|
||||
let value = signed_addresses;
|
||||
@@ -208,9 +211,7 @@ fn new_registers_metrics() {
|
||||
let (_dht_event_tx, dht_event_rx) = mpsc::channel(1000);
|
||||
let network: Arc<TestNetwork> = Arc::new(Default::default());
|
||||
let key_store = KeyStore::new();
|
||||
let test_api = Arc::new(TestApi {
|
||||
authorities: vec![],
|
||||
});
|
||||
let test_api = Arc::new(TestApi { authorities: vec![] });
|
||||
|
||||
let registry = prometheus_endpoint::Registry::new();
|
||||
|
||||
@@ -275,65 +276,67 @@ fn publish_discover_cycle() {
|
||||
|
||||
let key_store = KeyStore::new();
|
||||
|
||||
let _ = pool.spawner().spawn_local_obj(async move {
|
||||
let node_a_public = key_store
|
||||
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)
|
||||
.await
|
||||
.unwrap();
|
||||
let test_api = Arc::new(TestApi {
|
||||
authorities: vec![node_a_public.into()],
|
||||
});
|
||||
let _ = pool.spawner().spawn_local_obj(
|
||||
async move {
|
||||
let node_a_public = key_store
|
||||
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)
|
||||
.await
|
||||
.unwrap();
|
||||
let test_api = Arc::new(TestApi { authorities: vec![node_a_public.into()] });
|
||||
|
||||
let (_to_worker, from_service) = mpsc::channel(0);
|
||||
let mut worker = Worker::new(
|
||||
from_service,
|
||||
test_api,
|
||||
network.clone(),
|
||||
Box::pin(dht_event_rx),
|
||||
Role::PublishAndDiscover(key_store.into()),
|
||||
None,
|
||||
Default::default(),
|
||||
);
|
||||
let (_to_worker, from_service) = mpsc::channel(0);
|
||||
let mut worker = Worker::new(
|
||||
from_service,
|
||||
test_api,
|
||||
network.clone(),
|
||||
Box::pin(dht_event_rx),
|
||||
Role::PublishAndDiscover(key_store.into()),
|
||||
None,
|
||||
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.
|
||||
assert_eq!(network.put_value_call.lock().unwrap().len(), 1);
|
||||
// Expect authority discovery to put a new record onto the dht.
|
||||
assert_eq!(network.put_value_call.lock().unwrap().len(), 1);
|
||||
|
||||
let dht_event = {
|
||||
let (key, value) = network.put_value_call.lock().unwrap().pop().unwrap();
|
||||
sc_network::DhtEvent::ValueFound(vec![(key, value)])
|
||||
};
|
||||
let dht_event = {
|
||||
let (key, value) = network.put_value_call.lock().unwrap().pop().unwrap();
|
||||
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 test_api = Arc::new(TestApi {
|
||||
// Make sure node B identifies node A as an authority.
|
||||
authorities: vec![node_a_public.into()],
|
||||
});
|
||||
let network: Arc<TestNetwork> = Arc::new(Default::default());
|
||||
let key_store = KeyStore::new();
|
||||
let (mut dht_event_tx, dht_event_rx) = channel(1000);
|
||||
let test_api = Arc::new(TestApi {
|
||||
// Make sure node B identifies node A as an authority.
|
||||
authorities: vec![node_a_public.into()],
|
||||
});
|
||||
let network: Arc<TestNetwork> = Arc::new(Default::default());
|
||||
let key_store = KeyStore::new();
|
||||
|
||||
let (_to_worker, from_service) = mpsc::channel(0);
|
||||
let mut worker = Worker::new(
|
||||
from_service,
|
||||
test_api,
|
||||
network.clone(),
|
||||
Box::pin(dht_event_rx),
|
||||
Role::PublishAndDiscover(key_store.into()),
|
||||
None,
|
||||
Default::default(),
|
||||
);
|
||||
let (_to_worker, from_service) = mpsc::channel(0);
|
||||
let mut worker = Worker::new(
|
||||
from_service,
|
||||
test_api,
|
||||
network.clone(),
|
||||
Box::pin(dht_event_rx),
|
||||
Role::PublishAndDiscover(key_store.into()),
|
||||
None,
|
||||
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.start_new_lookups();
|
||||
worker.refill_pending_lookups_queue().await.unwrap();
|
||||
worker.start_new_lookups();
|
||||
|
||||
// Make authority discovery handle the event.
|
||||
worker.handle_dht_event(dht_event).await;
|
||||
}.boxed_local().into());
|
||||
// Make authority discovery handle the event.
|
||||
worker.handle_dht_event(dht_event).await;
|
||||
}
|
||||
.boxed_local()
|
||||
.into(),
|
||||
);
|
||||
|
||||
pool.run();
|
||||
}
|
||||
@@ -345,9 +348,7 @@ fn terminate_when_event_stream_terminates() {
|
||||
let (dht_event_tx, dht_event_rx) = channel(1000);
|
||||
let network: Arc<TestNetwork> = Arc::new(Default::default());
|
||||
let key_store = KeyStore::new();
|
||||
let test_api = Arc::new(TestApi {
|
||||
authorities: vec![],
|
||||
});
|
||||
let test_api = Arc::new(TestApi { authorities: vec![] });
|
||||
|
||||
let (to_worker, from_service) = mpsc::channel(0);
|
||||
let worker = Worker::new(
|
||||
@@ -358,7 +359,8 @@ fn terminate_when_event_stream_terminates() {
|
||||
Role::PublishAndDiscover(key_store.into()),
|
||||
None,
|
||||
Default::default(),
|
||||
).run();
|
||||
)
|
||||
.run();
|
||||
futures::pin_mut!(worker);
|
||||
|
||||
block_on(async {
|
||||
@@ -367,7 +369,8 @@ fn terminate_when_event_stream_terminates() {
|
||||
// Drop sender side of service channel.
|
||||
drop(to_worker);
|
||||
assert_eq!(
|
||||
Poll::Pending, futures::poll!(&mut worker),
|
||||
Poll::Pending,
|
||||
futures::poll!(&mut worker),
|
||||
"Expect the authority discovery module not to terminate once the \
|
||||
sender side of the service channel is closed.",
|
||||
);
|
||||
@@ -377,7 +380,8 @@ fn terminate_when_event_stream_terminates() {
|
||||
drop(dht_event_tx);
|
||||
|
||||
assert_eq!(
|
||||
Poll::Ready(()), futures::poll!(&mut worker),
|
||||
Poll::Ready(()),
|
||||
futures::poll!(&mut worker),
|
||||
"Expect the authority discovery module to terminate once the \
|
||||
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 address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
|
||||
|
||||
address.with(multiaddr::Protocol::P2p(
|
||||
peer_id.into(),
|
||||
))
|
||||
address.with(multiaddr::Protocol::P2p(peer_id.into()))
|
||||
};
|
||||
let remote_key_store = KeyStore::new();
|
||||
let remote_public_key: AuthorityId = block_on(
|
||||
remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None),
|
||||
).unwrap().into();
|
||||
let remote_public_key: AuthorityId =
|
||||
block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
||||
.unwrap()
|
||||
.into();
|
||||
|
||||
let (mut dht_event_tx, dht_event_rx) = channel(1);
|
||||
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 test_api = Arc::new(TestApi {
|
||||
authorities: vec![remote_public_key.clone()],
|
||||
});
|
||||
let test_api = Arc::new(TestApi { authorities: vec![remote_public_key.clone()] });
|
||||
let mut pool = LocalPool::new();
|
||||
|
||||
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
|
||||
// can make progress until the future returns `Pending`.
|
||||
let _ = pool.spawner().spawn_local_obj(async move {
|
||||
// Refilling `pending_lookups` only happens every X minutes. Fast
|
||||
// forward by calling `refill_pending_lookups_queue` directly.
|
||||
worker.refill_pending_lookups_queue().await.unwrap();
|
||||
worker.run().await
|
||||
}.boxed_local().into());
|
||||
let _ = pool.spawner().spawn_local_obj(
|
||||
async move {
|
||||
// Refilling `pending_lookups` only happens every X minutes. Fast
|
||||
// forward by calling `refill_pending_lookups_queue` directly.
|
||||
worker.refill_pending_lookups_queue().await.unwrap();
|
||||
worker.run().await
|
||||
}
|
||||
.boxed_local()
|
||||
.into(),
|
||||
);
|
||||
|
||||
pool.run_until(async {
|
||||
// Assert worker to trigger a lookup for the one and only authority.
|
||||
assert!(matches!(
|
||||
network_events.next().await,
|
||||
Some(TestNetworkEvent::GetCalled(_))
|
||||
));
|
||||
assert!(matches!(network_events.next().await, Some(TestNetworkEvent::GetCalled(_))));
|
||||
|
||||
// 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.");
|
||||
|
||||
// Make previously triggered lookup succeed.
|
||||
let dht_event = {
|
||||
let (key, value) = build_dht_event(
|
||||
vec![remote_multiaddr.clone()],
|
||||
remote_public_key.clone(), &remote_key_store,
|
||||
).await;
|
||||
remote_public_key.clone(),
|
||||
&remote_key_store,
|
||||
)
|
||||
.await;
|
||||
sc_network::DhtEvent::ValueFound(vec![(key, value)])
|
||||
};
|
||||
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
|
||||
// address for the remote node.
|
||||
let (sender, addresses) = futures::channel::oneshot::channel();
|
||||
to_worker.send(ServicetoWorkerMsg::GetAddressesByAuthorityId(
|
||||
remote_public_key,
|
||||
sender,
|
||||
)).await.expect("Channel has capacity of 1.");
|
||||
to_worker
|
||||
.send(ServicetoWorkerMsg::GetAddressesByAuthorityId(remote_public_key, sender))
|
||||
.await
|
||||
.expect("Channel has capacity of 1.");
|
||||
assert_eq!(Some(vec![remote_multiaddr]), addresses.await.unwrap());
|
||||
});
|
||||
}
|
||||
@@ -469,23 +475,19 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() {
|
||||
#[test]
|
||||
fn limit_number_of_addresses_added_to_cache_per_authority() {
|
||||
let remote_key_store = KeyStore::new();
|
||||
let remote_public = block_on(remote_key_store
|
||||
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
||||
.unwrap();
|
||||
let remote_public =
|
||||
block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
||||
.unwrap();
|
||||
|
||||
let addresses = (0..100).map(|_| {
|
||||
let peer_id = PeerId::random();
|
||||
let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
|
||||
address.with(multiaddr::Protocol::P2p(
|
||||
peer_id.into(),
|
||||
))
|
||||
}).collect();
|
||||
let addresses = (0..100)
|
||||
.map(|_| {
|
||||
let peer_id = PeerId::random();
|
||||
let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
|
||||
address.with(multiaddr::Protocol::P2p(peer_id.into()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let dht_event = block_on(build_dht_event(
|
||||
addresses,
|
||||
remote_public.into(),
|
||||
&remote_key_store,
|
||||
));
|
||||
let dht_event = block_on(build_dht_event(addresses, remote_public.into(), &remote_key_store));
|
||||
|
||||
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();
|
||||
assert_eq!(
|
||||
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]
|
||||
fn do_not_cache_addresses_without_peer_id() {
|
||||
let remote_key_store = KeyStore::new();
|
||||
let remote_public = block_on(remote_key_store
|
||||
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
||||
.unwrap();
|
||||
let remote_public =
|
||||
block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
||||
.unwrap();
|
||||
|
||||
let multiaddr_with_peer_id = {
|
||||
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()))
|
||||
};
|
||||
|
||||
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(
|
||||
vec![
|
||||
multiaddr_with_peer_id.clone(),
|
||||
multiaddr_without_peer_id,
|
||||
],
|
||||
vec![multiaddr_with_peer_id.clone(), multiaddr_without_peer_id],
|
||||
remote_public.into(),
|
||||
&remote_key_store,
|
||||
));
|
||||
|
||||
let (_dht_event_tx, dht_event_rx) = channel(1);
|
||||
let local_test_api = Arc::new(TestApi {
|
||||
authorities: vec![remote_public.into()],
|
||||
});
|
||||
let local_test_api = Arc::new(TestApi { authorities: vec![remote_public.into()] });
|
||||
let local_network: Arc<TestNetwork> = Arc::new(Default::default());
|
||||
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 worker = Worker::new(
|
||||
from_service,
|
||||
Arc::new(TestApi {
|
||||
authorities: vec![],
|
||||
}),
|
||||
Arc::new(TestApi { authorities: vec![] }),
|
||||
network.clone(),
|
||||
Box::pin(dht_event_rx),
|
||||
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 {
|
||||
external_addresses: vec![
|
||||
"/ip6/2001:db8::/tcp/30333/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"
|
||||
.parse().unwrap(),
|
||||
.parse()
|
||||
.unwrap(),
|
||||
],
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let (_to_worker, from_service) = mpsc::channel(0);
|
||||
let worker = Worker::new(
|
||||
from_service,
|
||||
Arc::new(TestApi {
|
||||
authorities: vec![],
|
||||
}),
|
||||
Arc::new(TestApi { authorities: vec![] }),
|
||||
network.clone(),
|
||||
Box::pin(dht_event_rx),
|
||||
Role::PublishAndDiscover(Arc::new(KeyStore::new())),
|
||||
@@ -624,7 +623,8 @@ fn addresses_to_publish_respects_existing_p2p_protocol() {
|
||||
);
|
||||
|
||||
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.",
|
||||
);
|
||||
}
|
||||
@@ -635,21 +635,21 @@ fn lookup_throttling() {
|
||||
let peer_id = PeerId::random();
|
||||
let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
|
||||
|
||||
address.with(multiaddr::Protocol::P2p(
|
||||
peer_id.into(),
|
||||
))
|
||||
address.with(multiaddr::Protocol::P2p(peer_id.into()))
|
||||
};
|
||||
let remote_key_store = KeyStore::new();
|
||||
let remote_public_keys: Vec<AuthorityId> = (0..20).map(|_| {
|
||||
block_on(remote_key_store
|
||||
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
||||
.unwrap().into()
|
||||
}).collect();
|
||||
let remote_hash_to_key = remote_public_keys.iter()
|
||||
let remote_public_keys: Vec<AuthorityId> = (0..20)
|
||||
.map(|_| {
|
||||
block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
||||
.unwrap()
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
let remote_hash_to_key = remote_public_keys
|
||||
.iter()
|
||||
.map(|k| (hash_authority_id(k.as_ref()), k.clone()))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
|
||||
let (mut dht_event_tx, dht_event_rx) = channel(1);
|
||||
let (_to_worker, from_service) = mpsc::channel(0);
|
||||
let mut network = TestNetwork::default();
|
||||
@@ -668,56 +668,61 @@ fn lookup_throttling() {
|
||||
let mut pool = LocalPool::new();
|
||||
let metrics = worker.metrics.clone().unwrap();
|
||||
|
||||
let _ = pool.spawner().spawn_local_obj(async move {
|
||||
// Refilling `pending_lookups` only happens every X minutes. Fast
|
||||
// forward by calling `refill_pending_lookups_queue` directly.
|
||||
worker.refill_pending_lookups_queue().await.unwrap();
|
||||
worker.run().await
|
||||
}.boxed_local().into());
|
||||
|
||||
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(_))));
|
||||
let _ = pool.spawner().spawn_local_obj(
|
||||
async move {
|
||||
// Refilling `pending_lookups` only happens every X minutes. Fast
|
||||
// forward by calling `refill_pending_lookups_queue` directly.
|
||||
worker.refill_pending_lookups_queue().await.unwrap();
|
||||
worker.run().await
|
||||
}
|
||||
assert_eq!(
|
||||
metrics.requests_pending.get(),
|
||||
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS) as u64
|
||||
);
|
||||
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS);
|
||||
.boxed_local()
|
||||
.into(),
|
||||
);
|
||||
|
||||
// Make first lookup succeed.
|
||||
let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap();
|
||||
let remote_key: AuthorityId = remote_hash_to_key.get(&remote_hash).unwrap().clone();
|
||||
let dht_event = {
|
||||
let (key, value) = build_dht_event(
|
||||
vec![remote_multiaddr.clone()],
|
||||
remote_key,
|
||||
&remote_key_store
|
||||
).await;
|
||||
sc_network::DhtEvent::ValueFound(vec![(key, value)])
|
||||
};
|
||||
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
|
||||
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!(
|
||||
metrics.requests_pending.get(),
|
||||
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS) as u64
|
||||
);
|
||||
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS);
|
||||
|
||||
// Assert worker to trigger another lookup.
|
||||
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
|
||||
assert_eq!(
|
||||
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);
|
||||
// Make first lookup succeed.
|
||||
let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap();
|
||||
let remote_key: AuthorityId = remote_hash_to_key.get(&remote_hash).unwrap().clone();
|
||||
let dht_event = {
|
||||
let (key, value) =
|
||||
build_dht_event(vec![remote_multiaddr.clone()], remote_key, &remote_key_store)
|
||||
.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.
|
||||
let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap();
|
||||
let dht_event = sc_network::DhtEvent::ValueNotFound(remote_hash);
|
||||
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
|
||||
// Assert worker to trigger another lookup.
|
||||
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
|
||||
assert_eq!(
|
||||
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.
|
||||
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
|
||||
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());
|
||||
// Make second one fail.
|
||||
let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap();
|
||||
let dht_event = sc_network::DhtEvent::ValueNotFound(remote_hash);
|
||||
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
|
||||
|
||||
// Assert worker to trigger another lookup.
|
||||
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
|
||||
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
|
||||
|
||||
use std::{pin::Pin, time, sync::Arc};
|
||||
use sc_client_api::backend;
|
||||
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_inherents::InherentData;
|
||||
use log::{error, info, debug, trace, warn};
|
||||
use sp_runtime::{
|
||||
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 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 std::{marker::PhantomData, pin::Pin, sync::Arc, time};
|
||||
|
||||
use prometheus_endpoint::Registry as PrometheusRegistry;
|
||||
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>
|
||||
where
|
||||
A: TransactionPool<Block = Block> + 'static,
|
||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||
Block: BlockT,
|
||||
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block>
|
||||
+ Send + Sync + 'static,
|
||||
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
|
||||
+ BlockBuilderApi<Block>,
|
||||
where
|
||||
A: TransactionPool<Block = Block> + 'static,
|
||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||
Block: BlockT,
|
||||
C: BlockBuilderProvider<B, Block, C>
|
||||
+ HeaderBackend<Block>
|
||||
+ ProvideRuntimeApi<Block>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
C::Api:
|
||||
ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + BlockBuilderApi<Block>,
|
||||
{
|
||||
fn init_with_now(
|
||||
&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
|
||||
ProposerFactory<A, B, C, PR>
|
||||
where
|
||||
A: TransactionPool<Block = Block> + 'static,
|
||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||
Block: BlockT,
|
||||
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block>
|
||||
+ Send + Sync + 'static,
|
||||
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
|
||||
+ BlockBuilderApi<Block>,
|
||||
PR: ProofRecording,
|
||||
impl<A, B, Block, C, PR> sp_consensus::Environment<Block> for ProposerFactory<A, B, C, PR>
|
||||
where
|
||||
A: TransactionPool<Block = Block> + 'static,
|
||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||
Block: BlockT,
|
||||
C: BlockBuilderProvider<B, Block, C>
|
||||
+ HeaderBackend<Block>
|
||||
+ ProvideRuntimeApi<Block>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
C::Api:
|
||||
ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + BlockBuilderApi<Block>,
|
||||
PR: ProofRecording,
|
||||
{
|
||||
type CreateProposer = future::Ready<Result<Self::Proposer, Self::Error>>;
|
||||
type Proposer = Proposer<B, Block, C, A, PR>;
|
||||
type Error = sp_blockchain::Error;
|
||||
|
||||
fn init(
|
||||
&mut self,
|
||||
parent_header: &<Block as BlockT>::Header,
|
||||
) -> Self::CreateProposer {
|
||||
fn init(&mut self, parent_header: &<Block as BlockT>::Header) -> Self::CreateProposer {
|
||||
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)>,
|
||||
}
|
||||
|
||||
impl<A, B, Block, C, PR> sp_consensus::Proposer<Block> for
|
||||
Proposer<B, Block, C, A, PR>
|
||||
where
|
||||
A: TransactionPool<Block = Block> + 'static,
|
||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||
Block: BlockT,
|
||||
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block>
|
||||
+ Send + Sync + 'static,
|
||||
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
|
||||
+ BlockBuilderApi<Block>,
|
||||
PR: ProofRecording,
|
||||
impl<A, B, Block, C, PR> sp_consensus::Proposer<Block> for Proposer<B, Block, C, A, PR>
|
||||
where
|
||||
A: TransactionPool<Block = Block> + 'static,
|
||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||
Block: BlockT,
|
||||
C: BlockBuilderProvider<B, Block, C>
|
||||
+ HeaderBackend<Block>
|
||||
+ ProvideRuntimeApi<Block>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
C::Api:
|
||||
ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + BlockBuilderApi<Block>,
|
||||
PR: ProofRecording,
|
||||
{
|
||||
type Transaction = backend::TransactionFor<B, Block>;
|
||||
type Proposal = Pin<Box<dyn Future<
|
||||
Output = Result<Proposal<Block, Self::Transaction, PR::Proof>, Self::Error>
|
||||
> + Send>>;
|
||||
type Proposal = Pin<
|
||||
Box<
|
||||
dyn Future<Output = Result<Proposal<Block, Self::Transaction, PR::Proof>, Self::Error>>
|
||||
+ Send,
|
||||
>,
|
||||
>;
|
||||
type Error = sp_blockchain::Error;
|
||||
type ProofRecording = PR;
|
||||
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 spawn_handle = self.spawn_handle.clone();
|
||||
|
||||
spawn_handle.spawn_blocking("basic-authorship-proposer", Box::pin(async move {
|
||||
// leave some time for evaluation and block finalization (33%)
|
||||
let deadline = (self.now)() + max_duration - max_duration / 3;
|
||||
let res = self.propose_with(
|
||||
inherent_data,
|
||||
inherent_digests,
|
||||
deadline,
|
||||
block_size_limit,
|
||||
).await;
|
||||
if tx.send(res).is_err() {
|
||||
trace!("Could not send block production result to proposer!");
|
||||
}
|
||||
}));
|
||||
spawn_handle.spawn_blocking(
|
||||
"basic-authorship-proposer",
|
||||
Box::pin(async move {
|
||||
// leave some time for evaluation and block finalization (33%)
|
||||
let deadline = (self.now)() + max_duration - max_duration / 3;
|
||||
let res = self
|
||||
.propose_with(inherent_data, inherent_digests, deadline, block_size_limit)
|
||||
.await;
|
||||
if tx.send(res).is_err() {
|
||||
trace!("Could not send block production result to proposer!");
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
async move {
|
||||
rx.await?
|
||||
}.boxed()
|
||||
async move { rx.await? }.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
||||
where
|
||||
A: TransactionPool<Block = Block>,
|
||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||
Block: BlockT,
|
||||
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block>
|
||||
+ Send + Sync + 'static,
|
||||
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
|
||||
+ BlockBuilderApi<Block>,
|
||||
PR: ProofRecording,
|
||||
where
|
||||
A: TransactionPool<Block = Block>,
|
||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||
Block: BlockT,
|
||||
C: BlockBuilderProvider<B, Block, C>
|
||||
+ HeaderBackend<Block>
|
||||
+ ProvideRuntimeApi<Block>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
C::Api:
|
||||
ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + BlockBuilderApi<Block>,
|
||||
PR: ProofRecording,
|
||||
{
|
||||
async fn propose_with(
|
||||
self,
|
||||
@@ -287,30 +305,30 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
||||
inherent_digests: DigestFor<Block>,
|
||||
deadline: time::Instant,
|
||||
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
|
||||
/// this number of transactions before quitting for real.
|
||||
/// It allows us to increase block utilization.
|
||||
const MAX_SKIPPED_TRANSACTIONS: usize = 8;
|
||||
|
||||
let mut block_builder = self.client.new_block_at(
|
||||
&self.parent_id,
|
||||
inherent_digests,
|
||||
PR::ENABLED,
|
||||
)?;
|
||||
let mut block_builder =
|
||||
self.client.new_block_at(&self.parent_id, inherent_digests, PR::ENABLED)?;
|
||||
|
||||
for inherent in block_builder.create_inherents(inherent_data)? {
|
||||
match block_builder.push(inherent) {
|
||||
Err(ApplyExtrinsicFailed(Validity(e))) if e.exhausted_resources() =>
|
||||
warn!("⚠️ Dropping non-mandatory inherent from overweight block."),
|
||||
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(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 t1 = self.transaction_pool.ready_at(self.parent_number).fuse();
|
||||
let mut t2 = futures_timer::Delay::new(
|
||||
deadline.saturating_duration_since((self.now)()) / 8,
|
||||
).fuse();
|
||||
let mut t2 =
|
||||
futures_timer::Delay::new(deadline.saturating_duration_since((self.now)()) / 8).fuse();
|
||||
|
||||
let pending_iterator = select! {
|
||||
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, \
|
||||
proceeding with proposing."
|
||||
);
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
let pending_tx_data = pending_tx.data().clone();
|
||||
let pending_tx_hash = pending_tx.hash().clone();
|
||||
|
||||
let block_size = block_builder.estimate_block_size(
|
||||
self.include_proof_in_block_size_estimation,
|
||||
);
|
||||
let block_size =
|
||||
block_builder.estimate_block_size(self.include_proof_in_block_size_estimation);
|
||||
if block_size + pending_tx_data.encoded_size() > block_size_limit {
|
||||
if skipped < MAX_SKIPPED_TRANSACTIONS {
|
||||
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.",
|
||||
MAX_SKIPPED_TRANSACTIONS - skipped,
|
||||
);
|
||||
continue;
|
||||
continue
|
||||
} else {
|
||||
debug!("Reached block size limit, proceeding with proposing.");
|
||||
hit_block_size_limit = true;
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,9 +395,8 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
||||
Ok(()) => {
|
||||
transaction_pushed = true;
|
||||
debug!("[{:?}] Pushed to the block.", pending_tx_hash);
|
||||
}
|
||||
Err(ApplyExtrinsicFailed(Validity(e)))
|
||||
if e.exhausted_resources() => {
|
||||
},
|
||||
Err(ApplyExtrinsicFailed(Validity(e))) if e.exhausted_resources() => {
|
||||
if skipped < MAX_SKIPPED_TRANSACTIONS {
|
||||
skipped += 1;
|
||||
debug!(
|
||||
@@ -390,20 +405,20 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
||||
);
|
||||
} else {
|
||||
debug!("Block is full, proceed with proposing.");
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) if skipped > 0 => {
|
||||
trace!(
|
||||
"[{:?}] Ignoring invalid transaction when skipping: {}",
|
||||
pending_tx_hash,
|
||||
e
|
||||
);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
debug!("[{:?}] Invalid transaction: {}", pending_tx_hash, e);
|
||||
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();
|
||||
|
||||
self.metrics.report(
|
||||
|metrics| {
|
||||
metrics.number_of_transactions.set(block.extrinsics().len() as u64);
|
||||
metrics.block_constructed.observe(block_timer.elapsed().as_secs_f64());
|
||||
}
|
||||
);
|
||||
self.metrics.report(|metrics| {
|
||||
metrics.number_of_transactions.set(block.extrinsics().len() as u64);
|
||||
metrics.block_constructed.observe(block_timer.elapsed().as_secs_f64());
|
||||
});
|
||||
|
||||
info!(
|
||||
"🎁 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");
|
||||
}
|
||||
|
||||
if let Err(err) = evaluation::evaluate_initial(
|
||||
&block,
|
||||
&self.parent_hash,
|
||||
self.parent_number,
|
||||
) {
|
||||
if let Err(err) =
|
||||
evaluation::evaluate_initial(&block, &self.parent_hash, self.parent_number)
|
||||
{
|
||||
error!("Failed to evaluate authored block: {:?}", err);
|
||||
}
|
||||
|
||||
let proof = PR::into_proof(proof)
|
||||
.map_err(|e| sp_blockchain::Error::Application(Box::new(e)))?;
|
||||
let proof =
|
||||
PR::into_proof(proof).map_err(|e| sp_blockchain::Error::Application(Box::new(e)))?;
|
||||
Ok(Proposal { block, proof, storage_changes })
|
||||
}
|
||||
}
|
||||
@@ -467,19 +478,20 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use futures::executor::block_on;
|
||||
use parking_lot::Mutex;
|
||||
use sp_consensus::{BlockOrigin, Proposer};
|
||||
use substrate_test_runtime_client::{
|
||||
prelude::*, TestClientBuilder, runtime::{Extrinsic, Transfer}, TestClientBuilderExt,
|
||||
};
|
||||
use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool, TransactionSource};
|
||||
use sc_client_api::Backend;
|
||||
use sc_transaction_pool::BasicPool;
|
||||
use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool, TransactionSource};
|
||||
use sp_api::Core;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::{BlockOrigin, Environment, Proposer};
|
||||
use sp_runtime::traits::NumberFor;
|
||||
use sc_client_api::Backend;
|
||||
use futures::executor::block_on;
|
||||
use sp_consensus::Environment;
|
||||
use substrate_test_runtime_client::{
|
||||
prelude::*,
|
||||
runtime::{Extrinsic, Transfer},
|
||||
TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
|
||||
const SOURCE: TransactionSource = TransactionSource::External;
|
||||
|
||||
@@ -489,16 +501,15 @@ mod tests {
|
||||
nonce,
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: Default::default(),
|
||||
}.into_signed_tx()
|
||||
}
|
||||
.into_signed_tx()
|
||||
}
|
||||
|
||||
fn chain_event<B: BlockT>(header: B::Header) -> ChainEvent<B>
|
||||
where NumberFor<B>: From<u64>
|
||||
where
|
||||
NumberFor<B>: From<u64>,
|
||||
{
|
||||
ChainEvent::NewBestBlock {
|
||||
hash: header.hash(),
|
||||
tree_route: None,
|
||||
}
|
||||
ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -514,25 +525,20 @@ mod tests {
|
||||
client.clone(),
|
||||
);
|
||||
|
||||
block_on(
|
||||
txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0), extrinsic(1)])
|
||||
).unwrap();
|
||||
block_on(txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0), extrinsic(1)]))
|
||||
.unwrap();
|
||||
|
||||
block_on(
|
||||
txpool.maintain(chain_event(
|
||||
client.header(&BlockId::Number(0u64))
|
||||
client
|
||||
.header(&BlockId::Number(0u64))
|
||||
.expect("header get error")
|
||||
.expect("there should be header")
|
||||
))
|
||||
.expect("there should be header"),
|
||||
)),
|
||||
);
|
||||
|
||||
let mut proposer_factory = ProposerFactory::new(
|
||||
spawner.clone(),
|
||||
client.clone(),
|
||||
txpool.clone(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let mut proposer_factory =
|
||||
ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
|
||||
|
||||
let cell = Mutex::new((false, time::Instant::now()));
|
||||
let proposer = proposer_factory.init_with_now(
|
||||
@@ -541,20 +547,21 @@ mod tests {
|
||||
let mut value = cell.lock();
|
||||
if !value.0 {
|
||||
value.0 = true;
|
||||
return value.1;
|
||||
return value.1
|
||||
}
|
||||
let old = value.1;
|
||||
let new = old + time::Duration::from_secs(2);
|
||||
*value = (true, new);
|
||||
old
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// when
|
||||
let deadline = time::Duration::from_secs(3);
|
||||
let block = block_on(
|
||||
proposer.propose(Default::default(), Default::default(), deadline, None)
|
||||
).map(|r| r.block).unwrap();
|
||||
let block =
|
||||
block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
|
||||
.map(|r| r.block)
|
||||
.unwrap();
|
||||
|
||||
// then
|
||||
// block should have some extrinsics although we have some more in the pool.
|
||||
@@ -574,13 +581,8 @@ mod tests {
|
||||
client.clone(),
|
||||
);
|
||||
|
||||
let mut proposer_factory = ProposerFactory::new(
|
||||
spawner.clone(),
|
||||
client.clone(),
|
||||
txpool.clone(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let mut proposer_factory =
|
||||
ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
|
||||
|
||||
let cell = Mutex::new((false, time::Instant::now()));
|
||||
let proposer = proposer_factory.init_with_now(
|
||||
@@ -589,18 +591,18 @@ mod tests {
|
||||
let mut value = cell.lock();
|
||||
if !value.0 {
|
||||
value.0 = true;
|
||||
return value.1;
|
||||
return value.1
|
||||
}
|
||||
let new = value.1 + time::Duration::from_secs(160);
|
||||
*value = (true, new);
|
||||
new
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
let deadline = time::Duration::from_secs(1);
|
||||
block_on(
|
||||
proposer.propose(Default::default(), Default::default(), deadline, None)
|
||||
).map(|r| r.block).unwrap();
|
||||
block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
|
||||
.map(|r| r.block)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -619,25 +621,19 @@ mod tests {
|
||||
let genesis_hash = client.info().best_hash;
|
||||
let block_id = BlockId::Hash(genesis_hash);
|
||||
|
||||
block_on(
|
||||
txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0)]),
|
||||
).unwrap();
|
||||
block_on(txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0)])).unwrap();
|
||||
|
||||
block_on(
|
||||
txpool.maintain(chain_event(
|
||||
client.header(&BlockId::Number(0u64))
|
||||
client
|
||||
.header(&BlockId::Number(0u64))
|
||||
.expect("header get error")
|
||||
.expect("there should be header"),
|
||||
))
|
||||
)),
|
||||
);
|
||||
|
||||
let mut proposer_factory = ProposerFactory::new(
|
||||
spawner.clone(),
|
||||
client.clone(),
|
||||
txpool.clone(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let mut proposer_factory =
|
||||
ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
|
||||
|
||||
let proposer = proposer_factory.init_with_now(
|
||||
&client.header(&block_id).unwrap().unwrap(),
|
||||
@@ -645,9 +641,9 @@ mod tests {
|
||||
);
|
||||
|
||||
let deadline = time::Duration::from_secs(9);
|
||||
let proposal = block_on(
|
||||
proposer.propose(Default::default(), Default::default(), deadline, None),
|
||||
).unwrap();
|
||||
let proposal =
|
||||
block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(proposal.block.extrinsics().len(), 1);
|
||||
|
||||
@@ -655,16 +651,13 @@ mod tests {
|
||||
api.execute_block(&block_id, proposal.block).unwrap();
|
||||
|
||||
let state = backend.state_at(block_id).unwrap();
|
||||
let changes_trie_state = backend::changes_tries_state_at_block(
|
||||
&block_id,
|
||||
backend.changes_trie_storage(),
|
||||
).unwrap();
|
||||
let changes_trie_state =
|
||||
backend::changes_tries_state_at_block(&block_id, backend.changes_trie_storage())
|
||||
.unwrap();
|
||||
|
||||
let storage_changes = api.into_storage_changes(
|
||||
&state,
|
||||
changes_trie_state.as_ref(),
|
||||
genesis_hash,
|
||||
).unwrap();
|
||||
let storage_changes = api
|
||||
.into_storage_changes(&state, changes_trie_state.as_ref(), genesis_hash)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
proposal.storage_changes.transaction_storage_root,
|
||||
@@ -685,8 +678,10 @@ mod tests {
|
||||
client.clone(),
|
||||
);
|
||||
|
||||
block_on(
|
||||
txpool.submit_at(&BlockId::number(0), SOURCE, vec![
|
||||
block_on(txpool.submit_at(
|
||||
&BlockId::number(0),
|
||||
SOURCE,
|
||||
vec![
|
||||
extrinsic(0),
|
||||
extrinsic(1),
|
||||
Transfer {
|
||||
@@ -704,22 +699,16 @@ mod tests {
|
||||
}.into_resources_exhausting_tx(),
|
||||
extrinsic(5),
|
||||
extrinsic(6),
|
||||
])
|
||||
).unwrap();
|
||||
],
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let mut proposer_factory = ProposerFactory::new(
|
||||
spawner.clone(),
|
||||
client.clone(),
|
||||
txpool.clone(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let mut propose_block = |
|
||||
client: &TestClient,
|
||||
number,
|
||||
expected_block_extrinsics,
|
||||
expected_pool_transactions,
|
||||
| {
|
||||
let mut proposer_factory =
|
||||
ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
|
||||
let mut propose_block = |client: &TestClient,
|
||||
number,
|
||||
expected_block_extrinsics,
|
||||
expected_pool_transactions| {
|
||||
let proposer = proposer_factory.init_with_now(
|
||||
&client.header(&BlockId::number(number)).unwrap().unwrap(),
|
||||
Box::new(move || time::Instant::now()),
|
||||
@@ -727,9 +716,10 @@ mod tests {
|
||||
|
||||
// when
|
||||
let deadline = time::Duration::from_secs(9);
|
||||
let block = block_on(
|
||||
proposer.propose(Default::default(), Default::default(), deadline, None)
|
||||
).map(|r| r.block).unwrap();
|
||||
let block =
|
||||
block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
|
||||
.map(|r| r.block)
|
||||
.unwrap();
|
||||
|
||||
// then
|
||||
// block should have some extrinsics although we have some more in the pool.
|
||||
@@ -741,10 +731,11 @@ mod tests {
|
||||
|
||||
block_on(
|
||||
txpool.maintain(chain_event(
|
||||
client.header(&BlockId::Number(0u64))
|
||||
client
|
||||
.header(&BlockId::Number(0u64))
|
||||
.expect("header get error")
|
||||
.expect("there should be header")
|
||||
))
|
||||
.expect("there should be header"),
|
||||
)),
|
||||
);
|
||||
|
||||
// let's create one block and import it
|
||||
@@ -753,10 +744,11 @@ mod tests {
|
||||
|
||||
block_on(
|
||||
txpool.maintain(chain_event(
|
||||
client.header(&BlockId::Number(1))
|
||||
client
|
||||
.header(&BlockId::Number(1))
|
||||
.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
|
||||
@@ -775,7 +767,8 @@ mod tests {
|
||||
spawner.clone(),
|
||||
client.clone(),
|
||||
);
|
||||
let genesis_header = client.header(&BlockId::Number(0u64))
|
||||
let genesis_header = client
|
||||
.header(&BlockId::Number(0u64))
|
||||
.expect("header get error")
|
||||
.expect("there should be header");
|
||||
|
||||
@@ -784,40 +777,43 @@ mod tests {
|
||||
.map(|v| Extrinsic::IncludeData(vec![v as u8; 10]))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let block_limit = genesis_header.encoded_size()
|
||||
+ extrinsics.iter().take(extrinsics_num - 1).map(Encode::encoded_size).sum::<usize>()
|
||||
+ Vec::<Extrinsic>::new().encoded_size();
|
||||
let block_limit = genesis_header.encoded_size() +
|
||||
extrinsics
|
||||
.iter()
|
||||
.take(extrinsics_num - 1)
|
||||
.map(Encode::encoded_size)
|
||||
.sum::<usize>() +
|
||||
Vec::<Extrinsic>::new().encoded_size();
|
||||
|
||||
block_on(
|
||||
txpool.submit_at(&BlockId::number(0), SOURCE, extrinsics)
|
||||
).unwrap();
|
||||
block_on(txpool.submit_at(&BlockId::number(0), SOURCE, extrinsics)).unwrap();
|
||||
|
||||
block_on(txpool.maintain(chain_event(genesis_header.clone())));
|
||||
|
||||
let mut proposer_factory = ProposerFactory::new(
|
||||
spawner.clone(),
|
||||
client.clone(),
|
||||
txpool.clone(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let mut proposer_factory =
|
||||
ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
|
||||
|
||||
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
|
||||
|
||||
// Give it enough time
|
||||
let deadline = time::Duration::from_secs(300);
|
||||
let block = block_on(
|
||||
proposer.propose(Default::default(), Default::default(), deadline, Some(block_limit))
|
||||
).map(|r| r.block).unwrap();
|
||||
let block = block_on(proposer.propose(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
deadline,
|
||||
Some(block_limit),
|
||||
))
|
||||
.map(|r| r.block)
|
||||
.unwrap();
|
||||
|
||||
// Based on the block limit, one transaction shouldn't be included.
|
||||
assert_eq!(block.extrinsics().len(), extrinsics_num - 1);
|
||||
|
||||
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
|
||||
|
||||
let block = block_on(
|
||||
proposer.propose(Default::default(), Default::default(), deadline, None,
|
||||
)).map(|r| r.block).unwrap();
|
||||
let block =
|
||||
block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
|
||||
.map(|r| r.block)
|
||||
.unwrap();
|
||||
|
||||
// Without a block limit we should include all of them
|
||||
assert_eq!(block.extrinsics().len(), extrinsics_num);
|
||||
@@ -833,9 +829,14 @@ mod tests {
|
||||
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
|
||||
|
||||
// Give it enough time
|
||||
let block = block_on(
|
||||
proposer.propose(Default::default(), Default::default(), deadline, Some(block_limit))
|
||||
).map(|r| r.block).unwrap();
|
||||
let block = block_on(proposer.propose(
|
||||
Default::default(),
|
||||
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
|
||||
// block size and thus, one less transaction should fit into the limit.
|
||||
|
||||
@@ -41,12 +41,12 @@
|
||||
//! # );
|
||||
//! // The first step is to create a `ProposerFactory`.
|
||||
//! let mut proposer_factory = ProposerFactory::new(
|
||||
//! spawner,
|
||||
//! client.clone(),
|
||||
//! txpool.clone(),
|
||||
//! None,
|
||||
//! None,
|
||||
//! );
|
||||
//! spawner,
|
||||
//! client.clone(),
|
||||
//! txpool.clone(),
|
||||
//! None,
|
||||
//! None,
|
||||
//! );
|
||||
//!
|
||||
//! // From this factory, we create a `Proposer`.
|
||||
//! let proposer = proposer_factory.init(
|
||||
@@ -69,8 +69,7 @@
|
||||
//! let block = futures::executor::block_on(future).unwrap();
|
||||
//! println!("Generated block: {:?}", block.block);
|
||||
//! ```
|
||||
//!
|
||||
|
||||
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};
|
||||
|
||||
@@ -28,14 +28,14 @@
|
||||
|
||||
use codec::Encode;
|
||||
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Header as HeaderT, Hash, Block as BlockT, HashFor, DigestFor, NumberFor, One},
|
||||
use sp_api::{
|
||||
ApiExt, ApiRef, Core, ProvideRuntimeApi, StorageChanges, StorageProof, TransactionOutcome,
|
||||
};
|
||||
use sp_blockchain::{ApplyExtrinsicFailed, Error};
|
||||
use sp_core::ExecutionContext;
|
||||
use sp_api::{
|
||||
Core, ApiExt, ApiRef, ProvideRuntimeApi, StorageChanges, StorageProof, TransactionOutcome,
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, DigestFor, Hash, HashFor, Header as HeaderT, NumberFor, One},
|
||||
};
|
||||
|
||||
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>,
|
||||
}
|
||||
|
||||
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.
|
||||
pub fn into_inner(self) -> (Block, StorageChanges<StateBackend, Block>, Option<StorageProof>) {
|
||||
(self.block, self.storage_changes, self.proof)
|
||||
@@ -103,11 +105,11 @@ impl<Block: BlockT, StateBackend: backend::StateBackend<HashFor<Block>>> BuiltBl
|
||||
|
||||
/// Block builder provider
|
||||
pub trait BlockBuilderProvider<B, Block, RA>
|
||||
where
|
||||
Block: BlockT,
|
||||
B: backend::Backend<Block>,
|
||||
Self: Sized,
|
||||
RA: ProvideRuntimeApi<Block>,
|
||||
where
|
||||
Block: BlockT,
|
||||
B: backend::Backend<Block>,
|
||||
Self: Sized,
|
||||
RA: ProvideRuntimeApi<Block>,
|
||||
{
|
||||
/// Create a new block, built on top of `parent`.
|
||||
///
|
||||
@@ -143,7 +145,8 @@ impl<'a, Block, A, B> BlockBuilder<'a, Block, A, B>
|
||||
where
|
||||
Block: BlockT,
|
||||
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>,
|
||||
{
|
||||
/// 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);
|
||||
|
||||
api.initialize_block_with_context(
|
||||
&block_id, ExecutionContext::BlockConstruction, &header,
|
||||
)?;
|
||||
api.initialize_block_with_context(&block_id, ExecutionContext::BlockConstruction, &header)?;
|
||||
|
||||
Ok(Self {
|
||||
parent_hash,
|
||||
@@ -207,12 +208,10 @@ where
|
||||
Ok(Ok(_)) => {
|
||||
extrinsics.push(xt);
|
||||
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))),
|
||||
}
|
||||
})
|
||||
@@ -224,9 +223,9 @@ where
|
||||
/// supplied by `self.api`, combined as [`BuiltBlock`].
|
||||
/// The storage proof will be `Some(_)` when proof recording was enabled.
|
||||
pub fn build(mut self) -> Result<BuiltBlock<Block, backend::StateBackendFor<B, Block>>, Error> {
|
||||
let header = self.api.finalize_block_with_context(
|
||||
&self.block_id, ExecutionContext::BlockConstruction
|
||||
)?;
|
||||
let header = self
|
||||
.api
|
||||
.finalize_block_with_context(&self.block_id, ExecutionContext::BlockConstruction)?;
|
||||
|
||||
debug_assert_eq!(
|
||||
header.extrinsics_root().clone(),
|
||||
@@ -244,11 +243,10 @@ where
|
||||
)?;
|
||||
let parent_hash = self.parent_hash;
|
||||
|
||||
let storage_changes = self.api.into_storage_changes(
|
||||
&state,
|
||||
changes_trie_state.as_ref(),
|
||||
parent_hash,
|
||||
).map_err(|e| sp_blockchain::Error::StorageChanges(e))?;
|
||||
let storage_changes = self
|
||||
.api
|
||||
.into_storage_changes(&state, changes_trie_state.as_ref(), parent_hash)
|
||||
.map_err(|e| sp_blockchain::Error::StorageChanges(e))?;
|
||||
|
||||
Ok(BuiltBlock {
|
||||
block: <Block as BlockT>::new(header, self.extrinsics),
|
||||
@@ -265,15 +263,17 @@ where
|
||||
inherent_data: sp_inherents::InherentData,
|
||||
) -> Result<Vec<Block::Extrinsic>, Error> {
|
||||
let block_id = self.block_id;
|
||||
self.api.execute_in_transaction(move |api| {
|
||||
// `create_inherents` should not change any state, to ensure this we always rollback
|
||||
// the transaction.
|
||||
TransactionOutcome::Rollback(api.inherent_extrinsics_with_context(
|
||||
&block_id,
|
||||
ExecutionContext::BlockConstruction,
|
||||
inherent_data
|
||||
))
|
||||
}).map_err(|e| Error::Application(Box::new(e)))
|
||||
self.api
|
||||
.execute_in_transaction(move |api| {
|
||||
// `create_inherents` should not change any state, to ensure this we always rollback
|
||||
// the transaction.
|
||||
TransactionOutcome::Rollback(api.inherent_extrinsics_with_context(
|
||||
&block_id,
|
||||
ExecutionContext::BlockConstruction,
|
||||
inherent_data,
|
||||
))
|
||||
})
|
||||
.map_err(|e| Error::Application(Box::new(e)))
|
||||
}
|
||||
|
||||
/// Estimate the size of the block in the current state.
|
||||
@@ -312,19 +312,22 @@ mod tests {
|
||||
RecordProof::Yes,
|
||||
Default::default(),
|
||||
&*backend,
|
||||
).unwrap().build().unwrap();
|
||||
)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let proof = block.proof.expect("Proof is build on request");
|
||||
|
||||
let backend = sp_state_machine::create_proof_check_backend::<Blake2Hasher>(
|
||||
block.storage_changes.transaction_storage_root,
|
||||
proof,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
backend.storage(&sp_core::storage::well_known_keys::CODE)
|
||||
.unwrap_err()
|
||||
.contains("Database missing expected key"),
|
||||
);
|
||||
assert!(backend
|
||||
.storage(&sp_core::storage::well_known_keys::CODE)
|
||||
.unwrap_err()
|
||||
.contains("Database missing expected key"),);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{DeriveInput, Ident, Error};
|
||||
use proc_macro_crate::{crate_name, FoundCrate};
|
||||
use quote::quote;
|
||||
use syn::{DeriveInput, Error, Ident};
|
||||
|
||||
const CRATE_NAME: &str = "sc-chain-spec";
|
||||
const ATTRIBUTE_NAME: &str = "forks";
|
||||
@@ -31,14 +31,18 @@ const ATTRIBUTE_NAME: &str = "forks";
|
||||
pub fn extension_derive(ast: &DeriveInput) -> proc_macro::TokenStream {
|
||||
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 forks = fields.named.iter().find_map(|f| {
|
||||
if f.attrs.iter().any(|attr| attr.path.is_ident(ATTRIBUTE_NAME)) {
|
||||
let typ = &f.ty;
|
||||
Some(quote! { #typ })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).unwrap_or_else(|| quote! { #crate_name::NoExtension });
|
||||
let forks = fields
|
||||
.named
|
||||
.iter()
|
||||
.find_map(|f| {
|
||||
if f.attrs.iter().any(|attr| attr.path.is_ident(ATTRIBUTE_NAME)) {
|
||||
let typ = &f.ty;
|
||||
Some(quote! { #typ })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| quote! { #crate_name::NoExtension });
|
||||
|
||||
quote! {
|
||||
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::Name(name)) => Ident::new(&name, Span::call_site()),
|
||||
Err(e) => {
|
||||
let err = Error::new(
|
||||
Span::call_site(),
|
||||
&format!("Could not find `serde` crate: {}", e),
|
||||
).to_compile_error();
|
||||
let err =
|
||||
Error::new(Span::call_site(), &format!("Could not find `serde` crate: {}", e))
|
||||
.to_compile_error();
|
||||
|
||||
return quote!( #err ).into();
|
||||
}
|
||||
return quote!( #err ).into()
|
||||
},
|
||||
};
|
||||
|
||||
quote! {
|
||||
@@ -131,14 +134,20 @@ pub fn group_derive(ast: &DeriveInput) -> proc_macro::TokenStream {
|
||||
pub fn derive(
|
||||
ast: &DeriveInput,
|
||||
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,
|
||||
) -> proc_macro::TokenStream {
|
||||
let err = || {
|
||||
let err = Error::new(
|
||||
Span::call_site(),
|
||||
"ChainSpecGroup is only available for structs with named fields."
|
||||
).to_compile_error();
|
||||
"ChainSpecGroup is only available for structs with named fields.",
|
||||
)
|
||||
.to_compile_error();
|
||||
quote!( #err ).into()
|
||||
};
|
||||
|
||||
@@ -168,47 +177,35 @@ pub fn derive(
|
||||
derive(&crate_name, name, &ast.generics, field_names, field_types, fields).into()
|
||||
}
|
||||
|
||||
fn generate_fork_fields(
|
||||
crate_name: &Ident,
|
||||
names: &[&Ident],
|
||||
types: &[&syn::Type],
|
||||
) -> TokenStream {
|
||||
fn generate_fork_fields(crate_name: &Ident, names: &[&Ident], types: &[&syn::Type]) -> TokenStream {
|
||||
let crate_name = std::iter::repeat(crate_name);
|
||||
quote! {
|
||||
#( pub #names: Option<<#types as #crate_name::Group>::Fork>, )*
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_base_to_fork(
|
||||
fork_name: &Ident,
|
||||
names: &[&Ident],
|
||||
) -> TokenStream {
|
||||
fn generate_base_to_fork(fork_name: &Ident, names: &[&Ident]) -> TokenStream {
|
||||
let names2 = names.to_vec();
|
||||
|
||||
quote!{
|
||||
quote! {
|
||||
#fork_name {
|
||||
#( #names: Some(self.#names2.to_fork()), )*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_combine_with(
|
||||
names: &[&Ident],
|
||||
) -> TokenStream {
|
||||
fn generate_combine_with(names: &[&Ident]) -> TokenStream {
|
||||
let names2 = names.to_vec();
|
||||
|
||||
quote!{
|
||||
quote! {
|
||||
#( self.#names.combine_with(other.#names2); )*
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_fork_to_base(
|
||||
fork: &Ident,
|
||||
names: &[&Ident],
|
||||
) -> TokenStream {
|
||||
fn generate_fork_to_base(fork: &Ident, names: &[&Ident]) -> TokenStream {
|
||||
let names2 = names.to_vec();
|
||||
|
||||
quote!{
|
||||
quote! {
|
||||
Some(#fork {
|
||||
#( #names: self.#names2?.to_base()?, )*
|
||||
})
|
||||
|
||||
@@ -19,15 +19,20 @@
|
||||
//! Substrate chain configurations.
|
||||
#![warn(missing_docs)]
|
||||
|
||||
use std::{borrow::Cow, fs::File, path::PathBuf, sync::Arc, collections::HashMap};
|
||||
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 crate::{extension::GetExtension, ChainType, Properties, RuntimeGenesis};
|
||||
use sc_network::config::MultiaddrWithPeerId;
|
||||
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> {
|
||||
File(PathBuf),
|
||||
@@ -56,8 +61,8 @@ impl<G: RuntimeGenesis> GenesisSource<G> {
|
||||
|
||||
match self {
|
||||
Self::File(path) => {
|
||||
let file = File::open(path)
|
||||
.map_err(|e| format!("Error opening spec file: {}", e))?;
|
||||
let file =
|
||||
File::open(path).map_err(|e| format!("Error opening spec file: {}", e))?;
|
||||
let genesis: GenesisContainer<G> = json::from_reader(file)
|
||||
.map_err(|e| format!("Error parsing spec file: {}", e))?;
|
||||
Ok(genesis.genesis)
|
||||
@@ -69,22 +74,25 @@ impl<G: RuntimeGenesis> GenesisSource<G> {
|
||||
},
|
||||
Self::Factory(f) => Ok(Genesis::Runtime(f())),
|
||||
Self::Storage(storage) => {
|
||||
let top = storage.top
|
||||
let top = storage
|
||||
.top
|
||||
.iter()
|
||||
.map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone())))
|
||||
.collect();
|
||||
|
||||
let children_default = storage.children_default
|
||||
let children_default = storage
|
||||
.children_default
|
||||
.iter()
|
||||
.map(|(k, child)|
|
||||
(
|
||||
StorageKey(k.clone()),
|
||||
child.data
|
||||
.map(|(k, child)| {
|
||||
(
|
||||
StorageKey(k.clone()),
|
||||
child
|
||||
.data
|
||||
.iter()
|
||||
.map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone())))
|
||||
.collect()
|
||||
)
|
||||
)
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
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::Raw(RawGenesis { top: map, children_default: children_map }) => Ok(Storage {
|
||||
top: map.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
|
||||
children_default: children_map.into_iter().map(|(storage_key, child_content)| {
|
||||
let child_info = ChildInfo::new_default(storage_key.0.as_slice());
|
||||
(
|
||||
storage_key.0,
|
||||
StorageChild {
|
||||
data: child_content.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
|
||||
child_info,
|
||||
},
|
||||
)
|
||||
}).collect(),
|
||||
children_default: children_map
|
||||
.into_iter()
|
||||
.map(|(storage_key, child_content)| {
|
||||
let child_info = ChildInfo::new_default(storage_key.0.as_slice());
|
||||
(
|
||||
storage_key.0,
|
||||
StorageChild {
|
||||
data: child_content.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
|
||||
child_info,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn assimilate_storage(
|
||||
&self,
|
||||
_: &mut Storage,
|
||||
) -> Result<(), String> {
|
||||
fn assimilate_storage(&self, _: &mut Storage) -> Result<(), String> {
|
||||
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> {
|
||||
fn clone(&self) -> Self {
|
||||
ChainSpec {
|
||||
client_spec: self.client_spec.clone(),
|
||||
genesis: self.genesis.clone(),
|
||||
}
|
||||
ChainSpec { client_spec: self.client_spec.clone(), genesis: self.genesis.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,10 +263,7 @@ impl<G, E> ChainSpec<G, E> {
|
||||
code_substitutes: HashMap::new(),
|
||||
};
|
||||
|
||||
ChainSpec {
|
||||
client_spec,
|
||||
genesis: GenesisSource::Factory(Arc::new(constructor)),
|
||||
}
|
||||
ChainSpec { client_spec, genesis: GenesisSource::Factory(Arc::new(constructor)) }
|
||||
}
|
||||
|
||||
/// Type of the chain.
|
||||
@@ -281,22 +283,15 @@ impl<G, E: serde::de::DeserializeOwned> ChainSpec<G, E> {
|
||||
let json = json.into();
|
||||
let client_spec = json::from_slice(json.as_ref())
|
||||
.map_err(|e| format!("Error parsing spec file: {}", e))?;
|
||||
Ok(ChainSpec {
|
||||
client_spec,
|
||||
genesis: GenesisSource::Binary(json),
|
||||
})
|
||||
Ok(ChainSpec { client_spec, genesis: GenesisSource::Binary(json) })
|
||||
}
|
||||
|
||||
/// Parse json file into a `ChainSpec`
|
||||
pub fn from_json_file(path: PathBuf) -> Result<Self, String> {
|
||||
let file = File::open(&path)
|
||||
.map_err(|e| format!("Error opening spec file: {}", e))?;
|
||||
let client_spec = json::from_reader(file)
|
||||
.map_err(|e| format!("Error parsing spec file: {}", e))?;
|
||||
Ok(ChainSpec {
|
||||
client_spec,
|
||||
genesis: GenesisSource::File(path),
|
||||
})
|
||||
let file = File::open(&path).map_err(|e| format!("Error opening spec file: {}", e))?;
|
||||
let client_spec =
|
||||
json::from_reader(file).map_err(|e| format!("Error parsing spec file: {}", e))?;
|
||||
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()?) {
|
||||
(true, Genesis::Runtime(g)) => {
|
||||
let storage = g.build_storage()?;
|
||||
let top = storage.top.into_iter()
|
||||
.map(|(k, v)| (StorageKey(k), StorageData(v)))
|
||||
.collect();
|
||||
let children_default = storage.children_default.into_iter()
|
||||
.map(|(sk, child)| (
|
||||
StorageKey(sk),
|
||||
child.data.into_iter()
|
||||
.map(|(k, v)| (StorageKey(k), StorageData(v)))
|
||||
.collect(),
|
||||
))
|
||||
let top =
|
||||
storage.top.into_iter().map(|(k, v)| (StorageKey(k), StorageData(v))).collect();
|
||||
let children_default = storage
|
||||
.children_default
|
||||
.into_iter()
|
||||
.map(|(sk, child)| {
|
||||
(
|
||||
StorageKey(sk),
|
||||
child
|
||||
.data
|
||||
.into_iter()
|
||||
.map(|(k, v)| (StorageKey(k), StorageData(v)))
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Genesis::Raw(RawGenesis { top, children_default })
|
||||
},
|
||||
(_, genesis) => genesis,
|
||||
};
|
||||
Ok(JsonContainer {
|
||||
client_spec: self.client_spec.clone(),
|
||||
genesis,
|
||||
})
|
||||
Ok(JsonContainer { client_spec: self.client_spec.clone(), genesis })
|
||||
}
|
||||
|
||||
/// Dump to json string.
|
||||
pub fn as_json(&self, raw: bool) -> Result<String, String> {
|
||||
let container = self.json_container(raw)?;
|
||||
json::to_string_pretty(&container)
|
||||
.map_err(|e| format!("Error generating spec json: {}", e))
|
||||
json::to_string_pretty(&container).map_err(|e| format!("Error generating spec json: {}", e))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +400,11 @@ where
|
||||
}
|
||||
|
||||
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.
|
||||
pub babe_finalized_block_weight: sp_consensus_babe::BabeBlockWeight,
|
||||
/// 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> {
|
||||
@@ -427,25 +428,25 @@ impl<Block: BlockT> LightSyncState<Block> {
|
||||
|
||||
SerializableLightSyncState {
|
||||
finalized_block_header: StorageData(self.finalized_block_header.encode()),
|
||||
babe_epoch_changes:
|
||||
StorageData(self.babe_epoch_changes.encode()),
|
||||
babe_finalized_block_weight:
|
||||
self.babe_finalized_block_weight,
|
||||
grandpa_authority_set:
|
||||
StorageData(self.grandpa_authority_set.encode()),
|
||||
babe_epoch_changes: StorageData(self.babe_epoch_changes.encode()),
|
||||
babe_finalized_block_weight: self.babe_finalized_block_weight,
|
||||
grandpa_authority_set: StorageData(self.grandpa_authority_set.encode()),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
finalized_block_header: codec::Decode::decode(&mut &serialized.finalized_block_header.0[..])?,
|
||||
babe_epoch_changes:
|
||||
codec::Decode::decode(&mut &serialized.babe_epoch_changes.0[..])?,
|
||||
babe_finalized_block_weight:
|
||||
serialized.babe_finalized_block_weight,
|
||||
grandpa_authority_set:
|
||||
codec::Decode::decode(&mut &serialized.grandpa_authority_set.0[..])?,
|
||||
finalized_block_header: codec::Decode::decode(
|
||||
&mut &serialized.finalized_block_header.0[..],
|
||||
)?,
|
||||
babe_epoch_changes: codec::Decode::decode(&mut &serialized.babe_epoch_changes.0[..])?,
|
||||
babe_finalized_block_weight: serialized.babe_finalized_block_weight,
|
||||
grandpa_authority_set: codec::Decode::decode(
|
||||
&mut &serialized.grandpa_authority_set.0[..],
|
||||
)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -469,12 +470,9 @@ mod tests {
|
||||
struct Genesis(HashMap<String, String>);
|
||||
|
||||
impl BuildStorage for Genesis {
|
||||
fn assimilate_storage(
|
||||
&self,
|
||||
storage: &mut Storage,
|
||||
) -> Result<(), String> {
|
||||
fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> {
|
||||
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(())
|
||||
}
|
||||
@@ -485,11 +483,10 @@ mod tests {
|
||||
#[test]
|
||||
fn should_deserialize_example_chain_spec() {
|
||||
let spec1 = TestSpec::from_json_bytes(Cow::Owned(
|
||||
include_bytes!("../res/chain_spec.json").to_vec()
|
||||
)).unwrap();
|
||||
let spec2 = TestSpec::from_json_file(
|
||||
PathBuf::from("./res/chain_spec.json")
|
||||
).unwrap();
|
||||
include_bytes!("../res/chain_spec.json").to_vec(),
|
||||
))
|
||||
.unwrap();
|
||||
let spec2 = TestSpec::from_json_file(PathBuf::from("./res/chain_spec.json")).unwrap();
|
||||
|
||||
assert_eq!(spec1.as_json(false), spec2.as_json(false));
|
||||
assert_eq!(spec2.chain_type(), ChainType::Live)
|
||||
@@ -506,8 +503,9 @@ mod tests {
|
||||
#[test]
|
||||
fn should_deserialize_chain_spec_with_extensions() {
|
||||
let spec = TestSpec2::from_json_bytes(Cow::Owned(
|
||||
include_bytes!("../res/chain_spec2.json").to_vec()
|
||||
)).unwrap();
|
||||
include_bytes!("../res/chain_spec2.json").to_vec(),
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(spec.extensions().my_property, "Test Extension");
|
||||
}
|
||||
|
||||
@@ -18,19 +18,21 @@
|
||||
|
||||
//! Chain Spec extensions helpers.
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::any::{TypeId, Any};
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
fmt::Debug,
|
||||
};
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
/// A `ChainSpec` extension.
|
||||
///
|
||||
/// This trait is implemented automatically by `ChainSpecGroup` macro.
|
||||
pub trait Group: Clone + Sized {
|
||||
/// An associated type containing fork definition.
|
||||
type Fork: Fork<Base=Self>;
|
||||
type Fork: Fork<Base = Self>;
|
||||
|
||||
/// Convert to fork type.
|
||||
fn to_fork(self) -> Self::Fork;
|
||||
@@ -45,7 +47,7 @@ pub trait Group: Clone + Sized {
|
||||
/// a complete set of parameters
|
||||
pub trait Fork: Serialize + DeserializeOwned + Clone + Sized {
|
||||
/// A base `Group` type.
|
||||
type Base: Group<Fork=Self>;
|
||||
type Base: Group<Fork = Self>;
|
||||
|
||||
/// Combine with another struct.
|
||||
///
|
||||
@@ -128,7 +130,8 @@ pub trait Extension: Serialize + DeserializeOwned + Clone {
|
||||
fn get_any(&self, t: TypeId) -> &dyn Any;
|
||||
|
||||
/// 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,
|
||||
T: Group + 'static,
|
||||
<Self::Forks as IsForks>::Extension: Extension,
|
||||
@@ -142,8 +145,12 @@ pub trait Extension: Serialize + DeserializeOwned + Clone {
|
||||
impl Extension for crate::NoExtension {
|
||||
type Forks = Self;
|
||||
|
||||
fn get<T: 'static>(&self) -> Option<&T> { None }
|
||||
fn get_any(&self, _t: TypeId) -> &dyn Any { self }
|
||||
fn get<T: 'static>(&self) -> Option<&T> {
|
||||
None
|
||||
}
|
||||
fn get_any(&self, _t: TypeId) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
base: Default::default(),
|
||||
forks: Default::default(),
|
||||
}
|
||||
Self { 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,
|
||||
{
|
||||
/// 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,
|
||||
T: Group + 'static,
|
||||
{
|
||||
@@ -203,29 +209,31 @@ impl<B, T> IsForks for Forks<B, T> where
|
||||
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,
|
||||
{
|
||||
/// Get forks definition for a subset of this extension.
|
||||
///
|
||||
/// Returns the `Forks` struct, but limited to a particular type
|
||||
/// 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,
|
||||
{
|
||||
let base = self.base.get::<X>()?.clone();
|
||||
let forks = self.forks.iter().filter_map(|(k, v)| {
|
||||
Some((k.clone(), v.get::<Option<X::Fork>>()?.clone()?))
|
||||
}).collect();
|
||||
let forks = self
|
||||
.forks
|
||||
.iter()
|
||||
.filter_map(|(k, v)| Some((k.clone(), v.get::<Option<X::Fork>>()?.clone()?)))
|
||||
.collect();
|
||||
|
||||
Some(Forks {
|
||||
base,
|
||||
forks,
|
||||
})
|
||||
Some(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,
|
||||
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,
|
||||
T: Group + 'static,
|
||||
<Self::Forks as IsForks>::Extension: Extension,
|
||||
@@ -266,7 +275,7 @@ pub trait GetExtension {
|
||||
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 {
|
||||
Extension::get_any(self, t)
|
||||
}
|
||||
@@ -281,7 +290,7 @@ pub fn get_extension<T: 'static>(e: &dyn GetExtension) -> Option<&T> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
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.
|
||||
use crate as sc_chain_spec;
|
||||
|
||||
@@ -297,7 +306,9 @@ mod tests {
|
||||
pub test: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]
|
||||
#[derive(
|
||||
Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension,
|
||||
)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Extensions {
|
||||
pub ext1: Extension1,
|
||||
@@ -315,11 +326,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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:
|
||||
// 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,
|
||||
"forkable": {
|
||||
@@ -342,40 +354,40 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
"#).unwrap();
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let ext: Ext2 = serde_json::from_value(ext_val).unwrap();
|
||||
|
||||
assert_eq!(ext.get::<Extension1>(), Some(&Extension1 {
|
||||
test: 11
|
||||
}));
|
||||
assert_eq!(ext.get::<Extension1>(), Some(&Extension1 { test: 11 }));
|
||||
|
||||
// get forks definition
|
||||
let forks = ext.get::<Forks<u64, Extensions>>().unwrap();
|
||||
assert_eq!(forks.at_block(0), Extensions {
|
||||
ext1: Extension1 { test: 15 },
|
||||
ext2: Extension2 { test: 123 },
|
||||
});
|
||||
assert_eq!(forks.at_block(1), Extensions {
|
||||
ext1: Extension1 { test: 5 },
|
||||
ext2: Extension2 { test: 123 },
|
||||
});
|
||||
assert_eq!(forks.at_block(2), Extensions {
|
||||
ext1: Extension1 { test: 5 },
|
||||
ext2: Extension2 { test: 5 },
|
||||
});
|
||||
assert_eq!(forks.at_block(4), Extensions {
|
||||
ext1: Extension1 { test: 5 },
|
||||
ext2: Extension2 { test: 5 },
|
||||
});
|
||||
assert_eq!(forks.at_block(5), Extensions {
|
||||
ext1: Extension1 { test: 5 },
|
||||
ext2: Extension2 { test: 1 },
|
||||
});
|
||||
assert_eq!(forks.at_block(10), Extensions {
|
||||
ext1: Extension1 { test: 5 },
|
||||
ext2: Extension2 { test: 1 },
|
||||
});
|
||||
assert_eq!(
|
||||
forks.at_block(0),
|
||||
Extensions { ext1: Extension1 { test: 15 }, ext2: Extension2 { test: 123 } }
|
||||
);
|
||||
assert_eq!(
|
||||
forks.at_block(1),
|
||||
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 123 } }
|
||||
);
|
||||
assert_eq!(
|
||||
forks.at_block(2),
|
||||
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 5 } }
|
||||
);
|
||||
assert_eq!(
|
||||
forks.at_block(4),
|
||||
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 5 } }
|
||||
);
|
||||
assert_eq!(
|
||||
forks.at_block(5),
|
||||
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 1 } }
|
||||
);
|
||||
assert_eq!(
|
||||
forks.at_block(10),
|
||||
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 1 } }
|
||||
);
|
||||
assert!(forks.at_block(10).get::<Extension2>().is_some());
|
||||
|
||||
// filter forks for `Extension2`
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
//!
|
||||
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecExtension)]
|
||||
//! pub struct MyExtension {
|
||||
//! pub known_blocks: HashMap<u64, String>,
|
||||
//! pub known_blocks: HashMap<u64, String>,
|
||||
//! }
|
||||
//!
|
||||
//! pub type MyChainSpec<G> = GenericChainSpec<G, MyExtension>;
|
||||
@@ -53,19 +53,19 @@
|
||||
//!
|
||||
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)]
|
||||
//! pub struct ClientParams {
|
||||
//! max_block_size: usize,
|
||||
//! max_extrinsic_size: usize,
|
||||
//! max_block_size: usize,
|
||||
//! max_extrinsic_size: usize,
|
||||
//! }
|
||||
//!
|
||||
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)]
|
||||
//! pub struct PoolParams {
|
||||
//! max_transaction_size: usize,
|
||||
//! max_transaction_size: usize,
|
||||
//! }
|
||||
//!
|
||||
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup, ChainSpecExtension)]
|
||||
//! pub struct Extension {
|
||||
//! pub client: ClientParams,
|
||||
//! pub pool: PoolParams,
|
||||
//! pub client: ClientParams,
|
||||
//! pub pool: PoolParams,
|
||||
//! }
|
||||
//!
|
||||
//! pub type BlockNumber = u64;
|
||||
@@ -88,20 +88,20 @@
|
||||
//!
|
||||
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
|
||||
//! pub struct ClientParams {
|
||||
//! max_block_size: usize,
|
||||
//! max_extrinsic_size: usize,
|
||||
//! max_block_size: usize,
|
||||
//! max_extrinsic_size: usize,
|
||||
//! }
|
||||
//!
|
||||
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
|
||||
//! pub struct PoolParams {
|
||||
//! max_transaction_size: usize,
|
||||
//! max_transaction_size: usize,
|
||||
//! }
|
||||
//!
|
||||
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecExtension)]
|
||||
//! pub struct Extension {
|
||||
//! pub client: ClientParams,
|
||||
//! #[forks]
|
||||
//! pub pool: Forks<u64, PoolParams>,
|
||||
//! pub client: ClientParams,
|
||||
//! #[forks]
|
||||
//! pub pool: Forks<u64, PoolParams>,
|
||||
//! }
|
||||
//!
|
||||
//! pub type MyChainSpec<G> = GenericChainSpec<G, Extension>;
|
||||
@@ -111,16 +111,16 @@ mod chain_spec;
|
||||
mod extension;
|
||||
|
||||
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};
|
||||
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use sp_runtime::BuildStorage;
|
||||
use sc_network::config::MultiaddrWithPeerId;
|
||||
use sc_telemetry::TelemetryEndpoints;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use sp_core::storage::Storage;
|
||||
use sp_runtime::BuildStorage;
|
||||
|
||||
/// The type of a chain.
|
||||
///
|
||||
|
||||
@@ -74,9 +74,8 @@ impl WasmExecutionMethod {
|
||||
impl Into<sc_service::config::WasmExecutionMethod> for WasmExecutionMethod {
|
||||
fn into(self) -> sc_service::config::WasmExecutionMethod {
|
||||
match self {
|
||||
WasmExecutionMethod::Interpreted => {
|
||||
sc_service::config::WasmExecutionMethod::Interpreted
|
||||
}
|
||||
WasmExecutionMethod::Interpreted =>
|
||||
sc_service::config::WasmExecutionMethod::Interpreted,
|
||||
#[cfg(feature = "wasmtime")]
|
||||
WasmExecutionMethod::Compiled => sc_service::config::WasmExecutionMethod::Compiled,
|
||||
#[cfg(not(feature = "wasmtime"))]
|
||||
@@ -250,14 +249,10 @@ impl Into<sc_network::config::SyncMode> for SyncMode {
|
||||
fn into(self) -> sc_network::config::SyncMode {
|
||||
match self {
|
||||
SyncMode::Full => sc_network::config::SyncMode::Full,
|
||||
SyncMode::Fast => sc_network::config::SyncMode::Fast {
|
||||
skip_proofs: false,
|
||||
storage_chain_mode: false,
|
||||
},
|
||||
SyncMode::FastUnsafe => sc_network::config::SyncMode::Fast {
|
||||
skip_proofs: true,
|
||||
storage_chain_mode: false,
|
||||
},
|
||||
SyncMode::Fast =>
|
||||
sc_network::config::SyncMode::Fast { skip_proofs: false, 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
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::error;
|
||||
use crate::params::NodeKeyParams;
|
||||
use crate::params::SharedParams;
|
||||
use crate::CliConfiguration;
|
||||
use crate::{
|
||||
error,
|
||||
params::{NodeKeyParams, SharedParams},
|
||||
CliConfiguration,
|
||||
};
|
||||
use log::info;
|
||||
use sc_network::config::build_multiaddr;
|
||||
use sc_service::{config::{MultiaddrWithPeerId, NetworkConfiguration}, ChainSpec};
|
||||
use structopt::StructOpt;
|
||||
use sc_service::{
|
||||
config::{MultiaddrWithPeerId, NetworkConfiguration},
|
||||
ChainSpec,
|
||||
};
|
||||
use std::io::Write;
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// The `build-spec` command used to build a specification.
|
||||
#[derive(Debug, StructOpt, Clone)]
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
CliConfiguration, error, params::{ImportParams, SharedParams, BlockNumberOrHash},
|
||||
error,
|
||||
params::{BlockNumberOrHash, ImportParams, SharedParams},
|
||||
CliConfiguration,
|
||||
};
|
||||
use sc_client_api::{BlockBackend, UsageProvider};
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
||||
@@ -48,11 +50,7 @@ pub struct CheckBlockCmd {
|
||||
|
||||
impl CheckBlockCmd {
|
||||
/// Run the check-block command
|
||||
pub async fn run<B, C, IQ>(
|
||||
&self,
|
||||
client: Arc<C>,
|
||||
import_queue: IQ,
|
||||
) -> error::Result<()>
|
||||
pub async fn run<B, C, IQ>(&self, client: Arc<C>, import_queue: IQ) -> error::Result<()>
|
||||
where
|
||||
B: BlockT + for<'de> serde::Deserialize<'de>,
|
||||
C: BlockBackend<B> + UsageProvider<B> + Send + Sync + 'static,
|
||||
|
||||
@@ -16,21 +16,16 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::error;
|
||||
use crate::params::{GenericNumber, DatabaseParams, PruningParams, SharedParams};
|
||||
use crate::CliConfiguration;
|
||||
use log::info;
|
||||
use sc_service::{
|
||||
config::DatabaseConfig, chain_ops::export_blocks,
|
||||
use crate::{
|
||||
error,
|
||||
params::{DatabaseParams, GenericNumber, PruningParams, SharedParams},
|
||||
CliConfiguration,
|
||||
};
|
||||
use log::info;
|
||||
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 std::fmt::Debug;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::{fmt::Debug, fs, io, path::PathBuf, str::FromStr, sync::Arc};
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// The `export-blocks` command used to export blocks.
|
||||
@@ -95,9 +90,7 @@ impl ExportBlocksCmd {
|
||||
None => Box::new(io::stdout()),
|
||||
};
|
||||
|
||||
export_blocks(client, file, from.into(), to, binary)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
export_blocks(client, file, from.into(), to, binary).await.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,13 +17,15 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
CliConfiguration, error, params::{PruningParams, SharedParams, BlockNumberOrHash},
|
||||
error,
|
||||
params::{BlockNumberOrHash, PruningParams, SharedParams},
|
||||
CliConfiguration,
|
||||
};
|
||||
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 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
|
||||
/// a chain spec.
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
// limitations under the License.
|
||||
|
||||
//! Implementation of the `generate` subcommand
|
||||
use bip39::{MnemonicType, Mnemonic, Language};
|
||||
use structopt::StructOpt;
|
||||
use crate::{
|
||||
utils::print_from_uri, KeystoreParams, Error,
|
||||
with_crypto_scheme, NetworkSchemeFlag, OutputTypeFlag, CryptoSchemeFlag,
|
||||
utils::print_from_uri, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams,
|
||||
NetworkSchemeFlag, OutputTypeFlag,
|
||||
};
|
||||
use bip39::{Language, Mnemonic, MnemonicType};
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// The `generate` command
|
||||
#[derive(Debug, StructOpt, Clone)]
|
||||
@@ -52,12 +52,11 @@ impl GenerateCmd {
|
||||
/// Run the command
|
||||
pub fn run(&self) -> Result<(), Error> {
|
||||
let words = match self.words {
|
||||
Some(words) => {
|
||||
MnemonicType::for_word_count(words)
|
||||
.map_err(|_| {
|
||||
Error::Input("Invalid number of words given for phrase: must be 12/15/18/21/24".into())
|
||||
})?
|
||||
},
|
||||
Some(words) => MnemonicType::for_word_count(words).map_err(|_| {
|
||||
Error::Input(
|
||||
"Invalid number of words given for phrase: must be 12/15/18/21/24".into(),
|
||||
)
|
||||
})?,
|
||||
None => MnemonicType::Words12,
|
||||
};
|
||||
let mnemonic = Mnemonic::new(words, Language::English);
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
//! Implementation of the `generate-node-key` subcommand
|
||||
|
||||
use crate::Error;
|
||||
use structopt::StructOpt;
|
||||
use std::{path::PathBuf, fs};
|
||||
use libp2p::identity::{ed25519 as libp2p_ed25519, PublicKey};
|
||||
use std::{fs, path::PathBuf};
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// The `generate-node-key` command
|
||||
#[derive(Debug, StructOpt)]
|
||||
@@ -59,15 +59,14 @@ impl GenerateNodeKeyCmd {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tempfile::Builder;
|
||||
use std::io::Read;
|
||||
use tempfile::Builder;
|
||||
|
||||
#[test]
|
||||
fn generate_node_key() {
|
||||
let mut file = Builder::new().prefix("keyfile").tempfile().unwrap();
|
||||
let file_path = file.path().display().to_string();
|
||||
let generate =
|
||||
GenerateNodeKeyCmd::from_iter(&["generate-node-key", "--file", &file_path]);
|
||||
let generate = GenerateNodeKeyCmd::from_iter(&["generate-node-key", "--file", &file_path]);
|
||||
assert!(generate.run().is_ok());
|
||||
let mut buf = String::new();
|
||||
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
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::error;
|
||||
use crate::params::ImportParams;
|
||||
use crate::params::SharedParams;
|
||||
use crate::CliConfiguration;
|
||||
use crate::{
|
||||
error,
|
||||
params::{ImportParams, SharedParams},
|
||||
CliConfiguration,
|
||||
};
|
||||
use sc_client_api::UsageProvider;
|
||||
use sc_service::chain_ops::import_blocks;
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use std::fmt::Debug;
|
||||
use std::fs;
|
||||
use std::io::{self, Read, Seek};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
fs,
|
||||
io::{self, Read, Seek},
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
use structopt::StructOpt;
|
||||
use sc_client_api::UsageProvider;
|
||||
|
||||
/// The `import-blocks` command used to import blocks.
|
||||
#[derive(Debug, StructOpt)]
|
||||
@@ -63,11 +66,7 @@ impl<T: Read + Seek> ReadPlusSeek for T {}
|
||||
|
||||
impl ImportBlocksCmd {
|
||||
/// Run the import-blocks command
|
||||
pub async fn run<B, C, IQ>(
|
||||
&self,
|
||||
client: Arc<C>,
|
||||
import_queue: IQ,
|
||||
) -> error::Result<()>
|
||||
pub async fn run<B, C, IQ>(&self, client: Arc<C>, import_queue: IQ) -> error::Result<()>
|
||||
where
|
||||
C: UsageProvider<B> + Send + Sync + 'static,
|
||||
B: BlockT + for<'de> serde::Deserialize<'de>,
|
||||
@@ -79,7 +78,7 @@ impl ImportBlocksCmd {
|
||||
let mut buffer = Vec::new();
|
||||
io::stdin().read_to_end(&mut buffer)?;
|
||||
Box::new(io::Cursor::new(buffer))
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
import_blocks(client, import_queue, file, false, self.binary)
|
||||
|
||||
@@ -18,22 +18,18 @@
|
||||
//! Implementation of the `insert` subcommand
|
||||
|
||||
use crate::{
|
||||
Error, KeystoreParams, CryptoSchemeFlag, SharedParams, utils, with_crypto_scheme,
|
||||
SubstrateCli,
|
||||
utils, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, SharedParams, 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_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
|
||||
#[derive(Debug, StructOpt, Clone)]
|
||||
#[structopt(
|
||||
name = "insert",
|
||||
about = "Insert a key to the keystore of a node."
|
||||
)]
|
||||
#[structopt(name = "insert", about = "Insert a key to the keystore of a node.")]
|
||||
pub struct InsertKeyCmd {
|
||||
/// The secret key URI.
|
||||
/// If the value is a file, the file content is used as URI.
|
||||
@@ -62,7 +58,8 @@ impl InsertKeyCmd {
|
||||
/// Run the command
|
||||
pub fn run<C: SubstrateCli>(&self, cli: &C) -> Result<(), Error> {
|
||||
let suri = utils::read_uri(self.suri.as_ref())?;
|
||||
let base_path = self.shared_params
|
||||
let base_path = self
|
||||
.shared_params
|
||||
.base_path()
|
||||
.unwrap_or_else(|| BasePath::from_project("", "", &C::executable_name()));
|
||||
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)?);
|
||||
(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[..])
|
||||
.map_err(|_| Error::KeyStoreOperation)?;
|
||||
@@ -98,10 +96,10 @@ fn to_vec<P: sp_core::Pair>(uri: &str, pass: Option<SecretString>) -> Result<Vec
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sc_service::{ChainSpec, ChainType, GenericChainSpec, NoExtension};
|
||||
use sp_core::{sr25519::Pair, Pair as _, Public};
|
||||
use structopt::StructOpt;
|
||||
use tempfile::TempDir;
|
||||
use sp_core::{sr25519::Pair, Pair as _, Public};
|
||||
use sc_service::{ChainSpec, GenericChainSpec, ChainType, NoExtension};
|
||||
|
||||
struct Cli;
|
||||
|
||||
@@ -135,21 +133,17 @@ mod tests {
|
||||
}
|
||||
|
||||
fn load_spec(&self, _: &str) -> std::result::Result<Box<dyn ChainSpec>, String> {
|
||||
Ok(
|
||||
Box::new(
|
||||
GenericChainSpec::from_genesis(
|
||||
"test",
|
||||
"test_id",
|
||||
ChainType::Development,
|
||||
|| unimplemented!("Not required in tests"),
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
NoExtension::None,
|
||||
),
|
||||
),
|
||||
)
|
||||
Ok(Box::new(GenericChainSpec::from_genesis(
|
||||
"test",
|
||||
"test_id",
|
||||
ChainType::Development,
|
||||
|| unimplemented!("Not required in tests"),
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
NoExtension::None,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,15 +153,20 @@ mod tests {
|
||||
let path_str = format!("{}", path.path().display());
|
||||
let (key, uri, _) = Pair::generate_with_phrase(None);
|
||||
|
||||
let inspect = InsertKeyCmd::from_iter(
|
||||
&["insert-key", "-d", &path_str, "--key-type", "test", "--suri", &uri],
|
||||
);
|
||||
let inspect = InsertKeyCmd::from_iter(&[
|
||||
"insert-key",
|
||||
"-d",
|
||||
&path_str,
|
||||
"--key-type",
|
||||
"test",
|
||||
"--suri",
|
||||
&uri,
|
||||
]);
|
||||
assert!(inspect.run(&Cli).is_ok());
|
||||
|
||||
let keystore = LocalKeystore::open(
|
||||
path.path().join("chains").join("test_id").join("keystore"),
|
||||
None,
|
||||
).unwrap();
|
||||
let keystore =
|
||||
LocalKeystore::open(path.path().join("chains").join("test_id").join("keystore"), None)
|
||||
.unwrap();
|
||||
assert!(keystore.has_keys(&[(key.public().to_raw_vec(), KeyTypeId(*b"test"))]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
//! Implementation of the `inspect` subcommand
|
||||
|
||||
use crate::{
|
||||
utils::{self, print_from_uri, print_from_public}, KeystoreParams,
|
||||
with_crypto_scheme, NetworkSchemeFlag, OutputTypeFlag, CryptoSchemeFlag, Error,
|
||||
utils::{self, print_from_public, print_from_uri},
|
||||
with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, NetworkSchemeFlag, OutputTypeFlag,
|
||||
};
|
||||
use structopt::StructOpt;
|
||||
/// The `inspect` command
|
||||
@@ -103,8 +103,7 @@ mod tests {
|
||||
"remember fiber forum demise paper uniform squirrel feel access exclude casual effort";
|
||||
let seed = "0xad1fb77243b536b90cfe5f0d351ab1b1ac40e3890b41dc64f766ee56340cfca5";
|
||||
|
||||
let inspect =
|
||||
InspectKeyCmd::from_iter(&["inspect-key", words, "--password", "12345"]);
|
||||
let inspect = InspectKeyCmd::from_iter(&["inspect-key", words, "--password", "12345"]);
|
||||
assert!(inspect.run().is_ok());
|
||||
|
||||
let inspect = InspectKeyCmd::from_iter(&["inspect-key", seed]);
|
||||
|
||||
@@ -18,9 +18,8 @@
|
||||
//! Implementation of the `inspect-node-key` subcommand
|
||||
|
||||
use crate::{Error, NetworkSchemeFlag};
|
||||
use std::fs;
|
||||
use libp2p::identity::{PublicKey, ed25519};
|
||||
use std::path::PathBuf;
|
||||
use libp2p::identity::{ed25519, PublicKey};
|
||||
use std::{fs, path::PathBuf};
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// The `inspect-node-key` command
|
||||
@@ -42,10 +41,10 @@ pub struct InspectNodeKeyCmd {
|
||||
impl InspectNodeKeyCmd {
|
||||
/// runs the command
|
||||
pub fn run(&self) -> Result<(), Error> {
|
||||
let mut file_content = hex::decode(fs::read(&self.file)?)
|
||||
.map_err(|_| "failed to decode secret as hex")?;
|
||||
let secret = ed25519::SecretKey::from_bytes(&mut file_content)
|
||||
.map_err(|_| "Bad node key file")?;
|
||||
let mut file_content =
|
||||
hex::decode(fs::read(&self.file)?).map_err(|_| "failed to decode secret as hex")?;
|
||||
let secret =
|
||||
ed25519::SecretKey::from_bytes(&mut file_content).map_err(|_| "Bad node key file")?;
|
||||
|
||||
let keypair = ed25519::Keypair::from(secret);
|
||||
let peer_id = PublicKey::Ed25519(keypair.public()).into_peer_id();
|
||||
@@ -58,8 +57,7 @@ impl InspectNodeKeyCmd {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::super::GenerateNodeKeyCmd;
|
||||
use super::{super::GenerateNodeKeyCmd, *};
|
||||
|
||||
#[test]
|
||||
fn inspect_node_key() {
|
||||
|
||||
@@ -21,11 +21,8 @@ use crate::{Error, SubstrateCli};
|
||||
use structopt::StructOpt;
|
||||
|
||||
use super::{
|
||||
insert_key::InsertKeyCmd,
|
||||
inspect_key::InspectKeyCmd,
|
||||
generate::GenerateCmd,
|
||||
inspect_node_key::InspectNodeKeyCmd,
|
||||
generate_node_key::GenerateNodeKeyCmd,
|
||||
generate::GenerateCmd, generate_node_key::GenerateNodeKeyCmd, insert_key::InsertKeyCmd,
|
||||
inspect_key::InspectKeyCmd, inspect_node_key::InspectNodeKeyCmd,
|
||||
};
|
||||
|
||||
/// Key utilities for the cli.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user