Skip to content

Commit

Permalink
Adapt RemoteExternalities and its related types to be used with gen…
Browse files Browse the repository at this point in the history
…eric hash parameters (paritytech#3953)

Closes  paritytech#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>
  • Loading branch information
3 people authored and dharjeezy committed Apr 9, 2024
1 parent 83c11b8 commit a952176
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 39 deletions.
19 changes: 19 additions & 0 deletions prdoc/pr_3953.prdoc
Original file line number Diff line number Diff line change
@@ -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
6 changes: 4 additions & 2 deletions substrate/frame/state-trie-migration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
74 changes: 38 additions & 36 deletions substrate/utils/frame/remote-externalities/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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.
Expand All @@ -105,38 +105,38 @@ 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
}
}

/// 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())
}
Expand Down Expand Up @@ -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`.
Expand All @@ -240,20 +240,20 @@ 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
.as_client()
.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()),
Expand All @@ -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() }
}
Expand Down Expand Up @@ -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.
///
Expand All @@ -328,15 +328,15 @@ 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,
_ => panic!("Unexpected mode: Online"),
}
}

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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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?;
Expand All @@ -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,
Expand All @@ -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?,
Expand Down Expand Up @@ -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
}
Expand All @@ -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();

Expand Down
2 changes: 1 addition & 1 deletion substrate/utils/frame/try-runtime/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit a952176

Please sign in to comment.