mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 00:31:07 +00:00
Removal of execution strategies (#14387)
* Start * More work! * Moar * More changes * More fixes * More worrk * More fixes * More fixes to make it compile * Adds `NoOffchainStorage` * Pass the extensions * Small basti making small progress * Fix merge errors and remove `ExecutionContext` * Move registration of `ReadRuntimeVersionExt` to `ExecutionExtension` Instead of registering `ReadRuntimeVersionExt` in `sp-state-machine` it is moved to `ExecutionExtension` which provides the default extensions. * Fix compilation * Register the global extensions inside runtime api instance * Fixes * Fix `generate_initial_session_keys` by passing the keystore extension * Fix the grandpa tests * Fix more tests * Fix more tests * Don't set any heap pages if there isn't an override * Fix small fallout * FMT * Fix tests * More tests * Offchain worker custom extensions * More fixes * Make offchain tx pool creation reusable Introduces an `OffchainTransactionPoolFactory` for creating offchain transactions pools that can be registered in the runtime externalities context. This factory will be required for a later pr to make the creation of offchain transaction pools easier. * Fixes * Fixes * Set offchain transaction pool in BABE before using it in the runtime * Add the `offchain_tx_pool` to Grandpa as well * Fix the nodes * Print some error when using the old warnings * Fix merge issues * Fix compilation * Rename `babe_link` * Rename to `offchain_tx_pool_factory` * Cleanup * FMT * Fix benchmark name * Fix `try-runtime` * Remove `--execution` CLI args * Make clippy happy * Forward bls functions * Fix docs * Update UI tests * Update client/api/src/execution_extensions.rs Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Koute <koute@users.noreply.github.com> * Update client/cli/src/params/import_params.rs Co-authored-by: Koute <koute@users.noreply.github.com> * Update client/api/src/execution_extensions.rs Co-authored-by: Koute <koute@users.noreply.github.com> * Pass the offchain storage to the MMR RPC * Update client/api/src/execution_extensions.rs Co-authored-by: Sebastian Kunert <skunert49@gmail.com> * Review comments * Fixes --------- Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Co-authored-by: Koute <koute@users.noreply.github.com> Co-authored-by: Sebastian Kunert <skunert49@gmail.com>
This commit is contained in:
Generated
+15
-2
@@ -5415,6 +5415,7 @@ dependencies = [
|
||||
"sc-network-common",
|
||||
"sc-network-statement",
|
||||
"sc-network-sync",
|
||||
"sc-offchain",
|
||||
"sc-rpc",
|
||||
"sc-service",
|
||||
"sc-service-test",
|
||||
@@ -5577,8 +5578,10 @@ dependencies = [
|
||||
"sc-consensus-grandpa",
|
||||
"sc-executor",
|
||||
"sc-network",
|
||||
"sc-offchain",
|
||||
"sc-rpc-api",
|
||||
"sc-service",
|
||||
"sc-statement-store",
|
||||
"sc-telemetry",
|
||||
"sc-transaction-pool",
|
||||
"sc-transaction-pool-api",
|
||||
@@ -9087,7 +9090,6 @@ dependencies = [
|
||||
"sp-core",
|
||||
"sp-database",
|
||||
"sp-externalities",
|
||||
"sp-keystore",
|
||||
"sp-runtime",
|
||||
"sp-state-machine",
|
||||
"sp-statement-store",
|
||||
@@ -9216,6 +9218,7 @@ dependencies = [
|
||||
"sc-network",
|
||||
"sc-network-test",
|
||||
"sc-telemetry",
|
||||
"sc-transaction-pool-api",
|
||||
"scale-info",
|
||||
"sp-api",
|
||||
"sp-application-crypto",
|
||||
@@ -9248,6 +9251,7 @@ dependencies = [
|
||||
"sc-consensus-epochs",
|
||||
"sc-keystore",
|
||||
"sc-rpc-api",
|
||||
"sc-transaction-pool-api",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sp-api",
|
||||
@@ -9365,6 +9369,7 @@ dependencies = [
|
||||
"sc-network-gossip",
|
||||
"sc-network-test",
|
||||
"sc-telemetry",
|
||||
"sc-transaction-pool-api",
|
||||
"sc-utils",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -9846,6 +9851,7 @@ dependencies = [
|
||||
"hyper-rustls 0.24.0",
|
||||
"lazy_static",
|
||||
"libp2p",
|
||||
"log",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"parity-scale-codec",
|
||||
@@ -9855,12 +9861,15 @@ dependencies = [
|
||||
"sc-client-api",
|
||||
"sc-client-db",
|
||||
"sc-network",
|
||||
"sc-network-common",
|
||||
"sc-transaction-pool",
|
||||
"sc-transaction-pool-api",
|
||||
"sc-utils",
|
||||
"sp-api",
|
||||
"sp-consensus",
|
||||
"sp-core",
|
||||
"sp-externalities",
|
||||
"sp-keystore",
|
||||
"sp-offchain",
|
||||
"sp-runtime",
|
||||
"sp-tracing",
|
||||
@@ -9889,6 +9898,7 @@ dependencies = [
|
||||
"log",
|
||||
"parity-scale-codec",
|
||||
"parking_lot 0.12.1",
|
||||
"pretty_assertions",
|
||||
"sc-block-builder",
|
||||
"sc-chain-spec",
|
||||
"sc-client-api",
|
||||
@@ -9961,6 +9971,7 @@ dependencies = [
|
||||
"log",
|
||||
"parity-scale-codec",
|
||||
"parking_lot 0.12.1",
|
||||
"pretty_assertions",
|
||||
"sc-block-builder",
|
||||
"sc-chain-spec",
|
||||
"sc-client-api",
|
||||
@@ -10024,7 +10035,6 @@ dependencies = [
|
||||
"sc-network-light",
|
||||
"sc-network-sync",
|
||||
"sc-network-transactions",
|
||||
"sc-offchain",
|
||||
"sc-rpc",
|
||||
"sc-rpc-server",
|
||||
"sc-rpc-spec-v2",
|
||||
@@ -10770,6 +10780,7 @@ dependencies = [
|
||||
"scale-info",
|
||||
"sp-api-proc-macro",
|
||||
"sp-core",
|
||||
"sp-externalities",
|
||||
"sp-metadata-ir",
|
||||
"sp-runtime",
|
||||
"sp-state-machine",
|
||||
@@ -11153,6 +11164,7 @@ dependencies = [
|
||||
"substrate-bip39",
|
||||
"thiserror",
|
||||
"tiny-bip39",
|
||||
"tracing",
|
||||
"w3f-bls",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -11500,6 +11512,7 @@ dependencies = [
|
||||
"scale-info",
|
||||
"sp-api",
|
||||
"sp-core",
|
||||
"sp-keystore",
|
||||
"sp-runtime",
|
||||
"sp-staking",
|
||||
"sp-std",
|
||||
|
||||
@@ -28,6 +28,8 @@ sc-service = { version = "0.10.0-dev", path = "../../../client/service" }
|
||||
sc-telemetry = { version = "4.0.0-dev", path = "../../../client/telemetry" }
|
||||
sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" }
|
||||
sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" }
|
||||
sc-offchain = { version = "4.0.0-dev", path = "../../../client/offchain" }
|
||||
sc-statement-store = { version = "4.0.0-dev", path = "../../../client/statement-store" }
|
||||
sc-consensus-aura = { version = "0.10.0-dev", path = "../../../client/consensus/aura" }
|
||||
sp-consensus-aura = { version = "0.10.0-dev", path = "../../../primitives/consensus/aura" }
|
||||
sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" }
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
|
||||
|
||||
use futures::FutureExt;
|
||||
use node_template_runtime::{self, opaque::Block, RuntimeApi};
|
||||
use sc_client_api::BlockBackend;
|
||||
use sc_client_api::{Backend, BlockBackend};
|
||||
use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams};
|
||||
use sc_consensus_grandpa::SharedVoterState;
|
||||
pub use sc_executor::NativeElseWasmExecutor;
|
||||
use sc_service::{error::Error as ServiceError, Configuration, TaskManager, WarpSyncParams};
|
||||
use sc_telemetry::{Telemetry, TelemetryWorker};
|
||||
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
|
||||
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
@@ -179,11 +181,23 @@ pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
|
||||
})?;
|
||||
|
||||
if config.offchain_worker.enabled {
|
||||
sc_service::build_offchain_workers(
|
||||
&config,
|
||||
task_manager.spawn_handle(),
|
||||
client.clone(),
|
||||
network.clone(),
|
||||
task_manager.spawn_handle().spawn(
|
||||
"offchain-workers-runner",
|
||||
"offchain-worker",
|
||||
sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
|
||||
runtime_api_provider: client.clone(),
|
||||
is_validator: config.role.is_authority(),
|
||||
keystore: Some(keystore_container.keystore()),
|
||||
offchain_db: backend.offchain_storage(),
|
||||
transaction_pool: Some(OffchainTransactionPoolFactory::new(
|
||||
transaction_pool.clone(),
|
||||
)),
|
||||
network_provider: network.clone(),
|
||||
enable_http_requests: true,
|
||||
custom_extensions: |_| vec![],
|
||||
})
|
||||
.run(client.clone(), task_manager.spawn_handle())
|
||||
.boxed(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -224,7 +238,7 @@ pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
|
||||
let proposer_factory = sc_basic_authorship::ProposerFactory::new(
|
||||
task_manager.spawn_handle(),
|
||||
client.clone(),
|
||||
transaction_pool,
|
||||
transaction_pool.clone(),
|
||||
prometheus_registry.as_ref(),
|
||||
telemetry.as_ref().map(|x| x.handle()),
|
||||
);
|
||||
@@ -300,6 +314,7 @@ pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
|
||||
prometheus_registry,
|
||||
shared_voter_state: SharedVoterState::empty(),
|
||||
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(transaction_pool),
|
||||
};
|
||||
|
||||
// the GRANDPA voter task is considered infallible, i.e.
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
// *
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --output
|
||||
// pallets/template/src/weights.rs
|
||||
|
||||
@@ -28,7 +28,7 @@ use futures::Future;
|
||||
use std::{borrow::Cow, collections::HashMap, pin::Pin, sync::Arc};
|
||||
|
||||
use node_primitives::Block;
|
||||
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile};
|
||||
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes};
|
||||
use sc_transaction_pool_api::{
|
||||
ImportNotificationStream, PoolFuture, PoolStatus, ReadyTransactions, TransactionFor,
|
||||
TransactionSource, TransactionStatusStreamFor, TxHash,
|
||||
@@ -43,7 +43,6 @@ use crate::{
|
||||
};
|
||||
|
||||
pub struct ConstructionBenchmarkDescription {
|
||||
pub profile: Profile,
|
||||
pub key_types: KeyTypes,
|
||||
pub block_type: BlockType,
|
||||
pub size: SizeType,
|
||||
@@ -51,7 +50,6 @@ pub struct ConstructionBenchmarkDescription {
|
||||
}
|
||||
|
||||
pub struct ConstructionBenchmark {
|
||||
profile: Profile,
|
||||
database: BenchDb,
|
||||
transactions: Transactions,
|
||||
}
|
||||
@@ -60,11 +58,6 @@ impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
|
||||
fn path(&self) -> Path {
|
||||
let mut path = Path::new(&["node", "proposer"]);
|
||||
|
||||
match self.profile {
|
||||
Profile::Wasm => path.push("wasm"),
|
||||
Profile::Native => path.push("native"),
|
||||
}
|
||||
|
||||
match self.key_types {
|
||||
KeyTypes::Sr25519 => path.push("sr25519"),
|
||||
KeyTypes::Ed25519 => path.push("ed25519"),
|
||||
@@ -99,7 +92,6 @@ impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
|
||||
}
|
||||
|
||||
Box::new(ConstructionBenchmark {
|
||||
profile: self.profile,
|
||||
database: bench_db,
|
||||
transactions: Transactions(extrinsics),
|
||||
})
|
||||
@@ -107,8 +99,8 @@ impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
|
||||
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
format!(
|
||||
"Block construction ({:?}/{}, {:?}, {:?} backend)",
|
||||
self.block_type, self.size, self.profile, self.database_type,
|
||||
"Block construction ({:?}/{}, {:?} backend)",
|
||||
self.block_type, self.size, self.database_type,
|
||||
)
|
||||
.into()
|
||||
}
|
||||
@@ -116,7 +108,7 @@ impl core::BenchmarkDescription for ConstructionBenchmarkDescription {
|
||||
|
||||
impl core::Benchmark for ConstructionBenchmark {
|
||||
fn run(&mut self, mode: Mode) -> std::time::Duration {
|
||||
let context = self.database.create_context(self.profile);
|
||||
let context = self.database.create_context();
|
||||
|
||||
let _ = context
|
||||
.client
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use node_primitives::Block;
|
||||
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile};
|
||||
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes};
|
||||
use sc_client_api::backend::Backend;
|
||||
use sp_state_machine::InspectState;
|
||||
|
||||
@@ -43,7 +43,6 @@ use crate::{
|
||||
};
|
||||
|
||||
pub struct ImportBenchmarkDescription {
|
||||
pub profile: Profile,
|
||||
pub key_types: KeyTypes,
|
||||
pub block_type: BlockType,
|
||||
pub size: SizeType,
|
||||
@@ -51,7 +50,6 @@ pub struct ImportBenchmarkDescription {
|
||||
}
|
||||
|
||||
pub struct ImportBenchmark {
|
||||
profile: Profile,
|
||||
database: BenchDb,
|
||||
block: Block,
|
||||
block_type: BlockType,
|
||||
@@ -61,11 +59,6 @@ impl core::BenchmarkDescription for ImportBenchmarkDescription {
|
||||
fn path(&self) -> Path {
|
||||
let mut path = Path::new(&["node", "import"]);
|
||||
|
||||
match self.profile {
|
||||
Profile::Wasm => path.push("wasm"),
|
||||
Profile::Native => path.push("native"),
|
||||
}
|
||||
|
||||
match self.key_types {
|
||||
KeyTypes::Sr25519 => path.push("sr25519"),
|
||||
KeyTypes::Ed25519 => path.push("ed25519"),
|
||||
@@ -88,21 +81,15 @@ impl core::BenchmarkDescription for ImportBenchmarkDescription {
|
||||
}
|
||||
|
||||
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
|
||||
let profile = self.profile;
|
||||
let mut bench_db = BenchDb::with_key_types(self.database_type, 50_000, self.key_types);
|
||||
let block = bench_db.generate_block(self.block_type.to_content(self.size.transactions()));
|
||||
Box::new(ImportBenchmark {
|
||||
database: bench_db,
|
||||
block_type: self.block_type,
|
||||
block,
|
||||
profile,
|
||||
})
|
||||
Box::new(ImportBenchmark { database: bench_db, block_type: self.block_type, block })
|
||||
}
|
||||
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
format!(
|
||||
"Block import ({:?}/{}, {:?}, {:?} backend)",
|
||||
self.block_type, self.size, self.profile, self.database_type,
|
||||
"Block import ({:?}/{}, {:?} backend)",
|
||||
self.block_type, self.size, self.database_type,
|
||||
)
|
||||
.into()
|
||||
}
|
||||
@@ -110,7 +97,7 @@ impl core::BenchmarkDescription for ImportBenchmarkDescription {
|
||||
|
||||
impl core::Benchmark for ImportBenchmark {
|
||||
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();
|
||||
|
||||
let _ = context
|
||||
.client
|
||||
|
||||
@@ -30,7 +30,7 @@ mod txpool;
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
use node_testing::bench::{BlockType, DatabaseType as BenchDataBaseType, KeyTypes, Profile};
|
||||
use node_testing::bench::{BlockType, DatabaseType as BenchDataBaseType, KeyTypes};
|
||||
|
||||
use crate::{
|
||||
common::SizeType,
|
||||
@@ -85,31 +85,28 @@ fn main() {
|
||||
|
||||
let mut import_benchmarks = Vec::new();
|
||||
|
||||
for profile in [Profile::Wasm, Profile::Native] {
|
||||
for size in [
|
||||
SizeType::Empty,
|
||||
SizeType::Small,
|
||||
SizeType::Medium,
|
||||
SizeType::Large,
|
||||
SizeType::Full,
|
||||
SizeType::Custom(opt.transactions.unwrap_or(0)),
|
||||
for size in [
|
||||
SizeType::Empty,
|
||||
SizeType::Small,
|
||||
SizeType::Medium,
|
||||
SizeType::Large,
|
||||
SizeType::Full,
|
||||
SizeType::Custom(opt.transactions.unwrap_or(0)),
|
||||
] {
|
||||
for block_type in [
|
||||
BlockType::RandomTransfersKeepAlive,
|
||||
BlockType::RandomTransfersReaping,
|
||||
BlockType::Noop,
|
||||
] {
|
||||
for block_type in [
|
||||
BlockType::RandomTransfersKeepAlive,
|
||||
BlockType::RandomTransfersReaping,
|
||||
BlockType::Noop,
|
||||
] {
|
||||
for database_type in [BenchDataBaseType::RocksDb, BenchDataBaseType::ParityDb] {
|
||||
import_benchmarks.push((profile, size, block_type, database_type));
|
||||
}
|
||||
for database_type in [BenchDataBaseType::RocksDb, BenchDataBaseType::ParityDb] {
|
||||
import_benchmarks.push((size, block_type, database_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let benchmarks = matrix!(
|
||||
(profile, size, block_type, database_type) in import_benchmarks.into_iter() =>
|
||||
(size, block_type, database_type) in import_benchmarks.into_iter() =>
|
||||
ImportBenchmarkDescription {
|
||||
profile,
|
||||
key_types: KeyTypes::Sr25519,
|
||||
size,
|
||||
block_type,
|
||||
@@ -138,14 +135,12 @@ fn main() {
|
||||
.iter().map(move |db_type| (size, db_type)))
|
||||
=> TrieWriteBenchmarkDescription { database_size: *size, database_type: *db_type },
|
||||
ConstructionBenchmarkDescription {
|
||||
profile: Profile::Wasm,
|
||||
key_types: KeyTypes::Sr25519,
|
||||
block_type: BlockType::RandomTransfersKeepAlive,
|
||||
size: SizeType::Medium,
|
||||
database_type: BenchDataBaseType::RocksDb,
|
||||
},
|
||||
ConstructionBenchmarkDescription {
|
||||
profile: Profile::Wasm,
|
||||
key_types: KeyTypes::Sr25519,
|
||||
block_type: BlockType::RandomTransfersKeepAlive,
|
||||
size: SizeType::Large,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile};
|
||||
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes};
|
||||
|
||||
use sc_transaction_pool::BasicPool;
|
||||
use sc_transaction_pool_api::{TransactionPool, TransactionSource};
|
||||
@@ -57,7 +57,7 @@ impl core::BenchmarkDescription for PoolBenchmarkDescription {
|
||||
|
||||
impl core::Benchmark for PoolBenchmark {
|
||||
fn run(&mut self, mode: Mode) -> std::time::Duration {
|
||||
let context = self.database.create_context(Profile::Wasm);
|
||||
let context = self.database.create_context();
|
||||
|
||||
let _ = context
|
||||
.client
|
||||
|
||||
@@ -83,6 +83,7 @@ sc-authority-discovery = { version = "0.10.0-dev", path = "../../../client/autho
|
||||
sc-sync-state-rpc = { version = "0.10.0-dev", path = "../../../client/sync-state-rpc" }
|
||||
sc-sysinfo = { version = "6.0.0-dev", path = "../../../client/sysinfo" }
|
||||
sc-storage-monitor = { version = "0.1.0", path = "../../../client/storage-monitor" }
|
||||
sc-offchain = { version = "4.0.0-dev", path = "../../../client/offchain" }
|
||||
|
||||
# frame dependencies
|
||||
frame-system = { version = "4.0.0-dev", path = "../../../frame/system" }
|
||||
|
||||
@@ -21,7 +21,6 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughpu
|
||||
use kitchensink_runtime::{constants::currency::*, BalancesCall};
|
||||
use node_cli::service::{create_extrinsic, FullClient};
|
||||
use sc_block_builder::{BlockBuilderProvider, BuiltBlock, RecordProof};
|
||||
use sc_client_api::execution_extensions::ExecutionStrategies;
|
||||
use sc_consensus::{
|
||||
block_import::{BlockImportParams, ForkChoiceStrategy},
|
||||
BlockImport, StateAction,
|
||||
@@ -56,9 +55,6 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase {
|
||||
|
||||
let spec = Box::new(node_cli::chain_spec::development_config());
|
||||
|
||||
// NOTE: We enforce the use of the WASM runtime to benchmark block production using WASM.
|
||||
let execution_strategy = sc_client_api::ExecutionStrategy::AlwaysWasm;
|
||||
|
||||
let config = Configuration {
|
||||
impl_name: "BenchmarkImpl".into(),
|
||||
impl_version: "1.0".into(),
|
||||
@@ -77,13 +73,6 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase {
|
||||
wasm_method: WasmExecutionMethod::Compiled {
|
||||
instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite,
|
||||
},
|
||||
execution_strategies: ExecutionStrategies {
|
||||
syncing: execution_strategy,
|
||||
importing: execution_strategy,
|
||||
block_construction: execution_strategy,
|
||||
offchain_worker: execution_strategy,
|
||||
other: execution_strategy,
|
||||
},
|
||||
rpc_addr: None,
|
||||
rpc_max_connections: Default::default(),
|
||||
rpc_cors: None,
|
||||
|
||||
@@ -23,7 +23,6 @@ use futures::{future, StreamExt};
|
||||
use kitchensink_runtime::{constants::currency::*, BalancesCall, SudoCall};
|
||||
use node_cli::service::{create_extrinsic, fetch_nonce, FullClient, TransactionPool};
|
||||
use node_primitives::AccountId;
|
||||
use sc_client_api::execution_extensions::ExecutionStrategies;
|
||||
use sc_service::{
|
||||
config::{
|
||||
BlocksPruning, DatabaseSource, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig,
|
||||
@@ -70,14 +69,6 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase {
|
||||
blocks_pruning: BlocksPruning::KeepAll,
|
||||
chain_spec: spec,
|
||||
wasm_method: Default::default(),
|
||||
// NOTE: we enforce the use of the native runtime to make the errors more debuggable
|
||||
execution_strategies: ExecutionStrategies {
|
||||
syncing: sc_client_api::ExecutionStrategy::NativeWhenPossible,
|
||||
importing: sc_client_api::ExecutionStrategy::NativeWhenPossible,
|
||||
block_construction: sc_client_api::ExecutionStrategy::NativeWhenPossible,
|
||||
offchain_worker: sc_client_api::ExecutionStrategy::NativeWhenPossible,
|
||||
other: sc_client_api::ExecutionStrategy::NativeWhenPossible,
|
||||
},
|
||||
rpc_addr: None,
|
||||
rpc_max_connections: Default::default(),
|
||||
rpc_cors: None,
|
||||
|
||||
@@ -28,7 +28,7 @@ use futures::prelude::*;
|
||||
use kitchensink_runtime::RuntimeApi;
|
||||
use node_executor::ExecutorDispatch;
|
||||
use node_primitives::Block;
|
||||
use sc_client_api::BlockBackend;
|
||||
use sc_client_api::{Backend, BlockBackend};
|
||||
use sc_consensus_babe::{self, SlotProportion};
|
||||
use sc_executor::NativeElseWasmExecutor;
|
||||
use sc_network::{event::Event, NetworkEventStream, NetworkService};
|
||||
@@ -37,6 +37,7 @@ use sc_network_sync::SyncingService;
|
||||
use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager};
|
||||
use sc_statement_store::Store as StatementStore;
|
||||
use sc_telemetry::{Telemetry, TelemetryWorker};
|
||||
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_core::crypto::Pair;
|
||||
use sp_runtime::{generic, traits::Block as BlockT, SaturatedConversion};
|
||||
@@ -205,27 +206,29 @@ pub fn new_partial(
|
||||
)?;
|
||||
|
||||
let slot_duration = babe_link.config().slot_duration();
|
||||
let (import_queue, babe_worker_handle) = sc_consensus_babe::import_queue(
|
||||
babe_link.clone(),
|
||||
block_import.clone(),
|
||||
Some(Box::new(justification_import)),
|
||||
client.clone(),
|
||||
select_chain.clone(),
|
||||
move |_, ()| async move {
|
||||
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
let (import_queue, babe_worker_handle) =
|
||||
sc_consensus_babe::import_queue(sc_consensus_babe::ImportQueueParams {
|
||||
link: babe_link.clone(),
|
||||
block_import: block_import.clone(),
|
||||
justification_import: Some(Box::new(justification_import)),
|
||||
client: client.clone(),
|
||||
select_chain: select_chain.clone(),
|
||||
create_inherent_data_providers: move |_, ()| async move {
|
||||
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
|
||||
let slot =
|
||||
let slot =
|
||||
sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
|
||||
*timestamp,
|
||||
slot_duration,
|
||||
);
|
||||
|
||||
Ok((slot, timestamp))
|
||||
},
|
||||
&task_manager.spawn_essential_handle(),
|
||||
config.prometheus_registry(),
|
||||
telemetry.as_ref().map(|x| x.handle()),
|
||||
)?;
|
||||
Ok((slot, timestamp))
|
||||
},
|
||||
spawner: &task_manager.spawn_essential_handle(),
|
||||
registry: config.prometheus_registry(),
|
||||
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(transaction_pool.clone()),
|
||||
})?;
|
||||
|
||||
let import_setup = (block_import, grandpa_link, babe_link);
|
||||
|
||||
@@ -278,9 +281,10 @@ pub fn new_partial(
|
||||
finality_provider: finality_proof_provider.clone(),
|
||||
},
|
||||
statement_store: rpc_statement_store.clone(),
|
||||
backend: rpc_backend.clone(),
|
||||
};
|
||||
|
||||
node_rpc::create_full(deps, rpc_backend.clone()).map_err(Into::into)
|
||||
node_rpc::create_full(deps).map_err(Into::into)
|
||||
};
|
||||
|
||||
(rpc_extensions_builder, shared_voter_state2)
|
||||
@@ -381,15 +385,6 @@ pub fn new_full_base(
|
||||
warp_sync_params: Some(WarpSyncParams::WithProvider(warp_sync)),
|
||||
})?;
|
||||
|
||||
if config.offchain_worker.enabled {
|
||||
sc_service::build_offchain_workers(
|
||||
&config,
|
||||
task_manager.spawn_handle(),
|
||||
client.clone(),
|
||||
network.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
let role = config.role.clone();
|
||||
let force_authoring = config.force_authoring;
|
||||
let backoff_authoring_blocks =
|
||||
@@ -397,10 +392,11 @@ pub fn new_full_base(
|
||||
let name = config.network.node_name.clone();
|
||||
let enable_grandpa = !config.disable_grandpa;
|
||||
let prometheus_registry = config.prometheus_registry().cloned();
|
||||
let enable_offchain_worker = config.offchain_worker.enabled;
|
||||
|
||||
let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||
config,
|
||||
backend,
|
||||
backend: backend.clone(),
|
||||
client: client.clone(),
|
||||
keystore: keystore_container.keystore(),
|
||||
network: network.clone(),
|
||||
@@ -525,14 +521,14 @@ pub fn new_full_base(
|
||||
// need a keystore, regardless of which protocol we use below.
|
||||
let keystore = if role.is_authority() { Some(keystore_container.keystore()) } else { None };
|
||||
|
||||
let config = grandpa::Config {
|
||||
let grandpa_config = grandpa::Config {
|
||||
// FIXME #1578 make this available through chainspec
|
||||
gossip_duration: std::time::Duration::from_millis(333),
|
||||
justification_period: 512,
|
||||
name: Some(name),
|
||||
observer_enabled: false,
|
||||
keystore,
|
||||
local_role: role,
|
||||
local_role: role.clone(),
|
||||
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
||||
protocol_name: grandpa_protocol_name,
|
||||
};
|
||||
@@ -545,7 +541,7 @@ pub fn new_full_base(
|
||||
// been tested extensively yet and having most nodes in a network run it
|
||||
// could lead to finality stalls.
|
||||
let grandpa_config = grandpa::GrandpaParams {
|
||||
config,
|
||||
config: grandpa_config,
|
||||
link: grandpa_link,
|
||||
network: network.clone(),
|
||||
sync: Arc::new(sync_service.clone()),
|
||||
@@ -553,6 +549,7 @@ pub fn new_full_base(
|
||||
voting_rule: grandpa::VotingRulesBuilder::default().build(),
|
||||
prometheus_registry: prometheus_registry.clone(),
|
||||
shared_voter_state,
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(transaction_pool.clone()),
|
||||
};
|
||||
|
||||
// the GRANDPA voter task is considered infallible, i.e.
|
||||
@@ -584,6 +581,29 @@ pub fn new_full_base(
|
||||
statement_handler.run(),
|
||||
);
|
||||
|
||||
if enable_offchain_worker {
|
||||
task_manager.spawn_handle().spawn(
|
||||
"offchain-workers-runner",
|
||||
"offchain-work",
|
||||
sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
|
||||
runtime_api_provider: client.clone(),
|
||||
keystore: Some(keystore_container.keystore()),
|
||||
offchain_db: backend.offchain_storage(),
|
||||
transaction_pool: Some(OffchainTransactionPoolFactory::new(
|
||||
transaction_pool.clone(),
|
||||
)),
|
||||
network_provider: network.clone(),
|
||||
is_validator: role.is_authority(),
|
||||
enable_http_requests: true,
|
||||
custom_extensions: move |_| {
|
||||
vec![Box::new(statement_store.clone().as_statement_store_ext()) as Box<_>]
|
||||
},
|
||||
})
|
||||
.run(client.clone(), task_manager.spawn_handle())
|
||||
.boxed(),
|
||||
);
|
||||
}
|
||||
|
||||
network_starter.start_network();
|
||||
Ok(NewFullBase {
|
||||
task_manager,
|
||||
|
||||
@@ -39,7 +39,7 @@ async fn benchmark_block_works() {
|
||||
.arg(base_dir.path())
|
||||
.args(["--from", "1", "--to", "1"])
|
||||
.args(["--repeat", "1"])
|
||||
.args(["--execution", "wasm", "--wasm-execution", "compiled"])
|
||||
.args(["--wasm-execution", "compiled"])
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -90,12 +90,23 @@ pub struct FullDeps<C, P, SC, B> {
|
||||
pub grandpa: GrandpaDeps<B>,
|
||||
/// Shared statement store reference.
|
||||
pub statement_store: Arc<dyn sp_statement_store::StatementStore>,
|
||||
/// The backend used by the node.
|
||||
pub backend: Arc<B>,
|
||||
}
|
||||
|
||||
/// Instantiate all Full RPC extensions.
|
||||
pub fn create_full<C, P, SC, B>(
|
||||
deps: FullDeps<C, P, SC, B>,
|
||||
backend: Arc<B>,
|
||||
FullDeps {
|
||||
client,
|
||||
pool,
|
||||
select_chain,
|
||||
chain_spec,
|
||||
deny_unsafe,
|
||||
babe,
|
||||
grandpa,
|
||||
statement_store,
|
||||
backend,
|
||||
}: FullDeps<C, P, SC, B>,
|
||||
) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
|
||||
where
|
||||
C: ProvideRuntimeApi<Block>
|
||||
@@ -130,16 +141,6 @@ where
|
||||
use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer};
|
||||
|
||||
let mut io = RpcModule::new(());
|
||||
let FullDeps {
|
||||
client,
|
||||
pool,
|
||||
select_chain,
|
||||
chain_spec,
|
||||
deny_unsafe,
|
||||
babe,
|
||||
grandpa,
|
||||
statement_store,
|
||||
} = deps;
|
||||
|
||||
let BabeDeps { keystore, babe_worker_handle } = babe;
|
||||
let GrandpaDeps {
|
||||
@@ -159,7 +160,15 @@ where
|
||||
// Making synchronous calls in light client freezes the browser currently,
|
||||
// more context: https://github.com/paritytech/substrate/pull/3480
|
||||
// These RPCs should use an asynchronous caller instead.
|
||||
io.merge(Mmr::new(client.clone()).into_rpc())?;
|
||||
io.merge(
|
||||
Mmr::new(
|
||||
client.clone(),
|
||||
backend
|
||||
.offchain_storage()
|
||||
.ok_or_else(|| "Backend doesn't provide an offchain storage")?,
|
||||
)
|
||||
.into_rpc(),
|
||||
)?;
|
||||
io.merge(TransactionPayment::new(client.clone()).into_rpc())?;
|
||||
io.merge(
|
||||
Babe::new(client.clone(), babe_worker_handle.clone(), keystore, select_chain, deny_unsafe)
|
||||
|
||||
@@ -40,17 +40,14 @@ use kitchensink_runtime::{
|
||||
};
|
||||
use node_primitives::Block;
|
||||
use sc_block_builder::BlockBuilderProvider;
|
||||
use sc_client_api::{
|
||||
execution_extensions::{ExecutionExtensions, ExecutionStrategies},
|
||||
ExecutionStrategy,
|
||||
};
|
||||
use sc_client_api::execution_extensions::ExecutionExtensions;
|
||||
use sc_client_db::PruningMode;
|
||||
use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, ImportedAux};
|
||||
use sc_executor::{NativeElseWasmExecutor, WasmExecutionMethod, WasmtimeInstantiationStrategy};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_block_builder::BlockBuilder;
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_core::{blake2_256, ed25519, sr25519, traits::SpawnNamed, ExecutionContext, Pair, Public};
|
||||
use sp_core::{blake2_256, ed25519, sr25519, traits::SpawnNamed, Pair, Public};
|
||||
use sp_inherents::InherentData;
|
||||
use sp_runtime::{
|
||||
traits::{Block as BlockT, IdentifyAccount, Verify},
|
||||
@@ -354,7 +351,7 @@ impl BenchDb {
|
||||
dir.path().to_string_lossy(),
|
||||
);
|
||||
let (_client, _backend, _task_executor) =
|
||||
Self::bench_client(database_type, dir.path(), Profile::Native, &keyring);
|
||||
Self::bench_client(database_type, dir.path(), &keyring);
|
||||
let directory_guard = Guard(dir);
|
||||
|
||||
BenchDb { keyring, directory_guard, database_type }
|
||||
@@ -380,7 +377,6 @@ impl BenchDb {
|
||||
fn bench_client(
|
||||
database_type: DatabaseType,
|
||||
dir: &std::path::Path,
|
||||
profile: Profile,
|
||||
keyring: &BenchKeyring,
|
||||
) -> (Client, std::sync::Arc<Backend>, TaskExecutor) {
|
||||
let db_config = sc_client_db::DatabaseSettings {
|
||||
@@ -415,12 +411,7 @@ impl BenchDb {
|
||||
genesis_block_builder,
|
||||
None,
|
||||
None,
|
||||
ExecutionExtensions::new(
|
||||
profile.into_execution_strategies(),
|
||||
None,
|
||||
None,
|
||||
Arc::new(executor),
|
||||
),
|
||||
ExecutionExtensions::new(None, Arc::new(executor)),
|
||||
Box::new(task_executor.clone()),
|
||||
None,
|
||||
None,
|
||||
@@ -444,11 +435,7 @@ impl BenchDb {
|
||||
|
||||
client
|
||||
.runtime_api()
|
||||
.inherent_extrinsics_with_context(
|
||||
client.chain_info().genesis_hash,
|
||||
ExecutionContext::BlockConstruction,
|
||||
inherent_data,
|
||||
)
|
||||
.inherent_extrinsics(client.chain_info().genesis_hash, inherent_data)
|
||||
.expect("Get inherents failed")
|
||||
}
|
||||
|
||||
@@ -459,12 +446,8 @@ impl BenchDb {
|
||||
|
||||
/// Get cliet for this database operations.
|
||||
pub fn client(&mut self) -> Client {
|
||||
let (client, _backend, _task_executor) = Self::bench_client(
|
||||
self.database_type,
|
||||
self.directory_guard.path(),
|
||||
Profile::Wasm,
|
||||
&self.keyring,
|
||||
);
|
||||
let (client, _backend, _task_executor) =
|
||||
Self::bench_client(self.database_type, self.directory_guard.path(), &self.keyring);
|
||||
|
||||
client
|
||||
}
|
||||
@@ -507,10 +490,10 @@ impl BenchDb {
|
||||
}
|
||||
|
||||
/// Clone this database and create context for testing/benchmarking.
|
||||
pub fn create_context(&self, profile: Profile) -> BenchContext {
|
||||
pub fn create_context(&self) -> BenchContext {
|
||||
let BenchDb { directory_guard, keyring, database_type } = self.clone();
|
||||
let (client, backend, task_executor) =
|
||||
Self::bench_client(database_type, directory_guard.path(), profile, &keyring);
|
||||
Self::bench_client(database_type, directory_guard.path(), &keyring);
|
||||
|
||||
BenchContext {
|
||||
client: Arc::new(client),
|
||||
@@ -611,36 +594,6 @@ impl BenchKeyring {
|
||||
}
|
||||
}
|
||||
|
||||
/// Profile for exetion strategies.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Profile {
|
||||
/// As native as possible.
|
||||
Native,
|
||||
/// As wasm as possible.
|
||||
Wasm,
|
||||
}
|
||||
|
||||
impl Profile {
|
||||
fn into_execution_strategies(self) -> ExecutionStrategies {
|
||||
match self {
|
||||
Profile::Wasm => ExecutionStrategies {
|
||||
syncing: ExecutionStrategy::AlwaysWasm,
|
||||
importing: ExecutionStrategy::AlwaysWasm,
|
||||
block_construction: ExecutionStrategy::AlwaysWasm,
|
||||
offchain_worker: ExecutionStrategy::AlwaysWasm,
|
||||
other: ExecutionStrategy::AlwaysWasm,
|
||||
},
|
||||
Profile::Native => ExecutionStrategies {
|
||||
syncing: ExecutionStrategy::NativeElseWasm,
|
||||
importing: ExecutionStrategy::NativeElseWasm,
|
||||
block_construction: ExecutionStrategy::NativeElseWasm,
|
||||
offchain_worker: ExecutionStrategy::NativeElseWasm,
|
||||
other: ExecutionStrategy::NativeElseWasm,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Guard(tempfile::TempDir);
|
||||
|
||||
impl Guard {
|
||||
|
||||
@@ -31,7 +31,6 @@ sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/comm
|
||||
sp-core = { version = "21.0.0", default-features = false, path = "../../primitives/core" }
|
||||
sp-database = { version = "4.0.0-dev", path = "../../primitives/database" }
|
||||
sp-externalities = { version = "0.19.0", path = "../../primitives/externalities" }
|
||||
sp-keystore = { version = "0.27.0", default-features = false, path = "../../primitives/keystore" }
|
||||
sp-runtime = { version = "24.0.0", default-features = false, path = "../../primitives/runtime" }
|
||||
sp-state-machine = { version = "0.28.0", path = "../../primitives/state-machine" }
|
||||
sp-statement-store = { version = "4.0.0-dev", path = "../../primitives/statement-store" }
|
||||
|
||||
@@ -20,12 +20,13 @@
|
||||
|
||||
use sc_executor::{RuntimeVersion, RuntimeVersionOf};
|
||||
use sp_core::traits::CallContext;
|
||||
use sp_externalities::Extensions;
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use sp_state_machine::{ExecutionStrategy, OverlayedChanges, StorageProof};
|
||||
use sp_state_machine::{OverlayedChanges, StorageProof};
|
||||
use std::cell::RefCell;
|
||||
|
||||
use crate::execution_extensions::ExecutionExtensions;
|
||||
use sp_api::{ExecutionContext, ProofRecorder, StorageTransactionCache};
|
||||
use sp_api::{ProofRecorder, StorageTransactionCache};
|
||||
|
||||
/// Executor Provider
|
||||
pub trait ExecutorProvider<Block: BlockT> {
|
||||
@@ -58,7 +59,6 @@ pub trait CallExecutor<B: BlockT>: RuntimeVersionOf {
|
||||
at_hash: B::Hash,
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
strategy: ExecutionStrategy,
|
||||
context: CallContext,
|
||||
) -> Result<Vec<u8>, sp_blockchain::Error>;
|
||||
|
||||
@@ -79,7 +79,8 @@ pub trait CallExecutor<B: BlockT>: RuntimeVersionOf {
|
||||
>,
|
||||
>,
|
||||
proof_recorder: &Option<ProofRecorder<B>>,
|
||||
context: ExecutionContext,
|
||||
call_context: CallContext,
|
||||
extensions: &RefCell<Extensions>,
|
||||
) -> sp_blockchain::Result<Vec<u8>>;
|
||||
|
||||
/// Extract RuntimeVersion of given block
|
||||
|
||||
@@ -23,48 +23,10 @@
|
||||
//! extensions to support APIs for particular execution context & capabilities.
|
||||
|
||||
use parking_lot::RwLock;
|
||||
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
|
||||
use sp_core::{
|
||||
offchain::{self, OffchainDbExt, OffchainWorkerExt},
|
||||
traits::{ReadRuntimeVersion, ReadRuntimeVersionExt},
|
||||
ExecutionContext,
|
||||
};
|
||||
use sp_core::traits::{ReadRuntimeVersion, ReadRuntimeVersionExt};
|
||||
use sp_externalities::{Extension, Extensions};
|
||||
use sp_keystore::{KeystoreExt, KeystorePtr};
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor};
|
||||
pub use sp_state_machine::ExecutionStrategy;
|
||||
use sp_state_machine::{DefaultHandler, ExecutionManager};
|
||||
use std::{
|
||||
marker::PhantomData,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
/// Execution strategies settings.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExecutionStrategies {
|
||||
/// Execution strategy used when syncing.
|
||||
pub syncing: ExecutionStrategy,
|
||||
/// Execution strategy used when importing blocks.
|
||||
pub importing: ExecutionStrategy,
|
||||
/// Execution strategy used when constructing blocks.
|
||||
pub block_construction: ExecutionStrategy,
|
||||
/// Execution strategy used for offchain workers.
|
||||
pub offchain_worker: ExecutionStrategy,
|
||||
/// Execution strategy used in other cases.
|
||||
pub other: ExecutionStrategy,
|
||||
}
|
||||
|
||||
impl Default for ExecutionStrategies {
|
||||
fn default() -> ExecutionStrategies {
|
||||
ExecutionStrategies {
|
||||
syncing: ExecutionStrategy::NativeElseWasm,
|
||||
importing: ExecutionStrategy::NativeElseWasm,
|
||||
block_construction: ExecutionStrategy::AlwaysWasm,
|
||||
offchain_worker: ExecutionStrategy::NativeWhenPossible,
|
||||
other: ExecutionStrategy::NativeElseWasm,
|
||||
}
|
||||
}
|
||||
}
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
|
||||
/// Generate the starting set of [`Extensions`].
|
||||
///
|
||||
@@ -74,22 +36,12 @@ pub trait ExtensionsFactory<Block: BlockT>: Send + Sync {
|
||||
///
|
||||
/// - `block_hash`: The hash of the block in the context that extensions will be used.
|
||||
/// - `block_number`: The number of the block in the context that extensions will be used.
|
||||
/// - `capabilities`: The capabilities
|
||||
fn extensions_for(
|
||||
&self,
|
||||
block_hash: Block::Hash,
|
||||
block_number: NumberFor<Block>,
|
||||
capabilities: offchain::Capabilities,
|
||||
) -> Extensions;
|
||||
fn extensions_for(&self, block_hash: Block::Hash, block_number: NumberFor<Block>)
|
||||
-> Extensions;
|
||||
}
|
||||
|
||||
impl<Block: BlockT> ExtensionsFactory<Block> for () {
|
||||
fn extensions_for(
|
||||
&self,
|
||||
_: Block::Hash,
|
||||
_: NumberFor<Block>,
|
||||
_capabilities: offchain::Capabilities,
|
||||
) -> Extensions {
|
||||
fn extensions_for(&self, _: Block::Hash, _: NumberFor<Block>) -> Extensions {
|
||||
Extensions::new()
|
||||
}
|
||||
}
|
||||
@@ -99,10 +51,9 @@ impl<Block: BlockT, T: ExtensionsFactory<Block>> ExtensionsFactory<Block> for Ve
|
||||
&self,
|
||||
block_hash: Block::Hash,
|
||||
block_number: NumberFor<Block>,
|
||||
capabilities: offchain::Capabilities,
|
||||
) -> Extensions {
|
||||
let mut exts = Extensions::new();
|
||||
exts.extend(self.iter().map(|e| e.extensions_for(block_hash, block_number, capabilities)));
|
||||
exts.extend(self.iter().map(|e| e.extensions_for(block_hash, block_number)));
|
||||
exts
|
||||
}
|
||||
}
|
||||
@@ -125,12 +76,7 @@ impl<Block: BlockT, Ext> ExtensionBeforeBlock<Block, Ext> {
|
||||
impl<Block: BlockT, Ext: Default + Extension> ExtensionsFactory<Block>
|
||||
for ExtensionBeforeBlock<Block, Ext>
|
||||
{
|
||||
fn extensions_for(
|
||||
&self,
|
||||
_: Block::Hash,
|
||||
block_number: NumberFor<Block>,
|
||||
_: offchain::Capabilities,
|
||||
) -> Extensions {
|
||||
fn extensions_for(&self, _: Block::Hash, block_number: NumberFor<Block>) -> Extensions {
|
||||
let mut exts = Extensions::new();
|
||||
|
||||
if block_number < self.before {
|
||||
@@ -141,154 +87,47 @@ impl<Block: BlockT, Ext: Default + Extension> ExtensionsFactory<Block>
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a Offchain DB accessor object.
|
||||
pub trait DbExternalitiesFactory: Send + Sync {
|
||||
/// Create [`offchain::DbExternalities`] instance.
|
||||
fn create(&self) -> Box<dyn offchain::DbExternalities>;
|
||||
}
|
||||
|
||||
impl<T: offchain::DbExternalities + Clone + Sync + Send + 'static> DbExternalitiesFactory for T {
|
||||
fn create(&self) -> Box<dyn offchain::DbExternalities> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// A producer of execution extensions for offchain calls.
|
||||
///
|
||||
/// This crate aggregates extensions available for the offchain calls
|
||||
/// and is responsible for producing a correct `Extensions` object.
|
||||
/// for each call, based on required `Capabilities`.
|
||||
pub struct ExecutionExtensions<Block: BlockT> {
|
||||
strategies: ExecutionStrategies,
|
||||
keystore: Option<KeystorePtr>,
|
||||
offchain_db: Option<Box<dyn DbExternalitiesFactory>>,
|
||||
// FIXME: these three are only RwLock because of https://github.com/paritytech/substrate/issues/4587
|
||||
// remove when fixed.
|
||||
transaction_pool_factory: RwLock<Option<OffchainTransactionPoolFactory<Block>>>,
|
||||
extensions_factory: RwLock<Box<dyn ExtensionsFactory<Block>>>,
|
||||
statement_store: RwLock<Option<Weak<dyn sp_statement_store::StatementStore>>>,
|
||||
read_runtime_version: Arc<dyn ReadRuntimeVersion>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> ExecutionExtensions<Block> {
|
||||
/// Create new `ExecutionExtensions` given a `keystore` and `ExecutionStrategies`.
|
||||
/// Create new `ExecutionExtensions` given an `extensions_factory`.
|
||||
pub fn new(
|
||||
strategies: ExecutionStrategies,
|
||||
keystore: Option<KeystorePtr>,
|
||||
offchain_db: Option<Box<dyn DbExternalitiesFactory>>,
|
||||
extensions_factory: Option<Box<dyn ExtensionsFactory<Block>>>,
|
||||
read_runtime_version: Arc<dyn ReadRuntimeVersion>,
|
||||
) -> Self {
|
||||
let transaction_pool = RwLock::new(None);
|
||||
let statement_store = RwLock::new(None);
|
||||
let extensions_factory = Box::new(());
|
||||
Self {
|
||||
strategies,
|
||||
keystore,
|
||||
offchain_db,
|
||||
extensions_factory: RwLock::new(extensions_factory),
|
||||
transaction_pool_factory: transaction_pool,
|
||||
statement_store,
|
||||
extensions_factory: extensions_factory
|
||||
.map(RwLock::new)
|
||||
.unwrap_or_else(|| RwLock::new(Box::new(()))),
|
||||
read_runtime_version,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to the execution strategies.
|
||||
pub fn strategies(&self) -> &ExecutionStrategies {
|
||||
&self.strategies
|
||||
}
|
||||
|
||||
/// Set the new extensions_factory
|
||||
pub fn set_extensions_factory(&self, maker: impl ExtensionsFactory<Block> + 'static) {
|
||||
*self.extensions_factory.write() = Box::new(maker);
|
||||
}
|
||||
|
||||
/// Register transaction pool extension.
|
||||
pub fn register_transaction_pool_factory(
|
||||
&self,
|
||||
factory: OffchainTransactionPoolFactory<Block>,
|
||||
) {
|
||||
*self.transaction_pool_factory.write() = Some(factory);
|
||||
}
|
||||
|
||||
/// Register statement store extension.
|
||||
pub fn register_statement_store(&self, store: Arc<dyn sp_statement_store::StatementStore>) {
|
||||
*self.statement_store.write() = Some(Arc::downgrade(&store) as _);
|
||||
}
|
||||
|
||||
/// Based on the execution context and capabilities it produces
|
||||
/// the extensions object to support desired set of APIs.
|
||||
pub fn extensions(
|
||||
&self,
|
||||
block_hash: Block::Hash,
|
||||
block_number: NumberFor<Block>,
|
||||
context: ExecutionContext,
|
||||
) -> Extensions {
|
||||
let capabilities = context.capabilities();
|
||||
|
||||
let mut extensions =
|
||||
self.extensions_factory
|
||||
.read()
|
||||
.extensions_for(block_hash, block_number, capabilities);
|
||||
|
||||
if capabilities.contains(offchain::Capabilities::KEYSTORE) {
|
||||
if let Some(ref keystore) = self.keystore {
|
||||
extensions.register(KeystoreExt(keystore.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
if capabilities.contains(offchain::Capabilities::TRANSACTION_POOL) {
|
||||
if let Some(pool) = self.transaction_pool_factory.read().as_ref() {
|
||||
extensions.register(pool.offchain_transaction_pool(block_hash));
|
||||
}
|
||||
}
|
||||
|
||||
if capabilities.contains(offchain::Capabilities::STATEMENT_STORE) {
|
||||
if let Some(store) = self.statement_store.read().as_ref().and_then(|x| x.upgrade()) {
|
||||
extensions.register(sp_statement_store::runtime_api::StatementStoreExt(store));
|
||||
}
|
||||
}
|
||||
if capabilities.contains(offchain::Capabilities::OFFCHAIN_DB_READ) ||
|
||||
capabilities.contains(offchain::Capabilities::OFFCHAIN_DB_WRITE)
|
||||
{
|
||||
if let Some(offchain_db) = self.offchain_db.as_ref() {
|
||||
extensions.register(OffchainDbExt::new(offchain::LimitedExternalities::new(
|
||||
capabilities,
|
||||
offchain_db.create(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
if let ExecutionContext::OffchainCall(Some(ext)) = context {
|
||||
extensions.register(OffchainWorkerExt::new(offchain::LimitedExternalities::new(
|
||||
capabilities,
|
||||
ext.0,
|
||||
)));
|
||||
}
|
||||
self.extensions_factory.read().extensions_for(block_hash, block_number);
|
||||
|
||||
extensions.register(ReadRuntimeVersionExt::new(self.read_runtime_version.clone()));
|
||||
|
||||
extensions
|
||||
}
|
||||
|
||||
/// Create `ExecutionManager` and `Extensions` for given offchain call.
|
||||
///
|
||||
/// Based on the execution context and capabilities it produces
|
||||
/// the right manager and extensions object to support desired set of APIs.
|
||||
pub fn manager_and_extensions<E: std::fmt::Debug>(
|
||||
&self,
|
||||
block_hash: Block::Hash,
|
||||
block_number: NumberFor<Block>,
|
||||
context: ExecutionContext,
|
||||
) -> (ExecutionManager<DefaultHandler<E>>, Extensions) {
|
||||
let manager = match context {
|
||||
ExecutionContext::BlockConstruction => self.strategies.block_construction.get_manager(),
|
||||
ExecutionContext::Syncing => self.strategies.syncing.get_manager(),
|
||||
ExecutionContext::Importing => self.strategies.importing.get_manager(),
|
||||
ExecutionContext::OffchainCall(Some((_, capabilities))) if capabilities.is_all() =>
|
||||
self.strategies.offchain_worker.get_manager(),
|
||||
ExecutionContext::OffchainCall(_) => self.strategies.other.get_manager(),
|
||||
};
|
||||
|
||||
(manager, self.extensions(block_hash, block_number, context))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ pub use proof_provider::*;
|
||||
pub use sp_blockchain as blockchain;
|
||||
pub use sp_blockchain::HeaderBackend;
|
||||
|
||||
pub use sp_state_machine::{CompactProof, ExecutionStrategy, StorageProof};
|
||||
pub use sp_state_machine::{CompactProof, StorageProof};
|
||||
pub use sp_storage::{ChildInfo, PrefixedStorageKey, StorageData, StorageKey};
|
||||
|
||||
/// Usage Information Provider interface
|
||||
|
||||
@@ -32,7 +32,7 @@ use sp_api::{
|
||||
ApiExt, ApiRef, Core, ProvideRuntimeApi, StorageChanges, StorageProof, TransactionOutcome,
|
||||
};
|
||||
use sp_blockchain::{ApplyExtrinsicFailed, Error};
|
||||
use sp_core::ExecutionContext;
|
||||
use sp_core::traits::CallContext;
|
||||
use sp_runtime::{
|
||||
legacy,
|
||||
traits::{Block as BlockT, Hash, HashFor, Header as HeaderT, NumberFor, One},
|
||||
@@ -178,11 +178,9 @@ where
|
||||
api.record_proof();
|
||||
}
|
||||
|
||||
api.initialize_block_with_context(
|
||||
parent_hash,
|
||||
ExecutionContext::BlockConstruction,
|
||||
&header,
|
||||
)?;
|
||||
api.set_call_context(CallContext::Onchain);
|
||||
|
||||
api.initialize_block(parent_hash, &header)?;
|
||||
|
||||
let version = api
|
||||
.api_version::<dyn BlockBuilderApi<Block>>(parent_hash)?
|
||||
@@ -209,18 +207,10 @@ where
|
||||
self.api.execute_in_transaction(|api| {
|
||||
let res = if version < 6 {
|
||||
#[allow(deprecated)]
|
||||
api.apply_extrinsic_before_version_6_with_context(
|
||||
parent_hash,
|
||||
ExecutionContext::BlockConstruction,
|
||||
xt.clone(),
|
||||
)
|
||||
.map(legacy::byte_sized_error::convert_to_latest)
|
||||
api.apply_extrinsic_before_version_6(parent_hash, xt.clone())
|
||||
.map(legacy::byte_sized_error::convert_to_latest)
|
||||
} else {
|
||||
api.apply_extrinsic_with_context(
|
||||
parent_hash,
|
||||
ExecutionContext::BlockConstruction,
|
||||
xt.clone(),
|
||||
)
|
||||
api.apply_extrinsic(parent_hash, xt.clone())
|
||||
};
|
||||
|
||||
match res {
|
||||
@@ -242,9 +232,7 @@ where
|
||||
/// supplied by `self.api`, combined as [`BuiltBlock`].
|
||||
/// The storage proof will be `Some(_)` when proof recording was enabled.
|
||||
pub fn build(mut self) -> Result<BuiltBlock<Block, backend::StateBackendFor<B, Block>>, Error> {
|
||||
let header = self
|
||||
.api
|
||||
.finalize_block_with_context(self.parent_hash, ExecutionContext::BlockConstruction)?;
|
||||
let header = self.api.finalize_block(self.parent_hash)?;
|
||||
|
||||
debug_assert_eq!(
|
||||
header.extrinsics_root().clone(),
|
||||
@@ -282,11 +270,7 @@ where
|
||||
.execute_in_transaction(move |api| {
|
||||
// `create_inherents` should not change any state, to ensure this we always rollback
|
||||
// the transaction.
|
||||
TransactionOutcome::Rollback(api.inherent_extrinsics_with_context(
|
||||
parent_hash,
|
||||
ExecutionContext::BlockConstruction,
|
||||
inherent_data,
|
||||
))
|
||||
TransactionOutcome::Rollback(api.inherent_extrinsics(parent_hash, inherent_data))
|
||||
})
|
||||
.map_err(|e| Error::Application(Box::new(e)))
|
||||
}
|
||||
|
||||
@@ -161,17 +161,6 @@ pub enum ExecutionStrategy {
|
||||
NativeElseWasm,
|
||||
}
|
||||
|
||||
impl Into<sc_client_api::ExecutionStrategy> for ExecutionStrategy {
|
||||
fn into(self) -> sc_client_api::ExecutionStrategy {
|
||||
match self {
|
||||
ExecutionStrategy::Native => sc_client_api::ExecutionStrategy::NativeWhenPossible,
|
||||
ExecutionStrategy::Wasm => sc_client_api::ExecutionStrategy::AlwaysWasm,
|
||||
ExecutionStrategy::Both => sc_client_api::ExecutionStrategy::Both,
|
||||
ExecutionStrategy::NativeElseWasm => sc_client_api::ExecutionStrategy::NativeElseWasm,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Available RPC methods.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, ValueEnum)]
|
||||
@@ -270,16 +259,3 @@ impl Into<sc_network::config::SyncMode> for SyncMode {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Default value for the `--execution-syncing` parameter.
|
||||
pub const DEFAULT_EXECUTION_SYNCING: ExecutionStrategy = ExecutionStrategy::Wasm;
|
||||
/// Default value for the `--execution-import-block` parameter.
|
||||
pub const DEFAULT_EXECUTION_IMPORT_BLOCK: ExecutionStrategy = ExecutionStrategy::Wasm;
|
||||
/// Default value for the `--execution-import-block` parameter when the node is a validator.
|
||||
pub const DEFAULT_EXECUTION_IMPORT_BLOCK_VALIDATOR: ExecutionStrategy = ExecutionStrategy::Wasm;
|
||||
/// Default value for the `--execution-block-construction` parameter.
|
||||
pub const DEFAULT_EXECUTION_BLOCK_CONSTRUCTION: ExecutionStrategy = ExecutionStrategy::Wasm;
|
||||
/// Default value for the `--execution-offchain-worker` parameter.
|
||||
pub const DEFAULT_EXECUTION_OFFCHAIN_WORKER: ExecutionStrategy = ExecutionStrategy::Wasm;
|
||||
/// Default value for the `--execution-other` parameter.
|
||||
pub const DEFAULT_EXECUTION_OTHER: ExecutionStrategy = ExecutionStrategy::Wasm;
|
||||
|
||||
@@ -24,7 +24,6 @@ use crate::{
|
||||
};
|
||||
use log::warn;
|
||||
use names::{Generator, Name};
|
||||
use sc_client_api::execution_extensions::ExecutionStrategies;
|
||||
use sc_service::{
|
||||
config::{
|
||||
BasePath, Configuration, DatabaseSource, KeystoreConfig, NetworkConfiguration,
|
||||
@@ -291,21 +290,6 @@ pub trait CliConfiguration<DCV: DefaultConfigurationValues = ()>: Sized {
|
||||
self.import_params().map(|x| x.wasm_runtime_overrides()).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Get the execution strategies.
|
||||
///
|
||||
/// By default this is retrieved from `ImportParams` if it is available. Otherwise its
|
||||
/// `ExecutionStrategies::default()`.
|
||||
fn execution_strategies(
|
||||
&self,
|
||||
is_dev: bool,
|
||||
is_validator: bool,
|
||||
) -> Result<ExecutionStrategies> {
|
||||
Ok(self
|
||||
.import_params()
|
||||
.map(|x| x.execution_strategies(is_dev, is_validator))
|
||||
.unwrap_or_default())
|
||||
}
|
||||
|
||||
/// Get the RPC address.
|
||||
fn rpc_addr(&self, _default_listen_port: u16) -> Result<Option<SocketAddr>> {
|
||||
Ok(None)
|
||||
@@ -508,7 +492,6 @@ pub trait CliConfiguration<DCV: DefaultConfigurationValues = ()>: Sized {
|
||||
blocks_pruning: self.blocks_pruning()?,
|
||||
wasm_method: self.wasm_method()?,
|
||||
wasm_runtime_overrides: self.wasm_runtime_overrides(),
|
||||
execution_strategies: self.execution_strategies(is_dev, is_validator)?,
|
||||
rpc_addr: self.rpc_addr(DCV::rpc_listen_port())?,
|
||||
rpc_methods: self.rpc_methods()?,
|
||||
rpc_max_connections: self.rpc_max_connections()?,
|
||||
|
||||
@@ -19,15 +19,11 @@
|
||||
use crate::{
|
||||
arg_enums::{
|
||||
ExecutionStrategy, WasmExecutionMethod, WasmtimeInstantiationStrategy,
|
||||
DEFAULT_EXECUTION_BLOCK_CONSTRUCTION, DEFAULT_EXECUTION_IMPORT_BLOCK,
|
||||
DEFAULT_EXECUTION_IMPORT_BLOCK_VALIDATOR, DEFAULT_EXECUTION_OFFCHAIN_WORKER,
|
||||
DEFAULT_EXECUTION_OTHER, DEFAULT_EXECUTION_SYNCING,
|
||||
DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, DEFAULT_WASM_EXECUTION_METHOD,
|
||||
},
|
||||
params::{DatabaseParams, PruningParams},
|
||||
};
|
||||
use clap::Args;
|
||||
use sc_client_api::execution_extensions::ExecutionStrategies;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Parameters for block import.
|
||||
@@ -104,6 +100,8 @@ impl ImportParams {
|
||||
|
||||
/// Get the WASM execution method from the parameters
|
||||
pub fn wasm_method(&self) -> sc_service::config::WasmExecutionMethod {
|
||||
self.execution_strategies.check_usage_and_print_deprecation_warning();
|
||||
|
||||
crate::execution_method_from_cli(self.wasm_method, self.wasmtime_instantiation_strategy)
|
||||
}
|
||||
|
||||
@@ -112,36 +110,6 @@ impl ImportParams {
|
||||
pub fn wasm_runtime_overrides(&self) -> Option<PathBuf> {
|
||||
self.wasm_runtime_overrides.clone()
|
||||
}
|
||||
|
||||
/// Get execution strategies for the parameters
|
||||
pub fn execution_strategies(&self, is_dev: bool, is_validator: bool) -> ExecutionStrategies {
|
||||
let exec = &self.execution_strategies;
|
||||
let exec_all_or = |strat: Option<ExecutionStrategy>, default: ExecutionStrategy| {
|
||||
let default = if is_dev { ExecutionStrategy::Native } else { default };
|
||||
|
||||
exec.execution.unwrap_or_else(|| strat.unwrap_or(default)).into()
|
||||
};
|
||||
|
||||
let default_execution_import_block = if is_validator {
|
||||
DEFAULT_EXECUTION_IMPORT_BLOCK_VALIDATOR
|
||||
} else {
|
||||
DEFAULT_EXECUTION_IMPORT_BLOCK
|
||||
};
|
||||
|
||||
ExecutionStrategies {
|
||||
syncing: exec_all_or(exec.execution_syncing, DEFAULT_EXECUTION_SYNCING),
|
||||
importing: exec_all_or(exec.execution_import_block, default_execution_import_block),
|
||||
block_construction: exec_all_or(
|
||||
exec.execution_block_construction,
|
||||
DEFAULT_EXECUTION_BLOCK_CONSTRUCTION,
|
||||
),
|
||||
offchain_worker: exec_all_or(
|
||||
exec.execution_offchain_worker,
|
||||
DEFAULT_EXECUTION_OFFCHAIN_WORKER,
|
||||
),
|
||||
other: exec_all_or(exec.execution_other, DEFAULT_EXECUTION_OTHER),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Execution strategies parameters.
|
||||
@@ -186,3 +154,23 @@ pub struct ExecutionStrategiesParams {
|
||||
)]
|
||||
pub execution: Option<ExecutionStrategy>,
|
||||
}
|
||||
|
||||
impl ExecutionStrategiesParams {
|
||||
/// Check if one of the parameters is still passed and print a warning if so.
|
||||
fn check_usage_and_print_deprecation_warning(&self) {
|
||||
for (param, name) in [
|
||||
(&self.execution_syncing, "execution-syncing"),
|
||||
(&self.execution_import_block, "execution-import-block"),
|
||||
(&self.execution_block_construction, "execution-block-construction"),
|
||||
(&self.execution_offchain_worker, "execution-offchain-worker"),
|
||||
(&self.execution_other, "execution-other"),
|
||||
(&self.execution, "execution"),
|
||||
] {
|
||||
if param.is_some() {
|
||||
eprintln!(
|
||||
"CLI parameter `--{name}` has no effect anymore and will be removed in the future!"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +265,6 @@ mod tests {
|
||||
)),
|
||||
wasm_method: Default::default(),
|
||||
wasm_runtime_overrides: None,
|
||||
execution_strategies: Default::default(),
|
||||
rpc_addr: None,
|
||||
rpc_max_connections: Default::default(),
|
||||
rpc_cors: None,
|
||||
|
||||
@@ -38,7 +38,7 @@ use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::Error as ConsensusError;
|
||||
use sp_consensus_aura::{inherents::AuraInherentData, AuraApi};
|
||||
use sp_consensus_slots::Slot;
|
||||
use sp_core::{crypto::Pair, ExecutionContext};
|
||||
use sp_core::crypto::Pair;
|
||||
use sp_inherents::{CreateInherentDataProviders, InherentDataProvider as _};
|
||||
use sp_runtime::{
|
||||
traits::{Block as BlockT, Header, NumberFor},
|
||||
@@ -138,7 +138,6 @@ where
|
||||
at_hash: B::Hash,
|
||||
inherent_data: sp_inherents::InherentData,
|
||||
create_inherent_data_providers: CIDP::InherentDataProviders,
|
||||
execution_context: ExecutionContext,
|
||||
) -> Result<(), Error<B>>
|
||||
where
|
||||
C: ProvideRuntimeApi<B>,
|
||||
@@ -148,7 +147,7 @@ where
|
||||
let inherent_res = self
|
||||
.client
|
||||
.runtime_api()
|
||||
.check_inherents_with_context(at_hash, execution_context, block, inherent_data)
|
||||
.check_inherents(at_hash, block, inherent_data)
|
||||
.map_err(|e| Error::Client(e.into()))?;
|
||||
|
||||
if !inherent_res.ok() {
|
||||
@@ -249,7 +248,6 @@ where
|
||||
parent_hash,
|
||||
inherent_data,
|
||||
create_inherent_data_providers,
|
||||
block.origin.into(),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
@@ -31,6 +31,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo
|
||||
sc-consensus-epochs = { version = "0.10.0-dev", path = "../epochs" }
|
||||
sc-consensus-slots = { version = "0.10.0-dev", path = "../slots" }
|
||||
sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" }
|
||||
sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../transaction-pool/api" }
|
||||
sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" }
|
||||
sp-application-crypto = { version = "23.0.0", path = "../../../primitives/application-crypto" }
|
||||
sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" }
|
||||
|
||||
@@ -34,5 +34,6 @@ serde_json = "1.0.85"
|
||||
tokio = "1.22.0"
|
||||
sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" }
|
||||
sc-keystore = { version = "4.0.0-dev", path = "../../../keystore" }
|
||||
sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../transaction-pool/api" }
|
||||
sp-keyring = { version = "24.0.0", path = "../../../../primitives/keyring" }
|
||||
substrate-test-runtime-client = { version = "2.0.0", path = "../../../../test-utils/runtime/client" }
|
||||
|
||||
@@ -186,6 +186,8 @@ impl From<Error> for JsonRpseeError {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sc_consensus_babe::ImportQueueParams;
|
||||
use sc_transaction_pool_api::{OffchainTransactionPoolFactory, RejectAllTxPool};
|
||||
use sp_consensus_babe::inherents::InherentDataProvider;
|
||||
use sp_core::{crypto::key_types::BABE, testing::TaskExecutor};
|
||||
use sp_keyring::Sr25519Keyring;
|
||||
@@ -219,22 +221,25 @@ mod tests {
|
||||
sc_consensus_babe::block_import(config.clone(), client.clone(), client.clone())
|
||||
.expect("can initialize block-import");
|
||||
|
||||
let (_, babe_worker_handle) = sc_consensus_babe::import_queue(
|
||||
link.clone(),
|
||||
block_import.clone(),
|
||||
None,
|
||||
client.clone(),
|
||||
longest_chain.clone(),
|
||||
move |_, _| async move {
|
||||
let (_, babe_worker_handle) = sc_consensus_babe::import_queue(ImportQueueParams {
|
||||
link: link.clone(),
|
||||
block_import: block_import.clone(),
|
||||
justification_import: None,
|
||||
client: client.clone(),
|
||||
select_chain: longest_chain.clone(),
|
||||
create_inherent_data_providers: move |_, _| async move {
|
||||
Ok((InherentDataProvider::from_timestamp_and_slot_duration(
|
||||
0.into(),
|
||||
slot_duration,
|
||||
),))
|
||||
},
|
||||
&task_executor,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
spawner: &task_executor,
|
||||
registry: None,
|
||||
telemetry: None,
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(
|
||||
RejectAllTxPool::default(),
|
||||
),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
Babe::new(client.clone(), babe_worker_handle, keystore, longest_chain, deny_unsafe)
|
||||
|
||||
@@ -106,6 +106,7 @@ use sc_consensus_slots::{
|
||||
SlotInfo, StorageChanges,
|
||||
};
|
||||
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_TRACE};
|
||||
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use sp_application_crypto::AppCrypto;
|
||||
use sp_block_builder::BlockBuilder as BlockBuilderApi;
|
||||
@@ -116,7 +117,7 @@ use sp_blockchain::{
|
||||
use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain};
|
||||
use sp_consensus_babe::inherents::BabeInherentData;
|
||||
use sp_consensus_slots::Slot;
|
||||
use sp_core::ExecutionContext;
|
||||
use sp_core::traits::SpawnEssentialNamed;
|
||||
use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider};
|
||||
use sp_keystore::KeystorePtr;
|
||||
use sp_runtime::{
|
||||
@@ -992,6 +993,7 @@ pub struct BabeVerifier<Block: BlockT, Client, SelectChain, CIDP> {
|
||||
config: BabeConfiguration,
|
||||
epoch_changes: SharedEpochChanges<Block, Epoch>,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory<Block>,
|
||||
}
|
||||
|
||||
impl<Block, Client, SelectChain, CIDP> BabeVerifier<Block, Client, SelectChain, CIDP>
|
||||
@@ -1008,12 +1010,11 @@ where
|
||||
at_hash: Block::Hash,
|
||||
inherent_data: InherentData,
|
||||
create_inherent_data_providers: CIDP::InherentDataProviders,
|
||||
execution_context: ExecutionContext,
|
||||
) -> Result<(), Error<Block>> {
|
||||
let inherent_res = self
|
||||
.client
|
||||
.runtime_api()
|
||||
.check_inherents_with_context(at_hash, execution_context, block, inherent_data)
|
||||
.check_inherents(at_hash, block, inherent_data)
|
||||
.map_err(Error::RuntimeApi)?;
|
||||
|
||||
if !inherent_res.ok() {
|
||||
@@ -1098,8 +1099,13 @@ where
|
||||
};
|
||||
|
||||
// submit equivocation report at best block.
|
||||
self.client
|
||||
.runtime_api()
|
||||
let mut runtime_api = self.client.runtime_api();
|
||||
|
||||
// Register the offchain tx pool to be able to use it from the runtime.
|
||||
runtime_api
|
||||
.register_extension(self.offchain_tx_pool_factory.offchain_transaction_pool(best_hash));
|
||||
|
||||
runtime_api
|
||||
.submit_report_equivocation_unsigned_extrinsic(
|
||||
best_hash,
|
||||
equivocation_proof,
|
||||
@@ -1250,7 +1256,6 @@ where
|
||||
parent_hash,
|
||||
inherent_data,
|
||||
create_inherent_data_providers,
|
||||
block.origin.into(),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
@@ -1768,6 +1773,38 @@ where
|
||||
Ok((import, link))
|
||||
}
|
||||
|
||||
/// Parameters passed to [`import_queue`].
|
||||
pub struct ImportQueueParams<'a, Block: BlockT, BI, Client, CIDP, SelectChain, Spawn> {
|
||||
/// The BABE link that is created by [`block_import`].
|
||||
pub link: BabeLink<Block>,
|
||||
/// The block import that should be wrapped.
|
||||
pub block_import: BI,
|
||||
/// Optional justification import.
|
||||
pub justification_import: Option<BoxJustificationImport<Block>>,
|
||||
/// The client to interact with the internals of the node.
|
||||
pub client: Arc<Client>,
|
||||
/// A [`SelectChain`] implementation.
|
||||
///
|
||||
/// Used to determine the best block that should be used as basis when sending an equivocation
|
||||
/// report.
|
||||
pub select_chain: SelectChain,
|
||||
/// Used to crate the inherent data providers.
|
||||
///
|
||||
/// These inherent data providers are then used to create the inherent data that is
|
||||
/// passed to the `check_inherents` runtime call.
|
||||
pub create_inherent_data_providers: CIDP,
|
||||
/// Spawner for spawning futures.
|
||||
pub spawner: &'a Spawn,
|
||||
/// Registry for prometheus metrics.
|
||||
pub registry: Option<&'a Registry>,
|
||||
/// Optional telemetry handle to report telemetry events.
|
||||
pub telemetry: Option<TelemetryHandle>,
|
||||
/// The offchain transaction pool factory.
|
||||
///
|
||||
/// Will be used when sending equivocation reports.
|
||||
pub offchain_tx_pool_factory: OffchainTransactionPoolFactory<Block>,
|
||||
}
|
||||
|
||||
/// Start an import queue for the BABE consensus algorithm.
|
||||
///
|
||||
/// This method returns the import queue, some data that needs to be passed to the block authoring
|
||||
@@ -1777,19 +1814,22 @@ where
|
||||
///
|
||||
/// The block import object provided must be the `BabeBlockImport` or a wrapper
|
||||
/// of it, otherwise crucial import logic will be omitted.
|
||||
pub fn import_queue<Block: BlockT, Client, SelectChain, Inner, CIDP>(
|
||||
babe_link: BabeLink<Block>,
|
||||
block_import: Inner,
|
||||
justification_import: Option<BoxJustificationImport<Block>>,
|
||||
client: Arc<Client>,
|
||||
select_chain: SelectChain,
|
||||
create_inherent_data_providers: CIDP,
|
||||
spawner: &impl sp_core::traits::SpawnEssentialNamed,
|
||||
registry: Option<&Registry>,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
pub fn import_queue<Block: BlockT, Client, SelectChain, BI, CIDP, Spawn>(
|
||||
ImportQueueParams {
|
||||
link: babe_link,
|
||||
block_import,
|
||||
justification_import,
|
||||
client,
|
||||
select_chain,
|
||||
create_inherent_data_providers,
|
||||
spawner,
|
||||
registry,
|
||||
telemetry,
|
||||
offchain_tx_pool_factory,
|
||||
}: ImportQueueParams<'_, Block, BI, Client, CIDP, SelectChain, Spawn>,
|
||||
) -> ClientResult<(DefaultImportQueue<Block, Client>, BabeWorkerHandle<Block>)>
|
||||
where
|
||||
Inner: BlockImport<
|
||||
BI: BlockImport<
|
||||
Block,
|
||||
Error = ConsensusError,
|
||||
Transaction = sp_api::TransactionFor<Client, Block>,
|
||||
@@ -1807,6 +1847,7 @@ where
|
||||
SelectChain: sp_consensus::SelectChain<Block> + 'static,
|
||||
CIDP: CreateInherentDataProviders<Block, ()> + Send + Sync + 'static,
|
||||
CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync,
|
||||
Spawn: SpawnEssentialNamed,
|
||||
{
|
||||
const HANDLE_BUFFER_SIZE: usize = 1024;
|
||||
|
||||
@@ -1817,6 +1858,7 @@ where
|
||||
epoch_changes: babe_link.epoch_changes.clone(),
|
||||
telemetry,
|
||||
client: client.clone(),
|
||||
offchain_tx_pool_factory,
|
||||
};
|
||||
|
||||
let (worker_tx, worker_rx) = channel(HANDLE_BUFFER_SIZE);
|
||||
|
||||
@@ -26,6 +26,7 @@ use sc_consensus::{BoxBlockImport, BoxJustificationImport};
|
||||
use sc_consensus_epochs::{EpochIdentifier, EpochIdentifierPosition};
|
||||
use sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging;
|
||||
use sc_network_test::{Block as TestBlock, *};
|
||||
use sc_transaction_pool_api::RejectAllTxPool;
|
||||
use sp_application_crypto::key_types::BABE;
|
||||
use sp_consensus::{DisableProofRecording, NoNetwork as DummyOracle, Proposal};
|
||||
use sp_consensus_babe::{
|
||||
@@ -283,6 +284,9 @@ impl TestNetFactory for BabeTestNet {
|
||||
config: data.link.config.clone(),
|
||||
epoch_changes: data.link.epoch_changes.clone(),
|
||||
telemetry: None,
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(
|
||||
RejectAllTxPool::default(),
|
||||
),
|
||||
},
|
||||
mutator: MUTATOR.with(|m| m.borrow().clone()),
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.
|
||||
sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" }
|
||||
sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" }
|
||||
sc-client-api = { version = "4.0.0-dev", path = "../../api" }
|
||||
sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../transaction-pool/api" }
|
||||
sc-consensus = { version = "0.10.0-dev", path = "../common" }
|
||||
sc-network = { version = "0.10.0-dev", path = "../../network" }
|
||||
sc-network-gossip = { version = "0.10.0-dev", path = "../../network-gossip" }
|
||||
|
||||
@@ -40,6 +40,8 @@ use sc_client_api::{
|
||||
utils::is_descendent_of,
|
||||
};
|
||||
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO};
|
||||
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
|
||||
use sp_api::ApiExt;
|
||||
use sp_blockchain::HeaderMetadata;
|
||||
use sp_consensus::SelectChain as SelectChainT;
|
||||
use sp_consensus_grandpa::{
|
||||
@@ -444,6 +446,7 @@ pub(crate) struct Environment<
|
||||
pub(crate) metrics: Option<Metrics>,
|
||||
pub(crate) justification_sender: Option<GrandpaJustificationSender<Block>>,
|
||||
pub(crate) telemetry: Option<TelemetryHandle>,
|
||||
pub(crate) offchain_tx_pool_factory: OffchainTransactionPoolFactory<Block>,
|
||||
pub(crate) _phantom: PhantomData<Backend>,
|
||||
}
|
||||
|
||||
@@ -570,8 +573,13 @@ where
|
||||
// submit equivocation report at **best** block
|
||||
let equivocation_proof = EquivocationProof::new(authority_set.set_id, equivocation);
|
||||
|
||||
self.client
|
||||
.runtime_api()
|
||||
let mut runtime_api = self.client.runtime_api();
|
||||
|
||||
runtime_api.register_extension(
|
||||
self.offchain_tx_pool_factory.offchain_transaction_pool(best_block_hash),
|
||||
);
|
||||
|
||||
runtime_api
|
||||
.submit_report_equivocation_unsigned_extrinsic(
|
||||
best_block_hash,
|
||||
equivocation_proof,
|
||||
|
||||
@@ -64,12 +64,13 @@ use prometheus_endpoint::{PrometheusError, Registry};
|
||||
use sc_client_api::{
|
||||
backend::{AuxStore, Backend},
|
||||
utils::is_descendent_of,
|
||||
BlockchainEvents, CallExecutor, ExecutionStrategy, ExecutorProvider, Finalizer, LockImportRun,
|
||||
StorageProvider, TransactionFor,
|
||||
BlockchainEvents, CallExecutor, ExecutorProvider, Finalizer, LockImportRun, StorageProvider,
|
||||
TransactionFor,
|
||||
};
|
||||
use sc_consensus::BlockImport;
|
||||
use sc_network::types::ProtocolName;
|
||||
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO};
|
||||
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
|
||||
use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_application_crypto::AppCrypto;
|
||||
@@ -479,7 +480,6 @@ where
|
||||
self.expect_block_hash_from_id(&BlockId::Number(Zero::zero()))?,
|
||||
"GrandpaApi_grandpa_authorities",
|
||||
&[],
|
||||
ExecutionStrategy::NativeElseWasm,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.and_then(|call_result| {
|
||||
@@ -688,6 +688,11 @@ pub struct GrandpaParams<Block: BlockT, C, N, S, SC, VR> {
|
||||
pub shared_voter_state: SharedVoterState,
|
||||
/// TelemetryHandle instance.
|
||||
pub telemetry: Option<TelemetryHandle>,
|
||||
/// Offchain transaction pool factory.
|
||||
///
|
||||
/// This will be used to create an offchain transaction pool instance for sending an
|
||||
/// equivocation report from the runtime.
|
||||
pub offchain_tx_pool_factory: OffchainTransactionPoolFactory<Block>,
|
||||
}
|
||||
|
||||
/// Returns the configuration value to put in
|
||||
@@ -736,6 +741,7 @@ where
|
||||
prometheus_registry,
|
||||
shared_voter_state,
|
||||
telemetry,
|
||||
offchain_tx_pool_factory,
|
||||
} = grandpa_params;
|
||||
|
||||
// NOTE: we have recently removed `run_grandpa_observer` from the public
|
||||
@@ -810,6 +816,7 @@ where
|
||||
shared_voter_state,
|
||||
justification_sender,
|
||||
telemetry,
|
||||
offchain_tx_pool_factory,
|
||||
);
|
||||
|
||||
let voter_work = voter_work.map(|res| match res {
|
||||
@@ -879,6 +886,7 @@ where
|
||||
shared_voter_state: SharedVoterState,
|
||||
justification_sender: GrandpaJustificationSender<Block>,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory<Block>,
|
||||
) -> Self {
|
||||
let metrics = match prometheus_registry.as_ref().map(Metrics::register) {
|
||||
Some(Ok(metrics)) => Some(metrics),
|
||||
@@ -903,6 +911,7 @@ where
|
||||
metrics: metrics.as_ref().map(|m| m.environment.clone()),
|
||||
justification_sender: Some(justification_sender),
|
||||
telemetry: telemetry.clone(),
|
||||
offchain_tx_pool_factory,
|
||||
_phantom: PhantomData,
|
||||
});
|
||||
|
||||
@@ -1054,6 +1063,7 @@ where
|
||||
metrics: self.env.metrics.clone(),
|
||||
justification_sender: self.env.justification_sender.clone(),
|
||||
telemetry: self.telemetry.clone(),
|
||||
offchain_tx_pool_factory: self.env.offchain_tx_pool_factory.clone(),
|
||||
_phantom: PhantomData,
|
||||
});
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ use sc_network_test::{
|
||||
Block, BlockImportAdapter, FullPeerConfig, Hash, PassThroughVerifier, Peer, PeersClient,
|
||||
PeersFullClient, TestClient, TestNetFactory,
|
||||
};
|
||||
use sc_transaction_pool_api::RejectAllTxPool;
|
||||
use sp_api::{ApiRef, ProvideRuntimeApi};
|
||||
use sp_consensus::{BlockOrigin, Error as ConsensusError, SelectChain};
|
||||
use sp_consensus_grandpa::{
|
||||
@@ -331,6 +332,9 @@ fn initialize_grandpa(
|
||||
voting_rule: (),
|
||||
prometheus_registry: None,
|
||||
shared_voter_state: SharedVoterState::empty(),
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(
|
||||
RejectAllTxPool::default(),
|
||||
),
|
||||
telemetry: None,
|
||||
};
|
||||
let voter =
|
||||
@@ -481,6 +485,9 @@ async fn finalize_3_voters_1_full_observer() {
|
||||
prometheus_registry: None,
|
||||
shared_voter_state: SharedVoterState::empty(),
|
||||
telemetry: None,
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(
|
||||
RejectAllTxPool::default(),
|
||||
),
|
||||
};
|
||||
|
||||
run_grandpa_voter(grandpa_params).expect("all in order with client and network")
|
||||
@@ -573,6 +580,9 @@ async fn transition_3_voters_twice_1_full_observer() {
|
||||
prometheus_registry: None,
|
||||
shared_voter_state: SharedVoterState::empty(),
|
||||
telemetry: None,
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(
|
||||
RejectAllTxPool::default(),
|
||||
),
|
||||
};
|
||||
|
||||
voters
|
||||
@@ -1040,6 +1050,9 @@ async fn voter_persists_its_votes() {
|
||||
prometheus_registry: None,
|
||||
shared_voter_state: SharedVoterState::empty(),
|
||||
telemetry: None,
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(
|
||||
RejectAllTxPool::default(),
|
||||
),
|
||||
};
|
||||
|
||||
run_grandpa_voter(grandpa_params).expect("all in order with client and network")
|
||||
@@ -1083,6 +1096,9 @@ async fn voter_persists_its_votes() {
|
||||
prometheus_registry: None,
|
||||
shared_voter_state: SharedVoterState::empty(),
|
||||
telemetry: None,
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(
|
||||
RejectAllTxPool::default(),
|
||||
),
|
||||
};
|
||||
|
||||
run_grandpa_voter(grandpa_params)
|
||||
@@ -1293,6 +1309,9 @@ async fn voter_catches_up_to_latest_round_when_behind() {
|
||||
prometheus_registry: None,
|
||||
shared_voter_state: SharedVoterState::empty(),
|
||||
telemetry: None,
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(
|
||||
RejectAllTxPool::default(),
|
||||
),
|
||||
};
|
||||
|
||||
Box::pin(run_grandpa_voter(grandpa_params).expect("all in order with client and network"))
|
||||
@@ -1422,6 +1441,7 @@ where
|
||||
justification_sender: None,
|
||||
telemetry: None,
|
||||
_phantom: PhantomData,
|
||||
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(RejectAllTxPool::default()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1986,7 +2006,7 @@ async fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() {
|
||||
// keys it should work
|
||||
equivocation.identity = TryFrom::try_from(&[1; 32][..]).unwrap();
|
||||
let equivocation_proof = sp_consensus_grandpa::Equivocation::Prevote(equivocation);
|
||||
assert!(environment.report_equivocation(equivocation_proof).is_ok());
|
||||
environment.report_equivocation(equivocation_proof).unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -58,7 +58,6 @@ use sp_block_builder::BlockBuilder as BlockBuilderApi;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::{Environment, Error as ConsensusError, Proposer, SelectChain, SyncOracle};
|
||||
use sp_consensus_pow::{Seal, TotalDifficulty, POW_ENGINE_ID};
|
||||
use sp_core::ExecutionContext;
|
||||
use sp_inherents::{CreateInherentDataProviders, InherentDataProvider};
|
||||
use sp_runtime::{
|
||||
generic::{BlockId, Digest, DigestItem},
|
||||
@@ -269,7 +268,6 @@ where
|
||||
block: B,
|
||||
at_hash: B::Hash,
|
||||
inherent_data_providers: CIDP::InherentDataProviders,
|
||||
execution_context: ExecutionContext,
|
||||
) -> Result<(), Error<B>> {
|
||||
if *block.header().number() < self.check_inherents_after {
|
||||
return Ok(())
|
||||
@@ -283,7 +281,7 @@ where
|
||||
let inherent_res = self
|
||||
.client
|
||||
.runtime_api()
|
||||
.check_inherents_with_context(at_hash, execution_context, block, inherent_data)
|
||||
.check_inherents(at_hash, block, inherent_data)
|
||||
.map_err(|e| Error::Client(e.into()))?;
|
||||
|
||||
if !inherent_res.ok() {
|
||||
@@ -348,7 +346,6 @@ where
|
||||
self.create_inherent_data_providers
|
||||
.create_inherent_data_providers(parent_hash, ())
|
||||
.await?,
|
||||
block.origin.into(),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
@@ -30,9 +30,12 @@ use jsonrpsee::{
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use sp_api::{NumberFor, ProvideRuntimeApi};
|
||||
use sp_api::{ApiExt, NumberFor, ProvideRuntimeApi};
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_core::Bytes;
|
||||
use sp_core::{
|
||||
offchain::{storage::OffchainDb, OffchainDbExt, OffchainStorage},
|
||||
Bytes,
|
||||
};
|
||||
use sp_mmr_primitives::{Error as MmrError, Proof};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
|
||||
@@ -127,26 +130,28 @@ pub trait MmrApi<BlockHash, BlockNumber, MmrHash> {
|
||||
}
|
||||
|
||||
/// MMR RPC methods.
|
||||
pub struct Mmr<Client, Block> {
|
||||
pub struct Mmr<Client, Block, S> {
|
||||
client: Arc<Client>,
|
||||
offchain_db: OffchainDb<S>,
|
||||
_marker: PhantomData<Block>,
|
||||
}
|
||||
|
||||
impl<C, B> Mmr<C, B> {
|
||||
impl<C, B, S> Mmr<C, B, S> {
|
||||
/// Create new `Mmr` with the given reference to the client.
|
||||
pub fn new(client: Arc<C>) -> Self {
|
||||
Self { client, _marker: Default::default() }
|
||||
pub fn new(client: Arc<C>, offchain_storage: S) -> Self {
|
||||
Self { client, _marker: Default::default(), offchain_db: OffchainDb::new(offchain_storage) }
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<Client, Block, MmrHash> MmrApiServer<<Block as BlockT>::Hash, NumberFor<Block>, MmrHash>
|
||||
for Mmr<Client, (Block, MmrHash)>
|
||||
impl<Client, Block, MmrHash, S> MmrApiServer<<Block as BlockT>::Hash, NumberFor<Block>, MmrHash>
|
||||
for Mmr<Client, (Block, MmrHash), S>
|
||||
where
|
||||
Block: BlockT,
|
||||
Client: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
|
||||
Client::Api: MmrRuntimeApi<Block, MmrHash, NumberFor<Block>>,
|
||||
MmrHash: Codec + Send + Sync + 'static,
|
||||
S: OffchainStorage + 'static,
|
||||
{
|
||||
fn mmr_root(&self, at: Option<<Block as BlockT>::Hash>) -> RpcResult<MmrHash> {
|
||||
let block_hash = at.unwrap_or_else(||
|
||||
@@ -166,18 +171,15 @@ where
|
||||
best_known_block_number: Option<NumberFor<Block>>,
|
||||
at: Option<<Block as BlockT>::Hash>,
|
||||
) -> RpcResult<LeavesProof<<Block as BlockT>::Hash>> {
|
||||
let api = self.client.runtime_api();
|
||||
let mut api = self.client.runtime_api();
|
||||
let block_hash = at.unwrap_or_else(||
|
||||
// If the block hash is not supplied assume the best block.
|
||||
self.client.info().best_hash);
|
||||
|
||||
api.register_extension(OffchainDbExt::new(self.offchain_db.clone()));
|
||||
|
||||
let (leaves, proof) = api
|
||||
.generate_proof_with_context(
|
||||
block_hash,
|
||||
sp_core::ExecutionContext::OffchainCall(None),
|
||||
block_numbers,
|
||||
best_known_block_number,
|
||||
)
|
||||
.generate_proof(block_hash, block_numbers, best_known_block_number)
|
||||
.map_err(runtime_error_into_rpc_error)?
|
||||
.map_err(mmr_error_into_rpc_error)?;
|
||||
|
||||
@@ -185,7 +187,7 @@ where
|
||||
}
|
||||
|
||||
fn verify_proof(&self, proof: LeavesProof<<Block as BlockT>::Hash>) -> RpcResult<bool> {
|
||||
let api = self.client.runtime_api();
|
||||
let mut api = self.client.runtime_api();
|
||||
|
||||
let leaves = Decode::decode(&mut &proof.leaves.0[..])
|
||||
.map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?;
|
||||
@@ -193,14 +195,11 @@ where
|
||||
let decoded_proof = Decode::decode(&mut &proof.proof.0[..])
|
||||
.map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?;
|
||||
|
||||
api.verify_proof_with_context(
|
||||
proof.block_hash,
|
||||
sp_core::ExecutionContext::OffchainCall(None),
|
||||
leaves,
|
||||
decoded_proof,
|
||||
)
|
||||
.map_err(runtime_error_into_rpc_error)?
|
||||
.map_err(mmr_error_into_rpc_error)?;
|
||||
api.register_extension(OffchainDbExt::new(self.offchain_db.clone()));
|
||||
|
||||
api.verify_proof(proof.block_hash, leaves, decoded_proof)
|
||||
.map_err(runtime_error_into_rpc_error)?
|
||||
.map_err(mmr_error_into_rpc_error)?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -30,11 +30,16 @@ threadpool = "1.7"
|
||||
tracing = "0.1.29"
|
||||
sc-client-api = { version = "4.0.0-dev", path = "../api" }
|
||||
sc-network = { version = "0.10.0-dev", path = "../network" }
|
||||
sc-network-common = { version = "0.10.0-dev", path = "../network/common" }
|
||||
sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" }
|
||||
sc-utils = { version = "4.0.0-dev", path = "../utils" }
|
||||
sp-api = { version = "4.0.0-dev", path = "../../primitives/api" }
|
||||
sp-core = { version = "21.0.0", path = "../../primitives/core" }
|
||||
sp-offchain = { version = "4.0.0-dev", path = "../../primitives/offchain" }
|
||||
sp-runtime = { version = "24.0.0", path = "../../primitives/runtime" }
|
||||
sp-keystore = { version = "0.27.0", path = "../../primitives/keystore" }
|
||||
sp-externalities = { version = "0.19.0", path = "../../primitives/externalities" }
|
||||
log = "0.4.17"
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
@@ -25,8 +25,8 @@ pub use http::SharedClient;
|
||||
use libp2p::{Multiaddr, PeerId};
|
||||
use sp_core::{
|
||||
offchain::{
|
||||
self, HttpError, HttpRequestId, HttpRequestStatus, OffchainStorage, OpaqueMultiaddr,
|
||||
OpaqueNetworkState, StorageKind, Timestamp,
|
||||
self, HttpError, HttpRequestId, HttpRequestStatus, OpaqueMultiaddr, OpaqueNetworkState,
|
||||
Timestamp,
|
||||
},
|
||||
OpaquePeerId,
|
||||
};
|
||||
@@ -36,110 +36,6 @@ mod http;
|
||||
|
||||
mod timestamp;
|
||||
|
||||
fn unavailable_yet<R: Default>(name: &str) -> R {
|
||||
tracing::error!(
|
||||
target: super::LOG_TARGET,
|
||||
"The {:?} API is not available for offchain workers yet. Follow \
|
||||
https://github.com/paritytech/substrate/issues/1458 for details",
|
||||
name
|
||||
);
|
||||
Default::default()
|
||||
}
|
||||
|
||||
const LOCAL_DB: &str = "LOCAL (fork-aware) DB";
|
||||
|
||||
/// Offchain DB reference.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Db<Storage> {
|
||||
/// Persistent storage database.
|
||||
persistent: Storage,
|
||||
}
|
||||
|
||||
impl<Storage: OffchainStorage> Db<Storage> {
|
||||
/// Create new instance of Offchain DB.
|
||||
pub fn new(persistent: Storage) -> Self {
|
||||
Self { persistent }
|
||||
}
|
||||
|
||||
/// Create new instance of Offchain DB, backed by given backend.
|
||||
pub fn factory_from_backend<Backend, Block>(
|
||||
backend: &Backend,
|
||||
) -> Option<Box<dyn sc_client_api::execution_extensions::DbExternalitiesFactory>>
|
||||
where
|
||||
Backend: sc_client_api::Backend<Block, OffchainStorage = Storage>,
|
||||
Block: sp_runtime::traits::Block,
|
||||
Storage: 'static,
|
||||
{
|
||||
sc_client_api::Backend::offchain_storage(backend).map(|db| Box::new(Self::new(db)) as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Storage: OffchainStorage> offchain::DbExternalities for Db<Storage> {
|
||||
fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) {
|
||||
tracing::debug!(
|
||||
target: "offchain-worker::storage",
|
||||
?kind,
|
||||
key = ?array_bytes::bytes2hex("", key),
|
||||
value = ?array_bytes::bytes2hex("", value),
|
||||
"Write",
|
||||
);
|
||||
match kind {
|
||||
StorageKind::PERSISTENT => self.persistent.set(STORAGE_PREFIX, key, value),
|
||||
StorageKind::LOCAL => unavailable_yet(LOCAL_DB),
|
||||
}
|
||||
}
|
||||
|
||||
fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]) {
|
||||
tracing::debug!(
|
||||
target: "offchain-worker::storage",
|
||||
?kind,
|
||||
key = ?array_bytes::bytes2hex("", key),
|
||||
"Clear",
|
||||
);
|
||||
match kind {
|
||||
StorageKind::PERSISTENT => self.persistent.remove(STORAGE_PREFIX, key),
|
||||
StorageKind::LOCAL => unavailable_yet(LOCAL_DB),
|
||||
}
|
||||
}
|
||||
|
||||
fn local_storage_compare_and_set(
|
||||
&mut self,
|
||||
kind: StorageKind,
|
||||
key: &[u8],
|
||||
old_value: Option<&[u8]>,
|
||||
new_value: &[u8],
|
||||
) -> bool {
|
||||
tracing::debug!(
|
||||
target: "offchain-worker::storage",
|
||||
?kind,
|
||||
key = ?array_bytes::bytes2hex("", key),
|
||||
new_value = ?array_bytes::bytes2hex("", new_value),
|
||||
old_value = ?old_value.as_ref().map(|s| array_bytes::bytes2hex("", s)),
|
||||
"CAS",
|
||||
);
|
||||
match kind {
|
||||
StorageKind::PERSISTENT =>
|
||||
self.persistent.compare_and_set(STORAGE_PREFIX, key, old_value, new_value),
|
||||
StorageKind::LOCAL => unavailable_yet(LOCAL_DB),
|
||||
}
|
||||
}
|
||||
|
||||
fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>> {
|
||||
let result = match kind {
|
||||
StorageKind::PERSISTENT => self.persistent.get(STORAGE_PREFIX, key),
|
||||
StorageKind::LOCAL => unavailable_yet(LOCAL_DB),
|
||||
};
|
||||
tracing::debug!(
|
||||
target: "offchain-worker::storage",
|
||||
?kind,
|
||||
key = ?array_bytes::bytes2hex("", key),
|
||||
result = ?result.as_ref().map(|s| array_bytes::bytes2hex("", s)),
|
||||
"Read",
|
||||
);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// Asynchronous offchain API.
|
||||
///
|
||||
/// NOTE this is done to prevent recursive calls into the runtime
|
||||
@@ -329,7 +225,7 @@ mod tests {
|
||||
config::MultiaddrWithPeerId, types::ProtocolName, NetworkPeers, NetworkStateInfo,
|
||||
ReputationChange,
|
||||
};
|
||||
use sp_core::offchain::{DbExternalities, Externalities};
|
||||
use sp_core::offchain::{storage::OffchainDb, DbExternalities, Externalities, StorageKind};
|
||||
use std::time::SystemTime;
|
||||
|
||||
pub(super) struct TestNetwork();
|
||||
@@ -418,8 +314,8 @@ mod tests {
|
||||
AsyncApi::new(mock, false, shared_client)
|
||||
}
|
||||
|
||||
fn offchain_db() -> Db<LocalStorage> {
|
||||
Db::new(LocalStorage::new_test())
|
||||
fn offchain_db() -> OffchainDb<LocalStorage> {
|
||||
OffchainDb::new(LocalStorage::new_test())
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -35,22 +35,26 @@
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
use std::{fmt, marker::PhantomData, sync::Arc};
|
||||
use std::{fmt, sync::Arc};
|
||||
|
||||
use futures::{
|
||||
future::{ready, Future},
|
||||
prelude::*,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use sc_client_api::BlockchainEvents;
|
||||
use sc_network::{NetworkPeers, NetworkStateInfo};
|
||||
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use sp_core::{offchain, traits::SpawnNamed, ExecutionContext};
|
||||
use sp_core::{offchain, traits::SpawnNamed};
|
||||
use sp_externalities::Extension;
|
||||
use sp_keystore::{KeystoreExt, KeystorePtr};
|
||||
use sp_runtime::traits::{self, Header};
|
||||
use threadpool::ThreadPool;
|
||||
|
||||
mod api;
|
||||
|
||||
pub use api::Db as OffchainDb;
|
||||
pub use sp_core::offchain::storage::OffchainDb;
|
||||
pub use sp_offchain::{OffchainWorkerApi, STORAGE_PREFIX};
|
||||
|
||||
const LOG_TARGET: &str = "offchain-worker";
|
||||
@@ -61,65 +65,160 @@ pub trait NetworkProvider: NetworkStateInfo + NetworkPeers {}
|
||||
|
||||
impl<T> NetworkProvider for T where T: NetworkStateInfo + NetworkPeers {}
|
||||
|
||||
/// Special type that implements [`OffchainStorage`](offchain::OffchainStorage).
|
||||
///
|
||||
/// This type can not be constructed and should only be used when passing `None` as `offchain_db` to
|
||||
/// [`OffchainWorkerOptions`] to make the compiler happy.
|
||||
#[derive(Clone)]
|
||||
pub enum NoOffchainStorage {}
|
||||
|
||||
impl offchain::OffchainStorage for NoOffchainStorage {
|
||||
fn set(&mut self, _: &[u8], _: &[u8], _: &[u8]) {
|
||||
unimplemented!("`NoOffchainStorage` can not be constructed!")
|
||||
}
|
||||
|
||||
fn remove(&mut self, _: &[u8], _: &[u8]) {
|
||||
unimplemented!("`NoOffchainStorage` can not be constructed!")
|
||||
}
|
||||
|
||||
fn get(&self, _: &[u8], _: &[u8]) -> Option<Vec<u8>> {
|
||||
unimplemented!("`NoOffchainStorage` can not be constructed!")
|
||||
}
|
||||
|
||||
fn compare_and_set(&mut self, _: &[u8], _: &[u8], _: Option<&[u8]>, _: &[u8]) -> bool {
|
||||
unimplemented!("`NoOffchainStorage` can not be constructed!")
|
||||
}
|
||||
}
|
||||
|
||||
/// Options for [`OffchainWorkers`]
|
||||
pub struct OffchainWorkerOptions {
|
||||
pub struct OffchainWorkerOptions<RA, Block: traits::Block, Storage, CE> {
|
||||
/// Provides access to the runtime api.
|
||||
pub runtime_api_provider: Arc<RA>,
|
||||
/// Provides access to the keystore.
|
||||
pub keystore: Option<KeystorePtr>,
|
||||
/// Provides access to the offchain database.
|
||||
///
|
||||
/// Use [`NoOffchainStorage`] as type when passing `None` to have some type that works.
|
||||
pub offchain_db: Option<Storage>,
|
||||
/// Provides access to the transaction pool.
|
||||
pub transaction_pool: Option<OffchainTransactionPoolFactory<Block>>,
|
||||
/// Provides access to network information.
|
||||
pub network_provider: Arc<dyn NetworkProvider + Send + Sync>,
|
||||
/// Is the node running as validator?
|
||||
pub is_validator: bool,
|
||||
/// Enable http requests from offchain workers?
|
||||
///
|
||||
/// If not enabled, any http request will panic.
|
||||
pub enable_http_requests: bool,
|
||||
/// Callback to create custom [`Extension`]s that should be registered for the
|
||||
/// `offchain_worker` runtime call.
|
||||
///
|
||||
/// These [`Extension`]s are registered along-side the default extensions and are accessible in
|
||||
/// the host functions.
|
||||
///
|
||||
/// # Example:
|
||||
///
|
||||
/// ```nocompile
|
||||
/// custom_extensions: |block_hash| {
|
||||
/// vec![MyCustomExtension::new()]
|
||||
/// }
|
||||
/// ```
|
||||
pub custom_extensions: CE,
|
||||
}
|
||||
|
||||
/// An offchain workers manager.
|
||||
pub struct OffchainWorkers<Client, Block: traits::Block> {
|
||||
client: Arc<Client>,
|
||||
_block: PhantomData<Block>,
|
||||
pub struct OffchainWorkers<RA, Block: traits::Block, Storage> {
|
||||
runtime_api_provider: Arc<RA>,
|
||||
thread_pool: Mutex<ThreadPool>,
|
||||
shared_http_client: api::SharedClient,
|
||||
enable_http: bool,
|
||||
enable_http_requests: bool,
|
||||
keystore: Option<KeystorePtr>,
|
||||
offchain_db: Option<OffchainDb<Storage>>,
|
||||
transaction_pool: Option<OffchainTransactionPoolFactory<Block>>,
|
||||
network_provider: Arc<dyn NetworkProvider + Send + Sync>,
|
||||
is_validator: bool,
|
||||
custom_extensions: Box<dyn Fn(Block::Hash) -> Vec<Box<dyn Extension>> + Send>,
|
||||
}
|
||||
|
||||
impl<Client, Block: traits::Block> OffchainWorkers<Client, Block> {
|
||||
impl<RA, Block: traits::Block, Storage> OffchainWorkers<RA, Block, Storage> {
|
||||
/// Creates new [`OffchainWorkers`].
|
||||
pub fn new(client: Arc<Client>) -> Self {
|
||||
Self::new_with_options(client, OffchainWorkerOptions { enable_http_requests: true })
|
||||
}
|
||||
|
||||
/// Creates new [`OffchainWorkers`] using the given `options`.
|
||||
pub fn new_with_options(client: Arc<Client>, options: OffchainWorkerOptions) -> Self {
|
||||
pub fn new<CE: Fn(Block::Hash) -> Vec<Box<dyn Extension>> + Send + 'static>(
|
||||
OffchainWorkerOptions {
|
||||
runtime_api_provider,
|
||||
keystore,
|
||||
offchain_db,
|
||||
transaction_pool,
|
||||
network_provider,
|
||||
is_validator,
|
||||
enable_http_requests,
|
||||
custom_extensions,
|
||||
}: OffchainWorkerOptions<RA, Block, Storage, CE>,
|
||||
) -> Self {
|
||||
Self {
|
||||
client,
|
||||
_block: PhantomData,
|
||||
runtime_api_provider,
|
||||
thread_pool: Mutex::new(ThreadPool::with_name(
|
||||
"offchain-worker".into(),
|
||||
num_cpus::get(),
|
||||
)),
|
||||
shared_http_client: api::SharedClient::new(),
|
||||
enable_http: options.enable_http_requests,
|
||||
enable_http_requests,
|
||||
keystore,
|
||||
offchain_db: offchain_db.map(OffchainDb::new),
|
||||
transaction_pool,
|
||||
is_validator,
|
||||
network_provider,
|
||||
custom_extensions: Box::new(custom_extensions),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Client, Block: traits::Block> fmt::Debug for OffchainWorkers<Client, Block> {
|
||||
impl<RA, Block: traits::Block, Storage: offchain::OffchainStorage> fmt::Debug
|
||||
for OffchainWorkers<RA, Block, Storage>
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("OffchainWorkers").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Client, Block> OffchainWorkers<Client, Block>
|
||||
impl<RA, Block, Storage> OffchainWorkers<RA, Block, Storage>
|
||||
where
|
||||
Block: traits::Block,
|
||||
Client: ProvideRuntimeApi<Block> + Send + Sync + 'static,
|
||||
Client::Api: OffchainWorkerApi<Block>,
|
||||
RA: ProvideRuntimeApi<Block> + Send + Sync + 'static,
|
||||
RA::Api: OffchainWorkerApi<Block>,
|
||||
Storage: offchain::OffchainStorage + 'static,
|
||||
{
|
||||
/// Run the offchain workers on every block import.
|
||||
pub async fn run<BE: BlockchainEvents<Block>>(
|
||||
self,
|
||||
import_events: Arc<BE>,
|
||||
spawner: impl SpawnNamed,
|
||||
) {
|
||||
import_events
|
||||
.import_notification_stream()
|
||||
.for_each(move |n| {
|
||||
if n.is_new_best {
|
||||
spawner.spawn(
|
||||
"offchain-on-block",
|
||||
Some("offchain-worker"),
|
||||
self.on_block_imported(&n.header).boxed(),
|
||||
);
|
||||
} else {
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
"Skipping offchain workers for non-canon block: {:?}",
|
||||
n.header,
|
||||
)
|
||||
}
|
||||
|
||||
ready(())
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Start the offchain workers after given block.
|
||||
#[must_use]
|
||||
pub fn on_block_imported(
|
||||
&self,
|
||||
header: &Block::Header,
|
||||
network_provider: Arc<dyn NetworkProvider + Send + Sync>,
|
||||
is_validator: bool,
|
||||
) -> impl Future<Output = ()> {
|
||||
let runtime = self.client.runtime_api();
|
||||
fn on_block_imported(&self, header: &Block::Header) -> impl Future<Output = ()> {
|
||||
let runtime = self.runtime_api_provider.runtime_api();
|
||||
let hash = header.hash();
|
||||
let has_api_v1 = runtime.has_api_with::<dyn OffchainWorkerApi<Block>, _>(hash, |v| v == 1);
|
||||
let has_api_v2 = runtime.has_api_with::<dyn OffchainWorkerApi<Block>, _>(hash, |v| v == 2);
|
||||
@@ -140,36 +239,59 @@ where
|
||||
};
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
"Checking offchain workers at {:?}: version:{}",
|
||||
hash,
|
||||
version
|
||||
"Checking offchain workers at {hash:?}: version: {version}",
|
||||
);
|
||||
|
||||
let process = (version > 0).then(|| {
|
||||
let (api, runner) =
|
||||
api::AsyncApi::new(network_provider, is_validator, self.shared_http_client.clone());
|
||||
tracing::debug!(target: LOG_TARGET, "Spawning offchain workers at {:?}", hash);
|
||||
let (api, runner) = api::AsyncApi::new(
|
||||
self.network_provider.clone(),
|
||||
self.is_validator,
|
||||
self.shared_http_client.clone(),
|
||||
);
|
||||
tracing::debug!(target: LOG_TARGET, "Spawning offchain workers at {hash:?}");
|
||||
let header = header.clone();
|
||||
let client = self.client.clone();
|
||||
let client = self.runtime_api_provider.clone();
|
||||
|
||||
let mut capabilities = offchain::Capabilities::all();
|
||||
capabilities.set(offchain::Capabilities::HTTP, self.enable_http_requests);
|
||||
|
||||
let keystore = self.keystore.clone();
|
||||
let db = self.offchain_db.clone();
|
||||
let tx_pool = self.transaction_pool.clone();
|
||||
let custom_extensions = (*self.custom_extensions)(hash);
|
||||
|
||||
capabilities.set(offchain::Capabilities::HTTP, self.enable_http);
|
||||
self.spawn_worker(move || {
|
||||
let runtime = client.runtime_api();
|
||||
let mut runtime = client.runtime_api();
|
||||
let api = Box::new(api);
|
||||
tracing::debug!(target: LOG_TARGET, "Running offchain workers at {:?}", hash);
|
||||
tracing::debug!(target: LOG_TARGET, "Running offchain workers at {hash:?}");
|
||||
|
||||
if let Some(keystore) = keystore {
|
||||
runtime.register_extension(KeystoreExt(keystore.clone()));
|
||||
}
|
||||
|
||||
if let Some(pool) = tx_pool {
|
||||
runtime.register_extension(pool.offchain_transaction_pool(hash));
|
||||
}
|
||||
|
||||
if let Some(offchain_db) = db {
|
||||
runtime.register_extension(offchain::OffchainDbExt::new(
|
||||
offchain::LimitedExternalities::new(capabilities, offchain_db.clone()),
|
||||
));
|
||||
}
|
||||
|
||||
runtime.register_extension(offchain::OffchainWorkerExt::new(
|
||||
offchain::LimitedExternalities::new(capabilities, api),
|
||||
));
|
||||
|
||||
custom_extensions.into_iter().for_each(|ext| runtime.register_extension(ext));
|
||||
|
||||
let context = ExecutionContext::OffchainCall(Some((api, capabilities)));
|
||||
let run = if version == 2 {
|
||||
runtime.offchain_worker_with_context(hash, context, &header)
|
||||
runtime.offchain_worker(hash, &header)
|
||||
} else {
|
||||
#[allow(deprecated)]
|
||||
runtime.offchain_worker_before_version_2_with_context(
|
||||
hash,
|
||||
context,
|
||||
*header.number(),
|
||||
)
|
||||
runtime.offchain_worker_before_version_2(hash, *header.number())
|
||||
};
|
||||
|
||||
if let Err(e) = run {
|
||||
tracing::error!(
|
||||
target: LOG_TARGET,
|
||||
@@ -201,44 +323,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Inform the offchain worker about new imported blocks
|
||||
pub async fn notification_future<Client, Block, Spawner>(
|
||||
is_validator: bool,
|
||||
client: Arc<Client>,
|
||||
offchain: Arc<OffchainWorkers<Client, Block>>,
|
||||
spawner: Spawner,
|
||||
network_provider: Arc<dyn NetworkProvider + Send + Sync>,
|
||||
) where
|
||||
Block: traits::Block,
|
||||
Client:
|
||||
ProvideRuntimeApi<Block> + sc_client_api::BlockchainEvents<Block> + Send + Sync + 'static,
|
||||
Client::Api: OffchainWorkerApi<Block>,
|
||||
Spawner: SpawnNamed,
|
||||
{
|
||||
client
|
||||
.import_notification_stream()
|
||||
.for_each(move |n| {
|
||||
if n.is_new_best {
|
||||
spawner.spawn(
|
||||
"offchain-on-block",
|
||||
Some("offchain-worker"),
|
||||
offchain
|
||||
.on_block_imported(&n.header, network_provider.clone(), is_validator)
|
||||
.boxed(),
|
||||
);
|
||||
} else {
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
"Skipping offchain workers for non-canon block: {:?}",
|
||||
n.header,
|
||||
)
|
||||
}
|
||||
|
||||
ready(())
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -348,8 +432,17 @@ mod tests {
|
||||
let header = client.header(client.chain_info().genesis_hash).unwrap().unwrap();
|
||||
|
||||
// when
|
||||
let offchain = OffchainWorkers::new(client);
|
||||
futures::executor::block_on(offchain.on_block_imported(&header, network, false));
|
||||
let offchain = OffchainWorkers::new(OffchainWorkerOptions {
|
||||
runtime_api_provider: client,
|
||||
keystore: None,
|
||||
offchain_db: None::<NoOffchainStorage>,
|
||||
transaction_pool: Some(OffchainTransactionPoolFactory::new(pool.clone())),
|
||||
network_provider: network,
|
||||
is_validator: false,
|
||||
enable_http_requests: false,
|
||||
custom_extensions: |_| Vec::new(),
|
||||
});
|
||||
futures::executor::block_on(offchain.on_block_imported(&header));
|
||||
|
||||
// then
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
@@ -46,3 +46,4 @@ sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" }
|
||||
sc-service = { version = "0.10.0-dev", features = ["test-helpers"], path = "../service" }
|
||||
sc-utils = { version = "4.0.0-dev", path = "../utils" }
|
||||
assert_matches = "1.3.0"
|
||||
pretty_assertions = "1.2.1"
|
||||
|
||||
@@ -420,13 +420,7 @@ where
|
||||
|
||||
let res = client
|
||||
.executor()
|
||||
.call(
|
||||
hash,
|
||||
&function,
|
||||
&call_parameters,
|
||||
client.execution_extensions().strategies().other,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.call(hash, &function, &call_parameters, CallContext::Offchain)
|
||||
.map(|result| {
|
||||
let result = format!("0x{:?}", HexDisplay::from(&result));
|
||||
ChainHeadEvent::Done(ChainHeadResult { result })
|
||||
|
||||
@@ -539,7 +539,6 @@ mod tests {
|
||||
genesis_block_builder,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Box::new(TaskExecutor::new()),
|
||||
client_config,
|
||||
)
|
||||
|
||||
@@ -217,6 +217,14 @@ impl<Block: BlockT, Client: CallApiAt<Block>> CallApiAt<Block> for ChainHeadMock
|
||||
fn state_at(&self, at: Block::Hash) -> Result<Self::StateBackend, sp_api::ApiError> {
|
||||
self.client.state_at(at)
|
||||
}
|
||||
|
||||
fn initialize_extensions(
|
||||
&self,
|
||||
at: <Block as BlockT>::Hash,
|
||||
extensions: &mut sp_api::Extensions,
|
||||
) -> Result<(), sp_api::ApiError> {
|
||||
self.client.initialize_extensions(at, extensions)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT, Client: BlockBackend<Block>> BlockBackend<Block>
|
||||
|
||||
@@ -191,6 +191,7 @@ async fn follow_with_runtime() {
|
||||
[\"0xbc9d89904f5b923f\",1],[\"0xc6e9a76309f39b09\",2],[\"0xdd718d5cc53262d4\",1],\
|
||||
[\"0xcbca25e39f142387\",2],[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],\
|
||||
[\"0xed99c5acb25eedf5\",3]],\"transactionVersion\":1,\"stateVersion\":1}";
|
||||
|
||||
let runtime: RuntimeVersion = serde_json::from_str(runtime_str).unwrap();
|
||||
|
||||
let finalized_block_runtime =
|
||||
@@ -201,7 +202,7 @@ async fn follow_with_runtime() {
|
||||
finalized_block_runtime,
|
||||
with_runtime: false,
|
||||
});
|
||||
assert_eq!(event, expected);
|
||||
pretty_assertions::assert_eq!(event, expected);
|
||||
|
||||
// Import a new block without runtime changes.
|
||||
// The runtime field must be None in this case.
|
||||
@@ -1365,7 +1366,6 @@ async fn pin_block_references() {
|
||||
genesis_block_builder,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Box::new(TaskExecutor::new()),
|
||||
client_config,
|
||||
)
|
||||
|
||||
@@ -50,6 +50,7 @@ sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/comm
|
||||
tokio = "1.22.0"
|
||||
sp-io = { version = "23.0.0", path = "../../primitives/io" }
|
||||
substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" }
|
||||
pretty_assertions = "1.2.1"
|
||||
|
||||
[features]
|
||||
test-helpers = []
|
||||
|
||||
@@ -37,10 +37,10 @@ use sc_transaction_pool_api::{
|
||||
error::IntoPoolError, BlockHash, InPoolTransaction, TransactionFor, TransactionPool,
|
||||
TransactionSource, TxHash,
|
||||
};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_core::Bytes;
|
||||
use sp_keystore::KeystorePtr;
|
||||
use sp_keystore::{KeystoreExt, KeystorePtr};
|
||||
use sp_runtime::{generic, traits::Block as BlockT};
|
||||
use sp_session::SessionKeys;
|
||||
|
||||
@@ -122,8 +122,11 @@ where
|
||||
self.deny_unsafe.check_if_safe()?;
|
||||
|
||||
let best_block_hash = self.client.info().best_hash;
|
||||
self.client
|
||||
.runtime_api()
|
||||
let mut runtime_api = self.client.runtime_api();
|
||||
|
||||
runtime_api.register_extension(KeystoreExt::from(self.keystore.clone()));
|
||||
|
||||
runtime_api
|
||||
.generate_session_keys(best_block_hash, None)
|
||||
.map(Into::into)
|
||||
.map_err(|api_err| Error::Client(Box::new(api_err)).into())
|
||||
|
||||
@@ -66,8 +66,7 @@ struct TestSetup {
|
||||
impl Default for TestSetup {
|
||||
fn default() -> Self {
|
||||
let keystore = Arc::new(MemoryKeystore::new());
|
||||
let client_builder = substrate_test_runtime_client::TestClientBuilder::new();
|
||||
let client = Arc::new(client_builder.set_keystore(keystore.clone()).build());
|
||||
let client = Arc::new(substrate_test_runtime_client::TestClientBuilder::new().build());
|
||||
|
||||
let spawner = sp_core::testing::TaskExecutor::new();
|
||||
let pool =
|
||||
|
||||
@@ -198,13 +198,7 @@ where
|
||||
.and_then(|block| {
|
||||
self.client
|
||||
.executor()
|
||||
.call(
|
||||
block,
|
||||
&method,
|
||||
&call_data,
|
||||
self.client.execution_extensions().strategies().other,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.call(block, &method, &call_data, CallContext::Offchain)
|
||||
.map(Into::into)
|
||||
})
|
||||
.map_err(client_err)
|
||||
|
||||
@@ -522,7 +522,7 @@ async fn should_return_runtime_version() {
|
||||
|
||||
let runtime_version = api.runtime_version(None.into()).unwrap();
|
||||
let serialized = serde_json::to_string(&runtime_version).unwrap();
|
||||
assert_eq!(serialized, result);
|
||||
pretty_assertions::assert_eq!(serialized, result);
|
||||
|
||||
let deserialized: RuntimeVersion = serde_json::from_str(result).unwrap();
|
||||
assert_eq!(deserialized, runtime_version);
|
||||
|
||||
@@ -69,7 +69,6 @@ sc-rpc-spec-v2 = { version = "0.10.0-dev", path = "../rpc-spec-v2" }
|
||||
sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" }
|
||||
sc-informant = { version = "0.10.0-dev", path = "../informant" }
|
||||
sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" }
|
||||
sc-offchain = { version = "4.0.0-dev", path = "../offchain" }
|
||||
prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.10.0-dev" }
|
||||
sc-tracing = { version = "4.0.0-dev", path = "../tracing" }
|
||||
sc-sysinfo = { version = "6.0.0-dev", path = "../sysinfo" }
|
||||
|
||||
@@ -187,9 +187,7 @@ where
|
||||
|
||||
let client = {
|
||||
let extensions = sc_client_api::execution_extensions::ExecutionExtensions::new(
|
||||
config.execution_strategies.clone(),
|
||||
Some(keystore_container.keystore()),
|
||||
sc_offchain::OffchainDb::factory_from_backend(&*backend),
|
||||
None,
|
||||
Arc::new(executor.clone()),
|
||||
);
|
||||
|
||||
@@ -322,19 +320,14 @@ where
|
||||
|
||||
/// Shared network instance implementing a set of mandatory traits.
|
||||
pub trait SpawnTaskNetwork<Block: BlockT>:
|
||||
sc_offchain::NetworkProvider + NetworkStateInfo + NetworkStatusProvider + Send + Sync + 'static
|
||||
NetworkStateInfo + NetworkStatusProvider + Send + Sync + 'static
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, Block> SpawnTaskNetwork<Block> for T
|
||||
where
|
||||
Block: BlockT,
|
||||
T: sc_offchain::NetworkProvider
|
||||
+ NetworkStateInfo
|
||||
+ NetworkStatusProvider
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
T: NetworkStateInfo + NetworkStatusProvider + Send + Sync + 'static,
|
||||
{
|
||||
}
|
||||
|
||||
@@ -368,38 +361,6 @@ pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> {
|
||||
pub telemetry: Option<&'a mut Telemetry>,
|
||||
}
|
||||
|
||||
/// Build a shared offchain workers instance.
|
||||
pub fn build_offchain_workers<TBl, TCl>(
|
||||
config: &Configuration,
|
||||
spawn_handle: SpawnTaskHandle,
|
||||
client: Arc<TCl>,
|
||||
network: Arc<dyn sc_offchain::NetworkProvider + Send + Sync>,
|
||||
) -> Option<Arc<sc_offchain::OffchainWorkers<TCl, TBl>>>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TCl: Send + Sync + ProvideRuntimeApi<TBl> + BlockchainEvents<TBl> + 'static,
|
||||
<TCl as ProvideRuntimeApi<TBl>>::Api: sc_offchain::OffchainWorkerApi<TBl>,
|
||||
{
|
||||
let offchain_workers = Some(Arc::new(sc_offchain::OffchainWorkers::new(client.clone())));
|
||||
|
||||
// Inform the offchain worker about new imported blocks
|
||||
if let Some(offchain) = offchain_workers.clone() {
|
||||
spawn_handle.spawn(
|
||||
"offchain-notifications",
|
||||
Some("offchain-worker"),
|
||||
sc_offchain::notification_future(
|
||||
config.role.is_authority(),
|
||||
client,
|
||||
offchain,
|
||||
Clone::clone(&spawn_handle),
|
||||
network,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
offchain_workers
|
||||
}
|
||||
|
||||
/// Spawn the tasks that are required to run a node.
|
||||
pub fn spawn_tasks<TBl, TBackend, TExPool, TRpc, TCl>(
|
||||
params: SpawnTasksParams<TBl, TCl, TExPool, TRpc, TBackend>,
|
||||
@@ -420,7 +381,6 @@ where
|
||||
+ Send
|
||||
+ 'static,
|
||||
<TCl as ProvideRuntimeApi<TBl>>::Api: sp_api::Metadata<TBl>
|
||||
+ sc_offchain::OffchainWorkerApi<TBl>
|
||||
+ sp_transaction_pool::runtime_api::TaggedTransactionQueue<TBl>
|
||||
+ sp_session::SessionKeys<TBl>
|
||||
+ sp_api::ApiExt<TBl, StateBackend = TBackend::State>,
|
||||
@@ -451,6 +411,7 @@ where
|
||||
client.clone(),
|
||||
chain_info.best_hash,
|
||||
config.dev_key_seed.clone().map(|s| vec![s]).unwrap_or_default(),
|
||||
keystore.clone(),
|
||||
)
|
||||
.map_err(|e| Error::Application(Box::new(e)))?;
|
||||
|
||||
|
||||
@@ -22,14 +22,10 @@ use sc_client_api::{
|
||||
};
|
||||
use sc_executor::{RuntimeVersion, RuntimeVersionOf};
|
||||
use sp_api::{ProofRecorder, StorageTransactionCache};
|
||||
use sp_core::{
|
||||
traits::{CallContext, CodeExecutor, RuntimeCode},
|
||||
ExecutionContext,
|
||||
};
|
||||
use sp_core::traits::{CallContext, CodeExecutor, RuntimeCode};
|
||||
use sp_externalities::Extensions;
|
||||
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
|
||||
use sp_state_machine::{
|
||||
backend::AsTrieBackend, ExecutionStrategy, Ext, OverlayedChanges, StateMachine, StorageProof,
|
||||
};
|
||||
use sp_state_machine::{backend::AsTrieBackend, Ext, OverlayedChanges, StateMachine, StorageProof};
|
||||
use std::{cell::RefCell, sync::Arc};
|
||||
|
||||
/// Call executor that executes methods locally, querying all required
|
||||
@@ -166,7 +162,6 @@ where
|
||||
at_hash: Block::Hash,
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
strategy: ExecutionStrategy,
|
||||
context: CallContext,
|
||||
) -> sp_blockchain::Result<Vec<u8>> {
|
||||
let mut changes = OverlayedChanges::default();
|
||||
@@ -180,11 +175,7 @@ where
|
||||
|
||||
let runtime_code = self.check_override(runtime_code, &state, at_hash)?.0;
|
||||
|
||||
let extensions = self.execution_extensions.extensions(
|
||||
at_hash,
|
||||
at_number,
|
||||
ExecutionContext::OffchainCall(None),
|
||||
);
|
||||
let mut extensions = self.execution_extensions.extensions(at_hash, at_number);
|
||||
|
||||
let mut sm = StateMachine::new(
|
||||
&state,
|
||||
@@ -192,14 +183,13 @@ where
|
||||
&self.executor,
|
||||
method,
|
||||
call_data,
|
||||
extensions,
|
||||
&mut extensions,
|
||||
&runtime_code,
|
||||
context,
|
||||
)
|
||||
.set_parent_hash(at_hash);
|
||||
|
||||
sm.execute_using_consensus_failure_handler(strategy.get_manager())
|
||||
.map_err(Into::into)
|
||||
sm.execute().map_err(Into::into)
|
||||
}
|
||||
|
||||
fn contextual_call(
|
||||
@@ -210,22 +200,13 @@ where
|
||||
changes: &RefCell<OverlayedChanges>,
|
||||
storage_transaction_cache: Option<&RefCell<StorageTransactionCache<Block, B::State>>>,
|
||||
recorder: &Option<ProofRecorder<Block>>,
|
||||
context: ExecutionContext,
|
||||
call_context: CallContext,
|
||||
extensions: &RefCell<Extensions>,
|
||||
) -> Result<Vec<u8>, sp_blockchain::Error> {
|
||||
let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut());
|
||||
|
||||
let at_number =
|
||||
self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(at_hash))?;
|
||||
let state = self.backend.state_at(at_hash)?;
|
||||
|
||||
let call_context = match context {
|
||||
ExecutionContext::OffchainCall(_) => CallContext::Offchain,
|
||||
_ => CallContext::Onchain,
|
||||
};
|
||||
|
||||
let (execution_manager, extensions) =
|
||||
self.execution_extensions.manager_and_extensions(at_hash, at_number, context);
|
||||
|
||||
let changes = &mut *changes.borrow_mut();
|
||||
|
||||
// It is important to extract the runtime code here before we create the proof
|
||||
@@ -236,6 +217,7 @@ where
|
||||
let runtime_code =
|
||||
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
|
||||
let runtime_code = self.check_override(runtime_code, &state, at_hash)?.0;
|
||||
let mut extensions = extensions.borrow_mut();
|
||||
|
||||
match recorder {
|
||||
Some(recorder) => {
|
||||
@@ -251,13 +233,13 @@ where
|
||||
&self.executor,
|
||||
method,
|
||||
call_data,
|
||||
extensions,
|
||||
&mut extensions,
|
||||
&runtime_code,
|
||||
call_context,
|
||||
)
|
||||
.with_storage_transaction_cache(storage_transaction_cache.as_deref_mut())
|
||||
.set_parent_hash(at_hash);
|
||||
state_machine.execute_using_consensus_failure_handler(execution_manager)
|
||||
state_machine.execute()
|
||||
},
|
||||
None => {
|
||||
let mut state_machine = StateMachine::new(
|
||||
@@ -266,13 +248,13 @@ where
|
||||
&self.executor,
|
||||
method,
|
||||
call_data,
|
||||
extensions,
|
||||
&mut extensions,
|
||||
&runtime_code,
|
||||
call_context,
|
||||
)
|
||||
.with_storage_transaction_cache(storage_transaction_cache.as_deref_mut())
|
||||
.set_parent_hash(at_hash);
|
||||
state_machine.execute_using_consensus_failure_handler(execution_manager)
|
||||
state_machine.execute()
|
||||
},
|
||||
}
|
||||
.map_err(Into::into)
|
||||
@@ -311,11 +293,7 @@ where
|
||||
method,
|
||||
call_data,
|
||||
&runtime_code,
|
||||
self.execution_extensions.extensions(
|
||||
at_hash,
|
||||
at_number,
|
||||
ExecutionContext::OffchainCall(None),
|
||||
),
|
||||
&mut self.execution_extensions.extensions(at_hash, at_number),
|
||||
)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
@@ -411,7 +389,6 @@ mod tests {
|
||||
backend.clone(),
|
||||
executor.clone(),
|
||||
genesis_block_builder,
|
||||
None,
|
||||
Box::new(TaskExecutor::new()),
|
||||
None,
|
||||
None,
|
||||
@@ -430,8 +407,6 @@ mod tests {
|
||||
)
|
||||
.unwrap(),
|
||||
execution_extensions: Arc::new(ExecutionExtensions::new(
|
||||
Default::default(),
|
||||
None,
|
||||
None,
|
||||
Arc::new(executor.clone()),
|
||||
)),
|
||||
@@ -486,7 +461,6 @@ mod tests {
|
||||
backend.clone(),
|
||||
executor.clone(),
|
||||
genesis_block_builder,
|
||||
None,
|
||||
Box::new(TaskExecutor::new()),
|
||||
None,
|
||||
None,
|
||||
|
||||
@@ -62,10 +62,8 @@ use sp_core::{
|
||||
well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, StorageChild, StorageData,
|
||||
StorageKey,
|
||||
},
|
||||
traits::SpawnNamed,
|
||||
traits::{CallContext, SpawnNamed},
|
||||
};
|
||||
#[cfg(feature = "test-helpers")]
|
||||
use sp_keystore::KeystorePtr;
|
||||
use sp_runtime::{
|
||||
generic::{BlockId, SignedBlock},
|
||||
traits::{
|
||||
@@ -161,7 +159,6 @@ pub fn new_in_mem<E, Block, G, RA>(
|
||||
backend: Arc<in_mem::Backend<Block>>,
|
||||
executor: E,
|
||||
genesis_block_builder: G,
|
||||
keystore: Option<KeystorePtr>,
|
||||
prometheus_registry: Option<Registry>,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
spawn_handle: Box<dyn SpawnNamed>,
|
||||
@@ -181,7 +178,6 @@ where
|
||||
backend,
|
||||
executor,
|
||||
genesis_block_builder,
|
||||
keystore,
|
||||
spawn_handle,
|
||||
prometheus_registry,
|
||||
telemetry,
|
||||
@@ -224,7 +220,6 @@ pub fn new_with_backend<B, E, Block, G, RA>(
|
||||
backend: Arc<B>,
|
||||
executor: E,
|
||||
genesis_block_builder: G,
|
||||
keystore: Option<KeystorePtr>,
|
||||
spawn_handle: Box<dyn SpawnNamed>,
|
||||
prometheus_registry: Option<Registry>,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
@@ -239,12 +234,7 @@ where
|
||||
Block: BlockT,
|
||||
B: backend::LocalBackend<Block> + 'static,
|
||||
{
|
||||
let extensions = ExecutionExtensions::new(
|
||||
Default::default(),
|
||||
keystore,
|
||||
sc_offchain::OffchainDb::factory_from_backend(&*backend),
|
||||
Arc::new(executor.clone()),
|
||||
);
|
||||
let extensions = ExecutionExtensions::new(None, Arc::new(executor.clone()));
|
||||
|
||||
let call_executor =
|
||||
LocalCallExecutor::new(backend.clone(), executor, config.clone(), extensions)?;
|
||||
@@ -875,12 +865,12 @@ where
|
||||
// We should enact state, but don't have any storage changes, so we need to execute the
|
||||
// block.
|
||||
(true, None, Some(ref body)) => {
|
||||
let runtime_api = self.runtime_api();
|
||||
let execution_context = import_block.origin.into();
|
||||
let mut runtime_api = self.runtime_api();
|
||||
|
||||
runtime_api.execute_block_with_context(
|
||||
runtime_api.set_call_context(CallContext::Onchain);
|
||||
|
||||
runtime_api.execute_block(
|
||||
*parent_hash,
|
||||
execution_context,
|
||||
Block::new(import_block.header.clone(), body.clone()),
|
||||
)?;
|
||||
|
||||
@@ -1727,7 +1717,8 @@ where
|
||||
params.overlayed_changes,
|
||||
Some(params.storage_transaction_cache),
|
||||
params.recorder,
|
||||
params.context,
|
||||
params.call_context,
|
||||
params.extensions,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
@@ -1739,6 +1730,18 @@ where
|
||||
fn state_at(&self, at: Block::Hash) -> Result<Self::StateBackend, sp_api::ApiError> {
|
||||
self.state_at(at).map_err(Into::into)
|
||||
}
|
||||
|
||||
fn initialize_extensions(
|
||||
&self,
|
||||
at: Block::Hash,
|
||||
extensions: &mut sp_externalities::Extensions,
|
||||
) -> Result<(), sp_api::ApiError> {
|
||||
let block_number = self.expect_block_number_from_id(&BlockId::Hash(at))?;
|
||||
|
||||
extensions.merge(self.executor.execution_extensions().extensions(at, block_number));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// NOTE: only use this implementation when you are sure there are NO consensus-level BlockImport
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
//! Service configuration.
|
||||
|
||||
pub use sc_client_api::execution_extensions::{ExecutionStrategies, ExecutionStrategy};
|
||||
pub use sc_client_db::{BlocksPruning, Database, DatabaseSource, PruningMode};
|
||||
pub use sc_executor::{WasmExecutionMethod, WasmtimeInstantiationStrategy};
|
||||
pub use sc_network::{
|
||||
@@ -81,8 +80,6 @@ pub struct Configuration {
|
||||
/// over on-chain runtimes when the spec version matches. Set to `None` to
|
||||
/// disable overrides (default).
|
||||
pub wasm_runtime_overrides: Option<PathBuf>,
|
||||
/// Execution strategies.
|
||||
pub execution_strategies: ExecutionStrategies,
|
||||
/// JSON-RPC server binding address.
|
||||
pub rpc_addr: Option<SocketAddr>,
|
||||
/// Maximum number of connections for JSON-RPC server.
|
||||
|
||||
@@ -55,8 +55,8 @@ use sp_runtime::{
|
||||
|
||||
pub use self::{
|
||||
builder::{
|
||||
build_network, build_offchain_workers, new_client, new_db_backend, new_full_client,
|
||||
new_full_parts, new_full_parts_with_genesis_builder, new_native_or_wasm_executor,
|
||||
build_network, new_client, new_db_backend, new_full_client, new_full_parts,
|
||||
new_full_parts_with_genesis_builder, new_native_or_wasm_executor, new_wasm_executor,
|
||||
spawn_tasks, BuildNetworkParams, KeystoreContainer, NetworkStarter, SpawnTasksParams,
|
||||
TFullBackend, TFullCallExecutor, TFullClient,
|
||||
},
|
||||
|
||||
@@ -37,9 +37,7 @@ use sp_runtime::{
|
||||
traits::{BlakeTwo256, Block as BlockT, Header as HeaderT},
|
||||
ConsensusEngineId, Justifications, StateVersion,
|
||||
};
|
||||
use sp_state_machine::{
|
||||
backend::Backend as _, ExecutionStrategy, InMemoryBackend, OverlayedChanges, StateMachine,
|
||||
};
|
||||
use sp_state_machine::{backend::Backend as _, InMemoryBackend, OverlayedChanges, StateMachine};
|
||||
use sp_storage::{ChildInfo, StorageKey};
|
||||
use sp_trie::{LayoutV0, TrieConfiguration};
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
@@ -90,11 +88,11 @@ fn construct_block(
|
||||
&new_native_or_wasm_executor(),
|
||||
"Core_initialize_block",
|
||||
&header.encode(),
|
||||
Default::default(),
|
||||
&mut Default::default(),
|
||||
&runtime_code,
|
||||
CallContext::Onchain,
|
||||
)
|
||||
.execute(ExecutionStrategy::NativeElseWasm)
|
||||
.execute()
|
||||
.unwrap();
|
||||
|
||||
for tx in transactions.iter() {
|
||||
@@ -104,11 +102,11 @@ fn construct_block(
|
||||
&new_native_or_wasm_executor(),
|
||||
"BlockBuilder_apply_extrinsic",
|
||||
&tx.encode(),
|
||||
Default::default(),
|
||||
&mut Default::default(),
|
||||
&runtime_code,
|
||||
CallContext::Onchain,
|
||||
)
|
||||
.execute(ExecutionStrategy::NativeElseWasm)
|
||||
.execute()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -118,11 +116,11 @@ fn construct_block(
|
||||
&new_native_or_wasm_executor(),
|
||||
"BlockBuilder_finalize_block",
|
||||
&[],
|
||||
Default::default(),
|
||||
&mut Default::default(),
|
||||
&runtime_code,
|
||||
CallContext::Onchain,
|
||||
)
|
||||
.execute(ExecutionStrategy::NativeElseWasm)
|
||||
.execute()
|
||||
.unwrap();
|
||||
header = Header::decode(&mut &ret_data[..]).unwrap();
|
||||
|
||||
@@ -189,11 +187,11 @@ fn construct_genesis_should_work_with_native() {
|
||||
&new_native_or_wasm_executor(),
|
||||
"Core_execute_block",
|
||||
&b1data,
|
||||
Default::default(),
|
||||
&mut Default::default(),
|
||||
&runtime_code,
|
||||
CallContext::Onchain,
|
||||
)
|
||||
.execute(ExecutionStrategy::NativeElseWasm)
|
||||
.execute()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -220,11 +218,11 @@ fn construct_genesis_should_work_with_wasm() {
|
||||
&new_native_or_wasm_executor(),
|
||||
"Core_execute_block",
|
||||
&b1data,
|
||||
Default::default(),
|
||||
&mut Default::default(),
|
||||
&runtime_code,
|
||||
CallContext::Onchain,
|
||||
)
|
||||
.execute(ExecutionStrategy::AlwaysWasm)
|
||||
.execute()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -1670,22 +1668,21 @@ fn storage_keys_prefix_and_start_key_works() {
|
||||
|
||||
let block_hash = client.info().best_hash;
|
||||
|
||||
let child_root = b":child_storage:default:child".to_vec();
|
||||
let child_root = array_bytes::bytes2hex("", b":child_storage:default:child");
|
||||
let prefix = StorageKey(array_bytes::hex2bytes_unchecked("3a"));
|
||||
let child_prefix = StorageKey(b"sec".to_vec());
|
||||
|
||||
let res: Vec<_> = client
|
||||
.storage_keys(block_hash, Some(&prefix), None)
|
||||
.unwrap()
|
||||
.map(|x| x.0)
|
||||
.map(|x| array_bytes::bytes2hex("", &x.0))
|
||||
.collect();
|
||||
assert_eq!(
|
||||
res,
|
||||
[
|
||||
child_root.clone(),
|
||||
array_bytes::hex2bytes_unchecked("3a636f6465"), //":code"
|
||||
array_bytes::hex2bytes_unchecked("3a65787472696e7369635f696e646578"), //":extrinsic_index"
|
||||
array_bytes::hex2bytes_unchecked("3a686561707061676573"), //":heappages"
|
||||
&child_root,
|
||||
"3a636f6465", //":code"
|
||||
"3a65787472696e7369635f696e646578", //":extrinsic_index"
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1696,15 +1693,9 @@ fn storage_keys_prefix_and_start_key_works() {
|
||||
Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a636f6465"))),
|
||||
)
|
||||
.unwrap()
|
||||
.map(|x| x.0)
|
||||
.map(|x| array_bytes::bytes2hex("", &x.0))
|
||||
.collect();
|
||||
assert_eq!(
|
||||
res,
|
||||
[
|
||||
array_bytes::hex2bytes_unchecked("3a65787472696e7369635f696e646578"),
|
||||
array_bytes::hex2bytes_unchecked("3a686561707061676573")
|
||||
]
|
||||
);
|
||||
assert_eq!(res, ["3a65787472696e7369635f696e646578",]);
|
||||
|
||||
let res: Vec<_> = client
|
||||
.storage_keys(
|
||||
@@ -1737,7 +1728,7 @@ fn storage_keys_works() {
|
||||
sp_tracing::try_init_simple();
|
||||
|
||||
let expected_keys =
|
||||
substrate_test_runtime::storage_key_generator::get_expected_storage_hashed_keys();
|
||||
substrate_test_runtime::storage_key_generator::get_expected_storage_hashed_keys(false);
|
||||
|
||||
let client = substrate_test_runtime_client::new();
|
||||
let block_hash = client.info().best_hash;
|
||||
@@ -1776,10 +1767,10 @@ fn storage_keys_works() {
|
||||
res,
|
||||
expected_keys
|
||||
.iter()
|
||||
.filter(|&i| i > &"3a636f64".to_string())
|
||||
.filter(|&i| *i > "3a636f64")
|
||||
.take(8)
|
||||
.cloned()
|
||||
.collect::<Vec<String>>()
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
// Starting at a complete key the first key is skipped.
|
||||
@@ -1797,10 +1788,10 @@ fn storage_keys_works() {
|
||||
res,
|
||||
expected_keys
|
||||
.iter()
|
||||
.filter(|&i| i > &"3a636f6465".to_string())
|
||||
.filter(|&i| *i > "3a636f6465")
|
||||
.take(8)
|
||||
.cloned()
|
||||
.collect::<Vec<String>>()
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
const SOME_BALANCE_KEY : &str = "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e2c1dc507e2035edbbd8776c440d870460c57f0008067cc01c5ff9eb2e2f9b3a94299a915a91198bd1021a6c55596f57";
|
||||
@@ -1818,10 +1809,10 @@ fn storage_keys_works() {
|
||||
res,
|
||||
expected_keys
|
||||
.iter()
|
||||
.filter(|&i| i > &SOME_BALANCE_KEY.to_string())
|
||||
.filter(|&i| *i > SOME_BALANCE_KEY)
|
||||
.take(8)
|
||||
.cloned()
|
||||
.collect::<Vec<String>>()
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1850,7 +1841,6 @@ fn cleans_up_closed_notification_sinks_on_block_import() {
|
||||
genesis_block_builder,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Box::new(TaskExecutor::new()),
|
||||
client_config,
|
||||
)
|
||||
|
||||
@@ -245,7 +245,6 @@ fn node_config<
|
||||
chain_spec: Box::new((*spec).clone()),
|
||||
wasm_method: Default::default(),
|
||||
wasm_runtime_overrides: Default::default(),
|
||||
execution_strategies: Default::default(),
|
||||
rpc_addr: Default::default(),
|
||||
rpc_max_connections: Default::default(),
|
||||
rpc_cors: None,
|
||||
|
||||
@@ -59,7 +59,9 @@ use sp_blockchain::HeaderBackend;
|
||||
use sp_core::{hexdisplay::HexDisplay, traits::SpawnNamed, Decode, Encode};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use sp_statement_store::{
|
||||
runtime_api::{InvalidStatement, StatementSource, ValidStatement, ValidateStatement},
|
||||
runtime_api::{
|
||||
InvalidStatement, StatementSource, StatementStoreExt, ValidStatement, ValidateStatement,
|
||||
},
|
||||
AccountId, BlockHash, Channel, DecryptionKey, Hash, NetworkPriority, Proof, Result, Statement,
|
||||
SubmitResult, Topic,
|
||||
};
|
||||
@@ -491,8 +493,7 @@ impl Store {
|
||||
+ 'static,
|
||||
Client::Api: ValidateStatement<Block>,
|
||||
{
|
||||
let store = Arc::new(Self::new(path, options, client.clone(), prometheus)?);
|
||||
client.execution_extensions().register_statement_store(store.clone());
|
||||
let store = Arc::new(Self::new(path, options, client, prometheus)?);
|
||||
|
||||
// Perform periodic statement store maintenance
|
||||
let worker_store = store.clone();
|
||||
@@ -696,6 +697,11 @@ impl Store {
|
||||
fn set_time(&mut self, time: u64) {
|
||||
self.time_override = Some(time);
|
||||
}
|
||||
|
||||
/// Returns `self` as [`StatementStoreExt`].
|
||||
pub fn as_statement_store_ext(self: Arc<Self>) -> StatementStoreExt {
|
||||
StatementStoreExt::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl StatementStore for Store {
|
||||
|
||||
@@ -29,12 +29,7 @@ use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, Member, NumberFor},
|
||||
};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
hash::Hash,
|
||||
pin::Pin,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::{collections::HashMap, hash::Hash, marker::PhantomData, pin::Pin, sync::Arc};
|
||||
|
||||
const LOG_TARGET: &str = "txpool::api";
|
||||
|
||||
@@ -354,6 +349,22 @@ pub trait LocalTransactionPool: Send + Sync {
|
||||
) -> Result<Self::Hash, Self::Error>;
|
||||
}
|
||||
|
||||
impl<T: LocalTransactionPool> LocalTransactionPool for Arc<T> {
|
||||
type Block = T::Block;
|
||||
|
||||
type Hash = T::Hash;
|
||||
|
||||
type Error = T::Error;
|
||||
|
||||
fn submit_local(
|
||||
&self,
|
||||
at: <Self::Block as BlockT>::Hash,
|
||||
xt: LocalTransactionFor<Self>,
|
||||
) -> Result<Self::Hash, Self::Error> {
|
||||
(**self).submit_local(at, xt)
|
||||
}
|
||||
}
|
||||
|
||||
/// An abstraction for [`LocalTransactionPool`]
|
||||
///
|
||||
/// We want to use a transaction pool in [`OffchainTransactionPoolFactory`] in a `Arc` without
|
||||
@@ -396,15 +407,13 @@ impl<TPool: LocalTransactionPool> OffchainSubmitTransaction<TPool::Block> for TP
|
||||
/// the wasm execution environment to send transactions from an offchain call to the runtime.
|
||||
#[derive(Clone)]
|
||||
pub struct OffchainTransactionPoolFactory<Block: BlockT> {
|
||||
// To break retain cycle between `Client` and `TransactionPool` we require this
|
||||
// extension to be a `Weak` reference.
|
||||
pool: Weak<dyn OffchainSubmitTransaction<Block>>,
|
||||
pool: Arc<dyn OffchainSubmitTransaction<Block>>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> OffchainTransactionPoolFactory<Block> {
|
||||
/// Creates a new instance using the given `tx_pool`.
|
||||
pub fn new<T: LocalTransactionPool<Block = Block> + 'static>(tx_pool: &Arc<T>) -> Self {
|
||||
Self { pool: Arc::downgrade(tx_pool) as Weak<_> }
|
||||
pub fn new<T: LocalTransactionPool<Block = Block> + 'static>(tx_pool: T) -> Self {
|
||||
Self { pool: Arc::new(tx_pool) as Arc<_> }
|
||||
}
|
||||
|
||||
/// Returns an instance of [`TransactionPoolExt`] bound to the given `block_hash`.
|
||||
@@ -419,7 +428,7 @@ impl<Block: BlockT> OffchainTransactionPoolFactory<Block> {
|
||||
/// Wraps a `pool` and `block_hash` to implement [`sp_core::offchain::TransactionPool`].
|
||||
struct OffchainTransactionPool<Block: BlockT> {
|
||||
block_hash: Block::Hash,
|
||||
pool: Weak<dyn OffchainSubmitTransaction<Block>>,
|
||||
pool: Arc<dyn OffchainSubmitTransaction<Block>>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> sp_core::offchain::TransactionPool for OffchainTransactionPool<Block> {
|
||||
@@ -436,7 +445,7 @@ impl<Block: BlockT> sp_core::offchain::TransactionPool for OffchainTransactionPo
|
||||
},
|
||||
};
|
||||
|
||||
self.pool.upgrade().ok_or(())?.submit_at(self.block_hash, extrinsic)
|
||||
self.pool.submit_at(self.block_hash, extrinsic)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,6 +472,29 @@ mod v1_compatible {
|
||||
}
|
||||
}
|
||||
|
||||
/// Transaction pool that rejects all submitted transactions.
|
||||
///
|
||||
/// Could be used for example in tests.
|
||||
pub struct RejectAllTxPool<Block>(PhantomData<Block>);
|
||||
|
||||
impl<Block> Default for RejectAllTxPool<Block> {
|
||||
fn default() -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT> LocalTransactionPool for RejectAllTxPool<Block> {
|
||||
type Block = Block;
|
||||
|
||||
type Hash = Block::Hash;
|
||||
|
||||
type Error = error::Error;
|
||||
|
||||
fn submit_local(&self, _: Block::Hash, _: Block::Extrinsic) -> Result<Self::Hash, Self::Error> {
|
||||
Err(error::Error::ImmediatelyDropped)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -52,8 +52,8 @@ use std::{
|
||||
use graph::{ExtrinsicHash, IsValidator};
|
||||
use sc_transaction_pool_api::{
|
||||
error::Error as TxPoolError, ChainEvent, ImportNotificationStream, MaintainedTransactionPool,
|
||||
OffchainTransactionPoolFactory, PoolFuture, PoolStatus, ReadyTransactions, TransactionFor,
|
||||
TransactionPool, TransactionSource, TransactionStatusStreamFor, TxHash,
|
||||
PoolFuture, PoolStatus, ReadyTransactions, TransactionFor, TransactionPool, TransactionSource,
|
||||
TransactionStatusStreamFor, TxHash,
|
||||
};
|
||||
use sp_core::traits::SpawnEssentialNamed;
|
||||
use sp_runtime::{
|
||||
@@ -396,11 +396,6 @@ where
|
||||
client.usage_info().chain.finalized_hash,
|
||||
));
|
||||
|
||||
// make transaction pool available for off-chain runtime calls.
|
||||
client
|
||||
.execution_extensions()
|
||||
.register_transaction_pool_factory(OffchainTransactionPoolFactory::new(&pool));
|
||||
|
||||
pool
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +175,6 @@ Then you can run a benchmark like so:
|
||||
```bash
|
||||
./target/production/substrate benchmark pallet \
|
||||
--chain dev \ # Configurable Chain Spec
|
||||
--execution=wasm \ # Always test with Wasm
|
||||
--wasm-execution=compiled \ # Always used `wasm-time`
|
||||
--pallet pallet_balances \ # Select the pallet
|
||||
--extrinsic transfer \ # Select the extrinsic
|
||||
|
||||
Generated
-1
@@ -35,7 +35,6 @@
|
||||
// --no-median-slopes
|
||||
// --no-min-squares
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --output=./frame/nfts/src/weights.rs
|
||||
|
||||
@@ -18,6 +18,7 @@ sp-api-proc-macro = { version = "4.0.0-dev", path = "proc-macro" }
|
||||
sp-core = { version = "21.0.0", default-features = false, path = "../core" }
|
||||
sp-std = { version = "8.0.0", default-features = false, path = "../std" }
|
||||
sp-runtime = { version = "24.0.0", default-features = false, path = "../runtime" }
|
||||
sp-externalities = { version = "0.19.0", default-features = false, optional = true, path = "../externalities" }
|
||||
sp-version = { version = "22.0.0", default-features = false, path = "../version" }
|
||||
sp-state-machine = { version = "0.28.0", default-features = false, optional = true, path = "../state-machine" }
|
||||
sp-trie = { version = "22.0.0", default-features = false, optional = true, path = "../trie" }
|
||||
@@ -35,6 +36,7 @@ default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"sp-core/std",
|
||||
"sp-externalities",
|
||||
"sp-std/std",
|
||||
"sp-runtime/std",
|
||||
"sp-state-machine/std",
|
||||
|
||||
@@ -315,7 +315,6 @@ impl<'a> ToClientSideDecl<'a> {
|
||||
fn __runtime_api_internal_call_api_at(
|
||||
&self,
|
||||
at: #block_hash,
|
||||
context: #crate_::ExecutionContext,
|
||||
params: std::vec::Vec<u8>,
|
||||
fn_name: &dyn Fn(#crate_::RuntimeVersion) -> &'static str,
|
||||
) -> std::result::Result<std::vec::Vec<u8>, #crate_::ApiError>;
|
||||
@@ -335,9 +334,8 @@ impl<'a> ToClientSideDecl<'a> {
|
||||
|
||||
items.into_iter().for_each(|i| match i {
|
||||
TraitItem::Fn(method) => {
|
||||
let (fn_decl, fn_decl_ctx) = self.fold_trait_item_fn(method, trait_generics_num);
|
||||
let fn_decl = self.create_method_decl(method, trait_generics_num);
|
||||
result.push(fn_decl.into());
|
||||
result.push(fn_decl_ctx.into());
|
||||
},
|
||||
r => result.push(r),
|
||||
});
|
||||
@@ -345,41 +343,12 @@ impl<'a> ToClientSideDecl<'a> {
|
||||
result
|
||||
}
|
||||
|
||||
fn fold_trait_item_fn(
|
||||
&mut self,
|
||||
method: TraitItemFn,
|
||||
trait_generics_num: usize,
|
||||
) -> (TraitItemFn, TraitItemFn) {
|
||||
let crate_ = self.crate_;
|
||||
let context = quote!( #crate_::ExecutionContext::OffchainCall(None) );
|
||||
let fn_decl = self.create_method_decl(method.clone(), context, trait_generics_num);
|
||||
let fn_decl_ctx = self.create_method_decl_with_context(method, trait_generics_num);
|
||||
|
||||
(fn_decl, fn_decl_ctx)
|
||||
}
|
||||
|
||||
fn create_method_decl_with_context(
|
||||
&mut self,
|
||||
method: TraitItemFn,
|
||||
trait_generics_num: usize,
|
||||
) -> TraitItemFn {
|
||||
let crate_ = self.crate_;
|
||||
let context_arg: syn::FnArg = parse_quote!( context: #crate_::ExecutionContext );
|
||||
let mut fn_decl_ctx = self.create_method_decl(method, quote!(context), trait_generics_num);
|
||||
fn_decl_ctx.sig.ident =
|
||||
Ident::new(&format!("{}_with_context", &fn_decl_ctx.sig.ident), Span::call_site());
|
||||
fn_decl_ctx.sig.inputs.insert(2, context_arg);
|
||||
|
||||
fn_decl_ctx
|
||||
}
|
||||
|
||||
/// Takes the method declared by the user and creates the declaration we require for the runtime
|
||||
/// api client side. This method will call by default the `method_runtime_api_impl` for doing
|
||||
/// the actual call into the runtime.
|
||||
fn create_method_decl(
|
||||
&mut self,
|
||||
mut method: TraitItemFn,
|
||||
context: TokenStream,
|
||||
trait_generics_num: usize,
|
||||
) -> TraitItemFn {
|
||||
let params = match extract_parameter_names_types_and_borrows(
|
||||
@@ -467,7 +436,6 @@ impl<'a> ToClientSideDecl<'a> {
|
||||
<Self as #trait_name<#( #underscores ),*>>::__runtime_api_internal_call_api_at(
|
||||
self,
|
||||
__runtime_api_at_param__,
|
||||
#context,
|
||||
__runtime_api_impl_params_encoded__,
|
||||
&|_version| {
|
||||
#(
|
||||
|
||||
@@ -224,8 +224,8 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
||||
|
||||
Ok(quote!(
|
||||
pub struct RuntimeApi {}
|
||||
/// Implements all runtime apis for the client side.
|
||||
#crate_::std_enabled! {
|
||||
/// Implements all runtime apis for the client side.
|
||||
pub struct RuntimeApiImpl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block> + 'static> {
|
||||
call: &'static C,
|
||||
transaction_depth: std::cell::RefCell<u16>,
|
||||
@@ -234,6 +234,9 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
||||
#crate_::StorageTransactionCache<Block, C::StateBackend>
|
||||
>,
|
||||
recorder: std::option::Option<#crate_::ProofRecorder<Block>>,
|
||||
call_context: #crate_::CallContext,
|
||||
extensions: std::cell::RefCell<#crate_::Extensions>,
|
||||
extensions_generated_for: std::cell::RefCell<std::option::Option<Block::Hash>>,
|
||||
}
|
||||
|
||||
impl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block>> #crate_::ApiExt<Block> for
|
||||
@@ -321,6 +324,14 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
||||
state_version,
|
||||
)
|
||||
}
|
||||
|
||||
fn set_call_context(&mut self, call_context: #crate_::CallContext) {
|
||||
self.call_context = call_context;
|
||||
}
|
||||
|
||||
fn register_extension<E: #crate_::Extension>(&mut self, extension: E) {
|
||||
std::cell::RefCell::borrow_mut(&self.extensions).register(extension);
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: #crate_::BlockT, C> #crate_::ConstructRuntimeApi<Block, C>
|
||||
@@ -339,6 +350,9 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
||||
changes: std::default::Default::default(),
|
||||
recorder: std::default::Default::default(),
|
||||
storage_transaction_cache: std::default::Default::default(),
|
||||
call_context: #crate_::CallContext::Offchain,
|
||||
extensions: std::default::Default::default(),
|
||||
extensions_generated_for: std::default::Default::default(),
|
||||
}.into()
|
||||
}
|
||||
}
|
||||
@@ -480,7 +494,6 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> {
|
||||
fn __runtime_api_internal_call_api_at(
|
||||
&self,
|
||||
at: <__SrApiBlock__ as #crate_::BlockT>::Hash,
|
||||
context: #crate_::ExecutionContext,
|
||||
params: std::vec::Vec<u8>,
|
||||
fn_name: &dyn Fn(#crate_::RuntimeVersion) -> &'static str,
|
||||
) -> std::result::Result<std::vec::Vec<u8>, #crate_::ApiError> {
|
||||
@@ -498,14 +511,34 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> {
|
||||
at,
|
||||
)?;
|
||||
|
||||
match &mut *std::cell::RefCell::borrow_mut(&self.extensions_generated_for) {
|
||||
Some(generated_for) => {
|
||||
if *generated_for != at {
|
||||
return std::result::Result::Err(
|
||||
#crate_::ApiError::UsingSameInstanceForDifferentBlocks
|
||||
)
|
||||
}
|
||||
},
|
||||
generated_for @ None => {
|
||||
#crate_::CallApiAt::<__SrApiBlock__>::initialize_extensions(
|
||||
self.call,
|
||||
at,
|
||||
&mut std::cell::RefCell::borrow_mut(&self.extensions),
|
||||
)?;
|
||||
|
||||
*generated_for = Some(at);
|
||||
}
|
||||
}
|
||||
|
||||
let params = #crate_::CallApiAtParams {
|
||||
at,
|
||||
function: (*fn_name)(version),
|
||||
arguments: params,
|
||||
overlayed_changes: &self.changes,
|
||||
storage_transaction_cache: &self.storage_transaction_cache,
|
||||
context,
|
||||
call_context: self.call_context,
|
||||
recorder: &self.recorder,
|
||||
extensions: &self.extensions,
|
||||
};
|
||||
|
||||
#crate_::CallApiAt::<__SrApiBlock__>::call_api_at(
|
||||
|
||||
@@ -121,13 +121,20 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result<To
|
||||
> where Self: Sized {
|
||||
unimplemented!("`into_storage_changes` not implemented for runtime api mocks")
|
||||
}
|
||||
|
||||
fn set_call_context(&mut self, _: #crate_::CallContext) {
|
||||
unimplemented!("`set_call_context` not implemented for runtime api mocks")
|
||||
}
|
||||
|
||||
fn register_extension<E: #crate_::Extension>(&mut self, _: E) {
|
||||
unimplemented!("`register_extension` not implemented for runtime api mocks")
|
||||
}
|
||||
}
|
||||
|
||||
impl #crate_::Core<#block_type> for #self_ty {
|
||||
fn __runtime_api_internal_call_api_at(
|
||||
&self,
|
||||
_: <#block_type as #crate_::BlockT>::Hash,
|
||||
_: #crate_::ExecutionContext,
|
||||
_: std::vec::Vec<u8>,
|
||||
_: &dyn Fn(#crate_::RuntimeVersion) -> &'static str,
|
||||
) -> std::result::Result<std::vec::Vec<u8>, #crate_::ApiError> {
|
||||
@@ -141,14 +148,6 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result<To
|
||||
unimplemented!("`Core::version` not implemented for runtime api mocks")
|
||||
}
|
||||
|
||||
fn version_with_context(
|
||||
&self,
|
||||
_: <#block_type as #crate_::BlockT>::Hash,
|
||||
_: #crate_::ExecutionContext,
|
||||
) -> std::result::Result<#crate_::RuntimeVersion, #crate_::ApiError> {
|
||||
unimplemented!("`Core::version` not implemented for runtime api mocks")
|
||||
}
|
||||
|
||||
fn execute_block(
|
||||
&self,
|
||||
_: <#block_type as #crate_::BlockT>::Hash,
|
||||
@@ -157,15 +156,6 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result<To
|
||||
unimplemented!("`Core::execute_block` not implemented for runtime api mocks")
|
||||
}
|
||||
|
||||
fn execute_block_with_context(
|
||||
&self,
|
||||
_: <#block_type as #crate_::BlockT>::Hash,
|
||||
_: #crate_::ExecutionContext,
|
||||
_: #block_type,
|
||||
) -> std::result::Result<(), #crate_::ApiError> {
|
||||
unimplemented!("`Core::execute_block` not implemented for runtime api mocks")
|
||||
}
|
||||
|
||||
fn initialize_block(
|
||||
&self,
|
||||
_: <#block_type as #crate_::BlockT>::Hash,
|
||||
@@ -173,15 +163,6 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result<To
|
||||
) -> std::result::Result<(), #crate_::ApiError> {
|
||||
unimplemented!("`Core::initialize_block` not implemented for runtime api mocks")
|
||||
}
|
||||
|
||||
fn initialize_block_with_context(
|
||||
&self,
|
||||
_: <#block_type as #crate_::BlockT>::Hash,
|
||||
_: #crate_::ExecutionContext,
|
||||
_: &<#block_type as #crate_::BlockT>::Header,
|
||||
) -> std::result::Result<(), #crate_::ApiError> {
|
||||
unimplemented!("`Core::initialize_block` not implemented for runtime api mocks")
|
||||
}
|
||||
}
|
||||
))
|
||||
}
|
||||
@@ -255,26 +236,12 @@ impl<'a> FoldRuntimeApiImpl<'a> {
|
||||
|
||||
let crate_ = generate_crate_access();
|
||||
|
||||
// We also need to overwrite all the `_with_context` methods. To do this,
|
||||
// we clone all methods and add them again with the new name plus one more argument.
|
||||
impl_item.items.extend(impl_item.items.clone().into_iter().filter_map(|i| {
|
||||
if let syn::ImplItem::Fn(mut m) = i {
|
||||
m.sig.ident = quote::format_ident!("{}_with_context", m.sig.ident);
|
||||
m.sig.inputs.insert(2, parse_quote!( _: #crate_::ExecutionContext ));
|
||||
|
||||
Some(m.into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}));
|
||||
|
||||
let block_type = self.block_type;
|
||||
|
||||
impl_item.items.push(parse_quote! {
|
||||
fn __runtime_api_internal_call_api_at(
|
||||
&self,
|
||||
_: <#block_type as #crate_::BlockT>::Hash,
|
||||
_: #crate_::ExecutionContext,
|
||||
_: std::vec::Vec<u8>,
|
||||
_: &dyn Fn(#crate_::RuntimeVersion) -> &'static str,
|
||||
) -> std::result::Result<std::vec::Vec<u8>, #crate_::ApiError> {
|
||||
|
||||
@@ -78,11 +78,17 @@ pub use hash_db::Hasher;
|
||||
#[doc(hidden)]
|
||||
pub use scale_info;
|
||||
#[doc(hidden)]
|
||||
pub use sp_core::offchain;
|
||||
#[doc(hidden)]
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub use sp_core::to_substrate_wasm_fn_return_value;
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "std")]
|
||||
pub use sp_core::traits::CallContext;
|
||||
use sp_core::OpaqueMetadata;
|
||||
#[doc(hidden)]
|
||||
pub use sp_core::{offchain, ExecutionContext};
|
||||
#[cfg(feature = "std")]
|
||||
pub use sp_externalities::{Extension, Extensions};
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "frame-metadata")]
|
||||
pub use sp_metadata_ir::{self as metadata_ir, frame_metadata as metadata};
|
||||
@@ -518,6 +524,8 @@ pub enum ApiError {
|
||||
Application(#[from] Box<dyn std::error::Error + Send + Sync>),
|
||||
#[error("Api called for an unknown Block: {0}")]
|
||||
UnknownBlock(String),
|
||||
#[error("Using the same api instance to call into multiple independent blocks.")]
|
||||
UsingSameInstanceForDifferentBlocks,
|
||||
}
|
||||
|
||||
/// Extends the runtime api implementation with some common functionality.
|
||||
@@ -581,6 +589,12 @@ pub trait ApiExt<Block: BlockT> {
|
||||
) -> Result<StorageChanges<Self::StateBackend, Block>, String>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Set the [`CallContext`] to be used by the runtime api calls done by this instance.
|
||||
fn set_call_context(&mut self, call_context: CallContext);
|
||||
|
||||
/// Register an [`Extension`] that will be accessible while executing a runtime api call.
|
||||
fn register_extension<E: Extension>(&mut self, extension: E);
|
||||
}
|
||||
|
||||
/// Parameters for [`CallApiAt::call_api_at`].
|
||||
@@ -596,10 +610,12 @@ pub struct CallApiAtParams<'a, Block: BlockT, Backend: StateBackend<HashFor<Bloc
|
||||
pub overlayed_changes: &'a RefCell<OverlayedChanges>,
|
||||
/// The cache for storage transactions.
|
||||
pub storage_transaction_cache: &'a RefCell<StorageTransactionCache<Block, Backend>>,
|
||||
/// The context this function is executed in.
|
||||
pub context: ExecutionContext,
|
||||
/// The call context of this call.
|
||||
pub call_context: CallContext,
|
||||
/// The optional proof recorder for recording storage accesses.
|
||||
pub recorder: &'a Option<ProofRecorder<Block>>,
|
||||
/// The extensions that should be used for this call.
|
||||
pub extensions: &'a RefCell<Extensions>,
|
||||
}
|
||||
|
||||
/// Something that can call into the an api at a given block.
|
||||
@@ -620,6 +636,13 @@ pub trait CallApiAt<Block: BlockT> {
|
||||
|
||||
/// Get the state `at` the given block.
|
||||
fn state_at(&self, at: Block::Hash) -> Result<Self::StateBackend, ApiError>;
|
||||
|
||||
/// Initialize the `extensions` for the given block `at` by using the global extensions factory.
|
||||
fn initialize_extensions(
|
||||
&self,
|
||||
at: Block::Hash,
|
||||
extensions: &mut Extensions,
|
||||
) -> Result<(), ApiError>;
|
||||
}
|
||||
|
||||
/// Auxiliary wrapper that holds an api instance and binds it to the given lifetime.
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_state_machine::ExecutionStrategy;
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
@@ -56,17 +55,13 @@ fn sp_api_benchmark(c: &mut Criterion) {
|
||||
});
|
||||
|
||||
c.bench_function("calling function by function pointer in wasm", |b| {
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
|
||||
.build();
|
||||
let client = TestClientBuilder::new().build();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
b.iter(|| client.runtime_api().benchmark_indirect_call(best_hash).unwrap())
|
||||
});
|
||||
|
||||
c.bench_function("calling function in wasm", |b| {
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
|
||||
.build();
|
||||
c.bench_function("calling function", |b| {
|
||||
let client = TestClientBuilder::new().build();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
b.iter(|| client.runtime_api().benchmark_direct_call(best_hash).unwrap())
|
||||
});
|
||||
|
||||
@@ -22,9 +22,8 @@ use sp_runtime::{
|
||||
traits::{HashFor, Header as HeaderT},
|
||||
TransactionOutcome,
|
||||
};
|
||||
use sp_state_machine::{
|
||||
create_proof_check_backend, execution_proof_check_on_trie_backend, ExecutionStrategy,
|
||||
};
|
||||
use sp_state_machine::{create_proof_check_backend, execution_proof_check_on_trie_backend};
|
||||
|
||||
use substrate_test_runtime_client::{
|
||||
prelude::*,
|
||||
runtime::{Block, Header, TestAPI, Transfer},
|
||||
@@ -36,29 +35,18 @@ use sc_block_builder::BlockBuilderProvider;
|
||||
use sp_consensus::SelectChain;
|
||||
use substrate_test_runtime_client::sc_executor::WasmExecutor;
|
||||
|
||||
fn calling_function_with_strat(strat: ExecutionStrategy) {
|
||||
let client = TestClientBuilder::new().set_execution_strategy(strat).build();
|
||||
#[test]
|
||||
fn calling_runtime_function() {
|
||||
let client = TestClientBuilder::new().build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
|
||||
assert_eq!(runtime_api.benchmark_add_one(best_hash, &1).unwrap(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calling_native_runtime_function() {
|
||||
calling_function_with_strat(ExecutionStrategy::NativeWhenPossible);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calling_wasm_runtime_function() {
|
||||
calling_function_with_strat(ExecutionStrategy::AlwaysWasm);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calling_native_runtime_signature_changed_function() {
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::NativeWhenPossible)
|
||||
.build();
|
||||
let client = TestClientBuilder::new().build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
|
||||
@@ -67,9 +55,7 @@ fn calling_native_runtime_signature_changed_function() {
|
||||
|
||||
#[test]
|
||||
fn use_trie_function() {
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
|
||||
.build();
|
||||
let client = TestClientBuilder::new().build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
assert_eq!(runtime_api.use_trie(best_hash).unwrap(), 2);
|
||||
@@ -77,7 +63,7 @@ fn use_trie_function() {
|
||||
|
||||
#[test]
|
||||
fn initialize_block_works() {
|
||||
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
|
||||
let client = TestClientBuilder::new().build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
runtime_api
|
||||
@@ -97,9 +83,7 @@ fn initialize_block_works() {
|
||||
|
||||
#[test]
|
||||
fn record_proof_works() {
|
||||
let (client, longest_chain) = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::Both)
|
||||
.build_with_longest_chain();
|
||||
let (client, longest_chain) = TestClientBuilder::new().build_with_longest_chain();
|
||||
|
||||
let storage_root =
|
||||
*futures::executor::block_on(longest_chain.best_chain()).unwrap().state_root();
|
||||
@@ -151,7 +135,7 @@ fn record_proof_works() {
|
||||
|
||||
#[test]
|
||||
fn call_runtime_api_with_multiple_arguments() {
|
||||
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
|
||||
let client = TestClientBuilder::new().build();
|
||||
|
||||
let data = vec![1, 2, 4, 5, 6, 7, 8, 8, 10, 12];
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
@@ -166,8 +150,7 @@ fn disable_logging_works() {
|
||||
if std::env::var("RUN_TEST").is_ok() {
|
||||
sp_tracing::try_init_simple();
|
||||
|
||||
let mut builder =
|
||||
TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::AlwaysWasm);
|
||||
let mut builder = TestClientBuilder::new();
|
||||
builder.genesis_init_mut().set_wasm_code(
|
||||
substrate_test_runtime_client::runtime::wasm_binary_logging_disabled_unwrap().to_vec(),
|
||||
);
|
||||
|
||||
@@ -48,42 +48,3 @@ error[E0050]: method `test2` has 2 parameters but the declaration in trait `Api:
|
||||
| |_^ expected 3 parameters, found 2
|
||||
|
|
||||
= note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0050]: method `test_with_context` has 3 parameters but the declaration in trait `Api::test_with_context` has 4
|
||||
--> tests/ui/mock_only_self_reference.rs:12:1
|
||||
|
|
||||
3 | / sp_api::decl_runtime_apis! {
|
||||
4 | | pub trait Api {
|
||||
5 | | fn test(data: u64);
|
||||
| |_________________________- trait requires 4 parameters
|
||||
...
|
||||
12 | / sp_api::mock_impl_runtime_apis! {
|
||||
13 | | impl Api<Block> for MockApi {
|
||||
14 | | fn test(self, data: u64) {}
|
||||
15 | |
|
||||
16 | | fn test2(&mut self, data: u64) {}
|
||||
17 | | }
|
||||
18 | | }
|
||||
| |_^ expected 4 parameters, found 3
|
||||
|
|
||||
= note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0050]: method `test2_with_context` has 3 parameters but the declaration in trait `Api::test2_with_context` has 4
|
||||
--> tests/ui/mock_only_self_reference.rs:12:1
|
||||
|
|
||||
3 | / sp_api::decl_runtime_apis! {
|
||||
4 | | pub trait Api {
|
||||
5 | | fn test(data: u64);
|
||||
6 | | fn test2(data: u64);
|
||||
| |__________________________- trait requires 4 parameters
|
||||
...
|
||||
12 | / sp_api::mock_impl_runtime_apis! {
|
||||
13 | | impl Api<Block> for MockApi {
|
||||
14 | | fn test(self, data: u64) {}
|
||||
15 | |
|
||||
16 | | fn test2(&mut self, data: u64) {}
|
||||
17 | | }
|
||||
18 | | }
|
||||
| |_^ expected 4 parameters, found 3
|
||||
|
|
||||
= note: this error originates in the macro `sp_api::mock_impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
// limitations under the License.
|
||||
|
||||
//! Integration tests for ecdsa
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use sp_application_crypto::ecdsa::AppPair;
|
||||
use sp_core::{
|
||||
crypto::{ByteArray, Pair},
|
||||
testing::ECDSA,
|
||||
};
|
||||
use sp_keystore::{testing::MemoryKeystore, Keystore};
|
||||
use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt};
|
||||
use std::sync::Arc;
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
|
||||
@@ -31,9 +31,12 @@ use substrate_test_runtime_client::{
|
||||
#[test]
|
||||
fn ecdsa_works_in_runtime() {
|
||||
let keystore = Arc::new(MemoryKeystore::new());
|
||||
let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build();
|
||||
let (signature, public) = test_client
|
||||
.runtime_api()
|
||||
let test_client = TestClientBuilder::new().build();
|
||||
|
||||
let mut runtime_api = test_client.runtime_api();
|
||||
runtime_api.register_extension(KeystoreExt::new(keystore.clone()));
|
||||
|
||||
let (signature, public) = runtime_api
|
||||
.test_ecdsa_crypto(test_client.chain_info().genesis_hash)
|
||||
.expect("Tests `ecdsa` crypto.");
|
||||
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
|
||||
//! Integration tests for ed25519
|
||||
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use sp_application_crypto::ed25519::AppPair;
|
||||
use sp_core::{
|
||||
crypto::{ByteArray, Pair},
|
||||
testing::ED25519,
|
||||
};
|
||||
use sp_keystore::{testing::MemoryKeystore, Keystore};
|
||||
use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt};
|
||||
use std::sync::Arc;
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
|
||||
@@ -32,9 +32,12 @@ use substrate_test_runtime_client::{
|
||||
#[test]
|
||||
fn ed25519_works_in_runtime() {
|
||||
let keystore = Arc::new(MemoryKeystore::new());
|
||||
let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build();
|
||||
let (signature, public) = test_client
|
||||
.runtime_api()
|
||||
let test_client = TestClientBuilder::new().build();
|
||||
|
||||
let mut runtime_api = test_client.runtime_api();
|
||||
runtime_api.register_extension(KeystoreExt::new(keystore.clone()));
|
||||
|
||||
let (signature, public) = runtime_api
|
||||
.test_ed25519_crypto(test_client.chain_info().genesis_hash)
|
||||
.expect("Tests `ed25519` crypto.");
|
||||
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
|
||||
//! Integration tests for sr25519
|
||||
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use sp_application_crypto::sr25519::AppPair;
|
||||
use sp_core::{
|
||||
crypto::{ByteArray, Pair},
|
||||
testing::SR25519,
|
||||
};
|
||||
use sp_keystore::{testing::MemoryKeystore, Keystore};
|
||||
use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt};
|
||||
use std::sync::Arc;
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
|
||||
@@ -32,9 +32,12 @@ use substrate_test_runtime_client::{
|
||||
#[test]
|
||||
fn sr25519_works_in_runtime() {
|
||||
let keystore = Arc::new(MemoryKeystore::new());
|
||||
let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build();
|
||||
let (signature, public) = test_client
|
||||
.runtime_api()
|
||||
let test_client = TestClientBuilder::new().build();
|
||||
|
||||
let mut runtime_api = test_client.runtime_api();
|
||||
runtime_api.register_extension(KeystoreExt::new(keystore.clone()));
|
||||
|
||||
let (signature, public) = runtime_api
|
||||
.test_sr25519_crypto(test_client.chain_info().genesis_hash)
|
||||
.expect("Tests `sr25519` crypto.");
|
||||
|
||||
|
||||
@@ -71,16 +71,6 @@ pub enum BlockOrigin {
|
||||
File,
|
||||
}
|
||||
|
||||
impl From<BlockOrigin> for sp_core::ExecutionContext {
|
||||
fn from(origin: BlockOrigin) -> Self {
|
||||
if origin == BlockOrigin::NetworkInitialSync {
|
||||
sp_core::ExecutionContext::Syncing
|
||||
} else {
|
||||
sp_core::ExecutionContext::Importing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Environment for a Consensus instance.
|
||||
///
|
||||
/// Creates proposer instance.
|
||||
|
||||
@@ -39,6 +39,7 @@ sp-externalities = { version = "0.19.0", optional = true, path = "../externaliti
|
||||
futures = { version = "0.3.21", optional = true }
|
||||
dyn-clonable = { version = "0.9.0", optional = true }
|
||||
thiserror = { version = "1.0.30", optional = true }
|
||||
tracing = { version = "0.1.29", optional = true }
|
||||
bitflags = "1.3"
|
||||
paste = "1.0.7"
|
||||
|
||||
@@ -113,6 +114,7 @@ std = [
|
||||
"futures/thread-pool",
|
||||
"libsecp256k1/std",
|
||||
"dyn-clonable",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
# Serde support without relying on std features.
|
||||
|
||||
@@ -98,45 +98,6 @@ pub use sp_storage as storage;
|
||||
#[doc(hidden)]
|
||||
pub use sp_std;
|
||||
|
||||
/// Context for executing a call into the runtime.
|
||||
pub enum ExecutionContext {
|
||||
/// Context used for general block import (including locally authored blocks).
|
||||
Importing,
|
||||
/// Context used for importing blocks as part of an initial sync of the blockchain.
|
||||
///
|
||||
/// We distinguish between major sync and import so that validators who are running
|
||||
/// their initial sync (or catching up after some time offline) can use the faster
|
||||
/// native runtime (since we can reasonably assume the network as a whole has already
|
||||
/// come to a broad consensus on the block and it probably hasn't been crafted
|
||||
/// specifically to attack this node), but when importing blocks at the head of the
|
||||
/// chain in normal operation they can use the safer Wasm version.
|
||||
Syncing,
|
||||
/// Context used for block construction.
|
||||
BlockConstruction,
|
||||
/// Context used for offchain calls.
|
||||
///
|
||||
/// This allows passing offchain extension and customizing available capabilities.
|
||||
OffchainCall(Option<(Box<dyn offchain::Externalities>, offchain::Capabilities)>),
|
||||
}
|
||||
|
||||
impl ExecutionContext {
|
||||
/// Returns the capabilities of particular context.
|
||||
pub fn capabilities(&self) -> offchain::Capabilities {
|
||||
use ExecutionContext::*;
|
||||
|
||||
match self {
|
||||
Importing | Syncing | BlockConstruction => offchain::Capabilities::empty(),
|
||||
// Enable keystore, transaction pool and Offchain DB reads by default for offchain
|
||||
// calls.
|
||||
OffchainCall(None) =>
|
||||
offchain::Capabilities::KEYSTORE |
|
||||
offchain::Capabilities::OFFCHAIN_DB_READ |
|
||||
offchain::Capabilities::TRANSACTION_POOL,
|
||||
OffchainCall(Some((_, capabilities))) => *capabilities,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Hex-serialized shim for `Vec<u8>`.
|
||||
#[derive(PartialEq, Eq, Clone, RuntimeDebug)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, Hash, PartialOrd, Ord))]
|
||||
|
||||
@@ -260,26 +260,22 @@ impl Timestamp {
|
||||
bitflags::bitflags! {
|
||||
/// Execution context extra capabilities.
|
||||
pub struct Capabilities: u32 {
|
||||
/// Access to transaction pool.
|
||||
const TRANSACTION_POOL = 0b0000_0000_0001;
|
||||
/// External http calls.
|
||||
const HTTP = 0b0000_0000_0010;
|
||||
const HTTP = 1 << 0;
|
||||
/// Keystore access.
|
||||
const KEYSTORE = 0b0000_0000_0100;
|
||||
const KEYSTORE = 1 << 2;
|
||||
/// Randomness source.
|
||||
const RANDOMNESS = 0b0000_0000_1000;
|
||||
const RANDOMNESS = 1 << 3;
|
||||
/// Access to opaque network state.
|
||||
const NETWORK_STATE = 0b0000_0001_0000;
|
||||
const NETWORK_STATE = 1 << 4;
|
||||
/// Access to offchain worker DB (read only).
|
||||
const OFFCHAIN_DB_READ = 0b0000_0010_0000;
|
||||
const OFFCHAIN_DB_READ = 1 << 5;
|
||||
/// Access to offchain worker DB (writes).
|
||||
const OFFCHAIN_DB_WRITE = 0b0000_0100_0000;
|
||||
const OFFCHAIN_DB_WRITE = 1 << 6;
|
||||
/// Manage the authorized nodes
|
||||
const NODE_AUTHORIZATION = 0b0000_1000_0000;
|
||||
const NODE_AUTHORIZATION = 1 << 7;
|
||||
/// Access time related functionality
|
||||
const TIME = 0b0001_0000_0000;
|
||||
/// Access the statement store.
|
||||
const STATEMENT_STORE = 0b0010_0000_0000;
|
||||
const TIME = 1 << 8;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -785,8 +781,8 @@ mod tests {
|
||||
assert!(!none.contains(Capabilities::KEYSTORE));
|
||||
assert!(all.contains(Capabilities::KEYSTORE));
|
||||
assert!(some.contains(Capabilities::KEYSTORE));
|
||||
assert!(!none.contains(Capabilities::TRANSACTION_POOL));
|
||||
assert!(all.contains(Capabilities::TRANSACTION_POOL));
|
||||
assert!(!some.contains(Capabilities::TRANSACTION_POOL));
|
||||
assert!(!none.contains(Capabilities::RANDOMNESS));
|
||||
assert!(all.contains(Capabilities::RANDOMNESS));
|
||||
assert!(!some.contains(Capabilities::TIME));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
|
||||
//! In-memory implementation of offchain workers database.
|
||||
|
||||
use crate::offchain::OffchainStorage;
|
||||
use crate::offchain::{DbExternalities, OffchainStorage, StorageKind, STORAGE_PREFIX};
|
||||
use std::{
|
||||
collections::hash_map::{Entry, HashMap},
|
||||
iter::Iterator,
|
||||
};
|
||||
|
||||
const LOG_TARGET: &str = "offchain-worker::storage";
|
||||
|
||||
/// In-memory storage for offchain workers.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct InMemOffchainStorage {
|
||||
@@ -88,3 +90,95 @@ impl OffchainStorage for InMemOffchainStorage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unavailable_yet<R: Default>(name: &str) -> R {
|
||||
tracing::error!(
|
||||
target: LOG_TARGET,
|
||||
"The {:?} API is not available for offchain workers yet. Follow \
|
||||
https://github.com/paritytech/substrate/issues/1458 for details",
|
||||
name
|
||||
);
|
||||
Default::default()
|
||||
}
|
||||
|
||||
const LOCAL_DB: &str = "LOCAL (fork-aware) DB";
|
||||
|
||||
/// Offchain DB that implements [`DbExternalities`] for [`OffchainStorage`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct OffchainDb<Storage> {
|
||||
/// Persistent storage database.
|
||||
persistent: Storage,
|
||||
}
|
||||
|
||||
impl<Storage> OffchainDb<Storage> {
|
||||
/// Create new instance of Offchain DB.
|
||||
pub fn new(persistent: Storage) -> Self {
|
||||
Self { persistent }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Storage: OffchainStorage> DbExternalities for OffchainDb<Storage> {
|
||||
fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) {
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
?kind,
|
||||
key = ?array_bytes::bytes2hex("", key),
|
||||
value = ?array_bytes::bytes2hex("", value),
|
||||
"Write",
|
||||
);
|
||||
match kind {
|
||||
StorageKind::PERSISTENT => self.persistent.set(STORAGE_PREFIX, key, value),
|
||||
StorageKind::LOCAL => unavailable_yet(LOCAL_DB),
|
||||
}
|
||||
}
|
||||
|
||||
fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]) {
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
?kind,
|
||||
key = ?array_bytes::bytes2hex("", key),
|
||||
"Clear",
|
||||
);
|
||||
match kind {
|
||||
StorageKind::PERSISTENT => self.persistent.remove(STORAGE_PREFIX, key),
|
||||
StorageKind::LOCAL => unavailable_yet(LOCAL_DB),
|
||||
}
|
||||
}
|
||||
|
||||
fn local_storage_compare_and_set(
|
||||
&mut self,
|
||||
kind: StorageKind,
|
||||
key: &[u8],
|
||||
old_value: Option<&[u8]>,
|
||||
new_value: &[u8],
|
||||
) -> bool {
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
?kind,
|
||||
key = ?array_bytes::bytes2hex("", key),
|
||||
new_value = ?array_bytes::bytes2hex("", new_value),
|
||||
old_value = ?old_value.as_ref().map(|s| array_bytes::bytes2hex("", s)),
|
||||
"CAS",
|
||||
);
|
||||
match kind {
|
||||
StorageKind::PERSISTENT =>
|
||||
self.persistent.compare_and_set(STORAGE_PREFIX, key, old_value, new_value),
|
||||
StorageKind::LOCAL => unavailable_yet(LOCAL_DB),
|
||||
}
|
||||
}
|
||||
|
||||
fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>> {
|
||||
let result = match kind {
|
||||
StorageKind::PERSISTENT => self.persistent.get(STORAGE_PREFIX, key),
|
||||
StorageKind::LOCAL => unavailable_yet(LOCAL_DB),
|
||||
};
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
?kind,
|
||||
key = ?array_bytes::bytes2hex("", key),
|
||||
result = ?result.as_ref().map(|s| array_bytes::bytes2hex("", s)),
|
||||
"Read",
|
||||
);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,12 @@ pub trait Extension: Send + Any {
|
||||
fn as_mut_any(&mut self) -> &mut dyn Any;
|
||||
}
|
||||
|
||||
impl Extension for Box<dyn Extension> {
|
||||
fn as_mut_any(&mut self) -> &mut dyn Any {
|
||||
(**self).as_mut_any()
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro for declaring an extension that usable with [`Extensions`].
|
||||
///
|
||||
/// The extension will be an unit wrapper struct that implements [`Extension`], `Deref` and
|
||||
@@ -190,6 +196,14 @@ impl Extensions {
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&TypeId, &mut Box<dyn Extension>)> {
|
||||
self.extensions.iter_mut()
|
||||
}
|
||||
|
||||
/// Merge `other` into `self`.
|
||||
///
|
||||
/// If both contain the same extension, the extension instance of `other` will overwrite the
|
||||
/// instance found in `self`.
|
||||
pub fn merge(&mut self, other: Self) {
|
||||
self.extensions.extend(other.extensions);
|
||||
}
|
||||
}
|
||||
|
||||
impl Extend<Extensions> for Extensions {
|
||||
|
||||
@@ -174,37 +174,36 @@ pub trait Keystore: Send + Sync {
|
||||
msg: &[u8; 32],
|
||||
) -> Result<Option<ecdsa::Signature>, Error>;
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
/// Returns all bls12-381 public keys for the given key type.
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls381_public_keys(&self, id: KeyTypeId) -> Vec<bls381::Public>;
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
/// Returns all bls12-377 public keys for the given key type.
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls377_public_keys(&self, id: KeyTypeId) -> Vec<bls377::Public>;
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
/// Generate a new bls381 key pair for the given key type and an optional seed.
|
||||
///
|
||||
/// Returns an `bls381::Public` key of the generated key pair or an `Err` if
|
||||
/// something failed during key generation.
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls381_generate_new(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<bls381::Public, Error>;
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
/// Generate a new bls377 key pair for the given key type and an optional seed.
|
||||
///
|
||||
/// Returns an `bls377::Public` key of the generated key pair or an `Err` if
|
||||
/// something failed during key generation.
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls377_generate_new(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<bls377::Public, Error>;
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
/// Generate a bls381 signature for a given message.
|
||||
///
|
||||
/// Receives [`KeyTypeId`] and a [`bls381::Public`] key to be able to map
|
||||
@@ -213,6 +212,7 @@ pub trait Keystore: Send + Sync {
|
||||
/// Returns an [`bls381::Signature`] or `None` in case the given `key_type`
|
||||
/// and `public` combination doesn't exist in the keystore.
|
||||
/// An `Err` will be returned if generating the signature itself failed.
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls381_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
@@ -220,7 +220,6 @@ pub trait Keystore: Send + Sync {
|
||||
msg: &[u8],
|
||||
) -> Result<Option<bls381::Signature>, Error>;
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
/// Generate a bls377 signature for a given message.
|
||||
///
|
||||
/// Receives [`KeyTypeId`] and a [`bls377::Public`] key to be able to map
|
||||
@@ -229,6 +228,7 @@ pub trait Keystore: Send + Sync {
|
||||
/// Returns an [`bls377::Signature`] or `None` in case the given `key_type`
|
||||
/// and `public` combination doesn't exist in the keystore.
|
||||
/// An `Err` will be returned if generating the signature itself failed.
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls377_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
@@ -309,6 +309,158 @@ pub trait Keystore: Send + Sync {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Keystore + ?Sized> Keystore for Arc<T> {
|
||||
fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec<sr25519::Public> {
|
||||
(**self).sr25519_public_keys(key_type)
|
||||
}
|
||||
|
||||
fn sr25519_generate_new(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<sr25519::Public, Error> {
|
||||
(**self).sr25519_generate_new(key_type, seed)
|
||||
}
|
||||
|
||||
fn sr25519_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &sr25519::Public,
|
||||
msg: &[u8],
|
||||
) -> Result<Option<sr25519::Signature>, Error> {
|
||||
(**self).sr25519_sign(key_type, public, msg)
|
||||
}
|
||||
|
||||
fn sr25519_vrf_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &sr25519::Public,
|
||||
data: &sr25519::vrf::VrfSignData,
|
||||
) -> Result<Option<sr25519::vrf::VrfSignature>, Error> {
|
||||
(**self).sr25519_vrf_sign(key_type, public, data)
|
||||
}
|
||||
|
||||
fn sr25519_vrf_output(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &sr25519::Public,
|
||||
input: &sr25519::vrf::VrfInput,
|
||||
) -> Result<Option<sr25519::vrf::VrfOutput>, Error> {
|
||||
(**self).sr25519_vrf_output(key_type, public, input)
|
||||
}
|
||||
|
||||
fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec<ed25519::Public> {
|
||||
(**self).ed25519_public_keys(key_type)
|
||||
}
|
||||
|
||||
fn ed25519_generate_new(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<ed25519::Public, Error> {
|
||||
(**self).ed25519_generate_new(key_type, seed)
|
||||
}
|
||||
|
||||
fn ed25519_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &ed25519::Public,
|
||||
msg: &[u8],
|
||||
) -> Result<Option<ed25519::Signature>, Error> {
|
||||
(**self).ed25519_sign(key_type, public, msg)
|
||||
}
|
||||
|
||||
fn ecdsa_public_keys(&self, key_type: KeyTypeId) -> Vec<ecdsa::Public> {
|
||||
(**self).ecdsa_public_keys(key_type)
|
||||
}
|
||||
|
||||
fn ecdsa_generate_new(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<ecdsa::Public, Error> {
|
||||
(**self).ecdsa_generate_new(key_type, seed)
|
||||
}
|
||||
|
||||
fn ecdsa_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &ecdsa::Public,
|
||||
msg: &[u8],
|
||||
) -> Result<Option<ecdsa::Signature>, Error> {
|
||||
(**self).ecdsa_sign(key_type, public, msg)
|
||||
}
|
||||
|
||||
fn ecdsa_sign_prehashed(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &ecdsa::Public,
|
||||
msg: &[u8; 32],
|
||||
) -> Result<Option<ecdsa::Signature>, Error> {
|
||||
(**self).ecdsa_sign_prehashed(key_type, public, msg)
|
||||
}
|
||||
|
||||
fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> {
|
||||
(**self).insert(key_type, suri, public)
|
||||
}
|
||||
|
||||
fn keys(&self, key_type: KeyTypeId) -> Result<Vec<Vec<u8>>, Error> {
|
||||
(**self).keys(key_type)
|
||||
}
|
||||
|
||||
fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool {
|
||||
(**self).has_keys(public_keys)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls381_public_keys(&self, id: KeyTypeId) -> Vec<bls381::Public> {
|
||||
(**self).bls381_public_keys(id)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls377_public_keys(&self, id: KeyTypeId) -> Vec<bls377::Public> {
|
||||
(**self).bls377_public_keys(id)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls381_generate_new(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<bls381::Public, Error> {
|
||||
(**self).bls381_generate_new(key_type, seed)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls377_generate_new(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<bls377::Public, Error> {
|
||||
(**self).bls377_generate_new(key_type, seed)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls381_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &bls381::Public,
|
||||
msg: &[u8],
|
||||
) -> Result<Option<bls381::Signature>, Error> {
|
||||
(**self).bls381_sign(key_type, public, msg)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls377_sign(
|
||||
&self,
|
||||
key_type: KeyTypeId,
|
||||
public: &bls377::Public,
|
||||
msg: &[u8],
|
||||
) -> Result<Option<bls377::Signature>, Error> {
|
||||
(**self).bls377_sign(key_type, public, msg)
|
||||
}
|
||||
}
|
||||
|
||||
/// A shared pointer to a keystore implementation.
|
||||
pub type KeystorePtr = Arc<dyn Keystore>;
|
||||
|
||||
@@ -319,6 +471,13 @@ sp_externalities::decl_extension! {
|
||||
|
||||
impl KeystoreExt {
|
||||
/// Create a new instance of `KeystoreExt`
|
||||
///
|
||||
/// This is more performant as we don't need to wrap keystore in another [`Arc`].
|
||||
pub fn from(keystore: KeystorePtr) -> Self {
|
||||
Self(keystore)
|
||||
}
|
||||
|
||||
/// Create a new instance of `KeystoreExt` using the given `keystore`.
|
||||
pub fn new<T: Keystore + 'static>(keystore: T) -> Self {
|
||||
Self(Arc::new(keystore))
|
||||
}
|
||||
|
||||
@@ -68,8 +68,7 @@ mod tests {
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use std::{env, str::FromStr};
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::TestAPI, DefaultTestClientBuilderExt, ExecutionStrategy, TestClientBuilder,
|
||||
TestClientBuilderExt,
|
||||
runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -78,9 +77,7 @@ mod tests {
|
||||
sp_tracing::try_init_simple();
|
||||
log::set_max_level(log::LevelFilter::from_str(&env::var("RUST_LOG").unwrap()).unwrap());
|
||||
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
|
||||
.build();
|
||||
let client = TestClientBuilder::new().build();
|
||||
let runtime_api = client.runtime_api();
|
||||
runtime_api
|
||||
.do_trace_log(client.chain_info().genesis_hash)
|
||||
|
||||
@@ -20,6 +20,7 @@ sp-core = { version = "21.0.0", default-features = false, path = "../core" }
|
||||
sp-runtime = { version = "24.0.0", optional = true, path = "../runtime" }
|
||||
sp-staking = { version = "4.0.0-dev", default-features = false, path = "../staking" }
|
||||
sp-std = { version = "8.0.0", default-features = false, path = "../std" }
|
||||
sp-keystore = { version = "0.27.0", path = "../keystore", optional = true }
|
||||
|
||||
[features]
|
||||
default = [ "std" ]
|
||||
@@ -31,4 +32,5 @@ std = [
|
||||
"sp-runtime/std",
|
||||
"sp-staking/std",
|
||||
"sp-std/std",
|
||||
"sp-keystore",
|
||||
]
|
||||
|
||||
@@ -112,17 +112,22 @@ pub fn generate_initial_session_keys<Block, T>(
|
||||
client: std::sync::Arc<T>,
|
||||
at: Block::Hash,
|
||||
seeds: Vec<String>,
|
||||
keystore: sp_keystore::KeystorePtr,
|
||||
) -> Result<(), sp_api::ApiError>
|
||||
where
|
||||
Block: BlockT,
|
||||
T: ProvideRuntimeApi<Block>,
|
||||
T::Api: SessionKeys<Block>,
|
||||
{
|
||||
use sp_api::ApiExt;
|
||||
|
||||
if seeds.is_empty() {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let runtime_api = client.runtime_api();
|
||||
let mut runtime_api = client.runtime_api();
|
||||
|
||||
runtime_api.register_extension(sp_keystore::KeystoreExt::from(keystore));
|
||||
|
||||
for seed in seeds {
|
||||
runtime_api.generate_session_keys(at, Some(seed.as_bytes().to_vec()))?;
|
||||
|
||||
@@ -168,14 +168,7 @@ mod execution {
|
||||
traits::{CallContext, CodeExecutor, RuntimeCode},
|
||||
};
|
||||
use sp_externalities::Extensions;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fmt,
|
||||
};
|
||||
|
||||
const PROOF_CLOSE_TRANSACTION: &str = "\
|
||||
Closing a transaction that was started in this function. Client initiated transactions
|
||||
are protected from being closed by the runtime. qed";
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
pub(crate) type CallResult<E> = Result<Vec<u8>, E>;
|
||||
|
||||
@@ -185,21 +178,6 @@ mod execution {
|
||||
/// Trie backend with in-memory storage.
|
||||
pub type InMemoryBackend<H> = TrieBackend<MemoryDB<H>, H>;
|
||||
|
||||
/// Strategy for executing a call into the runtime.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum ExecutionStrategy {
|
||||
/// Execute with the native equivalent if it is compatible with the given wasm module;
|
||||
/// otherwise fall back to the wasm.
|
||||
NativeWhenPossible,
|
||||
/// Use the given wasm module.
|
||||
AlwaysWasm,
|
||||
/// Run with both the wasm and the native variant (if compatible). Report any discrepancy
|
||||
/// as an error.
|
||||
Both,
|
||||
/// First native, then if that fails or is not possible, wasm.
|
||||
NativeElseWasm,
|
||||
}
|
||||
|
||||
/// Storage backend trust level.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum BackendTrustLevel {
|
||||
@@ -211,73 +189,6 @@ mod execution {
|
||||
Untrusted,
|
||||
}
|
||||
|
||||
/// Like `ExecutionStrategy` only it also stores a handler in case of consensus failure.
|
||||
#[derive(Clone)]
|
||||
pub enum ExecutionManager<F> {
|
||||
/// Execute with the native equivalent if it is compatible with the given wasm module;
|
||||
/// otherwise fall back to the wasm.
|
||||
NativeWhenPossible,
|
||||
/// Use the given wasm module. The backend on which code is executed code could be
|
||||
/// trusted to provide all storage or not (i.e. the light client cannot be trusted to
|
||||
/// provide for all storage queries since the storage entries it has come from an external
|
||||
/// node).
|
||||
AlwaysWasm(BackendTrustLevel),
|
||||
/// Run with both the wasm and the native variant (if compatible). Call `F` in the case of
|
||||
/// any discrepancy.
|
||||
Both(F),
|
||||
/// First native, then if that fails or is not possible, wasm.
|
||||
NativeElseWasm,
|
||||
}
|
||||
|
||||
impl<'a, F> From<&'a ExecutionManager<F>> for ExecutionStrategy {
|
||||
fn from(s: &'a ExecutionManager<F>) -> Self {
|
||||
match *s {
|
||||
ExecutionManager::NativeWhenPossible => ExecutionStrategy::NativeWhenPossible,
|
||||
ExecutionManager::AlwaysWasm(_) => ExecutionStrategy::AlwaysWasm,
|
||||
ExecutionManager::NativeElseWasm => ExecutionStrategy::NativeElseWasm,
|
||||
ExecutionManager::Both(_) => ExecutionStrategy::Both,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExecutionStrategy {
|
||||
/// Gets the corresponding manager for the execution strategy.
|
||||
pub fn get_manager<E: fmt::Debug>(self) -> ExecutionManager<DefaultHandler<E>> {
|
||||
match self {
|
||||
ExecutionStrategy::AlwaysWasm =>
|
||||
ExecutionManager::AlwaysWasm(BackendTrustLevel::Trusted),
|
||||
ExecutionStrategy::NativeWhenPossible => ExecutionManager::NativeWhenPossible,
|
||||
ExecutionStrategy::NativeElseWasm => ExecutionManager::NativeElseWasm,
|
||||
ExecutionStrategy::Both => ExecutionManager::Both(|wasm_result, native_result| {
|
||||
warn!(
|
||||
"Consensus error between wasm {:?} and native {:?}. Using wasm.",
|
||||
wasm_result, native_result,
|
||||
);
|
||||
warn!(" Native result {:?}", native_result);
|
||||
warn!(" Wasm result {:?}", wasm_result);
|
||||
wasm_result
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluate to ExecutionManager::NativeElseWasm, without having to figure out the type.
|
||||
pub fn native_else_wasm<E>() -> ExecutionManager<DefaultHandler<E>> {
|
||||
ExecutionManager::NativeElseWasm
|
||||
}
|
||||
|
||||
/// Evaluate to ExecutionManager::AlwaysWasm with trusted backend, without having to figure out
|
||||
/// the type.
|
||||
fn always_wasm<E>() -> ExecutionManager<DefaultHandler<E>> {
|
||||
ExecutionManager::AlwaysWasm(BackendTrustLevel::Trusted)
|
||||
}
|
||||
|
||||
/// Evaluate ExecutionManager::AlwaysWasm with untrusted backend, without having to figure out
|
||||
/// the type.
|
||||
fn always_untrusted_wasm<E>() -> ExecutionManager<DefaultHandler<E>> {
|
||||
ExecutionManager::AlwaysWasm(BackendTrustLevel::Untrusted)
|
||||
}
|
||||
|
||||
/// The substrate state machine.
|
||||
pub struct StateMachine<'a, B, H, Exec>
|
||||
where
|
||||
@@ -289,7 +200,7 @@ mod execution {
|
||||
method: &'a str,
|
||||
call_data: &'a [u8],
|
||||
overlay: &'a mut OverlayedChanges,
|
||||
extensions: Extensions,
|
||||
extensions: &'a mut Extensions,
|
||||
storage_transaction_cache: Option<&'a mut StorageTransactionCache<B::Transaction, H>>,
|
||||
runtime_code: &'a RuntimeCode<'a>,
|
||||
stats: StateMachineStats,
|
||||
@@ -324,7 +235,7 @@ mod execution {
|
||||
exec: &'a Exec,
|
||||
method: &'a str,
|
||||
call_data: &'a [u8],
|
||||
extensions: Extensions,
|
||||
extensions: &'a mut Extensions,
|
||||
runtime_code: &'a RuntimeCode,
|
||||
context: CallContext,
|
||||
) -> Self {
|
||||
@@ -372,13 +283,7 @@ mod execution {
|
||||
/// blocks (e.g. a transaction at a time), ensure a different method is used.
|
||||
///
|
||||
/// Returns the SCALE encoded result of the executed function.
|
||||
pub fn execute(&mut self, strategy: ExecutionStrategy) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
// We are not giving a native call and thus we are sure that the result can never be a
|
||||
// native value.
|
||||
self.execute_using_consensus_failure_handler(strategy.get_manager())
|
||||
}
|
||||
|
||||
fn execute_aux(&mut self, use_native: bool) -> (CallResult<Exec::Error>, bool) {
|
||||
pub fn execute(&mut self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
let mut cache = StorageTransactionCache::default();
|
||||
|
||||
let cache = match self.storage_transaction_cache.as_mut() {
|
||||
@@ -390,7 +295,7 @@ mod execution {
|
||||
.enter_runtime()
|
||||
.expect("StateMachine is never called from the runtime; qed");
|
||||
|
||||
let mut ext = Ext::new(self.overlay, cache, self.backend, Some(&mut self.extensions));
|
||||
let mut ext = Ext::new(self.overlay, cache, self.backend, Some(self.extensions));
|
||||
|
||||
let ext_id = ext.id;
|
||||
|
||||
@@ -403,14 +308,10 @@ mod execution {
|
||||
"Call",
|
||||
);
|
||||
|
||||
let (result, was_native) = self.exec.call(
|
||||
&mut ext,
|
||||
self.runtime_code,
|
||||
self.method,
|
||||
self.call_data,
|
||||
use_native,
|
||||
self.context,
|
||||
);
|
||||
let result = self
|
||||
.exec
|
||||
.call(&mut ext, self.runtime_code, self.method, self.call_data, false, self.context)
|
||||
.0;
|
||||
|
||||
self.overlay
|
||||
.exit_runtime()
|
||||
@@ -419,92 +320,11 @@ mod execution {
|
||||
trace!(
|
||||
target: "state",
|
||||
ext_id = %HexDisplay::from(&ext_id.to_le_bytes()),
|
||||
?was_native,
|
||||
?result,
|
||||
"Return",
|
||||
);
|
||||
|
||||
(result, was_native)
|
||||
}
|
||||
|
||||
fn execute_call_with_both_strategy<Handler>(
|
||||
&mut self,
|
||||
on_consensus_failure: Handler,
|
||||
) -> CallResult<Exec::Error>
|
||||
where
|
||||
Handler:
|
||||
FnOnce(CallResult<Exec::Error>, CallResult<Exec::Error>) -> CallResult<Exec::Error>,
|
||||
{
|
||||
self.overlay.start_transaction();
|
||||
let (result, was_native) = self.execute_aux(true);
|
||||
|
||||
if was_native {
|
||||
self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION);
|
||||
let (wasm_result, _) = self.execute_aux(false);
|
||||
|
||||
if (result.is_ok() &&
|
||||
wasm_result.is_ok() && result.as_ref().ok() == wasm_result.as_ref().ok()) ||
|
||||
result.is_err() && wasm_result.is_err()
|
||||
{
|
||||
result
|
||||
} else {
|
||||
on_consensus_failure(wasm_result, result)
|
||||
}
|
||||
} else {
|
||||
self.overlay.commit_transaction().expect(PROOF_CLOSE_TRANSACTION);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_call_with_native_else_wasm_strategy(&mut self) -> CallResult<Exec::Error> {
|
||||
self.overlay.start_transaction();
|
||||
let (result, was_native) = self.execute_aux(true);
|
||||
|
||||
if !was_native || result.is_ok() {
|
||||
self.overlay.commit_transaction().expect(PROOF_CLOSE_TRANSACTION);
|
||||
result
|
||||
} else {
|
||||
self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION);
|
||||
self.execute_aux(false).0
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute a call using the given state backend, overlayed changes, and call executor.
|
||||
///
|
||||
/// On an error, no prospective changes are written to the overlay.
|
||||
///
|
||||
/// Note: changes to code will be in place if this call is made again. For running partial
|
||||
/// blocks (e.g. a transaction at a time), ensure a different method is used.
|
||||
///
|
||||
/// Returns the result of the executed function either in native representation `R` or
|
||||
/// in SCALE encoded representation.
|
||||
pub fn execute_using_consensus_failure_handler<Handler>(
|
||||
&mut self,
|
||||
manager: ExecutionManager<Handler>,
|
||||
) -> Result<Vec<u8>, Box<dyn Error>>
|
||||
where
|
||||
Handler:
|
||||
FnOnce(CallResult<Exec::Error>, CallResult<Exec::Error>) -> CallResult<Exec::Error>,
|
||||
{
|
||||
let result = {
|
||||
match manager {
|
||||
ExecutionManager::Both(on_consensus_failure) =>
|
||||
self.execute_call_with_both_strategy(on_consensus_failure),
|
||||
ExecutionManager::NativeElseWasm =>
|
||||
self.execute_call_with_native_else_wasm_strategy(),
|
||||
ExecutionManager::AlwaysWasm(trust_level) => {
|
||||
let _abort_guard = match trust_level {
|
||||
BackendTrustLevel::Trusted => None,
|
||||
BackendTrustLevel::Untrusted =>
|
||||
Some(sp_panic_handler::AbortGuard::never_abort()),
|
||||
};
|
||||
self.execute_aux(false).0
|
||||
},
|
||||
ExecutionManager::NativeWhenPossible => self.execute_aux(true).0,
|
||||
}
|
||||
};
|
||||
|
||||
result.map_err(|e| Box::new(e) as _)
|
||||
result.map_err(|e| Box::new(e) as Box<_>)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,7 +351,7 @@ mod execution {
|
||||
method,
|
||||
call_data,
|
||||
runtime_code,
|
||||
Default::default(),
|
||||
&mut Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -551,7 +371,7 @@ mod execution {
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
runtime_code: &RuntimeCode,
|
||||
extensions: Extensions,
|
||||
extensions: &mut Extensions,
|
||||
) -> Result<(Vec<u8>, StorageProof), Box<dyn Error>>
|
||||
where
|
||||
S: trie_backend_essence::TrieBackendStorage<H>,
|
||||
@@ -572,7 +392,7 @@ mod execution {
|
||||
runtime_code,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.execute_using_consensus_failure_handler::<_>(always_wasm())?;
|
||||
.execute()?;
|
||||
|
||||
let proof = proving_backend
|
||||
.extract_proof()
|
||||
@@ -627,11 +447,11 @@ mod execution {
|
||||
exec,
|
||||
method,
|
||||
call_data,
|
||||
Extensions::default(),
|
||||
&mut Extensions::default(),
|
||||
runtime_code,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.execute_using_consensus_failure_handler(always_untrusted_wasm())
|
||||
.execute()
|
||||
}
|
||||
|
||||
/// Generate storage read proof.
|
||||
@@ -1356,6 +1176,7 @@ mod tests {
|
||||
let backend = trie_backend::tests::test_trie(state_version, None, None);
|
||||
let mut overlayed_changes = Default::default();
|
||||
let wasm_code = RuntimeCode::empty();
|
||||
let mut execution_extensions = &mut Default::default();
|
||||
|
||||
let mut state_machine = StateMachine::new(
|
||||
&backend,
|
||||
@@ -1367,12 +1188,12 @@ mod tests {
|
||||
},
|
||||
"test",
|
||||
&[],
|
||||
Default::default(),
|
||||
&mut execution_extensions,
|
||||
&wasm_code,
|
||||
CallContext::Offchain,
|
||||
);
|
||||
|
||||
assert_eq!(state_machine.execute(ExecutionStrategy::NativeWhenPossible).unwrap(), vec![66]);
|
||||
assert_eq!(state_machine.execute().unwrap(), vec![66]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1384,6 +1205,7 @@ mod tests {
|
||||
let backend = trie_backend::tests::test_trie(state_version, None, None);
|
||||
let mut overlayed_changes = Default::default();
|
||||
let wasm_code = RuntimeCode::empty();
|
||||
let mut execution_extensions = &mut Default::default();
|
||||
|
||||
let mut state_machine = StateMachine::new(
|
||||
&backend,
|
||||
@@ -1395,47 +1217,12 @@ mod tests {
|
||||
},
|
||||
"test",
|
||||
&[],
|
||||
Default::default(),
|
||||
&mut execution_extensions,
|
||||
&wasm_code,
|
||||
CallContext::Offchain,
|
||||
);
|
||||
|
||||
assert_eq!(state_machine.execute(ExecutionStrategy::NativeElseWasm).unwrap(), vec![66]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dual_execution_strategy_detects_consensus_failure() {
|
||||
dual_execution_strategy_detects_consensus_failure_inner(StateVersion::V0);
|
||||
dual_execution_strategy_detects_consensus_failure_inner(StateVersion::V1);
|
||||
}
|
||||
fn dual_execution_strategy_detects_consensus_failure_inner(state_version: StateVersion) {
|
||||
let mut consensus_failed = false;
|
||||
let backend = trie_backend::tests::test_trie(state_version, None, None);
|
||||
let mut overlayed_changes = Default::default();
|
||||
let wasm_code = RuntimeCode::empty();
|
||||
|
||||
let mut state_machine = StateMachine::new(
|
||||
&backend,
|
||||
&mut overlayed_changes,
|
||||
&DummyCodeExecutor {
|
||||
native_available: true,
|
||||
native_succeeds: true,
|
||||
fallback_succeeds: false,
|
||||
},
|
||||
"test",
|
||||
&[],
|
||||
Default::default(),
|
||||
&wasm_code,
|
||||
CallContext::Offchain,
|
||||
);
|
||||
|
||||
assert!(state_machine
|
||||
.execute_using_consensus_failure_handler(ExecutionManager::Both(|we, _ne| {
|
||||
consensus_failed = true;
|
||||
we
|
||||
}),)
|
||||
.is_err());
|
||||
assert!(consensus_failed);
|
||||
assert_eq!(state_machine.execute().unwrap(), vec![66]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -115,8 +115,8 @@ cargo-check-benches:
|
||||
rusty-cachier cache upload
|
||||
;;
|
||||
2)
|
||||
cargo run --locked --release -p node-bench -- ::node::import::native::sr25519::transfer_keep_alive::paritydb::small --json
|
||||
| tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::node::import::native::sr25519::transfer_keep_alive::paritydb::small.json
|
||||
cargo run --locked --release -p node-bench -- ::node::import::sr25519::transfer_keep_alive::paritydb::small --json
|
||||
| tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::node::import::sr25519::transfer_keep_alive::paritydb::small.json
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -305,7 +305,7 @@ quick-benchmarks:
|
||||
WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings"
|
||||
script:
|
||||
- rusty-cachier snapshot create
|
||||
- time cargo run --locked --release --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1
|
||||
- time cargo run --locked --release --features runtime-benchmarks -- benchmark pallet --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1
|
||||
- rusty-cachier cache upload
|
||||
|
||||
test-frame-examples-compile-to-wasm:
|
||||
|
||||
@@ -119,7 +119,6 @@ for PALLET in "${PALLETS[@]}"; do
|
||||
--repeat=20 \
|
||||
--pallet="$PALLET" \
|
||||
--extrinsic="*" \
|
||||
--execution=wasm \
|
||||
--wasm-execution=compiled \
|
||||
--heap-pages=4096 \
|
||||
--output="$WEIGHT_FILE" \
|
||||
@@ -137,7 +136,6 @@ echo "[+] Benchmarking block and extrinsic overheads..."
|
||||
OUTPUT=$(
|
||||
$SUBSTRATE benchmark overhead \
|
||||
--chain=dev \
|
||||
--execution=wasm \
|
||||
--wasm-execution=compiled \
|
||||
--weight-path="./frame/support/src/weights/" \
|
||||
--header="./HEADER-APACHE2" \
|
||||
|
||||
@@ -22,10 +22,7 @@
|
||||
pub mod client_ext;
|
||||
|
||||
pub use self::client_ext::{ClientBlockImportExt, ClientExt};
|
||||
pub use sc_client_api::{
|
||||
execution_extensions::{ExecutionExtensions, ExecutionStrategies},
|
||||
BadBlocks, ForkBlocks,
|
||||
};
|
||||
pub use sc_client_api::{execution_extensions::ExecutionExtensions, BadBlocks, ForkBlocks};
|
||||
pub use sc_client_db::{self, Backend, BlocksPruning};
|
||||
pub use sc_executor::{self, NativeElseWasmExecutor, WasmExecutionMethod, WasmExecutor};
|
||||
pub use sc_service::{client, RpcHandlers};
|
||||
@@ -35,7 +32,6 @@ pub use sp_keyring::{
|
||||
};
|
||||
pub use sp_keystore::{Keystore, KeystorePtr};
|
||||
pub use sp_runtime::{Storage, StorageChild};
|
||||
pub use sp_state_machine::ExecutionStrategy;
|
||||
|
||||
use futures::{future::Future, stream::StreamExt};
|
||||
use sc_client_api::BlockchainEvents;
|
||||
@@ -67,14 +63,12 @@ impl GenesisInit for () {
|
||||
|
||||
/// A builder for creating a test client instance.
|
||||
pub struct TestClientBuilder<Block: BlockT, ExecutorDispatch, Backend: 'static, G: GenesisInit> {
|
||||
execution_strategies: ExecutionStrategies,
|
||||
genesis_init: G,
|
||||
/// The key is an unprefixed storage key, this only contains
|
||||
/// default child trie content.
|
||||
child_storage_extension: HashMap<Vec<u8>, StorageChild>,
|
||||
backend: Arc<Backend>,
|
||||
_executor: std::marker::PhantomData<ExecutorDispatch>,
|
||||
keystore: Option<KeystorePtr>,
|
||||
fork_blocks: ForkBlocks<Block>,
|
||||
bad_blocks: BadBlocks<Block>,
|
||||
enable_offchain_indexing_api: bool,
|
||||
@@ -119,11 +113,9 @@ impl<Block: BlockT, ExecutorDispatch, Backend, G: GenesisInit>
|
||||
pub fn with_backend(backend: Arc<Backend>) -> Self {
|
||||
TestClientBuilder {
|
||||
backend,
|
||||
execution_strategies: ExecutionStrategies::default(),
|
||||
child_storage_extension: Default::default(),
|
||||
genesis_init: Default::default(),
|
||||
_executor: Default::default(),
|
||||
keystore: None,
|
||||
fork_blocks: None,
|
||||
bad_blocks: None,
|
||||
enable_offchain_indexing_api: false,
|
||||
@@ -131,12 +123,6 @@ impl<Block: BlockT, ExecutorDispatch, Backend, G: GenesisInit>
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the keystore that should be used by the externalities.
|
||||
pub fn set_keystore(mut self, keystore: KeystorePtr) -> Self {
|
||||
self.keystore = Some(keystore);
|
||||
self
|
||||
}
|
||||
|
||||
/// Alter the genesis storage parameters.
|
||||
pub fn genesis_init_mut(&mut self) -> &mut G {
|
||||
&mut self.genesis_init
|
||||
@@ -162,18 +148,6 @@ impl<Block: BlockT, ExecutorDispatch, Backend, G: GenesisInit>
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the execution strategy that should be used by all contexts.
|
||||
pub fn set_execution_strategy(mut self, execution_strategy: ExecutionStrategy) -> Self {
|
||||
self.execution_strategies = ExecutionStrategies {
|
||||
syncing: execution_strategy,
|
||||
importing: execution_strategy,
|
||||
block_construction: execution_strategy,
|
||||
offchain_worker: execution_strategy,
|
||||
other: execution_strategy,
|
||||
};
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets custom block rules.
|
||||
pub fn set_block_rules(
|
||||
mut self,
|
||||
@@ -296,12 +270,7 @@ impl<Block: BlockT, D, Backend, G: GenesisInit>
|
||||
self.backend.clone(),
|
||||
executor.clone(),
|
||||
Default::default(),
|
||||
ExecutionExtensions::new(
|
||||
self.execution_strategies.clone(),
|
||||
self.keystore.clone(),
|
||||
sc_offchain::OffchainDb::factory_from_backend(&*self.backend),
|
||||
Arc::new(executor),
|
||||
),
|
||||
ExecutionExtensions::new(None, Arc::new(executor)),
|
||||
)
|
||||
.expect("Creates LocalCallExecutor");
|
||||
|
||||
|
||||
@@ -138,10 +138,9 @@ impl GenesisStorageBuilder {
|
||||
.build_storage()
|
||||
.expect("Build storage from substrate-test-runtime GenesisConfig");
|
||||
|
||||
storage.top.insert(
|
||||
well_known_keys::HEAP_PAGES.into(),
|
||||
self.heap_pages_override.unwrap_or(16_u64).encode(),
|
||||
);
|
||||
if let Some(heap_pages) = self.heap_pages_override {
|
||||
storage.top.insert(well_known_keys::HEAP_PAGES.into(), heap_pages.encode());
|
||||
}
|
||||
|
||||
storage.top.extend(self.extra_storage.top.clone());
|
||||
storage.children_default.extend(self.extra_storage.children_default.clone());
|
||||
|
||||
@@ -845,8 +845,12 @@ pub mod storage_key_generator {
|
||||
|
||||
/// Generate the hashed storage keys from the raw literals. These keys are expected to be be in
|
||||
/// storage with given substrate-test runtime.
|
||||
pub fn generate_expected_storage_hashed_keys() -> Vec<String> {
|
||||
let literals: Vec<&[u8]> = vec![b":code", b":extrinsic_index", b":heappages"];
|
||||
pub fn generate_expected_storage_hashed_keys(custom_heap_pages: bool) -> Vec<String> {
|
||||
let mut literals: Vec<&[u8]> = vec![b":code", b":extrinsic_index"];
|
||||
|
||||
if custom_heap_pages {
|
||||
literals.push(b":heappages");
|
||||
}
|
||||
|
||||
let keys: Vec<Vec<&[u8]>> = vec![
|
||||
vec![b"Babe", b"Authorities"],
|
||||
@@ -906,8 +910,11 @@ pub mod storage_key_generator {
|
||||
/// that would be generated by `generate_expected_storage_hashed_keys`. This list is provided
|
||||
/// for the debugging convenience only. Value of each hex-string is documented with the literal
|
||||
/// origin.
|
||||
pub fn get_expected_storage_hashed_keys() -> Vec<String> {
|
||||
[
|
||||
///
|
||||
/// `custom_heap_pages`: Should be set to `true` when the state contains the `:heap_pages` key
|
||||
/// aka when overriding the heap pages to be used by the executor.
|
||||
pub fn get_expected_storage_hashed_keys(custom_heap_pages: bool) -> Vec<&'static str> {
|
||||
let mut res = vec![
|
||||
//System|:__STORAGE_VERSION__:
|
||||
"00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429",
|
||||
//SubstrateTest|Authorities
|
||||
@@ -977,20 +984,25 @@ pub mod storage_key_generator {
|
||||
"3a636f6465",
|
||||
// :extrinsic_index
|
||||
"3a65787472696e7369635f696e646578",
|
||||
// :heappages
|
||||
"3a686561707061676573",
|
||||
// Balances|:__STORAGE_VERSION__:
|
||||
"c2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429",
|
||||
// Balances|TotalIssuance
|
||||
"c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80",
|
||||
].into_iter().map(String::from).collect::<Vec<_>>()
|
||||
];
|
||||
|
||||
if custom_heap_pages {
|
||||
// :heappages
|
||||
res.push("3a686561707061676573");
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expected_keys_vec_are_matching() {
|
||||
assert_eq!(
|
||||
storage_key_generator::get_expected_storage_hashed_keys(),
|
||||
storage_key_generator::generate_expected_storage_hashed_keys(),
|
||||
storage_key_generator::get_expected_storage_hashed_keys(false),
|
||||
storage_key_generator::generate_expected_storage_hashed_keys(false),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1001,15 +1013,14 @@ mod tests {
|
||||
use codec::Encode;
|
||||
use frame_support::dispatch::DispatchInfo;
|
||||
use sc_block_builder::BlockBuilderProvider;
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_core::{storage::well_known_keys::HEAP_PAGES, ExecutionContext};
|
||||
use sp_core::{storage::well_known_keys::HEAP_PAGES, traits::CallContext};
|
||||
use sp_keyring::AccountKeyring;
|
||||
use sp_runtime::{
|
||||
traits::{Hash as _, SignedExtension},
|
||||
transaction_validity::{InvalidTransaction, ValidTransaction},
|
||||
};
|
||||
use sp_state_machine::ExecutionStrategy;
|
||||
use substrate_test_runtime_client::{
|
||||
prelude::*, runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder,
|
||||
};
|
||||
@@ -1019,20 +1030,15 @@ mod tests {
|
||||
// This tests that the on-chain `HEAP_PAGES` parameter is respected.
|
||||
|
||||
// Create a client devoting only 8 pages of wasm memory. This gives us ~512k of heap memory.
|
||||
let mut client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
|
||||
.set_heap_pages(8)
|
||||
.build();
|
||||
let mut client = TestClientBuilder::new().set_heap_pages(8).build();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
|
||||
// Try to allocate 1024k of memory on heap. This is going to fail since it is twice larger
|
||||
// than the heap.
|
||||
let ret = client.runtime_api().vec_with_capacity_with_context(
|
||||
best_hash,
|
||||
// Use `BlockImport` to ensure we use the on chain heap pages as configured above.
|
||||
ExecutionContext::Importing,
|
||||
1048576,
|
||||
);
|
||||
let mut runtime_api = client.runtime_api();
|
||||
// This is currently required to allocate the 1024k of memory as configured above.
|
||||
runtime_api.set_call_context(CallContext::Onchain);
|
||||
let ret = runtime_api.vec_with_capacity(best_hash, 1048576);
|
||||
assert!(ret.is_err());
|
||||
|
||||
// Create a block that sets the `:heap_pages` to 32 pages of memory which corresponds to
|
||||
@@ -1054,8 +1060,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_storage() {
|
||||
let client =
|
||||
TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
|
||||
let client = TestClientBuilder::new().build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
|
||||
@@ -1080,8 +1085,7 @@ mod tests {
|
||||
let backend =
|
||||
sp_state_machine::TrieBackendBuilder::<_, crate::Hashing>::new(db, root).build();
|
||||
let proof = sp_state_machine::prove_read(backend, vec![b"value3"]).unwrap();
|
||||
let client =
|
||||
TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
|
||||
let client = TestClientBuilder::new().build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
|
||||
@@ -1108,7 +1112,7 @@ mod tests {
|
||||
.cloned()
|
||||
.map(storage_key_generator::hex)
|
||||
.collect::<Vec<_>>(),
|
||||
storage_key_generator::get_expected_storage_hashed_keys()
|
||||
storage_key_generator::get_expected_storage_hashed_keys(false)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
use frame_support::{pallet_prelude::*, storage};
|
||||
use sp_core::sr25519::Public;
|
||||
use sp_runtime::{
|
||||
traits::{BlakeTwo256, Hash},
|
||||
traits::Hash,
|
||||
transaction_validity::{
|
||||
InvalidTransaction, TransactionSource, TransactionValidity, ValidTransaction,
|
||||
},
|
||||
@@ -41,7 +41,7 @@ pub mod pallet {
|
||||
use crate::TransferData;
|
||||
use frame_system::pallet_prelude::*;
|
||||
use sp_core::storage::well_known_keys;
|
||||
use sp_runtime::{transaction_validity::TransactionPriority, Perbill};
|
||||
use sp_runtime::{traits::BlakeTwo256, transaction_validity::TransactionPriority, Perbill};
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::without_storage_info]
|
||||
|
||||
@@ -39,12 +39,12 @@ use super::bench::{Benchmark, BenchmarkParams};
|
||||
/// did not use more weight than declared which would otherwise be an issue.
|
||||
/// To test this with a dev node, first create one with a temp directory:
|
||||
///
|
||||
/// $ substrate --dev -d /tmp/my-dev --execution wasm --wasm-execution compiled
|
||||
/// $ substrate --dev -d /tmp/my-dev --wasm-execution compiled
|
||||
///
|
||||
/// And wait some time to let it produce 3 blocks. Then benchmark them with:
|
||||
///
|
||||
/// $ substrate benchmark-block --from 1 --to 3 --dev -d /tmp/my-dev
|
||||
/// --execution wasm --wasm-execution compiled --pruning archive
|
||||
/// --wasm-execution compiled --pruning archive
|
||||
///
|
||||
/// The output will be similar to this:
|
||||
///
|
||||
|
||||
@@ -103,12 +103,12 @@ Writing weights to "extrinsic_weights.rs"
|
||||
|
||||
The complete command for Polkadot looks like this:
|
||||
```sh
|
||||
cargo run --profile=production -- benchmark overhead --chain=polkadot-dev --execution=wasm --wasm-execution=compiled --weight-path=runtime/polkadot/constants/src/weights/
|
||||
cargo run --profile=production -- benchmark overhead --chain=polkadot-dev --wasm-execution=compiled --weight-path=runtime/polkadot/constants/src/weights/
|
||||
```
|
||||
|
||||
This will overwrite the the [block_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/block_weights.rs) and [extrinsic_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/extrinsic_weights.rs) files in the Polkadot runtime directory.
|
||||
You can try the same for *Rococo* and to see that the results slightly differ.
|
||||
👉 It is paramount to use `--profile=production`, `--execution=wasm` and `--wasm-execution=compiled` as the results are otherwise useless.
|
||||
👉 It is paramount to use `--profile=production` and `--wasm-execution=compiled` as the results are otherwise useless.
|
||||
|
||||
## Output Interpretation
|
||||
|
||||
@@ -122,7 +122,6 @@ Minimizing this is important to have a large transaction throughput.
|
||||
- `--weight-path` Set the output directory or file to write the weights to.
|
||||
- `--repeat` Set the repetitions of both benchmarks.
|
||||
- `--warmup` Set the rounds of warmup before measuring.
|
||||
- `--execution` Should be set to `wasm` for correct results.
|
||||
- `--wasm-execution` Should be set to `compiled` for correct results.
|
||||
- [`--mul`](../shared/README.md#arguments)
|
||||
- [`--add`](../shared/README.md#arguments)
|
||||
|
||||
@@ -23,9 +23,7 @@ use frame_benchmarking::{
|
||||
};
|
||||
use frame_support::traits::StorageInfo;
|
||||
use linked_hash_map::LinkedHashMap;
|
||||
use sc_cli::{
|
||||
execution_method_from_cli, CliConfiguration, ExecutionStrategy, Result, SharedParams,
|
||||
};
|
||||
use sc_cli::{execution_method_from_cli, CliConfiguration, Result, SharedParams};
|
||||
use sc_client_db::BenchmarkingState;
|
||||
use sc_executor::WasmExecutor;
|
||||
use sc_service::Configuration;
|
||||
@@ -182,7 +180,6 @@ impl PalletCmd {
|
||||
}
|
||||
|
||||
let spec = config.chain_spec;
|
||||
let strategy = self.execution.unwrap_or(ExecutionStrategy::Wasm);
|
||||
let pallet = self.pallet.clone().unwrap_or_default();
|
||||
let pallet = pallet.as_bytes();
|
||||
let extrinsic = self.extrinsic.clone().unwrap_or_default();
|
||||
@@ -243,11 +240,11 @@ impl PalletCmd {
|
||||
&executor,
|
||||
"Benchmark_benchmark_metadata",
|
||||
&(self.extra).encode(),
|
||||
extensions(),
|
||||
&mut extensions(),
|
||||
&sp_state_machine::backend::BackendRuntimeCode::new(state).runtime_code()?,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.execute(strategy.into())
|
||||
.execute()
|
||||
.map_err(|e| format!("{}: {}", ERROR_METADATA_NOT_FOUND, e))?;
|
||||
|
||||
let (list, storage_info) =
|
||||
@@ -379,12 +376,12 @@ impl PalletCmd {
|
||||
1, // no need to do internal repeats
|
||||
)
|
||||
.encode(),
|
||||
extensions(),
|
||||
&mut extensions(),
|
||||
&sp_state_machine::backend::BackendRuntimeCode::new(state)
|
||||
.runtime_code()?,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.execute(strategy.into())
|
||||
.execute()
|
||||
.map_err(|e| {
|
||||
format!("Error executing and verifying runtime benchmark: {}", e)
|
||||
})?;
|
||||
@@ -419,12 +416,12 @@ impl PalletCmd {
|
||||
self.repeat,
|
||||
)
|
||||
.encode(),
|
||||
extensions(),
|
||||
&mut extensions(),
|
||||
&sp_state_machine::backend::BackendRuntimeCode::new(state)
|
||||
.runtime_code()?,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.execute(strategy.into())
|
||||
.execute()
|
||||
.map_err(|e| format!("Error executing runtime benchmark: {}", e))?;
|
||||
|
||||
let batch =
|
||||
@@ -451,12 +448,12 @@ impl PalletCmd {
|
||||
self.repeat,
|
||||
)
|
||||
.encode(),
|
||||
extensions(),
|
||||
&mut extensions(),
|
||||
&sp_state_machine::backend::BackendRuntimeCode::new(state)
|
||||
.runtime_code()?,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.execute(strategy.into())
|
||||
.execute()
|
||||
.map_err(|e| format!("Error executing runtime benchmark: {}", e))?;
|
||||
|
||||
let batch =
|
||||
|
||||
@@ -20,8 +20,8 @@ mod writer;
|
||||
|
||||
use crate::shared::HostInfoParams;
|
||||
use sc_cli::{
|
||||
ExecutionStrategy, WasmExecutionMethod, WasmtimeInstantiationStrategy,
|
||||
DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, DEFAULT_WASM_EXECUTION_METHOD,
|
||||
WasmExecutionMethod, WasmtimeInstantiationStrategy, DEFAULT_WASMTIME_INSTANTIATION_STRATEGY,
|
||||
DEFAULT_WASM_EXECUTION_METHOD,
|
||||
};
|
||||
use std::{fmt::Debug, path::PathBuf};
|
||||
|
||||
@@ -129,10 +129,6 @@ pub struct PalletCmd {
|
||||
#[clap(flatten)]
|
||||
pub shared_params: sc_cli::SharedParams,
|
||||
|
||||
/// The execution strategy that should be used for benchmarks.
|
||||
#[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)]
|
||||
pub execution: Option<ExecutionStrategy>,
|
||||
|
||||
/// Method for executing Wasm runtime code.
|
||||
#[arg(
|
||||
long = "wasm-execution",
|
||||
|
||||
@@ -90,7 +90,6 @@ struct CmdData {
|
||||
repeat: u32,
|
||||
lowest_range_values: Vec<u32>,
|
||||
highest_range_values: Vec<u32>,
|
||||
execution: String,
|
||||
wasm_execution: String,
|
||||
chain: String,
|
||||
db_cache: u32,
|
||||
@@ -425,7 +424,6 @@ pub(crate) fn write_results(
|
||||
repeat: cmd.repeat,
|
||||
lowest_range_values: cmd.lowest_range_values.clone(),
|
||||
highest_range_values: cmd.highest_range_values.clone(),
|
||||
execution: format!("{:?}", cmd.execution),
|
||||
wasm_execution: cmd.wasm_method.to_string(),
|
||||
chain: format!("{:?}", cmd.shared_params.chain),
|
||||
db_cache: cmd.database_cache_size,
|
||||
|
||||
@@ -858,7 +858,7 @@ pub(crate) fn state_machine_call<Block: BlockT, HostFns: HostFunctions>(
|
||||
executor: &WasmExecutor<HostFns>,
|
||||
method: &'static str,
|
||||
data: &[u8],
|
||||
extensions: Extensions,
|
||||
mut extensions: Extensions,
|
||||
) -> sc_cli::Result<(OverlayedChanges, Vec<u8>)> {
|
||||
let mut changes = Default::default();
|
||||
let encoded_results = StateMachine::new(
|
||||
@@ -867,11 +867,11 @@ pub(crate) fn state_machine_call<Block: BlockT, HostFns: HostFunctions>(
|
||||
executor,
|
||||
method,
|
||||
data,
|
||||
extensions,
|
||||
&mut extensions,
|
||||
&sp_state_machine::backend::BackendRuntimeCode::new(&ext.backend).runtime_code()?,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.execute(sp_state_machine::ExecutionStrategy::AlwaysWasm)
|
||||
.execute()
|
||||
.map_err(|e| format!("failed to execute '{}': {}", method, e))
|
||||
.map_err::<sc_cli::Error, _>(Into::into)?;
|
||||
|
||||
@@ -887,7 +887,7 @@ pub(crate) fn state_machine_call_with_proof<Block: BlockT, HostFns: HostFunction
|
||||
executor: &WasmExecutor<HostFns>,
|
||||
method: &'static str,
|
||||
data: &[u8],
|
||||
extensions: Extensions,
|
||||
mut extensions: Extensions,
|
||||
maybe_export_proof: Option<PathBuf>,
|
||||
) -> sc_cli::Result<(OverlayedChanges, Vec<u8>)> {
|
||||
use parity_scale_codec::Encode;
|
||||
@@ -906,11 +906,11 @@ pub(crate) fn state_machine_call_with_proof<Block: BlockT, HostFns: HostFunction
|
||||
executor,
|
||||
method,
|
||||
data,
|
||||
extensions,
|
||||
&mut extensions,
|
||||
&runtime_code,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.execute(sp_state_machine::ExecutionStrategy::AlwaysWasm)
|
||||
.execute()
|
||||
.map_err(|e| format!("failed to execute {}: {}", method, e))
|
||||
.map_err::<sc_cli::Error, _>(Into::into)?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user