Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 17 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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: Runtime Dev
bkchr marked this conversation as resolved.
Show resolved Hide resolved
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.clone().at.expect("block at must be initialized; qed")
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
bkchr marked this conversation as resolved.
Show resolved Hide resolved
}
}

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
Loading