mirror of https://github.com/certusone/wasmd.git
Store code history for contract
This commit is contained in:
parent
774f6d7876
commit
f8dbfd12f0
|
@ -43,7 +43,7 @@ var (
|
|||
GetContractAddressKey = types.GetContractAddressKey
|
||||
GetContractStorePrefixKey = types.GetContractStorePrefixKey
|
||||
NewCodeInfo = types.NewCodeInfo
|
||||
NewCreatedAt = types.NewCreatedAt
|
||||
NewCreatedAt = types.NewAbsoluteTxPosition
|
||||
NewContractInfo = types.NewContractInfo
|
||||
NewEnv = types.NewEnv
|
||||
NewWasmCoins = types.NewWasmCoins
|
||||
|
|
|
@ -2,6 +2,7 @@ package keeper
|
|||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
|
@ -29,8 +30,8 @@ func TestGenesisExportImport(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// store some test data
|
||||
f := fuzz.New().Funcs(FuzzAddr, FuzzAbsoluteTxPosition, FuzzContractInfo, FuzzStateModel, FuzzAccessType, FuzzAccessConfig)
|
||||
for i := 0; i < 25; i++ {
|
||||
f := fuzz.New().Funcs(ModelFuzzers...)
|
||||
for i := 0; i < 1; i++ {
|
||||
var (
|
||||
codeInfo types.CodeInfo
|
||||
contract types.ContractInfo
|
||||
|
@ -39,7 +40,6 @@ func TestGenesisExportImport(t *testing.T) {
|
|||
f.Fuzz(&codeInfo)
|
||||
f.Fuzz(&contract)
|
||||
f.Fuzz(&stateModels)
|
||||
|
||||
codeID, err := srcKeeper.Create(srcCtx, codeInfo.Creator, wasmCode, codeInfo.Source, codeInfo.Builder, &codeInfo.InstantiateConfig)
|
||||
require.NoError(t, err)
|
||||
contract.CodeID = codeID
|
||||
|
@ -52,24 +52,28 @@ func TestGenesisExportImport(t *testing.T) {
|
|||
srcKeeper.setParams(srcCtx, wasmParams)
|
||||
|
||||
// export
|
||||
genesisState := ExportGenesis(srcCtx, srcKeeper)
|
||||
|
||||
exportedState := ExportGenesis(srcCtx, srcKeeper)
|
||||
// order should not matter
|
||||
rand.Shuffle(len(genesisState.Codes), func(i, j int) {
|
||||
genesisState.Codes[i], genesisState.Codes[j] = genesisState.Codes[j], genesisState.Codes[i]
|
||||
rand.Shuffle(len(exportedState.Codes), func(i, j int) {
|
||||
exportedState.Codes[i], exportedState.Codes[j] = exportedState.Codes[j], exportedState.Codes[i]
|
||||
})
|
||||
rand.Shuffle(len(genesisState.Contracts), func(i, j int) {
|
||||
genesisState.Contracts[i], genesisState.Contracts[j] = genesisState.Contracts[j], genesisState.Contracts[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(genesisState.Sequences), func(i, j int) {
|
||||
genesisState.Sequences[i], genesisState.Sequences[j] = genesisState.Sequences[j], genesisState.Sequences[i]
|
||||
rand.Shuffle(len(exportedState.Sequences), func(i, j int) {
|
||||
exportedState.Sequences[i], exportedState.Sequences[j] = exportedState.Sequences[j], exportedState.Sequences[i]
|
||||
})
|
||||
exportedGenesis, err := json.Marshal(exportedState)
|
||||
require.NoError(t, err)
|
||||
|
||||
// re-import
|
||||
dstKeeper, dstCtx, dstStoreKeys, dstCleanup := setupKeeper(t)
|
||||
defer dstCleanup()
|
||||
|
||||
InitGenesis(dstCtx, dstKeeper, genesisState)
|
||||
var importState wasmTypes.GenesisState
|
||||
err = json.Unmarshal(exportedGenesis, &importState)
|
||||
require.NoError(t, err)
|
||||
InitGenesis(dstCtx, dstKeeper, importState)
|
||||
|
||||
// compare whole DB
|
||||
for j := range srcStoreKeys {
|
||||
|
|
|
@ -240,7 +240,7 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A
|
|||
}
|
||||
|
||||
// persist instance
|
||||
createdAt := types.NewCreatedAt(ctx)
|
||||
createdAt := types.NewAbsoluteTxPosition(ctx)
|
||||
instance := types.NewContractInfo(codeID, creator, admin, initMsg, label, createdAt)
|
||||
store.Set(types.GetContractAddressKey(contractAddress), k.cdc.MustMarshalBinaryBare(instance))
|
||||
|
||||
|
@ -340,7 +340,7 @@ func (k Keeper) migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller
|
|||
events := types.ParseEvents(res.Log, contractAddress)
|
||||
ctx.EventManager().EmitEvents(events)
|
||||
|
||||
contractInfo.UpdateCodeID(ctx, newCodeID)
|
||||
contractInfo.AddMigration(ctx, newCodeID, msg)
|
||||
k.setContractInfo(ctx, contractAddress, contractInfo)
|
||||
|
||||
if err := k.dispatchMessages(ctx, contractAddress, res.Messages); err != nil {
|
||||
|
|
|
@ -306,15 +306,23 @@ func TestInstantiate(t *testing.T) {
|
|||
require.Equal(t, "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", addr.String())
|
||||
|
||||
gasAfter := ctx.GasMeter().GasConsumed()
|
||||
require.Equal(t, uint64(0x1155d), gasAfter-gasBefore)
|
||||
require.Equal(t, uint64(0x11740), gasAfter-gasBefore)
|
||||
|
||||
// ensure it is stored properly
|
||||
info := keeper.GetContractInfo(ctx, addr)
|
||||
require.NotNil(t, info)
|
||||
assert.Equal(t, info.Creator, creator)
|
||||
assert.Equal(t, info.CodeID, contractID)
|
||||
assert.Equal(t, info.InitMsg, json.RawMessage(initMsgBz))
|
||||
assert.Equal(t, info.Label, "demo contract 1")
|
||||
|
||||
exp := []types.ContractCodeHistoryEntry{{
|
||||
Operation: types.InitContractCodeHistoryType,
|
||||
CodeID: contractID,
|
||||
Updated: types.NewAbsoluteTxPosition(ctx),
|
||||
Msg: json.RawMessage(initMsgBz),
|
||||
}}
|
||||
assert.Equal(t, exp, info.ContractCodeHistory)
|
||||
|
||||
}
|
||||
|
||||
func TestInstantiateWithDeposit(t *testing.T) {
|
||||
|
@ -527,7 +535,7 @@ func TestExecute(t *testing.T) {
|
|||
|
||||
// make sure gas is properly deducted from ctx
|
||||
gasAfter := ctx.GasMeter().GasConsumed()
|
||||
require.Equal(t, uint64(0x11c16), gasAfter-gasBefore)
|
||||
require.Equal(t, uint64(0x11c2e), gasAfter-gasBefore)
|
||||
|
||||
// ensure bob now exists and got both payments released
|
||||
bobAcct = accKeeper.GetAccount(ctx, bob)
|
||||
|
@ -772,11 +780,11 @@ func TestMigrate(t *testing.T) {
|
|||
wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
|
||||
require.NoError(t, err)
|
||||
|
||||
originalContractID, err := keeper.Create(ctx, creator, wasmCode, "", "", nil)
|
||||
originalCodeID, err := keeper.Create(ctx, creator, wasmCode, "", "", nil)
|
||||
require.NoError(t, err)
|
||||
newContractID, err := keeper.Create(ctx, creator, wasmCode, "", "", nil)
|
||||
newCodeID, err := keeper.Create(ctx, creator, wasmCode, "", "", nil)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, originalContractID, newContractID)
|
||||
require.NotEqual(t, originalCodeID, newCodeID)
|
||||
|
||||
_, _, anyAddr := keyPubAddr()
|
||||
_, _, newVerifierAddr := keyPubAddr()
|
||||
|
@ -805,33 +813,33 @@ func TestMigrate(t *testing.T) {
|
|||
"all good with same code id": {
|
||||
admin: creator,
|
||||
caller: creator,
|
||||
codeID: originalContractID,
|
||||
codeID: originalCodeID,
|
||||
migrateMsg: migMsgBz,
|
||||
expVerifier: newVerifierAddr,
|
||||
},
|
||||
"all good with different code id": {
|
||||
admin: creator,
|
||||
caller: creator,
|
||||
codeID: newContractID,
|
||||
codeID: newCodeID,
|
||||
migrateMsg: migMsgBz,
|
||||
expVerifier: newVerifierAddr,
|
||||
},
|
||||
"all good with admin set": {
|
||||
admin: fred,
|
||||
caller: fred,
|
||||
codeID: newContractID,
|
||||
codeID: newCodeID,
|
||||
migrateMsg: migMsgBz,
|
||||
expVerifier: newVerifierAddr,
|
||||
},
|
||||
"prevent migration when admin was not set on instantiate": {
|
||||
caller: creator,
|
||||
codeID: originalContractID,
|
||||
codeID: originalCodeID,
|
||||
expErr: sdkerrors.ErrUnauthorized,
|
||||
},
|
||||
"prevent migration when not sent by admin": {
|
||||
caller: creator,
|
||||
admin: fred,
|
||||
codeID: originalContractID,
|
||||
codeID: originalCodeID,
|
||||
expErr: sdkerrors.ErrUnauthorized,
|
||||
},
|
||||
"fail with non existing code id": {
|
||||
|
@ -844,20 +852,20 @@ func TestMigrate(t *testing.T) {
|
|||
admin: creator,
|
||||
caller: creator,
|
||||
overrideContractAddr: anyAddr,
|
||||
codeID: originalContractID,
|
||||
codeID: originalCodeID,
|
||||
expErr: sdkerrors.ErrInvalidRequest,
|
||||
},
|
||||
"fail in contract with invalid migrate msg": {
|
||||
admin: creator,
|
||||
caller: creator,
|
||||
codeID: originalContractID,
|
||||
codeID: originalCodeID,
|
||||
migrateMsg: bytes.Repeat([]byte{0x1}, 7),
|
||||
expErr: types.ErrMigrationFailed,
|
||||
},
|
||||
"fail in contract without migrate msg": {
|
||||
admin: creator,
|
||||
caller: creator,
|
||||
codeID: originalContractID,
|
||||
codeID: originalCodeID,
|
||||
expErr: types.ErrMigrationFailed,
|
||||
},
|
||||
}
|
||||
|
@ -865,7 +873,7 @@ func TestMigrate(t *testing.T) {
|
|||
for msg, spec := range specs {
|
||||
t.Run(msg, func(t *testing.T) {
|
||||
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
|
||||
addr, err := keeper.Instantiate(ctx, originalContractID, creator, spec.admin, initMsgBz, "demo contract", nil)
|
||||
addr, err := keeper.Instantiate(ctx, originalCodeID, creator, spec.admin, initMsgBz, "demo contract", nil)
|
||||
require.NoError(t, err)
|
||||
if spec.overrideContractAddr != nil {
|
||||
addr = spec.overrideContractAddr
|
||||
|
@ -877,8 +885,19 @@ func TestMigrate(t *testing.T) {
|
|||
}
|
||||
cInfo := keeper.GetContractInfo(ctx, addr)
|
||||
assert.Equal(t, spec.codeID, cInfo.CodeID)
|
||||
assert.Equal(t, originalContractID, cInfo.PreviousCodeID)
|
||||
assert.Equal(t, types.NewCreatedAt(ctx), cInfo.LastUpdated)
|
||||
|
||||
expHistory := []types.ContractCodeHistoryEntry{{
|
||||
Operation: types.InitContractCodeHistoryType,
|
||||
CodeID: originalCodeID,
|
||||
Updated: types.NewAbsoluteTxPosition(ctx),
|
||||
Msg: initMsgBz,
|
||||
}, {
|
||||
Operation: types.MigrateContractCodeHistoryType,
|
||||
CodeID: spec.codeID,
|
||||
Updated: types.NewAbsoluteTxPosition(ctx),
|
||||
Msg: spec.migrateMsg,
|
||||
}}
|
||||
assert.Equal(t, expHistory, cInfo.ContractCodeHistory)
|
||||
|
||||
m := keeper.QueryRaw(ctx, addr, []byte("config"))
|
||||
require.Len(t, m, 1)
|
||||
|
|
|
@ -104,7 +104,14 @@ func TestInstantiateProposal(t *testing.T) {
|
|||
assert.Equal(t, oneAddress, cInfo.Creator)
|
||||
assert.Equal(t, otherAddress, cInfo.Admin)
|
||||
assert.Equal(t, "testing", cInfo.Label)
|
||||
assert.Equal(t, src.InitMsg, cInfo.InitMsg)
|
||||
expHistory := []types.ContractCodeHistoryEntry{{
|
||||
Operation: types.InitContractCodeHistoryType,
|
||||
CodeID: src.Code,
|
||||
Updated: types.NewAbsoluteTxPosition(ctx),
|
||||
Msg: src.InitMsg,
|
||||
}}
|
||||
assert.Equal(t, expHistory, cInfo.ContractCodeHistory)
|
||||
|
||||
}
|
||||
|
||||
func TestMigrateProposal(t *testing.T) {
|
||||
|
@ -169,9 +176,21 @@ func TestMigrateProposal(t *testing.T) {
|
|||
cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr)
|
||||
require.NotNil(t, cInfo)
|
||||
assert.Equal(t, uint64(2), cInfo.CodeID)
|
||||
assert.Equal(t, uint64(1), cInfo.PreviousCodeID)
|
||||
assert.Equal(t, anyAddress, cInfo.Admin)
|
||||
assert.Equal(t, "testing", cInfo.Label)
|
||||
expHistory := []types.ContractCodeHistoryEntry{{
|
||||
// Operation: types.InitContractCodeHistoryType,
|
||||
// CodeID: 1,
|
||||
// Updated: types.NewAbsoluteTxPosition(ctx),
|
||||
// Msg: initMsgBz,
|
||||
//}, {
|
||||
Operation: types.MigrateContractCodeHistoryType,
|
||||
CodeID: src.Code,
|
||||
Updated: types.NewAbsoluteTxPosition(ctx),
|
||||
Msg: src.MigrateMsg,
|
||||
}}
|
||||
assert.Equal(t, expHistory, cInfo.ContractCodeHistory)
|
||||
|
||||
}
|
||||
|
||||
func TestAdminProposals(t *testing.T) {
|
||||
|
|
|
@ -69,11 +69,7 @@ func queryContractInfo(ctx sdk.Context, bech string, req abci.RequestQuery, keep
|
|||
if info == nil {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
// redact the Created field (just used for sorting, not part of public API)
|
||||
info.Created = nil
|
||||
info.LastUpdated = nil
|
||||
info.PreviousCodeID = 0
|
||||
|
||||
redact(info)
|
||||
infoWithAddress := ContractInfoWithAddress{
|
||||
Address: addr,
|
||||
ContractInfo: info,
|
||||
|
@ -85,6 +81,15 @@ func queryContractInfo(ctx sdk.Context, bech string, req abci.RequestQuery, keep
|
|||
return bz, nil
|
||||
}
|
||||
|
||||
// redact clears all fields not in the public api
|
||||
func redact(info *types.ContractInfo) {
|
||||
info.Created = nil
|
||||
for i := range info.ContractCodeHistory {
|
||||
info.ContractCodeHistory[i].Updated = nil
|
||||
info.ContractCodeHistory[i].Msg = nil
|
||||
}
|
||||
}
|
||||
|
||||
func queryContractListByCode(ctx sdk.Context, codeIDstr string, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
|
||||
codeID, err := strconv.ParseUint(codeIDstr, 10, 64)
|
||||
if err != nil {
|
||||
|
@ -94,8 +99,6 @@ func queryContractListByCode(ctx sdk.Context, codeIDstr string, req abci.Request
|
|||
var contracts []ContractInfoWithAddress
|
||||
keeper.ListContractInfo(ctx, func(addr sdk.AccAddress, info types.ContractInfo) bool {
|
||||
if info.CodeID == codeID {
|
||||
// remove init message on list
|
||||
info.InitMsg = nil
|
||||
// and add the address
|
||||
infoWithAddress := ContractInfoWithAddress{
|
||||
Address: addr,
|
||||
|
@ -112,7 +115,7 @@ func queryContractListByCode(ctx sdk.Context, codeIDstr string, req abci.Request
|
|||
})
|
||||
// and remove that info for the final json (yes, the json:"-" tag doesn't work)
|
||||
for i := range contracts {
|
||||
contracts[i].Created = nil
|
||||
redact(contracts[i].ContractInfo)
|
||||
}
|
||||
|
||||
bz, err := json.MarshalIndent(contracts, "", " ")
|
||||
|
|
|
@ -208,7 +208,10 @@ func TestListContractByCodeOrdering(t *testing.T) {
|
|||
assert.Equal(t, fmt.Sprintf("contract %d", i), contract.Label)
|
||||
assert.NotEmpty(t, contract.Address)
|
||||
// ensure these are not shown
|
||||
assert.Nil(t, contract.InitMsg)
|
||||
assert.Nil(t, contract.Created)
|
||||
for _, entry := range contract.ContractCodeHistory {
|
||||
assert.Nil(t, entry.Updated)
|
||||
assert.Nil(t, entry.Msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
fuzz "github.com/google/gofuzz"
|
||||
tmBytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
)
|
||||
|
||||
var ModelFuzzers = []interface{}{FuzzAddr, FuzzAbsoluteTxPosition, FuzzContractInfo, FuzzStateModel, FuzzAccessType, FuzzAccessConfig, FuzzContractCodeHistory}
|
||||
|
||||
func FuzzAddr(m *sdk.AccAddress, c fuzz.Continue) {
|
||||
*m = make([]byte, 20)
|
||||
c.Read(*m)
|
||||
|
@ -18,16 +22,29 @@ func FuzzAbsoluteTxPosition(m *types.AbsoluteTxPosition, c fuzz.Continue) {
|
|||
}
|
||||
|
||||
func FuzzContractInfo(m *types.ContractInfo, c fuzz.Continue) {
|
||||
const maxSize = 1024
|
||||
m.CodeID = c.RandUint64()
|
||||
FuzzAddr(&m.Creator, c)
|
||||
FuzzAddr(&m.Admin, c)
|
||||
m.Label = c.RandString()
|
||||
m.InitMsg = make([]byte, c.RandUint64()%maxSize)
|
||||
c.Read(m.InitMsg)
|
||||
c.Fuzz(&m.Created)
|
||||
c.Fuzz(&m.LastUpdated)
|
||||
m.PreviousCodeID = c.RandUint64()
|
||||
historyElements := c.Int() % 128 // 128 should be enough for tests
|
||||
m.ContractCodeHistory = make([]types.ContractCodeHistoryEntry, historyElements)
|
||||
for i := range m.ContractCodeHistory {
|
||||
c.Fuzz(&m.ContractCodeHistory[i])
|
||||
}
|
||||
}
|
||||
|
||||
func FuzzContractCodeHistory(m *types.ContractCodeHistoryEntry, c fuzz.Continue) {
|
||||
const maxMsgSize = 128
|
||||
m.CodeID = c.RandUint64()
|
||||
msg := make([]byte, c.RandUint64()%maxMsgSize)
|
||||
c.Read(msg)
|
||||
var err error
|
||||
if m.Msg, err = json.Marshal(msg); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c.Fuzz(&m.Updated)
|
||||
m.Operation = types.AllCodeHistoryTypes[c.Int()%len(types.AllCodeHistoryTypes)]
|
||||
}
|
||||
|
||||
func FuzzStateModel(m *types.Model, c fuzz.Continue) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package types
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sort"
|
||||
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
tmBytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
|
@ -64,24 +65,46 @@ func NewCodeInfo(codeHash []byte, creator sdk.AccAddress, source string, builder
|
|||
}
|
||||
}
|
||||
|
||||
// ContractInfo stores a WASM contract instance
|
||||
type ContractInfo struct {
|
||||
CodeID uint64 `json:"code_id"`
|
||||
Creator sdk.AccAddress `json:"creator"`
|
||||
Admin sdk.AccAddress `json:"admin,omitempty"`
|
||||
Label string `json:"label"`
|
||||
InitMsg json.RawMessage `json:"init_msg,omitempty"`
|
||||
// never show this in query results, just use for sorting
|
||||
// (Note: when using json tag "-" amino refused to serialize it...)
|
||||
Created *AbsoluteTxPosition `json:"created,omitempty"`
|
||||
LastUpdated *AbsoluteTxPosition `json:"last_updated,omitempty"`
|
||||
PreviousCodeID uint64 `json:"previous_code_id,omitempty"`
|
||||
type ContractCodeHistoryOperationType string
|
||||
|
||||
const (
|
||||
InitContractCodeHistoryType ContractCodeHistoryOperationType = "Init"
|
||||
MigrateContractCodeHistoryType ContractCodeHistoryOperationType = "Migrate"
|
||||
)
|
||||
|
||||
var AllCodeHistoryTypes = []ContractCodeHistoryOperationType{InitContractCodeHistoryType, MigrateContractCodeHistoryType}
|
||||
|
||||
type ContractCodeHistoryEntry struct {
|
||||
Operation ContractCodeHistoryOperationType `json:"operation"`
|
||||
CodeID uint64 `json:"code_id"`
|
||||
Updated *AbsoluteTxPosition `json:"updated,omitempty"`
|
||||
Msg json.RawMessage `json:"msg,omitempty"`
|
||||
}
|
||||
|
||||
func (c *ContractInfo) UpdateCodeID(ctx sdk.Context, newCodeID uint64) {
|
||||
c.PreviousCodeID = c.CodeID
|
||||
c.CodeID = newCodeID
|
||||
c.LastUpdated = NewCreatedAt(ctx)
|
||||
// ContractInfo stores a WASM contract instance
|
||||
type ContractInfo struct {
|
||||
CodeID uint64 `json:"code_id"`
|
||||
Creator sdk.AccAddress `json:"creator"`
|
||||
Admin sdk.AccAddress `json:"admin,omitempty"`
|
||||
Label string `json:"label"`
|
||||
// never show this in query results, just use for sorting
|
||||
// (Note: when using json tag "-" amino refused to serialize it...)
|
||||
Created *AbsoluteTxPosition `json:"created,omitempty"`
|
||||
ContractCodeHistory []ContractCodeHistoryEntry `json:"contract_code_history"`
|
||||
}
|
||||
|
||||
func (c *ContractInfo) AddMigration(ctx sdk.Context, codeID uint64, msg []byte) {
|
||||
h := ContractCodeHistoryEntry{
|
||||
Operation: MigrateContractCodeHistoryType,
|
||||
CodeID: codeID,
|
||||
Updated: NewAbsoluteTxPosition(ctx),
|
||||
Msg: msg,
|
||||
}
|
||||
c.ContractCodeHistory = append(c.ContractCodeHistory, h)
|
||||
sort.Slice(c.ContractCodeHistory, func(i, j int) bool {
|
||||
return c.ContractCodeHistory[i].Updated.LessThan(c.ContractCodeHistory[j].Updated)
|
||||
})
|
||||
c.CodeID = codeID
|
||||
}
|
||||
|
||||
func (c *ContractInfo) ValidateBasic() error {
|
||||
|
@ -105,9 +128,7 @@ func (c *ContractInfo) ValidateBasic() error {
|
|||
if err := c.Created.ValidateBasic(); err != nil {
|
||||
return sdkerrors.Wrap(err, "created")
|
||||
}
|
||||
if err := c.LastUpdated.ValidateBasic(); err != nil {
|
||||
return sdkerrors.Wrap(err, "last updated")
|
||||
}
|
||||
// TODO: validate history
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -140,8 +161,8 @@ func (a *AbsoluteTxPosition) ValidateBasic() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// NewCreatedAt gets a timestamp from the context
|
||||
func NewCreatedAt(ctx sdk.Context) *AbsoluteTxPosition {
|
||||
// NewAbsoluteTxPosition gets a timestamp from the context
|
||||
func NewAbsoluteTxPosition(ctx sdk.Context) *AbsoluteTxPosition {
|
||||
// we must safely handle nil gas meters
|
||||
var index uint64
|
||||
meter := ctx.BlockGasMeter()
|
||||
|
@ -160,9 +181,14 @@ func NewContractInfo(codeID uint64, creator, admin sdk.AccAddress, initMsg []byt
|
|||
CodeID: codeID,
|
||||
Creator: creator,
|
||||
Admin: admin,
|
||||
InitMsg: initMsg,
|
||||
Label: label,
|
||||
Created: createdAt,
|
||||
ContractCodeHistory: []ContractCodeHistoryEntry{{
|
||||
Operation: InitContractCodeHistoryType,
|
||||
CodeID: codeID,
|
||||
Updated: createdAt,
|
||||
Msg: initMsg,
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,9 +42,6 @@ func TestContractInfoValidateBasic(t *testing.T) {
|
|||
srcMutator: func(c *ContractInfo) { c.Label = strings.Repeat("a", MaxLabelSize+1) },
|
||||
expError: true,
|
||||
},
|
||||
"init msg empty": {
|
||||
srcMutator: func(c *ContractInfo) { c.InitMsg = nil },
|
||||
},
|
||||
"created nil": {
|
||||
srcMutator: func(c *ContractInfo) { c.Created = nil },
|
||||
expError: true,
|
||||
|
@ -53,12 +50,6 @@ func TestContractInfoValidateBasic(t *testing.T) {
|
|||
srcMutator: func(c *ContractInfo) { c.Created = &AbsoluteTxPosition{BlockHeight: -1} },
|
||||
expError: true,
|
||||
},
|
||||
"last updated nil": {
|
||||
srcMutator: func(c *ContractInfo) { c.LastUpdated = nil },
|
||||
},
|
||||
"previous code id empty": {
|
||||
srcMutator: func(c *ContractInfo) { c.PreviousCodeID = 0 },
|
||||
},
|
||||
}
|
||||
for msg, spec := range specs {
|
||||
t.Run(msg, func(t *testing.T) {
|
||||
|
|
Loading…
Reference in New Issue