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 6 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
16 changes: 16 additions & 0 deletions prdoc/pr_3953.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 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: Refactor RemoteExternalities and its related types to depend on Hash/HashOutput

doc:
- audience: Runtime Dev
bkchr marked this conversation as resolved.
Show resolved Hide resolved
description: |
Change traits bound for `RemoteExternalities` types as `RemoteExternalities`,
`Mode`, `OnlineConfig`, `Snapshot` to use `Hash` or `HashOutput`
instead of `BlockT`

crates:
- name: frame-remote-externalities
- name: pallet-state-trie-migration
- name: try-runtime-cli
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
72 changes: 37 additions & 35 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, HashOutput, 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: HashOutput> {
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
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: HashOutput> 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: HashOutput> {
/// 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: HashOutput> 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: HashOutput> {
/// 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: HashOutput> OnlineConfig<H> {
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
/// 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 {
fn at_expected(&self) -> H {
self.at.expect("block at must be initialized; qed")
}
}

impl<B: BlockT> Default for OnlineConfig<B> {
impl<H: HashOutput> Default for OnlineConfig<H> {
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
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: HashOutput> From<String> for OnlineConfig<H> {
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
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