mirror of https://github.com/certusone/wasmd.git
Merge pull request #168 from CosmWasm/genesis_io_codeids
Genesis code import not position agnostic
This commit is contained in:
commit
3f62e8a001
|
@ -1,8 +1,6 @@
|
||||||
package keeper
|
package keeper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
|
|
||||||
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
|
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
|
@ -14,23 +12,24 @@ import (
|
||||||
//
|
//
|
||||||
// CONTRACT: all types of accounts must have been already initialized/created
|
// CONTRACT: all types of accounts must have been already initialized/created
|
||||||
func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) error {
|
func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) error {
|
||||||
|
var maxCodeID uint64
|
||||||
for i, code := range data.Codes {
|
for i, code := range data.Codes {
|
||||||
newId, err := keeper.Create(ctx, code.CodeInfo.Creator, code.CodesBytes, code.CodeInfo.Source, code.CodeInfo.Builder)
|
err := keeper.importCode(ctx, code.CodeID, code.CodeInfo, code.CodesBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdkerrors.Wrapf(err, "code number %d", i)
|
return sdkerrors.Wrapf(err, "code %d with id: %d", i, code.CodeID)
|
||||||
|
|
||||||
}
|
}
|
||||||
newInfo := keeper.GetCodeInfo(ctx, newId)
|
if code.CodeID > maxCodeID {
|
||||||
if !bytes.Equal(code.CodeInfo.CodeHash, newInfo.CodeHash) {
|
maxCodeID = code.CodeID
|
||||||
return sdkerrors.Wrap(types.ErrInvalid, "code hashes not same")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var maxContractID int
|
||||||
for i, contract := range data.Contracts {
|
for i, contract := range data.Contracts {
|
||||||
err := keeper.importContract(ctx, contract.ContractAddress, &contract.ContractInfo, contract.ContractState)
|
err := keeper.importContract(ctx, contract.ContractAddress, &contract.ContractInfo, contract.ContractState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdkerrors.Wrapf(err, "contract number %d", i)
|
return sdkerrors.Wrapf(err, "contract number %d", i)
|
||||||
}
|
}
|
||||||
|
maxContractID = i + 1 // not ideal but max(contractID) is not persisted otherwise
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, seq := range data.Sequences {
|
for i, seq := range data.Sequences {
|
||||||
|
@ -39,6 +38,15 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) error
|
||||||
return sdkerrors.Wrapf(err, "sequence number %d", i)
|
return sdkerrors.Wrapf(err, "sequence number %d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sanity check seq values
|
||||||
|
if keeper.peekAutoIncrementID(ctx, types.KeyLastCodeID) <= maxCodeID {
|
||||||
|
return sdkerrors.Wrapf(types.ErrInvalid, "seq %s must be greater %d ", string(types.KeyLastCodeID), maxCodeID)
|
||||||
|
}
|
||||||
|
if keeper.peekAutoIncrementID(ctx, types.KeyLastInstanceID) <= uint64(maxContractID) {
|
||||||
|
return sdkerrors.Wrapf(types.ErrInvalid, "seq %s must be greater %d ", string(types.KeyLastInstanceID), maxContractID)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,11 +56,15 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
|
||||||
|
|
||||||
maxCodeID := keeper.GetNextCodeID(ctx)
|
maxCodeID := keeper.GetNextCodeID(ctx)
|
||||||
for i := uint64(1); i < maxCodeID; i++ {
|
for i := uint64(1); i < maxCodeID; i++ {
|
||||||
|
if !keeper.containsCodeInfo(ctx, i) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
bytecode, err := keeper.GetByteCode(ctx, i)
|
bytecode, err := keeper.GetByteCode(ctx, i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
genState.Codes = append(genState.Codes, types.Code{
|
genState.Codes = append(genState.Codes, types.Code{
|
||||||
|
CodeID: i,
|
||||||
CodeInfo: *keeper.GetCodeInfo(ctx, i),
|
CodeInfo: *keeper.GetCodeInfo(ctx, i),
|
||||||
CodesBytes: bytecode,
|
CodesBytes: bytecode,
|
||||||
})
|
})
|
||||||
|
@ -78,8 +90,7 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
// types.KeyLastCodeID is updated via keeper create
|
for _, k := range [][]byte{types.KeyLastCodeID, types.KeyLastInstanceID} {
|
||||||
for _, k := range [][]byte{types.KeyLastInstanceID} {
|
|
||||||
genState.Sequences = append(genState.Sequences, types.Sequence{
|
genState.Sequences = append(genState.Sequences, types.Sequence{
|
||||||
IDKey: k,
|
IDKey: k,
|
||||||
Value: keeper.peekAutoIncrementID(ctx, k),
|
Value: keeper.peekAutoIncrementID(ctx, k),
|
||||||
|
|
|
@ -3,6 +3,7 @@ package keeper
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -49,9 +50,21 @@ func TestGenesisExportImport(t *testing.T) {
|
||||||
// export
|
// export
|
||||||
genesisState := ExportGenesis(srcCtx, srcKeeper)
|
genesisState := 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(genesisState.Contracts), func(i, j int) {
|
||||||
|
genesisState.Contracts[i], genesisState.Contracts[j] = genesisState.Contracts[j], genesisState.Contracts[i]
|
||||||
|
})
|
||||||
|
rand.Shuffle(len(genesisState.Sequences), func(i, j int) {
|
||||||
|
genesisState.Sequences[i], genesisState.Sequences[j] = genesisState.Sequences[j], genesisState.Sequences[i]
|
||||||
|
})
|
||||||
|
|
||||||
// re-import
|
// re-import
|
||||||
dstKeeper, dstCtx, dstCleanup := setupKeeper(t)
|
dstKeeper, dstCtx, dstCleanup := setupKeeper(t)
|
||||||
defer dstCleanup()
|
defer dstCleanup()
|
||||||
|
|
||||||
InitGenesis(dstCtx, dstKeeper, genesisState)
|
InitGenesis(dstCtx, dstKeeper, genesisState)
|
||||||
|
|
||||||
// compare whole DB
|
// compare whole DB
|
||||||
|
@ -81,6 +94,7 @@ func TestFailFastImport(t *testing.T) {
|
||||||
"happy path: code info correct": {
|
"happy path: code info correct": {
|
||||||
src: types.GenesisState{
|
src: types.GenesisState{
|
||||||
Codes: []types.Code{{
|
Codes: []types.Code{{
|
||||||
|
CodeID: 1,
|
||||||
CodeInfo: wasmTypes.CodeInfo{
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
CodeHash: codeHash[:],
|
CodeHash: codeHash[:],
|
||||||
Creator: anyAddress,
|
Creator: anyAddress,
|
||||||
|
@ -88,11 +102,66 @@ func TestFailFastImport(t *testing.T) {
|
||||||
CodesBytes: wasmCode,
|
CodesBytes: wasmCode,
|
||||||
}},
|
}},
|
||||||
Contracts: nil,
|
Contracts: nil,
|
||||||
|
Sequences: []types.Sequence{
|
||||||
|
{IDKey: types.KeyLastCodeID, Value: 2},
|
||||||
|
{IDKey: types.KeyLastInstanceID, Value: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expSuccess: true,
|
||||||
|
},
|
||||||
|
"happy path: code ids can contain gaps": {
|
||||||
|
src: types.GenesisState{
|
||||||
|
Codes: []types.Code{{
|
||||||
|
CodeID: 1,
|
||||||
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
|
CodeHash: codeHash[:],
|
||||||
|
Creator: anyAddress,
|
||||||
|
},
|
||||||
|
CodesBytes: wasmCode,
|
||||||
|
}, {
|
||||||
|
CodeID: 3,
|
||||||
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
|
CodeHash: codeHash[:],
|
||||||
|
Creator: anyAddress,
|
||||||
|
},
|
||||||
|
CodesBytes: wasmCode,
|
||||||
|
}},
|
||||||
|
Contracts: nil,
|
||||||
|
Sequences: []types.Sequence{
|
||||||
|
{IDKey: types.KeyLastCodeID, Value: 10},
|
||||||
|
{IDKey: types.KeyLastInstanceID, Value: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expSuccess: true,
|
||||||
|
},
|
||||||
|
"happy path: code order does not matter": {
|
||||||
|
src: types.GenesisState{
|
||||||
|
Codes: []types.Code{{
|
||||||
|
CodeID: 2,
|
||||||
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
|
CodeHash: codeHash[:],
|
||||||
|
Creator: anyAddress,
|
||||||
|
},
|
||||||
|
CodesBytes: wasmCode,
|
||||||
|
}, {
|
||||||
|
CodeID: 1,
|
||||||
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
|
CodeHash: codeHash[:],
|
||||||
|
Creator: anyAddress,
|
||||||
|
},
|
||||||
|
CodesBytes: wasmCode,
|
||||||
|
}},
|
||||||
|
Contracts: nil,
|
||||||
|
Sequences: []types.Sequence{
|
||||||
|
{IDKey: types.KeyLastCodeID, Value: 3},
|
||||||
|
{IDKey: types.KeyLastInstanceID, Value: 1},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expSuccess: true,
|
expSuccess: true,
|
||||||
},
|
},
|
||||||
"prevent code hash mismatch": {src: types.GenesisState{
|
"prevent code hash mismatch": {src: types.GenesisState{
|
||||||
Codes: []types.Code{{
|
Codes: []types.Code{{
|
||||||
|
CodeID: 1,
|
||||||
CodeInfo: wasmTypes.CodeInfo{
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
CodeHash: make([]byte, len(codeHash)),
|
CodeHash: make([]byte, len(codeHash)),
|
||||||
Creator: anyAddress,
|
Creator: anyAddress,
|
||||||
|
@ -101,9 +170,30 @@ func TestFailFastImport(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
Contracts: nil,
|
Contracts: nil,
|
||||||
}},
|
}},
|
||||||
|
"prevent duplicate codeIDs": {src: types.GenesisState{
|
||||||
|
Codes: []types.Code{
|
||||||
|
{
|
||||||
|
CodeID: 1,
|
||||||
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
|
CodeHash: codeHash[:],
|
||||||
|
Creator: anyAddress,
|
||||||
|
},
|
||||||
|
CodesBytes: wasmCode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CodeID: 1,
|
||||||
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
|
CodeHash: codeHash[:],
|
||||||
|
Creator: anyAddress,
|
||||||
|
},
|
||||||
|
CodesBytes: wasmCode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
"happy path: code id in info and contract do match": {
|
"happy path: code id in info and contract do match": {
|
||||||
src: types.GenesisState{
|
src: types.GenesisState{
|
||||||
Codes: []types.Code{{
|
Codes: []types.Code{{
|
||||||
|
CodeID: 1,
|
||||||
CodeInfo: wasmTypes.CodeInfo{
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
CodeHash: codeHash[:],
|
CodeHash: codeHash[:],
|
||||||
Creator: anyAddress,
|
Creator: anyAddress,
|
||||||
|
@ -116,12 +206,17 @@ func TestFailFastImport(t *testing.T) {
|
||||||
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }),
|
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Sequences: []types.Sequence{
|
||||||
|
{IDKey: types.KeyLastCodeID, Value: 2},
|
||||||
|
{IDKey: types.KeyLastInstanceID, Value: 2},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expSuccess: true,
|
expSuccess: true,
|
||||||
},
|
},
|
||||||
"happy path: code info with two contracts": {
|
"happy path: code info with two contracts": {
|
||||||
src: types.GenesisState{
|
src: types.GenesisState{
|
||||||
Codes: []types.Code{{
|
Codes: []types.Code{{
|
||||||
|
CodeID: 1,
|
||||||
CodeInfo: wasmTypes.CodeInfo{
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
CodeHash: codeHash[:],
|
CodeHash: codeHash[:],
|
||||||
Creator: anyAddress,
|
Creator: anyAddress,
|
||||||
|
@ -133,10 +228,14 @@ func TestFailFastImport(t *testing.T) {
|
||||||
ContractAddress: contractAddress(1, 1),
|
ContractAddress: contractAddress(1, 1),
|
||||||
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }),
|
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }),
|
||||||
}, {
|
}, {
|
||||||
ContractAddress: contractAddress(2, 1),
|
ContractAddress: contractAddress(1, 2),
|
||||||
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }),
|
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Sequences: []types.Sequence{
|
||||||
|
{IDKey: types.KeyLastCodeID, Value: 2},
|
||||||
|
{IDKey: types.KeyLastInstanceID, Value: 3},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expSuccess: true,
|
expSuccess: true,
|
||||||
},
|
},
|
||||||
|
@ -153,6 +252,7 @@ func TestFailFastImport(t *testing.T) {
|
||||||
"prevent duplicate contract address": {
|
"prevent duplicate contract address": {
|
||||||
src: types.GenesisState{
|
src: types.GenesisState{
|
||||||
Codes: []types.Code{{
|
Codes: []types.Code{{
|
||||||
|
CodeID: 1,
|
||||||
CodeInfo: wasmTypes.CodeInfo{
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
CodeHash: codeHash[:],
|
CodeHash: codeHash[:],
|
||||||
Creator: anyAddress,
|
Creator: anyAddress,
|
||||||
|
@ -173,6 +273,7 @@ func TestFailFastImport(t *testing.T) {
|
||||||
"prevent duplicate contract model keys": {
|
"prevent duplicate contract model keys": {
|
||||||
src: types.GenesisState{
|
src: types.GenesisState{
|
||||||
Codes: []types.Code{{
|
Codes: []types.Code{{
|
||||||
|
CodeID: 1,
|
||||||
CodeInfo: wasmTypes.CodeInfo{
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
CodeHash: codeHash[:],
|
CodeHash: codeHash[:],
|
||||||
Creator: anyAddress,
|
Creator: anyAddress,
|
||||||
|
@ -205,6 +306,43 @@ func TestFailFastImport(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"prevent code id seq init value == max codeID used": {
|
||||||
|
src: types.GenesisState{
|
||||||
|
Codes: []types.Code{{
|
||||||
|
CodeID: 2,
|
||||||
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
|
CodeHash: codeHash[:],
|
||||||
|
Creator: anyAddress,
|
||||||
|
},
|
||||||
|
CodesBytes: wasmCode,
|
||||||
|
}},
|
||||||
|
Sequences: []types.Sequence{
|
||||||
|
{IDKey: types.KeyLastCodeID, Value: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"prevent contract id seq init value == count contracts": {
|
||||||
|
src: types.GenesisState{
|
||||||
|
Codes: []types.Code{{
|
||||||
|
CodeID: 1,
|
||||||
|
CodeInfo: wasmTypes.CodeInfo{
|
||||||
|
CodeHash: codeHash[:],
|
||||||
|
Creator: anyAddress,
|
||||||
|
},
|
||||||
|
CodesBytes: wasmCode,
|
||||||
|
}},
|
||||||
|
Contracts: []types.Contract{
|
||||||
|
{
|
||||||
|
ContractAddress: contractAddress(1, 1),
|
||||||
|
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Sequences: []types.Sequence{
|
||||||
|
{IDKey: types.KeyLastCodeID, Value: 2},
|
||||||
|
{IDKey: types.KeyLastInstanceID, Value: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for msg, spec := range specs {
|
for msg, spec := range specs {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package keeper
|
package keeper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
@ -97,6 +98,29 @@ func (k Keeper) Create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte,
|
||||||
return codeID, nil
|
return codeID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k Keeper) importCode(ctx sdk.Context, codeID uint64, codeInfo types.CodeInfo, wasmCode []byte) error {
|
||||||
|
wasmCode, err := uncompress(wasmCode)
|
||||||
|
if err != nil {
|
||||||
|
return sdkerrors.Wrap(types.ErrCreateFailed, err.Error())
|
||||||
|
}
|
||||||
|
newCodeHash, err := k.wasmer.Create(wasmCode)
|
||||||
|
if err != nil {
|
||||||
|
return sdkerrors.Wrap(types.ErrCreateFailed, err.Error())
|
||||||
|
}
|
||||||
|
if !bytes.Equal(codeInfo.CodeHash, newCodeHash) {
|
||||||
|
return sdkerrors.Wrap(types.ErrInvalid, "code hashes not same")
|
||||||
|
}
|
||||||
|
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
key := types.GetCodeKey(codeID)
|
||||||
|
if store.Has(key) {
|
||||||
|
return sdkerrors.Wrapf(types.ErrDuplicate, "duplicate code: %d", codeID)
|
||||||
|
}
|
||||||
|
// 0x01 | codeID (uint64) -> ContractInfo
|
||||||
|
store.Set(key, k.cdc.MustMarshalBinaryBare(codeInfo))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Instantiate creates an instance of a WASM contract
|
// Instantiate creates an instance of a WASM contract
|
||||||
func (k Keeper) Instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins) (sdk.AccAddress, error) {
|
func (k Keeper) Instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins) (sdk.AccAddress, error) {
|
||||||
ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: init")
|
ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: init")
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
|
import "C"
|
||||||
import (
|
import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
|
@ -45,11 +46,15 @@ func (s GenesisState) ValidateBasic() error {
|
||||||
|
|
||||||
// Code struct encompasses CodeInfo and CodeBytes
|
// Code struct encompasses CodeInfo and CodeBytes
|
||||||
type Code struct {
|
type Code struct {
|
||||||
|
CodeID uint64 `json:"code_id"`
|
||||||
CodeInfo CodeInfo `json:"code_info"`
|
CodeInfo CodeInfo `json:"code_info"`
|
||||||
CodesBytes []byte `json:"code_bytes"`
|
CodesBytes []byte `json:"code_bytes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Code) ValidateBasic() error {
|
func (c Code) ValidateBasic() error {
|
||||||
|
if c.CodeID == 0 {
|
||||||
|
return sdkerrors.Wrap(ErrEmpty, "code id")
|
||||||
|
}
|
||||||
if err := c.CodeInfo.ValidateBasic(); err != nil {
|
if err := c.CodeInfo.ValidateBasic(); err != nil {
|
||||||
return sdkerrors.Wrap(err, "code info")
|
return sdkerrors.Wrap(err, "code info")
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,12 @@ func TestCodeValidateBasic(t *testing.T) {
|
||||||
expError bool
|
expError bool
|
||||||
}{
|
}{
|
||||||
"all good": {srcMutator: func(_ *Code) {}},
|
"all good": {srcMutator: func(_ *Code) {}},
|
||||||
|
"code id invalid": {
|
||||||
|
srcMutator: func(c *Code) {
|
||||||
|
c.CodeID = 0
|
||||||
|
},
|
||||||
|
expError: true,
|
||||||
|
},
|
||||||
"codeinfo invalid": {
|
"codeinfo invalid": {
|
||||||
srcMutator: func(c *Code) {
|
srcMutator: func(c *Code) {
|
||||||
c.CodeInfo.CodeHash = nil
|
c.CodeInfo.CodeHash = nil
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,11 +34,15 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetCodeKey constructs the key for retreiving the ID for the WASM code
|
// GetCodeKey constructs the key for retreiving the ID for the WASM code
|
||||||
func GetCodeKey(contractID uint64) []byte {
|
func GetCodeKey(codeID uint64) []byte {
|
||||||
contractIDBz := sdk.Uint64ToBigEndian(contractID)
|
contractIDBz := sdk.Uint64ToBigEndian(codeID)
|
||||||
return append(CodeKeyPrefix, contractIDBz...)
|
return append(CodeKeyPrefix, contractIDBz...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodeCodeKey(src []byte) uint64 {
|
||||||
|
return binary.BigEndian.Uint64(src[len(CodeKeyPrefix):])
|
||||||
|
}
|
||||||
|
|
||||||
// GetContractAddressKey returns the key for the WASM contract instance
|
// GetContractAddressKey returns the key for the WASM contract instance
|
||||||
func GetContractAddressKey(addr sdk.AccAddress) []byte {
|
func GetContractAddressKey(addr sdk.AccAddress) []byte {
|
||||||
return append(ContractKeyPrefix, addr...)
|
return append(ContractKeyPrefix, addr...)
|
||||||
|
|
|
@ -43,6 +43,7 @@ func CodeFixture(mutators ...func(*Code)) Code {
|
||||||
anyAddress := make([]byte, 20)
|
anyAddress := make([]byte, 20)
|
||||||
|
|
||||||
fixture := Code{
|
fixture := Code{
|
||||||
|
CodeID: 1,
|
||||||
CodeInfo: CodeInfo{
|
CodeInfo: CodeInfo{
|
||||||
CodeHash: codeHash[:],
|
CodeHash: codeHash[:],
|
||||||
Creator: anyAddress,
|
Creator: anyAddress,
|
||||||
|
|
Loading…
Reference in New Issue