1919//!
2020//! An equivalent of `sp_io::TestExternalities` that can load its state from a remote substrate
2121//! based chain, or a local state snapshot file.
22- //!
23- //! #### Runtime to Test Against
24- //!
25- //! While not absolutely necessary, you most likely need a `Runtime` equivalent in your test setup
26- //! through which you can infer storage types. There are two options here:
27- //!
28- //! 1. Build a mock runtime, similar how to you would build one in a pallet test (see example
29- //! below). The very important point here is that this mock needs to hold real values for types
30- //! that matter for you, based on the chain of interest. Some typical ones are:
31- //!
32- //! - `sp_runtime::AccountId32` as `AccountId`.
33- //! - `u32` as `BlockNumber`.
34- //! - `u128` as Balance.
35- //!
36- //! Once you have your `Runtime`, you can use it for storage type resolution and do things like
37- //! `<my_pallet::Pallet<Runtime>>::storage_getter()` or `<my_pallet::StorageItem<Runtime>>::get()`.
38- //!
39- //! 2. Or, you can use a real runtime.
40- //!
41- //! ### Example
42- //!
43- //! With a test runtime
44- //!
45- //! ```ignore
46- //! use remote_externalities::Builder;
47- //!
48- //! #[derive(Clone, Eq, PartialEq, Debug, Default)]
49- //! pub struct TestRuntime;
50- //!
51- //! use frame_system as system;
52- //! impl_outer_origin! {
53- //! pub enum Origin for TestRuntime {}
54- //! }
55- //!
56- //! impl frame_system::Config for TestRuntime {
57- //! ..
58- //! // we only care about these two for now. The rest can be mock. The block number type of
59- //! // kusama is u32.
60- //! type BlockNumber = u32;
61- //! type Header = Header;
62- //! ..
63- //! }
64- //!
65- //! #[test]
66- //! fn test_runtime_works() {
67- //! let hash: Hash =
68- //! hex!["f9a4ce984129569f63edc01b1c13374779f9384f1befd39931ffdcc83acf63a7"].into();
69- //! let parent: Hash =
70- //! hex!["540922e96a8fcaf945ed23c6f09c3e189bd88504ec945cc2171deaebeaf2f37e"].into();
71- //! Builder::new()
72- //! .at(hash)
73- //! .module("System")
74- //! .build()
75- //! .execute_with(|| {
76- //! assert_eq!(
77- //! // note: the hash corresponds to 3098546. We can check only the parent.
78- //! // https://polkascan.io/kusama/block/3098546
79- //! <frame_system::Pallet<Runtime>>::block_hash(3098545u32),
80- //! parent,
81- //! )
82- //! });
83- //! }
84- //! ```
85- //!
86- //! Or with the real kusama runtime.
87- //!
88- //! ```ignore
89- //! use remote_externalities::Builder;
90- //! use kusama_runtime::Runtime;
91- //!
92- //! #[test]
93- //! fn test_runtime_works() {
94- //! let hash: Hash =
95- //! hex!["f9a4ce984129569f63edc01b1c13374779f9384f1befd39931ffdcc83acf63a7"].into();
96- //! Builder::new()
97- //! .at(hash)
98- //! .module("Staking")
99- //! .build()
100- //! .execute_with(|| assert_eq!(<pallet_staking::Module<Runtime>>::validator_count(), 400));
101- //! }
102- //! ```
10322
10423use std:: {
10524 fs,
@@ -235,8 +154,10 @@ impl Default for SnapshotConfig {
235154
236155/// Builder for remote-externalities.
237156pub struct Builder < B : BlockT > {
238- /// Pallets to inject their prefix into the externalities.
157+ /// Custom key-pairs to be injected into the externalities.
239158 inject : Vec < KeyPair > ,
159+ /// Storage entry key prefixes to be injected into the externalities. The *hashed* prefix must be given.
160+ hashed_prefixes : Vec < Vec < u8 > > ,
240161 /// connectivity mode, online or offline.
241162 mode : Mode < B > ,
242163}
@@ -245,7 +166,7 @@ pub struct Builder<B: BlockT> {
245166// that.
246167impl < B : BlockT > Default for Builder < B > {
247168 fn default ( ) -> Self {
248- Self { inject : Default :: default ( ) , mode : Default :: default ( ) }
169+ Self { inject : Default :: default ( ) , mode : Default :: default ( ) , hashed_prefixes : Default :: default ( ) }
249170 }
250171}
251172
@@ -394,7 +315,7 @@ impl<B: BlockT> Builder<B> {
394315
395316 /// initialize `Self` from state snapshot. Panics if the file does not exist.
396317 fn load_state_snapshot ( & self , path : & Path ) -> Result < Vec < KeyPair > , & ' static str > {
397- info ! ( target: LOG_TARGET , "scraping keypairs from state snapshot {:?}" , path, ) ;
318+ info ! ( target: LOG_TARGET , "scraping key-pairs from state snapshot {:?}" , path, ) ;
398319 let bytes = fs:: read ( path) . map_err ( |_| "fs::read failed." ) ?;
399320 Decode :: decode ( & mut & * bytes) . map_err ( |_| "decode failed" )
400321 }
@@ -407,9 +328,9 @@ impl<B: BlockT> Builder<B> {
407328 . at
408329 . expect ( "online config must be initialized by this point; qed." )
409330 . clone ( ) ;
410- info ! ( target: LOG_TARGET , "scraping keypairs from remote @ {:?}" , at) ;
331+ info ! ( target: LOG_TARGET , "scraping key-pairs from remote @ {:?}" , at) ;
411332
412- let keys_and_values = if config. modules . len ( ) > 0 {
333+ let mut keys_and_values = if config. modules . len ( ) > 0 {
413334 let mut filtered_kv = vec ! [ ] ;
414335 for f in config. modules . iter ( ) {
415336 let hashed_prefix = StorageKey ( twox_128 ( f. as_bytes ( ) ) . to_vec ( ) ) ;
@@ -429,6 +350,12 @@ impl<B: BlockT> Builder<B> {
429350 self . rpc_get_pairs_paged ( StorageKey ( vec ! [ ] ) , at) . await ?
430351 } ;
431352
353+ for prefix in & self . hashed_prefixes {
354+ info ! ( target: LOG_TARGET , "adding data for hashed prefix: {:?}" , HexDisplay :: from( prefix) ) ;
355+ let additional_key_values = self . rpc_get_pairs_paged ( StorageKey ( prefix. to_vec ( ) ) , at) . await ?;
356+ keys_and_values. extend ( additional_key_values) ;
357+ }
358+
432359 Ok ( keys_and_values)
433360 }
434361
@@ -491,6 +418,12 @@ impl<B: BlockT> Builder<B> {
491418 self
492419 }
493420
421+ /// Inject a hashed prefix. This is treated as-is, and should be pre-hashed.
422+ pub fn inject_hashed_prefix ( mut self , hashed : & [ u8 ] ) -> Self {
423+ self . hashed_prefixes . push ( hashed. to_vec ( ) ) ;
424+ self
425+ }
426+
494427 /// Configure a state snapshot to be used.
495428 pub fn mode ( mut self , mode : Mode < B > ) -> Self {
496429 self . mode = mode;
0 commit comments