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

Inject hashed prefix for remote-ext #8960

Merged
merged 5 commits into from
Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
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