1919//! This module defines and implements the wasm part of Substrate Host Interface and provides
2020//! an interface for calling into the wasm runtime.
2121
22- use std:: { convert:: TryFrom , str} ;
22+ use std:: { convert:: TryFrom , str, panic } ;
2323use tiny_keccak;
2424use secp256k1;
2525
@@ -31,8 +31,8 @@ use crate::error::{Error, Result};
3131use codec:: { Encode , Decode } ;
3232use primitives:: {
3333 blake2_128, blake2_256, twox_64, twox_128, twox_256, ed25519, sr25519, Pair , crypto:: KeyTypeId ,
34- offchain, hexdisplay:: HexDisplay , sandbox as sandbox_primitives, H256 , Blake2Hasher ,
35- traits:: Externalities , child_storage_key :: ChildStorageKey ,
34+ offchain, hexdisplay:: HexDisplay , sandbox as sandbox_primitives, Blake2Hasher ,
35+ traits:: Externalities ,
3636} ;
3737use trie:: { TrieConfiguration , trie_types:: Layout } ;
3838use crate :: sandbox;
@@ -447,7 +447,9 @@ impl_wasm_host_interface! {
447447 . map_err( |_| "Invalid attempt to determine key in ext_set_storage" ) ?;
448448 let value = context. read_memory( value_data, value_len)
449449 . map_err( |_| "Invalid attempt to determine value in ext_set_storage" ) ?;
450- runtime_io:: set_storage( & key, & value) ;
450+ with_external_storage( move ||
451+ Ok ( runtime_io:: set_storage( & key, & value) )
452+ ) ?;
451453 Ok ( ( ) )
452454 }
453455
@@ -466,7 +468,9 @@ impl_wasm_host_interface! {
466468 let value = context. read_memory( value_data, value_len)
467469 . map_err( |_| "Invalid attempt to determine value in ext_set_child_storage" ) ?;
468470
469- runtime_io:: set_child_storage( & storage_key, & key, & value) ;
471+ with_external_storage( move ||
472+ Ok ( runtime_io:: set_child_storage( & storage_key, & key, & value) )
473+ ) ?;
470474 Ok ( ( ) )
471475 }
472476
@@ -481,21 +485,27 @@ impl_wasm_host_interface! {
481485 let key = context. read_memory( key_data, key_len)
482486 . map_err( |_| "Invalid attempt to determine key in ext_clear_child_storage" ) ?;
483487
484- runtime_io:: clear_child_storage( & storage_key, & key) ;
488+ with_external_storage( move ||
489+ Ok ( runtime_io:: clear_child_storage( & storage_key, & key) )
490+ ) ?;
485491 Ok ( ( ) )
486492 }
487493
488494 ext_clear_storage( key_data: Pointer <u8 >, key_len: WordSize ) {
489495 let key = context. read_memory( key_data, key_len)
490496 . map_err( |_| "Invalid attempt to determine key in ext_clear_storage" ) ?;
491- runtime_io:: clear_storage( & key) ;
497+ with_external_storage( move ||
498+ Ok ( runtime_io:: clear_storage( & key) )
499+ ) ?;
492500 Ok ( ( ) )
493501 }
494502
495503 ext_exists_storage( key_data: Pointer <u8 >, key_len: WordSize ) -> u32 {
496504 let key = context. read_memory( key_data, key_len)
497505 . map_err( |_| "Invalid attempt to determine key in ext_exists_storage" ) ?;
498- Ok ( if runtime_io:: exists_storage( & key) { 1 } else { 0 } )
506+ with_external_storage( move ||
507+ Ok ( if runtime_io:: exists_storage( & key) { 1 } else { 0 } )
508+ )
499509 }
500510
501511 ext_exists_child_storage(
@@ -509,13 +519,17 @@ impl_wasm_host_interface! {
509519 let key = context. read_memory( key_data, key_len)
510520 . map_err( |_| "Invalid attempt to determine key in ext_exists_child_storage" ) ?;
511521
512- Ok ( if runtime_io:: exists_child_storage( & storage_key, & key) { 1 } else { 0 } )
522+ with_external_storage( move ||
523+ Ok ( if runtime_io:: exists_child_storage( & storage_key, & key) { 1 } else { 0 } )
524+ )
513525 }
514526
515527 ext_clear_prefix( prefix_data: Pointer <u8 >, prefix_len: WordSize ) {
516528 let prefix = context. read_memory( prefix_data, prefix_len)
517529 . map_err( |_| "Invalid attempt to determine prefix in ext_clear_prefix" ) ?;
518- runtime_io:: clear_prefix( & prefix) ;
530+ with_external_storage( move ||
531+ Ok ( runtime_io:: clear_prefix( & prefix) )
532+ ) ?;
519533 Ok ( ( ) )
520534 }
521535
@@ -529,15 +543,19 @@ impl_wasm_host_interface! {
529543 . map_err( |_| "Invalid attempt to determine storage_key in ext_clear_child_prefix" ) ?;
530544 let prefix = context. read_memory( prefix_data, prefix_len)
531545 . map_err( |_| "Invalid attempt to determine prefix in ext_clear_child_prefix" ) ?;
532- runtime_io:: clear_child_prefix( & storage_key, & prefix) ;
546+ with_external_storage( move ||
547+ Ok ( runtime_io:: clear_child_prefix( & storage_key, & prefix) )
548+ ) ?;
533549
534550 Ok ( ( ) )
535551 }
536552
537553 ext_kill_child_storage( storage_key_data: Pointer <u8 >, storage_key_len: WordSize ) {
538554 let storage_key = context. read_memory( storage_key_data, storage_key_len)
539555 . map_err( |_| "Invalid attempt to determine storage_key in ext_kill_child_storage" ) ?;
540- runtime_io:: kill_child_storage( & storage_key) ;
556+ with_external_storage( move ||
557+ Ok ( runtime_io:: kill_child_storage( & storage_key) )
558+ ) ?;
541559
542560 Ok ( ( ) )
543561 }
@@ -549,7 +567,9 @@ impl_wasm_host_interface! {
549567 ) -> Pointer <u8 > {
550568 let key = context. read_memory( key_data, key_len)
551569 . map_err( |_| "Invalid attempt to determine key in ext_get_allocated_storage" ) ?;
552- let maybe_value = runtime_io:: storage( & key) ;
570+ let maybe_value = with_external_storage( move ||
571+ Ok ( runtime_io:: storage( & key) )
572+ ) ?;
553573
554574 if let Some ( value) = maybe_value {
555575 let offset = context. allocate_memory( value. len( ) as u32 ) ?;
@@ -577,7 +597,9 @@ impl_wasm_host_interface! {
577597 let key = context. read_memory( key_data, key_len)
578598 . map_err( |_| "Invalid attempt to determine key in ext_get_allocated_child_storage" ) ?;
579599
580- let maybe_value = runtime_io:: child_storage( & storage_key, & key) ;
600+ let maybe_value = with_external_storage( move ||
601+ Ok ( runtime_io:: child_storage( & storage_key, & key) )
602+ ) ?;
581603
582604 if let Some ( value) = maybe_value {
583605 let offset = context. allocate_memory( value. len( ) as u32 ) ?;
@@ -602,7 +624,9 @@ impl_wasm_host_interface! {
602624 ) -> WordSize {
603625 let key = context. read_memory( key_data, key_len)
604626 . map_err( |_| "Invalid attempt to get key in ext_get_storage_into" ) ?;
605- let maybe_value = runtime_io:: storage( & key) ;
627+ let maybe_value = with_external_storage( move ||
628+ Ok ( runtime_io:: storage( & key) )
629+ ) ?;
606630
607631 if let Some ( value) = maybe_value {
608632 let value = & value[ value_offset as usize ..] ;
@@ -629,7 +653,9 @@ impl_wasm_host_interface! {
629653 let key = context. read_memory( key_data, key_len)
630654 . map_err( |_| "Invalid attempt to get key in ext_get_child_storage_into" ) ?;
631655
632- let maybe_value = runtime_io:: child_storage( & storage_key, & key) ;
656+ let maybe_value = with_external_storage( move ||
657+ Ok ( runtime_io:: child_storage( & storage_key, & key) )
658+ ) ?;
633659
634660 if let Some ( value) = maybe_value {
635661 let value = & value[ value_offset as usize ..] ;
@@ -643,7 +669,9 @@ impl_wasm_host_interface! {
643669 }
644670
645671 ext_storage_root( result: Pointer <u8 >) {
646- let r = runtime_io:: storage_root( ) ;
672+ let r = with_external_storage( move ||
673+ Ok ( runtime_io:: storage_root( ) )
674+ ) ?;
647675 context. write_memory( result, r. as_ref( ) )
648676 . map_err( |_| "Invalid attempt to set memory in ext_storage_root" ) ?;
649677 Ok ( ( ) )
@@ -656,7 +684,9 @@ impl_wasm_host_interface! {
656684 ) -> Pointer <u8 > {
657685 let storage_key = context. read_memory( storage_key_data, storage_key_len)
658686 . map_err( |_| "Invalid attempt to determine storage_key in ext_child_storage_root" ) ?;
659- let value = runtime_io:: child_storage_root( & storage_key) ;
687+ let value = with_external_storage( move ||
688+ Ok ( runtime_io:: child_storage_root( & storage_key) )
689+ ) ?;
660690
661691 let offset = context. allocate_memory( value. len( ) as u32 ) ?;
662692 context. write_memory( offset, & value)
@@ -674,7 +704,9 @@ impl_wasm_host_interface! {
674704 let mut parent_hash = [ 0u8 ; 32 ] ;
675705 context. read_memory_into( parent_hash_data, & mut parent_hash[ ..] )
676706 . map_err( |_| "Invalid attempt to get parent_hash in ext_storage_changes_root" ) ?;
677- let r = runtime_io:: storage_changes_root( parent_hash) ;
707+ let r = with_external_storage( move ||
708+ Ok ( runtime_io:: storage_changes_root( parent_hash) )
709+ ) ?;
678710
679711 if let Some ( r) = r {
680712 context. write_memory( result, & r[ ..] )
@@ -1331,6 +1363,25 @@ impl_wasm_host_interface! {
13311363 }
13321364}
13331365
1366+ /// Execute closure that access external storage.
1367+ ///
1368+ /// All panics that happen within closure are captured and transformed into
1369+ /// runtime error. This requires special panic handler mode to be enabled
1370+ /// during the call (see `panic_handler::AbortGuard::never_abort`).
1371+ /// If this mode isn't enabled, then all panics within externalities are
1372+ /// leading to process abort.
1373+ fn with_external_storage < T , F > ( f : F ) -> std:: result:: Result < T , String >
1374+ where
1375+ F : panic:: UnwindSafe + FnOnce ( ) -> Result < T >
1376+ {
1377+ // it is safe beause basic methods of StorageExternalities are guaranteed to touch only
1378+ // its internal state + we should discard it on error
1379+ panic:: catch_unwind ( move || f ( ) )
1380+ . map_err ( |_| Error :: Runtime )
1381+ . and_then ( |result| result)
1382+ . map_err ( |err| format ! ( "{}" , err) )
1383+ }
1384+
13341385/// Wasm rust executor for contracts.
13351386///
13361387/// Executes the provided code in a sandboxed wasm runtime.
0 commit comments