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. /// This will print some very useful statistics, make sure [`crate::LOG_TARGET`] is enabled.
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) async fn run_with_limits<Runtime, Block>(limits: MigrationLimits, mode: Mode<Block>) pub(crate) async fn run_with_limits<Runtime, Block>(
where limits: MigrationLimits,
mode: Mode<Block::Hash>,
) where
Runtime: crate::Config<Hash = H256>, Runtime: crate::Config<Hash = H256>,
Block: BlockT<Hash = H256> + DeserializeOwned, Block: BlockT<Hash = H256> + DeserializeOwned,
Block::Header: serde::de::DeserializeOwned, Block::Header: serde::de::DeserializeOwned,
@@ -36,7 +36,7 @@ use sp_core::{
}, },
}; };
use sp_runtime::{ use sp_runtime::{
traits::{Block as BlockT, HashingFor}, traits::{Block as BlockT, Hash, HashingFor},
StateVersion, StateVersion,
}; };
use sp_state_machine::TestExternalities; use sp_state_machine::TestExternalities;
@@ -63,21 +63,21 @@ const SNAPSHOT_VERSION: SnapshotVersion = Compact(3);
/// The snapshot that we store on disk. /// The snapshot that we store on disk.
#[derive(Decode, Encode)] #[derive(Decode, Encode)]
struct Snapshot<B: BlockT> { struct Snapshot<H> {
snapshot_version: SnapshotVersion, snapshot_version: SnapshotVersion,
state_version: StateVersion, state_version: StateVersion,
block_hash: B::Hash, block_hash: H,
// <Vec<Key, (Value, MemoryDbRefCount)>> // <Vec<Key, (Value, MemoryDbRefCount)>>
raw_storage: Vec<(Vec<u8>, (Vec<u8>, i32))>, 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( pub fn new(
state_version: StateVersion, state_version: StateVersion,
block_hash: B::Hash, block_hash: H,
raw_storage: Vec<(Vec<u8>, (Vec<u8>, i32))>, raw_storage: Vec<(Vec<u8>, (Vec<u8>, i32))>,
storage_root: B::Hash, storage_root: H,
) -> Self { ) -> Self {
Self { Self {
snapshot_version: SNAPSHOT_VERSION, 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.")?; 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 // 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. // 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 /// 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. /// bits and pieces to it, and can be loaded remotely.
pub struct RemoteExternalities<B: BlockT> { pub struct RemoteExternalities<H: Hash> {
/// The inner externalities. /// The inner externalities.
pub inner_ext: TestExternalities<HashingFor<B>>, pub inner_ext: TestExternalities<H>,
/// The block hash it which we created this externality env. /// The block hash with which we created this externality env.
pub block_hash: B::Hash, pub block_hash: H::Out,
} }
impl<B: BlockT> Deref for RemoteExternalities<B> { impl<H: Hash> Deref for RemoteExternalities<H> {
type Target = TestExternalities<HashingFor<B>>; type Target = TestExternalities<H>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.inner_ext &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 { fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner_ext &mut self.inner_ext
} }
@@ -127,16 +127,16 @@ impl<B: BlockT> DerefMut for RemoteExternalities<B> {
/// The execution mode. /// The execution mode.
#[derive(Clone)] #[derive(Clone)]
pub enum Mode<B: BlockT> { pub enum Mode<H> {
/// Online. Potentially writes to a snapshot file. /// 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. Uses a state snapshot file and needs not any client config.
Offline(OfflineConfig), Offline(OfflineConfig),
/// Prefer using a snapshot file if it exists, else use a remote server. /// 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 { fn default() -> Self {
Mode::Online(OnlineConfig::default()) 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. /// A state snapshot config may be present and will be written to in that case.
#[derive(Clone)] #[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 /// The block hash at which to get the runtime state. Will be latest finalized head if not
/// provided. /// 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`. /// An optional state snapshot file to WRITE to, not for reading. Not written if set to `None`.
pub state_snapshot: Option<SnapshotConfig>, pub state_snapshot: Option<SnapshotConfig>,
/// The pallets to scrape. These values are hashed and added to `hashed_prefix`. /// 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>>, pub hashed_keys: Vec<Vec<u8>>,
} }
impl<B: BlockT> OnlineConfig<B> { impl<H: Clone> OnlineConfig<H> {
/// Return rpc (http) client reference. /// Return rpc (http) client reference.
fn rpc_client(&self) -> &HttpClient { fn rpc_client(&self) -> &HttpClient {
self.transport self.transport
@@ -248,12 +248,12 @@ impl<B: BlockT> OnlineConfig<B> {
.expect("http client must have been initialized by now; qed.") .expect("http client must have been initialized by now; qed.")
} }
fn at_expected(&self) -> B::Hash { fn at_expected(&self) -> H {
self.at.expect("block at must be initialized; qed") 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 { fn default() -> Self {
Self { Self {
transport: Transport::from(DEFAULT_HTTP_ENDPOINT.to_owned()), 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 { fn from(t: String) -> Self {
Self { transport: t.into(), ..Default::default() } 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. /// The keys that will be excluded from the final externality. The *hashed* key must be given.
hashed_blacklist: Vec<Vec<u8>>, hashed_blacklist: Vec<Vec<u8>>,
/// Connectivity mode, online or offline. /// 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 /// 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. /// 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 // Mode methods
impl<B: BlockT> Builder<B> { impl<B: BlockT> Builder<B> {
fn as_online(&self) -> &OnlineConfig<B> { fn as_online(&self) -> &OnlineConfig<B::Hash> {
match &self.mode { match &self.mode {
Mode::Online(config) => config, Mode::Online(config) => config,
Mode::OfflineOrElseOnline(_, 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 { match &mut self.mode {
Mode::Online(config) => config, Mode::Online(config) => config,
Mode::OfflineOrElseOnline(_, 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 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) { 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 (raw_storage, storage_root) = pending_ext.into_raw_snapshot();
let snapshot = Snapshot::<B>::new( let snapshot = Snapshot::<B::Hash>::new(
state_version, state_version,
self.as_online() self.as_online()
.at .at
@@ -1083,7 +1083,7 @@ where
Ok(pending_ext) 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?; self.init_remote_client().await?;
let block_hash = self.as_online().at_expected(); let block_hash = self.as_online().at_expected();
let inner_ext = self.load_remote_and_maybe_save().await?; let inner_ext = self.load_remote_and_maybe_save().await?;
@@ -1093,12 +1093,12 @@ where
fn do_load_offline( fn do_load_offline(
&mut self, &mut self,
config: OfflineConfig, 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 mut sp = Spinner::with_timer(Spinners::Dots, "Loading snapshot...".into());
let start = Instant::now(); let start = Instant::now();
info!(target: LOG_TARGET, "Loading snapshot from {:?}", &config.state_snapshot.path); info!(target: LOG_TARGET, "Loading snapshot from {:?}", &config.state_snapshot.path);
let Snapshot { snapshot_version: _, block_hash, state_version, raw_storage, storage_root } = 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( let inner_ext = TestExternalities::from_raw_snapshot(
raw_storage, raw_storage,
@@ -1110,7 +1110,9 @@ where
Ok(RemoteExternalities { inner_ext, block_hash }) 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() { let mut ext = match self.mode.clone() {
Mode::Offline(config) => self.do_load_offline(config)?, Mode::Offline(config) => self.do_load_offline(config)?,
Mode::Online(_) => self.do_load_remote().await?, Mode::Online(_) => self.do_load_remote().await?,
@@ -1175,7 +1177,7 @@ where
} }
/// Configure a state snapshot to be used. /// 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.mode = mode;
self self
} }
@@ -1186,7 +1188,7 @@ where
self 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?; let mut ext = self.pre_build().await?;
ext.commit_all().unwrap(); ext.commit_all().unwrap();
@@ -288,7 +288,7 @@ impl State {
executor: &WasmExecutor<HostFns>, executor: &WasmExecutor<HostFns>,
state_snapshot: Option<SnapshotConfig>, state_snapshot: Option<SnapshotConfig>,
try_runtime_check: bool, try_runtime_check: bool,
) -> sc_cli::Result<RemoteExternalities<Block>> ) -> sc_cli::Result<RemoteExternalities<HashingFor<Block>>>
where where
Block::Header: DeserializeOwned, Block::Header: DeserializeOwned,
<Block::Hash as FromStr>::Err: Debug, <Block::Hash as FromStr>::Err: Debug,