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 (#3953)

Closes  #3737

---------

Co-authored-by: command-bot <>
Co-authored-by: Oliver Tale-Yazdi <[email protected]>
Co-authored-by: Bastian Köcher <[email protected]>
  • Loading branch information
3 people authored and Ank4n committed Apr 9, 2024
1 parent 527e039 commit 0cc0af3
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 0cc0af3

Please sign in to comment.