1use std::{
21 any::{Any, TypeId},
22 panic::{AssertUnwindSafe, UnwindSafe},
23};
24
25use crate::{
26 backend::Backend, ext::Ext, InMemoryBackend, OverlayedChanges, StorageKey, StorageValue,
27 TrieBackendBuilder,
28};
29
30use hash_db::{HashDB, Hasher};
31use pezsp_core::{
32 offchain::testing::TestPersistentOffchainDB,
33 storage::{
34 well_known_keys::{is_child_storage_key, CODE},
35 StateVersion, Storage,
36 },
37};
38use pezsp_externalities::{Extension, ExtensionStore, Extensions};
39use pezsp_trie::{recorder::Recorder, PrefixedMemoryDB, StorageProof};
40
41pub struct TestExternalities<H>
43where
44 H: Hasher + 'static,
45 H::Out: codec::Codec + Ord,
46{
47 overlay: OverlayedChanges<H>,
49 offchain_db: TestPersistentOffchainDB,
50 pub backend: InMemoryBackend<H>,
52 pub extensions: Extensions,
54 pub state_version: StateVersion,
56}
57
58impl<H> TestExternalities<H>
59where
60 H: Hasher + 'static,
61 H::Out: Ord + 'static + codec::Codec,
62{
63 pub fn ext(&mut self) -> Ext<'_, H, InMemoryBackend<H>> {
65 Ext::new(&mut self.overlay, &self.backend, Some(&mut self.extensions))
66 }
67
68 pub fn new(storage: Storage) -> Self {
70 Self::new_with_code_and_state(&[], storage, Default::default())
71 }
72
73 pub fn new_with_state_version(storage: Storage, state_version: StateVersion) -> Self {
75 Self::new_with_code_and_state(&[], storage, state_version)
76 }
77
78 pub fn new_empty() -> Self {
80 Self::new_with_code_and_state(&[], Storage::default(), Default::default())
81 }
82
83 pub fn new_with_code(code: &[u8], storage: Storage) -> Self {
85 Self::new_with_code_and_state(code, storage, Default::default())
86 }
87
88 pub fn new_with_code_and_state(
91 code: &[u8],
92 mut storage: Storage,
93 state_version: StateVersion,
94 ) -> Self {
95 assert!(storage.top.keys().all(|key| !is_child_storage_key(key)));
96
97 storage.top.insert(CODE.to_vec(), code.to_vec());
98
99 let offchain_db = TestPersistentOffchainDB::new();
100
101 let backend = (storage, state_version).into();
102
103 TestExternalities {
104 overlay: OverlayedChanges::default(),
105 offchain_db,
106 extensions: Default::default(),
107 backend,
108 state_version,
109 }
110 }
111
112 pub fn overlayed_changes(&self) -> &OverlayedChanges<H> {
114 &self.overlay
115 }
116
117 pub fn persist_offchain_overlay(&mut self) {
119 self.offchain_db.apply_offchain_changes(self.overlay.offchain_drain_committed());
120 }
121
122 pub fn offchain_db(&self) -> TestPersistentOffchainDB {
124 self.offchain_db.clone()
125 }
126
127 pub fn batch_insert<I>(&mut self, kvs: I)
129 where
130 I: IntoIterator<Item = (StorageKey, StorageValue)>,
131 {
132 self.backend.insert(
133 Some((None, kvs.into_iter().map(|(k, v)| (k, Some(v))).collect())),
134 self.state_version,
135 );
136 }
137
138 pub fn insert(&mut self, k: StorageKey, v: StorageValue) {
140 self.backend.insert(vec![(None, vec![(k, Some(v))])], self.state_version);
141 }
142
143 pub fn insert_child(
147 &mut self,
148 c: pezsp_core::storage::ChildInfo,
149 k: StorageKey,
150 v: StorageValue,
151 ) {
152 self.backend.insert(vec![(Some(c), vec![(k, Some(v))])], self.state_version);
153 }
154
155 pub fn register_extension<E: Any + Extension>(&mut self, ext: E) {
157 self.extensions.register(ext);
158 }
159
160 pub fn from_raw_snapshot(
165 raw_storage: Vec<(Vec<u8>, (Vec<u8>, i32))>,
166 storage_root: H::Out,
167 state_version: StateVersion,
168 ) -> Self {
169 let mut backend = PrefixedMemoryDB::default();
170
171 for (key, (v, ref_count)) in raw_storage {
172 let mut hash = H::Out::default();
173 let hash_len = hash.as_ref().len();
174
175 if key.len() < hash_len {
176 log::warn!("Invalid key in `from_raw_snapshot`: {key:?}");
177 continue;
178 }
179
180 hash.as_mut().copy_from_slice(&key[(key.len() - hash_len)..]);
181
182 for _ in 0..ref_count {
185 backend.emplace(hash, (&key[..(key.len() - hash_len)], None), v.clone());
186 }
187 }
188
189 Self {
190 backend: TrieBackendBuilder::new(backend, storage_root).build(),
191 overlay: Default::default(),
192 offchain_db: Default::default(),
193 extensions: Default::default(),
194 state_version,
195 }
196 }
197
198 pub fn into_raw_snapshot(mut self) -> (Vec<(Vec<u8>, (Vec<u8>, i32))>, H::Out) {
202 let raw_key_values = self
203 .backend
204 .backend_storage_mut()
205 .drain()
206 .into_iter()
207 .filter(|(_, (_, r))| *r > 0)
208 .collect::<Vec<(Vec<u8>, (Vec<u8>, i32))>>();
209
210 (raw_key_values, *self.backend.root())
211 }
212
213 pub fn as_backend(&mut self) -> InMemoryBackend<H> {
218 let top: Vec<_> = self
219 .overlay
220 .changes_mut()
221 .map(|(k, v)| (k.clone(), v.value().cloned()))
222 .collect();
223 let mut transaction = vec![(None, top)];
224
225 for (child_changes, child_info) in self.overlay.children_mut() {
226 transaction.push((
227 Some(child_info.clone()),
228 child_changes.map(|(k, v)| (k.clone(), v.value().cloned())).collect(),
229 ))
230 }
231
232 self.backend.update(transaction, self.state_version)
233 }
234
235 pub fn commit_all(&mut self) -> Result<(), String> {
241 let changes = self.overlay.drain_storage_changes(&self.backend, self.state_version)?;
242
243 self.backend
244 .apply_transaction(changes.transaction_storage_root, changes.transaction);
245 Ok(())
246 }
247
248 pub fn execute_with<R>(&mut self, execute: impl FnOnce() -> R) -> R {
252 let mut ext = self.ext();
253 pezsp_externalities::set_and_run_with_externalities(&mut ext, execute)
254 }
255
256 pub fn execute_and_prove<R>(&mut self, execute: impl FnOnce() -> R) -> (R, StorageProof) {
262 let proving_backend = TrieBackendBuilder::wrap(&self.backend)
263 .with_recorder(Default::default())
264 .build();
265 let mut proving_ext =
266 Ext::new(&mut self.overlay, &proving_backend, Some(&mut self.extensions));
267
268 let outcome =
269 pezsp_externalities::set_and_run_with_externalities(&mut proving_ext, execute);
270 let proof = proving_backend.extract_proof().expect("Failed to extract storage proof");
271
272 (outcome, proof)
273 }
274
275 pub fn execute_with_recorder<R>(
278 &mut self,
279 proof_recorder: Recorder<H>,
280 execute: impl FnOnce() -> R,
281 ) -> R {
282 let proving_backend =
283 TrieBackendBuilder::wrap(&self.backend).with_recorder(proof_recorder).build();
284 let mut proving_ext =
285 Ext::new(&mut self.overlay, &proving_backend, Some(&mut self.extensions));
286
287 pezsp_externalities::set_and_run_with_externalities(&mut proving_ext, execute)
288 }
289
290 pub fn execute_with_safe<R>(
295 &mut self,
296 f: impl FnOnce() -> R + UnwindSafe,
297 ) -> Result<R, String> {
298 let mut ext = AssertUnwindSafe(self.ext());
299 std::panic::catch_unwind(move || {
300 pezsp_externalities::set_and_run_with_externalities(&mut *ext, f)
301 })
302 .map_err(|e| format!("Closure panicked: {:?}", e))
303 }
304
305 pub fn reset_overlay(&mut self) {
307 self.overlay = Default::default();
308 }
309}
310
311impl<H: Hasher> std::fmt::Debug for TestExternalities<H>
312where
313 H::Out: Ord + codec::Codec,
314{
315 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
316 let pairs: Vec<_> = self
317 .backend
318 .pairs(Default::default())
319 .expect("creating an iterator over all of the pairs doesn't fail in tests")
320 .collect();
321 write!(f, "overlay: {:?}\nbackend: {:?}", self.overlay, pairs)
322 }
323}
324
325impl<H> TestExternalities<H>
326where
327 H: Hasher,
328 H::Out: Ord + 'static + codec::Codec,
329{
330 pub fn eq(&mut self, other: &mut TestExternalities<H>) -> bool {
333 self.as_backend().eq(&other.as_backend())
334 }
335}
336
337impl<H: Hasher> Default for TestExternalities<H>
338where
339 H::Out: Ord + 'static + codec::Codec,
340{
341 fn default() -> Self {
342 Self::new_with_state_version(Storage::default(), Default::default())
344 }
345}
346
347impl<H: Hasher> From<Storage> for TestExternalities<H>
348where
349 H::Out: Ord + 'static + codec::Codec,
350{
351 fn from(storage: Storage) -> Self {
352 Self::new_with_state_version(storage, Default::default())
353 }
354}
355
356impl<H: Hasher> From<(Storage, StateVersion)> for TestExternalities<H>
357where
358 H::Out: Ord + 'static + codec::Codec,
359{
360 fn from((storage, state_version): (Storage, StateVersion)) -> Self {
361 Self::new_with_state_version(storage, state_version)
362 }
363}
364
365impl<H> pezsp_externalities::ExtensionStore for TestExternalities<H>
366where
367 H: Hasher,
368 H::Out: Ord + codec::Codec,
369{
370 fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> {
371 self.extensions.get_mut(type_id)
372 }
373
374 fn register_extension_with_type_id(
375 &mut self,
376 type_id: TypeId,
377 extension: Box<dyn Extension>,
378 ) -> Result<(), pezsp_externalities::Error> {
379 self.extensions.register_with_type_id(type_id, extension)
380 }
381
382 fn deregister_extension_by_type_id(
383 &mut self,
384 type_id: TypeId,
385 ) -> Result<(), pezsp_externalities::Error> {
386 if self.extensions.deregister(type_id) {
387 Ok(())
388 } else {
389 Err(pezsp_externalities::Error::ExtensionIsNotRegistered(type_id))
390 }
391 }
392}
393
394impl<H> pezsp_externalities::ExternalitiesExt for TestExternalities<H>
395where
396 H: Hasher,
397 H::Out: Ord + codec::Codec,
398{
399 fn extension<T: Any + Extension>(&mut self) -> Option<&mut T> {
400 self.extension_by_type_id(TypeId::of::<T>()).and_then(<dyn Any>::downcast_mut)
401 }
402
403 fn register_extension<T: Extension>(
404 &mut self,
405 ext: T,
406 ) -> Result<(), pezsp_externalities::Error> {
407 self.register_extension_with_type_id(TypeId::of::<T>(), Box::new(ext))
408 }
409
410 fn deregister_extension<T: Extension>(&mut self) -> Result<(), pezsp_externalities::Error> {
411 self.deregister_extension_by_type_id(TypeId::of::<T>())
412 }
413}
414
415#[cfg(test)]
416mod tests {
417 use super::*;
418 use pezsp_core::{storage::ChildInfo, traits::Externalities, H256};
419 use pezsp_runtime::traits::BlakeTwo256;
420
421 #[test]
422 fn commit_should_work() {
423 let storage = Storage::default(); let mut ext = TestExternalities::<BlakeTwo256>::from((storage, Default::default()));
425 let mut ext = ext.ext();
426 ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec());
427 ext.set_storage(b"dog".to_vec(), b"puppy".to_vec());
428 ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec());
429 let root = array_bytes::hex_n_into_unchecked::<_, H256, 32>(
430 "ed4d8c799d996add422395a6abd7545491d40bd838d738afafa1b8a4de625489",
431 );
432 assert_eq!(H256::from_slice(ext.storage_root(Default::default()).as_slice()), root);
433 }
434
435 #[test]
436 fn raw_storage_drain_and_restore() {
437 let mut original_ext =
439 TestExternalities::<BlakeTwo256>::from((Default::default(), Default::default()));
440 original_ext.insert(b"doe".to_vec(), b"reindeer".to_vec());
441 original_ext.insert(b"dog".to_vec(), b"puppy".to_vec());
442 original_ext.insert(b"dogglesworth".to_vec(), b"cat".to_vec());
443 let child_info = ChildInfo::new_default(&b"test_child"[..]);
444 original_ext.insert_child(child_info.clone(), b"cattytown".to_vec(), b"is_dark".to_vec());
445 original_ext.insert_child(child_info.clone(), b"doggytown".to_vec(), b"is_sunny".to_vec());
446
447 original_ext.backend.apply_transaction(
449 *original_ext.backend.root(),
450 original_ext.backend.clone().into_storage(),
451 );
452
453 assert!(original_ext.backend.backend_storage().keys().values().all(|r| *r == 2));
455
456 let root = *original_ext.backend.root();
458 let (raw_storage, storage_root) = original_ext.into_raw_snapshot();
459
460 let recovered_ext = TestExternalities::<BlakeTwo256>::from_raw_snapshot(
462 raw_storage,
463 storage_root,
464 Default::default(),
465 );
466
467 assert_eq!(root, *recovered_ext.backend.root());
469
470 assert_eq!(recovered_ext.backend.storage(b"doe").unwrap(), Some(b"reindeer".to_vec()));
472 assert_eq!(recovered_ext.backend.storage(b"dog").unwrap(), Some(b"puppy".to_vec()));
473 assert_eq!(recovered_ext.backend.storage(b"dogglesworth").unwrap(), Some(b"cat".to_vec()));
474
475 assert_eq!(
477 recovered_ext.backend.child_storage(&child_info, b"cattytown").unwrap(),
478 Some(b"is_dark".to_vec())
479 );
480 assert_eq!(
481 recovered_ext.backend.child_storage(&child_info, b"doggytown").unwrap(),
482 Some(b"is_sunny".to_vec())
483 );
484
485 assert!(recovered_ext.backend.backend_storage().keys().values().all(|r| *r == 2));
487 }
488
489 #[test]
490 fn set_and_retrieve_code() {
491 let mut ext = TestExternalities::<BlakeTwo256>::default();
492 let mut ext = ext.ext();
493
494 let code = vec![1, 2, 3];
495 ext.set_storage(CODE.to_vec(), code.clone());
496
497 assert_eq!(&ext.storage(CODE).unwrap(), &code);
498 }
499
500 #[test]
501 fn check_send() {
502 fn assert_send<T: Send>() {}
503 assert_send::<TestExternalities<BlakeTwo256>>();
504 }
505
506 #[test]
507 fn commit_all_and_kill_child_storage() {
508 let mut ext = TestExternalities::<BlakeTwo256>::default();
509 let child_info = ChildInfo::new_default(&b"test_child"[..]);
510
511 {
512 let mut ext = ext.ext();
513 ext.place_child_storage(&child_info, b"doe".to_vec(), Some(b"reindeer".to_vec()));
514 ext.place_child_storage(&child_info, b"dog".to_vec(), Some(b"puppy".to_vec()));
515 ext.place_child_storage(&child_info, b"dog2".to_vec(), Some(b"puppy2".to_vec()));
516 }
517
518 ext.commit_all().unwrap();
519
520 {
521 let mut ext = ext.ext();
522
523 assert!(
524 ext.kill_child_storage(&child_info, Some(2), None).maybe_cursor.is_some(),
525 "Should not delete all keys"
526 );
527
528 assert!(ext.child_storage(&child_info, &b"doe"[..]).is_none());
529 assert!(ext.child_storage(&child_info, &b"dog"[..]).is_none());
530 assert!(ext.child_storage(&child_info, &b"dog2"[..]).is_some());
531 }
532 }
533
534 #[test]
535 fn as_backend_generates_same_backend_as_commit_all() {
536 let mut ext = TestExternalities::<BlakeTwo256>::default();
537 {
538 let mut ext = ext.ext();
539 ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec());
540 ext.set_storage(b"dog".to_vec(), b"puppy".to_vec());
541 ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec());
542 }
543
544 let backend = ext.as_backend();
545
546 ext.commit_all().unwrap();
547 assert!(ext.backend.eq(&backend), "Both backend should be equal.");
548 }
549}