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:
Bernhard Schuster
2020-04-24 16:46:19 +02:00
committed by GitHub
parent f66168505b
commit 72ee7d5797
40 changed files with 675 additions and 80 deletions
@@ -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| {
+6
View File
@@ -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>>;
+17
View File
@@ -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)]
+5
View File
@@ -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"
]
+2 -2
View File
@@ -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()
}
+55 -12
View File
@@ -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(),