1#![warn(missing_docs)]
21#![cfg_attr(not(feature = "std"), no_std)]
22
23pub mod backend;
24#[cfg(feature = "std")]
25mod in_memory_backend;
26#[cfg(feature = "std")]
27mod changes_trie;
28mod error;
29mod ext;
30#[cfg(feature = "std")]
31mod testing;
32#[cfg(feature = "std")]
33mod basic;
34pub(crate) mod overlayed_changes;
35#[cfg(feature = "std")]
36mod proving_backend;
37mod trie_backend;
38mod trie_backend_essence;
39mod stats;
40#[cfg(feature = "std")]
41mod read_only;
42
43#[cfg(feature = "std")]
44pub use std_reexport::*;
45
46#[cfg(feature = "std")]
47pub use execution::*;
48#[cfg(feature = "std")]
49pub use log::{debug, warn, trace, error as log_error};
50
51#[cfg(not(feature = "std"))]
54#[macro_export]
55macro_rules! warn {
56 (target: $target:expr, $($arg:tt)+) => (
57 ()
58 );
59 ($($arg:tt)+) => (
60 ()
61 );
62}
63
64#[cfg(not(feature = "std"))]
67#[macro_export]
68macro_rules! debug {
69 (target: $target:expr, $($arg:tt)+) => (
70 ()
71 );
72 ($($arg:tt)+) => (
73 ()
74 );
75}
76
77#[cfg(not(feature = "std"))]
80#[macro_export]
81macro_rules! trace {
82 (target: $target:expr, $($arg:tt)+) => (
83 ()
84 );
85 ($($arg:tt)+) => (
86 ()
87 );
88}
89
90#[cfg(not(feature = "std"))]
93#[macro_export]
94macro_rules! log_error {
95 (target: $target:expr, $($arg:tt)+) => (
96 ()
97 );
98 ($($arg:tt)+) => (
99 ()
100 );
101}
102
103#[cfg(feature = "std")]
105pub type DefaultError = String;
106#[cfg(not(feature = "std"))]
108#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
109pub struct DefaultError;
110
111#[cfg(not(feature = "std"))]
112impl tetcore_std::fmt::Display for DefaultError {
113 fn fmt(&self, f: &mut tetcore_std::fmt::Formatter) -> tetcore_std::fmt::Result {
114 write!(f, "DefaultError")
115 }
116}
117
118pub use crate::overlayed_changes::{
119 OverlayedChanges, StorageKey, StorageValue,
120 StorageCollection, ChildStorageCollection,
121 StorageChanges, StorageTransactionCache,
122 OffchainChangesCollection,
123 OffchainOverlayedChanges,
124};
125pub use crate::backend::Backend;
126pub use crate::trie_backend_essence::{TrieBackendStorage, Storage};
127pub use crate::trie_backend::TrieBackend;
128pub use crate::stats::{UsageInfo, UsageUnit, StateMachineStats};
129pub use error::{Error, ExecutionError};
130pub use crate::ext::Ext;
131
132#[cfg(not(feature = "std"))]
133mod changes_trie {
134 pub trait BlockNumber {}
137
138 impl<N> BlockNumber for N {}
139}
140
141#[cfg(feature = "std")]
142mod std_reexport {
143 pub use tp_trie::{trie_types::{Layout, TrieDBMut}, StorageProof, TrieMut, DBValue, MemoryDB};
144 pub use crate::testing::TestExternalities;
145 pub use crate::basic::BasicExternalities;
146 pub use crate::read_only::{ReadOnlyExternalities, InspectState};
147 pub use crate::changes_trie::{
148 AnchorBlockId as ChangesTrieAnchorBlockId,
149 State as ChangesTrieState,
150 Storage as ChangesTrieStorage,
151 RootsStorage as ChangesTrieRootsStorage,
152 InMemoryStorage as InMemoryChangesTrieStorage,
153 BuildCache as ChangesTrieBuildCache,
154 CacheAction as ChangesTrieCacheAction,
155 ConfigurationRange as ChangesTrieConfigurationRange,
156 key_changes, key_changes_proof,
157 key_changes_proof_check, key_changes_proof_check_with_db,
158 prune as prune_changes_tries,
159 disabled_state as disabled_changes_trie_state,
160 BlockNumber as ChangesTrieBlockNumber,
161 };
162 pub use crate::proving_backend::{
163 create_proof_check_backend, ProofRecorder, ProvingBackend, ProvingBackendRecorder,
164 };
165 pub use crate::error::{Error, ExecutionError};
166 pub use crate::in_memory_backend::new_in_mem;
167}
168
169#[cfg(feature = "std")]
170mod execution {
171 use super::*;
172 use std::{fmt, result, collections::HashMap, panic::UnwindSafe};
173 use log::{warn, trace};
174 use tetsy_hash_db::Hasher;
175 use codec::{Decode, Encode, Codec};
176 use tet_core::{
177 storage::ChildInfo, NativeOrEncoded, NeverNativeValue, hexdisplay::HexDisplay,
178 traits::{CodeExecutor, CallInWasmExt, RuntimeCode, SpawnNamed},
179 };
180 use externalities::Extensions;
181
182
183 const PROOF_CLOSE_TRANSACTION: &str = "\
184 Closing a transaction that was started in this function. Client initiated transactions
185 are protected from being closed by the runtime. qed";
186
187 pub(crate) type CallResult<R, E> = Result<NativeOrEncoded<R>, E>;
188
189 pub type DefaultHandler<R, E> = fn(CallResult<R, E>, CallResult<R, E>) -> CallResult<R, E>;
191
192 pub type ChangesTrieTransaction<H, N> = (
194 MemoryDB<H>,
195 ChangesTrieCacheAction<<H as Hasher>::Out, N>,
196 );
197
198 pub type InMemoryBackend<H> = TrieBackend<MemoryDB<H>, H>;
200
201 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
203 pub enum ExecutionStrategy {
204 NativeWhenPossible,
207 AlwaysWasm,
209 Both,
211 NativeElseWasm,
213 }
214
215 #[derive(Debug, Clone)]
217 pub enum BackendTrustLevel {
218 Trusted,
220 Untrusted,
224 }
225
226 #[derive(Clone)]
228 pub enum ExecutionManager<F> {
229 NativeWhenPossible,
232 AlwaysWasm(BackendTrustLevel),
236 Both(F),
238 NativeElseWasm,
240 }
241
242 impl<'a, F> From<&'a ExecutionManager<F>> for ExecutionStrategy {
243 fn from(s: &'a ExecutionManager<F>) -> Self {
244 match *s {
245 ExecutionManager::NativeWhenPossible => ExecutionStrategy::NativeWhenPossible,
246 ExecutionManager::AlwaysWasm(_) => ExecutionStrategy::AlwaysWasm,
247 ExecutionManager::NativeElseWasm => ExecutionStrategy::NativeElseWasm,
248 ExecutionManager::Both(_) => ExecutionStrategy::Both,
249 }
250 }
251 }
252
253 impl ExecutionStrategy {
254 pub fn get_manager<E: fmt::Debug, R: Decode + Encode>(
256 self,
257 ) -> ExecutionManager<DefaultHandler<R, E>> {
258 match self {
259 ExecutionStrategy::AlwaysWasm => ExecutionManager::AlwaysWasm(BackendTrustLevel::Trusted),
260 ExecutionStrategy::NativeWhenPossible => ExecutionManager::NativeWhenPossible,
261 ExecutionStrategy::NativeElseWasm => ExecutionManager::NativeElseWasm,
262 ExecutionStrategy::Both => ExecutionManager::Both(|wasm_result, native_result| {
263 warn!(
264 "Consensus error between wasm {:?} and native {:?}. Using wasm.",
265 wasm_result,
266 native_result,
267 );
268 warn!(" Native result {:?}", native_result);
269 warn!(" Wasm result {:?}", wasm_result);
270 wasm_result
271 }),
272 }
273 }
274 }
275
276 pub fn native_else_wasm<E, R: Decode>() -> ExecutionManager<DefaultHandler<R, E>> {
278 ExecutionManager::NativeElseWasm
279 }
280
281 fn always_wasm<E, R: Decode>() -> ExecutionManager<DefaultHandler<R, E>> {
283 ExecutionManager::AlwaysWasm(BackendTrustLevel::Trusted)
284 }
285
286 fn always_untrusted_wasm<E, R: Decode>() -> ExecutionManager<DefaultHandler<R, E>> {
288 ExecutionManager::AlwaysWasm(BackendTrustLevel::Untrusted)
289 }
290
291 pub struct StateMachine<'a, B, H, N, Exec>
293 where
294 H: Hasher,
295 B: Backend<H>,
296 N: ChangesTrieBlockNumber,
297 {
298 backend: &'a B,
299 exec: &'a Exec,
300 method: &'a str,
301 call_data: &'a [u8],
302 overlay: &'a mut OverlayedChanges,
303 extensions: Extensions,
304 changes_trie_state: Option<ChangesTrieState<'a, H, N>>,
305 storage_transaction_cache: Option<&'a mut StorageTransactionCache<B::Transaction, H, N>>,
306 runtime_code: &'a RuntimeCode<'a>,
307 stats: StateMachineStats,
308 }
309
310 impl<'a, B, H, N, Exec> Drop for StateMachine<'a, B, H, N, Exec> where
311 H: Hasher,
312 B: Backend<H>,
313 N: ChangesTrieBlockNumber,
314 {
315 fn drop(&mut self) {
316 self.backend.register_overlay_stats(&self.stats);
317 }
318 }
319
320 impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where
321 H: Hasher,
322 H::Out: Ord + 'static + codec::Codec,
323 Exec: CodeExecutor + Clone + 'static,
324 B: Backend<H>,
325 N: crate::changes_trie::BlockNumber,
326 {
327 pub fn new(
329 backend: &'a B,
330 changes_trie_state: Option<ChangesTrieState<'a, H, N>>,
331 overlay: &'a mut OverlayedChanges,
332 exec: &'a Exec,
333 method: &'a str,
334 call_data: &'a [u8],
335 mut extensions: Extensions,
336 runtime_code: &'a RuntimeCode,
337 spawn_handle: impl SpawnNamed + Send + 'static,
338 ) -> Self {
339 extensions.register(CallInWasmExt::new(exec.clone()));
340 extensions.register(tet_core::traits::TaskExecutorExt::new(spawn_handle));
341
342 Self {
343 backend,
344 exec,
345 method,
346 call_data,
347 extensions,
348 overlay,
349 changes_trie_state,
350 storage_transaction_cache: None,
351 runtime_code,
352 stats: StateMachineStats::default(),
353 }
354 }
355
356 pub fn with_storage_transaction_cache(
362 mut self,
363 cache: Option<&'a mut StorageTransactionCache<B::Transaction, H, N>>,
364 ) -> Self {
365 self.storage_transaction_cache = cache;
366 self
367 }
368
369 pub fn execute(&mut self, strategy: ExecutionStrategy) -> Result<Vec<u8>, Box<dyn Error>> {
378 self.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
381 strategy.get_manager(),
382 None,
383 ).map(NativeOrEncoded::into_encoded)
384 }
385
386 fn execute_aux<R, NC>(
387 &mut self,
388 use_native: bool,
389 native_call: Option<NC>,
390 ) -> (
391 CallResult<R, Exec::Error>,
392 bool,
393 ) where
394 R: Decode + Encode + PartialEq,
395 NC: FnOnce() -> result::Result<R, String> + UnwindSafe,
396 {
397 let mut cache = StorageTransactionCache::default();
398
399 let cache = match self.storage_transaction_cache.as_mut() {
400 Some(cache) => cache,
401 None => &mut cache,
402 };
403
404 self.overlay.enter_runtime().expect("StateMachine is never called from the runtime; qed");
405
406 let mut ext = Ext::new(
407 self.overlay,
408 cache,
409 self.backend,
410 self.changes_trie_state.clone(),
411 Some(&mut self.extensions),
412 );
413
414 let id = ext.id;
415 trace!(
416 target: "state", "{:04x}: Call {} at {:?}. Input={:?}",
417 id,
418 self.method,
419 self.backend,
420 HexDisplay::from(&self.call_data),
421 );
422
423 let (result, was_native) = self.exec.call(
424 &mut ext,
425 self.runtime_code,
426 self.method,
427 self.call_data,
428 use_native,
429 native_call,
430 );
431
432 self.overlay.exit_runtime()
433 .expect("Runtime is not able to call this function in the overlay; qed");
434
435 trace!(
436 target: "state", "{:04x}: Return. Native={:?}, Result={:?}",
437 id,
438 was_native,
439 result,
440 );
441
442 (result, was_native)
443 }
444
445 fn execute_call_with_both_strategy<Handler, R, NC>(
446 &mut self,
447 mut native_call: Option<NC>,
448 on_consensus_failure: Handler,
449 ) -> CallResult<R, Exec::Error>
450 where
451 R: Decode + Encode + PartialEq,
452 NC: FnOnce() -> result::Result<R, String> + UnwindSafe,
453 Handler: FnOnce(
454 CallResult<R, Exec::Error>,
455 CallResult<R, Exec::Error>,
456 ) -> CallResult<R, Exec::Error>
457 {
458 self.overlay.start_transaction();
459 let (result, was_native) = self.execute_aux(true, native_call.take());
460
461 if was_native {
462 self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION);
463 let (wasm_result, _) = self.execute_aux(
464 false,
465 native_call,
466 );
467
468 if (result.is_ok() && wasm_result.is_ok()
469 && result.as_ref().ok() == wasm_result.as_ref().ok())
470 || result.is_err() && wasm_result.is_err()
471 {
472 result
473 } else {
474 on_consensus_failure(wasm_result, result)
475 }
476 } else {
477 self.overlay.commit_transaction().expect(PROOF_CLOSE_TRANSACTION);
478 result
479 }
480 }
481
482 fn execute_call_with_native_else_wasm_strategy<R, NC>(
483 &mut self,
484 mut native_call: Option<NC>,
485 ) -> CallResult<R, Exec::Error>
486 where
487 R: Decode + Encode + PartialEq,
488 NC: FnOnce() -> result::Result<R, String> + UnwindSafe,
489 {
490 self.overlay.start_transaction();
491 let (result, was_native) = self.execute_aux(
492 true,
493 native_call.take(),
494 );
495
496 if !was_native || result.is_ok() {
497 self.overlay.commit_transaction().expect(PROOF_CLOSE_TRANSACTION);
498 result
499 } else {
500 self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION);
501 let (wasm_result, _) = self.execute_aux(
502 false,
503 native_call,
504 );
505 wasm_result
506 }
507 }
508
509 pub fn execute_using_consensus_failure_handler<Handler, R, NC>(
519 &mut self,
520 manager: ExecutionManager<Handler>,
521 mut native_call: Option<NC>,
522 ) -> Result<NativeOrEncoded<R>, Box<dyn Error>>
523 where
524 R: Decode + Encode + PartialEq,
525 NC: FnOnce() -> result::Result<R, String> + UnwindSafe,
526 Handler: FnOnce(
527 CallResult<R, Exec::Error>,
528 CallResult<R, Exec::Error>,
529 ) -> CallResult<R, Exec::Error>
530 {
531 let changes_tries_enabled = self.changes_trie_state.is_some();
532 self.overlay.set_collect_extrinsics(changes_tries_enabled);
533
534 let result = {
535 match manager {
536 ExecutionManager::Both(on_consensus_failure) => {
537 self.execute_call_with_both_strategy(
538 native_call.take(),
539 on_consensus_failure,
540 )
541 },
542 ExecutionManager::NativeElseWasm => {
543 self.execute_call_with_native_else_wasm_strategy(
544 native_call.take(),
545 )
546 },
547 ExecutionManager::AlwaysWasm(trust_level) => {
548 let _abort_guard = match trust_level {
549 BackendTrustLevel::Trusted => None,
550 BackendTrustLevel::Untrusted => Some(panic_handler::AbortGuard::never_abort()),
551 };
552 self.execute_aux(false, native_call).0
553 },
554 ExecutionManager::NativeWhenPossible => {
555 self.execute_aux(true, native_call).0
556 },
557 }
558 };
559
560 result.map_err(|e| Box::new(e) as _)
561 }
562 }
563
564 pub fn prove_execution<B, H, N, Exec, Spawn>(
566 mut backend: B,
567 overlay: &mut OverlayedChanges,
568 exec: &Exec,
569 spawn_handle: Spawn,
570 method: &str,
571 call_data: &[u8],
572 runtime_code: &RuntimeCode,
573 ) -> Result<(Vec<u8>, StorageProof), Box<dyn Error>>
574 where
575 B: Backend<H>,
576 H: Hasher,
577 H::Out: Ord + 'static + codec::Codec,
578 Exec: CodeExecutor + Clone + 'static,
579 N: crate::changes_trie::BlockNumber,
580 Spawn: SpawnNamed + Send + 'static,
581 {
582 let trie_backend = backend.as_trie_backend()
583 .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box<dyn Error>)?;
584 prove_execution_on_trie_backend::<_, _, N, _, _>(
585 trie_backend,
586 overlay,
587 exec,
588 spawn_handle,
589 method,
590 call_data,
591 runtime_code,
592 )
593 }
594
595 pub fn prove_execution_on_trie_backend<S, H, N, Exec, Spawn>(
605 trie_backend: &TrieBackend<S, H>,
606 overlay: &mut OverlayedChanges,
607 exec: &Exec,
608 spawn_handle: Spawn,
609 method: &str,
610 call_data: &[u8],
611 runtime_code: &RuntimeCode,
612 ) -> Result<(Vec<u8>, StorageProof), Box<dyn Error>>
613 where
614 S: trie_backend_essence::TrieBackendStorage<H>,
615 H: Hasher,
616 H::Out: Ord + 'static + codec::Codec,
617 Exec: CodeExecutor + 'static + Clone,
618 N: crate::changes_trie::BlockNumber,
619 Spawn: SpawnNamed + Send + 'static,
620 {
621 let proving_backend = proving_backend::ProvingBackend::new(trie_backend);
622 let mut sm = StateMachine::<_, H, N, Exec>::new(
623 &proving_backend,
624 None,
625 overlay,
626 exec,
627 method,
628 call_data,
629 Extensions::default(),
630 runtime_code,
631 spawn_handle,
632 );
633
634 let result = sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
635 always_wasm(),
636 None,
637 )?;
638 let proof = sm.backend.extract_proof();
639 Ok((result.into_encoded(), proof))
640 }
641
642 pub fn execution_proof_check<H, N, Exec, Spawn>(
644 root: H::Out,
645 proof: StorageProof,
646 overlay: &mut OverlayedChanges,
647 exec: &Exec,
648 spawn_handle: Spawn,
649 method: &str,
650 call_data: &[u8],
651 runtime_code: &RuntimeCode,
652 ) -> Result<Vec<u8>, Box<dyn Error>>
653 where
654 H: Hasher,
655 Exec: CodeExecutor + Clone + 'static,
656 H::Out: Ord + 'static + codec::Codec,
657 N: crate::changes_trie::BlockNumber,
658 Spawn: SpawnNamed + Send + 'static,
659 {
660 let trie_backend = create_proof_check_backend::<H>(root.into(), proof)?;
661 execution_proof_check_on_trie_backend::<_, N, _, _>(
662 &trie_backend,
663 overlay,
664 exec,
665 spawn_handle,
666 method,
667 call_data,
668 runtime_code,
669 )
670 }
671
672 pub fn execution_proof_check_on_trie_backend<H, N, Exec, Spawn>(
674 trie_backend: &TrieBackend<MemoryDB<H>, H>,
675 overlay: &mut OverlayedChanges,
676 exec: &Exec,
677 spawn_handle: Spawn,
678 method: &str,
679 call_data: &[u8],
680 runtime_code: &RuntimeCode,
681 ) -> Result<Vec<u8>, Box<dyn Error>>
682 where
683 H: Hasher,
684 H::Out: Ord + 'static + codec::Codec,
685 Exec: CodeExecutor + Clone + 'static,
686 N: crate::changes_trie::BlockNumber,
687 Spawn: SpawnNamed + Send + 'static,
688 {
689 let mut sm = StateMachine::<_, H, N, Exec>::new(
690 trie_backend,
691 None,
692 overlay,
693 exec,
694 method,
695 call_data,
696 Extensions::default(),
697 runtime_code,
698 spawn_handle,
699 );
700
701 sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
702 always_untrusted_wasm(),
703 None,
704 ).map(NativeOrEncoded::into_encoded)
705 }
706
707 pub fn prove_read<B, H, I>(
709 mut backend: B,
710 keys: I,
711 ) -> Result<StorageProof, Box<dyn Error>>
712 where
713 B: Backend<H>,
714 H: Hasher,
715 H::Out: Ord + Codec,
716 I: IntoIterator,
717 I::Item: AsRef<[u8]>,
718 {
719 let trie_backend = backend.as_trie_backend()
720 .ok_or_else(
721 || Box::new(ExecutionError::UnableToGenerateProof) as Box<dyn Error>
722 )?;
723 prove_read_on_trie_backend(trie_backend, keys)
724 }
725
726 pub fn prove_child_read<B, H, I>(
728 mut backend: B,
729 child_info: &ChildInfo,
730 keys: I,
731 ) -> Result<StorageProof, Box<dyn Error>>
732 where
733 B: Backend<H>,
734 H: Hasher,
735 H::Out: Ord + Codec,
736 I: IntoIterator,
737 I::Item: AsRef<[u8]>,
738 {
739 let trie_backend = backend.as_trie_backend()
740 .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box<dyn Error>)?;
741 prove_child_read_on_trie_backend(trie_backend, child_info, keys)
742 }
743
744 pub fn prove_read_on_trie_backend<S, H, I>(
746 trie_backend: &TrieBackend<S, H>,
747 keys: I,
748 ) -> Result<StorageProof, Box<dyn Error>>
749 where
750 S: trie_backend_essence::TrieBackendStorage<H>,
751 H: Hasher,
752 H::Out: Ord + Codec,
753 I: IntoIterator,
754 I::Item: AsRef<[u8]>,
755 {
756 let proving_backend = proving_backend::ProvingBackend::<_, H>::new(trie_backend);
757 for key in keys.into_iter() {
758 proving_backend
759 .storage(key.as_ref())
760 .map_err(|e| Box::new(e) as Box<dyn Error>)?;
761 }
762 Ok(proving_backend.extract_proof())
763 }
764
765 pub fn prove_child_read_on_trie_backend<S, H, I>(
767 trie_backend: &TrieBackend<S, H>,
768 child_info: &ChildInfo,
769 keys: I,
770 ) -> Result<StorageProof, Box<dyn Error>>
771 where
772 S: trie_backend_essence::TrieBackendStorage<H>,
773 H: Hasher,
774 H::Out: Ord + Codec,
775 I: IntoIterator,
776 I::Item: AsRef<[u8]>,
777 {
778 let proving_backend = proving_backend::ProvingBackend::<_, H>::new(trie_backend);
779 for key in keys.into_iter() {
780 proving_backend
781 .child_storage(child_info, key.as_ref())
782 .map_err(|e| Box::new(e) as Box<dyn Error>)?;
783 }
784 Ok(proving_backend.extract_proof())
785 }
786
787 pub fn read_proof_check<H, I>(
789 root: H::Out,
790 proof: StorageProof,
791 keys: I,
792 ) -> Result<HashMap<Vec<u8>, Option<Vec<u8>>>, Box<dyn Error>>
793 where
794 H: Hasher,
795 H::Out: Ord + Codec,
796 I: IntoIterator,
797 I::Item: AsRef<[u8]>,
798 {
799 let proving_backend = create_proof_check_backend::<H>(root, proof)?;
800 let mut result = HashMap::new();
801 for key in keys.into_iter() {
802 let value = read_proof_check_on_proving_backend(&proving_backend, key.as_ref())?;
803 result.insert(key.as_ref().to_vec(), value);
804 }
805 Ok(result)
806 }
807
808 pub fn read_child_proof_check<H, I>(
810 root: H::Out,
811 proof: StorageProof,
812 child_info: &ChildInfo,
813 keys: I,
814 ) -> Result<HashMap<Vec<u8>, Option<Vec<u8>>>, Box<dyn Error>>
815 where
816 H: Hasher,
817 H::Out: Ord + Codec,
818 I: IntoIterator,
819 I::Item: AsRef<[u8]>,
820 {
821 let proving_backend = create_proof_check_backend::<H>(root, proof)?;
822 let mut result = HashMap::new();
823 for key in keys.into_iter() {
824 let value = read_child_proof_check_on_proving_backend(
825 &proving_backend,
826 child_info,
827 key.as_ref(),
828 )?;
829 result.insert(key.as_ref().to_vec(), value);
830 }
831 Ok(result)
832 }
833
834 pub fn read_proof_check_on_proving_backend<H>(
836 proving_backend: &TrieBackend<MemoryDB<H>, H>,
837 key: &[u8],
838 ) -> Result<Option<Vec<u8>>, Box<dyn Error>>
839 where
840 H: Hasher,
841 H::Out: Ord + Codec,
842 {
843 proving_backend.storage(key).map_err(|e| Box::new(e) as Box<dyn Error>)
844 }
845
846 pub fn read_child_proof_check_on_proving_backend<H>(
848 proving_backend: &TrieBackend<MemoryDB<H>, H>,
849 child_info: &ChildInfo,
850 key: &[u8],
851 ) -> Result<Option<Vec<u8>>, Box<dyn Error>>
852 where
853 H: Hasher,
854 H::Out: Ord + Codec,
855 {
856 proving_backend.child_storage(child_info, key)
857 .map_err(|e| Box::new(e) as Box<dyn Error>)
858 }
859}
860
861#[cfg(test)]
862mod tests {
863 use std::collections::BTreeMap;
864 use codec::Encode;
865 use super::*;
866 use super::ext::Ext;
867 use super::changes_trie::Configuration as ChangesTrieConfig;
868 use tet_core::{
869 map, traits::{Externalities, RuntimeCode}, testing::TaskExecutor,
870 };
871 use tp_runtime::traits::BlakeTwo256;
872 use std::{result, collections::HashMap};
873 use codec::Decode;
874 use tet_core::{
875 storage::ChildInfo, NativeOrEncoded, NeverNativeValue,
876 traits::CodeExecutor,
877 };
878 use crate::execution::CallResult;
879
880
881 #[derive(Clone)]
882 struct DummyCodeExecutor {
883 change_changes_trie_config: bool,
884 native_available: bool,
885 native_succeeds: bool,
886 fallback_succeeds: bool,
887 }
888
889 impl CodeExecutor for DummyCodeExecutor {
890 type Error = u8;
891
892 fn call<
893 R: Encode + Decode + PartialEq,
894 NC: FnOnce() -> result::Result<R, String>,
895 >(
896 &self,
897 ext: &mut dyn Externalities,
898 _: &RuntimeCode,
899 _method: &str,
900 _data: &[u8],
901 use_native: bool,
902 native_call: Option<NC>,
903 ) -> (CallResult<R, Self::Error>, bool) {
904 if self.change_changes_trie_config {
905 ext.place_storage(
906 tet_core::storage::well_known_keys::CHANGES_TRIE_CONFIG.to_vec(),
907 Some(
908 ChangesTrieConfig {
909 digest_interval: 777,
910 digest_levels: 333,
911 }.encode()
912 )
913 );
914 }
915
916 let using_native = use_native && self.native_available;
917 match (using_native, self.native_succeeds, self.fallback_succeeds, native_call) {
918 (true, true, _, Some(call)) => {
919 let res = externalities::set_and_run_with_externalities(ext, || call());
920 (
921 res.map(NativeOrEncoded::Native).map_err(|_| 0),
922 true
923 )
924 },
925 (true, true, _, None) | (false, _, true, None) => {
926 (
927 Ok(
928 NativeOrEncoded::Encoded(
929 vec![
930 ext.storage(b"value1").unwrap()[0] +
931 ext.storage(b"value2").unwrap()[0]
932 ]
933 )
934 ),
935 using_native
936 )
937 },
938 _ => (Err(0), using_native),
939 }
940 }
941 }
942
943 impl tet_core::traits::CallInWasm for DummyCodeExecutor {
944 fn call_in_wasm(
945 &self,
946 _: &[u8],
947 _: Option<Vec<u8>>,
948 _: &str,
949 _: &[u8],
950 _: &mut dyn Externalities,
951 _: tet_core::traits::MissingHostFunctions,
952 ) -> std::result::Result<Vec<u8>, String> {
953 unimplemented!("Not required in tests.")
954 }
955 }
956
957 #[test]
958 fn execute_works() {
959 let backend = trie_backend::tests::test_trie();
960 let mut overlayed_changes = Default::default();
961 let wasm_code = RuntimeCode::empty();
962
963 let mut state_machine = StateMachine::new(
964 &backend,
965 changes_trie::disabled_state::<_, u64>(),
966 &mut overlayed_changes,
967 &DummyCodeExecutor {
968 change_changes_trie_config: false,
969 native_available: true,
970 native_succeeds: true,
971 fallback_succeeds: true,
972 },
973 "test",
974 &[],
975 Default::default(),
976 &wasm_code,
977 TaskExecutor::new(),
978 );
979
980 assert_eq!(
981 state_machine.execute(ExecutionStrategy::NativeWhenPossible).unwrap(),
982 vec![66],
983 );
984 }
985
986
987 #[test]
988 fn execute_works_with_native_else_wasm() {
989 let backend = trie_backend::tests::test_trie();
990 let mut overlayed_changes = Default::default();
991 let wasm_code = RuntimeCode::empty();
992
993 let mut state_machine = StateMachine::new(
994 &backend,
995 changes_trie::disabled_state::<_, u64>(),
996 &mut overlayed_changes,
997 &DummyCodeExecutor {
998 change_changes_trie_config: false,
999 native_available: true,
1000 native_succeeds: true,
1001 fallback_succeeds: true,
1002 },
1003 "test",
1004 &[],
1005 Default::default(),
1006 &wasm_code,
1007 TaskExecutor::new(),
1008 );
1009
1010 assert_eq!(state_machine.execute(ExecutionStrategy::NativeElseWasm).unwrap(), vec![66]);
1011 }
1012
1013 #[test]
1014 fn dual_execution_strategy_detects_consensus_failure() {
1015 let mut consensus_failed = false;
1016 let backend = trie_backend::tests::test_trie();
1017 let mut overlayed_changes = Default::default();
1018 let wasm_code = RuntimeCode::empty();
1019
1020 let mut state_machine = StateMachine::new(
1021 &backend,
1022 changes_trie::disabled_state::<_, u64>(),
1023 &mut overlayed_changes,
1024 &DummyCodeExecutor {
1025 change_changes_trie_config: false,
1026 native_available: true,
1027 native_succeeds: true,
1028 fallback_succeeds: false,
1029 },
1030 "test",
1031 &[],
1032 Default::default(),
1033 &wasm_code,
1034 TaskExecutor::new(),
1035 );
1036
1037 assert!(
1038 state_machine.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
1039 ExecutionManager::Both(|we, _ne| {
1040 consensus_failed = true;
1041 we
1042 }),
1043 None,
1044 ).is_err()
1045 );
1046 assert!(consensus_failed);
1047 }
1048
1049 #[test]
1050 fn prove_execution_and_proof_check_works() {
1051 let executor = DummyCodeExecutor {
1052 change_changes_trie_config: false,
1053 native_available: true,
1054 native_succeeds: true,
1055 fallback_succeeds: true,
1056 };
1057
1058 let remote_backend = trie_backend::tests::test_trie();
1060 let remote_root = remote_backend.storage_root(std::iter::empty()).0;
1061 let (remote_result, remote_proof) = prove_execution::<_, _, u64, _, _>(
1062 remote_backend,
1063 &mut Default::default(),
1064 &executor,
1065 TaskExecutor::new(),
1066 "test",
1067 &[],
1068 &RuntimeCode::empty(),
1069 ).unwrap();
1070
1071 let local_result = execution_proof_check::<BlakeTwo256, u64, _, _>(
1073 remote_root,
1074 remote_proof,
1075 &mut Default::default(),
1076 &executor,
1077 TaskExecutor::new(),
1078 "test",
1079 &[],
1080 &RuntimeCode::empty(),
1081 ).unwrap();
1082
1083 assert_eq!(remote_result, vec![66]);
1085 assert_eq!(remote_result, local_result);
1086 }
1087
1088 #[test]
1089 fn clear_prefix_in_ext_works() {
1090 let initial: BTreeMap<_, _> = map![
1091 b"aaa".to_vec() => b"0".to_vec(),
1092 b"abb".to_vec() => b"1".to_vec(),
1093 b"abc".to_vec() => b"2".to_vec(),
1094 b"bbb".to_vec() => b"3".to_vec()
1095 ];
1096 let mut state = InMemoryBackend::<BlakeTwo256>::from(initial);
1097 let backend = state.as_trie_backend().unwrap();
1098
1099 let mut overlay = OverlayedChanges::default();
1100 overlay.set_storage(b"aba".to_vec(), Some(b"1312".to_vec()));
1101 overlay.set_storage(b"bab".to_vec(), Some(b"228".to_vec()));
1102 overlay.start_transaction();
1103 overlay.set_storage(b"abd".to_vec(), Some(b"69".to_vec()));
1104 overlay.set_storage(b"bbd".to_vec(), Some(b"42".to_vec()));
1105
1106 {
1107 let mut cache = StorageTransactionCache::default();
1108 let mut ext = Ext::new(
1109 &mut overlay,
1110 &mut cache,
1111 backend,
1112 changes_trie::disabled_state::<_, u64>(),
1113 None,
1114 );
1115 ext.clear_prefix(b"ab");
1116 }
1117 overlay.commit_transaction().unwrap();
1118
1119 assert_eq!(
1120 overlay.changes().map(|(k, v)| (k.clone(), v.value().cloned()))
1121 .collect::<HashMap<_, _>>(),
1122 map![
1123 b"abc".to_vec() => None.into(),
1124 b"abb".to_vec() => None.into(),
1125 b"aba".to_vec() => None.into(),
1126 b"abd".to_vec() => None.into(),
1127
1128 b"bab".to_vec() => Some(b"228".to_vec()).into(),
1129 b"bbd".to_vec() => Some(b"42".to_vec()).into()
1130 ],
1131 );
1132 }
1133
1134 #[test]
1135 fn limited_child_kill_works() {
1136 let child_info = ChildInfo::new_default(b"sub1");
1137 let initial: HashMap<_, BTreeMap<_, _>> = map![
1138 Some(child_info.clone()) => map![
1139 b"a".to_vec() => b"0".to_vec(),
1140 b"b".to_vec() => b"1".to_vec(),
1141 b"c".to_vec() => b"2".to_vec(),
1142 b"d".to_vec() => b"3".to_vec()
1143 ],
1144 ];
1145 let backend = InMemoryBackend::<BlakeTwo256>::from(initial);
1146
1147 let mut overlay = OverlayedChanges::default();
1148 overlay.set_child_storage(&child_info, b"1".to_vec(), Some(b"1312".to_vec()));
1149 overlay.set_child_storage(&child_info, b"2".to_vec(), Some(b"1312".to_vec()));
1150 overlay.set_child_storage(&child_info, b"3".to_vec(), Some(b"1312".to_vec()));
1151 overlay.set_child_storage(&child_info, b"4".to_vec(), Some(b"1312".to_vec()));
1152
1153 {
1154 let mut cache = StorageTransactionCache::default();
1155 let mut ext = Ext::new(
1156 &mut overlay,
1157 &mut cache,
1158 &backend,
1159 changes_trie::disabled_state::<_, u64>(),
1160 None,
1161 );
1162 assert_eq!(ext.kill_child_storage(&child_info, Some(2)), false);
1163 }
1164
1165 assert_eq!(
1166 overlay.children()
1167 .flat_map(|(iter, _child_info)| iter)
1168 .map(|(k, v)| (k.clone(), v.value().clone()))
1169 .collect::<BTreeMap<_, _>>(),
1170 map![
1171 b"1".to_vec() => None.into(),
1172 b"2".to_vec() => None.into(),
1173 b"3".to_vec() => None.into(),
1174 b"4".to_vec() => None.into(),
1175 b"a".to_vec() => None.into(),
1176 b"b".to_vec() => None.into(),
1177 ],
1178 );
1179 }
1180
1181 #[test]
1182 fn limited_child_kill_off_by_one_works() {
1183 let child_info = ChildInfo::new_default(b"sub1");
1184 let initial: HashMap<_, BTreeMap<_, _>> = map![
1185 Some(child_info.clone()) => map![
1186 b"a".to_vec() => b"0".to_vec(),
1187 b"b".to_vec() => b"1".to_vec(),
1188 b"c".to_vec() => b"2".to_vec(),
1189 b"d".to_vec() => b"3".to_vec()
1190 ],
1191 ];
1192 let backend = InMemoryBackend::<BlakeTwo256>::from(initial);
1193 let mut overlay = OverlayedChanges::default();
1194 let mut cache = StorageTransactionCache::default();
1195 let mut ext = Ext::new(
1196 &mut overlay,
1197 &mut cache,
1198 &backend,
1199 changes_trie::disabled_state::<_, u64>(),
1200 None,
1201 );
1202 assert_eq!(ext.kill_child_storage(&child_info, Some(0)), false);
1203 assert_eq!(ext.kill_child_storage(&child_info, Some(1)), false);
1204 assert_eq!(ext.kill_child_storage(&child_info, Some(2)), false);
1205 assert_eq!(ext.kill_child_storage(&child_info, Some(3)), false);
1206 assert_eq!(ext.kill_child_storage(&child_info, Some(4)), true);
1207 assert_eq!(ext.kill_child_storage(&child_info, Some(5)), true);
1208 }
1209
1210 #[test]
1211 fn set_child_storage_works() {
1212 let child_info = ChildInfo::new_default(b"sub1");
1213 let child_info = &child_info;
1214 let mut state = new_in_mem::<BlakeTwo256>();
1215 let backend = state.as_trie_backend().unwrap();
1216 let mut overlay = OverlayedChanges::default();
1217 let mut cache = StorageTransactionCache::default();
1218 let mut ext = Ext::new(
1219 &mut overlay,
1220 &mut cache,
1221 backend,
1222 changes_trie::disabled_state::<_, u64>(),
1223 None,
1224 );
1225
1226 ext.set_child_storage(
1227 child_info,
1228 b"abc".to_vec(),
1229 b"def".to_vec()
1230 );
1231 assert_eq!(
1232 ext.child_storage(
1233 child_info,
1234 b"abc"
1235 ),
1236 Some(b"def".to_vec())
1237 );
1238 ext.kill_child_storage(
1239 child_info,
1240 None,
1241 );
1242 assert_eq!(
1243 ext.child_storage(
1244 child_info,
1245 b"abc"
1246 ),
1247 None
1248 );
1249 }
1250
1251 #[test]
1252 fn append_storage_works() {
1253 let reference_data = vec![
1254 b"data1".to_vec(),
1255 b"2".to_vec(),
1256 b"D3".to_vec(),
1257 b"d4".to_vec(),
1258 ];
1259 let key = b"key".to_vec();
1260 let mut state = new_in_mem::<BlakeTwo256>();
1261 let backend = state.as_trie_backend().unwrap();
1262 let mut overlay = OverlayedChanges::default();
1263 let mut cache = StorageTransactionCache::default();
1264 {
1265 let mut ext = Ext::new(
1266 &mut overlay,
1267 &mut cache,
1268 backend,
1269 changes_trie::disabled_state::<_, u64>(),
1270 None,
1271 );
1272
1273 ext.storage_append(key.clone(), reference_data[0].encode());
1274 assert_eq!(
1275 ext.storage(key.as_slice()),
1276 Some(vec![reference_data[0].clone()].encode()),
1277 );
1278 }
1279 overlay.start_transaction();
1280 {
1281 let mut ext = Ext::new(
1282 &mut overlay,
1283 &mut cache,
1284 backend,
1285 changes_trie::disabled_state::<_, u64>(),
1286 None,
1287 );
1288
1289 for i in reference_data.iter().skip(1) {
1290 ext.storage_append(key.clone(), i.encode());
1291 }
1292 assert_eq!(
1293 ext.storage(key.as_slice()),
1294 Some(reference_data.encode()),
1295 );
1296 }
1297 overlay.rollback_transaction().unwrap();
1298 {
1299 let ext = Ext::new(
1300 &mut overlay,
1301 &mut cache,
1302 backend,
1303 changes_trie::disabled_state::<_, u64>(),
1304 None,
1305 );
1306 assert_eq!(
1307 ext.storage(key.as_slice()),
1308 Some(vec![reference_data[0].clone()].encode()),
1309 );
1310 }
1311 }
1312
1313 #[test]
1314 fn remove_with_append_then_rollback_appended_then_append_again() {
1315
1316 #[derive(codec::Encode, codec::Decode)]
1317 enum Item { InitializationItem, DiscardedItem, CommitedItem }
1318
1319 let key = b"events".to_vec();
1320 let mut cache = StorageTransactionCache::default();
1321 let mut state = new_in_mem::<BlakeTwo256>();
1322 let backend = state.as_trie_backend().unwrap();
1323 let mut overlay = OverlayedChanges::default();
1324
1325 {
1327 let mut ext = Ext::new(
1328 &mut overlay,
1329 &mut cache,
1330 backend,
1331 changes_trie::disabled_state::<_, u64>(),
1332 None,
1333 );
1334 ext.clear_storage(key.as_slice());
1335 ext.storage_append(key.clone(), Item::InitializationItem.encode());
1336 }
1337 overlay.start_transaction();
1338
1339 {
1341 let mut ext = Ext::new(
1342 &mut overlay,
1343 &mut cache,
1344 backend,
1345 changes_trie::disabled_state::<_, u64>(),
1346 None,
1347 );
1348
1349 assert_eq!(
1350 ext.storage(key.as_slice()),
1351 Some(vec![Item::InitializationItem].encode()),
1352 );
1353
1354 ext.storage_append(key.clone(), Item::DiscardedItem.encode());
1355
1356 assert_eq!(
1357 ext.storage(key.as_slice()),
1358 Some(vec![Item::InitializationItem, Item::DiscardedItem].encode()),
1359 );
1360 }
1361 overlay.rollback_transaction().unwrap();
1362
1363 {
1365 let mut ext = Ext::new(
1366 &mut overlay,
1367 &mut cache,
1368 backend,
1369 changes_trie::disabled_state::<_, u64>(),
1370 None,
1371 );
1372
1373 assert_eq!(
1374 ext.storage(key.as_slice()),
1375 Some(vec![Item::InitializationItem].encode()),
1376 );
1377
1378 ext.storage_append(key.clone(), Item::CommitedItem.encode());
1379
1380 assert_eq!(
1381 ext.storage(key.as_slice()),
1382 Some(vec![Item::InitializationItem, Item::CommitedItem].encode()),
1383 );
1384
1385 }
1386 overlay.start_transaction();
1387
1388 {
1390 let ext = Ext::new(
1391 &mut overlay,
1392 &mut cache,
1393 backend,
1394 changes_trie::disabled_state::<_, u64>(),
1395 None,
1396 );
1397 assert_eq!(
1398 ext.storage(key.as_slice()),
1399 Some(vec![Item::InitializationItem, Item::CommitedItem].encode()),
1400 );
1401 }
1402 }
1403
1404 #[test]
1405 fn prove_read_and_proof_check_works() {
1406 let child_info = ChildInfo::new_default(b"sub1");
1407 let child_info = &child_info;
1408 let remote_backend = trie_backend::tests::test_trie();
1410 let remote_root = remote_backend.storage_root(::std::iter::empty()).0;
1411 let remote_proof = prove_read(remote_backend, &[b"value2"]).unwrap();
1412 let local_result1 = read_proof_check::<BlakeTwo256, _>(
1414 remote_root,
1415 remote_proof.clone(),
1416 &[b"value2"],
1417 ).unwrap();
1418 let local_result2 = read_proof_check::<BlakeTwo256, _>(
1419 remote_root,
1420 remote_proof.clone(),
1421 &[&[0xff]],
1422 ).is_ok();
1423 assert_eq!(
1425 local_result1.into_iter().collect::<Vec<_>>(),
1426 vec![(b"value2".to_vec(), Some(vec![24]))],
1427 );
1428 assert_eq!(local_result2, false);
1429 let remote_backend = trie_backend::tests::test_trie();
1431 let remote_root = remote_backend.storage_root(::std::iter::empty()).0;
1432 let remote_proof = prove_child_read(
1433 remote_backend,
1434 child_info,
1435 &[b"value3"],
1436 ).unwrap();
1437 let local_result1 = read_child_proof_check::<BlakeTwo256, _>(
1438 remote_root,
1439 remote_proof.clone(),
1440 child_info,
1441 &[b"value3"],
1442 ).unwrap();
1443 let local_result2 = read_child_proof_check::<BlakeTwo256, _>(
1444 remote_root,
1445 remote_proof.clone(),
1446 child_info,
1447 &[b"value2"],
1448 ).unwrap();
1449 assert_eq!(
1450 local_result1.into_iter().collect::<Vec<_>>(),
1451 vec![(b"value3".to_vec(), Some(vec![142]))],
1452 );
1453 assert_eq!(
1454 local_result2.into_iter().collect::<Vec<_>>(),
1455 vec![(b"value2".to_vec(), None)],
1456 );
1457 }
1458
1459 #[test]
1460 fn child_storage_uuid() {
1461
1462 let child_info_1 = ChildInfo::new_default(b"sub_test1");
1463 let child_info_2 = ChildInfo::new_default(b"sub_test2");
1464
1465 use crate::trie_backend::tests::test_trie;
1466 let mut overlay = OverlayedChanges::default();
1467
1468 let mut transaction = {
1469 let backend = test_trie();
1470 let mut cache = StorageTransactionCache::default();
1471 let mut ext = Ext::new(
1472 &mut overlay,
1473 &mut cache,
1474 &backend,
1475 changes_trie::disabled_state::<_, u64>(),
1476 None,
1477 );
1478 ext.set_child_storage(&child_info_1, b"abc".to_vec(), b"def".to_vec());
1479 ext.set_child_storage(&child_info_2, b"abc".to_vec(), b"def".to_vec());
1480 ext.storage_root();
1481 cache.transaction.unwrap()
1482 };
1483 let mut duplicate = false;
1484 for (k, (value, rc)) in transaction.drain().iter() {
1485 if *rc == 2 {
1487 duplicate = true;
1488 println!("test duplicate for {:?} {:?}", k, value);
1489 }
1490 }
1491 assert!(!duplicate);
1492 }
1493
1494 #[test]
1495 fn set_storage_empty_allowed() {
1496 let initial: BTreeMap<_, _> = map![
1497 b"aaa".to_vec() => b"0".to_vec(),
1498 b"bbb".to_vec() => b"".to_vec()
1499 ];
1500 let mut state = InMemoryBackend::<BlakeTwo256>::from(initial);
1501 let backend = state.as_trie_backend().unwrap();
1502
1503 let mut overlay = OverlayedChanges::default();
1504 overlay.start_transaction();
1505 overlay.set_storage(b"ccc".to_vec(), Some(b"".to_vec()));
1506 assert_eq!(overlay.storage(b"ccc"), Some(Some(&[][..])));
1507 overlay.commit_transaction().unwrap();
1508 overlay.start_transaction();
1509 assert_eq!(overlay.storage(b"ccc"), Some(Some(&[][..])));
1510 assert_eq!(overlay.storage(b"bbb"), None);
1511
1512 {
1513 let mut cache = StorageTransactionCache::default();
1514 let mut ext = Ext::new(
1515 &mut overlay,
1516 &mut cache,
1517 backend,
1518 changes_trie::disabled_state::<_, u64>(),
1519 None,
1520 );
1521 assert_eq!(ext.storage(b"bbb"), Some(vec![]));
1522 assert_eq!(ext.storage(b"ccc"), Some(vec![]));
1523 ext.clear_storage(b"ccc");
1524 assert_eq!(ext.storage(b"ccc"), None);
1525 }
1526 overlay.commit_transaction().unwrap();
1527 assert_eq!(overlay.storage(b"ccc"), Some(None));
1528 }
1529
1530 #[test]
1531 fn runtime_registered_extensions_are_removed_after_execution() {
1532 use externalities::ExternalitiesExt;
1533 externalities::decl_extension! {
1534 struct DummyExt(u32);
1535 }
1536
1537 let backend = trie_backend::tests::test_trie();
1538 let mut overlayed_changes = Default::default();
1539 let wasm_code = RuntimeCode::empty();
1540
1541 let mut state_machine = StateMachine::new(
1542 &backend,
1543 changes_trie::disabled_state::<_, u64>(),
1544 &mut overlayed_changes,
1545 &DummyCodeExecutor {
1546 change_changes_trie_config: false,
1547 native_available: true,
1548 native_succeeds: true,
1549 fallback_succeeds: false,
1550 },
1551 "test",
1552 &[],
1553 Default::default(),
1554 &wasm_code,
1555 TaskExecutor::new(),
1556 );
1557
1558 let run_state_machine = |state_machine: &mut StateMachine<_, _, _, _>| {
1559 state_machine.execute_using_consensus_failure_handler::<fn(_, _) -> _, _, _>(
1560 ExecutionManager::NativeWhenPossible,
1561 Some(|| {
1562 externalities::with_externalities(|mut ext| {
1563 ext.register_extension(DummyExt(2)).unwrap();
1564 }).unwrap();
1565
1566 Ok(())
1567 }),
1568 ).unwrap();
1569 };
1570
1571 run_state_machine(&mut state_machine);
1572 run_state_machine(&mut state_machine);
1573 }
1574}