@@ -33,7 +33,7 @@ use runtime_primitives::testing::{Digest, DigestItem, Header, UintAuthorityId, H
3333use runtime_primitives:: traits:: { BlakeTwo256 , IdentityLookup } ;
3434use runtime_primitives:: BuildStorage ;
3535use srml_support:: {
36- assert_ok, impl_outer_dispatch, impl_outer_event, impl_outer_origin, storage:: child,
36+ assert_ok, assert_err , impl_outer_dispatch, impl_outer_event, impl_outer_origin, storage:: child,
3737 traits:: Currency , StorageMap , StorageValue
3838} ;
3939use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
@@ -522,6 +522,110 @@ fn dispatch_call() {
522522 ) ;
523523}
524524
525+ const CODE_DISPATCH_CALL_THEN_TRAP : & str = r#"
526+ (module
527+ (import "env" "ext_dispatch_call" (func $ext_dispatch_call (param i32 i32)))
528+ (import "env" "memory" (memory 1 1))
529+
530+ (func (export "call")
531+ (call $ext_dispatch_call
532+ (i32.const 8) ;; Pointer to the start of encoded call buffer
533+ (i32.const 11) ;; Length of the buffer
534+ )
535+ (unreachable) ;; trap so that the top level transaction fails
536+ )
537+ (func (export "deploy"))
538+
539+ (data (i32.const 8) "\00\00\03\00\00\00\00\00\00\00\C8")
540+ )
541+ "# ;
542+ const HASH_DISPATCH_CALL_THEN_TRAP : [ u8 ; 32 ] = hex ! ( "55fe5c142dfe2519ca76c7c9b9f05012bd2624b7dcc128d2ce5a7af9d2da1846" ) ;
543+
544+ #[ test]
545+ fn dispatch_call_not_dispatched_after_top_level_transaction_failure ( ) {
546+ // This test can fail due to the encoding changes. In case it becomes too annoying
547+ // let's rewrite so as we use this module controlled call or we serialize it in runtime.
548+ let encoded = Encode :: encode ( & Call :: Balances ( balances:: Call :: transfer ( CHARLIE , 50 ) ) ) ;
549+ assert_eq ! ( & encoded[ ..] , & hex!( "00000300000000000000C8" ) [ ..] ) ;
550+
551+ let wasm = wabt:: wat2wasm ( CODE_DISPATCH_CALL_THEN_TRAP ) . unwrap ( ) ;
552+
553+ with_externalities (
554+ & mut ExtBuilder :: default ( ) . existential_deposit ( 50 ) . build ( ) ,
555+ || {
556+ Balances :: deposit_creating ( & ALICE , 1_000_000 ) ;
557+
558+ assert_ok ! ( Contract :: put_code( Origin :: signed( ALICE ) , 100_000 , wasm) ) ;
559+
560+ // Let's keep this assert even though it's redundant. If you ever need to update the
561+ // wasm source this test will fail and will show you the actual hash.
562+ assert_eq ! ( System :: events( ) , vec![
563+ EventRecord {
564+ phase: Phase :: ApplyExtrinsic ( 0 ) ,
565+ event: MetaEvent :: balances( balances:: RawEvent :: NewAccount ( 1 , 1_000_000 ) ) ,
566+ topics: vec![ ] ,
567+ } ,
568+ EventRecord {
569+ phase: Phase :: ApplyExtrinsic ( 0 ) ,
570+ event: MetaEvent :: contract( RawEvent :: CodeStored ( HASH_DISPATCH_CALL_THEN_TRAP . into( ) ) ) ,
571+ topics: vec![ ] ,
572+ } ,
573+ ] ) ;
574+
575+ assert_ok ! ( Contract :: create(
576+ Origin :: signed( ALICE ) ,
577+ 100 ,
578+ 100_000 ,
579+ HASH_DISPATCH_CALL_THEN_TRAP . into( ) ,
580+ vec![ ] ,
581+ ) ) ;
582+
583+ // Call the newly created contract. The contract is expected to dispatch a call
584+ // and then trap.
585+ assert_err ! (
586+ Contract :: call(
587+ Origin :: signed( ALICE ) ,
588+ BOB , // newly created account
589+ 0 ,
590+ 100_000 ,
591+ vec![ ] ,
592+ ) ,
593+ "during execution"
594+ ) ;
595+ assert_eq ! ( System :: events( ) , vec![
596+ EventRecord {
597+ phase: Phase :: ApplyExtrinsic ( 0 ) ,
598+ event: MetaEvent :: balances( balances:: RawEvent :: NewAccount ( 1 , 1_000_000 ) ) ,
599+ topics: vec![ ] ,
600+ } ,
601+ EventRecord {
602+ phase: Phase :: ApplyExtrinsic ( 0 ) ,
603+ event: MetaEvent :: contract( RawEvent :: CodeStored ( HASH_DISPATCH_CALL_THEN_TRAP . into( ) ) ) ,
604+ topics: vec![ ] ,
605+ } ,
606+ EventRecord {
607+ phase: Phase :: ApplyExtrinsic ( 0 ) ,
608+ event: MetaEvent :: balances(
609+ balances:: RawEvent :: NewAccount ( BOB , 100 )
610+ ) ,
611+ topics: vec![ ] ,
612+ } ,
613+ EventRecord {
614+ phase: Phase :: ApplyExtrinsic ( 0 ) ,
615+ event: MetaEvent :: contract( RawEvent :: Transfer ( ALICE , BOB , 100 ) ) ,
616+ topics: vec![ ] ,
617+ } ,
618+ EventRecord {
619+ phase: Phase :: ApplyExtrinsic ( 0 ) ,
620+ event: MetaEvent :: contract( RawEvent :: Instantiated ( ALICE , BOB ) ) ,
621+ topics: vec![ ] ,
622+ } ,
623+ // ABSENCE of events which would be caused by dispatched Balances::transfer call
624+ ] ) ;
625+ } ,
626+ ) ;
627+ }
628+
525629const CODE_SET_RENT : & str = r#"
526630(module
527631 (import "env" "ext_dispatch_call" (func $ext_dispatch_call (param i32 i32)))
0 commit comments