@@ -2,6 +2,7 @@ package keeper
2
2
3
3
import (
4
4
"bytes"
5
+ "encoding/base64"
5
6
"encoding/binary"
6
7
"encoding/json"
7
8
"io/ioutil"
@@ -461,9 +462,8 @@ func TestMigrate(t *testing.T) {
461
462
accKeeper , keeper := keepers .AccountKeeper , keepers .WasmKeeper
462
463
463
464
deposit := sdk .NewCoins (sdk .NewInt64Coin ("denom" , 100000 ))
464
- topUp := sdk .NewCoins (sdk .NewInt64Coin ("denom" , 5000 ))
465
465
creator := createFakeFundedAccount (ctx , accKeeper , deposit .Add (deposit ... ))
466
- fred := createFakeFundedAccount (ctx , accKeeper , topUp )
466
+ fred := createFakeFundedAccount (ctx , accKeeper , sdk . NewCoins ( sdk . NewInt64Coin ( "denom" , 5000 )) )
467
467
468
468
wasmCode , err := ioutil .ReadFile ("./testdata/contract.wasm" )
469
469
require .NoError (t , err )
@@ -475,41 +475,56 @@ func TestMigrate(t *testing.T) {
475
475
require .NotEqual (t , originalContractID , newContractID )
476
476
477
477
_ , _ , anyAddr := keyPubAddr ()
478
+ _ , _ , newVerifierAddr := keyPubAddr ()
478
479
initMsg := InitMsg {
479
480
Verifier : fred ,
480
481
Beneficiary : anyAddr ,
481
482
}
482
483
initMsgBz , err := json .Marshal (initMsg )
483
484
require .NoError (t , err )
485
+
486
+ migMsg := struct {
487
+ Verifier sdk.AccAddress `json:"verifier"`
488
+ }{Verifier : newVerifierAddr }
489
+ migMsgBz , err := json .Marshal (migMsg )
490
+ require .NoError (t , err )
491
+
484
492
specs := map [string ]struct {
485
493
admin sdk.AccAddress
486
494
overrideContractAddr sdk.AccAddress
487
495
caller sdk.AccAddress
488
496
codeID uint64
489
497
migrateMsg []byte
490
498
expErr * sdkerrors.Error
499
+ expVerifier sdk.AccAddress
491
500
}{
492
501
"all good with same code id" : {
493
- admin : creator ,
494
- caller : creator ,
495
- codeID : originalContractID ,
502
+ admin : creator ,
503
+ caller : creator ,
504
+ codeID : originalContractID ,
505
+ migrateMsg : migMsgBz ,
506
+ expVerifier : newVerifierAddr ,
496
507
},
497
- "all good with new code id" : {
498
- admin : creator ,
499
- caller : creator ,
500
- codeID : newContractID ,
508
+ "all good with different code id" : {
509
+ admin : creator ,
510
+ caller : creator ,
511
+ codeID : newContractID ,
512
+ migrateMsg : migMsgBz ,
513
+ expVerifier : newVerifierAddr ,
501
514
},
502
515
"all good with admin set" : {
503
- admin : fred ,
504
- caller : fred ,
505
- codeID : newContractID ,
516
+ admin : fred ,
517
+ caller : fred ,
518
+ codeID : newContractID ,
519
+ migrateMsg : migMsgBz ,
520
+ expVerifier : newVerifierAddr ,
506
521
},
507
522
"prevent migration when admin was not set on instantiate" : {
508
523
caller : creator ,
509
524
codeID : originalContractID ,
510
525
expErr : sdkerrors .ErrUnauthorized ,
511
526
},
512
- "prevent migration when not admin" : {
527
+ "prevent migration when not sent by admin" : {
513
528
caller : creator ,
514
529
admin : fred ,
515
530
codeID : originalContractID ,
@@ -528,18 +543,21 @@ func TestMigrate(t *testing.T) {
528
543
codeID : originalContractID ,
529
544
expErr : sdkerrors .ErrInvalidRequest ,
530
545
},
531
- "fail when migration caused error " : {
546
+ "fail in contract with invalid migrate msg " : {
532
547
admin : creator ,
533
548
caller : creator ,
534
549
codeID : originalContractID ,
535
- migrateMsg : bytes .Repeat ([]byte {0x1 }, 7 ), // condition hard coded in stub: >6 = error
550
+ migrateMsg : bytes .Repeat ([]byte {0x1 }, 7 ),
536
551
expErr : types .ErrMigrationFailed ,
537
552
},
553
+ "fail in contract without migrate msg" : {
554
+ admin : creator ,
555
+ caller : creator ,
556
+ codeID : originalContractID ,
557
+ expErr : types .ErrMigrationFailed ,
558
+ },
538
559
}
539
- var (
540
- builtIntoGoCosmWasmStubGas = sdk .Gas (10000 )
541
- builtIntoGoCosmWasmStubData = []byte (("my-migration-response-data" ))
542
- )
560
+
543
561
for msg , spec := range specs {
544
562
t .Run (msg , func (t * testing.T ) {
545
563
ctx = ctx .WithBlockHeight (ctx .BlockHeight () + 1 )
@@ -548,26 +566,141 @@ func TestMigrate(t *testing.T) {
548
566
if spec .overrideContractAddr != nil {
549
567
addr = spec .overrideContractAddr
550
568
}
551
- gasBefore := ctx .GasMeter ().GasConsumed ()
552
- res , err := keeper .Migrate (ctx , addr , spec .caller , spec .codeID , spec .migrateMsg )
569
+ _ , err = keeper .Migrate (ctx , addr , spec .caller , spec .codeID , spec .migrateMsg )
553
570
require .True (t , spec .expErr .Is (err ), "expected %v but got %+v" , spec .expErr , err )
554
571
if spec .expErr != nil {
555
572
return
556
573
}
557
- gasAfter := ctx .GasMeter ().GasConsumed ()
558
- assert .Greater (t , gasAfter - gasBefore , builtIntoGoCosmWasmStubGas / GasMultiplier )
559
- assert .Equal (t , builtIntoGoCosmWasmStubData , res .Data )
560
574
cInfo := keeper .GetContractInfo (ctx , addr )
561
575
assert .Equal (t , spec .codeID , cInfo .CodeID )
562
576
assert .Equal (t , originalContractID , cInfo .PreviousCodeID )
563
577
assert .Equal (t , types .NewCreatedAt (ctx ), cInfo .LastUpdated )
564
- // TODO: check contract store was updated by migration code (impl also in contract)
565
- // TODO: check any messages dispatched proper
566
- // TODO: check events?
578
+
579
+ m := keeper .QueryRaw (ctx , addr , []byte ("config" ))
580
+ require .Len (t , m , 1 )
581
+ var stored map [string ][]byte
582
+ require .NoError (t , json .Unmarshal (m [0 ].Value , & stored ))
583
+ require .Contains (t , stored , "verifier" )
584
+ require .NoError (t , err )
585
+ assert .Equal (t , spec .expVerifier , sdk .AccAddress (stored ["verifier" ]))
567
586
})
568
587
}
569
588
}
570
589
590
+ func TestMigrateWithDispatchedMessage (t * testing.T ) {
591
+ tempDir , err := ioutil .TempDir ("" , "wasm" )
592
+ require .NoError (t , err )
593
+ defer os .RemoveAll (tempDir )
594
+ ctx , keepers := CreateTestInput (t , false , tempDir , SupportedFeatures , nil , nil )
595
+ accKeeper , keeper := keepers .AccountKeeper , keepers .WasmKeeper
596
+
597
+ deposit := sdk .NewCoins (sdk .NewInt64Coin ("denom" , 100000 ))
598
+ creator := createFakeFundedAccount (ctx , accKeeper , deposit .Add (deposit ... ))
599
+ fred := createFakeFundedAccount (ctx , accKeeper , sdk .NewCoins (sdk .NewInt64Coin ("denom" , 5000 )))
600
+
601
+ wasmCode , err := ioutil .ReadFile ("./testdata/contract.wasm" )
602
+ require .NoError (t , err )
603
+ burnerCode , err := ioutil .ReadFile ("./testdata/burner.wasm" )
604
+ require .NoError (t , err )
605
+
606
+ originalContractID , err := keeper .Create (ctx , creator , wasmCode , "" , "" )
607
+ require .NoError (t , err )
608
+ burnerContractID , err := keeper .Create (ctx , creator , burnerCode , "" , "" )
609
+ require .NoError (t , err )
610
+ require .NotEqual (t , originalContractID , burnerContractID )
611
+
612
+ _ , _ , myPayoutAddr := keyPubAddr ()
613
+ initMsg := InitMsg {
614
+ Verifier : fred ,
615
+ Beneficiary : fred ,
616
+ }
617
+ initMsgBz , err := json .Marshal (initMsg )
618
+ require .NoError (t , err )
619
+
620
+ ctx = ctx .WithBlockHeight (ctx .BlockHeight () + 1 )
621
+ contractAddr , err := keeper .Instantiate (ctx , originalContractID , creator , fred , initMsgBz , "demo contract" , deposit )
622
+ require .NoError (t , err )
623
+
624
+ migMsg := struct {
625
+ Payout sdk.AccAddress `json:"payout"`
626
+ }{Payout : myPayoutAddr }
627
+ migMsgBz , err := json .Marshal (migMsg )
628
+ require .NoError (t , err )
629
+ ctx = ctx .WithEventManager (sdk .NewEventManager ()).WithBlockHeight (ctx .BlockHeight () + 1 )
630
+ res , err := keeper .Migrate (ctx , contractAddr , fred , burnerContractID , migMsgBz )
631
+ require .NoError (t , err )
632
+ dataBz , err := base64 .StdEncoding .DecodeString (string (res .Data ))
633
+ require .NoError (t , err )
634
+ assert .Equal (t , "burnt" , string (dataBz ))
635
+ assert .Equal (t , "" , res .Log )
636
+ type dict map [string ]interface {}
637
+ expEvents := []dict {
638
+ {
639
+ "Type" : "wasm" ,
640
+ "Attr" : []dict {
641
+ {"contract_address" : contractAddr },
642
+ {"action" : "burn" },
643
+ {"payout" : myPayoutAddr },
644
+ },
645
+ },
646
+ {
647
+ "Type" : "transfer" ,
648
+ "Attr" : []dict {
649
+ {"recipient" : myPayoutAddr },
650
+ {"sender" : contractAddr },
651
+ {"amount" : "100000denom" },
652
+ },
653
+ },
654
+ {
655
+ "Type" : "message" ,
656
+ "Attr" : []dict {
657
+ {"sender" : contractAddr },
658
+ },
659
+ },
660
+ {
661
+ "Type" : "message" ,
662
+ "Attr" : []dict {
663
+ {"module" : "bank" },
664
+ },
665
+ },
666
+ }
667
+ expJsonEvts := string (mustMarshal (t , expEvents ))
668
+ assert .JSONEq (t , expJsonEvts , prettyEvents (t , ctx .EventManager ().Events ()))
669
+
670
+ // all persistent data cleared
671
+ m := keeper .QueryRaw (ctx , contractAddr , []byte ("config" ))
672
+ require .Len (t , m , 0 )
673
+
674
+ // and all deposit tokens sent to myPayoutAddr
675
+ balance := accKeeper .GetAccount (ctx , myPayoutAddr ).GetCoins ()
676
+ assert .Equal (t , deposit , balance )
677
+ }
678
+
679
+ func prettyEvents (t * testing.T , events sdk.Events ) string {
680
+ t .Helper ()
681
+ type prettyEvent struct {
682
+ Type string
683
+ Attr []map [string ]string
684
+ }
685
+
686
+ r := make ([]prettyEvent , len (events ))
687
+ for i , e := range events {
688
+ attr := make ([]map [string ]string , len (e .Attributes ))
689
+ for j , a := range e .Attributes {
690
+ attr [j ] = map [string ]string {string (a .Key ): string (a .Value )}
691
+ }
692
+ r [i ] = prettyEvent {Type : e .Type , Attr : attr }
693
+ }
694
+ return string (mustMarshal (t , r ))
695
+ }
696
+
697
+ func mustMarshal (t * testing.T , r interface {}) []byte {
698
+ t .Helper ()
699
+ bz , err := json .Marshal (r )
700
+ require .NoError (t , err )
701
+ return bz
702
+ }
703
+
571
704
func TestUpdateContractAdmin (t * testing.T ) {
572
705
tempDir , err := ioutil .TempDir ("" , "wasm" )
573
706
require .NoError (t , err )
0 commit comments