mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 17:31:05 +00:00
state_machine no_std witness externalities (#6934)
* checkpoint before removing CT from change trie * before trie backend without tx * undo * Started no transaction, but would need using a different root calculation method, out of the scope of this pr, will roll back. * Remove NoTransaction. * partially address review. dummy stats implementation for no_std. * Remove ChangeTrieOverlay. * modified function * Remove witness_ext * need noops changes root * update from cumulus branch * line break * remove warning * line break * From review: renamings and stats active in no std (except time). * include cache, exclude change trie cache with individual temporary bad looking no_std check * little test * fuse imports and filter_map prepare_extrinsics_input_inner fold. * put back ExtInner into Ext, awkward double proto for new function. * Apply suggestions from code review * Update primitives/state-machine/Cargo.toml Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
@@ -18,23 +18,28 @@
|
||||
//! Concrete externalities implementation.
|
||||
|
||||
use crate::{
|
||||
StorageKey, StorageValue, OverlayedChanges, StorageTransactionCache,
|
||||
StorageKey, StorageValue, OverlayedChanges,
|
||||
backend::Backend,
|
||||
changes_trie::State as ChangesTrieState,
|
||||
};
|
||||
|
||||
use hash_db::Hasher;
|
||||
use sp_core::{
|
||||
offchain::storage::OffchainOverlayedChanges,
|
||||
storage::{well_known_keys::is_child_storage_key, ChildInfo, TrackedStorageKey},
|
||||
traits::Externalities, hexdisplay::HexDisplay,
|
||||
hexdisplay::HexDisplay,
|
||||
};
|
||||
use sp_trie::{trie_types::Layout, empty_child_trie_root};
|
||||
use sp_externalities::{Extensions, Extension};
|
||||
use sp_externalities::{Externalities, Extensions, Extension,
|
||||
ExtensionStore};
|
||||
use codec::{Decode, Encode, EncodeAppend};
|
||||
|
||||
use std::{error, fmt, any::{Any, TypeId}};
|
||||
use log::{warn, trace};
|
||||
use sp_std::{fmt, any::{Any, TypeId}, vec::Vec, vec, boxed::Box};
|
||||
use crate::{warn, trace, log_error};
|
||||
#[cfg(feature = "std")]
|
||||
use sp_core::offchain::storage::OffchainOverlayedChanges;
|
||||
#[cfg(feature = "std")]
|
||||
use crate::changes_trie::State as ChangesTrieState;
|
||||
use crate::StorageTransactionCache;
|
||||
#[cfg(feature = "std")]
|
||||
use std::error;
|
||||
|
||||
const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime";
|
||||
const BENCHMARKING_FN: &str = "\
|
||||
@@ -42,7 +47,19 @@ const BENCHMARKING_FN: &str = "\
|
||||
For that reason client started transactions before calling into runtime are not allowed.
|
||||
Without client transactions the loop condition garantuees the success of the tx close.";
|
||||
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn guard() -> sp_panic_handler::AbortGuard {
|
||||
sp_panic_handler::AbortGuard::force_abort()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn guard() -> () {
|
||||
()
|
||||
}
|
||||
|
||||
/// Errors that can occur when interacting with the externalities.
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Error<B, E> {
|
||||
/// Failure to load state data from the backend.
|
||||
@@ -53,6 +70,7 @@ pub enum Error<B, E> {
|
||||
Executor(E),
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<B: fmt::Display, E: fmt::Display> fmt::Display for Error<B, E> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
@@ -62,6 +80,7 @@ impl<B: fmt::Display, E: fmt::Display> fmt::Display for Error<B, E> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<B: error::Error, E: error::Error> error::Error for Error<B, E> {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
@@ -81,30 +100,49 @@ 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.
|
||||
#[cfg(feature = "std")]
|
||||
offchain_overlay: &'a mut OffchainOverlayedChanges,
|
||||
/// The storage backend to read from.
|
||||
backend: &'a B,
|
||||
/// The cache for the storage transactions.
|
||||
storage_transaction_cache: &'a mut StorageTransactionCache<B::Transaction, H, N>,
|
||||
/// Changes trie state to read from.
|
||||
#[cfg(feature = "std")]
|
||||
changes_trie_state: Option<ChangesTrieState<'a, H, N>>,
|
||||
/// Pseudo-unique id used for tracing.
|
||||
pub id: u16,
|
||||
/// Dummy usage of N arg.
|
||||
_phantom: std::marker::PhantomData<N>,
|
||||
_phantom: sp_std::marker::PhantomData<N>,
|
||||
/// Extensions registered with this instance.
|
||||
#[cfg(feature = "std")]
|
||||
extensions: Option<&'a mut Extensions>,
|
||||
}
|
||||
|
||||
|
||||
impl<'a, H, N, B> Ext<'a, H, N, B>
|
||||
where
|
||||
H: Hasher,
|
||||
H::Out: Ord + 'static + codec::Codec,
|
||||
B: 'a + Backend<H>,
|
||||
N: crate::changes_trie::BlockNumber,
|
||||
where
|
||||
H: Hasher,
|
||||
B: Backend<H>,
|
||||
N: crate::changes_trie::BlockNumber,
|
||||
{
|
||||
/// Create a new `Ext`.
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub fn new(
|
||||
overlay: &'a mut OverlayedChanges,
|
||||
storage_transaction_cache: &'a mut StorageTransactionCache<B::Transaction, H, N>,
|
||||
backend: &'a B,
|
||||
) -> Self {
|
||||
Ext {
|
||||
overlay,
|
||||
backend,
|
||||
id: 0,
|
||||
storage_transaction_cache,
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `Ext` from overlayed changes and read-only backend
|
||||
#[cfg(feature = "std")]
|
||||
pub fn new(
|
||||
overlay: &'a mut OverlayedChanges,
|
||||
offchain_overlay: &'a mut OffchainOverlayedChanges,
|
||||
@@ -133,6 +171,7 @@ where
|
||||
}
|
||||
|
||||
/// Read only accessor for the scheduled overlay changes.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn get_offchain_storage_changes(&self) -> &OffchainOverlayedChanges {
|
||||
&*self.offchain_overlay
|
||||
}
|
||||
@@ -159,14 +198,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, H, B, N> Externalities for Ext<'a, H, N, B>
|
||||
impl<'a, H, N, B> Externalities for Ext<'a, H, N, B>
|
||||
where
|
||||
H: Hasher,
|
||||
H::Out: Ord + 'static + codec::Codec,
|
||||
B: 'a + Backend<H>,
|
||||
B: Backend<H>,
|
||||
N: crate::changes_trie::BlockNumber,
|
||||
{
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn set_offchain_storage(&mut self, key: &[u8], value: Option<&[u8]>) {
|
||||
use ::sp_core::offchain::STORAGE_PREFIX;
|
||||
match value {
|
||||
@@ -175,8 +214,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn set_offchain_storage(&mut self, _key: &[u8], _value: Option<&[u8]>) {}
|
||||
|
||||
fn storage(&self, key: &[u8]) -> Option<StorageValue> {
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
let result = self.overlay.storage(key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(||
|
||||
self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL));
|
||||
trace!(target: "state", "{:04x}: Get {}={:?}",
|
||||
@@ -188,7 +230,7 @@ where
|
||||
}
|
||||
|
||||
fn storage_hash(&self, key: &[u8]) -> Option<Vec<u8>> {
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
let result = self.overlay
|
||||
.storage(key)
|
||||
.map(|x| x.map(|x| H::hash(x)))
|
||||
@@ -207,7 +249,7 @@ where
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Option<StorageValue> {
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
let result = self.overlay
|
||||
.child_storage(child_info, key)
|
||||
.map(|x| x.map(|x| x.to_vec()))
|
||||
@@ -231,7 +273,7 @@ where
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Option<Vec<u8>> {
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
let result = self.overlay
|
||||
.child_storage(child_info, key)
|
||||
.map(|x| x.map(|x| H::hash(x)))
|
||||
@@ -251,7 +293,7 @@ where
|
||||
}
|
||||
|
||||
fn exists_storage(&self, key: &[u8]) -> bool {
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
let result = match self.overlay.storage(key) {
|
||||
Some(x) => x.is_some(),
|
||||
_ => self.backend.exists_storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL),
|
||||
@@ -271,7 +313,7 @@ where
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> bool {
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
|
||||
let result = match self.overlay.child_storage(child_info, key) {
|
||||
Some(x) => x.is_some(),
|
||||
@@ -337,7 +379,7 @@ where
|
||||
HexDisplay::from(&key),
|
||||
value.as_ref().map(HexDisplay::from)
|
||||
);
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
if is_child_storage_key(&key) {
|
||||
warn!(target: "trie", "Refuse to directly set child storage key");
|
||||
return;
|
||||
@@ -359,7 +401,7 @@ where
|
||||
HexDisplay::from(&key),
|
||||
value.as_ref().map(HexDisplay::from)
|
||||
);
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
|
||||
self.mark_dirty();
|
||||
self.overlay.set_child_storage(child_info, key, value);
|
||||
@@ -373,7 +415,7 @@ where
|
||||
self.id,
|
||||
HexDisplay::from(&child_info.storage_key()),
|
||||
);
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
|
||||
self.mark_dirty();
|
||||
self.overlay.clear_child_storage(child_info);
|
||||
@@ -387,7 +429,7 @@ where
|
||||
self.id,
|
||||
HexDisplay::from(&prefix),
|
||||
);
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
if is_child_storage_key(prefix) {
|
||||
warn!(target: "trie", "Refuse to directly clear prefix that is part of child storage key");
|
||||
return;
|
||||
@@ -410,7 +452,7 @@ where
|
||||
HexDisplay::from(&child_info.storage_key()),
|
||||
HexDisplay::from(&prefix),
|
||||
);
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
|
||||
self.mark_dirty();
|
||||
self.overlay.clear_child_prefix(child_info, prefix);
|
||||
@@ -430,7 +472,7 @@ where
|
||||
HexDisplay::from(&value),
|
||||
);
|
||||
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
self.mark_dirty();
|
||||
|
||||
let backend = &mut self.backend;
|
||||
@@ -446,7 +488,7 @@ where
|
||||
}
|
||||
|
||||
fn storage_root(&mut self) -> Vec<u8> {
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
if let Some(ref root) = self.storage_transaction_cache.transaction_storage_root {
|
||||
trace!(target: "state", "{:04x}: Root(cached) {}",
|
||||
self.id,
|
||||
@@ -464,7 +506,7 @@ where
|
||||
&mut self,
|
||||
child_info: &ChildInfo,
|
||||
) -> Vec<u8> {
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
let storage_key = child_info.storage_key();
|
||||
let prefixed_storage_key = child_info.prefixed_storage_key();
|
||||
if self.storage_transaction_cache.transaction_storage_root.is_some() {
|
||||
@@ -525,8 +567,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn storage_changes_root(&mut self, _parent_hash: &[u8]) -> Result<Option<Vec<u8>>, ()> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn storage_changes_root(&mut self, parent_hash: &[u8]) -> Result<Option<Vec<u8>>, ()> {
|
||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||
let _guard = guard();
|
||||
let root = self.overlay.changes_trie_root(
|
||||
self.backend,
|
||||
self.changes_trie_state.as_ref(),
|
||||
@@ -569,6 +617,7 @@ where
|
||||
}
|
||||
self.overlay.drain_storage_changes(
|
||||
&self.backend,
|
||||
#[cfg(feature = "std")]
|
||||
None,
|
||||
Default::default(),
|
||||
self.storage_transaction_cache,
|
||||
@@ -586,6 +635,7 @@ where
|
||||
}
|
||||
let changes = self.overlay.drain_storage_changes(
|
||||
&self.backend,
|
||||
#[cfg(feature = "std")]
|
||||
None,
|
||||
Default::default(),
|
||||
self.storage_transaction_cache,
|
||||
@@ -619,7 +669,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Implement `Encode` by forwarding the stored raw vec.
|
||||
struct EncodeOpaqueValue(Vec<u8>);
|
||||
|
||||
@@ -644,12 +693,12 @@ impl<'a> StorageAppend<'a> {
|
||||
pub fn append(&mut self, value: Vec<u8>) {
|
||||
let value = vec![EncodeOpaqueValue(value)];
|
||||
|
||||
let item = std::mem::take(self.0);
|
||||
let item = sp_std::mem::take(self.0);
|
||||
|
||||
*self.0 = match Vec::<EncodeOpaqueValue>::append_or_new(item, &value) {
|
||||
Ok(item) => item,
|
||||
Err(_) => {
|
||||
log::error!(
|
||||
log_error!(
|
||||
target: "runtime",
|
||||
"Failed to append value, resetting storage item to `[value]`.",
|
||||
);
|
||||
@@ -659,7 +708,36 @@ impl<'a> StorageAppend<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, H, B, N> sp_externalities::ExtensionStore for Ext<'a, H, N, B>
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<'a, H, N, B> ExtensionStore for Ext<'a, H, N, B>
|
||||
where
|
||||
H: Hasher,
|
||||
H::Out: Ord + 'static + codec::Codec,
|
||||
B: Backend<H>,
|
||||
N: crate::changes_trie::BlockNumber,
|
||||
{
|
||||
fn extension_by_type_id(&mut self, _type_id: TypeId) -> Option<&mut dyn Any> {
|
||||
None
|
||||
}
|
||||
|
||||
fn register_extension_with_type_id(
|
||||
&mut self,
|
||||
_type_id: TypeId,
|
||||
_extension: Box<dyn Extension>,
|
||||
) -> Result<(), sp_externalities::Error> {
|
||||
Err(sp_externalities::Error::ExtensionsAreNotSupported)
|
||||
}
|
||||
|
||||
fn deregister_extension_by_type_id(
|
||||
&mut self,
|
||||
_type_id: TypeId,
|
||||
) -> Result<(), sp_externalities::Error> {
|
||||
Err(sp_externalities::Error::ExtensionsAreNotSupported)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'a, H, N, B> ExtensionStore for Ext<'a, H, N, B>
|
||||
where
|
||||
H: Hasher,
|
||||
B: 'a + Backend<H>,
|
||||
|
||||
Reference in New Issue
Block a user