Adapt RemoteExternalities and its related types to be used with generic hash parameters (#3953)

Closes  https://github.com/paritytech/polkadot-sdk/issues/3737

---------

Co-authored-by: command-bot <>
Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
Léa Narzis
2024-04-08 23:56:41 +02:00
committed by GitHub
parent 80616f6d03
commit d733c77ee2
4 changed files with 62 additions and 39 deletions
+19
View File
@@ -0,0 +1,19 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
title: Adapt RemoteExternalities and its related types to be used with generic hash parameters
doc:
- audience: Node Dev
description: |
Modify `RemoteExternalities`, `Mode`, `OnlineConfig` and`Snapshot` to rely now on generic parameter, instead of `BlockT`.
Adjust in consequence their implementation to be compatible with types `Hash`, or if possible any generic.
Adapt Builder struct and implementation for these bounds.
crates:
- name: frame-remote-externalities
bump: major
- name: pallet-state-trie-migration
bump: patch
- name: try-runtime-cli
bump: patch
@@ -1698,8 +1698,10 @@ pub(crate) mod remote_tests {
///
/// This will print some very useful statistics, make sure [`crate::LOG_TARGET`] is enabled.
#[allow(dead_code)]
pub(crate) async fn run_with_limits<Runtime, Block>(limits: MigrationLimits, mode: Mode<Block>)
where
pub(crate) async fn run_with_limits<Runtime, Block>(
limits: MigrationLimits,
mode: Mode<Block::Hash>,
) where
Runtime: crate::Config<Hash = H256>,
Block: BlockT<Hash = H256> + DeserializeOwned,
Block::Header: serde::de::DeserializeOwned,
@@ -36,7 +36,7 @@ use sp_core::{
},
};
use sp_runtime::{
traits::{Block as BlockT, HashingFor},
traits::{Block as BlockT, Hash, HashingFor},
StateVersion,
};
use sp_state_machine::TestExternalities;
@@ -63,21 +63,21 @@ const SNAPSHOT_VERSION: SnapshotVersion = Compact(3);
/// The snapshot that we store on disk.
#[derive(Decode, Encode)]
struct Snapshot<B: BlockT> {
struct Snapshot<H> {
snapshot_version: SnapshotVersion,
state_version: StateVersion,
block_hash: B::Hash,
block_hash: H,
// <Vec<Key, (Value, MemoryDbRefCount)>>
raw_storage: Vec<(Vec<u8>, (Vec<u8>, i32))>,
storage_root: B::Hash,
storage_root: H,
}
impl<B: BlockT> Snapshot<B> {
impl<H: Decode> Snapshot<H> {
pub fn new(
state_version: StateVersion,
block_hash: B::Hash,
block_hash: H,
raw_storage: Vec<(Vec<u8>, (Vec<u8>, i32))>,
storage_root: B::Hash,
storage_root: H,
) -> Self {
Self {
snapshot_version: SNAPSHOT_VERSION,
@@ -88,7 +88,7 @@ impl<B: BlockT> Snapshot<B> {
}
}
fn load(path: &PathBuf) -> Result<Snapshot<B>, &'static str> {
fn load(path: &PathBuf) -> Result<Snapshot<H>, &'static str> {
let bytes = fs::read(path).map_err(|_| "fs::read failed.")?;
// The first item in the SCALE encoded struct bytes is the snapshot version. We decode and
// check that first, before proceeding to decode the rest of the snapshot.
@@ -105,21 +105,21 @@ impl<B: BlockT> Snapshot<B> {
/// An externalities that acts exactly the same as [`sp_io::TestExternalities`] but has a few extra
/// bits and pieces to it, and can be loaded remotely.
pub struct RemoteExternalities<B: BlockT> {
pub struct RemoteExternalities<H: Hash> {
/// The inner externalities.
pub inner_ext: TestExternalities<HashingFor<B>>,
/// The block hash it which we created this externality env.
pub block_hash: B::Hash,
pub inner_ext: TestExternalities<H>,
/// The block hash with which we created this externality env.
pub block_hash: H::Out,
}
impl<B: BlockT> Deref for RemoteExternalities<B> {
type Target = TestExternalities<HashingFor<B>>;
impl<H: Hash> Deref for RemoteExternalities<H> {
type Target = TestExternalities<H>;
fn deref(&self) -> &Self::Target {
&self.inner_ext
}
}
impl<B: BlockT> DerefMut for RemoteExternalities<B> {
impl<H: Hash> DerefMut for RemoteExternalities<H> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner_ext
}
@@ -127,16 +127,16 @@ impl<B: BlockT> DerefMut for RemoteExternalities<B> {
/// The execution mode.
#[derive(Clone)]
pub enum Mode<B: BlockT> {
pub enum Mode<H> {
/// Online. Potentially writes to a snapshot file.
Online(OnlineConfig<B>),
Online(OnlineConfig<H>),
/// Offline. Uses a state snapshot file and needs not any client config.
Offline(OfflineConfig),
/// Prefer using a snapshot file if it exists, else use a remote server.
OfflineOrElseOnline(OfflineConfig, OnlineConfig<B>),
OfflineOrElseOnline(OfflineConfig, OnlineConfig<H>),
}
impl<B: BlockT> Default for Mode<B> {
impl<H> Default for Mode<H> {
fn default() -> Self {
Mode::Online(OnlineConfig::default())
}
@@ -221,10 +221,10 @@ impl From<HttpClient> for Transport {
///
/// A state snapshot config may be present and will be written to in that case.
#[derive(Clone)]
pub struct OnlineConfig<B: BlockT> {
pub struct OnlineConfig<H> {
/// The block hash at which to get the runtime state. Will be latest finalized head if not
/// provided.
pub at: Option<B::Hash>,
pub at: Option<H>,
/// An optional state snapshot file to WRITE to, not for reading. Not written if set to `None`.
pub state_snapshot: Option<SnapshotConfig>,
/// The pallets to scrape. These values are hashed and added to `hashed_prefix`.
@@ -240,7 +240,7 @@ pub struct OnlineConfig<B: BlockT> {
pub hashed_keys: Vec<Vec<u8>>,
}
impl<B: BlockT> OnlineConfig<B> {
impl<H: Clone> OnlineConfig<H> {
/// Return rpc (http) client reference.
fn rpc_client(&self) -> &HttpClient {
self.transport
@@ -248,12 +248,12 @@ impl<B: BlockT> OnlineConfig<B> {
.expect("http client must have been initialized by now; qed.")
}
fn at_expected(&self) -> B::Hash {
self.at.expect("block at must be initialized; qed")
fn at_expected(&self) -> H {
self.at.clone().expect("block at must be initialized; qed")
}
}
impl<B: BlockT> Default for OnlineConfig<B> {
impl<H> Default for OnlineConfig<H> {
fn default() -> Self {
Self {
transport: Transport::from(DEFAULT_HTTP_ENDPOINT.to_owned()),
@@ -267,7 +267,7 @@ impl<B: BlockT> Default for OnlineConfig<B> {
}
}
impl<B: BlockT> From<String> for OnlineConfig<B> {
impl<H> From<String> for OnlineConfig<H> {
fn from(t: String) -> Self {
Self { transport: t.into(), ..Default::default() }
}
@@ -307,7 +307,7 @@ pub struct Builder<B: BlockT> {
/// The keys that will be excluded from the final externality. The *hashed* key must be given.
hashed_blacklist: Vec<Vec<u8>>,
/// Connectivity mode, online or offline.
mode: Mode<B>,
mode: Mode<B::Hash>,
/// If provided, overwrite the state version with this. Otherwise, the state_version of the
/// remote node is used. All cache files also store their state version.
///
@@ -328,7 +328,7 @@ impl<B: BlockT> Default for Builder<B> {
// Mode methods
impl<B: BlockT> Builder<B> {
fn as_online(&self) -> &OnlineConfig<B> {
fn as_online(&self) -> &OnlineConfig<B::Hash> {
match &self.mode {
Mode::Online(config) => config,
Mode::OfflineOrElseOnline(_, config) => config,
@@ -336,7 +336,7 @@ impl<B: BlockT> Builder<B> {
}
}
fn as_online_mut(&mut self) -> &mut OnlineConfig<B> {
fn as_online_mut(&mut self) -> &mut OnlineConfig<B::Hash> {
match &mut self.mode {
Mode::Online(config) => config,
Mode::OfflineOrElseOnline(_, config) => config,
@@ -1055,7 +1055,7 @@ where
// If we need to save a snapshot, save the raw storage and root hash to the snapshot.
if let Some(path) = self.as_online().state_snapshot.clone().map(|c| c.path) {
let (raw_storage, storage_root) = pending_ext.into_raw_snapshot();
let snapshot = Snapshot::<B>::new(
let snapshot = Snapshot::<B::Hash>::new(
state_version,
self.as_online()
.at
@@ -1083,7 +1083,7 @@ where
Ok(pending_ext)
}
async fn do_load_remote(&mut self) -> Result<RemoteExternalities<B>, &'static str> {
async fn do_load_remote(&mut self) -> Result<RemoteExternalities<HashingFor<B>>, &'static str> {
self.init_remote_client().await?;
let block_hash = self.as_online().at_expected();
let inner_ext = self.load_remote_and_maybe_save().await?;
@@ -1093,12 +1093,12 @@ where
fn do_load_offline(
&mut self,
config: OfflineConfig,
) -> Result<RemoteExternalities<B>, &'static str> {
) -> Result<RemoteExternalities<HashingFor<B>>, &'static str> {
let mut sp = Spinner::with_timer(Spinners::Dots, "Loading snapshot...".into());
let start = Instant::now();
info!(target: LOG_TARGET, "Loading snapshot from {:?}", &config.state_snapshot.path);
let Snapshot { snapshot_version: _, block_hash, state_version, raw_storage, storage_root } =
Snapshot::<B>::load(&config.state_snapshot.path)?;
Snapshot::<B::Hash>::load(&config.state_snapshot.path)?;
let inner_ext = TestExternalities::from_raw_snapshot(
raw_storage,
@@ -1110,7 +1110,9 @@ where
Ok(RemoteExternalities { inner_ext, block_hash })
}
pub(crate) async fn pre_build(mut self) -> Result<RemoteExternalities<B>, &'static str> {
pub(crate) async fn pre_build(
mut self,
) -> Result<RemoteExternalities<HashingFor<B>>, &'static str> {
let mut ext = match self.mode.clone() {
Mode::Offline(config) => self.do_load_offline(config)?,
Mode::Online(_) => self.do_load_remote().await?,
@@ -1175,7 +1177,7 @@ where
}
/// Configure a state snapshot to be used.
pub fn mode(mut self, mode: Mode<B>) -> Self {
pub fn mode(mut self, mode: Mode<B::Hash>) -> Self {
self.mode = mode;
self
}
@@ -1186,7 +1188,7 @@ where
self
}
pub async fn build(self) -> Result<RemoteExternalities<B>, &'static str> {
pub async fn build(self) -> Result<RemoteExternalities<HashingFor<B>>, &'static str> {
let mut ext = self.pre_build().await?;
ext.commit_all().unwrap();
@@ -288,7 +288,7 @@ impl State {
executor: &WasmExecutor<HostFns>,
state_snapshot: Option<SnapshotConfig>,
try_runtime_check: bool,
) -> sc_cli::Result<RemoteExternalities<Block>>
) -> sc_cli::Result<RemoteExternalities<HashingFor<Block>>>
where
Block::Header: DeserializeOwned,
<Block::Hash as FromStr>::Err: Debug,