Skip to content

Commit 8aad0c9

Browse files
authored
Merge pull request #142 from CosmWasm/genesis_io_tests
Add genesis ex-/import for `lastContractId` sequence
2 parents 7f7afbf + 005c8bf commit 8aad0c9

File tree

6 files changed

+161
-0
lines changed

6 files changed

+161
-0
lines changed

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ require (
88
github.com/btcsuite/btcd v0.0.0-20190807005414-4063feeff79a // indirect
99
github.com/cosmos/cosmos-sdk v0.38.3
1010
github.com/golang/mock v1.4.3 // indirect
11+
github.com/google/gofuzz v1.0.0
1112
github.com/gorilla/mux v1.7.4
1213
github.com/onsi/ginkgo v1.8.0 // indirect
1314
github.com/onsi/gomega v1.5.0 // indirect

x/wasm/internal/keeper/genesis.go

+11
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
2929
keeper.setContractState(ctx, contract.ContractAddress, contract.ContractState)
3030
}
3131

32+
for _, seq := range data.Sequences {
33+
keeper.setAutoIncrementID(ctx, seq.IDKey, seq.Value)
34+
}
3235
}
3336

3437
// ExportGenesis returns a GenesisState for a given context and keeper.
@@ -67,5 +70,13 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
6770
return false
6871
})
6972

73+
// types.KeyLastCodeID is updated via keeper create
74+
for _, k := range [][]byte{types.KeyLastInstanceID} {
75+
genState.Sequences = append(genState.Sequences, types.Sequence{
76+
IDKey: k,
77+
Value: keeper.peekAutoIncrementID(ctx, k),
78+
})
79+
}
80+
7081
return genState
7182
}
+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package keeper
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"testing"
7+
"time"
8+
9+
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
10+
wasmTypes "github.com/CosmWasm/wasmd/x/wasm/internal/types"
11+
"github.com/cosmos/cosmos-sdk/store"
12+
sdk "github.com/cosmos/cosmos-sdk/types"
13+
"github.com/cosmos/cosmos-sdk/x/auth"
14+
"github.com/cosmos/cosmos-sdk/x/staking"
15+
fuzz "github.com/google/gofuzz"
16+
"github.com/stretchr/testify/require"
17+
abci "github.com/tendermint/tendermint/abci/types"
18+
"github.com/tendermint/tendermint/libs/log"
19+
dbm "github.com/tendermint/tm-db"
20+
)
21+
22+
func TestGenesisExportImport(t *testing.T) {
23+
srcKeeper, srcCtx, srcCleanup := setupKeeper(t)
24+
defer srcCleanup()
25+
wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
26+
require.NoError(t, err)
27+
28+
// store some test data
29+
f := fuzz.New().Funcs(FuzzAddr, FuzzAbsoluteTxPosition, FuzzContractInfo, FuzzStateModel)
30+
for i := 0; i < 25; i++ {
31+
var (
32+
codeInfo types.CodeInfo
33+
contract types.ContractInfo
34+
stateModels []types.Model
35+
)
36+
f.Fuzz(&codeInfo)
37+
f.Fuzz(&contract)
38+
f.Fuzz(&stateModels)
39+
40+
codeID, err := srcKeeper.Create(srcCtx, codeInfo.Creator, wasmCode, codeInfo.Source, codeInfo.Builder)
41+
require.NoError(t, err)
42+
contract.CodeID = codeID
43+
contractAddr := srcKeeper.generateContractAddress(srcCtx, codeID)
44+
srcKeeper.setContractInfo(srcCtx, contractAddr, &contract)
45+
srcKeeper.setContractState(srcCtx, contractAddr, stateModels)
46+
}
47+
48+
// export
49+
genesisState := ExportGenesis(srcCtx, srcKeeper)
50+
51+
// re-import
52+
dstKeeper, dstCtx, dstCleanup := setupKeeper(t)
53+
defer dstCleanup()
54+
InitGenesis(dstCtx, dstKeeper, genesisState)
55+
56+
// compare whole DB
57+
srcIT := srcCtx.KVStore(srcKeeper.storeKey).Iterator(nil, nil)
58+
dstIT := dstCtx.KVStore(dstKeeper.storeKey).Iterator(nil, nil)
59+
60+
for i := 0; srcIT.Valid(); i++ {
61+
require.True(t, dstIT.Valid(), "destination DB has less elements than source. Missing: %q", srcIT.Key())
62+
require.Equal(t, srcIT.Key(), dstIT.Key(), i)
63+
require.Equal(t, srcIT.Value(), dstIT.Value(), "element (%d): %s", i, srcIT.Key())
64+
srcIT.Next()
65+
dstIT.Next()
66+
}
67+
require.False(t, dstIT.Valid())
68+
}
69+
70+
func setupKeeper(t *testing.T) (Keeper, sdk.Context, func()) {
71+
tempDir, err := ioutil.TempDir("", "wasm")
72+
require.NoError(t, err)
73+
cleanup := func() { os.RemoveAll(tempDir) }
74+
//t.Cleanup(cleanup) todo: add with Go 1.14
75+
76+
keyContract := sdk.NewKVStoreKey(wasmTypes.StoreKey)
77+
db := dbm.NewMemDB()
78+
ms := store.NewCommitMultiStore(db)
79+
ms.MountStoreWithDB(keyContract, sdk.StoreTypeIAVL, db)
80+
require.NoError(t, ms.LoadLatestVersion())
81+
82+
ctx := sdk.NewContext(ms, abci.Header{
83+
Height: 1234567,
84+
Time: time.Date(2020, time.April, 22, 12, 0, 0, 0, time.UTC),
85+
}, false, log.NewNopLogger())
86+
87+
cdc := MakeTestCodec()
88+
wasmConfig := wasmTypes.DefaultWasmConfig()
89+
90+
srcKeeper := NewKeeper(cdc, keyContract, auth.AccountKeeper{}, nil, staking.Keeper{}, nil, tempDir, wasmConfig, "", nil, nil)
91+
return srcKeeper, ctx, cleanup
92+
}

x/wasm/internal/keeper/keeper.go

+17
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,23 @@ func (k Keeper) autoIncrementID(ctx sdk.Context, lastIDKey []byte) uint64 {
485485
return id
486486
}
487487

488+
// peekAutoIncrementID reads the current value without incrementing it.
489+
func (k Keeper) peekAutoIncrementID(ctx sdk.Context, lastIDKey []byte) uint64 {
490+
store := ctx.KVStore(k.storeKey)
491+
bz := store.Get(lastIDKey)
492+
id := uint64(1)
493+
if bz != nil {
494+
id = binary.BigEndian.Uint64(bz)
495+
}
496+
return id
497+
}
498+
499+
func (k Keeper) setAutoIncrementID(ctx sdk.Context, lastIDKey []byte, val uint64) {
500+
store := ctx.KVStore(k.storeKey)
501+
bz := sdk.Uint64ToBigEndian(val)
502+
store.Set(lastIDKey, bz)
503+
}
504+
488505
func addrFromUint64(id uint64) sdk.AccAddress {
489506
addr := make([]byte, 20)
490507
addr[0] = 'C'

x/wasm/internal/keeper/test_fuzz.go

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package keeper
2+
3+
import (
4+
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
5+
sdk "github.com/cosmos/cosmos-sdk/types"
6+
fuzz "github.com/google/gofuzz"
7+
tmBytes "github.com/tendermint/tendermint/libs/bytes"
8+
)
9+
10+
func FuzzAddr(m *sdk.AccAddress, c fuzz.Continue) {
11+
*m = make([]byte, 20)
12+
c.Read(*m)
13+
}
14+
func FuzzAbsoluteTxPosition(m *types.AbsoluteTxPosition, c fuzz.Continue) {
15+
m.BlockHeight = int64(c.RandUint64()) // can't be negative
16+
m.TxIndex = c.RandUint64()
17+
}
18+
19+
func FuzzContractInfo(m *types.ContractInfo, c fuzz.Continue) {
20+
const maxSize = 1024
21+
m.CodeID = c.RandUint64()
22+
FuzzAddr(&m.Creator, c)
23+
FuzzAddr(&m.Admin, c)
24+
m.Label = c.RandString()
25+
m.InitMsg = make([]byte, c.RandUint64()%maxSize)
26+
c.Read(m.InitMsg)
27+
c.Fuzz(&m.Created)
28+
c.Fuzz(&m.LastUpdated)
29+
m.PreviousCodeID = c.RandUint64()
30+
}
31+
func FuzzStateModel(m *types.Model, c fuzz.Continue) {
32+
m.Key = tmBytes.HexBytes(c.RandString())
33+
c.Fuzz(&m.Value)
34+
}

x/wasm/internal/types/genesis.go

+6
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,16 @@ package types
22

33
import sdk "github.com/cosmos/cosmos-sdk/types"
44

5+
type Sequence struct {
6+
IDKey []byte `json:"id_key"`
7+
Value uint64 `json:"value"`
8+
}
9+
510
// GenesisState is the struct representation of the export genesis
611
type GenesisState struct {
712
Codes []Code `json:"codes"`
813
Contracts []Contract `json:"contracts"`
14+
Sequences []Sequence `json:"sequences"`
915
}
1016

1117
// Code struct encompasses CodeInfo and CodeBytes

0 commit comments

Comments
 (0)