mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-23 22:25:42 +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.
|
# FIXME: Temorarily allow to fail.
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
|
|
||||||
|
cargo-fmt:
|
||||||
|
stage: test
|
||||||
|
<<: *docker-env
|
||||||
|
<<: *test-refs
|
||||||
|
script:
|
||||||
|
- cargo +nightly fmt --all -- --check
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
cargo-check-benches:
|
cargo-check-benches:
|
||||||
stage: test
|
stage: test
|
||||||
<<: *docker-env
|
<<: *docker-env
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
// {{arg}}
|
// {{arg}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
|
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
#![allow(unused_parens)]
|
#![allow(unused_parens)]
|
||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use sp_core::{Pair, Public, sr25519};
|
|
||||||
use node_template_runtime::{
|
use node_template_runtime::{
|
||||||
AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig,
|
AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,
|
||||||
SudoConfig, SystemConfig, WASM_BINARY, Signature
|
SystemConfig, WASM_BINARY,
|
||||||
};
|
};
|
||||||
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
|
||||||
use sp_finality_grandpa::AuthorityId as GrandpaId;
|
|
||||||
use sp_runtime::traits::{Verify, IdentifyAccount};
|
|
||||||
use sc_service::ChainType;
|
use sc_service::ChainType;
|
||||||
|
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
||||||
|
use sp_core::{sr25519, Pair, Public};
|
||||||
|
use sp_finality_grandpa::AuthorityId as GrandpaId;
|
||||||
|
use sp_runtime::traits::{IdentifyAccount, Verify};
|
||||||
|
|
||||||
// The URL for the telemetry server.
|
// The URL for the telemetry server.
|
||||||
// const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
|
// const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
|
||||||
@@ -24,18 +24,16 @@ pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Pu
|
|||||||
type AccountPublic = <Signature as Verify>::Signer;
|
type AccountPublic = <Signature as Verify>::Signer;
|
||||||
|
|
||||||
/// Generate an account ID from seed.
|
/// Generate an account ID from seed.
|
||||||
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId where
|
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
|
||||||
AccountPublic: From<<TPublic::Pair as Pair>::Public>
|
where
|
||||||
|
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
|
||||||
{
|
{
|
||||||
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
|
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate an Aura authority key.
|
/// Generate an Aura authority key.
|
||||||
pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {
|
pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {
|
||||||
(
|
(get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))
|
||||||
get_from_seed::<AuraId>(s),
|
|
||||||
get_from_seed::<GrandpaId>(s),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn development_config() -> Result<ChainSpec, String> {
|
pub fn development_config() -> Result<ChainSpec, String> {
|
||||||
@@ -47,23 +45,23 @@ pub fn development_config() -> Result<ChainSpec, String> {
|
|||||||
// ID
|
// ID
|
||||||
"dev",
|
"dev",
|
||||||
ChainType::Development,
|
ChainType::Development,
|
||||||
move || testnet_genesis(
|
move || {
|
||||||
wasm_binary,
|
testnet_genesis(
|
||||||
// Initial PoA authorities
|
wasm_binary,
|
||||||
vec![
|
// Initial PoA authorities
|
||||||
authority_keys_from_seed("Alice"),
|
vec![authority_keys_from_seed("Alice")],
|
||||||
],
|
// Sudo account
|
||||||
// Sudo account
|
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
|
||||||
// Pre-funded accounts
|
|
||||||
vec![
|
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
// Pre-funded accounts
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
vec![
|
||||||
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
],
|
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
||||||
true,
|
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||||
),
|
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
},
|
||||||
// Bootnodes
|
// Bootnodes
|
||||||
vec![],
|
vec![],
|
||||||
// Telemetry
|
// Telemetry
|
||||||
@@ -86,32 +84,31 @@ pub fn local_testnet_config() -> Result<ChainSpec, String> {
|
|||||||
// ID
|
// ID
|
||||||
"local_testnet",
|
"local_testnet",
|
||||||
ChainType::Local,
|
ChainType::Local,
|
||||||
move || testnet_genesis(
|
move || {
|
||||||
wasm_binary,
|
testnet_genesis(
|
||||||
// Initial PoA authorities
|
wasm_binary,
|
||||||
vec![
|
// Initial PoA authorities
|
||||||
authority_keys_from_seed("Alice"),
|
vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")],
|
||||||
authority_keys_from_seed("Bob"),
|
// Sudo account
|
||||||
],
|
|
||||||
// Sudo account
|
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
|
||||||
// Pre-funded accounts
|
|
||||||
vec![
|
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
// Pre-funded accounts
|
||||||
get_account_id_from_seed::<sr25519::Public>("Charlie"),
|
vec![
|
||||||
get_account_id_from_seed::<sr25519::Public>("Dave"),
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Eve"),
|
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
|
get_account_id_from_seed::<sr25519::Public>("Charlie"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Dave"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Eve"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
|
||||||
],
|
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
|
||||||
true,
|
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
|
||||||
),
|
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
},
|
||||||
// Bootnodes
|
// Bootnodes
|
||||||
vec![],
|
vec![],
|
||||||
// Telemetry
|
// Telemetry
|
||||||
@@ -141,7 +138,7 @@ fn testnet_genesis(
|
|||||||
},
|
},
|
||||||
balances: BalancesConfig {
|
balances: BalancesConfig {
|
||||||
// Configure endowed accounts with initial balance of 1 << 60.
|
// Configure endowed accounts with initial balance of 1 << 60.
|
||||||
balances: endowed_accounts.iter().cloned().map(|k|(k, 1 << 60)).collect(),
|
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
|
||||||
},
|
},
|
||||||
aura: AuraConfig {
|
aura: AuraConfig {
|
||||||
authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),
|
authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use structopt::StructOpt;
|
|
||||||
use sc_cli::RunCmd;
|
use sc_cli::RunCmd;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
|
|||||||
@@ -15,11 +15,14 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::{chain_spec, service};
|
use crate::{
|
||||||
use crate::cli::{Cli, Subcommand};
|
chain_spec,
|
||||||
use sc_cli::{SubstrateCli, RuntimeVersion, Role, ChainSpec};
|
cli::{Cli, Subcommand},
|
||||||
use sc_service::PartialComponents;
|
service,
|
||||||
|
};
|
||||||
use node_template_runtime::Block;
|
use node_template_runtime::Block;
|
||||||
|
use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli};
|
||||||
|
use sc_service::PartialComponents;
|
||||||
|
|
||||||
impl SubstrateCli for Cli {
|
impl SubstrateCli for Cli {
|
||||||
fn impl_name() -> String {
|
fn impl_name() -> String {
|
||||||
@@ -50,9 +53,8 @@ impl SubstrateCli for Cli {
|
|||||||
Ok(match id {
|
Ok(match id {
|
||||||
"dev" => Box::new(chain_spec::development_config()?),
|
"dev" => Box::new(chain_spec::development_config()?),
|
||||||
"" | "local" => Box::new(chain_spec::local_testnet_config()?),
|
"" | "local" => Box::new(chain_spec::local_testnet_config()?),
|
||||||
path => Box::new(chain_spec::ChainSpec::from_json_file(
|
path =>
|
||||||
std::path::PathBuf::from(path),
|
Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
|
||||||
)?),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,32 +76,30 @@ pub fn run() -> sc_cli::Result<()> {
|
|||||||
Some(Subcommand::CheckBlock(cmd)) => {
|
Some(Subcommand::CheckBlock(cmd)) => {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
runner.async_run(|config| {
|
runner.async_run(|config| {
|
||||||
let PartialComponents { client, task_manager, import_queue, ..}
|
let PartialComponents { client, task_manager, import_queue, .. } =
|
||||||
= service::new_partial(&config)?;
|
service::new_partial(&config)?;
|
||||||
Ok((cmd.run(client, import_queue), task_manager))
|
Ok((cmd.run(client, import_queue), task_manager))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Some(Subcommand::ExportBlocks(cmd)) => {
|
Some(Subcommand::ExportBlocks(cmd)) => {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
runner.async_run(|config| {
|
runner.async_run(|config| {
|
||||||
let PartialComponents { client, task_manager, ..}
|
let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?;
|
||||||
= service::new_partial(&config)?;
|
|
||||||
Ok((cmd.run(client, config.database), task_manager))
|
Ok((cmd.run(client, config.database), task_manager))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Some(Subcommand::ExportState(cmd)) => {
|
Some(Subcommand::ExportState(cmd)) => {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
runner.async_run(|config| {
|
runner.async_run(|config| {
|
||||||
let PartialComponents { client, task_manager, ..}
|
let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?;
|
||||||
= service::new_partial(&config)?;
|
|
||||||
Ok((cmd.run(client, config.chain_spec), task_manager))
|
Ok((cmd.run(client, config.chain_spec), task_manager))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Some(Subcommand::ImportBlocks(cmd)) => {
|
Some(Subcommand::ImportBlocks(cmd)) => {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
runner.async_run(|config| {
|
runner.async_run(|config| {
|
||||||
let PartialComponents { client, task_manager, import_queue, ..}
|
let PartialComponents { client, task_manager, import_queue, .. } =
|
||||||
= service::new_partial(&config)?;
|
service::new_partial(&config)?;
|
||||||
Ok((cmd.run(client, import_queue), task_manager))
|
Ok((cmd.run(client, import_queue), task_manager))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -110,29 +110,30 @@ pub fn run() -> sc_cli::Result<()> {
|
|||||||
Some(Subcommand::Revert(cmd)) => {
|
Some(Subcommand::Revert(cmd)) => {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
runner.async_run(|config| {
|
runner.async_run(|config| {
|
||||||
let PartialComponents { client, task_manager, backend, ..}
|
let PartialComponents { client, task_manager, backend, .. } =
|
||||||
= service::new_partial(&config)?;
|
service::new_partial(&config)?;
|
||||||
Ok((cmd.run(client, backend), task_manager))
|
Ok((cmd.run(client, backend), task_manager))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Some(Subcommand::Benchmark(cmd)) => {
|
Some(Subcommand::Benchmark(cmd)) =>
|
||||||
if cfg!(feature = "runtime-benchmarks") {
|
if cfg!(feature = "runtime-benchmarks") {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
|
|
||||||
runner.sync_run(|config| cmd.run::<Block, service::Executor>(config))
|
runner.sync_run(|config| cmd.run::<Block, service::Executor>(config))
|
||||||
} else {
|
} else {
|
||||||
Err("Benchmarking wasn't enabled when building the node. \
|
Err("Benchmarking wasn't enabled when building the node. \
|
||||||
You can enable it with `--features runtime-benchmarks`.".into())
|
You can enable it with `--features runtime-benchmarks`."
|
||||||
}
|
.into())
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let runner = cli.create_runner(&cli.run)?;
|
let runner = cli.create_runner(&cli.run)?;
|
||||||
runner.run_node_until_exit(|config| async move {
|
runner.run_node_until_exit(|config| async move {
|
||||||
match config.role {
|
match config.role {
|
||||||
Role::Light => service::new_light(config),
|
Role::Light => service::new_light(config),
|
||||||
_ => service::new_full(config),
|
_ => service::new_full(config),
|
||||||
}.map_err(sc_cli::Error::Service)
|
}
|
||||||
|
.map_err(sc_cli::Error::Service)
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
pub mod chain_spec;
|
pub mod chain_spec;
|
||||||
pub mod service;
|
|
||||||
pub mod rpc;
|
pub mod rpc;
|
||||||
|
pub mod service;
|
||||||
|
|||||||
@@ -8,12 +8,11 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use node_template_runtime::{opaque::Block, AccountId, Balance, Index};
|
use node_template_runtime::{opaque::Block, AccountId, Balance, Index};
|
||||||
use sp_api::ProvideRuntimeApi;
|
|
||||||
use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend};
|
|
||||||
use sp_block_builder::BlockBuilder;
|
|
||||||
pub use sc_rpc_api::DenyUnsafe;
|
pub use sc_rpc_api::DenyUnsafe;
|
||||||
use sc_transaction_pool_api::TransactionPool;
|
use sc_transaction_pool_api::TransactionPool;
|
||||||
|
use sp_api::ProvideRuntimeApi;
|
||||||
|
use sp_block_builder::BlockBuilder;
|
||||||
|
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
|
||||||
|
|
||||||
/// Full client dependencies.
|
/// Full client dependencies.
|
||||||
pub struct FullDeps<C, P> {
|
pub struct FullDeps<C, P> {
|
||||||
@@ -26,34 +25,25 @@ pub struct FullDeps<C, P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiate all full RPC extensions.
|
/// Instantiate all full RPC extensions.
|
||||||
pub fn create_full<C, P>(
|
pub fn create_full<C, P>(deps: FullDeps<C, P>) -> jsonrpc_core::IoHandler<sc_rpc::Metadata>
|
||||||
deps: FullDeps<C, P>,
|
where
|
||||||
) -> jsonrpc_core::IoHandler<sc_rpc::Metadata> where
|
|
||||||
C: ProvideRuntimeApi<Block>,
|
C: ProvideRuntimeApi<Block>,
|
||||||
C: HeaderBackend<Block> + HeaderMetadata<Block, Error=BlockChainError> + 'static,
|
C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError> + 'static,
|
||||||
C: Send + Sync + 'static,
|
C: Send + Sync + 'static,
|
||||||
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
|
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
|
||||||
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
|
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
|
||||||
C::Api: BlockBuilder<Block>,
|
C::Api: BlockBuilder<Block>,
|
||||||
P: TransactionPool + 'static,
|
P: TransactionPool + 'static,
|
||||||
{
|
{
|
||||||
use substrate_frame_rpc_system::{FullSystem, SystemApi};
|
|
||||||
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
|
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
|
||||||
|
use substrate_frame_rpc_system::{FullSystem, SystemApi};
|
||||||
|
|
||||||
let mut io = jsonrpc_core::IoHandler::default();
|
let mut io = jsonrpc_core::IoHandler::default();
|
||||||
let FullDeps {
|
let FullDeps { client, pool, deny_unsafe } = deps;
|
||||||
client,
|
|
||||||
pool,
|
|
||||||
deny_unsafe,
|
|
||||||
} = deps;
|
|
||||||
|
|
||||||
io.extend_with(
|
io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe)));
|
||||||
SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))
|
|
||||||
);
|
|
||||||
|
|
||||||
io.extend_with(
|
io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone())));
|
||||||
TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone()))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Extend this RPC with a custom API by using the following syntax.
|
// Extend this RPC with a custom API by using the following syntax.
|
||||||
// `YourRpcStruct` should have a reference to a client, which is needed
|
// `YourRpcStruct` should have a reference to a client, which is needed
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
|
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
|
||||||
|
|
||||||
use std::{sync::Arc, time::Duration};
|
|
||||||
use sc_client_api::{ExecutorProvider, RemoteBackend};
|
|
||||||
use node_template_runtime::{self, opaque::Block, RuntimeApi};
|
use node_template_runtime::{self, opaque::Block, RuntimeApi};
|
||||||
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
|
use sc_client_api::{ExecutorProvider, RemoteBackend};
|
||||||
|
use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams};
|
||||||
use sc_executor::native_executor_instance;
|
use sc_executor::native_executor_instance;
|
||||||
pub use sc_executor::NativeExecutor;
|
pub use sc_executor::NativeExecutor;
|
||||||
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
|
|
||||||
use sc_consensus_aura::{ImportQueueParams, StartAuraParams, SlotProportion};
|
|
||||||
use sc_finality_grandpa::SharedVoterState;
|
use sc_finality_grandpa::SharedVoterState;
|
||||||
use sc_keystore::LocalKeystore;
|
use sc_keystore::LocalKeystore;
|
||||||
|
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
|
||||||
use sc_telemetry::{Telemetry, TelemetryWorker};
|
use sc_telemetry::{Telemetry, TelemetryWorker};
|
||||||
use sp_consensus::SlotData;
|
use sp_consensus::SlotData;
|
||||||
|
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
|
||||||
|
use std::{sync::Arc, time::Duration};
|
||||||
|
|
||||||
// Our native executor instance.
|
// Our native executor instance.
|
||||||
native_executor_instance!(
|
native_executor_instance!(
|
||||||
@@ -25,22 +25,35 @@ type FullClient = sc_service::TFullClient<Block, RuntimeApi, Executor>;
|
|||||||
type FullBackend = sc_service::TFullBackend<Block>;
|
type FullBackend = sc_service::TFullBackend<Block>;
|
||||||
type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
|
type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
|
||||||
|
|
||||||
pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponents<
|
pub fn new_partial(
|
||||||
FullClient, FullBackend, FullSelectChain,
|
config: &Configuration,
|
||||||
sp_consensus::DefaultImportQueue<Block, FullClient>,
|
) -> Result<
|
||||||
sc_transaction_pool::FullPool<Block, FullClient>,
|
sc_service::PartialComponents<
|
||||||
(
|
FullClient,
|
||||||
sc_finality_grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, FullSelectChain>,
|
FullBackend,
|
||||||
sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
|
FullSelectChain,
|
||||||
Option<Telemetry>,
|
sp_consensus::DefaultImportQueue<Block, FullClient>,
|
||||||
)
|
sc_transaction_pool::FullPool<Block, FullClient>,
|
||||||
>, ServiceError> {
|
(
|
||||||
|
sc_finality_grandpa::GrandpaBlockImport<
|
||||||
|
FullBackend,
|
||||||
|
Block,
|
||||||
|
FullClient,
|
||||||
|
FullSelectChain,
|
||||||
|
>,
|
||||||
|
sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
|
||||||
|
Option<Telemetry>,
|
||||||
|
),
|
||||||
|
>,
|
||||||
|
ServiceError,
|
||||||
|
> {
|
||||||
if config.keystore_remote.is_some() {
|
if config.keystore_remote.is_some() {
|
||||||
return Err(ServiceError::Other(
|
return Err(ServiceError::Other(format!("Remote Keystores are not supported.")))
|
||||||
format!("Remote Keystores are not supported.")))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let telemetry = config.telemetry_endpoints.clone()
|
let telemetry = config
|
||||||
|
.telemetry_endpoints
|
||||||
|
.clone()
|
||||||
.filter(|x| !x.is_empty())
|
.filter(|x| !x.is_empty())
|
||||||
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
|
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
|
||||||
let worker = TelemetryWorker::new(16)?;
|
let worker = TelemetryWorker::new(16)?;
|
||||||
@@ -56,11 +69,10 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen
|
|||||||
)?;
|
)?;
|
||||||
let client = Arc::new(client);
|
let client = Arc::new(client);
|
||||||
|
|
||||||
let telemetry = telemetry
|
let telemetry = telemetry.map(|(worker, telemetry)| {
|
||||||
.map(|(worker, telemetry)| {
|
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
telemetry
|
||||||
telemetry
|
});
|
||||||
});
|
|
||||||
|
|
||||||
let select_chain = sc_consensus::LongestChain::new(backend.clone());
|
let select_chain = sc_consensus::LongestChain::new(backend.clone());
|
||||||
|
|
||||||
@@ -81,8 +93,8 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen
|
|||||||
|
|
||||||
let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
|
let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
|
||||||
|
|
||||||
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(
|
let import_queue =
|
||||||
ImportQueueParams {
|
sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
|
||||||
block_import: grandpa_block_import.clone(),
|
block_import: grandpa_block_import.clone(),
|
||||||
justification_import: Some(Box::new(grandpa_block_import.clone())),
|
justification_import: Some(Box::new(grandpa_block_import.clone())),
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
@@ -98,12 +110,13 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen
|
|||||||
Ok((timestamp, slot))
|
Ok((timestamp, slot))
|
||||||
},
|
},
|
||||||
spawner: &task_manager.spawn_essential_handle(),
|
spawner: &task_manager.spawn_essential_handle(),
|
||||||
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
|
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(
|
||||||
|
client.executor().clone(),
|
||||||
|
),
|
||||||
registry: config.prometheus_registry(),
|
registry: config.prometheus_registry(),
|
||||||
check_for_equivocation: Default::default(),
|
check_for_equivocation: Default::default(),
|
||||||
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
||||||
},
|
})?;
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(sc_service::PartialComponents {
|
Ok(sc_service::PartialComponents {
|
||||||
client,
|
client,
|
||||||
@@ -140,10 +153,11 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
if let Some(url) = &config.keystore_remote {
|
if let Some(url) = &config.keystore_remote {
|
||||||
match remote_keystore(url) {
|
match remote_keystore(url) {
|
||||||
Ok(k) => keystore_container.set_remote_keystore(k),
|
Ok(k) => keystore_container.set_remote_keystore(k),
|
||||||
Err(e) => {
|
Err(e) =>
|
||||||
return Err(ServiceError::Other(
|
return Err(ServiceError::Other(format!(
|
||||||
format!("Error hooking up remote keystore for {}: {}", url, e)))
|
"Error hooking up remote keystore for {}: {}",
|
||||||
}
|
url, e
|
||||||
|
))),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +176,10 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
|
|
||||||
if config.offchain_worker.enabled {
|
if config.offchain_worker.enabled {
|
||||||
sc_service::build_offchain_workers(
|
sc_service::build_offchain_workers(
|
||||||
&config, task_manager.spawn_handle(), client.clone(), network.clone(),
|
&config,
|
||||||
|
task_manager.spawn_handle(),
|
||||||
|
client.clone(),
|
||||||
|
network.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,32 +195,27 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
let pool = transaction_pool.clone();
|
let pool = transaction_pool.clone();
|
||||||
|
|
||||||
Box::new(move |deny_unsafe, _| {
|
Box::new(move |deny_unsafe, _| {
|
||||||
let deps = crate::rpc::FullDeps {
|
let deps =
|
||||||
client: client.clone(),
|
crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe };
|
||||||
pool: pool.clone(),
|
|
||||||
deny_unsafe,
|
|
||||||
};
|
|
||||||
|
|
||||||
crate::rpc::create_full(deps)
|
crate::rpc::create_full(deps)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let _rpc_handlers = sc_service::spawn_tasks(
|
let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||||
sc_service::SpawnTasksParams {
|
network: network.clone(),
|
||||||
network: network.clone(),
|
client: client.clone(),
|
||||||
client: client.clone(),
|
keystore: keystore_container.sync_keystore(),
|
||||||
keystore: keystore_container.sync_keystore(),
|
task_manager: &mut task_manager,
|
||||||
task_manager: &mut task_manager,
|
transaction_pool: transaction_pool.clone(),
|
||||||
transaction_pool: transaction_pool.clone(),
|
rpc_extensions_builder,
|
||||||
rpc_extensions_builder,
|
on_demand: None,
|
||||||
on_demand: None,
|
remote_blockchain: None,
|
||||||
remote_blockchain: None,
|
backend,
|
||||||
backend,
|
system_rpc_tx,
|
||||||
system_rpc_tx,
|
config,
|
||||||
config,
|
telemetry: telemetry.as_mut(),
|
||||||
telemetry: telemetry.as_mut(),
|
})?;
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if role.is_authority() {
|
if role.is_authority() {
|
||||||
let proposer_factory = sc_basic_authorship::ProposerFactory::new(
|
let proposer_factory = sc_basic_authorship::ProposerFactory::new(
|
||||||
@@ -257,11 +269,8 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
|
|
||||||
// if the node isn't actively participating in consensus then it doesn't
|
// if the node isn't actively participating in consensus then it doesn't
|
||||||
// need a keystore, regardless of which protocol we use below.
|
// need a keystore, regardless of which protocol we use below.
|
||||||
let keystore = if role.is_authority() {
|
let keystore =
|
||||||
Some(keystore_container.sync_keystore())
|
if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None };
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let grandpa_config = sc_finality_grandpa::Config {
|
let grandpa_config = sc_finality_grandpa::Config {
|
||||||
// FIXME #1578 make this available through chainspec
|
// FIXME #1578 make this available through chainspec
|
||||||
@@ -295,7 +304,7 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
// if it fails we take down the service with it.
|
// if it fails we take down the service with it.
|
||||||
task_manager.spawn_essential_handle().spawn_blocking(
|
task_manager.spawn_essential_handle().spawn_blocking(
|
||||||
"grandpa-voter",
|
"grandpa-voter",
|
||||||
sc_finality_grandpa::run_grandpa_voter(grandpa_config)?
|
sc_finality_grandpa::run_grandpa_voter(grandpa_config)?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,7 +314,9 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
|
|
||||||
/// Builds a new service for a light client.
|
/// Builds a new service for a light client.
|
||||||
pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError> {
|
pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError> {
|
||||||
let telemetry = config.telemetry_endpoints.clone()
|
let telemetry = config
|
||||||
|
.telemetry_endpoints
|
||||||
|
.clone()
|
||||||
.filter(|x| !x.is_empty())
|
.filter(|x| !x.is_empty())
|
||||||
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
|
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
|
||||||
let worker = TelemetryWorker::new(16)?;
|
let worker = TelemetryWorker::new(16)?;
|
||||||
@@ -320,11 +331,10 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
|
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut telemetry = telemetry
|
let mut telemetry = telemetry.map(|(worker, telemetry)| {
|
||||||
.map(|(worker, telemetry)| {
|
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
telemetry
|
||||||
telemetry
|
});
|
||||||
});
|
|
||||||
|
|
||||||
config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config());
|
config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config());
|
||||||
|
|
||||||
@@ -347,8 +357,8 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
|
|
||||||
let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
|
let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
|
||||||
|
|
||||||
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(
|
let import_queue =
|
||||||
ImportQueueParams {
|
sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
|
||||||
block_import: grandpa_block_import.clone(),
|
block_import: grandpa_block_import.clone(),
|
||||||
justification_import: Some(Box::new(grandpa_block_import.clone())),
|
justification_import: Some(Box::new(grandpa_block_import.clone())),
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
@@ -368,8 +378,7 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
registry: config.prometheus_registry(),
|
registry: config.prometheus_registry(),
|
||||||
check_for_equivocation: Default::default(),
|
check_for_equivocation: Default::default(),
|
||||||
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
||||||
},
|
})?;
|
||||||
)?;
|
|
||||||
|
|
||||||
let (network, system_rpc_tx, network_starter) =
|
let (network, system_rpc_tx, network_starter) =
|
||||||
sc_service::build_network(sc_service::BuildNetworkParams {
|
sc_service::build_network(sc_service::BuildNetworkParams {
|
||||||
@@ -384,7 +393,10 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
|
|
||||||
if config.offchain_worker.enabled {
|
if config.offchain_worker.enabled {
|
||||||
sc_service::build_offchain_workers(
|
sc_service::build_offchain_workers(
|
||||||
&config, task_manager.spawn_handle(), client.clone(), network.clone(),
|
&config,
|
||||||
|
task_manager.spawn_handle(),
|
||||||
|
client.clone(),
|
||||||
|
network.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use frame_system::RawOrigin;
|
|
||||||
use frame_benchmarking::{benchmarks, whitelisted_caller, impl_benchmark_test_suite};
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use crate::Pallet as Template;
|
use crate::Pallet as Template;
|
||||||
|
use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller};
|
||||||
|
use frame_system::RawOrigin;
|
||||||
|
|
||||||
benchmarks! {
|
benchmarks! {
|
||||||
do_something {
|
do_something {
|
||||||
@@ -17,8 +17,4 @@ benchmarks! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_benchmark_test_suite!(
|
impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test);
|
||||||
Template,
|
|
||||||
crate::mock::new_test_ext(),
|
|
||||||
crate::mock::Test,
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
/// Edit this file to define custom logic or remove it if it is not needed.
|
/// Edit this file to define custom logic or remove it if it is not needed.
|
||||||
/// Learn more about FRAME and the core library of Substrate FRAME pallets:
|
/// Learn more about FRAME and the core library of Substrate FRAME pallets:
|
||||||
/// <https://substrate.dev/docs/en/knowledgebase/runtime/frame>
|
/// <https://substrate.dev/docs/en/knowledgebase/runtime/frame>
|
||||||
|
|
||||||
pub use pallet::*;
|
pub use pallet::*;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -63,7 +62,7 @@ pub mod pallet {
|
|||||||
// These functions materialize as "extrinsics", which are often compared to transactions.
|
// These functions materialize as "extrinsics", which are often compared to transactions.
|
||||||
// Dispatchable functions must be annotated with a weight and must return a DispatchResult.
|
// Dispatchable functions must be annotated with a weight and must return a DispatchResult.
|
||||||
#[pallet::call]
|
#[pallet::call]
|
||||||
impl<T:Config> Pallet<T> {
|
impl<T: Config> Pallet<T> {
|
||||||
/// An example dispatchable that takes a singles value as a parameter, writes the value to
|
/// An example dispatchable that takes a singles value as a parameter, writes the value to
|
||||||
/// storage and emits an event. This function must be dispatched by a signed extrinsic.
|
/// storage and emits an event. This function must be dispatched by a signed extrinsic.
|
||||||
#[pallet::weight(10_000 + T::DbWeight::get().writes(1))]
|
#[pallet::weight(10_000 + T::DbWeight::get().writes(1))]
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
use crate as pallet_template;
|
use crate as pallet_template;
|
||||||
use sp_core::H256;
|
|
||||||
use frame_support::parameter_types;
|
use frame_support::parameter_types;
|
||||||
use sp_runtime::{
|
|
||||||
traits::{BlakeTwo256, IdentityLookup}, testing::Header,
|
|
||||||
};
|
|
||||||
use frame_system as system;
|
use frame_system as system;
|
||||||
|
use sp_core::H256;
|
||||||
|
use sp_runtime::{
|
||||||
|
testing::Header,
|
||||||
|
traits::{BlakeTwo256, IdentityLookup},
|
||||||
|
};
|
||||||
|
|
||||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
|
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
|
||||||
type Block = frame_system::mocking::MockBlock<Test>;
|
type Block = frame_system::mocking::MockBlock<Test>;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::{Error, mock::*};
|
use crate::{mock::*, Error};
|
||||||
use frame_support::{assert_ok, assert_noop};
|
use frame_support::{assert_noop, assert_ok};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_works_for_default_value() {
|
fn it_works_for_default_value() {
|
||||||
@@ -15,9 +15,6 @@ fn it_works_for_default_value() {
|
|||||||
fn correct_error_for_none_value() {
|
fn correct_error_for_none_value() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
// Ensure the expected error is thrown when no value is present.
|
// Ensure the expected error is thrown when no value is present.
|
||||||
assert_noop!(
|
assert_noop!(TemplateModule::cause_error(Origin::signed(1)), Error::<Test>::NoneValue);
|
||||||
TemplateModule::cause_error(Origin::signed(1)),
|
|
||||||
Error::<Test>::NoneValue
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +1,44 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
|
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
|
||||||
#![recursion_limit="256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
// Make the WASM binary available.
|
// Make the WASM binary available.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||||
|
|
||||||
use sp_std::prelude::*;
|
use pallet_grandpa::{
|
||||||
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
|
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
|
||||||
use sp_runtime::{
|
|
||||||
ApplyExtrinsicResult, generic, create_runtime_str, impl_opaque_keys, MultiSignature,
|
|
||||||
transaction_validity::{TransactionValidity, TransactionSource},
|
|
||||||
};
|
|
||||||
use sp_runtime::traits::{
|
|
||||||
BlakeTwo256, Block as BlockT, AccountIdLookup, Verify, IdentifyAccount, NumberFor,
|
|
||||||
};
|
};
|
||||||
use sp_api::impl_runtime_apis;
|
use sp_api::impl_runtime_apis;
|
||||||
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
||||||
use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
|
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
|
||||||
use pallet_grandpa::fg_primitives;
|
use sp_runtime::{
|
||||||
use sp_version::RuntimeVersion;
|
create_runtime_str, generic, impl_opaque_keys,
|
||||||
|
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, Verify},
|
||||||
|
transaction_validity::{TransactionSource, TransactionValidity},
|
||||||
|
ApplyExtrinsicResult, MultiSignature,
|
||||||
|
};
|
||||||
|
use sp_std::prelude::*;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use sp_version::NativeVersion;
|
use sp_version::NativeVersion;
|
||||||
|
use sp_version::RuntimeVersion;
|
||||||
|
|
||||||
// A few exports that help ease life for downstream crates.
|
// A few exports that help ease life for downstream crates.
|
||||||
#[cfg(any(feature = "std", test))]
|
|
||||||
pub use sp_runtime::BuildStorage;
|
|
||||||
pub use pallet_timestamp::Call as TimestampCall;
|
|
||||||
pub use pallet_balances::Call as BalancesCall;
|
|
||||||
pub use sp_runtime::{Permill, Perbill};
|
|
||||||
pub use frame_support::{
|
pub use frame_support::{
|
||||||
construct_runtime, parameter_types, StorageValue,
|
construct_runtime, parameter_types,
|
||||||
traits::{KeyOwnerProofSystem, Randomness, StorageInfo},
|
traits::{KeyOwnerProofSystem, Randomness, StorageInfo},
|
||||||
weights::{
|
weights::{
|
||||||
Weight, IdentityFee,
|
|
||||||
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
|
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
|
||||||
|
IdentityFee, Weight,
|
||||||
},
|
},
|
||||||
|
StorageValue,
|
||||||
};
|
};
|
||||||
|
pub use pallet_balances::Call as BalancesCall;
|
||||||
|
pub use pallet_timestamp::Call as TimestampCall;
|
||||||
use pallet_transaction_payment::CurrencyAdapter;
|
use pallet_transaction_payment::CurrencyAdapter;
|
||||||
|
#[cfg(any(feature = "std", test))]
|
||||||
|
pub use sp_runtime::BuildStorage;
|
||||||
|
pub use sp_runtime::{Perbill, Permill};
|
||||||
|
|
||||||
/// Import the template pallet.
|
/// Import the template pallet.
|
||||||
pub use pallet_template;
|
pub use pallet_template;
|
||||||
@@ -123,10 +124,7 @@ pub const DAYS: BlockNumber = HOURS * 24;
|
|||||||
/// The version information used to identify this runtime when compiled natively.
|
/// The version information used to identify this runtime when compiled natively.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn native_version() -> NativeVersion {
|
pub fn native_version() -> NativeVersion {
|
||||||
NativeVersion {
|
NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
|
||||||
runtime_version: VERSION,
|
|
||||||
can_author_with: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
|
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
|
||||||
@@ -306,7 +304,7 @@ pub type SignedExtra = (
|
|||||||
frame_system::CheckEra<Runtime>,
|
frame_system::CheckEra<Runtime>,
|
||||||
frame_system::CheckNonce<Runtime>,
|
frame_system::CheckNonce<Runtime>,
|
||||||
frame_system::CheckWeight<Runtime>,
|
frame_system::CheckWeight<Runtime>,
|
||||||
pallet_transaction_payment::ChargeTransactionPayment<Runtime>
|
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
|
||||||
);
|
);
|
||||||
/// Unchecked extrinsic type as expected by this runtime.
|
/// Unchecked extrinsic type as expected by this runtime.
|
||||||
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
|
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
|
||||||
|
|||||||
@@ -24,36 +24,22 @@
|
|||||||
//! DO NOT depend on user input). Thus transaction generation should be
|
//! DO NOT depend on user input). Thus transaction generation should be
|
||||||
//! based on randomized data.
|
//! based on randomized data.
|
||||||
|
|
||||||
use std::{
|
|
||||||
borrow::Cow,
|
|
||||||
collections::HashMap,
|
|
||||||
pin::Pin,
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
|
use std::{borrow::Cow, collections::HashMap, pin::Pin, sync::Arc};
|
||||||
|
|
||||||
use node_primitives::Block;
|
use node_primitives::Block;
|
||||||
use node_testing::bench::{BenchDb, Profile, BlockType, KeyTypes, DatabaseType};
|
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile};
|
||||||
use sp_runtime::{
|
|
||||||
generic::BlockId,
|
|
||||||
traits::NumberFor,
|
|
||||||
OpaqueExtrinsic,
|
|
||||||
};
|
|
||||||
use sc_transaction_pool_api::{
|
use sc_transaction_pool_api::{
|
||||||
ImportNotificationStream,
|
ImportNotificationStream, PoolFuture, PoolStatus, TransactionFor, TransactionSource,
|
||||||
PoolFuture,
|
TransactionStatusStreamFor, TxHash,
|
||||||
PoolStatus,
|
|
||||||
TransactionFor,
|
|
||||||
TransactionSource,
|
|
||||||
TransactionStatusStreamFor,
|
|
||||||
TxHash,
|
|
||||||
};
|
};
|
||||||
use sp_consensus::{Environment, Proposer};
|
use sp_consensus::{Environment, Proposer};
|
||||||
use sp_inherents::InherentDataProvider;
|
use sp_inherents::InherentDataProvider;
|
||||||
|
use sp_runtime::{generic::BlockId, traits::NumberFor, OpaqueExtrinsic};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::SizeType,
|
common::SizeType,
|
||||||
core::{self, Path, Mode},
|
core::{self, Mode, Path},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ConstructionBenchmarkDescription {
|
pub struct ConstructionBenchmarkDescription {
|
||||||
@@ -72,7 +58,6 @@ pub struct ConstructionBenchmark {
|
|||||||
|
|
||||||
impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
|
impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
|
||||||
fn path(&self) -> Path {
|
fn path(&self) -> Path {
|
||||||
|
|
||||||
let mut path = Path::new(&["node", "proposer"]);
|
let mut path = Path::new(&["node", "proposer"]);
|
||||||
|
|
||||||
match self.profile {
|
match self.profile {
|
||||||
@@ -104,11 +89,7 @@ impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
|
|||||||
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
|
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
|
||||||
let mut extrinsics: Vec<Arc<PoolTransaction>> = Vec::new();
|
let mut extrinsics: Vec<Arc<PoolTransaction>> = Vec::new();
|
||||||
|
|
||||||
let mut bench_db = BenchDb::with_key_types(
|
let mut bench_db = BenchDb::with_key_types(self.database_type, 50_000, self.key_types);
|
||||||
self.database_type,
|
|
||||||
50_000,
|
|
||||||
self.key_types
|
|
||||||
);
|
|
||||||
|
|
||||||
let client = bench_db.client();
|
let client = bench_db.client();
|
||||||
|
|
||||||
@@ -127,11 +108,9 @@ impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
|
|||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> Cow<'static, str> {
|
||||||
format!(
|
format!(
|
||||||
"Block construction ({:?}/{}, {:?}, {:?} backend)",
|
"Block construction ({:?}/{}, {:?}, {:?} backend)",
|
||||||
self.block_type,
|
self.block_type, self.size, self.profile, self.database_type,
|
||||||
self.size,
|
)
|
||||||
self.profile,
|
.into()
|
||||||
self.database_type,
|
|
||||||
).into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +118,9 @@ impl core::Benchmark for ConstructionBenchmark {
|
|||||||
fn run(&mut self, mode: Mode) -> std::time::Duration {
|
fn run(&mut self, mode: Mode) -> std::time::Duration {
|
||||||
let context = self.database.create_context(self.profile);
|
let context = self.database.create_context(self.profile);
|
||||||
|
|
||||||
let _ = context.client.runtime_version_at(&BlockId::Number(0))
|
let _ = context
|
||||||
|
.client
|
||||||
|
.runtime_version_at(&BlockId::Number(0))
|
||||||
.expect("Failed to get runtime version")
|
.expect("Failed to get runtime version")
|
||||||
.spec_version;
|
.spec_version;
|
||||||
|
|
||||||
@@ -158,20 +139,25 @@ impl core::Benchmark for ConstructionBenchmark {
|
|||||||
|
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
let proposer = futures::executor::block_on(proposer_factory.init(
|
let proposer = futures::executor::block_on(
|
||||||
&context.client.header(&BlockId::number(0))
|
proposer_factory.init(
|
||||||
.expect("Database error querying block #0")
|
&context
|
||||||
.expect("Block #0 should exist"),
|
.client
|
||||||
)).expect("Proposer initialization failed");
|
.header(&BlockId::number(0))
|
||||||
|
.expect("Database error querying block #0")
|
||||||
let _block = futures::executor::block_on(
|
.expect("Block #0 should exist"),
|
||||||
proposer.propose(
|
|
||||||
timestamp_provider.create_inherent_data().expect("Create inherent data failed"),
|
|
||||||
Default::default(),
|
|
||||||
std::time::Duration::from_secs(20),
|
|
||||||
None,
|
|
||||||
),
|
),
|
||||||
).map(|r| r.block).expect("Proposing failed");
|
)
|
||||||
|
.expect("Proposer initialization failed");
|
||||||
|
|
||||||
|
let _block = futures::executor::block_on(proposer.propose(
|
||||||
|
timestamp_provider.create_inherent_data().expect("Create inherent data failed"),
|
||||||
|
Default::default(),
|
||||||
|
std::time::Duration::from_secs(20),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
.map(|r| r.block)
|
||||||
|
.expect("Proposing failed");
|
||||||
|
|
||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
|
|
||||||
@@ -191,10 +177,7 @@ pub struct PoolTransaction {
|
|||||||
|
|
||||||
impl From<OpaqueExtrinsic> for PoolTransaction {
|
impl From<OpaqueExtrinsic> for PoolTransaction {
|
||||||
fn from(e: OpaqueExtrinsic) -> Self {
|
fn from(e: OpaqueExtrinsic) -> Self {
|
||||||
PoolTransaction {
|
PoolTransaction { data: e, hash: node_primitives::Hash::zero() }
|
||||||
data: e,
|
|
||||||
hash: node_primitives::Hash::zero(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,15 +193,25 @@ impl sc_transaction_pool_api::InPoolTransaction for PoolTransaction {
|
|||||||
&self.hash
|
&self.hash
|
||||||
}
|
}
|
||||||
|
|
||||||
fn priority(&self) -> &u64 { unimplemented!() }
|
fn priority(&self) -> &u64 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn longevity(&self) -> &u64 { unimplemented!() }
|
fn longevity(&self) -> &u64 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn requires(&self) -> &[Vec<u8>] { unimplemented!() }
|
fn requires(&self) -> &[Vec<u8>] {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn provides(&self) -> &[Vec<u8>] { unimplemented!() }
|
fn provides(&self) -> &[Vec<u8>] {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn is_propagable(&self) -> bool { unimplemented!() }
|
fn is_propagable(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -236,7 +229,7 @@ impl sc_transaction_pool_api::TransactionPool for Transactions {
|
|||||||
_at: &BlockId<Self::Block>,
|
_at: &BlockId<Self::Block>,
|
||||||
_source: TransactionSource,
|
_source: TransactionSource,
|
||||||
_xts: Vec<TransactionFor<Self>>,
|
_xts: Vec<TransactionFor<Self>>,
|
||||||
) -> PoolFuture<Vec<Result<node_primitives::Hash, Self::Error>>, Self::Error> {
|
) -> PoolFuture<Vec<Result<node_primitives::Hash, Self::Error>>, Self::Error> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,14 +252,21 @@ impl sc_transaction_pool_api::TransactionPool for Transactions {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ready_at(&self, _at: NumberFor<Self::Block>)
|
fn ready_at(
|
||||||
-> Pin<Box<dyn Future<Output=Box<dyn Iterator<Item=Arc<Self::InPoolTransaction>> + Send>> + Send>>
|
&self,
|
||||||
{
|
_at: NumberFor<Self::Block>,
|
||||||
let iter: Box<dyn Iterator<Item=Arc<PoolTransaction>> + Send> = Box::new(self.0.clone().into_iter());
|
) -> Pin<
|
||||||
|
Box<
|
||||||
|
dyn Future<Output = Box<dyn Iterator<Item = Arc<Self::InPoolTransaction>> + Send>>
|
||||||
|
+ Send,
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
let iter: Box<dyn Iterator<Item = Arc<PoolTransaction>> + Send> =
|
||||||
|
Box::new(self.0.clone().into_iter());
|
||||||
Box::pin(futures::future::ready(iter))
|
Box::pin(futures::future::ready(iter))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ready(&self) -> Box<dyn Iterator<Item=Arc<Self::InPoolTransaction>> + Send> {
|
fn ready(&self) -> Box<dyn Iterator<Item = Arc<Self::InPoolTransaction>> + Send> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,11 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{fmt, borrow::{Cow, ToOwned}};
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::{
|
||||||
|
borrow::{Cow, ToOwned},
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Path(Vec<String>);
|
pub struct Path(Vec<String>);
|
||||||
|
|
||||||
@@ -33,7 +36,11 @@ impl Path {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn full(&self) -> String {
|
pub fn full(&self) -> String {
|
||||||
self.0.iter().fold(String::new(), |mut val, next| { val.push_str("::"); val.push_str(next); val })
|
self.0.iter().fold(String::new(), |mut val, next| {
|
||||||
|
val.push_str("::");
|
||||||
|
val.push_str(next);
|
||||||
|
val
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has(&self, path: &str) -> bool {
|
pub fn has(&self, path: &str) -> bool {
|
||||||
@@ -115,10 +122,7 @@ impl fmt::Display for BenchmarkOutput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_benchmark(
|
pub fn run_benchmark(benchmark: Box<dyn BenchmarkDescription>, mode: Mode) -> BenchmarkOutput {
|
||||||
benchmark: Box<dyn BenchmarkDescription>,
|
|
||||||
mode: Mode,
|
|
||||||
) -> BenchmarkOutput {
|
|
||||||
let name = benchmark.name().to_owned();
|
let name = benchmark.name().to_owned();
|
||||||
let mut benchmark = benchmark.setup();
|
let mut benchmark = benchmark.setup();
|
||||||
|
|
||||||
@@ -133,11 +137,7 @@ pub fn run_benchmark(
|
|||||||
let raw_average = (durations.iter().sum::<u128>() / (durations.len() as u128)) as u64;
|
let raw_average = (durations.iter().sum::<u128>() / (durations.len() as u128)) as u64;
|
||||||
let average = (durations.iter().skip(10).take(30).sum::<u128>() / 30) as u64;
|
let average = (durations.iter().skip(10).take(30).sum::<u128>() / 30) as u64;
|
||||||
|
|
||||||
BenchmarkOutput {
|
BenchmarkOutput { name: name.into(), raw_average, average }
|
||||||
name: name.into(),
|
|
||||||
raw_average,
|
|
||||||
average,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! matrix(
|
macro_rules! matrix(
|
||||||
|
|||||||
@@ -30,14 +30,15 @@ use crate::simple_trie::SimpleTrie;
|
|||||||
/// return root.
|
/// return root.
|
||||||
pub fn generate_trie(
|
pub fn generate_trie(
|
||||||
db: Arc<dyn KeyValueDB>,
|
db: Arc<dyn KeyValueDB>,
|
||||||
key_values: impl IntoIterator<Item=(Vec<u8>, Vec<u8>)>,
|
key_values: impl IntoIterator<Item = (Vec<u8>, Vec<u8>)>,
|
||||||
) -> Hash {
|
) -> Hash {
|
||||||
let mut root = Hash::default();
|
let mut root = Hash::default();
|
||||||
|
|
||||||
let (db, overlay) = {
|
let (db, overlay) = {
|
||||||
let mut overlay = HashMap::new();
|
let mut overlay = HashMap::new();
|
||||||
overlay.insert(
|
overlay.insert(
|
||||||
hex::decode("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").expect("null key is valid"),
|
hex::decode("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314")
|
||||||
|
.expect("null key is valid"),
|
||||||
Some(vec![0]),
|
Some(vec![0]),
|
||||||
);
|
);
|
||||||
let mut trie = SimpleTrie { db, overlay: &mut overlay };
|
let mut trie = SimpleTrie { db, overlay: &mut overlay };
|
||||||
@@ -50,7 +51,7 @@ pub fn generate_trie(
|
|||||||
|
|
||||||
trie_db.commit();
|
trie_db.commit();
|
||||||
}
|
}
|
||||||
( trie.db, overlay )
|
(trie.db, overlay)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut transaction = db.transaction();
|
let mut transaction = db.transaction();
|
||||||
|
|||||||
@@ -32,15 +32,15 @@
|
|||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use node_testing::bench::{BenchDb, Profile, BlockType, KeyTypes, DatabaseType};
|
|
||||||
use node_primitives::Block;
|
use node_primitives::Block;
|
||||||
|
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile};
|
||||||
use sc_client_api::backend::Backend;
|
use sc_client_api::backend::Backend;
|
||||||
use sp_runtime::generic::BlockId;
|
use sp_runtime::generic::BlockId;
|
||||||
use sp_state_machine::InspectState;
|
use sp_state_machine::InspectState;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::SizeType,
|
common::SizeType,
|
||||||
core::{self, Path, Mode},
|
core::{self, Mode, Path},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ImportBenchmarkDescription {
|
pub struct ImportBenchmarkDescription {
|
||||||
@@ -60,7 +60,6 @@ pub struct ImportBenchmark {
|
|||||||
|
|
||||||
impl core::BenchmarkDescription for ImportBenchmarkDescription {
|
impl core::BenchmarkDescription for ImportBenchmarkDescription {
|
||||||
fn path(&self) -> Path {
|
fn path(&self) -> Path {
|
||||||
|
|
||||||
let mut path = Path::new(&["node", "import"]);
|
let mut path = Path::new(&["node", "import"]);
|
||||||
|
|
||||||
match self.profile {
|
match self.profile {
|
||||||
@@ -91,11 +90,7 @@ impl core::BenchmarkDescription for ImportBenchmarkDescription {
|
|||||||
|
|
||||||
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
|
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
|
||||||
let profile = self.profile;
|
let profile = self.profile;
|
||||||
let mut bench_db = BenchDb::with_key_types(
|
let mut bench_db = BenchDb::with_key_types(self.database_type, 50_000, self.key_types);
|
||||||
self.database_type,
|
|
||||||
50_000,
|
|
||||||
self.key_types
|
|
||||||
);
|
|
||||||
let block = bench_db.generate_block(self.block_type.to_content(self.size.transactions()));
|
let block = bench_db.generate_block(self.block_type.to_content(self.size.transactions()));
|
||||||
Box::new(ImportBenchmark {
|
Box::new(ImportBenchmark {
|
||||||
database: bench_db,
|
database: bench_db,
|
||||||
@@ -108,11 +103,9 @@ impl core::BenchmarkDescription for ImportBenchmarkDescription {
|
|||||||
fn name(&self) -> Cow<'static, str> {
|
fn name(&self) -> Cow<'static, str> {
|
||||||
format!(
|
format!(
|
||||||
"Block import ({:?}/{}, {:?}, {:?} backend)",
|
"Block import ({:?}/{}, {:?}, {:?} backend)",
|
||||||
self.block_type,
|
self.block_type, self.size, self.profile, self.database_type,
|
||||||
self.size,
|
)
|
||||||
self.profile,
|
.into()
|
||||||
self.database_type,
|
|
||||||
).into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +113,9 @@ impl core::Benchmark for ImportBenchmark {
|
|||||||
fn run(&mut self, mode: Mode) -> std::time::Duration {
|
fn run(&mut self, mode: Mode) -> std::time::Duration {
|
||||||
let mut context = self.database.create_context(self.profile);
|
let mut context = self.database.create_context(self.profile);
|
||||||
|
|
||||||
let _ = context.client.runtime_version_at(&BlockId::Number(0))
|
let _ = context
|
||||||
|
.client
|
||||||
|
.runtime_version_at(&BlockId::Number(0))
|
||||||
.expect("Failed to get runtime version")
|
.expect("Failed to get runtime version")
|
||||||
.spec_version;
|
.spec_version;
|
||||||
|
|
||||||
@@ -133,7 +128,8 @@ impl core::Benchmark for ImportBenchmark {
|
|||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
|
|
||||||
// Sanity checks.
|
// Sanity checks.
|
||||||
context.client
|
context
|
||||||
|
.client
|
||||||
.state_at(&BlockId::number(1))
|
.state_at(&BlockId::number(1))
|
||||||
.expect("state_at failed for block#1")
|
.expect("state_at failed for block#1")
|
||||||
.inspect_state(|| {
|
.inspect_state(|| {
|
||||||
@@ -155,19 +151,17 @@ impl core::Benchmark for ImportBenchmark {
|
|||||||
BlockType::Noop => {
|
BlockType::Noop => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
node_runtime::System::events().len(),
|
node_runtime::System::events().len(),
|
||||||
|
|
||||||
// should be 2 per signed extrinsic + 1 per unsigned
|
// should be 2 per signed extrinsic + 1 per unsigned
|
||||||
// we have 1 unsigned and the rest are signed in the block
|
// we have 1 unsigned and the rest are signed in the block
|
||||||
// those 2 events per signed are:
|
// those 2 events per signed are:
|
||||||
// - deposit event for charging transaction fee
|
// - deposit event for charging transaction fee
|
||||||
// - extrinsic success
|
// - extrinsic success
|
||||||
(self.block.extrinsics.len() - 1) * 2 + 1,
|
(self.block.extrinsics.len() - 1) * 2 + 1,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
if mode == Mode::Profile {
|
if mode == Mode::Profile {
|
||||||
std::thread::park_timeout(std::time::Duration::from_secs(1));
|
std::thread::park_timeout(std::time::Duration::from_secs(1));
|
||||||
|
|||||||
@@ -18,9 +18,10 @@
|
|||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
mod construct;
|
mod construct;
|
||||||
#[macro_use] mod core;
|
#[macro_use]
|
||||||
mod import;
|
mod core;
|
||||||
mod generator;
|
mod generator;
|
||||||
|
mod import;
|
||||||
mod simple_trie;
|
mod simple_trie;
|
||||||
mod state_sizes;
|
mod state_sizes;
|
||||||
mod tempdb;
|
mod tempdb;
|
||||||
@@ -29,15 +30,15 @@ mod txpool;
|
|||||||
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use node_testing::bench::{Profile, KeyTypes, BlockType, DatabaseType as BenchDataBaseType};
|
use node_testing::bench::{BlockType, DatabaseType as BenchDataBaseType, KeyTypes, Profile};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::SizeType,
|
common::SizeType,
|
||||||
core::{run_benchmark, Mode as BenchmarkMode},
|
|
||||||
tempdb::DatabaseType,
|
|
||||||
import::ImportBenchmarkDescription,
|
|
||||||
trie::{TrieReadBenchmarkDescription, TrieWriteBenchmarkDescription, DatabaseSize},
|
|
||||||
construct::ConstructionBenchmarkDescription,
|
construct::ConstructionBenchmarkDescription,
|
||||||
|
core::{run_benchmark, Mode as BenchmarkMode},
|
||||||
|
import::ImportBenchmarkDescription,
|
||||||
|
tempdb::DatabaseType,
|
||||||
|
trie::{DatabaseSize, TrieReadBenchmarkDescription, TrieWriteBenchmarkDescription},
|
||||||
txpool::PoolBenchmarkDescription,
|
txpool::PoolBenchmarkDescription,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -92,14 +93,25 @@ fn main() {
|
|||||||
SizeType::Large,
|
SizeType::Large,
|
||||||
SizeType::Full,
|
SizeType::Full,
|
||||||
SizeType::Custom(opt.transactions.unwrap_or(0)),
|
SizeType::Custom(opt.transactions.unwrap_or(0)),
|
||||||
].iter() {
|
]
|
||||||
|
.iter()
|
||||||
|
{
|
||||||
for block_type in [
|
for block_type in [
|
||||||
BlockType::RandomTransfersKeepAlive,
|
BlockType::RandomTransfersKeepAlive,
|
||||||
BlockType::RandomTransfersReaping,
|
BlockType::RandomTransfersReaping,
|
||||||
BlockType::Noop,
|
BlockType::Noop,
|
||||||
].iter() {
|
]
|
||||||
for database_type in [BenchDataBaseType::RocksDb, BenchDataBaseType::ParityDb].iter() {
|
.iter()
|
||||||
import_benchmarks.push((profile, size.clone(), block_type.clone(), database_type));
|
{
|
||||||
|
for database_type in
|
||||||
|
[BenchDataBaseType::RocksDb, BenchDataBaseType::ParityDb].iter()
|
||||||
|
{
|
||||||
|
import_benchmarks.push((
|
||||||
|
profile,
|
||||||
|
size.clone(),
|
||||||
|
block_type.clone(),
|
||||||
|
database_type,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,7 +175,7 @@ fn main() {
|
|||||||
println!("{}: {}", benchmark.name(), benchmark.path().full())
|
println!("{}: {}", benchmark.name(), benchmark.path().full())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
@@ -183,7 +195,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opt.json {
|
if opt.json {
|
||||||
let json_result: String = serde_json::to_string(&results).expect("Failed to construct json");
|
let json_result: String =
|
||||||
|
serde_json::to_string(&results).expect("Failed to construct json");
|
||||||
println!("{}", json_result);
|
println!("{}", json_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,10 @@
|
|||||||
|
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
|
use hash_db::{AsHashDB, HashDB, Hasher as _, Prefix};
|
||||||
use kvdb::KeyValueDB;
|
use kvdb::KeyValueDB;
|
||||||
use node_primitives::Hash;
|
use node_primitives::Hash;
|
||||||
use sp_trie::DBValue;
|
use sp_trie::DBValue;
|
||||||
use hash_db::{HashDB, AsHashDB, Prefix, Hasher as _};
|
|
||||||
|
|
||||||
pub type Hasher = sp_core::Blake2Hasher;
|
pub type Hasher = sp_core::Blake2Hasher;
|
||||||
|
|
||||||
@@ -32,7 +32,9 @@ pub struct SimpleTrie<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AsHashDB<Hasher, DBValue> for SimpleTrie<'a> {
|
impl<'a> AsHashDB<Hasher, DBValue> for SimpleTrie<'a> {
|
||||||
fn as_hash_db(&self) -> &dyn hash_db::HashDB<Hasher, DBValue> { &*self }
|
fn as_hash_db(&self) -> &dyn hash_db::HashDB<Hasher, DBValue> {
|
||||||
|
&*self
|
||||||
|
}
|
||||||
|
|
||||||
fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn HashDB<Hasher, DBValue> + 'b) {
|
fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn HashDB<Hasher, DBValue> + 'b) {
|
||||||
&mut *self
|
&mut *self
|
||||||
@@ -43,7 +45,7 @@ impl<'a> HashDB<Hasher, DBValue> for SimpleTrie<'a> {
|
|||||||
fn get(&self, key: &Hash, prefix: Prefix) -> Option<DBValue> {
|
fn get(&self, key: &Hash, prefix: Prefix) -> Option<DBValue> {
|
||||||
let key = sp_trie::prefixed_key::<Hasher>(key, prefix);
|
let key = sp_trie::prefixed_key::<Hasher>(key, prefix);
|
||||||
if let Some(value) = self.overlay.get(&key) {
|
if let Some(value) = self.overlay.get(&key) {
|
||||||
return value.clone();
|
return value.clone()
|
||||||
}
|
}
|
||||||
self.db.get(0, &key).expect("Database backend error")
|
self.db.get(0, &key).expect("Database backend error")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/// Kusama value size distribution
|
/// Kusama value size distribution
|
||||||
pub const KUSAMA_STATE_DISTRIBUTION: &'static[(u32, u32)] = &[
|
pub const KUSAMA_STATE_DISTRIBUTION: &'static [(u32, u32)] = &[
|
||||||
(32, 35),
|
(32, 35),
|
||||||
(33, 20035),
|
(33, 20035),
|
||||||
(34, 5369),
|
(34, 5369),
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use kvdb::{DBTransaction, KeyValueDB};
|
||||||
|
use kvdb_rocksdb::{Database, DatabaseConfig};
|
||||||
use std::{io, path::PathBuf, sync::Arc};
|
use std::{io, path::PathBuf, sync::Arc};
|
||||||
use kvdb::{KeyValueDB, DBTransaction};
|
|
||||||
use kvdb_rocksdb::{DatabaseConfig, Database};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, derive_more::Display)]
|
#[derive(Debug, Clone, Copy, derive_more::Display)]
|
||||||
pub enum DatabaseType {
|
pub enum DatabaseType {
|
||||||
@@ -44,13 +44,14 @@ impl KeyValueDB for ParityDbWrapper {
|
|||||||
|
|
||||||
/// Write a transaction of changes to the buffer.
|
/// Write a transaction of changes to the buffer.
|
||||||
fn write(&self, transaction: DBTransaction) -> io::Result<()> {
|
fn write(&self, transaction: DBTransaction) -> io::Result<()> {
|
||||||
self.0.commit(
|
self.0
|
||||||
transaction.ops.iter().map(|op| match op {
|
.commit(transaction.ops.iter().map(|op| match op {
|
||||||
kvdb::DBOp::Insert { col, key, value } => (*col as u8, &key[key.len() - 32..], Some(value.to_vec())),
|
kvdb::DBOp::Insert { col, key, value } =>
|
||||||
|
(*col as u8, &key[key.len() - 32..], Some(value.to_vec())),
|
||||||
kvdb::DBOp::Delete { col, key } => (*col as u8, &key[key.len() - 32..], None),
|
kvdb::DBOp::Delete { col, key } => (*col as u8, &key[key.len() - 32..], None),
|
||||||
kvdb::DBOp::DeletePrefix { col: _, prefix: _ } => unimplemented!()
|
kvdb::DBOp::DeletePrefix { col: _, prefix: _ } => unimplemented!(),
|
||||||
})
|
}))
|
||||||
).expect("db error");
|
.expect("db error");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,21 +91,19 @@ impl TempDatabase {
|
|||||||
match db_type {
|
match db_type {
|
||||||
DatabaseType::RocksDb => {
|
DatabaseType::RocksDb => {
|
||||||
let db_cfg = DatabaseConfig::with_columns(1);
|
let db_cfg = DatabaseConfig::with_columns(1);
|
||||||
let db = Database::open(&db_cfg, &self.0.path().to_string_lossy()).expect("Database backend error");
|
let db = Database::open(&db_cfg, &self.0.path().to_string_lossy())
|
||||||
|
.expect("Database backend error");
|
||||||
Arc::new(db)
|
Arc::new(db)
|
||||||
},
|
},
|
||||||
DatabaseType::ParityDb => {
|
DatabaseType::ParityDb => Arc::new(ParityDbWrapper({
|
||||||
Arc::new(ParityDbWrapper({
|
let mut options = parity_db::Options::with_columns(self.0.path(), 1);
|
||||||
let mut options = parity_db::Options::with_columns(self.0.path(), 1);
|
let mut column_options = &mut options.columns[0];
|
||||||
let mut column_options = &mut options.columns[0];
|
column_options.ref_counted = true;
|
||||||
column_options.ref_counted = true;
|
column_options.preimage = true;
|
||||||
column_options.preimage = true;
|
column_options.uniform = true;
|
||||||
column_options.uniform = true;
|
parity_db::Db::open(&options).expect("db open error")
|
||||||
parity_db::Db::open(&options).expect("db open error")
|
})),
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,15 +120,10 @@ impl Clone for TempDatabase {
|
|||||||
);
|
);
|
||||||
let self_db_files = std::fs::read_dir(self_dir)
|
let self_db_files = std::fs::read_dir(self_dir)
|
||||||
.expect("failed to list file in seed dir")
|
.expect("failed to list file in seed dir")
|
||||||
.map(|f_result|
|
.map(|f_result| f_result.expect("failed to read file in seed db").path())
|
||||||
f_result.expect("failed to read file in seed db")
|
.collect::<Vec<PathBuf>>();
|
||||||
.path()
|
fs_extra::copy_items(&self_db_files, new_dir.path(), &fs_extra::dir::CopyOptions::new())
|
||||||
).collect::<Vec<PathBuf>>();
|
.expect("Copy of seed database is ok");
|
||||||
fs_extra::copy_items(
|
|
||||||
&self_db_files,
|
|
||||||
new_dir.path(),
|
|
||||||
&fs_extra::dir::CopyOptions::new(),
|
|
||||||
).expect("Copy of seed database is ok");
|
|
||||||
|
|
||||||
TempDatabase(new_dir)
|
TempDatabase(new_dir)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,13 +18,13 @@
|
|||||||
|
|
||||||
//! Trie benchmark (integrated).
|
//! Trie benchmark (integrated).
|
||||||
|
|
||||||
use std::{borrow::Cow, collections::HashMap, sync::Arc};
|
use hash_db::Prefix;
|
||||||
use kvdb::KeyValueDB;
|
use kvdb::KeyValueDB;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use hash_db::Prefix;
|
|
||||||
use sp_state_machine::Backend as _;
|
use sp_state_machine::Backend as _;
|
||||||
use sp_trie::{trie_types::TrieDBMut, TrieMut as _};
|
use sp_trie::{trie_types::TrieDBMut, TrieMut as _};
|
||||||
|
use std::{borrow::Cow, collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use node_primitives::Hash;
|
use node_primitives::Hash;
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ use crate::{
|
|||||||
core::{self, Mode, Path},
|
core::{self, Mode, Path},
|
||||||
generator::generate_trie,
|
generator::generate_trie,
|
||||||
simple_trie::SimpleTrie,
|
simple_trie::SimpleTrie,
|
||||||
tempdb::{TempDatabase, DatabaseType},
|
tempdb::{DatabaseType, TempDatabase},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const SAMPLE_SIZE: usize = 100;
|
pub const SAMPLE_SIZE: usize = 100;
|
||||||
@@ -142,10 +142,7 @@ impl core::BenchmarkDescription for TrieReadBenchmarkDescription {
|
|||||||
assert_eq!(warmup_keys.len(), SAMPLE_SIZE);
|
assert_eq!(warmup_keys.len(), SAMPLE_SIZE);
|
||||||
assert_eq!(query_keys.len(), SAMPLE_SIZE);
|
assert_eq!(query_keys.len(), SAMPLE_SIZE);
|
||||||
|
|
||||||
let root = generate_trie(
|
let root = generate_trie(database.open(self.database_type), key_values);
|
||||||
database.open(self.database_type),
|
|
||||||
key_values,
|
|
||||||
);
|
|
||||||
|
|
||||||
Box::new(TrieReadBenchmark {
|
Box::new(TrieReadBenchmark {
|
||||||
database,
|
database,
|
||||||
@@ -162,7 +159,8 @@ impl core::BenchmarkDescription for TrieReadBenchmarkDescription {
|
|||||||
self.database_size,
|
self.database_size,
|
||||||
pretty_print(self.database_size.keys()),
|
pretty_print(self.database_size.keys()),
|
||||||
self.database_type,
|
self.database_type,
|
||||||
).into()
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,12 +180,10 @@ impl core::Benchmark for TrieReadBenchmark {
|
|||||||
let storage: Arc<dyn sp_state_machine::Storage<sp_core::Blake2Hasher>> =
|
let storage: Arc<dyn sp_state_machine::Storage<sp_core::Blake2Hasher>> =
|
||||||
Arc::new(Storage(db.open(self.database_type)));
|
Arc::new(Storage(db.open(self.database_type)));
|
||||||
|
|
||||||
let trie_backend = sp_state_machine::TrieBackend::new(
|
let trie_backend = sp_state_machine::TrieBackend::new(storage, self.root);
|
||||||
storage,
|
|
||||||
self.root,
|
|
||||||
);
|
|
||||||
for (warmup_key, warmup_value) in self.warmup_keys.iter() {
|
for (warmup_key, warmup_value) in self.warmup_keys.iter() {
|
||||||
let value = trie_backend.storage(&warmup_key[..])
|
let value = trie_backend
|
||||||
|
.storage(&warmup_key[..])
|
||||||
.expect("Failed to get key: db error")
|
.expect("Failed to get key: db error")
|
||||||
.expect("Warmup key should exist");
|
.expect("Warmup key should exist");
|
||||||
|
|
||||||
@@ -218,7 +214,6 @@ pub struct TrieWriteBenchmarkDescription {
|
|||||||
pub database_type: DatabaseType,
|
pub database_type: DatabaseType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl core::BenchmarkDescription for TrieWriteBenchmarkDescription {
|
impl core::BenchmarkDescription for TrieWriteBenchmarkDescription {
|
||||||
fn path(&self) -> Path {
|
fn path(&self) -> Path {
|
||||||
let mut path = Path::new(&["trie", "write"]);
|
let mut path = Path::new(&["trie", "write"]);
|
||||||
@@ -253,10 +248,7 @@ impl core::BenchmarkDescription for TrieWriteBenchmarkDescription {
|
|||||||
|
|
||||||
assert_eq!(warmup_keys.len(), SAMPLE_SIZE);
|
assert_eq!(warmup_keys.len(), SAMPLE_SIZE);
|
||||||
|
|
||||||
let root = generate_trie(
|
let root = generate_trie(database.open(self.database_type), key_values);
|
||||||
database.open(self.database_type),
|
|
||||||
key_values,
|
|
||||||
);
|
|
||||||
|
|
||||||
Box::new(TrieWriteBenchmark {
|
Box::new(TrieWriteBenchmark {
|
||||||
database,
|
database,
|
||||||
@@ -272,7 +264,8 @@ impl core::BenchmarkDescription for TrieWriteBenchmarkDescription {
|
|||||||
self.database_size,
|
self.database_size,
|
||||||
pretty_print(self.database_size.keys()),
|
pretty_print(self.database_size.keys()),
|
||||||
self.database_type,
|
self.database_type,
|
||||||
).into()
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,15 +285,13 @@ impl core::Benchmark for TrieWriteBenchmark {
|
|||||||
let mut new_root = self.root.clone();
|
let mut new_root = self.root.clone();
|
||||||
|
|
||||||
let mut overlay = HashMap::new();
|
let mut overlay = HashMap::new();
|
||||||
let mut trie = SimpleTrie {
|
let mut trie = SimpleTrie { db: kvdb.clone(), overlay: &mut overlay };
|
||||||
db: kvdb.clone(),
|
let mut trie_db_mut =
|
||||||
overlay: &mut overlay,
|
TrieDBMut::from_existing(&mut trie, &mut new_root).expect("Failed to create TrieDBMut");
|
||||||
};
|
|
||||||
let mut trie_db_mut = TrieDBMut::from_existing(&mut trie, &mut new_root)
|
|
||||||
.expect("Failed to create TrieDBMut");
|
|
||||||
|
|
||||||
for (warmup_key, warmup_value) in self.warmup_keys.iter() {
|
for (warmup_key, warmup_value) in self.warmup_keys.iter() {
|
||||||
let value = trie_db_mut.get(&warmup_key[..])
|
let value = trie_db_mut
|
||||||
|
.get(&warmup_key[..])
|
||||||
.expect("Failed to get key: db error")
|
.expect("Failed to get key: db error")
|
||||||
.expect("Warmup key should exist");
|
.expect("Warmup key should exist");
|
||||||
|
|
||||||
@@ -367,7 +358,9 @@ impl SizePool {
|
|||||||
|
|
||||||
fn value<R: Rng>(&self, rng: &mut R) -> Vec<u8> {
|
fn value<R: Rng>(&self, rng: &mut R) -> Vec<u8> {
|
||||||
let sr = (rng.next_u64() % self.total as u64) as u32;
|
let sr = (rng.next_u64() % self.total as u64) as u32;
|
||||||
let mut range = self.distribution.range((std::ops::Bound::Included(sr), std::ops::Bound::Unbounded));
|
let mut range = self
|
||||||
|
.distribution
|
||||||
|
.range((std::ops::Bound::Included(sr), std::ops::Bound::Unbounded));
|
||||||
let size = *range.next().unwrap().1 as usize;
|
let size = *range.next().unwrap().1 as usize;
|
||||||
random_vec(rng, size)
|
random_vec(rng, size)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,13 +23,13 @@
|
|||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use node_testing::bench::{BenchDb, Profile, BlockType, KeyTypes, DatabaseType};
|
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile};
|
||||||
|
|
||||||
use sc_transaction_pool::BasicPool;
|
use sc_transaction_pool::BasicPool;
|
||||||
use sp_runtime::generic::BlockId;
|
|
||||||
use sc_transaction_pool_api::{TransactionPool, TransactionSource};
|
use sc_transaction_pool_api::{TransactionPool, TransactionSource};
|
||||||
|
use sp_runtime::generic::BlockId;
|
||||||
|
|
||||||
use crate::core::{self, Path, Mode};
|
use crate::core::{self, Mode, Path};
|
||||||
|
|
||||||
pub struct PoolBenchmarkDescription {
|
pub struct PoolBenchmarkDescription {
|
||||||
pub database_type: DatabaseType,
|
pub database_type: DatabaseType,
|
||||||
@@ -46,11 +46,7 @@ impl core::BenchmarkDescription for PoolBenchmarkDescription {
|
|||||||
|
|
||||||
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
|
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
|
||||||
Box::new(PoolBenchmark {
|
Box::new(PoolBenchmark {
|
||||||
database: BenchDb::with_key_types(
|
database: BenchDb::with_key_types(self.database_type, 50_000, KeyTypes::Sr25519),
|
||||||
self.database_type,
|
|
||||||
50_000,
|
|
||||||
KeyTypes::Sr25519,
|
|
||||||
),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +59,9 @@ impl core::Benchmark for PoolBenchmark {
|
|||||||
fn run(&mut self, mode: Mode) -> std::time::Duration {
|
fn run(&mut self, mode: Mode) -> std::time::Duration {
|
||||||
let context = self.database.create_context(Profile::Wasm);
|
let context = self.database.create_context(Profile::Wasm);
|
||||||
|
|
||||||
let _ = context.client.runtime_version_at(&BlockId::Number(0))
|
let _ = context
|
||||||
|
.client
|
||||||
|
.runtime_version_at(&BlockId::Number(0))
|
||||||
.expect("Failed to get runtime version")
|
.expect("Failed to get runtime version")
|
||||||
.spec_version;
|
.spec_version;
|
||||||
|
|
||||||
@@ -80,22 +78,20 @@ impl core::Benchmark for PoolBenchmark {
|
|||||||
context.client.clone(),
|
context.client.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let generated_transactions = self.database.block_content(
|
let generated_transactions = self
|
||||||
BlockType::RandomTransfersKeepAlive.to_content(Some(100)),
|
.database
|
||||||
&context.client,
|
.block_content(
|
||||||
).into_iter().collect::<Vec<_>>();
|
BlockType::RandomTransfersKeepAlive.to_content(Some(100)),
|
||||||
|
&context.client,
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
let submissions = generated_transactions.into_iter().map(|tx| {
|
let submissions = generated_transactions
|
||||||
txpool.submit_one(
|
.into_iter()
|
||||||
&BlockId::Number(0),
|
.map(|tx| txpool.submit_one(&BlockId::Number(0), TransactionSource::External, tx));
|
||||||
TransactionSource::External,
|
futures::executor::block_on(futures::future::join_all(submissions));
|
||||||
tx,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
futures::executor::block_on(
|
|
||||||
futures::future::join_all(submissions)
|
|
||||||
);
|
|
||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
|
|
||||||
if mode == Mode::Profile {
|
if mode == Mode::Profile {
|
||||||
|
|||||||
@@ -28,11 +28,11 @@
|
|||||||
//! flag and open a browser to the url that `wasm-pack test` outputs.
|
//! flag and open a browser to the url that `wasm-pack test` outputs.
|
||||||
//! For more infomation see <https://rustwasm.github.io/docs/wasm-pack/>.
|
//! For more infomation see <https://rustwasm.github.io/docs/wasm-pack/>.
|
||||||
|
|
||||||
use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
|
use jsonrpc_core::types::{Id, MethodCall, Params, Success, Version};
|
||||||
use wasm_bindgen_futures::JsFuture;
|
|
||||||
use wasm_bindgen::JsValue;
|
|
||||||
use jsonrpc_core::types::{MethodCall, Success, Version, Params, Id};
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
|
use wasm_bindgen::JsValue;
|
||||||
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
|
||||||
|
|
||||||
wasm_bindgen_test_configure!(run_in_browser);
|
wasm_bindgen_test_configure!(run_in_browser);
|
||||||
|
|
||||||
@@ -41,8 +41,9 @@ fn rpc_call(method: &str) -> String {
|
|||||||
jsonrpc: Some(Version::V2),
|
jsonrpc: Some(Version::V2),
|
||||||
method: method.into(),
|
method: method.into(),
|
||||||
params: Params::None,
|
params: Params::None,
|
||||||
id: Id::Num(1)
|
id: Id::Num(1),
|
||||||
}).unwrap()
|
})
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_rpc_result<T: DeserializeOwned>(js_value: JsValue) -> T {
|
fn deserialize_rpc_result<T: DeserializeOwned>(js_value: JsValue) -> T {
|
||||||
@@ -55,15 +56,12 @@ fn deserialize_rpc_result<T: DeserializeOwned>(js_value: JsValue) -> T {
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
async fn runs() {
|
async fn runs() {
|
||||||
let mut client = node_cli::start_client(None, "info".into())
|
let mut client = node_cli::start_client(None, "info".into()).unwrap();
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Check that the node handles rpc calls.
|
// Check that the node handles rpc calls.
|
||||||
// TODO: Re-add the code that checks if the node is syncing.
|
// TODO: Re-add the code that checks if the node is syncing.
|
||||||
let chain_name: String = deserialize_rpc_result(
|
let chain_name: String = deserialize_rpc_result(
|
||||||
JsFuture::from(client.rpc_send(&rpc_call("system_chain")))
|
JsFuture::from(client.rpc_send(&rpc_call("system_chain"))).await.unwrap(),
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
);
|
);
|
||||||
assert_eq!(chain_name, "Development");
|
assert_eq!(chain_name, "Development");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ fn main() {
|
|||||||
mod cli {
|
mod cli {
|
||||||
include!("src/cli.rs");
|
include!("src/cli.rs");
|
||||||
|
|
||||||
use std::{fs, env, path::Path};
|
|
||||||
use sc_cli::structopt::clap::Shell;
|
use sc_cli::structopt::clap::Shell;
|
||||||
|
use std::{env, fs, path::Path};
|
||||||
use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed};
|
use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed};
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
@@ -51,9 +51,12 @@ mod cli {
|
|||||||
Some(dir) => dir,
|
Some(dir) => dir,
|
||||||
};
|
};
|
||||||
let path = Path::new(&outdir)
|
let path = Path::new(&outdir)
|
||||||
.parent().unwrap()
|
.parent()
|
||||||
.parent().unwrap()
|
.unwrap()
|
||||||
.parent().unwrap()
|
.parent()
|
||||||
|
.unwrap()
|
||||||
|
.parent()
|
||||||
|
.unwrap()
|
||||||
.join("completion-scripts");
|
.join("completion-scripts");
|
||||||
|
|
||||||
fs::create_dir(&path).ok();
|
fs::create_dir(&path).ok();
|
||||||
|
|||||||
@@ -17,18 +17,14 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::chain_spec::ChainSpec;
|
use crate::chain_spec::ChainSpec;
|
||||||
|
use browser_utils::{browser_configuration, init_logging, set_console_error_panic_hook, Client};
|
||||||
use log::info;
|
use log::info;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use browser_utils::{
|
|
||||||
Client,
|
|
||||||
browser_configuration, init_logging, set_console_error_panic_hook,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Starts the client.
|
/// Starts the client.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn start_client(chain_spec: Option<String>, log_level: String) -> Result<Client, JsValue> {
|
pub fn start_client(chain_spec: Option<String>, log_level: String) -> Result<Client, JsValue> {
|
||||||
start_inner(chain_spec, log_level)
|
start_inner(chain_spec, log_level).map_err(|err| JsValue::from_str(&err.to_string()))
|
||||||
.map_err(|err| JsValue::from_str(&err.to_string()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_inner(
|
fn start_inner(
|
||||||
@@ -53,10 +49,9 @@ fn start_inner(
|
|||||||
info!("👤 Role: {:?}", config.role);
|
info!("👤 Role: {:?}", config.role);
|
||||||
|
|
||||||
// Create the service. This is the most heavy initialization step.
|
// Create the service. This is the most heavy initialization step.
|
||||||
let (task_manager, rpc_handlers) =
|
let (task_manager, rpc_handlers) = crate::service::new_light_base(config)
|
||||||
crate::service::new_light_base(config)
|
.map(|(components, rpc_handlers, _, _, _)| (components, rpc_handlers))
|
||||||
.map(|(components, rpc_handlers, _, _, _)| (components, rpc_handlers))
|
.map_err(|e| format!("{:?}", e))?;
|
||||||
.map_err(|e| format!("{:?}", e))?;
|
|
||||||
|
|
||||||
Ok(browser_utils::start_client(task_manager, rpc_handlers))
|
Ok(browser_utils::start_client(task_manager, rpc_handlers))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,25 +18,26 @@
|
|||||||
|
|
||||||
//! Substrate chain configurations.
|
//! Substrate chain configurations.
|
||||||
|
|
||||||
use sc_chain_spec::ChainSpecExtension;
|
use grandpa_primitives::AuthorityId as GrandpaId;
|
||||||
use sp_core::{Pair, Public, crypto::UncheckedInto, sr25519};
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use node_runtime::{
|
|
||||||
AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, CouncilConfig,
|
|
||||||
DemocracyConfig, GrandpaConfig, ImOnlineConfig, SessionConfig, SessionKeys, StakerStatus,
|
|
||||||
StakingConfig, ElectionsConfig, IndicesConfig, SocietyConfig, SudoConfig, SystemConfig,
|
|
||||||
TechnicalCommitteeConfig, wasm_binary_unwrap, MAX_NOMINATIONS,
|
|
||||||
};
|
|
||||||
use node_runtime::Block;
|
|
||||||
use node_runtime::constants::currency::*;
|
|
||||||
use sc_service::ChainType;
|
|
||||||
use hex_literal::hex;
|
use hex_literal::hex;
|
||||||
|
use node_runtime::{
|
||||||
|
constants::currency::*, wasm_binary_unwrap, AuthorityDiscoveryConfig, BabeConfig,
|
||||||
|
BalancesConfig, Block, CouncilConfig, DemocracyConfig, ElectionsConfig, GrandpaConfig,
|
||||||
|
ImOnlineConfig, IndicesConfig, SessionConfig, SessionKeys, SocietyConfig, StakerStatus,
|
||||||
|
StakingConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig, MAX_NOMINATIONS,
|
||||||
|
};
|
||||||
|
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
|
||||||
|
use sc_chain_spec::ChainSpecExtension;
|
||||||
|
use sc_service::ChainType;
|
||||||
use sc_telemetry::TelemetryEndpoints;
|
use sc_telemetry::TelemetryEndpoints;
|
||||||
use grandpa_primitives::{AuthorityId as GrandpaId};
|
use serde::{Deserialize, Serialize};
|
||||||
use sp_consensus_babe::{AuthorityId as BabeId};
|
|
||||||
use pallet_im_online::sr25519::{AuthorityId as ImOnlineId};
|
|
||||||
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
|
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
|
||||||
use sp_runtime::{Perbill, traits::{Verify, IdentifyAccount}};
|
use sp_consensus_babe::AuthorityId as BabeId;
|
||||||
|
use sp_core::{crypto::UncheckedInto, sr25519, Pair, Public};
|
||||||
|
use sp_runtime::{
|
||||||
|
traits::{IdentifyAccount, Verify},
|
||||||
|
Perbill,
|
||||||
|
};
|
||||||
|
|
||||||
pub use node_primitives::{AccountId, Balance, Signature};
|
pub use node_primitives::{AccountId, Balance, Signature};
|
||||||
pub use node_runtime::GenesisConfig;
|
pub use node_runtime::GenesisConfig;
|
||||||
@@ -59,10 +60,7 @@ pub struct Extensions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Specialized `ChainSpec`.
|
/// Specialized `ChainSpec`.
|
||||||
pub type ChainSpec = sc_service::GenericChainSpec<
|
pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig, Extensions>;
|
||||||
GenesisConfig,
|
|
||||||
Extensions,
|
|
||||||
>;
|
|
||||||
/// Flaming Fir testnet generator
|
/// Flaming Fir testnet generator
|
||||||
pub fn flaming_fir_config() -> Result<ChainSpec, String> {
|
pub fn flaming_fir_config() -> Result<ChainSpec, String> {
|
||||||
ChainSpec::from_json_bytes(&include_bytes!("../res/flaming-fir.json")[..])
|
ChainSpec::from_json_bytes(&include_bytes!("../res/flaming-fir.json")[..])
|
||||||
@@ -84,65 +82,94 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
|||||||
// and
|
// and
|
||||||
// for i in 1 2 3 4 ; do for j in session; do subkey --ed25519 inspect "$secret"//fir//$j//$i; done; done
|
// for i in 1 2 3 4 ; do for j in session; do subkey --ed25519 inspect "$secret"//fir//$j//$i; done; done
|
||||||
|
|
||||||
let initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId)> = vec![(
|
let initial_authorities: Vec<(
|
||||||
// 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy
|
AccountId,
|
||||||
hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].into(),
|
AccountId,
|
||||||
// 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq
|
GrandpaId,
|
||||||
hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].into(),
|
BabeId,
|
||||||
// 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC
|
ImOnlineId,
|
||||||
hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"].unchecked_into(),
|
AuthorityDiscoveryId,
|
||||||
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
|
)> = vec![
|
||||||
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"].unchecked_into(),
|
(
|
||||||
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
|
// 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy
|
||||||
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"].unchecked_into(),
|
hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].into(),
|
||||||
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
|
// 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq
|
||||||
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"].unchecked_into(),
|
hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].into(),
|
||||||
),(
|
// 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC
|
||||||
// 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2
|
hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"]
|
||||||
hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].into(),
|
.unchecked_into(),
|
||||||
// 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF
|
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
|
||||||
hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].into(),
|
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"]
|
||||||
// 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE
|
.unchecked_into(),
|
||||||
hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"].unchecked_into(),
|
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
|
||||||
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
|
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"]
|
||||||
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"].unchecked_into(),
|
.unchecked_into(),
|
||||||
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
|
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
|
||||||
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"].unchecked_into(),
|
hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"]
|
||||||
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
|
.unchecked_into(),
|
||||||
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"].unchecked_into(),
|
),
|
||||||
),(
|
(
|
||||||
// 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp
|
// 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2
|
||||||
hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].into(),
|
hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].into(),
|
||||||
// 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9
|
// 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF
|
||||||
hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].into(),
|
hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].into(),
|
||||||
// 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d
|
// 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE
|
||||||
hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"].unchecked_into(),
|
hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"]
|
||||||
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
|
.unchecked_into(),
|
||||||
hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"].unchecked_into(),
|
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
|
||||||
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
|
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"]
|
||||||
hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"].unchecked_into(),
|
.unchecked_into(),
|
||||||
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
|
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
|
||||||
hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"].unchecked_into(),
|
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"]
|
||||||
),(
|
.unchecked_into(),
|
||||||
// 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9
|
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
|
||||||
hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].into(),
|
hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"]
|
||||||
// 5EPQdAQ39WQNLCRjWsCk5jErsCitHiY5ZmjfWzzbXDoAoYbn
|
.unchecked_into(),
|
||||||
hex!["66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"].into(),
|
),
|
||||||
// 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4
|
(
|
||||||
hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"].unchecked_into(),
|
// 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp
|
||||||
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
|
hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].into(),
|
||||||
hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"].unchecked_into(),
|
// 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9
|
||||||
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
|
hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].into(),
|
||||||
hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"].unchecked_into(),
|
// 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d
|
||||||
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
|
hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"]
|
||||||
hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"].unchecked_into(),
|
.unchecked_into(),
|
||||||
)];
|
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
|
||||||
|
hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"]
|
||||||
|
.unchecked_into(),
|
||||||
|
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
|
||||||
|
hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"]
|
||||||
|
.unchecked_into(),
|
||||||
|
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
|
||||||
|
hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"]
|
||||||
|
.unchecked_into(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
// 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9
|
||||||
|
hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].into(),
|
||||||
|
// 5EPQdAQ39WQNLCRjWsCk5jErsCitHiY5ZmjfWzzbXDoAoYbn
|
||||||
|
hex!["66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"].into(),
|
||||||
|
// 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4
|
||||||
|
hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"]
|
||||||
|
.unchecked_into(),
|
||||||
|
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
|
||||||
|
hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"]
|
||||||
|
.unchecked_into(),
|
||||||
|
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
|
||||||
|
hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"]
|
||||||
|
.unchecked_into(),
|
||||||
|
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
|
||||||
|
hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"]
|
||||||
|
.unchecked_into(),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
// generated with secret: subkey inspect "$secret"/fir
|
// generated with secret: subkey inspect "$secret"/fir
|
||||||
let root_key: AccountId = hex![
|
let root_key: AccountId = hex![
|
||||||
// 5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo
|
// 5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo
|
||||||
"9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809"
|
"9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809"
|
||||||
].into();
|
]
|
||||||
|
.into();
|
||||||
|
|
||||||
let endowed_accounts: Vec<AccountId> = vec![root_key.clone()];
|
let endowed_accounts: Vec<AccountId> = vec![root_key.clone()];
|
||||||
|
|
||||||
@@ -158,8 +185,10 @@ pub fn staging_testnet_config() -> ChainSpec {
|
|||||||
ChainType::Live,
|
ChainType::Live,
|
||||||
staging_testnet_config_genesis,
|
staging_testnet_config_genesis,
|
||||||
boot_nodes,
|
boot_nodes,
|
||||||
Some(TelemetryEndpoints::new(vec![(STAGING_TELEMETRY_URL.to_string(), 0)])
|
Some(
|
||||||
.expect("Staging telemetry url is valid; qed")),
|
TelemetryEndpoints::new(vec![(STAGING_TELEMETRY_URL.to_string(), 0)])
|
||||||
|
.expect("Staging telemetry url is valid; qed"),
|
||||||
|
),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
@@ -174,21 +203,17 @@ pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Pu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to generate an account ID from seed
|
/// Helper function to generate an account ID from seed
|
||||||
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId where
|
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
|
||||||
AccountPublic: From<<TPublic::Pair as Pair>::Public>
|
where
|
||||||
|
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
|
||||||
{
|
{
|
||||||
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
|
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to generate stash, controller and session key from seed
|
/// Helper function to generate stash, controller and session key from seed
|
||||||
pub fn authority_keys_from_seed(seed: &str) -> (
|
pub fn authority_keys_from_seed(
|
||||||
AccountId,
|
seed: &str,
|
||||||
AccountId,
|
) -> (AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId) {
|
||||||
GrandpaId,
|
|
||||||
BabeId,
|
|
||||||
ImOnlineId,
|
|
||||||
AuthorityDiscoveryId,
|
|
||||||
) {
|
|
||||||
(
|
(
|
||||||
get_account_id_from_seed::<sr25519::Public>(&format!("{}//stash", seed)),
|
get_account_id_from_seed::<sr25519::Public>(&format!("{}//stash", seed)),
|
||||||
get_account_id_from_seed::<sr25519::Public>(seed),
|
get_account_id_from_seed::<sr25519::Public>(seed),
|
||||||
@@ -230,11 +255,15 @@ pub fn testnet_genesis(
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
// endow all authorities and nominators.
|
// endow all authorities and nominators.
|
||||||
initial_authorities.iter().map(|x| &x.0).chain(initial_nominators.iter()).for_each(|x| {
|
initial_authorities
|
||||||
if !endowed_accounts.contains(&x) {
|
.iter()
|
||||||
endowed_accounts.push(x.clone())
|
.map(|x| &x.0)
|
||||||
}
|
.chain(initial_nominators.iter())
|
||||||
});
|
.for_each(|x| {
|
||||||
|
if !endowed_accounts.contains(&x) {
|
||||||
|
endowed_accounts.push(x.clone())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// stakers: all validators and nominators.
|
// stakers: all validators and nominators.
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
@@ -266,22 +295,20 @@ pub fn testnet_genesis(
|
|||||||
changes_trie_config: Default::default(),
|
changes_trie_config: Default::default(),
|
||||||
},
|
},
|
||||||
balances: BalancesConfig {
|
balances: BalancesConfig {
|
||||||
balances: endowed_accounts.iter().cloned()
|
balances: endowed_accounts.iter().cloned().map(|x| (x, ENDOWMENT)).collect(),
|
||||||
.map(|x| (x, ENDOWMENT))
|
|
||||||
.collect()
|
|
||||||
},
|
|
||||||
indices: IndicesConfig {
|
|
||||||
indices: vec![],
|
|
||||||
},
|
},
|
||||||
|
indices: IndicesConfig { indices: vec![] },
|
||||||
session: SessionConfig {
|
session: SessionConfig {
|
||||||
keys: initial_authorities.iter().map(|x| {
|
keys: initial_authorities
|
||||||
(x.0.clone(), x.0.clone(), session_keys(
|
.iter()
|
||||||
x.2.clone(),
|
.map(|x| {
|
||||||
x.3.clone(),
|
(
|
||||||
x.4.clone(),
|
x.0.clone(),
|
||||||
x.5.clone(),
|
x.0.clone(),
|
||||||
))
|
session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()),
|
||||||
}).collect::<Vec<_>>(),
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
},
|
},
|
||||||
staking: StakingConfig {
|
staking: StakingConfig {
|
||||||
validator_count: initial_authorities.len() as u32,
|
validator_count: initial_authorities.len() as u32,
|
||||||
@@ -289,47 +316,42 @@ pub fn testnet_genesis(
|
|||||||
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
|
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
|
||||||
slash_reward_fraction: Perbill::from_percent(10),
|
slash_reward_fraction: Perbill::from_percent(10),
|
||||||
stakers,
|
stakers,
|
||||||
.. Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
democracy: DemocracyConfig::default(),
|
democracy: DemocracyConfig::default(),
|
||||||
elections: ElectionsConfig {
|
elections: ElectionsConfig {
|
||||||
members: endowed_accounts.iter()
|
members: endowed_accounts
|
||||||
.take((num_endowed_accounts + 1) / 2)
|
.iter()
|
||||||
.cloned()
|
.take((num_endowed_accounts + 1) / 2)
|
||||||
.map(|member| (member, STASH))
|
.cloned()
|
||||||
.collect(),
|
.map(|member| (member, STASH))
|
||||||
|
.collect(),
|
||||||
},
|
},
|
||||||
council: CouncilConfig::default(),
|
council: CouncilConfig::default(),
|
||||||
technical_committee: TechnicalCommitteeConfig {
|
technical_committee: TechnicalCommitteeConfig {
|
||||||
members: endowed_accounts.iter()
|
members: endowed_accounts
|
||||||
.take((num_endowed_accounts + 1) / 2)
|
.iter()
|
||||||
.cloned()
|
.take((num_endowed_accounts + 1) / 2)
|
||||||
.collect(),
|
.cloned()
|
||||||
|
.collect(),
|
||||||
phantom: Default::default(),
|
phantom: Default::default(),
|
||||||
},
|
},
|
||||||
sudo: SudoConfig {
|
sudo: SudoConfig { key: root_key },
|
||||||
key: root_key,
|
|
||||||
},
|
|
||||||
babe: BabeConfig {
|
babe: BabeConfig {
|
||||||
authorities: vec![],
|
authorities: vec![],
|
||||||
epoch_config: Some(node_runtime::BABE_GENESIS_EPOCH_CONFIG),
|
epoch_config: Some(node_runtime::BABE_GENESIS_EPOCH_CONFIG),
|
||||||
},
|
},
|
||||||
im_online: ImOnlineConfig {
|
im_online: ImOnlineConfig { keys: vec![] },
|
||||||
keys: vec![],
|
authority_discovery: AuthorityDiscoveryConfig { keys: vec![] },
|
||||||
},
|
grandpa: GrandpaConfig { authorities: vec![] },
|
||||||
authority_discovery: AuthorityDiscoveryConfig {
|
|
||||||
keys: vec![],
|
|
||||||
},
|
|
||||||
grandpa: GrandpaConfig {
|
|
||||||
authorities: vec![],
|
|
||||||
},
|
|
||||||
technical_membership: Default::default(),
|
technical_membership: Default::default(),
|
||||||
treasury: Default::default(),
|
treasury: Default::default(),
|
||||||
society: SocietyConfig {
|
society: SocietyConfig {
|
||||||
members: endowed_accounts.iter()
|
members: endowed_accounts
|
||||||
.take((num_endowed_accounts + 1) / 2)
|
.iter()
|
||||||
.cloned()
|
.take((num_endowed_accounts + 1) / 2)
|
||||||
.collect(),
|
.cloned()
|
||||||
|
.collect(),
|
||||||
pot: 0,
|
pot: 0,
|
||||||
max_members: 999,
|
max_members: 999,
|
||||||
},
|
},
|
||||||
@@ -341,9 +363,7 @@ pub fn testnet_genesis(
|
|||||||
|
|
||||||
fn development_config_genesis() -> GenesisConfig {
|
fn development_config_genesis() -> GenesisConfig {
|
||||||
testnet_genesis(
|
testnet_genesis(
|
||||||
vec![
|
vec![authority_keys_from_seed("Alice")],
|
||||||
authority_keys_from_seed("Alice"),
|
|
||||||
],
|
|
||||||
vec![],
|
vec![],
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
None,
|
None,
|
||||||
@@ -367,10 +387,7 @@ pub fn development_config() -> ChainSpec {
|
|||||||
|
|
||||||
fn local_testnet_genesis() -> GenesisConfig {
|
fn local_testnet_genesis() -> GenesisConfig {
|
||||||
testnet_genesis(
|
testnet_genesis(
|
||||||
vec![
|
vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")],
|
||||||
authority_keys_from_seed("Alice"),
|
|
||||||
authority_keys_from_seed("Bob"),
|
|
||||||
],
|
|
||||||
vec![],
|
vec![],
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
None,
|
None,
|
||||||
@@ -401,9 +418,7 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
fn local_testnet_genesis_instant_single() -> GenesisConfig {
|
fn local_testnet_genesis_instant_single() -> GenesisConfig {
|
||||||
testnet_genesis(
|
testnet_genesis(
|
||||||
vec![
|
vec![authority_keys_from_seed("Alice")],
|
||||||
authority_keys_from_seed("Alice"),
|
|
||||||
],
|
|
||||||
vec![],
|
vec![],
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
None,
|
None,
|
||||||
@@ -446,14 +461,24 @@ pub(crate) mod tests {
|
|||||||
sc_service_test::connectivity(
|
sc_service_test::connectivity(
|
||||||
integration_test_config_with_two_authorities(),
|
integration_test_config_with_two_authorities(),
|
||||||
|config| {
|
|config| {
|
||||||
let NewFullBase { task_manager, client, network, transaction_pool, .. }
|
let NewFullBase { task_manager, client, network, transaction_pool, .. } =
|
||||||
= new_full_base(config,|_, _| ())?;
|
new_full_base(config, |_, _| ())?;
|
||||||
Ok(sc_service_test::TestNetComponents::new(task_manager, client, network, transaction_pool))
|
Ok(sc_service_test::TestNetComponents::new(
|
||||||
|
task_manager,
|
||||||
|
client,
|
||||||
|
network,
|
||||||
|
transaction_pool,
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|config| {
|
|config| {
|
||||||
let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?;
|
let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?;
|
||||||
Ok(sc_service_test::TestNetComponents::new(keep_alive, client, network, transaction_pool))
|
Ok(sc_service_test::TestNetComponents::new(
|
||||||
}
|
keep_alive,
|
||||||
|
client,
|
||||||
|
network,
|
||||||
|
transaction_pool,
|
||||||
|
))
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use sc_cli::{RunCmd, KeySubcommand, SignCmd, VanityCmd, VerifyCmd};
|
use sc_cli::{KeySubcommand, RunCmd, SignCmd, VanityCmd, VerifyCmd};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
/// An overarching CLI command definition.
|
/// An overarching CLI command definition.
|
||||||
|
|||||||
@@ -16,12 +16,11 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{chain_spec, service, Cli, Subcommand};
|
use crate::{chain_spec, service, service::new_partial, Cli, Subcommand};
|
||||||
use node_executor::Executor;
|
use node_executor::Executor;
|
||||||
use node_runtime::{Block, RuntimeApi};
|
use node_runtime::{Block, RuntimeApi};
|
||||||
use sc_cli::{Result, SubstrateCli, RuntimeVersion, Role, ChainSpec};
|
use sc_cli::{ChainSpec, Result, Role, RuntimeVersion, SubstrateCli};
|
||||||
use sc_service::PartialComponents;
|
use sc_service::PartialComponents;
|
||||||
use crate::service::new_partial;
|
|
||||||
|
|
||||||
impl SubstrateCli for Cli {
|
impl SubstrateCli for Cli {
|
||||||
fn impl_name() -> String {
|
fn impl_name() -> String {
|
||||||
@@ -49,17 +48,19 @@ impl SubstrateCli for Cli {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
|
fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
|
||||||
let spec =
|
let spec = match id {
|
||||||
match id {
|
"" =>
|
||||||
"" => return Err("Please specify which chain you want to run, e.g. --dev or --chain=local".into()),
|
return Err(
|
||||||
"dev" => Box::new(chain_spec::development_config()),
|
"Please specify which chain you want to run, e.g. --dev or --chain=local"
|
||||||
"local" => Box::new(chain_spec::local_testnet_config()),
|
.into(),
|
||||||
"fir" | "flaming-fir" => Box::new(chain_spec::flaming_fir_config()?),
|
),
|
||||||
"staging" => Box::new(chain_spec::staging_testnet_config()),
|
"dev" => Box::new(chain_spec::development_config()),
|
||||||
path => Box::new(chain_spec::ChainSpec::from_json_file(
|
"local" => Box::new(chain_spec::local_testnet_config()),
|
||||||
std::path::PathBuf::from(path),
|
"fir" | "flaming-fir" => Box::new(chain_spec::flaming_fir_config()?),
|
||||||
)?),
|
"staging" => Box::new(chain_spec::staging_testnet_config()),
|
||||||
};
|
path =>
|
||||||
|
Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
|
||||||
|
};
|
||||||
Ok(spec)
|
Ok(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,24 +80,25 @@ pub fn run() -> Result<()> {
|
|||||||
match config.role {
|
match config.role {
|
||||||
Role::Light => service::new_light(config),
|
Role::Light => service::new_light(config),
|
||||||
_ => service::new_full(config),
|
_ => service::new_full(config),
|
||||||
}.map_err(sc_cli::Error::Service)
|
}
|
||||||
|
.map_err(sc_cli::Error::Service)
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
Some(Subcommand::Inspect(cmd)) => {
|
Some(Subcommand::Inspect(cmd)) => {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
|
|
||||||
runner.sync_run(|config| cmd.run::<Block, RuntimeApi, Executor>(config))
|
runner.sync_run(|config| cmd.run::<Block, RuntimeApi, Executor>(config))
|
||||||
}
|
},
|
||||||
Some(Subcommand::Benchmark(cmd)) => {
|
Some(Subcommand::Benchmark(cmd)) =>
|
||||||
if cfg!(feature = "runtime-benchmarks") {
|
if cfg!(feature = "runtime-benchmarks") {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
|
|
||||||
runner.sync_run(|config| cmd.run::<Block, Executor>(config))
|
runner.sync_run(|config| cmd.run::<Block, Executor>(config))
|
||||||
} else {
|
} else {
|
||||||
Err("Benchmarking wasn't enabled when building the node. \
|
Err("Benchmarking wasn't enabled when building the node. \
|
||||||
You can enable it with `--features runtime-benchmarks`.".into())
|
You can enable it with `--features runtime-benchmarks`."
|
||||||
}
|
.into())
|
||||||
}
|
},
|
||||||
Some(Subcommand::Key(cmd)) => cmd.run(&cli),
|
Some(Subcommand::Key(cmd)) => cmd.run(&cli),
|
||||||
Some(Subcommand::Sign(cmd)) => cmd.run(),
|
Some(Subcommand::Sign(cmd)) => cmd.run(),
|
||||||
Some(Subcommand::Verify(cmd)) => cmd.run(),
|
Some(Subcommand::Verify(cmd)) => cmd.run(),
|
||||||
@@ -108,32 +110,30 @@ pub fn run() -> Result<()> {
|
|||||||
Some(Subcommand::CheckBlock(cmd)) => {
|
Some(Subcommand::CheckBlock(cmd)) => {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
runner.async_run(|config| {
|
runner.async_run(|config| {
|
||||||
let PartialComponents { client, task_manager, import_queue, ..}
|
let PartialComponents { client, task_manager, import_queue, .. } =
|
||||||
= new_partial(&config)?;
|
new_partial(&config)?;
|
||||||
Ok((cmd.run(client, import_queue), task_manager))
|
Ok((cmd.run(client, import_queue), task_manager))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Some(Subcommand::ExportBlocks(cmd)) => {
|
Some(Subcommand::ExportBlocks(cmd)) => {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
runner.async_run(|config| {
|
runner.async_run(|config| {
|
||||||
let PartialComponents { client, task_manager, ..}
|
let PartialComponents { client, task_manager, .. } = new_partial(&config)?;
|
||||||
= new_partial(&config)?;
|
|
||||||
Ok((cmd.run(client, config.database), task_manager))
|
Ok((cmd.run(client, config.database), task_manager))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Some(Subcommand::ExportState(cmd)) => {
|
Some(Subcommand::ExportState(cmd)) => {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
runner.async_run(|config| {
|
runner.async_run(|config| {
|
||||||
let PartialComponents { client, task_manager, ..}
|
let PartialComponents { client, task_manager, .. } = new_partial(&config)?;
|
||||||
= new_partial(&config)?;
|
|
||||||
Ok((cmd.run(client, config.chain_spec), task_manager))
|
Ok((cmd.run(client, config.chain_spec), task_manager))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Some(Subcommand::ImportBlocks(cmd)) => {
|
Some(Subcommand::ImportBlocks(cmd)) => {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
runner.async_run(|config| {
|
runner.async_run(|config| {
|
||||||
let PartialComponents { client, task_manager, import_queue, ..}
|
let PartialComponents { client, task_manager, import_queue, .. } =
|
||||||
= new_partial(&config)?;
|
new_partial(&config)?;
|
||||||
Ok((cmd.run(client, import_queue), task_manager))
|
Ok((cmd.run(client, import_queue), task_manager))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -144,8 +144,7 @@ pub fn run() -> Result<()> {
|
|||||||
Some(Subcommand::Revert(cmd)) => {
|
Some(Subcommand::Revert(cmd)) => {
|
||||||
let runner = cli.create_runner(cmd)?;
|
let runner = cli.create_runner(cmd)?;
|
||||||
runner.async_run(|config| {
|
runner.async_run(|config| {
|
||||||
let PartialComponents { client, task_manager, backend, ..}
|
let PartialComponents { client, task_manager, backend, .. } = new_partial(&config)?;
|
||||||
= new_partial(&config)?;
|
|
||||||
Ok((cmd.run(client, backend), task_manager))
|
Ok((cmd.run(client, backend), task_manager))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -156,18 +155,16 @@ pub fn run() -> Result<()> {
|
|||||||
// we don't need any of the components of new_partial, just a runtime, or a task
|
// we don't need any of the components of new_partial, just a runtime, or a task
|
||||||
// manager to do `async_run`.
|
// manager to do `async_run`.
|
||||||
let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry);
|
let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry);
|
||||||
let task_manager = sc_service::TaskManager::new(
|
let task_manager =
|
||||||
config.task_executor.clone(),
|
sc_service::TaskManager::new(config.task_executor.clone(), registry)
|
||||||
registry,
|
.map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?;
|
||||||
).map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?;
|
|
||||||
|
|
||||||
Ok((cmd.run::<Block, Executor>(config), task_manager))
|
Ok((cmd.run::<Block, Executor>(config), task_manager))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
#[cfg(not(feature = "try-runtime"))]
|
#[cfg(not(feature = "try-runtime"))]
|
||||||
Some(Subcommand::TryRuntime) => {
|
Some(Subcommand::TryRuntime) => Err("TryRuntime wasn't enabled when building the node. \
|
||||||
Err("TryRuntime wasn't enabled when building the node. \
|
You can enable it with `--features try-runtime`."
|
||||||
You can enable it with `--features try-runtime`.".into())
|
.into()),
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,20 +20,17 @@
|
|||||||
|
|
||||||
//! Service implementation. Specialized wrapper over substrate service.
|
//! Service implementation. Specialized wrapper over substrate service.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use futures::prelude::*;
|
||||||
use sc_consensus_babe;
|
use node_executor::Executor;
|
||||||
use node_primitives::Block;
|
use node_primitives::Block;
|
||||||
use node_runtime::RuntimeApi;
|
use node_runtime::RuntimeApi;
|
||||||
use sc_service::{
|
|
||||||
config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager,
|
|
||||||
};
|
|
||||||
use sc_network::{Event, NetworkService};
|
|
||||||
use sp_runtime::traits::Block as BlockT;
|
|
||||||
use futures::prelude::*;
|
|
||||||
use sc_client_api::{ExecutorProvider, RemoteBackend};
|
use sc_client_api::{ExecutorProvider, RemoteBackend};
|
||||||
use node_executor::Executor;
|
use sc_consensus_babe::{self, SlotProportion};
|
||||||
|
use sc_network::{Event, NetworkService};
|
||||||
|
use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager};
|
||||||
use sc_telemetry::{Telemetry, TelemetryWorker};
|
use sc_telemetry::{Telemetry, TelemetryWorker};
|
||||||
use sc_consensus_babe::SlotProportion;
|
use sp_runtime::traits::Block as BlockT;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
type FullClient = sc_service::TFullClient<Block, RuntimeApi, Executor>;
|
type FullClient = sc_service::TFullClient<Block, RuntimeApi, Executor>;
|
||||||
type FullBackend = sc_service::TFullBackend<Block>;
|
type FullBackend = sc_service::TFullBackend<Block>;
|
||||||
@@ -44,25 +41,29 @@ type LightClient = sc_service::TLightClient<Block, RuntimeApi, Executor>;
|
|||||||
|
|
||||||
pub fn new_partial(
|
pub fn new_partial(
|
||||||
config: &Configuration,
|
config: &Configuration,
|
||||||
) -> Result<sc_service::PartialComponents<
|
) -> Result<
|
||||||
FullClient, FullBackend, FullSelectChain,
|
sc_service::PartialComponents<
|
||||||
sp_consensus::DefaultImportQueue<Block, FullClient>,
|
FullClient,
|
||||||
sc_transaction_pool::FullPool<Block, FullClient>,
|
FullBackend,
|
||||||
(
|
FullSelectChain,
|
||||||
impl Fn(
|
sp_consensus::DefaultImportQueue<Block, FullClient>,
|
||||||
node_rpc::DenyUnsafe,
|
sc_transaction_pool::FullPool<Block, FullClient>,
|
||||||
sc_rpc::SubscriptionTaskExecutor,
|
|
||||||
) -> node_rpc::IoHandler,
|
|
||||||
(
|
(
|
||||||
sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>,
|
impl Fn(node_rpc::DenyUnsafe, sc_rpc::SubscriptionTaskExecutor) -> node_rpc::IoHandler,
|
||||||
grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
|
(
|
||||||
sc_consensus_babe::BabeLink<Block>,
|
sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>,
|
||||||
|
grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
|
||||||
|
sc_consensus_babe::BabeLink<Block>,
|
||||||
|
),
|
||||||
|
grandpa::SharedVoterState,
|
||||||
|
Option<Telemetry>,
|
||||||
),
|
),
|
||||||
grandpa::SharedVoterState,
|
>,
|
||||||
Option<Telemetry>,
|
ServiceError,
|
||||||
)
|
> {
|
||||||
>, ServiceError> {
|
let telemetry = config
|
||||||
let telemetry = config.telemetry_endpoints.clone()
|
.telemetry_endpoints
|
||||||
|
.clone()
|
||||||
.filter(|x| !x.is_empty())
|
.filter(|x| !x.is_empty())
|
||||||
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
|
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
|
||||||
let worker = TelemetryWorker::new(16)?;
|
let worker = TelemetryWorker::new(16)?;
|
||||||
@@ -78,11 +79,10 @@ pub fn new_partial(
|
|||||||
)?;
|
)?;
|
||||||
let client = Arc::new(client);
|
let client = Arc::new(client);
|
||||||
|
|
||||||
let telemetry = telemetry
|
let telemetry = telemetry.map(|(worker, telemetry)| {
|
||||||
.map(|(worker, telemetry)| {
|
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
telemetry
|
||||||
telemetry
|
});
|
||||||
});
|
|
||||||
|
|
||||||
let select_chain = sc_consensus::LongestChain::new(backend.clone());
|
let select_chain = sc_consensus::LongestChain::new(backend.clone());
|
||||||
|
|
||||||
@@ -115,21 +115,19 @@ pub fn new_partial(
|
|||||||
Some(Box::new(justification_import)),
|
Some(Box::new(justification_import)),
|
||||||
client.clone(),
|
client.clone(),
|
||||||
select_chain.clone(),
|
select_chain.clone(),
|
||||||
move |_, ()| {
|
move |_, ()| async move {
|
||||||
async move {
|
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
|
||||||
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
|
|
||||||
|
|
||||||
let slot =
|
let slot =
|
||||||
sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
|
sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
|
||||||
*timestamp,
|
*timestamp,
|
||||||
slot_duration,
|
slot_duration,
|
||||||
);
|
);
|
||||||
|
|
||||||
let uncles =
|
let uncles =
|
||||||
sp_authorship::InherentDataProvider::<<Block as BlockT>::Header>::check_inherents();
|
sp_authorship::InherentDataProvider::<<Block as BlockT>::Header>::check_inherents();
|
||||||
|
|
||||||
Ok((timestamp, slot, uncles))
|
Ok((timestamp, slot, uncles))
|
||||||
}
|
|
||||||
},
|
},
|
||||||
&task_manager.spawn_essential_handle(),
|
&task_manager.spawn_essential_handle(),
|
||||||
config.prometheus_registry(),
|
config.prometheus_registry(),
|
||||||
@@ -213,7 +211,7 @@ pub fn new_full_base(
|
|||||||
with_startup_data: impl FnOnce(
|
with_startup_data: impl FnOnce(
|
||||||
&sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>,
|
&sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>,
|
||||||
&sc_consensus_babe::BabeLink<Block>,
|
&sc_consensus_babe::BabeLink<Block>,
|
||||||
)
|
),
|
||||||
) -> Result<NewFullBase, ServiceError> {
|
) -> Result<NewFullBase, ServiceError> {
|
||||||
let sc_service::PartialComponents {
|
let sc_service::PartialComponents {
|
||||||
client,
|
client,
|
||||||
@@ -238,7 +236,7 @@ pub fn new_full_base(
|
|||||||
task_manager.spawn_handle(),
|
task_manager.spawn_handle(),
|
||||||
backend.clone(),
|
backend.clone(),
|
||||||
import_setup.1.shared_authority_set().clone(),
|
import_setup.1.shared_authority_set().clone(),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let (network, system_rpc_tx, network_starter) =
|
let (network, system_rpc_tx, network_starter) =
|
||||||
@@ -254,7 +252,10 @@ pub fn new_full_base(
|
|||||||
|
|
||||||
if config.offchain_worker.enabled {
|
if config.offchain_worker.enabled {
|
||||||
sc_service::build_offchain_workers(
|
sc_service::build_offchain_workers(
|
||||||
&config, task_manager.spawn_handle(), client.clone(), network.clone(),
|
&config,
|
||||||
|
task_manager.spawn_handle(),
|
||||||
|
client.clone(),
|
||||||
|
network.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,22 +267,20 @@ pub fn new_full_base(
|
|||||||
let enable_grandpa = !config.disable_grandpa;
|
let enable_grandpa = !config.disable_grandpa;
|
||||||
let prometheus_registry = config.prometheus_registry().cloned();
|
let prometheus_registry = config.prometheus_registry().cloned();
|
||||||
|
|
||||||
let _rpc_handlers = sc_service::spawn_tasks(
|
let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||||
sc_service::SpawnTasksParams {
|
config,
|
||||||
config,
|
backend: backend.clone(),
|
||||||
backend: backend.clone(),
|
client: client.clone(),
|
||||||
client: client.clone(),
|
keystore: keystore_container.sync_keystore(),
|
||||||
keystore: keystore_container.sync_keystore(),
|
network: network.clone(),
|
||||||
network: network.clone(),
|
rpc_extensions_builder: Box::new(rpc_extensions_builder),
|
||||||
rpc_extensions_builder: Box::new(rpc_extensions_builder),
|
transaction_pool: transaction_pool.clone(),
|
||||||
transaction_pool: transaction_pool.clone(),
|
task_manager: &mut task_manager,
|
||||||
task_manager: &mut task_manager,
|
on_demand: None,
|
||||||
on_demand: None,
|
remote_blockchain: None,
|
||||||
remote_blockchain: None,
|
system_rpc_tx,
|
||||||
system_rpc_tx,
|
telemetry: telemetry.as_mut(),
|
||||||
telemetry: telemetry.as_mut(),
|
})?;
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let (block_import, grandpa_link, babe_link) = import_setup;
|
let (block_import, grandpa_link, babe_link) = import_setup;
|
||||||
|
|
||||||
@@ -343,36 +342,37 @@ pub fn new_full_base(
|
|||||||
|
|
||||||
// Spawn authority discovery module.
|
// Spawn authority discovery module.
|
||||||
if role.is_authority() {
|
if role.is_authority() {
|
||||||
let authority_discovery_role = sc_authority_discovery::Role::PublishAndDiscover(
|
let authority_discovery_role =
|
||||||
keystore_container.keystore(),
|
sc_authority_discovery::Role::PublishAndDiscover(keystore_container.keystore());
|
||||||
);
|
let dht_event_stream =
|
||||||
let dht_event_stream = network.event_stream("authority-discovery")
|
network.event_stream("authority-discovery").filter_map(|e| async move {
|
||||||
.filter_map(|e| async move { match e {
|
match e {
|
||||||
Event::Dht(e) => Some(e),
|
Event::Dht(e) => Some(e),
|
||||||
_ => None,
|
_ => None,
|
||||||
}});
|
}
|
||||||
let (authority_discovery_worker, _service) = sc_authority_discovery::new_worker_and_service_with_config(
|
});
|
||||||
sc_authority_discovery::WorkerConfig {
|
let (authority_discovery_worker, _service) =
|
||||||
publish_non_global_ips: auth_disc_publish_non_global_ips,
|
sc_authority_discovery::new_worker_and_service_with_config(
|
||||||
..Default::default()
|
sc_authority_discovery::WorkerConfig {
|
||||||
},
|
publish_non_global_ips: auth_disc_publish_non_global_ips,
|
||||||
client.clone(),
|
..Default::default()
|
||||||
network.clone(),
|
},
|
||||||
Box::pin(dht_event_stream),
|
client.clone(),
|
||||||
authority_discovery_role,
|
network.clone(),
|
||||||
prometheus_registry.clone(),
|
Box::pin(dht_event_stream),
|
||||||
);
|
authority_discovery_role,
|
||||||
|
prometheus_registry.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
task_manager.spawn_handle().spawn("authority-discovery-worker", authority_discovery_worker.run());
|
task_manager
|
||||||
|
.spawn_handle()
|
||||||
|
.spawn("authority-discovery-worker", authority_discovery_worker.run());
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the node isn't actively participating in consensus then it doesn't
|
// if the node isn't actively participating in consensus then it doesn't
|
||||||
// need a keystore, regardless of which protocol we use below.
|
// need a keystore, regardless of which protocol we use below.
|
||||||
let keystore = if role.is_authority() {
|
let keystore =
|
||||||
Some(keystore_container.sync_keystore())
|
if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None };
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let config = grandpa::Config {
|
let config = grandpa::Config {
|
||||||
// FIXME #1578 make this available through chainspec
|
// FIXME #1578 make this available through chainspec
|
||||||
@@ -404,46 +404,41 @@ pub fn new_full_base(
|
|||||||
|
|
||||||
// the GRANDPA voter task is considered infallible, i.e.
|
// the GRANDPA voter task is considered infallible, i.e.
|
||||||
// if it fails we take down the service with it.
|
// if it fails we take down the service with it.
|
||||||
task_manager.spawn_essential_handle().spawn_blocking(
|
task_manager
|
||||||
"grandpa-voter",
|
.spawn_essential_handle()
|
||||||
grandpa::run_grandpa_voter(grandpa_config)?
|
.spawn_blocking("grandpa-voter", grandpa::run_grandpa_voter(grandpa_config)?);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
network_starter.start_network();
|
network_starter.start_network();
|
||||||
Ok(NewFullBase {
|
Ok(NewFullBase { task_manager, client, network, transaction_pool })
|
||||||
task_manager,
|
|
||||||
client,
|
|
||||||
network,
|
|
||||||
transaction_pool,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a new service for a full client.
|
/// Builds a new service for a full client.
|
||||||
pub fn new_full(
|
pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
|
||||||
config: Configuration,
|
new_full_base(config, |_, _| ()).map(|NewFullBase { task_manager, .. }| task_manager)
|
||||||
) -> Result<TaskManager, ServiceError> {
|
|
||||||
new_full_base(config, |_, _| ()).map(|NewFullBase { task_manager, .. }| {
|
|
||||||
task_manager
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_light_base(
|
pub fn new_light_base(
|
||||||
mut config: Configuration,
|
mut config: Configuration,
|
||||||
) -> Result<(
|
) -> Result<
|
||||||
TaskManager,
|
(
|
||||||
RpcHandlers,
|
TaskManager,
|
||||||
Arc<LightClient>,
|
RpcHandlers,
|
||||||
Arc<NetworkService<Block, <Block as BlockT>::Hash>>,
|
Arc<LightClient>,
|
||||||
Arc<sc_transaction_pool::LightPool<Block, LightClient, sc_network::config::OnDemand<Block>>>
|
Arc<NetworkService<Block, <Block as BlockT>::Hash>>,
|
||||||
), ServiceError> {
|
Arc<
|
||||||
let telemetry = config.telemetry_endpoints.clone()
|
sc_transaction_pool::LightPool<Block, LightClient, sc_network::config::OnDemand<Block>>,
|
||||||
|
>,
|
||||||
|
),
|
||||||
|
ServiceError,
|
||||||
|
> {
|
||||||
|
let telemetry = config
|
||||||
|
.telemetry_endpoints
|
||||||
|
.clone()
|
||||||
.filter(|x| !x.is_empty())
|
.filter(|x| !x.is_empty())
|
||||||
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
|
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
|
||||||
#[cfg(feature = "browser")]
|
#[cfg(feature = "browser")]
|
||||||
let transport = Some(
|
let transport = Some(sc_telemetry::ExtTransport::new(libp2p_wasm_ext::ffi::websocket_transport()));
|
||||||
sc_telemetry::ExtTransport::new(libp2p_wasm_ext::ffi::websocket_transport())
|
|
||||||
);
|
|
||||||
#[cfg(not(feature = "browser"))]
|
#[cfg(not(feature = "browser"))]
|
||||||
let transport = None;
|
let transport = None;
|
||||||
|
|
||||||
@@ -459,11 +454,10 @@ pub fn new_light_base(
|
|||||||
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
|
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut telemetry = telemetry
|
let mut telemetry = telemetry.map(|(worker, telemetry)| {
|
||||||
.map(|(worker, telemetry)| {
|
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
telemetry
|
||||||
telemetry
|
});
|
||||||
});
|
|
||||||
|
|
||||||
config.network.extra_sets.push(grandpa::grandpa_peers_set_config());
|
config.network.extra_sets.push(grandpa::grandpa_peers_set_config());
|
||||||
|
|
||||||
@@ -567,71 +561,60 @@ pub fn new_light_base(
|
|||||||
|
|
||||||
let rpc_extensions = node_rpc::create_light(light_deps);
|
let rpc_extensions = node_rpc::create_light(light_deps);
|
||||||
|
|
||||||
let rpc_handlers =
|
let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||||
sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
on_demand: Some(on_demand),
|
||||||
on_demand: Some(on_demand),
|
remote_blockchain: Some(backend.remote_blockchain()),
|
||||||
remote_blockchain: Some(backend.remote_blockchain()),
|
rpc_extensions_builder: Box::new(sc_service::NoopRpcExtensionBuilder(rpc_extensions)),
|
||||||
rpc_extensions_builder: Box::new(sc_service::NoopRpcExtensionBuilder(rpc_extensions)),
|
client: client.clone(),
|
||||||
client: client.clone(),
|
transaction_pool: transaction_pool.clone(),
|
||||||
transaction_pool: transaction_pool.clone(),
|
keystore: keystore_container.sync_keystore(),
|
||||||
keystore: keystore_container.sync_keystore(),
|
config,
|
||||||
config, backend, system_rpc_tx,
|
backend,
|
||||||
network: network.clone(),
|
system_rpc_tx,
|
||||||
task_manager: &mut task_manager,
|
network: network.clone(),
|
||||||
telemetry: telemetry.as_mut(),
|
task_manager: &mut task_manager,
|
||||||
})?;
|
telemetry: telemetry.as_mut(),
|
||||||
|
})?;
|
||||||
|
|
||||||
network_starter.start_network();
|
network_starter.start_network();
|
||||||
Ok((
|
Ok((task_manager, rpc_handlers, client, network, transaction_pool))
|
||||||
task_manager,
|
|
||||||
rpc_handlers,
|
|
||||||
client,
|
|
||||||
network,
|
|
||||||
transaction_pool,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a new service for a light client.
|
/// Builds a new service for a light client.
|
||||||
pub fn new_light(
|
pub fn new_light(config: Configuration) -> Result<TaskManager, ServiceError> {
|
||||||
config: Configuration,
|
new_light_base(config).map(|(task_manager, _, _, _, _)| task_manager)
|
||||||
) -> Result<TaskManager, ServiceError> {
|
|
||||||
new_light_base(config).map(|(task_manager, _, _, _, _)| {
|
|
||||||
task_manager
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{sync::Arc, borrow::Cow, convert::TryInto};
|
use crate::service::{new_full_base, new_light_base, NewFullBase};
|
||||||
use sc_consensus_babe::{CompatibleDigestItem, BabeIntermediate, INTERMEDIATE_KEY};
|
|
||||||
use sc_consensus_epochs::descendent_query;
|
|
||||||
use sp_consensus::{
|
|
||||||
Environment, Proposer, BlockImportParams, BlockOrigin, ForkChoiceStrategy, BlockImport,
|
|
||||||
};
|
|
||||||
use node_primitives::{Block, DigestItem, Signature};
|
|
||||||
use node_runtime::{BalancesCall, Call, UncheckedExtrinsic, Address};
|
|
||||||
use node_runtime::constants::{currency::CENTS, time::SLOT_DURATION};
|
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use sp_core::{
|
use node_primitives::{Block, DigestItem, Signature};
|
||||||
crypto::Pair as CryptoPair,
|
use node_runtime::{
|
||||||
H256,
|
constants::{currency::CENTS, time::SLOT_DURATION},
|
||||||
Public
|
Address, BalancesCall, Call, UncheckedExtrinsic,
|
||||||
};
|
};
|
||||||
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
|
use sc_client_api::BlockBackend;
|
||||||
|
use sc_consensus_babe::{BabeIntermediate, CompatibleDigestItem, INTERMEDIATE_KEY};
|
||||||
|
use sc_consensus_epochs::descendent_query;
|
||||||
|
use sc_keystore::LocalKeystore;
|
||||||
|
use sc_service_test::TestNetNode;
|
||||||
|
use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool};
|
||||||
|
use sp_consensus::{
|
||||||
|
BlockImport, BlockImportParams, BlockOrigin, Environment, ForkChoiceStrategy, Proposer,
|
||||||
|
};
|
||||||
|
use sp_core::{crypto::Pair as CryptoPair, Public, H256};
|
||||||
|
use sp_inherents::InherentDataProvider;
|
||||||
|
use sp_keyring::AccountKeyring;
|
||||||
|
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
generic::{BlockId, Era, Digest, SignedPayload},
|
generic::{BlockId, Digest, Era, SignedPayload},
|
||||||
traits::{Block as BlockT, Header as HeaderT},
|
key_types::BABE,
|
||||||
traits::Verify,
|
traits::{Block as BlockT, Header as HeaderT, IdentifyAccount, Verify},
|
||||||
|
RuntimeAppPublic,
|
||||||
};
|
};
|
||||||
use sp_timestamp;
|
use sp_timestamp;
|
||||||
use sp_keyring::AccountKeyring;
|
use std::{borrow::Cow, convert::TryInto, sync::Arc};
|
||||||
use sc_service_test::TestNetNode;
|
|
||||||
use crate::service::{new_full_base, new_light_base, NewFullBase};
|
|
||||||
use sp_runtime::{key_types::BABE, traits::IdentifyAccount, RuntimeAppPublic};
|
|
||||||
use sc_transaction_pool_api::{MaintainedTransactionPool, ChainEvent};
|
|
||||||
use sc_client_api::BlockBackend;
|
|
||||||
use sc_keystore::LocalKeystore;
|
|
||||||
use sp_inherents::InherentDataProvider;
|
|
||||||
|
|
||||||
type AccountPublic = <Signature as Verify>::Signer;
|
type AccountPublic = <Signature as Verify>::Signer;
|
||||||
|
|
||||||
@@ -641,10 +624,12 @@ mod tests {
|
|||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_sync() {
|
fn test_sync() {
|
||||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
|
let keystore: SyncCryptoStorePtr =
|
||||||
.expect("Creates keystore"));
|
Arc::new(LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore"));
|
||||||
let alice: sp_consensus_babe::AuthorityId = SyncCryptoStore::sr25519_generate_new(&*keystore, BABE, Some("//Alice"))
|
let alice: sp_consensus_babe::AuthorityId =
|
||||||
.expect("Creates authority pair").into();
|
SyncCryptoStore::sr25519_generate_new(&*keystore, BABE, Some("//Alice"))
|
||||||
|
.expect("Creates authority pair")
|
||||||
|
.into();
|
||||||
|
|
||||||
let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority();
|
let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority();
|
||||||
|
|
||||||
@@ -660,25 +645,31 @@ mod tests {
|
|||||||
chain_spec,
|
chain_spec,
|
||||||
|config| {
|
|config| {
|
||||||
let mut setup_handles = None;
|
let mut setup_handles = None;
|
||||||
let NewFullBase {
|
let NewFullBase { task_manager, client, network, transaction_pool, .. } =
|
||||||
task_manager, client, network, transaction_pool, ..
|
new_full_base(
|
||||||
} = new_full_base(config,
|
config,
|
||||||
|
|
|block_import: &sc_consensus_babe::BabeBlockImport<Block, _, _>,
|
||||||
block_import: &sc_consensus_babe::BabeBlockImport<Block, _, _>,
|
babe_link: &sc_consensus_babe::BabeLink<Block>| {
|
||||||
babe_link: &sc_consensus_babe::BabeLink<Block>,
|
setup_handles = Some((block_import.clone(), babe_link.clone()));
|
||||||
| {
|
},
|
||||||
setup_handles = Some((block_import.clone(), babe_link.clone()));
|
)?;
|
||||||
}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let node = sc_service_test::TestNetComponents::new(
|
let node = sc_service_test::TestNetComponents::new(
|
||||||
task_manager, client, network, transaction_pool
|
task_manager,
|
||||||
|
client,
|
||||||
|
network,
|
||||||
|
transaction_pool,
|
||||||
);
|
);
|
||||||
Ok((node, setup_handles.unwrap()))
|
Ok((node, setup_handles.unwrap()))
|
||||||
},
|
},
|
||||||
|config| {
|
|config| {
|
||||||
let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?;
|
let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?;
|
||||||
Ok(sc_service_test::TestNetComponents::new(keep_alive, client, network, transaction_pool))
|
Ok(sc_service_test::TestNetComponents::new(
|
||||||
|
keep_alive,
|
||||||
|
client,
|
||||||
|
network,
|
||||||
|
transaction_pool,
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|service, &mut (ref mut block_import, ref babe_link)| {
|
|service, &mut (ref mut block_import, ref babe_link)| {
|
||||||
let parent_id = BlockId::number(service.client().chain_info().best_number);
|
let parent_id = BlockId::number(service.client().chain_info().best_number);
|
||||||
@@ -686,14 +677,9 @@ mod tests {
|
|||||||
let parent_hash = parent_header.hash();
|
let parent_hash = parent_header.hash();
|
||||||
let parent_number = *parent_header.number();
|
let parent_number = *parent_header.number();
|
||||||
|
|
||||||
futures::executor::block_on(
|
futures::executor::block_on(service.transaction_pool().maintain(
|
||||||
service.transaction_pool().maintain(
|
ChainEvent::NewBestBlock { hash: parent_header.hash(), tree_route: None },
|
||||||
ChainEvent::NewBestBlock {
|
));
|
||||||
hash: parent_header.hash(),
|
|
||||||
tree_route: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut proposer_factory = sc_basic_authorship::ProposerFactory::new(
|
let mut proposer_factory = sc_basic_authorship::ProposerFactory::new(
|
||||||
service.spawn_handle(),
|
service.spawn_handle(),
|
||||||
@@ -708,23 +694,30 @@ mod tests {
|
|||||||
// even though there's only one authority some slots might be empty,
|
// even though there's only one authority some slots might be empty,
|
||||||
// so we must keep trying the next slots until we can claim one.
|
// so we must keep trying the next slots until we can claim one.
|
||||||
let (babe_pre_digest, epoch_descriptor) = loop {
|
let (babe_pre_digest, epoch_descriptor) = loop {
|
||||||
let epoch_descriptor = babe_link.epoch_changes().shared_data().epoch_descriptor_for_child_of(
|
let epoch_descriptor = babe_link
|
||||||
descendent_query(&*service.client()),
|
.epoch_changes()
|
||||||
&parent_hash,
|
.shared_data()
|
||||||
parent_number,
|
.epoch_descriptor_for_child_of(
|
||||||
slot.into(),
|
descendent_query(&*service.client()),
|
||||||
).unwrap().unwrap();
|
&parent_hash,
|
||||||
|
parent_number,
|
||||||
|
slot.into(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let epoch = babe_link.epoch_changes().shared_data().epoch_data(
|
let epoch = babe_link
|
||||||
&epoch_descriptor,
|
.epoch_changes()
|
||||||
|slot| sc_consensus_babe::Epoch::genesis(&babe_link.config(), slot),
|
.shared_data()
|
||||||
).unwrap();
|
.epoch_data(&epoch_descriptor, |slot| {
|
||||||
|
sc_consensus_babe::Epoch::genesis(&babe_link.config(), slot)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
if let Some(babe_pre_digest) = sc_consensus_babe::authorship::claim_slot(
|
if let Some(babe_pre_digest) =
|
||||||
slot.into(),
|
sc_consensus_babe::authorship::claim_slot(slot.into(), &epoch, &keystore)
|
||||||
&epoch,
|
.map(|(digest, _)| digest)
|
||||||
&keystore,
|
{
|
||||||
).map(|(digest, _)| digest) {
|
|
||||||
break (babe_pre_digest, epoch_descriptor)
|
break (babe_pre_digest, epoch_descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,19 +729,21 @@ mod tests {
|
|||||||
std::time::Duration::from_millis(SLOT_DURATION * slot).into(),
|
std::time::Duration::from_millis(SLOT_DURATION * slot).into(),
|
||||||
),
|
),
|
||||||
sp_consensus_babe::inherents::InherentDataProvider::new(slot.into()),
|
sp_consensus_babe::inherents::InherentDataProvider::new(slot.into()),
|
||||||
).create_inherent_data().expect("Creates inherent data");
|
)
|
||||||
|
.create_inherent_data()
|
||||||
|
.expect("Creates inherent data");
|
||||||
|
|
||||||
digest.push(<DigestItem as CompatibleDigestItem>::babe_pre_digest(babe_pre_digest));
|
digest.push(<DigestItem as CompatibleDigestItem>::babe_pre_digest(babe_pre_digest));
|
||||||
|
|
||||||
let new_block = futures::executor::block_on(async move {
|
let new_block = futures::executor::block_on(async move {
|
||||||
let proposer = proposer_factory.init(&parent_header).await;
|
let proposer = proposer_factory.init(&parent_header).await;
|
||||||
proposer.unwrap().propose(
|
proposer
|
||||||
inherent_data,
|
.unwrap()
|
||||||
digest,
|
.propose(inherent_data, digest, std::time::Duration::from_secs(1), None)
|
||||||
std::time::Duration::from_secs(1),
|
.await
|
||||||
None,
|
})
|
||||||
).await
|
.expect("Error making test block")
|
||||||
}).expect("Error making test block").block;
|
.block;
|
||||||
|
|
||||||
let (new_header, new_body) = new_block.deconstruct();
|
let (new_header, new_body) = new_block.deconstruct();
|
||||||
let pre_hash = new_header.hash();
|
let pre_hash = new_header.hash();
|
||||||
@@ -760,10 +755,12 @@ mod tests {
|
|||||||
sp_consensus_babe::AuthorityId::ID,
|
sp_consensus_babe::AuthorityId::ID,
|
||||||
&alice.to_public_crypto_pair(),
|
&alice.to_public_crypto_pair(),
|
||||||
&to_sign,
|
&to_sign,
|
||||||
).unwrap().unwrap().try_into().unwrap();
|
)
|
||||||
let item = <DigestItem as CompatibleDigestItem>::babe_seal(
|
.unwrap()
|
||||||
signature,
|
.unwrap()
|
||||||
);
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
let item = <DigestItem as CompatibleDigestItem>::babe_seal(signature);
|
||||||
slot += 1;
|
slot += 1;
|
||||||
|
|
||||||
let mut params = BlockImportParams::new(BlockOrigin::File, new_header);
|
let mut params = BlockImportParams::new(BlockOrigin::File, new_header);
|
||||||
@@ -811,19 +808,13 @@ mod tests {
|
|||||||
let raw_payload = SignedPayload::from_raw(
|
let raw_payload = SignedPayload::from_raw(
|
||||||
function,
|
function,
|
||||||
extra,
|
extra,
|
||||||
(spec_version, transaction_version, genesis_hash, genesis_hash, (), (), ())
|
(spec_version, transaction_version, genesis_hash, genesis_hash, (), (), ()),
|
||||||
);
|
);
|
||||||
let signature = raw_payload.using_encoded(|payload| {
|
let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
|
||||||
signer.sign(payload)
|
|
||||||
});
|
|
||||||
let (function, extra, _) = raw_payload.deconstruct();
|
let (function, extra, _) = raw_payload.deconstruct();
|
||||||
index += 1;
|
index += 1;
|
||||||
UncheckedExtrinsic::new_signed(
|
UncheckedExtrinsic::new_signed(function, from.into(), signature.into(), extra)
|
||||||
function,
|
.into()
|
||||||
from.into(),
|
|
||||||
signature.into(),
|
|
||||||
extra,
|
|
||||||
).into()
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -834,18 +825,25 @@ mod tests {
|
|||||||
sc_service_test::consensus(
|
sc_service_test::consensus(
|
||||||
crate::chain_spec::tests::integration_test_config_with_two_authorities(),
|
crate::chain_spec::tests::integration_test_config_with_two_authorities(),
|
||||||
|config| {
|
|config| {
|
||||||
let NewFullBase { task_manager, client, network, transaction_pool, .. }
|
let NewFullBase { task_manager, client, network, transaction_pool, .. } =
|
||||||
= new_full_base(config,|_, _| ())?;
|
new_full_base(config, |_, _| ())?;
|
||||||
Ok(sc_service_test::TestNetComponents::new(task_manager, client, network, transaction_pool))
|
Ok(sc_service_test::TestNetComponents::new(
|
||||||
|
task_manager,
|
||||||
|
client,
|
||||||
|
network,
|
||||||
|
transaction_pool,
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|config| {
|
|config| {
|
||||||
let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?;
|
let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?;
|
||||||
Ok(sc_service_test::TestNetComponents::new(keep_alive, client, network, transaction_pool))
|
Ok(sc_service_test::TestNetComponents::new(
|
||||||
|
keep_alive,
|
||||||
|
client,
|
||||||
|
network,
|
||||||
|
transaction_pool,
|
||||||
|
))
|
||||||
},
|
},
|
||||||
vec![
|
vec!["//Alice".into(), "//Bob".into()],
|
||||||
"//Alice".into(),
|
|
||||||
"//Bob".into(),
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,18 @@
|
|||||||
|
|
||||||
#![cfg(unix)]
|
#![cfg(unix)]
|
||||||
|
|
||||||
use std::{process::{Child, ExitStatus}, thread, time::Duration, path::Path};
|
|
||||||
use assert_cmd::cargo::cargo_bin;
|
use assert_cmd::cargo::cargo_bin;
|
||||||
use std::{convert::TryInto, process::Command};
|
use nix::{
|
||||||
use nix::sys::signal::{kill, Signal::SIGINT};
|
sys::signal::{kill, Signal::SIGINT},
|
||||||
use nix::unistd::Pid;
|
unistd::Pid,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
convert::TryInto,
|
||||||
|
path::Path,
|
||||||
|
process::{Child, Command, ExitStatus},
|
||||||
|
thread,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
/// Wait for the given `child` the given number of `secs`.
|
/// Wait for the given `child` the given number of `secs`.
|
||||||
///
|
///
|
||||||
@@ -50,12 +57,7 @@ pub fn wait_for(child: &mut Child, secs: usize) -> Option<ExitStatus> {
|
|||||||
pub fn run_dev_node_for_a_while(base_path: &Path) {
|
pub fn run_dev_node_for_a_while(base_path: &Path) {
|
||||||
let mut cmd = Command::new(cargo_bin("substrate"));
|
let mut cmd = Command::new(cargo_bin("substrate"));
|
||||||
|
|
||||||
let mut cmd = cmd
|
let mut cmd = cmd.args(&["--dev"]).arg("-d").arg(base_path).spawn().unwrap();
|
||||||
.args(&["--dev"])
|
|
||||||
.arg("-d")
|
|
||||||
.arg(base_path)
|
|
||||||
.spawn()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Let it produce some blocks.
|
// Let it produce some blocks.
|
||||||
thread::sleep(Duration::from_secs(30));
|
thread::sleep(Duration::from_secs(30));
|
||||||
|
|||||||
@@ -19,9 +19,9 @@
|
|||||||
#![cfg(unix)]
|
#![cfg(unix)]
|
||||||
|
|
||||||
use assert_cmd::cargo::cargo_bin;
|
use assert_cmd::cargo::cargo_bin;
|
||||||
use std::{process::Command, fs, path::PathBuf};
|
|
||||||
use tempfile::{tempdir, TempDir};
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use std::{fs, path::PathBuf, process::Command};
|
||||||
|
use tempfile::{tempdir, TempDir};
|
||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
|
||||||
@@ -63,26 +63,23 @@ impl<'a> ExportImportRevertExecutor<'a> {
|
|||||||
fn new(
|
fn new(
|
||||||
base_path: &'a TempDir,
|
base_path: &'a TempDir,
|
||||||
exported_blocks_file: &'a PathBuf,
|
exported_blocks_file: &'a PathBuf,
|
||||||
db_path: &'a PathBuf
|
db_path: &'a PathBuf,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self { base_path, exported_blocks_file, db_path, num_exported_blocks: None }
|
||||||
base_path,
|
|
||||||
exported_blocks_file,
|
|
||||||
db_path,
|
|
||||||
num_exported_blocks: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper method to run a command. Returns a string corresponding to what has been logged.
|
/// Helper method to run a command. Returns a string corresponding to what has been logged.
|
||||||
fn run_block_command(&self,
|
fn run_block_command(
|
||||||
|
&self,
|
||||||
sub_command: SubCommand,
|
sub_command: SubCommand,
|
||||||
format_opt: FormatOpt,
|
format_opt: FormatOpt,
|
||||||
expected_to_fail: bool
|
expected_to_fail: bool,
|
||||||
) -> String {
|
) -> String {
|
||||||
let sub_command_str = sub_command.to_string();
|
let sub_command_str = sub_command.to_string();
|
||||||
// Adding "--binary" if need be.
|
// Adding "--binary" if need be.
|
||||||
let arguments: Vec<&str> = match format_opt {
|
let arguments: Vec<&str> = match format_opt {
|
||||||
FormatOpt::Binary => vec![&sub_command_str, "--dev", "--pruning", "archive", "--binary", "-d"],
|
FormatOpt::Binary =>
|
||||||
|
vec![&sub_command_str, "--dev", "--pruning", "archive", "--binary", "-d"],
|
||||||
FormatOpt::Json => vec![&sub_command_str, "--dev", "--pruning", "archive", "-d"],
|
FormatOpt::Json => vec![&sub_command_str, "--dev", "--pruning", "archive", "-d"],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,7 +91,7 @@ impl<'a> ExportImportRevertExecutor<'a> {
|
|||||||
SubCommand::ImportBlocks => {
|
SubCommand::ImportBlocks => {
|
||||||
tmp = tempdir().unwrap();
|
tmp = tempdir().unwrap();
|
||||||
tmp.path()
|
tmp.path()
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Running the command and capturing the output.
|
// Running the command and capturing the output.
|
||||||
@@ -144,16 +141,13 @@ impl<'a> ExportImportRevertExecutor<'a> {
|
|||||||
if !expected_to_fail {
|
if !expected_to_fail {
|
||||||
// Using regex to find out how much block we imported,
|
// Using regex to find out how much block we imported,
|
||||||
// and what's the best current block.
|
// and what's the best current block.
|
||||||
let re = Regex::new(r"Imported (?P<imported>\d*) blocks. Best: #(?P<best>\d*)").unwrap();
|
let re =
|
||||||
|
Regex::new(r"Imported (?P<imported>\d*) blocks. Best: #(?P<best>\d*)").unwrap();
|
||||||
let caps = re.captures(&log).expect("capture should have succeeded");
|
let caps = re.captures(&log).expect("capture should have succeeded");
|
||||||
let imported = caps["imported"].parse::<u64>().unwrap();
|
let imported = caps["imported"].parse::<u64>().unwrap();
|
||||||
let best = caps["best"].parse::<u64>().unwrap();
|
let best = caps["best"].parse::<u64>().unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(imported, best, "numbers of blocks imported and best number differs");
|
||||||
imported,
|
|
||||||
best,
|
|
||||||
"numbers of blocks imported and best number differs"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
best,
|
best,
|
||||||
self.num_exported_blocks.expect("number of exported blocks cannot be None; qed"),
|
self.num_exported_blocks.expect("number of exported blocks cannot be None; qed"),
|
||||||
@@ -195,11 +189,7 @@ fn export_import_revert() {
|
|||||||
|
|
||||||
common::run_dev_node_for_a_while(base_path.path());
|
common::run_dev_node_for_a_while(base_path.path());
|
||||||
|
|
||||||
let mut executor = ExportImportRevertExecutor::new(
|
let mut executor = ExportImportRevertExecutor::new(&base_path, &exported_blocks_file, &db_path);
|
||||||
&base_path,
|
|
||||||
&exported_blocks_file,
|
|
||||||
&db_path,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Binary and binary should work.
|
// Binary and binary should work.
|
||||||
executor.run(FormatOpt::Binary, FormatOpt::Binary, false);
|
executor.run(FormatOpt::Binary, FormatOpt::Binary, false);
|
||||||
|
|||||||
@@ -25,8 +25,13 @@ pub mod common;
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn running_the_node_works_and_can_be_interrupted() {
|
fn running_the_node_works_and_can_be_interrupted() {
|
||||||
use nix::sys::signal::{kill, Signal::{self, SIGINT, SIGTERM}};
|
use nix::{
|
||||||
use nix::unistd::Pid;
|
sys::signal::{
|
||||||
|
kill,
|
||||||
|
Signal::{self, SIGINT, SIGTERM},
|
||||||
|
},
|
||||||
|
unistd::Pid,
|
||||||
|
};
|
||||||
|
|
||||||
fn run_command_and_kill(signal: Signal) {
|
fn run_command_and_kill(signal: Signal) {
|
||||||
let base_path = tempdir().expect("could not create a temp dir");
|
let base_path = tempdir().expect("could not create a temp dir");
|
||||||
|
|||||||
@@ -17,10 +17,11 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use assert_cmd::cargo::cargo_bin;
|
use assert_cmd::cargo::cargo_bin;
|
||||||
use nix::sys::signal::{kill, Signal::SIGINT};
|
use nix::{
|
||||||
use nix::unistd::Pid;
|
sys::signal::{kill, Signal::SIGINT},
|
||||||
use std::convert::TryInto;
|
unistd::Pid,
|
||||||
use std::process;
|
};
|
||||||
|
use std::{convert::TryInto, process};
|
||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
pub mod websocket_server;
|
pub mod websocket_server;
|
||||||
@@ -45,27 +46,22 @@ async fn telemetry_works() {
|
|||||||
Event::ConnectionOpen { address } => {
|
Event::ConnectionOpen { address } => {
|
||||||
println!("New connection from {:?}", address);
|
println!("New connection from {:?}", address);
|
||||||
server.accept();
|
server.accept();
|
||||||
}
|
},
|
||||||
|
|
||||||
// Received a message from a connection.
|
// Received a message from a connection.
|
||||||
Event::BinaryFrame { message, .. } => {
|
Event::BinaryFrame { message, .. } => {
|
||||||
let json: serde_json::Value = serde_json::from_slice(&message).unwrap();
|
let json: serde_json::Value = serde_json::from_slice(&message).unwrap();
|
||||||
let object = json
|
let object =
|
||||||
.as_object()
|
json.as_object().unwrap().get("payload").unwrap().as_object().unwrap();
|
||||||
.unwrap()
|
|
||||||
.get("payload")
|
|
||||||
.unwrap()
|
|
||||||
.as_object()
|
|
||||||
.unwrap();
|
|
||||||
if matches!(object.get("best"), Some(serde_json::Value::String(_))) {
|
if matches!(object.get("best"), Some(serde_json::Value::String(_))) {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
Event::TextFrame { .. } => panic!("Got a TextFrame over the socket, this is a bug"),
|
Event::TextFrame { .. } => panic!("Got a TextFrame over the socket, this is a bug"),
|
||||||
|
|
||||||
// Connection has been closed.
|
// Connection has been closed.
|
||||||
Event::ConnectionError { .. } => {}
|
Event::ConnectionError { .. } => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -83,16 +79,11 @@ async fn telemetry_works() {
|
|||||||
|
|
||||||
server_task.await;
|
server_task.await;
|
||||||
|
|
||||||
assert!(
|
assert!(substrate.try_wait().unwrap().is_none(), "the process should still be running");
|
||||||
substrate.try_wait().unwrap().is_none(),
|
|
||||||
"the process should still be running"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Stop the process
|
// Stop the process
|
||||||
kill(Pid::from_raw(substrate.id().try_into().unwrap()), SIGINT).unwrap();
|
kill(Pid::from_raw(substrate.id().try_into().unwrap()), SIGINT).unwrap();
|
||||||
assert!(common::wait_for(&mut substrate, 40)
|
assert!(common::wait_for(&mut substrate, 40).map(|x| x.success()).unwrap_or_default());
|
||||||
.map(|x| x.success())
|
|
||||||
.unwrap_or_default());
|
|
||||||
|
|
||||||
let output = substrate.wait_with_output().unwrap();
|
let output = substrate.wait_with_output().unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -19,15 +19,19 @@
|
|||||||
#![cfg(unix)]
|
#![cfg(unix)]
|
||||||
|
|
||||||
use assert_cmd::cargo::cargo_bin;
|
use assert_cmd::cargo::cargo_bin;
|
||||||
use nix::sys::signal::{kill, Signal::SIGINT};
|
use nix::{
|
||||||
use nix::unistd::Pid;
|
sys::signal::{kill, Signal::SIGINT},
|
||||||
|
unistd::Pid,
|
||||||
|
};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::convert::TryInto;
|
use std::{
|
||||||
use std::io::Read;
|
convert::TryInto,
|
||||||
use std::path::PathBuf;
|
io::Read,
|
||||||
use std::process::{Command, Stdio};
|
path::PathBuf,
|
||||||
use std::thread;
|
process::{Command, Stdio},
|
||||||
use std::time::Duration;
|
thread,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
|
||||||
@@ -44,29 +48,18 @@ fn temp_base_path_works() {
|
|||||||
|
|
||||||
// Let it produce some blocks.
|
// Let it produce some blocks.
|
||||||
thread::sleep(Duration::from_secs(30));
|
thread::sleep(Duration::from_secs(30));
|
||||||
assert!(
|
assert!(cmd.try_wait().unwrap().is_none(), "the process should still be running");
|
||||||
cmd.try_wait().unwrap().is_none(),
|
|
||||||
"the process should still be running"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Stop the process
|
// Stop the process
|
||||||
kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap();
|
kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap();
|
||||||
assert!(common::wait_for(&mut cmd, 40)
|
assert!(common::wait_for(&mut cmd, 40).map(|x| x.success()).unwrap_or_default());
|
||||||
.map(|x| x.success())
|
|
||||||
.unwrap_or_default());
|
|
||||||
|
|
||||||
// Ensure the database has been deleted
|
// Ensure the database has been deleted
|
||||||
let mut stderr = String::new();
|
let mut stderr = String::new();
|
||||||
cmd.stderr.unwrap().read_to_string(&mut stderr).unwrap();
|
cmd.stderr.unwrap().read_to_string(&mut stderr).unwrap();
|
||||||
let re = Regex::new(r"Database: .+ at (\S+)").unwrap();
|
let re = Regex::new(r"Database: .+ at (\S+)").unwrap();
|
||||||
let db_path = PathBuf::from(
|
let db_path =
|
||||||
re.captures(stderr.as_str())
|
PathBuf::from(re.captures(stderr.as_str()).unwrap().get(1).unwrap().as_str().to_string());
|
||||||
.unwrap()
|
|
||||||
.get(1)
|
|
||||||
.unwrap()
|
|
||||||
.as_str()
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(!db_path.exists());
|
assert!(!db_path.exists());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,61 +22,45 @@ use regex::Regex;
|
|||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
fn expected_regex() -> Regex {
|
fn expected_regex() -> Regex {
|
||||||
Regex::new(r"^substrate (\d+\.\d+\.\d+(?:-.+?)?)-([a-f\d]+|unknown)-(.+?)-(.+?)(?:-(.+))?$").unwrap()
|
Regex::new(r"^substrate (\d+\.\d+\.\d+(?:-.+?)?)-([a-f\d]+|unknown)-(.+?)-(.+?)(?:-(.+))?$")
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn version_is_full() {
|
fn version_is_full() {
|
||||||
let expected = expected_regex();
|
let expected = expected_regex();
|
||||||
let output = Command::new(cargo_bin("substrate"))
|
let output = Command::new(cargo_bin("substrate")).args(&["--version"]).output().unwrap();
|
||||||
.args(&["--version"])
|
|
||||||
.output()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert!(
|
assert!(output.status.success(), "command returned with non-success exit code");
|
||||||
output.status.success(),
|
|
||||||
"command returned with non-success exit code"
|
|
||||||
);
|
|
||||||
|
|
||||||
let output = String::from_utf8_lossy(&output.stdout).trim().to_owned();
|
let output = String::from_utf8_lossy(&output.stdout).trim().to_owned();
|
||||||
let captures = expected
|
let captures = expected.captures(output.as_str()).expect("could not parse version in output");
|
||||||
.captures(output.as_str())
|
|
||||||
.expect("could not parse version in output");
|
|
||||||
|
|
||||||
assert_eq!(&captures[1], env!("CARGO_PKG_VERSION"));
|
assert_eq!(&captures[1], env!("CARGO_PKG_VERSION"));
|
||||||
assert_eq!(&captures[3], TARGET_ARCH.as_str());
|
assert_eq!(&captures[3], TARGET_ARCH.as_str());
|
||||||
assert_eq!(&captures[4], TARGET_OS.as_str());
|
assert_eq!(&captures[4], TARGET_OS.as_str());
|
||||||
assert_eq!(
|
assert_eq!(captures.get(5).map(|x| x.as_str()), TARGET_ENV.map(|x| x.as_str()));
|
||||||
captures.get(5).map(|x| x.as_str()),
|
|
||||||
TARGET_ENV.map(|x| x.as_str())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_regex_matches_properly() {
|
fn test_regex_matches_properly() {
|
||||||
let expected = expected_regex();
|
let expected = expected_regex();
|
||||||
|
|
||||||
let captures = expected
|
let captures = expected.captures("substrate 2.0.0-da487d19d-x86_64-linux-gnu").unwrap();
|
||||||
.captures("substrate 2.0.0-da487d19d-x86_64-linux-gnu")
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(&captures[1], "2.0.0");
|
assert_eq!(&captures[1], "2.0.0");
|
||||||
assert_eq!(&captures[2], "da487d19d");
|
assert_eq!(&captures[2], "da487d19d");
|
||||||
assert_eq!(&captures[3], "x86_64");
|
assert_eq!(&captures[3], "x86_64");
|
||||||
assert_eq!(&captures[4], "linux");
|
assert_eq!(&captures[4], "linux");
|
||||||
assert_eq!(captures.get(5).map(|x| x.as_str()), Some("gnu"));
|
assert_eq!(captures.get(5).map(|x| x.as_str()), Some("gnu"));
|
||||||
|
|
||||||
let captures = expected
|
let captures = expected.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux-gnu").unwrap();
|
||||||
.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux-gnu")
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(&captures[1], "2.0.0-alpha.5");
|
assert_eq!(&captures[1], "2.0.0-alpha.5");
|
||||||
assert_eq!(&captures[2], "da487d19d");
|
assert_eq!(&captures[2], "da487d19d");
|
||||||
assert_eq!(&captures[3], "x86_64");
|
assert_eq!(&captures[3], "x86_64");
|
||||||
assert_eq!(&captures[4], "linux");
|
assert_eq!(&captures[4], "linux");
|
||||||
assert_eq!(captures.get(5).map(|x| x.as_str()), Some("gnu"));
|
assert_eq!(captures.get(5).map(|x| x.as_str()), Some("gnu"));
|
||||||
|
|
||||||
let captures = expected
|
let captures = expected.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux").unwrap();
|
||||||
.captures("substrate 2.0.0-alpha.5-da487d19d-x86_64-linux")
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(&captures[1], "2.0.0-alpha.5");
|
assert_eq!(&captures[1], "2.0.0-alpha.5");
|
||||||
assert_eq!(&captures[2], "da487d19d");
|
assert_eq!(&captures[2], "da487d19d");
|
||||||
assert_eq!(&captures[3], "x86_64");
|
assert_eq!(&captures[3], "x86_64");
|
||||||
|
|||||||
@@ -116,7 +116,6 @@ impl WsServer {
|
|||||||
/// # Panic
|
/// # Panic
|
||||||
///
|
///
|
||||||
/// Panics if no connection is pending.
|
/// Panics if no connection is pending.
|
||||||
///
|
|
||||||
pub fn accept(&mut self) {
|
pub fn accept(&mut self) {
|
||||||
let pending_incoming = self.pending_incoming.take().expect("no pending socket");
|
let pending_incoming = self.pending_incoming.take().expect("no pending socket");
|
||||||
|
|
||||||
@@ -129,15 +128,10 @@ impl WsServer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match server
|
match server
|
||||||
.send_response(&{
|
.send_response(&{ Response::Accept { key: &websocket_key, protocol: None } })
|
||||||
Response::Accept {
|
|
||||||
key: &websocket_key,
|
|
||||||
protocol: None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(()) => {}
|
Ok(()) => {},
|
||||||
Err(err) => return Err(Box::new(err) as Box<_>),
|
Err(err) => return Err(Box::new(err) as Box<_>),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -153,7 +147,6 @@ impl WsServer {
|
|||||||
/// # Panic
|
/// # Panic
|
||||||
///
|
///
|
||||||
/// Panics if no connection is pending.
|
/// Panics if no connection is pending.
|
||||||
///
|
|
||||||
pub fn reject(&mut self) {
|
pub fn reject(&mut self) {
|
||||||
let _ = self.pending_incoming.take().expect("no pending socket");
|
let _ = self.pending_incoming.take().expect("no pending socket");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,29 +16,33 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
|
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
|
||||||
|
use frame_support::Hashable;
|
||||||
use node_executor::Executor;
|
use node_executor::Executor;
|
||||||
use node_primitives::{BlockNumber, Hash};
|
use node_primitives::{BlockNumber, Hash};
|
||||||
use node_runtime::{
|
use node_runtime::{
|
||||||
Block, BuildStorage, Call, CheckedExtrinsic, GenesisConfig, Header, UncheckedExtrinsic,
|
constants::currency::*, Block, BuildStorage, Call, CheckedExtrinsic, GenesisConfig, Header,
|
||||||
|
UncheckedExtrinsic,
|
||||||
};
|
};
|
||||||
use node_runtime::constants::currency::*;
|
|
||||||
use node_testing::keyring::*;
|
use node_testing::keyring::*;
|
||||||
use sp_core::{NativeOrEncoded, NeverNativeValue};
|
use sc_executor::{Externalities, NativeExecutor, RuntimeInfo, WasmExecutionMethod};
|
||||||
use sp_core::storage::well_known_keys;
|
use sp_core::{
|
||||||
use sp_core::traits::{CodeExecutor, RuntimeCode};
|
storage::well_known_keys,
|
||||||
use frame_support::Hashable;
|
traits::{CodeExecutor, RuntimeCode},
|
||||||
use sp_state_machine::TestExternalities as CoreTestExternalities;
|
NativeOrEncoded, NeverNativeValue,
|
||||||
use sc_executor::{NativeExecutor, RuntimeInfo, WasmExecutionMethod, Externalities};
|
};
|
||||||
use sp_runtime::traits::BlakeTwo256;
|
use sp_runtime::traits::BlakeTwo256;
|
||||||
|
use sp_state_machine::TestExternalities as CoreTestExternalities;
|
||||||
|
|
||||||
criterion_group!(benches, bench_execute_block);
|
criterion_group!(benches, bench_execute_block);
|
||||||
criterion_main!(benches);
|
criterion_main!(benches);
|
||||||
|
|
||||||
/// The wasm runtime code.
|
/// The wasm runtime code.
|
||||||
pub fn compact_code_unwrap() -> &'static [u8] {
|
pub fn compact_code_unwrap() -> &'static [u8] {
|
||||||
node_runtime::WASM_BINARY.expect("Development wasm binary is not available. \
|
node_runtime::WASM_BINARY.expect(
|
||||||
Testing is only supported with the flag disabled.")
|
"Development wasm binary is not available. \
|
||||||
|
Testing is only supported with the flag disabled.",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const GENESIS_HASH: [u8; 32] = [69u8; 32];
|
const GENESIS_HASH: [u8; 32] = [69u8; 32];
|
||||||
@@ -66,7 +70,9 @@ fn new_test_ext(genesis_config: &GenesisConfig) -> TestExternalities<BlakeTwo256
|
|||||||
compact_code_unwrap(),
|
compact_code_unwrap(),
|
||||||
genesis_config.build_storage().unwrap(),
|
genesis_config.build_storage().unwrap(),
|
||||||
);
|
);
|
||||||
test_ext.ext().place_storage(well_known_keys::HEAP_PAGES.to_vec(), Some(HEAP_PAGES.encode()));
|
test_ext
|
||||||
|
.ext()
|
||||||
|
.place_storage(well_known_keys::HEAP_PAGES.to_vec(), Some(HEAP_PAGES.encode()));
|
||||||
test_ext
|
test_ext
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,16 +83,16 @@ fn construct_block<E: Externalities>(
|
|||||||
parent_hash: Hash,
|
parent_hash: Hash,
|
||||||
extrinsics: Vec<CheckedExtrinsic>,
|
extrinsics: Vec<CheckedExtrinsic>,
|
||||||
) -> (Vec<u8>, Hash) {
|
) -> (Vec<u8>, Hash) {
|
||||||
use sp_trie::{TrieConfiguration, trie_types::Layout};
|
use sp_trie::{trie_types::Layout, TrieConfiguration};
|
||||||
|
|
||||||
// sign extrinsics.
|
// sign extrinsics.
|
||||||
let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>();
|
let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>();
|
||||||
|
|
||||||
// calculate the header fields that we can.
|
// calculate the header fields that we can.
|
||||||
let extrinsics_root = Layout::<BlakeTwo256>::ordered_trie_root(
|
let extrinsics_root =
|
||||||
extrinsics.iter().map(Encode::encode)
|
Layout::<BlakeTwo256>::ordered_trie_root(extrinsics.iter().map(Encode::encode))
|
||||||
).to_fixed_bytes()
|
.to_fixed_bytes()
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let header = Header {
|
let header = Header {
|
||||||
parent_hash,
|
parent_hash,
|
||||||
@@ -103,34 +109,44 @@ fn construct_block<E: Externalities>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// execute the block to get the real header.
|
// execute the block to get the real header.
|
||||||
executor.call::<NeverNativeValue, fn() -> _>(
|
executor
|
||||||
ext,
|
.call::<NeverNativeValue, fn() -> _>(
|
||||||
&runtime_code,
|
|
||||||
"Core_initialize_block",
|
|
||||||
&header.encode(),
|
|
||||||
true,
|
|
||||||
None,
|
|
||||||
).0.unwrap();
|
|
||||||
|
|
||||||
for i in extrinsics.iter() {
|
|
||||||
executor.call::<NeverNativeValue, fn() -> _>(
|
|
||||||
ext,
|
ext,
|
||||||
&runtime_code,
|
&runtime_code,
|
||||||
"BlockBuilder_apply_extrinsic",
|
"Core_initialize_block",
|
||||||
&i.encode(),
|
&header.encode(),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
for i in extrinsics.iter() {
|
||||||
|
executor
|
||||||
|
.call::<NeverNativeValue, fn() -> _>(
|
||||||
|
ext,
|
||||||
|
&runtime_code,
|
||||||
|
"BlockBuilder_apply_extrinsic",
|
||||||
|
&i.encode(),
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let header = match executor.call::<NeverNativeValue, fn() -> _>(
|
let header = match executor
|
||||||
ext,
|
.call::<NeverNativeValue, fn() -> _>(
|
||||||
&runtime_code,
|
ext,
|
||||||
"BlockBuilder_finalize_block",
|
&runtime_code,
|
||||||
&[0u8;0],
|
"BlockBuilder_finalize_block",
|
||||||
true,
|
&[0u8; 0],
|
||||||
None,
|
true,
|
||||||
).0.unwrap() {
|
None,
|
||||||
|
)
|
||||||
|
.0
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
NativeOrEncoded::Native(_) => unreachable!(),
|
NativeOrEncoded::Native(_) => unreachable!(),
|
||||||
NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(),
|
NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(),
|
||||||
};
|
};
|
||||||
@@ -139,29 +155,21 @@ fn construct_block<E: Externalities>(
|
|||||||
(Block { header, extrinsics }.encode(), hash.into())
|
(Block { header, extrinsics }.encode(), hash.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_blocks(genesis_config: &GenesisConfig, executor: &NativeExecutor<Executor>)
|
fn test_blocks(
|
||||||
-> Vec<(Vec<u8>, Hash)>
|
genesis_config: &GenesisConfig,
|
||||||
{
|
executor: &NativeExecutor<Executor>,
|
||||||
|
) -> Vec<(Vec<u8>, Hash)> {
|
||||||
let mut test_ext = new_test_ext(genesis_config);
|
let mut test_ext = new_test_ext(genesis_config);
|
||||||
let mut block1_extrinsics = vec![
|
let mut block1_extrinsics = vec![CheckedExtrinsic {
|
||||||
CheckedExtrinsic {
|
signed: None,
|
||||||
signed: None,
|
function: Call::Timestamp(pallet_timestamp::Call::set(0)),
|
||||||
function: Call::Timestamp(pallet_timestamp::Call::set(0)),
|
}];
|
||||||
},
|
block1_extrinsics.extend((0..20).map(|i| CheckedExtrinsic {
|
||||||
];
|
signed: Some((alice(), signed_extra(i, 0))),
|
||||||
block1_extrinsics.extend((0..20).map(|i| {
|
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 1 * DOLLARS)),
|
||||||
CheckedExtrinsic {
|
|
||||||
signed: Some((alice(), signed_extra(i, 0))),
|
|
||||||
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 1 * DOLLARS)),
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
let block1 = construct_block(
|
let block1 =
|
||||||
executor,
|
construct_block(executor, &mut test_ext.ext(), 1, GENESIS_HASH.into(), block1_extrinsics);
|
||||||
&mut test_ext.ext(),
|
|
||||||
1,
|
|
||||||
GENESIS_HASH.into(),
|
|
||||||
block1_extrinsics,
|
|
||||||
);
|
|
||||||
|
|
||||||
vec![block1]
|
vec![block1]
|
||||||
}
|
}
|
||||||
@@ -176,47 +184,47 @@ fn bench_execute_block(c: &mut Criterion) {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for strategy in execution_methods {
|
for strategy in execution_methods {
|
||||||
group.bench_function(
|
group.bench_function(format!("{:?}", strategy), |b| {
|
||||||
format!("{:?}", strategy),
|
let genesis_config = node_testing::genesis::config(false, Some(compact_code_unwrap()));
|
||||||
|b| {
|
let (use_native, wasm_method) = match strategy {
|
||||||
let genesis_config = node_testing::genesis::config(false, Some(compact_code_unwrap()));
|
ExecutionMethod::Native => (true, WasmExecutionMethod::Interpreted),
|
||||||
let (use_native, wasm_method) = match strategy {
|
ExecutionMethod::Wasm(wasm_method) => (false, wasm_method),
|
||||||
ExecutionMethod::Native => (true, WasmExecutionMethod::Interpreted),
|
};
|
||||||
ExecutionMethod::Wasm(wasm_method) => (false, wasm_method),
|
|
||||||
};
|
|
||||||
|
|
||||||
let executor = NativeExecutor::new(wasm_method, None, 8);
|
let executor = NativeExecutor::new(wasm_method, None, 8);
|
||||||
let runtime_code = RuntimeCode {
|
let runtime_code = RuntimeCode {
|
||||||
code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()),
|
code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()),
|
||||||
hash: vec![1, 2, 3],
|
hash: vec![1, 2, 3],
|
||||||
heap_pages: None,
|
heap_pages: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the runtime version to initialize the runtimes cache.
|
// Get the runtime version to initialize the runtimes cache.
|
||||||
{
|
{
|
||||||
let mut test_ext = new_test_ext(&genesis_config);
|
let mut test_ext = new_test_ext(&genesis_config);
|
||||||
executor.runtime_version(&mut test_ext.ext(), &runtime_code).unwrap();
|
executor.runtime_version(&mut test_ext.ext(), &runtime_code).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let blocks = test_blocks(&genesis_config, &executor);
|
let blocks = test_blocks(&genesis_config, &executor);
|
||||||
|
|
||||||
b.iter_batched_ref(
|
b.iter_batched_ref(
|
||||||
|| new_test_ext(&genesis_config),
|
|| new_test_ext(&genesis_config),
|
||||||
|test_ext| {
|
|test_ext| {
|
||||||
for block in blocks.iter() {
|
for block in blocks.iter() {
|
||||||
executor.call::<NeverNativeValue, fn() -> _>(
|
executor
|
||||||
|
.call::<NeverNativeValue, fn() -> _>(
|
||||||
&mut test_ext.ext(),
|
&mut test_ext.ext(),
|
||||||
&runtime_code,
|
&runtime_code,
|
||||||
"Core_execute_block",
|
"Core_execute_block",
|
||||||
&block.0,
|
&block.0,
|
||||||
use_native,
|
use_native,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
}
|
.0
|
||||||
},
|
.unwrap();
|
||||||
BatchSize::LargeInput,
|
}
|
||||||
);
|
},
|
||||||
},
|
BatchSize::LargeInput,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
//! A `CodeExecutor` specialization which uses natively compiled runtime when the wasm to be
|
//! A `CodeExecutor` specialization which uses natively compiled runtime when the wasm to be
|
||||||
//! executed is equivalent to the natively compiled code.
|
//! executed is equivalent to the natively compiled code.
|
||||||
|
|
||||||
pub use sc_executor::NativeExecutor;
|
|
||||||
use sc_executor::native_executor_instance;
|
use sc_executor::native_executor_instance;
|
||||||
|
pub use sc_executor::NativeExecutor;
|
||||||
|
|
||||||
// Declare an instance of the native executor named `Executor`. Include the wasm binary as the
|
// Declare an instance of the native executor named `Executor`. Include the wasm binary as the
|
||||||
// equivalent wasm code.
|
// equivalent wasm code.
|
||||||
|
|||||||
@@ -15,30 +15,28 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use codec::{Encode, Decode, Joiner};
|
use codec::{Decode, Encode, Joiner};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
traits::Currency,
|
traits::Currency,
|
||||||
weights::{GetDispatchInfo, DispatchInfo, DispatchClass},
|
weights::{DispatchClass, DispatchInfo, GetDispatchInfo},
|
||||||
};
|
};
|
||||||
use sp_core::{NeverNativeValue, traits::Externalities, storage::well_known_keys};
|
use frame_system::{self, AccountInfo, EventRecord, Phase};
|
||||||
|
use sp_core::{storage::well_known_keys, traits::Externalities, NeverNativeValue};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
ApplyExtrinsicResult,
|
traits::Hash as HashT, transaction_validity::InvalidTransaction, ApplyExtrinsicResult,
|
||||||
traits::Hash as HashT,
|
|
||||||
transaction_validity::InvalidTransaction,
|
|
||||||
};
|
};
|
||||||
use frame_system::{self, EventRecord, Phase, AccountInfo};
|
|
||||||
|
|
||||||
use node_runtime::{
|
|
||||||
Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances,
|
|
||||||
System, TransactionPayment, Event,
|
|
||||||
constants::{time::SLOT_DURATION, currency::*},
|
|
||||||
};
|
|
||||||
use node_primitives::{Balance, Hash};
|
use node_primitives::{Balance, Hash};
|
||||||
use wat;
|
use node_runtime::{
|
||||||
|
constants::{currency::*, time::SLOT_DURATION},
|
||||||
|
Balances, Block, Call, CheckedExtrinsic, Event, Header, Runtime, System, TransactionPayment,
|
||||||
|
UncheckedExtrinsic,
|
||||||
|
};
|
||||||
use node_testing::keyring::*;
|
use node_testing::keyring::*;
|
||||||
|
use wat;
|
||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
use self::common::{*, sign};
|
use self::common::{sign, *};
|
||||||
|
|
||||||
/// The wasm runtime binary which hasn't undergone the compacting process.
|
/// The wasm runtime binary which hasn't undergone the compacting process.
|
||||||
///
|
///
|
||||||
@@ -46,8 +44,10 @@ use self::common::{*, sign};
|
|||||||
/// have to execute provided wasm code instead of the native equivalent. This trick is used to
|
/// have to execute provided wasm code instead of the native equivalent. This trick is used to
|
||||||
/// test code paths that differ between native and wasm versions.
|
/// test code paths that differ between native and wasm versions.
|
||||||
pub fn bloaty_code_unwrap() -> &'static [u8] {
|
pub fn bloaty_code_unwrap() -> &'static [u8] {
|
||||||
node_runtime::WASM_BINARY_BLOATY.expect("Development wasm binary is not available. \
|
node_runtime::WASM_BINARY_BLOATY.expect(
|
||||||
Testing is only supported with the flag disabled.")
|
"Development wasm binary is not available. \
|
||||||
|
Testing is only supported with the flag disabled.",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default transfer fee. This will use the same logic that is implemented in transaction-payment module.
|
/// Default transfer fee. This will use the same logic that is implemented in transaction-payment module.
|
||||||
@@ -87,7 +87,10 @@ fn changes_trie_block() -> (Vec<u8>, Hash) {
|
|||||||
},
|
},
|
||||||
CheckedExtrinsic {
|
CheckedExtrinsic {
|
||||||
signed: Some((alice(), signed_extra(0, 0))),
|
signed: Some((alice(), signed_extra(0, 0))),
|
||||||
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 69 * DOLLARS)),
|
function: Call::Balances(pallet_balances::Call::transfer(
|
||||||
|
bob().into(),
|
||||||
|
69 * DOLLARS,
|
||||||
|
)),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
(time / SLOT_DURATION).into(),
|
(time / SLOT_DURATION).into(),
|
||||||
@@ -111,7 +114,10 @@ fn blocks() -> ((Vec<u8>, Hash), (Vec<u8>, Hash)) {
|
|||||||
},
|
},
|
||||||
CheckedExtrinsic {
|
CheckedExtrinsic {
|
||||||
signed: Some((alice(), signed_extra(0, 0))),
|
signed: Some((alice(), signed_extra(0, 0))),
|
||||||
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 69 * DOLLARS)),
|
function: Call::Balances(pallet_balances::Call::transfer(
|
||||||
|
bob().into(),
|
||||||
|
69 * DOLLARS,
|
||||||
|
)),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
(time1 / SLOT_DURATION).into(),
|
(time1 / SLOT_DURATION).into(),
|
||||||
@@ -128,12 +134,18 @@ fn blocks() -> ((Vec<u8>, Hash), (Vec<u8>, Hash)) {
|
|||||||
},
|
},
|
||||||
CheckedExtrinsic {
|
CheckedExtrinsic {
|
||||||
signed: Some((bob(), signed_extra(0, 0))),
|
signed: Some((bob(), signed_extra(0, 0))),
|
||||||
function: Call::Balances(pallet_balances::Call::transfer(alice().into(), 5 * DOLLARS)),
|
function: Call::Balances(pallet_balances::Call::transfer(
|
||||||
|
alice().into(),
|
||||||
|
5 * DOLLARS,
|
||||||
|
)),
|
||||||
},
|
},
|
||||||
CheckedExtrinsic {
|
CheckedExtrinsic {
|
||||||
signed: Some((alice(), signed_extra(1, 0))),
|
signed: Some((alice(), signed_extra(1, 0))),
|
||||||
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 15 * DOLLARS)),
|
function: Call::Balances(pallet_balances::Call::transfer(
|
||||||
}
|
bob().into(),
|
||||||
|
15 * DOLLARS,
|
||||||
|
)),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
(time2 / SLOT_DURATION).into(),
|
(time2 / SLOT_DURATION).into(),
|
||||||
);
|
);
|
||||||
@@ -158,7 +170,7 @@ fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec<u8>, Hash) {
|
|||||||
CheckedExtrinsic {
|
CheckedExtrinsic {
|
||||||
signed: Some((alice(), signed_extra(nonce, 0))),
|
signed: Some((alice(), signed_extra(nonce, 0))),
|
||||||
function: Call::System(frame_system::Call::remark(vec![0; size])),
|
function: Call::System(frame_system::Call::remark(vec![0; size])),
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
(time * 1000 / SLOT_DURATION).into(),
|
(time * 1000 / SLOT_DURATION).into(),
|
||||||
)
|
)
|
||||||
@@ -169,7 +181,7 @@ fn panic_execution_with_foreign_code_gives_error() {
|
|||||||
let mut t = new_test_ext(bloaty_code_unwrap(), false);
|
let mut t = new_test_ext(bloaty_code_unwrap(), false);
|
||||||
t.insert(
|
t.insert(
|
||||||
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
||||||
(69u128, 0u32, 0u128, 0u128, 0u128).encode()
|
(69u128, 0u32, 0u128, 0u128, 0u128).encode(),
|
||||||
);
|
);
|
||||||
t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 69_u128.encode());
|
t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 69_u128.encode());
|
||||||
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
||||||
@@ -180,7 +192,8 @@ fn panic_execution_with_foreign_code_gives_error() {
|
|||||||
&vec![].and(&from_block_number(1u32)),
|
&vec![].and(&from_block_number(1u32)),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
let v = executor_call::<NeverNativeValue, fn() -> _>(
|
let v = executor_call::<NeverNativeValue, fn() -> _>(
|
||||||
&mut t,
|
&mut t,
|
||||||
@@ -188,7 +201,9 @@ fn panic_execution_with_foreign_code_gives_error() {
|
|||||||
&vec![].and(&xt()),
|
&vec![].and(&xt()),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap();
|
let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap();
|
||||||
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
|
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
|
||||||
}
|
}
|
||||||
@@ -198,7 +213,7 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() {
|
|||||||
let mut t = new_test_ext(compact_code_unwrap(), false);
|
let mut t = new_test_ext(compact_code_unwrap(), false);
|
||||||
t.insert(
|
t.insert(
|
||||||
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
||||||
(0u32, 0u32, 0u32, 69u128, 0u128, 0u128, 0u128).encode()
|
(0u32, 0u32, 0u32, 69u128, 0u128, 0u128, 0u128).encode(),
|
||||||
);
|
);
|
||||||
t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 69_u128.encode());
|
t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 69_u128.encode());
|
||||||
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
||||||
@@ -209,7 +224,8 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() {
|
|||||||
&vec![].and(&from_block_number(1u32)),
|
&vec![].and(&from_block_number(1u32)),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
let v = executor_call::<NeverNativeValue, fn() -> _>(
|
let v = executor_call::<NeverNativeValue, fn() -> _>(
|
||||||
&mut t,
|
&mut t,
|
||||||
@@ -217,7 +233,9 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() {
|
|||||||
&vec![].and(&xt()),
|
&vec![].and(&xt()),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap();
|
let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap();
|
||||||
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
|
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
|
||||||
}
|
}
|
||||||
@@ -229,19 +247,21 @@ fn successful_execution_with_native_equivalent_code_gives_ok() {
|
|||||||
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
||||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||||
data: (111 * DOLLARS, 0u128, 0u128, 0u128),
|
data: (111 * DOLLARS, 0u128, 0u128, 0u128),
|
||||||
.. Default::default()
|
..Default::default()
|
||||||
}.encode(),
|
}
|
||||||
|
.encode(),
|
||||||
);
|
);
|
||||||
t.insert(
|
t.insert(
|
||||||
<frame_system::Account<Runtime>>::hashed_key_for(bob()),
|
<frame_system::Account<Runtime>>::hashed_key_for(bob()),
|
||||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||||
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
|
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
|
||||||
.. Default::default()
|
..Default::default()
|
||||||
}.encode(),
|
}
|
||||||
|
.encode(),
|
||||||
);
|
);
|
||||||
t.insert(
|
t.insert(
|
||||||
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
|
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
|
||||||
(111 * DOLLARS).encode()
|
(111 * DOLLARS).encode(),
|
||||||
);
|
);
|
||||||
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
||||||
|
|
||||||
@@ -251,7 +271,8 @@ fn successful_execution_with_native_equivalent_code_gives_ok() {
|
|||||||
&vec![].and(&from_block_number(1u32)),
|
&vec![].and(&from_block_number(1u32)),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
|
|
||||||
let fees = t.execute_with(|| transfer_fee(&xt()));
|
let fees = t.execute_with(|| transfer_fee(&xt()));
|
||||||
@@ -262,7 +283,8 @@ fn successful_execution_with_native_equivalent_code_gives_ok() {
|
|||||||
&vec![].and(&xt()),
|
&vec![].and(&xt()),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
|
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
@@ -278,19 +300,21 @@ fn successful_execution_with_foreign_code_gives_ok() {
|
|||||||
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
||||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||||
data: (111 * DOLLARS, 0u128, 0u128, 0u128),
|
data: (111 * DOLLARS, 0u128, 0u128, 0u128),
|
||||||
.. Default::default()
|
..Default::default()
|
||||||
}.encode(),
|
}
|
||||||
|
.encode(),
|
||||||
);
|
);
|
||||||
t.insert(
|
t.insert(
|
||||||
<frame_system::Account<Runtime>>::hashed_key_for(bob()),
|
<frame_system::Account<Runtime>>::hashed_key_for(bob()),
|
||||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||||
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
|
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
|
||||||
.. Default::default()
|
..Default::default()
|
||||||
}.encode(),
|
}
|
||||||
|
.encode(),
|
||||||
);
|
);
|
||||||
t.insert(
|
t.insert(
|
||||||
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
|
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
|
||||||
(111 * DOLLARS).encode()
|
(111 * DOLLARS).encode(),
|
||||||
);
|
);
|
||||||
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
||||||
|
|
||||||
@@ -300,7 +324,8 @@ fn successful_execution_with_foreign_code_gives_ok() {
|
|||||||
&vec![].and(&from_block_number(1u32)),
|
&vec![].and(&from_block_number(1u32)),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
|
|
||||||
let fees = t.execute_with(|| transfer_fee(&xt()));
|
let fees = t.execute_with(|| transfer_fee(&xt()));
|
||||||
@@ -311,7 +336,8 @@ fn successful_execution_with_foreign_code_gives_ok() {
|
|||||||
&vec![].and(&xt()),
|
&vec![].and(&xt()),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
|
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
@@ -330,7 +356,9 @@ fn full_native_block_import_works() {
|
|||||||
let mut fees = t.execute_with(|| transfer_fee(&xt()));
|
let mut fees = t.execute_with(|| transfer_fee(&xt()));
|
||||||
|
|
||||||
let transfer_weight = default_transfer_call().get_dispatch_info().weight;
|
let transfer_weight = default_transfer_call().get_dispatch_info().weight;
|
||||||
let timestamp_weight = pallet_timestamp::Call::set::<Runtime>(Default::default()).get_dispatch_info().weight;
|
let timestamp_weight = pallet_timestamp::Call::set::<Runtime>(Default::default())
|
||||||
|
.get_dispatch_info()
|
||||||
|
.weight;
|
||||||
|
|
||||||
executor_call::<NeverNativeValue, fn() -> _>(
|
executor_call::<NeverNativeValue, fn() -> _>(
|
||||||
&mut t,
|
&mut t,
|
||||||
@@ -338,7 +366,9 @@ fn full_native_block_import_works() {
|
|||||||
&block1.0,
|
&block1.0,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
|
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
|
||||||
@@ -347,9 +377,11 @@ fn full_native_block_import_works() {
|
|||||||
let events = vec![
|
let events = vec![
|
||||||
EventRecord {
|
EventRecord {
|
||||||
phase: Phase::ApplyExtrinsic(0),
|
phase: Phase::ApplyExtrinsic(0),
|
||||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(
|
event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
|
||||||
DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, ..Default::default() }
|
weight: timestamp_weight,
|
||||||
)),
|
class: DispatchClass::Mandatory,
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
},
|
},
|
||||||
EventRecord {
|
EventRecord {
|
||||||
@@ -368,9 +400,10 @@ fn full_native_block_import_works() {
|
|||||||
},
|
},
|
||||||
EventRecord {
|
EventRecord {
|
||||||
phase: Phase::ApplyExtrinsic(1),
|
phase: Phase::ApplyExtrinsic(1),
|
||||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(
|
event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
|
||||||
DispatchInfo { weight: transfer_weight, ..Default::default() }
|
weight: transfer_weight,
|
||||||
)),
|
..Default::default()
|
||||||
|
})),
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -385,34 +418,33 @@ fn full_native_block_import_works() {
|
|||||||
&block2.0,
|
&block2.0,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Balances::total_balance(&alice()),
|
Balances::total_balance(&alice()),
|
||||||
alice_last_known_balance - 10 * DOLLARS - fees,
|
alice_last_known_balance - 10 * DOLLARS - fees,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - fees,);
|
||||||
Balances::total_balance(&bob()),
|
|
||||||
179 * DOLLARS - fees,
|
|
||||||
);
|
|
||||||
let events = vec![
|
let events = vec![
|
||||||
EventRecord {
|
EventRecord {
|
||||||
phase: Phase::ApplyExtrinsic(0),
|
phase: Phase::ApplyExtrinsic(0),
|
||||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(
|
event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
|
||||||
DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, ..Default::default() }
|
weight: timestamp_weight,
|
||||||
)),
|
class: DispatchClass::Mandatory,
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
},
|
},
|
||||||
EventRecord {
|
EventRecord {
|
||||||
phase: Phase::ApplyExtrinsic(1),
|
phase: Phase::ApplyExtrinsic(1),
|
||||||
event: Event::Balances(
|
event: Event::Balances(pallet_balances::Event::Transfer(
|
||||||
pallet_balances::Event::Transfer(
|
bob().into(),
|
||||||
bob().into(),
|
alice().into(),
|
||||||
alice().into(),
|
5 * DOLLARS,
|
||||||
5 * DOLLARS,
|
)),
|
||||||
)
|
|
||||||
),
|
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
},
|
},
|
||||||
EventRecord {
|
EventRecord {
|
||||||
@@ -422,20 +454,19 @@ fn full_native_block_import_works() {
|
|||||||
},
|
},
|
||||||
EventRecord {
|
EventRecord {
|
||||||
phase: Phase::ApplyExtrinsic(1),
|
phase: Phase::ApplyExtrinsic(1),
|
||||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(
|
event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
|
||||||
DispatchInfo { weight: transfer_weight, ..Default::default() }
|
weight: transfer_weight,
|
||||||
)),
|
..Default::default()
|
||||||
|
})),
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
},
|
},
|
||||||
EventRecord {
|
EventRecord {
|
||||||
phase: Phase::ApplyExtrinsic(2),
|
phase: Phase::ApplyExtrinsic(2),
|
||||||
event: Event::Balances(
|
event: Event::Balances(pallet_balances::Event::Transfer(
|
||||||
pallet_balances::Event::Transfer(
|
alice().into(),
|
||||||
alice().into(),
|
bob().into(),
|
||||||
bob().into(),
|
15 * DOLLARS,
|
||||||
15 * DOLLARS,
|
)),
|
||||||
)
|
|
||||||
),
|
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
},
|
},
|
||||||
EventRecord {
|
EventRecord {
|
||||||
@@ -445,9 +476,10 @@ fn full_native_block_import_works() {
|
|||||||
},
|
},
|
||||||
EventRecord {
|
EventRecord {
|
||||||
phase: Phase::ApplyExtrinsic(2),
|
phase: Phase::ApplyExtrinsic(2),
|
||||||
event: Event::System(frame_system::Event::ExtrinsicSuccess(
|
event: Event::System(frame_system::Event::ExtrinsicSuccess(DispatchInfo {
|
||||||
DispatchInfo { weight: transfer_weight, ..Default::default() }
|
weight: transfer_weight,
|
||||||
)),
|
..Default::default()
|
||||||
|
})),
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -470,7 +502,9 @@ fn full_wasm_block_import_works() {
|
|||||||
&block1.0,
|
&block1.0,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
|
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
|
||||||
@@ -486,17 +520,16 @@ fn full_wasm_block_import_works() {
|
|||||||
&block2.0,
|
&block2.0,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Balances::total_balance(&alice()),
|
Balances::total_balance(&alice()),
|
||||||
alice_last_known_balance - 10 * DOLLARS - fees,
|
alice_last_known_balance - 10 * DOLLARS - fees,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * fees,);
|
||||||
Balances::total_balance(&bob()),
|
|
||||||
179 * DOLLARS - 1 * fees,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,11 +633,7 @@ fn deploying_wasm_contract_should_work() {
|
|||||||
let transfer_code = wat::parse_str(CODE_TRANSFER).unwrap();
|
let transfer_code = wat::parse_str(CODE_TRANSFER).unwrap();
|
||||||
let transfer_ch = <Runtime as frame_system::Config>::Hashing::hash(&transfer_code);
|
let transfer_ch = <Runtime as frame_system::Config>::Hashing::hash(&transfer_code);
|
||||||
|
|
||||||
let addr = pallet_contracts::Pallet::<Runtime>::contract_address(
|
let addr = pallet_contracts::Pallet::<Runtime>::contract_address(&charlie(), &transfer_ch, &[]);
|
||||||
&charlie(),
|
|
||||||
&transfer_ch,
|
|
||||||
&[],
|
|
||||||
);
|
|
||||||
|
|
||||||
let subsistence = pallet_contracts::Pallet::<Runtime>::subsistence_threshold();
|
let subsistence = pallet_contracts::Pallet::<Runtime>::subsistence_threshold();
|
||||||
|
|
||||||
@@ -627,19 +656,17 @@ fn deploying_wasm_contract_should_work() {
|
|||||||
transfer_code,
|
transfer_code,
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
CheckedExtrinsic {
|
CheckedExtrinsic {
|
||||||
signed: Some((charlie(), signed_extra(1, 0))),
|
signed: Some((charlie(), signed_extra(1, 0))),
|
||||||
function: Call::Contracts(
|
function: Call::Contracts(pallet_contracts::Call::call::<Runtime>(
|
||||||
pallet_contracts::Call::call::<Runtime>(
|
sp_runtime::MultiAddress::Id(addr.clone()),
|
||||||
sp_runtime::MultiAddress::Id(addr.clone()),
|
10,
|
||||||
10,
|
500_000_000,
|
||||||
500_000_000,
|
vec![0x00, 0x01, 0x02, 0x03],
|
||||||
vec![0x00, 0x01, 0x02, 0x03]
|
)),
|
||||||
)
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
(time / SLOT_DURATION).into(),
|
(time / SLOT_DURATION).into(),
|
||||||
@@ -647,20 +674,14 @@ fn deploying_wasm_contract_should_work() {
|
|||||||
|
|
||||||
let mut t = new_test_ext(compact_code_unwrap(), false);
|
let mut t = new_test_ext(compact_code_unwrap(), false);
|
||||||
|
|
||||||
executor_call::<NeverNativeValue, fn() -> _>(
|
executor_call::<NeverNativeValue, fn() -> _>(&mut t, "Core_execute_block", &b.0, false, None)
|
||||||
&mut t,
|
.0
|
||||||
"Core_execute_block",
|
.unwrap();
|
||||||
&b.0,
|
|
||||||
false,
|
|
||||||
None,
|
|
||||||
).0.unwrap();
|
|
||||||
|
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
// Verify that the contract does exist by querying some of its storage items
|
// Verify that the contract does exist by querying some of its storage items
|
||||||
// It does not matter that the storage item itself does not exist.
|
// It does not matter that the storage item itself does not exist.
|
||||||
assert!(
|
assert!(&pallet_contracts::Pallet::<Runtime>::get_storage(addr, Default::default()).is_ok());
|
||||||
&pallet_contracts::Pallet::<Runtime>::get_storage(addr, Default::default()).is_ok()
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,7 +697,8 @@ fn wasm_big_block_import_fails() {
|
|||||||
&block_with_size(42, 0, 120_000).0,
|
&block_with_size(42, 0, 120_000).0,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
assert!(result.is_err()); // Err(Wasmi(Trap(Trap { kind: Host(AllocatorOutOfSpace) })))
|
assert!(result.is_err()); // Err(Wasmi(Trap(Trap { kind: Host(AllocatorOutOfSpace) })))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -690,7 +712,9 @@ fn native_big_block_import_succeeds() {
|
|||||||
&block_with_size(42, 0, 120_000).0,
|
&block_with_size(42, 0, 120_000).0,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -700,15 +724,15 @@ fn native_big_block_import_fails_on_fallback() {
|
|||||||
// We set the heap pages to 8 because we know that should give an OOM in WASM with the given block.
|
// We set the heap pages to 8 because we know that should give an OOM in WASM with the given block.
|
||||||
set_heap_pages(&mut t.ext(), 8);
|
set_heap_pages(&mut t.ext(), 8);
|
||||||
|
|
||||||
assert!(
|
assert!(executor_call::<NeverNativeValue, fn() -> _>(
|
||||||
executor_call::<NeverNativeValue, fn() -> _>(
|
&mut t,
|
||||||
&mut t,
|
"Core_execute_block",
|
||||||
"Core_execute_block",
|
&block_with_size(42, 0, 120_000).0,
|
||||||
&block_with_size(42, 0, 120_000).0,
|
false,
|
||||||
false,
|
None,
|
||||||
None,
|
)
|
||||||
).0.is_err()
|
.0
|
||||||
);
|
.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -718,8 +742,9 @@ fn panic_execution_gives_error() {
|
|||||||
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
||||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||||
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
|
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
|
||||||
.. Default::default()
|
..Default::default()
|
||||||
}.encode(),
|
}
|
||||||
|
.encode(),
|
||||||
);
|
);
|
||||||
t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 0_u128.encode());
|
t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 0_u128.encode());
|
||||||
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
||||||
@@ -730,7 +755,8 @@ fn panic_execution_gives_error() {
|
|||||||
&vec![].and(&from_block_number(1u32)),
|
&vec![].and(&from_block_number(1u32)),
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
let r = executor_call::<NeverNativeValue, fn() -> _>(
|
let r = executor_call::<NeverNativeValue, fn() -> _>(
|
||||||
&mut t,
|
&mut t,
|
||||||
@@ -738,7 +764,10 @@ fn panic_execution_gives_error() {
|
|||||||
&vec![].and(&xt()),
|
&vec![].and(&xt()),
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
).0.unwrap().into_encoded();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap()
|
||||||
|
.into_encoded();
|
||||||
let r = ApplyExtrinsicResult::decode(&mut &r[..]).unwrap();
|
let r = ApplyExtrinsicResult::decode(&mut &r[..]).unwrap();
|
||||||
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
|
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
|
||||||
}
|
}
|
||||||
@@ -750,19 +779,21 @@ fn successful_execution_gives_ok() {
|
|||||||
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
|
||||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||||
data: (111 * DOLLARS, 0u128, 0u128, 0u128),
|
data: (111 * DOLLARS, 0u128, 0u128, 0u128),
|
||||||
.. Default::default()
|
..Default::default()
|
||||||
}.encode(),
|
}
|
||||||
|
.encode(),
|
||||||
);
|
);
|
||||||
t.insert(
|
t.insert(
|
||||||
<frame_system::Account<Runtime>>::hashed_key_for(bob()),
|
<frame_system::Account<Runtime>>::hashed_key_for(bob()),
|
||||||
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
AccountInfo::<<Runtime as frame_system::Config>::Index, _> {
|
||||||
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
|
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
|
||||||
.. Default::default()
|
..Default::default()
|
||||||
}.encode(),
|
}
|
||||||
|
.encode(),
|
||||||
);
|
);
|
||||||
t.insert(
|
t.insert(
|
||||||
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
|
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
|
||||||
(111 * DOLLARS).encode()
|
(111 * DOLLARS).encode(),
|
||||||
);
|
);
|
||||||
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
||||||
|
|
||||||
@@ -772,7 +803,8 @@ fn successful_execution_gives_ok() {
|
|||||||
&vec![].and(&from_block_number(1u32)),
|
&vec![].and(&from_block_number(1u32)),
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
assert_eq!(Balances::total_balance(&alice()), 111 * DOLLARS);
|
assert_eq!(Balances::total_balance(&alice()), 111 * DOLLARS);
|
||||||
@@ -786,7 +818,10 @@ fn successful_execution_gives_ok() {
|
|||||||
&vec![].and(&xt()),
|
&vec![].and(&xt()),
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
).0.unwrap().into_encoded();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap()
|
||||||
|
.into_encoded();
|
||||||
ApplyExtrinsicResult::decode(&mut &r[..])
|
ApplyExtrinsicResult::decode(&mut &r[..])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.expect("Extrinsic could not be applied")
|
.expect("Extrinsic could not be applied")
|
||||||
@@ -811,7 +846,9 @@ fn full_native_block_import_works_with_changes_trie() {
|
|||||||
&block.encode(),
|
&block.encode(),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some());
|
assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some());
|
||||||
}
|
}
|
||||||
@@ -827,7 +864,9 @@ fn full_wasm_block_import_works_with_changes_trie() {
|
|||||||
&block1.0,
|
&block1.0,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some());
|
assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some());
|
||||||
}
|
}
|
||||||
@@ -835,8 +874,7 @@ fn full_wasm_block_import_works_with_changes_trie() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_import_block_with_test_client() {
|
fn should_import_block_with_test_client() {
|
||||||
use node_testing::client::{
|
use node_testing::client::{
|
||||||
ClientBlockImportExt, TestClientBuilderExt, TestClientBuilder,
|
sp_consensus::BlockOrigin, ClientBlockImportExt, TestClientBuilder, TestClientBuilderExt,
|
||||||
sp_consensus::BlockOrigin,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut client = TestClientBuilder::new().build();
|
let mut client = TestClientBuilder::new().build();
|
||||||
|
|||||||
@@ -15,34 +15,32 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use codec::{Encode, Decode};
|
use codec::{Decode, Encode};
|
||||||
use frame_system::offchain::AppCrypto;
|
|
||||||
use frame_support::Hashable;
|
use frame_support::Hashable;
|
||||||
use sp_state_machine::TestExternalities as CoreTestExternalities;
|
use frame_system::offchain::AppCrypto;
|
||||||
use sp_consensus_babe::{BABE_ENGINE_ID, Slot, digests::{PreDigest, SecondaryPlainPreDigest}};
|
use sc_executor::{error::Result, NativeExecutor, WasmExecutionMethod};
|
||||||
|
use sp_consensus_babe::{
|
||||||
|
digests::{PreDigest, SecondaryPlainPreDigest},
|
||||||
|
Slot, BABE_ENGINE_ID,
|
||||||
|
};
|
||||||
use sp_core::{
|
use sp_core::{
|
||||||
NeverNativeValue, NativeOrEncoded,
|
|
||||||
crypto::KeyTypeId,
|
crypto::KeyTypeId,
|
||||||
sr25519::Signature,
|
sr25519::Signature,
|
||||||
traits::{CodeExecutor, RuntimeCode},
|
traits::{CodeExecutor, RuntimeCode},
|
||||||
|
NativeOrEncoded, NeverNativeValue,
|
||||||
};
|
};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
ApplyExtrinsicResult,
|
traits::{BlakeTwo256, Header as HeaderT},
|
||||||
MultiSigner,
|
ApplyExtrinsicResult, Digest, DigestItem, MultiSignature, MultiSigner,
|
||||||
MultiSignature,
|
|
||||||
Digest,
|
|
||||||
DigestItem,
|
|
||||||
traits::{Header as HeaderT, BlakeTwo256},
|
|
||||||
};
|
};
|
||||||
use sc_executor::{NativeExecutor, WasmExecutionMethod};
|
use sp_state_machine::TestExternalities as CoreTestExternalities;
|
||||||
use sc_executor::error::Result;
|
|
||||||
|
|
||||||
use node_executor::Executor;
|
use node_executor::Executor;
|
||||||
|
use node_primitives::{BlockNumber, Hash};
|
||||||
use node_runtime::{
|
use node_runtime::{
|
||||||
Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Runtime, BuildStorage,
|
constants::currency::*, Block, BuildStorage, CheckedExtrinsic, Header, Runtime,
|
||||||
constants::currency::*,
|
UncheckedExtrinsic,
|
||||||
};
|
};
|
||||||
use node_primitives::{Hash, BlockNumber};
|
|
||||||
use node_testing::keyring::*;
|
use node_testing::keyring::*;
|
||||||
use sp_externalities::Externalities;
|
use sp_externalities::Externalities;
|
||||||
|
|
||||||
@@ -50,8 +48,8 @@ pub const TEST_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"test");
|
|||||||
|
|
||||||
pub mod sr25519 {
|
pub mod sr25519 {
|
||||||
mod app_sr25519 {
|
mod app_sr25519 {
|
||||||
use sp_application_crypto::{app_crypto, sr25519};
|
|
||||||
use super::super::TEST_KEY_TYPE_ID;
|
use super::super::TEST_KEY_TYPE_ID;
|
||||||
|
use sp_application_crypto::{app_crypto, sr25519};
|
||||||
app_crypto!(sr25519, TEST_KEY_TYPE_ID);
|
app_crypto!(sr25519, TEST_KEY_TYPE_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,8 +70,10 @@ impl AppCrypto<MultiSigner, MultiSignature> for TestAuthorityId {
|
|||||||
/// as canonical. This is why `native_executor_instance` also uses the compact version of the
|
/// as canonical. This is why `native_executor_instance` also uses the compact version of the
|
||||||
/// runtime.
|
/// runtime.
|
||||||
pub fn compact_code_unwrap() -> &'static [u8] {
|
pub fn compact_code_unwrap() -> &'static [u8] {
|
||||||
node_runtime::WASM_BINARY.expect("Development wasm binary is not available. \
|
node_runtime::WASM_BINARY.expect(
|
||||||
Testing is only supported with the flag disabled.")
|
"Development wasm binary is not available. \
|
||||||
|
Testing is only supported with the flag disabled.",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const GENESIS_HASH: [u8; 32] = [69u8; 32];
|
pub const GENESIS_HASH: [u8; 32] = [69u8; 32];
|
||||||
@@ -101,8 +101,9 @@ pub fn executor() -> NativeExecutor<Executor> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn executor_call<
|
pub fn executor_call<
|
||||||
R:Decode + Encode + PartialEq,
|
R: Decode + Encode + PartialEq,
|
||||||
NC: FnOnce() -> std::result::Result<R, Box<dyn std::error::Error + Send + Sync>> + std::panic::UnwindSafe
|
NC: FnOnce() -> std::result::Result<R, Box<dyn std::error::Error + Send + Sync>>
|
||||||
|
+ std::panic::UnwindSafe,
|
||||||
>(
|
>(
|
||||||
t: &mut TestExternalities<BlakeTwo256>,
|
t: &mut TestExternalities<BlakeTwo256>,
|
||||||
method: &str,
|
method: &str,
|
||||||
@@ -120,20 +121,15 @@ pub fn executor_call<
|
|||||||
heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()),
|
heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()),
|
||||||
};
|
};
|
||||||
|
|
||||||
executor().call::<R, NC>(
|
executor().call::<R, NC>(&mut t, &runtime_code, method, data, use_native, native_call)
|
||||||
&mut t,
|
|
||||||
&runtime_code,
|
|
||||||
method,
|
|
||||||
data,
|
|
||||||
use_native,
|
|
||||||
native_call,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities<BlakeTwo256> {
|
pub fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities<BlakeTwo256> {
|
||||||
let mut ext = TestExternalities::new_with_code(
|
let mut ext = TestExternalities::new_with_code(
|
||||||
code,
|
code,
|
||||||
node_testing::genesis::config(support_changes_trie, Some(code)).build_storage().unwrap(),
|
node_testing::genesis::config(support_changes_trie, Some(code))
|
||||||
|
.build_storage()
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
ext.changes_trie_storage().insert(0, GENESIS_HASH.into(), Default::default());
|
ext.changes_trie_storage().insert(0, GENESIS_HASH.into(), Default::default());
|
||||||
ext
|
ext
|
||||||
@@ -150,7 +146,7 @@ pub fn construct_block(
|
|||||||
extrinsics: Vec<CheckedExtrinsic>,
|
extrinsics: Vec<CheckedExtrinsic>,
|
||||||
babe_slot: Slot,
|
babe_slot: Slot,
|
||||||
) -> (Vec<u8>, Hash) {
|
) -> (Vec<u8>, Hash) {
|
||||||
use sp_trie::{TrieConfiguration, trie_types::Layout};
|
use sp_trie::{trie_types::Layout, TrieConfiguration};
|
||||||
|
|
||||||
// sign extrinsics.
|
// sign extrinsics.
|
||||||
let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>();
|
let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>();
|
||||||
@@ -167,15 +163,14 @@ pub fn construct_block(
|
|||||||
extrinsics_root,
|
extrinsics_root,
|
||||||
state_root: Default::default(),
|
state_root: Default::default(),
|
||||||
digest: Digest {
|
digest: Digest {
|
||||||
logs: vec![
|
logs: vec![DigestItem::PreRuntime(
|
||||||
DigestItem::PreRuntime(
|
BABE_ENGINE_ID,
|
||||||
BABE_ENGINE_ID,
|
PreDigest::SecondaryPlain(SecondaryPlainPreDigest {
|
||||||
PreDigest::SecondaryPlain(SecondaryPlainPreDigest {
|
slot: babe_slot,
|
||||||
slot: babe_slot,
|
authority_index: 42,
|
||||||
authority_index: 42,
|
})
|
||||||
}).encode()
|
.encode(),
|
||||||
),
|
)],
|
||||||
],
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -186,7 +181,9 @@ pub fn construct_block(
|
|||||||
&header.encode(),
|
&header.encode(),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
for extrinsic in extrinsics.iter() {
|
for extrinsic in extrinsics.iter() {
|
||||||
// Try to apply the `extrinsic`. It should be valid, in the sense that it passes
|
// Try to apply the `extrinsic`. It should be valid, in the sense that it passes
|
||||||
@@ -197,8 +194,13 @@ pub fn construct_block(
|
|||||||
&extrinsic.encode(),
|
&extrinsic.encode(),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0.expect("application of an extrinsic failed").into_encoded();
|
)
|
||||||
match ApplyExtrinsicResult::decode(&mut &r[..]).expect("apply result deserialization failed") {
|
.0
|
||||||
|
.expect("application of an extrinsic failed")
|
||||||
|
.into_encoded();
|
||||||
|
match ApplyExtrinsicResult::decode(&mut &r[..])
|
||||||
|
.expect("apply result deserialization failed")
|
||||||
|
{
|
||||||
Ok(_) => {},
|
Ok(_) => {},
|
||||||
Err(e) => panic!("Applying extrinsic failed: {:?}", e),
|
Err(e) => panic!("Applying extrinsic failed: {:?}", e),
|
||||||
}
|
}
|
||||||
@@ -207,10 +209,13 @@ pub fn construct_block(
|
|||||||
let header = match executor_call::<NeverNativeValue, fn() -> _>(
|
let header = match executor_call::<NeverNativeValue, fn() -> _>(
|
||||||
env,
|
env,
|
||||||
"BlockBuilder_finalize_block",
|
"BlockBuilder_finalize_block",
|
||||||
&[0u8;0],
|
&[0u8; 0],
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0.unwrap() {
|
)
|
||||||
|
.0
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
NativeOrEncoded::Native(_) => unreachable!(),
|
NativeOrEncoded::Native(_) => unreachable!(),
|
||||||
NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(),
|
NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,20 +18,21 @@
|
|||||||
use codec::{Encode, Joiner};
|
use codec::{Encode, Joiner};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
traits::Currency,
|
traits::Currency,
|
||||||
weights::{GetDispatchInfo, constants::ExtrinsicBaseWeight, IdentityFee, WeightToFeePolynomial},
|
weights::{
|
||||||
};
|
constants::ExtrinsicBaseWeight, GetDispatchInfo, IdentityFee, WeightToFeePolynomial,
|
||||||
use sp_core::NeverNativeValue;
|
},
|
||||||
use sp_runtime::{Perbill, traits::One};
|
|
||||||
use node_runtime::{
|
|
||||||
CheckedExtrinsic, Call, Runtime, Balances, TransactionPayment, Multiplier,
|
|
||||||
TransactionByteFee,
|
|
||||||
constants::{time::SLOT_DURATION, currency::*},
|
|
||||||
};
|
};
|
||||||
use node_primitives::Balance;
|
use node_primitives::Balance;
|
||||||
|
use node_runtime::{
|
||||||
|
constants::{currency::*, time::SLOT_DURATION},
|
||||||
|
Balances, Call, CheckedExtrinsic, Multiplier, Runtime, TransactionByteFee, TransactionPayment,
|
||||||
|
};
|
||||||
use node_testing::keyring::*;
|
use node_testing::keyring::*;
|
||||||
|
use sp_core::NeverNativeValue;
|
||||||
|
use sp_runtime::{traits::One, Perbill};
|
||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
use self::common::{*, sign};
|
use self::common::{sign, *};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fee_multiplier_increases_and_decreases_on_big_weight() {
|
fn fee_multiplier_increases_and_decreases_on_big_weight() {
|
||||||
@@ -60,7 +61,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
|
|||||||
CheckedExtrinsic {
|
CheckedExtrinsic {
|
||||||
signed: Some((charlie(), signed_extra(0, 0))),
|
signed: Some((charlie(), signed_extra(0, 0))),
|
||||||
function: Call::System(frame_system::Call::fill_block(Perbill::from_percent(60))),
|
function: Call::System(frame_system::Call::fill_block(Perbill::from_percent(60))),
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
(time1 / SLOT_DURATION).into(),
|
(time1 / SLOT_DURATION).into(),
|
||||||
);
|
);
|
||||||
@@ -79,7 +80,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
|
|||||||
CheckedExtrinsic {
|
CheckedExtrinsic {
|
||||||
signed: Some((charlie(), signed_extra(1, 0))),
|
signed: Some((charlie(), signed_extra(1, 0))),
|
||||||
function: Call::System(frame_system::Call::remark(vec![0; 1])),
|
function: Call::System(frame_system::Call::remark(vec![0; 1])),
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
(time2 / SLOT_DURATION).into(),
|
(time2 / SLOT_DURATION).into(),
|
||||||
);
|
);
|
||||||
@@ -97,7 +98,9 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
|
|||||||
&block1.0,
|
&block1.0,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// weight multiplier is increased for next block.
|
// weight multiplier is increased for next block.
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
@@ -114,7 +117,9 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() {
|
|||||||
&block2.0,
|
&block2.0,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0.unwrap();
|
)
|
||||||
|
.0
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// weight multiplier is increased for next block.
|
// weight multiplier is increased for next block.
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
@@ -131,7 +136,8 @@ fn new_account_info(free_dollars: u128) -> Vec<u8> {
|
|||||||
providers: 0,
|
providers: 0,
|
||||||
sufficients: 0,
|
sufficients: 0,
|
||||||
data: (free_dollars * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS),
|
data: (free_dollars * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS),
|
||||||
}.encode()
|
}
|
||||||
|
.encode()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -148,7 +154,7 @@ fn transaction_fee_is_correct() {
|
|||||||
t.insert(<frame_system::Account<Runtime>>::hashed_key_for(bob()), new_account_info(10));
|
t.insert(<frame_system::Account<Runtime>>::hashed_key_for(bob()), new_account_info(10));
|
||||||
t.insert(
|
t.insert(
|
||||||
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
|
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
|
||||||
(110 * DOLLARS).encode()
|
(110 * DOLLARS).encode(),
|
||||||
);
|
);
|
||||||
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
|
||||||
|
|
||||||
@@ -164,7 +170,8 @@ fn transaction_fee_is_correct() {
|
|||||||
&vec![].and(&from_block_number(1u32)),
|
&vec![].and(&from_block_number(1u32)),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
|
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
let r = executor_call::<NeverNativeValue, fn() -> _>(
|
let r = executor_call::<NeverNativeValue, fn() -> _>(
|
||||||
@@ -173,7 +180,8 @@ fn transaction_fee_is_correct() {
|
|||||||
&vec![].and(&xt.clone()),
|
&vec![].and(&xt.clone()),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
|
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
@@ -228,15 +236,20 @@ fn block_weight_capacity_report() {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
let num_transfers = block_number * factor;
|
let num_transfers = block_number * factor;
|
||||||
let mut xts = (0..num_transfers).map(|i| CheckedExtrinsic {
|
let mut xts = (0..num_transfers)
|
||||||
signed: Some((charlie(), signed_extra(nonce + i as Index, 0))),
|
.map(|i| CheckedExtrinsic {
|
||||||
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 0)),
|
signed: Some((charlie(), signed_extra(nonce + i as Index, 0))),
|
||||||
}).collect::<Vec<CheckedExtrinsic>>();
|
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 0)),
|
||||||
|
})
|
||||||
|
.collect::<Vec<CheckedExtrinsic>>();
|
||||||
|
|
||||||
xts.insert(0, CheckedExtrinsic {
|
xts.insert(
|
||||||
signed: None,
|
0,
|
||||||
function: Call::Timestamp(pallet_timestamp::Call::set(time * 1000)),
|
CheckedExtrinsic {
|
||||||
});
|
signed: None,
|
||||||
|
function: Call::Timestamp(pallet_timestamp::Call::set(time * 1000)),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// NOTE: this is super slow. Can probably be improved.
|
// NOTE: this is super slow. Can probably be improved.
|
||||||
let block = construct_block(
|
let block = construct_block(
|
||||||
@@ -262,7 +275,8 @@ fn block_weight_capacity_report() {
|
|||||||
&block.0,
|
&block.0,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
|
|
||||||
println!(" || Result = {:?}", r);
|
println!(" || Result = {:?}", r);
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
@@ -307,7 +321,11 @@ fn block_length_capacity_report() {
|
|||||||
},
|
},
|
||||||
CheckedExtrinsic {
|
CheckedExtrinsic {
|
||||||
signed: Some((charlie(), signed_extra(nonce, 0))),
|
signed: Some((charlie(), signed_extra(nonce, 0))),
|
||||||
function: Call::System(frame_system::Call::remark(vec![0u8; (block_number * factor) as usize])),
|
function: Call::System(frame_system::Call::remark(vec![
|
||||||
|
0u8;
|
||||||
|
(block_number * factor)
|
||||||
|
as usize
|
||||||
|
])),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
(time * 1000 / SLOT_DURATION).into(),
|
(time * 1000 / SLOT_DURATION).into(),
|
||||||
@@ -327,7 +345,8 @@ fn block_length_capacity_report() {
|
|||||||
&block.0,
|
&block.0,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).0;
|
)
|
||||||
|
.0;
|
||||||
|
|
||||||
println!(" || Result = {:?}", r);
|
println!(" || Result = {:?}", r);
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
|
|||||||
@@ -15,26 +15,13 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
use node_runtime::{
|
|
||||||
Executive, Indices, Runtime, UncheckedExtrinsic,
|
|
||||||
};
|
|
||||||
use sp_application_crypto::AppKey;
|
|
||||||
use sp_core::{
|
|
||||||
offchain::{
|
|
||||||
TransactionPoolExt,
|
|
||||||
testing::TestTransactionPoolExt,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use sp_keystore::{KeystoreExt, SyncCryptoStore, testing::KeyStore};
|
|
||||||
use frame_system::{
|
|
||||||
offchain::{
|
|
||||||
Signer,
|
|
||||||
SubmitTransaction,
|
|
||||||
SendSignedTransaction,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
|
use frame_system::offchain::{SendSignedTransaction, Signer, SubmitTransaction};
|
||||||
|
use node_runtime::{Executive, Indices, Runtime, UncheckedExtrinsic};
|
||||||
|
use sp_application_crypto::AppKey;
|
||||||
|
use sp_core::offchain::{testing::TestTransactionPoolExt, TransactionPoolExt};
|
||||||
|
use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStore};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
use self::common::*;
|
use self::common::*;
|
||||||
@@ -56,8 +43,10 @@ fn should_submit_unsigned_transaction() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let call = pallet_im_online::Call::heartbeat(heartbeat_data, signature);
|
let call = pallet_im_online::Call::heartbeat(heartbeat_data, signature);
|
||||||
SubmitTransaction::<Runtime, pallet_im_online::Call<Runtime>>::submit_unsigned_transaction(call.into())
|
SubmitTransaction::<Runtime, pallet_im_online::Call<Runtime>>::submit_unsigned_transaction(
|
||||||
.unwrap();
|
call.into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(state.read().transactions.len(), 1)
|
assert_eq!(state.read().transactions.len(), 1)
|
||||||
});
|
});
|
||||||
@@ -75,23 +64,26 @@ fn should_submit_signed_transaction() {
|
|||||||
SyncCryptoStore::sr25519_generate_new(
|
SyncCryptoStore::sr25519_generate_new(
|
||||||
&keystore,
|
&keystore,
|
||||||
sr25519::AuthorityId::ID,
|
sr25519::AuthorityId::ID,
|
||||||
Some(&format!("{}/hunter1", PHRASE))
|
Some(&format!("{}/hunter1", PHRASE)),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
SyncCryptoStore::sr25519_generate_new(
|
SyncCryptoStore::sr25519_generate_new(
|
||||||
&keystore,
|
&keystore,
|
||||||
sr25519::AuthorityId::ID,
|
sr25519::AuthorityId::ID,
|
||||||
Some(&format!("{}/hunter2", PHRASE))
|
Some(&format!("{}/hunter2", PHRASE)),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
SyncCryptoStore::sr25519_generate_new(
|
SyncCryptoStore::sr25519_generate_new(
|
||||||
&keystore,
|
&keystore,
|
||||||
sr25519::AuthorityId::ID,
|
sr25519::AuthorityId::ID,
|
||||||
Some(&format!("{}/hunter3", PHRASE))
|
Some(&format!("{}/hunter3", PHRASE)),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
||||||
|
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
let results = Signer::<Runtime, TestAuthorityId>::all_accounts()
|
let results =
|
||||||
.send_signed_transaction(|_| {
|
Signer::<Runtime, TestAuthorityId>::all_accounts().send_signed_transaction(|_| {
|
||||||
pallet_balances::Call::transfer(Default::default(), Default::default())
|
pallet_balances::Call::transfer(Default::default(), Default::default())
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -112,18 +104,20 @@ fn should_submit_signed_twice_from_the_same_account() {
|
|||||||
SyncCryptoStore::sr25519_generate_new(
|
SyncCryptoStore::sr25519_generate_new(
|
||||||
&keystore,
|
&keystore,
|
||||||
sr25519::AuthorityId::ID,
|
sr25519::AuthorityId::ID,
|
||||||
Some(&format!("{}/hunter1", PHRASE))
|
Some(&format!("{}/hunter1", PHRASE)),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
SyncCryptoStore::sr25519_generate_new(
|
SyncCryptoStore::sr25519_generate_new(
|
||||||
&keystore,
|
&keystore,
|
||||||
sr25519::AuthorityId::ID,
|
sr25519::AuthorityId::ID,
|
||||||
Some(&format!("{}/hunter2", PHRASE))
|
Some(&format!("{}/hunter2", PHRASE)),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
||||||
|
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
let result = Signer::<Runtime, TestAuthorityId>::any_account()
|
let result =
|
||||||
.send_signed_transaction(|_| {
|
Signer::<Runtime, TestAuthorityId>::any_account().send_signed_transaction(|_| {
|
||||||
pallet_balances::Call::transfer(Default::default(), Default::default())
|
pallet_balances::Call::transfer(Default::default(), Default::default())
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -131,8 +125,8 @@ fn should_submit_signed_twice_from_the_same_account() {
|
|||||||
assert_eq!(state.read().transactions.len(), 1);
|
assert_eq!(state.read().transactions.len(), 1);
|
||||||
|
|
||||||
// submit another one from the same account. The nonce should be incremented.
|
// submit another one from the same account. The nonce should be incremented.
|
||||||
let result = Signer::<Runtime, TestAuthorityId>::any_account()
|
let result =
|
||||||
.send_signed_transaction(|_| {
|
Signer::<Runtime, TestAuthorityId>::any_account().send_signed_transaction(|_| {
|
||||||
pallet_balances::Call::transfer(Default::default(), Default::default())
|
pallet_balances::Call::transfer(Default::default(), Default::default())
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -147,10 +141,7 @@ fn should_submit_signed_twice_from_the_same_account() {
|
|||||||
}
|
}
|
||||||
let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap());
|
let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap());
|
||||||
let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap());
|
let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap());
|
||||||
assert!(
|
assert!(nonce1 != nonce2, "Transactions should have different nonces. Got: {:?}", nonce1);
|
||||||
nonce1 != nonce2,
|
|
||||||
"Transactions should have different nonces. Got: {:?}", nonce1
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,14 +152,12 @@ fn should_submit_signed_twice_from_all_accounts() {
|
|||||||
t.register_extension(TransactionPoolExt::new(pool));
|
t.register_extension(TransactionPoolExt::new(pool));
|
||||||
|
|
||||||
let keystore = KeyStore::new();
|
let keystore = KeyStore::new();
|
||||||
keystore.sr25519_generate_new(
|
keystore
|
||||||
sr25519::AuthorityId::ID,
|
.sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE)))
|
||||||
Some(&format!("{}/hunter1", PHRASE))
|
.unwrap();
|
||||||
).unwrap();
|
keystore
|
||||||
keystore.sr25519_generate_new(
|
.sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter2", PHRASE)))
|
||||||
sr25519::AuthorityId::ID,
|
.unwrap();
|
||||||
Some(&format!("{}/hunter2", PHRASE))
|
|
||||||
).unwrap();
|
|
||||||
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
||||||
|
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
@@ -217,8 +206,10 @@ fn should_submit_signed_twice_from_all_accounts() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn submitted_transaction_should_be_valid() {
|
fn submitted_transaction_should_be_valid() {
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use sp_runtime::transaction_validity::{TransactionSource, TransactionTag};
|
use sp_runtime::{
|
||||||
use sp_runtime::traits::StaticLookup;
|
traits::StaticLookup,
|
||||||
|
transaction_validity::{TransactionSource, TransactionTag},
|
||||||
|
};
|
||||||
|
|
||||||
let mut t = new_test_ext(compact_code_unwrap(), false);
|
let mut t = new_test_ext(compact_code_unwrap(), false);
|
||||||
let (pool, state) = TestTransactionPoolExt::new();
|
let (pool, state) = TestTransactionPoolExt::new();
|
||||||
@@ -227,13 +218,15 @@ fn submitted_transaction_should_be_valid() {
|
|||||||
let keystore = KeyStore::new();
|
let keystore = KeyStore::new();
|
||||||
SyncCryptoStore::sr25519_generate_new(
|
SyncCryptoStore::sr25519_generate_new(
|
||||||
&keystore,
|
&keystore,
|
||||||
sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE))
|
sr25519::AuthorityId::ID,
|
||||||
).unwrap();
|
Some(&format!("{}/hunter1", PHRASE)),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
t.register_extension(KeystoreExt(Arc::new(keystore)));
|
||||||
|
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
let results = Signer::<Runtime, TestAuthorityId>::all_accounts()
|
let results =
|
||||||
.send_signed_transaction(|_| {
|
Signer::<Runtime, TestAuthorityId>::all_accounts().send_signed_transaction(|_| {
|
||||||
pallet_balances::Call::transfer(Default::default(), Default::default())
|
pallet_balances::Call::transfer(Default::default(), Default::default())
|
||||||
});
|
});
|
||||||
let len = results.len();
|
let len = results.len();
|
||||||
@@ -252,7 +245,7 @@ fn submitted_transaction_should_be_valid() {
|
|||||||
let author = extrinsic.signature.clone().unwrap().0;
|
let author = extrinsic.signature.clone().unwrap().0;
|
||||||
let address = Indices::lookup(author).unwrap();
|
let address = Indices::lookup(author).unwrap();
|
||||||
let data = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() };
|
let data = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() };
|
||||||
let account = frame_system::AccountInfo { data, .. Default::default() };
|
let account = frame_system::AccountInfo { data, ..Default::default() };
|
||||||
<frame_system::Account<Runtime>>::insert(&address, account);
|
<frame_system::Account<Runtime>>::insert(&address, account);
|
||||||
|
|
||||||
// check validity
|
// check validity
|
||||||
@@ -260,7 +253,8 @@ fn submitted_transaction_should_be_valid() {
|
|||||||
source,
|
source,
|
||||||
extrinsic,
|
extrinsic,
|
||||||
frame_system::BlockHash::<Runtime>::get(0),
|
frame_system::BlockHash::<Runtime>::get(0),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// We ignore res.priority since this number can change based on updates to weights and such.
|
// We ignore res.priority since this number can change based on updates to weights and such.
|
||||||
assert_eq!(res.requires, Vec::<TransactionTag>::new());
|
assert_eq!(res.requires, Vec::<TransactionTag>::new());
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
//! Structs to easily compose inspect sub-command for CLI.
|
//! Structs to easily compose inspect sub-command for CLI.
|
||||||
|
|
||||||
use std::fmt::Debug;
|
|
||||||
use sc_cli::{ImportParams, SharedParams};
|
use sc_cli::{ImportParams, SharedParams};
|
||||||
|
use std::fmt::Debug;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
/// The `inspect` command used to print decoded chain data.
|
/// The `inspect` command used to print decoded chain data.
|
||||||
|
|||||||
@@ -18,8 +18,10 @@
|
|||||||
|
|
||||||
//! Command ran by the CLI
|
//! Command ran by the CLI
|
||||||
|
|
||||||
use crate::cli::{InspectCmd, InspectSubCmd};
|
use crate::{
|
||||||
use crate::Inspector;
|
cli::{InspectCmd, InspectSubCmd},
|
||||||
|
Inspector,
|
||||||
|
};
|
||||||
use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams};
|
use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams};
|
||||||
use sc_service::{new_full_client, Configuration, NativeExecutionDispatch};
|
use sc_service::{new_full_client, Configuration, NativeExecutionDispatch};
|
||||||
use sp_runtime::traits::Block;
|
use sp_runtime::traits::Block;
|
||||||
@@ -43,13 +45,13 @@ impl InspectCmd {
|
|||||||
let res = inspect.block(input).map_err(|e| format!("{}", e))?;
|
let res = inspect.block(input).map_err(|e| format!("{}", e))?;
|
||||||
println!("{}", res);
|
println!("{}", res);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
},
|
||||||
InspectSubCmd::Extrinsic { input } => {
|
InspectSubCmd::Extrinsic { input } => {
|
||||||
let input = input.parse()?;
|
let input = input.parse()?;
|
||||||
let res = inspect.extrinsic(input).map_err(|e| format!("{}", e))?;
|
let res = inspect.extrinsic(input).map_err(|e| format!("{}", e))?;
|
||||||
println!("{}", res);
|
println!("{}", res);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,33 +27,27 @@
|
|||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod command;
|
pub mod command;
|
||||||
|
|
||||||
use std::{
|
use codec::{Decode, Encode};
|
||||||
fmt,
|
|
||||||
fmt::Debug,
|
|
||||||
marker::PhantomData,
|
|
||||||
str::FromStr,
|
|
||||||
};
|
|
||||||
use codec::{Encode, Decode};
|
|
||||||
use sc_client_api::BlockBackend;
|
use sc_client_api::BlockBackend;
|
||||||
use sp_blockchain::HeaderBackend;
|
use sp_blockchain::HeaderBackend;
|
||||||
use sp_core::hexdisplay::HexDisplay;
|
use sp_core::hexdisplay::HexDisplay;
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
generic::BlockId,
|
generic::BlockId,
|
||||||
traits::{Block, HashFor, NumberFor, Hash}
|
traits::{Block, Hash, HashFor, NumberFor},
|
||||||
};
|
};
|
||||||
|
use std::{fmt, fmt::Debug, marker::PhantomData, str::FromStr};
|
||||||
|
|
||||||
/// A helper type for a generic block input.
|
/// A helper type for a generic block input.
|
||||||
pub type BlockAddressFor<TBlock> = BlockAddress<
|
pub type BlockAddressFor<TBlock> =
|
||||||
<HashFor<TBlock> as Hash>::Output,
|
BlockAddress<<HashFor<TBlock> as Hash>::Output, NumberFor<TBlock>>;
|
||||||
NumberFor<TBlock>
|
|
||||||
>;
|
|
||||||
|
|
||||||
/// A Pretty formatter implementation.
|
/// A Pretty formatter implementation.
|
||||||
pub trait PrettyPrinter<TBlock: Block> {
|
pub trait PrettyPrinter<TBlock: Block> {
|
||||||
/// Nicely format block.
|
/// Nicely format block.
|
||||||
fn fmt_block(&self, fmt: &mut fmt::Formatter, block: &TBlock) -> fmt::Result;
|
fn fmt_block(&self, fmt: &mut fmt::Formatter, block: &TBlock) -> fmt::Result;
|
||||||
/// Nicely format extrinsic.
|
/// Nicely format extrinsic.
|
||||||
fn fmt_extrinsic(&self, fmt: &mut fmt::Formatter, extrinsic: &TBlock::Extrinsic) -> fmt::Result;
|
fn fmt_extrinsic(&self, fmt: &mut fmt::Formatter, extrinsic: &TBlock::Extrinsic)
|
||||||
|
-> fmt::Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default dummy debug printer.
|
/// Default dummy debug printer.
|
||||||
@@ -72,7 +66,11 @@ impl<TBlock: Block> PrettyPrinter<TBlock> for DebugPrinter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_extrinsic(&self, fmt: &mut fmt::Formatter, extrinsic: &TBlock::Extrinsic) -> fmt::Result {
|
fn fmt_extrinsic(
|
||||||
|
&self,
|
||||||
|
fmt: &mut fmt::Formatter,
|
||||||
|
extrinsic: &TBlock::Extrinsic,
|
||||||
|
) -> fmt::Result {
|
||||||
writeln!(fmt, " {:#?}", extrinsic)?;
|
writeln!(fmt, " {:#?}", extrinsic)?;
|
||||||
writeln!(fmt, " Bytes: {:?}", HexDisplay::from(&extrinsic.encode()))?;
|
writeln!(fmt, " Bytes: {:?}", HexDisplay::from(&extrinsic.encode()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -101,15 +99,14 @@ impl std::error::Error for Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A helper trait to access block headers and bodies.
|
/// A helper trait to access block headers and bodies.
|
||||||
pub trait ChainAccess<TBlock: Block>:
|
pub trait ChainAccess<TBlock: Block>: HeaderBackend<TBlock> + BlockBackend<TBlock> {}
|
||||||
HeaderBackend<TBlock> +
|
|
||||||
BlockBackend<TBlock>
|
|
||||||
{}
|
|
||||||
|
|
||||||
impl<T, TBlock> ChainAccess<TBlock> for T where
|
impl<T, TBlock> ChainAccess<TBlock> for T
|
||||||
|
where
|
||||||
TBlock: Block,
|
TBlock: Block,
|
||||||
T: sp_blockchain::HeaderBackend<TBlock> + sc_client_api::BlockBackend<TBlock>,
|
T: sp_blockchain::HeaderBackend<TBlock> + sc_client_api::BlockBackend<TBlock>,
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// Blockchain inspector.
|
/// Blockchain inspector.
|
||||||
pub struct Inspector<TBlock: Block, TPrinter: PrettyPrinter<TBlock> = DebugPrinter> {
|
pub struct Inspector<TBlock: Block, TPrinter: PrettyPrinter<TBlock> = DebugPrinter> {
|
||||||
@@ -120,22 +117,16 @@ pub struct Inspector<TBlock: Block, TPrinter: PrettyPrinter<TBlock> = DebugPrint
|
|||||||
|
|
||||||
impl<TBlock: Block, TPrinter: PrettyPrinter<TBlock>> Inspector<TBlock, TPrinter> {
|
impl<TBlock: Block, TPrinter: PrettyPrinter<TBlock>> Inspector<TBlock, TPrinter> {
|
||||||
/// Create new instance of the inspector with default printer.
|
/// Create new instance of the inspector with default printer.
|
||||||
pub fn new(
|
pub fn new(chain: impl ChainAccess<TBlock> + 'static) -> Self
|
||||||
chain: impl ChainAccess<TBlock> + 'static,
|
where
|
||||||
) -> Self where TPrinter: Default {
|
TPrinter: Default,
|
||||||
|
{
|
||||||
Self::with_printer(chain, Default::default())
|
Self::with_printer(chain, Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Customize pretty-printing of the data.
|
/// Customize pretty-printing of the data.
|
||||||
pub fn with_printer(
|
pub fn with_printer(chain: impl ChainAccess<TBlock> + 'static, printer: TPrinter) -> Self {
|
||||||
chain: impl ChainAccess<TBlock> + 'static,
|
Inspector { chain: Box::new(chain) as _, printer, _block: Default::default() }
|
||||||
printer: TPrinter,
|
|
||||||
) -> Self {
|
|
||||||
Inspector {
|
|
||||||
chain: Box::new(chain) as _,
|
|
||||||
printer,
|
|
||||||
_block: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a pretty-printed block.
|
/// Get a pretty-printed block.
|
||||||
@@ -153,25 +144,27 @@ impl<TBlock: Block, TPrinter: PrettyPrinter<TBlock>> Inspector<TBlock, TPrinter>
|
|||||||
|
|
||||||
fn get_block(&self, input: BlockAddressFor<TBlock>) -> Result<TBlock, Error> {
|
fn get_block(&self, input: BlockAddressFor<TBlock>) -> Result<TBlock, Error> {
|
||||||
Ok(match input {
|
Ok(match input {
|
||||||
BlockAddress::Bytes(bytes) => {
|
BlockAddress::Bytes(bytes) => TBlock::decode(&mut &*bytes)?,
|
||||||
TBlock::decode(&mut &*bytes)?
|
|
||||||
},
|
|
||||||
BlockAddress::Number(number) => {
|
BlockAddress::Number(number) => {
|
||||||
let id = BlockId::number(number);
|
let id = BlockId::number(number);
|
||||||
let not_found = format!("Could not find block {:?}", id);
|
let not_found = format!("Could not find block {:?}", id);
|
||||||
let body = self.chain.block_body(&id)?
|
let body = self
|
||||||
.ok_or_else(|| Error::NotFound(not_found.clone()))?;
|
.chain
|
||||||
let header = self.chain.header(id)?
|
.block_body(&id)?
|
||||||
.ok_or_else(|| Error::NotFound(not_found.clone()))?;
|
.ok_or_else(|| Error::NotFound(not_found.clone()))?;
|
||||||
|
let header =
|
||||||
|
self.chain.header(id)?.ok_or_else(|| Error::NotFound(not_found.clone()))?;
|
||||||
TBlock::new(header, body)
|
TBlock::new(header, body)
|
||||||
},
|
},
|
||||||
BlockAddress::Hash(hash) => {
|
BlockAddress::Hash(hash) => {
|
||||||
let id = BlockId::hash(hash);
|
let id = BlockId::hash(hash);
|
||||||
let not_found = format!("Could not find block {:?}", id);
|
let not_found = format!("Could not find block {:?}", id);
|
||||||
let body = self.chain.block_body(&id)?
|
let body = self
|
||||||
.ok_or_else(|| Error::NotFound(not_found.clone()))?;
|
.chain
|
||||||
let header = self.chain.header(id)?
|
.block_body(&id)?
|
||||||
.ok_or_else(|| Error::NotFound(not_found.clone()))?;
|
.ok_or_else(|| Error::NotFound(not_found.clone()))?;
|
||||||
|
let header =
|
||||||
|
self.chain.header(id)?.ok_or_else(|| Error::NotFound(not_found.clone()))?;
|
||||||
TBlock::new(header, body)
|
TBlock::new(header, body)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -192,16 +185,14 @@ impl<TBlock: Block, TPrinter: PrettyPrinter<TBlock>> Inspector<TBlock, TPrinter>
|
|||||||
let ext = match input {
|
let ext = match input {
|
||||||
ExtrinsicAddress::Block(block, index) => {
|
ExtrinsicAddress::Block(block, index) => {
|
||||||
let block = self.get_block(block)?;
|
let block = self.get_block(block)?;
|
||||||
block.extrinsics()
|
block.extrinsics().get(index).cloned().ok_or_else(|| {
|
||||||
.get(index)
|
Error::NotFound(format!(
|
||||||
.cloned()
|
"Could not find extrinsic {} in block {:?}",
|
||||||
.ok_or_else(|| Error::NotFound(format!(
|
index, block
|
||||||
"Could not find extrinsic {} in block {:?}", index, block
|
))
|
||||||
)))?
|
})?
|
||||||
},
|
},
|
||||||
ExtrinsicAddress::Bytes(bytes) => {
|
ExtrinsicAddress::Bytes(bytes) => TBlock::Extrinsic::decode(&mut &*bytes)?,
|
||||||
TBlock::Extrinsic::decode(&mut &*bytes)?
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(format!("{}", ExtrinsicPrinter(ext, &self.printer)))
|
Ok(format!("{}", ExtrinsicPrinter(ext, &self.printer)))
|
||||||
@@ -234,12 +225,12 @@ impl<Hash: FromStr, Number: FromStr> FromStr for BlockAddress<Hash, Number> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// then assume it's bytes (hex-encoded)
|
// then assume it's bytes (hex-encoded)
|
||||||
sp_core::bytes::from_hex(s)
|
sp_core::bytes::from_hex(s).map(Self::Bytes).map_err(|e| {
|
||||||
.map(Self::Bytes)
|
format!(
|
||||||
.map_err(|e| format!(
|
|
||||||
"Given string does not look like hash or number. It could not be parsed as bytes either: {}",
|
"Given string does not look like hash or number. It could not be parsed as bytes either: {}",
|
||||||
e
|
e
|
||||||
))
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,11 +254,13 @@ impl<Hash: FromStr + Debug, Number: FromStr + Debug> FromStr for ExtrinsicAddres
|
|||||||
|
|
||||||
// split by a bunch of different characters
|
// split by a bunch of different characters
|
||||||
let mut it = s.split(|c| c == '.' || c == ':' || c == ' ');
|
let mut it = s.split(|c| c == '.' || c == ':' || c == ' ');
|
||||||
let block = it.next()
|
let block = it
|
||||||
|
.next()
|
||||||
.expect("First element of split iterator is never empty; qed")
|
.expect("First element of split iterator is never empty; qed")
|
||||||
.parse()?;
|
.parse()?;
|
||||||
|
|
||||||
let index = it.next()
|
let index = it
|
||||||
|
.next()
|
||||||
.ok_or_else(|| format!("Extrinsic index missing: example \"5:0\""))?
|
.ok_or_else(|| format!("Extrinsic index missing: example \"5:0\""))?
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|e| format!("Invalid index format: {}", e))?;
|
.map_err(|e| format!("Invalid index format: {}", e))?;
|
||||||
@@ -290,10 +283,10 @@ mod tests {
|
|||||||
let b2 = BlockAddress::from_str("0");
|
let b2 = BlockAddress::from_str("0");
|
||||||
let b3 = BlockAddress::from_str("0x0012345f");
|
let b3 = BlockAddress::from_str("0x0012345f");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
assert_eq!(b0, Ok(BlockAddress::Hash(
|
b0,
|
||||||
"3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()
|
Ok(BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()))
|
||||||
)));
|
);
|
||||||
assert_eq!(b1, Ok(BlockAddress::Number(1234)));
|
assert_eq!(b1, Ok(BlockAddress::Number(1234)));
|
||||||
assert_eq!(b2, Ok(BlockAddress::Number(0)));
|
assert_eq!(b2, Ok(BlockAddress::Number(0)));
|
||||||
assert_eq!(b3, Ok(BlockAddress::Bytes(vec![0, 0x12, 0x34, 0x5f])));
|
assert_eq!(b3, Ok(BlockAddress::Bytes(vec![0, 0x12, 0x34, 0x5f])));
|
||||||
@@ -310,20 +303,16 @@ mod tests {
|
|||||||
let b2 = ExtrinsicAddress::from_str("0 0");
|
let b2 = ExtrinsicAddress::from_str("0 0");
|
||||||
let b3 = ExtrinsicAddress::from_str("0x0012345f");
|
let b3 = ExtrinsicAddress::from_str("0x0012345f");
|
||||||
|
|
||||||
|
|
||||||
assert_eq!(e0, Err("Extrinsic index missing: example \"5:0\"".into()));
|
assert_eq!(e0, Err("Extrinsic index missing: example \"5:0\"".into()));
|
||||||
assert_eq!(b0, Ok(ExtrinsicAddress::Block(
|
assert_eq!(
|
||||||
BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()),
|
b0,
|
||||||
5
|
Ok(ExtrinsicAddress::Block(
|
||||||
)));
|
BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()),
|
||||||
assert_eq!(b1, Ok(ExtrinsicAddress::Block(
|
5
|
||||||
BlockAddress::Number(1234),
|
))
|
||||||
0
|
);
|
||||||
)));
|
assert_eq!(b1, Ok(ExtrinsicAddress::Block(BlockAddress::Number(1234), 0)));
|
||||||
assert_eq!(b2, Ok(ExtrinsicAddress::Block(
|
assert_eq!(b2, Ok(ExtrinsicAddress::Block(BlockAddress::Number(0), 0)));
|
||||||
BlockAddress::Number(0),
|
|
||||||
0
|
|
||||||
)));
|
|
||||||
assert_eq!(b3, Ok(ExtrinsicAddress::Bytes(vec![0, 0x12, 0x34, 0x5f])));
|
assert_eq!(b3, Ok(ExtrinsicAddress::Bytes(vec![0, 0x12, 0x34, 0x5f])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,12 @@
|
|||||||
//! Low-level types used throughout the Substrate code.
|
//! Low-level types used throughout the Substrate code.
|
||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
generic, traits::{Verify, BlakeTwo256, IdentifyAccount}, OpaqueExtrinsic, MultiSignature
|
generic,
|
||||||
|
traits::{BlakeTwo256, IdentifyAccount, Verify},
|
||||||
|
MultiSignature, OpaqueExtrinsic,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An index to a block.
|
/// An index to a block.
|
||||||
|
|||||||
@@ -24,15 +24,9 @@
|
|||||||
|
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use hyper::rt;
|
use hyper::rt;
|
||||||
|
use jsonrpc_core_client::{transports::http, RpcError};
|
||||||
use node_primitives::Hash;
|
use node_primitives::Hash;
|
||||||
use sc_rpc::author::{
|
use sc_rpc::author::{hash::ExtrinsicOrHash, AuthorClient};
|
||||||
AuthorClient,
|
|
||||||
hash::ExtrinsicOrHash,
|
|
||||||
};
|
|
||||||
use jsonrpc_core_client::{
|
|
||||||
transports::http,
|
|
||||||
RpcError,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
sp_tracing::try_init_simple();
|
sp_tracing::try_init_simple();
|
||||||
@@ -41,9 +35,7 @@ fn main() {
|
|||||||
let uri = "http://localhost:9933";
|
let uri = "http://localhost:9933";
|
||||||
|
|
||||||
http::connect(uri)
|
http::connect(uri)
|
||||||
.and_then(|client: AuthorClient<Hash, Hash>| {
|
.and_then(|client: AuthorClient<Hash, Hash>| remove_all_extrinsics(client))
|
||||||
remove_all_extrinsics(client)
|
|
||||||
})
|
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
println!("Error: {:?}", e);
|
println!("Error: {:?}", e);
|
||||||
})
|
})
|
||||||
@@ -58,11 +50,14 @@ fn main() {
|
|||||||
///
|
///
|
||||||
/// As the result of running the code the entire content of the transaction pool is going
|
/// As the result of running the code the entire content of the transaction pool is going
|
||||||
/// to be removed and the extrinsics are going to be temporarily banned.
|
/// to be removed and the extrinsics are going to be temporarily banned.
|
||||||
fn remove_all_extrinsics(client: AuthorClient<Hash, Hash>) -> impl Future<Item=(), Error=RpcError> {
|
fn remove_all_extrinsics(
|
||||||
client.pending_extrinsics()
|
client: AuthorClient<Hash, Hash>,
|
||||||
|
) -> impl Future<Item = (), Error = RpcError> {
|
||||||
|
client
|
||||||
|
.pending_extrinsics()
|
||||||
.and_then(move |pending| {
|
.and_then(move |pending| {
|
||||||
client.remove_extrinsic(
|
client.remove_extrinsic(
|
||||||
pending.into_iter().map(|tx| ExtrinsicOrHash::Extrinsic(tx.into())).collect()
|
pending.into_iter().map(|tx| ExtrinsicOrHash::Extrinsic(tx.into())).collect(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map(|removed| {
|
.map(|removed| {
|
||||||
|
|||||||
@@ -32,24 +32,24 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use sp_keystore::SyncCryptoStorePtr;
|
use node_primitives::{AccountId, Balance, Block, BlockNumber, Hash, Index};
|
||||||
use node_primitives::{Block, BlockNumber, AccountId, Index, Balance, Hash};
|
use sc_client_api::AuxStore;
|
||||||
use sc_consensus_babe::{Config, Epoch};
|
use sc_consensus_babe::{Config, Epoch};
|
||||||
use sc_consensus_babe_rpc::BabeRpcHandler;
|
use sc_consensus_babe_rpc::BabeRpcHandler;
|
||||||
use sc_consensus_epochs::SharedEpochChanges;
|
use sc_consensus_epochs::SharedEpochChanges;
|
||||||
use sc_finality_grandpa::{
|
use sc_finality_grandpa::{
|
||||||
SharedVoterState, SharedAuthoritySet, FinalityProofProvider, GrandpaJustificationStream
|
FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState,
|
||||||
};
|
};
|
||||||
use sc_finality_grandpa_rpc::GrandpaRpcHandler;
|
use sc_finality_grandpa_rpc::GrandpaRpcHandler;
|
||||||
|
use sc_rpc::SubscriptionTaskExecutor;
|
||||||
pub use sc_rpc_api::DenyUnsafe;
|
pub use sc_rpc_api::DenyUnsafe;
|
||||||
|
use sc_transaction_pool_api::TransactionPool;
|
||||||
use sp_api::ProvideRuntimeApi;
|
use sp_api::ProvideRuntimeApi;
|
||||||
use sp_block_builder::BlockBuilder;
|
use sp_block_builder::BlockBuilder;
|
||||||
use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend};
|
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
|
||||||
use sp_consensus::SelectChain;
|
use sp_consensus::SelectChain;
|
||||||
use sp_consensus_babe::BabeApi;
|
use sp_consensus_babe::BabeApi;
|
||||||
use sc_rpc::SubscriptionTaskExecutor;
|
use sp_keystore::SyncCryptoStorePtr;
|
||||||
use sc_transaction_pool_api::TransactionPool;
|
|
||||||
use sc_client_api::AuxStore;
|
|
||||||
|
|
||||||
/// Light client extra dependencies.
|
/// Light client extra dependencies.
|
||||||
pub struct LightDeps<C, F, P> {
|
pub struct LightDeps<C, F, P> {
|
||||||
@@ -111,9 +111,15 @@ pub type IoHandler = jsonrpc_core::IoHandler<sc_rpc::Metadata>;
|
|||||||
/// Instantiate all Full RPC extensions.
|
/// Instantiate all Full RPC extensions.
|
||||||
pub fn create_full<C, P, SC, B>(
|
pub fn create_full<C, P, SC, B>(
|
||||||
deps: FullDeps<C, P, SC, B>,
|
deps: FullDeps<C, P, SC, B>,
|
||||||
) -> jsonrpc_core::IoHandler<sc_rpc_api::Metadata> where
|
) -> jsonrpc_core::IoHandler<sc_rpc_api::Metadata>
|
||||||
C: ProvideRuntimeApi<Block> + HeaderBackend<Block> + AuxStore +
|
where
|
||||||
HeaderMetadata<Block, Error=BlockChainError> + Sync + Send + 'static,
|
C: ProvideRuntimeApi<Block>
|
||||||
|
+ HeaderBackend<Block>
|
||||||
|
+ AuxStore
|
||||||
|
+ HeaderMetadata<Block, Error = BlockChainError>
|
||||||
|
+ Sync
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
|
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
|
||||||
C::Api: pallet_contracts_rpc::ContractsRuntimeApi<Block, AccountId, Balance, BlockNumber, Hash>,
|
C::Api: pallet_contracts_rpc::ContractsRuntimeApi<Block, AccountId, Balance, BlockNumber, Hash>,
|
||||||
C::Api: pallet_mmr_rpc::MmrRuntimeApi<Block, <Block as sp_runtime::traits::Block>::Hash>,
|
C::Api: pallet_mmr_rpc::MmrRuntimeApi<Block, <Block as sp_runtime::traits::Block>::Hash>,
|
||||||
@@ -121,31 +127,19 @@ pub fn create_full<C, P, SC, B>(
|
|||||||
C::Api: BabeApi<Block>,
|
C::Api: BabeApi<Block>,
|
||||||
C::Api: BlockBuilder<Block>,
|
C::Api: BlockBuilder<Block>,
|
||||||
P: TransactionPool + 'static,
|
P: TransactionPool + 'static,
|
||||||
SC: SelectChain<Block> +'static,
|
SC: SelectChain<Block> + 'static,
|
||||||
B: sc_client_api::Backend<Block> + Send + Sync + 'static,
|
B: sc_client_api::Backend<Block> + Send + Sync + 'static,
|
||||||
B::State: sc_client_api::backend::StateBackend<sp_runtime::traits::HashFor<Block>>,
|
B::State: sc_client_api::backend::StateBackend<sp_runtime::traits::HashFor<Block>>,
|
||||||
{
|
{
|
||||||
use substrate_frame_rpc_system::{FullSystem, SystemApi};
|
|
||||||
use pallet_contracts_rpc::{Contracts, ContractsApi};
|
use pallet_contracts_rpc::{Contracts, ContractsApi};
|
||||||
use pallet_mmr_rpc::{MmrApi, Mmr};
|
use pallet_mmr_rpc::{Mmr, MmrApi};
|
||||||
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
|
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
|
||||||
|
use substrate_frame_rpc_system::{FullSystem, SystemApi};
|
||||||
|
|
||||||
let mut io = jsonrpc_core::IoHandler::default();
|
let mut io = jsonrpc_core::IoHandler::default();
|
||||||
let FullDeps {
|
let FullDeps { client, pool, select_chain, chain_spec, deny_unsafe, babe, grandpa } = deps;
|
||||||
client,
|
|
||||||
pool,
|
|
||||||
select_chain,
|
|
||||||
chain_spec,
|
|
||||||
deny_unsafe,
|
|
||||||
babe,
|
|
||||||
grandpa,
|
|
||||||
} = deps;
|
|
||||||
|
|
||||||
let BabeDeps {
|
let BabeDeps { keystore, babe_config, shared_epoch_changes } = babe;
|
||||||
keystore,
|
|
||||||
babe_config,
|
|
||||||
shared_epoch_changes,
|
|
||||||
} = babe;
|
|
||||||
let GrandpaDeps {
|
let GrandpaDeps {
|
||||||
shared_voter_state,
|
shared_voter_state,
|
||||||
shared_authority_set,
|
shared_authority_set,
|
||||||
@@ -154,64 +148,45 @@ pub fn create_full<C, P, SC, B>(
|
|||||||
finality_provider,
|
finality_provider,
|
||||||
} = grandpa;
|
} = grandpa;
|
||||||
|
|
||||||
io.extend_with(
|
io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe)));
|
||||||
SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))
|
|
||||||
);
|
|
||||||
// Making synchronous calls in light client freezes the browser currently,
|
// Making synchronous calls in light client freezes the browser currently,
|
||||||
// more context: https://github.com/paritytech/substrate/pull/3480
|
// more context: https://github.com/paritytech/substrate/pull/3480
|
||||||
// These RPCs should use an asynchronous caller instead.
|
// These RPCs should use an asynchronous caller instead.
|
||||||
io.extend_with(
|
io.extend_with(ContractsApi::to_delegate(Contracts::new(client.clone())));
|
||||||
ContractsApi::to_delegate(Contracts::new(client.clone()))
|
io.extend_with(MmrApi::to_delegate(Mmr::new(client.clone())));
|
||||||
);
|
io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone())));
|
||||||
io.extend_with(
|
io.extend_with(sc_consensus_babe_rpc::BabeApi::to_delegate(BabeRpcHandler::new(
|
||||||
MmrApi::to_delegate(Mmr::new(client.clone()))
|
client.clone(),
|
||||||
);
|
shared_epoch_changes.clone(),
|
||||||
io.extend_with(
|
keystore,
|
||||||
TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone()))
|
babe_config,
|
||||||
);
|
select_chain,
|
||||||
io.extend_with(
|
deny_unsafe,
|
||||||
sc_consensus_babe_rpc::BabeApi::to_delegate(
|
)));
|
||||||
BabeRpcHandler::new(
|
io.extend_with(sc_finality_grandpa_rpc::GrandpaApi::to_delegate(GrandpaRpcHandler::new(
|
||||||
client.clone(),
|
shared_authority_set.clone(),
|
||||||
shared_epoch_changes.clone(),
|
shared_voter_state,
|
||||||
keystore,
|
justification_stream,
|
||||||
babe_config,
|
subscription_executor,
|
||||||
select_chain,
|
finality_provider,
|
||||||
deny_unsafe,
|
)));
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
io.extend_with(
|
|
||||||
sc_finality_grandpa_rpc::GrandpaApi::to_delegate(
|
|
||||||
GrandpaRpcHandler::new(
|
|
||||||
shared_authority_set.clone(),
|
|
||||||
shared_voter_state,
|
|
||||||
justification_stream,
|
|
||||||
subscription_executor,
|
|
||||||
finality_provider,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
io.extend_with(
|
io.extend_with(sc_sync_state_rpc::SyncStateRpcApi::to_delegate(
|
||||||
sc_sync_state_rpc::SyncStateRpcApi::to_delegate(
|
sc_sync_state_rpc::SyncStateRpcHandler::new(
|
||||||
sc_sync_state_rpc::SyncStateRpcHandler::new(
|
chain_spec,
|
||||||
chain_spec,
|
client,
|
||||||
client,
|
shared_authority_set,
|
||||||
shared_authority_set,
|
shared_epoch_changes,
|
||||||
shared_epoch_changes,
|
deny_unsafe,
|
||||||
deny_unsafe,
|
),
|
||||||
)
|
));
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
io
|
io
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiate all Light RPC extensions.
|
/// Instantiate all Light RPC extensions.
|
||||||
pub fn create_light<C, P, M, F>(
|
pub fn create_light<C, P, M, F>(deps: LightDeps<C, F, P>) -> jsonrpc_core::IoHandler<M>
|
||||||
deps: LightDeps<C, F, P>,
|
where
|
||||||
) -> jsonrpc_core::IoHandler<M> where
|
|
||||||
C: sp_blockchain::HeaderBackend<Block>,
|
C: sp_blockchain::HeaderBackend<Block>,
|
||||||
C: Send + Sync + 'static,
|
C: Send + Sync + 'static,
|
||||||
F: sc_client_api::light::Fetcher<Block> + 'static,
|
F: sc_client_api::light::Fetcher<Block> + 'static,
|
||||||
@@ -220,16 +195,14 @@ pub fn create_light<C, P, M, F>(
|
|||||||
{
|
{
|
||||||
use substrate_frame_rpc_system::{LightSystem, SystemApi};
|
use substrate_frame_rpc_system::{LightSystem, SystemApi};
|
||||||
|
|
||||||
let LightDeps {
|
let LightDeps { client, pool, remote_blockchain, fetcher } = deps;
|
||||||
client,
|
|
||||||
pool,
|
|
||||||
remote_blockchain,
|
|
||||||
fetcher
|
|
||||||
} = deps;
|
|
||||||
let mut io = jsonrpc_core::IoHandler::default();
|
let mut io = jsonrpc_core::IoHandler::default();
|
||||||
io.extend_with(
|
io.extend_with(SystemApi::<Hash, AccountId, Index>::to_delegate(LightSystem::new(
|
||||||
SystemApi::<Hash, AccountId, Index>::to_delegate(LightSystem::new(client, remote_blockchain, fetcher, pool))
|
client,
|
||||||
);
|
remote_blockchain,
|
||||||
|
fetcher,
|
||||||
|
pool,
|
||||||
|
)));
|
||||||
|
|
||||||
io
|
io
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub mod currency {
|
|||||||
use node_primitives::Balance;
|
use node_primitives::Balance;
|
||||||
|
|
||||||
pub const MILLICENTS: Balance = 1_000_000_000;
|
pub const MILLICENTS: Balance = 1_000_000_000;
|
||||||
pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent.
|
pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent.
|
||||||
pub const DOLLARS: Balance = 100 * CENTS;
|
pub const DOLLARS: Balance = 100 * CENTS;
|
||||||
|
|
||||||
pub const fn deposit(items: u32, bytes: u32) -> Balance {
|
pub const fn deposit(items: u32, bytes: u32) -> Balance {
|
||||||
@@ -32,7 +32,7 @@ pub mod currency {
|
|||||||
|
|
||||||
/// Time.
|
/// Time.
|
||||||
pub mod time {
|
pub mod time {
|
||||||
use node_primitives::{Moment, BlockNumber};
|
use node_primitives::{BlockNumber, Moment};
|
||||||
|
|
||||||
/// Since BABE is probabilistic this is the average expected block time that
|
/// Since BABE is probabilistic this is the average expected block time that
|
||||||
/// we are targeting. Blocks will be produced at a minimum duration defined
|
/// we are targeting. Blocks will be produced at a minimum duration defined
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
//! Some configurable implementations as associated type for the substrate runtime.
|
//! Some configurable implementations as associated type for the substrate runtime.
|
||||||
|
|
||||||
use frame_support::traits::{OnUnbalanced, Currency};
|
use crate::{Authorship, Balances, NegativeImbalance};
|
||||||
use crate::{Balances, Authorship, NegativeImbalance};
|
use frame_support::traits::{Currency, OnUnbalanced};
|
||||||
|
|
||||||
pub struct Author;
|
pub struct Author;
|
||||||
impl OnUnbalanced<NegativeImbalance> for Author {
|
impl OnUnbalanced<NegativeImbalance> for Author {
|
||||||
@@ -29,19 +29,24 @@ impl OnUnbalanced<NegativeImbalance> for Author {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod multiplier_tests {
|
mod multiplier_tests {
|
||||||
use sp_runtime::{assert_eq_error_rate, FixedPointNumber, traits::{Convert, One, Zero}};
|
|
||||||
use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment};
|
use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment};
|
||||||
|
use sp_runtime::{
|
||||||
|
assert_eq_error_rate,
|
||||||
|
traits::{Convert, One, Zero},
|
||||||
|
FixedPointNumber,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{currency::*, time::*},
|
constants::{currency::*, time::*},
|
||||||
TransactionPayment, Runtime, TargetBlockFullness,
|
AdjustmentVariable, MinimumMultiplier, Runtime, RuntimeBlockWeights as BlockWeights,
|
||||||
AdjustmentVariable, System, MinimumMultiplier,
|
System, TargetBlockFullness, TransactionPayment,
|
||||||
RuntimeBlockWeights as BlockWeights,
|
|
||||||
};
|
};
|
||||||
use frame_support::weights::{Weight, WeightToFeePolynomial, DispatchClass};
|
use frame_support::weights::{DispatchClass, Weight, WeightToFeePolynomial};
|
||||||
|
|
||||||
fn max_normal() -> Weight {
|
fn max_normal() -> Weight {
|
||||||
BlockWeights::get().get(DispatchClass::Normal).max_total
|
BlockWeights::get()
|
||||||
|
.get(DispatchClass::Normal)
|
||||||
|
.max_total
|
||||||
.unwrap_or_else(|| BlockWeights::get().max_block)
|
.unwrap_or_else(|| BlockWeights::get().max_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +69,7 @@ mod multiplier_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update based on reference impl.
|
// update based on reference impl.
|
||||||
fn truth_value_update(block_weight: Weight, previous: Multiplier) -> Multiplier {
|
fn truth_value_update(block_weight: Weight, previous: Multiplier) -> Multiplier {
|
||||||
let accuracy = Multiplier::accuracy() as f64;
|
let accuracy = Multiplier::accuracy() as f64;
|
||||||
let previous_float = previous.into_inner() as f64 / accuracy;
|
let previous_float = previous.into_inner() as f64 / accuracy;
|
||||||
// bump if it is zero.
|
// bump if it is zero.
|
||||||
@@ -81,15 +86,20 @@ mod multiplier_tests {
|
|||||||
// Current saturation in terms of weight
|
// Current saturation in terms of weight
|
||||||
let s = block_weight;
|
let s = block_weight;
|
||||||
|
|
||||||
let t1 = v * (s/m - ss/m);
|
let t1 = v * (s / m - ss / m);
|
||||||
let t2 = v.powi(2) * (s/m - ss/m).powi(2) / 2.0;
|
let t2 = v.powi(2) * (s / m - ss / m).powi(2) / 2.0;
|
||||||
let next_float = previous_float * (1.0 + t1 + t2);
|
let next_float = previous_float * (1.0 + t1 + t2);
|
||||||
Multiplier::from_float(next_float)
|
Multiplier::from_float(next_float)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_with_system_weight<F>(w: Weight, assertions: F) where F: Fn() -> () {
|
fn run_with_system_weight<F>(w: Weight, assertions: F)
|
||||||
let mut t: sp_io::TestExternalities =
|
where
|
||||||
frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap().into();
|
F: Fn() -> (),
|
||||||
|
{
|
||||||
|
let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default()
|
||||||
|
.build_storage::<Runtime>()
|
||||||
|
.unwrap()
|
||||||
|
.into();
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
System::set_block_consumed_resources(w, 0);
|
System::set_block_consumed_resources(w, 0);
|
||||||
assertions()
|
assertions()
|
||||||
@@ -157,7 +167,9 @@ mod multiplier_tests {
|
|||||||
loop {
|
loop {
|
||||||
let next = runtime_multiplier_update(fm);
|
let next = runtime_multiplier_update(fm);
|
||||||
fm = next;
|
fm = next;
|
||||||
if fm == min_multiplier() { break; }
|
if fm == min_multiplier() {
|
||||||
|
break
|
||||||
|
}
|
||||||
iterations += 1;
|
iterations += 1;
|
||||||
}
|
}
|
||||||
assert!(iterations > 533_333);
|
assert!(iterations > 533_333);
|
||||||
@@ -198,7 +210,9 @@ mod multiplier_tests {
|
|||||||
loop {
|
loop {
|
||||||
let next = runtime_multiplier_update(fm);
|
let next = runtime_multiplier_update(fm);
|
||||||
// if no change, panic. This should never happen in this case.
|
// if no change, panic. This should never happen in this case.
|
||||||
if fm == next { panic!("The fee should ever increase"); }
|
if fm == next {
|
||||||
|
panic!("The fee should ever increase");
|
||||||
|
}
|
||||||
fm = next;
|
fm = next;
|
||||||
iterations += 1;
|
iterations += 1;
|
||||||
let fee =
|
let fee =
|
||||||
@@ -225,7 +239,7 @@ mod multiplier_tests {
|
|||||||
let next = runtime_multiplier_update(fm);
|
let next = runtime_multiplier_update(fm);
|
||||||
assert_eq_error_rate!(
|
assert_eq_error_rate!(
|
||||||
next,
|
next,
|
||||||
truth_value_update(target() / 4 , fm),
|
truth_value_update(target() / 4, fm),
|
||||||
Multiplier::from_inner(100),
|
Multiplier::from_inner(100),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -237,12 +251,11 @@ mod multiplier_tests {
|
|||||||
let next = runtime_multiplier_update(fm);
|
let next = runtime_multiplier_update(fm);
|
||||||
assert_eq_error_rate!(
|
assert_eq_error_rate!(
|
||||||
next,
|
next,
|
||||||
truth_value_update(target() / 2 , fm),
|
truth_value_update(target() / 2, fm),
|
||||||
Multiplier::from_inner(100),
|
Multiplier::from_inner(100),
|
||||||
);
|
);
|
||||||
// Light block. Multiplier is reduced a little.
|
// Light block. Multiplier is reduced a little.
|
||||||
assert!(next < fm);
|
assert!(next < fm);
|
||||||
|
|
||||||
});
|
});
|
||||||
run_with_system_weight(target(), || {
|
run_with_system_weight(target(), || {
|
||||||
let next = runtime_multiplier_update(fm);
|
let next = runtime_multiplier_update(fm);
|
||||||
@@ -259,7 +272,7 @@ mod multiplier_tests {
|
|||||||
let next = runtime_multiplier_update(fm);
|
let next = runtime_multiplier_update(fm);
|
||||||
assert_eq_error_rate!(
|
assert_eq_error_rate!(
|
||||||
next,
|
next,
|
||||||
truth_value_update(target() * 2 , fm),
|
truth_value_update(target() * 2, fm),
|
||||||
Multiplier::from_inner(100),
|
Multiplier::from_inner(100),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -326,28 +339,24 @@ mod multiplier_tests {
|
|||||||
BlockWeights::get().max_block,
|
BlockWeights::get().max_block,
|
||||||
Weight::max_value() / 2,
|
Weight::max_value() / 2,
|
||||||
Weight::max_value(),
|
Weight::max_value(),
|
||||||
].into_iter().for_each(|i| {
|
]
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|i| {
|
||||||
run_with_system_weight(i, || {
|
run_with_system_weight(i, || {
|
||||||
let next = runtime_multiplier_update(Multiplier::one());
|
let next = runtime_multiplier_update(Multiplier::one());
|
||||||
let truth = truth_value_update(i, Multiplier::one());
|
let truth = truth_value_update(i, Multiplier::one());
|
||||||
assert_eq_error_rate!(
|
assert_eq_error_rate!(truth, next, Multiplier::from_inner(50_000_000));
|
||||||
truth,
|
|
||||||
next,
|
|
||||||
Multiplier::from_inner(50_000_000)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Some values that are all above the target and will cause an increase.
|
// Some values that are all above the target and will cause an increase.
|
||||||
let t = target();
|
let t = target();
|
||||||
vec![t + 100, t * 2, t * 4]
|
vec![t + 100, t * 2, t * 4].into_iter().for_each(|i| {
|
||||||
.into_iter()
|
run_with_system_weight(i, || {
|
||||||
.for_each(|i| {
|
let fm = runtime_multiplier_update(max_fm);
|
||||||
run_with_system_weight(i, || {
|
// won't grow. The convert saturates everything.
|
||||||
let fm = runtime_multiplier_update(max_fm);
|
assert_eq!(fm, max_fm);
|
||||||
// won't grow. The convert saturates everything.
|
})
|
||||||
assert_eq!(fm, max_fm);
|
});
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,67 +22,67 @@
|
|||||||
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
|
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
|
use codec::{Decode, Encode, MaxEncodedLen};
|
||||||
use sp_std::prelude::*;
|
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
construct_runtime, parameter_types, RuntimeDebug,
|
construct_runtime, parameter_types,
|
||||||
weights::{
|
|
||||||
Weight, IdentityFee,
|
|
||||||
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
|
|
||||||
DispatchClass,
|
|
||||||
},
|
|
||||||
traits::{
|
traits::{
|
||||||
Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, LockIdentifier,
|
AllowAll, Currency, DenyAll, Imbalance, InstanceFilter, KeyOwnerProofSystem,
|
||||||
U128CurrencyToVote, AllowAll, DenyAll,
|
LockIdentifier, OnUnbalanced, U128CurrencyToVote,
|
||||||
},
|
},
|
||||||
|
weights::{
|
||||||
|
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
|
||||||
|
DispatchClass, IdentityFee, Weight,
|
||||||
|
},
|
||||||
|
PalletId, RuntimeDebug,
|
||||||
};
|
};
|
||||||
use frame_system::{
|
use frame_system::{
|
||||||
EnsureRoot, EnsureOneOf,
|
limits::{BlockLength, BlockWeights},
|
||||||
limits::{BlockWeights, BlockLength}
|
EnsureOneOf, EnsureRoot,
|
||||||
};
|
};
|
||||||
use frame_support::{traits::InstanceFilter, PalletId};
|
pub use node_primitives::{AccountId, Signature};
|
||||||
use codec::{Encode, Decode, MaxEncodedLen};
|
use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment};
|
||||||
|
use pallet_contracts::weights::WeightInfo;
|
||||||
|
use pallet_election_provider_multi_phase::FallbackStrategy;
|
||||||
|
use pallet_grandpa::{
|
||||||
|
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
|
||||||
|
};
|
||||||
|
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
|
||||||
|
use pallet_session::historical as pallet_session_historical;
|
||||||
|
pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment};
|
||||||
|
use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
|
||||||
|
use sp_api::impl_runtime_apis;
|
||||||
|
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
|
||||||
use sp_core::{
|
use sp_core::{
|
||||||
crypto::KeyTypeId,
|
crypto::KeyTypeId,
|
||||||
u32_trait::{_1, _2, _3, _4, _5},
|
u32_trait::{_1, _2, _3, _4, _5},
|
||||||
OpaqueMetadata,
|
OpaqueMetadata,
|
||||||
};
|
};
|
||||||
pub use node_primitives::{AccountId, Signature};
|
use sp_inherents::{CheckInherentsResult, InherentData};
|
||||||
use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment};
|
|
||||||
use sp_api::impl_runtime_apis;
|
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
Permill, Perbill, Perquintill, Percent, ApplyExtrinsicResult, impl_opaque_keys, generic,
|
create_runtime_str,
|
||||||
create_runtime_str, FixedPointNumber,
|
curve::PiecewiseLinear,
|
||||||
|
generic, impl_opaque_keys,
|
||||||
|
traits::{
|
||||||
|
self, BlakeTwo256, Block as BlockT, ConvertInto, NumberFor, OpaqueKeys,
|
||||||
|
SaturatedConversion, StaticLookup,
|
||||||
|
},
|
||||||
|
transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity},
|
||||||
|
ApplyExtrinsicResult, FixedPointNumber, Perbill, Percent, Permill, Perquintill,
|
||||||
};
|
};
|
||||||
use sp_runtime::curve::PiecewiseLinear;
|
use sp_std::prelude::*;
|
||||||
use sp_runtime::transaction_validity::{TransactionValidity, TransactionSource, TransactionPriority};
|
|
||||||
use sp_runtime::traits::{
|
|
||||||
self, BlakeTwo256, Block as BlockT, StaticLookup, SaturatedConversion, ConvertInto, OpaqueKeys,
|
|
||||||
NumberFor,
|
|
||||||
};
|
|
||||||
use sp_version::RuntimeVersion;
|
|
||||||
#[cfg(any(feature = "std", test))]
|
#[cfg(any(feature = "std", test))]
|
||||||
use sp_version::NativeVersion;
|
use sp_version::NativeVersion;
|
||||||
use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
|
use sp_version::RuntimeVersion;
|
||||||
use pallet_grandpa::fg_primitives;
|
|
||||||
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
|
|
||||||
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
|
|
||||||
use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
|
|
||||||
pub use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment, CurrencyAdapter};
|
|
||||||
use pallet_session::{historical as pallet_session_historical};
|
|
||||||
use sp_inherents::{InherentData, CheckInherentsResult};
|
|
||||||
use static_assertions::const_assert;
|
use static_assertions::const_assert;
|
||||||
use pallet_contracts::weights::WeightInfo;
|
|
||||||
use pallet_election_provider_multi_phase::FallbackStrategy;
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", test))]
|
|
||||||
pub use sp_runtime::BuildStorage;
|
|
||||||
#[cfg(any(feature = "std", test))]
|
|
||||||
pub use pallet_balances::Call as BalancesCall;
|
|
||||||
#[cfg(any(feature = "std", test))]
|
#[cfg(any(feature = "std", test))]
|
||||||
pub use frame_system::Call as SystemCall;
|
pub use frame_system::Call as SystemCall;
|
||||||
#[cfg(any(feature = "std", test))]
|
#[cfg(any(feature = "std", test))]
|
||||||
|
pub use pallet_balances::Call as BalancesCall;
|
||||||
|
#[cfg(any(feature = "std", test))]
|
||||||
pub use pallet_staking::StakerStatus;
|
pub use pallet_staking::StakerStatus;
|
||||||
|
#[cfg(any(feature = "std", test))]
|
||||||
|
pub use sp_runtime::BuildStorage;
|
||||||
|
|
||||||
/// Implementations of some helper traits passed into runtime modules as associated types.
|
/// Implementations of some helper traits passed into runtime modules as associated types.
|
||||||
pub mod impls;
|
pub mod impls;
|
||||||
@@ -90,7 +90,7 @@ use impls::Author;
|
|||||||
|
|
||||||
/// Constant values used within the runtime.
|
/// Constant values used within the runtime.
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
use constants::{time::*, currency::*};
|
use constants::{currency::*, time::*};
|
||||||
use sp_runtime::generic::Era;
|
use sp_runtime::generic::Era;
|
||||||
|
|
||||||
// Make the WASM binary available.
|
// Make the WASM binary available.
|
||||||
@@ -100,9 +100,11 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
|||||||
/// Wasm binary unwrapped. If built with `SKIP_WASM_BUILD`, the function panics.
|
/// Wasm binary unwrapped. If built with `SKIP_WASM_BUILD`, the function panics.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn wasm_binary_unwrap() -> &'static [u8] {
|
pub fn wasm_binary_unwrap() -> &'static [u8] {
|
||||||
WASM_BINARY.expect("Development wasm binary is not available. This means the client is \
|
WASM_BINARY.expect(
|
||||||
|
"Development wasm binary is not available. This means the client is \
|
||||||
built with `SKIP_WASM_BUILD` flag and it is only usable for \
|
built with `SKIP_WASM_BUILD` flag and it is only usable for \
|
||||||
production chains. Please rebuild with the flag disabled.")
|
production chains. Please rebuild with the flag disabled.",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runtime version.
|
/// Runtime version.
|
||||||
@@ -125,23 +127,20 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration =
|
pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration =
|
||||||
sp_consensus_babe::BabeEpochConfiguration {
|
sp_consensus_babe::BabeEpochConfiguration {
|
||||||
c: PRIMARY_PROBABILITY,
|
c: PRIMARY_PROBABILITY,
|
||||||
allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots
|
allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Native version.
|
/// Native version.
|
||||||
#[cfg(any(feature = "std", test))]
|
#[cfg(any(feature = "std", test))]
|
||||||
pub fn native_version() -> NativeVersion {
|
pub fn native_version() -> NativeVersion {
|
||||||
NativeVersion {
|
NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
|
||||||
runtime_version: VERSION,
|
|
||||||
can_author_with: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
|
type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
|
||||||
|
|
||||||
pub struct DealWithFees;
|
pub struct DealWithFees;
|
||||||
impl OnUnbalanced<NegativeImbalance> for DealWithFees {
|
impl OnUnbalanced<NegativeImbalance> for DealWithFees {
|
||||||
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item=NegativeImbalance>) {
|
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
|
||||||
if let Some(fees) = fees_then_tips.next() {
|
if let Some(fees) = fees_then_tips.next() {
|
||||||
// for fees, 80% to treasury, 20% to author
|
// for fees, 80% to treasury, 20% to author
|
||||||
let mut split = fees.ration(80, 20);
|
let mut split = fees.ration(80, 20);
|
||||||
@@ -256,14 +255,20 @@ parameter_types! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The type used to represent the kinds of proxying allowed.
|
/// The type used to represent the kinds of proxying allowed.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, MaxEncodedLen)]
|
#[derive(
|
||||||
|
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, MaxEncodedLen,
|
||||||
|
)]
|
||||||
pub enum ProxyType {
|
pub enum ProxyType {
|
||||||
Any,
|
Any,
|
||||||
NonTransfer,
|
NonTransfer,
|
||||||
Governance,
|
Governance,
|
||||||
Staking,
|
Staking,
|
||||||
}
|
}
|
||||||
impl Default for ProxyType { fn default() -> Self { Self::Any } }
|
impl Default for ProxyType {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Any
|
||||||
|
}
|
||||||
|
}
|
||||||
impl InstanceFilter<Call> for ProxyType {
|
impl InstanceFilter<Call> for ProxyType {
|
||||||
fn filter(&self, c: &Call) -> bool {
|
fn filter(&self, c: &Call) -> bool {
|
||||||
match self {
|
match self {
|
||||||
@@ -271,19 +276,16 @@ impl InstanceFilter<Call> for ProxyType {
|
|||||||
ProxyType::NonTransfer => !matches!(
|
ProxyType::NonTransfer => !matches!(
|
||||||
c,
|
c,
|
||||||
Call::Balances(..) |
|
Call::Balances(..) |
|
||||||
Call::Assets(..) |
|
Call::Assets(..) | Call::Uniques(..) |
|
||||||
Call::Uniques(..) |
|
Call::Vesting(pallet_vesting::Call::vested_transfer(..)) |
|
||||||
Call::Vesting(pallet_vesting::Call::vested_transfer(..)) |
|
Call::Indices(pallet_indices::Call::transfer(..))
|
||||||
Call::Indices(pallet_indices::Call::transfer(..))
|
|
||||||
),
|
),
|
||||||
ProxyType::Governance => matches!(
|
ProxyType::Governance => matches!(
|
||||||
c,
|
c,
|
||||||
Call::Democracy(..) |
|
Call::Democracy(..) |
|
||||||
Call::Council(..) |
|
Call::Council(..) | Call::Society(..) |
|
||||||
Call::Society(..) |
|
Call::TechnicalCommittee(..) |
|
||||||
Call::TechnicalCommittee(..) |
|
Call::Elections(..) | Call::Treasury(..)
|
||||||
Call::Elections(..) |
|
|
||||||
Call::Treasury(..)
|
|
||||||
),
|
),
|
||||||
ProxyType::Staking => matches!(c, Call::Staking(..)),
|
ProxyType::Staking => matches!(c, Call::Staking(..)),
|
||||||
}
|
}
|
||||||
@@ -500,15 +502,16 @@ impl pallet_staking::Config for Runtime {
|
|||||||
type SlashCancelOrigin = EnsureOneOf<
|
type SlashCancelOrigin = EnsureOneOf<
|
||||||
AccountId,
|
AccountId,
|
||||||
EnsureRoot<AccountId>,
|
EnsureRoot<AccountId>,
|
||||||
pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>
|
pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>,
|
||||||
>;
|
>;
|
||||||
type SessionInterface = Self;
|
type SessionInterface = Self;
|
||||||
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
|
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
|
||||||
type NextNewSession = Session;
|
type NextNewSession = Session;
|
||||||
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
|
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
|
||||||
type ElectionProvider = ElectionProviderMultiPhase;
|
type ElectionProvider = ElectionProviderMultiPhase;
|
||||||
type GenesisElectionProvider =
|
type GenesisElectionProvider = onchain::OnChainSequentialPhragmen<
|
||||||
onchain::OnChainSequentialPhragmen<pallet_election_provider_multi_phase::OnChainConfig<Self>>;
|
pallet_election_provider_multi_phase::OnChainConfig<Self>,
|
||||||
|
>;
|
||||||
type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
|
type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,20 +621,26 @@ impl pallet_democracy::Config for Runtime {
|
|||||||
type VotingPeriod = VotingPeriod;
|
type VotingPeriod = VotingPeriod;
|
||||||
type MinimumDeposit = MinimumDeposit;
|
type MinimumDeposit = MinimumDeposit;
|
||||||
/// A straight majority of the council can decide what their next motion is.
|
/// A straight majority of the council can decide what their next motion is.
|
||||||
type ExternalOrigin = pallet_collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilCollective>;
|
type ExternalOrigin =
|
||||||
|
pallet_collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilCollective>;
|
||||||
/// A super-majority can have the next scheduled referendum be a straight majority-carries vote.
|
/// A super-majority can have the next scheduled referendum be a straight majority-carries vote.
|
||||||
type ExternalMajorityOrigin = pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>;
|
type ExternalMajorityOrigin =
|
||||||
|
pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>;
|
||||||
/// A unanimous council can have the next scheduled referendum be a straight default-carries
|
/// A unanimous council can have the next scheduled referendum be a straight default-carries
|
||||||
/// (NTB) vote.
|
/// (NTB) vote.
|
||||||
type ExternalDefaultOrigin = pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, CouncilCollective>;
|
type ExternalDefaultOrigin =
|
||||||
|
pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, CouncilCollective>;
|
||||||
/// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote
|
/// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote
|
||||||
/// be tabled immediately and with a shorter voting/enactment period.
|
/// be tabled immediately and with a shorter voting/enactment period.
|
||||||
type FastTrackOrigin = pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalCollective>;
|
type FastTrackOrigin =
|
||||||
type InstantOrigin = pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, TechnicalCollective>;
|
pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalCollective>;
|
||||||
|
type InstantOrigin =
|
||||||
|
pallet_collective::EnsureProportionAtLeast<_1, _1, AccountId, TechnicalCollective>;
|
||||||
type InstantAllowed = InstantAllowed;
|
type InstantAllowed = InstantAllowed;
|
||||||
type FastTrackVotingPeriod = FastTrackVotingPeriod;
|
type FastTrackVotingPeriod = FastTrackVotingPeriod;
|
||||||
// To cancel a proposal which has been passed, 2/3 of the council must agree to it.
|
// To cancel a proposal which has been passed, 2/3 of the council must agree to it.
|
||||||
type CancellationOrigin = pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilCollective>;
|
type CancellationOrigin =
|
||||||
|
pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilCollective>;
|
||||||
// To cancel a proposal before it has been passed, the technical committee must be unanimous or
|
// To cancel a proposal before it has been passed, the technical committee must be unanimous or
|
||||||
// Root must agree.
|
// Root must agree.
|
||||||
type CancelProposalOrigin = EnsureOneOf<
|
type CancelProposalOrigin = EnsureOneOf<
|
||||||
@@ -728,7 +737,7 @@ impl pallet_collective::Config<TechnicalCollective> for Runtime {
|
|||||||
type EnsureRootOrHalfCouncil = EnsureOneOf<
|
type EnsureRootOrHalfCouncil = EnsureOneOf<
|
||||||
AccountId,
|
AccountId,
|
||||||
EnsureRoot<AccountId>,
|
EnsureRoot<AccountId>,
|
||||||
pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>
|
pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>,
|
||||||
>;
|
>;
|
||||||
impl pallet_membership::Config<pallet_membership::Instance1> for Runtime {
|
impl pallet_membership::Config<pallet_membership::Instance1> for Runtime {
|
||||||
type Event = Event;
|
type Event = Event;
|
||||||
@@ -768,12 +777,12 @@ impl pallet_treasury::Config for Runtime {
|
|||||||
type ApproveOrigin = EnsureOneOf<
|
type ApproveOrigin = EnsureOneOf<
|
||||||
AccountId,
|
AccountId,
|
||||||
EnsureRoot<AccountId>,
|
EnsureRoot<AccountId>,
|
||||||
pallet_collective::EnsureProportionAtLeast<_3, _5, AccountId, CouncilCollective>
|
pallet_collective::EnsureProportionAtLeast<_3, _5, AccountId, CouncilCollective>,
|
||||||
>;
|
>;
|
||||||
type RejectOrigin = EnsureOneOf<
|
type RejectOrigin = EnsureOneOf<
|
||||||
AccountId,
|
AccountId,
|
||||||
EnsureRoot<AccountId>,
|
EnsureRoot<AccountId>,
|
||||||
pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>
|
pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>,
|
||||||
>;
|
>;
|
||||||
type Event = Event;
|
type Event = Event;
|
||||||
type OnSlash = ();
|
type OnSlash = ();
|
||||||
@@ -876,8 +885,8 @@ parameter_types! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
|
impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
|
||||||
where
|
where
|
||||||
Call: From<LocalCall>,
|
Call: From<LocalCall>,
|
||||||
{
|
{
|
||||||
fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
|
fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
|
||||||
call: Call,
|
call: Call,
|
||||||
@@ -887,10 +896,8 @@ impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for R
|
|||||||
) -> Option<(Call, <UncheckedExtrinsic as traits::Extrinsic>::SignaturePayload)> {
|
) -> Option<(Call, <UncheckedExtrinsic as traits::Extrinsic>::SignaturePayload)> {
|
||||||
let tip = 0;
|
let tip = 0;
|
||||||
// take the biggest period possible.
|
// take the biggest period possible.
|
||||||
let period = BlockHashCount::get()
|
let period =
|
||||||
.checked_next_power_of_two()
|
BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64;
|
||||||
.map(|c| c / 2)
|
|
||||||
.unwrap_or(2) as u64;
|
|
||||||
let current_block = System::block_number()
|
let current_block = System::block_number()
|
||||||
.saturated_into::<u64>()
|
.saturated_into::<u64>()
|
||||||
// The `System::block_number` is initialized with `n+1`,
|
// The `System::block_number` is initialized with `n+1`,
|
||||||
@@ -911,10 +918,7 @@ impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for R
|
|||||||
log::warn!("Unable to create signed payload: {:?}", e);
|
log::warn!("Unable to create signed payload: {:?}", e);
|
||||||
})
|
})
|
||||||
.ok()?;
|
.ok()?;
|
||||||
let signature = raw_payload
|
let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?;
|
||||||
.using_encoded(|payload| {
|
|
||||||
C::sign(payload, public)
|
|
||||||
})?;
|
|
||||||
let address = Indices::unlookup(account);
|
let address = Indices::unlookup(account);
|
||||||
let (call, extra, _) = raw_payload.deconstruct();
|
let (call, extra, _) = raw_payload.deconstruct();
|
||||||
Some((call, (address, signature.into(), extra)))
|
Some((call, (address, signature.into(), extra)))
|
||||||
@@ -926,7 +930,8 @@ impl frame_system::offchain::SigningTypes for Runtime {
|
|||||||
type Signature = Signature;
|
type Signature = Signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime where
|
impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime
|
||||||
|
where
|
||||||
Call: From<C>,
|
Call: From<C>,
|
||||||
{
|
{
|
||||||
type Extrinsic = UncheckedExtrinsic;
|
type Extrinsic = UncheckedExtrinsic;
|
||||||
@@ -965,8 +970,11 @@ impl pallet_grandpa::Config for Runtime {
|
|||||||
GrandpaId,
|
GrandpaId,
|
||||||
)>>::IdentificationTuple;
|
)>>::IdentificationTuple;
|
||||||
|
|
||||||
type HandleEquivocation =
|
type HandleEquivocation = pallet_grandpa::EquivocationHandler<
|
||||||
pallet_grandpa::EquivocationHandler<Self::KeyOwnerIdentification, Offences, ReportLongevity>;
|
Self::KeyOwnerIdentification,
|
||||||
|
Offences,
|
||||||
|
ReportLongevity,
|
||||||
|
>;
|
||||||
|
|
||||||
type WeightInfo = ();
|
type WeightInfo = ();
|
||||||
}
|
}
|
||||||
@@ -1036,7 +1044,8 @@ impl pallet_society::Config for Runtime {
|
|||||||
type MembershipChanged = ();
|
type MembershipChanged = ();
|
||||||
type RotationPeriod = RotationPeriod;
|
type RotationPeriod = RotationPeriod;
|
||||||
type MaxLockDuration = MaxLockDuration;
|
type MaxLockDuration = MaxLockDuration;
|
||||||
type FounderSetOrigin = pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>;
|
type FounderSetOrigin =
|
||||||
|
pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>;
|
||||||
type SuspensionJudgementOrigin = pallet_society::EnsureFounder<Runtime>;
|
type SuspensionJudgementOrigin = pallet_society::EnsureFounder<Runtime>;
|
||||||
type MaxCandidateIntake = MaxCandidateIntake;
|
type MaxCandidateIntake = MaxCandidateIntake;
|
||||||
type ChallengePeriod = ChallengePeriod;
|
type ChallengePeriod = ChallengePeriod;
|
||||||
@@ -1261,11 +1270,7 @@ mod mmr {
|
|||||||
use super::Runtime;
|
use super::Runtime;
|
||||||
pub use pallet_mmr::primitives::*;
|
pub use pallet_mmr::primitives::*;
|
||||||
|
|
||||||
pub type Leaf = <
|
pub type Leaf = <<Runtime as pallet_mmr::Config>::LeafData as LeafDataProvider>::LeafData;
|
||||||
<Runtime as pallet_mmr::Config>::LeafData
|
|
||||||
as
|
|
||||||
LeafDataProvider
|
|
||||||
>::LeafData;
|
|
||||||
pub type Hash = <Runtime as pallet_mmr::Config>::Hash;
|
pub type Hash = <Runtime as pallet_mmr::Config>::Hash;
|
||||||
pub type Hashing = <Runtime as pallet_mmr::Config>::Hashing;
|
pub type Hashing = <Runtime as pallet_mmr::Config>::Hashing;
|
||||||
}
|
}
|
||||||
@@ -1613,9 +1618,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn validate_transaction_submitter_bounds() {
|
fn validate_transaction_submitter_bounds() {
|
||||||
fn is_submit_signed_transaction<T>() where
|
fn is_submit_signed_transaction<T>()
|
||||||
|
where
|
||||||
T: CreateSignedTransaction<Call>,
|
T: CreateSignedTransaction<Call>,
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
is_submit_signed_transaction::<Runtime>();
|
is_submit_signed_transaction::<Runtime>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,12 @@
|
|||||||
|
|
||||||
//! Basic example of end to end runtime tests.
|
//! Basic example of end to end runtime tests.
|
||||||
|
|
||||||
use test_runner::{ChainInfo, SignatureVerificationOverride};
|
|
||||||
use grandpa::GrandpaBlockImport;
|
use grandpa::GrandpaBlockImport;
|
||||||
use sc_service::{TFullBackend, TFullClient};
|
|
||||||
use sc_consensus_babe::BabeBlockImport;
|
use sc_consensus_babe::BabeBlockImport;
|
||||||
use sc_consensus_manual_seal::consensus::babe::SlotTimestampProvider;
|
use sc_consensus_manual_seal::consensus::babe::SlotTimestampProvider;
|
||||||
|
use sc_service::{TFullBackend, TFullClient};
|
||||||
use sp_runtime::generic::Era;
|
use sp_runtime::generic::Era;
|
||||||
|
use test_runner::{ChainInfo, SignatureVerificationOverride};
|
||||||
|
|
||||||
type BlockImport<B, BE, C, SC> = BabeBlockImport<B, C, GrandpaBlockImport<BE, B, C, SC>>;
|
type BlockImport<B, BE, C, SC> = BabeBlockImport<B, C, GrandpaBlockImport<BE, B, C, SC>>;
|
||||||
|
|
||||||
@@ -54,15 +54,20 @@ impl ChainInfo for NodeTemplateChainInfo {
|
|||||||
Self::SelectChain,
|
Self::SelectChain,
|
||||||
>;
|
>;
|
||||||
type SignedExtras = node_runtime::SignedExtra;
|
type SignedExtras = node_runtime::SignedExtra;
|
||||||
type InherentDataProviders = (SlotTimestampProvider, sp_consensus_babe::inherents::InherentDataProvider);
|
type InherentDataProviders =
|
||||||
|
(SlotTimestampProvider, sp_consensus_babe::inherents::InherentDataProvider);
|
||||||
|
|
||||||
fn signed_extras(from: <Self::Runtime as frame_system::Config>::AccountId) -> Self::SignedExtras {
|
fn signed_extras(
|
||||||
|
from: <Self::Runtime as frame_system::Config>::AccountId,
|
||||||
|
) -> Self::SignedExtras {
|
||||||
(
|
(
|
||||||
frame_system::CheckSpecVersion::<Self::Runtime>::new(),
|
frame_system::CheckSpecVersion::<Self::Runtime>::new(),
|
||||||
frame_system::CheckTxVersion::<Self::Runtime>::new(),
|
frame_system::CheckTxVersion::<Self::Runtime>::new(),
|
||||||
frame_system::CheckGenesis::<Self::Runtime>::new(),
|
frame_system::CheckGenesis::<Self::Runtime>::new(),
|
||||||
frame_system::CheckMortality::<Self::Runtime>::from(Era::Immortal),
|
frame_system::CheckMortality::<Self::Runtime>::from(Era::Immortal),
|
||||||
frame_system::CheckNonce::<Self::Runtime>::from(frame_system::Pallet::<Self::Runtime>::account_nonce(from)),
|
frame_system::CheckNonce::<Self::Runtime>::from(
|
||||||
|
frame_system::Pallet::<Self::Runtime>::account_nonce(from),
|
||||||
|
),
|
||||||
frame_system::CheckWeight::<Self::Runtime>::new(),
|
frame_system::CheckWeight::<Self::Runtime>::new(),
|
||||||
pallet_transaction_payment::ChargeTransactionPayment::<Self::Runtime>::from(0),
|
pallet_transaction_payment::ChargeTransactionPayment::<Self::Runtime>::from(0),
|
||||||
)
|
)
|
||||||
@@ -72,32 +77,43 @@ impl ChainInfo for NodeTemplateChainInfo {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use test_runner::{Node, client_parts, ConfigOrChainSpec, build_runtime, task_executor};
|
|
||||||
use sp_keyring::sr25519::Keyring::Alice;
|
|
||||||
use node_cli::chain_spec::development_config;
|
use node_cli::chain_spec::development_config;
|
||||||
|
use sp_keyring::sr25519::Keyring::Alice;
|
||||||
use sp_runtime::{traits::IdentifyAccount, MultiSigner};
|
use sp_runtime::{traits::IdentifyAccount, MultiSigner};
|
||||||
|
use test_runner::{build_runtime, client_parts, task_executor, ConfigOrChainSpec, Node};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_runner() {
|
fn test_runner() {
|
||||||
let mut tokio_runtime = build_runtime().unwrap();
|
let mut tokio_runtime = build_runtime().unwrap();
|
||||||
let task_executor = task_executor(tokio_runtime.handle().clone());
|
let task_executor = task_executor(tokio_runtime.handle().clone());
|
||||||
let (rpc, task_manager, client, pool, command_sink, backend) =
|
let (rpc, task_manager, client, pool, command_sink, backend) = client_parts::<
|
||||||
client_parts::<NodeTemplateChainInfo>(
|
NodeTemplateChainInfo,
|
||||||
ConfigOrChainSpec::ChainSpec(Box::new(development_config()), task_executor)
|
>(
|
||||||
).unwrap();
|
ConfigOrChainSpec::ChainSpec(Box::new(development_config()), task_executor),
|
||||||
let node = Node::<NodeTemplateChainInfo>::new(rpc, task_manager, client, pool, command_sink, backend);
|
)
|
||||||
|
.unwrap();
|
||||||
|
let node = Node::<NodeTemplateChainInfo>::new(
|
||||||
|
rpc,
|
||||||
|
task_manager,
|
||||||
|
client,
|
||||||
|
pool,
|
||||||
|
command_sink,
|
||||||
|
backend,
|
||||||
|
);
|
||||||
|
|
||||||
tokio_runtime.block_on(async {
|
tokio_runtime.block_on(async {
|
||||||
// seals blocks
|
// seals blocks
|
||||||
node.seal_blocks(1).await;
|
node.seal_blocks(1).await;
|
||||||
// submit extrinsics
|
// submit extrinsics
|
||||||
let alice = MultiSigner::from(Alice.public()).into_account();
|
let alice = MultiSigner::from(Alice.public()).into_account();
|
||||||
let _hash = node.submit_extrinsic(frame_system::Call::remark((b"hello world").to_vec()), alice)
|
let _hash = node
|
||||||
|
.submit_extrinsic(frame_system::Call::remark((b"hello world").to_vec()), alice)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// look ma, I can read state.
|
// look ma, I can read state.
|
||||||
let _events = node.with_state(|| frame_system::Pallet::<node_runtime::Runtime>::events());
|
let _events =
|
||||||
|
node.with_state(|| frame_system::Pallet::<node_runtime::Runtime>::events());
|
||||||
// get access to the underlying client.
|
// get access to the underlying client.
|
||||||
let _client = node.client();
|
let _client = node.client();
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -22,44 +22,42 @@
|
|||||||
//! can pregenerate seed database and `clone` it for every iteration of your benchmarks
|
//! can pregenerate seed database and `clone` it for every iteration of your benchmarks
|
||||||
//! or tests to get consistent, smooth benchmark experience!
|
//! or tests to get consistent, smooth benchmark experience!
|
||||||
|
|
||||||
use std::{sync::Arc, path::{Path, PathBuf}, collections::BTreeMap};
|
use std::{
|
||||||
|
collections::BTreeMap,
|
||||||
use node_primitives::Block;
|
path::{Path, PathBuf},
|
||||||
use crate::client::{Client, Backend};
|
sync::Arc,
|
||||||
use crate::keyring::*;
|
|
||||||
use sc_client_db::PruningMode;
|
|
||||||
use sc_executor::{NativeExecutor, WasmExecutionMethod};
|
|
||||||
use sp_consensus::{
|
|
||||||
BlockOrigin, BlockImport, BlockImportParams,
|
|
||||||
ForkChoiceStrategy, ImportResult, ImportedAux
|
|
||||||
};
|
};
|
||||||
use sp_runtime::{
|
|
||||||
generic::BlockId,
|
use crate::{
|
||||||
OpaqueExtrinsic,
|
client::{Backend, Client},
|
||||||
traits::{Block as BlockT, Verify, Zero, IdentifyAccount},
|
keyring::*,
|
||||||
};
|
};
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
|
use futures::executor;
|
||||||
|
use node_primitives::Block;
|
||||||
use node_runtime::{
|
use node_runtime::{
|
||||||
Call,
|
constants::currency::DOLLARS, AccountId, BalancesCall, Call, CheckedExtrinsic, MinimumPeriod,
|
||||||
CheckedExtrinsic,
|
Signature, SystemCall, UncheckedExtrinsic,
|
||||||
constants::currency::DOLLARS,
|
|
||||||
UncheckedExtrinsic,
|
|
||||||
MinimumPeriod,
|
|
||||||
SystemCall,
|
|
||||||
BalancesCall,
|
|
||||||
AccountId,
|
|
||||||
Signature,
|
|
||||||
};
|
|
||||||
use sp_core::{ExecutionContext, blake2_256, traits::SpawnNamed, Pair, Public, sr25519, ed25519};
|
|
||||||
use sp_api::ProvideRuntimeApi;
|
|
||||||
use sp_block_builder::BlockBuilder;
|
|
||||||
use sp_inherents::InherentData;
|
|
||||||
use sc_client_api::{
|
|
||||||
ExecutionStrategy, BlockBackend,
|
|
||||||
execution_extensions::{ExecutionExtensions, ExecutionStrategies},
|
|
||||||
};
|
};
|
||||||
use sc_block_builder::BlockBuilderProvider;
|
use sc_block_builder::BlockBuilderProvider;
|
||||||
use futures::executor;
|
use sc_client_api::{
|
||||||
|
execution_extensions::{ExecutionExtensions, ExecutionStrategies},
|
||||||
|
BlockBackend, ExecutionStrategy,
|
||||||
|
};
|
||||||
|
use sc_client_db::PruningMode;
|
||||||
|
use sc_executor::{NativeExecutor, WasmExecutionMethod};
|
||||||
|
use sp_api::ProvideRuntimeApi;
|
||||||
|
use sp_block_builder::BlockBuilder;
|
||||||
|
use sp_consensus::{
|
||||||
|
BlockImport, BlockImportParams, BlockOrigin, ForkChoiceStrategy, ImportResult, ImportedAux,
|
||||||
|
};
|
||||||
|
use sp_core::{blake2_256, ed25519, sr25519, traits::SpawnNamed, ExecutionContext, Pair, Public};
|
||||||
|
use sp_inherents::InherentData;
|
||||||
|
use sp_runtime::{
|
||||||
|
generic::BlockId,
|
||||||
|
traits::{Block as BlockT, IdentifyAccount, Verify, Zero},
|
||||||
|
OpaqueExtrinsic,
|
||||||
|
};
|
||||||
|
|
||||||
/// Keyring full of accounts for benching.
|
/// Keyring full of accounts for benching.
|
||||||
///
|
///
|
||||||
@@ -92,19 +90,21 @@ impl BenchPair {
|
|||||||
///
|
///
|
||||||
/// Will panic if cache drop is impossbile.
|
/// Will panic if cache drop is impossbile.
|
||||||
pub fn drop_system_cache() {
|
pub fn drop_system_cache() {
|
||||||
#[cfg(target_os = "windows")] {
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
log::warn!(
|
log::warn!(
|
||||||
target: "bench-logistics",
|
target: "bench-logistics",
|
||||||
"Clearing system cache on windows is not supported. Benchmark might totally be wrong.",
|
"Clearing system cache on windows is not supported. Benchmark might totally be wrong.",
|
||||||
);
|
);
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
std::process::Command::new("sync")
|
std::process::Command::new("sync")
|
||||||
.output()
|
.output()
|
||||||
.expect("Failed to execute system cache clear");
|
.expect("Failed to execute system cache clear");
|
||||||
|
|
||||||
#[cfg(target_os = "linux")] {
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
log::trace!(target: "bench-logistics", "Clearing system cache...");
|
log::trace!(target: "bench-logistics", "Clearing system cache...");
|
||||||
std::process::Command::new("echo")
|
std::process::Command::new("echo")
|
||||||
.args(&["3", ">", "/proc/sys/vm/drop_caches", "2>", "/dev/null"])
|
.args(&["3", ">", "/proc/sys/vm/drop_caches", "2>", "/dev/null"])
|
||||||
@@ -133,7 +133,8 @@ pub fn drop_system_cache() {
|
|||||||
log::trace!(target: "bench-logistics", "Clearing system cache done!");
|
log::trace!(target: "bench-logistics", "Clearing system cache done!");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")] {
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
log::trace!(target: "bench-logistics", "Clearing system cache...");
|
log::trace!(target: "bench-logistics", "Clearing system cache...");
|
||||||
if let Err(err) = std::process::Command::new("purge").output() {
|
if let Err(err) = std::process::Command::new("purge").output() {
|
||||||
log::error!("purge error {:?}: ", err);
|
log::error!("purge error {:?}: ", err);
|
||||||
@@ -169,15 +170,10 @@ impl Clone for BenchDb {
|
|||||||
);
|
);
|
||||||
let seed_db_files = std::fs::read_dir(seed_dir)
|
let seed_db_files = std::fs::read_dir(seed_dir)
|
||||||
.expect("failed to list file in seed dir")
|
.expect("failed to list file in seed dir")
|
||||||
.map(|f_result|
|
.map(|f_result| f_result.expect("failed to read file in seed db").path())
|
||||||
f_result.expect("failed to read file in seed db")
|
.collect::<Vec<PathBuf>>();
|
||||||
.path()
|
fs_extra::copy_items(&seed_db_files, dir.path(), &fs_extra::dir::CopyOptions::new())
|
||||||
).collect::<Vec<PathBuf>>();
|
.expect("Copy of seed database is ok");
|
||||||
fs_extra::copy_items(
|
|
||||||
&seed_db_files,
|
|
||||||
dir.path(),
|
|
||||||
&fs_extra::dir::CopyOptions::new(),
|
|
||||||
).expect("Copy of seed database is ok");
|
|
||||||
|
|
||||||
// We clear system cache after db clone but before any warmups.
|
// We clear system cache after db clone but before any warmups.
|
||||||
// This populates system cache with some data unrelated to actual
|
// This populates system cache with some data unrelated to actual
|
||||||
@@ -204,10 +200,7 @@ pub enum BlockType {
|
|||||||
impl BlockType {
|
impl BlockType {
|
||||||
/// Create block content description with specified number of transactions.
|
/// Create block content description with specified number of transactions.
|
||||||
pub fn to_content(self, size: Option<usize>) -> BlockContent {
|
pub fn to_content(self, size: Option<usize>) -> BlockContent {
|
||||||
BlockContent {
|
BlockContent { block_type: self, size }
|
||||||
block_type: self,
|
|
||||||
size,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,13 +223,8 @@ pub enum DatabaseType {
|
|||||||
impl DatabaseType {
|
impl DatabaseType {
|
||||||
fn into_settings(self, path: PathBuf) -> sc_client_db::DatabaseSettingsSrc {
|
fn into_settings(self, path: PathBuf) -> sc_client_db::DatabaseSettingsSrc {
|
||||||
match self {
|
match self {
|
||||||
Self::RocksDb => sc_client_db::DatabaseSettingsSrc::RocksDb {
|
Self::RocksDb => sc_client_db::DatabaseSettingsSrc::RocksDb { path, cache_size: 512 },
|
||||||
path,
|
Self::ParityDb => sc_client_db::DatabaseSettingsSrc::ParityDb { path },
|
||||||
cache_size: 512,
|
|
||||||
},
|
|
||||||
Self::ParityDb => sc_client_db::DatabaseSettingsSrc::ParityDb {
|
|
||||||
path,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,10 +239,7 @@ pub struct TaskExecutor {
|
|||||||
|
|
||||||
impl TaskExecutor {
|
impl TaskExecutor {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self { pool: executor::ThreadPool::new().expect("Failed to create task executor") }
|
||||||
pool: executor::ThreadPool::new()
|
|
||||||
.expect("Failed to create task executor")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,21 +264,17 @@ pub struct BlockContentIterator<'a> {
|
|||||||
|
|
||||||
impl<'a> BlockContentIterator<'a> {
|
impl<'a> BlockContentIterator<'a> {
|
||||||
fn new(content: BlockContent, keyring: &'a BenchKeyring, client: &Client) -> Self {
|
fn new(content: BlockContent, keyring: &'a BenchKeyring, client: &Client) -> Self {
|
||||||
let runtime_version = client.runtime_version_at(&BlockId::number(0))
|
let runtime_version = client
|
||||||
|
.runtime_version_at(&BlockId::number(0))
|
||||||
.expect("There should be runtime version at 0");
|
.expect("There should be runtime version at 0");
|
||||||
|
|
||||||
let genesis_hash = client.block_hash(Zero::zero())
|
let genesis_hash = client
|
||||||
|
.block_hash(Zero::zero())
|
||||||
.expect("Database error?")
|
.expect("Database error?")
|
||||||
.expect("Genesis block always exists; qed")
|
.expect("Genesis block always exists; qed")
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
BlockContentIterator {
|
BlockContentIterator { iteration: 0, content, keyring, runtime_version, genesis_hash }
|
||||||
iteration: 0,
|
|
||||||
content,
|
|
||||||
keyring,
|
|
||||||
runtime_version,
|
|
||||||
genesis_hash,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,41 +283,36 @@ impl<'a> Iterator for BlockContentIterator<'a> {
|
|||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.content.size.map(|size| size <= self.iteration).unwrap_or(false) {
|
if self.content.size.map(|size| size <= self.iteration).unwrap_or(false) {
|
||||||
return None;
|
return None
|
||||||
}
|
}
|
||||||
|
|
||||||
let sender = self.keyring.at(self.iteration);
|
let sender = self.keyring.at(self.iteration);
|
||||||
let receiver = get_account_id_from_seed::<sr25519::Public>(
|
let receiver = get_account_id_from_seed::<sr25519::Public>(&format!(
|
||||||
&format!("random-user//{}", self.iteration)
|
"random-user//{}",
|
||||||
);
|
self.iteration
|
||||||
|
));
|
||||||
|
|
||||||
let signed = self.keyring.sign(
|
let signed = self.keyring.sign(
|
||||||
CheckedExtrinsic {
|
CheckedExtrinsic {
|
||||||
signed: Some((sender, signed_extra(0, node_runtime::ExistentialDeposit::get() + 1))),
|
signed: Some((
|
||||||
|
sender,
|
||||||
|
signed_extra(0, node_runtime::ExistentialDeposit::get() + 1),
|
||||||
|
)),
|
||||||
function: match self.content.block_type {
|
function: match self.content.block_type {
|
||||||
BlockType::RandomTransfersKeepAlive => {
|
BlockType::RandomTransfersKeepAlive =>
|
||||||
Call::Balances(
|
Call::Balances(BalancesCall::transfer_keep_alive(
|
||||||
BalancesCall::transfer_keep_alive(
|
sp_runtime::MultiAddress::Id(receiver),
|
||||||
sp_runtime::MultiAddress::Id(receiver),
|
node_runtime::ExistentialDeposit::get() + 1,
|
||||||
node_runtime::ExistentialDeposit::get() + 1,
|
)),
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
BlockType::RandomTransfersReaping => {
|
BlockType::RandomTransfersReaping => {
|
||||||
Call::Balances(
|
Call::Balances(BalancesCall::transfer(
|
||||||
BalancesCall::transfer(
|
sp_runtime::MultiAddress::Id(receiver),
|
||||||
sp_runtime::MultiAddress::Id(receiver),
|
// Transfer so that ending balance would be 1 less than existential deposit
|
||||||
// Transfer so that ending balance would be 1 less than existential deposit
|
// so that we kill the sender account.
|
||||||
// so that we kill the sender account.
|
100 * DOLLARS - (node_runtime::ExistentialDeposit::get() - 1),
|
||||||
100*DOLLARS - (node_runtime::ExistentialDeposit::get() - 1),
|
))
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
BlockType::Noop => {
|
|
||||||
Call::System(
|
|
||||||
SystemCall::remark(Vec::new())
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
BlockType::Noop => Call::System(SystemCall::remark(Vec::new())),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
self.runtime_version.spec_version,
|
self.runtime_version.spec_version,
|
||||||
@@ -346,8 +322,7 @@ impl<'a> Iterator for BlockContentIterator<'a> {
|
|||||||
|
|
||||||
let encoded = Encode::encode(&signed);
|
let encoded = Encode::encode(&signed);
|
||||||
|
|
||||||
let opaque = OpaqueExtrinsic::decode(&mut &encoded[..])
|
let opaque = OpaqueExtrinsic::decode(&mut &encoded[..]).expect("Failed to decode opaque");
|
||||||
.expect("Failed to decode opaque");
|
|
||||||
|
|
||||||
self.iteration += 1;
|
self.iteration += 1;
|
||||||
|
|
||||||
@@ -373,12 +348,8 @@ impl BenchDb {
|
|||||||
"Created seed db at {}",
|
"Created seed db at {}",
|
||||||
dir.path().to_string_lossy(),
|
dir.path().to_string_lossy(),
|
||||||
);
|
);
|
||||||
let (_client, _backend, _task_executor) = Self::bench_client(
|
let (_client, _backend, _task_executor) =
|
||||||
database_type,
|
Self::bench_client(database_type, dir.path(), Profile::Native, &keyring);
|
||||||
dir.path(),
|
|
||||||
Profile::Native,
|
|
||||||
&keyring,
|
|
||||||
);
|
|
||||||
let directory_guard = Guard(dir);
|
let directory_guard = Guard(dir);
|
||||||
|
|
||||||
BenchDb { keyring, directory_guard, database_type }
|
BenchDb { keyring, directory_guard, database_type }
|
||||||
@@ -408,7 +379,7 @@ impl BenchDb {
|
|||||||
keyring: &BenchKeyring,
|
keyring: &BenchKeyring,
|
||||||
) -> (Client, std::sync::Arc<Backend>, TaskExecutor) {
|
) -> (Client, std::sync::Arc<Backend>, TaskExecutor) {
|
||||||
let db_config = sc_client_db::DatabaseSettings {
|
let db_config = sc_client_db::DatabaseSettings {
|
||||||
state_cache_size: 16*1024*1024,
|
state_cache_size: 16 * 1024 * 1024,
|
||||||
state_cache_child_ratio: Some((0, 100)),
|
state_cache_child_ratio: Some((0, 100)),
|
||||||
state_pruning: PruningMode::ArchiveAll,
|
state_pruning: PruningMode::ArchiveAll,
|
||||||
source: database_type.into_settings(dir.into()),
|
source: database_type.into_settings(dir.into()),
|
||||||
@@ -429,7 +400,8 @@ impl BenchDb {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
).expect("Should not fail");
|
)
|
||||||
|
.expect("Should not fail");
|
||||||
|
|
||||||
(client, backend, task_executor)
|
(client, backend, task_executor)
|
||||||
}
|
}
|
||||||
@@ -445,12 +417,14 @@ impl BenchDb {
|
|||||||
.put_data(sp_timestamp::INHERENT_IDENTIFIER, ×tamp)
|
.put_data(sp_timestamp::INHERENT_IDENTIFIER, ×tamp)
|
||||||
.expect("Put timestamp failed");
|
.expect("Put timestamp failed");
|
||||||
|
|
||||||
client.runtime_api()
|
client
|
||||||
|
.runtime_api()
|
||||||
.inherent_extrinsics_with_context(
|
.inherent_extrinsics_with_context(
|
||||||
&BlockId::number(0),
|
&BlockId::number(0),
|
||||||
ExecutionContext::BlockConstruction,
|
ExecutionContext::BlockConstruction,
|
||||||
inherent_data,
|
inherent_data,
|
||||||
).expect("Get inherents failed")
|
)
|
||||||
|
.expect("Get inherents failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over some block content with transaction signed using this database keyring.
|
/// Iterate over some block content with transaction signed using this database keyring.
|
||||||
@@ -474,9 +448,7 @@ impl BenchDb {
|
|||||||
pub fn generate_block(&mut self, content: BlockContent) -> Block {
|
pub fn generate_block(&mut self, content: BlockContent) -> Block {
|
||||||
let client = self.client();
|
let client = self.client();
|
||||||
|
|
||||||
let mut block = client
|
let mut block = client.new_block(Default::default()).expect("Block creation failed");
|
||||||
.new_block(Default::default())
|
|
||||||
.expect("Block creation failed");
|
|
||||||
|
|
||||||
for extrinsic in self.generate_inherents(&client) {
|
for extrinsic in self.generate_inherents(&client) {
|
||||||
block.push(extrinsic).expect("Push inherent failed");
|
block.push(extrinsic).expect("Push inherent failed");
|
||||||
@@ -486,14 +458,12 @@ impl BenchDb {
|
|||||||
for opaque in self.block_content(content, &client) {
|
for opaque in self.block_content(content, &client) {
|
||||||
match block.push(opaque) {
|
match block.push(opaque) {
|
||||||
Err(sp_blockchain::Error::ApplyExtrinsicFailed(
|
Err(sp_blockchain::Error::ApplyExtrinsicFailed(
|
||||||
sp_blockchain::ApplyExtrinsicFailed::Validity(e)
|
sp_blockchain::ApplyExtrinsicFailed::Validity(e),
|
||||||
)) if e.exhausted_resources() => {
|
)) if e.exhausted_resources() => break,
|
||||||
break;
|
|
||||||
},
|
|
||||||
Err(err) => panic!("Error pushing transaction: {:?}", err),
|
Err(err) => panic!("Error pushing transaction: {:?}", err),
|
||||||
Ok(_) => {},
|
Ok(_) => {},
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
let block = block.build().expect("Block build failed").block;
|
let block = block.build().expect("Block build failed").block;
|
||||||
|
|
||||||
@@ -514,12 +484,8 @@ impl BenchDb {
|
|||||||
/// Clone this database and create context for testing/benchmarking.
|
/// Clone this database and create context for testing/benchmarking.
|
||||||
pub fn create_context(&self, profile: Profile) -> BenchContext {
|
pub fn create_context(&self, profile: Profile) -> BenchContext {
|
||||||
let BenchDb { directory_guard, keyring, database_type } = self.clone();
|
let BenchDb { directory_guard, keyring, database_type } = self.clone();
|
||||||
let (client, backend, task_executor) = Self::bench_client(
|
let (client, backend, task_executor) =
|
||||||
database_type,
|
Self::bench_client(database_type, directory_guard.path(), profile, &keyring);
|
||||||
directory_guard.path(),
|
|
||||||
profile,
|
|
||||||
&keyring
|
|
||||||
);
|
|
||||||
|
|
||||||
BenchContext {
|
BenchContext {
|
||||||
client: Arc::new(client),
|
client: Arc::new(client),
|
||||||
@@ -549,7 +515,8 @@ impl BenchKeyring {
|
|||||||
let seed = format!("//endowed-user/{}", n);
|
let seed = format!("//endowed-user/{}", n);
|
||||||
let (account_id, pair) = match key_types {
|
let (account_id, pair) = match key_types {
|
||||||
KeyTypes::Sr25519 => {
|
KeyTypes::Sr25519 => {
|
||||||
let pair = sr25519::Pair::from_string(&seed, None).expect("failed to generate pair");
|
let pair =
|
||||||
|
sr25519::Pair::from_string(&seed, None).expect("failed to generate pair");
|
||||||
let account_id = AccountPublic::from(pair.public()).into_account();
|
let account_id = AccountPublic::from(pair.public()).into_account();
|
||||||
(account_id, BenchPair::Sr25519(pair))
|
(account_id, BenchPair::Sr25519(pair))
|
||||||
},
|
},
|
||||||
@@ -581,28 +548,34 @@ impl BenchKeyring {
|
|||||||
xt: CheckedExtrinsic,
|
xt: CheckedExtrinsic,
|
||||||
spec_version: u32,
|
spec_version: u32,
|
||||||
tx_version: u32,
|
tx_version: u32,
|
||||||
genesis_hash: [u8; 32]
|
genesis_hash: [u8; 32],
|
||||||
) -> UncheckedExtrinsic {
|
) -> UncheckedExtrinsic {
|
||||||
match xt.signed {
|
match xt.signed {
|
||||||
Some((signed, extra)) => {
|
Some((signed, extra)) => {
|
||||||
let payload = (xt.function, extra.clone(), spec_version, tx_version, genesis_hash, genesis_hash);
|
let payload = (
|
||||||
|
xt.function,
|
||||||
|
extra.clone(),
|
||||||
|
spec_version,
|
||||||
|
tx_version,
|
||||||
|
genesis_hash,
|
||||||
|
genesis_hash,
|
||||||
|
);
|
||||||
let key = self.accounts.get(&signed).expect("Account id not found in keyring");
|
let key = self.accounts.get(&signed).expect("Account id not found in keyring");
|
||||||
let signature = payload.using_encoded(|b| {
|
let signature = payload
|
||||||
if b.len() > 256 {
|
.using_encoded(|b| {
|
||||||
key.sign(&sp_io::hashing::blake2_256(b))
|
if b.len() > 256 {
|
||||||
} else {
|
key.sign(&sp_io::hashing::blake2_256(b))
|
||||||
key.sign(b)
|
} else {
|
||||||
}
|
key.sign(b)
|
||||||
}).into();
|
}
|
||||||
|
})
|
||||||
|
.into();
|
||||||
UncheckedExtrinsic {
|
UncheckedExtrinsic {
|
||||||
signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)),
|
signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)),
|
||||||
function: payload.0,
|
function: payload.0,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None => UncheckedExtrinsic {
|
|
||||||
signature: None,
|
|
||||||
function: xt.function,
|
|
||||||
},
|
},
|
||||||
|
None => UncheckedExtrinsic { signature: None, function: xt.function },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,7 +614,7 @@ impl Profile {
|
|||||||
block_construction: ExecutionStrategy::NativeElseWasm,
|
block_construction: ExecutionStrategy::NativeElseWasm,
|
||||||
offchain_worker: ExecutionStrategy::NativeElseWasm,
|
offchain_worker: ExecutionStrategy::NativeElseWasm,
|
||||||
other: ExecutionStrategy::NativeElseWasm,
|
other: ExecutionStrategy::NativeElseWasm,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -676,7 +649,7 @@ fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public
|
|||||||
|
|
||||||
fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
|
fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
|
||||||
where
|
where
|
||||||
AccountPublic: From<<TPublic::Pair as Pair>::Public>
|
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
|
||||||
{
|
{
|
||||||
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
|
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
|
||||||
}
|
}
|
||||||
@@ -684,24 +657,25 @@ where
|
|||||||
impl BenchContext {
|
impl BenchContext {
|
||||||
/// Import some block.
|
/// Import some block.
|
||||||
pub fn import_block(&mut self, block: Block) {
|
pub fn import_block(&mut self, block: Block) {
|
||||||
let mut import_params = BlockImportParams::new(BlockOrigin::NetworkBroadcast, block.header.clone());
|
let mut import_params =
|
||||||
|
BlockImportParams::new(BlockOrigin::NetworkBroadcast, block.header.clone());
|
||||||
import_params.body = Some(block.extrinsics().to_vec());
|
import_params.body = Some(block.extrinsics().to_vec());
|
||||||
import_params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
|
import_params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
|
||||||
|
|
||||||
assert_eq!(self.client.chain_info().best_number, 0);
|
assert_eq!(self.client.chain_info().best_number, 0);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
futures::executor::block_on(self.client.import_block(import_params, Default::default()))
|
futures::executor::block_on(
|
||||||
.expect("Failed to import block"),
|
self.client.import_block(import_params, Default::default())
|
||||||
ImportResult::Imported(
|
|
||||||
ImportedAux {
|
|
||||||
header_only: false,
|
|
||||||
clear_justification_requests: false,
|
|
||||||
needs_justification: false,
|
|
||||||
bad_justification: false,
|
|
||||||
is_new_best: true,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
.expect("Failed to import block"),
|
||||||
|
ImportResult::Imported(ImportedAux {
|
||||||
|
header_only: false,
|
||||||
|
clear_justification_requests: false,
|
||||||
|
needs_justification: false,
|
||||||
|
bad_justification: false,
|
||||||
|
is_new_best: true,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(self.client.chain_info().best_number, 1);
|
assert_eq!(self.client.chain_info().best_number, 1);
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
//! Utilities to build a `TestClient` for `node-runtime`.
|
//! Utilities to build a `TestClient` for `node-runtime`.
|
||||||
|
|
||||||
use sp_runtime::BuildStorage;
|
|
||||||
use sc_service::client;
|
use sc_service::client;
|
||||||
|
use sp_runtime::BuildStorage;
|
||||||
/// Re-export test-client utilities.
|
/// Re-export test-client utilities.
|
||||||
pub use substrate_test_client::*;
|
pub use substrate_test_client::*;
|
||||||
|
|
||||||
@@ -61,13 +61,15 @@ pub trait TestClientBuilderExt: Sized {
|
|||||||
fn build(self) -> Client;
|
fn build(self) -> Client;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestClientBuilderExt for substrate_test_client::TestClientBuilder<
|
impl TestClientBuilderExt
|
||||||
node_primitives::Block,
|
for substrate_test_client::TestClientBuilder<
|
||||||
client::LocalCallExecutor<node_primitives::Block, Backend, Executor>,
|
node_primitives::Block,
|
||||||
Backend,
|
client::LocalCallExecutor<node_primitives::Block, Backend, Executor>,
|
||||||
GenesisParameters,
|
Backend,
|
||||||
> {
|
GenesisParameters,
|
||||||
fn new() -> Self{
|
>
|
||||||
|
{
|
||||||
|
fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,5 +77,3 @@ impl TestClientBuilderExt for substrate_test_client::TestClientBuilder<
|
|||||||
self.build_with_native_executor(None).0
|
self.build_with_native_executor(None).0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,13 @@
|
|||||||
//! Genesis Configuration.
|
//! Genesis Configuration.
|
||||||
|
|
||||||
use crate::keyring::*;
|
use crate::keyring::*;
|
||||||
use sp_keyring::{Ed25519Keyring, Sr25519Keyring};
|
|
||||||
use node_runtime::{
|
use node_runtime::{
|
||||||
GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, SystemConfig,
|
constants::currency::*, wasm_binary_unwrap, AccountId, BabeConfig, BalancesConfig,
|
||||||
GrandpaConfig, IndicesConfig, SocietyConfig, wasm_binary_unwrap,
|
GenesisConfig, GrandpaConfig, IndicesConfig, SessionConfig, SocietyConfig, StakerStatus,
|
||||||
AccountId, StakerStatus, BabeConfig, BABE_GENESIS_EPOCH_CONFIG,
|
StakingConfig, SystemConfig, BABE_GENESIS_EPOCH_CONFIG,
|
||||||
};
|
};
|
||||||
use node_runtime::constants::currency::*;
|
|
||||||
use sp_core::ChangesTrieConfiguration;
|
use sp_core::ChangesTrieConfiguration;
|
||||||
|
use sp_keyring::{Ed25519Keyring, Sr25519Keyring};
|
||||||
use sp_runtime::Perbill;
|
use sp_runtime::Perbill;
|
||||||
|
|
||||||
/// Create genesis runtime configuration for tests.
|
/// Create genesis runtime configuration for tests.
|
||||||
@@ -41,7 +40,6 @@ pub fn config_endowed(
|
|||||||
code: Option<&[u8]>,
|
code: Option<&[u8]>,
|
||||||
extra_endowed: Vec<AccountId>,
|
extra_endowed: Vec<AccountId>,
|
||||||
) -> GenesisConfig {
|
) -> GenesisConfig {
|
||||||
|
|
||||||
let mut endowed = vec![
|
let mut endowed = vec![
|
||||||
(alice(), 111 * DOLLARS),
|
(alice(), 111 * DOLLARS),
|
||||||
(bob(), 100 * DOLLARS),
|
(bob(), 100 * DOLLARS),
|
||||||
@@ -51,59 +49,44 @@ pub fn config_endowed(
|
|||||||
(ferdie(), 100 * DOLLARS),
|
(ferdie(), 100 * DOLLARS),
|
||||||
];
|
];
|
||||||
|
|
||||||
endowed.extend(
|
endowed.extend(extra_endowed.into_iter().map(|endowed| (endowed, 100 * DOLLARS)));
|
||||||
extra_endowed.into_iter().map(|endowed| (endowed, 100*DOLLARS))
|
|
||||||
);
|
|
||||||
|
|
||||||
GenesisConfig {
|
GenesisConfig {
|
||||||
system: SystemConfig {
|
system: SystemConfig {
|
||||||
changes_trie_config: if support_changes_trie { Some(ChangesTrieConfiguration {
|
changes_trie_config: if support_changes_trie {
|
||||||
digest_interval: 2,
|
Some(ChangesTrieConfiguration { digest_interval: 2, digest_levels: 2 })
|
||||||
digest_levels: 2,
|
} else {
|
||||||
}) } else { None },
|
None
|
||||||
|
},
|
||||||
code: code.map(|x| x.to_vec()).unwrap_or_else(|| wasm_binary_unwrap().to_vec()),
|
code: code.map(|x| x.to_vec()).unwrap_or_else(|| wasm_binary_unwrap().to_vec()),
|
||||||
},
|
},
|
||||||
indices: IndicesConfig {
|
indices: IndicesConfig { indices: vec![] },
|
||||||
indices: vec![],
|
balances: BalancesConfig { balances: endowed },
|
||||||
},
|
|
||||||
balances: BalancesConfig {
|
|
||||||
balances: endowed,
|
|
||||||
},
|
|
||||||
session: SessionConfig {
|
session: SessionConfig {
|
||||||
keys: vec![
|
keys: vec![
|
||||||
(dave(), alice(), to_session_keys(
|
(dave(), alice(), to_session_keys(&Ed25519Keyring::Alice, &Sr25519Keyring::Alice)),
|
||||||
&Ed25519Keyring::Alice,
|
(eve(), bob(), to_session_keys(&Ed25519Keyring::Bob, &Sr25519Keyring::Bob)),
|
||||||
&Sr25519Keyring::Alice,
|
(
|
||||||
)),
|
ferdie(),
|
||||||
(eve(), bob(), to_session_keys(
|
charlie(),
|
||||||
&Ed25519Keyring::Bob,
|
to_session_keys(&Ed25519Keyring::Charlie, &Sr25519Keyring::Charlie),
|
||||||
&Sr25519Keyring::Bob,
|
),
|
||||||
)),
|
],
|
||||||
(ferdie(), charlie(), to_session_keys(
|
|
||||||
&Ed25519Keyring::Charlie,
|
|
||||||
&Sr25519Keyring::Charlie,
|
|
||||||
)),
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
staking: StakingConfig {
|
staking: StakingConfig {
|
||||||
stakers: vec![
|
stakers: vec![
|
||||||
(dave(), alice(), 111 * DOLLARS, StakerStatus::Validator),
|
(dave(), alice(), 111 * DOLLARS, StakerStatus::Validator),
|
||||||
(eve(), bob(), 100 * DOLLARS, StakerStatus::Validator),
|
(eve(), bob(), 100 * DOLLARS, StakerStatus::Validator),
|
||||||
(ferdie(), charlie(), 100 * DOLLARS, StakerStatus::Validator)
|
(ferdie(), charlie(), 100 * DOLLARS, StakerStatus::Validator),
|
||||||
],
|
],
|
||||||
validator_count: 3,
|
validator_count: 3,
|
||||||
minimum_validator_count: 0,
|
minimum_validator_count: 0,
|
||||||
slash_reward_fraction: Perbill::from_percent(10),
|
slash_reward_fraction: Perbill::from_percent(10),
|
||||||
invulnerables: vec![alice(), bob(), charlie()],
|
invulnerables: vec![alice(), bob(), charlie()],
|
||||||
.. Default::default()
|
..Default::default()
|
||||||
},
|
|
||||||
babe: BabeConfig {
|
|
||||||
authorities: vec![],
|
|
||||||
epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG),
|
|
||||||
},
|
|
||||||
grandpa: GrandpaConfig {
|
|
||||||
authorities: vec![],
|
|
||||||
},
|
},
|
||||||
|
babe: BabeConfig { authorities: vec![], epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG) },
|
||||||
|
grandpa: GrandpaConfig { authorities: vec![] },
|
||||||
im_online: Default::default(),
|
im_online: Default::default(),
|
||||||
authority_discovery: Default::default(),
|
authority_discovery: Default::default(),
|
||||||
democracy: Default::default(),
|
democracy: Default::default(),
|
||||||
@@ -113,11 +96,7 @@ pub fn config_endowed(
|
|||||||
elections: Default::default(),
|
elections: Default::default(),
|
||||||
sudo: Default::default(),
|
sudo: Default::default(),
|
||||||
treasury: Default::default(),
|
treasury: Default::default(),
|
||||||
society: SocietyConfig {
|
society: SocietyConfig { members: vec![alice(), bob()], pot: 0, max_members: 999 },
|
||||||
members: vec![alice(), bob()],
|
|
||||||
pot: 0,
|
|
||||||
max_members: 999,
|
|
||||||
},
|
|
||||||
vesting: Default::default(),
|
vesting: Default::default(),
|
||||||
gilt: Default::default(),
|
gilt: Default::default(),
|
||||||
transaction_storage: Default::default(),
|
transaction_storage: Default::default(),
|
||||||
|
|||||||
@@ -18,11 +18,11 @@
|
|||||||
|
|
||||||
//! Test accounts.
|
//! Test accounts.
|
||||||
|
|
||||||
use sp_keyring::{AccountKeyring, Sr25519Keyring, Ed25519Keyring};
|
|
||||||
use node_primitives::{AccountId, Balance, Index};
|
|
||||||
use node_runtime::{CheckedExtrinsic, UncheckedExtrinsic, SessionKeys, SignedExtra};
|
|
||||||
use sp_runtime::generic::Era;
|
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
|
use node_primitives::{AccountId, Balance, Index};
|
||||||
|
use node_runtime::{CheckedExtrinsic, SessionKeys, SignedExtra, UncheckedExtrinsic};
|
||||||
|
use sp_keyring::{AccountKeyring, Ed25519Keyring, Sr25519Keyring};
|
||||||
|
use sp_runtime::generic::Era;
|
||||||
|
|
||||||
/// Alice's account id.
|
/// Alice's account id.
|
||||||
pub fn alice() -> AccountId {
|
pub fn alice() -> AccountId {
|
||||||
@@ -81,26 +81,31 @@ pub fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sign given `CheckedExtrinsic`.
|
/// Sign given `CheckedExtrinsic`.
|
||||||
pub fn sign(xt: CheckedExtrinsic, spec_version: u32, tx_version: u32, genesis_hash: [u8; 32]) -> UncheckedExtrinsic {
|
pub fn sign(
|
||||||
|
xt: CheckedExtrinsic,
|
||||||
|
spec_version: u32,
|
||||||
|
tx_version: u32,
|
||||||
|
genesis_hash: [u8; 32],
|
||||||
|
) -> UncheckedExtrinsic {
|
||||||
match xt.signed {
|
match xt.signed {
|
||||||
Some((signed, extra)) => {
|
Some((signed, extra)) => {
|
||||||
let payload = (xt.function, extra.clone(), spec_version, tx_version, genesis_hash, genesis_hash);
|
let payload =
|
||||||
|
(xt.function, extra.clone(), spec_version, tx_version, genesis_hash, genesis_hash);
|
||||||
let key = AccountKeyring::from_account_id(&signed).unwrap();
|
let key = AccountKeyring::from_account_id(&signed).unwrap();
|
||||||
let signature = payload.using_encoded(|b| {
|
let signature = payload
|
||||||
if b.len() > 256 {
|
.using_encoded(|b| {
|
||||||
key.sign(&sp_io::hashing::blake2_256(b))
|
if b.len() > 256 {
|
||||||
} else {
|
key.sign(&sp_io::hashing::blake2_256(b))
|
||||||
key.sign(b)
|
} else {
|
||||||
}
|
key.sign(b)
|
||||||
}).into();
|
}
|
||||||
|
})
|
||||||
|
.into();
|
||||||
UncheckedExtrinsic {
|
UncheckedExtrinsic {
|
||||||
signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)),
|
signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)),
|
||||||
function: payload.0,
|
function: payload.0,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None => UncheckedExtrinsic {
|
|
||||||
signature: None,
|
|
||||||
function: xt.function,
|
|
||||||
},
|
},
|
||||||
|
None => UncheckedExtrinsic { signature: None, function: xt.function },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
pub mod bench;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod genesis;
|
pub mod genesis;
|
||||||
pub mod keyring;
|
pub mod keyring;
|
||||||
pub mod bench;
|
|
||||||
|
|||||||
@@ -16,19 +16,23 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{fs, path::{Path, PathBuf}, sync::Arc};
|
use std::{
|
||||||
|
fs,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use ansi_term::Style;
|
use ansi_term::Style;
|
||||||
use rand::{Rng, distributions::Alphanumeric, rngs::OsRng};
|
use rand::{distributions::Alphanumeric, rngs::OsRng, Rng};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use sc_keystore::LocalKeystore;
|
|
||||||
use node_cli::chain_spec::{self, AccountId};
|
use node_cli::chain_spec::{self, AccountId};
|
||||||
|
use sc_keystore::LocalKeystore;
|
||||||
use sp_core::{
|
use sp_core::{
|
||||||
sr25519,
|
|
||||||
crypto::{Public, Ss58Codec},
|
crypto::{Public, Ss58Codec},
|
||||||
|
sr25519,
|
||||||
};
|
};
|
||||||
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
|
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
|
||||||
|
|
||||||
/// A utility to easily create a testnet chain spec definition with a given set
|
/// A utility to easily create a testnet chain spec definition with a given set
|
||||||
/// of authorities and endowed accounts and/or generate random accounts.
|
/// of authorities and endowed accounts and/or generate random accounts.
|
||||||
@@ -86,10 +90,8 @@ impl ChainSpecBuilder {
|
|||||||
/// Returns the path where the chain spec should be saved.
|
/// Returns the path where the chain spec should be saved.
|
||||||
fn chain_spec_path(&self) -> &Path {
|
fn chain_spec_path(&self) -> &Path {
|
||||||
match self {
|
match self {
|
||||||
ChainSpecBuilder::New { chain_spec_path, .. } =>
|
ChainSpecBuilder::New { chain_spec_path, .. } => chain_spec_path.as_path(),
|
||||||
chain_spec_path.as_path(),
|
ChainSpecBuilder::Generate { chain_spec_path, .. } => chain_spec_path.as_path(),
|
||||||
ChainSpecBuilder::Generate { chain_spec_path, .. } =>
|
|
||||||
chain_spec_path.as_path(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,11 +127,15 @@ fn generate_chain_spec(
|
|||||||
.map_err(|err| format!("Failed to parse account address: {:?}", err))
|
.map_err(|err| format!("Failed to parse account address: {:?}", err))
|
||||||
};
|
};
|
||||||
|
|
||||||
let nominator_accounts =
|
let nominator_accounts = nominator_accounts
|
||||||
nominator_accounts.into_iter().map(parse_account).collect::<Result<Vec<_>, String>>()?;
|
.into_iter()
|
||||||
|
.map(parse_account)
|
||||||
|
.collect::<Result<Vec<_>, String>>()?;
|
||||||
|
|
||||||
let endowed_accounts =
|
let endowed_accounts = endowed_accounts
|
||||||
endowed_accounts.into_iter().map(parse_account).collect::<Result<Vec<_>, String>>()?;
|
.into_iter()
|
||||||
|
.map(parse_account)
|
||||||
|
.collect::<Result<Vec<_>, String>>()?;
|
||||||
|
|
||||||
let sudo_account = parse_account(sudo_account)?;
|
let sudo_account = parse_account(sudo_account)?;
|
||||||
|
|
||||||
@@ -137,7 +143,14 @@ fn generate_chain_spec(
|
|||||||
"Custom",
|
"Custom",
|
||||||
"custom",
|
"custom",
|
||||||
sc_chain_spec::ChainType::Live,
|
sc_chain_spec::ChainType::Live,
|
||||||
move || genesis_constructor(&authority_seeds, &nominator_accounts, &endowed_accounts, &sudo_account),
|
move || {
|
||||||
|
genesis_constructor(
|
||||||
|
&authority_seeds,
|
||||||
|
&nominator_accounts,
|
||||||
|
&endowed_accounts,
|
||||||
|
&sudo_account,
|
||||||
|
)
|
||||||
|
},
|
||||||
vec![],
|
vec![],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
@@ -148,42 +161,26 @@ fn generate_chain_spec(
|
|||||||
chain_spec.as_json(false).map_err(|err| err)
|
chain_spec.as_json(false).map_err(|err| err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_authority_keys_and_store(
|
fn generate_authority_keys_and_store(seeds: &[String], keystore_path: &Path) -> Result<(), String> {
|
||||||
seeds: &[String],
|
|
||||||
keystore_path: &Path,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
for (n, seed) in seeds.into_iter().enumerate() {
|
for (n, seed) in seeds.into_iter().enumerate() {
|
||||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(
|
let keystore: SyncCryptoStorePtr = Arc::new(
|
||||||
keystore_path.join(format!("auth-{}", n)),
|
LocalKeystore::open(keystore_path.join(format!("auth-{}", n)), None)
|
||||||
None,
|
.map_err(|err| err.to_string())?,
|
||||||
).map_err(|err| err.to_string())?);
|
);
|
||||||
|
|
||||||
let (_, _, grandpa, babe, im_online, authority_discovery) =
|
let (_, _, grandpa, babe, im_online, authority_discovery) =
|
||||||
chain_spec::authority_keys_from_seed(seed);
|
chain_spec::authority_keys_from_seed(seed);
|
||||||
|
|
||||||
let insert_key = |key_type, public| {
|
let insert_key = |key_type, public| {
|
||||||
SyncCryptoStore::insert_unknown(
|
SyncCryptoStore::insert_unknown(&*keystore, key_type, &format!("//{}", seed), public)
|
||||||
&*keystore,
|
.map_err(|_| format!("Failed to insert key: {}", grandpa))
|
||||||
key_type,
|
|
||||||
&format!("//{}", seed),
|
|
||||||
public,
|
|
||||||
).map_err(|_| format!("Failed to insert key: {}", grandpa))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
insert_key(
|
insert_key(sp_core::crypto::key_types::BABE, babe.as_slice())?;
|
||||||
sp_core::crypto::key_types::BABE,
|
|
||||||
babe.as_slice(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
insert_key(
|
insert_key(sp_core::crypto::key_types::GRANDPA, grandpa.as_slice())?;
|
||||||
sp_core::crypto::key_types::GRANDPA,
|
|
||||||
grandpa.as_slice(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
insert_key(
|
insert_key(sp_core::crypto::key_types::IM_ONLINE, im_online.as_slice())?;
|
||||||
sp_core::crypto::key_types::IM_ONLINE,
|
|
||||||
im_online.as_slice(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
insert_key(
|
insert_key(
|
||||||
sp_core::crypto::key_types::AUTHORITY_DISCOVERY,
|
sp_core::crypto::key_types::AUTHORITY_DISCOVERY,
|
||||||
@@ -206,10 +203,7 @@ fn print_seeds(
|
|||||||
println!("{}", header.paint("Authority seeds"));
|
println!("{}", header.paint("Authority seeds"));
|
||||||
|
|
||||||
for (n, seed) in authority_seeds.iter().enumerate() {
|
for (n, seed) in authority_seeds.iter().enumerate() {
|
||||||
println!("{} //{}",
|
println!("{} //{}", entry.paint(format!("auth-{}:", n)), seed,);
|
||||||
entry.paint(format!("auth-{}:", n)),
|
|
||||||
seed,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", header.paint("Nominator seeds"));
|
println!("{}", header.paint("Nominator seeds"));
|
||||||
@@ -223,10 +217,7 @@ fn print_seeds(
|
|||||||
if !endowed_seeds.is_empty() {
|
if !endowed_seeds.is_empty() {
|
||||||
println!("{}", header.paint("Endowed seeds"));
|
println!("{}", header.paint("Endowed seeds"));
|
||||||
for (n, seed) in endowed_seeds.iter().enumerate() {
|
for (n, seed) in endowed_seeds.iter().enumerate() {
|
||||||
println!("{} //{}",
|
println!("{} //{}", entry.paint(format!("endowed-{}:", n)), seed,);
|
||||||
entry.paint(format!("endowed-{}:", n)),
|
|
||||||
seed,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
@@ -260,10 +251,7 @@ fn main() -> Result<(), String> {
|
|||||||
print_seeds(&authority_seeds, &nominator_seeds, &endowed_seeds, &sudo_seed);
|
print_seeds(&authority_seeds, &nominator_seeds, &endowed_seeds, &sudo_seed);
|
||||||
|
|
||||||
if let Some(keystore_path) = keystore_path {
|
if let Some(keystore_path) = keystore_path {
|
||||||
generate_authority_keys_and_store(
|
generate_authority_keys_and_store(&authority_seeds, &keystore_path)?;
|
||||||
&authority_seeds,
|
|
||||||
&keystore_path,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let nominator_accounts = nominator_seeds
|
let nominator_accounts = nominator_seeds
|
||||||
@@ -284,7 +272,7 @@ fn main() -> Result<(), String> {
|
|||||||
chain_spec::get_account_id_from_seed::<sr25519::Public>(&sudo_seed).to_ss58check();
|
chain_spec::get_account_id_from_seed::<sr25519::Public>(&sudo_seed).to_ss58check();
|
||||||
|
|
||||||
(authority_seeds, nominator_accounts, endowed_accounts, sudo_account)
|
(authority_seeds, nominator_accounts, endowed_accounts, sudo_account)
|
||||||
}
|
},
|
||||||
ChainSpecBuilder::New {
|
ChainSpecBuilder::New {
|
||||||
authority_seeds,
|
authority_seeds,
|
||||||
nominator_accounts,
|
nominator_accounts,
|
||||||
@@ -294,12 +282,8 @@ fn main() -> Result<(), String> {
|
|||||||
} => (authority_seeds, nominator_accounts, endowed_accounts, sudo_account),
|
} => (authority_seeds, nominator_accounts, endowed_accounts, sudo_account),
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = generate_chain_spec(
|
let json =
|
||||||
authority_seeds,
|
generate_chain_spec(authority_seeds, nominator_accounts, endowed_accounts, sudo_account)?;
|
||||||
nominator_accounts,
|
|
||||||
endowed_accounts,
|
|
||||||
sudo_account,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
fs::write(chain_spec_path, json).map_err(|err| err.to_string())
|
fs::write(chain_spec_path, json).map_err(|err| err.to_string())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,17 +16,17 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use structopt::StructOpt;
|
|
||||||
use sc_cli::{
|
use sc_cli::{
|
||||||
Error, VanityCmd, SignCmd, VerifyCmd, GenerateNodeKeyCmd, GenerateCmd, InspectKeyCmd,
|
Error, GenerateCmd, GenerateNodeKeyCmd, InspectKeyCmd, InspectNodeKeyCmd, SignCmd, VanityCmd,
|
||||||
InspectNodeKeyCmd
|
VerifyCmd,
|
||||||
};
|
};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
#[structopt(
|
#[structopt(
|
||||||
name = "subkey",
|
name = "subkey",
|
||||||
author = "Parity Team <admin@parity.io>",
|
author = "Parity Team <admin@parity.io>",
|
||||||
about = "Utility for generating and restoring with Substrate keys",
|
about = "Utility for generating and restoring with Substrate keys"
|
||||||
)]
|
)]
|
||||||
pub enum Subkey {
|
pub enum Subkey {
|
||||||
/// Generate a random node libp2p key, save it to file or print it to stdout
|
/// Generate a random node libp2p key, save it to file or print it to stdout
|
||||||
|
|||||||
@@ -26,5 +26,5 @@ pub enum Error {
|
|||||||
AllocatorOutOfSpace,
|
AllocatorOutOfSpace,
|
||||||
/// Some other error occurred.
|
/// Some other error occurred.
|
||||||
#[error("Other: {0}")]
|
#[error("Other: {0}")]
|
||||||
Other(&'static str)
|
Other(&'static str),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,8 +68,12 @@
|
|||||||
//! sizes.
|
//! sizes.
|
||||||
|
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use std::{mem, convert::{TryFrom, TryInto}, ops::{Range, Index, IndexMut}};
|
|
||||||
use sp_wasm_interface::{Pointer, WordSize};
|
use sp_wasm_interface::{Pointer, WordSize};
|
||||||
|
use std::{
|
||||||
|
convert::{TryFrom, TryInto},
|
||||||
|
mem,
|
||||||
|
ops::{Index, IndexMut, Range},
|
||||||
|
};
|
||||||
|
|
||||||
/// The minimal alignment guaranteed by this allocator.
|
/// The minimal alignment guaranteed by this allocator.
|
||||||
///
|
///
|
||||||
@@ -139,7 +143,7 @@ impl Order {
|
|||||||
fn from_size(size: u32) -> Result<Self, Error> {
|
fn from_size(size: u32) -> Result<Self, Error> {
|
||||||
let clamped_size = if size > MAX_POSSIBLE_ALLOCATION {
|
let clamped_size = if size > MAX_POSSIBLE_ALLOCATION {
|
||||||
log::warn!(target: LOG_TARGET, "going to fail due to allocating {:?}", size);
|
log::warn!(target: LOG_TARGET, "going to fail due to allocating {:?}", size);
|
||||||
return Err(Error::RequestedAllocationTooLarge);
|
return Err(Error::RequestedAllocationTooLarge)
|
||||||
} else if size < MIN_POSSIBLE_ALLOCATION {
|
} else if size < MIN_POSSIBLE_ALLOCATION {
|
||||||
MIN_POSSIBLE_ALLOCATION
|
MIN_POSSIBLE_ALLOCATION
|
||||||
} else {
|
} else {
|
||||||
@@ -216,7 +220,6 @@ impl Link {
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ## Occupied header
|
/// ## Occupied header
|
||||||
///
|
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// 64 32 0
|
/// 64 32 0
|
||||||
// +--------------+-------------------+
|
// +--------------+-------------------+
|
||||||
@@ -290,9 +293,7 @@ struct FreeLists {
|
|||||||
impl FreeLists {
|
impl FreeLists {
|
||||||
/// Creates the free empty lists.
|
/// Creates the free empty lists.
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self { heads: [Link::Nil; N_ORDERS] }
|
||||||
heads: [Link::Nil; N_ORDERS]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces a given link for the specified order and returns the old one.
|
/// Replaces a given link for the specified order and returns the old one.
|
||||||
@@ -397,15 +398,11 @@ impl FreeingBumpHeapAllocator {
|
|||||||
self.free_lists[order] = next_free;
|
self.free_lists[order] = next_free;
|
||||||
|
|
||||||
header_ptr
|
header_ptr
|
||||||
}
|
},
|
||||||
Link::Nil => {
|
Link::Nil => {
|
||||||
// Corresponding free list is empty. Allocate a new item.
|
// Corresponding free list is empty. Allocate a new item.
|
||||||
Self::bump(
|
Self::bump(&mut self.bumper, order.size() + HEADER_SIZE, mem.size())?
|
||||||
&mut self.bumper,
|
},
|
||||||
order.size() + HEADER_SIZE,
|
|
||||||
mem.size(),
|
|
||||||
)?
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write the order in the occupied header.
|
// Write the order in the occupied header.
|
||||||
@@ -440,7 +437,11 @@ impl FreeingBumpHeapAllocator {
|
|||||||
///
|
///
|
||||||
/// - `mem` - a slice representing the linear memory on which this allocator operates.
|
/// - `mem` - a slice representing the linear memory on which this allocator operates.
|
||||||
/// - `ptr` - pointer to the allocated chunk
|
/// - `ptr` - pointer to the allocated chunk
|
||||||
pub fn deallocate<M: Memory + ?Sized>(&mut self, mem: &mut M, ptr: Pointer<u8>) -> Result<(), Error> {
|
pub fn deallocate<M: Memory + ?Sized>(
|
||||||
|
&mut self,
|
||||||
|
mem: &mut M,
|
||||||
|
ptr: Pointer<u8>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
if self.poisoned {
|
if self.poisoned {
|
||||||
return Err(error("the allocator has been poisoned"))
|
return Err(error("the allocator has been poisoned"))
|
||||||
}
|
}
|
||||||
@@ -480,8 +481,13 @@ impl FreeingBumpHeapAllocator {
|
|||||||
/// the operation would exhaust the heap.
|
/// the operation would exhaust the heap.
|
||||||
fn bump(bumper: &mut u32, size: u32, heap_end: u32) -> Result<u32, Error> {
|
fn bump(bumper: &mut u32, size: u32, heap_end: u32) -> Result<u32, Error> {
|
||||||
if *bumper + size > heap_end {
|
if *bumper + size > heap_end {
|
||||||
log::error!(target: LOG_TARGET, "running out of space with current bumper {}, mem size {}", bumper, heap_end);
|
log::error!(
|
||||||
return Err(Error::AllocatorOutOfSpace);
|
target: LOG_TARGET,
|
||||||
|
"running out of space with current bumper {}, mem size {}",
|
||||||
|
bumper,
|
||||||
|
heap_end
|
||||||
|
);
|
||||||
|
return Err(Error::AllocatorOutOfSpace)
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = *bumper;
|
let res = *bumper;
|
||||||
|
|||||||
@@ -25,5 +25,5 @@
|
|||||||
mod error;
|
mod error;
|
||||||
mod freeing_bump;
|
mod freeing_bump;
|
||||||
|
|
||||||
pub use freeing_bump::FreeingBumpHeapAllocator;
|
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
|
pub use freeing_bump::FreeingBumpHeapAllocator;
|
||||||
|
|||||||
@@ -18,30 +18,32 @@
|
|||||||
|
|
||||||
//! Substrate Client data backend
|
//! Substrate Client data backend
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use sp_core::ChangesTrieConfigurationRange;
|
|
||||||
use sp_core::offchain::OffchainStorage;
|
|
||||||
use sp_runtime::{generic::BlockId, Justification, Justifications, Storage};
|
|
||||||
use sp_runtime::traits::{Block as BlockT, NumberFor, HashFor};
|
|
||||||
use sp_state_machine::{
|
|
||||||
ChangesTrieState, ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction,
|
|
||||||
StorageCollection, ChildStorageCollection, OffchainChangesCollection, IndexOperation,
|
|
||||||
};
|
|
||||||
use sp_storage::{StorageData, StorageKey, PrefixedStorageKey, ChildInfo};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
blockchain::{
|
blockchain::{well_known_cache_keys, Backend as BlockchainBackend},
|
||||||
Backend as BlockchainBackend, well_known_cache_keys
|
|
||||||
},
|
|
||||||
light::RemoteBlockchain,
|
light::RemoteBlockchain,
|
||||||
UsageInfo,
|
UsageInfo,
|
||||||
};
|
};
|
||||||
|
use parking_lot::RwLock;
|
||||||
use sp_blockchain;
|
use sp_blockchain;
|
||||||
use sp_consensus::BlockOrigin;
|
use sp_consensus::BlockOrigin;
|
||||||
use parking_lot::RwLock;
|
use sp_core::{offchain::OffchainStorage, ChangesTrieConfigurationRange};
|
||||||
|
use sp_runtime::{
|
||||||
|
generic::BlockId,
|
||||||
|
traits::{Block as BlockT, HashFor, NumberFor},
|
||||||
|
Justification, Justifications, Storage,
|
||||||
|
};
|
||||||
|
use sp_state_machine::{
|
||||||
|
ChangesTrieState, ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction,
|
||||||
|
ChildStorageCollection, IndexOperation, OffchainChangesCollection, StorageCollection,
|
||||||
|
};
|
||||||
|
use sp_storage::{ChildInfo, PrefixedStorageKey, StorageData, StorageKey};
|
||||||
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
pub use sp_state_machine::Backend as StateBackend;
|
|
||||||
pub use sp_consensus::ImportedState;
|
pub use sp_consensus::ImportedState;
|
||||||
|
pub use sp_state_machine::Backend as StateBackend;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// Extracts the state backend type for the given backend.
|
/// Extracts the state backend type for the given backend.
|
||||||
@@ -90,16 +92,17 @@ pub fn apply_aux<'a, 'b: 'a, 'c: 'a, B, Block, D, I>(
|
|||||||
insert: I,
|
insert: I,
|
||||||
delete: D,
|
delete: D,
|
||||||
) -> sp_blockchain::Result<()>
|
) -> sp_blockchain::Result<()>
|
||||||
where
|
where
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
B: Backend<Block>,
|
B: Backend<Block>,
|
||||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||||
{
|
{
|
||||||
operation.op.insert_aux(
|
operation.op.insert_aux(
|
||||||
insert.into_iter()
|
insert
|
||||||
|
.into_iter()
|
||||||
.map(|(k, v)| (k.to_vec(), Some(v.to_vec())))
|
.map(|(k, v)| (k.to_vec(), Some(v.to_vec())))
|
||||||
.chain(delete.into_iter().map(|k| (k.to_vec(), None)))
|
.chain(delete.into_iter().map(|k| (k.to_vec(), None))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +168,11 @@ pub trait BlockImportOperation<Block: BlockT> {
|
|||||||
|
|
||||||
/// Set genesis state. If `commit` is `false` the state is saved in memory, but is not written
|
/// Set genesis state. If `commit` is `false` the state is saved in memory, but is not written
|
||||||
/// to the database.
|
/// to the database.
|
||||||
fn set_genesis_state(&mut self, storage: Storage, commit: bool) -> sp_blockchain::Result<Block::Hash>;
|
fn set_genesis_state(
|
||||||
|
&mut self,
|
||||||
|
storage: Storage,
|
||||||
|
commit: bool,
|
||||||
|
) -> sp_blockchain::Result<Block::Hash>;
|
||||||
|
|
||||||
/// Inject storage data into the database replacing any existing data.
|
/// Inject storage data into the database replacing any existing data.
|
||||||
fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result<Block::Hash>;
|
fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result<Block::Hash>;
|
||||||
@@ -182,7 +189,7 @@ pub trait BlockImportOperation<Block: BlockT> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
_offchain_update: OffchainChangesCollection,
|
_offchain_update: OffchainChangesCollection,
|
||||||
) -> sp_blockchain::Result<()> {
|
) -> sp_blockchain::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inject changes trie data into the database.
|
/// Inject changes trie data into the database.
|
||||||
@@ -195,7 +202,8 @@ pub trait BlockImportOperation<Block: BlockT> {
|
|||||||
///
|
///
|
||||||
/// Values are `None` if should be deleted.
|
/// Values are `None` if should be deleted.
|
||||||
fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()>
|
fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()>
|
||||||
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>;
|
where
|
||||||
|
I: IntoIterator<Item = (Vec<u8>, Option<Vec<u8>>)>;
|
||||||
|
|
||||||
/// Mark a block as finalized.
|
/// Mark a block as finalized.
|
||||||
fn mark_finalized(
|
fn mark_finalized(
|
||||||
@@ -209,16 +217,17 @@ pub trait BlockImportOperation<Block: BlockT> {
|
|||||||
fn mark_head(&mut self, id: BlockId<Block>) -> sp_blockchain::Result<()>;
|
fn mark_head(&mut self, id: BlockId<Block>) -> sp_blockchain::Result<()>;
|
||||||
|
|
||||||
/// Add a transaction index operation.
|
/// Add a transaction index operation.
|
||||||
fn update_transaction_index(&mut self, index: Vec<IndexOperation>) -> sp_blockchain::Result<()>;
|
fn update_transaction_index(&mut self, index: Vec<IndexOperation>)
|
||||||
|
-> sp_blockchain::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interface for performing operations on the backend.
|
/// Interface for performing operations on the backend.
|
||||||
pub trait LockImportRun<Block: BlockT, B: Backend<Block>> {
|
pub trait LockImportRun<Block: BlockT, B: Backend<Block>> {
|
||||||
/// Lock the import lock, and run operations inside.
|
/// Lock the import lock, and run operations inside.
|
||||||
fn lock_import_and_run<R, Err, F>(&self, f: F) -> Result<R, Err>
|
fn lock_import_and_run<R, Err, F>(&self, f: F) -> Result<R, Err>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut ClientImportOperation<Block, B>) -> Result<R, Err>,
|
F: FnOnce(&mut ClientImportOperation<Block, B>) -> Result<R, Err>,
|
||||||
Err: From<sp_blockchain::Error>;
|
Err: From<sp_blockchain::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finalize Facilities
|
/// Finalize Facilities
|
||||||
@@ -270,9 +279,13 @@ pub trait AuxStore {
|
|||||||
'a,
|
'a,
|
||||||
'b: 'a,
|
'b: 'a,
|
||||||
'c: 'a,
|
'c: 'a,
|
||||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||||
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()>;
|
>(
|
||||||
|
&self,
|
||||||
|
insert: I,
|
||||||
|
delete: D,
|
||||||
|
) -> sp_blockchain::Result<()>;
|
||||||
|
|
||||||
/// Query auxiliary data from key-value store.
|
/// Query auxiliary data from key-value store.
|
||||||
fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>>;
|
fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>>;
|
||||||
@@ -287,16 +300,10 @@ pub struct KeyIterator<'a, State, Block> {
|
|||||||
_phantom: PhantomData<Block>,
|
_phantom: PhantomData<Block>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a, State, Block> KeyIterator<'a, State, Block> {
|
impl<'a, State, Block> KeyIterator<'a, State, Block> {
|
||||||
/// create a KeyIterator instance
|
/// create a KeyIterator instance
|
||||||
pub fn new(state: State, prefix: Option<&'a StorageKey>, current_key: Vec<u8>) -> Self {
|
pub fn new(state: State, prefix: Option<&'a StorageKey>, current_key: Vec<u8>) -> Self {
|
||||||
Self {
|
Self { state, child_storage: None, prefix, current_key, _phantom: PhantomData }
|
||||||
state,
|
|
||||||
child_storage: None,
|
|
||||||
prefix,
|
|
||||||
current_key,
|
|
||||||
_phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `KeyIterator` instance for a child storage.
|
/// Create a `KeyIterator` instance for a child storage.
|
||||||
@@ -306,17 +313,12 @@ impl <'a, State, Block> KeyIterator<'a, State, Block> {
|
|||||||
prefix: Option<&'a StorageKey>,
|
prefix: Option<&'a StorageKey>,
|
||||||
current_key: Vec<u8>,
|
current_key: Vec<u8>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self { state, child_storage: Some(child_info), prefix, current_key, _phantom: PhantomData }
|
||||||
state,
|
|
||||||
child_storage: Some(child_info),
|
|
||||||
prefix,
|
|
||||||
current_key,
|
|
||||||
_phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> where
|
impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block>
|
||||||
|
where
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
State: StateBackend<HashFor<Block>>,
|
State: StateBackend<HashFor<Block>>,
|
||||||
{
|
{
|
||||||
@@ -327,11 +329,13 @@ impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> where
|
|||||||
self.state.next_child_storage_key(child_info, &self.current_key)
|
self.state.next_child_storage_key(child_info, &self.current_key)
|
||||||
} else {
|
} else {
|
||||||
self.state.next_storage_key(&self.current_key)
|
self.state.next_storage_key(&self.current_key)
|
||||||
}.ok().flatten()?;
|
}
|
||||||
|
.ok()
|
||||||
|
.flatten()?;
|
||||||
// this terminates the iterator the first time it fails.
|
// this terminates the iterator the first time it fails.
|
||||||
if let Some(prefix) = self.prefix {
|
if let Some(prefix) = self.prefix {
|
||||||
if !next_key.starts_with(&prefix.0[..]) {
|
if !next_key.starts_with(&prefix.0[..]) {
|
||||||
return None;
|
return None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.current_key = next_key.clone();
|
self.current_key = next_key.clone();
|
||||||
@@ -342,19 +346,31 @@ impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> where
|
|||||||
/// Provides acess to storage primitives
|
/// Provides acess to storage primitives
|
||||||
pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||||
/// Given a `BlockId` and a key, return the value under the key in that block.
|
/// Given a `BlockId` and a key, return the value under the key in that block.
|
||||||
fn storage(&self, id: &BlockId<Block>, key: &StorageKey) -> sp_blockchain::Result<Option<StorageData>>;
|
fn storage(
|
||||||
|
&self,
|
||||||
|
id: &BlockId<Block>,
|
||||||
|
key: &StorageKey,
|
||||||
|
) -> sp_blockchain::Result<Option<StorageData>>;
|
||||||
|
|
||||||
/// Given a `BlockId` and a key prefix, return the matching storage keys in that block.
|
/// Given a `BlockId` and a key prefix, return the matching storage keys in that block.
|
||||||
fn storage_keys(&self, id: &BlockId<Block>, key_prefix: &StorageKey) -> sp_blockchain::Result<Vec<StorageKey>>;
|
fn storage_keys(
|
||||||
|
&self,
|
||||||
|
id: &BlockId<Block>,
|
||||||
|
key_prefix: &StorageKey,
|
||||||
|
) -> sp_blockchain::Result<Vec<StorageKey>>;
|
||||||
|
|
||||||
/// Given a `BlockId` and a key, return the value under the hash in that block.
|
/// Given a `BlockId` and a key, return the value under the hash in that block.
|
||||||
fn storage_hash(&self, id: &BlockId<Block>, key: &StorageKey) -> sp_blockchain::Result<Option<Block::Hash>>;
|
fn storage_hash(
|
||||||
|
&self,
|
||||||
|
id: &BlockId<Block>,
|
||||||
|
key: &StorageKey,
|
||||||
|
) -> sp_blockchain::Result<Option<Block::Hash>>;
|
||||||
|
|
||||||
/// Given a `BlockId` and a key prefix, return the matching child storage keys and values in that block.
|
/// Given a `BlockId` and a key prefix, return the matching child storage keys and values in that block.
|
||||||
fn storage_pairs(
|
fn storage_pairs(
|
||||||
&self,
|
&self,
|
||||||
id: &BlockId<Block>,
|
id: &BlockId<Block>,
|
||||||
key_prefix: &StorageKey
|
key_prefix: &StorageKey,
|
||||||
) -> sp_blockchain::Result<Vec<(StorageKey, StorageData)>>;
|
) -> sp_blockchain::Result<Vec<(StorageKey, StorageData)>>;
|
||||||
|
|
||||||
/// Given a `BlockId` and a key prefix, return a `KeyIterator` iterates matching storage keys in that block.
|
/// Given a `BlockId` and a key prefix, return a `KeyIterator` iterates matching storage keys in that block.
|
||||||
@@ -362,7 +378,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
|||||||
&self,
|
&self,
|
||||||
id: &BlockId<Block>,
|
id: &BlockId<Block>,
|
||||||
prefix: Option<&'a StorageKey>,
|
prefix: Option<&'a StorageKey>,
|
||||||
start_key: Option<&StorageKey>
|
start_key: Option<&StorageKey>,
|
||||||
) -> sp_blockchain::Result<KeyIterator<'a, B::State, Block>>;
|
) -> sp_blockchain::Result<KeyIterator<'a, B::State, Block>>;
|
||||||
|
|
||||||
/// Given a `BlockId`, a key and a child storage key, return the value under the key in that block.
|
/// Given a `BlockId`, a key and a child storage key, return the value under the key in that block.
|
||||||
@@ -370,7 +386,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
|||||||
&self,
|
&self,
|
||||||
id: &BlockId<Block>,
|
id: &BlockId<Block>,
|
||||||
child_info: &ChildInfo,
|
child_info: &ChildInfo,
|
||||||
key: &StorageKey
|
key: &StorageKey,
|
||||||
) -> sp_blockchain::Result<Option<StorageData>>;
|
) -> sp_blockchain::Result<Option<StorageData>>;
|
||||||
|
|
||||||
/// Given a `BlockId`, a key prefix, and a child storage key, return the matching child storage keys.
|
/// Given a `BlockId`, a key prefix, and a child storage key, return the matching child storage keys.
|
||||||
@@ -378,7 +394,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
|||||||
&self,
|
&self,
|
||||||
id: &BlockId<Block>,
|
id: &BlockId<Block>,
|
||||||
child_info: &ChildInfo,
|
child_info: &ChildInfo,
|
||||||
key_prefix: &StorageKey
|
key_prefix: &StorageKey,
|
||||||
) -> sp_blockchain::Result<Vec<StorageKey>>;
|
) -> sp_blockchain::Result<Vec<StorageKey>>;
|
||||||
|
|
||||||
/// Given a `BlockId` and a key `prefix` and a child storage key,
|
/// Given a `BlockId` and a key `prefix` and a child storage key,
|
||||||
@@ -388,7 +404,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
|||||||
id: &BlockId<Block>,
|
id: &BlockId<Block>,
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
prefix: Option<&'a StorageKey>,
|
prefix: Option<&'a StorageKey>,
|
||||||
start_key: Option<&StorageKey>
|
start_key: Option<&StorageKey>,
|
||||||
) -> sp_blockchain::Result<KeyIterator<'a, B::State, Block>>;
|
) -> sp_blockchain::Result<KeyIterator<'a, B::State, Block>>;
|
||||||
|
|
||||||
/// Given a `BlockId`, a key and a child storage key, return the hash under the key in that block.
|
/// Given a `BlockId`, a key and a child storage key, return the hash under the key in that block.
|
||||||
@@ -396,7 +412,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
|||||||
&self,
|
&self,
|
||||||
id: &BlockId<Block>,
|
id: &BlockId<Block>,
|
||||||
child_info: &ChildInfo,
|
child_info: &ChildInfo,
|
||||||
key: &StorageKey
|
key: &StorageKey,
|
||||||
) -> sp_blockchain::Result<Option<Block::Hash>>;
|
) -> sp_blockchain::Result<Option<Block::Hash>>;
|
||||||
|
|
||||||
/// Get longest range within [first; last] that is possible to use in `key_changes`
|
/// Get longest range within [first; last] that is possible to use in `key_changes`
|
||||||
@@ -418,7 +434,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
|||||||
first: NumberFor<Block>,
|
first: NumberFor<Block>,
|
||||||
last: BlockId<Block>,
|
last: BlockId<Block>,
|
||||||
storage_key: Option<&PrefixedStorageKey>,
|
storage_key: Option<&PrefixedStorageKey>,
|
||||||
key: &StorageKey
|
key: &StorageKey,
|
||||||
) -> sp_blockchain::Result<Vec<(NumberFor<Block>, u32)>>;
|
) -> sp_blockchain::Result<Vec<(NumberFor<Block>, u32)>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,20 +527,20 @@ pub trait Backend<Block: BlockT>: AuxStore + Send + Sync {
|
|||||||
) -> sp_blockchain::Result<(NumberFor<Block>, HashSet<Block::Hash>)>;
|
) -> sp_blockchain::Result<(NumberFor<Block>, HashSet<Block::Hash>)>;
|
||||||
|
|
||||||
/// Discard non-best, unfinalized leaf block.
|
/// Discard non-best, unfinalized leaf block.
|
||||||
fn remove_leaf_block(
|
fn remove_leaf_block(&self, hash: &Block::Hash) -> sp_blockchain::Result<()>;
|
||||||
&self,
|
|
||||||
hash: &Block::Hash,
|
|
||||||
) -> sp_blockchain::Result<()>;
|
|
||||||
|
|
||||||
/// Insert auxiliary data into key-value store.
|
/// Insert auxiliary data into key-value store.
|
||||||
fn insert_aux<
|
fn insert_aux<
|
||||||
'a,
|
'a,
|
||||||
'b: 'a,
|
'b: 'a,
|
||||||
'c: 'a,
|
'c: 'a,
|
||||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||||
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()>
|
>(
|
||||||
{
|
&self,
|
||||||
|
insert: I,
|
||||||
|
delete: D,
|
||||||
|
) -> sp_blockchain::Result<()> {
|
||||||
AuxStore::insert_aux(self, insert, delete)
|
AuxStore::insert_aux(self, insert, delete)
|
||||||
}
|
}
|
||||||
/// Query auxiliary data from key-value store.
|
/// Query auxiliary data from key-value store.
|
||||||
@@ -548,9 +564,10 @@ pub trait PrunableStateChangesTrieStorage<Block: BlockT>:
|
|||||||
/// Get reference to StateChangesTrieStorage.
|
/// Get reference to StateChangesTrieStorage.
|
||||||
fn storage(&self) -> &dyn StateChangesTrieStorage<HashFor<Block>, NumberFor<Block>>;
|
fn storage(&self) -> &dyn StateChangesTrieStorage<HashFor<Block>, NumberFor<Block>>;
|
||||||
/// Get configuration at given block.
|
/// Get configuration at given block.
|
||||||
fn configuration_at(&self, at: &BlockId<Block>) -> sp_blockchain::Result<
|
fn configuration_at(
|
||||||
ChangesTrieConfigurationRange<NumberFor<Block>, Block::Hash>
|
&self,
|
||||||
>;
|
at: &BlockId<Block>,
|
||||||
|
) -> sp_blockchain::Result<ChangesTrieConfigurationRange<NumberFor<Block>, Block::Hash>>;
|
||||||
/// Get end block (inclusive) of oldest pruned max-level (or skewed) digest trie blocks range.
|
/// Get end block (inclusive) of oldest pruned max-level (or skewed) digest trie blocks range.
|
||||||
/// It is guaranteed that we have no any changes tries before (and including) this block.
|
/// It is guaranteed that we have no any changes tries before (and including) this block.
|
||||||
/// It is guaranteed that all existing changes tries after this block are not yet pruned (if created).
|
/// It is guaranteed that all existing changes tries after this block are not yet pruned (if created).
|
||||||
@@ -584,7 +601,8 @@ pub fn changes_tries_state_at_block<'a, Block: BlockT>(
|
|||||||
|
|
||||||
let config_range = storage.configuration_at(block)?;
|
let config_range = storage.configuration_at(block)?;
|
||||||
match config_range.config {
|
match config_range.config {
|
||||||
Some(config) => Ok(Some(ChangesTrieState::new(config, config_range.zero.0, storage.storage()))),
|
Some(config) =>
|
||||||
|
Ok(Some(ChangesTrieState::new(config, config_range.zero.0, storage.storage()))),
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,19 @@
|
|||||||
|
|
||||||
//! A method call executor interface.
|
//! A method call executor interface.
|
||||||
|
|
||||||
use std::{panic::UnwindSafe, result, cell::RefCell};
|
use codec::{Decode, Encode};
|
||||||
use codec::{Encode, Decode};
|
use sc_executor::{NativeVersion, RuntimeVersion};
|
||||||
use sp_runtime::{
|
|
||||||
generic::BlockId, traits::{Block as BlockT, HashFor},
|
|
||||||
};
|
|
||||||
use sp_state_machine::{
|
|
||||||
OverlayedChanges, ExecutionManager, ExecutionStrategy, StorageProof,
|
|
||||||
};
|
|
||||||
use sc_executor::{RuntimeVersion, NativeVersion};
|
|
||||||
use sp_externalities::Extensions;
|
|
||||||
use sp_core::NativeOrEncoded;
|
use sp_core::NativeOrEncoded;
|
||||||
|
use sp_externalities::Extensions;
|
||||||
|
use sp_runtime::{
|
||||||
|
generic::BlockId,
|
||||||
|
traits::{Block as BlockT, HashFor},
|
||||||
|
};
|
||||||
|
use sp_state_machine::{ExecutionManager, ExecutionStrategy, OverlayedChanges, StorageProof};
|
||||||
|
use std::{cell::RefCell, panic::UnwindSafe, result};
|
||||||
|
|
||||||
use sp_api::{ProofRecorder, StorageTransactionCache};
|
|
||||||
use crate::execution_extensions::ExecutionExtensions;
|
use crate::execution_extensions::ExecutionExtensions;
|
||||||
|
use sp_api::{ProofRecorder, StorageTransactionCache};
|
||||||
|
|
||||||
/// Executor Provider
|
/// Executor Provider
|
||||||
pub trait ExecutorProvider<Block: BlockT> {
|
pub trait ExecutorProvider<Block: BlockT> {
|
||||||
@@ -73,7 +72,7 @@ pub trait CallExecutor<B: BlockT> {
|
|||||||
fn contextual_call<
|
fn contextual_call<
|
||||||
EM: Fn(
|
EM: Fn(
|
||||||
Result<NativeOrEncoded<R>, Self::Error>,
|
Result<NativeOrEncoded<R>, Self::Error>,
|
||||||
Result<NativeOrEncoded<R>, Self::Error>
|
Result<NativeOrEncoded<R>, Self::Error>,
|
||||||
) -> Result<NativeOrEncoded<R>, Self::Error>,
|
) -> Result<NativeOrEncoded<R>, Self::Error>,
|
||||||
R: Encode + Decode + PartialEq,
|
R: Encode + Decode + PartialEq,
|
||||||
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
|
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
|
||||||
@@ -83,14 +82,18 @@ pub trait CallExecutor<B: BlockT> {
|
|||||||
method: &str,
|
method: &str,
|
||||||
call_data: &[u8],
|
call_data: &[u8],
|
||||||
changes: &RefCell<OverlayedChanges>,
|
changes: &RefCell<OverlayedChanges>,
|
||||||
storage_transaction_cache: Option<&RefCell<
|
storage_transaction_cache: Option<
|
||||||
StorageTransactionCache<B, <Self::Backend as crate::backend::Backend<B>>::State>,
|
&RefCell<
|
||||||
>>,
|
StorageTransactionCache<B, <Self::Backend as crate::backend::Backend<B>>::State>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
execution_manager: ExecutionManager<EM>,
|
execution_manager: ExecutionManager<EM>,
|
||||||
native_call: Option<NC>,
|
native_call: Option<NC>,
|
||||||
proof_recorder: &Option<ProofRecorder<B>>,
|
proof_recorder: &Option<ProofRecorder<B>>,
|
||||||
extensions: Option<Extensions>,
|
extensions: Option<Extensions>,
|
||||||
) -> sp_blockchain::Result<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone;
|
) -> sp_blockchain::Result<NativeOrEncoded<R>>
|
||||||
|
where
|
||||||
|
ExecutionManager<EM>: Clone;
|
||||||
|
|
||||||
/// Extract RuntimeVersion of given block
|
/// Extract RuntimeVersion of given block
|
||||||
///
|
///
|
||||||
@@ -105,12 +108,13 @@ pub trait CallExecutor<B: BlockT> {
|
|||||||
mut state: S,
|
mut state: S,
|
||||||
overlay: &mut OverlayedChanges,
|
overlay: &mut OverlayedChanges,
|
||||||
method: &str,
|
method: &str,
|
||||||
call_data: &[u8]
|
call_data: &[u8],
|
||||||
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error> {
|
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error> {
|
||||||
let trie_state = state.as_trie_backend()
|
let trie_state = state.as_trie_backend().ok_or_else(|| {
|
||||||
.ok_or_else(||
|
sp_blockchain::Error::from_state(Box::new(
|
||||||
sp_blockchain::Error::from_state(Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof) as Box<_>)
|
sp_state_machine::ExecutionError::UnableToGenerateProof,
|
||||||
)?;
|
) as Box<_>)
|
||||||
|
})?;
|
||||||
self.prove_at_trie_state(trie_state, overlay, method, call_data)
|
self.prove_at_trie_state(trie_state, overlay, method, call_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +126,7 @@ pub trait CallExecutor<B: BlockT> {
|
|||||||
trie_state: &sp_state_machine::TrieBackend<S, HashFor<B>>,
|
trie_state: &sp_state_machine::TrieBackend<S, HashFor<B>>,
|
||||||
overlay: &mut OverlayedChanges,
|
overlay: &mut OverlayedChanges,
|
||||||
method: &str,
|
method: &str,
|
||||||
call_data: &[u8]
|
call_data: &[u8],
|
||||||
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error>;
|
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error>;
|
||||||
|
|
||||||
/// Get runtime version if supported.
|
/// Get runtime version if supported.
|
||||||
|
|||||||
+115
-107
@@ -25,15 +25,15 @@
|
|||||||
//! root hash. A correct proof implies that the claimed block is identical to the one
|
//! root hash. A correct proof implies that the claimed block is identical to the one
|
||||||
//! we discarded.
|
//! we discarded.
|
||||||
|
|
||||||
use hash_db;
|
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
|
use hash_db;
|
||||||
use sp_trie;
|
use sp_trie;
|
||||||
|
|
||||||
use sp_core::{H256, convert_hash};
|
use sp_core::{convert_hash, H256};
|
||||||
use sp_runtime::traits::{Header as HeaderT, AtLeast32Bit, Zero, One};
|
use sp_runtime::traits::{AtLeast32Bit, Header as HeaderT, One, Zero};
|
||||||
use sp_state_machine::{
|
use sp_state_machine::{
|
||||||
MemoryDB, TrieBackend, Backend as StateBackend, StorageProof, InMemoryBackend,
|
prove_read_on_trie_backend, read_proof_check, read_proof_check_on_proving_backend,
|
||||||
prove_read_on_trie_backend, read_proof_check, read_proof_check_on_proving_backend
|
Backend as StateBackend, InMemoryBackend, MemoryDB, StorageProof, TrieBackend,
|
||||||
};
|
};
|
||||||
|
|
||||||
use sp_blockchain::{Error as ClientError, Result as ClientResult};
|
use sp_blockchain::{Error as ClientError, Result as ClientResult};
|
||||||
@@ -49,17 +49,17 @@ pub fn size<N: From<u32>>() -> N {
|
|||||||
|
|
||||||
/// Returns Some(cht_number) if CHT is need to be built when the block with given number is canonized.
|
/// Returns Some(cht_number) if CHT is need to be built when the block with given number is canonized.
|
||||||
pub fn is_build_required<N>(cht_size: N, block_num: N) -> Option<N>
|
pub fn is_build_required<N>(cht_size: N, block_num: N) -> Option<N>
|
||||||
where
|
where
|
||||||
N: Clone + AtLeast32Bit,
|
N: Clone + AtLeast32Bit,
|
||||||
{
|
{
|
||||||
let block_cht_num = block_to_cht_number(cht_size.clone(), block_num.clone())?;
|
let block_cht_num = block_to_cht_number(cht_size.clone(), block_num.clone())?;
|
||||||
let two = N::one() + N::one();
|
let two = N::one() + N::one();
|
||||||
if block_cht_num < two {
|
if block_cht_num < two {
|
||||||
return None;
|
return None
|
||||||
}
|
}
|
||||||
let cht_start = start_number(cht_size, block_cht_num.clone());
|
let cht_start = start_number(cht_size, block_cht_num.clone());
|
||||||
if cht_start != block_num {
|
if cht_start != block_num {
|
||||||
return None;
|
return None
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(block_cht_num - two)
|
Some(block_cht_num - two)
|
||||||
@@ -67,13 +67,13 @@ pub fn is_build_required<N>(cht_size: N, block_num: N) -> Option<N>
|
|||||||
|
|
||||||
/// Returns Some(max_cht_number) if CHT has ever been built given maximal canonical block number.
|
/// Returns Some(max_cht_number) if CHT has ever been built given maximal canonical block number.
|
||||||
pub fn max_cht_number<N>(cht_size: N, max_canonical_block: N) -> Option<N>
|
pub fn max_cht_number<N>(cht_size: N, max_canonical_block: N) -> Option<N>
|
||||||
where
|
where
|
||||||
N: Clone + AtLeast32Bit,
|
N: Clone + AtLeast32Bit,
|
||||||
{
|
{
|
||||||
let max_cht_number = block_to_cht_number(cht_size, max_canonical_block)?;
|
let max_cht_number = block_to_cht_number(cht_size, max_canonical_block)?;
|
||||||
let two = N::one() + N::one();
|
let two = N::one() + N::one();
|
||||||
if max_cht_number < two {
|
if max_cht_number < two {
|
||||||
return None;
|
return None
|
||||||
}
|
}
|
||||||
Some(max_cht_number - two)
|
Some(max_cht_number - two)
|
||||||
}
|
}
|
||||||
@@ -86,16 +86,16 @@ pub fn compute_root<Header, Hasher, I>(
|
|||||||
cht_num: Header::Number,
|
cht_num: Header::Number,
|
||||||
hashes: I,
|
hashes: I,
|
||||||
) -> ClientResult<Hasher::Out>
|
) -> ClientResult<Hasher::Out>
|
||||||
where
|
where
|
||||||
Header: HeaderT,
|
Header: HeaderT,
|
||||||
Hasher: hash_db::Hasher,
|
Hasher: hash_db::Hasher,
|
||||||
Hasher::Out: Ord,
|
Hasher::Out: Ord,
|
||||||
I: IntoIterator<Item=ClientResult<Option<Header::Hash>>>,
|
I: IntoIterator<Item = ClientResult<Option<Header::Hash>>>,
|
||||||
{
|
{
|
||||||
use sp_trie::TrieConfiguration;
|
use sp_trie::TrieConfiguration;
|
||||||
Ok(sp_trie::trie_types::Layout::<Hasher>::trie_root(
|
Ok(sp_trie::trie_types::Layout::<Hasher>::trie_root(build_pairs::<Header, I>(
|
||||||
build_pairs::<Header, I>(cht_size, cht_num, hashes)?
|
cht_size, cht_num, hashes,
|
||||||
))
|
)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build CHT-based header proof.
|
/// Build CHT-based header proof.
|
||||||
@@ -103,26 +103,28 @@ pub fn build_proof<Header, Hasher, BlocksI, HashesI>(
|
|||||||
cht_size: Header::Number,
|
cht_size: Header::Number,
|
||||||
cht_num: Header::Number,
|
cht_num: Header::Number,
|
||||||
blocks: BlocksI,
|
blocks: BlocksI,
|
||||||
hashes: HashesI
|
hashes: HashesI,
|
||||||
) -> ClientResult<StorageProof>
|
) -> ClientResult<StorageProof>
|
||||||
where
|
where
|
||||||
Header: HeaderT,
|
Header: HeaderT,
|
||||||
Hasher: hash_db::Hasher,
|
Hasher: hash_db::Hasher,
|
||||||
Hasher::Out: Ord + codec::Codec,
|
Hasher::Out: Ord + codec::Codec,
|
||||||
BlocksI: IntoIterator<Item=Header::Number>,
|
BlocksI: IntoIterator<Item = Header::Number>,
|
||||||
HashesI: IntoIterator<Item=ClientResult<Option<Header::Hash>>>,
|
HashesI: IntoIterator<Item = ClientResult<Option<Header::Hash>>>,
|
||||||
{
|
{
|
||||||
let transaction = build_pairs::<Header, _>(cht_size, cht_num, hashes)?
|
let transaction = build_pairs::<Header, _>(cht_size, cht_num, hashes)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(k, v)| (k, Some(v)))
|
.map(|(k, v)| (k, Some(v)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let mut storage = InMemoryBackend::<Hasher>::default().update(vec![(None, transaction)]);
|
let mut storage = InMemoryBackend::<Hasher>::default().update(vec![(None, transaction)]);
|
||||||
let trie_storage = storage.as_trie_backend()
|
let trie_storage = storage
|
||||||
|
.as_trie_backend()
|
||||||
.expect("InMemoryState::as_trie_backend always returns Some; qed");
|
.expect("InMemoryState::as_trie_backend always returns Some; qed");
|
||||||
prove_read_on_trie_backend(
|
prove_read_on_trie_backend(
|
||||||
trie_storage,
|
trie_storage,
|
||||||
blocks.into_iter().map(|number| encode_cht_key(number)),
|
blocks.into_iter().map(|number| encode_cht_key(number)),
|
||||||
).map_err(ClientError::from_state)
|
)
|
||||||
|
.map_err(ClientError::from_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check CHT-based header proof.
|
/// Check CHT-based header proof.
|
||||||
@@ -132,25 +134,24 @@ pub fn check_proof<Header, Hasher>(
|
|||||||
remote_hash: Header::Hash,
|
remote_hash: Header::Hash,
|
||||||
remote_proof: StorageProof,
|
remote_proof: StorageProof,
|
||||||
) -> ClientResult<()>
|
) -> ClientResult<()>
|
||||||
where
|
where
|
||||||
Header: HeaderT,
|
Header: HeaderT,
|
||||||
Hasher: hash_db::Hasher,
|
Hasher: hash_db::Hasher,
|
||||||
Hasher::Out: Ord + codec::Codec,
|
Hasher::Out: Ord + codec::Codec,
|
||||||
{
|
{
|
||||||
do_check_proof::<Header, Hasher, _>(
|
do_check_proof::<Header, Hasher, _>(
|
||||||
local_root,
|
local_root,
|
||||||
local_number,
|
local_number,
|
||||||
remote_hash,
|
remote_hash,
|
||||||
move |local_root, local_cht_key|
|
move |local_root, local_cht_key| {
|
||||||
read_proof_check::<Hasher, _>(
|
read_proof_check::<Hasher, _>(
|
||||||
local_root,
|
local_root,
|
||||||
remote_proof,
|
remote_proof,
|
||||||
::std::iter::once(local_cht_key),
|
::std::iter::once(local_cht_key),
|
||||||
)
|
)
|
||||||
.map(|mut map| map
|
.map(|mut map| map.remove(local_cht_key).expect("checked proof of local_cht_key; qed"))
|
||||||
.remove(local_cht_key)
|
.map_err(ClientError::from_state)
|
||||||
.expect("checked proof of local_cht_key; qed"))
|
},
|
||||||
.map_err(ClientError::from_state),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,20 +162,19 @@ pub fn check_proof_on_proving_backend<Header, Hasher>(
|
|||||||
remote_hash: Header::Hash,
|
remote_hash: Header::Hash,
|
||||||
proving_backend: &TrieBackend<MemoryDB<Hasher>, Hasher>,
|
proving_backend: &TrieBackend<MemoryDB<Hasher>, Hasher>,
|
||||||
) -> ClientResult<()>
|
) -> ClientResult<()>
|
||||||
where
|
where
|
||||||
Header: HeaderT,
|
Header: HeaderT,
|
||||||
Hasher: hash_db::Hasher,
|
Hasher: hash_db::Hasher,
|
||||||
Hasher::Out: Ord + codec::Codec,
|
Hasher::Out: Ord + codec::Codec,
|
||||||
{
|
{
|
||||||
do_check_proof::<Header, Hasher, _>(
|
do_check_proof::<Header, Hasher, _>(
|
||||||
local_root,
|
local_root,
|
||||||
local_number,
|
local_number,
|
||||||
remote_hash,
|
remote_hash,
|
||||||
|_, local_cht_key|
|
|_, local_cht_key| {
|
||||||
read_proof_check_on_proving_backend::<Hasher>(
|
read_proof_check_on_proving_backend::<Hasher>(proving_backend, local_cht_key)
|
||||||
proving_backend,
|
.map_err(ClientError::from_state)
|
||||||
local_cht_key,
|
},
|
||||||
).map_err(ClientError::from_state),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,22 +185,22 @@ fn do_check_proof<Header, Hasher, F>(
|
|||||||
remote_hash: Header::Hash,
|
remote_hash: Header::Hash,
|
||||||
checker: F,
|
checker: F,
|
||||||
) -> ClientResult<()>
|
) -> ClientResult<()>
|
||||||
where
|
where
|
||||||
Header: HeaderT,
|
Header: HeaderT,
|
||||||
Hasher: hash_db::Hasher,
|
Hasher: hash_db::Hasher,
|
||||||
Hasher::Out: Ord,
|
Hasher::Out: Ord,
|
||||||
F: FnOnce(Hasher::Out, &[u8]) -> ClientResult<Option<Vec<u8>>>,
|
F: FnOnce(Hasher::Out, &[u8]) -> ClientResult<Option<Vec<u8>>>,
|
||||||
{
|
{
|
||||||
let root: Hasher::Out = convert_hash(&local_root);
|
let root: Hasher::Out = convert_hash(&local_root);
|
||||||
let local_cht_key = encode_cht_key(local_number);
|
let local_cht_key = encode_cht_key(local_number);
|
||||||
let local_cht_value = checker(root, &local_cht_key)?;
|
let local_cht_value = checker(root, &local_cht_key)?;
|
||||||
let local_cht_value = local_cht_value.ok_or_else(|| ClientError::InvalidCHTProof)?;
|
let local_cht_value = local_cht_value.ok_or_else(|| ClientError::InvalidCHTProof)?;
|
||||||
let local_hash = decode_cht_value(&local_cht_value).ok_or_else(|| ClientError::InvalidCHTProof)?;
|
let local_hash =
|
||||||
|
decode_cht_value(&local_cht_value).ok_or_else(|| ClientError::InvalidCHTProof)?;
|
||||||
match &local_hash[..] == remote_hash.as_ref() {
|
match &local_hash[..] == remote_hash.as_ref() {
|
||||||
true => Ok(()),
|
true => Ok(()),
|
||||||
false => Err(ClientError::InvalidCHTProof.into()),
|
false => Err(ClientError::InvalidCHTProof.into()),
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Group ordered blocks by CHT number and call functor with blocks of each group.
|
/// Group ordered blocks by CHT number and call functor with blocks of each group.
|
||||||
@@ -210,29 +210,31 @@ pub fn for_each_cht_group<Header, I, F, P>(
|
|||||||
mut functor: F,
|
mut functor: F,
|
||||||
mut functor_param: P,
|
mut functor_param: P,
|
||||||
) -> ClientResult<()>
|
) -> ClientResult<()>
|
||||||
where
|
where
|
||||||
Header: HeaderT,
|
Header: HeaderT,
|
||||||
I: IntoIterator<Item=Header::Number>,
|
I: IntoIterator<Item = Header::Number>,
|
||||||
F: FnMut(P, Header::Number, Vec<Header::Number>) -> ClientResult<P>,
|
F: FnMut(P, Header::Number, Vec<Header::Number>) -> ClientResult<P>,
|
||||||
{
|
{
|
||||||
let mut current_cht_num = None;
|
let mut current_cht_num = None;
|
||||||
let mut current_cht_blocks = Vec::new();
|
let mut current_cht_blocks = Vec::new();
|
||||||
for block in blocks {
|
for block in blocks {
|
||||||
let new_cht_num = block_to_cht_number(cht_size, block).ok_or_else(|| ClientError::Backend(format!(
|
let new_cht_num = block_to_cht_number(cht_size, block).ok_or_else(|| {
|
||||||
"Cannot compute CHT root for the block #{}", block))
|
ClientError::Backend(format!("Cannot compute CHT root for the block #{}", block))
|
||||||
)?;
|
})?;
|
||||||
|
|
||||||
let advance_to_next_cht = current_cht_num.is_some() && current_cht_num != Some(new_cht_num);
|
let advance_to_next_cht = current_cht_num.is_some() && current_cht_num != Some(new_cht_num);
|
||||||
if advance_to_next_cht {
|
if advance_to_next_cht {
|
||||||
let current_cht_num = current_cht_num.expect("advance_to_next_cht is true;
|
let current_cht_num = current_cht_num.expect(
|
||||||
it is true only when current_cht_num is Some; qed");
|
"advance_to_next_cht is true;
|
||||||
assert!(new_cht_num > current_cht_num, "for_each_cht_group only supports ordered iterators");
|
it is true only when current_cht_num is Some; qed",
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
new_cht_num > current_cht_num,
|
||||||
|
"for_each_cht_group only supports ordered iterators"
|
||||||
|
);
|
||||||
|
|
||||||
functor_param = functor(
|
functor_param =
|
||||||
functor_param,
|
functor(functor_param, current_cht_num, std::mem::take(&mut current_cht_blocks))?;
|
||||||
current_cht_num,
|
|
||||||
std::mem::take(&mut current_cht_blocks),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
current_cht_blocks.push(block);
|
current_cht_blocks.push(block);
|
||||||
@@ -240,11 +242,7 @@ pub fn for_each_cht_group<Header, I, F, P>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(current_cht_num) = current_cht_num {
|
if let Some(current_cht_num) = current_cht_num {
|
||||||
functor(
|
functor(functor_param, current_cht_num, std::mem::take(&mut current_cht_blocks))?;
|
||||||
functor_param,
|
|
||||||
current_cht_num,
|
|
||||||
std::mem::take(&mut current_cht_blocks),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -254,26 +252,22 @@ pub fn for_each_cht_group<Header, I, F, P>(
|
|||||||
fn build_pairs<Header, I>(
|
fn build_pairs<Header, I>(
|
||||||
cht_size: Header::Number,
|
cht_size: Header::Number,
|
||||||
cht_num: Header::Number,
|
cht_num: Header::Number,
|
||||||
hashes: I
|
hashes: I,
|
||||||
) -> ClientResult<Vec<(Vec<u8>, Vec<u8>)>>
|
) -> ClientResult<Vec<(Vec<u8>, Vec<u8>)>>
|
||||||
where
|
where
|
||||||
Header: HeaderT,
|
Header: HeaderT,
|
||||||
I: IntoIterator<Item=ClientResult<Option<Header::Hash>>>,
|
I: IntoIterator<Item = ClientResult<Option<Header::Hash>>>,
|
||||||
{
|
{
|
||||||
let start_num = start_number(cht_size, cht_num);
|
let start_num = start_number(cht_size, cht_num);
|
||||||
let mut pairs = Vec::new();
|
let mut pairs = Vec::new();
|
||||||
let mut hash_index = Header::Number::zero();
|
let mut hash_index = Header::Number::zero();
|
||||||
for hash in hashes.into_iter() {
|
for hash in hashes.into_iter() {
|
||||||
let hash = hash?.ok_or_else(|| ClientError::from(
|
let hash =
|
||||||
ClientError::MissingHashRequiredForCHT
|
hash?.ok_or_else(|| ClientError::from(ClientError::MissingHashRequiredForCHT))?;
|
||||||
))?;
|
pairs.push((encode_cht_key(start_num + hash_index).to_vec(), encode_cht_value(hash)));
|
||||||
pairs.push((
|
|
||||||
encode_cht_key(start_num + hash_index).to_vec(),
|
|
||||||
encode_cht_value(hash)
|
|
||||||
));
|
|
||||||
hash_index += Header::Number::one();
|
hash_index += Header::Number::one();
|
||||||
if hash_index == cht_size {
|
if hash_index == cht_size {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,7 +319,6 @@ pub fn decode_cht_value(value: &[u8]) -> Option<H256> {
|
|||||||
32 => Some(H256::from_slice(&value[0..32])),
|
32 => Some(H256::from_slice(&value[0..32])),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -379,8 +372,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn build_pairs_fails_when_no_enough_blocks() {
|
fn build_pairs_fails_when_no_enough_blocks() {
|
||||||
assert!(build_pairs::<Header, _>(SIZE as _, 0,
|
assert!(build_pairs::<Header, _>(
|
||||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize / 2)).is_err());
|
SIZE as _,
|
||||||
|
0,
|
||||||
|
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize / 2)
|
||||||
|
)
|
||||||
|
.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -391,9 +388,12 @@ mod tests {
|
|||||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
||||||
.take(SIZE as usize / 2)
|
.take(SIZE as usize / 2)
|
||||||
.chain(::std::iter::once(Ok(None)))
|
.chain(::std::iter::once(Ok(None)))
|
||||||
.chain(::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(2))))
|
.chain(
|
||||||
.take(SIZE as usize / 2 - 1))
|
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(2))))
|
||||||
).is_err());
|
.take(SIZE as usize / 2 - 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -401,9 +401,9 @@ mod tests {
|
|||||||
assert!(compute_root::<Header, BlakeTwo256, _>(
|
assert!(compute_root::<Header, BlakeTwo256, _>(
|
||||||
SIZE as _,
|
SIZE as _,
|
||||||
42,
|
42,
|
||||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize)
|
||||||
.take(SIZE as usize)
|
)
|
||||||
).is_ok());
|
.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -413,9 +413,9 @@ mod tests {
|
|||||||
SIZE as _,
|
SIZE as _,
|
||||||
0,
|
0,
|
||||||
vec![(SIZE * 1000) as u64],
|
vec![(SIZE * 1000) as u64],
|
||||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize)
|
||||||
.take(SIZE as usize)
|
)
|
||||||
).is_err());
|
.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -424,9 +424,9 @@ mod tests {
|
|||||||
SIZE as _,
|
SIZE as _,
|
||||||
0,
|
0,
|
||||||
vec![(SIZE / 2) as u64],
|
vec![(SIZE / 2) as u64],
|
||||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize)
|
||||||
.take(SIZE as usize)
|
)
|
||||||
).is_ok());
|
.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -447,19 +447,27 @@ mod tests {
|
|||||||
let _ = for_each_cht_group::<Header, _, _, _>(
|
let _ = for_each_cht_group::<Header, _, _, _>(
|
||||||
cht_size,
|
cht_size,
|
||||||
vec![
|
vec![
|
||||||
cht_size * 2 + 1, cht_size * 2 + 2, cht_size * 2 + 5,
|
cht_size * 2 + 1,
|
||||||
cht_size * 4 + 1, cht_size * 4 + 7,
|
cht_size * 2 + 2,
|
||||||
cht_size * 6 + 1
|
cht_size * 2 + 5,
|
||||||
], |_, cht_num, blocks| {
|
cht_size * 4 + 1,
|
||||||
|
cht_size * 4 + 7,
|
||||||
|
cht_size * 6 + 1,
|
||||||
|
],
|
||||||
|
|_, cht_num, blocks| {
|
||||||
match cht_num {
|
match cht_num {
|
||||||
2 => assert_eq!(blocks, vec![cht_size * 2 + 1, cht_size * 2 + 2, cht_size * 2 + 5]),
|
2 => assert_eq!(
|
||||||
|
blocks,
|
||||||
|
vec![cht_size * 2 + 1, cht_size * 2 + 2, cht_size * 2 + 5]
|
||||||
|
),
|
||||||
4 => assert_eq!(blocks, vec![cht_size * 4 + 1, cht_size * 4 + 7]),
|
4 => assert_eq!(blocks, vec![cht_size * 4 + 1, cht_size * 4 + 7]),
|
||||||
6 => assert_eq!(blocks, vec![cht_size * 6 + 1]),
|
6 => assert_eq!(blocks, vec![cht_size * 6 + 1]),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}, ()
|
},
|
||||||
|
(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,19 @@
|
|||||||
|
|
||||||
//! A set of APIs supported by the client along with their primitives.
|
//! A set of APIs supported by the client along with their primitives.
|
||||||
|
|
||||||
use std::{fmt, collections::HashSet, sync::Arc, convert::TryFrom};
|
use sp_consensus::BlockOrigin;
|
||||||
use sp_core::storage::StorageKey;
|
use sp_core::storage::StorageKey;
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
traits::{Block as BlockT, NumberFor},
|
|
||||||
generic::{BlockId, SignedBlock},
|
generic::{BlockId, SignedBlock},
|
||||||
|
traits::{Block as BlockT, NumberFor},
|
||||||
Justifications,
|
Justifications,
|
||||||
};
|
};
|
||||||
use sp_consensus::BlockOrigin;
|
use std::{collections::HashSet, convert::TryFrom, fmt, sync::Arc};
|
||||||
|
|
||||||
use crate::blockchain::Info;
|
use crate::{blockchain::Info, notifications::StorageEventStream};
|
||||||
use crate::notifications::StorageEventStream;
|
|
||||||
use sp_utils::mpsc::TracingUnboundedReceiver;
|
|
||||||
use sp_blockchain;
|
|
||||||
use sc_transaction_pool_api::ChainEvent;
|
use sc_transaction_pool_api::ChainEvent;
|
||||||
|
use sp_blockchain;
|
||||||
|
use sp_utils::mpsc::TracingUnboundedReceiver;
|
||||||
|
|
||||||
/// Type that implements `futures::Stream` of block import events.
|
/// Type that implements `futures::Stream` of block import events.
|
||||||
pub type ImportNotifications<Block> = TracingUnboundedReceiver<BlockImportNotification<Block>>;
|
pub type ImportNotifications<Block> = TracingUnboundedReceiver<BlockImportNotification<Block>>;
|
||||||
@@ -82,7 +81,7 @@ pub trait BlockBackend<Block: BlockT> {
|
|||||||
/// Get block body by ID. Returns `None` if the body is not stored.
|
/// Get block body by ID. Returns `None` if the body is not stored.
|
||||||
fn block_body(
|
fn block_body(
|
||||||
&self,
|
&self,
|
||||||
id: &BlockId<Block>
|
id: &BlockId<Block>,
|
||||||
) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
|
) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
|
||||||
|
|
||||||
/// Get all indexed transactions for a block,
|
/// Get all indexed transactions for a block,
|
||||||
@@ -99,7 +98,8 @@ pub trait BlockBackend<Block: BlockT> {
|
|||||||
fn block(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<SignedBlock<Block>>>;
|
fn block(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<SignedBlock<Block>>>;
|
||||||
|
|
||||||
/// Get block status.
|
/// Get block status.
|
||||||
fn block_status(&self, id: &BlockId<Block>) -> sp_blockchain::Result<sp_consensus::BlockStatus>;
|
fn block_status(&self, id: &BlockId<Block>)
|
||||||
|
-> sp_blockchain::Result<sp_consensus::BlockStatus>;
|
||||||
|
|
||||||
/// Get block justifications for the block with the given id.
|
/// Get block justifications for the block with the given id.
|
||||||
fn justifications(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<Justifications>>;
|
fn justifications(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<Justifications>>;
|
||||||
@@ -107,14 +107,11 @@ pub trait BlockBackend<Block: BlockT> {
|
|||||||
/// Get block hash by number.
|
/// Get block hash by number.
|
||||||
fn block_hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>>;
|
fn block_hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>>;
|
||||||
|
|
||||||
/// Get single indexed transaction by content hash.
|
/// Get single indexed transaction by content hash.
|
||||||
///
|
///
|
||||||
/// Note that this will only fetch transactions
|
/// Note that this will only fetch transactions
|
||||||
/// that are indexed by the runtime with `storage_index_transaction`.
|
/// that are indexed by the runtime with `storage_index_transaction`.
|
||||||
fn indexed_transaction(
|
fn indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result<Option<Vec<u8>>>;
|
||||||
&self,
|
|
||||||
hash: &Block::Hash,
|
|
||||||
) -> sp_blockchain::Result<Option<Vec<u8>>>;
|
|
||||||
|
|
||||||
/// Check if transaction index exists.
|
/// Check if transaction index exists.
|
||||||
fn has_indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result<bool> {
|
fn has_indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result<bool> {
|
||||||
@@ -125,8 +122,11 @@ pub trait BlockBackend<Block: BlockT> {
|
|||||||
/// Provide a list of potential uncle headers for a given block.
|
/// Provide a list of potential uncle headers for a given block.
|
||||||
pub trait ProvideUncles<Block: BlockT> {
|
pub trait ProvideUncles<Block: BlockT> {
|
||||||
/// Gets the uncles of the block with `target_hash` going back `max_generation` ancestors.
|
/// Gets the uncles of the block with `target_hash` going back `max_generation` ancestors.
|
||||||
fn uncles(&self, target_hash: Block::Hash, max_generation: NumberFor<Block>)
|
fn uncles(
|
||||||
-> sp_blockchain::Result<Vec<Block::Header>>;
|
&self,
|
||||||
|
target_hash: Block::Hash,
|
||||||
|
max_generation: NumberFor<Block>,
|
||||||
|
) -> sp_blockchain::Result<Vec<Block::Header>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Client info
|
/// Client info
|
||||||
@@ -284,10 +284,7 @@ impl<B: BlockT> TryFrom<BlockImportNotification<B>> for ChainEvent<B> {
|
|||||||
|
|
||||||
fn try_from(n: BlockImportNotification<B>) -> Result<Self, ()> {
|
fn try_from(n: BlockImportNotification<B>) -> Result<Self, ()> {
|
||||||
if n.is_new_best {
|
if n.is_new_best {
|
||||||
Ok(Self::NewBestBlock {
|
Ok(Self::NewBestBlock { hash: n.hash, tree_route: n.tree_route })
|
||||||
hash: n.hash,
|
|
||||||
tree_route: n.tree_route,
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
@@ -296,8 +293,6 @@ impl<B: BlockT> TryFrom<BlockImportNotification<B>> for ChainEvent<B> {
|
|||||||
|
|
||||||
impl<B: BlockT> From<FinalityNotification<B>> for ChainEvent<B> {
|
impl<B: BlockT> From<FinalityNotification<B>> for ChainEvent<B> {
|
||||||
fn from(n: FinalityNotification<B>) -> Self {
|
fn from(n: FinalityNotification<B>) -> Self {
|
||||||
Self::Finalized {
|
Self::Finalized { hash: n.hash }
|
||||||
hash: n.hash,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,22 +22,19 @@
|
|||||||
//! strategy for the runtime calls and provide the right `Externalities`
|
//! strategy for the runtime calls and provide the right `Externalities`
|
||||||
//! extensions to support APIs for particular execution context & capabilities.
|
//! extensions to support APIs for particular execution context & capabilities.
|
||||||
|
|
||||||
use std::sync::{Weak, Arc};
|
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
use sp_core::{
|
|
||||||
ExecutionContext,
|
|
||||||
offchain::{self, OffchainWorkerExt, TransactionPoolExt, OffchainDbExt},
|
|
||||||
};
|
|
||||||
use sp_keystore::{KeystoreExt, SyncCryptoStorePtr};
|
|
||||||
use sp_runtime::{
|
|
||||||
generic::BlockId,
|
|
||||||
traits,
|
|
||||||
};
|
|
||||||
use sp_state_machine::{ExecutionManager, DefaultHandler};
|
|
||||||
pub use sp_state_machine::ExecutionStrategy;
|
|
||||||
use sp_externalities::Extensions;
|
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use sc_transaction_pool_api::OffchainSubmitTransaction;
|
use sc_transaction_pool_api::OffchainSubmitTransaction;
|
||||||
|
use sp_core::{
|
||||||
|
offchain::{self, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt},
|
||||||
|
ExecutionContext,
|
||||||
|
};
|
||||||
|
use sp_externalities::Extensions;
|
||||||
|
use sp_keystore::{KeystoreExt, SyncCryptoStorePtr};
|
||||||
|
use sp_runtime::{generic::BlockId, traits};
|
||||||
|
pub use sp_state_machine::ExecutionStrategy;
|
||||||
|
use sp_state_machine::{DefaultHandler, ExecutionManager};
|
||||||
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
/// Execution strategies settings.
|
/// Execution strategies settings.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -151,7 +148,8 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
|||||||
|
|
||||||
/// Register transaction pool extension.
|
/// Register transaction pool extension.
|
||||||
pub fn register_transaction_pool<T>(&self, pool: &Arc<T>)
|
pub fn register_transaction_pool<T>(&self, pool: &Arc<T>)
|
||||||
where T: OffchainSubmitTransaction<Block> + 'static
|
where
|
||||||
|
T: OffchainSubmitTransaction<Block> + 'static,
|
||||||
{
|
{
|
||||||
*self.transaction_pool.write() = Some(Arc::downgrade(&pool) as _);
|
*self.transaction_pool.write() = Some(Arc::downgrade(&pool) as _);
|
||||||
}
|
}
|
||||||
@@ -171,14 +169,10 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
|||||||
|
|
||||||
if capabilities.has(offchain::Capability::TransactionPool) {
|
if capabilities.has(offchain::Capability::TransactionPool) {
|
||||||
if let Some(pool) = self.transaction_pool.read().as_ref().and_then(|x| x.upgrade()) {
|
if let Some(pool) = self.transaction_pool.read().as_ref().and_then(|x| x.upgrade()) {
|
||||||
extensions.register(
|
extensions
|
||||||
TransactionPoolExt(
|
.register(TransactionPoolExt(
|
||||||
Box::new(TransactionPoolAdapter {
|
Box::new(TransactionPoolAdapter { at: *at, pool }) as _,
|
||||||
at: *at,
|
));
|
||||||
pool,
|
|
||||||
}) as _
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,19 +180,18 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
|||||||
capabilities.has(offchain::Capability::OffchainDbWrite)
|
capabilities.has(offchain::Capability::OffchainDbWrite)
|
||||||
{
|
{
|
||||||
if let Some(offchain_db) = self.offchain_db.as_ref() {
|
if let Some(offchain_db) = self.offchain_db.as_ref() {
|
||||||
extensions.register(
|
extensions.register(OffchainDbExt::new(offchain::LimitedExternalities::new(
|
||||||
OffchainDbExt::new(offchain::LimitedExternalities::new(
|
capabilities,
|
||||||
capabilities,
|
offchain_db.create(),
|
||||||
offchain_db.create(),
|
)));
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ExecutionContext::OffchainCall(Some(ext)) = context {
|
if let ExecutionContext::OffchainCall(Some(ext)) = context {
|
||||||
extensions.register(
|
extensions.register(OffchainWorkerExt::new(offchain::LimitedExternalities::new(
|
||||||
OffchainWorkerExt::new(offchain::LimitedExternalities::new(capabilities, ext.0)),
|
capabilities,
|
||||||
);
|
ext.0,
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
extensions
|
extensions
|
||||||
@@ -212,21 +205,14 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
|||||||
&self,
|
&self,
|
||||||
at: &BlockId<Block>,
|
at: &BlockId<Block>,
|
||||||
context: ExecutionContext,
|
context: ExecutionContext,
|
||||||
) -> (
|
) -> (ExecutionManager<DefaultHandler<R, E>>, Extensions) {
|
||||||
ExecutionManager<DefaultHandler<R, E>>,
|
|
||||||
Extensions,
|
|
||||||
) {
|
|
||||||
let manager = match context {
|
let manager = match context {
|
||||||
ExecutionContext::BlockConstruction =>
|
ExecutionContext::BlockConstruction => self.strategies.block_construction.get_manager(),
|
||||||
self.strategies.block_construction.get_manager(),
|
ExecutionContext::Syncing => self.strategies.syncing.get_manager(),
|
||||||
ExecutionContext::Syncing =>
|
ExecutionContext::Importing => self.strategies.importing.get_manager(),
|
||||||
self.strategies.syncing.get_manager(),
|
|
||||||
ExecutionContext::Importing =>
|
|
||||||
self.strategies.importing.get_manager(),
|
|
||||||
ExecutionContext::OffchainCall(Some((_, capabilities))) if capabilities.has_all() =>
|
ExecutionContext::OffchainCall(Some((_, capabilities))) if capabilities.has_all() =>
|
||||||
self.strategies.offchain_worker.get_manager(),
|
self.strategies.offchain_worker.get_manager(),
|
||||||
ExecutionContext::OffchainCall(_) =>
|
ExecutionContext::OffchainCall(_) => self.strategies.other.get_manager(),
|
||||||
self.strategies.other.get_manager(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(manager, self.extensions(at, context))
|
(manager, self.extensions(at, context))
|
||||||
@@ -245,7 +231,7 @@ impl<Block: traits::Block> offchain::TransactionPool for TransactionPoolAdapter<
|
|||||||
Ok(xt) => xt,
|
Ok(xt) => xt,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Unable to decode extrinsic: {:?}: {}", data, e);
|
log::warn!("Unable to decode extrinsic: {:?}: {}", data, e);
|
||||||
return Err(());
|
return Err(())
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+231
-137
@@ -18,30 +18,31 @@
|
|||||||
|
|
||||||
//! In memory client backend
|
//! In memory client backend
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use std::ptr;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use sp_core::{
|
|
||||||
storage::well_known_keys, offchain::storage::InMemOffchainStorage as OffchainStorage,
|
|
||||||
};
|
|
||||||
use sp_runtime::generic::BlockId;
|
|
||||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Zero, NumberFor, HashFor};
|
|
||||||
use sp_runtime::{Justification, Justifications, Storage};
|
|
||||||
use sp_state_machine::{
|
|
||||||
ChangesTrieTransaction, InMemoryBackend, Backend as StateBackend, StorageCollection,
|
|
||||||
ChildStorageCollection, IndexOperation,
|
|
||||||
};
|
|
||||||
use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata};
|
use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata};
|
||||||
|
use sp_core::{
|
||||||
|
offchain::storage::InMemOffchainStorage as OffchainStorage, storage::well_known_keys,
|
||||||
|
};
|
||||||
|
use sp_runtime::{
|
||||||
|
generic::BlockId,
|
||||||
|
traits::{Block as BlockT, HashFor, Header as HeaderT, NumberFor, Zero},
|
||||||
|
Justification, Justifications, Storage,
|
||||||
|
};
|
||||||
|
use sp_state_machine::{
|
||||||
|
Backend as StateBackend, ChangesTrieTransaction, ChildStorageCollection, InMemoryBackend,
|
||||||
|
IndexOperation, StorageCollection,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
ptr,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{self, NewBlockState, ProvideChtRoots},
|
backend::{self, NewBlockState, ProvideChtRoots},
|
||||||
blockchain::{
|
blockchain::{self, well_known_cache_keys::Id as CacheKeyId, BlockStatus, HeaderBackend},
|
||||||
self, BlockStatus, HeaderBackend, well_known_cache_keys::Id as CacheKeyId
|
|
||||||
},
|
|
||||||
UsageInfo,
|
|
||||||
light,
|
|
||||||
leaves::LeafSet,
|
leaves::LeafSet,
|
||||||
|
light, UsageInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PendingBlock<B: BlockT> {
|
struct PendingBlock<B: BlockT> {
|
||||||
@@ -56,7 +57,11 @@ enum StoredBlock<B: BlockT> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<B: BlockT> StoredBlock<B> {
|
impl<B: BlockT> StoredBlock<B> {
|
||||||
fn new(header: B::Header, body: Option<Vec<B::Extrinsic>>, just: Option<Justifications>) -> Self {
|
fn new(
|
||||||
|
header: B::Header,
|
||||||
|
body: Option<Vec<B::Extrinsic>>,
|
||||||
|
just: Option<Justifications>,
|
||||||
|
) -> Self {
|
||||||
match body {
|
match body {
|
||||||
Some(body) => StoredBlock::Full(B::new(header, body), just),
|
Some(body) => StoredBlock::Full(B::new(header, body), just),
|
||||||
None => StoredBlock::Header(header, just),
|
None => StoredBlock::Header(header, just),
|
||||||
@@ -72,7 +77,7 @@ impl<B: BlockT> StoredBlock<B> {
|
|||||||
|
|
||||||
fn justifications(&self) -> Option<&Justifications> {
|
fn justifications(&self) -> Option<&Justifications> {
|
||||||
match *self {
|
match *self {
|
||||||
StoredBlock::Header(_, ref j) | StoredBlock::Full(_, ref j) => j.as_ref()
|
StoredBlock::Header(_, ref j) | StoredBlock::Full(_, ref j) => j.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +94,7 @@ impl<B: BlockT> StoredBlock<B> {
|
|||||||
StoredBlock::Full(block, just) => {
|
StoredBlock::Full(block, just) => {
|
||||||
let (header, body) = block.deconstruct();
|
let (header, body) = block.deconstruct();
|
||||||
(header, Some(body), just)
|
(header, Some(body), just)
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,9 +128,7 @@ impl<Block: BlockT> Default for Blockchain<Block> {
|
|||||||
impl<Block: BlockT + Clone> Clone for Blockchain<Block> {
|
impl<Block: BlockT + Clone> Clone for Blockchain<Block> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
let storage = Arc::new(RwLock::new(self.storage.read().clone()));
|
let storage = Arc::new(RwLock::new(self.storage.read().clone()));
|
||||||
Blockchain {
|
Blockchain { storage }
|
||||||
storage,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,23 +143,20 @@ impl<Block: BlockT> Blockchain<Block> {
|
|||||||
|
|
||||||
/// Create new in-memory blockchain storage.
|
/// Create new in-memory blockchain storage.
|
||||||
pub fn new() -> Blockchain<Block> {
|
pub fn new() -> Blockchain<Block> {
|
||||||
let storage = Arc::new(RwLock::new(
|
let storage = Arc::new(RwLock::new(BlockchainStorage {
|
||||||
BlockchainStorage {
|
blocks: HashMap::new(),
|
||||||
blocks: HashMap::new(),
|
hashes: HashMap::new(),
|
||||||
hashes: HashMap::new(),
|
best_hash: Default::default(),
|
||||||
best_hash: Default::default(),
|
best_number: Zero::zero(),
|
||||||
best_number: Zero::zero(),
|
finalized_hash: Default::default(),
|
||||||
finalized_hash: Default::default(),
|
finalized_number: Zero::zero(),
|
||||||
finalized_number: Zero::zero(),
|
genesis_hash: Default::default(),
|
||||||
genesis_hash: Default::default(),
|
header_cht_roots: HashMap::new(),
|
||||||
header_cht_roots: HashMap::new(),
|
changes_trie_cht_roots: HashMap::new(),
|
||||||
changes_trie_cht_roots: HashMap::new(),
|
leaves: LeafSet::new(),
|
||||||
leaves: LeafSet::new(),
|
aux: HashMap::new(),
|
||||||
aux: HashMap::new(),
|
}));
|
||||||
}));
|
Blockchain { storage }
|
||||||
Blockchain {
|
|
||||||
storage,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a block header and associated data.
|
/// Insert a block header and associated data.
|
||||||
@@ -175,8 +175,12 @@ impl<Block: BlockT> Blockchain<Block> {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let mut storage = self.storage.write();
|
let mut storage = self.storage.write();
|
||||||
storage.leaves.import(hash.clone(), number.clone(), header.parent_hash().clone());
|
storage
|
||||||
storage.blocks.insert(hash.clone(), StoredBlock::new(header, body, justifications));
|
.leaves
|
||||||
|
.import(hash.clone(), number.clone(), header.parent_hash().clone());
|
||||||
|
storage
|
||||||
|
.blocks
|
||||||
|
.insert(hash.clone(), StoredBlock::new(header, body, justifications));
|
||||||
|
|
||||||
if let NewBlockState::Final = new_state {
|
if let NewBlockState::Final = new_state {
|
||||||
storage.finalized_hash = hash;
|
storage.finalized_hash = hash;
|
||||||
@@ -200,7 +204,7 @@ impl<Block: BlockT> Blockchain<Block> {
|
|||||||
pub fn equals_to(&self, other: &Self) -> bool {
|
pub fn equals_to(&self, other: &Self) -> bool {
|
||||||
// Check ptr equality first to avoid double read locks.
|
// Check ptr equality first to avoid double read locks.
|
||||||
if ptr::eq(self, other) {
|
if ptr::eq(self, other) {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
self.canon_equals_to(other) && self.storage.read().blocks == other.storage.read().blocks
|
self.canon_equals_to(other) && self.storage.read().blocks == other.storage.read().blocks
|
||||||
}
|
}
|
||||||
@@ -209,14 +213,14 @@ impl<Block: BlockT> Blockchain<Block> {
|
|||||||
pub fn canon_equals_to(&self, other: &Self) -> bool {
|
pub fn canon_equals_to(&self, other: &Self) -> bool {
|
||||||
// Check ptr equality first to avoid double read locks.
|
// Check ptr equality first to avoid double read locks.
|
||||||
if ptr::eq(self, other) {
|
if ptr::eq(self, other) {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
let this = self.storage.read();
|
let this = self.storage.read();
|
||||||
let other = other.storage.read();
|
let other = other.storage.read();
|
||||||
this.hashes == other.hashes
|
this.hashes == other.hashes &&
|
||||||
&& this.best_hash == other.best_hash
|
this.best_hash == other.best_hash &&
|
||||||
&& this.best_number == other.best_number
|
this.best_number == other.best_number &&
|
||||||
&& this.genesis_hash == other.genesis_hash
|
this.genesis_hash == other.genesis_hash
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert header CHT root.
|
/// Insert header CHT root.
|
||||||
@@ -226,7 +230,8 @@ impl<Block: BlockT> Blockchain<Block> {
|
|||||||
|
|
||||||
/// Set an existing block as head.
|
/// Set an existing block as head.
|
||||||
pub fn set_head(&self, id: BlockId<Block>) -> sp_blockchain::Result<()> {
|
pub fn set_head(&self, id: BlockId<Block>) -> sp_blockchain::Result<()> {
|
||||||
let header = self.header(id)?
|
let header = self
|
||||||
|
.header(id)?
|
||||||
.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", id)))?;
|
.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", id)))?;
|
||||||
|
|
||||||
self.apply_head(&header)
|
self.apply_head(&header)
|
||||||
@@ -270,7 +275,11 @@ impl<Block: BlockT> Blockchain<Block> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finalize_header(&self, id: BlockId<Block>, justification: Option<Justification>) -> sp_blockchain::Result<()> {
|
fn finalize_header(
|
||||||
|
&self,
|
||||||
|
id: BlockId<Block>,
|
||||||
|
justification: Option<Justification>,
|
||||||
|
) -> sp_blockchain::Result<()> {
|
||||||
let hash = match self.header(id)? {
|
let hash = match self.header(id)? {
|
||||||
Some(h) => h.hash(),
|
Some(h) => h.hash(),
|
||||||
None => return Err(sp_blockchain::Error::UnknownBlock(format!("{}", id))),
|
None => return Err(sp_blockchain::Error::UnknownBlock(format!("{}", id))),
|
||||||
@@ -280,11 +289,13 @@ impl<Block: BlockT> Blockchain<Block> {
|
|||||||
storage.finalized_hash = hash;
|
storage.finalized_hash = hash;
|
||||||
|
|
||||||
if justification.is_some() {
|
if justification.is_some() {
|
||||||
let block = storage.blocks.get_mut(&hash)
|
let block = storage
|
||||||
|
.blocks
|
||||||
|
.get_mut(&hash)
|
||||||
.expect("hash was fetched from a block in the db; qed");
|
.expect("hash was fetched from a block in the db; qed");
|
||||||
|
|
||||||
let block_justifications = match block {
|
let block_justifications = match block {
|
||||||
StoredBlock::Header(_, ref mut j) | StoredBlock::Full(_, ref mut j) => j
|
StoredBlock::Header(_, ref mut j) | StoredBlock::Full(_, ref mut j) => j,
|
||||||
};
|
};
|
||||||
|
|
||||||
*block_justifications = justification.map(Justifications::from);
|
*block_justifications = justification.map(Justifications::from);
|
||||||
@@ -293,9 +304,11 @@ impl<Block: BlockT> Blockchain<Block> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_justification(&self, id: BlockId<Block>, justification: Justification)
|
fn append_justification(
|
||||||
-> sp_blockchain::Result<()>
|
&self,
|
||||||
{
|
id: BlockId<Block>,
|
||||||
|
justification: Justification,
|
||||||
|
) -> sp_blockchain::Result<()> {
|
||||||
let hash = self.expect_block_hash_from_id(&id)?;
|
let hash = self.expect_block_hash_from_id(&id)?;
|
||||||
let mut storage = self.storage.write();
|
let mut storage = self.storage.write();
|
||||||
|
|
||||||
@@ -305,14 +318,14 @@ impl<Block: BlockT> Blockchain<Block> {
|
|||||||
.expect("hash was fetched from a block in the db; qed");
|
.expect("hash was fetched from a block in the db; qed");
|
||||||
|
|
||||||
let block_justifications = match block {
|
let block_justifications = match block {
|
||||||
StoredBlock::Header(_, ref mut j) | StoredBlock::Full(_, ref mut j) => j
|
StoredBlock::Header(_, ref mut j) | StoredBlock::Full(_, ref mut j) => j,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(stored_justifications) = block_justifications {
|
if let Some(stored_justifications) = block_justifications {
|
||||||
if !stored_justifications.append(justification) {
|
if !stored_justifications.append(justification) {
|
||||||
return Err(sp_blockchain::Error::BadJustification(
|
return Err(sp_blockchain::Error::BadJustification(
|
||||||
"Duplicate consensus engine ID".into()
|
"Duplicate consensus engine ID".into(),
|
||||||
));
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*block_justifications = Some(Justifications::from(justification));
|
*block_justifications = Some(Justifications::from(justification));
|
||||||
@@ -333,10 +346,13 @@ impl<Block: BlockT> Blockchain<Block> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
|
impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
|
||||||
fn header(&self, id: BlockId<Block>) -> sp_blockchain::Result<Option<<Block as BlockT>::Header>> {
|
fn header(
|
||||||
Ok(self.id(id).and_then(|hash| {
|
&self,
|
||||||
self.storage.read().blocks.get(&hash).map(|b| b.header().clone())
|
id: BlockId<Block>,
|
||||||
}))
|
) -> sp_blockchain::Result<Option<<Block as BlockT>::Header>> {
|
||||||
|
Ok(self
|
||||||
|
.id(id)
|
||||||
|
.and_then(|hash| self.storage.read().blocks.get(&hash).map(|b| b.header().clone())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn info(&self) -> blockchain::Info<Block> {
|
fn info(&self) -> blockchain::Info<Block> {
|
||||||
@@ -352,7 +368,7 @@ impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
number_leaves: storage.leaves.count()
|
number_leaves: storage.leaves.count(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +383,10 @@ impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
|
|||||||
Ok(self.storage.read().blocks.get(&hash).map(|b| *b.header().number()))
|
Ok(self.storage.read().blocks.get(&hash).map(|b| *b.header().number()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash(&self, number: <<Block as BlockT>::Header as HeaderT>::Number) -> sp_blockchain::Result<Option<Block::Hash>> {
|
fn hash(
|
||||||
|
&self,
|
||||||
|
number: <<Block as BlockT>::Header as HeaderT>::Number,
|
||||||
|
) -> sp_blockchain::Result<Option<Block::Hash>> {
|
||||||
Ok(self.id(BlockId::Number(number)))
|
Ok(self.id(BlockId::Number(number)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -375,9 +394,15 @@ impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
|
|||||||
impl<Block: BlockT> HeaderMetadata<Block> for Blockchain<Block> {
|
impl<Block: BlockT> HeaderMetadata<Block> for Blockchain<Block> {
|
||||||
type Error = sp_blockchain::Error;
|
type Error = sp_blockchain::Error;
|
||||||
|
|
||||||
fn header_metadata(&self, hash: Block::Hash) -> Result<CachedHeaderMetadata<Block>, Self::Error> {
|
fn header_metadata(
|
||||||
self.header(BlockId::hash(hash))?.map(|header| CachedHeaderMetadata::from(&header))
|
&self,
|
||||||
.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("header not found: {}", hash)))
|
hash: Block::Hash,
|
||||||
|
) -> Result<CachedHeaderMetadata<Block>, Self::Error> {
|
||||||
|
self.header(BlockId::hash(hash))?
|
||||||
|
.map(|header| CachedHeaderMetadata::from(&header))
|
||||||
|
.ok_or_else(|| {
|
||||||
|
sp_blockchain::Error::UnknownBlock(format!("header not found: {}", hash))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_header_metadata(&self, _hash: Block::Hash, _metadata: CachedHeaderMetadata<Block>) {
|
fn insert_header_metadata(&self, _hash: Block::Hash, _metadata: CachedHeaderMetadata<Block>) {
|
||||||
@@ -389,17 +414,27 @@ impl<Block: BlockT> HeaderMetadata<Block> for Blockchain<Block> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT> blockchain::Backend<Block> for Blockchain<Block> {
|
impl<Block: BlockT> blockchain::Backend<Block> for Blockchain<Block> {
|
||||||
fn body(&self, id: BlockId<Block>) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
|
fn body(
|
||||||
|
&self,
|
||||||
|
id: BlockId<Block>,
|
||||||
|
) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
|
||||||
Ok(self.id(id).and_then(|hash| {
|
Ok(self.id(id).and_then(|hash| {
|
||||||
self.storage.read().blocks.get(&hash)
|
self.storage
|
||||||
|
.read()
|
||||||
|
.blocks
|
||||||
|
.get(&hash)
|
||||||
.and_then(|b| b.extrinsics().map(|x| x.to_vec()))
|
.and_then(|b| b.extrinsics().map(|x| x.to_vec()))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn justifications(&self, id: BlockId<Block>) -> sp_blockchain::Result<Option<Justifications>> {
|
fn justifications(&self, id: BlockId<Block>) -> sp_blockchain::Result<Option<Justifications>> {
|
||||||
Ok(self.id(id).and_then(|hash| self.storage.read().blocks.get(&hash).and_then(|b|
|
Ok(self.id(id).and_then(|hash| {
|
||||||
b.justifications().map(|x| x.clone()))
|
self.storage
|
||||||
))
|
.read()
|
||||||
|
.blocks
|
||||||
|
.get(&hash)
|
||||||
|
.and_then(|b| b.justifications().map(|x| x.clone()))
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last_finalized(&self) -> sp_blockchain::Result<Block::Hash> {
|
fn last_finalized(&self) -> sp_blockchain::Result<Block::Hash> {
|
||||||
@@ -418,16 +453,13 @@ impl<Block: BlockT> blockchain::Backend<Block> for Blockchain<Block> {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn indexed_transaction(
|
fn indexed_transaction(&self, _hash: &Block::Hash) -> sp_blockchain::Result<Option<Vec<u8>>> {
|
||||||
&self,
|
|
||||||
_hash: &Block::Hash,
|
|
||||||
) -> sp_blockchain::Result<Option<Vec<u8>>> {
|
|
||||||
unimplemented!("Not supported by the in-mem backend.")
|
unimplemented!("Not supported by the in-mem backend.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_indexed_body(
|
fn block_indexed_body(
|
||||||
&self,
|
&self,
|
||||||
_id: BlockId<Block>
|
_id: BlockId<Block>,
|
||||||
) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>> {
|
) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>> {
|
||||||
unimplemented!("Not supported by the in-mem backend.")
|
unimplemented!("Not supported by the in-mem backend.")
|
||||||
}
|
}
|
||||||
@@ -444,9 +476,13 @@ impl<Block: BlockT> backend::AuxStore for Blockchain<Block> {
|
|||||||
'a,
|
'a,
|
||||||
'b: 'a,
|
'b: 'a,
|
||||||
'c: 'a,
|
'c: 'a,
|
||||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||||
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()> {
|
>(
|
||||||
|
&self,
|
||||||
|
insert: I,
|
||||||
|
delete: D,
|
||||||
|
) -> sp_blockchain::Result<()> {
|
||||||
let mut storage = self.storage.write();
|
let mut storage = self.storage.write();
|
||||||
for (k, v) in insert {
|
for (k, v) in insert {
|
||||||
storage.aux.insert(k.to_vec(), v.to_vec());
|
storage.aux.insert(k.to_vec(), v.to_vec());
|
||||||
@@ -463,8 +499,8 @@ impl<Block: BlockT> backend::AuxStore for Blockchain<Block> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT> light::Storage<Block> for Blockchain<Block>
|
impl<Block: BlockT> light::Storage<Block> for Blockchain<Block>
|
||||||
where
|
where
|
||||||
Block::Hash: From<[u8; 32]>,
|
Block::Hash: From<[u8; 32]>,
|
||||||
{
|
{
|
||||||
fn import_header(
|
fn import_header(
|
||||||
&self,
|
&self,
|
||||||
@@ -507,8 +543,14 @@ impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
|
|||||||
_cht_size: NumberFor<Block>,
|
_cht_size: NumberFor<Block>,
|
||||||
block: NumberFor<Block>,
|
block: NumberFor<Block>,
|
||||||
) -> sp_blockchain::Result<Option<Block::Hash>> {
|
) -> sp_blockchain::Result<Option<Block::Hash>> {
|
||||||
self.storage.read().header_cht_roots.get(&block).cloned()
|
self.storage
|
||||||
.ok_or_else(|| sp_blockchain::Error::Backend(format!("Header CHT for block {} not exists", block)))
|
.read()
|
||||||
|
.header_cht_roots
|
||||||
|
.get(&block)
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
sp_blockchain::Error::Backend(format!("Header CHT for block {} not exists", block))
|
||||||
|
})
|
||||||
.map(Some)
|
.map(Some)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,8 +559,17 @@ impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
|
|||||||
_cht_size: NumberFor<Block>,
|
_cht_size: NumberFor<Block>,
|
||||||
block: NumberFor<Block>,
|
block: NumberFor<Block>,
|
||||||
) -> sp_blockchain::Result<Option<Block::Hash>> {
|
) -> sp_blockchain::Result<Option<Block::Hash>> {
|
||||||
self.storage.read().changes_trie_cht_roots.get(&block).cloned()
|
self.storage
|
||||||
.ok_or_else(|| sp_blockchain::Error::Backend(format!("Changes trie CHT for block {} not exists", block)))
|
.read()
|
||||||
|
.changes_trie_cht_roots
|
||||||
|
.get(&block)
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
sp_blockchain::Error::Backend(format!(
|
||||||
|
"Changes trie CHT for block {} not exists",
|
||||||
|
block
|
||||||
|
))
|
||||||
|
})
|
||||||
.map(Some)
|
.map(Some)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,25 +578,30 @@ impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
|
|||||||
pub struct BlockImportOperation<Block: BlockT> {
|
pub struct BlockImportOperation<Block: BlockT> {
|
||||||
pending_block: Option<PendingBlock<Block>>,
|
pending_block: Option<PendingBlock<Block>>,
|
||||||
old_state: InMemoryBackend<HashFor<Block>>,
|
old_state: InMemoryBackend<HashFor<Block>>,
|
||||||
new_state: Option<<InMemoryBackend<HashFor<Block>> as StateBackend<HashFor<Block>>>::Transaction>,
|
new_state:
|
||||||
|
Option<<InMemoryBackend<HashFor<Block>> as StateBackend<HashFor<Block>>>::Transaction>,
|
||||||
aux: Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
aux: Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
||||||
finalized_blocks: Vec<(BlockId<Block>, Option<Justification>)>,
|
finalized_blocks: Vec<(BlockId<Block>, Option<Justification>)>,
|
||||||
set_head: Option<BlockId<Block>>,
|
set_head: Option<BlockId<Block>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT> BlockImportOperation<Block> where
|
impl<Block: BlockT> BlockImportOperation<Block>
|
||||||
|
where
|
||||||
Block::Hash: Ord,
|
Block::Hash: Ord,
|
||||||
{
|
{
|
||||||
fn apply_storage(&mut self, storage: Storage, commit: bool) -> sp_blockchain::Result<Block::Hash> {
|
fn apply_storage(
|
||||||
|
&mut self,
|
||||||
|
storage: Storage,
|
||||||
|
commit: bool,
|
||||||
|
) -> sp_blockchain::Result<Block::Hash> {
|
||||||
check_genesis_storage(&storage)?;
|
check_genesis_storage(&storage)?;
|
||||||
|
|
||||||
let child_delta = storage.children_default.iter()
|
let child_delta = storage.children_default.iter().map(|(_storage_key, child_content)| {
|
||||||
.map(|(_storage_key, child_content)|
|
(
|
||||||
(
|
&child_content.child_info,
|
||||||
&child_content.child_info,
|
child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))),
|
||||||
child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref())))
|
)
|
||||||
)
|
});
|
||||||
);
|
|
||||||
|
|
||||||
let (root, transaction) = self.old_state.full_storage_root(
|
let (root, transaction) = self.old_state.full_storage_root(
|
||||||
storage.top.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))),
|
storage.top.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))),
|
||||||
@@ -559,7 +615,8 @@ impl<Block: BlockT> BlockImportOperation<Block> where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperation<Block> where
|
impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperation<Block>
|
||||||
|
where
|
||||||
Block::Hash: Ord,
|
Block::Hash: Ord,
|
||||||
{
|
{
|
||||||
type State = InMemoryBackend<HashFor<Block>>;
|
type State = InMemoryBackend<HashFor<Block>>;
|
||||||
@@ -577,10 +634,8 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
|||||||
state: NewBlockState,
|
state: NewBlockState,
|
||||||
) -> sp_blockchain::Result<()> {
|
) -> sp_blockchain::Result<()> {
|
||||||
assert!(self.pending_block.is_none(), "Only one block per operation is allowed");
|
assert!(self.pending_block.is_none(), "Only one block per operation is allowed");
|
||||||
self.pending_block = Some(PendingBlock {
|
self.pending_block =
|
||||||
block: StoredBlock::new(header, body, justifications),
|
Some(PendingBlock { block: StoredBlock::new(header, body, justifications), state });
|
||||||
state,
|
|
||||||
});
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,7 +656,11 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_genesis_state(&mut self, storage: Storage, commit: bool) -> sp_blockchain::Result<Block::Hash> {
|
fn set_genesis_state(
|
||||||
|
&mut self,
|
||||||
|
storage: Storage,
|
||||||
|
commit: bool,
|
||||||
|
) -> sp_blockchain::Result<Block::Hash> {
|
||||||
self.apply_storage(storage, commit)
|
self.apply_storage(storage, commit)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,7 +669,8 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()>
|
fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()>
|
||||||
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>
|
where
|
||||||
|
I: IntoIterator<Item = (Vec<u8>, Option<Vec<u8>>)>,
|
||||||
{
|
{
|
||||||
self.aux.append(&mut ops.into_iter().collect());
|
self.aux.append(&mut ops.into_iter().collect());
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -639,7 +699,10 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_transaction_index(&mut self, _index: Vec<IndexOperation>) -> sp_blockchain::Result<()> {
|
fn update_transaction_index(
|
||||||
|
&mut self,
|
||||||
|
_index: Vec<IndexOperation>,
|
||||||
|
) -> sp_blockchain::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -648,13 +711,19 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
|||||||
///
|
///
|
||||||
/// > **Warning**: Doesn't support all the features necessary for a proper database. Only use this
|
/// > **Warning**: Doesn't support all the features necessary for a proper database. Only use this
|
||||||
/// > struct for testing purposes. Do **NOT** use in production.
|
/// > struct for testing purposes. Do **NOT** use in production.
|
||||||
pub struct Backend<Block: BlockT> where Block::Hash: Ord {
|
pub struct Backend<Block: BlockT>
|
||||||
|
where
|
||||||
|
Block::Hash: Ord,
|
||||||
|
{
|
||||||
states: RwLock<HashMap<Block::Hash, InMemoryBackend<HashFor<Block>>>>,
|
states: RwLock<HashMap<Block::Hash, InMemoryBackend<HashFor<Block>>>>,
|
||||||
blockchain: Blockchain<Block>,
|
blockchain: Blockchain<Block>,
|
||||||
import_lock: RwLock<()>,
|
import_lock: RwLock<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT> Backend<Block> where Block::Hash: Ord {
|
impl<Block: BlockT> Backend<Block>
|
||||||
|
where
|
||||||
|
Block::Hash: Ord,
|
||||||
|
{
|
||||||
/// Create a new instance of in-mem backend.
|
/// Create a new instance of in-mem backend.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Backend {
|
Backend {
|
||||||
@@ -665,14 +734,21 @@ impl<Block: BlockT> Backend<Block> where Block::Hash: Ord {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT> backend::AuxStore for Backend<Block> where Block::Hash: Ord {
|
impl<Block: BlockT> backend::AuxStore for Backend<Block>
|
||||||
|
where
|
||||||
|
Block::Hash: Ord,
|
||||||
|
{
|
||||||
fn insert_aux<
|
fn insert_aux<
|
||||||
'a,
|
'a,
|
||||||
'b: 'a,
|
'b: 'a,
|
||||||
'c: 'a,
|
'c: 'a,
|
||||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||||
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()> {
|
>(
|
||||||
|
&self,
|
||||||
|
insert: I,
|
||||||
|
delete: D,
|
||||||
|
) -> sp_blockchain::Result<()> {
|
||||||
self.blockchain.insert_aux(insert, delete)
|
self.blockchain.insert_aux(insert, delete)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,7 +757,10 @@ impl<Block: BlockT> backend::AuxStore for Backend<Block> where Block::Hash: Ord
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash: Ord {
|
impl<Block: BlockT> backend::Backend<Block> for Backend<Block>
|
||||||
|
where
|
||||||
|
Block::Hash: Ord,
|
||||||
|
{
|
||||||
type BlockImportOperation = BlockImportOperation<Block>;
|
type BlockImportOperation = BlockImportOperation<Block>;
|
||||||
type Blockchain = Blockchain<Block>;
|
type Blockchain = Blockchain<Block>;
|
||||||
type State = InMemoryBackend<HashFor<Block>>;
|
type State = InMemoryBackend<HashFor<Block>>;
|
||||||
@@ -708,10 +787,7 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit_operation(
|
fn commit_operation(&self, operation: Self::BlockImportOperation) -> sp_blockchain::Result<()> {
|
||||||
&self,
|
|
||||||
operation: Self::BlockImportOperation,
|
|
||||||
) -> sp_blockchain::Result<()> {
|
|
||||||
if !operation.finalized_blocks.is_empty() {
|
if !operation.finalized_blocks.is_empty() {
|
||||||
for (block, justification) in operation.finalized_blocks {
|
for (block, justification) in operation.finalized_blocks {
|
||||||
self.blockchain.finalize_header(block, justification)?;
|
self.blockchain.finalize_header(block, justification)?;
|
||||||
@@ -779,13 +855,13 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
|||||||
|
|
||||||
fn state_at(&self, block: BlockId<Block>) -> sp_blockchain::Result<Self::State> {
|
fn state_at(&self, block: BlockId<Block>) -> sp_blockchain::Result<Self::State> {
|
||||||
match block {
|
match block {
|
||||||
BlockId::Hash(h) if h == Default::default() => {
|
BlockId::Hash(h) if h == Default::default() => return Ok(Self::State::default()),
|
||||||
return Ok(Self::State::default());
|
|
||||||
},
|
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
self.blockchain.id(block).and_then(|id| self.states.read().get(&id).cloned())
|
self.blockchain
|
||||||
|
.id(block)
|
||||||
|
.and_then(|id| self.states.read().get(&id).cloned())
|
||||||
.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", block)))
|
.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", block)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -797,10 +873,7 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
|||||||
Ok((Zero::zero(), HashSet::new()))
|
Ok((Zero::zero(), HashSet::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_leaf_block(
|
fn remove_leaf_block(&self, _hash: &Block::Hash) -> sp_blockchain::Result<()> {
|
||||||
&self,
|
|
||||||
_hash: &Block::Hash,
|
|
||||||
) -> sp_blockchain::Result<()> {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,9 +884,13 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
|||||||
|
|
||||||
impl<Block: BlockT> backend::LocalBackend<Block> for Backend<Block> where Block::Hash: Ord {}
|
impl<Block: BlockT> backend::LocalBackend<Block> for Backend<Block> where Block::Hash: Ord {}
|
||||||
|
|
||||||
impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block> where Block::Hash: Ord {
|
impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block>
|
||||||
|
where
|
||||||
|
Block::Hash: Ord,
|
||||||
|
{
|
||||||
fn is_local_state_available(&self, block: &BlockId<Block>) -> bool {
|
fn is_local_state_available(&self, block: &BlockId<Block>) -> bool {
|
||||||
self.blockchain.expect_block_number_from_id(block)
|
self.blockchain
|
||||||
|
.expect_block_number_from_id(block)
|
||||||
.map(|num| num.is_zero())
|
.map(|num| num.is_zero())
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
@@ -826,12 +903,15 @@ impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block> where Block
|
|||||||
/// Check that genesis storage is valid.
|
/// Check that genesis storage is valid.
|
||||||
pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
|
pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
|
||||||
if storage.top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) {
|
if storage.top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) {
|
||||||
return Err(sp_blockchain::Error::InvalidState.into());
|
return Err(sp_blockchain::Error::InvalidState.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
if storage.children_default.keys()
|
if storage
|
||||||
.any(|child_key| !well_known_keys::is_child_storage_key(&child_key)) {
|
.children_default
|
||||||
return Err(sp_blockchain::Error::InvalidState.into());
|
.keys()
|
||||||
|
.any(|child_key| !well_known_keys::is_child_storage_key(&child_key))
|
||||||
|
{
|
||||||
|
return Err(sp_blockchain::Error::InvalidState.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -839,10 +919,10 @@ pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{NewBlockState, in_mem::Blockchain};
|
use crate::{in_mem::Blockchain, NewBlockState};
|
||||||
use sp_api::{BlockId, HeaderT};
|
use sp_api::{BlockId, HeaderT};
|
||||||
use sp_runtime::{ConsensusEngineId, Justifications};
|
|
||||||
use sp_blockchain::Backend;
|
use sp_blockchain::Backend;
|
||||||
|
use sp_runtime::{ConsensusEngineId, Justifications};
|
||||||
use substrate_test_runtime::{Block, Header, H256};
|
use substrate_test_runtime::{Block, Header, H256};
|
||||||
|
|
||||||
pub const ID1: ConsensusEngineId = *b"TST1";
|
pub const ID1: ConsensusEngineId = *b"TST1";
|
||||||
@@ -853,7 +933,13 @@ mod tests {
|
|||||||
0 => Default::default(),
|
0 => Default::default(),
|
||||||
_ => header(number - 1).hash(),
|
_ => header(number - 1).hash(),
|
||||||
};
|
};
|
||||||
Header::new(number, H256::from_low_u64_be(0), H256::from_low_u64_be(0), parent_hash, Default::default())
|
Header::new(
|
||||||
|
number,
|
||||||
|
H256::from_low_u64_be(0),
|
||||||
|
H256::from_low_u64_be(0),
|
||||||
|
parent_hash,
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_blockchain() -> Blockchain<Block> {
|
fn test_blockchain() -> Blockchain<Block> {
|
||||||
@@ -862,10 +948,18 @@ mod tests {
|
|||||||
let just1 = Some(Justifications::from((ID1, vec![1])));
|
let just1 = Some(Justifications::from((ID1, vec![1])));
|
||||||
let just2 = None;
|
let just2 = None;
|
||||||
let just3 = Some(Justifications::from((ID1, vec![3])));
|
let just3 = Some(Justifications::from((ID1, vec![3])));
|
||||||
blockchain.insert(header(0).hash(), header(0), just0, None, NewBlockState::Final).unwrap();
|
blockchain
|
||||||
blockchain.insert(header(1).hash(), header(1), just1, None, NewBlockState::Final).unwrap();
|
.insert(header(0).hash(), header(0), just0, None, NewBlockState::Final)
|
||||||
blockchain.insert(header(2).hash(), header(2), just2, None, NewBlockState::Best).unwrap();
|
.unwrap();
|
||||||
blockchain.insert(header(3).hash(), header(3), just3, None, NewBlockState::Final).unwrap();
|
blockchain
|
||||||
|
.insert(header(1).hash(), header(1), just1, None, NewBlockState::Final)
|
||||||
|
.unwrap();
|
||||||
|
blockchain
|
||||||
|
.insert(header(2).hash(), header(2), just2, None, NewBlockState::Best)
|
||||||
|
.unwrap();
|
||||||
|
blockchain
|
||||||
|
.insert(header(3).hash(), header(3), just3, None, NewBlockState::Final)
|
||||||
|
.unwrap();
|
||||||
blockchain
|
blockchain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,11 @@
|
|||||||
|
|
||||||
//! Helper for managing the set of available leaves in the chain for DB implementations.
|
//! Helper for managing the set of available leaves in the chain for DB implementations.
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use codec::{Decode, Encode};
|
||||||
use std::cmp::Reverse;
|
use sp_blockchain::{Error, Result};
|
||||||
use sp_database::{Database, Transaction};
|
use sp_database::{Database, Transaction};
|
||||||
use sp_runtime::traits::AtLeast32Bit;
|
use sp_runtime::traits::AtLeast32Bit;
|
||||||
use codec::{Encode, Decode};
|
use std::{cmp::Reverse, collections::BTreeMap};
|
||||||
use sp_blockchain::{Error, Result};
|
|
||||||
|
|
||||||
type DbHash = sp_core::H256;
|
type DbHash = sp_core::H256;
|
||||||
|
|
||||||
@@ -57,7 +56,7 @@ impl<H, N: Ord> FinalizationDisplaced<H, N> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over all displaced leaves.
|
/// Iterate over all displaced leaves.
|
||||||
pub fn leaves(&self) -> impl IntoIterator<Item=&H> {
|
pub fn leaves(&self) -> impl IntoIterator<Item = &H> {
|
||||||
self.leaves.values().flatten()
|
self.leaves.values().flatten()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,17 +71,14 @@ pub struct LeafSet<H, N> {
|
|||||||
pending_removed: Vec<H>,
|
pending_removed: Vec<H>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, N> LeafSet<H, N> where
|
impl<H, N> LeafSet<H, N>
|
||||||
|
where
|
||||||
H: Clone + PartialEq + Decode + Encode,
|
H: Clone + PartialEq + Decode + Encode,
|
||||||
N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode,
|
N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode,
|
||||||
{
|
{
|
||||||
/// Construct a new, blank leaf set.
|
/// Construct a new, blank leaf set.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self { storage: BTreeMap::new(), pending_added: Vec::new(), pending_removed: Vec::new() }
|
||||||
storage: BTreeMap::new(),
|
|
||||||
pending_added: Vec::new(),
|
|
||||||
pending_removed: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read the leaf list from the DB, using given prefix for keys.
|
/// Read the leaf list from the DB, using given prefix for keys.
|
||||||
@@ -98,14 +94,10 @@ impl<H, N> LeafSet<H, N> where
|
|||||||
for (number, hashes) in vals.into_iter() {
|
for (number, hashes) in vals.into_iter() {
|
||||||
storage.insert(Reverse(number), hashes);
|
storage.insert(Reverse(number), hashes);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
None => {},
|
None => {},
|
||||||
}
|
}
|
||||||
Ok(Self {
|
Ok(Self { storage, pending_added: Vec::new(), pending_removed: Vec::new() })
|
||||||
storage,
|
|
||||||
pending_added: Vec::new(),
|
|
||||||
pending_removed: Vec::new(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// update the leaf list on import. returns a displaced leaf if there was one.
|
/// update the leaf list on import. returns a displaced leaf if there was one.
|
||||||
@@ -119,10 +111,7 @@ impl<H, N> LeafSet<H, N> where
|
|||||||
self.pending_removed.push(parent_hash.clone());
|
self.pending_removed.push(parent_hash.clone());
|
||||||
Some(ImportDisplaced {
|
Some(ImportDisplaced {
|
||||||
new_hash: hash.clone(),
|
new_hash: hash.clone(),
|
||||||
displaced: LeafSetItem {
|
displaced: LeafSetItem { hash: parent_hash, number: new_number },
|
||||||
hash: parent_hash,
|
|
||||||
number: new_number,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -144,16 +133,15 @@ impl<H, N> LeafSet<H, N> where
|
|||||||
/// will be pruned soon afterwards anyway.
|
/// will be pruned soon afterwards anyway.
|
||||||
pub fn finalize_height(&mut self, number: N) -> FinalizationDisplaced<H, N> {
|
pub fn finalize_height(&mut self, number: N) -> FinalizationDisplaced<H, N> {
|
||||||
let boundary = if number == N::zero() {
|
let boundary = if number == N::zero() {
|
||||||
return FinalizationDisplaced { leaves: BTreeMap::new() };
|
return FinalizationDisplaced { leaves: BTreeMap::new() }
|
||||||
} else {
|
} else {
|
||||||
number - N::one()
|
number - N::one()
|
||||||
};
|
};
|
||||||
|
|
||||||
let below_boundary = self.storage.split_off(&Reverse(boundary));
|
let below_boundary = self.storage.split_off(&Reverse(boundary));
|
||||||
self.pending_removed.extend(below_boundary.values().flat_map(|h| h.iter()).cloned());
|
self.pending_removed
|
||||||
FinalizationDisplaced {
|
.extend(below_boundary.values().flat_map(|h| h.iter()).cloned());
|
||||||
leaves: below_boundary,
|
FinalizationDisplaced { leaves: below_boundary }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Undo all pending operations.
|
/// Undo all pending operations.
|
||||||
@@ -169,7 +157,9 @@ impl<H, N> LeafSet<H, N> where
|
|||||||
/// Revert to the given block height by dropping all leaves in the leaf set
|
/// Revert to the given block height by dropping all leaves in the leaf set
|
||||||
/// with a block number higher than the target.
|
/// with a block number higher than the target.
|
||||||
pub fn revert(&mut self, best_hash: H, best_number: N) {
|
pub fn revert(&mut self, best_hash: H, best_number: N) {
|
||||||
let items = self.storage.iter()
|
let items = self
|
||||||
|
.storage
|
||||||
|
.iter()
|
||||||
.flat_map(|(number, hashes)| hashes.iter().map(move |h| (h.clone(), number.clone())))
|
.flat_map(|(number, hashes)| hashes.iter().map(move |h| (h.clone(), number.clone())))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
@@ -185,7 +175,8 @@ impl<H, N> LeafSet<H, N> where
|
|||||||
}
|
}
|
||||||
|
|
||||||
let best_number = Reverse(best_number);
|
let best_number = Reverse(best_number);
|
||||||
let leaves_contains_best = self.storage
|
let leaves_contains_best = self
|
||||||
|
.storage
|
||||||
.get(&best_number)
|
.get(&best_number)
|
||||||
.map_or(false, |hashes| hashes.contains(&best_hash));
|
.map_or(false, |hashes| hashes.contains(&best_hash));
|
||||||
|
|
||||||
@@ -209,7 +200,12 @@ impl<H, N> LeafSet<H, N> where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write the leaf list to the database transaction.
|
/// Write the leaf list to the database transaction.
|
||||||
pub fn prepare_transaction(&mut self, tx: &mut Transaction<DbHash>, column: u32, prefix: &[u8]) {
|
pub fn prepare_transaction(
|
||||||
|
&mut self,
|
||||||
|
tx: &mut Transaction<DbHash>,
|
||||||
|
column: u32,
|
||||||
|
prefix: &[u8],
|
||||||
|
) {
|
||||||
let leaves: Vec<_> = self.storage.iter().map(|(n, h)| (n.0.clone(), h.clone())).collect();
|
let leaves: Vec<_> = self.storage.iter().map(|(n, h)| (n.0.clone(), h.clone())).collect();
|
||||||
tx.set_from_vec(column, prefix, leaves.encode());
|
tx.set_from_vec(column, prefix, leaves.encode());
|
||||||
self.pending_added.clear();
|
self.pending_added.clear();
|
||||||
@@ -218,7 +214,9 @@ impl<H, N> LeafSet<H, N> where
|
|||||||
|
|
||||||
/// Check if given block is a leaf.
|
/// Check if given block is a leaf.
|
||||||
pub fn contains(&self, number: N, hash: H) -> bool {
|
pub fn contains(&self, number: N, hash: H) -> bool {
|
||||||
self.storage.get(&Reverse(number)).map_or(false, |hashes| hashes.contains(&hash))
|
self.storage
|
||||||
|
.get(&Reverse(number))
|
||||||
|
.map_or(false, |hashes| hashes.contains(&hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_leaf(&mut self, number: Reverse<N>, hash: H) {
|
fn insert_leaf(&mut self, number: Reverse<N>, hash: H) {
|
||||||
@@ -230,14 +228,18 @@ impl<H, N> LeafSet<H, N> where
|
|||||||
let mut empty = false;
|
let mut empty = false;
|
||||||
let removed = self.storage.get_mut(number).map_or(false, |leaves| {
|
let removed = self.storage.get_mut(number).map_or(false, |leaves| {
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
leaves.retain(|h| if h == hash {
|
leaves.retain(|h| {
|
||||||
found = true;
|
if h == hash {
|
||||||
false
|
found = true;
|
||||||
} else {
|
false
|
||||||
true
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if leaves.is_empty() { empty = true }
|
if leaves.is_empty() {
|
||||||
|
empty = true
|
||||||
|
}
|
||||||
|
|
||||||
found
|
found
|
||||||
});
|
});
|
||||||
@@ -255,7 +257,8 @@ pub struct Undo<'a, H: 'a, N: 'a> {
|
|||||||
inner: &'a mut LeafSet<H, N>,
|
inner: &'a mut LeafSet<H, N>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, H: 'a, N: 'a> Undo<'a, H, N> where
|
impl<'a, H: 'a, N: 'a> Undo<'a, H, N>
|
||||||
|
where
|
||||||
H: Clone + PartialEq + Decode + Encode,
|
H: Clone + PartialEq + Decode + Encode,
|
||||||
N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode,
|
N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode,
|
||||||
{
|
{
|
||||||
@@ -329,7 +332,7 @@ mod tests {
|
|||||||
fn two_leaves_same_height_can_be_included() {
|
fn two_leaves_same_height_can_be_included() {
|
||||||
let mut set = LeafSet::new();
|
let mut set = LeafSet::new();
|
||||||
|
|
||||||
set.import(1_1u32, 10u32,0u32);
|
set.import(1_1u32, 10u32, 0u32);
|
||||||
set.import(1_2, 10, 0);
|
set.import(1_2, 10, 0);
|
||||||
|
|
||||||
assert!(set.storage.contains_key(&Reverse(10)));
|
assert!(set.storage.contains_key(&Reverse(10)));
|
||||||
|
|||||||
@@ -21,30 +21,28 @@
|
|||||||
|
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
pub mod call_executor;
|
pub mod call_executor;
|
||||||
pub mod client;
|
|
||||||
pub mod cht;
|
pub mod cht;
|
||||||
|
pub mod client;
|
||||||
pub mod execution_extensions;
|
pub mod execution_extensions;
|
||||||
pub mod in_mem;
|
pub mod in_mem;
|
||||||
pub mod light;
|
|
||||||
pub mod leaves;
|
pub mod leaves;
|
||||||
|
pub mod light;
|
||||||
pub mod notifications;
|
pub mod notifications;
|
||||||
pub mod proof_provider;
|
pub mod proof_provider;
|
||||||
|
|
||||||
pub use sp_blockchain as blockchain;
|
|
||||||
pub use backend::*;
|
pub use backend::*;
|
||||||
pub use notifications::*;
|
|
||||||
pub use call_executor::*;
|
pub use call_executor::*;
|
||||||
pub use client::*;
|
pub use client::*;
|
||||||
pub use light::*;
|
pub use light::*;
|
||||||
pub use notifications::*;
|
pub use notifications::*;
|
||||||
pub use proof_provider::*;
|
pub use proof_provider::*;
|
||||||
|
pub use sp_blockchain as blockchain;
|
||||||
pub use sp_blockchain::HeaderBackend;
|
pub use sp_blockchain::HeaderBackend;
|
||||||
|
|
||||||
pub use sp_state_machine::{StorageProof, ExecutionStrategy};
|
pub use sp_state_machine::{ExecutionStrategy, StorageProof};
|
||||||
pub use sp_storage::{StorageData, StorageKey, PrefixedStorageKey, ChildInfo};
|
pub use sp_storage::{ChildInfo, PrefixedStorageKey, StorageData, StorageKey};
|
||||||
|
|
||||||
/// Usage Information Provider interface
|
/// Usage Information Provider interface
|
||||||
///
|
|
||||||
pub trait UsageProvider<Block: sp_runtime::traits::Block> {
|
pub trait UsageProvider<Block: sp_runtime::traits::Block> {
|
||||||
/// Get usage info about current client.
|
/// Get usage info about current client.
|
||||||
fn usage_info(&self) -> ClientInfo<Block>;
|
fn usage_info(&self) -> ClientInfo<Block>;
|
||||||
@@ -52,7 +50,7 @@ pub trait UsageProvider<Block: sp_runtime::traits::Block> {
|
|||||||
|
|
||||||
/// Utility methods for the client.
|
/// Utility methods for the client.
|
||||||
pub mod utils {
|
pub mod utils {
|
||||||
use sp_blockchain::{HeaderBackend, HeaderMetadata, Error};
|
use sp_blockchain::{Error, HeaderBackend, HeaderMetadata};
|
||||||
use sp_runtime::traits::Block as BlockT;
|
use sp_runtime::traits::Block as BlockT;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
@@ -66,19 +64,24 @@ pub mod utils {
|
|||||||
client: &'a T,
|
client: &'a T,
|
||||||
current: Option<(Block::Hash, Block::Hash)>,
|
current: Option<(Block::Hash, Block::Hash)>,
|
||||||
) -> impl Fn(&Block::Hash, &Block::Hash) -> Result<bool, Error> + 'a
|
) -> impl Fn(&Block::Hash, &Block::Hash) -> Result<bool, Error> + 'a
|
||||||
where T: HeaderBackend<Block> + HeaderMetadata<Block, Error = Error>,
|
where
|
||||||
|
T: HeaderBackend<Block> + HeaderMetadata<Block, Error = Error>,
|
||||||
{
|
{
|
||||||
move |base, hash| {
|
move |base, hash| {
|
||||||
if base == hash { return Ok(false); }
|
if base == hash {
|
||||||
|
return Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
let current = current.as_ref().map(|(c, p)| (c.borrow(), p.borrow()));
|
let current = current.as_ref().map(|(c, p)| (c.borrow(), p.borrow()));
|
||||||
|
|
||||||
let mut hash = hash;
|
let mut hash = hash;
|
||||||
if let Some((current_hash, current_parent_hash)) = current {
|
if let Some((current_hash, current_parent_hash)) = current {
|
||||||
if base == current_hash { return Ok(false); }
|
if base == current_hash {
|
||||||
|
return Ok(false)
|
||||||
|
}
|
||||||
if hash == current_hash {
|
if hash == current_hash {
|
||||||
if base == current_parent_hash {
|
if base == current_parent_hash {
|
||||||
return Ok(true);
|
return Ok(true)
|
||||||
} else {
|
} else {
|
||||||
hash = current_parent_hash;
|
hash = current_parent_hash;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,23 +18,26 @@
|
|||||||
|
|
||||||
//! Substrate light client interfaces
|
//! Substrate light client interfaces
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{
|
||||||
use std::collections::{BTreeMap, HashMap};
|
collections::{BTreeMap, HashMap},
|
||||||
use std::future::Future;
|
future::Future,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use sp_runtime::{
|
use crate::{
|
||||||
traits::{
|
backend::{AuxStore, NewBlockState},
|
||||||
Block as BlockT, Header as HeaderT, NumberFor,
|
ProvideChtRoots, UsageInfo,
|
||||||
},
|
|
||||||
generic::BlockId
|
|
||||||
};
|
};
|
||||||
use sp_core::{ChangesTrieConfigurationRange, storage::PrefixedStorageKey};
|
|
||||||
use sp_state_machine::StorageProof;
|
|
||||||
use sp_blockchain::{
|
use sp_blockchain::{
|
||||||
HeaderMetadata, well_known_cache_keys, HeaderBackend, Cache as BlockchainCache,
|
well_known_cache_keys, Cache as BlockchainCache, Error as ClientError, HeaderBackend,
|
||||||
Error as ClientError, Result as ClientResult,
|
HeaderMetadata, Result as ClientResult,
|
||||||
};
|
};
|
||||||
use crate::{backend::{AuxStore, NewBlockState}, UsageInfo, ProvideChtRoots};
|
use sp_core::{storage::PrefixedStorageKey, ChangesTrieConfigurationRange};
|
||||||
|
use sp_runtime::{
|
||||||
|
generic::BlockId,
|
||||||
|
traits::{Block as BlockT, Header as HeaderT, NumberFor},
|
||||||
|
};
|
||||||
|
use sp_state_machine::StorageProof;
|
||||||
|
|
||||||
/// Remote call request.
|
/// Remote call request.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
@@ -142,48 +145,48 @@ pub struct RemoteBodyRequest<Header: HeaderT> {
|
|||||||
/// is correct (see FetchedDataChecker) and return already checked data.
|
/// is correct (see FetchedDataChecker) and return already checked data.
|
||||||
pub trait Fetcher<Block: BlockT>: Send + Sync {
|
pub trait Fetcher<Block: BlockT>: Send + Sync {
|
||||||
/// Remote header future.
|
/// Remote header future.
|
||||||
type RemoteHeaderResult: Future<Output = Result<
|
type RemoteHeaderResult: Future<Output = Result<Block::Header, ClientError>>
|
||||||
Block::Header,
|
+ Unpin
|
||||||
ClientError,
|
+ Send
|
||||||
>> + Unpin + Send + 'static;
|
+ 'static;
|
||||||
/// Remote storage read future.
|
/// Remote storage read future.
|
||||||
type RemoteReadResult: Future<Output = Result<
|
type RemoteReadResult: Future<Output = Result<HashMap<Vec<u8>, Option<Vec<u8>>>, ClientError>>
|
||||||
HashMap<Vec<u8>, Option<Vec<u8>>>,
|
+ Unpin
|
||||||
ClientError,
|
+ Send
|
||||||
>> + Unpin + Send + 'static;
|
+ 'static;
|
||||||
/// Remote call result future.
|
/// Remote call result future.
|
||||||
type RemoteCallResult: Future<Output = Result<
|
type RemoteCallResult: Future<Output = Result<Vec<u8>, ClientError>> + Unpin + Send + 'static;
|
||||||
Vec<u8>,
|
|
||||||
ClientError,
|
|
||||||
>> + Unpin + Send + 'static;
|
|
||||||
/// Remote changes result future.
|
/// Remote changes result future.
|
||||||
type RemoteChangesResult: Future<Output = Result<
|
type RemoteChangesResult: Future<Output = Result<Vec<(NumberFor<Block>, u32)>, ClientError>>
|
||||||
Vec<(NumberFor<Block>, u32)>,
|
+ Unpin
|
||||||
ClientError,
|
+ Send
|
||||||
>> + Unpin + Send + 'static;
|
+ 'static;
|
||||||
/// Remote block body result future.
|
/// Remote block body result future.
|
||||||
type RemoteBodyResult: Future<Output = Result<
|
type RemoteBodyResult: Future<Output = Result<Vec<Block::Extrinsic>, ClientError>>
|
||||||
Vec<Block::Extrinsic>,
|
+ Unpin
|
||||||
ClientError,
|
+ Send
|
||||||
>> + Unpin + Send + 'static;
|
+ 'static;
|
||||||
|
|
||||||
/// Fetch remote header.
|
/// Fetch remote header.
|
||||||
fn remote_header(&self, request: RemoteHeaderRequest<Block::Header>) -> Self::RemoteHeaderResult;
|
fn remote_header(
|
||||||
/// Fetch remote storage value.
|
|
||||||
fn remote_read(
|
|
||||||
&self,
|
&self,
|
||||||
request: RemoteReadRequest<Block::Header>
|
request: RemoteHeaderRequest<Block::Header>,
|
||||||
) -> Self::RemoteReadResult;
|
) -> Self::RemoteHeaderResult;
|
||||||
|
/// Fetch remote storage value.
|
||||||
|
fn remote_read(&self, request: RemoteReadRequest<Block::Header>) -> Self::RemoteReadResult;
|
||||||
/// Fetch remote storage child value.
|
/// Fetch remote storage child value.
|
||||||
fn remote_read_child(
|
fn remote_read_child(
|
||||||
&self,
|
&self,
|
||||||
request: RemoteReadChildRequest<Block::Header>
|
request: RemoteReadChildRequest<Block::Header>,
|
||||||
) -> Self::RemoteReadResult;
|
) -> Self::RemoteReadResult;
|
||||||
/// Fetch remote call result.
|
/// Fetch remote call result.
|
||||||
fn remote_call(&self, request: RemoteCallRequest<Block::Header>) -> Self::RemoteCallResult;
|
fn remote_call(&self, request: RemoteCallRequest<Block::Header>) -> Self::RemoteCallResult;
|
||||||
/// Fetch remote changes ((block number, extrinsic index)) where given key has been changed
|
/// Fetch remote changes ((block number, extrinsic index)) where given key has been changed
|
||||||
/// at a given blocks range.
|
/// at a given blocks range.
|
||||||
fn remote_changes(&self, request: RemoteChangesRequest<Block::Header>) -> Self::RemoteChangesResult;
|
fn remote_changes(
|
||||||
|
&self,
|
||||||
|
request: RemoteChangesRequest<Block::Header>,
|
||||||
|
) -> Self::RemoteChangesResult;
|
||||||
/// Fetch remote block body
|
/// Fetch remote block body
|
||||||
fn remote_body(&self, request: RemoteBodyRequest<Block::Header>) -> Self::RemoteBodyResult;
|
fn remote_body(&self, request: RemoteBodyRequest<Block::Header>) -> Self::RemoteBodyResult;
|
||||||
}
|
}
|
||||||
@@ -222,20 +225,22 @@ pub trait FetchChecker<Block: BlockT>: Send + Sync {
|
|||||||
fn check_changes_proof(
|
fn check_changes_proof(
|
||||||
&self,
|
&self,
|
||||||
request: &RemoteChangesRequest<Block::Header>,
|
request: &RemoteChangesRequest<Block::Header>,
|
||||||
proof: ChangesProof<Block::Header>
|
proof: ChangesProof<Block::Header>,
|
||||||
) -> ClientResult<Vec<(NumberFor<Block>, u32)>>;
|
) -> ClientResult<Vec<(NumberFor<Block>, u32)>>;
|
||||||
/// Check remote body proof.
|
/// Check remote body proof.
|
||||||
fn check_body_proof(
|
fn check_body_proof(
|
||||||
&self,
|
&self,
|
||||||
request: &RemoteBodyRequest<Block::Header>,
|
request: &RemoteBodyRequest<Block::Header>,
|
||||||
body: Vec<Block::Extrinsic>
|
body: Vec<Block::Extrinsic>,
|
||||||
) -> ClientResult<Vec<Block::Extrinsic>>;
|
) -> ClientResult<Vec<Block::Extrinsic>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Light client blockchain storage.
|
/// Light client blockchain storage.
|
||||||
pub trait Storage<Block: BlockT>: AuxStore + HeaderBackend<Block>
|
pub trait Storage<Block: BlockT>:
|
||||||
+ HeaderMetadata<Block, Error=ClientError> + ProvideChtRoots<Block>
|
AuxStore
|
||||||
|
+ HeaderBackend<Block>
|
||||||
|
+ HeaderMetadata<Block, Error = ClientError>
|
||||||
|
+ ProvideChtRoots<Block>
|
||||||
{
|
{
|
||||||
/// Store new header. Should refuse to revert any finalized blocks.
|
/// Store new header. Should refuse to revert any finalized blocks.
|
||||||
///
|
///
|
||||||
@@ -280,10 +285,10 @@ pub enum LocalOrRemote<Data, Request> {
|
|||||||
/// locally, or fetches required data from remote node.
|
/// locally, or fetches required data from remote node.
|
||||||
pub trait RemoteBlockchain<Block: BlockT>: Send + Sync {
|
pub trait RemoteBlockchain<Block: BlockT>: Send + Sync {
|
||||||
/// Get block header.
|
/// Get block header.
|
||||||
fn header(&self, id: BlockId<Block>) -> ClientResult<LocalOrRemote<
|
fn header(
|
||||||
Block::Header,
|
&self,
|
||||||
RemoteHeaderRequest<Block::Header>,
|
id: BlockId<Block>,
|
||||||
>>;
|
) -> ClientResult<LocalOrRemote<Block::Header, RemoteHeaderRequest<Block::Header>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns future that resolves header either locally, or remotely.
|
/// Returns future that resolves header either locally, or remotely.
|
||||||
@@ -295,11 +300,8 @@ pub fn future_header<Block: BlockT, F: Fetcher<Block>>(
|
|||||||
use futures::future::{ready, Either, FutureExt};
|
use futures::future::{ready, Either, FutureExt};
|
||||||
|
|
||||||
match blockchain.header(id) {
|
match blockchain.header(id) {
|
||||||
Ok(LocalOrRemote::Remote(request)) => Either::Left(
|
Ok(LocalOrRemote::Remote(request)) =>
|
||||||
fetcher
|
Either::Left(fetcher.remote_header(request).then(|header| ready(header.map(Some)))),
|
||||||
.remote_header(request)
|
|
||||||
.then(|header| ready(header.map(Some)))
|
|
||||||
),
|
|
||||||
Ok(LocalOrRemote::Unknown) => Either::Right(ready(Ok(None))),
|
Ok(LocalOrRemote::Unknown) => Either::Right(ready(Ok(None))),
|
||||||
Ok(LocalOrRemote::Local(local_header)) => Either::Right(ready(Ok(Some(local_header)))),
|
Ok(LocalOrRemote::Local(local_header)) => Either::Right(ready(Ok(Some(local_header)))),
|
||||||
Err(err) => Either::Right(ready(Err(err))),
|
Err(err) => Either::Right(ready(Err(err))),
|
||||||
@@ -308,11 +310,11 @@ pub fn future_header<Block: BlockT, F: Fetcher<Block>>(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
|
use super::*;
|
||||||
use futures::future::Ready;
|
use futures::future::Ready;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use sp_blockchain::Error as ClientError;
|
use sp_blockchain::Error as ClientError;
|
||||||
use sp_test_primitives::{Block, Header, Extrinsic};
|
use sp_test_primitives::{Block, Extrinsic, Header};
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
#[error("Not implemented on test node")]
|
#[error("Not implemented on test node")]
|
||||||
@@ -322,12 +324,11 @@ pub mod tests {
|
|||||||
fn into(self) -> ClientError {
|
fn into(self) -> ClientError {
|
||||||
ClientError::Application(Box::new(self))
|
ClientError::Application(Box::new(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type OkCallFetcher = Mutex<Vec<u8>>;
|
pub type OkCallFetcher = Mutex<Vec<u8>>;
|
||||||
|
|
||||||
fn not_implemented_in_tests<T>() -> Ready<Result<T, ClientError>>
|
fn not_implemented_in_tests<T>() -> Ready<Result<T, ClientError>> {
|
||||||
{
|
|
||||||
futures::future::ready(Err(MockError.into()))
|
futures::future::ready(Err(MockError.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,7 +347,10 @@ pub mod tests {
|
|||||||
not_implemented_in_tests()
|
not_implemented_in_tests()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remote_read_child(&self, _request: RemoteReadChildRequest<Header>) -> Self::RemoteReadResult {
|
fn remote_read_child(
|
||||||
|
&self,
|
||||||
|
_request: RemoteReadChildRequest<Header>,
|
||||||
|
) -> Self::RemoteReadResult {
|
||||||
not_implemented_in_tests()
|
not_implemented_in_tests()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +358,10 @@ pub mod tests {
|
|||||||
futures::future::ready(Ok((*self.lock()).clone()))
|
futures::future::ready(Ok((*self.lock()).clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remote_changes(&self, _request: RemoteChangesRequest<Header>) -> Self::RemoteChangesResult {
|
fn remote_changes(
|
||||||
|
&self,
|
||||||
|
_request: RemoteChangesRequest<Header>,
|
||||||
|
) -> Self::RemoteChangesResult {
|
||||||
not_implemented_in_tests()
|
not_implemented_in_tests()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,15 +19,15 @@
|
|||||||
//! Storage notifications
|
//! Storage notifications
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashSet, HashMap},
|
collections::{HashMap, HashSet},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use fnv::{FnvHashSet, FnvHashMap};
|
use fnv::{FnvHashMap, FnvHashSet};
|
||||||
use sp_core::storage::{StorageKey, StorageData};
|
use prometheus_endpoint::{register, CounterVec, Opts, Registry, U64};
|
||||||
|
use sp_core::storage::{StorageData, StorageKey};
|
||||||
use sp_runtime::traits::Block as BlockT;
|
use sp_runtime::traits::Block as BlockT;
|
||||||
use sp_utils::mpsc::{TracingUnboundedSender, TracingUnboundedReceiver, tracing_unbounded};
|
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
|
||||||
use prometheus_endpoint::{Registry, CounterVec, Opts, U64, register};
|
|
||||||
|
|
||||||
/// Storage change set
|
/// Storage change set
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -40,29 +40,34 @@ pub struct StorageChangeSet {
|
|||||||
|
|
||||||
impl StorageChangeSet {
|
impl StorageChangeSet {
|
||||||
/// Convert the change set into iterator over storage items.
|
/// Convert the change set into iterator over storage items.
|
||||||
pub fn iter<'a>(&'a self)
|
pub fn iter<'a>(
|
||||||
-> impl Iterator<Item=(Option<&'a StorageKey>, &'a StorageKey, Option<&'a StorageData>)> + 'a {
|
&'a self,
|
||||||
let top = self.changes
|
) -> impl Iterator<Item = (Option<&'a StorageKey>, &'a StorageKey, Option<&'a StorageData>)> + 'a
|
||||||
|
{
|
||||||
|
let top = self
|
||||||
|
.changes
|
||||||
.iter()
|
.iter()
|
||||||
.filter(move |&(key, _)| match self.filter {
|
.filter(move |&(key, _)| match self.filter {
|
||||||
Some(ref filter) => filter.contains(key),
|
Some(ref filter) => filter.contains(key),
|
||||||
None => true,
|
None => true,
|
||||||
})
|
})
|
||||||
.map(move |(k,v)| (None, k, v.as_ref()));
|
.map(move |(k, v)| (None, k, v.as_ref()));
|
||||||
let children = self.child_changes
|
let children = self
|
||||||
|
.child_changes
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(move |(sk, changes)|
|
.filter_map(move |(sk, changes)| {
|
||||||
self.child_filters.as_ref().and_then(|cf|
|
self.child_filters.as_ref().and_then(|cf| {
|
||||||
cf.get(sk).map(|filter| changes
|
cf.get(sk).map(|filter| {
|
||||||
|
changes
|
||||||
.iter()
|
.iter()
|
||||||
.filter(move |&(key, _)| match filter {
|
.filter(move |&(key, _)| match filter {
|
||||||
Some(ref filter) => filter.contains(key),
|
Some(ref filter) => filter.contains(key),
|
||||||
None => true,
|
None => true,
|
||||||
})
|
})
|
||||||
.map(move |(k,v)| (Some(sk), k, v.as_ref()))
|
.map(move |(k, v)| (Some(sk), k, v.as_ref()))
|
||||||
)
|
})
|
||||||
)
|
})
|
||||||
)
|
})
|
||||||
.flatten();
|
.flatten();
|
||||||
top.chain(children)
|
top.chain(children)
|
||||||
}
|
}
|
||||||
@@ -82,15 +87,18 @@ pub struct StorageNotifications<Block: BlockT> {
|
|||||||
next_id: SubscriberId,
|
next_id: SubscriberId,
|
||||||
wildcard_listeners: FnvHashSet<SubscriberId>,
|
wildcard_listeners: FnvHashSet<SubscriberId>,
|
||||||
listeners: HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
listeners: HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
||||||
child_listeners: HashMap<StorageKey, (
|
child_listeners: HashMap<
|
||||||
HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
StorageKey,
|
||||||
FnvHashSet<SubscriberId>
|
(HashMap<StorageKey, FnvHashSet<SubscriberId>>, FnvHashSet<SubscriberId>),
|
||||||
)>,
|
>,
|
||||||
sinks: FnvHashMap<SubscriberId, (
|
sinks: FnvHashMap<
|
||||||
TracingUnboundedSender<(Block::Hash, StorageChangeSet)>,
|
SubscriberId,
|
||||||
Option<HashSet<StorageKey>>,
|
(
|
||||||
Option<HashMap<StorageKey, Option<HashSet<StorageKey>>>>,
|
TracingUnboundedSender<(Block::Hash, StorageChangeSet)>,
|
||||||
)>,
|
Option<HashSet<StorageKey>>,
|
||||||
|
Option<HashMap<StorageKey, Option<HashSet<StorageKey>>>>,
|
||||||
|
),
|
||||||
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT> Default for StorageNotifications<Block> {
|
impl<Block: BlockT> Default for StorageNotifications<Block> {
|
||||||
@@ -110,16 +118,17 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
|||||||
/// Initialize a new StorageNotifications
|
/// Initialize a new StorageNotifications
|
||||||
/// optionally pass a prometheus registry to send subscriber metrics to
|
/// optionally pass a prometheus registry to send subscriber metrics to
|
||||||
pub fn new(prometheus_registry: Option<Registry>) -> Self {
|
pub fn new(prometheus_registry: Option<Registry>) -> Self {
|
||||||
let metrics = prometheus_registry.and_then(|r|
|
let metrics = prometheus_registry.and_then(|r| {
|
||||||
CounterVec::new(
|
CounterVec::new(
|
||||||
Opts::new(
|
Opts::new(
|
||||||
"storage_notification_subscribers",
|
"storage_notification_subscribers",
|
||||||
"Number of subscribers in storage notification sytem"
|
"Number of subscribers in storage notification sytem",
|
||||||
),
|
),
|
||||||
&["action"], //added | removed
|
&["action"], // added | removed
|
||||||
).and_then(|g| register(g, &r))
|
)
|
||||||
|
.and_then(|g| register(g, &r))
|
||||||
.ok()
|
.ok()
|
||||||
);
|
});
|
||||||
|
|
||||||
StorageNotifications {
|
StorageNotifications {
|
||||||
metrics,
|
metrics,
|
||||||
@@ -137,17 +146,16 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
|||||||
pub fn trigger(
|
pub fn trigger(
|
||||||
&mut self,
|
&mut self,
|
||||||
hash: &Block::Hash,
|
hash: &Block::Hash,
|
||||||
changeset: impl Iterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
changeset: impl Iterator<Item = (Vec<u8>, Option<Vec<u8>>)>,
|
||||||
child_changeset: impl Iterator<
|
child_changeset: impl Iterator<
|
||||||
Item=(Vec<u8>, impl Iterator<Item=(Vec<u8>, Option<Vec<u8>>)>)
|
Item = (Vec<u8>, impl Iterator<Item = (Vec<u8>, Option<Vec<u8>>)>),
|
||||||
>,
|
>,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
let has_wildcard = !self.wildcard_listeners.is_empty();
|
let has_wildcard = !self.wildcard_listeners.is_empty();
|
||||||
|
|
||||||
// early exit if no listeners
|
// early exit if no listeners
|
||||||
if !has_wildcard && self.listeners.is_empty() && self.child_listeners.is_empty() {
|
if !has_wildcard && self.listeners.is_empty() && self.child_listeners.is_empty() {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut subscribers = self.wildcard_listeners.clone();
|
let mut subscribers = self.wildcard_listeners.clone();
|
||||||
@@ -193,24 +201,29 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
|||||||
|
|
||||||
// Don't send empty notifications
|
// Don't send empty notifications
|
||||||
if changes.is_empty() && child_changes.is_empty() {
|
if changes.is_empty() && child_changes.is_empty() {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let changes = Arc::new(changes);
|
let changes = Arc::new(changes);
|
||||||
let child_changes = Arc::new(child_changes);
|
let child_changes = Arc::new(child_changes);
|
||||||
// Trigger the events
|
// Trigger the events
|
||||||
|
|
||||||
let to_remove = self.sinks
|
let to_remove = self
|
||||||
|
.sinks
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(subscriber, &(ref sink, ref filter, ref child_filters))| {
|
.filter_map(|(subscriber, &(ref sink, ref filter, ref child_filters))| {
|
||||||
let should_remove = {
|
let should_remove = {
|
||||||
if subscribers.contains(subscriber) {
|
if subscribers.contains(subscriber) {
|
||||||
sink.unbounded_send((hash.clone(), StorageChangeSet {
|
sink.unbounded_send((
|
||||||
changes: changes.clone(),
|
hash.clone(),
|
||||||
child_changes: child_changes.clone(),
|
StorageChangeSet {
|
||||||
filter: filter.clone(),
|
changes: changes.clone(),
|
||||||
child_filters: child_filters.clone(),
|
child_changes: child_changes.clone(),
|
||||||
})).is_err()
|
filter: filter.clone(),
|
||||||
|
child_filters: child_filters.clone(),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
.is_err()
|
||||||
} else {
|
} else {
|
||||||
sink.is_closed()
|
sink.is_closed()
|
||||||
}
|
}
|
||||||
@@ -221,7 +234,8 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}).collect::<Vec<_>>();
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
for sub_id in to_remove {
|
for sub_id in to_remove {
|
||||||
self.remove_subscriber(sub_id);
|
self.remove_subscriber(sub_id);
|
||||||
@@ -233,13 +247,12 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
|||||||
filters: &Option<HashSet<StorageKey>>,
|
filters: &Option<HashSet<StorageKey>>,
|
||||||
listeners: &mut HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
listeners: &mut HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
||||||
wildcards: &mut FnvHashSet<SubscriberId>,
|
wildcards: &mut FnvHashSet<SubscriberId>,
|
||||||
){
|
) {
|
||||||
match filters {
|
match filters {
|
||||||
None => {
|
None => {
|
||||||
wildcards.remove(subscriber);
|
wildcards.remove(subscriber);
|
||||||
},
|
},
|
||||||
Some(filters) => {
|
Some(filters) =>
|
||||||
|
|
||||||
for key in filters.iter() {
|
for key in filters.iter() {
|
||||||
let remove_key = match listeners.get_mut(key) {
|
let remove_key = match listeners.get_mut(key) {
|
||||||
Some(ref mut set) => {
|
Some(ref mut set) => {
|
||||||
@@ -252,8 +265,7 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
|||||||
if remove_key {
|
if remove_key {
|
||||||
listeners.remove(key);
|
listeners.remove(key);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,7 +279,6 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
|||||||
);
|
);
|
||||||
if let Some(child_filters) = child_filters.as_ref() {
|
if let Some(child_filters) = child_filters.as_ref() {
|
||||||
for (c_key, filters) in child_filters {
|
for (c_key, filters) in child_filters {
|
||||||
|
|
||||||
if let Some((listeners, wildcards)) = self.child_listeners.get_mut(&c_key) {
|
if let Some((listeners, wildcards)) = self.child_listeners.get_mut(&c_key) {
|
||||||
Self::remove_subscriber_from(
|
Self::remove_subscriber_from(
|
||||||
&subscriber,
|
&subscriber,
|
||||||
@@ -293,20 +304,24 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
|||||||
filter_keys: &Option<impl AsRef<[StorageKey]>>,
|
filter_keys: &Option<impl AsRef<[StorageKey]>>,
|
||||||
listeners: &mut HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
listeners: &mut HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
||||||
wildcards: &mut FnvHashSet<SubscriberId>,
|
wildcards: &mut FnvHashSet<SubscriberId>,
|
||||||
) -> Option<HashSet<StorageKey>>
|
) -> Option<HashSet<StorageKey>> {
|
||||||
{
|
|
||||||
match filter_keys {
|
match filter_keys {
|
||||||
None => {
|
None => {
|
||||||
wildcards.insert(current_id);
|
wildcards.insert(current_id);
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
Some(keys) => Some(keys.as_ref().iter().map(|key| {
|
Some(keys) => Some(
|
||||||
listeners
|
keys.as_ref()
|
||||||
.entry(key.clone())
|
.iter()
|
||||||
.or_insert_with(Default::default)
|
.map(|key| {
|
||||||
.insert(current_id);
|
listeners
|
||||||
key.clone()
|
.entry(key.clone())
|
||||||
}).collect())
|
.or_insert_with(Default::default)
|
||||||
|
.insert(current_id);
|
||||||
|
key.clone()
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,21 +342,20 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
|||||||
&mut self.wildcard_listeners,
|
&mut self.wildcard_listeners,
|
||||||
);
|
);
|
||||||
let child_keys = filter_child_keys.map(|filter_child_keys| {
|
let child_keys = filter_child_keys.map(|filter_child_keys| {
|
||||||
filter_child_keys.iter().map(|(c_key, o_keys)| {
|
filter_child_keys
|
||||||
let (c_listeners, c_wildcards) = self.child_listeners
|
.iter()
|
||||||
.entry(c_key.clone())
|
.map(|(c_key, o_keys)| {
|
||||||
.or_insert_with(Default::default);
|
let (c_listeners, c_wildcards) =
|
||||||
|
self.child_listeners.entry(c_key.clone()).or_insert_with(Default::default);
|
||||||
|
|
||||||
(c_key.clone(), Self::listen_from(
|
(
|
||||||
current_id,
|
c_key.clone(),
|
||||||
o_keys,
|
Self::listen_from(current_id, o_keys, &mut *c_listeners, &mut *c_wildcards),
|
||||||
&mut *c_listeners,
|
)
|
||||||
&mut *c_wildcards,
|
})
|
||||||
))
|
.collect()
|
||||||
}).collect()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// insert sink
|
// insert sink
|
||||||
let (tx, rx) = tracing_unbounded("mpsc_storage_notification_items");
|
let (tx, rx) = tracing_unbounded("mpsc_storage_notification_items");
|
||||||
self.sinks.insert(current_id, (tx, keys, child_keys));
|
self.sinks.insert(current_id, (tx, keys, child_keys));
|
||||||
@@ -356,8 +370,8 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use sp_runtime::testing::{H256 as Hash, Block as RawBlock, ExtrinsicWrapper};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash};
|
||||||
use std::iter::{empty, Empty};
|
use std::iter::{empty, Empty};
|
||||||
|
|
||||||
type TestChangeSet = (
|
type TestChangeSet = (
|
||||||
@@ -369,10 +383,12 @@ mod tests {
|
|||||||
impl From<TestChangeSet> for StorageChangeSet {
|
impl From<TestChangeSet> for StorageChangeSet {
|
||||||
fn from(changes: TestChangeSet) -> Self {
|
fn from(changes: TestChangeSet) -> Self {
|
||||||
// warning hardcoded child trie wildcard to test upon
|
// warning hardcoded child trie wildcard to test upon
|
||||||
let child_filters = Some([
|
let child_filters = Some(
|
||||||
(StorageKey(vec![4]), None),
|
[(StorageKey(vec![4]), None), (StorageKey(vec![5]), None)]
|
||||||
(StorageKey(vec![5]), None),
|
.iter()
|
||||||
].iter().cloned().collect());
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
StorageChangeSet {
|
StorageChangeSet {
|
||||||
changes: Arc::new(changes.0),
|
changes: Arc::new(changes.0),
|
||||||
child_changes: Arc::new(changes.1),
|
child_changes: Arc::new(changes.1),
|
||||||
@@ -396,34 +412,40 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let mut notifications = StorageNotifications::<Block>::default();
|
let mut notifications = StorageNotifications::<Block>::default();
|
||||||
let child_filter = [(StorageKey(vec![4]), None)];
|
let child_filter = [(StorageKey(vec![4]), None)];
|
||||||
let mut recv = futures::executor::block_on_stream(
|
let mut recv =
|
||||||
notifications.listen(None, Some(&child_filter[..]))
|
futures::executor::block_on_stream(notifications.listen(None, Some(&child_filter[..])));
|
||||||
);
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let changeset = vec![
|
let changeset = vec![(vec![2], Some(vec![3])), (vec![3], None)];
|
||||||
(vec![2], Some(vec![3])),
|
let c_changeset_1 = vec![(vec![5], Some(vec![4])), (vec![6], None)];
|
||||||
(vec![3], None),
|
|
||||||
];
|
|
||||||
let c_changeset_1 = vec![
|
|
||||||
(vec![5], Some(vec![4])),
|
|
||||||
(vec![6], None),
|
|
||||||
];
|
|
||||||
let c_changeset = vec![(vec![4], c_changeset_1)];
|
let c_changeset = vec![(vec![4], c_changeset_1)];
|
||||||
notifications.trigger(
|
notifications.trigger(
|
||||||
&Hash::from_low_u64_be(1),
|
&Hash::from_low_u64_be(1),
|
||||||
changeset.into_iter(),
|
changeset.into_iter(),
|
||||||
c_changeset.into_iter().map(|(a,b)| (a, b.into_iter())),
|
c_changeset.into_iter().map(|(a, b)| (a, b.into_iter())),
|
||||||
);
|
);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(recv.next().unwrap(), (Hash::from_low_u64_be(1), (vec![
|
assert_eq!(
|
||||||
(StorageKey(vec![2]), Some(StorageData(vec![3]))),
|
recv.next().unwrap(),
|
||||||
(StorageKey(vec![3]), None),
|
(
|
||||||
], vec![(StorageKey(vec![4]), vec![
|
Hash::from_low_u64_be(1),
|
||||||
(StorageKey(vec![5]), Some(StorageData(vec![4]))),
|
(
|
||||||
(StorageKey(vec![6]), None),
|
vec![
|
||||||
])]).into()));
|
(StorageKey(vec![2]), Some(StorageData(vec![3]))),
|
||||||
|
(StorageKey(vec![3]), None),
|
||||||
|
],
|
||||||
|
vec![(
|
||||||
|
StorageKey(vec![4]),
|
||||||
|
vec![
|
||||||
|
(StorageKey(vec![5]), Some(StorageData(vec![4]))),
|
||||||
|
(StorageKey(vec![6]), None),
|
||||||
|
]
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -432,44 +454,52 @@ mod tests {
|
|||||||
let mut notifications = StorageNotifications::<Block>::default();
|
let mut notifications = StorageNotifications::<Block>::default();
|
||||||
let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))];
|
let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))];
|
||||||
let mut recv1 = futures::executor::block_on_stream(
|
let mut recv1 = futures::executor::block_on_stream(
|
||||||
notifications.listen(Some(&[StorageKey(vec![1])]), None)
|
notifications.listen(Some(&[StorageKey(vec![1])]), None),
|
||||||
);
|
);
|
||||||
let mut recv2 = futures::executor::block_on_stream(
|
let mut recv2 = futures::executor::block_on_stream(
|
||||||
notifications.listen(Some(&[StorageKey(vec![2])]), None)
|
notifications.listen(Some(&[StorageKey(vec![2])]), None),
|
||||||
);
|
);
|
||||||
let mut recv3 = futures::executor::block_on_stream(
|
let mut recv3 = futures::executor::block_on_stream(
|
||||||
notifications.listen(Some(&[]), Some(&child_filter))
|
notifications.listen(Some(&[]), Some(&child_filter)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let changeset = vec![
|
let changeset = vec![(vec![2], Some(vec![3])), (vec![1], None)];
|
||||||
(vec![2], Some(vec![3])),
|
let c_changeset_1 = vec![(vec![5], Some(vec![4])), (vec![6], None)];
|
||||||
(vec![1], None),
|
|
||||||
];
|
|
||||||
let c_changeset_1 = vec![
|
|
||||||
(vec![5], Some(vec![4])),
|
|
||||||
(vec![6], None),
|
|
||||||
];
|
|
||||||
|
|
||||||
let c_changeset = vec![(vec![4], c_changeset_1)];
|
let c_changeset = vec![(vec![4], c_changeset_1)];
|
||||||
notifications.trigger(
|
notifications.trigger(
|
||||||
&Hash::from_low_u64_be(1),
|
&Hash::from_low_u64_be(1),
|
||||||
changeset.into_iter(),
|
changeset.into_iter(),
|
||||||
c_changeset.into_iter().map(|(a,b)| (a, b.into_iter())),
|
c_changeset.into_iter().map(|(a, b)| (a, b.into_iter())),
|
||||||
);
|
);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(recv1.next().unwrap(), (Hash::from_low_u64_be(1), (vec![
|
assert_eq!(
|
||||||
(StorageKey(vec![1]), None),
|
recv1.next().unwrap(),
|
||||||
], vec![]).into()));
|
(Hash::from_low_u64_be(1), (vec![(StorageKey(vec![1]), None),], vec![]).into())
|
||||||
assert_eq!(recv2.next().unwrap(), (Hash::from_low_u64_be(1), (vec![
|
);
|
||||||
(StorageKey(vec![2]), Some(StorageData(vec![3]))),
|
assert_eq!(
|
||||||
], vec![]).into()));
|
recv2.next().unwrap(),
|
||||||
assert_eq!(recv3.next().unwrap(), (Hash::from_low_u64_be(1), (vec![],
|
(
|
||||||
vec![
|
Hash::from_low_u64_be(1),
|
||||||
(StorageKey(vec![4]), vec![(StorageKey(vec![5]), Some(StorageData(vec![4])))]),
|
(vec![(StorageKey(vec![2]), Some(StorageData(vec![3]))),], vec![]).into()
|
||||||
]).into()));
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
recv3.next().unwrap(),
|
||||||
|
(
|
||||||
|
Hash::from_low_u64_be(1),
|
||||||
|
(
|
||||||
|
vec![],
|
||||||
|
vec![(
|
||||||
|
StorageKey(vec![4]),
|
||||||
|
vec![(StorageKey(vec![5]), Some(StorageData(vec![4])))]
|
||||||
|
),]
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -479,27 +509,21 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))];
|
let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))];
|
||||||
let _recv1 = futures::executor::block_on_stream(
|
let _recv1 = futures::executor::block_on_stream(
|
||||||
notifications.listen(Some(&[StorageKey(vec![1])]), None)
|
notifications.listen(Some(&[StorageKey(vec![1])]), None),
|
||||||
);
|
);
|
||||||
let _recv2 = futures::executor::block_on_stream(
|
let _recv2 = futures::executor::block_on_stream(
|
||||||
notifications.listen(Some(&[StorageKey(vec![2])]), None)
|
notifications.listen(Some(&[StorageKey(vec![2])]), None),
|
||||||
);
|
|
||||||
let _recv3 = futures::executor::block_on_stream(
|
|
||||||
notifications.listen(None, None)
|
|
||||||
);
|
|
||||||
let _recv4 = futures::executor::block_on_stream(
|
|
||||||
notifications.listen(None, Some(&child_filter))
|
|
||||||
);
|
);
|
||||||
|
let _recv3 = futures::executor::block_on_stream(notifications.listen(None, None));
|
||||||
|
let _recv4 =
|
||||||
|
futures::executor::block_on_stream(notifications.listen(None, Some(&child_filter)));
|
||||||
assert_eq!(notifications.listeners.len(), 2);
|
assert_eq!(notifications.listeners.len(), 2);
|
||||||
assert_eq!(notifications.wildcard_listeners.len(), 2);
|
assert_eq!(notifications.wildcard_listeners.len(), 2);
|
||||||
assert_eq!(notifications.child_listeners.len(), 1);
|
assert_eq!(notifications.child_listeners.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let changeset = vec![
|
let changeset = vec![(vec![2], Some(vec![3])), (vec![1], None)];
|
||||||
(vec![2], Some(vec![3])),
|
|
||||||
(vec![1], None),
|
|
||||||
];
|
|
||||||
let c_changeset = empty::<(_, Empty<_>)>();
|
let c_changeset = empty::<(_, Empty<_>)>();
|
||||||
notifications.trigger(&Hash::from_low_u64_be(1), changeset.into_iter(), c_changeset);
|
notifications.trigger(&Hash::from_low_u64_be(1), changeset.into_iter(), c_changeset);
|
||||||
|
|
||||||
|
|||||||
@@ -17,12 +17,9 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Proof utilities
|
//! Proof utilities
|
||||||
use sp_runtime::{
|
use crate::{ChangesProof, StorageProof};
|
||||||
generic::BlockId,
|
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
|
||||||
traits::{Block as BlockT},
|
use sp_storage::{ChildInfo, PrefixedStorageKey, StorageKey};
|
||||||
};
|
|
||||||
use crate::{StorageProof, ChangesProof};
|
|
||||||
use sp_storage::{ChildInfo, StorageKey, PrefixedStorageKey};
|
|
||||||
|
|
||||||
/// Interface for providing block proving utilities.
|
/// Interface for providing block proving utilities.
|
||||||
pub trait ProofProvider<Block: BlockT> {
|
pub trait ProofProvider<Block: BlockT> {
|
||||||
@@ -30,7 +27,7 @@ pub trait ProofProvider<Block: BlockT> {
|
|||||||
fn read_proof(
|
fn read_proof(
|
||||||
&self,
|
&self,
|
||||||
id: &BlockId<Block>,
|
id: &BlockId<Block>,
|
||||||
keys: &mut dyn Iterator<Item=&[u8]>,
|
keys: &mut dyn Iterator<Item = &[u8]>,
|
||||||
) -> sp_blockchain::Result<StorageProof>;
|
) -> sp_blockchain::Result<StorageProof>;
|
||||||
|
|
||||||
/// Reads child storage value at a given block + storage_key + key, returning
|
/// Reads child storage value at a given block + storage_key + key, returning
|
||||||
@@ -39,7 +36,7 @@ pub trait ProofProvider<Block: BlockT> {
|
|||||||
&self,
|
&self,
|
||||||
id: &BlockId<Block>,
|
id: &BlockId<Block>,
|
||||||
child_info: &ChildInfo,
|
child_info: &ChildInfo,
|
||||||
keys: &mut dyn Iterator<Item=&[u8]>,
|
keys: &mut dyn Iterator<Item = &[u8]>,
|
||||||
) -> sp_blockchain::Result<StorageProof>;
|
) -> sp_blockchain::Result<StorageProof>;
|
||||||
|
|
||||||
/// Execute a call to a contract on top of state in a block of given hash
|
/// Execute a call to a contract on top of state in a block of given hash
|
||||||
@@ -53,7 +50,10 @@ pub trait ProofProvider<Block: BlockT> {
|
|||||||
call_data: &[u8],
|
call_data: &[u8],
|
||||||
) -> sp_blockchain::Result<(Vec<u8>, StorageProof)>;
|
) -> sp_blockchain::Result<(Vec<u8>, StorageProof)>;
|
||||||
/// Reads given header and generates CHT-based header proof.
|
/// Reads given header and generates CHT-based header proof.
|
||||||
fn header_proof(&self, id: &BlockId<Block>) -> sp_blockchain::Result<(Block::Header, StorageProof)>;
|
fn header_proof(
|
||||||
|
&self,
|
||||||
|
id: &BlockId<Block>,
|
||||||
|
) -> sp_blockchain::Result<(Block::Header, StorageProof)>;
|
||||||
|
|
||||||
/// Get proof for computation of (block, extrinsic) pairs where key has been changed at given blocks range.
|
/// Get proof for computation of (block, extrinsic) pairs where key has been changed at given blocks range.
|
||||||
/// `min` is the hash of the first block, which changes trie root is known to the requester - when we're using
|
/// `min` is the hash of the first block, which changes trie root is known to the requester - when we're using
|
||||||
|
|||||||
@@ -16,13 +16,13 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use futures::stream::Stream;
|
use futures::{future::FutureExt, ready, stream::Stream};
|
||||||
use futures::future::FutureExt;
|
|
||||||
use futures::ready;
|
|
||||||
use futures_timer::Delay;
|
use futures_timer::Delay;
|
||||||
use std::pin::Pin;
|
use std::{
|
||||||
use std::task::{Context, Poll};
|
pin::Pin,
|
||||||
use std::time::Duration;
|
task::{Context, Poll},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
/// Exponentially increasing interval
|
/// Exponentially increasing interval
|
||||||
///
|
///
|
||||||
@@ -37,11 +37,7 @@ impl ExpIncInterval {
|
|||||||
/// Create a new [`ExpIncInterval`].
|
/// Create a new [`ExpIncInterval`].
|
||||||
pub fn new(start: Duration, max: Duration) -> Self {
|
pub fn new(start: Duration, max: Duration) -> Self {
|
||||||
let delay = Delay::new(start);
|
let delay = Delay::new(start);
|
||||||
Self {
|
Self { max, next: start * 2, delay }
|
||||||
max,
|
|
||||||
next: start * 2,
|
|
||||||
delay,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fast forward the exponentially increasing interval to the configured maximum.
|
/// Fast forward the exponentially increasing interval to the configured maximum.
|
||||||
|
|||||||
@@ -26,18 +26,23 @@
|
|||||||
//!
|
//!
|
||||||
//! See [`Worker`] and [`Service`] for more documentation.
|
//! See [`Worker`] and [`Service`] for more documentation.
|
||||||
|
|
||||||
pub use crate::{service::Service, worker::{NetworkProvider, Worker, Role}};
|
pub use crate::{
|
||||||
|
service::Service,
|
||||||
|
worker::{NetworkProvider, Role, Worker},
|
||||||
|
};
|
||||||
|
|
||||||
use std::{sync::Arc, time::Duration};
|
use std::{sync::Arc, time::Duration};
|
||||||
|
|
||||||
use futures::channel::{mpsc, oneshot};
|
use futures::{
|
||||||
use futures::Stream;
|
channel::{mpsc, oneshot},
|
||||||
|
Stream,
|
||||||
|
};
|
||||||
|
|
||||||
use sc_client_api::blockchain::HeaderBackend;
|
use sc_client_api::blockchain::HeaderBackend;
|
||||||
use sc_network::{DhtEvent, Multiaddr, PeerId};
|
use sc_network::{DhtEvent, Multiaddr, PeerId};
|
||||||
|
use sp_api::ProvideRuntimeApi;
|
||||||
use sp_authority_discovery::{AuthorityDiscoveryApi, AuthorityId};
|
use sp_authority_discovery::{AuthorityDiscoveryApi, AuthorityId};
|
||||||
use sp_runtime::traits::Block as BlockT;
|
use sp_runtime::traits::Block as BlockT;
|
||||||
use sp_api::ProvideRuntimeApi;
|
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod interval;
|
mod interval;
|
||||||
@@ -141,15 +146,8 @@ where
|
|||||||
{
|
{
|
||||||
let (to_worker, from_service) = mpsc::channel(0);
|
let (to_worker, from_service) = mpsc::channel(0);
|
||||||
|
|
||||||
let worker = Worker::new(
|
let worker =
|
||||||
from_service,
|
Worker::new(from_service, client, network, dht_event_rx, role, prometheus_registry, config);
|
||||||
client,
|
|
||||||
network,
|
|
||||||
dht_event_rx,
|
|
||||||
role,
|
|
||||||
prometheus_registry,
|
|
||||||
config,
|
|
||||||
);
|
|
||||||
let service = Service::new(to_worker);
|
let service = Service::new(to_worker);
|
||||||
|
|
||||||
(worker, service)
|
(worker, service)
|
||||||
@@ -160,5 +158,5 @@ pub(crate) enum ServicetoWorkerMsg {
|
|||||||
/// See [`Service::get_addresses_by_authority_id`].
|
/// See [`Service::get_addresses_by_authority_id`].
|
||||||
GetAddressesByAuthorityId(AuthorityId, oneshot::Sender<Option<Vec<Multiaddr>>>),
|
GetAddressesByAuthorityId(AuthorityId, oneshot::Sender<Option<Vec<Multiaddr>>>),
|
||||||
/// See [`Service::get_authority_id_by_peer_id`].
|
/// See [`Service::get_authority_id_by_peer_id`].
|
||||||
GetAuthorityIdByPeerId(PeerId, oneshot::Sender<Option<AuthorityId>>)
|
GetAuthorityIdByPeerId(PeerId, oneshot::Sender<Option<AuthorityId>>),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ use std::fmt::Debug;
|
|||||||
|
|
||||||
use crate::ServicetoWorkerMsg;
|
use crate::ServicetoWorkerMsg;
|
||||||
|
|
||||||
use futures::channel::{mpsc, oneshot};
|
use futures::{
|
||||||
use futures::SinkExt;
|
channel::{mpsc, oneshot},
|
||||||
|
SinkExt,
|
||||||
|
};
|
||||||
|
|
||||||
use sc_network::{Multiaddr, PeerId};
|
use sc_network::{Multiaddr, PeerId};
|
||||||
use sp_authority_discovery::AuthorityId;
|
use sp_authority_discovery::AuthorityId;
|
||||||
@@ -42,9 +44,7 @@ impl Debug for Service {
|
|||||||
/// [`crate::Worker`]'s local address cache for a given [`AuthorityId`].
|
/// [`crate::Worker`]'s local address cache for a given [`AuthorityId`].
|
||||||
impl Service {
|
impl Service {
|
||||||
pub(crate) fn new(to_worker: mpsc::Sender<ServicetoWorkerMsg>) -> Self {
|
pub(crate) fn new(to_worker: mpsc::Sender<ServicetoWorkerMsg>) -> Self {
|
||||||
Self {
|
Self { to_worker }
|
||||||
to_worker,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the addresses for the given [`AuthorityId`] from the local address
|
/// Get the addresses for the given [`AuthorityId`] from the local address
|
||||||
@@ -59,7 +59,10 @@ impl Service {
|
|||||||
/// enforced today, given that there are still authorities out there
|
/// enforced today, given that there are still authorities out there
|
||||||
/// publishing the addresses of their sentry nodes on the DHT. In the future
|
/// publishing the addresses of their sentry nodes on the DHT. In the future
|
||||||
/// this guarantee can be provided.
|
/// this guarantee can be provided.
|
||||||
pub async fn get_addresses_by_authority_id(&mut self, authority: AuthorityId) -> Option<Vec<Multiaddr>> {
|
pub async fn get_addresses_by_authority_id(
|
||||||
|
&mut self,
|
||||||
|
authority: AuthorityId,
|
||||||
|
) -> Option<Vec<Multiaddr>> {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
|
|
||||||
self.to_worker
|
self.to_worker
|
||||||
|
|||||||
@@ -16,15 +16,24 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{new_worker_and_service, worker::{tests::{TestApi, TestNetwork}, Role}};
|
use crate::{
|
||||||
|
new_worker_and_service,
|
||||||
|
worker::{
|
||||||
|
tests::{TestApi, TestNetwork},
|
||||||
|
Role,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
use futures::{channel::mpsc::channel, executor::LocalPool, task::LocalSpawn};
|
use futures::{channel::mpsc::channel, executor::LocalPool, task::LocalSpawn};
|
||||||
use libp2p::core::{multiaddr::{Multiaddr, Protocol}, PeerId};
|
use libp2p::core::{
|
||||||
|
multiaddr::{Multiaddr, Protocol},
|
||||||
|
PeerId,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use sp_authority_discovery::AuthorityId;
|
use sp_authority_discovery::AuthorityId;
|
||||||
use sp_core::crypto::key_types;
|
use sp_core::crypto::key_types;
|
||||||
use sp_keystore::{CryptoStore, testing::KeyStore};
|
use sp_keystore::{testing::KeyStore, CryptoStore};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_addresses_and_authority_id() {
|
fn get_addresses_and_authority_id() {
|
||||||
@@ -44,13 +53,12 @@ fn get_addresses_and_authority_id() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let remote_peer_id = PeerId::random();
|
let remote_peer_id = PeerId::random();
|
||||||
let remote_addr = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333".parse::<Multiaddr>()
|
let remote_addr = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333"
|
||||||
|
.parse::<Multiaddr>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with(Protocol::P2p(remote_peer_id.clone().into()));
|
.with(Protocol::P2p(remote_peer_id.clone().into()));
|
||||||
|
|
||||||
let test_api = Arc::new(TestApi {
|
let test_api = Arc::new(TestApi { authorities: vec![] });
|
||||||
authorities: vec![],
|
|
||||||
});
|
|
||||||
|
|
||||||
let (mut worker, mut service) = new_worker_and_service(
|
let (mut worker, mut service) = new_worker_and_service(
|
||||||
test_api,
|
test_api,
|
||||||
|
|||||||
@@ -16,43 +16,49 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{error::{Error, Result}, interval::ExpIncInterval, ServicetoWorkerMsg};
|
use crate::{
|
||||||
|
error::{Error, Result},
|
||||||
|
interval::ExpIncInterval,
|
||||||
|
ServicetoWorkerMsg,
|
||||||
|
};
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::{
|
||||||
use std::convert::TryInto;
|
collections::{HashMap, HashSet},
|
||||||
use std::marker::PhantomData;
|
convert::TryInto,
|
||||||
use std::sync::Arc;
|
marker::PhantomData,
|
||||||
use std::time::Duration;
|
sync::Arc,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use futures::channel::mpsc;
|
use futures::{channel::mpsc, future, stream::Fuse, FutureExt, Stream, StreamExt};
|
||||||
use futures::{future, FutureExt, Stream, StreamExt, stream::Fuse};
|
|
||||||
|
|
||||||
use addr_cache::AddrCache;
|
use addr_cache::AddrCache;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
use ip_network::IpNetwork;
|
use ip_network::IpNetwork;
|
||||||
use libp2p::{core::multiaddr, multihash::{Multihash, Hasher}};
|
use libp2p::{
|
||||||
|
core::multiaddr,
|
||||||
|
multihash::{Hasher, Multihash},
|
||||||
|
};
|
||||||
use log::{debug, error, log_enabled};
|
use log::{debug, error, log_enabled};
|
||||||
use prometheus_endpoint::{Counter, CounterVec, Gauge, Opts, U64, register};
|
use prometheus_endpoint::{register, Counter, CounterVec, Gauge, Opts, U64};
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use rand::{seq::SliceRandom, thread_rng};
|
use rand::{seq::SliceRandom, thread_rng};
|
||||||
use sc_client_api::blockchain::HeaderBackend;
|
use sc_client_api::blockchain::HeaderBackend;
|
||||||
use sc_network::{
|
use sc_network::{DhtEvent, ExHashT, Multiaddr, NetworkStateInfo, PeerId};
|
||||||
DhtEvent,
|
use sp_api::ProvideRuntimeApi;
|
||||||
ExHashT,
|
use sp_authority_discovery::{
|
||||||
Multiaddr,
|
AuthorityDiscoveryApi, AuthorityId, AuthorityPair, AuthoritySignature,
|
||||||
NetworkStateInfo,
|
|
||||||
PeerId,
|
|
||||||
};
|
};
|
||||||
use sp_authority_discovery::{AuthorityDiscoveryApi, AuthorityId, AuthoritySignature, AuthorityPair};
|
|
||||||
use sp_core::crypto::{key_types, CryptoTypePublicPair, Pair};
|
use sp_core::crypto::{key_types, CryptoTypePublicPair, Pair};
|
||||||
use sp_keystore::CryptoStore;
|
use sp_keystore::CryptoStore;
|
||||||
use sp_runtime::{traits::Block as BlockT, generic::BlockId};
|
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
|
||||||
use sp_api::ProvideRuntimeApi;
|
|
||||||
|
|
||||||
mod addr_cache;
|
mod addr_cache;
|
||||||
/// Dht payload schemas generated from Protobuf definitions via Prost crate in build.rs.
|
/// Dht payload schemas generated from Protobuf definitions via Prost crate in build.rs.
|
||||||
mod schema { include!(concat!(env!("OUT_DIR"), "/authority_discovery.rs")); }
|
mod schema {
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/authority_discovery.rs"));
|
||||||
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests;
|
pub mod tests;
|
||||||
|
|
||||||
@@ -72,7 +78,6 @@ pub enum Role {
|
|||||||
Discover,
|
Discover,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// An authority discovery [`Worker`] can publish the local node's addresses as well as discover
|
/// An authority discovery [`Worker`] can publish the local node's addresses as well as discover
|
||||||
/// those of other nodes via a Kademlia DHT.
|
/// those of other nodes via a Kademlia DHT.
|
||||||
///
|
///
|
||||||
@@ -141,8 +146,7 @@ where
|
|||||||
Block: BlockT + Unpin + 'static,
|
Block: BlockT + Unpin + 'static,
|
||||||
Network: NetworkProvider,
|
Network: NetworkProvider,
|
||||||
Client: ProvideRuntimeApi<Block> + Send + Sync + 'static + HeaderBackend<Block>,
|
Client: ProvideRuntimeApi<Block> + Send + Sync + 'static + HeaderBackend<Block>,
|
||||||
<Client as ProvideRuntimeApi<Block>>::Api:
|
<Client as ProvideRuntimeApi<Block>>::Api: AuthorityDiscoveryApi<Block>,
|
||||||
AuthorityDiscoveryApi<Block>,
|
|
||||||
DhtEventStream: Stream<Item = DhtEvent> + Unpin,
|
DhtEventStream: Stream<Item = DhtEvent> + Unpin,
|
||||||
{
|
{
|
||||||
/// Construct a [`Worker`].
|
/// Construct a [`Worker`].
|
||||||
@@ -161,33 +165,24 @@ where
|
|||||||
// thus timely retries are not needed. For this reasoning use an exponentially increasing
|
// thus timely retries are not needed. For this reasoning use an exponentially increasing
|
||||||
// interval for `publish_interval`, `query_interval` and `priority_group_set_interval`
|
// interval for `publish_interval`, `query_interval` and `priority_group_set_interval`
|
||||||
// instead of a constant interval.
|
// instead of a constant interval.
|
||||||
let publish_interval = ExpIncInterval::new(
|
let publish_interval =
|
||||||
Duration::from_secs(2),
|
ExpIncInterval::new(Duration::from_secs(2), config.max_publish_interval);
|
||||||
config.max_publish_interval,
|
let query_interval = ExpIncInterval::new(Duration::from_secs(2), config.max_query_interval);
|
||||||
);
|
|
||||||
let query_interval = ExpIncInterval::new(
|
|
||||||
Duration::from_secs(2),
|
|
||||||
config.max_query_interval,
|
|
||||||
);
|
|
||||||
|
|
||||||
// An `ExpIncInterval` is overkill here because the interval is constant, but consistency
|
// An `ExpIncInterval` is overkill here because the interval is constant, but consistency
|
||||||
// is more simple.
|
// is more simple.
|
||||||
let publish_if_changed_interval = ExpIncInterval::new(
|
let publish_if_changed_interval =
|
||||||
config.keystore_refresh_interval,
|
ExpIncInterval::new(config.keystore_refresh_interval, config.keystore_refresh_interval);
|
||||||
config.keystore_refresh_interval
|
|
||||||
);
|
|
||||||
|
|
||||||
let addr_cache = AddrCache::new();
|
let addr_cache = AddrCache::new();
|
||||||
|
|
||||||
let metrics = match prometheus_registry {
|
let metrics = match prometheus_registry {
|
||||||
Some(registry) => {
|
Some(registry) => match Metrics::register(®istry) {
|
||||||
match Metrics::register(®istry) {
|
Ok(metrics) => Some(metrics),
|
||||||
Ok(metrics) => Some(metrics),
|
Err(e) => {
|
||||||
Err(e) => {
|
error!(target: LOG_TARGET, "Failed to register metrics: {:?}", e);
|
||||||
error!(target: LOG_TARGET, "Failed to register metrics: {:?}", e);
|
None
|
||||||
None
|
},
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
@@ -262,23 +257,23 @@ where
|
|||||||
let _ = sender.send(
|
let _ = sender.send(
|
||||||
self.addr_cache.get_addresses_by_authority_id(&authority).map(Clone::clone),
|
self.addr_cache.get_addresses_by_authority_id(&authority).map(Clone::clone),
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
ServicetoWorkerMsg::GetAuthorityIdByPeerId(peer_id, sender) => {
|
ServicetoWorkerMsg::GetAuthorityIdByPeerId(peer_id, sender) => {
|
||||||
let _ = sender.send(
|
let _ = sender
|
||||||
self.addr_cache.get_authority_id_by_peer_id(&peer_id).map(Clone::clone),
|
.send(self.addr_cache.get_authority_id_by_peer_id(&peer_id).map(Clone::clone));
|
||||||
);
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addresses_to_publish(&self) -> impl Iterator<Item = Multiaddr> {
|
fn addresses_to_publish(&self) -> impl Iterator<Item = Multiaddr> {
|
||||||
let peer_id: Multihash = self.network.local_peer_id().into();
|
let peer_id: Multihash = self.network.local_peer_id().into();
|
||||||
let publish_non_global_ips = self.publish_non_global_ips;
|
let publish_non_global_ips = self.publish_non_global_ips;
|
||||||
self.network.external_addresses()
|
self.network
|
||||||
|
.external_addresses()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(move |a| {
|
.filter(move |a| {
|
||||||
if publish_non_global_ips {
|
if publish_non_global_ips {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
a.iter().all(|p| match p {
|
a.iter().all(|p| match p {
|
||||||
@@ -321,9 +316,9 @@ where
|
|||||||
|
|
||||||
if let Some(metrics) = &self.metrics {
|
if let Some(metrics) = &self.metrics {
|
||||||
metrics.publish.inc();
|
metrics.publish.inc();
|
||||||
metrics.amount_addresses_last_published.set(
|
metrics
|
||||||
addresses.len().try_into().unwrap_or(std::u64::MAX),
|
.amount_addresses_last_published
|
||||||
);
|
.set(addresses.len().try_into().unwrap_or(std::u64::MAX));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut serialized_addresses = vec![];
|
let mut serialized_addresses = vec![];
|
||||||
@@ -332,30 +327,26 @@ where
|
|||||||
.map_err(Error::EncodingProto)?;
|
.map_err(Error::EncodingProto)?;
|
||||||
|
|
||||||
let keys_vec = keys.iter().cloned().collect::<Vec<_>>();
|
let keys_vec = keys.iter().cloned().collect::<Vec<_>>();
|
||||||
let signatures = key_store.sign_with_all(
|
let signatures = key_store
|
||||||
key_types::AUTHORITY_DISCOVERY,
|
.sign_with_all(
|
||||||
keys_vec.clone(),
|
key_types::AUTHORITY_DISCOVERY,
|
||||||
serialized_addresses.as_slice(),
|
keys_vec.clone(),
|
||||||
).await.map_err(|_| Error::Signing)?;
|
serialized_addresses.as_slice(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::Signing)?;
|
||||||
|
|
||||||
for (sign_result, key) in signatures.into_iter().zip(keys_vec.iter()) {
|
for (sign_result, key) in signatures.into_iter().zip(keys_vec.iter()) {
|
||||||
let mut signed_addresses = vec![];
|
let mut signed_addresses = vec![];
|
||||||
|
|
||||||
// Verify that all signatures exist for all provided keys.
|
// Verify that all signatures exist for all provided keys.
|
||||||
let signature = sign_result.ok()
|
let signature =
|
||||||
.flatten()
|
sign_result.ok().flatten().ok_or_else(|| Error::MissingSignature(key.clone()))?;
|
||||||
.ok_or_else(|| Error::MissingSignature(key.clone()))?;
|
schema::SignedAuthorityAddresses { addresses: serialized_addresses.clone(), signature }
|
||||||
schema::SignedAuthorityAddresses {
|
.encode(&mut signed_addresses)
|
||||||
addresses: serialized_addresses.clone(),
|
|
||||||
signature,
|
|
||||||
}
|
|
||||||
.encode(&mut signed_addresses)
|
|
||||||
.map_err(Error::EncodingProto)?;
|
.map_err(Error::EncodingProto)?;
|
||||||
|
|
||||||
self.network.put_value(
|
self.network.put_value(hash_authority_id(key.1.as_ref()), signed_addresses);
|
||||||
hash_authority_id(key.1.as_ref()),
|
|
||||||
signed_addresses,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.latest_published_keys = keys;
|
self.latest_published_keys = keys;
|
||||||
@@ -367,11 +358,11 @@ where
|
|||||||
let id = BlockId::hash(self.client.info().best_hash);
|
let id = BlockId::hash(self.client.info().best_hash);
|
||||||
|
|
||||||
let local_keys = match &self.role {
|
let local_keys = match &self.role {
|
||||||
Role::PublishAndDiscover(key_store) => {
|
Role::PublishAndDiscover(key_store) => key_store
|
||||||
key_store.sr25519_public_keys(
|
.sr25519_public_keys(key_types::AUTHORITY_DISCOVERY)
|
||||||
key_types::AUTHORITY_DISCOVERY
|
.await
|
||||||
).await.into_iter().collect::<HashSet<_>>()
|
.into_iter()
|
||||||
},
|
.collect::<HashSet<_>>(),
|
||||||
Role::Discover => HashSet::new(),
|
Role::Discover => HashSet::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -393,9 +384,9 @@ where
|
|||||||
self.in_flight_lookups.clear();
|
self.in_flight_lookups.clear();
|
||||||
|
|
||||||
if let Some(metrics) = &self.metrics {
|
if let Some(metrics) = &self.metrics {
|
||||||
metrics.requests_pending.set(
|
metrics
|
||||||
self.pending_lookups.len().try_into().unwrap_or(std::u64::MAX),
|
.requests_pending
|
||||||
);
|
.set(self.pending_lookups.len().try_into().unwrap_or(std::u64::MAX));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -408,15 +399,14 @@ where
|
|||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
let hash = hash_authority_id(authority_id.as_ref());
|
let hash = hash_authority_id(authority_id.as_ref());
|
||||||
self.network
|
self.network.get_value(&hash);
|
||||||
.get_value(&hash);
|
|
||||||
self.in_flight_lookups.insert(hash, authority_id);
|
self.in_flight_lookups.insert(hash, authority_id);
|
||||||
|
|
||||||
if let Some(metrics) = &self.metrics {
|
if let Some(metrics) = &self.metrics {
|
||||||
metrics.requests.inc();
|
metrics.requests.inc();
|
||||||
metrics.requests_pending.set(
|
metrics
|
||||||
self.pending_lookups.len().try_into().unwrap_or(std::u64::MAX),
|
.requests_pending
|
||||||
);
|
.set(self.pending_lookups.len().try_into().unwrap_or(std::u64::MAX));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,10 +421,7 @@ where
|
|||||||
|
|
||||||
if log_enabled!(log::Level::Debug) {
|
if log_enabled!(log::Level::Debug) {
|
||||||
let hashes: Vec<_> = v.iter().map(|(hash, _value)| hash.clone()).collect();
|
let hashes: Vec<_> = v.iter().map(|(hash, _value)| hash.clone()).collect();
|
||||||
debug!(
|
debug!(target: LOG_TARGET, "Value for hash '{:?}' found on Dht.", hashes,);
|
||||||
target: LOG_TARGET,
|
|
||||||
"Value for hash '{:?}' found on Dht.", hashes,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = self.handle_dht_value_found_event(v) {
|
if let Err(e) = self.handle_dht_value_found_event(v) {
|
||||||
@@ -442,22 +429,16 @@ where
|
|||||||
metrics.handle_value_found_event_failure.inc();
|
metrics.handle_value_found_event_failure.inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(
|
debug!(target: LOG_TARGET, "Failed to handle Dht value found event: {:?}", e,);
|
||||||
target: LOG_TARGET,
|
|
||||||
"Failed to handle Dht value found event: {:?}", e,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
DhtEvent::ValueNotFound(hash) => {
|
DhtEvent::ValueNotFound(hash) => {
|
||||||
if let Some(metrics) = &self.metrics {
|
if let Some(metrics) = &self.metrics {
|
||||||
metrics.dht_event_received.with_label_values(&["value_not_found"]).inc();
|
metrics.dht_event_received.with_label_values(&["value_not_found"]).inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.in_flight_lookups.remove(&hash).is_some() {
|
if self.in_flight_lookups.remove(&hash).is_some() {
|
||||||
debug!(
|
debug!(target: LOG_TARGET, "Value for hash '{:?}' not found on Dht.", hash)
|
||||||
target: LOG_TARGET,
|
|
||||||
"Value for hash '{:?}' not found on Dht.", hash
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
debug!(
|
debug!(
|
||||||
target: LOG_TARGET,
|
target: LOG_TARGET,
|
||||||
@@ -475,21 +456,15 @@ where
|
|||||||
metrics.dht_event_received.with_label_values(&["value_put"]).inc();
|
metrics.dht_event_received.with_label_values(&["value_put"]).inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(
|
debug!(target: LOG_TARGET, "Successfully put hash '{:?}' on Dht.", hash,)
|
||||||
target: LOG_TARGET,
|
|
||||||
"Successfully put hash '{:?}' on Dht.", hash,
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
DhtEvent::ValuePutFailed(hash) => {
|
DhtEvent::ValuePutFailed(hash) => {
|
||||||
if let Some(metrics) = &self.metrics {
|
if let Some(metrics) = &self.metrics {
|
||||||
metrics.dht_event_received.with_label_values(&["value_put_failed"]).inc();
|
metrics.dht_event_received.with_label_values(&["value_put_failed"]).inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(
|
debug!(target: LOG_TARGET, "Failed to put hash '{:?}' on Dht.", hash)
|
||||||
target: LOG_TARGET,
|
},
|
||||||
"Failed to put hash '{:?}' on Dht.", hash
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,34 +473,36 @@ where
|
|||||||
values: Vec<(libp2p::kad::record::Key, Vec<u8>)>,
|
values: Vec<(libp2p::kad::record::Key, Vec<u8>)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// Ensure `values` is not empty and all its keys equal.
|
// Ensure `values` is not empty and all its keys equal.
|
||||||
let remote_key = values.iter().fold(Ok(None), |acc, (key, _)| {
|
let remote_key = values
|
||||||
match acc {
|
.iter()
|
||||||
|
.fold(Ok(None), |acc, (key, _)| match acc {
|
||||||
Ok(None) => Ok(Some(key.clone())),
|
Ok(None) => Ok(Some(key.clone())),
|
||||||
Ok(Some(ref prev_key)) if prev_key != key => Err(
|
Ok(Some(ref prev_key)) if prev_key != key =>
|
||||||
Error::ReceivingDhtValueFoundEventWithDifferentKeys
|
Err(Error::ReceivingDhtValueFoundEventWithDifferentKeys),
|
||||||
),
|
|
||||||
x @ Ok(_) => x,
|
x @ Ok(_) => x,
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
})?
|
||||||
})?.ok_or(Error::ReceivingDhtValueFoundEventWithNoRecords)?;
|
.ok_or(Error::ReceivingDhtValueFoundEventWithNoRecords)?;
|
||||||
|
|
||||||
let authority_id: AuthorityId = self.in_flight_lookups
|
let authority_id: AuthorityId = self
|
||||||
|
.in_flight_lookups
|
||||||
.remove(&remote_key)
|
.remove(&remote_key)
|
||||||
.ok_or(Error::ReceivingUnexpectedRecord)?;
|
.ok_or(Error::ReceivingUnexpectedRecord)?;
|
||||||
|
|
||||||
let local_peer_id = self.network.local_peer_id();
|
let local_peer_id = self.network.local_peer_id();
|
||||||
|
|
||||||
let remote_addresses: Vec<Multiaddr> = values.into_iter()
|
let remote_addresses: Vec<Multiaddr> = values
|
||||||
|
.into_iter()
|
||||||
.map(|(_k, v)| {
|
.map(|(_k, v)| {
|
||||||
let schema::SignedAuthorityAddresses { signature, addresses } =
|
let schema::SignedAuthorityAddresses { signature, addresses } =
|
||||||
schema::SignedAuthorityAddresses::decode(v.as_slice())
|
schema::SignedAuthorityAddresses::decode(v.as_slice())
|
||||||
.map_err(Error::DecodingProto)?;
|
.map_err(Error::DecodingProto)?;
|
||||||
|
|
||||||
let signature = AuthoritySignature::decode(&mut &signature[..])
|
let signature = AuthoritySignature::decode(&mut &signature[..])
|
||||||
.map_err(Error::EncodingDecodingScale)?;
|
.map_err(Error::EncodingDecodingScale)?;
|
||||||
|
|
||||||
if !AuthorityPair::verify(&signature, &addresses, &authority_id) {
|
if !AuthorityPair::verify(&signature, &addresses, &authority_id) {
|
||||||
return Err(Error::VerifyingDhtPayload);
|
return Err(Error::VerifyingDhtPayload)
|
||||||
}
|
}
|
||||||
|
|
||||||
let addresses = schema::AuthorityAddresses::decode(addresses.as_slice())
|
let addresses = schema::AuthorityAddresses::decode(addresses.as_slice())
|
||||||
@@ -542,40 +519,41 @@ where
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
// Ignore [`Multiaddr`]s without [`PeerId`] and own addresses.
|
// Ignore [`Multiaddr`]s without [`PeerId`] and own addresses.
|
||||||
.filter(|addr| addr.iter().any(|protocol| {
|
.filter(|addr| {
|
||||||
// Parse to PeerId first as Multihashes of old and new PeerId
|
addr.iter().any(|protocol| {
|
||||||
// representation don't equal.
|
// Parse to PeerId first as Multihashes of old and new PeerId
|
||||||
//
|
// representation don't equal.
|
||||||
// See https://github.com/libp2p/rust-libp2p/issues/555 for
|
//
|
||||||
// details.
|
// See https://github.com/libp2p/rust-libp2p/issues/555 for
|
||||||
if let multiaddr::Protocol::P2p(hash) = protocol {
|
// details.
|
||||||
let peer_id = match PeerId::from_multihash(hash) {
|
if let multiaddr::Protocol::P2p(hash) = protocol {
|
||||||
Ok(peer_id) => peer_id,
|
let peer_id = match PeerId::from_multihash(hash) {
|
||||||
Err(_) => return false, // Discard address.
|
Ok(peer_id) => peer_id,
|
||||||
};
|
Err(_) => return false, // Discard address.
|
||||||
|
};
|
||||||
|
|
||||||
// Discard if equal to local peer id, keep if it differs.
|
// Discard if equal to local peer id, keep if it differs.
|
||||||
return !(peer_id == local_peer_id);
|
return !(peer_id == local_peer_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
false // `protocol` is not a [`Protocol::P2p`], let's keep looking.
|
false // `protocol` is not a [`Protocol::P2p`], let's keep looking.
|
||||||
}))
|
})
|
||||||
|
})
|
||||||
.take(MAX_ADDRESSES_PER_AUTHORITY)
|
.take(MAX_ADDRESSES_PER_AUTHORITY)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if !remote_addresses.is_empty() {
|
if !remote_addresses.is_empty() {
|
||||||
self.addr_cache.insert(authority_id, remote_addresses);
|
self.addr_cache.insert(authority_id, remote_addresses);
|
||||||
if let Some(metrics) = &self.metrics {
|
if let Some(metrics) = &self.metrics {
|
||||||
metrics.known_authorities_count.set(
|
metrics
|
||||||
self.addr_cache.num_ids().try_into().unwrap_or(std::u64::MAX)
|
.known_authorities_count
|
||||||
);
|
.set(self.addr_cache.num_ids().try_into().unwrap_or(std::u64::MAX));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve our public keys within the current and next authority set.
|
/// Retrieve our public keys within the current and next authority set.
|
||||||
//
|
|
||||||
// A node might have multiple authority discovery keys within its keystore, e.g. an old one and
|
// A node might have multiple authority discovery keys within its keystore, e.g. an old one and
|
||||||
// one for the upcoming session. In addition it could be participating in the current and (/ or)
|
// one for the upcoming session. In addition it could be participating in the current and (/ or)
|
||||||
// next authority set with two keys. The function does not return all of the local authority
|
// next authority set with two keys. The function does not return all of the local authority
|
||||||
@@ -591,14 +569,16 @@ where
|
|||||||
.collect::<HashSet<_>>();
|
.collect::<HashSet<_>>();
|
||||||
|
|
||||||
let id = BlockId::hash(client.info().best_hash);
|
let id = BlockId::hash(client.info().best_hash);
|
||||||
let authorities = client.runtime_api()
|
let authorities = client
|
||||||
|
.runtime_api()
|
||||||
.authorities(&id)
|
.authorities(&id)
|
||||||
.map_err(|e| Error::CallingRuntime(e.into()))?
|
.map_err(|e| Error::CallingRuntime(e.into()))?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(std::convert::Into::into)
|
.map(std::convert::Into::into)
|
||||||
.collect::<HashSet<_>>();
|
.collect::<HashSet<_>>();
|
||||||
|
|
||||||
let intersection = local_pub_keys.intersection(&authorities)
|
let intersection = local_pub_keys
|
||||||
|
.intersection(&authorities)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(std::convert::Into::into)
|
.map(std::convert::Into::into)
|
||||||
.collect();
|
.collect();
|
||||||
@@ -655,7 +635,7 @@ impl Metrics {
|
|||||||
publish: register(
|
publish: register(
|
||||||
Counter::new(
|
Counter::new(
|
||||||
"authority_discovery_times_published_total",
|
"authority_discovery_times_published_total",
|
||||||
"Number of times authority discovery has published external addresses."
|
"Number of times authority discovery has published external addresses.",
|
||||||
)?,
|
)?,
|
||||||
registry,
|
registry,
|
||||||
)?,
|
)?,
|
||||||
@@ -663,7 +643,7 @@ impl Metrics {
|
|||||||
Gauge::new(
|
Gauge::new(
|
||||||
"authority_discovery_amount_external_addresses_last_published",
|
"authority_discovery_amount_external_addresses_last_published",
|
||||||
"Number of external addresses published when authority discovery last \
|
"Number of external addresses published when authority discovery last \
|
||||||
published addresses."
|
published addresses.",
|
||||||
)?,
|
)?,
|
||||||
registry,
|
registry,
|
||||||
)?,
|
)?,
|
||||||
@@ -671,14 +651,14 @@ impl Metrics {
|
|||||||
Counter::new(
|
Counter::new(
|
||||||
"authority_discovery_authority_addresses_requested_total",
|
"authority_discovery_authority_addresses_requested_total",
|
||||||
"Number of times authority discovery has requested external addresses of a \
|
"Number of times authority discovery has requested external addresses of a \
|
||||||
single authority."
|
single authority.",
|
||||||
)?,
|
)?,
|
||||||
registry,
|
registry,
|
||||||
)?,
|
)?,
|
||||||
requests_pending: register(
|
requests_pending: register(
|
||||||
Gauge::new(
|
Gauge::new(
|
||||||
"authority_discovery_authority_address_requests_pending",
|
"authority_discovery_authority_address_requests_pending",
|
||||||
"Number of pending authority address requests."
|
"Number of pending authority address requests.",
|
||||||
)?,
|
)?,
|
||||||
registry,
|
registry,
|
||||||
)?,
|
)?,
|
||||||
@@ -686,7 +666,7 @@ impl Metrics {
|
|||||||
CounterVec::new(
|
CounterVec::new(
|
||||||
Opts::new(
|
Opts::new(
|
||||||
"authority_discovery_dht_event_received",
|
"authority_discovery_dht_event_received",
|
||||||
"Number of dht events received by authority discovery."
|
"Number of dht events received by authority discovery.",
|
||||||
),
|
),
|
||||||
&["name"],
|
&["name"],
|
||||||
)?,
|
)?,
|
||||||
@@ -695,14 +675,14 @@ impl Metrics {
|
|||||||
handle_value_found_event_failure: register(
|
handle_value_found_event_failure: register(
|
||||||
Counter::new(
|
Counter::new(
|
||||||
"authority_discovery_handle_value_found_event_failure",
|
"authority_discovery_handle_value_found_event_failure",
|
||||||
"Number of times handling a dht value found event failed."
|
"Number of times handling a dht value found event failed.",
|
||||||
)?,
|
)?,
|
||||||
registry,
|
registry,
|
||||||
)?,
|
)?,
|
||||||
known_authorities_count: register(
|
known_authorities_count: register(
|
||||||
Gauge::new(
|
Gauge::new(
|
||||||
"authority_discovery_known_authorities_count",
|
"authority_discovery_known_authorities_count",
|
||||||
"Number of authorities known by authority discovery."
|
"Number of authorities known by authority discovery.",
|
||||||
)?,
|
)?,
|
||||||
registry,
|
registry,
|
||||||
)?,
|
)?,
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
use libp2p::core::multiaddr::{Multiaddr, Protocol};
|
use libp2p::core::multiaddr::{Multiaddr, Protocol};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use sp_authority_discovery::AuthorityId;
|
|
||||||
use sc_network::PeerId;
|
use sc_network::PeerId;
|
||||||
|
use sp_authority_discovery::AuthorityId;
|
||||||
|
|
||||||
/// Cache for [`AuthorityId`] -> [`Vec<Multiaddr>`] and [`PeerId`] -> [`AuthorityId`] mappings.
|
/// Cache for [`AuthorityId`] -> [`Vec<Multiaddr>`] and [`PeerId`] -> [`AuthorityId`] mappings.
|
||||||
pub(super) struct AddrCache {
|
pub(super) struct AddrCache {
|
||||||
@@ -45,27 +45,34 @@ impl AddrCache {
|
|||||||
addresses.sort_unstable_by(|a, b| a.as_ref().cmp(b.as_ref()));
|
addresses.sort_unstable_by(|a, b| a.as_ref().cmp(b.as_ref()));
|
||||||
|
|
||||||
// Insert into `self.peer_id_to_authority_id`.
|
// Insert into `self.peer_id_to_authority_id`.
|
||||||
let peer_ids = addresses.iter()
|
let peer_ids = addresses
|
||||||
|
.iter()
|
||||||
.map(|a| peer_id_from_multiaddr(a))
|
.map(|a| peer_id_from_multiaddr(a))
|
||||||
.filter_map(|peer_id| peer_id);
|
.filter_map(|peer_id| peer_id);
|
||||||
for peer_id in peer_ids.clone() {
|
for peer_id in peer_ids.clone() {
|
||||||
let former_auth = match self.peer_id_to_authority_id.insert(peer_id, authority_id.clone()) {
|
let former_auth =
|
||||||
Some(a) if a != authority_id => a,
|
match self.peer_id_to_authority_id.insert(peer_id, authority_id.clone()) {
|
||||||
_ => continue,
|
Some(a) if a != authority_id => a,
|
||||||
};
|
_ => continue,
|
||||||
|
};
|
||||||
|
|
||||||
// PeerId was associated to a different authority id before.
|
// PeerId was associated to a different authority id before.
|
||||||
// Remove corresponding authority from `self.authority_id_to_addresses`.
|
// Remove corresponding authority from `self.authority_id_to_addresses`.
|
||||||
let former_auth_addrs = match self.authority_id_to_addresses.get_mut(&former_auth) {
|
let former_auth_addrs = match self.authority_id_to_addresses.get_mut(&former_auth) {
|
||||||
Some(a) => a,
|
Some(a) => a,
|
||||||
None => { debug_assert!(false); continue }
|
None => {
|
||||||
|
debug_assert!(false);
|
||||||
|
continue
|
||||||
|
},
|
||||||
};
|
};
|
||||||
former_auth_addrs.retain(|a| peer_id_from_multiaddr(a).map_or(true, |p| p != peer_id));
|
former_auth_addrs.retain(|a| peer_id_from_multiaddr(a).map_or(true, |p| p != peer_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert into `self.authority_id_to_addresses`.
|
// Insert into `self.authority_id_to_addresses`.
|
||||||
for former_addr in
|
for former_addr in self
|
||||||
self.authority_id_to_addresses.insert(authority_id.clone(), addresses.clone()).unwrap_or_default()
|
.authority_id_to_addresses
|
||||||
|
.insert(authority_id.clone(), addresses.clone())
|
||||||
|
.unwrap_or_default()
|
||||||
{
|
{
|
||||||
// Must remove from `self.peer_id_to_authority_id` any PeerId formerly associated
|
// Must remove from `self.peer_id_to_authority_id` any PeerId formerly associated
|
||||||
// to that authority but that can't be found in its new addresses.
|
// to that authority but that can't be found in its new addresses.
|
||||||
@@ -87,7 +94,10 @@ impl AddrCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the addresses for the given [`AuthorityId`].
|
/// Returns the addresses for the given [`AuthorityId`].
|
||||||
pub fn get_addresses_by_authority_id(&self, authority_id: &AuthorityId) -> Option<&Vec<Multiaddr>> {
|
pub fn get_addresses_by_authority_id(
|
||||||
|
&self,
|
||||||
|
authority_id: &AuthorityId,
|
||||||
|
) -> Option<&Vec<Multiaddr>> {
|
||||||
self.authority_id_to_addresses.get(&authority_id)
|
self.authority_id_to_addresses.get(&authority_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +110,9 @@ impl AddrCache {
|
|||||||
/// [`AuthorityId`]s.
|
/// [`AuthorityId`]s.
|
||||||
pub fn retain_ids(&mut self, authority_ids: &Vec<AuthorityId>) {
|
pub fn retain_ids(&mut self, authority_ids: &Vec<AuthorityId>) {
|
||||||
// The below logic could be replaced by `BtreeMap::drain_filter` once it stabilized.
|
// The below logic could be replaced by `BtreeMap::drain_filter` once it stabilized.
|
||||||
let authority_ids_to_remove = self.authority_id_to_addresses.iter()
|
let authority_ids_to_remove = self
|
||||||
|
.authority_id_to_addresses
|
||||||
|
.iter()
|
||||||
.filter(|(id, _addresses)| !authority_ids.contains(id))
|
.filter(|(id, _addresses)| !authority_ids.contains(id))
|
||||||
.map(|entry| entry.0)
|
.map(|entry| entry.0)
|
||||||
.cloned()
|
.cloned()
|
||||||
@@ -111,7 +123,8 @@ impl AddrCache {
|
|||||||
let addresses = self.authority_id_to_addresses.remove(&authority_id_to_remove);
|
let addresses = self.authority_id_to_addresses.remove(&authority_id_to_remove);
|
||||||
|
|
||||||
// Remove other entries from `self.peer_id_to_authority_id`.
|
// Remove other entries from `self.peer_id_to_authority_id`.
|
||||||
let peer_ids = addresses.iter()
|
let peer_ids = addresses
|
||||||
|
.iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.map(|a| peer_id_from_multiaddr(a))
|
.map(|a| peer_id_from_multiaddr(a))
|
||||||
.filter_map(|peer_id| peer_id);
|
.filter_map(|peer_id| peer_id);
|
||||||
@@ -125,10 +138,12 @@ impl AddrCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn peer_id_from_multiaddr(addr: &Multiaddr) -> Option<PeerId> {
|
fn peer_id_from_multiaddr(addr: &Multiaddr) -> Option<PeerId> {
|
||||||
addr.iter().last().and_then(|protocol| if let Protocol::P2p(multihash) = protocol {
|
addr.iter().last().and_then(|protocol| {
|
||||||
PeerId::from_multihash(multihash).ok()
|
if let Protocol::P2p(multihash) = protocol {
|
||||||
} else {
|
PeerId::from_multihash(multihash).ok()
|
||||||
None
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,9 +174,11 @@ mod tests {
|
|||||||
fn arbitrary(g: &mut Gen) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>();
|
let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>();
|
||||||
let peer_id = PeerId::from_multihash(
|
let peer_id = PeerId::from_multihash(
|
||||||
Multihash::wrap(multihash::Code::Sha2_256.into(), &seed).unwrap()
|
Multihash::wrap(multihash::Code::Sha2_256.into(), &seed).unwrap(),
|
||||||
).unwrap();
|
)
|
||||||
let multiaddr = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333".parse::<Multiaddr>()
|
.unwrap();
|
||||||
|
let multiaddr = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333"
|
||||||
|
.parse::<Multiaddr>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with(Protocol::P2p(peer_id.into()));
|
.with(Protocol::P2p(peer_id.into()));
|
||||||
|
|
||||||
@@ -176,12 +193,15 @@ mod tests {
|
|||||||
fn arbitrary(g: &mut Gen) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>();
|
let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>();
|
||||||
let peer_id = PeerId::from_multihash(
|
let peer_id = PeerId::from_multihash(
|
||||||
Multihash::wrap(multihash::Code::Sha2_256.into(), &seed).unwrap()
|
Multihash::wrap(multihash::Code::Sha2_256.into(), &seed).unwrap(),
|
||||||
).unwrap();
|
)
|
||||||
let multiaddr1 = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333".parse::<Multiaddr>()
|
.unwrap();
|
||||||
|
let multiaddr1 = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333"
|
||||||
|
.parse::<Multiaddr>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with(Protocol::P2p(peer_id.clone().into()));
|
.with(Protocol::P2p(peer_id.clone().into()));
|
||||||
let multiaddr2 = "/ip6/2002:db8:0:0:0:0:0:2/tcp/30133".parse::<Multiaddr>()
|
let multiaddr2 = "/ip6/2002:db8:0:0:0:0:0:2/tcp/30133"
|
||||||
|
.parse::<Multiaddr>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with(Protocol::P2p(peer_id.into()));
|
.with(Protocol::P2p(peer_id.into()));
|
||||||
TestMultiaddrsSamePeerCombo(multiaddr1, multiaddr2)
|
TestMultiaddrsSamePeerCombo(multiaddr1, multiaddr2)
|
||||||
@@ -219,11 +239,13 @@ mod tests {
|
|||||||
cache.retain_ids(&vec![first.0, second.0]);
|
cache.retain_ids(&vec![first.0, second.0]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
None, cache.get_addresses_by_authority_id(&third.0),
|
None,
|
||||||
|
cache.get_addresses_by_authority_id(&third.0),
|
||||||
"Expect `get_addresses_by_authority_id` to not return `None` for third authority."
|
"Expect `get_addresses_by_authority_id` to not return `None` for third authority."
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
None, cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&third.1).unwrap()),
|
None,
|
||||||
|
cache.get_authority_id_by_peer_id(&peer_id_from_multiaddr(&third.1).unwrap()),
|
||||||
"Expect `get_authority_id_by_peer_id` to return `None` for third authority."
|
"Expect `get_authority_id_by_peer_id` to return `None` for third authority."
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -253,7 +275,10 @@ mod tests {
|
|||||||
let mut cache = AddrCache::new();
|
let mut cache = AddrCache::new();
|
||||||
|
|
||||||
cache.insert(authority1.clone(), vec![multiaddr1.clone()]);
|
cache.insert(authority1.clone(), vec![multiaddr1.clone()]);
|
||||||
cache.insert(authority1.clone(), vec![multiaddr2.clone(), multiaddr3.clone(), multiaddr4.clone()]);
|
cache.insert(
|
||||||
|
authority1.clone(),
|
||||||
|
vec![multiaddr2.clone(), multiaddr3.clone(), multiaddr4.clone()],
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
None,
|
None,
|
||||||
|
|||||||
@@ -18,21 +18,26 @@
|
|||||||
|
|
||||||
use crate::worker::schema;
|
use crate::worker::schema;
|
||||||
|
|
||||||
use std::{sync::{Arc, Mutex}, task::Poll};
|
use std::{
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
task::Poll,
|
||||||
|
};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::channel::mpsc::{self, channel};
|
use futures::{
|
||||||
use futures::executor::{block_on, LocalPool};
|
channel::mpsc::{self, channel},
|
||||||
use futures::future::FutureExt;
|
executor::{block_on, LocalPool},
|
||||||
use futures::sink::SinkExt;
|
future::FutureExt,
|
||||||
use futures::task::LocalSpawn;
|
sink::SinkExt,
|
||||||
use libp2p::{kad, core::multiaddr, PeerId};
|
task::LocalSpawn,
|
||||||
|
};
|
||||||
|
use libp2p::{core::multiaddr, kad, PeerId};
|
||||||
use prometheus_endpoint::prometheus::default_registry;
|
use prometheus_endpoint::prometheus::default_registry;
|
||||||
|
|
||||||
use sp_api::{ProvideRuntimeApi, ApiRef};
|
use sp_api::{ApiRef, ProvideRuntimeApi};
|
||||||
use sp_core::crypto::Public;
|
use sp_core::crypto::Public;
|
||||||
use sp_keystore::{testing::KeyStore, CryptoStore};
|
use sp_keystore::{testing::KeyStore, CryptoStore};
|
||||||
use sp_runtime::traits::{Zero, Block as BlockT, NumberFor};
|
use sp_runtime::traits::{Block as BlockT, NumberFor, Zero};
|
||||||
use substrate_test_runtime_client::runtime::Block;
|
use substrate_test_runtime_client::runtime::Block;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -46,9 +51,7 @@ impl ProvideRuntimeApi<Block> for TestApi {
|
|||||||
type Api = RuntimeApi;
|
type Api = RuntimeApi;
|
||||||
|
|
||||||
fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> {
|
fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> {
|
||||||
RuntimeApi {
|
RuntimeApi { authorities: self.authorities.clone() }.into()
|
||||||
authorities: self.authorities.clone(),
|
|
||||||
}.into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,10 +138,7 @@ impl Default for TestNetwork {
|
|||||||
let (tx, rx) = mpsc::unbounded();
|
let (tx, rx) = mpsc::unbounded();
|
||||||
TestNetwork {
|
TestNetwork {
|
||||||
peer_id: PeerId::random(),
|
peer_id: PeerId::random(),
|
||||||
external_addresses: vec![
|
external_addresses: vec!["/ip6/2001:db8::/tcp/30333".parse().unwrap()],
|
||||||
"/ip6/2001:db8::/tcp/30333"
|
|
||||||
.parse().unwrap(),
|
|
||||||
],
|
|
||||||
put_value_call: Default::default(),
|
put_value_call: Default::default(),
|
||||||
get_value_call: Default::default(),
|
get_value_call: Default::default(),
|
||||||
event_sender: tx,
|
event_sender: tx,
|
||||||
@@ -151,11 +151,17 @@ impl Default for TestNetwork {
|
|||||||
impl NetworkProvider for TestNetwork {
|
impl NetworkProvider for TestNetwork {
|
||||||
fn put_value(&self, key: kad::record::Key, value: Vec<u8>) {
|
fn put_value(&self, key: kad::record::Key, value: Vec<u8>) {
|
||||||
self.put_value_call.lock().unwrap().push((key.clone(), value.clone()));
|
self.put_value_call.lock().unwrap().push((key.clone(), value.clone()));
|
||||||
self.event_sender.clone().unbounded_send(TestNetworkEvent::PutCalled(key, value)).unwrap();
|
self.event_sender
|
||||||
|
.clone()
|
||||||
|
.unbounded_send(TestNetworkEvent::PutCalled(key, value))
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
fn get_value(&self, key: &kad::record::Key) {
|
fn get_value(&self, key: &kad::record::Key) {
|
||||||
self.get_value_call.lock().unwrap().push(key.clone());
|
self.get_value_call.lock().unwrap().push(key.clone());
|
||||||
self.event_sender.clone().unbounded_send(TestNetworkEvent::GetCalled(key.clone())).unwrap();
|
self.event_sender
|
||||||
|
.clone()
|
||||||
|
.unbounded_send(TestNetworkEvent::GetCalled(key.clone()))
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,9 +181,8 @@ async fn build_dht_event(
|
|||||||
key_store: &KeyStore,
|
key_store: &KeyStore,
|
||||||
) -> (libp2p::kad::record::Key, Vec<u8>) {
|
) -> (libp2p::kad::record::Key, Vec<u8>) {
|
||||||
let mut serialized_addresses = vec![];
|
let mut serialized_addresses = vec![];
|
||||||
schema::AuthorityAddresses {
|
schema::AuthorityAddresses { addresses: addresses.into_iter().map(|a| a.to_vec()).collect() }
|
||||||
addresses: addresses.into_iter().map(|a| a.to_vec()).collect()
|
.encode(&mut serialized_addresses)
|
||||||
}.encode(&mut serialized_addresses)
|
|
||||||
.map_err(Error::EncodingProto)
|
.map_err(Error::EncodingProto)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -192,11 +197,9 @@ async fn build_dht_event(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut signed_addresses = vec![];
|
let mut signed_addresses = vec![];
|
||||||
schema::SignedAuthorityAddresses {
|
schema::SignedAuthorityAddresses { addresses: serialized_addresses.clone(), signature }
|
||||||
addresses: serialized_addresses.clone(),
|
.encode(&mut signed_addresses)
|
||||||
signature,
|
.unwrap();
|
||||||
}
|
|
||||||
.encode(&mut signed_addresses).unwrap();
|
|
||||||
|
|
||||||
let key = hash_authority_id(&public_key.to_raw_vec());
|
let key = hash_authority_id(&public_key.to_raw_vec());
|
||||||
let value = signed_addresses;
|
let value = signed_addresses;
|
||||||
@@ -208,9 +211,7 @@ fn new_registers_metrics() {
|
|||||||
let (_dht_event_tx, dht_event_rx) = mpsc::channel(1000);
|
let (_dht_event_tx, dht_event_rx) = mpsc::channel(1000);
|
||||||
let network: Arc<TestNetwork> = Arc::new(Default::default());
|
let network: Arc<TestNetwork> = Arc::new(Default::default());
|
||||||
let key_store = KeyStore::new();
|
let key_store = KeyStore::new();
|
||||||
let test_api = Arc::new(TestApi {
|
let test_api = Arc::new(TestApi { authorities: vec![] });
|
||||||
authorities: vec![],
|
|
||||||
});
|
|
||||||
|
|
||||||
let registry = prometheus_endpoint::Registry::new();
|
let registry = prometheus_endpoint::Registry::new();
|
||||||
|
|
||||||
@@ -275,65 +276,67 @@ fn publish_discover_cycle() {
|
|||||||
|
|
||||||
let key_store = KeyStore::new();
|
let key_store = KeyStore::new();
|
||||||
|
|
||||||
let _ = pool.spawner().spawn_local_obj(async move {
|
let _ = pool.spawner().spawn_local_obj(
|
||||||
let node_a_public = key_store
|
async move {
|
||||||
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)
|
let node_a_public = key_store
|
||||||
.await
|
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)
|
||||||
.unwrap();
|
.await
|
||||||
let test_api = Arc::new(TestApi {
|
.unwrap();
|
||||||
authorities: vec![node_a_public.into()],
|
let test_api = Arc::new(TestApi { authorities: vec![node_a_public.into()] });
|
||||||
});
|
|
||||||
|
|
||||||
let (_to_worker, from_service) = mpsc::channel(0);
|
let (_to_worker, from_service) = mpsc::channel(0);
|
||||||
let mut worker = Worker::new(
|
let mut worker = Worker::new(
|
||||||
from_service,
|
from_service,
|
||||||
test_api,
|
test_api,
|
||||||
network.clone(),
|
network.clone(),
|
||||||
Box::pin(dht_event_rx),
|
Box::pin(dht_event_rx),
|
||||||
Role::PublishAndDiscover(key_store.into()),
|
Role::PublishAndDiscover(key_store.into()),
|
||||||
None,
|
None,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
worker.publish_ext_addresses(false).await.unwrap();
|
worker.publish_ext_addresses(false).await.unwrap();
|
||||||
|
|
||||||
// Expect authority discovery to put a new record onto the dht.
|
// Expect authority discovery to put a new record onto the dht.
|
||||||
assert_eq!(network.put_value_call.lock().unwrap().len(), 1);
|
assert_eq!(network.put_value_call.lock().unwrap().len(), 1);
|
||||||
|
|
||||||
let dht_event = {
|
let dht_event = {
|
||||||
let (key, value) = network.put_value_call.lock().unwrap().pop().unwrap();
|
let (key, value) = network.put_value_call.lock().unwrap().pop().unwrap();
|
||||||
sc_network::DhtEvent::ValueFound(vec![(key, value)])
|
sc_network::DhtEvent::ValueFound(vec![(key, value)])
|
||||||
};
|
};
|
||||||
|
|
||||||
// Node B discovering node A's address.
|
// Node B discovering node A's address.
|
||||||
|
|
||||||
let (mut dht_event_tx, dht_event_rx) = channel(1000);
|
let (mut dht_event_tx, dht_event_rx) = channel(1000);
|
||||||
let test_api = Arc::new(TestApi {
|
let test_api = Arc::new(TestApi {
|
||||||
// Make sure node B identifies node A as an authority.
|
// Make sure node B identifies node A as an authority.
|
||||||
authorities: vec![node_a_public.into()],
|
authorities: vec![node_a_public.into()],
|
||||||
});
|
});
|
||||||
let network: Arc<TestNetwork> = Arc::new(Default::default());
|
let network: Arc<TestNetwork> = Arc::new(Default::default());
|
||||||
let key_store = KeyStore::new();
|
let key_store = KeyStore::new();
|
||||||
|
|
||||||
let (_to_worker, from_service) = mpsc::channel(0);
|
let (_to_worker, from_service) = mpsc::channel(0);
|
||||||
let mut worker = Worker::new(
|
let mut worker = Worker::new(
|
||||||
from_service,
|
from_service,
|
||||||
test_api,
|
test_api,
|
||||||
network.clone(),
|
network.clone(),
|
||||||
Box::pin(dht_event_rx),
|
Box::pin(dht_event_rx),
|
||||||
Role::PublishAndDiscover(key_store.into()),
|
Role::PublishAndDiscover(key_store.into()),
|
||||||
None,
|
None,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
dht_event_tx.try_send(dht_event.clone()).unwrap();
|
dht_event_tx.try_send(dht_event.clone()).unwrap();
|
||||||
|
|
||||||
worker.refill_pending_lookups_queue().await.unwrap();
|
worker.refill_pending_lookups_queue().await.unwrap();
|
||||||
worker.start_new_lookups();
|
worker.start_new_lookups();
|
||||||
|
|
||||||
// Make authority discovery handle the event.
|
// Make authority discovery handle the event.
|
||||||
worker.handle_dht_event(dht_event).await;
|
worker.handle_dht_event(dht_event).await;
|
||||||
}.boxed_local().into());
|
}
|
||||||
|
.boxed_local()
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
|
||||||
pool.run();
|
pool.run();
|
||||||
}
|
}
|
||||||
@@ -345,9 +348,7 @@ fn terminate_when_event_stream_terminates() {
|
|||||||
let (dht_event_tx, dht_event_rx) = channel(1000);
|
let (dht_event_tx, dht_event_rx) = channel(1000);
|
||||||
let network: Arc<TestNetwork> = Arc::new(Default::default());
|
let network: Arc<TestNetwork> = Arc::new(Default::default());
|
||||||
let key_store = KeyStore::new();
|
let key_store = KeyStore::new();
|
||||||
let test_api = Arc::new(TestApi {
|
let test_api = Arc::new(TestApi { authorities: vec![] });
|
||||||
authorities: vec![],
|
|
||||||
});
|
|
||||||
|
|
||||||
let (to_worker, from_service) = mpsc::channel(0);
|
let (to_worker, from_service) = mpsc::channel(0);
|
||||||
let worker = Worker::new(
|
let worker = Worker::new(
|
||||||
@@ -358,7 +359,8 @@ fn terminate_when_event_stream_terminates() {
|
|||||||
Role::PublishAndDiscover(key_store.into()),
|
Role::PublishAndDiscover(key_store.into()),
|
||||||
None,
|
None,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
).run();
|
)
|
||||||
|
.run();
|
||||||
futures::pin_mut!(worker);
|
futures::pin_mut!(worker);
|
||||||
|
|
||||||
block_on(async {
|
block_on(async {
|
||||||
@@ -367,7 +369,8 @@ fn terminate_when_event_stream_terminates() {
|
|||||||
// Drop sender side of service channel.
|
// Drop sender side of service channel.
|
||||||
drop(to_worker);
|
drop(to_worker);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Poll::Pending, futures::poll!(&mut worker),
|
Poll::Pending,
|
||||||
|
futures::poll!(&mut worker),
|
||||||
"Expect the authority discovery module not to terminate once the \
|
"Expect the authority discovery module not to terminate once the \
|
||||||
sender side of the service channel is closed.",
|
sender side of the service channel is closed.",
|
||||||
);
|
);
|
||||||
@@ -377,7 +380,8 @@ fn terminate_when_event_stream_terminates() {
|
|||||||
drop(dht_event_tx);
|
drop(dht_event_tx);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Poll::Ready(()), futures::poll!(&mut worker),
|
Poll::Ready(()),
|
||||||
|
futures::poll!(&mut worker),
|
||||||
"Expect the authority discovery module to terminate once the \
|
"Expect the authority discovery module to terminate once the \
|
||||||
sending side of the dht event channel is closed.",
|
sending side of the dht event channel is closed.",
|
||||||
);
|
);
|
||||||
@@ -390,14 +394,13 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() {
|
|||||||
let peer_id = PeerId::random();
|
let peer_id = PeerId::random();
|
||||||
let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
|
let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
|
||||||
|
|
||||||
address.with(multiaddr::Protocol::P2p(
|
address.with(multiaddr::Protocol::P2p(peer_id.into()))
|
||||||
peer_id.into(),
|
|
||||||
))
|
|
||||||
};
|
};
|
||||||
let remote_key_store = KeyStore::new();
|
let remote_key_store = KeyStore::new();
|
||||||
let remote_public_key: AuthorityId = block_on(
|
let remote_public_key: AuthorityId =
|
||||||
remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None),
|
block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
||||||
).unwrap().into();
|
.unwrap()
|
||||||
|
.into();
|
||||||
|
|
||||||
let (mut dht_event_tx, dht_event_rx) = channel(1);
|
let (mut dht_event_tx, dht_event_rx) = channel(1);
|
||||||
let (network, mut network_events) = {
|
let (network, mut network_events) = {
|
||||||
@@ -407,9 +410,7 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let key_store = KeyStore::new();
|
let key_store = KeyStore::new();
|
||||||
let test_api = Arc::new(TestApi {
|
let test_api = Arc::new(TestApi { authorities: vec![remote_public_key.clone()] });
|
||||||
authorities: vec![remote_public_key.clone()],
|
|
||||||
});
|
|
||||||
let mut pool = LocalPool::new();
|
let mut pool = LocalPool::new();
|
||||||
|
|
||||||
let (mut to_worker, from_service) = mpsc::channel(1);
|
let (mut to_worker, from_service) = mpsc::channel(1);
|
||||||
@@ -427,30 +428,35 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() {
|
|||||||
//
|
//
|
||||||
// As this is a local pool, only one future at a time will have the CPU and
|
// As this is a local pool, only one future at a time will have the CPU and
|
||||||
// can make progress until the future returns `Pending`.
|
// can make progress until the future returns `Pending`.
|
||||||
let _ = pool.spawner().spawn_local_obj(async move {
|
let _ = pool.spawner().spawn_local_obj(
|
||||||
// Refilling `pending_lookups` only happens every X minutes. Fast
|
async move {
|
||||||
// forward by calling `refill_pending_lookups_queue` directly.
|
// Refilling `pending_lookups` only happens every X minutes. Fast
|
||||||
worker.refill_pending_lookups_queue().await.unwrap();
|
// forward by calling `refill_pending_lookups_queue` directly.
|
||||||
worker.run().await
|
worker.refill_pending_lookups_queue().await.unwrap();
|
||||||
}.boxed_local().into());
|
worker.run().await
|
||||||
|
}
|
||||||
|
.boxed_local()
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
|
||||||
pool.run_until(async {
|
pool.run_until(async {
|
||||||
// Assert worker to trigger a lookup for the one and only authority.
|
// Assert worker to trigger a lookup for the one and only authority.
|
||||||
assert!(matches!(
|
assert!(matches!(network_events.next().await, Some(TestNetworkEvent::GetCalled(_))));
|
||||||
network_events.next().await,
|
|
||||||
Some(TestNetworkEvent::GetCalled(_))
|
|
||||||
));
|
|
||||||
|
|
||||||
// Send an event that should generate an error
|
// Send an event that should generate an error
|
||||||
dht_event_tx.send(DhtEvent::ValueFound(Default::default())).await
|
dht_event_tx
|
||||||
|
.send(DhtEvent::ValueFound(Default::default()))
|
||||||
|
.await
|
||||||
.expect("Channel has capacity of 1.");
|
.expect("Channel has capacity of 1.");
|
||||||
|
|
||||||
// Make previously triggered lookup succeed.
|
// Make previously triggered lookup succeed.
|
||||||
let dht_event = {
|
let dht_event = {
|
||||||
let (key, value) = build_dht_event(
|
let (key, value) = build_dht_event(
|
||||||
vec![remote_multiaddr.clone()],
|
vec![remote_multiaddr.clone()],
|
||||||
remote_public_key.clone(), &remote_key_store,
|
remote_public_key.clone(),
|
||||||
).await;
|
&remote_key_store,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
sc_network::DhtEvent::ValueFound(vec![(key, value)])
|
sc_network::DhtEvent::ValueFound(vec![(key, value)])
|
||||||
};
|
};
|
||||||
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
|
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
|
||||||
@@ -458,10 +464,10 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() {
|
|||||||
// Expect authority discovery to function normally, now knowing the
|
// Expect authority discovery to function normally, now knowing the
|
||||||
// address for the remote node.
|
// address for the remote node.
|
||||||
let (sender, addresses) = futures::channel::oneshot::channel();
|
let (sender, addresses) = futures::channel::oneshot::channel();
|
||||||
to_worker.send(ServicetoWorkerMsg::GetAddressesByAuthorityId(
|
to_worker
|
||||||
remote_public_key,
|
.send(ServicetoWorkerMsg::GetAddressesByAuthorityId(remote_public_key, sender))
|
||||||
sender,
|
.await
|
||||||
)).await.expect("Channel has capacity of 1.");
|
.expect("Channel has capacity of 1.");
|
||||||
assert_eq!(Some(vec![remote_multiaddr]), addresses.await.unwrap());
|
assert_eq!(Some(vec![remote_multiaddr]), addresses.await.unwrap());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -469,23 +475,19 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn limit_number_of_addresses_added_to_cache_per_authority() {
|
fn limit_number_of_addresses_added_to_cache_per_authority() {
|
||||||
let remote_key_store = KeyStore::new();
|
let remote_key_store = KeyStore::new();
|
||||||
let remote_public = block_on(remote_key_store
|
let remote_public =
|
||||||
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let addresses = (0..100).map(|_| {
|
let addresses = (0..100)
|
||||||
let peer_id = PeerId::random();
|
.map(|_| {
|
||||||
let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
|
let peer_id = PeerId::random();
|
||||||
address.with(multiaddr::Protocol::P2p(
|
let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
|
||||||
peer_id.into(),
|
address.with(multiaddr::Protocol::P2p(peer_id.into()))
|
||||||
))
|
})
|
||||||
}).collect();
|
.collect();
|
||||||
|
|
||||||
let dht_event = block_on(build_dht_event(
|
let dht_event = block_on(build_dht_event(addresses, remote_public.into(), &remote_key_store));
|
||||||
addresses,
|
|
||||||
remote_public.into(),
|
|
||||||
&remote_key_store,
|
|
||||||
));
|
|
||||||
|
|
||||||
let (_dht_event_tx, dht_event_rx) = channel(1);
|
let (_dht_event_tx, dht_event_rx) = channel(1);
|
||||||
|
|
||||||
@@ -506,16 +508,20 @@ fn limit_number_of_addresses_added_to_cache_per_authority() {
|
|||||||
worker.handle_dht_value_found_event(vec![dht_event]).unwrap();
|
worker.handle_dht_value_found_event(vec![dht_event]).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
MAX_ADDRESSES_PER_AUTHORITY,
|
MAX_ADDRESSES_PER_AUTHORITY,
|
||||||
worker.addr_cache.get_addresses_by_authority_id(&remote_public.into()).unwrap().len(),
|
worker
|
||||||
|
.addr_cache
|
||||||
|
.get_addresses_by_authority_id(&remote_public.into())
|
||||||
|
.unwrap()
|
||||||
|
.len(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn do_not_cache_addresses_without_peer_id() {
|
fn do_not_cache_addresses_without_peer_id() {
|
||||||
let remote_key_store = KeyStore::new();
|
let remote_key_store = KeyStore::new();
|
||||||
let remote_public = block_on(remote_key_store
|
let remote_public =
|
||||||
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let multiaddr_with_peer_id = {
|
let multiaddr_with_peer_id = {
|
||||||
let peer_id = PeerId::random();
|
let peer_id = PeerId::random();
|
||||||
@@ -524,21 +530,17 @@ fn do_not_cache_addresses_without_peer_id() {
|
|||||||
address.with(multiaddr::Protocol::P2p(peer_id.into()))
|
address.with(multiaddr::Protocol::P2p(peer_id.into()))
|
||||||
};
|
};
|
||||||
|
|
||||||
let multiaddr_without_peer_id: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
|
let multiaddr_without_peer_id: Multiaddr =
|
||||||
|
"/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
|
||||||
|
|
||||||
let dht_event = block_on(build_dht_event(
|
let dht_event = block_on(build_dht_event(
|
||||||
vec![
|
vec![multiaddr_with_peer_id.clone(), multiaddr_without_peer_id],
|
||||||
multiaddr_with_peer_id.clone(),
|
|
||||||
multiaddr_without_peer_id,
|
|
||||||
],
|
|
||||||
remote_public.into(),
|
remote_public.into(),
|
||||||
&remote_key_store,
|
&remote_key_store,
|
||||||
));
|
));
|
||||||
|
|
||||||
let (_dht_event_tx, dht_event_rx) = channel(1);
|
let (_dht_event_tx, dht_event_rx) = channel(1);
|
||||||
let local_test_api = Arc::new(TestApi {
|
let local_test_api = Arc::new(TestApi { authorities: vec![remote_public.into()] });
|
||||||
authorities: vec![remote_public.into()],
|
|
||||||
});
|
|
||||||
let local_network: Arc<TestNetwork> = Arc::new(Default::default());
|
let local_network: Arc<TestNetwork> = Arc::new(Default::default());
|
||||||
let local_key_store = KeyStore::new();
|
let local_key_store = KeyStore::new();
|
||||||
|
|
||||||
@@ -578,9 +580,7 @@ fn addresses_to_publish_adds_p2p() {
|
|||||||
let (_to_worker, from_service) = mpsc::channel(0);
|
let (_to_worker, from_service) = mpsc::channel(0);
|
||||||
let worker = Worker::new(
|
let worker = Worker::new(
|
||||||
from_service,
|
from_service,
|
||||||
Arc::new(TestApi {
|
Arc::new(TestApi { authorities: vec![] }),
|
||||||
authorities: vec![],
|
|
||||||
}),
|
|
||||||
network.clone(),
|
network.clone(),
|
||||||
Box::pin(dht_event_rx),
|
Box::pin(dht_event_rx),
|
||||||
Role::PublishAndDiscover(Arc::new(KeyStore::new())),
|
Role::PublishAndDiscover(Arc::new(KeyStore::new())),
|
||||||
@@ -605,17 +605,16 @@ fn addresses_to_publish_respects_existing_p2p_protocol() {
|
|||||||
let network: Arc<TestNetwork> = Arc::new(TestNetwork {
|
let network: Arc<TestNetwork> = Arc::new(TestNetwork {
|
||||||
external_addresses: vec![
|
external_addresses: vec![
|
||||||
"/ip6/2001:db8::/tcp/30333/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"
|
"/ip6/2001:db8::/tcp/30333/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"
|
||||||
.parse().unwrap(),
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
],
|
],
|
||||||
.. Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
let (_to_worker, from_service) = mpsc::channel(0);
|
let (_to_worker, from_service) = mpsc::channel(0);
|
||||||
let worker = Worker::new(
|
let worker = Worker::new(
|
||||||
from_service,
|
from_service,
|
||||||
Arc::new(TestApi {
|
Arc::new(TestApi { authorities: vec![] }),
|
||||||
authorities: vec![],
|
|
||||||
}),
|
|
||||||
network.clone(),
|
network.clone(),
|
||||||
Box::pin(dht_event_rx),
|
Box::pin(dht_event_rx),
|
||||||
Role::PublishAndDiscover(Arc::new(KeyStore::new())),
|
Role::PublishAndDiscover(Arc::new(KeyStore::new())),
|
||||||
@@ -624,7 +623,8 @@ fn addresses_to_publish_respects_existing_p2p_protocol() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
network.external_addresses, worker.addresses_to_publish().collect::<Vec<_>>(),
|
network.external_addresses,
|
||||||
|
worker.addresses_to_publish().collect::<Vec<_>>(),
|
||||||
"Expected Multiaddr from `TestNetwork` to not be altered.",
|
"Expected Multiaddr from `TestNetwork` to not be altered.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -635,21 +635,21 @@ fn lookup_throttling() {
|
|||||||
let peer_id = PeerId::random();
|
let peer_id = PeerId::random();
|
||||||
let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
|
let address: Multiaddr = "/ip6/2001:db8:0:0:0:0:0:1/tcp/30333".parse().unwrap();
|
||||||
|
|
||||||
address.with(multiaddr::Protocol::P2p(
|
address.with(multiaddr::Protocol::P2p(peer_id.into()))
|
||||||
peer_id.into(),
|
|
||||||
))
|
|
||||||
};
|
};
|
||||||
let remote_key_store = KeyStore::new();
|
let remote_key_store = KeyStore::new();
|
||||||
let remote_public_keys: Vec<AuthorityId> = (0..20).map(|_| {
|
let remote_public_keys: Vec<AuthorityId> = (0..20)
|
||||||
block_on(remote_key_store
|
.map(|_| {
|
||||||
.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None))
|
||||||
.unwrap().into()
|
.unwrap()
|
||||||
}).collect();
|
.into()
|
||||||
let remote_hash_to_key = remote_public_keys.iter()
|
})
|
||||||
|
.collect();
|
||||||
|
let remote_hash_to_key = remote_public_keys
|
||||||
|
.iter()
|
||||||
.map(|k| (hash_authority_id(k.as_ref()), k.clone()))
|
.map(|k| (hash_authority_id(k.as_ref()), k.clone()))
|
||||||
.collect::<HashMap<_, _>>();
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
|
||||||
let (mut dht_event_tx, dht_event_rx) = channel(1);
|
let (mut dht_event_tx, dht_event_rx) = channel(1);
|
||||||
let (_to_worker, from_service) = mpsc::channel(0);
|
let (_to_worker, from_service) = mpsc::channel(0);
|
||||||
let mut network = TestNetwork::default();
|
let mut network = TestNetwork::default();
|
||||||
@@ -668,56 +668,61 @@ fn lookup_throttling() {
|
|||||||
let mut pool = LocalPool::new();
|
let mut pool = LocalPool::new();
|
||||||
let metrics = worker.metrics.clone().unwrap();
|
let metrics = worker.metrics.clone().unwrap();
|
||||||
|
|
||||||
let _ = pool.spawner().spawn_local_obj(async move {
|
let _ = pool.spawner().spawn_local_obj(
|
||||||
// Refilling `pending_lookups` only happens every X minutes. Fast
|
async move {
|
||||||
// forward by calling `refill_pending_lookups_queue` directly.
|
// Refilling `pending_lookups` only happens every X minutes. Fast
|
||||||
worker.refill_pending_lookups_queue().await.unwrap();
|
// forward by calling `refill_pending_lookups_queue` directly.
|
||||||
worker.run().await
|
worker.refill_pending_lookups_queue().await.unwrap();
|
||||||
}.boxed_local().into());
|
worker.run().await
|
||||||
|
|
||||||
pool.run_until(async {
|
|
||||||
// Assert worker to trigger MAX_IN_FLIGHT_LOOKUPS lookups.
|
|
||||||
for _ in 0..MAX_IN_FLIGHT_LOOKUPS {
|
|
||||||
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
|
|
||||||
}
|
}
|
||||||
assert_eq!(
|
.boxed_local()
|
||||||
metrics.requests_pending.get(),
|
.into(),
|
||||||
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS) as u64
|
);
|
||||||
);
|
|
||||||
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS);
|
|
||||||
|
|
||||||
// Make first lookup succeed.
|
pool.run_until(
|
||||||
let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap();
|
async {
|
||||||
let remote_key: AuthorityId = remote_hash_to_key.get(&remote_hash).unwrap().clone();
|
// Assert worker to trigger MAX_IN_FLIGHT_LOOKUPS lookups.
|
||||||
let dht_event = {
|
for _ in 0..MAX_IN_FLIGHT_LOOKUPS {
|
||||||
let (key, value) = build_dht_event(
|
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
|
||||||
vec![remote_multiaddr.clone()],
|
}
|
||||||
remote_key,
|
assert_eq!(
|
||||||
&remote_key_store
|
metrics.requests_pending.get(),
|
||||||
).await;
|
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS) as u64
|
||||||
sc_network::DhtEvent::ValueFound(vec![(key, value)])
|
);
|
||||||
};
|
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS);
|
||||||
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
|
|
||||||
|
|
||||||
// Assert worker to trigger another lookup.
|
// Make first lookup succeed.
|
||||||
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
|
let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap();
|
||||||
assert_eq!(
|
let remote_key: AuthorityId = remote_hash_to_key.get(&remote_hash).unwrap().clone();
|
||||||
metrics.requests_pending.get(),
|
let dht_event = {
|
||||||
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS - 1) as u64
|
let (key, value) =
|
||||||
);
|
build_dht_event(vec![remote_multiaddr.clone()], remote_key, &remote_key_store)
|
||||||
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS);
|
.await;
|
||||||
|
sc_network::DhtEvent::ValueFound(vec![(key, value)])
|
||||||
|
};
|
||||||
|
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
|
||||||
|
|
||||||
// Make second one fail.
|
// Assert worker to trigger another lookup.
|
||||||
let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap();
|
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
|
||||||
let dht_event = sc_network::DhtEvent::ValueNotFound(remote_hash);
|
assert_eq!(
|
||||||
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
|
metrics.requests_pending.get(),
|
||||||
|
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS - 1) as u64
|
||||||
|
);
|
||||||
|
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS);
|
||||||
|
|
||||||
// Assert worker to trigger another lookup.
|
// Make second one fail.
|
||||||
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
|
let remote_hash = network.get_value_call.lock().unwrap().pop().unwrap();
|
||||||
assert_eq!(
|
let dht_event = sc_network::DhtEvent::ValueNotFound(remote_hash);
|
||||||
metrics.requests_pending.get(),
|
dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1.");
|
||||||
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS - 2) as u64
|
|
||||||
);
|
// Assert worker to trigger another lookup.
|
||||||
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS);
|
assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_))));
|
||||||
}.boxed_local());
|
assert_eq!(
|
||||||
|
metrics.requests_pending.get(),
|
||||||
|
(remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS - 2) as u64
|
||||||
|
);
|
||||||
|
assert_eq!(network.get_value_call.lock().unwrap().len(), MAX_IN_FLIGHT_LOOKUPS);
|
||||||
|
}
|
||||||
|
.boxed_local(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,24 +20,30 @@
|
|||||||
|
|
||||||
// FIXME #1021 move this into sp-consensus
|
// FIXME #1021 move this into sp-consensus
|
||||||
|
|
||||||
use std::{pin::Pin, time, sync::Arc};
|
|
||||||
use sc_client_api::backend;
|
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use sp_consensus::{evaluation, Proposal, ProofRecording, DisableProofRecording, EnableProofRecording};
|
use futures::{
|
||||||
|
channel::oneshot,
|
||||||
|
future,
|
||||||
|
future::{Future, FutureExt},
|
||||||
|
select,
|
||||||
|
};
|
||||||
|
use log::{debug, error, info, trace, warn};
|
||||||
|
use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider};
|
||||||
|
use sc_client_api::backend;
|
||||||
|
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_INFO};
|
||||||
|
use sc_transaction_pool_api::{InPoolTransaction, TransactionPool};
|
||||||
|
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||||
|
use sp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed, HeaderBackend};
|
||||||
|
use sp_consensus::{
|
||||||
|
evaluation, DisableProofRecording, EnableProofRecording, ProofRecording, Proposal,
|
||||||
|
};
|
||||||
use sp_core::traits::SpawnNamed;
|
use sp_core::traits::SpawnNamed;
|
||||||
use sp_inherents::InherentData;
|
use sp_inherents::InherentData;
|
||||||
use log::{error, info, debug, trace, warn};
|
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
generic::BlockId,
|
generic::BlockId,
|
||||||
traits::{Block as BlockT, Hash as HashT, Header as HeaderT, DigestFor, BlakeTwo256},
|
traits::{BlakeTwo256, Block as BlockT, DigestFor, Hash as HashT, Header as HeaderT},
|
||||||
};
|
};
|
||||||
use sc_transaction_pool_api::{TransactionPool, InPoolTransaction};
|
use std::{marker::PhantomData, pin::Pin, sync::Arc, time};
|
||||||
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_INFO};
|
|
||||||
use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider};
|
|
||||||
use sp_api::{ProvideRuntimeApi, ApiExt};
|
|
||||||
use futures::{future, future::{Future, FutureExt}, channel::oneshot, select};
|
|
||||||
use sp_blockchain::{HeaderBackend, ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed};
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
use prometheus_endpoint::Registry as PrometheusRegistry;
|
use prometheus_endpoint::Registry as PrometheusRegistry;
|
||||||
use sc_proposer_metrics::MetricsLink as PrometheusMetrics;
|
use sc_proposer_metrics::MetricsLink as PrometheusMetrics;
|
||||||
@@ -141,14 +147,18 @@ impl<A, B, C, PR> ProposerFactory<A, B, C, PR> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<B, Block, C, A, PR> ProposerFactory<A, B, C, PR>
|
impl<B, Block, C, A, PR> ProposerFactory<A, B, C, PR>
|
||||||
where
|
where
|
||||||
A: TransactionPool<Block = Block> + 'static,
|
A: TransactionPool<Block = Block> + 'static,
|
||||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block>
|
C: BlockBuilderProvider<B, Block, C>
|
||||||
+ Send + Sync + 'static,
|
+ HeaderBackend<Block>
|
||||||
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
|
+ ProvideRuntimeApi<Block>
|
||||||
+ BlockBuilderApi<Block>,
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
|
C::Api:
|
||||||
|
ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + BlockBuilderApi<Block>,
|
||||||
{
|
{
|
||||||
fn init_with_now(
|
fn init_with_now(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -180,26 +190,26 @@ impl<B, Block, C, A, PR> ProposerFactory<A, B, C, PR>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, Block, C, PR> sp_consensus::Environment<Block> for
|
impl<A, B, Block, C, PR> sp_consensus::Environment<Block> for ProposerFactory<A, B, C, PR>
|
||||||
ProposerFactory<A, B, C, PR>
|
where
|
||||||
where
|
A: TransactionPool<Block = Block> + 'static,
|
||||||
A: TransactionPool<Block = Block> + 'static,
|
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
Block: BlockT,
|
||||||
Block: BlockT,
|
C: BlockBuilderProvider<B, Block, C>
|
||||||
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block>
|
+ HeaderBackend<Block>
|
||||||
+ Send + Sync + 'static,
|
+ ProvideRuntimeApi<Block>
|
||||||
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
|
+ Send
|
||||||
+ BlockBuilderApi<Block>,
|
+ Sync
|
||||||
PR: ProofRecording,
|
+ 'static,
|
||||||
|
C::Api:
|
||||||
|
ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + BlockBuilderApi<Block>,
|
||||||
|
PR: ProofRecording,
|
||||||
{
|
{
|
||||||
type CreateProposer = future::Ready<Result<Self::Proposer, Self::Error>>;
|
type CreateProposer = future::Ready<Result<Self::Proposer, Self::Error>>;
|
||||||
type Proposer = Proposer<B, Block, C, A, PR>;
|
type Proposer = Proposer<B, Block, C, A, PR>;
|
||||||
type Error = sp_blockchain::Error;
|
type Error = sp_blockchain::Error;
|
||||||
|
|
||||||
fn init(
|
fn init(&mut self, parent_header: &<Block as BlockT>::Header) -> Self::CreateProposer {
|
||||||
&mut self,
|
|
||||||
parent_header: &<Block as BlockT>::Header,
|
|
||||||
) -> Self::CreateProposer {
|
|
||||||
future::ready(Ok(self.init_with_now(parent_header, Box::new(time::Instant::now))))
|
future::ready(Ok(self.init_with_now(parent_header, Box::new(time::Instant::now))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,22 +230,28 @@ pub struct Proposer<B, Block: BlockT, C, A: TransactionPool, PR> {
|
|||||||
_phantom: PhantomData<(B, PR)>,
|
_phantom: PhantomData<(B, PR)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, Block, C, PR> sp_consensus::Proposer<Block> for
|
impl<A, B, Block, C, PR> sp_consensus::Proposer<Block> for Proposer<B, Block, C, A, PR>
|
||||||
Proposer<B, Block, C, A, PR>
|
where
|
||||||
where
|
A: TransactionPool<Block = Block> + 'static,
|
||||||
A: TransactionPool<Block = Block> + 'static,
|
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
Block: BlockT,
|
||||||
Block: BlockT,
|
C: BlockBuilderProvider<B, Block, C>
|
||||||
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block>
|
+ HeaderBackend<Block>
|
||||||
+ Send + Sync + 'static,
|
+ ProvideRuntimeApi<Block>
|
||||||
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
|
+ Send
|
||||||
+ BlockBuilderApi<Block>,
|
+ Sync
|
||||||
PR: ProofRecording,
|
+ 'static,
|
||||||
|
C::Api:
|
||||||
|
ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + BlockBuilderApi<Block>,
|
||||||
|
PR: ProofRecording,
|
||||||
{
|
{
|
||||||
type Transaction = backend::TransactionFor<B, Block>;
|
type Transaction = backend::TransactionFor<B, Block>;
|
||||||
type Proposal = Pin<Box<dyn Future<
|
type Proposal = Pin<
|
||||||
Output = Result<Proposal<Block, Self::Transaction, PR::Proof>, Self::Error>
|
Box<
|
||||||
> + Send>>;
|
dyn Future<Output = Result<Proposal<Block, Self::Transaction, PR::Proof>, Self::Error>>
|
||||||
|
+ Send,
|
||||||
|
>,
|
||||||
|
>;
|
||||||
type Error = sp_blockchain::Error;
|
type Error = sp_blockchain::Error;
|
||||||
type ProofRecording = PR;
|
type ProofRecording = PR;
|
||||||
type Proof = PR::Proof;
|
type Proof = PR::Proof;
|
||||||
@@ -250,36 +266,38 @@ impl<A, B, Block, C, PR> sp_consensus::Proposer<Block> for
|
|||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
let spawn_handle = self.spawn_handle.clone();
|
let spawn_handle = self.spawn_handle.clone();
|
||||||
|
|
||||||
spawn_handle.spawn_blocking("basic-authorship-proposer", Box::pin(async move {
|
spawn_handle.spawn_blocking(
|
||||||
// leave some time for evaluation and block finalization (33%)
|
"basic-authorship-proposer",
|
||||||
let deadline = (self.now)() + max_duration - max_duration / 3;
|
Box::pin(async move {
|
||||||
let res = self.propose_with(
|
// leave some time for evaluation and block finalization (33%)
|
||||||
inherent_data,
|
let deadline = (self.now)() + max_duration - max_duration / 3;
|
||||||
inherent_digests,
|
let res = self
|
||||||
deadline,
|
.propose_with(inherent_data, inherent_digests, deadline, block_size_limit)
|
||||||
block_size_limit,
|
.await;
|
||||||
).await;
|
if tx.send(res).is_err() {
|
||||||
if tx.send(res).is_err() {
|
trace!("Could not send block production result to proposer!");
|
||||||
trace!("Could not send block production result to proposer!");
|
}
|
||||||
}
|
}),
|
||||||
}));
|
);
|
||||||
|
|
||||||
async move {
|
async move { rx.await? }.boxed()
|
||||||
rx.await?
|
|
||||||
}.boxed()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
||||||
where
|
where
|
||||||
A: TransactionPool<Block = Block>,
|
A: TransactionPool<Block = Block>,
|
||||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
C: BlockBuilderProvider<B, Block, C> + HeaderBackend<Block> + ProvideRuntimeApi<Block>
|
C: BlockBuilderProvider<B, Block, C>
|
||||||
+ Send + Sync + 'static,
|
+ HeaderBackend<Block>
|
||||||
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
|
+ ProvideRuntimeApi<Block>
|
||||||
+ BlockBuilderApi<Block>,
|
+ Send
|
||||||
PR: ProofRecording,
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
|
C::Api:
|
||||||
|
ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>> + BlockBuilderApi<Block>,
|
||||||
|
PR: ProofRecording,
|
||||||
{
|
{
|
||||||
async fn propose_with(
|
async fn propose_with(
|
||||||
self,
|
self,
|
||||||
@@ -287,30 +305,30 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
|||||||
inherent_digests: DigestFor<Block>,
|
inherent_digests: DigestFor<Block>,
|
||||||
deadline: time::Instant,
|
deadline: time::Instant,
|
||||||
block_size_limit: Option<usize>,
|
block_size_limit: Option<usize>,
|
||||||
) -> Result<Proposal<Block, backend::TransactionFor<B, Block>, PR::Proof>, sp_blockchain::Error> {
|
) -> Result<Proposal<Block, backend::TransactionFor<B, Block>, PR::Proof>, sp_blockchain::Error>
|
||||||
|
{
|
||||||
/// If the block is full we will attempt to push at most
|
/// If the block is full we will attempt to push at most
|
||||||
/// this number of transactions before quitting for real.
|
/// this number of transactions before quitting for real.
|
||||||
/// It allows us to increase block utilization.
|
/// It allows us to increase block utilization.
|
||||||
const MAX_SKIPPED_TRANSACTIONS: usize = 8;
|
const MAX_SKIPPED_TRANSACTIONS: usize = 8;
|
||||||
|
|
||||||
let mut block_builder = self.client.new_block_at(
|
let mut block_builder =
|
||||||
&self.parent_id,
|
self.client.new_block_at(&self.parent_id, inherent_digests, PR::ENABLED)?;
|
||||||
inherent_digests,
|
|
||||||
PR::ENABLED,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
for inherent in block_builder.create_inherents(inherent_data)? {
|
for inherent in block_builder.create_inherents(inherent_data)? {
|
||||||
match block_builder.push(inherent) {
|
match block_builder.push(inherent) {
|
||||||
Err(ApplyExtrinsicFailed(Validity(e))) if e.exhausted_resources() =>
|
Err(ApplyExtrinsicFailed(Validity(e))) if e.exhausted_resources() =>
|
||||||
warn!("⚠️ Dropping non-mandatory inherent from overweight block."),
|
warn!("⚠️ Dropping non-mandatory inherent from overweight block."),
|
||||||
Err(ApplyExtrinsicFailed(Validity(e))) if e.was_mandatory() => {
|
Err(ApplyExtrinsicFailed(Validity(e))) if e.was_mandatory() => {
|
||||||
error!("❌️ Mandatory inherent extrinsic returned error. Block cannot be produced.");
|
error!(
|
||||||
|
"❌️ Mandatory inherent extrinsic returned error. Block cannot be produced."
|
||||||
|
);
|
||||||
Err(ApplyExtrinsicFailed(Validity(e)))?
|
Err(ApplyExtrinsicFailed(Validity(e)))?
|
||||||
}
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("❗️ Inherent extrinsic returned unexpected error: {}. Dropping.", e);
|
warn!("❗️ Inherent extrinsic returned unexpected error: {}. Dropping.", e);
|
||||||
}
|
},
|
||||||
Ok(_) => {}
|
Ok(_) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,9 +338,8 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
|||||||
let mut unqueue_invalid = Vec::new();
|
let mut unqueue_invalid = Vec::new();
|
||||||
|
|
||||||
let mut t1 = self.transaction_pool.ready_at(self.parent_number).fuse();
|
let mut t1 = self.transaction_pool.ready_at(self.parent_number).fuse();
|
||||||
let mut t2 = futures_timer::Delay::new(
|
let mut t2 =
|
||||||
deadline.saturating_duration_since((self.now)()) / 8,
|
futures_timer::Delay::new(deadline.saturating_duration_since((self.now)()) / 8).fuse();
|
||||||
).fuse();
|
|
||||||
|
|
||||||
let pending_iterator = select! {
|
let pending_iterator = select! {
|
||||||
res = t1 => res,
|
res = t1 => res,
|
||||||
@@ -349,15 +366,14 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
|||||||
"Consensus deadline reached when pushing block transactions, \
|
"Consensus deadline reached when pushing block transactions, \
|
||||||
proceeding with proposing."
|
proceeding with proposing."
|
||||||
);
|
);
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
let pending_tx_data = pending_tx.data().clone();
|
let pending_tx_data = pending_tx.data().clone();
|
||||||
let pending_tx_hash = pending_tx.hash().clone();
|
let pending_tx_hash = pending_tx.hash().clone();
|
||||||
|
|
||||||
let block_size = block_builder.estimate_block_size(
|
let block_size =
|
||||||
self.include_proof_in_block_size_estimation,
|
block_builder.estimate_block_size(self.include_proof_in_block_size_estimation);
|
||||||
);
|
|
||||||
if block_size + pending_tx_data.encoded_size() > block_size_limit {
|
if block_size + pending_tx_data.encoded_size() > block_size_limit {
|
||||||
if skipped < MAX_SKIPPED_TRANSACTIONS {
|
if skipped < MAX_SKIPPED_TRANSACTIONS {
|
||||||
skipped += 1;
|
skipped += 1;
|
||||||
@@ -366,11 +382,11 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
|||||||
but will try {} more transactions before quitting.",
|
but will try {} more transactions before quitting.",
|
||||||
MAX_SKIPPED_TRANSACTIONS - skipped,
|
MAX_SKIPPED_TRANSACTIONS - skipped,
|
||||||
);
|
);
|
||||||
continue;
|
continue
|
||||||
} else {
|
} else {
|
||||||
debug!("Reached block size limit, proceeding with proposing.");
|
debug!("Reached block size limit, proceeding with proposing.");
|
||||||
hit_block_size_limit = true;
|
hit_block_size_limit = true;
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,9 +395,8 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
|||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
transaction_pushed = true;
|
transaction_pushed = true;
|
||||||
debug!("[{:?}] Pushed to the block.", pending_tx_hash);
|
debug!("[{:?}] Pushed to the block.", pending_tx_hash);
|
||||||
}
|
},
|
||||||
Err(ApplyExtrinsicFailed(Validity(e)))
|
Err(ApplyExtrinsicFailed(Validity(e))) if e.exhausted_resources() => {
|
||||||
if e.exhausted_resources() => {
|
|
||||||
if skipped < MAX_SKIPPED_TRANSACTIONS {
|
if skipped < MAX_SKIPPED_TRANSACTIONS {
|
||||||
skipped += 1;
|
skipped += 1;
|
||||||
debug!(
|
debug!(
|
||||||
@@ -390,20 +405,20 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
debug!("Block is full, proceed with proposing.");
|
debug!("Block is full, proceed with proposing.");
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Err(e) if skipped > 0 => {
|
Err(e) if skipped > 0 => {
|
||||||
trace!(
|
trace!(
|
||||||
"[{:?}] Ignoring invalid transaction when skipping: {}",
|
"[{:?}] Ignoring invalid transaction when skipping: {}",
|
||||||
pending_tx_hash,
|
pending_tx_hash,
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!("[{:?}] Invalid transaction: {}", pending_tx_hash, e);
|
debug!("[{:?}] Invalid transaction: {}", pending_tx_hash, e);
|
||||||
unqueue_invalid.push(pending_tx_hash);
|
unqueue_invalid.push(pending_tx_hash);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,12 +433,10 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
|||||||
|
|
||||||
let (block, storage_changes, proof) = block_builder.build()?.into_inner();
|
let (block, storage_changes, proof) = block_builder.build()?.into_inner();
|
||||||
|
|
||||||
self.metrics.report(
|
self.metrics.report(|metrics| {
|
||||||
|metrics| {
|
metrics.number_of_transactions.set(block.extrinsics().len() as u64);
|
||||||
metrics.number_of_transactions.set(block.extrinsics().len() as u64);
|
metrics.block_constructed.observe(block_timer.elapsed().as_secs_f64());
|
||||||
metrics.block_constructed.observe(block_timer.elapsed().as_secs_f64());
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"🎁 Prepared block for proposing at {} [hash: {:?}; parent_hash: {}; extrinsics ({}): [{}]]",
|
"🎁 Prepared block for proposing at {} [hash: {:?}; parent_hash: {}; extrinsics ({}): [{}]]",
|
||||||
@@ -449,16 +462,14 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
|||||||
error!("Failed to verify block encoding/decoding");
|
error!("Failed to verify block encoding/decoding");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(err) = evaluation::evaluate_initial(
|
if let Err(err) =
|
||||||
&block,
|
evaluation::evaluate_initial(&block, &self.parent_hash, self.parent_number)
|
||||||
&self.parent_hash,
|
{
|
||||||
self.parent_number,
|
|
||||||
) {
|
|
||||||
error!("Failed to evaluate authored block: {:?}", err);
|
error!("Failed to evaluate authored block: {:?}", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
let proof = PR::into_proof(proof)
|
let proof =
|
||||||
.map_err(|e| sp_blockchain::Error::Application(Box::new(e)))?;
|
PR::into_proof(proof).map_err(|e| sp_blockchain::Error::Application(Box::new(e)))?;
|
||||||
Ok(Proposal { block, proof, storage_changes })
|
Ok(Proposal { block, proof, storage_changes })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -467,19 +478,20 @@ impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use futures::executor::block_on;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use sp_consensus::{BlockOrigin, Proposer};
|
use sc_client_api::Backend;
|
||||||
use substrate_test_runtime_client::{
|
|
||||||
prelude::*, TestClientBuilder, runtime::{Extrinsic, Transfer}, TestClientBuilderExt,
|
|
||||||
};
|
|
||||||
use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool, TransactionSource};
|
|
||||||
use sc_transaction_pool::BasicPool;
|
use sc_transaction_pool::BasicPool;
|
||||||
|
use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool, TransactionSource};
|
||||||
use sp_api::Core;
|
use sp_api::Core;
|
||||||
use sp_blockchain::HeaderBackend;
|
use sp_blockchain::HeaderBackend;
|
||||||
|
use sp_consensus::{BlockOrigin, Environment, Proposer};
|
||||||
use sp_runtime::traits::NumberFor;
|
use sp_runtime::traits::NumberFor;
|
||||||
use sc_client_api::Backend;
|
use substrate_test_runtime_client::{
|
||||||
use futures::executor::block_on;
|
prelude::*,
|
||||||
use sp_consensus::Environment;
|
runtime::{Extrinsic, Transfer},
|
||||||
|
TestClientBuilder, TestClientBuilderExt,
|
||||||
|
};
|
||||||
|
|
||||||
const SOURCE: TransactionSource = TransactionSource::External;
|
const SOURCE: TransactionSource = TransactionSource::External;
|
||||||
|
|
||||||
@@ -489,16 +501,15 @@ mod tests {
|
|||||||
nonce,
|
nonce,
|
||||||
from: AccountKeyring::Alice.into(),
|
from: AccountKeyring::Alice.into(),
|
||||||
to: Default::default(),
|
to: Default::default(),
|
||||||
}.into_signed_tx()
|
}
|
||||||
|
.into_signed_tx()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chain_event<B: BlockT>(header: B::Header) -> ChainEvent<B>
|
fn chain_event<B: BlockT>(header: B::Header) -> ChainEvent<B>
|
||||||
where NumberFor<B>: From<u64>
|
where
|
||||||
|
NumberFor<B>: From<u64>,
|
||||||
{
|
{
|
||||||
ChainEvent::NewBestBlock {
|
ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }
|
||||||
hash: header.hash(),
|
|
||||||
tree_route: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -514,25 +525,20 @@ mod tests {
|
|||||||
client.clone(),
|
client.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
block_on(
|
block_on(txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0), extrinsic(1)]))
|
||||||
txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0), extrinsic(1)])
|
.unwrap();
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
block_on(
|
block_on(
|
||||||
txpool.maintain(chain_event(
|
txpool.maintain(chain_event(
|
||||||
client.header(&BlockId::Number(0u64))
|
client
|
||||||
|
.header(&BlockId::Number(0u64))
|
||||||
.expect("header get error")
|
.expect("header get error")
|
||||||
.expect("there should be header")
|
.expect("there should be header"),
|
||||||
))
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut proposer_factory = ProposerFactory::new(
|
let mut proposer_factory =
|
||||||
spawner.clone(),
|
ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
|
||||||
client.clone(),
|
|
||||||
txpool.clone(),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
let cell = Mutex::new((false, time::Instant::now()));
|
let cell = Mutex::new((false, time::Instant::now()));
|
||||||
let proposer = proposer_factory.init_with_now(
|
let proposer = proposer_factory.init_with_now(
|
||||||
@@ -541,20 +547,21 @@ mod tests {
|
|||||||
let mut value = cell.lock();
|
let mut value = cell.lock();
|
||||||
if !value.0 {
|
if !value.0 {
|
||||||
value.0 = true;
|
value.0 = true;
|
||||||
return value.1;
|
return value.1
|
||||||
}
|
}
|
||||||
let old = value.1;
|
let old = value.1;
|
||||||
let new = old + time::Duration::from_secs(2);
|
let new = old + time::Duration::from_secs(2);
|
||||||
*value = (true, new);
|
*value = (true, new);
|
||||||
old
|
old
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let deadline = time::Duration::from_secs(3);
|
let deadline = time::Duration::from_secs(3);
|
||||||
let block = block_on(
|
let block =
|
||||||
proposer.propose(Default::default(), Default::default(), deadline, None)
|
block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
|
||||||
).map(|r| r.block).unwrap();
|
.map(|r| r.block)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// block should have some extrinsics although we have some more in the pool.
|
// block should have some extrinsics although we have some more in the pool.
|
||||||
@@ -574,13 +581,8 @@ mod tests {
|
|||||||
client.clone(),
|
client.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut proposer_factory = ProposerFactory::new(
|
let mut proposer_factory =
|
||||||
spawner.clone(),
|
ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
|
||||||
client.clone(),
|
|
||||||
txpool.clone(),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
let cell = Mutex::new((false, time::Instant::now()));
|
let cell = Mutex::new((false, time::Instant::now()));
|
||||||
let proposer = proposer_factory.init_with_now(
|
let proposer = proposer_factory.init_with_now(
|
||||||
@@ -589,18 +591,18 @@ mod tests {
|
|||||||
let mut value = cell.lock();
|
let mut value = cell.lock();
|
||||||
if !value.0 {
|
if !value.0 {
|
||||||
value.0 = true;
|
value.0 = true;
|
||||||
return value.1;
|
return value.1
|
||||||
}
|
}
|
||||||
let new = value.1 + time::Duration::from_secs(160);
|
let new = value.1 + time::Duration::from_secs(160);
|
||||||
*value = (true, new);
|
*value = (true, new);
|
||||||
new
|
new
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
let deadline = time::Duration::from_secs(1);
|
let deadline = time::Duration::from_secs(1);
|
||||||
block_on(
|
block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
|
||||||
proposer.propose(Default::default(), Default::default(), deadline, None)
|
.map(|r| r.block)
|
||||||
).map(|r| r.block).unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -619,25 +621,19 @@ mod tests {
|
|||||||
let genesis_hash = client.info().best_hash;
|
let genesis_hash = client.info().best_hash;
|
||||||
let block_id = BlockId::Hash(genesis_hash);
|
let block_id = BlockId::Hash(genesis_hash);
|
||||||
|
|
||||||
block_on(
|
block_on(txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0)])).unwrap();
|
||||||
txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0)]),
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
block_on(
|
block_on(
|
||||||
txpool.maintain(chain_event(
|
txpool.maintain(chain_event(
|
||||||
client.header(&BlockId::Number(0u64))
|
client
|
||||||
|
.header(&BlockId::Number(0u64))
|
||||||
.expect("header get error")
|
.expect("header get error")
|
||||||
.expect("there should be header"),
|
.expect("there should be header"),
|
||||||
))
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut proposer_factory = ProposerFactory::new(
|
let mut proposer_factory =
|
||||||
spawner.clone(),
|
ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
|
||||||
client.clone(),
|
|
||||||
txpool.clone(),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
let proposer = proposer_factory.init_with_now(
|
let proposer = proposer_factory.init_with_now(
|
||||||
&client.header(&block_id).unwrap().unwrap(),
|
&client.header(&block_id).unwrap().unwrap(),
|
||||||
@@ -645,9 +641,9 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let deadline = time::Duration::from_secs(9);
|
let deadline = time::Duration::from_secs(9);
|
||||||
let proposal = block_on(
|
let proposal =
|
||||||
proposer.propose(Default::default(), Default::default(), deadline, None),
|
block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
|
||||||
).unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(proposal.block.extrinsics().len(), 1);
|
assert_eq!(proposal.block.extrinsics().len(), 1);
|
||||||
|
|
||||||
@@ -655,16 +651,13 @@ mod tests {
|
|||||||
api.execute_block(&block_id, proposal.block).unwrap();
|
api.execute_block(&block_id, proposal.block).unwrap();
|
||||||
|
|
||||||
let state = backend.state_at(block_id).unwrap();
|
let state = backend.state_at(block_id).unwrap();
|
||||||
let changes_trie_state = backend::changes_tries_state_at_block(
|
let changes_trie_state =
|
||||||
&block_id,
|
backend::changes_tries_state_at_block(&block_id, backend.changes_trie_storage())
|
||||||
backend.changes_trie_storage(),
|
.unwrap();
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
let storage_changes = api.into_storage_changes(
|
let storage_changes = api
|
||||||
&state,
|
.into_storage_changes(&state, changes_trie_state.as_ref(), genesis_hash)
|
||||||
changes_trie_state.as_ref(),
|
.unwrap();
|
||||||
genesis_hash,
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
proposal.storage_changes.transaction_storage_root,
|
proposal.storage_changes.transaction_storage_root,
|
||||||
@@ -685,8 +678,10 @@ mod tests {
|
|||||||
client.clone(),
|
client.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
block_on(
|
block_on(txpool.submit_at(
|
||||||
txpool.submit_at(&BlockId::number(0), SOURCE, vec![
|
&BlockId::number(0),
|
||||||
|
SOURCE,
|
||||||
|
vec![
|
||||||
extrinsic(0),
|
extrinsic(0),
|
||||||
extrinsic(1),
|
extrinsic(1),
|
||||||
Transfer {
|
Transfer {
|
||||||
@@ -704,22 +699,16 @@ mod tests {
|
|||||||
}.into_resources_exhausting_tx(),
|
}.into_resources_exhausting_tx(),
|
||||||
extrinsic(5),
|
extrinsic(5),
|
||||||
extrinsic(6),
|
extrinsic(6),
|
||||||
])
|
],
|
||||||
).unwrap();
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mut proposer_factory = ProposerFactory::new(
|
let mut proposer_factory =
|
||||||
spawner.clone(),
|
ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
|
||||||
client.clone(),
|
let mut propose_block = |client: &TestClient,
|
||||||
txpool.clone(),
|
number,
|
||||||
None,
|
expected_block_extrinsics,
|
||||||
None,
|
expected_pool_transactions| {
|
||||||
);
|
|
||||||
let mut propose_block = |
|
|
||||||
client: &TestClient,
|
|
||||||
number,
|
|
||||||
expected_block_extrinsics,
|
|
||||||
expected_pool_transactions,
|
|
||||||
| {
|
|
||||||
let proposer = proposer_factory.init_with_now(
|
let proposer = proposer_factory.init_with_now(
|
||||||
&client.header(&BlockId::number(number)).unwrap().unwrap(),
|
&client.header(&BlockId::number(number)).unwrap().unwrap(),
|
||||||
Box::new(move || time::Instant::now()),
|
Box::new(move || time::Instant::now()),
|
||||||
@@ -727,9 +716,10 @@ mod tests {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
let deadline = time::Duration::from_secs(9);
|
let deadline = time::Duration::from_secs(9);
|
||||||
let block = block_on(
|
let block =
|
||||||
proposer.propose(Default::default(), Default::default(), deadline, None)
|
block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
|
||||||
).map(|r| r.block).unwrap();
|
.map(|r| r.block)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// block should have some extrinsics although we have some more in the pool.
|
// block should have some extrinsics although we have some more in the pool.
|
||||||
@@ -741,10 +731,11 @@ mod tests {
|
|||||||
|
|
||||||
block_on(
|
block_on(
|
||||||
txpool.maintain(chain_event(
|
txpool.maintain(chain_event(
|
||||||
client.header(&BlockId::Number(0u64))
|
client
|
||||||
|
.header(&BlockId::Number(0u64))
|
||||||
.expect("header get error")
|
.expect("header get error")
|
||||||
.expect("there should be header")
|
.expect("there should be header"),
|
||||||
))
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// let's create one block and import it
|
// let's create one block and import it
|
||||||
@@ -753,10 +744,11 @@ mod tests {
|
|||||||
|
|
||||||
block_on(
|
block_on(
|
||||||
txpool.maintain(chain_event(
|
txpool.maintain(chain_event(
|
||||||
client.header(&BlockId::Number(1))
|
client
|
||||||
|
.header(&BlockId::Number(1))
|
||||||
.expect("header get error")
|
.expect("header get error")
|
||||||
.expect("there should be header")
|
.expect("there should be header"),
|
||||||
))
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// now let's make sure that we can still make some progress
|
// now let's make sure that we can still make some progress
|
||||||
@@ -775,7 +767,8 @@ mod tests {
|
|||||||
spawner.clone(),
|
spawner.clone(),
|
||||||
client.clone(),
|
client.clone(),
|
||||||
);
|
);
|
||||||
let genesis_header = client.header(&BlockId::Number(0u64))
|
let genesis_header = client
|
||||||
|
.header(&BlockId::Number(0u64))
|
||||||
.expect("header get error")
|
.expect("header get error")
|
||||||
.expect("there should be header");
|
.expect("there should be header");
|
||||||
|
|
||||||
@@ -784,40 +777,43 @@ mod tests {
|
|||||||
.map(|v| Extrinsic::IncludeData(vec![v as u8; 10]))
|
.map(|v| Extrinsic::IncludeData(vec![v as u8; 10]))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let block_limit = genesis_header.encoded_size()
|
let block_limit = genesis_header.encoded_size() +
|
||||||
+ extrinsics.iter().take(extrinsics_num - 1).map(Encode::encoded_size).sum::<usize>()
|
extrinsics
|
||||||
+ Vec::<Extrinsic>::new().encoded_size();
|
.iter()
|
||||||
|
.take(extrinsics_num - 1)
|
||||||
|
.map(Encode::encoded_size)
|
||||||
|
.sum::<usize>() +
|
||||||
|
Vec::<Extrinsic>::new().encoded_size();
|
||||||
|
|
||||||
block_on(
|
block_on(txpool.submit_at(&BlockId::number(0), SOURCE, extrinsics)).unwrap();
|
||||||
txpool.submit_at(&BlockId::number(0), SOURCE, extrinsics)
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
block_on(txpool.maintain(chain_event(genesis_header.clone())));
|
block_on(txpool.maintain(chain_event(genesis_header.clone())));
|
||||||
|
|
||||||
let mut proposer_factory = ProposerFactory::new(
|
let mut proposer_factory =
|
||||||
spawner.clone(),
|
ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
|
||||||
client.clone(),
|
|
||||||
txpool.clone(),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
|
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
|
||||||
|
|
||||||
// Give it enough time
|
// Give it enough time
|
||||||
let deadline = time::Duration::from_secs(300);
|
let deadline = time::Duration::from_secs(300);
|
||||||
let block = block_on(
|
let block = block_on(proposer.propose(
|
||||||
proposer.propose(Default::default(), Default::default(), deadline, Some(block_limit))
|
Default::default(),
|
||||||
).map(|r| r.block).unwrap();
|
Default::default(),
|
||||||
|
deadline,
|
||||||
|
Some(block_limit),
|
||||||
|
))
|
||||||
|
.map(|r| r.block)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Based on the block limit, one transaction shouldn't be included.
|
// Based on the block limit, one transaction shouldn't be included.
|
||||||
assert_eq!(block.extrinsics().len(), extrinsics_num - 1);
|
assert_eq!(block.extrinsics().len(), extrinsics_num - 1);
|
||||||
|
|
||||||
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
|
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
|
||||||
|
|
||||||
let block = block_on(
|
let block =
|
||||||
proposer.propose(Default::default(), Default::default(), deadline, None,
|
block_on(proposer.propose(Default::default(), Default::default(), deadline, None))
|
||||||
)).map(|r| r.block).unwrap();
|
.map(|r| r.block)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Without a block limit we should include all of them
|
// Without a block limit we should include all of them
|
||||||
assert_eq!(block.extrinsics().len(), extrinsics_num);
|
assert_eq!(block.extrinsics().len(), extrinsics_num);
|
||||||
@@ -833,9 +829,14 @@ mod tests {
|
|||||||
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
|
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
|
||||||
|
|
||||||
// Give it enough time
|
// Give it enough time
|
||||||
let block = block_on(
|
let block = block_on(proposer.propose(
|
||||||
proposer.propose(Default::default(), Default::default(), deadline, Some(block_limit))
|
Default::default(),
|
||||||
).map(|r| r.block).unwrap();
|
Default::default(),
|
||||||
|
deadline,
|
||||||
|
Some(block_limit),
|
||||||
|
))
|
||||||
|
.map(|r| r.block)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// The block limit didn't changed, but we now include the proof in the estimation of the
|
// The block limit didn't changed, but we now include the proof in the estimation of the
|
||||||
// block size and thus, one less transaction should fit into the limit.
|
// block size and thus, one less transaction should fit into the limit.
|
||||||
|
|||||||
@@ -41,12 +41,12 @@
|
|||||||
//! # );
|
//! # );
|
||||||
//! // The first step is to create a `ProposerFactory`.
|
//! // The first step is to create a `ProposerFactory`.
|
||||||
//! let mut proposer_factory = ProposerFactory::new(
|
//! let mut proposer_factory = ProposerFactory::new(
|
||||||
//! spawner,
|
//! spawner,
|
||||||
//! client.clone(),
|
//! client.clone(),
|
||||||
//! txpool.clone(),
|
//! txpool.clone(),
|
||||||
//! None,
|
//! None,
|
||||||
//! None,
|
//! None,
|
||||||
//! );
|
//! );
|
||||||
//!
|
//!
|
||||||
//! // From this factory, we create a `Proposer`.
|
//! // From this factory, we create a `Proposer`.
|
||||||
//! let proposer = proposer_factory.init(
|
//! let proposer = proposer_factory.init(
|
||||||
@@ -69,8 +69,7 @@
|
|||||||
//! let block = futures::executor::block_on(future).unwrap();
|
//! let block = futures::executor::block_on(future).unwrap();
|
||||||
//! println!("Generated block: {:?}", block.block);
|
//! println!("Generated block: {:?}", block.block);
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
|
||||||
|
|
||||||
mod basic_authorship;
|
mod basic_authorship;
|
||||||
|
|
||||||
pub use crate::basic_authorship::{ProposerFactory, Proposer, DEFAULT_BLOCK_SIZE_LIMIT};
|
pub use crate::basic_authorship::{Proposer, ProposerFactory, DEFAULT_BLOCK_SIZE_LIMIT};
|
||||||
|
|||||||
@@ -28,14 +28,14 @@
|
|||||||
|
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
|
|
||||||
use sp_runtime::{
|
use sp_api::{
|
||||||
generic::BlockId,
|
ApiExt, ApiRef, Core, ProvideRuntimeApi, StorageChanges, StorageProof, TransactionOutcome,
|
||||||
traits::{Header as HeaderT, Hash, Block as BlockT, HashFor, DigestFor, NumberFor, One},
|
|
||||||
};
|
};
|
||||||
use sp_blockchain::{ApplyExtrinsicFailed, Error};
|
use sp_blockchain::{ApplyExtrinsicFailed, Error};
|
||||||
use sp_core::ExecutionContext;
|
use sp_core::ExecutionContext;
|
||||||
use sp_api::{
|
use sp_runtime::{
|
||||||
Core, ApiExt, ApiRef, ProvideRuntimeApi, StorageChanges, StorageProof, TransactionOutcome,
|
generic::BlockId,
|
||||||
|
traits::{Block as BlockT, DigestFor, Hash, HashFor, Header as HeaderT, NumberFor, One},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use sp_block_builder::BlockBuilder as BlockBuilderApi;
|
pub use sp_block_builder::BlockBuilder as BlockBuilderApi;
|
||||||
@@ -94,7 +94,9 @@ pub struct BuiltBlock<Block: BlockT, StateBackend: backend::StateBackend<HashFor
|
|||||||
pub proof: Option<StorageProof>,
|
pub proof: Option<StorageProof>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT, StateBackend: backend::StateBackend<HashFor<Block>>> BuiltBlock<Block, StateBackend> {
|
impl<Block: BlockT, StateBackend: backend::StateBackend<HashFor<Block>>>
|
||||||
|
BuiltBlock<Block, StateBackend>
|
||||||
|
{
|
||||||
/// Convert into the inner values.
|
/// Convert into the inner values.
|
||||||
pub fn into_inner(self) -> (Block, StorageChanges<StateBackend, Block>, Option<StorageProof>) {
|
pub fn into_inner(self) -> (Block, StorageChanges<StateBackend, Block>, Option<StorageProof>) {
|
||||||
(self.block, self.storage_changes, self.proof)
|
(self.block, self.storage_changes, self.proof)
|
||||||
@@ -103,11 +105,11 @@ impl<Block: BlockT, StateBackend: backend::StateBackend<HashFor<Block>>> BuiltBl
|
|||||||
|
|
||||||
/// Block builder provider
|
/// Block builder provider
|
||||||
pub trait BlockBuilderProvider<B, Block, RA>
|
pub trait BlockBuilderProvider<B, Block, RA>
|
||||||
where
|
where
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
B: backend::Backend<Block>,
|
B: backend::Backend<Block>,
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
RA: ProvideRuntimeApi<Block>,
|
RA: ProvideRuntimeApi<Block>,
|
||||||
{
|
{
|
||||||
/// Create a new block, built on top of `parent`.
|
/// Create a new block, built on top of `parent`.
|
||||||
///
|
///
|
||||||
@@ -143,7 +145,8 @@ impl<'a, Block, A, B> BlockBuilder<'a, Block, A, B>
|
|||||||
where
|
where
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
A: ProvideRuntimeApi<Block> + 'a,
|
A: ProvideRuntimeApi<Block> + 'a,
|
||||||
A::Api: BlockBuilderApi<Block> + ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>,
|
A::Api:
|
||||||
|
BlockBuilderApi<Block> + ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>,
|
||||||
B: backend::Backend<Block>,
|
B: backend::Backend<Block>,
|
||||||
{
|
{
|
||||||
/// Create a new instance of builder based on the given `parent_hash` and `parent_number`.
|
/// Create a new instance of builder based on the given `parent_hash` and `parent_number`.
|
||||||
@@ -177,9 +180,7 @@ where
|
|||||||
|
|
||||||
let block_id = BlockId::Hash(parent_hash);
|
let block_id = BlockId::Hash(parent_hash);
|
||||||
|
|
||||||
api.initialize_block_with_context(
|
api.initialize_block_with_context(&block_id, ExecutionContext::BlockConstruction, &header)?;
|
||||||
&block_id, ExecutionContext::BlockConstruction, &header,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
parent_hash,
|
parent_hash,
|
||||||
@@ -207,12 +208,10 @@ where
|
|||||||
Ok(Ok(_)) => {
|
Ok(Ok(_)) => {
|
||||||
extrinsics.push(xt);
|
extrinsics.push(xt);
|
||||||
TransactionOutcome::Commit(Ok(()))
|
TransactionOutcome::Commit(Ok(()))
|
||||||
}
|
|
||||||
Ok(Err(tx_validity)) => {
|
|
||||||
TransactionOutcome::Rollback(
|
|
||||||
Err(ApplyExtrinsicFailed::Validity(tx_validity).into()),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
Ok(Err(tx_validity)) => TransactionOutcome::Rollback(Err(
|
||||||
|
ApplyExtrinsicFailed::Validity(tx_validity).into(),
|
||||||
|
)),
|
||||||
Err(e) => TransactionOutcome::Rollback(Err(Error::from(e))),
|
Err(e) => TransactionOutcome::Rollback(Err(Error::from(e))),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -224,9 +223,9 @@ where
|
|||||||
/// supplied by `self.api`, combined as [`BuiltBlock`].
|
/// supplied by `self.api`, combined as [`BuiltBlock`].
|
||||||
/// The storage proof will be `Some(_)` when proof recording was enabled.
|
/// The storage proof will be `Some(_)` when proof recording was enabled.
|
||||||
pub fn build(mut self) -> Result<BuiltBlock<Block, backend::StateBackendFor<B, Block>>, Error> {
|
pub fn build(mut self) -> Result<BuiltBlock<Block, backend::StateBackendFor<B, Block>>, Error> {
|
||||||
let header = self.api.finalize_block_with_context(
|
let header = self
|
||||||
&self.block_id, ExecutionContext::BlockConstruction
|
.api
|
||||||
)?;
|
.finalize_block_with_context(&self.block_id, ExecutionContext::BlockConstruction)?;
|
||||||
|
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
header.extrinsics_root().clone(),
|
header.extrinsics_root().clone(),
|
||||||
@@ -244,11 +243,10 @@ where
|
|||||||
)?;
|
)?;
|
||||||
let parent_hash = self.parent_hash;
|
let parent_hash = self.parent_hash;
|
||||||
|
|
||||||
let storage_changes = self.api.into_storage_changes(
|
let storage_changes = self
|
||||||
&state,
|
.api
|
||||||
changes_trie_state.as_ref(),
|
.into_storage_changes(&state, changes_trie_state.as_ref(), parent_hash)
|
||||||
parent_hash,
|
.map_err(|e| sp_blockchain::Error::StorageChanges(e))?;
|
||||||
).map_err(|e| sp_blockchain::Error::StorageChanges(e))?;
|
|
||||||
|
|
||||||
Ok(BuiltBlock {
|
Ok(BuiltBlock {
|
||||||
block: <Block as BlockT>::new(header, self.extrinsics),
|
block: <Block as BlockT>::new(header, self.extrinsics),
|
||||||
@@ -265,15 +263,17 @@ where
|
|||||||
inherent_data: sp_inherents::InherentData,
|
inherent_data: sp_inherents::InherentData,
|
||||||
) -> Result<Vec<Block::Extrinsic>, Error> {
|
) -> Result<Vec<Block::Extrinsic>, Error> {
|
||||||
let block_id = self.block_id;
|
let block_id = self.block_id;
|
||||||
self.api.execute_in_transaction(move |api| {
|
self.api
|
||||||
// `create_inherents` should not change any state, to ensure this we always rollback
|
.execute_in_transaction(move |api| {
|
||||||
// the transaction.
|
// `create_inherents` should not change any state, to ensure this we always rollback
|
||||||
TransactionOutcome::Rollback(api.inherent_extrinsics_with_context(
|
// the transaction.
|
||||||
&block_id,
|
TransactionOutcome::Rollback(api.inherent_extrinsics_with_context(
|
||||||
ExecutionContext::BlockConstruction,
|
&block_id,
|
||||||
inherent_data
|
ExecutionContext::BlockConstruction,
|
||||||
))
|
inherent_data,
|
||||||
}).map_err(|e| Error::Application(Box::new(e)))
|
))
|
||||||
|
})
|
||||||
|
.map_err(|e| Error::Application(Box::new(e)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Estimate the size of the block in the current state.
|
/// Estimate the size of the block in the current state.
|
||||||
@@ -312,19 +312,22 @@ mod tests {
|
|||||||
RecordProof::Yes,
|
RecordProof::Yes,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
&*backend,
|
&*backend,
|
||||||
).unwrap().build().unwrap();
|
)
|
||||||
|
.unwrap()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let proof = block.proof.expect("Proof is build on request");
|
let proof = block.proof.expect("Proof is build on request");
|
||||||
|
|
||||||
let backend = sp_state_machine::create_proof_check_backend::<Blake2Hasher>(
|
let backend = sp_state_machine::create_proof_check_backend::<Blake2Hasher>(
|
||||||
block.storage_changes.transaction_storage_root,
|
block.storage_changes.transaction_storage_root,
|
||||||
proof,
|
proof,
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(backend
|
||||||
backend.storage(&sp_core::storage::well_known_keys::CODE)
|
.storage(&sp_core::storage::well_known_keys::CODE)
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
.contains("Database missing expected key"),
|
.contains("Database missing expected key"),);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::quote;
|
|
||||||
use syn::{DeriveInput, Ident, Error};
|
|
||||||
use proc_macro_crate::{crate_name, FoundCrate};
|
use proc_macro_crate::{crate_name, FoundCrate};
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{DeriveInput, Error, Ident};
|
||||||
|
|
||||||
const CRATE_NAME: &str = "sc-chain-spec";
|
const CRATE_NAME: &str = "sc-chain-spec";
|
||||||
const ATTRIBUTE_NAME: &str = "forks";
|
const ATTRIBUTE_NAME: &str = "forks";
|
||||||
@@ -31,14 +31,18 @@ const ATTRIBUTE_NAME: &str = "forks";
|
|||||||
pub fn extension_derive(ast: &DeriveInput) -> proc_macro::TokenStream {
|
pub fn extension_derive(ast: &DeriveInput) -> proc_macro::TokenStream {
|
||||||
derive(ast, |crate_name, name, generics: &syn::Generics, field_names, field_types, fields| {
|
derive(ast, |crate_name, name, generics: &syn::Generics, field_names, field_types, fields| {
|
||||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||||
let forks = fields.named.iter().find_map(|f| {
|
let forks = fields
|
||||||
if f.attrs.iter().any(|attr| attr.path.is_ident(ATTRIBUTE_NAME)) {
|
.named
|
||||||
let typ = &f.ty;
|
.iter()
|
||||||
Some(quote! { #typ })
|
.find_map(|f| {
|
||||||
} else {
|
if f.attrs.iter().any(|attr| attr.path.is_ident(ATTRIBUTE_NAME)) {
|
||||||
None
|
let typ = &f.ty;
|
||||||
}
|
Some(quote! { #typ })
|
||||||
}).unwrap_or_else(|| quote! { #crate_name::NoExtension });
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| quote! { #crate_name::NoExtension });
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl #impl_generics #crate_name::Extension for #name #ty_generics #where_clause {
|
impl #impl_generics #crate_name::Extension for #name #ty_generics #where_clause {
|
||||||
@@ -80,13 +84,12 @@ pub fn group_derive(ast: &DeriveInput) -> proc_macro::TokenStream {
|
|||||||
Ok(FoundCrate::Itself) => Ident::new("serde", Span::call_site()),
|
Ok(FoundCrate::Itself) => Ident::new("serde", Span::call_site()),
|
||||||
Ok(FoundCrate::Name(name)) => Ident::new(&name, Span::call_site()),
|
Ok(FoundCrate::Name(name)) => Ident::new(&name, Span::call_site()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let err = Error::new(
|
let err =
|
||||||
Span::call_site(),
|
Error::new(Span::call_site(), &format!("Could not find `serde` crate: {}", e))
|
||||||
&format!("Could not find `serde` crate: {}", e),
|
.to_compile_error();
|
||||||
).to_compile_error();
|
|
||||||
|
|
||||||
return quote!( #err ).into();
|
return quote!( #err ).into()
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
@@ -131,14 +134,20 @@ pub fn group_derive(ast: &DeriveInput) -> proc_macro::TokenStream {
|
|||||||
pub fn derive(
|
pub fn derive(
|
||||||
ast: &DeriveInput,
|
ast: &DeriveInput,
|
||||||
derive: impl Fn(
|
derive: impl Fn(
|
||||||
&Ident, &Ident, &syn::Generics, Vec<&Ident>, Vec<&syn::Type>, &syn::FieldsNamed,
|
&Ident,
|
||||||
|
&Ident,
|
||||||
|
&syn::Generics,
|
||||||
|
Vec<&Ident>,
|
||||||
|
Vec<&syn::Type>,
|
||||||
|
&syn::FieldsNamed,
|
||||||
) -> TokenStream,
|
) -> TokenStream,
|
||||||
) -> proc_macro::TokenStream {
|
) -> proc_macro::TokenStream {
|
||||||
let err = || {
|
let err = || {
|
||||||
let err = Error::new(
|
let err = Error::new(
|
||||||
Span::call_site(),
|
Span::call_site(),
|
||||||
"ChainSpecGroup is only available for structs with named fields."
|
"ChainSpecGroup is only available for structs with named fields.",
|
||||||
).to_compile_error();
|
)
|
||||||
|
.to_compile_error();
|
||||||
quote!( #err ).into()
|
quote!( #err ).into()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -168,47 +177,35 @@ pub fn derive(
|
|||||||
derive(&crate_name, name, &ast.generics, field_names, field_types, fields).into()
|
derive(&crate_name, name, &ast.generics, field_names, field_types, fields).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_fork_fields(
|
fn generate_fork_fields(crate_name: &Ident, names: &[&Ident], types: &[&syn::Type]) -> TokenStream {
|
||||||
crate_name: &Ident,
|
|
||||||
names: &[&Ident],
|
|
||||||
types: &[&syn::Type],
|
|
||||||
) -> TokenStream {
|
|
||||||
let crate_name = std::iter::repeat(crate_name);
|
let crate_name = std::iter::repeat(crate_name);
|
||||||
quote! {
|
quote! {
|
||||||
#( pub #names: Option<<#types as #crate_name::Group>::Fork>, )*
|
#( pub #names: Option<<#types as #crate_name::Group>::Fork>, )*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_base_to_fork(
|
fn generate_base_to_fork(fork_name: &Ident, names: &[&Ident]) -> TokenStream {
|
||||||
fork_name: &Ident,
|
|
||||||
names: &[&Ident],
|
|
||||||
) -> TokenStream {
|
|
||||||
let names2 = names.to_vec();
|
let names2 = names.to_vec();
|
||||||
|
|
||||||
quote!{
|
quote! {
|
||||||
#fork_name {
|
#fork_name {
|
||||||
#( #names: Some(self.#names2.to_fork()), )*
|
#( #names: Some(self.#names2.to_fork()), )*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_combine_with(
|
fn generate_combine_with(names: &[&Ident]) -> TokenStream {
|
||||||
names: &[&Ident],
|
|
||||||
) -> TokenStream {
|
|
||||||
let names2 = names.to_vec();
|
let names2 = names.to_vec();
|
||||||
|
|
||||||
quote!{
|
quote! {
|
||||||
#( self.#names.combine_with(other.#names2); )*
|
#( self.#names.combine_with(other.#names2); )*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_fork_to_base(
|
fn generate_fork_to_base(fork: &Ident, names: &[&Ident]) -> TokenStream {
|
||||||
fork: &Ident,
|
|
||||||
names: &[&Ident],
|
|
||||||
) -> TokenStream {
|
|
||||||
let names2 = names.to_vec();
|
let names2 = names.to_vec();
|
||||||
|
|
||||||
quote!{
|
quote! {
|
||||||
Some(#fork {
|
Some(#fork {
|
||||||
#( #names: self.#names2?.to_base()?, )*
|
#( #names: self.#names2?.to_base()?, )*
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -19,15 +19,20 @@
|
|||||||
//! Substrate chain configurations.
|
//! Substrate chain configurations.
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use std::{borrow::Cow, fs::File, path::PathBuf, sync::Arc, collections::HashMap};
|
use crate::{extension::GetExtension, ChainType, Properties, RuntimeGenesis};
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use sp_core::{storage::{StorageKey, StorageData, ChildInfo, Storage, StorageChild}, Bytes};
|
|
||||||
use sp_runtime::BuildStorage;
|
|
||||||
use serde_json as json;
|
|
||||||
use crate::{RuntimeGenesis, ChainType, extension::GetExtension, Properties};
|
|
||||||
use sc_network::config::MultiaddrWithPeerId;
|
use sc_network::config::MultiaddrWithPeerId;
|
||||||
use sc_telemetry::TelemetryEndpoints;
|
use sc_telemetry::TelemetryEndpoints;
|
||||||
use sp_runtime::traits::{Block as BlockT, NumberFor};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json as json;
|
||||||
|
use sp_core::{
|
||||||
|
storage::{ChildInfo, Storage, StorageChild, StorageData, StorageKey},
|
||||||
|
Bytes,
|
||||||
|
};
|
||||||
|
use sp_runtime::{
|
||||||
|
traits::{Block as BlockT, NumberFor},
|
||||||
|
BuildStorage,
|
||||||
|
};
|
||||||
|
use std::{borrow::Cow, collections::HashMap, fs::File, path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
enum GenesisSource<G> {
|
enum GenesisSource<G> {
|
||||||
File(PathBuf),
|
File(PathBuf),
|
||||||
@@ -56,8 +61,8 @@ impl<G: RuntimeGenesis> GenesisSource<G> {
|
|||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::File(path) => {
|
Self::File(path) => {
|
||||||
let file = File::open(path)
|
let file =
|
||||||
.map_err(|e| format!("Error opening spec file: {}", e))?;
|
File::open(path).map_err(|e| format!("Error opening spec file: {}", e))?;
|
||||||
let genesis: GenesisContainer<G> = json::from_reader(file)
|
let genesis: GenesisContainer<G> = json::from_reader(file)
|
||||||
.map_err(|e| format!("Error parsing spec file: {}", e))?;
|
.map_err(|e| format!("Error parsing spec file: {}", e))?;
|
||||||
Ok(genesis.genesis)
|
Ok(genesis.genesis)
|
||||||
@@ -69,22 +74,25 @@ impl<G: RuntimeGenesis> GenesisSource<G> {
|
|||||||
},
|
},
|
||||||
Self::Factory(f) => Ok(Genesis::Runtime(f())),
|
Self::Factory(f) => Ok(Genesis::Runtime(f())),
|
||||||
Self::Storage(storage) => {
|
Self::Storage(storage) => {
|
||||||
let top = storage.top
|
let top = storage
|
||||||
|
.top
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone())))
|
.map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone())))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let children_default = storage.children_default
|
let children_default = storage
|
||||||
|
.children_default
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, child)|
|
.map(|(k, child)| {
|
||||||
(
|
(
|
||||||
StorageKey(k.clone()),
|
StorageKey(k.clone()),
|
||||||
child.data
|
child
|
||||||
|
.data
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone())))
|
.map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone())))
|
||||||
.collect()
|
.collect(),
|
||||||
)
|
)
|
||||||
)
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(Genesis::Raw(RawGenesis { top, children_default }))
|
Ok(Genesis::Raw(RawGenesis { top, children_default }))
|
||||||
@@ -99,24 +107,24 @@ impl<G: RuntimeGenesis, E> BuildStorage for ChainSpec<G, E> {
|
|||||||
Genesis::Runtime(gc) => gc.build_storage(),
|
Genesis::Runtime(gc) => gc.build_storage(),
|
||||||
Genesis::Raw(RawGenesis { top: map, children_default: children_map }) => Ok(Storage {
|
Genesis::Raw(RawGenesis { top: map, children_default: children_map }) => Ok(Storage {
|
||||||
top: map.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
|
top: map.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
|
||||||
children_default: children_map.into_iter().map(|(storage_key, child_content)| {
|
children_default: children_map
|
||||||
let child_info = ChildInfo::new_default(storage_key.0.as_slice());
|
.into_iter()
|
||||||
(
|
.map(|(storage_key, child_content)| {
|
||||||
storage_key.0,
|
let child_info = ChildInfo::new_default(storage_key.0.as_slice());
|
||||||
StorageChild {
|
(
|
||||||
data: child_content.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
|
storage_key.0,
|
||||||
child_info,
|
StorageChild {
|
||||||
},
|
data: child_content.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
|
||||||
)
|
child_info,
|
||||||
}).collect(),
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assimilate_storage(
|
fn assimilate_storage(&self, _: &mut Storage) -> Result<(), String> {
|
||||||
&self,
|
|
||||||
_: &mut Storage,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
Err("`assimilate_storage` not implemented for `ChainSpec`.".into())
|
Err("`assimilate_storage` not implemented for `ChainSpec`.".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,10 +189,7 @@ pub struct ChainSpec<G, E = NoExtension> {
|
|||||||
|
|
||||||
impl<G, E: Clone> Clone for ChainSpec<G, E> {
|
impl<G, E: Clone> Clone for ChainSpec<G, E> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
ChainSpec {
|
ChainSpec { client_spec: self.client_spec.clone(), genesis: self.genesis.clone() }
|
||||||
client_spec: self.client_spec.clone(),
|
|
||||||
genesis: self.genesis.clone(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,10 +263,7 @@ impl<G, E> ChainSpec<G, E> {
|
|||||||
code_substitutes: HashMap::new(),
|
code_substitutes: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
ChainSpec {
|
ChainSpec { client_spec, genesis: GenesisSource::Factory(Arc::new(constructor)) }
|
||||||
client_spec,
|
|
||||||
genesis: GenesisSource::Factory(Arc::new(constructor)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type of the chain.
|
/// Type of the chain.
|
||||||
@@ -281,22 +283,15 @@ impl<G, E: serde::de::DeserializeOwned> ChainSpec<G, E> {
|
|||||||
let json = json.into();
|
let json = json.into();
|
||||||
let client_spec = json::from_slice(json.as_ref())
|
let client_spec = json::from_slice(json.as_ref())
|
||||||
.map_err(|e| format!("Error parsing spec file: {}", e))?;
|
.map_err(|e| format!("Error parsing spec file: {}", e))?;
|
||||||
Ok(ChainSpec {
|
Ok(ChainSpec { client_spec, genesis: GenesisSource::Binary(json) })
|
||||||
client_spec,
|
|
||||||
genesis: GenesisSource::Binary(json),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse json file into a `ChainSpec`
|
/// Parse json file into a `ChainSpec`
|
||||||
pub fn from_json_file(path: PathBuf) -> Result<Self, String> {
|
pub fn from_json_file(path: PathBuf) -> Result<Self, String> {
|
||||||
let file = File::open(&path)
|
let file = File::open(&path).map_err(|e| format!("Error opening spec file: {}", e))?;
|
||||||
.map_err(|e| format!("Error opening spec file: {}", e))?;
|
let client_spec =
|
||||||
let client_spec = json::from_reader(file)
|
json::from_reader(file).map_err(|e| format!("Error parsing spec file: {}", e))?;
|
||||||
.map_err(|e| format!("Error parsing spec file: {}", e))?;
|
Ok(ChainSpec { client_spec, genesis: GenesisSource::File(path) })
|
||||||
Ok(ChainSpec {
|
|
||||||
client_spec,
|
|
||||||
genesis: GenesisSource::File(path),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,33 +307,34 @@ impl<G: RuntimeGenesis, E: serde::Serialize + Clone + 'static> ChainSpec<G, E> {
|
|||||||
let genesis = match (raw, self.genesis.resolve()?) {
|
let genesis = match (raw, self.genesis.resolve()?) {
|
||||||
(true, Genesis::Runtime(g)) => {
|
(true, Genesis::Runtime(g)) => {
|
||||||
let storage = g.build_storage()?;
|
let storage = g.build_storage()?;
|
||||||
let top = storage.top.into_iter()
|
let top =
|
||||||
.map(|(k, v)| (StorageKey(k), StorageData(v)))
|
storage.top.into_iter().map(|(k, v)| (StorageKey(k), StorageData(v))).collect();
|
||||||
.collect();
|
let children_default = storage
|
||||||
let children_default = storage.children_default.into_iter()
|
.children_default
|
||||||
.map(|(sk, child)| (
|
.into_iter()
|
||||||
StorageKey(sk),
|
.map(|(sk, child)| {
|
||||||
child.data.into_iter()
|
(
|
||||||
.map(|(k, v)| (StorageKey(k), StorageData(v)))
|
StorageKey(sk),
|
||||||
.collect(),
|
child
|
||||||
))
|
.data
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (StorageKey(k), StorageData(v)))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Genesis::Raw(RawGenesis { top, children_default })
|
Genesis::Raw(RawGenesis { top, children_default })
|
||||||
},
|
},
|
||||||
(_, genesis) => genesis,
|
(_, genesis) => genesis,
|
||||||
};
|
};
|
||||||
Ok(JsonContainer {
|
Ok(JsonContainer { client_spec: self.client_spec.clone(), genesis })
|
||||||
client_spec: self.client_spec.clone(),
|
|
||||||
genesis,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dump to json string.
|
/// Dump to json string.
|
||||||
pub fn as_json(&self, raw: bool) -> Result<String, String> {
|
pub fn as_json(&self, raw: bool) -> Result<String, String> {
|
||||||
let container = self.json_container(raw)?;
|
let container = self.json_container(raw)?;
|
||||||
json::to_string_pretty(&container)
|
json::to_string_pretty(&container).map_err(|e| format!("Error generating spec json: {}", e))
|
||||||
.map_err(|e| format!("Error generating spec json: {}", e))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,7 +400,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn code_substitutes(&self) -> std::collections::HashMap<String, Vec<u8>> {
|
fn code_substitutes(&self) -> std::collections::HashMap<String, Vec<u8>> {
|
||||||
self.client_spec.code_substitutes.iter().map(|(h, c)| (h.clone(), c.0.clone())).collect()
|
self.client_spec
|
||||||
|
.code_substitutes
|
||||||
|
.iter()
|
||||||
|
.map(|(h, c)| (h.clone(), c.0.clone()))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,7 +417,8 @@ pub struct LightSyncState<Block: BlockT> {
|
|||||||
/// The babe weight of the finalized block.
|
/// The babe weight of the finalized block.
|
||||||
pub babe_finalized_block_weight: sp_consensus_babe::BabeBlockWeight,
|
pub babe_finalized_block_weight: sp_consensus_babe::BabeBlockWeight,
|
||||||
/// The authority set for grandpa.
|
/// The authority set for grandpa.
|
||||||
pub grandpa_authority_set: sc_finality_grandpa::AuthoritySet<<Block as BlockT>::Hash, NumberFor<Block>>,
|
pub grandpa_authority_set:
|
||||||
|
sc_finality_grandpa::AuthoritySet<<Block as BlockT>::Hash, NumberFor<Block>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT> LightSyncState<Block> {
|
impl<Block: BlockT> LightSyncState<Block> {
|
||||||
@@ -427,25 +428,25 @@ impl<Block: BlockT> LightSyncState<Block> {
|
|||||||
|
|
||||||
SerializableLightSyncState {
|
SerializableLightSyncState {
|
||||||
finalized_block_header: StorageData(self.finalized_block_header.encode()),
|
finalized_block_header: StorageData(self.finalized_block_header.encode()),
|
||||||
babe_epoch_changes:
|
babe_epoch_changes: StorageData(self.babe_epoch_changes.encode()),
|
||||||
StorageData(self.babe_epoch_changes.encode()),
|
babe_finalized_block_weight: self.babe_finalized_block_weight,
|
||||||
babe_finalized_block_weight:
|
grandpa_authority_set: StorageData(self.grandpa_authority_set.encode()),
|
||||||
self.babe_finalized_block_weight,
|
|
||||||
grandpa_authority_set:
|
|
||||||
StorageData(self.grandpa_authority_set.encode()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert from a `SerializableLightSyncState`.
|
/// Convert from a `SerializableLightSyncState`.
|
||||||
pub fn from_serializable(serialized: &SerializableLightSyncState) -> Result<Self, codec::Error> {
|
pub fn from_serializable(
|
||||||
|
serialized: &SerializableLightSyncState,
|
||||||
|
) -> Result<Self, codec::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
finalized_block_header: codec::Decode::decode(&mut &serialized.finalized_block_header.0[..])?,
|
finalized_block_header: codec::Decode::decode(
|
||||||
babe_epoch_changes:
|
&mut &serialized.finalized_block_header.0[..],
|
||||||
codec::Decode::decode(&mut &serialized.babe_epoch_changes.0[..])?,
|
)?,
|
||||||
babe_finalized_block_weight:
|
babe_epoch_changes: codec::Decode::decode(&mut &serialized.babe_epoch_changes.0[..])?,
|
||||||
serialized.babe_finalized_block_weight,
|
babe_finalized_block_weight: serialized.babe_finalized_block_weight,
|
||||||
grandpa_authority_set:
|
grandpa_authority_set: codec::Decode::decode(
|
||||||
codec::Decode::decode(&mut &serialized.grandpa_authority_set.0[..])?,
|
&mut &serialized.grandpa_authority_set.0[..],
|
||||||
|
)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -469,12 +470,9 @@ mod tests {
|
|||||||
struct Genesis(HashMap<String, String>);
|
struct Genesis(HashMap<String, String>);
|
||||||
|
|
||||||
impl BuildStorage for Genesis {
|
impl BuildStorage for Genesis {
|
||||||
fn assimilate_storage(
|
fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> {
|
||||||
&self,
|
|
||||||
storage: &mut Storage,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
storage.top.extend(
|
storage.top.extend(
|
||||||
self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes()))
|
self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes())),
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -485,11 +483,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_deserialize_example_chain_spec() {
|
fn should_deserialize_example_chain_spec() {
|
||||||
let spec1 = TestSpec::from_json_bytes(Cow::Owned(
|
let spec1 = TestSpec::from_json_bytes(Cow::Owned(
|
||||||
include_bytes!("../res/chain_spec.json").to_vec()
|
include_bytes!("../res/chain_spec.json").to_vec(),
|
||||||
)).unwrap();
|
))
|
||||||
let spec2 = TestSpec::from_json_file(
|
.unwrap();
|
||||||
PathBuf::from("./res/chain_spec.json")
|
let spec2 = TestSpec::from_json_file(PathBuf::from("./res/chain_spec.json")).unwrap();
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(spec1.as_json(false), spec2.as_json(false));
|
assert_eq!(spec1.as_json(false), spec2.as_json(false));
|
||||||
assert_eq!(spec2.chain_type(), ChainType::Live)
|
assert_eq!(spec2.chain_type(), ChainType::Live)
|
||||||
@@ -506,8 +503,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_deserialize_chain_spec_with_extensions() {
|
fn should_deserialize_chain_spec_with_extensions() {
|
||||||
let spec = TestSpec2::from_json_bytes(Cow::Owned(
|
let spec = TestSpec2::from_json_bytes(Cow::Owned(
|
||||||
include_bytes!("../res/chain_spec2.json").to_vec()
|
include_bytes!("../res/chain_spec2.json").to_vec(),
|
||||||
)).unwrap();
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(spec.extensions().my_property, "Test Extension");
|
assert_eq!(spec.extensions().my_property, "Test Extension");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,19 +18,21 @@
|
|||||||
|
|
||||||
//! Chain Spec extensions helpers.
|
//! Chain Spec extensions helpers.
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::{
|
||||||
use std::any::{TypeId, Any};
|
any::{Any, TypeId},
|
||||||
|
fmt::Debug,
|
||||||
|
};
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
|
|
||||||
/// A `ChainSpec` extension.
|
/// A `ChainSpec` extension.
|
||||||
///
|
///
|
||||||
/// This trait is implemented automatically by `ChainSpecGroup` macro.
|
/// This trait is implemented automatically by `ChainSpecGroup` macro.
|
||||||
pub trait Group: Clone + Sized {
|
pub trait Group: Clone + Sized {
|
||||||
/// An associated type containing fork definition.
|
/// An associated type containing fork definition.
|
||||||
type Fork: Fork<Base=Self>;
|
type Fork: Fork<Base = Self>;
|
||||||
|
|
||||||
/// Convert to fork type.
|
/// Convert to fork type.
|
||||||
fn to_fork(self) -> Self::Fork;
|
fn to_fork(self) -> Self::Fork;
|
||||||
@@ -45,7 +47,7 @@ pub trait Group: Clone + Sized {
|
|||||||
/// a complete set of parameters
|
/// a complete set of parameters
|
||||||
pub trait Fork: Serialize + DeserializeOwned + Clone + Sized {
|
pub trait Fork: Serialize + DeserializeOwned + Clone + Sized {
|
||||||
/// A base `Group` type.
|
/// A base `Group` type.
|
||||||
type Base: Group<Fork=Self>;
|
type Base: Group<Fork = Self>;
|
||||||
|
|
||||||
/// Combine with another struct.
|
/// Combine with another struct.
|
||||||
///
|
///
|
||||||
@@ -128,7 +130,8 @@ pub trait Extension: Serialize + DeserializeOwned + Clone {
|
|||||||
fn get_any(&self, t: TypeId) -> &dyn Any;
|
fn get_any(&self, t: TypeId) -> &dyn Any;
|
||||||
|
|
||||||
/// Get forkable extensions of specific type.
|
/// Get forkable extensions of specific type.
|
||||||
fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>> where
|
fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>>
|
||||||
|
where
|
||||||
BlockNumber: Ord + Clone + 'static,
|
BlockNumber: Ord + Clone + 'static,
|
||||||
T: Group + 'static,
|
T: Group + 'static,
|
||||||
<Self::Forks as IsForks>::Extension: Extension,
|
<Self::Forks as IsForks>::Extension: Extension,
|
||||||
@@ -142,8 +145,12 @@ pub trait Extension: Serialize + DeserializeOwned + Clone {
|
|||||||
impl Extension for crate::NoExtension {
|
impl Extension for crate::NoExtension {
|
||||||
type Forks = Self;
|
type Forks = Self;
|
||||||
|
|
||||||
fn get<T: 'static>(&self) -> Option<&T> { None }
|
fn get<T: 'static>(&self) -> Option<&T> {
|
||||||
fn get_any(&self, _t: TypeId) -> &dyn Any { self }
|
None
|
||||||
|
}
|
||||||
|
fn get_any(&self, _t: TypeId) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IsForks {
|
pub trait IsForks {
|
||||||
@@ -166,14 +173,12 @@ pub struct Forks<BlockNumber: Ord, T: Group> {
|
|||||||
|
|
||||||
impl<B: Ord, T: Group + Default> Default for Forks<B, T> {
|
impl<B: Ord, T: Group + Default> Default for Forks<B, T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self { base: Default::default(), forks: Default::default() }
|
||||||
base: Default::default(),
|
|
||||||
forks: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Ord, T: Group> Forks<B, T> where
|
impl<B: Ord, T: Group> Forks<B, T>
|
||||||
|
where
|
||||||
T::Fork: Debug,
|
T::Fork: Debug,
|
||||||
{
|
{
|
||||||
/// Create new fork definition given the base and the forks.
|
/// Create new fork definition given the base and the forks.
|
||||||
@@ -195,7 +200,8 @@ impl<B: Ord, T: Group> Forks<B, T> where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, T> IsForks for Forks<B, T> where
|
impl<B, T> IsForks for Forks<B, T>
|
||||||
|
where
|
||||||
B: Ord + 'static,
|
B: Ord + 'static,
|
||||||
T: Group + 'static,
|
T: Group + 'static,
|
||||||
{
|
{
|
||||||
@@ -203,29 +209,31 @@ impl<B, T> IsForks for Forks<B, T> where
|
|||||||
type Extension = T;
|
type Extension = T;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Ord + Clone, T: Group + Extension> Forks<B, T> where
|
impl<B: Ord + Clone, T: Group + Extension> Forks<B, T>
|
||||||
|
where
|
||||||
T::Fork: Extension,
|
T::Fork: Extension,
|
||||||
{
|
{
|
||||||
/// Get forks definition for a subset of this extension.
|
/// Get forks definition for a subset of this extension.
|
||||||
///
|
///
|
||||||
/// Returns the `Forks` struct, but limited to a particular type
|
/// Returns the `Forks` struct, but limited to a particular type
|
||||||
/// within the extension.
|
/// within the extension.
|
||||||
pub fn for_type<X>(&self) -> Option<Forks<B, X>> where
|
pub fn for_type<X>(&self) -> Option<Forks<B, X>>
|
||||||
|
where
|
||||||
X: Group + 'static,
|
X: Group + 'static,
|
||||||
{
|
{
|
||||||
let base = self.base.get::<X>()?.clone();
|
let base = self.base.get::<X>()?.clone();
|
||||||
let forks = self.forks.iter().filter_map(|(k, v)| {
|
let forks = self
|
||||||
Some((k.clone(), v.get::<Option<X::Fork>>()?.clone()?))
|
.forks
|
||||||
}).collect();
|
.iter()
|
||||||
|
.filter_map(|(k, v)| Some((k.clone(), v.get::<Option<X::Fork>>()?.clone()?)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
Some(Forks {
|
Some(Forks { base, forks })
|
||||||
base,
|
|
||||||
forks,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, E> Extension for Forks<B, E> where
|
impl<B, E> Extension for Forks<B, E>
|
||||||
|
where
|
||||||
B: Serialize + DeserializeOwned + Ord + Clone + 'static,
|
B: Serialize + DeserializeOwned + Ord + Clone + 'static,
|
||||||
E: Extension + Group + 'static,
|
E: Extension + Group + 'static,
|
||||||
{
|
{
|
||||||
@@ -245,7 +253,8 @@ impl<B, E> Extension for Forks<B, E> where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>> where
|
fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>>
|
||||||
|
where
|
||||||
BlockNumber: Ord + Clone + 'static,
|
BlockNumber: Ord + Clone + 'static,
|
||||||
T: Group + 'static,
|
T: Group + 'static,
|
||||||
<Self::Forks as IsForks>::Extension: Extension,
|
<Self::Forks as IsForks>::Extension: Extension,
|
||||||
@@ -266,7 +275,7 @@ pub trait GetExtension {
|
|||||||
fn get_any(&self, t: TypeId) -> &dyn Any;
|
fn get_any(&self, t: TypeId) -> &dyn Any;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <E: Extension> GetExtension for E {
|
impl<E: Extension> GetExtension for E {
|
||||||
fn get_any(&self, t: TypeId) -> &dyn Any {
|
fn get_any(&self, t: TypeId) -> &dyn Any {
|
||||||
Extension::get_any(self, t)
|
Extension::get_any(self, t)
|
||||||
}
|
}
|
||||||
@@ -281,7 +290,7 @@ pub fn get_extension<T: 'static>(e: &dyn GetExtension) -> Option<&T> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use sc_chain_spec_derive::{ChainSpecGroup, ChainSpecExtension};
|
use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
|
||||||
// Make the proc macro work for tests and doc tests.
|
// Make the proc macro work for tests and doc tests.
|
||||||
use crate as sc_chain_spec;
|
use crate as sc_chain_spec;
|
||||||
|
|
||||||
@@ -297,7 +306,9 @@ mod tests {
|
|||||||
pub test: u8,
|
pub test: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]
|
#[derive(
|
||||||
|
Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension,
|
||||||
|
)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Extensions {
|
pub struct Extensions {
|
||||||
pub ext1: Extension1,
|
pub ext1: Extension1,
|
||||||
@@ -315,11 +326,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn forks_should_work_correctly() {
|
fn forks_should_work_correctly() {
|
||||||
use super::Extension as _ ;
|
use super::Extension as _;
|
||||||
|
|
||||||
// We first need to deserialize into a `Value` because of the following bug:
|
// We first need to deserialize into a `Value` because of the following bug:
|
||||||
// https://github.com/serde-rs/json/issues/505
|
// https://github.com/serde-rs/json/issues/505
|
||||||
let ext_val: serde_json::Value = serde_json::from_str(r#"
|
let ext_val: serde_json::Value = serde_json::from_str(
|
||||||
|
r#"
|
||||||
{
|
{
|
||||||
"test": 11,
|
"test": 11,
|
||||||
"forkable": {
|
"forkable": {
|
||||||
@@ -342,40 +354,40 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#).unwrap();
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let ext: Ext2 = serde_json::from_value(ext_val).unwrap();
|
let ext: Ext2 = serde_json::from_value(ext_val).unwrap();
|
||||||
|
|
||||||
assert_eq!(ext.get::<Extension1>(), Some(&Extension1 {
|
assert_eq!(ext.get::<Extension1>(), Some(&Extension1 { test: 11 }));
|
||||||
test: 11
|
|
||||||
}));
|
|
||||||
|
|
||||||
// get forks definition
|
// get forks definition
|
||||||
let forks = ext.get::<Forks<u64, Extensions>>().unwrap();
|
let forks = ext.get::<Forks<u64, Extensions>>().unwrap();
|
||||||
assert_eq!(forks.at_block(0), Extensions {
|
assert_eq!(
|
||||||
ext1: Extension1 { test: 15 },
|
forks.at_block(0),
|
||||||
ext2: Extension2 { test: 123 },
|
Extensions { ext1: Extension1 { test: 15 }, ext2: Extension2 { test: 123 } }
|
||||||
});
|
);
|
||||||
assert_eq!(forks.at_block(1), Extensions {
|
assert_eq!(
|
||||||
ext1: Extension1 { test: 5 },
|
forks.at_block(1),
|
||||||
ext2: Extension2 { test: 123 },
|
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 123 } }
|
||||||
});
|
);
|
||||||
assert_eq!(forks.at_block(2), Extensions {
|
assert_eq!(
|
||||||
ext1: Extension1 { test: 5 },
|
forks.at_block(2),
|
||||||
ext2: Extension2 { test: 5 },
|
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 5 } }
|
||||||
});
|
);
|
||||||
assert_eq!(forks.at_block(4), Extensions {
|
assert_eq!(
|
||||||
ext1: Extension1 { test: 5 },
|
forks.at_block(4),
|
||||||
ext2: Extension2 { test: 5 },
|
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 5 } }
|
||||||
});
|
);
|
||||||
assert_eq!(forks.at_block(5), Extensions {
|
assert_eq!(
|
||||||
ext1: Extension1 { test: 5 },
|
forks.at_block(5),
|
||||||
ext2: Extension2 { test: 1 },
|
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 1 } }
|
||||||
});
|
);
|
||||||
assert_eq!(forks.at_block(10), Extensions {
|
assert_eq!(
|
||||||
ext1: Extension1 { test: 5 },
|
forks.at_block(10),
|
||||||
ext2: Extension2 { test: 1 },
|
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 1 } }
|
||||||
});
|
);
|
||||||
assert!(forks.at_block(10).get::<Extension2>().is_some());
|
assert!(forks.at_block(10).get::<Extension2>().is_some());
|
||||||
|
|
||||||
// filter forks for `Extension2`
|
// filter forks for `Extension2`
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
//!
|
//!
|
||||||
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecExtension)]
|
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecExtension)]
|
||||||
//! pub struct MyExtension {
|
//! pub struct MyExtension {
|
||||||
//! pub known_blocks: HashMap<u64, String>,
|
//! pub known_blocks: HashMap<u64, String>,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! pub type MyChainSpec<G> = GenericChainSpec<G, MyExtension>;
|
//! pub type MyChainSpec<G> = GenericChainSpec<G, MyExtension>;
|
||||||
@@ -53,19 +53,19 @@
|
|||||||
//!
|
//!
|
||||||
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)]
|
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)]
|
||||||
//! pub struct ClientParams {
|
//! pub struct ClientParams {
|
||||||
//! max_block_size: usize,
|
//! max_block_size: usize,
|
||||||
//! max_extrinsic_size: usize,
|
//! max_extrinsic_size: usize,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)]
|
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)]
|
||||||
//! pub struct PoolParams {
|
//! pub struct PoolParams {
|
||||||
//! max_transaction_size: usize,
|
//! max_transaction_size: usize,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup, ChainSpecExtension)]
|
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup, ChainSpecExtension)]
|
||||||
//! pub struct Extension {
|
//! pub struct Extension {
|
||||||
//! pub client: ClientParams,
|
//! pub client: ClientParams,
|
||||||
//! pub pool: PoolParams,
|
//! pub pool: PoolParams,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! pub type BlockNumber = u64;
|
//! pub type BlockNumber = u64;
|
||||||
@@ -88,20 +88,20 @@
|
|||||||
//!
|
//!
|
||||||
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
|
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
|
||||||
//! pub struct ClientParams {
|
//! pub struct ClientParams {
|
||||||
//! max_block_size: usize,
|
//! max_block_size: usize,
|
||||||
//! max_extrinsic_size: usize,
|
//! max_extrinsic_size: usize,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
|
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
|
||||||
//! pub struct PoolParams {
|
//! pub struct PoolParams {
|
||||||
//! max_transaction_size: usize,
|
//! max_transaction_size: usize,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecExtension)]
|
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecExtension)]
|
||||||
//! pub struct Extension {
|
//! pub struct Extension {
|
||||||
//! pub client: ClientParams,
|
//! pub client: ClientParams,
|
||||||
//! #[forks]
|
//! #[forks]
|
||||||
//! pub pool: Forks<u64, PoolParams>,
|
//! pub pool: Forks<u64, PoolParams>,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! pub type MyChainSpec<G> = GenericChainSpec<G, Extension>;
|
//! pub type MyChainSpec<G> = GenericChainSpec<G, Extension>;
|
||||||
@@ -111,16 +111,16 @@ mod chain_spec;
|
|||||||
mod extension;
|
mod extension;
|
||||||
|
|
||||||
pub use chain_spec::{
|
pub use chain_spec::{
|
||||||
ChainSpec as GenericChainSpec, NoExtension, LightSyncState, SerializableLightSyncState,
|
ChainSpec as GenericChainSpec, LightSyncState, NoExtension, SerializableLightSyncState,
|
||||||
};
|
};
|
||||||
pub use extension::{Group, Fork, Forks, Extension, GetExtension, get_extension};
|
pub use extension::{get_extension, Extension, Fork, Forks, GetExtension, Group};
|
||||||
pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
|
pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
|
||||||
|
|
||||||
use serde::{Serialize, de::DeserializeOwned};
|
|
||||||
use sp_runtime::BuildStorage;
|
|
||||||
use sc_network::config::MultiaddrWithPeerId;
|
use sc_network::config::MultiaddrWithPeerId;
|
||||||
use sc_telemetry::TelemetryEndpoints;
|
use sc_telemetry::TelemetryEndpoints;
|
||||||
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
use sp_core::storage::Storage;
|
use sp_core::storage::Storage;
|
||||||
|
use sp_runtime::BuildStorage;
|
||||||
|
|
||||||
/// The type of a chain.
|
/// The type of a chain.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -74,9 +74,8 @@ impl WasmExecutionMethod {
|
|||||||
impl Into<sc_service::config::WasmExecutionMethod> for WasmExecutionMethod {
|
impl Into<sc_service::config::WasmExecutionMethod> for WasmExecutionMethod {
|
||||||
fn into(self) -> sc_service::config::WasmExecutionMethod {
|
fn into(self) -> sc_service::config::WasmExecutionMethod {
|
||||||
match self {
|
match self {
|
||||||
WasmExecutionMethod::Interpreted => {
|
WasmExecutionMethod::Interpreted =>
|
||||||
sc_service::config::WasmExecutionMethod::Interpreted
|
sc_service::config::WasmExecutionMethod::Interpreted,
|
||||||
}
|
|
||||||
#[cfg(feature = "wasmtime")]
|
#[cfg(feature = "wasmtime")]
|
||||||
WasmExecutionMethod::Compiled => sc_service::config::WasmExecutionMethod::Compiled,
|
WasmExecutionMethod::Compiled => sc_service::config::WasmExecutionMethod::Compiled,
|
||||||
#[cfg(not(feature = "wasmtime"))]
|
#[cfg(not(feature = "wasmtime"))]
|
||||||
@@ -250,14 +249,10 @@ impl Into<sc_network::config::SyncMode> for SyncMode {
|
|||||||
fn into(self) -> sc_network::config::SyncMode {
|
fn into(self) -> sc_network::config::SyncMode {
|
||||||
match self {
|
match self {
|
||||||
SyncMode::Full => sc_network::config::SyncMode::Full,
|
SyncMode::Full => sc_network::config::SyncMode::Full,
|
||||||
SyncMode::Fast => sc_network::config::SyncMode::Fast {
|
SyncMode::Fast =>
|
||||||
skip_proofs: false,
|
sc_network::config::SyncMode::Fast { skip_proofs: false, storage_chain_mode: false },
|
||||||
storage_chain_mode: false,
|
SyncMode::FastUnsafe =>
|
||||||
},
|
sc_network::config::SyncMode::Fast { skip_proofs: true, storage_chain_mode: false },
|
||||||
SyncMode::FastUnsafe => sc_network::config::SyncMode::Fast {
|
|
||||||
skip_proofs: true,
|
|
||||||
storage_chain_mode: false,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,15 +16,19 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::error;
|
use crate::{
|
||||||
use crate::params::NodeKeyParams;
|
error,
|
||||||
use crate::params::SharedParams;
|
params::{NodeKeyParams, SharedParams},
|
||||||
use crate::CliConfiguration;
|
CliConfiguration,
|
||||||
|
};
|
||||||
use log::info;
|
use log::info;
|
||||||
use sc_network::config::build_multiaddr;
|
use sc_network::config::build_multiaddr;
|
||||||
use sc_service::{config::{MultiaddrWithPeerId, NetworkConfiguration}, ChainSpec};
|
use sc_service::{
|
||||||
use structopt::StructOpt;
|
config::{MultiaddrWithPeerId, NetworkConfiguration},
|
||||||
|
ChainSpec,
|
||||||
|
};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
/// The `build-spec` command used to build a specification.
|
/// The `build-spec` command used to build a specification.
|
||||||
#[derive(Debug, StructOpt, Clone)]
|
#[derive(Debug, StructOpt, Clone)]
|
||||||
|
|||||||
@@ -17,7 +17,9 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CliConfiguration, error, params::{ImportParams, SharedParams, BlockNumberOrHash},
|
error,
|
||||||
|
params::{BlockNumberOrHash, ImportParams, SharedParams},
|
||||||
|
CliConfiguration,
|
||||||
};
|
};
|
||||||
use sc_client_api::{BlockBackend, UsageProvider};
|
use sc_client_api::{BlockBackend, UsageProvider};
|
||||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
||||||
@@ -48,11 +50,7 @@ pub struct CheckBlockCmd {
|
|||||||
|
|
||||||
impl CheckBlockCmd {
|
impl CheckBlockCmd {
|
||||||
/// Run the check-block command
|
/// Run the check-block command
|
||||||
pub async fn run<B, C, IQ>(
|
pub async fn run<B, C, IQ>(&self, client: Arc<C>, import_queue: IQ) -> error::Result<()>
|
||||||
&self,
|
|
||||||
client: Arc<C>,
|
|
||||||
import_queue: IQ,
|
|
||||||
) -> error::Result<()>
|
|
||||||
where
|
where
|
||||||
B: BlockT + for<'de> serde::Deserialize<'de>,
|
B: BlockT + for<'de> serde::Deserialize<'de>,
|
||||||
C: BlockBackend<B> + UsageProvider<B> + Send + Sync + 'static,
|
C: BlockBackend<B> + UsageProvider<B> + Send + Sync + 'static,
|
||||||
|
|||||||
@@ -16,21 +16,16 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::error;
|
use crate::{
|
||||||
use crate::params::{GenericNumber, DatabaseParams, PruningParams, SharedParams};
|
error,
|
||||||
use crate::CliConfiguration;
|
params::{DatabaseParams, GenericNumber, PruningParams, SharedParams},
|
||||||
use log::info;
|
CliConfiguration,
|
||||||
use sc_service::{
|
|
||||||
config::DatabaseConfig, chain_ops::export_blocks,
|
|
||||||
};
|
};
|
||||||
|
use log::info;
|
||||||
use sc_client_api::{BlockBackend, UsageProvider};
|
use sc_client_api::{BlockBackend, UsageProvider};
|
||||||
|
use sc_service::{chain_ops::export_blocks, config::DatabaseConfig};
|
||||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
||||||
use std::fmt::Debug;
|
use std::{fmt::Debug, fs, io, path::PathBuf, str::FromStr, sync::Arc};
|
||||||
use std::fs;
|
|
||||||
use std::io;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
/// The `export-blocks` command used to export blocks.
|
/// The `export-blocks` command used to export blocks.
|
||||||
@@ -95,9 +90,7 @@ impl ExportBlocksCmd {
|
|||||||
None => Box::new(io::stdout()),
|
None => Box::new(io::stdout()),
|
||||||
};
|
};
|
||||||
|
|
||||||
export_blocks(client, file, from.into(), to, binary)
|
export_blocks(client, file, from.into(), to, binary).await.map_err(Into::into)
|
||||||
.await
|
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,13 +17,15 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CliConfiguration, error, params::{PruningParams, SharedParams, BlockNumberOrHash},
|
error,
|
||||||
|
params::{BlockNumberOrHash, PruningParams, SharedParams},
|
||||||
|
CliConfiguration,
|
||||||
};
|
};
|
||||||
use log::info;
|
use log::info;
|
||||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
|
||||||
use std::{fmt::Debug, str::FromStr, io::Write, sync::Arc};
|
|
||||||
use structopt::StructOpt;
|
|
||||||
use sc_client_api::{StorageProvider, UsageProvider};
|
use sc_client_api::{StorageProvider, UsageProvider};
|
||||||
|
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
||||||
|
use std::{fmt::Debug, io::Write, str::FromStr, sync::Arc};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
/// The `export-state` command used to export the state of a given block into
|
/// The `export-state` command used to export the state of a given block into
|
||||||
/// a chain spec.
|
/// a chain spec.
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
//! Implementation of the `generate` subcommand
|
//! Implementation of the `generate` subcommand
|
||||||
use bip39::{MnemonicType, Mnemonic, Language};
|
|
||||||
use structopt::StructOpt;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
utils::print_from_uri, KeystoreParams, Error,
|
utils::print_from_uri, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams,
|
||||||
with_crypto_scheme, NetworkSchemeFlag, OutputTypeFlag, CryptoSchemeFlag,
|
NetworkSchemeFlag, OutputTypeFlag,
|
||||||
};
|
};
|
||||||
|
use bip39::{Language, Mnemonic, MnemonicType};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
/// The `generate` command
|
/// The `generate` command
|
||||||
#[derive(Debug, StructOpt, Clone)]
|
#[derive(Debug, StructOpt, Clone)]
|
||||||
@@ -52,12 +52,11 @@ impl GenerateCmd {
|
|||||||
/// Run the command
|
/// Run the command
|
||||||
pub fn run(&self) -> Result<(), Error> {
|
pub fn run(&self) -> Result<(), Error> {
|
||||||
let words = match self.words {
|
let words = match self.words {
|
||||||
Some(words) => {
|
Some(words) => MnemonicType::for_word_count(words).map_err(|_| {
|
||||||
MnemonicType::for_word_count(words)
|
Error::Input(
|
||||||
.map_err(|_| {
|
"Invalid number of words given for phrase: must be 12/15/18/21/24".into(),
|
||||||
Error::Input("Invalid number of words given for phrase: must be 12/15/18/21/24".into())
|
)
|
||||||
})?
|
})?,
|
||||||
},
|
|
||||||
None => MnemonicType::Words12,
|
None => MnemonicType::Words12,
|
||||||
};
|
};
|
||||||
let mnemonic = Mnemonic::new(words, Language::English);
|
let mnemonic = Mnemonic::new(words, Language::English);
|
||||||
|
|||||||
@@ -18,9 +18,9 @@
|
|||||||
//! Implementation of the `generate-node-key` subcommand
|
//! Implementation of the `generate-node-key` subcommand
|
||||||
|
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use structopt::StructOpt;
|
|
||||||
use std::{path::PathBuf, fs};
|
|
||||||
use libp2p::identity::{ed25519 as libp2p_ed25519, PublicKey};
|
use libp2p::identity::{ed25519 as libp2p_ed25519, PublicKey};
|
||||||
|
use std::{fs, path::PathBuf};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
/// The `generate-node-key` command
|
/// The `generate-node-key` command
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
@@ -59,15 +59,14 @@ impl GenerateNodeKeyCmd {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use tempfile::Builder;
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use tempfile::Builder;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn generate_node_key() {
|
fn generate_node_key() {
|
||||||
let mut file = Builder::new().prefix("keyfile").tempfile().unwrap();
|
let mut file = Builder::new().prefix("keyfile").tempfile().unwrap();
|
||||||
let file_path = file.path().display().to_string();
|
let file_path = file.path().display().to_string();
|
||||||
let generate =
|
let generate = GenerateNodeKeyCmd::from_iter(&["generate-node-key", "--file", &file_path]);
|
||||||
GenerateNodeKeyCmd::from_iter(&["generate-node-key", "--file", &file_path]);
|
|
||||||
assert!(generate.run().is_ok());
|
assert!(generate.run().is_ok());
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
assert!(file.read_to_string(&mut buf).is_ok());
|
assert!(file.read_to_string(&mut buf).is_ok());
|
||||||
|
|||||||
@@ -16,19 +16,22 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::error;
|
use crate::{
|
||||||
use crate::params::ImportParams;
|
error,
|
||||||
use crate::params::SharedParams;
|
params::{ImportParams, SharedParams},
|
||||||
use crate::CliConfiguration;
|
CliConfiguration,
|
||||||
|
};
|
||||||
|
use sc_client_api::UsageProvider;
|
||||||
use sc_service::chain_ops::import_blocks;
|
use sc_service::chain_ops::import_blocks;
|
||||||
use sp_runtime::traits::Block as BlockT;
|
use sp_runtime::traits::Block as BlockT;
|
||||||
use std::fmt::Debug;
|
use std::{
|
||||||
use std::fs;
|
fmt::Debug,
|
||||||
use std::io::{self, Read, Seek};
|
fs,
|
||||||
use std::path::PathBuf;
|
io::{self, Read, Seek},
|
||||||
use std::sync::Arc;
|
path::PathBuf,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use sc_client_api::UsageProvider;
|
|
||||||
|
|
||||||
/// The `import-blocks` command used to import blocks.
|
/// The `import-blocks` command used to import blocks.
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
@@ -63,11 +66,7 @@ impl<T: Read + Seek> ReadPlusSeek for T {}
|
|||||||
|
|
||||||
impl ImportBlocksCmd {
|
impl ImportBlocksCmd {
|
||||||
/// Run the import-blocks command
|
/// Run the import-blocks command
|
||||||
pub async fn run<B, C, IQ>(
|
pub async fn run<B, C, IQ>(&self, client: Arc<C>, import_queue: IQ) -> error::Result<()>
|
||||||
&self,
|
|
||||||
client: Arc<C>,
|
|
||||||
import_queue: IQ,
|
|
||||||
) -> error::Result<()>
|
|
||||||
where
|
where
|
||||||
C: UsageProvider<B> + Send + Sync + 'static,
|
C: UsageProvider<B> + Send + Sync + 'static,
|
||||||
B: BlockT + for<'de> serde::Deserialize<'de>,
|
B: BlockT + for<'de> serde::Deserialize<'de>,
|
||||||
@@ -79,7 +78,7 @@ impl ImportBlocksCmd {
|
|||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
io::stdin().read_to_end(&mut buffer)?;
|
io::stdin().read_to_end(&mut buffer)?;
|
||||||
Box::new(io::Cursor::new(buffer))
|
Box::new(io::Cursor::new(buffer))
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
import_blocks(client, import_queue, file, false, self.binary)
|
import_blocks(client, import_queue, file, false, self.binary)
|
||||||
|
|||||||
@@ -18,22 +18,18 @@
|
|||||||
//! Implementation of the `insert` subcommand
|
//! Implementation of the `insert` subcommand
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Error, KeystoreParams, CryptoSchemeFlag, SharedParams, utils, with_crypto_scheme,
|
utils, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, SharedParams, SubstrateCli,
|
||||||
SubstrateCli,
|
|
||||||
};
|
};
|
||||||
use std::{sync::Arc, convert::TryFrom};
|
|
||||||
use structopt::StructOpt;
|
|
||||||
use sp_core::{crypto::KeyTypeId, crypto::SecretString};
|
|
||||||
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
|
|
||||||
use sc_keystore::LocalKeystore;
|
use sc_keystore::LocalKeystore;
|
||||||
use sc_service::config::{KeystoreConfig, BasePath};
|
use sc_service::config::{BasePath, KeystoreConfig};
|
||||||
|
use sp_core::crypto::{KeyTypeId, SecretString};
|
||||||
|
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
|
||||||
|
use std::{convert::TryFrom, sync::Arc};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
/// The `insert` command
|
/// The `insert` command
|
||||||
#[derive(Debug, StructOpt, Clone)]
|
#[derive(Debug, StructOpt, Clone)]
|
||||||
#[structopt(
|
#[structopt(name = "insert", about = "Insert a key to the keystore of a node.")]
|
||||||
name = "insert",
|
|
||||||
about = "Insert a key to the keystore of a node."
|
|
||||||
)]
|
|
||||||
pub struct InsertKeyCmd {
|
pub struct InsertKeyCmd {
|
||||||
/// The secret key URI.
|
/// The secret key URI.
|
||||||
/// If the value is a file, the file content is used as URI.
|
/// If the value is a file, the file content is used as URI.
|
||||||
@@ -62,7 +58,8 @@ impl InsertKeyCmd {
|
|||||||
/// Run the command
|
/// Run the command
|
||||||
pub fn run<C: SubstrateCli>(&self, cli: &C) -> Result<(), Error> {
|
pub fn run<C: SubstrateCli>(&self, cli: &C) -> Result<(), Error> {
|
||||||
let suri = utils::read_uri(self.suri.as_ref())?;
|
let suri = utils::read_uri(self.suri.as_ref())?;
|
||||||
let base_path = self.shared_params
|
let base_path = self
|
||||||
|
.shared_params
|
||||||
.base_path()
|
.base_path()
|
||||||
.unwrap_or_else(|| BasePath::from_project("", "", &C::executable_name()));
|
.unwrap_or_else(|| BasePath::from_project("", "", &C::executable_name()));
|
||||||
let chain_id = self.shared_params.chain_id(self.shared_params.is_dev());
|
let chain_id = self.shared_params.chain_id(self.shared_params.is_dev());
|
||||||
@@ -78,10 +75,11 @@ impl InsertKeyCmd {
|
|||||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(path, password)?);
|
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(path, password)?);
|
||||||
(keystore, public)
|
(keystore, public)
|
||||||
},
|
},
|
||||||
_ => unreachable!("keystore_config always returns path and password; qed")
|
_ => unreachable!("keystore_config always returns path and password; qed"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let key_type = KeyTypeId::try_from(self.key_type.as_str()).map_err(|_| Error::KeyTypeInvalid)?;
|
let key_type =
|
||||||
|
KeyTypeId::try_from(self.key_type.as_str()).map_err(|_| Error::KeyTypeInvalid)?;
|
||||||
|
|
||||||
SyncCryptoStore::insert_unknown(&*keystore, key_type, &suri, &public[..])
|
SyncCryptoStore::insert_unknown(&*keystore, key_type, &suri, &public[..])
|
||||||
.map_err(|_| Error::KeyStoreOperation)?;
|
.map_err(|_| Error::KeyStoreOperation)?;
|
||||||
@@ -98,10 +96,10 @@ fn to_vec<P: sp_core::Pair>(uri: &str, pass: Option<SecretString>) -> Result<Vec
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use sc_service::{ChainSpec, ChainType, GenericChainSpec, NoExtension};
|
||||||
|
use sp_core::{sr25519::Pair, Pair as _, Public};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
use sp_core::{sr25519::Pair, Pair as _, Public};
|
|
||||||
use sc_service::{ChainSpec, GenericChainSpec, ChainType, NoExtension};
|
|
||||||
|
|
||||||
struct Cli;
|
struct Cli;
|
||||||
|
|
||||||
@@ -135,21 +133,17 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load_spec(&self, _: &str) -> std::result::Result<Box<dyn ChainSpec>, String> {
|
fn load_spec(&self, _: &str) -> std::result::Result<Box<dyn ChainSpec>, String> {
|
||||||
Ok(
|
Ok(Box::new(GenericChainSpec::from_genesis(
|
||||||
Box::new(
|
"test",
|
||||||
GenericChainSpec::from_genesis(
|
"test_id",
|
||||||
"test",
|
ChainType::Development,
|
||||||
"test_id",
|
|| unimplemented!("Not required in tests"),
|
||||||
ChainType::Development,
|
Vec::new(),
|
||||||
|| unimplemented!("Not required in tests"),
|
None,
|
||||||
Vec::new(),
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
NoExtension::None,
|
||||||
None,
|
)))
|
||||||
NoExtension::None,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,15 +153,20 @@ mod tests {
|
|||||||
let path_str = format!("{}", path.path().display());
|
let path_str = format!("{}", path.path().display());
|
||||||
let (key, uri, _) = Pair::generate_with_phrase(None);
|
let (key, uri, _) = Pair::generate_with_phrase(None);
|
||||||
|
|
||||||
let inspect = InsertKeyCmd::from_iter(
|
let inspect = InsertKeyCmd::from_iter(&[
|
||||||
&["insert-key", "-d", &path_str, "--key-type", "test", "--suri", &uri],
|
"insert-key",
|
||||||
);
|
"-d",
|
||||||
|
&path_str,
|
||||||
|
"--key-type",
|
||||||
|
"test",
|
||||||
|
"--suri",
|
||||||
|
&uri,
|
||||||
|
]);
|
||||||
assert!(inspect.run(&Cli).is_ok());
|
assert!(inspect.run(&Cli).is_ok());
|
||||||
|
|
||||||
let keystore = LocalKeystore::open(
|
let keystore =
|
||||||
path.path().join("chains").join("test_id").join("keystore"),
|
LocalKeystore::open(path.path().join("chains").join("test_id").join("keystore"), None)
|
||||||
None,
|
.unwrap();
|
||||||
).unwrap();
|
|
||||||
assert!(keystore.has_keys(&[(key.public().to_raw_vec(), KeyTypeId(*b"test"))]));
|
assert!(keystore.has_keys(&[(key.public().to_raw_vec(), KeyTypeId(*b"test"))]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
//! Implementation of the `inspect` subcommand
|
//! Implementation of the `inspect` subcommand
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
utils::{self, print_from_uri, print_from_public}, KeystoreParams,
|
utils::{self, print_from_public, print_from_uri},
|
||||||
with_crypto_scheme, NetworkSchemeFlag, OutputTypeFlag, CryptoSchemeFlag, Error,
|
with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, NetworkSchemeFlag, OutputTypeFlag,
|
||||||
};
|
};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
/// The `inspect` command
|
/// The `inspect` command
|
||||||
@@ -103,8 +103,7 @@ mod tests {
|
|||||||
"remember fiber forum demise paper uniform squirrel feel access exclude casual effort";
|
"remember fiber forum demise paper uniform squirrel feel access exclude casual effort";
|
||||||
let seed = "0xad1fb77243b536b90cfe5f0d351ab1b1ac40e3890b41dc64f766ee56340cfca5";
|
let seed = "0xad1fb77243b536b90cfe5f0d351ab1b1ac40e3890b41dc64f766ee56340cfca5";
|
||||||
|
|
||||||
let inspect =
|
let inspect = InspectKeyCmd::from_iter(&["inspect-key", words, "--password", "12345"]);
|
||||||
InspectKeyCmd::from_iter(&["inspect-key", words, "--password", "12345"]);
|
|
||||||
assert!(inspect.run().is_ok());
|
assert!(inspect.run().is_ok());
|
||||||
|
|
||||||
let inspect = InspectKeyCmd::from_iter(&["inspect-key", seed]);
|
let inspect = InspectKeyCmd::from_iter(&["inspect-key", seed]);
|
||||||
|
|||||||
@@ -18,9 +18,8 @@
|
|||||||
//! Implementation of the `inspect-node-key` subcommand
|
//! Implementation of the `inspect-node-key` subcommand
|
||||||
|
|
||||||
use crate::{Error, NetworkSchemeFlag};
|
use crate::{Error, NetworkSchemeFlag};
|
||||||
use std::fs;
|
use libp2p::identity::{ed25519, PublicKey};
|
||||||
use libp2p::identity::{PublicKey, ed25519};
|
use std::{fs, path::PathBuf};
|
||||||
use std::path::PathBuf;
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
/// The `inspect-node-key` command
|
/// The `inspect-node-key` command
|
||||||
@@ -42,10 +41,10 @@ pub struct InspectNodeKeyCmd {
|
|||||||
impl InspectNodeKeyCmd {
|
impl InspectNodeKeyCmd {
|
||||||
/// runs the command
|
/// runs the command
|
||||||
pub fn run(&self) -> Result<(), Error> {
|
pub fn run(&self) -> Result<(), Error> {
|
||||||
let mut file_content = hex::decode(fs::read(&self.file)?)
|
let mut file_content =
|
||||||
.map_err(|_| "failed to decode secret as hex")?;
|
hex::decode(fs::read(&self.file)?).map_err(|_| "failed to decode secret as hex")?;
|
||||||
let secret = ed25519::SecretKey::from_bytes(&mut file_content)
|
let secret =
|
||||||
.map_err(|_| "Bad node key file")?;
|
ed25519::SecretKey::from_bytes(&mut file_content).map_err(|_| "Bad node key file")?;
|
||||||
|
|
||||||
let keypair = ed25519::Keypair::from(secret);
|
let keypair = ed25519::Keypair::from(secret);
|
||||||
let peer_id = PublicKey::Ed25519(keypair.public()).into_peer_id();
|
let peer_id = PublicKey::Ed25519(keypair.public()).into_peer_id();
|
||||||
@@ -58,8 +57,7 @@ impl InspectNodeKeyCmd {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::{super::GenerateNodeKeyCmd, *};
|
||||||
use super::super::GenerateNodeKeyCmd;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn inspect_node_key() {
|
fn inspect_node_key() {
|
||||||
|
|||||||
@@ -21,11 +21,8 @@ use crate::{Error, SubstrateCli};
|
|||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
insert_key::InsertKeyCmd,
|
generate::GenerateCmd, generate_node_key::GenerateNodeKeyCmd, insert_key::InsertKeyCmd,
|
||||||
inspect_key::InspectKeyCmd,
|
inspect_key::InspectKeyCmd, inspect_node_key::InspectNodeKeyCmd,
|
||||||
generate::GenerateCmd,
|
|
||||||
inspect_node_key::InspectNodeKeyCmd,
|
|
||||||
generate_node_key::GenerateNodeKeyCmd,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Key utilities for the cli.
|
/// Key utilities for the cli.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user