diff --git a/app/sim_test.go b/app/sim_test.go index 41f729099e..e80c6fcae7 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -8,9 +8,6 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/store/prefix" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" @@ -196,37 +193,6 @@ func TestAppImportExport(t *testing.T) { // delete persistent tx counter value ctxA.KVStore(app.keys[wasm.StoreKey]).Delete(wasmtypes.TXCounterPrefix) - // reset contract code index in source DB for comparison with dest DB - dropContractHistory := func(s store.KVStore, keys ...[]byte) { - for _, key := range keys { - prefixStore := prefix.NewStore(s, key) - iter := prefixStore.Iterator(nil, nil) - for ; iter.Valid(); iter.Next() { - prefixStore.Delete(iter.Key()) - } - iter.Close() - } - } - prefixes := [][]byte{wasmtypes.ContractCodeHistoryElementPrefix, wasmtypes.ContractByCodeIDAndCreatedSecondaryIndexPrefix} - dropContractHistory(ctxA.KVStore(app.keys[wasm.StoreKey]), prefixes...) - dropContractHistory(ctxB.KVStore(newApp.keys[wasm.StoreKey]), prefixes...) - - normalizeContractInfo := func(ctx sdk.Context, app *WasmApp) { - var index uint64 - app.WasmKeeper.IterateContractInfo(ctx, func(address sdk.AccAddress, info wasmtypes.ContractInfo) bool { - created := &wasmtypes.AbsoluteTxPosition{ - BlockHeight: uint64(0), - TxIndex: index, - } - info.Created = created - store := ctx.KVStore(app.keys[wasm.StoreKey]) - store.Set(wasmtypes.GetContractAddressKey(address), app.appCodec.MustMarshal(&info)) - index++ - return false - }) - } - normalizeContractInfo(ctxA, app) - normalizeContractInfo(ctxB, newApp) // diff both stores for _, skp := range storeKeysPrefixes { storeA := ctxA.KVStore(skp.A) diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md index d6e5aee1d6..fdf641c81a 100644 --- a/docs/proto/proto-docs.md +++ b/docs/proto/proto-docs.md @@ -193,7 +193,7 @@ ContractInfo stores a WASM contract instance | `creator` | [string](#string) | | Creator address who initially instantiated the contract | | `admin` | [string](#string) | | Admin is an optional address that can execute migrations | | `label` | [string](#string) | | Label is optional metadata to be stored with a contract instance. | -| `created` | [AbsoluteTxPosition](#cosmwasm.wasm.v1.AbsoluteTxPosition) | | Created Tx position when the contract was instantiated. This data should kept internal and not be exposed via query results. Just use for sorting | +| `created` | [AbsoluteTxPosition](#cosmwasm.wasm.v1.AbsoluteTxPosition) | | Created Tx position when the contract was instantiated. | | `ibc_port_id` | [string](#string) | | | | `extension` | [google.protobuf.Any](#google.protobuf.Any) | | Extension is an extension point to store custom metadata within the persistence model. | @@ -568,6 +568,7 @@ Contract struct encompasses ContractAddress, ContractInfo, and ContractState | `contract_address` | [string](#string) | | | | `contract_info` | [ContractInfo](#cosmwasm.wasm.v1.ContractInfo) | | | | `contract_state` | [Model](#cosmwasm.wasm.v1.Model) | repeated | | +| `contract_code_history` | [ContractCodeHistoryEntry](#cosmwasm.wasm.v1.ContractCodeHistoryEntry) | repeated | | diff --git a/proto/cosmwasm/wasm/v1/genesis.proto b/proto/cosmwasm/wasm/v1/genesis.proto index 87373e18d7..b7622c206a 100644 --- a/proto/cosmwasm/wasm/v1/genesis.proto +++ b/proto/cosmwasm/wasm/v1/genesis.proto @@ -53,6 +53,8 @@ message Contract { string contract_address = 1; ContractInfo contract_info = 2 [ (gogoproto.nullable) = false ]; repeated Model contract_state = 3 [ (gogoproto.nullable) = false ]; + repeated ContractCodeHistoryEntry contract_code_history = 4 + [ (gogoproto.nullable) = false ]; } // Sequence key and value of an id generation counter diff --git a/proto/cosmwasm/wasm/v1/types.proto b/proto/cosmwasm/wasm/v1/types.proto index 8d140248a8..216b24e3b4 100644 --- a/proto/cosmwasm/wasm/v1/types.proto +++ b/proto/cosmwasm/wasm/v1/types.proto @@ -84,8 +84,6 @@ message ContractInfo { // Label is optional metadata to be stored with a contract instance. string label = 4; // Created Tx position when the contract was instantiated. - // This data should kept internal and not be exposed via query results. Just - // use for sorting AbsoluteTxPosition created = 5; string ibc_port_id = 6 [ (gogoproto.customname) = "IBCPortID" ]; diff --git a/x/wasm/client/cli/genesis_msg_test.go b/x/wasm/client/cli/genesis_msg_test.go index a1d24f29cd..cd8a5f3b7b 100644 --- a/x/wasm/client/cli/genesis_msg_test.go +++ b/x/wasm/client/cli/genesis_msg_test.go @@ -391,10 +391,11 @@ func TestExecuteContractCmd(t *testing.T) { Contracts: []types.Contract{ { ContractAddress: firstContractAddress, - ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) { - info.Created = nil - }), - ContractState: []types.Model{}, + ContractInfo: types.ContractInfoFixture(), + ContractState: []types.Model{}, + ContractCodeHistory: []types.ContractCodeHistoryEntry{ + types.ContractCodeHistoryEntryFixture(), + }, }, }, }, @@ -473,10 +474,11 @@ func TestExecuteContractCmd(t *testing.T) { Contracts: []types.Contract{ { ContractAddress: firstContractAddress, - ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) { - info.Created = nil - }), - ContractState: []types.Model{}, + ContractInfo: types.ContractInfoFixture(), + ContractState: []types.Model{}, + ContractCodeHistory: []types.ContractCodeHistoryEntry{ + types.ContractCodeHistoryEntryFixture(), + }, }, }, }, @@ -500,10 +502,11 @@ func TestExecuteContractCmd(t *testing.T) { Contracts: []types.Contract{ { ContractAddress: firstContractAddress, - ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) { - info.Created = nil - }), - ContractState: []types.Model{}, + ContractInfo: types.ContractInfoFixture(), + ContractState: []types.Model{}, + ContractCodeHistory: []types.ContractCodeHistoryEntry{ + types.ContractCodeHistoryEntryFixture(), + }, }, }, }, @@ -528,10 +531,11 @@ func TestExecuteContractCmd(t *testing.T) { Contracts: []types.Contract{ { ContractAddress: firstContractAddress, - ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) { - info.Created = nil - }), - ContractState: []types.Model{}, + ContractInfo: types.ContractInfoFixture(), + ContractState: []types.Model{}, + ContractCodeHistory: []types.ContractCodeHistoryEntry{ + types.ContractCodeHistoryEntryFixture(), + }, }, }, }, diff --git a/x/wasm/keeper/genesis.go b/x/wasm/keeper/genesis.go index 7fa5280b9e..2fb152a130 100644 --- a/x/wasm/keeper/genesis.go +++ b/x/wasm/keeper/genesis.go @@ -41,7 +41,7 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState, staki if err != nil { return nil, sdkerrors.Wrapf(err, "address in contract number %d", i) } - err = keeper.importContract(ctx, contractAddr, &contract.ContractInfo, contract.ContractState) + err = keeper.importContract(ctx, contractAddr, &contract.ContractInfo, contract.ContractState, contract.ContractCodeHistory) if err != nil { return nil, sdkerrors.Wrapf(err, "contract number %d", i) } @@ -107,12 +107,14 @@ func ExportGenesis(ctx sdk.Context, keeper *Keeper) *types.GenesisState { state = append(state, types.Model{Key: key, Value: value}) return false }) - // redact contract info - contract.Created = nil + + contractCodeHistory := keeper.GetContractHistory(ctx, addr) + genState.Contracts = append(genState.Contracts, types.Contract{ - ContractAddress: addr.String(), - ContractInfo: contract, - ContractState: state, + ContractAddress: addr.String(), + ContractInfo: contract, + ContractState: state, + ContractCodeHistory: contractCodeHistory, }) return false }) diff --git a/x/wasm/keeper/genesis_test.go b/x/wasm/keeper/genesis_test.go index 1d8f29a40f..beba80fe7d 100644 --- a/x/wasm/keeper/genesis_test.go +++ b/x/wasm/keeper/genesis_test.go @@ -12,7 +12,6 @@ import ( "time" "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" @@ -111,21 +110,10 @@ func TestGenesisExportImport(t *testing.T) { // reset contract code index in source DB for comparison with dest DB wasmKeeper.IterateContractInfo(srcCtx, func(address sdk.AccAddress, info wasmTypes.ContractInfo) bool { creatorAddress := sdk.MustAccAddressFromBech32(info.Creator) - wasmKeeper.removeFromContractCodeSecondaryIndex(srcCtx, address, wasmKeeper.getLastContractHistoryEntry(srcCtx, address)) + history := wasmKeeper.GetContractHistory(srcCtx, address) - prefixStore := prefix.NewStore(srcCtx.KVStore(wasmKeeper.storeKey), types.GetContractCodeHistoryElementPrefix(address)) - iter := prefixStore.Iterator(nil, nil) - - for ; iter.Valid(); iter.Next() { - prefixStore.Delete(iter.Key()) - } - x := &info - newHistory := x.ResetFromGenesis(dstCtx) - wasmKeeper.storeContractInfo(srcCtx, address, x) - wasmKeeper.addToContractCodeSecondaryIndex(srcCtx, address, newHistory) - wasmKeeper.addToContractCreatorSecondaryIndex(srcCtx, creatorAddress, newHistory.Updated, address) - wasmKeeper.appendToContractHistory(srcCtx, address, newHistory) - iter.Close() + wasmKeeper.addToContractCodeSecondaryIndex(srcCtx, address, history[len(history)-1]) + wasmKeeper.addToContractCreatorSecondaryIndex(srcCtx, creatorAddress, history[0].Updated, address) return false }) @@ -272,7 +260,15 @@ func TestGenesisInit(t *testing.T) { Contracts: []types.Contract{ { ContractAddress: BuildContractAddressClassic(1, 1).String(), - ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.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{ @@ -293,10 +289,26 @@ func TestGenesisInit(t *testing.T) { Contracts: []types.Contract{ { ContractAddress: BuildContractAddressClassic(1, 1).String(), - ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.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 *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.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{ @@ -312,7 +324,15 @@ func TestGenesisInit(t *testing.T) { Contracts: []types.Contract{ { ContractAddress: BuildContractAddressClassic(1, 1).String(), - ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.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(), @@ -328,10 +348,26 @@ func TestGenesisInit(t *testing.T) { Contracts: []types.Contract{ { ContractAddress: BuildContractAddressClassic(1, 1).String(), - ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.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 *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.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(), @@ -347,7 +383,7 @@ func TestGenesisInit(t *testing.T) { Contracts: []types.Contract{ { ContractAddress: BuildContractAddressClassic(1, 1).String(), - ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields), ContractState: []types.Model{ { Key: []byte{0x1}, @@ -358,6 +394,14 @@ func TestGenesisInit(t *testing.T) { 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(), @@ -395,7 +439,15 @@ func TestGenesisInit(t *testing.T) { Contracts: []types.Contract{ { ContractAddress: BuildContractAddressClassic(1, 1).String(), - ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.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{ @@ -459,7 +511,7 @@ func TestGenesisInit(t *testing.T) { } } -func TestImportContractWithCodeHistoryReset(t *testing.T) { +func TestImportContractWithCodeHistoryPreserved(t *testing.T) { genesisTemplate := ` { "params":{ @@ -489,8 +541,32 @@ func TestImportContractWithCodeHistoryReset(t *testing.T) { "code_id": "1", "creator": "cosmos13x849jzd03vne42ynpj25hn8npjecxqrjghd8x", "admin": "cosmos1h5t8zxmjr30e9dqghtlpl40f2zz5cgey6esxtn", - "label": "ȀĴnZV芢毤" - } + "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": [ @@ -550,15 +626,28 @@ func TestImportContractWithCodeHistoryReset(t *testing.T) { Creator: contractCreatorAddr, Admin: adminAddr, Label: "ȀĴnZV芢毤", - Created: &types.AbsoluteTxPosition{BlockHeight: 0, TxIndex: 0}, + Created: &types.AbsoluteTxPosition{BlockHeight: 100, TxIndex: 10}, } assert.Equal(t, expContractInfo, *gotContractInfo) expHistory := []types.ContractCodeHistoryEntry{ { - Operation: types.ContractCodeHistoryOperationTypeGenesis, + Operation: types.ContractCodeHistoryOperationTypeInit, CodeID: firstCodeID, - Updated: types.NewAbsoluteTxPosition(ctx), + 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)) diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index 3112a26eb5..195a4614ce 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -1062,7 +1062,7 @@ func (k Keeper) importAutoIncrementID(ctx sdk.Context, lastIDKey []byte, val uin return nil } -func (k Keeper) importContract(ctx sdk.Context, contractAddr sdk.AccAddress, c *types.ContractInfo, state []types.Model) error { +func (k Keeper) importContract(ctx sdk.Context, contractAddr sdk.AccAddress, c *types.ContractInfo, state []types.Model, entries []types.ContractCodeHistoryEntry) error { if !k.containsCodeInfo(ctx, c.CodeID) { return sdkerrors.Wrapf(types.ErrNotFound, "code id: %d", c.CodeID) } @@ -1074,11 +1074,11 @@ func (k Keeper) importContract(ctx sdk.Context, contractAddr sdk.AccAddress, c * if err != nil { return err } - historyEntry := c.ResetFromGenesis(ctx) - k.appendToContractHistory(ctx, contractAddr, historyEntry) + + k.appendToContractHistory(ctx, contractAddr, entries...) k.storeContractInfo(ctx, contractAddr, c) - k.addToContractCodeSecondaryIndex(ctx, contractAddr, historyEntry) - k.addToContractCreatorSecondaryIndex(ctx, creatorAddress, historyEntry.Updated, contractAddr) + k.addToContractCodeSecondaryIndex(ctx, contractAddr, entries[len(entries)-1]) + k.addToContractCreatorSecondaryIndex(ctx, creatorAddress, entries[0].Updated, contractAddr) return k.importContractState(ctx, contractAddr, state) } diff --git a/x/wasm/keeper/proposal_integration_test.go b/x/wasm/keeper/proposal_integration_test.go index 5a0305a485..1327ba88e3 100644 --- a/x/wasm/keeper/proposal_integration_test.go +++ b/x/wasm/keeper/proposal_integration_test.go @@ -231,14 +231,18 @@ func TestMigrateProposal(t *testing.T) { contractAddr = BuildContractAddressClassic(1, 1) ) - contractInfoFixture := types.ContractInfoFixture(func(c *types.ContractInfo) { + contractInfo := types.ContractInfoFixture(func(c *types.ContractInfo) { c.Label = "testing" c.Admin = anyAddress.String() + c.Created = types.NewAbsoluteTxPosition(ctx) }) + entries := []types.ContractCodeHistoryEntry{ + {Operation: types.ContractCodeHistoryOperationTypeInit, CodeID: 1, Updated: contractInfo.Created}, + } key, err := hex.DecodeString("636F6E666967") require.NoError(t, err) m := types.Model{Key: key, Value: []byte(`{"verifier":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","beneficiary":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","funder":"AQEBAQEBAQEBAQEBAQEBAQEBAQE="}`)} - require.NoError(t, wasmKeeper.importContract(ctx, contractAddr, &contractInfoFixture, []types.Model{m})) + require.NoError(t, wasmKeeper.importContract(ctx, contractAddr, &contractInfo, []types.Model{m}, entries)) migMsg := struct { Verifier sdk.AccAddress `json:"verifier"` @@ -273,7 +277,7 @@ func TestMigrateProposal(t *testing.T) { assert.Equal(t, anyAddress.String(), cInfo.Admin) assert.Equal(t, "testing", cInfo.Label) expHistory := []types.ContractCodeHistoryEntry{{ - Operation: types.ContractCodeHistoryOperationTypeGenesis, + Operation: types.ContractCodeHistoryOperationTypeInit, CodeID: firstCodeID, Updated: types.NewAbsoluteTxPosition(ctx), }, { @@ -469,10 +473,18 @@ func TestAdminProposals(t *testing.T) { InstantiateDefaultPermission: types.AccessTypeNobody, }) - codeInfoFixture := types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)) - require.NoError(t, wasmKeeper.importCode(ctx, 1, codeInfoFixture, wasmCode)) + codeInfo := types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)) + require.NoError(t, wasmKeeper.importCode(ctx, 1, codeInfo, wasmCode)) + + entries := []types.ContractCodeHistoryEntry{ + { + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: 1, + Updated: spec.state.Created, + }, + } - require.NoError(t, wasmKeeper.importContract(ctx, contractAddr, &spec.state, []types.Model{})) + require.NoError(t, wasmKeeper.importContract(ctx, contractAddr, &spec.state, []types.Model{}, entries)) // when stored storedProposal, err := govKeeper.SubmitProposal(ctx, spec.srcProposal) require.NoError(t, err) diff --git a/x/wasm/keeper/querier.go b/x/wasm/keeper/querier.go index 9b23c68d96..ceb0470de6 100644 --- a/x/wasm/keeper/querier.go +++ b/x/wasm/keeper/querier.go @@ -257,8 +257,6 @@ func queryContractInfo(ctx sdk.Context, addr sdk.AccAddress, keeper types.ViewKe if info == nil { return nil, types.ErrNotFound } - // redact the Created field (just used for sorting, not part of public API) - info.Created = nil return &types.QueryContractInfoResponse{ Address: addr.String(), ContractInfo: *info, diff --git a/x/wasm/keeper/querier_test.go b/x/wasm/keeper/querier_test.go index 52a17d0e11..197e6afaa2 100644 --- a/x/wasm/keeper/querier_test.go +++ b/x/wasm/keeper/querier_test.go @@ -560,20 +560,16 @@ func TestQueryContractInfo(t *testing.T) { src: &types.QueryContractInfoRequest{Address: contractAddr.String()}, stored: types.ContractInfoFixture(), expRsp: &types.QueryContractInfoResponse{ - Address: contractAddr.String(), - ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) { - info.Created = nil // not returned on queries - }), + Address: contractAddr.String(), + ContractInfo: types.ContractInfoFixture(), }, }, "with extension": { src: &types.QueryContractInfoRequest{Address: contractAddr.String()}, stored: types.ContractInfoFixture(myExtension), expRsp: &types.QueryContractInfoResponse{ - Address: contractAddr.String(), - ContractInfo: types.ContractInfoFixture(myExtension, func(info *types.ContractInfo) { - info.Created = nil // not returned on queries - }), + Address: contractAddr.String(), + ContractInfo: types.ContractInfoFixture(myExtension), }, }, "not found": { diff --git a/x/wasm/types/genesis.go b/x/wasm/types/genesis.go index ba973c6f02..a82893bd90 100644 --- a/x/wasm/types/genesis.go +++ b/x/wasm/types/genesis.go @@ -61,14 +61,22 @@ func (c Contract) ValidateBasic() error { return sdkerrors.Wrap(err, "contract info") } - if c.ContractInfo.Created != nil { - return sdkerrors.Wrap(ErrInvalid, "created must be empty") + if c.ContractInfo.Created == nil { + return sdkerrors.Wrap(ErrInvalid, "created must not be empty") } for i := range c.ContractState { if err := c.ContractState[i].ValidateBasic(); err != nil { return sdkerrors.Wrapf(err, "contract state %d", i) } } + if len(c.ContractCodeHistory) == 0 { + return ErrEmpty.Wrap("code history") + } + for i, v := range c.ContractCodeHistory { + if err := v.ValidateBasic(); err != nil { + return sdkerrors.Wrapf(err, "code history element %d", i) + } + } return nil } diff --git a/x/wasm/types/genesis.pb.go b/x/wasm/types/genesis.pb.go index 926b74c81c..3f7037985a 100644 --- a/x/wasm/types/genesis.pb.go +++ b/x/wasm/types/genesis.pb.go @@ -293,9 +293,10 @@ func (m *Code) GetPinned() bool { // Contract struct encompasses ContractAddress, ContractInfo, and ContractState type Contract struct { - ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` - ContractInfo ContractInfo `protobuf:"bytes,2,opt,name=contract_info,json=contractInfo,proto3" json:"contract_info"` - ContractState []Model `protobuf:"bytes,3,rep,name=contract_state,json=contractState,proto3" json:"contract_state"` + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + ContractInfo ContractInfo `protobuf:"bytes,2,opt,name=contract_info,json=contractInfo,proto3" json:"contract_info"` + ContractState []Model `protobuf:"bytes,3,rep,name=contract_state,json=contractState,proto3" json:"contract_state"` + ContractCodeHistory []ContractCodeHistoryEntry `protobuf:"bytes,4,rep,name=contract_code_history,json=contractCodeHistory,proto3" json:"contract_code_history"` } func (m *Contract) Reset() { *m = Contract{} } @@ -357,6 +358,13 @@ func (m *Contract) GetContractState() []Model { return nil } +func (m *Contract) GetContractCodeHistory() []ContractCodeHistoryEntry { + if m != nil { + return m.ContractCodeHistory + } + return nil +} + // Sequence key and value of an id generation counter type Sequence struct { IDKey []byte `protobuf:"bytes,1,opt,name=id_key,json=idKey,proto3" json:"id_key,omitempty"` @@ -426,48 +434,50 @@ func init() { func init() { proto.RegisterFile("cosmwasm/wasm/v1/genesis.proto", fileDescriptor_2ab3f539b23472a6) } var fileDescriptor_2ab3f539b23472a6 = []byte{ - // 646 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x94, 0xcf, 0x6e, 0xd3, 0x4e, - 0x10, 0xc7, 0xe3, 0x26, 0x4e, 0x93, 0x69, 0x7e, 0xbf, 0x56, 0xdb, 0xaa, 0x35, 0x06, 0x9c, 0x28, - 0xa0, 0x2a, 0x48, 0x28, 0x51, 0x8b, 0xc4, 0x0d, 0x01, 0x6e, 0x2b, 0x6a, 0x55, 0x95, 0xc0, 0x15, - 0x42, 0x42, 0xaa, 0x22, 0xd7, 0xde, 0x1a, 0x8b, 0xda, 0x1b, 0xb2, 0x9b, 0x52, 0x9f, 0x79, 0x01, - 0x1e, 0x01, 0x5e, 0x06, 0xf5, 0xd8, 0x23, 0xa7, 0x08, 0xa5, 0x37, 0x9e, 0x02, 0xed, 0x1f, 0xbb, - 0x06, 0xa7, 0x17, 0x2b, 0x3b, 0xf3, 0x9d, 0xcf, 0xfc, 0xc9, 0xec, 0x82, 0xe5, 0x13, 0x1a, 0x7f, - 0xf6, 0x68, 0x3c, 0x10, 0x9f, 0xf3, 0xad, 0x41, 0x88, 0x13, 0x4c, 0x23, 0xda, 0x1f, 0x8d, 0x09, - 0x23, 0x68, 0x25, 0xf3, 0xf7, 0xc5, 0xe7, 0x7c, 0xcb, 0x5c, 0x0b, 0x49, 0x48, 0x84, 0x73, 0xc0, - 0x7f, 0x49, 0x9d, 0x79, 0xaf, 0xc4, 0x61, 0xe9, 0x08, 0x2b, 0x8a, 0x79, 0xa7, 0xec, 0xbd, 0x90, - 0xae, 0xee, 0x37, 0x1d, 0x5a, 0xaf, 0x64, 0xca, 0x23, 0xe6, 0x31, 0x8c, 0x9e, 0x42, 0x7d, 0xe4, - 0x8d, 0xbd, 0x98, 0x1a, 0x5a, 0x47, 0xeb, 0x2d, 0x6d, 0x1b, 0xfd, 0x7f, 0x4b, 0xe8, 0xbf, 0x16, - 0x7e, 0xbb, 0x76, 0x39, 0x6d, 0x57, 0x5c, 0xa5, 0x46, 0x7b, 0xa0, 0xfb, 0x24, 0xc0, 0xd4, 0x58, - 0xe8, 0x54, 0x7b, 0x4b, 0xdb, 0xeb, 0xe5, 0xb0, 0x1d, 0x12, 0x60, 0x7b, 0x83, 0x07, 0xfd, 0x9e, - 0xb6, 0x97, 0x85, 0xf8, 0x31, 0x89, 0x23, 0x86, 0xe3, 0x11, 0x4b, 0x5d, 0x19, 0x8d, 0xde, 0x42, - 0xd3, 0x27, 0x09, 0x1b, 0x7b, 0x3e, 0xa3, 0x46, 0x55, 0xa0, 0xcc, 0x79, 0x28, 0x29, 0xb1, 0xef, - 0x2a, 0xdc, 0x6a, 0x1e, 0x54, 0x40, 0xde, 0x90, 0x38, 0x96, 0xe2, 0x4f, 0x13, 0x9c, 0xf8, 0x98, - 0x1a, 0xb5, 0xdb, 0xb0, 0x47, 0x4a, 0x72, 0x83, 0xcd, 0x83, 0x8a, 0xd8, 0xdc, 0x88, 0x8e, 0xa1, - 0x11, 0xe2, 0x64, 0x18, 0xd3, 0x90, 0x1a, 0xba, 0xa0, 0x6e, 0x96, 0xa9, 0xc5, 0xf1, 0xf2, 0xc3, - 0x21, 0x0d, 0xa9, 0x6d, 0xaa, 0x0c, 0x28, 0x8b, 0x2f, 0x24, 0x58, 0x0c, 0xa5, 0xc8, 0xfc, 0xb2, - 0x00, 0x8b, 0x2a, 0x00, 0x3d, 0x07, 0xa0, 0x8c, 0x8c, 0xf1, 0x90, 0xcf, 0x49, 0xfd, 0x37, 0x56, - 0x39, 0xd9, 0x21, 0x0d, 0x8f, 0xb8, 0x8c, 0x0f, 0x7b, 0xbf, 0xe2, 0x36, 0x69, 0x76, 0x40, 0xc7, - 0xb0, 0x16, 0x25, 0x94, 0x79, 0x09, 0x8b, 0x3c, 0xc6, 0x31, 0x72, 0x36, 0xc6, 0x82, 0x40, 0xf5, - 0xe6, 0xa2, 0x9c, 0x9b, 0x80, 0x6c, 0xe4, 0xfb, 0x15, 0x77, 0x35, 0x2a, 0x9b, 0xd1, 0x1b, 0x58, - 0xc1, 0x17, 0xd8, 0x9f, 0x14, 0xd1, 0x55, 0x81, 0x7e, 0x38, 0x17, 0xbd, 0x27, 0xc5, 0x05, 0xec, - 0x32, 0xfe, 0xdb, 0x64, 0xeb, 0x50, 0xa5, 0x93, 0xb8, 0xfb, 0x5d, 0x83, 0x9a, 0xe8, 0xe0, 0x01, - 0x2c, 0xf2, 0xe6, 0x87, 0x51, 0x20, 0xfa, 0xaf, 0xd9, 0x30, 0x9b, 0xb6, 0xeb, 0xdc, 0xe5, 0xec, - 0xba, 0x75, 0xee, 0x72, 0x02, 0xf4, 0x8c, 0x2f, 0x10, 0x17, 0x25, 0xa7, 0x44, 0xf5, 0x66, 0xce, - 0xdf, 0x45, 0x27, 0x39, 0x25, 0x6a, 0x89, 0x1b, 0xbe, 0x3a, 0xa3, 0xfb, 0x00, 0x22, 0xfc, 0x24, - 0x65, 0x98, 0x8a, 0x06, 0x5a, 0xae, 0x00, 0xda, 0xdc, 0x80, 0xd6, 0xa1, 0x3e, 0x8a, 0x92, 0x04, - 0x07, 0x46, 0xad, 0xa3, 0xf5, 0x1a, 0xae, 0x3a, 0x75, 0x7f, 0x68, 0xd0, 0xc8, 0x47, 0xf1, 0x08, - 0x56, 0xb2, 0x11, 0x0c, 0xbd, 0x20, 0x18, 0x63, 0x2a, 0x2f, 0x53, 0xd3, 0x5d, 0xce, 0xec, 0x2f, - 0xa5, 0x19, 0x39, 0xf0, 0x5f, 0x2e, 0x2d, 0x54, 0x6c, 0xdd, 0xbe, 0xf2, 0x85, 0xaa, 0x5b, 0x7e, - 0xc1, 0x86, 0x76, 0xe1, 0xff, 0x1c, 0x45, 0xf9, 0xae, 0xa9, 0xeb, 0xb3, 0x31, 0x67, 0xfc, 0x24, - 0xc0, 0x67, 0x0a, 0x92, 0xe7, 0x17, 0xfb, 0xd9, 0xb5, 0xa1, 0x91, 0xdd, 0x02, 0xd4, 0x81, 0x7a, - 0x14, 0x0c, 0x3f, 0xe2, 0x54, 0x54, 0xdf, 0xb2, 0x9b, 0xb3, 0x69, 0x5b, 0x77, 0x76, 0x0f, 0x70, - 0xea, 0xea, 0x51, 0x70, 0x80, 0x53, 0xb4, 0x06, 0xfa, 0xb9, 0x77, 0x36, 0xc1, 0xa2, 0xec, 0x9a, - 0x2b, 0x0f, 0xf6, 0x8b, 0xcb, 0x99, 0xa5, 0x5d, 0xcd, 0x2c, 0xed, 0xd7, 0xcc, 0xd2, 0xbe, 0x5e, - 0x5b, 0x95, 0xab, 0x6b, 0xab, 0xf2, 0xf3, 0xda, 0xaa, 0xbc, 0xdf, 0x0c, 0x23, 0xf6, 0x61, 0x72, - 0xd2, 0xf7, 0x49, 0x3c, 0xd8, 0x21, 0x34, 0x7e, 0x97, 0xbd, 0x49, 0xc1, 0xe0, 0x42, 0xbe, 0x4d, - 0xe2, 0xd9, 0x3a, 0xa9, 0x8b, 0xc7, 0xe9, 0xc9, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7c, 0x05, - 0x87, 0xde, 0x1f, 0x05, 0x00, 0x00, + // 676 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x94, 0xcf, 0x6e, 0xd3, 0x40, + 0x10, 0xc6, 0xe3, 0x24, 0x4e, 0x93, 0x69, 0xa0, 0xd5, 0xb6, 0xb4, 0xc6, 0x80, 0x13, 0x05, 0x54, + 0x05, 0x84, 0x12, 0xb5, 0x48, 0xdc, 0x10, 0xe0, 0xb6, 0xa2, 0x51, 0x55, 0x09, 0x5c, 0x21, 0x24, + 0xa4, 0x2a, 0x72, 0xed, 0xad, 0x6b, 0x51, 0x7b, 0x43, 0x76, 0x53, 0xea, 0x33, 0x2f, 0xc0, 0x23, + 0xc0, 0x9d, 0x07, 0xe9, 0xb1, 0x47, 0x4e, 0x11, 0x4a, 0x6f, 0x3c, 0x05, 0xda, 0x3f, 0x76, 0x0d, + 0x49, 0x2e, 0x56, 0x76, 0xe6, 0x9b, 0xdf, 0xee, 0x7e, 0x99, 0x59, 0xb0, 0x3c, 0x42, 0xa3, 0x2f, + 0x2e, 0x8d, 0xba, 0xe2, 0x73, 0xbe, 0xd9, 0x0d, 0x70, 0x8c, 0x69, 0x48, 0x3b, 0x83, 0x21, 0x61, + 0x04, 0x2d, 0xa7, 0xf9, 0x8e, 0xf8, 0x9c, 0x6f, 0x9a, 0xab, 0x01, 0x09, 0x88, 0x48, 0x76, 0xf9, + 0x2f, 0xa9, 0x33, 0xef, 0x4f, 0x71, 0x58, 0x32, 0xc0, 0x8a, 0x62, 0xde, 0x9d, 0xce, 0x5e, 0xc8, + 0x54, 0xeb, 0xbb, 0x0e, 0xf5, 0x37, 0x72, 0xcb, 0x43, 0xe6, 0x32, 0x8c, 0x9e, 0x43, 0x65, 0xe0, + 0x0e, 0xdd, 0x88, 0x1a, 0x5a, 0x53, 0x6b, 0x2f, 0x6e, 0x19, 0x9d, 0xff, 0x8f, 0xd0, 0x79, 0x2b, + 0xf2, 0x76, 0xf9, 0x72, 0xdc, 0x28, 0x38, 0x4a, 0x8d, 0x76, 0x41, 0xf7, 0x88, 0x8f, 0xa9, 0x51, + 0x6c, 0x96, 0xda, 0x8b, 0x5b, 0x6b, 0xd3, 0x65, 0xdb, 0xc4, 0xc7, 0xf6, 0x3a, 0x2f, 0xfa, 0x33, + 0x6e, 0x2c, 0x09, 0xf1, 0x53, 0x12, 0x85, 0x0c, 0x47, 0x03, 0x96, 0x38, 0xb2, 0x1a, 0xbd, 0x87, + 0x9a, 0x47, 0x62, 0x36, 0x74, 0x3d, 0x46, 0x8d, 0x92, 0x40, 0x99, 0xb3, 0x50, 0x52, 0x62, 0xdf, + 0x53, 0xb8, 0x95, 0xac, 0x28, 0x87, 0xbc, 0x21, 0x71, 0x2c, 0xc5, 0x9f, 0x47, 0x38, 0xf6, 0x30, + 0x35, 0xca, 0xf3, 0xb0, 0x87, 0x4a, 0x72, 0x83, 0xcd, 0x8a, 0xf2, 0xd8, 0x2c, 0x88, 0x8e, 0xa0, + 0x1a, 0xe0, 0xb8, 0x1f, 0xd1, 0x80, 0x1a, 0xba, 0xa0, 0x6e, 0x4c, 0x53, 0xf3, 0xf6, 0xf2, 0xc5, + 0x01, 0x0d, 0xa8, 0x6d, 0xaa, 0x1d, 0x50, 0x5a, 0x9f, 0xdb, 0x60, 0x21, 0x90, 0x22, 0xf3, 0x6b, + 0x11, 0x16, 0x54, 0x01, 0x7a, 0x09, 0x40, 0x19, 0x19, 0xe2, 0x3e, 0xf7, 0x49, 0xfd, 0x37, 0xd6, + 0xf4, 0x66, 0x07, 0x34, 0x38, 0xe4, 0x32, 0x6e, 0xf6, 0x5e, 0xc1, 0xa9, 0xd1, 0x74, 0x81, 0x8e, + 0x60, 0x35, 0x8c, 0x29, 0x73, 0x63, 0x16, 0xba, 0x8c, 0x63, 0xa4, 0x37, 0x46, 0x51, 0xa0, 0xda, + 0x33, 0x51, 0xbd, 0x9b, 0x82, 0xd4, 0xf2, 0xbd, 0x82, 0xb3, 0x12, 0x4e, 0x87, 0xd1, 0x3b, 0x58, + 0xc6, 0x17, 0xd8, 0x1b, 0xe5, 0xd1, 0x25, 0x81, 0x7e, 0x34, 0x13, 0xbd, 0x2b, 0xc5, 0x39, 0xec, + 0x12, 0xfe, 0x37, 0x64, 0xeb, 0x50, 0xa2, 0xa3, 0xa8, 0xf5, 0x43, 0x83, 0xb2, 0xb8, 0xc1, 0x43, + 0x58, 0xe0, 0x97, 0xef, 0x87, 0xbe, 0xb8, 0x7f, 0xd9, 0x86, 0xc9, 0xb8, 0x51, 0xe1, 0xa9, 0xde, + 0x8e, 0x53, 0xe1, 0xa9, 0x9e, 0x8f, 0x5e, 0xf0, 0x06, 0xe2, 0xa2, 0xf8, 0x84, 0xa8, 0xbb, 0x99, + 0xb3, 0x7b, 0xb1, 0x17, 0x9f, 0x10, 0xd5, 0xc4, 0x55, 0x4f, 0xad, 0xd1, 0x03, 0x00, 0x51, 0x7e, + 0x9c, 0x30, 0x4c, 0xc5, 0x05, 0xea, 0x8e, 0x00, 0xda, 0x3c, 0x80, 0xd6, 0xa0, 0x32, 0x08, 0xe3, + 0x18, 0xfb, 0x46, 0xb9, 0xa9, 0xb5, 0xab, 0x8e, 0x5a, 0xb5, 0x7e, 0x16, 0xa1, 0x9a, 0x59, 0xf1, + 0x18, 0x96, 0x53, 0x0b, 0xfa, 0xae, 0xef, 0x0f, 0x31, 0x95, 0xc3, 0x54, 0x73, 0x96, 0xd2, 0xf8, + 0x6b, 0x19, 0x46, 0x3d, 0xb8, 0x95, 0x49, 0x73, 0x27, 0xb6, 0xe6, 0xb7, 0x7c, 0xee, 0xd4, 0x75, + 0x2f, 0x17, 0x43, 0x3b, 0x70, 0x3b, 0x43, 0x51, 0xde, 0x6b, 0x6a, 0x7c, 0xd6, 0x67, 0xd8, 0x4f, + 0x7c, 0x7c, 0xa6, 0x20, 0xd9, 0xfe, 0x72, 0xfc, 0x7d, 0xb8, 0x93, 0x51, 0x84, 0x11, 0xa7, 0x21, + 0x6f, 0xa1, 0x44, 0x0d, 0xcd, 0x93, 0xf9, 0x07, 0x13, 0x1d, 0x27, 0xc5, 0xbb, 0x31, 0x1b, 0x26, + 0x8a, 0x9f, 0x4d, 0x66, 0x2e, 0xdf, 0xb2, 0xa1, 0x9a, 0xce, 0x1a, 0x6a, 0x42, 0x25, 0xf4, 0xfb, + 0x9f, 0x70, 0x22, 0x3c, 0xaa, 0xdb, 0xb5, 0xc9, 0xb8, 0xa1, 0xf7, 0x76, 0xf6, 0x71, 0xe2, 0xe8, + 0xa1, 0xbf, 0x8f, 0x13, 0xb4, 0x0a, 0xfa, 0xb9, 0x7b, 0x36, 0xc2, 0xc2, 0x9c, 0xb2, 0x23, 0x17, + 0xf6, 0xab, 0xcb, 0x89, 0xa5, 0x5d, 0x4d, 0x2c, 0xed, 0xf7, 0xc4, 0xd2, 0xbe, 0x5d, 0x5b, 0x85, + 0xab, 0x6b, 0xab, 0xf0, 0xeb, 0xda, 0x2a, 0x7c, 0xdc, 0x08, 0x42, 0x76, 0x3a, 0x3a, 0xee, 0x78, + 0x24, 0xea, 0x6e, 0x13, 0x1a, 0x7d, 0x48, 0x5f, 0x3e, 0xbf, 0x7b, 0x21, 0x5f, 0x40, 0xf1, 0x38, + 0x1e, 0x57, 0xc4, 0x13, 0xf8, 0xec, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0xb6, 0x2c, 0x20, + 0x85, 0x05, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -732,6 +742,20 @@ func (m *Contract) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.ContractCodeHistory) > 0 { + for iNdEx := len(m.ContractCodeHistory) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ContractCodeHistory[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } if len(m.ContractState) > 0 { for iNdEx := len(m.ContractState) - 1; iNdEx >= 0; iNdEx-- { { @@ -938,6 +962,12 @@ func (m *Contract) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.ContractCodeHistory) > 0 { + for _, e := range m.ContractCodeHistory { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } return n } @@ -1626,6 +1656,40 @@ func (m *Contract) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractCodeHistory", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractCodeHistory = append(m.ContractCodeHistory, ContractCodeHistoryEntry{}) + if err := m.ContractCodeHistory[len(m.ContractCodeHistory)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/wasm/types/genesis_test.go b/x/wasm/types/genesis_test.go index 3ef424e7e5..5ddcb20885 100644 --- a/x/wasm/types/genesis_test.go +++ b/x/wasm/types/genesis_test.go @@ -157,7 +157,7 @@ func TestContractValidateBasic(t *testing.T) { srcMutator: func(c *Contract) { c.ContractInfo.Created = &AbsoluteTxPosition{} }, - expError: true, + expError: false, }, "contract state invalid": { srcMutator: func(c *Contract) { @@ -165,6 +165,12 @@ func TestContractValidateBasic(t *testing.T) { }, expError: true, }, + "contract history invalid": { + srcMutator: func(c *Contract) { + c.ContractCodeHistory = []ContractCodeHistoryEntry{{}} + }, + expError: true, + }, } for msg, spec := range specs { t.Run(msg, func(t *testing.T) { diff --git a/x/wasm/types/query.pb.gw.go b/x/wasm/types/query.pb.gw.go index 527cac4e74..4bffee3d7c 100644 --- a/x/wasm/types/query.pb.gw.go +++ b/x/wasm/types/query.pb.gw.go @@ -868,6 +868,8 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv mux.Handle("GET", pattern_Query_ContractsByCreator_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) if err != nil { @@ -875,6 +877,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } resp, md, err := local_request_Query_ContractsByCreator_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1155,9 +1158,9 @@ var ( pattern_Query_PinnedCodes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmwasm", "wasm", "v1", "codes", "pinned"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmwasm", "wasm", "v1", "codes", "params"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmwasm", "wasm", "v1", "codes", "params"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ContractsByCreator_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmwasm", "wasm", "v1", "contracts", "creator", "creator_address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ContractsByCreator_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmwasm", "wasm", "v1", "contracts", "creator", "creator_address"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/wasm/types/test_fixtures.go b/x/wasm/types/test_fixtures.go index de07f175de..22da3520d6 100644 --- a/x/wasm/types/test_fixtures.go +++ b/x/wasm/types/test_fixtures.go @@ -87,9 +87,12 @@ func ContractFixture(mutators ...func(*Contract)) Contract { fixture := Contract{ ContractAddress: anyAddress, - ContractInfo: ContractInfoFixture(OnlyGenesisFields), + ContractInfo: ContractInfoFixture(RandCreatedFields), ContractState: []Model{{Key: []byte("anyKey"), Value: []byte("anyValue")}}, } + fixture.ContractCodeHistory = []ContractCodeHistoryEntry{ContractCodeHistoryEntryFixture(func(e *ContractCodeHistoryEntry) { + e.Updated = fixture.ContractInfo.Created + })} for _, m := range mutators { m(&fixture) @@ -101,6 +104,10 @@ func OnlyGenesisFields(info *ContractInfo) { info.Created = nil } +func RandCreatedFields(info *ContractInfo) { + info.Created = &AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()} +} + func ContractInfoFixture(mutators ...func(*ContractInfo)) ContractInfo { const anyAddress = "cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs2m6sx4" @@ -117,6 +124,20 @@ func ContractInfoFixture(mutators ...func(*ContractInfo)) ContractInfo { return fixture } +// ContractCodeHistoryEntryFixture test fixture +func ContractCodeHistoryEntryFixture(mutators ...func(*ContractCodeHistoryEntry)) ContractCodeHistoryEntry { + fixture := ContractCodeHistoryEntry{ + Operation: ContractCodeHistoryOperationTypeInit, + CodeID: 1, + Updated: ContractInfoFixture().Created, + Msg: []byte(`{"foo":"bar"}`), + } + for _, m := range mutators { + m(&fixture) + } + return fixture +} + func WithSHA256CodeHash(wasmCode []byte) func(info *CodeInfo) { return func(info *CodeInfo) { codeHash := sha256.Sum256(wasmCode) diff --git a/x/wasm/types/types.go b/x/wasm/types/types.go index 6453c5f1d0..4a0e198f03 100644 --- a/x/wasm/types/types.go +++ b/x/wasm/types/types.go @@ -171,16 +171,6 @@ func (c *ContractInfo) AddMigration(ctx sdk.Context, codeID uint64, msg []byte) return h } -// ResetFromGenesis resets contracts timestamp and history. -func (c *ContractInfo) ResetFromGenesis(ctx sdk.Context) ContractCodeHistoryEntry { - c.Created = NewAbsoluteTxPosition(ctx) - return ContractCodeHistoryEntry{ - Operation: ContractCodeHistoryOperationTypeGenesis, - CodeID: c.CodeID, - Updated: c.Created, - } -} - // AdminAddr convert into sdk.AccAddress or nil when not set func (c *ContractInfo) AdminAddr() sdk.AccAddress { if c.Admin == "" { @@ -253,6 +243,27 @@ func (a *AbsoluteTxPosition) Bytes() []byte { return r } +// ValidateBasic syntax checks +func (c ContractCodeHistoryEntry) ValidateBasic() error { + var found bool + for _, v := range AllCodeHistoryTypes { + if c.Operation == v { + found = true + break + } + } + if !found { + return ErrInvalid.Wrap("operation") + } + if c.CodeID == 0 { + return ErrEmpty.Wrap("code id") + } + if c.Updated == nil { + return ErrEmpty.Wrap("updated") + } + return sdkerrors.Wrap(c.Msg.ValidateBasic(), "msg") +} + // NewEnv initializes the environment for a contract instance func NewEnv(ctx sdk.Context, contractAddr sdk.AccAddress) wasmvmtypes.Env { // safety checks before casting below diff --git a/x/wasm/types/types.pb.go b/x/wasm/types/types.pb.go index 7b41c98394..d53952253e 100644 --- a/x/wasm/types/types.pb.go +++ b/x/wasm/types/types.pb.go @@ -296,8 +296,6 @@ type ContractInfo struct { // Label is optional metadata to be stored with a contract instance. Label string `protobuf:"bytes,4,opt,name=label,proto3" json:"label,omitempty"` // Created Tx position when the contract was instantiated. - // This data should kept internal and not be exposed via query results. Just - // use for sorting Created *AbsoluteTxPosition `protobuf:"bytes,5,opt,name=created,proto3" json:"created,omitempty"` IBCPortID string `protobuf:"bytes,6,opt,name=ibc_port_id,json=ibcPortId,proto3" json:"ibc_port_id,omitempty"` // Extension is an extension point to store custom metadata within the diff --git a/x/wasm/types/types_test.go b/x/wasm/types/types_test.go index be270ddeb3..25df828023 100644 --- a/x/wasm/types/types_test.go +++ b/x/wasm/types/types_test.go @@ -706,3 +706,42 @@ func TestAccessTypeSubset(t *testing.T) { }) } } + +func TestContractCodeHistoryEntryValidation(t *testing.T) { + specs := map[string]struct { + src ContractCodeHistoryEntry + expErr bool + }{ + "all good": { + src: ContractCodeHistoryEntryFixture(), + }, + "unknown operation": { + src: ContractCodeHistoryEntryFixture(func(entry *ContractCodeHistoryEntry) { + entry.Operation = 0 + }), + expErr: true, + }, + "empty code id": { + src: ContractCodeHistoryEntryFixture(func(entry *ContractCodeHistoryEntry) { + entry.CodeID = 0 + }), + expErr: true, + }, + "empty updated": { + src: ContractCodeHistoryEntryFixture(func(entry *ContractCodeHistoryEntry) { + entry.Updated = nil + }), + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotErr := spec.src.ValidateBasic() + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + }) + } +}