* Start cosmos-sdk v0.47 integration (#1136) * Upgrade to sdk v0.47 branch * More integration work * SDK version upgrade; fixes * More fixes * Fixes * Deactivate failing tests * SDK + ibc-go version upgrades * limix gas fix (cherry picked from commit f7f841768e5051d96d243b42ce4f231a33020326) * with valset in bench (cherry picked from commit 35b2a8fd2c23d6160fca540771fd348913f7f143) * Revert staking query handler; fix tests * Minor cleanup * Rebased * Address linter issues * Set legacy router proper * Deactivate failing test. Race condition needs to handled in SDK * Address some code smells * Bump sdk version * Use gov v1 internally for votes * Activate test after sdk fix * Add group test * Add config template for wasm fields * Add Rust backtrace flag for more debug output on simulations * Set unique node folder for tests * Revert "Add Rust backtrace flag for more debug output on simulations" This reverts commit 218c3c6ce137dc02f7bc38391408d3460fb27e6f. * Simulations * Run also im/export + deterministic sims * Add package prefix to interfaces * Add signer annotation (https://github.com/cosmos/cosmos-sdk/issues/10933), minor cleanup * Bump sdk version * Review comments Co-authored-by: vuong <nguyenvuong1122000@gmail.com> * Bump bufbuild/buf-setup-action from 1.11.0 to 1.12.0 Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.11.0 to 1.12.0. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.11.0...v1.12.0) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> (cherry picked from commitf4905955b5) * Remove intertx for vanilla ICA * fix msg format in EVENTS.md (cherry picked from commit38d466adfd) * Better to sdk coin convertion (#1164) * Better to sdk coin convertion * Review feedback (cherry picked from commita925a9ed61) * Disallow only address permission (#1163) * Remove AccessTypeOnlyAddress for store msg * Remove AccessTypeOnlyAddress for update config msg * Review feedback Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> (cherry picked from commit8991633de2) * Integrate wasmvm v1.2.0 (backport #1161) (#1175) * Integrate wasmvm v1.2.0 (#1161) * Bump wasmvm version * Bump wasm test contracts * Encode weighted votes * Encode instantiate2 * Handle code info query; better wasmvm errors * Fix readme * Make linter happy * add non cgo build * Review comments * Bump wasmvm to release version Co-authored-by: jhernandezb <contact@jhernandez.me> (cherry picked from commit957b38e0a5) # Conflicts: # x/wasm/keeper/handler_plugin_encoders.go # x/wasm/keeper/handler_plugin_encoders_test.go # x/wasm/keeper/keeper.go # x/wasm/keeper/keeper_test.go * Adress merge conflicts Co-authored-by: Alexander Peters <alpe@users.noreply.github.com> * Bump bufbuild/buf-setup-action from 1.12.0 to 1.13.0 Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.12.0 to 1.13.0. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.12.0...v1.13.0) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> (cherry picked from commitffa0e5e5e1) * Emit events for setContractAdmin + setAccessConfig (#1179) (cherry picked from commitc9e7830ac1) * Dependency upgrades (#1172) * Bump sdk version to lastest * Bump ibc-go version to lastest * Remove channel hack * Update to ibc-go v7 + protoVer=0.11.5 * Bump bufbuild/buf-setup-action from 1.13.0 to 1.13.1 Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.13.0 to 1.13.1. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.13.0...v1.13.1) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> (cherry picked from commitde27e7f82f) * Fix typos (backport #1185) (#1194) * Fix typos (cherry picked from commitc88b8194cb) # Conflicts: # proto/cosmwasm/wasm/v1/tx.proto * Fix merge conflict --------- Co-authored-by: Alex Peters <alpe@users.noreply.github.com> * Bump bufbuild/buf-setup-action from 1.13.1 to 1.14.0 (#1200) Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.13.1 to 1.14.0. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.13.1...v1.14.0) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> (cherry picked from commitf3fc31c386) * list-contract-by-code bugfix (cherry picked from commit2ccffed778) * fix: stargate querier does not reset the state (cherry picked from commitfd0323541d) * test: add unit test (cherry picked from commit6d8018ac59) * Add Windows client support (#1197) * Add Windows client support * Separate server and windows client --------- Co-authored-by: Alex Peters <alpe@users.noreply.github.com> (cherry picked from commit8a20779518) * Bump bufbuild/buf-setup-action from 1.14.0 to 1.15.0 Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.14.0 to 1.15.0. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.14.0...v1.15.0) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> (cherry picked from commite5fab3da5a) * Rename windows client binary (cherry picked from commitde09c7fe2b) * Return IBC packet sequence number (backport #1225) (#1233) * Return IBC packet sequence number (#1225) * Return IBC packet sequence number * Fix review feedbacks * Remove names to return values in DispatchMsg method * Fix comments (cherry picked from commit4f1c57fc12) # Conflicts: # x/wasm/keeper/handler_plugin.go * Fix merge conflict --------- Co-authored-by: pinosu <95283998+pinosu@users.noreply.github.com> Co-authored-by: Alex Peters <alpe@users.noreply.github.com> * Test rust panic for regression (cherry picked from commita52e604966) * Fix client checksum verification (#1234) * Fix client checksum verification * Review comments (cherry picked from commit1a8019b380) # Conflicts: # x/wasm/client/cli/gov_tx.go * Fix merge conflict * Fix linters * Configure sonarcloud analysis (cherry picked from commit85cf1614fb) * Bump bufbuild/buf-setup-action from 1.15.0 to 1.15.1 Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.15.0 to 1.15.1. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.15.0...v1.15.1) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> (cherry picked from commit730ea5a1cf) * Make `CaptureIbcEvents` in ibctesting public. Before this change, it wasn't possible to implement the `chain.SendMsgs` method without [copying](https://github.com/public-awesome/ics721/blob/main/e2e/suite_helpers.go#L81-L98) them over. (cherry picked from commitb64fa078a3) * Upgrade to wasmvm 1.2.1 (backport #1245) (#1254) * Upgrade to wasmvm 1.2.1 (#1245) * Use wasmvm store adapter * Bump wasmvm to v1.2.1 (cherry picked from commit850f901b2e) # Conflicts: # go.mod # go.sum # x/wasm/keeper/keeper.go * Resolve conflicts --------- Co-authored-by: Alexander Peters <alpe@users.noreply.github.com> * WIP All cometbft (#1244) * Dep upgrade; use CometBft * Remove duplicte message events * Add changelog for v0.31.0 (#1188) * Start changelog for v0.31.0 * Add ICA upgrade * Add proto version link to buf.build * Update changelog (#1239) * Update changelog * Update changelog with latest changes * Set release date --------- Co-authored-by: pinosu <95283998+pinosu@users.noreply.github.com> (cherry picked from commitbc0e817912) * Remove new message type event * Support msg update params gov proposal (#1247) * Add MsgUpdateParams support * Implement UpdateParams msg * Fix test UpdateParams * Add migration test * Fix * Fix lint issues * Revert changes according to review feedback * Remove more x/params dependencies * Remove x/params from genesis test * Formatting * Restore old changes * fix lint * Fix tests and restructure migrations * Rename alias for convention --------- Co-authored-by: Alex Peters <alpe@users.noreply.github.com> * Fix test data generator (#1263) * linting 47 pr (#1261) * lint cosmwasm for sdk 47 * fix * remove setGenesis * remove additional unused functions * pass tests * use SDK's errors module * unecessary conversions * unnecessary conversions * remove unneeded event manager * complete linting of tests for 47 * add test for reimportation * check errors * Update x/wasm/keeper/proposal_integration_test.go Co-authored-by: Alexander Peters <alpe@users.noreply.github.com> * apply suggestion * suggestions * lints * don't return error in when making new transactions * no todo's in the code * Fix test data generator * Update x/wasm/types/genesis_test.go Co-authored-by: Alexander Peters <alpe@users.noreply.github.com> * use the full string invalid address (2 words) always --------- Co-authored-by: Alexander Peters <alpe@users.noreply.github.com> * Regenerate from proto; remove dead code; polish code * Set SDK version to v0.47x.0 (#1262) * Set SDK version to v0.47x.0 * Set chainID * Minor updates * Set chainID for simulations * Buf mod update * Use sdk tag instead of hash in buf * Bump ibc-go to v7.0.0 * faddat/re merge main (#1274) undefined --------- Co-authored-by: vuong <nguyenvuong1122000@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: llllllluc <58892938+llllllluc@users.noreply.github.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Gjermund Garaba <gjermund@garaba.net> Co-authored-by: Nikhil Suri <nikhilsuri@comcast.net> Co-authored-by: Paul <p22626262@gmail.com> Co-authored-by: pinosu <95283998+pinosu@users.noreply.github.com> Co-authored-by: ekez <zekemedley@gmail.com> Co-authored-by: Jacob Gadikian <jacobgadikian@gmail.com>
706 lines
21 KiB
Go
706 lines
21 KiB
Go
package keeper
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"math/rand"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
abci "github.com/cometbft/cometbft/abci/types"
|
|
|
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
|
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
|
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
|
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
|
|
|
|
dbm "github.com/cometbft/cometbft-db"
|
|
"github.com/cometbft/cometbft/libs/log"
|
|
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
|
|
"github.com/cosmos/cosmos-sdk/store"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
|
|
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
|
|
fuzz "github.com/google/gofuzz"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/CosmWasm/wasmd/x/wasm/types"
|
|
)
|
|
|
|
const firstCodeID = 1
|
|
|
|
func TestGenesisExportImport(t *testing.T) {
|
|
wasmKeeper, srcCtx := setupKeeper(t)
|
|
contractKeeper := NewGovPermissionKeeper(wasmKeeper)
|
|
|
|
wasmCode, err := os.ReadFile("./testdata/hackatom.wasm")
|
|
require.NoError(t, err)
|
|
|
|
// store some test data
|
|
f := fuzz.New().Funcs(ModelFuzzers...)
|
|
|
|
err = wasmKeeper.SetParams(srcCtx, types.DefaultParams())
|
|
require.NoError(t, err)
|
|
|
|
for i := 0; i < 25; i++ {
|
|
var (
|
|
codeInfo types.CodeInfo
|
|
contract types.ContractInfo
|
|
stateModels []types.Model
|
|
history []types.ContractCodeHistoryEntry
|
|
pinned bool
|
|
contractExtension bool
|
|
)
|
|
f.Fuzz(&codeInfo)
|
|
f.Fuzz(&contract)
|
|
f.Fuzz(&stateModels)
|
|
f.NilChance(0).Fuzz(&history)
|
|
f.Fuzz(&pinned)
|
|
f.Fuzz(&contractExtension)
|
|
|
|
creatorAddr, err := sdk.AccAddressFromBech32(codeInfo.Creator)
|
|
require.NoError(t, err)
|
|
codeID, _, err := contractKeeper.Create(srcCtx, creatorAddr, wasmCode, &codeInfo.InstantiateConfig)
|
|
require.NoError(t, err)
|
|
if pinned {
|
|
err = contractKeeper.PinCode(srcCtx, codeID)
|
|
require.NoError(t, err)
|
|
}
|
|
if contractExtension {
|
|
anyTime := time.Now().UTC()
|
|
var nestedType v1beta1.TextProposal
|
|
f.NilChance(0).Fuzz(&nestedType)
|
|
myExtension, err := v1beta1.NewProposal(&nestedType, 1, anyTime, anyTime)
|
|
require.NoError(t, err)
|
|
err = contract.SetExtension(&myExtension)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
contract.CodeID = codeID
|
|
contractAddr := wasmKeeper.ClassicAddressGenerator()(srcCtx, codeID, nil)
|
|
wasmKeeper.storeContractInfo(srcCtx, contractAddr, &contract)
|
|
wasmKeeper.appendToContractHistory(srcCtx, contractAddr, history...)
|
|
err = wasmKeeper.importContractState(srcCtx, contractAddr, stateModels)
|
|
require.NoError(t, err)
|
|
}
|
|
var wasmParams types.Params
|
|
f.NilChance(0).Fuzz(&wasmParams)
|
|
err = wasmKeeper.SetParams(srcCtx, wasmParams)
|
|
require.NoError(t, err)
|
|
|
|
// export
|
|
exportedState := ExportGenesis(srcCtx, wasmKeeper)
|
|
// order should not matter
|
|
rand.Shuffle(len(exportedState.Codes), func(i, j int) {
|
|
exportedState.Codes[i], exportedState.Codes[j] = exportedState.Codes[j], exportedState.Codes[i]
|
|
})
|
|
rand.Shuffle(len(exportedState.Contracts), func(i, j int) {
|
|
exportedState.Contracts[i], exportedState.Contracts[j] = exportedState.Contracts[j], exportedState.Contracts[i]
|
|
})
|
|
rand.Shuffle(len(exportedState.Sequences), func(i, j int) {
|
|
exportedState.Sequences[i], exportedState.Sequences[j] = exportedState.Sequences[j], exportedState.Sequences[i]
|
|
})
|
|
exportedGenesis, err := wasmKeeper.cdc.MarshalJSON(exportedState)
|
|
require.NoError(t, err)
|
|
|
|
// setup new instances
|
|
dstKeeper, dstCtx := setupKeeper(t)
|
|
|
|
// reset contract code index in source DB for comparison with dest DB
|
|
wasmKeeper.IterateContractInfo(srcCtx, func(address sdk.AccAddress, info types.ContractInfo) bool {
|
|
creatorAddress := sdk.MustAccAddressFromBech32(info.Creator)
|
|
history := wasmKeeper.GetContractHistory(srcCtx, address)
|
|
|
|
wasmKeeper.addToContractCodeSecondaryIndex(srcCtx, address, history[len(history)-1])
|
|
wasmKeeper.addToContractCreatorSecondaryIndex(srcCtx, creatorAddress, history[0].Updated, address)
|
|
return false
|
|
})
|
|
|
|
// re-import
|
|
var importState types.GenesisState
|
|
err = dstKeeper.cdc.UnmarshalJSON(exportedGenesis, &importState)
|
|
require.NoError(t, err)
|
|
_, err = InitGenesis(dstCtx, dstKeeper, importState)
|
|
require.NoError(t, err)
|
|
|
|
// compare whole DB
|
|
|
|
srcIT := srcCtx.KVStore(wasmKeeper.storeKey).Iterator(nil, nil)
|
|
dstIT := dstCtx.KVStore(dstKeeper.storeKey).Iterator(nil, nil)
|
|
|
|
for i := 0; srcIT.Valid(); i++ {
|
|
require.True(t, dstIT.Valid(), "[%s] destination DB has less elements than source. Missing: %x", wasmKeeper.storeKey.Name(), srcIT.Key())
|
|
require.Equal(t, srcIT.Key(), dstIT.Key(), i)
|
|
require.Equal(t, srcIT.Value(), dstIT.Value(), "[%s] element (%d): %X", wasmKeeper.storeKey.Name(), i, srcIT.Key())
|
|
dstIT.Next()
|
|
srcIT.Next()
|
|
}
|
|
if !assert.False(t, dstIT.Valid()) {
|
|
t.Fatalf("dest Iterator still has key :%X", dstIT.Key())
|
|
}
|
|
srcIT.Close()
|
|
dstIT.Close()
|
|
}
|
|
|
|
func TestGenesisInit(t *testing.T) {
|
|
wasmCode, err := os.ReadFile("./testdata/hackatom.wasm")
|
|
require.NoError(t, err)
|
|
|
|
myCodeInfo := types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode))
|
|
specs := map[string]struct {
|
|
src types.GenesisState
|
|
expSuccess bool
|
|
}{
|
|
"happy path: code info correct": {
|
|
src: types.GenesisState{
|
|
Codes: []types.Code{{
|
|
CodeID: firstCodeID,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
}},
|
|
Sequences: []types.Sequence{
|
|
{IDKey: types.KeyLastCodeID, Value: 2},
|
|
{IDKey: types.KeyLastInstanceID, Value: 1},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
},
|
|
expSuccess: true,
|
|
},
|
|
"happy path: code ids can contain gaps": {
|
|
src: types.GenesisState{
|
|
Codes: []types.Code{{
|
|
CodeID: firstCodeID,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
}, {
|
|
CodeID: 3,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
}},
|
|
Sequences: []types.Sequence{
|
|
{IDKey: types.KeyLastCodeID, Value: 10},
|
|
{IDKey: types.KeyLastInstanceID, Value: 1},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
},
|
|
expSuccess: true,
|
|
},
|
|
"happy path: code order does not matter": {
|
|
src: types.GenesisState{
|
|
Codes: []types.Code{{
|
|
CodeID: 2,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
}, {
|
|
CodeID: firstCodeID,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
}},
|
|
Contracts: nil,
|
|
Sequences: []types.Sequence{
|
|
{IDKey: types.KeyLastCodeID, Value: 3},
|
|
{IDKey: types.KeyLastInstanceID, Value: 1},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
},
|
|
expSuccess: true,
|
|
},
|
|
"prevent code hash mismatch": {src: types.GenesisState{
|
|
Codes: []types.Code{{
|
|
CodeID: firstCodeID,
|
|
CodeInfo: types.CodeInfoFixture(func(i *types.CodeInfo) { i.CodeHash = make([]byte, sha256.Size) }),
|
|
CodeBytes: wasmCode,
|
|
}},
|
|
Params: types.DefaultParams(),
|
|
}},
|
|
"prevent duplicate codeIDs": {src: types.GenesisState{
|
|
Codes: []types.Code{
|
|
{
|
|
CodeID: firstCodeID,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
},
|
|
{
|
|
CodeID: firstCodeID,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
}},
|
|
"codes with same checksum can be pinned": {
|
|
src: types.GenesisState{
|
|
Codes: []types.Code{
|
|
{
|
|
CodeID: firstCodeID,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
Pinned: true,
|
|
},
|
|
{
|
|
CodeID: 2,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
Pinned: true,
|
|
},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
},
|
|
},
|
|
"happy path: code id in info and contract do match": {
|
|
src: types.GenesisState{
|
|
Codes: []types.Code{{
|
|
CodeID: firstCodeID,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
}},
|
|
Contracts: []types.Contract{
|
|
{
|
|
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
|
ContractInfo: types.ContractInfoFixture(func(c *types.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
|
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
|
{
|
|
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
|
CodeID: 1,
|
|
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
|
Msg: []byte(`{}`),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Sequences: []types.Sequence{
|
|
{IDKey: types.KeyLastCodeID, Value: 2},
|
|
{IDKey: types.KeyLastInstanceID, Value: 2},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
},
|
|
expSuccess: true,
|
|
},
|
|
"happy path: code info with two contracts": {
|
|
src: types.GenesisState{
|
|
Codes: []types.Code{{
|
|
CodeID: firstCodeID,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
}},
|
|
Contracts: []types.Contract{
|
|
{
|
|
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
|
ContractInfo: types.ContractInfoFixture(func(c *types.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
|
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
|
{
|
|
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
|
CodeID: 1,
|
|
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
|
Msg: []byte(`{}`),
|
|
},
|
|
},
|
|
}, {
|
|
ContractAddress: BuildContractAddressClassic(1, 2).String(),
|
|
ContractInfo: types.ContractInfoFixture(func(c *types.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
|
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
|
{
|
|
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
|
CodeID: 1,
|
|
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
|
Msg: []byte(`{"foo":"bar"}`),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Sequences: []types.Sequence{
|
|
{IDKey: types.KeyLastCodeID, Value: 2},
|
|
{IDKey: types.KeyLastInstanceID, Value: 3},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
},
|
|
expSuccess: true,
|
|
},
|
|
"prevent contracts that points to non existing codeID": {
|
|
src: types.GenesisState{
|
|
Contracts: []types.Contract{
|
|
{
|
|
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
|
ContractInfo: types.ContractInfoFixture(func(c *types.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
|
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
|
{
|
|
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
|
CodeID: 1,
|
|
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
|
Msg: []byte(`{"foo":"bar"}`),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
},
|
|
},
|
|
"prevent duplicate contract address": {
|
|
src: types.GenesisState{
|
|
Codes: []types.Code{{
|
|
CodeID: firstCodeID,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
}},
|
|
Contracts: []types.Contract{
|
|
{
|
|
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
|
ContractInfo: types.ContractInfoFixture(func(c *types.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
|
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
|
{
|
|
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
|
CodeID: 1,
|
|
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
|
Msg: []byte(`{"foo":"bar"}`),
|
|
},
|
|
},
|
|
}, {
|
|
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
|
ContractInfo: types.ContractInfoFixture(func(c *types.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
|
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
|
{
|
|
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
|
CodeID: 1,
|
|
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
|
Msg: []byte(`{"other":"value"}`),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
},
|
|
},
|
|
"prevent duplicate contract model keys": {
|
|
src: types.GenesisState{
|
|
Codes: []types.Code{{
|
|
CodeID: firstCodeID,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
}},
|
|
Contracts: []types.Contract{
|
|
{
|
|
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
|
ContractInfo: types.ContractInfoFixture(func(c *types.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
|
ContractState: []types.Model{
|
|
{
|
|
Key: []byte{0x1},
|
|
Value: []byte("foo"),
|
|
},
|
|
{
|
|
Key: []byte{0x1},
|
|
Value: []byte("bar"),
|
|
},
|
|
},
|
|
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
|
{
|
|
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
|
CodeID: 1,
|
|
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
|
Msg: []byte(`{"foo":"bar"}`),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
},
|
|
},
|
|
"prevent duplicate sequences": {
|
|
src: types.GenesisState{
|
|
Sequences: []types.Sequence{
|
|
{IDKey: []byte("foo"), Value: 1},
|
|
{IDKey: []byte("foo"), Value: 9999},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
},
|
|
},
|
|
"prevent code id seq init value == max codeID used": {
|
|
src: types.GenesisState{
|
|
Codes: []types.Code{{
|
|
CodeID: 2,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
}},
|
|
Sequences: []types.Sequence{
|
|
{IDKey: types.KeyLastCodeID, Value: 1},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
},
|
|
},
|
|
"prevent contract id seq init value == count contracts": {
|
|
src: types.GenesisState{
|
|
Codes: []types.Code{{
|
|
CodeID: firstCodeID,
|
|
CodeInfo: myCodeInfo,
|
|
CodeBytes: wasmCode,
|
|
}},
|
|
Contracts: []types.Contract{
|
|
{
|
|
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
|
ContractInfo: types.ContractInfoFixture(func(c *types.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
|
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
|
{
|
|
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
|
CodeID: 1,
|
|
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
|
Msg: []byte(`{}`),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Sequences: []types.Sequence{
|
|
{IDKey: types.KeyLastCodeID, Value: 2},
|
|
{IDKey: types.KeyLastInstanceID, Value: 1},
|
|
},
|
|
Params: types.DefaultParams(),
|
|
},
|
|
},
|
|
}
|
|
for msg, spec := range specs {
|
|
t.Run(msg, func(t *testing.T) {
|
|
keeper, ctx := setupKeeper(t)
|
|
|
|
require.NoError(t, types.ValidateGenesis(spec.src))
|
|
_, gotErr := InitGenesis(ctx, keeper, spec.src)
|
|
if !spec.expSuccess {
|
|
require.Error(t, gotErr)
|
|
return
|
|
}
|
|
require.NoError(t, gotErr)
|
|
|
|
for _, c := range spec.src.Codes {
|
|
assert.Equal(t, c.Pinned, keeper.IsPinnedCode(ctx, c.CodeID))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestImportContractWithCodeHistoryPreserved(t *testing.T) {
|
|
genesisTemplate := `
|
|
{
|
|
"params":{
|
|
"code_upload_access": {
|
|
"permission": "Everybody"
|
|
},
|
|
"instantiate_default_permission": "Everybody"
|
|
},
|
|
"codes": [
|
|
{
|
|
"code_id": "1",
|
|
"code_info": {
|
|
"code_hash": %q,
|
|
"creator": "cosmos1qtu5n0cnhfkjj6l2rq97hmky9fd89gwca9yarx",
|
|
"instantiate_config": {
|
|
"permission": "OnlyAddress",
|
|
"address": "cosmos1qtu5n0cnhfkjj6l2rq97hmky9fd89gwca9yarx"
|
|
}
|
|
},
|
|
"code_bytes": %q
|
|
}
|
|
],
|
|
"contracts": [
|
|
{
|
|
"contract_address": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr",
|
|
"contract_info": {
|
|
"code_id": "1",
|
|
"creator": "cosmos13x849jzd03vne42ynpj25hn8npjecxqrjghd8x",
|
|
"admin": "cosmos1h5t8zxmjr30e9dqghtlpl40f2zz5cgey6esxtn",
|
|
"label": "ȀĴnZV芢毤",
|
|
"created": {
|
|
"block_height" : "100",
|
|
"tx_index" : "10"
|
|
}
|
|
},
|
|
"contract_code_history": [
|
|
{
|
|
"operation": "CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT",
|
|
"code_id": "1",
|
|
"updated": {
|
|
"block_height" : "100",
|
|
"tx_index" : "10"
|
|
},
|
|
"msg": {"foo": "bar"}
|
|
},
|
|
{
|
|
"operation": "CONTRACT_CODE_HISTORY_OPERATION_TYPE_MIGRATE",
|
|
"code_id": "1",
|
|
"updated": {
|
|
"block_height" : "200",
|
|
"tx_index" : "10"
|
|
},
|
|
"msg": {"other": "msg"}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"sequences": [
|
|
{"id_key": "BGxhc3RDb2RlSWQ=", "value": "2"},
|
|
{"id_key": "BGxhc3RDb250cmFjdElk", "value": "3"}
|
|
]
|
|
}`
|
|
keeper, ctx := setupKeeper(t)
|
|
|
|
wasmCode, err := os.ReadFile("./testdata/hackatom.wasm")
|
|
require.NoError(t, err)
|
|
|
|
wasmCodeHash := sha256.Sum256(wasmCode)
|
|
enc64 := base64.StdEncoding.EncodeToString
|
|
genesisStr := fmt.Sprintf(genesisTemplate, enc64(wasmCodeHash[:]), enc64(wasmCode))
|
|
|
|
var importState types.GenesisState
|
|
err = keeper.cdc.UnmarshalJSON([]byte(genesisStr), &importState)
|
|
require.NoError(t, err)
|
|
require.NoError(t, importState.ValidateBasic(), genesisStr)
|
|
|
|
ctx = ctx.WithBlockHeight(0).WithGasMeter(sdk.NewInfiniteGasMeter())
|
|
|
|
// when
|
|
_, err = InitGenesis(ctx, keeper, importState)
|
|
require.NoError(t, err)
|
|
|
|
// verify wasm code
|
|
gotWasmCode, err := keeper.GetByteCode(ctx, 1)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, wasmCode, gotWasmCode, "byte code does not match")
|
|
|
|
// verify code info
|
|
gotCodeInfo := keeper.GetCodeInfo(ctx, 1)
|
|
require.NotNil(t, gotCodeInfo)
|
|
codeCreatorAddr := "cosmos1qtu5n0cnhfkjj6l2rq97hmky9fd89gwca9yarx"
|
|
expCodeInfo := types.CodeInfo{
|
|
CodeHash: wasmCodeHash[:],
|
|
Creator: codeCreatorAddr,
|
|
InstantiateConfig: types.AccessConfig{
|
|
Permission: types.AccessTypeOnlyAddress,
|
|
Address: codeCreatorAddr,
|
|
},
|
|
}
|
|
assert.Equal(t, expCodeInfo, *gotCodeInfo)
|
|
|
|
// verify contract
|
|
contractAddr, _ := sdk.AccAddressFromBech32("cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr")
|
|
gotContractInfo := keeper.GetContractInfo(ctx, contractAddr)
|
|
require.NotNil(t, gotContractInfo)
|
|
contractCreatorAddr := "cosmos13x849jzd03vne42ynpj25hn8npjecxqrjghd8x"
|
|
adminAddr := "cosmos1h5t8zxmjr30e9dqghtlpl40f2zz5cgey6esxtn"
|
|
|
|
expContractInfo := types.ContractInfo{
|
|
CodeID: firstCodeID,
|
|
Creator: contractCreatorAddr,
|
|
Admin: adminAddr,
|
|
Label: "ȀĴnZV芢毤",
|
|
Created: &types.AbsoluteTxPosition{BlockHeight: 100, TxIndex: 10},
|
|
}
|
|
assert.Equal(t, expContractInfo, *gotContractInfo)
|
|
|
|
expHistory := []types.ContractCodeHistoryEntry{
|
|
{
|
|
Operation: types.ContractCodeHistoryOperationTypeInit,
|
|
CodeID: firstCodeID,
|
|
Updated: &types.AbsoluteTxPosition{
|
|
BlockHeight: 100,
|
|
TxIndex: 10,
|
|
},
|
|
Msg: []byte(`{"foo": "bar"}`),
|
|
},
|
|
{
|
|
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
|
CodeID: firstCodeID,
|
|
Updated: &types.AbsoluteTxPosition{
|
|
BlockHeight: 200,
|
|
TxIndex: 10,
|
|
},
|
|
Msg: []byte(`{"other": "msg"}`),
|
|
},
|
|
}
|
|
assert.Equal(t, expHistory, keeper.GetContractHistory(ctx, contractAddr))
|
|
assert.Equal(t, uint64(2), keeper.PeekAutoIncrementID(ctx, types.KeyLastCodeID))
|
|
assert.Equal(t, uint64(3), keeper.PeekAutoIncrementID(ctx, types.KeyLastInstanceID))
|
|
}
|
|
|
|
func setupKeeper(t *testing.T) (*Keeper, sdk.Context) {
|
|
t.Helper()
|
|
tempDir, err := os.MkdirTemp("", "wasm")
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() { os.RemoveAll(tempDir) })
|
|
|
|
keyWasm := sdk.NewKVStoreKey(types.StoreKey)
|
|
|
|
db := dbm.NewMemDB()
|
|
ms := store.NewCommitMultiStore(db)
|
|
ms.MountStoreWithDB(keyWasm, storetypes.StoreTypeIAVL, db)
|
|
require.NoError(t, ms.LoadLatestVersion())
|
|
|
|
ctx := sdk.NewContext(ms, tmproto.Header{
|
|
Height: 1234567,
|
|
Time: time.Date(2020, time.April, 22, 12, 0, 0, 0, time.UTC),
|
|
}, false, log.NewNopLogger())
|
|
|
|
encodingConfig := MakeEncodingConfig(t)
|
|
// register an example extension. must be protobuf
|
|
encodingConfig.InterfaceRegistry.RegisterImplementations(
|
|
(*types.ContractInfoExtension)(nil),
|
|
&v1beta1.Proposal{},
|
|
)
|
|
// also registering gov interfaces for nested Any type
|
|
v1beta1.RegisterInterfaces(encodingConfig.InterfaceRegistry)
|
|
|
|
wasmConfig := types.DefaultWasmConfig()
|
|
|
|
srcKeeper := NewKeeper(
|
|
encodingConfig.Marshaler,
|
|
keyWasm,
|
|
authkeeper.AccountKeeper{},
|
|
&bankkeeper.BaseKeeper{},
|
|
stakingkeeper.Keeper{},
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
tempDir,
|
|
wasmConfig,
|
|
AvailableCapabilities,
|
|
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
|
|
)
|
|
return &srcKeeper, ctx
|
|
}
|
|
|
|
type StakingKeeperMock struct {
|
|
err error
|
|
validatorUpdate []abci.ValidatorUpdate
|
|
gotCalls int
|
|
}
|
|
|
|
func (s *StakingKeeperMock) ApplyAndReturnValidatorSetUpdates(_ sdk.Context) ([]abci.ValidatorUpdate, error) {
|
|
s.gotCalls++
|
|
return s.validatorUpdate, s.err
|
|
}
|
|
|
|
var _ MessageRouter = &MockMsgHandler{}
|
|
|
|
type MockMsgHandler struct {
|
|
result *sdk.Result
|
|
err error
|
|
expCalls int //nolint:unused
|
|
gotCalls int
|
|
expMsg sdk.Msg //nolint:unused
|
|
gotMsg sdk.Msg
|
|
}
|
|
|
|
func (m *MockMsgHandler) Handler(msg sdk.Msg) baseapp.MsgServiceHandler {
|
|
return m.Handle
|
|
}
|
|
|
|
func (m *MockMsgHandler) Handle(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
|
|
m.gotCalls++
|
|
m.gotMsg = msg
|
|
return m.result, m.err
|
|
}
|