Make contract addresses predictable
This commit is contained in:
@@ -103,7 +103,7 @@ func GenesisInstantiateContractCmd(defaultNodeHome string, genesisMutator Genesi
|
||||
}
|
||||
|
||||
return genesisMutator.AlterWasmModuleState(cmd, func(state *types.GenesisState, appState map[string]json.RawMessage) error {
|
||||
// simple sanity check that sender has some balance although it may be consumed by appState previous message already
|
||||
// simple sanity check that sender has some balance, although it may be consumed by appState previous message already
|
||||
switch ok, err := hasAccountBalance(cmd, appState, senderAddr, msg.Funds); {
|
||||
case err != nil:
|
||||
return err
|
||||
@@ -112,7 +112,7 @@ func GenesisInstantiateContractCmd(defaultNodeHome string, genesisMutator Genesi
|
||||
}
|
||||
|
||||
// does code id exists?
|
||||
codeInfos, err := GetAllCodes(state)
|
||||
codeInfos := GetAllCodes(state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -171,7 +171,7 @@ func GenesisExecuteContractCmd(defaultNodeHome string, genesisMutator GenesisMut
|
||||
}
|
||||
|
||||
return genesisMutator.AlterWasmModuleState(cmd, func(state *types.GenesisState, appState map[string]json.RawMessage) error {
|
||||
// simple sanity check that sender has some balance although it may be consumed by appState previous message already
|
||||
// simple sanity check that sender has some balance, although it may be consumed by appState previous message already
|
||||
switch ok, err := hasAccountBalance(cmd, appState, senderAddr, msg.Funds); {
|
||||
case err != nil:
|
||||
return err
|
||||
@@ -211,7 +211,7 @@ func GenesisListCodesCmd(defaultNodeHome string, genReader GenesisReader) *cobra
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
all, err := GetAllCodes(g.WasmModuleState)
|
||||
all := GetAllCodes(g.WasmModuleState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -236,7 +236,10 @@ func GenesisListContractsCmd(defaultNodeHome string, genReader GenesisReader) *c
|
||||
return err
|
||||
}
|
||||
state := g.WasmModuleState
|
||||
all := GetAllContracts(state)
|
||||
all, err := GetAllContracts(state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printJSONOutput(cmd, all)
|
||||
},
|
||||
}
|
||||
@@ -245,7 +248,7 @@ func GenesisListContractsCmd(defaultNodeHome string, genReader GenesisReader) *c
|
||||
return cmd
|
||||
}
|
||||
|
||||
// clientCtx marshaller works only with proto or bytes so we marshal the output ourself
|
||||
// clientCtx marshaller works only with proto or bytes, so we marshal the output ourselves
|
||||
func printJSONOutput(cmd *cobra.Command, obj interface{}) error {
|
||||
clientCtx := client.GetClientContextFromCmd(cmd)
|
||||
bz, err := json.MarshalIndent(obj, "", " ")
|
||||
@@ -260,7 +263,7 @@ type CodeMeta struct {
|
||||
Info types.CodeInfo `json:"info"`
|
||||
}
|
||||
|
||||
func GetAllCodes(state *types.GenesisState) ([]CodeMeta, error) {
|
||||
func GetAllCodes(state *types.GenesisState) []CodeMeta {
|
||||
all := make([]CodeMeta, len(state.Codes))
|
||||
for i, c := range state.Codes {
|
||||
all[i] = CodeMeta{
|
||||
@@ -277,10 +280,7 @@ func GetAllCodes(state *types.GenesisState) ([]CodeMeta, error) {
|
||||
accessConfig = *msg.InstantiatePermission
|
||||
} else {
|
||||
// default
|
||||
creator, err := sdk.AccAddressFromBech32(msg.Sender)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("sender: %s", err)
|
||||
}
|
||||
creator := sdk.MustAccAddressFromBech32(msg.Sender)
|
||||
accessConfig = state.Params.InstantiateDefaultPermission.With(creator)
|
||||
}
|
||||
hash := sha256.Sum256(msg.WASMByteCode)
|
||||
@@ -295,7 +295,7 @@ func GetAllCodes(state *types.GenesisState) ([]CodeMeta, error) {
|
||||
seq++
|
||||
}
|
||||
}
|
||||
return all, nil
|
||||
return all
|
||||
}
|
||||
|
||||
type ContractMeta struct {
|
||||
@@ -303,7 +303,18 @@ type ContractMeta struct {
|
||||
Info types.ContractInfo `json:"info"`
|
||||
}
|
||||
|
||||
func GetAllContracts(state *types.GenesisState) []ContractMeta {
|
||||
// returns nil when not found
|
||||
func codeHashByID(state *types.GenesisState, codeID uint64) []byte {
|
||||
codes := GetAllCodes(state)
|
||||
for _, v := range codes {
|
||||
if v.CodeID == codeID {
|
||||
return v.Info.CodeHash
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAllContracts(state *types.GenesisState) ([]ContractMeta, error) {
|
||||
all := make([]ContractMeta, len(state.Contracts))
|
||||
for i, c := range state.Contracts {
|
||||
all[i] = ContractMeta{
|
||||
@@ -312,11 +323,18 @@ func GetAllContracts(state *types.GenesisState) []ContractMeta {
|
||||
}
|
||||
}
|
||||
// add inflight
|
||||
seq := contractSeqValue(state)
|
||||
for _, m := range state.GenMsgs {
|
||||
if msg := m.GetInstantiateContract(); msg != nil {
|
||||
senderAddr, err := sdk.AccAddressFromBech32(msg.Sender)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("unsupported address %q: %s", msg.Sender, err))
|
||||
}
|
||||
codeHash := codeHashByID(state, msg.CodeID)
|
||||
if codeHash == nil {
|
||||
return nil, types.ErrNotFound.Wrapf("hash for code-id: %d", msg.CodeID)
|
||||
}
|
||||
all = append(all, ContractMeta{
|
||||
ContractAddress: keeper.BuildContractAddress(msg.CodeID, seq).String(),
|
||||
ContractAddress: keeper.BuildContractAddress(codeHash, senderAddr, msg.Label).String(),
|
||||
Info: types.ContractInfo{
|
||||
CodeID: msg.CodeID,
|
||||
Creator: msg.Sender,
|
||||
@@ -324,10 +342,9 @@ func GetAllContracts(state *types.GenesisState) []ContractMeta {
|
||||
Label: msg.Label,
|
||||
},
|
||||
})
|
||||
seq++
|
||||
}
|
||||
}
|
||||
return all
|
||||
return all, nil
|
||||
}
|
||||
|
||||
func hasAccountBalance(cmd *cobra.Command, appState map[string]json.RawMessage, sender sdk.AccAddress, coins sdk.Coins) (bool, error) {
|
||||
@@ -354,13 +371,19 @@ func hasContract(state *types.GenesisState, contractAddr string) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
seq := contractSeqValue(state)
|
||||
for _, m := range state.GenMsgs {
|
||||
if msg := m.GetInstantiateContract(); msg != nil {
|
||||
if keeper.BuildContractAddress(msg.CodeID, seq).String() == contractAddr {
|
||||
senderAddr, err := sdk.AccAddressFromBech32(msg.Sender)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("unsupported address %q: %s", msg.Sender, err))
|
||||
}
|
||||
hash := codeHashByID(state, msg.CodeID)
|
||||
if hash == nil {
|
||||
panic(fmt.Sprintf("unknown code id: %d", msg.CodeID))
|
||||
}
|
||||
if keeper.BuildContractAddress(hash, senderAddr, msg.Label).String() == contractAddr {
|
||||
return true
|
||||
}
|
||||
seq++
|
||||
}
|
||||
}
|
||||
return false
|
||||
@@ -453,19 +476,6 @@ func (x DefaultGenesisIO) AlterWasmModuleState(cmd *cobra.Command, callback func
|
||||
return genutil.ExportGenesisFile(g.GenDoc, g.GenesisFile)
|
||||
}
|
||||
|
||||
// contractSeqValue reads the contract sequence from the genesis or
|
||||
// returns default start value used in the keeper
|
||||
func contractSeqValue(state *types.GenesisState) uint64 {
|
||||
var seq uint64 = 1
|
||||
for _, s := range state.Sequences {
|
||||
if bytes.Equal(s.IDKey, types.KeyLastInstanceID) {
|
||||
seq = s.Value
|
||||
break
|
||||
}
|
||||
}
|
||||
return seq
|
||||
}
|
||||
|
||||
// codeSeqValue reads the code sequence from the genesis or
|
||||
// returns default start value used in the keeper
|
||||
func codeSeqValue(state *types.GenesisState) uint64 {
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/types/address"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
@@ -363,7 +366,8 @@ func TestInstantiateContractCmd(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestExecuteContractCmd(t *testing.T) {
|
||||
const firstContractAddress = "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
|
||||
mySenderAddr := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len))
|
||||
myFirstContractAddress := keeper.BuildContractAddress([]byte("myCodeHash"), mySenderAddr, "my").String()
|
||||
minimalWasmGenesis := types.GenesisState{
|
||||
Params: types.DefaultParams(),
|
||||
}
|
||||
@@ -390,7 +394,7 @@ func TestExecuteContractCmd(t *testing.T) {
|
||||
},
|
||||
Contracts: []types.Contract{
|
||||
{
|
||||
ContractAddress: firstContractAddress,
|
||||
ContractAddress: myFirstContractAddress,
|
||||
ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) {
|
||||
info.Created = nil
|
||||
}),
|
||||
@@ -399,53 +403,34 @@ func TestExecuteContractCmd(t *testing.T) {
|
||||
},
|
||||
},
|
||||
mutator: func(cmd *cobra.Command) {
|
||||
cmd.SetArgs([]string{firstContractAddress, `{}`})
|
||||
cmd.SetArgs([]string{myFirstContractAddress, `{}`})
|
||||
flagSet := cmd.Flags()
|
||||
flagSet.Set("run-as", myWellFundedAccount)
|
||||
},
|
||||
expMsgCount: 1,
|
||||
},
|
||||
"all good with contract from genesis store messages without initial sequence": {
|
||||
"all good with contract from genesis store messages": {
|
||||
srcGenesis: types.GenesisState{
|
||||
Params: types.DefaultParams(),
|
||||
Codes: []types.Code{
|
||||
{
|
||||
CodeID: 1,
|
||||
CodeInfo: types.CodeInfoFixture(),
|
||||
CodeID: 1,
|
||||
CodeInfo: types.CodeInfoFixture(func(info *types.CodeInfo) {
|
||||
info.CodeHash = []byte("myCodeHash")
|
||||
}),
|
||||
CodeBytes: wasmIdent,
|
||||
},
|
||||
},
|
||||
GenMsgs: []types.GenesisState_GenMsgs{
|
||||
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: types.MsgInstantiateContractFixture()}},
|
||||
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: types.MsgInstantiateContractFixture(
|
||||
func(m *types.MsgInstantiateContract) {
|
||||
m.Sender = mySenderAddr.String()
|
||||
m.Label = "my"
|
||||
})}},
|
||||
},
|
||||
},
|
||||
mutator: func(cmd *cobra.Command) {
|
||||
cmd.SetArgs([]string{firstContractAddress, `{}`})
|
||||
flagSet := cmd.Flags()
|
||||
flagSet.Set("run-as", myWellFundedAccount)
|
||||
},
|
||||
expMsgCount: 2,
|
||||
},
|
||||
"all good with contract from genesis store messages and contract sequence set": {
|
||||
srcGenesis: types.GenesisState{
|
||||
Params: types.DefaultParams(),
|
||||
Codes: []types.Code{
|
||||
{
|
||||
CodeID: 1,
|
||||
CodeInfo: types.CodeInfoFixture(),
|
||||
CodeBytes: wasmIdent,
|
||||
},
|
||||
},
|
||||
GenMsgs: []types.GenesisState_GenMsgs{
|
||||
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: types.MsgInstantiateContractFixture()}},
|
||||
},
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: types.KeyLastInstanceID, Value: 100},
|
||||
},
|
||||
},
|
||||
mutator: func(cmd *cobra.Command) {
|
||||
// See TestBuildContractAddress in keeper_test.go
|
||||
cmd.SetArgs([]string{"cosmos1mujpjkwhut9yjw4xueyugc02evfv46y0dtmnz4lh8xxkkdapym9stu5qm8", `{}`})
|
||||
cmd.SetArgs([]string{myFirstContractAddress, `{}`})
|
||||
flagSet := cmd.Flags()
|
||||
flagSet.Set("run-as", myWellFundedAccount)
|
||||
},
|
||||
@@ -472,7 +457,7 @@ func TestExecuteContractCmd(t *testing.T) {
|
||||
},
|
||||
Contracts: []types.Contract{
|
||||
{
|
||||
ContractAddress: firstContractAddress,
|
||||
ContractAddress: myFirstContractAddress,
|
||||
ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) {
|
||||
info.Created = nil
|
||||
}),
|
||||
@@ -481,7 +466,7 @@ func TestExecuteContractCmd(t *testing.T) {
|
||||
},
|
||||
},
|
||||
mutator: func(cmd *cobra.Command) {
|
||||
cmd.SetArgs([]string{firstContractAddress, `{}`})
|
||||
cmd.SetArgs([]string{myFirstContractAddress, `{}`})
|
||||
flagSet := cmd.Flags()
|
||||
flagSet.Set("run-as", keeper.RandomBech32AccountAddress(t))
|
||||
},
|
||||
@@ -499,7 +484,7 @@ func TestExecuteContractCmd(t *testing.T) {
|
||||
},
|
||||
Contracts: []types.Contract{
|
||||
{
|
||||
ContractAddress: firstContractAddress,
|
||||
ContractAddress: myFirstContractAddress,
|
||||
ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) {
|
||||
info.Created = nil
|
||||
}),
|
||||
@@ -508,7 +493,7 @@ func TestExecuteContractCmd(t *testing.T) {
|
||||
},
|
||||
},
|
||||
mutator: func(cmd *cobra.Command) {
|
||||
cmd.SetArgs([]string{firstContractAddress, `{}`})
|
||||
cmd.SetArgs([]string{myFirstContractAddress, `{}`})
|
||||
flagSet := cmd.Flags()
|
||||
flagSet.Set("run-as", myWellFundedAccount)
|
||||
flagSet.Set("amount", "100stake")
|
||||
@@ -527,7 +512,7 @@ func TestExecuteContractCmd(t *testing.T) {
|
||||
},
|
||||
Contracts: []types.Contract{
|
||||
{
|
||||
ContractAddress: firstContractAddress,
|
||||
ContractAddress: myFirstContractAddress,
|
||||
ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) {
|
||||
info.Created = nil
|
||||
}),
|
||||
@@ -536,7 +521,7 @@ func TestExecuteContractCmd(t *testing.T) {
|
||||
},
|
||||
},
|
||||
mutator: func(cmd *cobra.Command) {
|
||||
cmd.SetArgs([]string{firstContractAddress, `{}`})
|
||||
cmd.SetArgs([]string{myFirstContractAddress, `{}`})
|
||||
flagSet := cmd.Flags()
|
||||
flagSet.Set("run-as", keeper.RandomBech32AccountAddress(t))
|
||||
flagSet.Set("amount", "10stake")
|
||||
@@ -565,6 +550,9 @@ func TestExecuteContractCmd(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAllContracts(t *testing.T) {
|
||||
creatorAddr1 := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len))
|
||||
creatorAddr2 := sdk.AccAddress(bytes.Repeat([]byte{2}, address.Len))
|
||||
|
||||
specs := map[string]struct {
|
||||
src types.GenesisState
|
||||
exp []ContractMeta
|
||||
@@ -595,68 +583,55 @@ func TestGetAllContracts(t *testing.T) {
|
||||
},
|
||||
"read from message state": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{{CodeID: 1, CodeInfo: types.CodeInfo{CodeHash: []byte("firstCodeHash")}}},
|
||||
GenMsgs: []types.GenesisState_GenMsgs{
|
||||
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "first"}}},
|
||||
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "second"}}},
|
||||
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Sender: creatorAddr1.String(), Label: "first", CodeID: 1}}},
|
||||
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Sender: creatorAddr2.String(), Label: "second", CodeID: 1}}},
|
||||
},
|
||||
},
|
||||
exp: []ContractMeta{
|
||||
{
|
||||
ContractAddress: keeper.BuildContractAddress(0, 1).String(),
|
||||
Info: types.ContractInfo{Label: "first"},
|
||||
ContractAddress: keeper.BuildContractAddress([]byte("firstCodeHash"), creatorAddr1, "first").String(),
|
||||
Info: types.ContractInfo{Creator: creatorAddr1.String(), Label: "first", CodeID: 1},
|
||||
},
|
||||
{
|
||||
ContractAddress: keeper.BuildContractAddress(0, 2).String(),
|
||||
Info: types.ContractInfo{Label: "second"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"read from message state with contract sequence": {
|
||||
src: types.GenesisState{
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: types.KeyLastInstanceID, Value: 100},
|
||||
},
|
||||
GenMsgs: []types.GenesisState_GenMsgs{
|
||||
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "hundred"}}},
|
||||
},
|
||||
},
|
||||
exp: []ContractMeta{
|
||||
{
|
||||
ContractAddress: keeper.BuildContractAddress(0, 100).String(),
|
||||
Info: types.ContractInfo{Label: "hundred"},
|
||||
ContractAddress: keeper.BuildContractAddress([]byte("firstCodeHash"), creatorAddr2, "second").String(),
|
||||
Info: types.ContractInfo{Creator: creatorAddr2.String(), Label: "second", CodeID: 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
"read from contract and message state with contract sequence": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{
|
||||
{CodeID: 1, CodeInfo: types.CodeInfo{CodeHash: []byte("firstCodeHash")}},
|
||||
{CodeID: 100, CodeInfo: types.CodeInfo{CodeHash: []byte("otherCodeHash")}},
|
||||
},
|
||||
Contracts: []types.Contract{
|
||||
{
|
||||
ContractAddress: "first-contract",
|
||||
ContractInfo: types.ContractInfo{Label: "first"},
|
||||
ContractAddress: keeper.BuildContractAddress([]byte("firstCodeHash"), creatorAddr1, "first").String(),
|
||||
ContractInfo: types.ContractInfo{Label: "first", CodeID: 1},
|
||||
},
|
||||
},
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: types.KeyLastInstanceID, Value: 100},
|
||||
},
|
||||
GenMsgs: []types.GenesisState_GenMsgs{
|
||||
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "hundred"}}},
|
||||
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Sender: creatorAddr1.String(), Label: "hundred", CodeID: 100}}},
|
||||
},
|
||||
},
|
||||
exp: []ContractMeta{
|
||||
{
|
||||
ContractAddress: "first-contract",
|
||||
Info: types.ContractInfo{Label: "first"},
|
||||
ContractAddress: keeper.BuildContractAddress([]byte("firstCodeHash"), creatorAddr1, "first").String(),
|
||||
Info: types.ContractInfo{Label: "first", CodeID: 1},
|
||||
},
|
||||
{
|
||||
ContractAddress: keeper.BuildContractAddress(0, 100).String(),
|
||||
Info: types.ContractInfo{Label: "hundred"},
|
||||
ContractAddress: keeper.BuildContractAddress([]byte("otherCodeHash"), creatorAddr1, "hundred").String(),
|
||||
Info: types.ContractInfo{Creator: creatorAddr1.String(), Label: "hundred", CodeID: 100},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for msg, spec := range specs {
|
||||
t.Run(msg, func(t *testing.T) {
|
||||
got := GetAllContracts(&spec.src)
|
||||
got, err := GetAllContracts(&spec.src)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
"github.com/CosmWasm/wasmd/x/wasm/keeper"
|
||||
"github.com/CosmWasm/wasmd/x/wasm/types"
|
||||
)
|
||||
|
||||
@@ -39,6 +40,7 @@ func GetQueryCmd() *cobra.Command {
|
||||
GetCmdListPinnedCode(),
|
||||
GetCmdLibVersion(),
|
||||
GetCmdQueryParams(),
|
||||
GetCmdBuildAddress(),
|
||||
)
|
||||
return queryCmd
|
||||
}
|
||||
@@ -63,6 +65,33 @@ func GetCmdLibVersion() *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdBuildAddress build a contract address
|
||||
func GetCmdBuildAddress() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "build-address [code-hash] [creator-address] [label]",
|
||||
Short: "build contract address",
|
||||
Aliases: []string{"address"},
|
||||
Args: cobra.ExactArgs(3),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
codeHash, err := hex.DecodeString(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("code-hash: %s", err)
|
||||
}
|
||||
creator, err := sdk.AccAddressFromBech32(args[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("creator: %s", err)
|
||||
}
|
||||
label := args[2]
|
||||
if err := types.ValidateLabel(label); err != nil {
|
||||
return fmt.Errorf("label: %s", err)
|
||||
}
|
||||
cmd.Println(keeper.BuildContractAddress(codeHash, creator, label).String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdListCode lists all wasm code uploaded
|
||||
func GetCmdListCode() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
@@ -117,6 +146,9 @@ func GetCmdListContractByCode() *cobra.Command {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if codeID == 0 {
|
||||
return errors.New("empty code id")
|
||||
}
|
||||
|
||||
pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags()))
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user