Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Inject hashed prefix for remote-ext (#8960)
Browse files Browse the repository at this point in the history
* Inject for remote-ext

* Update utils/frame/remote-externalities/src/lib.rs

Co-authored-by: Zeke Mostov <[email protected]>

* Update utils/frame/remote-externalities/src/lib.rs

Co-authored-by: Zeke Mostov <[email protected]>

* Apply suggestions from code review

* Apply suggestions from code review

Co-authored-by: Zeke Mostov <[email protected]>
  • Loading branch information
kianenigma and emostov authored Jun 1, 2021
1 parent 04aa0e9 commit 408e803
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 87 deletions.
2 changes: 1 addition & 1 deletion frame/system/src/offchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ pub trait AppCrypto<Public, Signature> {
// TODO [#5663] Could this be just `T::Signature as traits::Verify>::Signer`?
// Seems that this may cause issues with bounds resolution.
pub trait SigningTypes: crate::Config {
/// A public key that is capable of identifing `AccountId`s.
/// A public key that is capable of identifying `AccountId`s.
///
/// Usually that's either a raw crypto public key (e.g. `sr25519::Public`) or
/// an aggregate type for multiple crypto public keys, like `MulitSigner`.
Expand Down
105 changes: 19 additions & 86 deletions utils/frame/remote-externalities/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,87 +19,6 @@
//!
//! An equivalent of `sp_io::TestExternalities` that can load its state from a remote substrate
//! based chain, or a local state snapshot file.
//!
//! #### Runtime to Test Against
//!
//! While not absolutely necessary, you most likely need a `Runtime` equivalent in your test setup
//! through which you can infer storage types. There are two options here:
//!
//! 1. Build a mock runtime, similar how to you would build one in a pallet test (see example
//! below). The very important point here is that this mock needs to hold real values for types
//! that matter for you, based on the chain of interest. Some typical ones are:
//!
//! - `sp_runtime::AccountId32` as `AccountId`.
//! - `u32` as `BlockNumber`.
//! - `u128` as Balance.
//!
//! Once you have your `Runtime`, you can use it for storage type resolution and do things like
//! `<my_pallet::Pallet<Runtime>>::storage_getter()` or `<my_pallet::StorageItem<Runtime>>::get()`.
//!
//! 2. Or, you can use a real runtime.
//!
//! ### Example
//!
//! With a test runtime
//!
//! ```ignore
//! use remote_externalities::Builder;
//!
//! #[derive(Clone, Eq, PartialEq, Debug, Default)]
//! pub struct TestRuntime;
//!
//! use frame_system as system;
//! impl_outer_origin! {
//! pub enum Origin for TestRuntime {}
//! }
//!
//! impl frame_system::Config for TestRuntime {
//! ..
//! // we only care about these two for now. The rest can be mock. The block number type of
//! // kusama is u32.
//! type BlockNumber = u32;
//! type Header = Header;
//! ..
//! }
//!
//! #[test]
//! fn test_runtime_works() {
//! let hash: Hash =
//! hex!["f9a4ce984129569f63edc01b1c13374779f9384f1befd39931ffdcc83acf63a7"].into();
//! let parent: Hash =
//! hex!["540922e96a8fcaf945ed23c6f09c3e189bd88504ec945cc2171deaebeaf2f37e"].into();
//! Builder::new()
//! .at(hash)
//! .module("System")
//! .build()
//! .execute_with(|| {
//! assert_eq!(
//! // note: the hash corresponds to 3098546. We can check only the parent.
//! // https://polkascan.io/kusama/block/3098546
//! <frame_system::Pallet<Runtime>>::block_hash(3098545u32),
//! parent,
//! )
//! });
//! }
//! ```
//!
//! Or with the real kusama runtime.
//!
//! ```ignore
//! use remote_externalities::Builder;
//! use kusama_runtime::Runtime;
//!
//! #[test]
//! fn test_runtime_works() {
//! let hash: Hash =
//! hex!["f9a4ce984129569f63edc01b1c13374779f9384f1befd39931ffdcc83acf63a7"].into();
//! Builder::new()
//! .at(hash)
//! .module("Staking")
//! .build()
//! .execute_with(|| assert_eq!(<pallet_staking::Module<Runtime>>::validator_count(), 400));
//! }
//! ```

use std::{
fs,
Expand Down Expand Up @@ -235,8 +154,10 @@ impl Default for SnapshotConfig {

/// Builder for remote-externalities.
pub struct Builder<B: BlockT> {
/// Pallets to inject their prefix into the externalities.
/// Custom key-pairs to be injected into the externalities.
inject: Vec<KeyPair>,
/// Storage entry key prefixes to be injected into the externalities. The *hashed* prefix must be given.
hashed_prefixes: Vec<Vec<u8>>,
/// connectivity mode, online or offline.
mode: Mode<B>,
}
Expand All @@ -245,7 +166,7 @@ pub struct Builder<B: BlockT> {
// that.
impl<B: BlockT> Default for Builder<B> {
fn default() -> Self {
Self { inject: Default::default(), mode: Default::default() }
Self { inject: Default::default(), mode: Default::default(), hashed_prefixes: Default::default() }
}
}

Expand Down Expand Up @@ -394,7 +315,7 @@ impl<B: BlockT> Builder<B> {

/// initialize `Self` from state snapshot. Panics if the file does not exist.
fn load_state_snapshot(&self, path: &Path) -> Result<Vec<KeyPair>, &'static str> {
info!(target: LOG_TARGET, "scraping keypairs from state snapshot {:?}", path,);
info!(target: LOG_TARGET, "scraping key-pairs from state snapshot {:?}", path,);
let bytes = fs::read(path).map_err(|_| "fs::read failed.")?;
Decode::decode(&mut &*bytes).map_err(|_| "decode failed")
}
Expand All @@ -407,9 +328,9 @@ impl<B: BlockT> Builder<B> {
.at
.expect("online config must be initialized by this point; qed.")
.clone();
info!(target: LOG_TARGET, "scraping keypairs from remote @ {:?}", at);
info!(target: LOG_TARGET, "scraping key-pairs from remote @ {:?}", at);

let keys_and_values = if config.modules.len() > 0 {
let mut keys_and_values = if config.modules.len() > 0 {
let mut filtered_kv = vec![];
for f in config.modules.iter() {
let hashed_prefix = StorageKey(twox_128(f.as_bytes()).to_vec());
Expand All @@ -429,6 +350,12 @@ impl<B: BlockT> Builder<B> {
self.rpc_get_pairs_paged(StorageKey(vec![]), at).await?
};

for prefix in &self.hashed_prefixes {
info!(target: LOG_TARGET, "adding data for hashed prefix: {:?}", HexDisplay::from(prefix));
let additional_key_values = self.rpc_get_pairs_paged(StorageKey(prefix.to_vec()), at).await?;
keys_and_values.extend(additional_key_values);
}

Ok(keys_and_values)
}

Expand Down Expand Up @@ -491,6 +418,12 @@ impl<B: BlockT> Builder<B> {
self
}

/// Inject a hashed prefix. This is treated as-is, and should be pre-hashed.
pub fn inject_hashed_prefix(mut self, hashed: &[u8]) -> Self {
self.hashed_prefixes.push(hashed.to_vec());
self
}

/// Configure a state snapshot to be used.
pub fn mode(mut self, mode: Mode<B>) -> Self {
self.mode = mode;
Expand Down

0 comments on commit 408e803

Please sign in to comment.