Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 10 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
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion utils/frame/remote-externalities/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ codec = { package = "parity-scale-codec", version = "2.0.0" }

sp-io = { version = "3.0.0", path = "../../../primitives/io" }
sp-core = { version = "3.0.0", path = "../../../primitives/core" }
sp-runtime = { version = "3.0.0", path = "../../../primitives/runtime" }

[dev-dependencies]
async-std = { version = "1.6.5", features = ["attributes"] }
tokio = { version = "0.2", features = ["macros"] }

[features]
remote-test = []
110 changes: 62 additions & 48 deletions utils/frame/remote-externalities/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ use std::{
path::{Path, PathBuf},
};
use log::*;
use sp_core::{hashing::twox_128};
use sp_core::hashing::twox_128;
pub use sp_io::TestExternalities;
use sp_core::{
hexdisplay::HexDisplay,
Expand All @@ -115,27 +115,28 @@ use sp_core::{
use codec::{Encode, Decode};
use jsonrpsee_http_client::{HttpClient, HttpConfig};

use sp_runtime::traits::Block as BlockT;

// TODO: Make KeyPair generic
Comment thread
hardliner66 marked this conversation as resolved.
Outdated
type KeyPair = (StorageKey, StorageData);
type Hash = sp_core::H256;
// TODO: make these two generic.

const LOG_TARGET: &str = "remote-ext";
const TARGET: &str = "http://localhost:9933";

jsonrpsee_proc_macros::rpc_client_api! {
RpcApi {
RpcApi<B: BlockT> {
#[rpc(method = "state_getPairs", positional_params)]
fn storage_pairs(prefix: StorageKey, hash: Option<Hash>) -> Vec<(StorageKey, StorageData)>;
fn storage_pairs(prefix: StorageKey, hash: Option<B::Hash>) -> Vec<(StorageKey, StorageData)>;
#[rpc(method = "chain_getFinalizedHead")]
fn finalized_head() -> Hash;
fn finalized_head() -> B::Hash;
}
}

/// The execution mode.
#[derive(Clone)]
pub enum Mode {
pub enum Mode<B: BlockT> {
/// Online.
Online(OnlineConfig),
Online(OnlineConfig<B>),
/// Offline. Uses a cached file and needs not any client config.
Offline(OfflineConfig),
}
Expand All @@ -153,24 +154,24 @@ pub struct OfflineConfig {
///
/// A cache config may be present and will be written to in that case.
#[derive(Clone)]
pub struct OnlineConfig {
pub struct OnlineConfig<B: BlockT> {
/// The HTTP uri to use.
pub uri: String,
/// The block number at which to connect. Will be latest finalized head if not provided.
pub at: Option<Hash>,
pub at: Option<B::Hash>,
/// An optional cache file to WRITE to, not for reading. Not cached if set to `None`.
pub cache: Option<CacheConfig>,
/// The modules to scrape. If empty, entire chain state will be scraped.
pub modules: Vec<String>,
}

impl Default for OnlineConfig {
impl<B: BlockT> Default for OnlineConfig<B> {
fn default() -> Self {
Self { uri: TARGET.to_owned(), at: None, cache: None, modules: Default::default() }
}
}

impl OnlineConfig {
impl<B: BlockT> OnlineConfig<B> {
/// Return a new http rpc client.
fn rpc(&self) -> HttpClient {
HttpClient::new(&self.uri, HttpConfig { max_request_body_size: u32::MAX })
Expand Down Expand Up @@ -202,30 +203,30 @@ impl CacheConfig {
}

/// Builder for remote-externalities.
pub struct Builder {
pub struct Builder<B: BlockT> {
inject: Vec<KeyPair>,
mode: Mode,
mode: Mode<B>,
}

impl Default for Builder {
impl<B: BlockT> Default for Builder<B> {
fn default() -> Self {
Self {
inject: Default::default(),
mode: Mode::Online(OnlineConfig::default())
mode: Mode::Online(OnlineConfig::default()),
}
}
}

// Mode methods
impl Builder {
fn as_online(&self) -> &OnlineConfig {
impl<B: BlockT> Builder<B> {
fn as_online(&self) -> &OnlineConfig<B> {
match &self.mode {
Mode::Online(config) => &config,
_ => panic!("Unexpected mode: Online"),
}
}

fn as_online_mut(&mut self) -> &mut OnlineConfig {
fn as_online_mut(&mut self) -> &mut OnlineConfig<B> {
match &mut self.mode {
Mode::Online(config) => config,
_ => panic!("Unexpected mode: Online"),
Expand All @@ -234,13 +235,13 @@ impl Builder {
}

// RPC methods
impl Builder {
async fn rpc_get_head(&self) -> Result<Hash, &'static str> {
impl<B: BlockT> Builder<B> {
async fn rpc_get_head(&self) -> Result<B::Hash, &'static str> {
trace!(target: LOG_TARGET, "rpc: finalized_head");
RpcApi::finalized_head(&self.as_online().rpc()).await.map_err(|e| {
RpcApi::<B>::finalized_head(&self.as_online().rpc()).await.map_err(|e| {
error!("Error = {:?}", e);
"rpc finalized_head failed."
})
})
}

/// Relay the request to `state_getPairs` rpc endpoint.
Expand All @@ -249,18 +250,18 @@ impl Builder {
async fn rpc_get_pairs(
&self,
prefix: StorageKey,
at: Hash,
at: B::Hash,
) -> Result<Vec<KeyPair>, &'static str> {
trace!(target: LOG_TARGET, "rpc: storage_pairs: {:?} / {:?}", prefix, at);
RpcApi::storage_pairs(&self.as_online().rpc(), prefix, Some(at)).await.map_err(|e| {
RpcApi::<B>::storage_pairs(&self.as_online().rpc(), prefix, Some(at)).await.map_err(|e| {
error!("Error = {:?}", e);
"rpc storage_pairs failed"
})
})
}
}

// Internal methods
impl Builder {
impl<B: BlockT> Builder<B> {
/// Save the given data as cache.
fn save_cache(&self, data: &[KeyPair], path: &Path) -> Result<(), &'static str> {
info!(target: LOG_TARGET, "writing to cache file {:?}", path);
Expand Down Expand Up @@ -341,7 +342,7 @@ impl Builder {
}

// Public methods
impl Builder {
impl<B: BlockT> Builder<B> {
/// Create a new builder.
pub fn new() -> Self {
Default::default()
Expand All @@ -356,7 +357,7 @@ impl Builder {
}

/// Configure a cache to be used.
pub fn mode(mut self, mode: Mode) -> Self {
pub fn mode(mut self, mode: Mode<B>) -> Self {
self.mode = mode;
self
}
Expand All @@ -375,49 +376,62 @@ impl Builder {
}
}

#[cfg(feature = "remote-test")]
#[cfg(test)]
mod tests {
use super::*;
mod test_prelude {
pub use super::*;
Comment thread
hardliner66 marked this conversation as resolved.
Outdated
pub use sp_runtime::testing::{H256 as Hash, Block as RawBlock, ExtrinsicWrapper};

fn init_logger() {
pub type Block = RawBlock<ExtrinsicWrapper<Hash>>;

pub fn init_logger() {
let _ = env_logger::Builder::from_default_env()
.format_module_path(false)
.format_level(true)
.try_init();
}
}

#[async_std::test]
async fn can_build_one_pallet() {
#[cfg(test)]
mod tests {
use super::test_prelude::*;

#[tokio::test]
async fn can_load_cache() {
init_logger();
Builder::new()
.mode(Mode::Online(OnlineConfig {
modules: vec!["Proxy".into()],
..Default::default()
Builder::<Block>::new()
.mode(Mode::Offline(OfflineConfig {
cache: CacheConfig { name: "test_data/proxy_test".into(), ..Default::default() },
}))
.build()
.await
.unwrap()
.execute_with(|| {});
}
}

#[async_std::test]
async fn can_load_cache() {
#[cfg(feature = "remote-test")]
#[cfg(test)]
Comment thread
hardliner66 marked this conversation as resolved.
Outdated
mod remote_tests {
use super::test_prelude::*;

#[tokio::test]
async fn can_build_one_pallet() {
init_logger();
Builder::new()
.mode(Mode::Offline(OfflineConfig {
cache: CacheConfig { name: "proxy_test".into(), ..Default::default() },
Builder::<Block>::new()
.mode(Mode::Online(OnlineConfig {
modules: vec!["Proxy".into()],
..Default::default()
}))
.build()
.await
.unwrap()
Comment thread
hardliner66 marked this conversation as resolved.
Outdated
.execute_with(|| {});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My original tests were not really sophisticated, and I think you can do better here:

We need a way to assert that some data has actually been injected into to the proxy pallet. For example, if you scrape the system pallet, now you want to try and read something like System::block_number or some other storage item that is unlikely not to change.

Or, you can assume that you know all storage items in proxy are prefixed with twox128("Proxy"), and then assert that sp_io::storage::next_key(twox128("Proxy")) is some.

There are other ways to also do this.

Treat it as a bonus, if you want to explore the storage a bit.

}

#[async_std::test]
#[tokio::test]
async fn can_create_cache() {
init_logger();
Builder::new()
Builder::<Block>::new()
.mode(Mode::Online(OnlineConfig {
cache: Some(CacheConfig {
name: "test_cache_to_remove.bin".into(),
Expand All @@ -444,9 +458,9 @@ mod tests {
}
}

#[async_std::test]
#[tokio::test]
async fn can_build_all() {
init_logger();
Builder::new().build().await.unwrap().execute_with(|| {});
Builder::<Block>::new().build().await.unwrap().execute_with(|| {});
}
}
Binary file not shown.
Loading