mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 03:01:07 +00:00
feat/ocw/bookkeeping (#5200)
Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
f66168505b
commit
72ee7d5797
Generated
+2
@@ -7532,7 +7532,9 @@ name = "sp-offchain"
|
||||
version = "2.0.0-dev"
|
||||
dependencies = [
|
||||
"sp-api",
|
||||
"sp-core",
|
||||
"sp-runtime",
|
||||
"sp-state-machine",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -230,6 +230,7 @@ impl BenchDb {
|
||||
ExecutionExtensions::new(profile.into_execution_strategies(), None),
|
||||
Box::new(TaskExecutor::new()),
|
||||
None,
|
||||
Default::default(),
|
||||
).expect("Should not fail");
|
||||
|
||||
(client, backend)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use sp_core::ChangesTrieConfigurationRange;
|
||||
use sp_core::offchain::OffchainStorage;
|
||||
use sp_core::offchain::{OffchainStorage,storage::OffchainOverlayedChanges};
|
||||
use sp_runtime::{generic::BlockId, Justification, Storage};
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor, HashFor};
|
||||
use sp_state_machine::{
|
||||
@@ -148,6 +148,14 @@ pub trait BlockImportOperation<Block: BlockT> {
|
||||
child_update: ChildStorageCollection,
|
||||
) -> sp_blockchain::Result<()>;
|
||||
|
||||
/// Write offchain storage changes to the database.
|
||||
fn update_offchain_storage(
|
||||
&mut self,
|
||||
_offchain_update: OffchainOverlayedChanges,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inject changes trie data into the database.
|
||||
fn update_changes_trie(
|
||||
&mut self,
|
||||
|
||||
@@ -26,7 +26,7 @@ use sp_state_machine::{
|
||||
};
|
||||
use sc_executor::{RuntimeVersion, NativeVersion};
|
||||
use sp_externalities::Extensions;
|
||||
use sp_core::NativeOrEncoded;
|
||||
use sp_core::{NativeOrEncoded,offchain::storage::OffchainOverlayedChanges};
|
||||
|
||||
use sp_api::{ProofRecorder, InitializeBlock, StorageTransactionCache};
|
||||
use crate::execution_extensions::ExecutionExtensions;
|
||||
@@ -84,6 +84,7 @@ pub trait CallExecutor<B: BlockT> {
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
changes: &RefCell<OverlayedChanges>,
|
||||
offchain_changes: &RefCell<OffchainOverlayedChanges>,
|
||||
storage_transaction_cache: Option<&RefCell<
|
||||
StorageTransactionCache<B, <Self::Backend as crate::backend::Backend<B>>::State>,
|
||||
>>,
|
||||
|
||||
@@ -177,7 +177,7 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
||||
if let ExecutionContext::OffchainCall(Some(ext)) = context {
|
||||
extensions.register(
|
||||
OffchainExt::new(offchain::LimitedExternalities::new(capabilities, ext.0))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
(manager, extensions)
|
||||
|
||||
@@ -136,6 +136,18 @@ arg_enum! {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
arg_enum! {
|
||||
/// Whether off-chain workers are enabled.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum OffchainWorkerEnabled {
|
||||
Always,
|
||||
Never,
|
||||
WhenValidating,
|
||||
}
|
||||
}
|
||||
|
||||
/// Default value for the `--execution-syncing` parameter.
|
||||
pub const DEFAULT_EXECUTION_SYNCING: ExecutionStrategy = ExecutionStrategy::NativeElseWasm;
|
||||
/// Default value for the `--execution-import-block` parameter.
|
||||
|
||||
@@ -144,6 +144,12 @@ macro_rules! substrate_cli_subcommands {
|
||||
}
|
||||
}
|
||||
|
||||
fn offchain_worker_params(&self) -> Option<&$crate::OffchainWorkerParams> {
|
||||
match self {
|
||||
$($enum::$variant(cmd) => cmd.offchain_worker_params()),*
|
||||
}
|
||||
}
|
||||
|
||||
fn base_path(&self) -> $crate::Result<::std::option::Option<::std::path::PathBuf>> {
|
||||
match self {
|
||||
$($enum::$variant(cmd) => cmd.base_path()),*
|
||||
@@ -327,7 +333,7 @@ macro_rules! substrate_cli_subcommands {
|
||||
}
|
||||
}
|
||||
|
||||
fn offchain_worker(&self, role: &::sc_service::Role) -> $crate::Result<bool> {
|
||||
fn offchain_worker(&self, role: &::sc_service::Role) -> $crate::Result<::sc_service::config::OffchainWorkerConfig> {
|
||||
match self {
|
||||
$($enum::$variant(cmd) => cmd.offchain_worker(role)),*
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ use crate::params::KeystoreParams;
|
||||
use crate::params::NetworkParams;
|
||||
use crate::params::SharedParams;
|
||||
use crate::params::TransactionPoolParams;
|
||||
use crate::params::OffchainWorkerParams;
|
||||
use crate::CliConfiguration;
|
||||
use regex::Regex;
|
||||
use sc_service::{
|
||||
@@ -28,18 +29,7 @@ use sc_service::{
|
||||
};
|
||||
use sc_telemetry::TelemetryEndpoints;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use structopt::{clap::arg_enum, StructOpt};
|
||||
|
||||
arg_enum! {
|
||||
/// Whether off-chain workers are enabled.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum OffchainWorkerEnabled {
|
||||
Always,
|
||||
Never,
|
||||
WhenValidating,
|
||||
}
|
||||
}
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// The `run` command used to run a node.
|
||||
#[derive(Debug, StructOpt, Clone)]
|
||||
@@ -173,17 +163,9 @@ pub struct RunCmd {
|
||||
#[structopt(long = "telemetry-url", value_name = "URL VERBOSITY", parse(try_from_str = parse_telemetry_endpoints))]
|
||||
pub telemetry_endpoints: Vec<(String, u8)>,
|
||||
|
||||
/// Should execute offchain workers on every block.
|
||||
///
|
||||
/// By default it's only enabled for nodes that are authoring new blocks.
|
||||
#[structopt(
|
||||
long = "offchain-worker",
|
||||
value_name = "ENABLED",
|
||||
possible_values = &OffchainWorkerEnabled::variants(),
|
||||
case_insensitive = true,
|
||||
default_value = "WhenValidating"
|
||||
)]
|
||||
pub offchain_worker: OffchainWorkerEnabled,
|
||||
#[allow(missing_docs)]
|
||||
#[structopt(flatten)]
|
||||
pub offchain_worker_params: OffchainWorkerParams,
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[structopt(flatten)]
|
||||
@@ -300,6 +282,10 @@ impl CliConfiguration for RunCmd {
|
||||
Some(&self.keystore_params)
|
||||
}
|
||||
|
||||
fn offchain_worker_params(&self) -> Option<&OffchainWorkerParams> {
|
||||
Some(&self.offchain_worker_params)
|
||||
}
|
||||
|
||||
fn node_name(&self) -> Result<String> {
|
||||
let name: String = match (self.name.as_ref(), self.get_keyring()) {
|
||||
(Some(name), _) => name.to_string(),
|
||||
@@ -439,15 +425,6 @@ impl CliConfiguration for RunCmd {
|
||||
Ok(self.unsafe_rpc_expose)
|
||||
}
|
||||
|
||||
fn offchain_worker(&self, role: &Role) -> Result<bool> {
|
||||
Ok(match (&self.offchain_worker, role) {
|
||||
(OffchainWorkerEnabled::WhenValidating, Role::Authority { .. }) => true,
|
||||
(OffchainWorkerEnabled::Always, _) => true,
|
||||
(OffchainWorkerEnabled::Never, _) => false,
|
||||
(OffchainWorkerEnabled::WhenValidating, _) => false,
|
||||
})
|
||||
}
|
||||
|
||||
fn transaction_pool(&self) -> Result<TransactionPoolOptions> {
|
||||
Ok(self.pool_config.transaction_pool())
|
||||
}
|
||||
|
||||
@@ -19,15 +19,15 @@
|
||||
use crate::error::Result;
|
||||
use crate::{
|
||||
init_logger, ImportParams, KeystoreParams, NetworkParams, NodeKeyParams,
|
||||
PruningParams, SharedParams, SubstrateCli,
|
||||
OffchainWorkerParams, PruningParams, SharedParams, SubstrateCli,
|
||||
};
|
||||
use crate::arg_enums::Database;
|
||||
use app_dirs::{AppDataType, AppInfo};
|
||||
use names::{Generator, Name};
|
||||
use sc_service::config::{
|
||||
Configuration, DatabaseConfig, ExecutionStrategies, ExtTransport, KeystoreConfig,
|
||||
NetworkConfiguration, NodeKeyConfig, PrometheusConfig, PruningMode, Role, TelemetryEndpoints,
|
||||
TransactionPoolOptions, WasmExecutionMethod,
|
||||
NetworkConfiguration, NodeKeyConfig, OffchainWorkerConfig, PrometheusConfig, PruningMode,
|
||||
Role, TelemetryEndpoints, TransactionPoolOptions, WasmExecutionMethod,
|
||||
};
|
||||
use sc_service::{ChainSpec, TracingReceiver};
|
||||
use std::future::Future;
|
||||
@@ -67,6 +67,11 @@ pub trait CliConfiguration: Sized {
|
||||
None
|
||||
}
|
||||
|
||||
/// Get a reference to `OffchainWorkerParams` for this object.
|
||||
fn offchain_worker_params(&self) -> Option<&OffchainWorkerParams> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Get the NodeKeyParams for this object
|
||||
fn node_key_params(&self) -> Option<&NodeKeyParams> {
|
||||
self.network_params()
|
||||
@@ -301,11 +306,13 @@ pub trait CliConfiguration: Sized {
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
/// Returns `Ok(true)` if offchain worker should be used
|
||||
/// Returns an offchain worker config wrapped in `Ok(_)`
|
||||
///
|
||||
/// By default this is `false`.
|
||||
fn offchain_worker(&self, _role: &Role) -> Result<bool> {
|
||||
Ok(Default::default())
|
||||
/// By default offchain workers are disabled.
|
||||
fn offchain_worker(&self, role: &Role) -> Result<OffchainWorkerConfig> {
|
||||
self.offchain_worker_params()
|
||||
.map(|x| x.offchain_worker(role))
|
||||
.unwrap_or_else(|| { Ok(OffchainWorkerConfig::default()) })
|
||||
}
|
||||
|
||||
/// Returns `Ok(true)` if authoring should be forced
|
||||
|
||||
@@ -21,6 +21,7 @@ mod node_key_params;
|
||||
mod pruning_params;
|
||||
mod shared_params;
|
||||
mod transaction_pool_params;
|
||||
mod offchain_worker_params;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::str::FromStr;
|
||||
@@ -29,6 +30,7 @@ pub use crate::params::import_params::*;
|
||||
pub use crate::params::keystore_params::*;
|
||||
pub use crate::params::network_params::*;
|
||||
pub use crate::params::node_key_params::*;
|
||||
pub use crate::params::offchain_worker_params::*;
|
||||
pub use crate::params::pruning_params::*;
|
||||
pub use crate::params::shared_params::*;
|
||||
pub use crate::params::transaction_pool_params::*;
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright 2020 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
//! Offchain worker related configuration parameters.
|
||||
//!
|
||||
//! A subset of configuration parameters which are relevant to
|
||||
//! the inner working of offchain workers. The usage is solely
|
||||
//! targeted at handling input parameter parsing providing
|
||||
//! a reasonable abstraction.
|
||||
|
||||
use structopt::StructOpt;
|
||||
use sc_service::config::OffchainWorkerConfig;
|
||||
use sc_network::config::Role;
|
||||
|
||||
use crate::error;
|
||||
use crate::OffchainWorkerEnabled;
|
||||
|
||||
|
||||
/// Offchain worker related parameters.
|
||||
#[derive(Debug, StructOpt, Clone)]
|
||||
pub struct OffchainWorkerParams {
|
||||
/// Should execute offchain workers on every block.
|
||||
///
|
||||
/// By default it's only enabled for nodes that are authoring new blocks.
|
||||
#[structopt(
|
||||
long = "offchain-worker",
|
||||
value_name = "ENABLED",
|
||||
possible_values = &OffchainWorkerEnabled::variants(),
|
||||
case_insensitive = true,
|
||||
default_value = "WhenValidating"
|
||||
)]
|
||||
pub enabled: OffchainWorkerEnabled,
|
||||
|
||||
/// Enable Offchain Indexing API, which allows block import to write to Offchain DB.
|
||||
///
|
||||
/// Enables a runtime to write directly to a offchain workers
|
||||
/// DB during block import.
|
||||
#[structopt(
|
||||
long = "enable-offchain-indexing",
|
||||
value_name = "ENABLE_OFFCHAIN_INDEXING"
|
||||
)]
|
||||
pub indexing_enabled: bool,
|
||||
}
|
||||
|
||||
impl OffchainWorkerParams {
|
||||
/// Load spec to `Configuration` from `OffchainWorkerParams` and spec factory.
|
||||
pub fn offchain_worker(
|
||||
&self,
|
||||
role: &Role,
|
||||
) -> error::Result<OffchainWorkerConfig>
|
||||
{
|
||||
let enabled = match (&self.enabled, role) {
|
||||
(OffchainWorkerEnabled::WhenValidating, Role::Authority { .. }) => true,
|
||||
(OffchainWorkerEnabled::Always, _) => true,
|
||||
(OffchainWorkerEnabled::Never, _) => false,
|
||||
(OffchainWorkerEnabled::WhenValidating, _) => false,
|
||||
};
|
||||
|
||||
let indexing_enabled = enabled && self.indexing_enabled;
|
||||
|
||||
Ok(OffchainWorkerConfig { enabled, indexing_enabled })
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ use std::path::{Path, PathBuf};
|
||||
use std::io;
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
||||
use sc_client_api::{
|
||||
ForkBlocks, UsageInfo, MemoryInfo, BadBlocks, IoInfo, MemorySize, CloneableSpawn,
|
||||
execution_extensions::ExecutionExtensions,
|
||||
@@ -65,6 +66,7 @@ use sp_trie::{MemoryDB, PrefixedMemoryDB, prefixed_key};
|
||||
use sp_database::Transaction;
|
||||
use parking_lot::RwLock;
|
||||
use sp_core::{ChangesTrieConfiguration, traits::CodeExecutor};
|
||||
use sp_core::offchain::storage::{OffchainOverlayedChange,OffchainOverlayedChanges};
|
||||
use sp_core::storage::{well_known_keys, ChildInfo};
|
||||
use sp_runtime::{
|
||||
generic::BlockId, Justification, Storage,
|
||||
@@ -324,6 +326,7 @@ pub fn new_client<E, Block, RA>(
|
||||
execution_extensions: ExecutionExtensions<Block>,
|
||||
spawn_handle: Box<dyn CloneableSpawn>,
|
||||
prometheus_registry: Option<Registry>,
|
||||
config: sc_client::ClientConfig,
|
||||
) -> Result<(
|
||||
sc_client::Client<
|
||||
Backend<Block>,
|
||||
@@ -340,7 +343,7 @@ pub fn new_client<E, Block, RA>(
|
||||
E: CodeExecutor + RuntimeInfo,
|
||||
{
|
||||
let backend = Arc::new(Backend::new(settings, CANONICALIZATION_DELAY)?);
|
||||
let executor = sc_client::LocalCallExecutor::new(backend.clone(), executor, spawn_handle);
|
||||
let executor = sc_client::LocalCallExecutor::new(backend.clone(), executor, spawn_handle, config.clone());
|
||||
Ok((
|
||||
sc_client::Client::new(
|
||||
backend.clone(),
|
||||
@@ -350,6 +353,7 @@ pub fn new_client<E, Block, RA>(
|
||||
bad_blocks,
|
||||
execution_extensions,
|
||||
prometheus_registry,
|
||||
config,
|
||||
)?,
|
||||
backend,
|
||||
))
|
||||
@@ -558,6 +562,7 @@ pub struct BlockImportOperation<Block: BlockT> {
|
||||
db_updates: PrefixedMemoryDB<HashFor<Block>>,
|
||||
storage_updates: StorageCollection,
|
||||
child_storage_updates: ChildStorageCollection,
|
||||
offchain_storage_updates: OffchainOverlayedChanges,
|
||||
changes_trie_updates: MemoryDB<HashFor<Block>>,
|
||||
changes_trie_build_cache_update: Option<ChangesTrieCacheAction<Block::Hash, NumberFor<Block>>>,
|
||||
changes_trie_config_update: Option<Option<ChangesTrieConfiguration>>,
|
||||
@@ -569,6 +574,15 @@ pub struct BlockImportOperation<Block: BlockT> {
|
||||
}
|
||||
|
||||
impl<Block: BlockT> BlockImportOperation<Block> {
|
||||
fn apply_offchain(&mut self, transaction: &mut Transaction<DbHash>) {
|
||||
for (key, value_operation) in self.offchain_storage_updates.drain() {
|
||||
match value_operation {
|
||||
OffchainOverlayedChange::SetValue(val) => transaction.set_from_vec(columns::OFFCHAIN, &key, val),
|
||||
OffchainOverlayedChange::Remove => transaction.remove(columns::OFFCHAIN, &key),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_aux(&mut self, transaction: &mut Transaction<DbHash>) {
|
||||
for (key, maybe_val) in self.aux_ops.drain(..) {
|
||||
match maybe_val {
|
||||
@@ -675,6 +689,14 @@ impl<Block: BlockT> sc_client_api::backend::BlockImportOperation<Block> for Bloc
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_offchain_storage(
|
||||
&mut self,
|
||||
offchain_update: OffchainOverlayedChanges,
|
||||
) -> ClientResult<()> {
|
||||
self.offchain_storage_updates = offchain_update;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mark_finalized(
|
||||
&mut self,
|
||||
block: BlockId<Block>,
|
||||
@@ -1017,6 +1039,7 @@ impl<Block: BlockT> Backend<Block> {
|
||||
let mut finalization_displaced_leaves = None;
|
||||
|
||||
operation.apply_aux(&mut transaction);
|
||||
operation.apply_offchain(&mut transaction);
|
||||
|
||||
let mut meta_updates = Vec::with_capacity(operation.finalized_blocks.len());
|
||||
let mut last_finalized_hash = self.blockchain.meta.read().finalized_hash;
|
||||
@@ -1360,6 +1383,7 @@ impl<Block: BlockT> sc_client_api::backend::Backend<Block> for Backend<Block> {
|
||||
db_updates: PrefixedMemoryDB::default(),
|
||||
storage_updates: Default::default(),
|
||||
child_storage_updates: Default::default(),
|
||||
offchain_storage_updates: Default::default(),
|
||||
changes_trie_config_update: None,
|
||||
changes_trie_updates: MemoryDB::default(),
|
||||
changes_trie_build_cache_update: None,
|
||||
|
||||
@@ -183,6 +183,12 @@ sp_core::wasm_export_functions! {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn test_offchain_index_set() {
|
||||
sp_io::offchain_index::set(b"k", b"v");
|
||||
}
|
||||
|
||||
|
||||
fn test_offchain_local_storage() -> bool {
|
||||
let kind = sp_core::offchain::StorageKind::PERSISTENT;
|
||||
assert_eq!(sp_io::offchain::local_storage_get(kind, b"test"), None);
|
||||
|
||||
@@ -450,6 +450,28 @@ fn ordered_trie_root_should_work(wasm_method: WasmExecutionMethod) {
|
||||
);
|
||||
}
|
||||
|
||||
#[test_case(WasmExecutionMethod::Interpreted)]
|
||||
#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
|
||||
fn offchain_index(wasm_method: WasmExecutionMethod) {
|
||||
let mut ext = TestExternalities::default();
|
||||
let (offchain, _state) = testing::TestOffchainExt::new();
|
||||
ext.register_extension(OffchainExt::new(offchain));
|
||||
call_in_wasm(
|
||||
"test_offchain_index_set",
|
||||
&[0],
|
||||
wasm_method,
|
||||
&mut ext.ext(),
|
||||
).unwrap();
|
||||
|
||||
use sp_core::offchain::storage::OffchainOverlayedChange;
|
||||
assert_eq!(
|
||||
ext.ext()
|
||||
.get_offchain_storage_changes()
|
||||
.get(sp_core::offchain::STORAGE_PREFIX, b"k"),
|
||||
Some(OffchainOverlayedChange::SetValue(b"v".to_vec()))
|
||||
);
|
||||
}
|
||||
|
||||
#[test_case(WasmExecutionMethod::Interpreted)]
|
||||
#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
|
||||
fn offchain_local_storage_should_work(wasm_method: WasmExecutionMethod) {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use crate::{Service, NetworkStatus, NetworkState, error::Error, DEFAULT_PROTOCOL_ID, MallocSizeOfWasm};
|
||||
use crate::{start_rpc_servers, build_network_future, TransactionPoolAdapter, TaskManager};
|
||||
use crate::status_sinks;
|
||||
use crate::config::{Configuration, KeystoreConfig, PrometheusConfig};
|
||||
use crate::config::{Configuration, KeystoreConfig, PrometheusConfig, OffchainWorkerConfig};
|
||||
use crate::metrics::MetricsService;
|
||||
use sc_client_api::{
|
||||
self,
|
||||
@@ -27,7 +27,7 @@ use sc_client_api::{
|
||||
ExecutorProvider, CallExecutor
|
||||
};
|
||||
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender};
|
||||
use sc_client::Client;
|
||||
use sc_client::{Client, ClientConfig};
|
||||
use sc_chain_spec::get_extension;
|
||||
use sp_consensus::import_queue::ImportQueue;
|
||||
use futures::{
|
||||
@@ -215,6 +215,10 @@ fn new_full_parts<TBl, TRtApi, TExecDisp>(
|
||||
extensions,
|
||||
Box::new(task_manager.spawn_handle()),
|
||||
config.prometheus_config.as_ref().map(|config| config.registry.clone()),
|
||||
ClientConfig {
|
||||
offchain_worker_enabled : config.offchain_worker.enabled ,
|
||||
offchain_indexing_api: config.offchain_worker.indexing_enabled,
|
||||
},
|
||||
)?
|
||||
};
|
||||
|
||||
@@ -834,11 +838,11 @@ ServiceBuilder<
|
||||
let network_status_sinks = Arc::new(Mutex::new(status_sinks::StatusSinks::new()));
|
||||
|
||||
let offchain_storage = backend.offchain_storage();
|
||||
let offchain_workers = match (config.offchain_worker, offchain_storage.clone()) {
|
||||
(true, Some(db)) => {
|
||||
let offchain_workers = match (config.offchain_worker.clone(), offchain_storage.clone()) {
|
||||
(OffchainWorkerConfig {enabled: true, .. }, Some(db)) => {
|
||||
Some(Arc::new(sc_offchain::OffchainWorkers::new(client.clone(), db)))
|
||||
},
|
||||
(true, None) => {
|
||||
(OffchainWorkerConfig {enabled: true, .. }, None) => {
|
||||
warn!("Offchain workers disabled, due to lack of offchain storage support in backend.");
|
||||
None
|
||||
},
|
||||
|
||||
@@ -79,7 +79,7 @@ pub struct Configuration {
|
||||
/// The default number of 64KB pages to allocate for Wasm execution
|
||||
pub default_heap_pages: Option<u64>,
|
||||
/// Should offchain workers be executed.
|
||||
pub offchain_worker: bool,
|
||||
pub offchain_worker: OffchainWorkerConfig,
|
||||
/// Enable authoring even when offline.
|
||||
pub force_authoring: bool,
|
||||
/// Disable GRANDPA when running in validator mode
|
||||
@@ -125,6 +125,14 @@ impl KeystoreConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Configuration of the database of the client.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct OffchainWorkerConfig {
|
||||
/// If this is allowed.
|
||||
pub enabled: bool,
|
||||
/// allow writes from the runtime to the offchain worker database.
|
||||
pub indexing_enabled: bool,
|
||||
}
|
||||
|
||||
/// Configuration of the Prometheus endpoint.
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -195,7 +195,7 @@ fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'sta
|
||||
telemetry_endpoints: None,
|
||||
telemetry_external_transport: None,
|
||||
default_heap_pages: None,
|
||||
offchain_worker: false,
|
||||
offchain_worker: Default::default(),
|
||||
force_authoring: false,
|
||||
disable_grandpa: false,
|
||||
dev_key_seed: key_seed,
|
||||
|
||||
@@ -25,9 +25,10 @@ use sp_state_machine::{
|
||||
};
|
||||
use sc_executor::{RuntimeVersion, RuntimeInfo, NativeVersion};
|
||||
use sp_externalities::Extensions;
|
||||
use sp_core::{NativeOrEncoded, NeverNativeValue, traits::CodeExecutor};
|
||||
use sp_core::{NativeOrEncoded, NeverNativeValue, traits::CodeExecutor, offchain::storage::OffchainOverlayedChanges};
|
||||
use sp_api::{ProofRecorder, InitializeBlock, StorageTransactionCache};
|
||||
use sc_client_api::{backend, call_executor::CallExecutor, CloneableSpawn};
|
||||
use crate::client::ClientConfig;
|
||||
|
||||
/// Call executor that executes methods locally, querying all required
|
||||
/// data from local backend.
|
||||
@@ -35,6 +36,7 @@ pub struct LocalCallExecutor<B, E> {
|
||||
backend: Arc<B>,
|
||||
executor: E,
|
||||
spawn_handle: Box<dyn CloneableSpawn>,
|
||||
client_config: ClientConfig,
|
||||
}
|
||||
|
||||
impl<B, E> LocalCallExecutor<B, E> {
|
||||
@@ -43,11 +45,13 @@ impl<B, E> LocalCallExecutor<B, E> {
|
||||
backend: Arc<B>,
|
||||
executor: E,
|
||||
spawn_handle: Box<dyn CloneableSpawn>,
|
||||
client_config: ClientConfig,
|
||||
) -> Self {
|
||||
LocalCallExecutor {
|
||||
backend,
|
||||
executor,
|
||||
spawn_handle,
|
||||
client_config,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +62,7 @@ impl<B, E> Clone for LocalCallExecutor<B, E> where E: Clone {
|
||||
backend: self.backend.clone(),
|
||||
executor: self.executor.clone(),
|
||||
spawn_handle: self.spawn_handle.clone(),
|
||||
client_config: self.client_config.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,6 +86,11 @@ where
|
||||
extensions: Option<Extensions>,
|
||||
) -> sp_blockchain::Result<Vec<u8>> {
|
||||
let mut changes = OverlayedChanges::default();
|
||||
let mut offchain_changes = if self.client_config.offchain_indexing_api {
|
||||
OffchainOverlayedChanges::enabled()
|
||||
} else {
|
||||
OffchainOverlayedChanges::disabled()
|
||||
};
|
||||
let changes_trie = backend::changes_tries_state_at_block(
|
||||
id, self.backend.changes_trie_storage()
|
||||
)?;
|
||||
@@ -90,6 +100,7 @@ where
|
||||
&state,
|
||||
changes_trie,
|
||||
&mut changes,
|
||||
&mut offchain_changes,
|
||||
&self.executor,
|
||||
method,
|
||||
call_data,
|
||||
@@ -120,6 +131,7 @@ where
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
changes: &RefCell<OverlayedChanges>,
|
||||
offchain_changes: &RefCell<OffchainOverlayedChanges>,
|
||||
storage_transaction_cache: Option<&RefCell<
|
||||
StorageTransactionCache<Block, B::State>
|
||||
>>,
|
||||
@@ -143,6 +155,9 @@ where
|
||||
|
||||
let mut state = self.backend.state_at(*at)?;
|
||||
|
||||
let changes = &mut *changes.borrow_mut();
|
||||
let offchain_changes = &mut *offchain_changes.borrow_mut();
|
||||
|
||||
match recorder {
|
||||
Some(recorder) => {
|
||||
let trie_state = state.as_trie_backend()
|
||||
@@ -160,11 +175,11 @@ where
|
||||
recorder.clone(),
|
||||
);
|
||||
|
||||
let changes = &mut *changes.borrow_mut();
|
||||
let mut state_machine = StateMachine::new(
|
||||
&backend,
|
||||
changes_trie_state,
|
||||
changes,
|
||||
offchain_changes,
|
||||
&self.executor,
|
||||
method,
|
||||
call_data,
|
||||
@@ -179,11 +194,11 @@ where
|
||||
None => {
|
||||
let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state);
|
||||
let runtime_code = state_runtime_code.runtime_code()?;
|
||||
let changes = &mut *changes.borrow_mut();
|
||||
let mut state_machine = StateMachine::new(
|
||||
&state,
|
||||
changes_trie_state,
|
||||
changes,
|
||||
offchain_changes,
|
||||
&self.executor,
|
||||
method,
|
||||
call_data,
|
||||
@@ -198,6 +213,7 @@ where
|
||||
|
||||
fn runtime_version(&self, id: &BlockId<Block>) -> sp_blockchain::Result<RuntimeVersion> {
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let mut offchain_overlay = OffchainOverlayedChanges::default();
|
||||
let changes_trie_state = backend::changes_tries_state_at_block(
|
||||
id,
|
||||
self.backend.changes_trie_storage(),
|
||||
@@ -206,6 +222,7 @@ where
|
||||
let mut cache = StorageTransactionCache::<Block, B::State>::default();
|
||||
let mut ext = Ext::new(
|
||||
&mut overlay,
|
||||
&mut offchain_overlay,
|
||||
&mut cache,
|
||||
&state,
|
||||
changes_trie_state,
|
||||
|
||||
@@ -99,6 +99,7 @@ pub struct Client<B, E, Block, RA> where Block: BlockT {
|
||||
importing_block: RwLock<Option<Block::Hash>>,
|
||||
block_rules: BlockRules<Block>,
|
||||
execution_extensions: ExecutionExtensions<Block>,
|
||||
config: ClientConfig,
|
||||
_phantom: PhantomData<RA>,
|
||||
}
|
||||
|
||||
@@ -136,6 +137,7 @@ pub fn new_in_mem<E, Block, S, RA>(
|
||||
keystore: Option<sp_core::traits::BareCryptoStorePtr>,
|
||||
prometheus_registry: Option<Registry>,
|
||||
spawn_handle: Box<dyn CloneableSpawn>,
|
||||
config: ClientConfig,
|
||||
) -> sp_blockchain::Result<Client<
|
||||
in_mem::Backend<Block>,
|
||||
LocalCallExecutor<in_mem::Backend<Block>, E>,
|
||||
@@ -146,7 +148,24 @@ pub fn new_in_mem<E, Block, S, RA>(
|
||||
S: BuildStorage,
|
||||
Block: BlockT,
|
||||
{
|
||||
new_with_backend(Arc::new(in_mem::Backend::new()), executor, genesis_storage, keystore, spawn_handle, prometheus_registry)
|
||||
new_with_backend(
|
||||
Arc::new(in_mem::Backend::new()),
|
||||
executor,
|
||||
genesis_storage,
|
||||
keystore,
|
||||
spawn_handle,
|
||||
prometheus_registry,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Relevant client configuration items relevant for the client.
|
||||
#[derive(Debug,Clone,Default)]
|
||||
pub struct ClientConfig {
|
||||
/// Enable the offchain worker db.
|
||||
pub offchain_worker_enabled: bool,
|
||||
/// If true, allows access from the runtime to write into offchain worker db.
|
||||
pub offchain_indexing_api: bool,
|
||||
}
|
||||
|
||||
/// Create a client with the explicitly provided backend.
|
||||
@@ -158,6 +177,7 @@ pub fn new_with_backend<B, E, Block, S, RA>(
|
||||
keystore: Option<sp_core::traits::BareCryptoStorePtr>,
|
||||
spawn_handle: Box<dyn CloneableSpawn>,
|
||||
prometheus_registry: Option<Registry>,
|
||||
config: ClientConfig,
|
||||
) -> sp_blockchain::Result<Client<B, LocalCallExecutor<B, E>, Block, RA>>
|
||||
where
|
||||
E: CodeExecutor + RuntimeInfo,
|
||||
@@ -165,7 +185,7 @@ pub fn new_with_backend<B, E, Block, S, RA>(
|
||||
Block: BlockT,
|
||||
B: backend::LocalBackend<Block> + 'static,
|
||||
{
|
||||
let call_executor = LocalCallExecutor::new(backend.clone(), executor, spawn_handle);
|
||||
let call_executor = LocalCallExecutor::new(backend.clone(), executor, spawn_handle, config.clone());
|
||||
let extensions = ExecutionExtensions::new(Default::default(), keystore);
|
||||
Client::new(
|
||||
backend,
|
||||
@@ -175,6 +195,7 @@ pub fn new_with_backend<B, E, Block, S, RA>(
|
||||
Default::default(),
|
||||
extensions,
|
||||
prometheus_registry,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -243,6 +264,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block>,
|
||||
E: CallExecutor<Block>,
|
||||
Block: BlockT,
|
||||
Block::Header: Clone,
|
||||
{
|
||||
/// Creates new Substrate Client with given blockchain and code executor.
|
||||
pub fn new(
|
||||
@@ -253,6 +275,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
bad_blocks: BadBlocks<Block>,
|
||||
execution_extensions: ExecutionExtensions<Block>,
|
||||
prometheus_registry: Option<Registry>,
|
||||
config: ClientConfig,
|
||||
) -> sp_blockchain::Result<Self> {
|
||||
if backend.blockchain().header(BlockId::Number(Zero::zero()))?.is_none() {
|
||||
let genesis_storage = build_genesis_storage.build_storage()?;
|
||||
@@ -282,6 +305,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
importing_block: Default::default(),
|
||||
block_rules: BlockRules::new(fork_blocks, bad_blocks),
|
||||
execution_extensions,
|
||||
config,
|
||||
_phantom: Default::default(),
|
||||
})
|
||||
}
|
||||
@@ -614,7 +638,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
if let Ok(ImportResult::Imported(ref aux)) = result {
|
||||
if aux.is_new_best {
|
||||
use rand::Rng;
|
||||
|
||||
|
||||
// don't send telemetry block import events during initial sync for every
|
||||
// block to avoid spamming the telemetry server, these events will be randomly
|
||||
// sent at a rate of 1/10.
|
||||
@@ -696,7 +720,22 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
|
||||
operation.op.update_cache(new_cache);
|
||||
|
||||
let (main_sc, child_sc, tx, _, changes_trie_tx) = storage_changes.into_inner();
|
||||
let (
|
||||
main_sc,
|
||||
child_sc,
|
||||
offchain_sc,
|
||||
tx, _,
|
||||
changes_trie_tx,
|
||||
) = storage_changes.into_inner();
|
||||
|
||||
if self.config.offchain_indexing_api {
|
||||
// if let Some(mut offchain_storage) = self.backend.offchain_storage() {
|
||||
// offchain_sc.iter().for_each(|(k,v)| {
|
||||
// offchain_storage.set(b"block-import-info", k,v)
|
||||
// });
|
||||
// }
|
||||
operation.op.update_offchain_storage(offchain_sc)?;
|
||||
}
|
||||
|
||||
operation.op.update_db_storage(tx)?;
|
||||
operation.op.update_storage(main_sc.clone(), child_sc.clone())?;
|
||||
@@ -1554,6 +1593,7 @@ impl<B, E, Block, RA> CallApiAt<Block> for Client<B, E, Block, RA> where
|
||||
params.function,
|
||||
¶ms.arguments,
|
||||
params.overlayed_changes,
|
||||
params.offchain_changes,
|
||||
Some(params.storage_transaction_cache),
|
||||
params.initialize_block,
|
||||
manager,
|
||||
@@ -3493,6 +3533,7 @@ pub(crate) mod tests {
|
||||
None,
|
||||
None,
|
||||
sp_core::tasks::executor(),
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ mod tests {
|
||||
};
|
||||
use sp_runtime::traits::BlakeTwo256;
|
||||
use sp_core::tasks::executor as tasks_executor;
|
||||
use sp_core::offchain::storage::OffchainOverlayedChanges;
|
||||
use hex_literal::*;
|
||||
|
||||
native_executor_instance!(
|
||||
@@ -90,6 +91,7 @@ mod tests {
|
||||
};
|
||||
let hash = header.hash();
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let mut offchain_overlay = OffchainOverlayedChanges::default();
|
||||
let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&backend);
|
||||
let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend");
|
||||
|
||||
@@ -97,6 +99,7 @@ mod tests {
|
||||
backend,
|
||||
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
|
||||
&mut overlay,
|
||||
&mut offchain_overlay,
|
||||
&executor(),
|
||||
"Core_initialize_block",
|
||||
&header.encode(),
|
||||
@@ -112,6 +115,7 @@ mod tests {
|
||||
backend,
|
||||
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
|
||||
&mut overlay,
|
||||
&mut offchain_overlay,
|
||||
&executor(),
|
||||
"BlockBuilder_apply_extrinsic",
|
||||
&tx.encode(),
|
||||
@@ -127,6 +131,7 @@ mod tests {
|
||||
backend,
|
||||
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
|
||||
&mut overlay,
|
||||
&mut offchain_overlay,
|
||||
&executor(),
|
||||
"BlockBuilder_finalize_block",
|
||||
&[],
|
||||
@@ -174,10 +179,13 @@ mod tests {
|
||||
let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend");
|
||||
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let mut offchain_overlay = OffchainOverlayedChanges::default();
|
||||
|
||||
let _ = StateMachine::new(
|
||||
&backend,
|
||||
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
|
||||
&mut overlay,
|
||||
&mut offchain_overlay,
|
||||
&executor(),
|
||||
"Core_execute_block",
|
||||
&b1data,
|
||||
@@ -206,10 +214,13 @@ mod tests {
|
||||
let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend");
|
||||
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let mut offchain_overlay = OffchainOverlayedChanges::default();
|
||||
|
||||
let _ = StateMachine::new(
|
||||
&backend,
|
||||
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
|
||||
&mut overlay,
|
||||
&mut offchain_overlay,
|
||||
&executor(),
|
||||
"Core_execute_block",
|
||||
&b1data,
|
||||
@@ -238,10 +249,13 @@ mod tests {
|
||||
let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend");
|
||||
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let mut offchain_overlay = OffchainOverlayedChanges::default();
|
||||
|
||||
let r = StateMachine::new(
|
||||
&backend,
|
||||
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
|
||||
&mut overlay,
|
||||
&mut offchain_overlay,
|
||||
&executor(),
|
||||
"Core_execute_block",
|
||||
&b1data,
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
//! backend.clone(),
|
||||
//! NativeExecutor::<LocalExecutor>::new(WasmExecutionMethod::Interpreted, None, 8),
|
||||
//! sp_core::tasks::executor(),
|
||||
//! Default::default(),
|
||||
//! ),
|
||||
//! // This parameter provides the storage for the chain genesis.
|
||||
//! &<Storage>::default(),
|
||||
@@ -70,6 +71,7 @@
|
||||
//! Default::default(),
|
||||
//! Default::default(),
|
||||
//! None,
|
||||
//! Default::default(),
|
||||
//! );
|
||||
//! ```
|
||||
//!
|
||||
@@ -99,8 +101,8 @@ pub use crate::{
|
||||
client::{
|
||||
new_with_backend,
|
||||
new_in_mem,
|
||||
BlockBackend, ImportNotifications, FinalityNotifications, BlockchainEvents, LockImportRun,
|
||||
BlockImportNotification, Client, ClientInfo, ExecutionStrategies, FinalityNotification,
|
||||
ImportNotifications, FinalityNotifications, BlockchainEvents, LockImportRun,
|
||||
BlockImportNotification, Client, ClientConfig, ClientInfo, ExecutionStrategies, FinalityNotification,
|
||||
LongestChain, BlockOf, ProvideUncles, BadBlocks, ForkBlocks, apply_aux,
|
||||
},
|
||||
leaves::LeafSet,
|
||||
|
||||
@@ -21,7 +21,7 @@ use std::{
|
||||
};
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
use sp_core::{convert_hash, NativeOrEncoded, traits::CodeExecutor};
|
||||
use sp_core::{convert_hash, NativeOrEncoded, traits::CodeExecutor, offchain::storage::OffchainOverlayedChanges};
|
||||
use sp_runtime::{
|
||||
generic::BlockId, traits::{One, Block as BlockT, Header as HeaderT, HashFor},
|
||||
};
|
||||
@@ -108,6 +108,7 @@ impl<Block, B, Local> CallExecutor<Block> for
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
changes: &RefCell<OverlayedChanges>,
|
||||
offchain_changes: &RefCell<OffchainOverlayedChanges>,
|
||||
_: Option<&RefCell<StorageTransactionCache<Block, B::State>>>,
|
||||
initialize_block: InitializeBlock<'a, Block>,
|
||||
_manager: ExecutionManager<EM>,
|
||||
@@ -134,6 +135,7 @@ impl<Block, B, Local> CallExecutor<Block> for
|
||||
method,
|
||||
call_data,
|
||||
changes,
|
||||
offchain_changes,
|
||||
None,
|
||||
initialize_block,
|
||||
ExecutionManager::NativeWhenPossible,
|
||||
@@ -338,6 +340,7 @@ mod tests {
|
||||
_method: &str,
|
||||
_call_data: &[u8],
|
||||
_changes: &RefCell<OverlayedChanges>,
|
||||
_offchain_changes: &RefCell<OffchainOverlayedChanges>,
|
||||
_storage_transaction_cache: Option<&RefCell<
|
||||
StorageTransactionCache<
|
||||
Block,
|
||||
|
||||
@@ -31,7 +31,7 @@ use sp_blockchain::Result as ClientResult;
|
||||
use prometheus_endpoint::Registry;
|
||||
|
||||
use crate::call_executor::LocalCallExecutor;
|
||||
use crate::client::Client;
|
||||
use crate::client::{Client,ClientConfig};
|
||||
use sc_client_api::{
|
||||
light::Storage as BlockchainStorage, CloneableSpawn,
|
||||
};
|
||||
@@ -77,7 +77,7 @@ pub fn new_light<B, S, RA, E>(
|
||||
S: BlockchainStorage<B> + 'static,
|
||||
E: CodeExecutor + RuntimeInfo + Clone + 'static,
|
||||
{
|
||||
let local_executor = LocalCallExecutor::new(backend.clone(), code_executor, spawn_handle.clone());
|
||||
let local_executor = LocalCallExecutor::new(backend.clone(), code_executor, spawn_handle.clone(), ClientConfig::default());
|
||||
let executor = GenesisCallExecutor::new(backend.clone(), local_executor);
|
||||
Client::new(
|
||||
backend,
|
||||
@@ -87,6 +87,7 @@ pub fn new_light<B, S, RA, E>(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
prometheus_registry,
|
||||
ClientConfig::default(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -407,6 +407,7 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result<TokenStream> {
|
||||
at: &#crate_::BlockId<Block>,
|
||||
args: Vec<u8>,
|
||||
changes: &std::cell::RefCell<#crate_::OverlayedChanges>,
|
||||
offchain_changes: &std::cell::RefCell<#crate_::OffchainOverlayedChanges>,
|
||||
storage_transaction_cache: &std::cell::RefCell<
|
||||
#crate_::StorageTransactionCache<Block, T::StateBackend>
|
||||
>,
|
||||
@@ -436,6 +437,7 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result<TokenStream> {
|
||||
native_call: None,
|
||||
arguments: args,
|
||||
overlayed_changes: changes,
|
||||
offchain_changes,
|
||||
storage_transaction_cache,
|
||||
initialize_block,
|
||||
context,
|
||||
@@ -456,6 +458,7 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result<TokenStream> {
|
||||
native_call,
|
||||
arguments: args,
|
||||
overlayed_changes: changes,
|
||||
offchain_changes,
|
||||
storage_transaction_cache,
|
||||
initialize_block,
|
||||
context,
|
||||
|
||||
@@ -207,6 +207,7 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
||||
commit_on_success: std::cell::RefCell<bool>,
|
||||
initialized_block: std::cell::RefCell<Option<#crate_::BlockId<Block>>>,
|
||||
changes: std::cell::RefCell<#crate_::OverlayedChanges>,
|
||||
offchain_changes: std::cell::RefCell<#crate_::OffchainOverlayedChanges>,
|
||||
storage_transaction_cache: std::cell::RefCell<
|
||||
#crate_::StorageTransactionCache<Block, C::StateBackend>
|
||||
>,
|
||||
@@ -335,6 +336,7 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
||||
commit_on_success: true.into(),
|
||||
initialized_block: None.into(),
|
||||
changes: Default::default(),
|
||||
offchain_changes: Default::default(),
|
||||
recorder: Default::default(),
|
||||
storage_transaction_cache: Default::default(),
|
||||
}.into()
|
||||
@@ -353,6 +355,7 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
||||
&C,
|
||||
&Self,
|
||||
&std::cell::RefCell<#crate_::OverlayedChanges>,
|
||||
&std::cell::RefCell<#crate_::OffchainOverlayedChanges>,
|
||||
&std::cell::RefCell<#crate_::StorageTransactionCache<Block, C::StateBackend>>,
|
||||
&std::cell::RefCell<Option<#crate_::BlockId<Block>>>,
|
||||
&Option<#crate_::ProofRecorder<Block>>,
|
||||
@@ -366,6 +369,7 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
||||
&self.call,
|
||||
self,
|
||||
&self.changes,
|
||||
&self.offchain_changes,
|
||||
&self.storage_transaction_cache,
|
||||
&self.initialized_block,
|
||||
&self.recorder,
|
||||
@@ -517,6 +521,7 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
|
||||
call_runtime_at,
|
||||
core_api,
|
||||
changes,
|
||||
offchain_changes,
|
||||
storage_transaction_cache,
|
||||
initialized_block,
|
||||
recorder
|
||||
@@ -527,6 +532,7 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
|
||||
at,
|
||||
params_encoded,
|
||||
changes,
|
||||
offchain_changes,
|
||||
storage_transaction_cache,
|
||||
initialized_block,
|
||||
params.map(|p| {
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
//!
|
||||
//! Besides the macros and the [`Core`] runtime api, this crates provides the [`Metadata`] runtime
|
||||
//! api, the [`ApiExt`] trait, the [`CallApiAt`] trait and the [`ConstructRuntimeApi`] trait.
|
||||
//!
|
||||
//! On a meta level this implies, the client calls the generated API from the client perspective.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
@@ -44,6 +46,8 @@ pub use sp_core::NativeOrEncoded;
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "std")]
|
||||
pub use hash_db::Hasher;
|
||||
#[cfg(feature = "std")]
|
||||
pub use sp_core::offchain::storage::OffchainOverlayedChanges;
|
||||
#[doc(hidden)]
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub use sp_core::to_substrate_wasm_fn_return_value;
|
||||
@@ -431,6 +435,8 @@ pub struct CallApiAtParams<'a, Block: BlockT, C, NC, Backend: StateBackend<HashF
|
||||
pub arguments: Vec<u8>,
|
||||
/// The overlayed changes that are on top of the state.
|
||||
pub overlayed_changes: &'a RefCell<OverlayedChanges>,
|
||||
/// The overlayed changes to be applied to the offchain worker database.
|
||||
pub offchain_changes: &'a RefCell<OffchainOverlayedChanges>,
|
||||
/// The cache for storage transactions.
|
||||
pub storage_transaction_cache: &'a RefCell<StorageTransactionCache<Block, Backend>>,
|
||||
/// Determines if the function requires that `initialize_block` should be called before calling
|
||||
|
||||
@@ -28,6 +28,9 @@ pub mod storage;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod testing;
|
||||
|
||||
/// Local storage prefix used by the Offchain Worker API to
|
||||
pub const STORAGE_PREFIX : &'static [u8] = b"storage";
|
||||
|
||||
/// Offchain workers local storage.
|
||||
pub trait OffchainStorage: Clone + Send + Sync {
|
||||
/// Persist a value in storage under given key and prefix.
|
||||
@@ -482,8 +485,8 @@ pub trait Externalities: Send {
|
||||
buffer: &mut [u8],
|
||||
deadline: Option<Timestamp>
|
||||
) -> Result<usize, HttpError>;
|
||||
|
||||
}
|
||||
|
||||
impl<T: Externalities + ?Sized> Externalities for Box<T> {
|
||||
fn is_validator(&self) -> bool {
|
||||
(& **self).is_validator()
|
||||
@@ -557,6 +560,7 @@ impl<T: Externalities + ?Sized> Externalities for Box<T> {
|
||||
(&mut **self).http_response_read_body(request_id, buffer, deadline)
|
||||
}
|
||||
}
|
||||
|
||||
/// An `OffchainExternalities` implementation with limited capabilities.
|
||||
pub struct LimitedExternalities<T> {
|
||||
capabilities: Capabilities,
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
use std::collections::hash_map::{HashMap, Entry};
|
||||
use crate::offchain::OffchainStorage;
|
||||
use std::iter::Iterator;
|
||||
|
||||
/// In-memory storage for offchain workers.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
@@ -25,6 +26,24 @@ pub struct InMemOffchainStorage {
|
||||
storage: HashMap<Vec<u8>, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl InMemOffchainStorage {
|
||||
/// Consume the offchain storage and iterate over all key value pairs.
|
||||
pub fn into_iter(self) -> impl Iterator<Item=(Vec<u8>,Vec<u8>)> {
|
||||
self.storage.into_iter()
|
||||
}
|
||||
|
||||
/// Iterate over all key value pairs by reference.
|
||||
pub fn iter<'a>(&'a self) -> impl Iterator<Item=(&'a Vec<u8>,&'a Vec<u8>)> {
|
||||
self.storage.iter()
|
||||
}
|
||||
|
||||
/// Remove a key and its associated value from the offchain database.
|
||||
pub fn remove(&mut self, prefix: &[u8], key: &[u8]) {
|
||||
let key: Vec<u8> = prefix.iter().chain(key).cloned().collect();
|
||||
let _ = self.storage.remove(&key);
|
||||
}
|
||||
}
|
||||
|
||||
impl OffchainStorage for InMemOffchainStorage {
|
||||
fn set(&mut self, prefix: &[u8], key: &[u8], value: &[u8]) {
|
||||
let key = prefix.iter().chain(key).cloned().collect();
|
||||
@@ -58,3 +77,212 @@ impl OffchainStorage for InMemOffchainStorage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// Change to be applied to the offchain worker db in regards to a key.
|
||||
#[derive(Debug,Clone,Hash,Eq,PartialEq)]
|
||||
pub enum OffchainOverlayedChange {
|
||||
/// Remove the data associated with the key
|
||||
Remove,
|
||||
/// Overwrite the value of an associated key
|
||||
SetValue(Vec<u8>),
|
||||
}
|
||||
|
||||
/// In-memory storage for offchain workers recoding changes for the actual offchain storage implementation.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum OffchainOverlayedChanges {
|
||||
/// Writing overlay changes to the offchain worker database is disabled by configuration.
|
||||
Disabled,
|
||||
/// Overlay changes can be recorded using the inner collection of this variant.
|
||||
Enabled(HashMap<Vec<u8>, OffchainOverlayedChange>),
|
||||
}
|
||||
|
||||
impl Default for OffchainOverlayedChanges {
|
||||
fn default() -> Self {
|
||||
Self::Disabled
|
||||
}
|
||||
}
|
||||
|
||||
impl OffchainOverlayedChanges {
|
||||
/// Create the disabled variant.
|
||||
pub fn disabled() -> Self {
|
||||
Self::Disabled
|
||||
}
|
||||
|
||||
/// Create the enabled variant.
|
||||
pub fn enabled() -> Self {
|
||||
Self::Enabled(HashMap::new())
|
||||
}
|
||||
|
||||
/// Consume the offchain storage and iterate over all key value pairs.
|
||||
pub fn into_iter(self) -> OffchainOverlayedChangesIntoIter {
|
||||
OffchainOverlayedChangesIntoIter::new(self)
|
||||
}
|
||||
|
||||
/// Iterate over all key value pairs by reference.
|
||||
pub fn iter<'a>(&'a self) -> OffchainOverlayedChangesIter {
|
||||
OffchainOverlayedChangesIter::new(&self)
|
||||
}
|
||||
|
||||
/// Drain all elements of changeset.
|
||||
pub fn drain<'a, 'd>(&'a mut self) -> OffchainOverlayedChangesDrain<'d> where 'a: 'd {
|
||||
OffchainOverlayedChangesDrain::new(self)
|
||||
}
|
||||
|
||||
/// Remove a key and its associated value from the offchain database.
|
||||
pub fn remove(&mut self, prefix: &[u8], key: &[u8]) {
|
||||
if let Self::Enabled(ref mut storage) = self {
|
||||
let key: Vec<u8> = prefix.iter().chain(key).cloned().collect();
|
||||
let _ = storage.insert(key, OffchainOverlayedChange::Remove);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the value associated with a key under a prefix to the value provided.
|
||||
pub fn set(&mut self, prefix: &[u8], key: &[u8], value: &[u8]) {
|
||||
if let Self::Enabled(ref mut storage) = self {
|
||||
let key = prefix.iter().chain(key).cloned().collect();
|
||||
let _ = storage.insert(key, OffchainOverlayedChange::SetValue(value.to_vec()));
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain a associated value to the given key in storage with prefix.
|
||||
pub fn get(&self, prefix: &[u8], key: &[u8]) -> Option<OffchainOverlayedChange> {
|
||||
if let Self::Enabled(ref storage) = self {
|
||||
let key: Vec<u8> = prefix.iter().chain(key).cloned().collect();
|
||||
storage.get(&key).cloned()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use std::collections::hash_map;
|
||||
|
||||
/// Iterate by reference over the prepared offchain worker storage changes.
|
||||
pub struct OffchainOverlayedChangesIter<'i> {
|
||||
inner: Option<hash_map::Iter<'i, Vec<u8>, OffchainOverlayedChange>>,
|
||||
}
|
||||
|
||||
impl<'i> Iterator for OffchainOverlayedChangesIter<'i> {
|
||||
type Item = (&'i Vec<u8>, &'i OffchainOverlayedChange);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(ref mut iter) = self.inner {
|
||||
iter.next()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i> OffchainOverlayedChangesIter<'i> {
|
||||
/// Create a new iterator based on a refernce to the parent container.
|
||||
pub fn new(container: &'i OffchainOverlayedChanges) -> Self {
|
||||
match container {
|
||||
OffchainOverlayedChanges::Enabled(inner) => Self {
|
||||
inner: Some(inner.iter())
|
||||
},
|
||||
OffchainOverlayedChanges::Disabled => Self { inner: None, },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Iterate by value over the prepared offchain worker storage changes.
|
||||
pub struct OffchainOverlayedChangesIntoIter {
|
||||
inner: Option<hash_map::IntoIter<Vec<u8>,OffchainOverlayedChange>>,
|
||||
}
|
||||
|
||||
impl Iterator for OffchainOverlayedChangesIntoIter {
|
||||
type Item = (Vec<u8>, OffchainOverlayedChange);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(ref mut iter) = self.inner {
|
||||
iter.next()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OffchainOverlayedChangesIntoIter {
|
||||
/// Create a new iterator by consuming the collection.
|
||||
pub fn new(container: OffchainOverlayedChanges) -> Self {
|
||||
match container {
|
||||
OffchainOverlayedChanges::Enabled(inner) => Self {
|
||||
inner: Some(inner.into_iter())
|
||||
},
|
||||
OffchainOverlayedChanges::Disabled => Self { inner: None, },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate over all items while draining them from the collection.
|
||||
pub struct OffchainOverlayedChangesDrain<'d> {
|
||||
inner: Option<hash_map::Drain<'d, Vec<u8>,OffchainOverlayedChange>>,
|
||||
}
|
||||
|
||||
impl<'d> Iterator for OffchainOverlayedChangesDrain<'d> {
|
||||
type Item = (Vec<u8>, OffchainOverlayedChange);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(ref mut iter) = self.inner {
|
||||
iter.next()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> OffchainOverlayedChangesDrain<'d> {
|
||||
/// Create a new iterator by taking a mut reference to the collection,
|
||||
/// for the lifetime of the created drain iterator.
|
||||
pub fn new(container: &'d mut OffchainOverlayedChanges) -> Self {
|
||||
match container {
|
||||
OffchainOverlayedChanges::Enabled(ref mut inner) => Self {
|
||||
inner: Some(inner.drain())
|
||||
},
|
||||
OffchainOverlayedChanges::Disabled => Self { inner: None, },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use super::super::STORAGE_PREFIX;
|
||||
|
||||
#[test]
|
||||
fn test_drain() {
|
||||
let mut ooc = OffchainOverlayedChanges::enabled();
|
||||
ooc.set(STORAGE_PREFIX,b"kkk", b"vvv");
|
||||
let drained = ooc.drain().count();
|
||||
assert_eq!(drained, 1);
|
||||
let leftover = ooc.iter().count();
|
||||
assert_eq!(leftover, 0);
|
||||
|
||||
ooc.set(STORAGE_PREFIX, b"a", b"v");
|
||||
ooc.set(STORAGE_PREFIX, b"b", b"v");
|
||||
ooc.set(STORAGE_PREFIX, b"c", b"v");
|
||||
ooc.set(STORAGE_PREFIX, b"d", b"v");
|
||||
ooc.set(STORAGE_PREFIX, b"e", b"v");
|
||||
assert_eq!(ooc.iter().count(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_accumulated_set_remove_set() {
|
||||
let mut ooc = OffchainOverlayedChanges::enabled();
|
||||
ooc.set(STORAGE_PREFIX, b"ppp", b"qqq");
|
||||
ooc.remove(STORAGE_PREFIX, b"ppp");
|
||||
// keys are equiv, so it will overwrite the value and the overlay will contain
|
||||
// one item
|
||||
assert_eq!(ooc.iter().count(), 1);
|
||||
|
||||
ooc.set(STORAGE_PREFIX, b"ppp", b"rrr");
|
||||
let mut iter = ooc.into_iter();
|
||||
let mut k = STORAGE_PREFIX.to_vec();
|
||||
k.extend_from_slice(&b"ppp"[..]);
|
||||
assert_eq!(iter.next(), Some((k, OffchainOverlayedChange::SetValue(b"rrr".to_vec()))));
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,9 @@ pub enum Error {
|
||||
///
|
||||
/// Provides access to the storage and to other registered extensions.
|
||||
pub trait Externalities: ExtensionStore {
|
||||
/// Write a key value pair to the offchain storage database.
|
||||
fn set_offchain_storage(&mut self, key: &[u8], value: Option<&[u8]>);
|
||||
|
||||
/// Read runtime storage.
|
||||
fn storage(&self, key: &[u8]) -> Option<Vec<u8>>;
|
||||
|
||||
|
||||
@@ -613,6 +613,20 @@ pub trait Hashing {
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface that provides functions to access the Offchain DB.
|
||||
#[runtime_interface]
|
||||
pub trait OffchainIndex {
|
||||
/// Write a key value pair to the Offchain DB database in a buffered fashion.
|
||||
fn set(&mut self, key: &[u8], value: &[u8]) {
|
||||
self.set_offchain_storage(key, Some(value));
|
||||
}
|
||||
|
||||
/// Remove a key and its associated value from the Offchain DB.
|
||||
fn clear(&mut self, key: &[u8]) {
|
||||
self.set_offchain_storage(key, None);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
sp_externalities::decl_extension! {
|
||||
/// The keystore extension to register/retrieve from the externalities.
|
||||
@@ -620,6 +634,8 @@ sp_externalities::decl_extension! {
|
||||
}
|
||||
|
||||
/// Interface that provides functions to access the offchain functionality.
|
||||
///
|
||||
/// These functions are being made available to the runtime and are called by the runtime.
|
||||
#[runtime_interface]
|
||||
pub trait Offchain {
|
||||
/// Returns if the local node is a potential validator.
|
||||
@@ -995,6 +1011,7 @@ pub type SubstrateHostFunctions = (
|
||||
logging::HostFunctions,
|
||||
sandbox::HostFunctions,
|
||||
crate::trie::HostFunctions,
|
||||
offchain_index::HostFunctions,
|
||||
);
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -12,12 +12,17 @@ repository = "https://github.com/paritytech/substrate/"
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
sp-core = { version = "2.0.0-dev", default-features = false, path = "../core" }
|
||||
sp-api = { version = "2.0.0-dev", default-features = false, path = "../api" }
|
||||
sp-runtime = { version = "2.0.0-dev", default-features = false, path = "../runtime" }
|
||||
|
||||
[dev-dependencies]
|
||||
sp-state-machine = { version = "0.8.0-alpha.5", default-features = false, path = "../state-machine" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"sp-core/std",
|
||||
"sp-api/std",
|
||||
"sp-runtime/std"
|
||||
]
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
/// Local Storage Prefix used by the Offchain Worker API to
|
||||
pub const STORAGE_PREFIX: &[u8] = b"storage";
|
||||
/// Re-export of parent module scope storage prefix.
|
||||
pub use sp_core::offchain::STORAGE_PREFIX as STORAGE_PREFIX;
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// The offchain worker api.
|
||||
|
||||
@@ -140,6 +140,8 @@ impl From<BTreeMap<StorageKey, StorageValue>> for BasicExternalities {
|
||||
}
|
||||
|
||||
impl Externalities for BasicExternalities {
|
||||
fn set_offchain_storage(&mut self, _key: &[u8], _value: Option<&[u8]>) {}
|
||||
|
||||
fn storage(&self, key: &[u8]) -> Option<StorageValue> {
|
||||
self.inner.top.get(key).cloned()
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ use crate::{
|
||||
|
||||
use hash_db::Hasher;
|
||||
use sp_core::{
|
||||
offchain::storage::OffchainOverlayedChanges,
|
||||
storage::{well_known_keys::is_child_storage_key, ChildInfo},
|
||||
traits::Externalities, hexdisplay::HexDisplay,
|
||||
};
|
||||
@@ -74,6 +75,8 @@ pub struct Ext<'a, H, N, B>
|
||||
{
|
||||
/// The overlayed changes to write to.
|
||||
overlay: &'a mut OverlayedChanges,
|
||||
/// The overlayed changes destined for the Offchain DB.
|
||||
offchain_overlay: &'a mut OffchainOverlayedChanges,
|
||||
/// The storage backend to read from.
|
||||
backend: &'a B,
|
||||
/// The cache for the storage transactions.
|
||||
@@ -99,13 +102,15 @@ where
|
||||
/// Create a new `Ext` from overlayed changes and read-only backend
|
||||
pub fn new(
|
||||
overlay: &'a mut OverlayedChanges,
|
||||
offchain_overlay: &'a mut OffchainOverlayedChanges,
|
||||
storage_transaction_cache: &'a mut StorageTransactionCache<B::Transaction, H, N>,
|
||||
backend: &'a B,
|
||||
changes_trie_state: Option<ChangesTrieState<'a, H, N>>,
|
||||
extensions: Option<&'a mut Extensions>,
|
||||
) -> Self {
|
||||
Ext {
|
||||
Self {
|
||||
overlay,
|
||||
offchain_overlay,
|
||||
backend,
|
||||
changes_trie_state,
|
||||
storage_transaction_cache,
|
||||
@@ -121,6 +126,11 @@ where
|
||||
fn mark_dirty(&mut self) {
|
||||
self.storage_transaction_cache.reset();
|
||||
}
|
||||
|
||||
/// Read only accessor for the scheduled overlay changes.
|
||||
pub fn get_offchain_storage_changes(&self) -> &OffchainOverlayedChanges {
|
||||
&*self.offchain_overlay
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -152,6 +162,15 @@ where
|
||||
B: 'a + Backend<H>,
|
||||
N: crate::changes_trie::BlockNumber,
|
||||
{
|
||||
|
||||
fn set_offchain_storage(&mut self, key: &[u8], value: Option<&[u8]>) {
|
||||
use ::sp_core::offchain::STORAGE_PREFIX;
|
||||
match value {
|
||||
Some(value) => self.offchain_overlay.set(STORAGE_PREFIX, key, value),
|
||||
None => self.offchain_overlay.remove(STORAGE_PREFIX, key),
|
||||
}
|
||||
}
|
||||
|
||||
fn storage(&self, key: &[u8]) -> Option<StorageValue> {
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let result = self.overlay.storage(key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(||
|
||||
@@ -572,14 +591,23 @@ mod tests {
|
||||
use hex_literal::hex;
|
||||
use num_traits::Zero;
|
||||
use codec::Encode;
|
||||
use sp_core::{H256, Blake2Hasher, storage::well_known_keys::EXTRINSIC_INDEX, map};
|
||||
use sp_core::{
|
||||
H256,
|
||||
Blake2Hasher,
|
||||
map,
|
||||
offchain,
|
||||
storage::{
|
||||
Storage,
|
||||
StorageChild,
|
||||
well_known_keys::EXTRINSIC_INDEX,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
changes_trie::{
|
||||
Configuration as ChangesTrieConfiguration,
|
||||
InMemoryStorage as TestChangesTrieStorage,
|
||||
}, InMemoryBackend, overlayed_changes::OverlayedValue,
|
||||
};
|
||||
use sp_core::storage::{Storage, StorageChild};
|
||||
|
||||
type TestBackend = InMemoryBackend<Blake2Hasher>;
|
||||
type TestExt<'a> = Ext<'a, Blake2Hasher, u64, TestBackend>;
|
||||
@@ -602,6 +630,13 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_offchain_overlay_with_changes() -> OffchainOverlayedChanges {
|
||||
let mut ooc = OffchainOverlayedChanges::enabled();
|
||||
ooc.set(offchain::STORAGE_PREFIX, b"k1", b"v1");
|
||||
ooc.set(offchain::STORAGE_PREFIX, b"k2", b"v2");
|
||||
ooc
|
||||
}
|
||||
|
||||
fn changes_trie_config() -> ChangesTrieConfiguration {
|
||||
ChangesTrieConfiguration {
|
||||
digest_interval: 0,
|
||||
@@ -612,29 +647,32 @@ mod tests {
|
||||
#[test]
|
||||
fn storage_changes_root_is_none_when_storage_is_not_provided() {
|
||||
let mut overlay = prepare_overlay_with_changes();
|
||||
let mut offchain_overlay = prepare_offchain_overlay_with_changes();
|
||||
let mut cache = StorageTransactionCache::default();
|
||||
let backend = TestBackend::default();
|
||||
let mut ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None);
|
||||
let mut ext = TestExt::new(&mut overlay, &mut offchain_overlay, &mut cache, &backend, None, None);
|
||||
assert_eq!(ext.storage_changes_root(&H256::default().encode()).unwrap(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn storage_changes_root_is_none_when_state_is_not_provided() {
|
||||
let mut overlay = prepare_overlay_with_changes();
|
||||
let mut offchain_overlay = prepare_offchain_overlay_with_changes();
|
||||
let mut cache = StorageTransactionCache::default();
|
||||
let backend = TestBackend::default();
|
||||
let mut ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None);
|
||||
let mut ext = TestExt::new(&mut overlay, &mut offchain_overlay, &mut cache, &backend, None, None);
|
||||
assert_eq!(ext.storage_changes_root(&H256::default().encode()).unwrap(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn storage_changes_root_is_some_when_extrinsic_changes_are_non_empty() {
|
||||
let mut overlay = prepare_overlay_with_changes();
|
||||
let mut offchain_overlay = prepare_offchain_overlay_with_changes();
|
||||
let mut cache = StorageTransactionCache::default();
|
||||
let storage = TestChangesTrieStorage::with_blocks(vec![(99, Default::default())]);
|
||||
let state = Some(ChangesTrieState::new(changes_trie_config(), Zero::zero(), &storage));
|
||||
let backend = TestBackend::default();
|
||||
let mut ext = TestExt::new(&mut overlay, &mut cache, &backend, state, None);
|
||||
let mut ext = TestExt::new(&mut overlay, &mut offchain_overlay, &mut cache, &backend, state, None);
|
||||
assert_eq!(
|
||||
ext.storage_changes_root(&H256::default().encode()).unwrap(),
|
||||
Some(hex!("bb0c2ef6e1d36d5490f9766cfcc7dfe2a6ca804504c3bb206053890d6dd02376").to_vec()),
|
||||
@@ -644,12 +682,13 @@ mod tests {
|
||||
#[test]
|
||||
fn storage_changes_root_is_some_when_extrinsic_changes_are_empty() {
|
||||
let mut overlay = prepare_overlay_with_changes();
|
||||
let mut offchain_overlay = prepare_offchain_overlay_with_changes();
|
||||
let mut cache = StorageTransactionCache::default();
|
||||
overlay.prospective.top.get_mut(&vec![1]).unwrap().value = None;
|
||||
let storage = TestChangesTrieStorage::with_blocks(vec![(99, Default::default())]);
|
||||
let state = Some(ChangesTrieState::new(changes_trie_config(), Zero::zero(), &storage));
|
||||
let backend = TestBackend::default();
|
||||
let mut ext = TestExt::new(&mut overlay, &mut cache, &backend, state, None);
|
||||
let mut ext = TestExt::new(&mut overlay, &mut offchain_overlay, &mut cache, &backend, state, None);
|
||||
assert_eq!(
|
||||
ext.storage_changes_root(&H256::default().encode()).unwrap(),
|
||||
Some(hex!("96f5aae4690e7302737b6f9b7f8567d5bbb9eac1c315f80101235a92d9ec27f4").to_vec()),
|
||||
@@ -662,6 +701,7 @@ mod tests {
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
overlay.set_storage(vec![20], None);
|
||||
overlay.set_storage(vec![30], Some(vec![31]));
|
||||
let mut offchain_overlay = prepare_offchain_overlay_with_changes();
|
||||
let backend = Storage {
|
||||
top: map![
|
||||
vec![10] => vec![10],
|
||||
@@ -671,7 +711,7 @@ mod tests {
|
||||
children_default: map![]
|
||||
}.into();
|
||||
|
||||
let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None);
|
||||
let ext = TestExt::new(&mut overlay, &mut offchain_overlay, &mut cache, &backend, None, None);
|
||||
|
||||
// next_backend < next_overlay
|
||||
assert_eq!(ext.next_storage_key(&[5]), Some(vec![10]));
|
||||
@@ -687,7 +727,7 @@ mod tests {
|
||||
|
||||
drop(ext);
|
||||
overlay.set_storage(vec![50], Some(vec![50]));
|
||||
let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None);
|
||||
let ext = TestExt::new(&mut overlay, &mut offchain_overlay, &mut cache, &backend, None, None);
|
||||
|
||||
// next_overlay exist but next_backend doesn't exist
|
||||
assert_eq!(ext.next_storage_key(&[40]), Some(vec![50]));
|
||||
@@ -717,7 +757,9 @@ mod tests {
|
||||
}.into();
|
||||
|
||||
|
||||
let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None);
|
||||
let mut offchain_overlay = prepare_offchain_overlay_with_changes();
|
||||
|
||||
let ext = TestExt::new(&mut overlay, &mut offchain_overlay, &mut cache, &backend, None, None);
|
||||
|
||||
// next_backend < next_overlay
|
||||
assert_eq!(ext.next_child_storage_key(child_info, &[5]), Some(vec![10]));
|
||||
@@ -733,7 +775,7 @@ mod tests {
|
||||
|
||||
drop(ext);
|
||||
overlay.set_child_storage(child_info, vec![50], Some(vec![50]));
|
||||
let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None);
|
||||
let ext = TestExt::new(&mut overlay, &mut offchain_overlay, &mut cache, &backend, None, None);
|
||||
|
||||
// next_overlay exist but next_backend doesn't exist
|
||||
assert_eq!(ext.next_child_storage_key(child_info, &[40]), Some(vec![50]));
|
||||
@@ -747,6 +789,7 @@ mod tests {
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
overlay.set_child_storage(child_info, vec![20], None);
|
||||
overlay.set_child_storage(child_info, vec![30], Some(vec![31]));
|
||||
let mut offchain_overlay = prepare_offchain_overlay_with_changes();
|
||||
let backend = Storage {
|
||||
top: map![],
|
||||
children_default: map![
|
||||
@@ -761,7 +804,7 @@ mod tests {
|
||||
],
|
||||
}.into();
|
||||
|
||||
let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None);
|
||||
let ext = TestExt::new(&mut overlay, &mut offchain_overlay, &mut cache, &backend, None, None);
|
||||
|
||||
assert_eq!(ext.child_storage(child_info, &[10]), Some(vec![10]));
|
||||
assert_eq!(
|
||||
|
||||
@@ -23,6 +23,7 @@ use log::{warn, trace};
|
||||
use hash_db::Hasher;
|
||||
use codec::{Decode, Encode, Codec};
|
||||
use sp_core::{
|
||||
offchain::storage::OffchainOverlayedChanges,
|
||||
storage::ChildInfo, NativeOrEncoded, NeverNativeValue, hexdisplay::HexDisplay,
|
||||
traits::{CodeExecutor, CallInWasmExt, RuntimeCode},
|
||||
};
|
||||
@@ -190,6 +191,7 @@ pub struct StateMachine<'a, B, H, N, Exec>
|
||||
method: &'a str,
|
||||
call_data: &'a [u8],
|
||||
overlay: &'a mut OverlayedChanges,
|
||||
offchain_overlay: &'a mut OffchainOverlayedChanges,
|
||||
extensions: Extensions,
|
||||
changes_trie_state: Option<ChangesTrieState<'a, H, N>>,
|
||||
storage_transaction_cache: Option<&'a mut StorageTransactionCache<B::Transaction, H, N>>,
|
||||
@@ -219,6 +221,7 @@ impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where
|
||||
backend: &'a B,
|
||||
changes_trie_state: Option<ChangesTrieState<'a, H, N>>,
|
||||
overlay: &'a mut OverlayedChanges,
|
||||
offchain_overlay: &'a mut OffchainOverlayedChanges,
|
||||
exec: &'a Exec,
|
||||
method: &'a str,
|
||||
call_data: &'a [u8],
|
||||
@@ -236,6 +239,7 @@ impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where
|
||||
call_data,
|
||||
extensions,
|
||||
overlay,
|
||||
offchain_overlay,
|
||||
changes_trie_state,
|
||||
storage_transaction_cache: None,
|
||||
runtime_code,
|
||||
@@ -293,6 +297,7 @@ impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where
|
||||
|
||||
let mut ext = Ext::new(
|
||||
self.overlay,
|
||||
self.offchain_overlay,
|
||||
cache,
|
||||
self.backend,
|
||||
self.changes_trie_state.clone(),
|
||||
@@ -503,11 +508,13 @@ where
|
||||
Exec: CodeExecutor + 'static + Clone,
|
||||
N: crate::changes_trie::BlockNumber,
|
||||
{
|
||||
let mut offchain_overlay = OffchainOverlayedChanges::default();
|
||||
let proving_backend = proving_backend::ProvingBackend::new(trie_backend);
|
||||
let mut sm = StateMachine::<_, H, N, Exec>::new(
|
||||
&proving_backend,
|
||||
None,
|
||||
overlay,
|
||||
&mut offchain_overlay,
|
||||
exec,
|
||||
method,
|
||||
call_data,
|
||||
@@ -569,10 +576,12 @@ where
|
||||
Exec: CodeExecutor + Clone + 'static,
|
||||
N: crate::changes_trie::BlockNumber,
|
||||
{
|
||||
let mut offchain_overlay = OffchainOverlayedChanges::default();
|
||||
let mut sm = StateMachine::<_, H, N, Exec>::new(
|
||||
trie_backend,
|
||||
None,
|
||||
overlay,
|
||||
&mut offchain_overlay,
|
||||
exec,
|
||||
method,
|
||||
call_data,
|
||||
@@ -824,12 +833,14 @@ mod tests {
|
||||
fn execute_works() {
|
||||
let backend = trie_backend::tests::test_trie();
|
||||
let mut overlayed_changes = Default::default();
|
||||
let mut offchain_overlayed_changes = Default::default();
|
||||
let wasm_code = RuntimeCode::empty();
|
||||
|
||||
let mut state_machine = StateMachine::new(
|
||||
&backend,
|
||||
changes_trie::disabled_state::<_, u64>(),
|
||||
&mut overlayed_changes,
|
||||
&mut offchain_overlayed_changes,
|
||||
&DummyCodeExecutor {
|
||||
change_changes_trie_config: false,
|
||||
native_available: true,
|
||||
@@ -854,12 +865,14 @@ mod tests {
|
||||
fn execute_works_with_native_else_wasm() {
|
||||
let backend = trie_backend::tests::test_trie();
|
||||
let mut overlayed_changes = Default::default();
|
||||
let mut offchain_overlayed_changes = Default::default();
|
||||
let wasm_code = RuntimeCode::empty();
|
||||
|
||||
let mut state_machine = StateMachine::new(
|
||||
&backend,
|
||||
changes_trie::disabled_state::<_, u64>(),
|
||||
&mut overlayed_changes,
|
||||
&mut offchain_overlayed_changes,
|
||||
&DummyCodeExecutor {
|
||||
change_changes_trie_config: false,
|
||||
native_available: true,
|
||||
@@ -881,12 +894,14 @@ mod tests {
|
||||
let mut consensus_failed = false;
|
||||
let backend = trie_backend::tests::test_trie();
|
||||
let mut overlayed_changes = Default::default();
|
||||
let mut offchain_overlayed_changes = Default::default();
|
||||
let wasm_code = RuntimeCode::empty();
|
||||
|
||||
let mut state_machine = StateMachine::new(
|
||||
&backend,
|
||||
changes_trie::disabled_state::<_, u64>(),
|
||||
&mut overlayed_changes,
|
||||
&mut offchain_overlayed_changes,
|
||||
&DummyCodeExecutor {
|
||||
change_changes_trie_config: false,
|
||||
native_available: true,
|
||||
@@ -972,11 +987,14 @@ mod tests {
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
let mut offchain_overlay = Default::default();
|
||||
|
||||
|
||||
{
|
||||
let mut cache = StorageTransactionCache::default();
|
||||
let mut ext = Ext::new(
|
||||
&mut overlay,
|
||||
&mut offchain_overlay,
|
||||
&mut cache,
|
||||
backend,
|
||||
changes_trie::disabled_state::<_, u64>(),
|
||||
@@ -1007,9 +1025,11 @@ mod tests {
|
||||
let mut state = new_in_mem::<BlakeTwo256>();
|
||||
let backend = state.as_trie_backend().unwrap();
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let mut offchain_overlay = OffchainOverlayedChanges::default();
|
||||
let mut cache = StorageTransactionCache::default();
|
||||
let mut ext = Ext::new(
|
||||
&mut overlay,
|
||||
&mut offchain_overlay,
|
||||
&mut cache,
|
||||
backend,
|
||||
changes_trie::disabled_state::<_, u64>(),
|
||||
@@ -1103,12 +1123,14 @@ mod tests {
|
||||
|
||||
use crate::trie_backend::tests::test_trie;
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let mut offchain_overlay = OffchainOverlayedChanges::default();
|
||||
|
||||
let mut transaction = {
|
||||
let backend = test_trie();
|
||||
let mut cache = StorageTransactionCache::default();
|
||||
let mut ext = Ext::new(
|
||||
&mut overlay,
|
||||
&mut offchain_overlay,
|
||||
&mut cache,
|
||||
&backend,
|
||||
changes_trie::disabled_state::<_, u64>(),
|
||||
|
||||
@@ -30,6 +30,7 @@ use std::iter::FromIterator;
|
||||
use std::collections::{HashMap, BTreeMap, BTreeSet};
|
||||
use codec::{Decode, Encode};
|
||||
use sp_core::storage::{well_known_keys::EXTRINSIC_INDEX, ChildInfo};
|
||||
use sp_core::offchain::storage::OffchainOverlayedChanges;
|
||||
use std::{mem, ops};
|
||||
|
||||
use hash_db::Hasher;
|
||||
@@ -94,9 +95,12 @@ pub struct StorageChanges<Transaction, H: Hasher, N: BlockNumber> {
|
||||
pub main_storage_changes: StorageCollection,
|
||||
/// All changes to the child storages.
|
||||
pub child_storage_changes: ChildStorageCollection,
|
||||
/// Offchain state changes to write to the offchain database.
|
||||
pub offchain_storage_changes: OffchainOverlayedChanges,
|
||||
/// A transaction for the backend that contains all changes from
|
||||
/// [`main_storage_changes`](Self::main_storage_changes) and from
|
||||
/// [`child_storage_changes`](Self::child_storage_changes).
|
||||
/// [`offchain_storage_changes`](Self::offchain_storage_changes).
|
||||
pub transaction: Transaction,
|
||||
/// The storage root after applying the transaction.
|
||||
pub transaction_storage_root: H::Out,
|
||||
@@ -111,6 +115,7 @@ impl<Transaction, H: Hasher, N: BlockNumber> StorageChanges<Transaction, H, N> {
|
||||
pub fn into_inner(self) -> (
|
||||
StorageCollection,
|
||||
ChildStorageCollection,
|
||||
OffchainOverlayedChanges,
|
||||
Transaction,
|
||||
H::Out,
|
||||
Option<ChangesTrieTransaction<H, N>>,
|
||||
@@ -118,6 +123,7 @@ impl<Transaction, H: Hasher, N: BlockNumber> StorageChanges<Transaction, H, N> {
|
||||
(
|
||||
self.main_storage_changes,
|
||||
self.child_storage_changes,
|
||||
self.offchain_storage_changes,
|
||||
self.transaction,
|
||||
self.transaction_storage_root,
|
||||
self.changes_trie_transaction,
|
||||
@@ -162,6 +168,7 @@ impl<Transaction: Default, H: Hasher, N: BlockNumber> Default for StorageChanges
|
||||
Self {
|
||||
main_storage_changes: Default::default(),
|
||||
child_storage_changes: Default::default(),
|
||||
offchain_storage_changes: Default::default(),
|
||||
transaction: Default::default(),
|
||||
transaction_storage_root: Default::default(),
|
||||
changes_trie_transaction: None,
|
||||
@@ -503,11 +510,13 @@ impl OverlayedChanges {
|
||||
.take()
|
||||
.expect("Changes trie transaction was generated by `changes_trie_root`; qed");
|
||||
|
||||
let offchain_storage_changes = Default::default();
|
||||
let (main_storage_changes, child_storage_changes) = self.drain_committed();
|
||||
|
||||
Ok(StorageChanges {
|
||||
main_storage_changes: main_storage_changes.collect(),
|
||||
child_storage_changes: child_storage_changes.map(|(sk, it)| (sk, it.0.collect())).collect(),
|
||||
offchain_storage_changes,
|
||||
transaction,
|
||||
transaction_storage_root,
|
||||
changes_trie_transaction,
|
||||
@@ -745,9 +754,11 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut offchain_overlay = Default::default();
|
||||
let mut cache = StorageTransactionCache::default();
|
||||
let mut ext = Ext::new(
|
||||
&mut overlay,
|
||||
&mut offchain_overlay,
|
||||
&mut cache,
|
||||
&backend,
|
||||
crate::changes_trie::disabled_state::<_, u64>(),
|
||||
|
||||
@@ -30,6 +30,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use sp_core::{
|
||||
offchain::storage::OffchainOverlayedChanges,
|
||||
storage::{
|
||||
well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES, is_child_storage_key},
|
||||
Storage,
|
||||
@@ -44,6 +45,7 @@ where
|
||||
H::Out: codec::Codec + Ord,
|
||||
{
|
||||
overlay: OverlayedChanges,
|
||||
offchain_overlay: OffchainOverlayedChanges,
|
||||
storage_transaction_cache: StorageTransactionCache<
|
||||
<InMemoryBackend<H> as Backend<H>>::Transaction, H, N
|
||||
>,
|
||||
@@ -61,6 +63,7 @@ impl<H: Hasher, N: ChangesTrieBlockNumber> TestExternalities<H, N>
|
||||
pub fn ext(&mut self) -> Ext<H, N, InMemoryBackend<H>> {
|
||||
Ext::new(
|
||||
&mut self.overlay,
|
||||
&mut self.offchain_overlay,
|
||||
&mut self.storage_transaction_cache,
|
||||
&self.backend,
|
||||
match self.changes_trie_config.clone() {
|
||||
@@ -98,11 +101,15 @@ impl<H: Hasher, N: ChangesTrieBlockNumber> TestExternalities<H, N>
|
||||
storage.top.insert(HEAP_PAGES.to_vec(), 8u64.encode());
|
||||
storage.top.insert(CODE.to_vec(), code.to_vec());
|
||||
|
||||
let offchain_overlay = OffchainOverlayedChanges::enabled();
|
||||
|
||||
let mut extensions = Extensions::default();
|
||||
extensions.register(sp_core::traits::TaskExecutorExt(sp_core::tasks::executor()));
|
||||
|
||||
|
||||
TestExternalities {
|
||||
overlay,
|
||||
offchain_overlay,
|
||||
changes_trie_config,
|
||||
extensions,
|
||||
changes_trie_storage: ChangesTrieInMemoryStorage::new(),
|
||||
|
||||
@@ -214,6 +214,7 @@ impl<Block: BlockT, Executor, Backend, G: GenesisInit> TestClientBuilder<Block,
|
||||
self.keystore.clone(),
|
||||
),
|
||||
None,
|
||||
sc_client::ClientConfig::default(),
|
||||
).expect("Creates new client");
|
||||
|
||||
let longest_chain = sc_client::LongestChain::new(self.backend);
|
||||
@@ -248,7 +249,7 @@ impl<Block: BlockT, E, Backend, G: GenesisInit> TestClientBuilder<
|
||||
let executor = executor.into().unwrap_or_else(||
|
||||
NativeExecutor::new(WasmExecutionMethod::Interpreted, None, 8)
|
||||
);
|
||||
let executor = LocalCallExecutor::new(self.backend.clone(), executor, tasks_executor());
|
||||
let executor = LocalCallExecutor::new(self.backend.clone(), executor, tasks_executor(), Default::default());
|
||||
|
||||
self.build_with_executor(executor)
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ pub fn new_light() -> (
|
||||
let blockchain = Arc::new(sc_client::light::blockchain::Blockchain::new(storage));
|
||||
let backend = Arc::new(LightBackend::new(blockchain.clone()));
|
||||
let executor = new_native_executor();
|
||||
let local_call_executor = sc_client::LocalCallExecutor::new(backend.clone(), executor, sp_core::tasks::executor());
|
||||
let local_call_executor = sc_client::LocalCallExecutor::new(backend.clone(), executor, sp_core::tasks::executor(), Default::default());
|
||||
let call_executor = LightExecutor::new(
|
||||
backend.clone(),
|
||||
local_call_executor,
|
||||
|
||||
@@ -44,6 +44,7 @@ impl BenchmarkCmd {
|
||||
|
||||
let genesis_storage = spec.build_storage()?;
|
||||
let mut changes = Default::default();
|
||||
let mut offchain_changes = Default::default();
|
||||
let cache_size = Some(self.database_cache_size as usize);
|
||||
let state = BenchmarkingState::<BB>::new(genesis_storage, cache_size)?;
|
||||
let executor = NativeExecutor::<ExecDispatch>::new(
|
||||
@@ -59,6 +60,7 @@ impl BenchmarkCmd {
|
||||
&state,
|
||||
None,
|
||||
&mut changes,
|
||||
&mut offchain_changes,
|
||||
&executor,
|
||||
"Benchmark_dispatch_benchmark",
|
||||
&(
|
||||
|
||||
Reference in New Issue
Block a user