From 9c5ebbbc4ca58053c633742f75503d231ef904bf Mon Sep 17 00:00:00 2001 From: Alexander Peters Date: Thu, 22 Sep 2022 18:22:35 +0200 Subject: [PATCH] Implement improvements to new address generation (#1014) * Revert default instance address generation to classic sequence based method Please enter the commit message for your changes. Lines starting * Start re-adding classic address generator * Extract address generation to file; minor updates * Review comments * Set max salt size * Support predictable address on instantiation * Switch attribute order for backwards compatiblity * Fix salt param check in CLI * Enable tests * Add more tests * Minor fix * Remove migration * Better cli description * Fix init message length prefix * Add sanity checks to address generation and minor updates * Reduce max length in tests for CI * CLI and address generation updates * Add test vectors * Minor updates * Fix cli long doc --- contrib/local/02-contracts.sh | 16 +- docs/proto/proto-docs.md | 50 +- proto/cosmwasm/wasm/v1/genesis.proto | 2 + proto/cosmwasm/wasm/v1/tx.proto | 45 +- x/wasm/alias.go | 2 + x/wasm/client/cli/genesis_msg.go | 65 +- x/wasm/client/cli/genesis_msg_test.go | 119 ++- x/wasm/client/cli/query.go | 28 +- x/wasm/client/cli/tx.go | 101 +- x/wasm/handler.go | 2 + x/wasm/keeper/addresses.go | 76 ++ x/wasm/keeper/addresses_test.go | 432 +++++++++ x/wasm/keeper/contract_keeper.go | 50 +- x/wasm/keeper/contract_keeper_test.go | 168 ++++ x/wasm/keeper/genesis.go | 8 +- x/wasm/keeper/genesis_test.go | 81 +- x/wasm/keeper/ibc_test.go | 4 +- x/wasm/keeper/keeper.go | 41 +- x/wasm/keeper/keeper_test.go | 195 +--- x/wasm/keeper/migrations.go | 27 - x/wasm/keeper/migrations_test.go | 20 - x/wasm/keeper/msg_server.go | 32 + x/wasm/keeper/proposal_integration_test.go | 29 +- x/wasm/keeper/querier_test.go | 5 +- x/wasm/keeper/test_common.go | 7 +- x/wasm/keeper/wasmtesting/coin_transferrer.go | 14 - x/wasm/keeper/wasmtesting/extension_mocks.go | 28 + x/wasm/module.go | 5 - x/wasm/module_test.go | 19 +- x/wasm/types/codec.go | 2 + x/wasm/types/exported_keepers.go | 23 +- x/wasm/types/keys.go | 3 +- x/wasm/types/tx.go | 53 + x/wasm/types/tx.pb.go | 917 ++++++++++++++++-- x/wasm/types/tx_test.go | 136 +++ x/wasm/types/validation.go | 18 +- 36 files changed, 2271 insertions(+), 552 deletions(-) create mode 100644 x/wasm/keeper/addresses.go create mode 100644 x/wasm/keeper/addresses_test.go create mode 100644 x/wasm/keeper/contract_keeper_test.go delete mode 100644 x/wasm/keeper/migrations.go delete mode 100644 x/wasm/keeper/migrations_test.go delete mode 100644 x/wasm/keeper/wasmtesting/coin_transferrer.go create mode 100644 x/wasm/keeper/wasmtesting/extension_mocks.go diff --git a/contrib/local/02-contracts.sh b/contrib/local/02-contracts.sh index ecbadf31eb..c445d948b6 100755 --- a/contrib/local/02-contracts.sh +++ b/contrib/local/02-contracts.sh @@ -1,5 +1,5 @@ #!/bin/bash -set -o errexit -o nounset -o pipefail +set -o errexit -o nounset -o pipefail -x DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" @@ -9,7 +9,10 @@ RESP=$(wasmd tx wasm store "$DIR/../../x/wasm/keeper/testdata/hackatom.wasm" \ --from validator --gas 1500000 -y --chain-id=testing --node=http://localhost:26657 -b block -o json) CODE_ID=$(echo "$RESP" | jq -r '.logs[0].events[1].attributes[-1].value') +CODE_HASH=$(echo "$RESP" | jq -r '.logs[0].events[1].attributes[-2].value') echo "* Code id: $CODE_ID" +echo "* Code checksum: $CODE_HASH" + echo "* Download code" TMPDIR=$(mktemp -t wasmdXXXXXX) wasmd q wasm code "$CODE_ID" "$TMPDIR" @@ -27,6 +30,17 @@ wasmd tx wasm instantiate "$CODE_ID" "$INIT" --admin="$(wasmd keys show validato CONTRACT=$(wasmd query wasm list-contract-by-code "$CODE_ID" -o json | jq -r '.contracts[-1]') echo "* Contract address: $CONTRACT" + +echo "## Create new contract instance with predictable address" +wasmd tx wasm instantiate2 "$CODE_ID" "$INIT" $(echo -n "testing" | xxd -ps) \ + --admin="$(wasmd keys show validator -a)" \ + --from validator --amount="100ustake" --label "local0.1.0" \ + --fix-msg \ + --gas 1000000 -y --chain-id=testing -b block -o json | jq + +predictedAdress=$(wasmd q wasm build-address "$CODE_HASH" $(wasmd keys show validator -a) $(echo -n "testing" | xxd -ps) "$INIT") +wasmd q wasm contract "$predictedAdress" -o json | jq + echo "### Query all" RESP=$(wasmd query wasm contract-state all "$CONTRACT" -o json) echo "$RESP" | jq diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md index 584398a709..add638f07f 100644 --- a/docs/proto/proto-docs.md +++ b/docs/proto/proto-docs.md @@ -23,6 +23,8 @@ - [MsgExecuteContract](#cosmwasm.wasm.v1.MsgExecuteContract) - [MsgExecuteContractResponse](#cosmwasm.wasm.v1.MsgExecuteContractResponse) - [MsgInstantiateContract](#cosmwasm.wasm.v1.MsgInstantiateContract) + - [MsgInstantiateContract2](#cosmwasm.wasm.v1.MsgInstantiateContract2) + - [MsgInstantiateContract2Response](#cosmwasm.wasm.v1.MsgInstantiateContract2Response) - [MsgInstantiateContractResponse](#cosmwasm.wasm.v1.MsgInstantiateContractResponse) - [MsgMigrateContract](#cosmwasm.wasm.v1.MsgMigrateContract) - [MsgMigrateContractResponse](#cosmwasm.wasm.v1.MsgMigrateContractResponse) @@ -327,7 +329,7 @@ MsgExecuteContractResponse returns execution result data. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `data` | [bytes](#bytes) | | Data contains base64-encoded bytes to returned from the contract | +| `data` | [bytes](#bytes) | | Data contains bytes to returned from the contract | @@ -355,6 +357,45 @@ code id. + + +### MsgInstantiateContract2 +MsgInstantiateContract2 create a new smart contract instance for the given +code id with a predicable address. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `sender` | [string](#string) | | Sender is the that actor that signed the messages | +| `admin` | [string](#string) | | Admin is an optional address that can execute migrations | +| `code_id` | [uint64](#uint64) | | CodeID is the reference to the stored WASM code | +| `label` | [string](#string) | | Label is optional metadata to be stored with a contract instance. | +| `msg` | [bytes](#bytes) | | Msg json encoded message to be passed to the contract on instantiation | +| `funds` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Funds coins that are transferred to the contract on instantiation | +| `salt` | [bytes](#bytes) | | Salt is an arbitrary value provided by the sender. Size can be 1 to 64. | +| `fix_msg` | [bool](#bool) | | FixMsg include the msg value into the hash for the predictable address. Default is false | + + + + + + + + +### MsgInstantiateContract2Response +MsgInstantiateContract2Response return instantiation result data + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `address` | [string](#string) | | Address is the bech32 address of the new contract instance. | +| `data` | [bytes](#bytes) | | Data contains bytes to returned from the contract | + + + + + + ### MsgInstantiateContractResponse @@ -364,7 +405,7 @@ MsgInstantiateContractResponse return instantiation result data | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `address` | [string](#string) | | Address is the bech32 address of the new contract instance. | -| `data` | [bytes](#bytes) | | Data contains base64-encoded bytes to returned from the contract | +| `data` | [bytes](#bytes) | | Data contains bytes to returned from the contract | @@ -478,7 +519,8 @@ Msg defines the wasm Msg service. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | | `StoreCode` | [MsgStoreCode](#cosmwasm.wasm.v1.MsgStoreCode) | [MsgStoreCodeResponse](#cosmwasm.wasm.v1.MsgStoreCodeResponse) | StoreCode to submit Wasm code to the system | | -| `InstantiateContract` | [MsgInstantiateContract](#cosmwasm.wasm.v1.MsgInstantiateContract) | [MsgInstantiateContractResponse](#cosmwasm.wasm.v1.MsgInstantiateContractResponse) | Instantiate creates a new smart contract instance for the given code id. | | +| `InstantiateContract` | [MsgInstantiateContract](#cosmwasm.wasm.v1.MsgInstantiateContract) | [MsgInstantiateContractResponse](#cosmwasm.wasm.v1.MsgInstantiateContractResponse) | InstantiateContract creates a new smart contract instance for the given code id. | | +| `InstantiateContract2` | [MsgInstantiateContract2](#cosmwasm.wasm.v1.MsgInstantiateContract2) | [MsgInstantiateContract2Response](#cosmwasm.wasm.v1.MsgInstantiateContract2Response) | InstantiateContract2 creates a new smart contract instance for the given code id with a predictable address | | | `ExecuteContract` | [MsgExecuteContract](#cosmwasm.wasm.v1.MsgExecuteContract) | [MsgExecuteContractResponse](#cosmwasm.wasm.v1.MsgExecuteContractResponse) | Execute submits the given message data to a smart contract | | | `MigrateContract` | [MsgMigrateContract](#cosmwasm.wasm.v1.MsgMigrateContract) | [MsgMigrateContractResponse](#cosmwasm.wasm.v1.MsgMigrateContractResponse) | Migrate runs a code upgrade/ downgrade for a smart contract | | | `UpdateAdmin` | [MsgUpdateAdmin](#cosmwasm.wasm.v1.MsgUpdateAdmin) | [MsgUpdateAdminResponse](#cosmwasm.wasm.v1.MsgUpdateAdminResponse) | UpdateAdmin sets a new admin for a smart contract | | @@ -560,7 +602,7 @@ order. The intention is to have more human readable data that is auditable. | ----- | ---- | ----- | ----------- | | `store_code` | [MsgStoreCode](#cosmwasm.wasm.v1.MsgStoreCode) | | | | `instantiate_contract` | [MsgInstantiateContract](#cosmwasm.wasm.v1.MsgInstantiateContract) | | | -| `execute_contract` | [MsgExecuteContract](#cosmwasm.wasm.v1.MsgExecuteContract) | | | +| `execute_contract` | [MsgExecuteContract](#cosmwasm.wasm.v1.MsgExecuteContract) | | MsgInstantiateContract2 intentionally not supported see https://github.com/CosmWasm/wasmd/issues/987 | diff --git a/proto/cosmwasm/wasm/v1/genesis.proto b/proto/cosmwasm/wasm/v1/genesis.proto index f02f330750..87373e18d7 100644 --- a/proto/cosmwasm/wasm/v1/genesis.proto +++ b/proto/cosmwasm/wasm/v1/genesis.proto @@ -33,6 +33,8 @@ message GenesisState { MsgStoreCode store_code = 1; MsgInstantiateContract instantiate_contract = 2; MsgExecuteContract execute_contract = 3; + // MsgInstantiateContract2 intentionally not supported + // see https://github.com/CosmWasm/wasmd/issues/987 } } } diff --git a/proto/cosmwasm/wasm/v1/tx.proto b/proto/cosmwasm/wasm/v1/tx.proto index f1eb8fec68..04acc8ef7f 100644 --- a/proto/cosmwasm/wasm/v1/tx.proto +++ b/proto/cosmwasm/wasm/v1/tx.proto @@ -12,9 +12,14 @@ option (gogoproto.goproto_getters_all) = false; service Msg { // StoreCode to submit Wasm code to the system rpc StoreCode(MsgStoreCode) returns (MsgStoreCodeResponse); - // Instantiate creates a new smart contract instance for the given code id. + // InstantiateContract creates a new smart contract instance for the given + // code id. rpc InstantiateContract(MsgInstantiateContract) returns (MsgInstantiateContractResponse); + // InstantiateContract2 creates a new smart contract instance for the given + // code id with a predictable address + rpc InstantiateContract2(MsgInstantiateContract2) + returns (MsgInstantiateContract2Response); // Execute submits the given message data to a smart contract rpc ExecuteContract(MsgExecuteContract) returns (MsgExecuteContractResponse); // Migrate runs a code upgrade/ downgrade for a smart contract @@ -64,11 +69,45 @@ message MsgInstantiateContract { (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; } + +// MsgInstantiateContract2 create a new smart contract instance for the given +// code id with a predicable address. +message MsgInstantiateContract2 { + // Sender is the that actor that signed the messages + string sender = 1; + // Admin is an optional address that can execute migrations + string admin = 2; + // CodeID is the reference to the stored WASM code + uint64 code_id = 3 [ (gogoproto.customname) = "CodeID" ]; + // Label is optional metadata to be stored with a contract instance. + string label = 4; + // Msg json encoded message to be passed to the contract on instantiation + bytes msg = 5 [ (gogoproto.casttype) = "RawContractMessage" ]; + // Funds coins that are transferred to the contract on instantiation + repeated cosmos.base.v1beta1.Coin funds = 6 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + // Salt is an arbitrary value provided by the sender. Size can be 1 to 64. + bytes salt = 7; + // FixMsg include the msg value into the hash for the predictable address. + // Default is false + bool fix_msg = 8; +} + // MsgInstantiateContractResponse return instantiation result data message MsgInstantiateContractResponse { // Address is the bech32 address of the new contract instance. string address = 1; - // Data contains base64-encoded bytes to returned from the contract + // Data contains bytes to returned from the contract + bytes data = 2; +} + +// MsgInstantiateContract2Response return instantiation result data +message MsgInstantiateContract2Response { + // Address is the bech32 address of the new contract instance. + string address = 1; + // Data contains bytes to returned from the contract bytes data = 2; } @@ -89,7 +128,7 @@ message MsgExecuteContract { // MsgExecuteContractResponse returns execution result data. message MsgExecuteContractResponse { - // Data contains base64-encoded bytes to returned from the contract + // Data contains bytes to returned from the contract bytes data = 1; } diff --git a/x/wasm/alias.go b/x/wasm/alias.go index 09f0e7af00..a64de37bdd 100644 --- a/x/wasm/alias.go +++ b/x/wasm/alias.go @@ -86,6 +86,7 @@ var ( ErrQueryFailed = types.ErrQueryFailed ErrInvalidMsg = types.ErrInvalidMsg KeyLastCodeID = types.KeyLastCodeID + KeyLastInstanceID = types.KeyLastInstanceID CodeKeyPrefix = types.CodeKeyPrefix ContractKeyPrefix = types.ContractKeyPrefix ContractStorePrefix = types.ContractStorePrefix @@ -101,6 +102,7 @@ type ( MsgStoreCode = types.MsgStoreCode MsgStoreCodeResponse = types.MsgStoreCodeResponse MsgInstantiateContract = types.MsgInstantiateContract + MsgInstantiateContract2 = types.MsgInstantiateContract2 MsgInstantiateContractResponse = types.MsgInstantiateContractResponse MsgExecuteContract = types.MsgExecuteContract MsgExecuteContractResponse = types.MsgExecuteContractResponse diff --git a/x/wasm/client/cli/genesis_msg.go b/x/wasm/client/cli/genesis_msg.go index 0859b03251..8aedae358a 100644 --- a/x/wasm/client/cli/genesis_msg.go +++ b/x/wasm/client/cli/genesis_msg.go @@ -8,10 +8,6 @@ import ( "errors" "fmt" - "github.com/CosmWasm/wasmd/x/wasm/ioutils" - - "github.com/CosmWasm/wasmd/x/wasm/keeper" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keyring" @@ -24,6 +20,8 @@ import ( "github.com/spf13/cobra" tmtypes "github.com/tendermint/tendermint/types" + "github.com/CosmWasm/wasmd/x/wasm/ioutils" + "github.com/CosmWasm/wasmd/x/wasm/keeper" "github.com/CosmWasm/wasmd/x/wasm/types" ) @@ -133,7 +131,7 @@ func GenesisInstantiateContractCmd(defaultNodeHome string, genesisMutator Genesi return fmt.Errorf("permissions were not granted for %s", senderAddr) } state.GenMsgs = append(state.GenMsgs, types.GenesisState_GenMsgs{ - Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &msg}, + Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: msg}, }) return nil }) @@ -238,10 +236,7 @@ func GenesisListContractsCmd(defaultNodeHome string, genReader GenesisReader) *c return err } state := g.WasmModuleState - all, err := GetAllContracts(state) - if err != nil { - return err - } + all := GetAllContracts(state) return printJSONOutput(cmd, all) }, } @@ -313,18 +308,7 @@ type ContractMeta struct { Info types.ContractInfo `json:"info"` } -// 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) { +func GetAllContracts(state *types.GenesisState) []ContractMeta { all := make([]ContractMeta, len(state.Contracts)) for i, c := range state.Contracts { all[i] = ContractMeta{ @@ -333,18 +317,11 @@ func GetAllContracts(state *types.GenesisState) ([]ContractMeta, error) { } } // 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(codeHash, senderAddr, msg.Label).String(), + ContractAddress: keeper.BuildContractAddressClassic(msg.CodeID, seq).String(), Info: types.ContractInfo{ CodeID: msg.CodeID, Creator: msg.Sender, @@ -352,9 +329,10 @@ func GetAllContracts(state *types.GenesisState) ([]ContractMeta, error) { Label: msg.Label, }, }) + seq++ } } - return all, nil + return all } func hasAccountBalance(cmd *cobra.Command, appState map[string]json.RawMessage, sender sdk.AccAddress, coins sdk.Coins) (bool, error) { @@ -381,19 +359,13 @@ func hasContract(state *types.GenesisState, contractAddr string) bool { return true } } + 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)) - } - 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 { + if keeper.BuildContractAddressClassic(msg.CodeID, seq).String() == contractAddr { return true } + seq++ } } return false @@ -486,6 +458,19 @@ 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 { diff --git a/x/wasm/client/cli/genesis_msg_test.go b/x/wasm/client/cli/genesis_msg_test.go index 6b67aa4942..a1d24f29cd 100644 --- a/x/wasm/client/cli/genesis_msg_test.go +++ b/x/wasm/client/cli/genesis_msg_test.go @@ -1,15 +1,12 @@ 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" @@ -366,8 +363,7 @@ func TestInstantiateContractCmd(t *testing.T) { } func TestExecuteContractCmd(t *testing.T) { - mySenderAddr := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len)) - myFirstContractAddress := keeper.BuildContractAddress([]byte("myCodeHash"), mySenderAddr, "my").String() + const firstContractAddress = "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr" minimalWasmGenesis := types.GenesisState{ Params: types.DefaultParams(), } @@ -394,7 +390,7 @@ func TestExecuteContractCmd(t *testing.T) { }, Contracts: []types.Contract{ { - ContractAddress: myFirstContractAddress, + ContractAddress: firstContractAddress, ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) { info.Created = nil }), @@ -403,34 +399,53 @@ func TestExecuteContractCmd(t *testing.T) { }, }, mutator: func(cmd *cobra.Command) { - cmd.SetArgs([]string{myFirstContractAddress, `{}`}) + cmd.SetArgs([]string{firstContractAddress, `{}`}) flagSet := cmd.Flags() flagSet.Set("run-as", myWellFundedAccount) }, expMsgCount: 1, }, - "all good with contract from genesis store messages": { + "all good with contract from genesis store messages without initial sequence": { srcGenesis: types.GenesisState{ Params: types.DefaultParams(), Codes: []types.Code{ { - CodeID: 1, - CodeInfo: types.CodeInfoFixture(func(info *types.CodeInfo) { - info.CodeHash = []byte("myCodeHash") - }), + CodeID: 1, + CodeInfo: types.CodeInfoFixture(), + CodeBytes: wasmIdent, + }, + }, + GenMsgs: []types.GenesisState_GenMsgs{ + {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: types.MsgInstantiateContractFixture()}}, + }, + }, + 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( - func(m *types.MsgInstantiateContract) { - m.Sender = mySenderAddr.String() - m.Label = "my" - })}}, + {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: types.MsgInstantiateContractFixture()}}, + }, + Sequences: []types.Sequence{ + {IDKey: types.KeyLastInstanceID, Value: 100}, }, }, mutator: func(cmd *cobra.Command) { - cmd.SetArgs([]string{myFirstContractAddress, `{}`}) + // See TestBuildContractAddress in keeper_test.go + cmd.SetArgs([]string{"cosmos1mujpjkwhut9yjw4xueyugc02evfv46y0dtmnz4lh8xxkkdapym9stu5qm8", `{}`}) flagSet := cmd.Flags() flagSet.Set("run-as", myWellFundedAccount) }, @@ -457,7 +472,7 @@ func TestExecuteContractCmd(t *testing.T) { }, Contracts: []types.Contract{ { - ContractAddress: myFirstContractAddress, + ContractAddress: firstContractAddress, ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) { info.Created = nil }), @@ -466,7 +481,7 @@ func TestExecuteContractCmd(t *testing.T) { }, }, mutator: func(cmd *cobra.Command) { - cmd.SetArgs([]string{myFirstContractAddress, `{}`}) + cmd.SetArgs([]string{firstContractAddress, `{}`}) flagSet := cmd.Flags() flagSet.Set("run-as", keeper.RandomBech32AccountAddress(t)) }, @@ -484,7 +499,7 @@ func TestExecuteContractCmd(t *testing.T) { }, Contracts: []types.Contract{ { - ContractAddress: myFirstContractAddress, + ContractAddress: firstContractAddress, ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) { info.Created = nil }), @@ -493,7 +508,7 @@ func TestExecuteContractCmd(t *testing.T) { }, }, mutator: func(cmd *cobra.Command) { - cmd.SetArgs([]string{myFirstContractAddress, `{}`}) + cmd.SetArgs([]string{firstContractAddress, `{}`}) flagSet := cmd.Flags() flagSet.Set("run-as", myWellFundedAccount) flagSet.Set("amount", "100stake") @@ -512,7 +527,7 @@ func TestExecuteContractCmd(t *testing.T) { }, Contracts: []types.Contract{ { - ContractAddress: myFirstContractAddress, + ContractAddress: firstContractAddress, ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) { info.Created = nil }), @@ -521,7 +536,7 @@ func TestExecuteContractCmd(t *testing.T) { }, }, mutator: func(cmd *cobra.Command) { - cmd.SetArgs([]string{myFirstContractAddress, `{}`}) + cmd.SetArgs([]string{firstContractAddress, `{}`}) flagSet := cmd.Flags() flagSet.Set("run-as", keeper.RandomBech32AccountAddress(t)) flagSet.Set("amount", "10stake") @@ -550,9 +565,6 @@ 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 @@ -583,55 +595,68 @@ 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{Sender: creatorAddr1.String(), Label: "first", CodeID: 1}}}, - {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Sender: creatorAddr2.String(), Label: "second", CodeID: 1}}}, + {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "first"}}}, + {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "second"}}}, }, }, exp: []ContractMeta{ { - ContractAddress: keeper.BuildContractAddress([]byte("firstCodeHash"), creatorAddr1, "first").String(), - Info: types.ContractInfo{Creator: creatorAddr1.String(), Label: "first", CodeID: 1}, + ContractAddress: keeper.BuildContractAddressClassic(0, 1).String(), + Info: types.ContractInfo{Label: "first"}, }, { - ContractAddress: keeper.BuildContractAddress([]byte("firstCodeHash"), creatorAddr2, "second").String(), - Info: types.ContractInfo{Creator: creatorAddr2.String(), Label: "second", CodeID: 1}, + ContractAddress: keeper.BuildContractAddressClassic(0, 2).String(), + Info: types.ContractInfo{Label: "second"}, }, }, }, - "read from contract and message state with contract sequence": { + "read from 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")}}, + 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.BuildContractAddressClassic(0, 100).String(), + Info: types.ContractInfo{Label: "hundred"}, }, + }, + }, + "read from contract and message state with contract sequence": { + src: types.GenesisState{ Contracts: []types.Contract{ { - ContractAddress: keeper.BuildContractAddress([]byte("firstCodeHash"), creatorAddr1, "first").String(), - ContractInfo: types.ContractInfo{Label: "first", CodeID: 1}, + ContractAddress: "first-contract", + ContractInfo: types.ContractInfo{Label: "first"}, }, }, + Sequences: []types.Sequence{ + {IDKey: types.KeyLastInstanceID, Value: 100}, + }, GenMsgs: []types.GenesisState_GenMsgs{ - {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Sender: creatorAddr1.String(), Label: "hundred", CodeID: 100}}}, + {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "hundred"}}}, }, }, exp: []ContractMeta{ { - ContractAddress: keeper.BuildContractAddress([]byte("firstCodeHash"), creatorAddr1, "first").String(), - Info: types.ContractInfo{Label: "first", CodeID: 1}, + ContractAddress: "first-contract", + Info: types.ContractInfo{Label: "first"}, }, { - ContractAddress: keeper.BuildContractAddress([]byte("otherCodeHash"), creatorAddr1, "hundred").String(), - Info: types.ContractInfo{Creator: creatorAddr1.String(), Label: "hundred", CodeID: 100}, + ContractAddress: keeper.BuildContractAddressClassic(0, 100).String(), + Info: types.ContractInfo{Label: "hundred"}, }, }, }, } for msg, spec := range specs { t.Run(msg, func(t *testing.T) { - got, err := GetAllContracts(&spec.src) - require.NoError(t, err) + got := GetAllContracts(&spec.src) assert.Equal(t, spec.exp, got) }) } diff --git a/x/wasm/client/cli/query.go b/x/wasm/client/cli/query.go index f399bfd7d6..b847b3d843 100644 --- a/x/wasm/client/cli/query.go +++ b/x/wasm/client/cli/query.go @@ -67,11 +67,12 @@ func GetCmdLibVersion() *cobra.Command { // GetCmdBuildAddress build a contract address func GetCmdBuildAddress() *cobra.Command { + decoder := newArgDecoder(hex.DecodeString) cmd := &cobra.Command{ - Use: "build-address [code-hash] [creator-address] [label]", + Use: "build-address [code-hash] [creator-address] [salt-hex-encoded] [json_encoded_init_args (required when set as fixed)]", Short: "build contract address", Aliases: []string{"address"}, - Args: cobra.ExactArgs(3), + Args: cobra.RangeArgs(3, 4), RunE: func(cmd *cobra.Command, args []string) error { codeHash, err := hex.DecodeString(args[0]) if err != nil { @@ -81,14 +82,27 @@ func GetCmdBuildAddress() *cobra.Command { 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) + salt, err := hex.DecodeString(args[2]) + switch { + case err != nil: + return fmt.Errorf("salt: %s", err) + case len(salt) == 0: + return errors.New("empty salt") + } + + if len(args) == 3 { + cmd.Println(keeper.BuildContractAddressPredictable(codeHash, creator, salt, []byte{}).String()) + return nil + } + msg := types.RawContractMessage(args[3]) + if err := msg.ValidateBasic(); err != nil { + return fmt.Errorf("init message: %s", err) } - cmd.Println(keeper.BuildContractAddress(codeHash, creator, label).String()) + cmd.Println(keeper.BuildContractAddressPredictable(codeHash, creator, salt, msg).String()) return nil }, } + decoder.RegisterFlags(cmd.PersistentFlags(), "salt") return cmd } @@ -526,7 +540,7 @@ func newArgDecoder(def func(string) ([]byte, error)) *argumentDecoder { func (a *argumentDecoder) RegisterFlags(f *flag.FlagSet, argName string) { f.BoolVar(&a.asciiF, "ascii", false, "ascii encoded "+argName) - f.BoolVar(&a.hexF, "hex", false, "hex encoded "+argName) + f.BoolVar(&a.hexF, "hex", false, "hex encoded "+argName) f.BoolVar(&a.b64F, "b64", false, "base64 encoded "+argName) } diff --git a/x/wasm/client/cli/tx.go b/x/wasm/client/cli/tx.go index c4dfa473f4..d65e45c2d1 100644 --- a/x/wasm/client/cli/tx.go +++ b/x/wasm/client/cli/tx.go @@ -1,6 +1,7 @@ package cli import ( + "encoding/hex" "errors" "fmt" "os" @@ -11,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/version" "github.com/spf13/cobra" flag "github.com/spf13/pflag" @@ -23,6 +25,7 @@ const ( flagLabel = "label" flagAdmin = "admin" flagNoAdmin = "no-admin" + flagFixMsg = "fix-msg" flagRunAs = "run-as" flagInstantiateByEverybody = "instantiate-everybody" flagInstantiateNobody = "instantiate-nobody" @@ -43,6 +46,7 @@ func GetTxCmd() *cobra.Command { txCmd.AddCommand( StoreCodeCmd(), InstantiateContractCmd(), + InstantiateContract2Cmd(), ExecuteContractCmd(), MigrateContractCmd(), UpdateContractAdminCmd(), @@ -174,8 +178,14 @@ func parseAccessConfigFlags(flags *flag.FlagSet) (*types.AccessConfig, error) { // InstantiateContractCmd will instantiate a contract from previously uploaded code. func InstantiateContractCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "instantiate [code_id_int64] [json_encoded_init_args] --label [text] --admin [address,optional] --amount [coins,optional]", - Short: "Instantiate a wasm contract", + Use: "instantiate [code_id_int64] [json_encoded_init_args] --label [text] --admin [address,optional] --amount [coins,optional] ", + Short: "Instantiate a wasm contract", + Long: fmt.Sprintf(`Creates a new instance of an uploaded wasm code with the given 'constructor' message. +Each contract instance has a unique address assigned. +Example: +$ %s wasmd tx wasm instantiate 1 '{"foo":"bar"}' --admin="$(%s keys show mykey -a)" \ + --from mykey --amount="100ustake" --label "local0.1.0" +`, version.AppName, version.AppName), Aliases: []string{"start", "init", "inst", "i"}, Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { @@ -183,7 +193,6 @@ func InstantiateContractCmd() *cobra.Command { if err != nil { return err } - msg, err := parseInstantiateArgs(args[0], args[1], clientCtx.GetFromAddress(), cmd.Flags()) if err != nil { return err @@ -191,7 +200,7 @@ func InstantiateContractCmd() *cobra.Command { if err := msg.ValidateBasic(); err != nil { return err } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } @@ -203,43 +212,105 @@ func InstantiateContractCmd() *cobra.Command { return cmd } -func parseInstantiateArgs(rawCodeID, initMsg string, sender sdk.AccAddress, flags *flag.FlagSet) (types.MsgInstantiateContract, error) { +// InstantiateContract2Cmd will instantiate a contract from previously uploaded code with predicable address generated +func InstantiateContract2Cmd() *cobra.Command { + decoder := newArgDecoder(hex.DecodeString) + cmd := &cobra.Command{ + Use: "instantiate2 [code_id_int64] [json_encoded_init_args] [salt] --label [text] --admin [address,optional] --amount [coins,optional] " + + "--fix-msg [bool,optional]", + Short: "Instantiate a wasm contract with predictable address", + Long: fmt.Sprintf(`Creates a new instance of an uploaded wasm code with the given 'constructor' message. +Each contract instance has a unique address assigned. They are assigned automatically but in order to have predictable addresses +for special use cases, the given 'salt' argument and '--fix-msg' parameters can be used to generate a custom address. + +Predictable address example (also see '%s query wasm build-address -h'): +$ %s wasmd tx wasm instantiate2 1 '{"foo":"bar"}' $(echo -n "testing" | xxd -ps) --admin="$(%s keys show mykey -a)" \ + --from mykey --amount="100ustake" --label "local0.1.0" \ + --fix-msg +`, version.AppName, version.AppName, version.AppName), + Aliases: []string{"start", "init", "inst", "i"}, + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + salt, err := decoder.DecodeString(args[2]) + if err != nil { + return fmt.Errorf("salt: %w", err) + } + fixMsg, err := cmd.Flags().GetBool(flagFixMsg) + if err != nil { + return fmt.Errorf("fix msg: %w", err) + } + data, err := parseInstantiateArgs(args[0], args[1], clientCtx.GetFromAddress(), cmd.Flags()) + if err != nil { + return err + } + msg := &types.MsgInstantiateContract2{ + Sender: data.Sender, + Admin: data.Admin, + CodeID: data.CodeID, + Label: data.Label, + Msg: data.Msg, + Funds: data.Funds, + Salt: salt, + FixMsg: fixMsg, + } + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation") + cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists") + cmd.Flags().String(flagAdmin, "", "Address of an admin") + cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin") + cmd.Flags().Bool(flagFixMsg, false, "An optional flag to include the json_encoded_init_args for the predictable address generation mode") + decoder.RegisterFlags(cmd.PersistentFlags(), "salt") + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func parseInstantiateArgs(rawCodeID, initMsg string, sender sdk.AccAddress, flags *flag.FlagSet) (*types.MsgInstantiateContract, error) { // get the id of the code to instantiate codeID, err := strconv.ParseUint(rawCodeID, 10, 64) if err != nil { - return types.MsgInstantiateContract{}, err + return nil, err } amountStr, err := flags.GetString(flagAmount) if err != nil { - return types.MsgInstantiateContract{}, fmt.Errorf("amount: %s", err) + return nil, fmt.Errorf("amount: %s", err) } amount, err := sdk.ParseCoinsNormalized(amountStr) if err != nil { - return types.MsgInstantiateContract{}, fmt.Errorf("amount: %s", err) + return nil, fmt.Errorf("amount: %s", err) } label, err := flags.GetString(flagLabel) if err != nil { - return types.MsgInstantiateContract{}, fmt.Errorf("label: %s", err) + return nil, fmt.Errorf("label: %s", err) } if label == "" { - return types.MsgInstantiateContract{}, errors.New("label is required on all contracts") + return nil, errors.New("label is required on all contracts") } adminStr, err := flags.GetString(flagAdmin) if err != nil { - return types.MsgInstantiateContract{}, fmt.Errorf("admin: %s", err) + return nil, fmt.Errorf("admin: %s", err) } noAdmin, err := flags.GetBool(flagNoAdmin) if err != nil { - return types.MsgInstantiateContract{}, fmt.Errorf("no-admin: %s", err) + return nil, fmt.Errorf("no-admin: %s", err) } // ensure sensible admin is set (or explicitly immutable) if adminStr == "" && !noAdmin { - return types.MsgInstantiateContract{}, fmt.Errorf("you must set an admin or explicitly pass --no-admin to make it immutible (wasmd issue #719)") + return nil, fmt.Errorf("you must set an admin or explicitly pass --no-admin to make it immutible (wasmd issue #719)") } if adminStr != "" && noAdmin { - return types.MsgInstantiateContract{}, fmt.Errorf("you set an admin and passed --no-admin, those cannot both be true") + return nil, fmt.Errorf("you set an admin and passed --no-admin, those cannot both be true") } // build and sign the transaction, then broadcast to Tendermint @@ -251,7 +322,7 @@ func parseInstantiateArgs(rawCodeID, initMsg string, sender sdk.AccAddress, flag Msg: []byte(initMsg), Admin: adminStr, } - return msg, nil + return &msg, nil } // ExecuteContractCmd will instantiate a contract from previously uploaded code. diff --git a/x/wasm/handler.go b/x/wasm/handler.go index e6004cd7a0..c7f27b754b 100644 --- a/x/wasm/handler.go +++ b/x/wasm/handler.go @@ -29,6 +29,8 @@ func NewHandler(k types.ContractOpsKeeper) sdk.Handler { res, err = msgServer.StoreCode(sdk.WrapSDKContext(ctx), msg) case *MsgInstantiateContract: res, err = msgServer.InstantiateContract(sdk.WrapSDKContext(ctx), msg) + case *MsgInstantiateContract2: + res, err = msgServer.InstantiateContract2(sdk.WrapSDKContext(ctx), msg) case *MsgExecuteContract: res, err = msgServer.ExecuteContract(sdk.WrapSDKContext(ctx), msg) case *MsgMigrateContract: diff --git a/x/wasm/keeper/addresses.go b/x/wasm/keeper/addresses.go new file mode 100644 index 0000000000..67eabb4403 --- /dev/null +++ b/x/wasm/keeper/addresses.go @@ -0,0 +1,76 @@ +package keeper + +import ( + "encoding/binary" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + + "github.com/CosmWasm/wasmd/x/wasm/types" +) + +// AddressGenerator abstract address generator to be used for a single contract address +type AddressGenerator func(ctx sdk.Context, codeID uint64, checksum []byte) sdk.AccAddress + +// ClassicAddressGenerator generates a contract address using codeID and instanceID sequence +func (k Keeper) ClassicAddressGenerator() AddressGenerator { + return func(ctx sdk.Context, codeID uint64, _ []byte) sdk.AccAddress { + instanceID := k.autoIncrementID(ctx, types.KeyLastInstanceID) + return BuildContractAddressClassic(codeID, instanceID) + } +} + +// PredicableAddressGenerator generates a predictable contract address +func PredicableAddressGenerator(creator sdk.AccAddress, salt []byte, msg []byte, fixMsg bool) AddressGenerator { + return func(ctx sdk.Context, _ uint64, checksum []byte) sdk.AccAddress { + if !fixMsg { // clear msg to not be included in the address generation + msg = []byte{} + } + return BuildContractAddressPredictable(checksum, creator, salt, msg) + } +} + +// BuildContractAddressClassic builds an sdk account address for a contract. +func BuildContractAddressClassic(codeID, instanceID uint64) sdk.AccAddress { + contractID := make([]byte, 16) + binary.BigEndian.PutUint64(contractID[:8], codeID) + binary.BigEndian.PutUint64(contractID[8:], instanceID) + return address.Module(types.ModuleName, contractID)[:types.ContractAddrLen] +} + +// BuildContractAddressPredictable generates a contract address for the wasm module with len = types.ContractAddrLen using the +// Cosmos SDK address.Module function. +// Internally a key is built containing: +// (len(checksum) | checksum | len(sender_address) | sender_address | len(salt) | salt| len(initMsg) | initMsg). +// +// All method parameter values must be valid and not nil. +func BuildContractAddressPredictable(checksum []byte, creator sdk.AccAddress, salt, initMsg types.RawContractMessage) sdk.AccAddress { + if len(checksum) != 32 { + panic("invalid checksum") + } + if err := sdk.VerifyAddressFormat(creator); err != nil { + panic(fmt.Sprintf("creator: %s", err)) + } + if err := types.ValidateSalt(salt); err != nil { + panic(fmt.Sprintf("salt: %s", err)) + } + if err := initMsg.ValidateBasic(); len(initMsg) != 0 && err != nil { + panic(fmt.Sprintf("initMsg: %s", err)) + } + checksum = UInt64LengthPrefix(checksum) + creator = UInt64LengthPrefix(creator) + salt = UInt64LengthPrefix(salt) + initMsg = UInt64LengthPrefix(initMsg) + key := make([]byte, len(checksum)+len(creator)+len(salt)+len(initMsg)) + copy(key[0:], checksum) + copy(key[len(checksum):], creator) + copy(key[len(checksum)+len(creator):], salt) + copy(key[len(checksum)+len(creator)+len(salt):], initMsg) + return address.Module(types.ModuleName, key)[:types.ContractAddrLen] +} + +// UInt64LengthPrefix prepend big endian encoded byte length +func UInt64LengthPrefix(bz []byte) []byte { + return append(sdk.Uint64ToBigEndian(uint64(len(bz))), bz...) +} diff --git a/x/wasm/keeper/addresses_test.go b/x/wasm/keeper/addresses_test.go new file mode 100644 index 0000000000..fbcc607fc5 --- /dev/null +++ b/x/wasm/keeper/addresses_test.go @@ -0,0 +1,432 @@ +package keeper + +import ( + "encoding/json" + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + tmbytes "github.com/tendermint/tendermint/libs/bytes" +) + +func TestBuildContractAddress(t *testing.T) { + x, y := sdk.GetConfig().GetBech32AccountAddrPrefix(), sdk.GetConfig().GetBech32AccountPubPrefix() + t.Cleanup(func() { + sdk.GetConfig().SetBech32PrefixForAccount(x, y) + }) + sdk.GetConfig().SetBech32PrefixForAccount("purple", "purple") + + // test vectors generated via cosmjs: https://github.com/cosmos/cosmjs/pull/1253/files + type Spec struct { + In struct { + Checksum tmbytes.HexBytes `json:"checksum"` + Creator sdk.AccAddress `json:"creator"` + Salt tmbytes.HexBytes `json:"salt"` + Msg string `json:"msg"` + } `json:"in"` + Out struct { + Address sdk.AccAddress `json:"address"` + } `json:"out"` + } + var specs []Spec + require.NoError(t, json.Unmarshal([]byte(goldenMasterPredictableContractAddr), &specs)) + require.NotEmpty(t, specs) + for i, spec := range specs { + t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) { + // when + gotAddr := BuildContractAddressPredictable(spec.In.Checksum, spec.In.Creator, spec.In.Salt.Bytes(), []byte(spec.In.Msg)) + + require.Equal(t, spec.Out.Address.String(), gotAddr.String()) + require.NoError(t, sdk.VerifyAddressFormat(gotAddr)) + }) + } +} + +const goldenMasterPredictableContractAddr = `[ + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": null + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000001610000000000000000", + "addressData": "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847" + }, + "out": { + "address": "purple1t6r960j945lfv8mhl4mage2rg97w63xeynwrupum2s2l7em4lprs9ce5hk" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc00000000000000016100000000000000027b7d", + "addressData": "0995499608947a5281e2c7ebd71bdb26a1ad981946dad57f6c4d3ee35de77835" + }, + "out": { + "address": "purple1px25n9sgj3a99q0zcl4awx7my6s6mxqegmdd2lmvf5lwxh080q6suttktr" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "83326e554723b15bac664ceabc8a5887e27003abe9fbd992af8c7bcea4745167" + }, + "out": { + "address": "purple1svexu428ywc4htrxfn4tezjcsl38qqata8aany4033auafr529ns4v254c" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": null + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000", + "addressData": "9384c6248c0bb171e306fd7da0993ec1e20eba006452a3a9e078883eb3594564" + }, + "out": { + "address": "purple1jwzvvfyvpwchrccxl476pxf7c83qawsqv3f2820q0zyrav6eg4jqdcq7gc" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d", + "addressData": "9a8d5f98fb186825401a26206158e7a1213311a9b6a87944469913655af52ffb" + }, + "out": { + "address": "purple1n2x4lx8mrp5z2sq6ycsxzk885ysnxydfk658j3zxnyfk2kh49lasesxf6j" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "932f07bc53f7d0b0b43cb5a54ac3e245b205e6ae6f7c1d991dc6af4a2ff9ac18" + }, + "out": { + "address": "purple1jvhs00zn7lgtpdpukkj54slzgkeqte4wda7pmxgac6h55tle4svq8cmp60" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": null + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000001610000000000000000", + "addressData": "9725e94f528d8b78d33c25f3dfcd60e6142d8be60ab36f6a5b59036fd51560db" + }, + "out": { + "address": "purple1juj7jn6j3k9h35euyhealntquc2zmzlxp2ek76jmtypkl4g4vrdsfwmwxk" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff00000000000000016100000000000000027b7d", + "addressData": "b056e539bbaf447ba18f3f13b792970111fc78933eb6700f4d227b5216d63658" + }, + "out": { + "address": "purple1kptw2wdm4az8hgv08ufm0y5hqyglc7yn86m8qr6dyfa4y9kkxevqmkm9q3" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "6c98434180f052294ff89fb6d2dae34f9f4468b0b8e6e7c002b2a44adee39abd" + }, + "out": { + "address": "purple1djvyxsvq7pfzjnlcn7md9khrf705g69shrnw0sqzk2jy4hhrn27sjh2ysy" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": null + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000", + "addressData": "0aaf1c31c5d529d21d898775bc35b3416f47bfd99188c334c6c716102cbd3101" + }, + "out": { + "address": "purple1p2h3cvw9655ay8vfsa6mcddng9h5007ejxyvxdxxcutpqt9axyqsagmmay" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d", + "addressData": "36fe6ab732187cdfed46290b448b32eb7f4798e7a4968b0537de8a842cbf030e" + }, + "out": { + "address": "purple1xmlx4dejrp7dlm2x9y95fzejadl50x885jtgkpfhm69ggt9lqv8qk3vn4f" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "a0d0c942adac6f3e5e7c23116c4c42a24e96e0ab75f53690ec2d3de16067c751" + }, + "out": { + "address": "purple15rgvjs4d43hnuhnuyvgkcnzz5f8fdc9twh6ndy8v9577zcr8cags40l9dt" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": null + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000001610000000000000000", + "addressData": "b95c467218d408a0f93046f227b6ece7fe18133ff30113db4d2a7becdfeca141" + }, + "out": { + "address": "purple1h9wyvusc6sy2p7fsgmez0dhvullpsyel7vq38k6d9fa7ehlv59qsvnyh36" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc00000000000000016100000000000000027b7d", + "addressData": "23fe45dbbd45dc6cd25244a74b6e99e7a65bf0bac2f2842a05049d37555a3ae6" + }, + "out": { + "address": "purple1y0lytkaaghwxe5jjgjn5km5eu7n9hu96ctegg2s9qjwnw4268tnqxhg60a" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "6faea261ed63baa65b05726269e83b217fa6205dc7d9fb74f9667d004a69c082" + }, + "out": { + "address": "purple1d7h2yc0dvwa2vkc9wf3xn6pmy9l6vgzaclvlka8eve7sqjnfczpqqsdnwu" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": null + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000", + "addressData": "67a3ab6384729925fdb144574628ce96836fe098d2c6be4e84ac106b2728d96c" + }, + "out": { + "address": "purple1v736kcuyw2vjtld3g3t5v2xwj6pklcyc6trtun5y4sgxkfegm9kq7vgpnt" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d", + "addressData": "23a121263bfce05c144f4af86f3d8a9f87dc56f9dc48dbcffc8c5a614da4c661" + }, + "out": { + "address": "purple1ywsjzf3mlns9c9z0ftux70v2n7rac4hem3ydhnlu33dxzndycesssc7x2m" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "dd90dba6d6fcd5fb9c9c8f536314eb1bb29cb5aa084b633c5806b926a5636b58" + }, + "out": { + "address": "purple1mkgdhfkkln2lh8yu3afkx98trwefedd2pp9kx0zcq6ujdftrddvq50esay" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": null + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000001610000000000000000", + "addressData": "547a743022f4f1af05b102f57bf1c1c7d7ee81bae427dc20d36b2c4ec57612ae" + }, + "out": { + "address": "purple123a8gvpz7nc67pd3qt6hhuwpclt7aqd6usnacgxndvkya3tkz2hq5hz38f" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff00000000000000016100000000000000027b7d", + "addressData": "416e169110e4b411bc53162d7503b2bbf14d6b36b1413a4f4c9af622696e9665" + }, + "out": { + "address": "purple1g9hpdygsuj6pr0znzckh2qajh0c566ekk9qn5n6vntmzy6twjejsrl9alk" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "619a0988b92d8796cea91dea63cbb1f1aefa4a6b6ee5c5d1e937007252697220" + }, + "out": { + "address": "purple1vxdqnz9e9kredn4frh4x8ja37xh05jntdmjut50fxuq8y5nfwgsquu9mxh" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": null + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000", + "addressData": "d8af856a6a04852d19b647ad6d4336eb26e077f740aef1a0331db34d299a885a" + }, + "out": { + "address": "purple1mzhc26n2qjzj6xdkg7kk6sekavnwqalhgzh0rgpnrke562v63pdq8grp8q" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d", + "addressData": "c7fb7bea96daab23e416c4fcf328215303005e1d0d5424257335568e5381e33c" + }, + "out": { + "address": "purple1clahh65km24j8eqkcn70x2pp2vpsqhsap42zgftnx4tgu5upuv7q9ywjws" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "ccdf9dea141a6c2475870529ab38fae9dec30df28e005894fe6578b66133ab4a" + }, + "out": { + "address": "purple1en0em6s5rfkzgav8q556kw86a80vxr0j3cq93987v4utvcfn4d9q0tql4w" + } + } +] +` diff --git a/x/wasm/keeper/contract_keeper.go b/x/wasm/keeper/contract_keeper.go index 6e1195dbd1..564adc5532 100644 --- a/x/wasm/keeper/contract_keeper.go +++ b/x/wasm/keeper/contract_keeper.go @@ -11,7 +11,18 @@ var _ types.ContractOpsKeeper = PermissionedKeeper{} // decoratedKeeper contains a subset of the wasm keeper that are already or can be guarded by an authorization policy in the future type decoratedKeeper interface { create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, instantiateAccess *types.AccessConfig, authZ AuthorizationPolicy) (codeID uint64, checksum []byte, err error) - instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins, authZ AuthorizationPolicy) (sdk.AccAddress, []byte, error) + + instantiate( + ctx sdk.Context, + codeID uint64, + creator, admin sdk.AccAddress, + initMsg []byte, + label string, + deposit sdk.Coins, + addressGenerator AddressGenerator, + authZ AuthorizationPolicy, + ) (sdk.AccAddress, []byte, error) + migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newCodeID uint64, msg []byte, authZ AuthorizationPolicy) ([]byte, error) setContractAdmin(ctx sdk.Context, contractAddress, caller, newAdmin sdk.AccAddress, authZ AuthorizationPolicy) error pinCode(ctx sdk.Context, codeID uint64) error @@ -20,6 +31,7 @@ type decoratedKeeper interface { Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte) ([]byte, error) setContractInfoExtension(ctx sdk.Context, contract sdk.AccAddress, extra types.ContractInfoExtension) error setAccessConfig(ctx sdk.Context, codeID uint64, caller sdk.AccAddress, newConfig types.AccessConfig, autz AuthorizationPolicy) error + ClassicAddressGenerator() AddressGenerator } type PermissionedKeeper struct { @@ -43,8 +55,40 @@ func (p PermissionedKeeper) Create(ctx sdk.Context, creator sdk.AccAddress, wasm return p.nested.create(ctx, creator, wasmCode, instantiateAccess, p.authZPolicy) } -func (p PermissionedKeeper) Instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins) (sdk.AccAddress, []byte, error) { - return p.nested.instantiate(ctx, codeID, creator, admin, initMsg, label, deposit, p.authZPolicy) +// Instantiate creates an instance of a WASM contract using the classic sequence based address generator +func (p PermissionedKeeper) Instantiate( + ctx sdk.Context, + codeID uint64, + creator, admin sdk.AccAddress, + initMsg []byte, + label string, + deposit sdk.Coins, +) (sdk.AccAddress, []byte, error) { + return p.nested.instantiate(ctx, codeID, creator, admin, initMsg, label, deposit, p.nested.ClassicAddressGenerator(), p.authZPolicy) +} + +// Instantiate2 creates an instance of a WASM contract using the predictable address generator +func (p PermissionedKeeper) Instantiate2( + ctx sdk.Context, + codeID uint64, + creator, admin sdk.AccAddress, + initMsg []byte, + label string, + deposit sdk.Coins, + salt []byte, + fixMsg bool, +) (sdk.AccAddress, []byte, error) { + return p.nested.instantiate( + ctx, + codeID, + creator, + admin, + initMsg, + label, + deposit, + PredicableAddressGenerator(creator, salt, initMsg, fixMsg), + p.authZPolicy, + ) } func (p PermissionedKeeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) ([]byte, error) { diff --git a/x/wasm/keeper/contract_keeper_test.go b/x/wasm/keeper/contract_keeper_test.go new file mode 100644 index 0000000000..0a8bd1e224 --- /dev/null +++ b/x/wasm/keeper/contract_keeper_test.go @@ -0,0 +1,168 @@ +package keeper + +import ( + "encoding/json" + "fmt" + "math" + "strings" + "testing" + + "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/CosmWasm/wasmd/x/wasm/types" +) + +func TestInstantiate2(t *testing.T) { + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) + example := StoreHackatomExampleContract(t, parentCtx, keepers) + otherExample := StoreReflectContract(t, parentCtx, keepers) + mock := &wasmtesting.MockWasmer{} + wasmtesting.MakeInstantiable(mock) + keepers.WasmKeeper.wasmVM = mock // set mock to not fail on contract init message + + verifierAddr := RandomAccountAddress(t) + beneficiaryAddr := RandomAccountAddress(t) + initMsg := mustMarshal(t, HackatomExampleInitMsg{Verifier: verifierAddr, Beneficiary: beneficiaryAddr}) + + otherAddr := keepers.Faucet.NewFundedRandomAccount(parentCtx, sdk.NewInt64Coin("denom", 1_000_000_000)) + + const ( + mySalt = "my salt" + myLabel = "my label" + ) + // create instances for duplicate checks + exampleContract := func(t *testing.T, ctx sdk.Context, fixMsg bool) { + _, _, err := keepers.ContractKeeper.Instantiate2( + ctx, + example.CodeID, + example.CreatorAddr, + nil, + initMsg, + myLabel, + sdk.NewCoins(sdk.NewInt64Coin("denom", 1)), + []byte(mySalt), + fixMsg, + ) + require.NoError(t, err) + } + exampleWithFixMsg := func(t *testing.T, ctx sdk.Context) { + exampleContract(t, ctx, true) + } + exampleWithoutFixMsg := func(t *testing.T, ctx sdk.Context) { + exampleContract(t, ctx, false) + } + specs := map[string]struct { + setup func(t *testing.T, ctx sdk.Context) + codeID uint64 + sender sdk.AccAddress + salt []byte + initMsg json.RawMessage + fixMsg bool + expErr error + }{ + "fix msg - generates different address than without fixMsg": { + setup: exampleWithoutFixMsg, + codeID: example.CodeID, + sender: example.CreatorAddr, + salt: []byte(mySalt), + initMsg: initMsg, + fixMsg: true, + }, + "fix msg - different sender": { + setup: exampleWithFixMsg, + codeID: example.CodeID, + sender: otherAddr, + salt: []byte(mySalt), + initMsg: initMsg, + fixMsg: true, + }, + "fix msg - different code": { + setup: exampleWithFixMsg, + codeID: otherExample.CodeID, + sender: example.CreatorAddr, + salt: []byte(mySalt), + initMsg: []byte(`{}`), + fixMsg: true, + }, + "fix msg - different salt": { + setup: exampleWithFixMsg, + codeID: example.CodeID, + sender: example.CreatorAddr, + salt: []byte("other salt"), + initMsg: initMsg, + fixMsg: true, + }, + "fix msg - different init msg": { + setup: exampleWithFixMsg, + codeID: example.CodeID, + sender: example.CreatorAddr, + salt: []byte(mySalt), + initMsg: mustMarshal(t, HackatomExampleInitMsg{Verifier: otherAddr, Beneficiary: beneficiaryAddr}), + fixMsg: true, + }, + "different sender": { + setup: exampleWithoutFixMsg, + codeID: example.CodeID, + sender: otherAddr, + salt: []byte(mySalt), + initMsg: initMsg, + }, + "different code": { + setup: exampleWithoutFixMsg, + codeID: otherExample.CodeID, + sender: example.CreatorAddr, + salt: []byte(mySalt), + initMsg: []byte(`{}`), + }, + "different salt": { + setup: exampleWithoutFixMsg, + codeID: example.CodeID, + sender: example.CreatorAddr, + salt: []byte(`other salt`), + initMsg: initMsg, + }, + "different init msg - reject same address": { + setup: exampleWithoutFixMsg, + codeID: example.CodeID, + sender: example.CreatorAddr, + salt: []byte(mySalt), + initMsg: mustMarshal(t, HackatomExampleInitMsg{Verifier: otherAddr, Beneficiary: beneficiaryAddr}), + expErr: types.ErrDuplicate, + }, + "fix msg - long msg": { + setup: exampleWithFixMsg, + codeID: example.CodeID, + sender: otherAddr, + salt: []byte(mySalt), + initMsg: []byte(fmt.Sprintf(`{"foo":%q}`, strings.Repeat("b", math.MaxInt16+1))), // too long kills CI + fixMsg: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + ctx, _ := parentCtx.CacheContext() + spec.setup(t, ctx) + gotAddr, _, gotErr := keepers.ContractKeeper.Instantiate2( + ctx, + spec.codeID, + spec.sender, + nil, + spec.initMsg, + myLabel, + sdk.NewCoins(sdk.NewInt64Coin("denom", 2)), + spec.salt, + spec.fixMsg, + ) + if spec.expErr != nil { + assert.ErrorIs(t, gotErr, spec.expErr) + return + } + require.NoError(t, gotErr) + assert.NotEmpty(t, gotAddr) + }) + } +} diff --git a/x/wasm/keeper/genesis.go b/x/wasm/keeper/genesis.go index d81750b708..7fa5280b9e 100644 --- a/x/wasm/keeper/genesis.go +++ b/x/wasm/keeper/genesis.go @@ -35,6 +35,7 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState, staki } } + var maxContractID int for i, contract := range data.Contracts { contractAddr, err := sdk.AccAddressFromBech32(contract.ContractAddress) if err != nil { @@ -44,6 +45,7 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState, staki if err != nil { return nil, 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 { @@ -58,6 +60,10 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState, staki if seqVal <= maxCodeID { return nil, sdkerrors.Wrapf(types.ErrInvalid, "seq %s with value: %d must be greater than: %d ", string(types.KeyLastCodeID), seqVal, maxCodeID) } + seqVal = keeper.PeekAutoIncrementID(ctx, types.KeyLastInstanceID) + if seqVal <= uint64(maxContractID) { + return nil, sdkerrors.Wrapf(types.ErrInvalid, "seq %s with value: %d must be greater than: %d ", string(types.KeyLastInstanceID), seqVal, maxContractID) + } if len(data.GenMsgs) == 0 { return nil, nil @@ -111,7 +117,7 @@ func ExportGenesis(ctx sdk.Context, keeper *Keeper) *types.GenesisState { return false }) - for _, k := range [][]byte{types.KeyLastCodeID} { + for _, k := range [][]byte{types.KeyLastCodeID, types.KeyLastInstanceID} { genState.Sequences = append(genState.Sequences, types.Sequence{ IDKey: k, Value: keeper.PeekAutoIncrementID(ctx, k), diff --git a/x/wasm/keeper/genesis_test.go b/x/wasm/keeper/genesis_test.go index 4b65f82eaa..aee7ad009e 100644 --- a/x/wasm/keeper/genesis_test.go +++ b/x/wasm/keeper/genesis_test.go @@ -11,14 +11,11 @@ import ( "testing" "time" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - - "github.com/cosmos/cosmos-sdk/types/address" - "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" distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" @@ -69,7 +66,7 @@ func TestGenesisExportImport(t *testing.T) { creatorAddr, err := sdk.AccAddressFromBech32(codeInfo.Creator) require.NoError(t, err) - codeID, checksum, err := contractKeeper.Create(srcCtx, creatorAddr, wasmCode, &codeInfo.InstantiateConfig) + codeID, _, err := contractKeeper.Create(srcCtx, creatorAddr, wasmCode, &codeInfo.InstantiateConfig) require.NoError(t, err) if pinned { contractKeeper.PinCode(srcCtx, codeID) @@ -84,7 +81,7 @@ func TestGenesisExportImport(t *testing.T) { } contract.CodeID = codeID - contractAddr := BuildContractAddress(checksum, creatorAddr, "testing") + contractAddr := wasmKeeper.ClassicAddressGenerator()(srcCtx, codeID, nil) wasmKeeper.storeContractInfo(srcCtx, contractAddr, &contract) wasmKeeper.appendToContractHistory(srcCtx, contractAddr, history...) wasmKeeper.importContractState(srcCtx, contractAddr, stateModels) @@ -160,16 +157,6 @@ func TestGenesisInit(t *testing.T) { require.NoError(t, err) myCodeInfo := wasmTypes.CodeInfoFixture(wasmTypes.WithSHA256CodeHash(wasmCode)) - mySenderAddr := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len)) - myLabel := "testing" - myContractInfoFixture := func(mutators ...func(*types.ContractInfo)) types.ContractInfo { - return types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { - c.CodeID = 1 - c.Creator = mySenderAddr.String() - c.Label = myLabel - }, types.OnlyGenesisFields) - } - specs := map[string]struct { src types.GenesisState stakingMock StakingKeeperMock @@ -185,6 +172,7 @@ func TestGenesisInit(t *testing.T) { }}, Sequences: []types.Sequence{ {IDKey: types.KeyLastCodeID, Value: 2}, + {IDKey: types.KeyLastInstanceID, Value: 1}, }, Params: types.DefaultParams(), }, @@ -203,6 +191,7 @@ func TestGenesisInit(t *testing.T) { }}, Sequences: []types.Sequence{ {IDKey: types.KeyLastCodeID, Value: 10}, + {IDKey: types.KeyLastInstanceID, Value: 1}, }, Params: types.DefaultParams(), }, @@ -222,6 +211,7 @@ func TestGenesisInit(t *testing.T) { Contracts: nil, Sequences: []types.Sequence{ {IDKey: types.KeyLastCodeID, Value: 3}, + {IDKey: types.KeyLastInstanceID, Value: 1}, }, Params: types.DefaultParams(), }, @@ -278,12 +268,13 @@ func TestGenesisInit(t *testing.T) { }}, Contracts: []types.Contract{ { - ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, myLabel).String(), - ContractInfo: myContractInfoFixture(), + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), }, }, Sequences: []types.Sequence{ {IDKey: types.KeyLastCodeID, Value: 2}, + {IDKey: types.KeyLastInstanceID, Value: 2}, }, Params: types.DefaultParams(), }, @@ -298,17 +289,16 @@ func TestGenesisInit(t *testing.T) { }}, Contracts: []types.Contract{ { - ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, myLabel).String(), - ContractInfo: myContractInfoFixture(), + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), }, { - ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, "other-label").String(), - ContractInfo: myContractInfoFixture(func(i *wasmTypes.ContractInfo) { - i.Label = "other-label" - }), + ContractAddress: BuildContractAddressClassic(1, 2).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), }, }, Sequences: []types.Sequence{ {IDKey: types.KeyLastCodeID, Value: 2}, + {IDKey: types.KeyLastInstanceID, Value: 3}, }, Params: types.DefaultParams(), }, @@ -318,8 +308,8 @@ func TestGenesisInit(t *testing.T) { src: types.GenesisState{ Contracts: []types.Contract{ { - ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, myLabel).String(), - ContractInfo: myContractInfoFixture(), + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), }, }, Params: types.DefaultParams(), @@ -334,11 +324,11 @@ func TestGenesisInit(t *testing.T) { }}, Contracts: []types.Contract{ { - ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, myLabel).String(), - ContractInfo: myContractInfoFixture(), + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), }, { - ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, myLabel).String(), - ContractInfo: myContractInfoFixture(), + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), }, }, Params: types.DefaultParams(), @@ -353,8 +343,8 @@ func TestGenesisInit(t *testing.T) { }}, Contracts: []types.Contract{ { - ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, myLabel).String(), - ContractInfo: myContractInfoFixture(), + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), ContractState: []types.Model{ { Key: []byte{0x1}, @@ -392,6 +382,26 @@ func TestGenesisInit(t *testing.T) { Params: types.DefaultParams(), }, }, + "prevent contract id seq init value == count contracts": { + src: types.GenesisState{ + Codes: []types.Code{{ + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }}, + Contracts: []types.Contract{ + { + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields), + }, + }, + Sequences: []types.Sequence{ + {IDKey: types.KeyLastCodeID, Value: 2}, + {IDKey: types.KeyLastInstanceID, Value: 1}, + }, + Params: types.DefaultParams(), + }, + }, "validator set update called for any genesis messages": { src: wasmTypes.GenesisState{ GenMsgs: []types.GenesisState_GenMsgs{ @@ -550,17 +560,16 @@ func TestImportContractWithCodeHistoryReset(t *testing.T) { } assert.Equal(t, expHistory, keeper.GetContractHistory(ctx, contractAddr)) assert.Equal(t, uint64(2), keeper.PeekAutoIncrementID(ctx, types.KeyLastCodeID)) + assert.Equal(t, uint64(3), keeper.PeekAutoIncrementID(ctx, types.KeyLastInstanceID)) } func TestSupportedGenMsgTypes(t *testing.T) { wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") require.NoError(t, err) - wasmHash := sha256.Sum256(wasmCode) var ( myAddress sdk.AccAddress = bytes.Repeat([]byte{1}, types.ContractAddrLen) verifierAddress sdk.AccAddress = bytes.Repeat([]byte{2}, types.ContractAddrLen) beneficiaryAddress sdk.AccAddress = bytes.Repeat([]byte{3}, types.ContractAddrLen) - contractAddr = BuildContractAddress(wasmHash[:], myAddress, "testing") ) const denom = "stake" importState := types.GenesisState{ @@ -592,7 +601,7 @@ func TestSupportedGenMsgTypes(t *testing.T) { Sum: &types.GenesisState_GenMsgs_ExecuteContract{ ExecuteContract: &types.MsgExecuteContract{ Sender: verifierAddress.String(), - Contract: contractAddr.String(), + Contract: BuildContractAddressClassic(1, 1).String(), Msg: []byte(`{"release":{}}`), }, }, @@ -617,7 +626,7 @@ func TestSupportedGenMsgTypes(t *testing.T) { require.NotNil(t, codeInfo) // verify contract instantiated - cInfo := keeper.GetContractInfo(ctx, contractAddr) + cInfo := keeper.GetContractInfo(ctx, BuildContractAddressClassic(1, 1)) require.NotNil(t, cInfo) // verify contract executed diff --git a/x/wasm/keeper/ibc_test.go b/x/wasm/keeper/ibc_test.go index bdbab1a37c..063dfb7f7d 100644 --- a/x/wasm/keeper/ibc_test.go +++ b/x/wasm/keeper/ibc_test.go @@ -4,8 +4,6 @@ import ( "fmt" "testing" - "github.com/tendermint/tendermint/libs/rand" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" @@ -43,7 +41,7 @@ func TestBindingPortForIBCContractOnInstantiate(t *testing.T) { } func TestContractFromPortID(t *testing.T) { - contractAddr := BuildContractAddress(rand.Bytes(32), RandomAccountAddress(t), "testing") + contractAddr := BuildContractAddressClassic(1, 100) specs := map[string]struct { srcPort string expAddr sdk.AccAddress diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index c349603613..f29f6e18ed 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -19,7 +19,6 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/address" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" vestingexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" @@ -224,8 +223,8 @@ func (k Keeper) create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, evt := sdk.NewEvent( types.EventTypeStoreCode, - sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)), sdk.NewAttribute(types.AttributeKeyChecksum, hex.EncodeToString(checksum)), + sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)), // last element to be compatible with scripts ) for _, f := range strings.Split(report.RequiredCapabilities, ",") { evt.AppendAttributes(sdk.NewAttribute(types.AttributeKeyRequiredCapability, strings.TrimSpace(f))) @@ -267,7 +266,16 @@ func (k Keeper) importCode(ctx sdk.Context, codeID uint64, codeInfo types.CodeIn return nil } -func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins, authPolicy AuthorizationPolicy) (sdk.AccAddress, []byte, error) { +func (k Keeper) instantiate( + ctx sdk.Context, + codeID uint64, + creator, admin sdk.AccAddress, + initMsg []byte, + label string, + deposit sdk.Coins, + addressGenerator AddressGenerator, + authPolicy AuthorizationPolicy, +) (sdk.AccAddress, []byte, error) { defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "instantiate") if creator == nil { @@ -277,19 +285,15 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A ctx.GasMeter().ConsumeGas(instanceCosts, "Loading CosmWasm module: instantiate") // get contact info - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.GetCodeKey(codeID)) - if bz == nil { + codeInfo := k.GetCodeInfo(ctx, codeID) + if codeInfo == nil { return nil, nil, sdkerrors.Wrap(types.ErrNotFound, "code") } - var codeInfo types.CodeInfo - k.cdc.MustUnmarshal(bz, &codeInfo) - if !authPolicy.CanInstantiateContract(codeInfo.InstantiateConfig, creator) { return nil, nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not instantiate") } - contractAddress := BuildContractAddress(codeInfo.CodeHash, creator, label) + contractAddress := addressGenerator(ctx, codeID, codeInfo.CodeHash) if k.HasContractInfo(ctx, contractAddress) { return nil, nil, types.ErrDuplicate.Wrap("instance with this code id, sender and label exists: try a different label") } @@ -338,7 +342,7 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A info := types.NewInfo(creator, deposit) // create prefixed data store - // 0x03 | BuildContractAddress (sdk.AccAddress) + // 0x03 | BuildContractAddressClassic (sdk.AccAddress) prefixStoreKey := types.GetContractStorePrefix(contractAddress) prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey) @@ -1006,21 +1010,6 @@ func (k Keeper) consumeRuntimeGas(ctx sdk.Context, gas uint64) { } } -// BuildContractAddress generates a contract address for the wasm module with len = types.ContractAddrLen using the -// Cosmos SDK address.Module function. -// Internally a key is built containing (len(checksum) | checksum | len(sender_address) | sender_address | len(label) | label). -// All method parameter values must be valid and not be empty or nil. -func BuildContractAddress(checksum []byte, creator sdk.AccAddress, label string) sdk.AccAddress { - checksum = address.MustLengthPrefix(checksum) - creator = address.MustLengthPrefix(creator) - labelBz := address.MustLengthPrefix([]byte(label)) - key := make([]byte, len(checksum)+len(creator)+len(labelBz)) - copy(key[0:], checksum) - copy(key[len(checksum):], creator) - copy(key[len(checksum)+len(creator):], labelBz) - return address.Module(types.ModuleName, key)[:types.ContractAddrLen] -} - func (k Keeper) autoIncrementID(ctx sdk.Context, lastIDKey []byte) uint64 { store := ctx.KVStore(k.storeKey) bz := store.Get(lastIDKey) diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go index 5235141f36..947edd27c3 100644 --- a/x/wasm/keeper/keeper_test.go +++ b/x/wasm/keeper/keeper_test.go @@ -3,12 +3,10 @@ package keeper import ( "bytes" _ "embed" - "encoding/hex" "encoding/json" "errors" "fmt" "os" - "strings" "testing" "time" @@ -62,7 +60,7 @@ func TestCreateSuccess(t *testing.T) { require.Equal(t, hackatomWasm, storedCode) // and events emitted codeHash := "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5" - exp := sdk.Events{sdk.NewEvent("store_code", sdk.NewAttribute("code_id", "1"), sdk.NewAttribute("code_checksum", codeHash))} + exp := sdk.Events{sdk.NewEvent("store_code", sdk.NewAttribute("code_checksum", codeHash), sdk.NewAttribute("code_id", "1"))} assert.Equal(t, exp, em.Events()) } @@ -398,11 +396,11 @@ func TestInstantiate(t *testing.T) { // create with no balance is also legal gotContractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx.WithEventManager(em), example.CodeID, creator, nil, initMsgBz, "demo contract 1", nil) require.NoError(t, err) - require.Equal(t, "cosmos1xaq0tcwz9fsqmtxlpzwjn2zr8gw66ljjr079ltfc5pelepcs7sjsk28n5n", gotContractAddr.String()) + require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", gotContractAddr.String()) gasAfter := ctx.GasMeter().GasConsumed() if types.EnableGasVerification { - require.Equal(t, uint64(0x187b8), gasAfter-gasBefore) + require.Equal(t, uint64(0x1964f), gasAfter-gasBefore) } // ensure it is stored properly @@ -541,65 +539,6 @@ func TestInstantiateWithPermissions(t *testing.T) { } } -func TestInstantiateWithUniqueContractAddress(t *testing.T) { - parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) - example := InstantiateHackatomExampleContract(t, parentCtx, keepers) - otherExample := InstantiateReflectExampleContract(t, parentCtx, keepers) - initMsg := mustMarshal(t, HackatomExampleInitMsg{Verifier: example.VerifierAddr, Beneficiary: example.BeneficiaryAddr}) - - otherAddress := DeterministicAccountAddress(t, 1) - keepers.Faucet.Fund(parentCtx, otherAddress, sdk.NewInt64Coin("denom", 100000000)) - used := make(map[string]struct{}) - specs := map[string]struct { - codeID uint64 - sender sdk.AccAddress - label string - initMsg json.RawMessage - expErr error - }{ - "reject duplicate which generates the same address": { - codeID: example.CodeID, - sender: example.CreatorAddr, - label: example.Label, - initMsg: initMsg, - expErr: types.ErrDuplicate, - }, - "different sender": { - codeID: example.CodeID, - sender: otherAddress, - label: example.Label, - initMsg: initMsg, - }, - "different code": { - codeID: otherExample.CodeID, - sender: example.CreatorAddr, - label: example.Label, - initMsg: []byte(`{}`), - }, - "different label": { - codeID: example.CodeID, - sender: example.CreatorAddr, - label: "other label", - initMsg: initMsg, - }, - } - for name, spec := range specs { - t.Run(name, func(t *testing.T) { - ctx, _ := parentCtx.CacheContext() - gotAddr, _, gotErr := keepers.ContractKeeper.Instantiate(ctx, spec.codeID, spec.sender, nil, spec.initMsg, spec.label, example.Deposit) - if spec.expErr != nil { - assert.ErrorIs(t, gotErr, spec.expErr) - return - } - require.NoError(t, gotErr) - expAddr := BuildContractAddress(keepers.WasmKeeper.GetCodeInfo(ctx, spec.codeID).CodeHash, spec.sender, spec.label) - assert.Equal(t, expAddr.String(), gotAddr.String()) - require.NotContains(t, used, gotAddr.String()) - used[gotAddr.String()] = struct{}{} - }) - } -} - func TestInstantiateWithAccounts(t *testing.T) { parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) example := StoreHackatomExampleContract(t, parentCtx, keepers) @@ -609,12 +548,13 @@ func TestInstantiateWithAccounts(t *testing.T) { senderAddr := DeterministicAccountAddress(t, 1) keepers.Faucet.Fund(parentCtx, senderAddr, sdk.NewInt64Coin("denom", 100000000)) const myLabel = "testing" - contractAddr := BuildContractAddress(example.Checksum, senderAddr, myLabel) + mySalt := []byte(`my salt`) + contractAddr := BuildContractAddressPredictable(example.Checksum, senderAddr, mySalt, []byte{}) lastAccountNumber := keepers.AccountKeeper.GetAccount(parentCtx, senderAddr).GetAccountNumber() specs := map[string]struct { - acceptList Option + option Option account authtypes.AccountI initBalance sdk.Coin deposit sdk.Coins @@ -679,7 +619,7 @@ func TestInstantiateWithAccounts(t *testing.T) { expErr: types.ErrAccountExists, }, "with option used to set non default type to accept list": { - acceptList: WithAcceptedAccountTypesOnContractInstantiation(&vestingtypes.DelayedVestingAccount{}), + option: WithAcceptedAccountTypesOnContractInstantiation(&vestingtypes.DelayedVestingAccount{}), account: vestingtypes.NewDelayedVestingAccount( authtypes.NewBaseAccount(contractAddr, nil, 0, 0), sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), time.Now().Add(30*time.Hour).Unix()), @@ -689,6 +629,15 @@ func TestInstantiateWithAccounts(t *testing.T) { sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), time.Now().Add(30*time.Hour).Unix()), expBalance: sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_001))), }, + "pruning account fails": { + option: WithAccountPruner(wasmtesting.AccountPrunerMock{CleanupExistingAccountFn: func(ctx sdk.Context, existingAccount authtypes.AccountI) (handled bool, err error) { + return false, types.ErrUnsupportedForContract.Wrap("testing") + }}), + account: vestingtypes.NewDelayedVestingAccount( + authtypes.NewBaseAccount(contractAddr, nil, 0, 0), + sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), time.Now().Add(30*time.Hour).Unix()), + expErr: types.ErrUnsupportedForContract, + }, } for name, spec := range specs { t.Run(name, func(t *testing.T) { @@ -699,16 +648,17 @@ func TestInstantiateWithAccounts(t *testing.T) { if !spec.initBalance.IsNil() { keepers.Faucet.Fund(ctx, spec.account.GetAddress(), spec.initBalance) } - if spec.acceptList != nil { - spec.acceptList.apply(keepers.WasmKeeper) + if spec.option != nil { + spec.option.apply(keepers.WasmKeeper) } defer func() { - if spec.acceptList != nil { // reset + if spec.option != nil { // reset WithAcceptedAccountTypesOnContractInstantiation(&authtypes.BaseAccount{}).apply(keepers.WasmKeeper) + WithAccountPruner(NewVestingCoinBurner(keepers.BankKeeper)).apply(keepers.WasmKeeper) } }() // when - gotAddr, _, gotErr := keepers.ContractKeeper.Instantiate(ctx, 1, senderAddr, nil, initMsg, myLabel, spec.deposit) + gotAddr, _, gotErr := keepers.ContractKeeper.Instantiate2(ctx, 1, senderAddr, nil, initMsg, myLabel, spec.deposit, mySalt, false) if spec.expErr != nil { assert.ErrorIs(t, gotErr, spec.expErr) return @@ -857,8 +807,7 @@ func TestExecute(t *testing.T) { addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 3", deposit) require.NoError(t, err) - // cosmos1eycfqpgtcp4gc9g24cvg6useyncxspq8qurv2z7cs0wzcgvmffaquzwe2e build with code-id 1, DeterministicAccountAddress(t, 1) and label `demo contract 3` - require.Equal(t, "cosmos1eycfqpgtcp4gc9g24cvg6useyncxspq8qurv2z7cs0wzcgvmffaquzwe2e", addr.String()) + require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", addr.String()) // ensure bob doesn't exist bobAcct := accKeeper.GetAccount(ctx, bob) @@ -1562,7 +1511,7 @@ func TestSudo(t *testing.T) { require.NoError(t, err) addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 3", deposit) require.NoError(t, err) - require.Equal(t, "cosmos1eycfqpgtcp4gc9g24cvg6useyncxspq8qurv2z7cs0wzcgvmffaquzwe2e", addr.String()) + require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", addr.String()) // the community is broke _, _, community := keyPubAddr() @@ -2077,104 +2026,6 @@ func TestQueryIsolation(t *testing.T) { assert.Nil(t, ctx.KVStore(k.storeKey).Get([]byte(`set_in_query`))) } -func TestBuildContractAddress(t *testing.T) { - x, y := sdk.GetConfig().GetBech32AccountAddrPrefix(), sdk.GetConfig().GetBech32AccountPubPrefix() - t.Cleanup(func() { - sdk.GetConfig().SetBech32PrefixForAccount(x, y) - }) - sdk.GetConfig().SetBech32PrefixForAccount("purple", "purple") - - // test vectors from https://gist.github.com/webmaster128/e4d401d414bd0e7e6f70482f11877fbe - specs := map[string]struct { - checksum []byte - label string - creator string - expAddress string - }{ - "initial account addr example": { - checksum: fromHex("13A1FC994CC6D1C81B746EE0C0FF6F90043875E0BF1D9BE6B7D779FC978DC2A5"), - label: "instance 1", - creator: "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", - expAddress: "purple1jukvumwqfxapueg6un6rtmafxktcluzv70xc3edz2m5t3slgw49qrmhc03", - }, - "account addr with different label": { - checksum: fromHex("13A1FC994CC6D1C81B746EE0C0FF6F90043875E0BF1D9BE6B7D779FC978DC2A5"), - label: "instance 2", - creator: "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", - expAddress: "purple1jpc2w2vu2t6k7u09p6v8e3w28ptnzvvt2snu5rytlj8qya27dq5sjkwm06", - }, - "initial contract addr example": { - checksum: fromHex("13A1FC994CC6D1C81B746EE0C0FF6F90043875E0BF1D9BE6B7D779FC978DC2A5"), - label: "instance 1", - creator: "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", - expAddress: "purple1wde5zlcveuh79w37w5g244qu9xja3hgfulyfkjvkxvwvjzgd5l3qfraz3c", - }, - "contract addr with different label": { - checksum: fromHex("13A1FC994CC6D1C81B746EE0C0FF6F90043875E0BF1D9BE6B7D779FC978DC2A5"), - label: "instance 2", - creator: "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", - expAddress: "purple1vae2kf0r3ehtq5q2jmfkg7wp4ckxwrw8dv4pvazz5nlzzu05lxzq878fa9", - }, - "account addr with different checksum": { - checksum: fromHex("1DA6C16DE2CBAF7AD8CBB66F0925BA33F5C278CB2491762D04658C1480EA229B"), - label: "instance 1", - creator: "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", - expAddress: "purple1gmgvt9levtn52mpfal3gl5tv60f47zez3wgczrh5c9352sfm9crs47zt0k", - }, - "account addr with different checksum and label": { - checksum: fromHex("1DA6C16DE2CBAF7AD8CBB66F0925BA33F5C278CB2491762D04658C1480EA229B"), - label: "instance 2", - creator: "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", - expAddress: "purple13jrcqxknt05rhdxmegjzjel666yay6fj3xvfp6445k7a9q2km4wqa7ss34", - }, - "contract addr with different checksum": { - checksum: fromHex("1DA6C16DE2CBAF7AD8CBB66F0925BA33F5C278CB2491762D04658C1480EA229B"), - label: "instance 1", - creator: "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", - expAddress: "purple1lu0lf6wmqeuwtrx93ptzvf4l0dyyz2vz6s8h5y9cj42fvhsmracq49pww9", - }, - "contract addr with different checksum and label": { - checksum: fromHex("1DA6C16DE2CBAF7AD8CBB66F0925BA33F5C278CB2491762D04658C1480EA229B"), - label: "instance 2", - creator: "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", - expAddress: "purple1zmerc8a9ml2au29rq3knuu35fktef3akceurckr6pf370n0wku7sw3c9mj", - }, - // regression tests - "min label size": { - checksum: fromHex("13A1FC994CC6D1C81B746EE0C0FF6F90043875E0BF1D9BE6B7D779FC978DC2A5"), - label: "x", - creator: "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", - expAddress: "purple16pc8gt824lmp3dh2sxvttj0ykcs02n5p3ldswhv3j7y853gghlfq7mqeh9", - }, - "max label size": { - checksum: fromHex("13A1FC994CC6D1C81B746EE0C0FF6F90043875E0BF1D9BE6B7D779FC978DC2A5"), - label: strings.Repeat("x", types.MaxLabelSize), - creator: "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", - expAddress: "purple1prkdvjmvv4s3tnppfxmlpj259v9cplf3wws4qq9qd7w3s4yqzqeqem4759", - }, - } - for name, spec := range specs { - t.Run(name, func(t *testing.T) { - creatorAddr, err := sdk.AccAddressFromBech32(spec.creator) - require.NoError(t, err) - - // when - gotAddr := BuildContractAddress(spec.checksum, creatorAddr, spec.label) - - require.Equal(t, spec.expAddress, gotAddr.String()) - require.NoError(t, sdk.VerifyAddressFormat(gotAddr)) - }) - } -} - -func fromHex(s string) []byte { - r, err := hex.DecodeString(s) - if err != nil { - panic(err) - } - return r -} - func TestSetAccessConfig(t *testing.T) { parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) k := keepers.WasmKeeper diff --git a/x/wasm/keeper/migrations.go b/x/wasm/keeper/migrations.go deleted file mode 100644 index 4d218d504a..0000000000 --- a/x/wasm/keeper/migrations.go +++ /dev/null @@ -1,27 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/CosmWasm/wasmd/x/wasm/types" -) - -// Migrator is a struct for handling in-place store migrations. -type Migrator struct { - keeper *Keeper -} - -// NewMigrator returns a new Migrator. -func NewMigrator(keeper *Keeper) Migrator { - return Migrator{keeper: keeper} -} - -var keyLastInstanceID = append(types.SequenceKeyPrefix, []byte("lastContractId")...) - -// Migrate1to2 migrates from version 1 to 2. -// Remove the unused sequence for address generation -func (m Migrator) Migrate1to2(ctx sdk.Context) error { - store := ctx.KVStore(m.keeper.storeKey) - store.Delete(keyLastInstanceID) - return nil -} diff --git a/x/wasm/keeper/migrations_test.go b/x/wasm/keeper/migrations_test.go deleted file mode 100644 index bc9110a3b3..0000000000 --- a/x/wasm/keeper/migrations_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package keeper - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/assert" -) - -func TestMigrateV1ToV2(t *testing.T) { - ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) - store := ctx.KVStore(keepers.WasmKeeper.storeKey) - store.Set(keyLastInstanceID, sdk.Uint64ToBigEndian(100)) - - // when - NewMigrator(keepers.WasmKeeper).Migrate1to2(ctx) - - // then - assert.False(t, store.Has(keyLastInstanceID)) -} diff --git a/x/wasm/keeper/msg_server.go b/x/wasm/keeper/msg_server.go index 8c2a592ebf..d3051f4307 100644 --- a/x/wasm/keeper/msg_server.go +++ b/x/wasm/keeper/msg_server.go @@ -43,6 +43,7 @@ func (m msgServer) StoreCode(goCtx context.Context, msg *types.MsgStoreCode) (*t }, nil } +// InstantiateContract instantiate a new contract with classic sequence based address generation func (m msgServer) InstantiateContract(goCtx context.Context, msg *types.MsgInstantiateContract) (*types.MsgInstantiateContractResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) @@ -74,6 +75,37 @@ func (m msgServer) InstantiateContract(goCtx context.Context, msg *types.MsgInst }, nil } +// InstantiateContract2 instantiate a new contract with predicatable address generated +func (m msgServer) InstantiateContract2(goCtx context.Context, msg *types.MsgInstantiateContract2) (*types.MsgInstantiateContract2Response, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, sdkerrors.Wrap(err, "sender") + } + var adminAddr sdk.AccAddress + if msg.Admin != "" { + if adminAddr, err = sdk.AccAddressFromBech32(msg.Admin); err != nil { + return nil, sdkerrors.Wrap(err, "admin") + } + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + )) + contractAddr, data, err := m.keeper.Instantiate2(ctx, msg.CodeID, senderAddr, adminAddr, msg.Msg, msg.Label, msg.Funds, msg.Salt, msg.FixMsg) + if err != nil { + return nil, err + } + + return &types.MsgInstantiateContract2Response{ + Address: contractAddr.String(), + Data: data, + }, nil +} + func (m msgServer) ExecuteContract(goCtx context.Context, msg *types.MsgExecuteContract) (*types.MsgExecuteContractResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) diff --git a/x/wasm/keeper/proposal_integration_test.go b/x/wasm/keeper/proposal_integration_test.go index ace55269db..5a0305a485 100644 --- a/x/wasm/keeper/proposal_integration_test.go +++ b/x/wasm/keeper/proposal_integration_test.go @@ -2,25 +2,21 @@ package keeper import ( "bytes" - "crypto/sha256" "encoding/hex" "encoding/json" "errors" "os" "testing" - "github.com/cosmos/cosmos-sdk/x/params/client/utils" - wasmvm "github.com/CosmWasm/wasmvm" - - "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting" - sdk "github.com/cosmos/cosmos-sdk/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/params/client/utils" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting" "github.com/CosmWasm/wasmd/x/wasm/types" ) @@ -117,8 +113,9 @@ func TestInstantiateProposal(t *testing.T) { require.NoError(t, err) // then - codeHash := keepers.WasmKeeper.GetCodeInfo(ctx, 1).CodeHash - contractAddr := BuildContractAddress(codeHash, oneAddress, "testing") + contractAddr, err := sdk.AccAddressFromBech32("cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr") + require.NoError(t, err) + cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr) require.NotNil(t, cInfo) assert.Equal(t, uint64(1), cInfo.CodeID) @@ -188,8 +185,9 @@ func TestInstantiateProposal_NoAdmin(t *testing.T) { require.NoError(t, err) // then - codeHash := keepers.WasmKeeper.GetCodeInfo(ctx, 1).CodeHash - contractAddr := BuildContractAddress(codeHash, oneAddress, "testing") + contractAddr, err := sdk.AccAddressFromBech32("cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr") + require.NoError(t, err) + cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr) require.NotNil(t, cInfo) assert.Equal(t, uint64(1), cInfo.CodeID) @@ -230,7 +228,7 @@ func TestMigrateProposal(t *testing.T) { var ( anyAddress = DeterministicAccountAddress(t, 1) otherAddress = DeterministicAccountAddress(t, 2) - contractAddr = BuildContractAddress(codeInfoFixture.CodeHash, RandomAccountAddress(t), "") + contractAddr = BuildContractAddressClassic(1, 1) ) contractInfoFixture := types.ContractInfoFixture(func(c *types.ContractInfo) { @@ -407,13 +405,12 @@ func TestSudoProposal(t *testing.T) { } func TestAdminProposals(t *testing.T) { - wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") - require.NoError(t, err) var ( - otherAddress = DeterministicAccountAddress(t, 2) - codeHash = sha256.Sum256(wasmCode) - contractAddr = BuildContractAddress(codeHash[:], RandomAccountAddress(t), "") + otherAddress sdk.AccAddress = bytes.Repeat([]byte{0x2}, types.ContractAddrLen) + contractAddr = BuildContractAddressClassic(1, 1) ) + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) specs := map[string]struct { state types.ContractInfo diff --git a/x/wasm/keeper/querier_test.go b/x/wasm/keeper/querier_test.go index 115eeb8419..f4341d169d 100644 --- a/x/wasm/keeper/querier_test.go +++ b/x/wasm/keeper/querier_test.go @@ -158,9 +158,8 @@ func TestQuerySmartContractState(t *testing.T) { func TestQuerySmartContractPanics(t *testing.T) { ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) - creator := RandomAccountAddress(t) - contractAddr := BuildContractAddress([]byte("myCodeHash"), creator, "testing") - keepers.WasmKeeper.storeCodeInfo(ctx, 1, types.CodeInfo{CodeHash: []byte("myCodeHash")}) + contractAddr := BuildContractAddressClassic(1, 1) + keepers.WasmKeeper.storeCodeInfo(ctx, 1, types.CodeInfo{}) keepers.WasmKeeper.storeContractInfo(ctx, contractAddr, &types.ContractInfo{ CodeID: 1, Created: types.NewAbsoluteTxPosition(ctx), diff --git a/x/wasm/keeper/test_common.go b/x/wasm/keeper/test_common.go index fff90af36b..721a327826 100644 --- a/x/wasm/keeper/test_common.go +++ b/x/wasm/keeper/test_common.go @@ -9,20 +9,18 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/x/auth/vesting" - - "github.com/cosmos/cosmos-sdk/types/address" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/std" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/auth/vesting" authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" "github.com/cosmos/cosmos-sdk/x/bank" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" @@ -72,7 +70,6 @@ import ( dbm "github.com/tendermint/tm-db" wasmappparams "github.com/CosmWasm/wasmd/app/params" - "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting" "github.com/CosmWasm/wasmd/x/wasm/types" ) diff --git a/x/wasm/keeper/wasmtesting/coin_transferrer.go b/x/wasm/keeper/wasmtesting/coin_transferrer.go deleted file mode 100644 index 497ecc747f..0000000000 --- a/x/wasm/keeper/wasmtesting/coin_transferrer.go +++ /dev/null @@ -1,14 +0,0 @@ -package wasmtesting - -import sdk "github.com/cosmos/cosmos-sdk/types" - -type MockCoinTransferrer struct { - TransferCoinsFn func(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error -} - -func (m *MockCoinTransferrer) TransferCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { - if m.TransferCoinsFn == nil { - panic("not expected to be called") - } - return m.TransferCoinsFn(ctx, fromAddr, toAddr, amt) -} diff --git a/x/wasm/keeper/wasmtesting/extension_mocks.go b/x/wasm/keeper/wasmtesting/extension_mocks.go new file mode 100644 index 0000000000..562d9e74b0 --- /dev/null +++ b/x/wasm/keeper/wasmtesting/extension_mocks.go @@ -0,0 +1,28 @@ +package wasmtesting + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +type MockCoinTransferrer struct { + TransferCoinsFn func(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error +} + +func (m *MockCoinTransferrer) TransferCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { + if m.TransferCoinsFn == nil { + panic("not expected to be called") + } + return m.TransferCoinsFn(ctx, fromAddr, toAddr, amt) +} + +type AccountPrunerMock struct { + CleanupExistingAccountFn func(ctx sdk.Context, existingAccount authtypes.AccountI) (handled bool, err error) +} + +func (m AccountPrunerMock) CleanupExistingAccount(ctx sdk.Context, existingAccount authtypes.AccountI) (handled bool, err error) { + if m.CleanupExistingAccountFn == nil { + panic("not expected to be called") + } + return m.CleanupExistingAccountFn(ctx, existingAccount) +} diff --git a/x/wasm/module.go b/x/wasm/module.go index 2433fe0219..c7ea6339c0 100644 --- a/x/wasm/module.go +++ b/x/wasm/module.go @@ -134,11 +134,6 @@ func NewAppModule( func (am AppModule) RegisterServices(cfg module.Configurator) { types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(keeper.NewDefaultPermissionKeeper(am.keeper))) types.RegisterQueryServer(cfg.QueryServer(), NewQuerier(am.keeper)) - - m := keeper.NewMigrator(am.keeper) - if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { - panic(err) - } } func (am AppModule) LegacyQuerierHandler(amino *codec.LegacyAmino) sdk.Querier { //nolint:staticcheck diff --git a/x/wasm/module_test.go b/x/wasm/module_test.go index d3530e5a3a..66591aba27 100644 --- a/x/wasm/module_test.go +++ b/x/wasm/module_test.go @@ -7,11 +7,8 @@ import ( "os" "testing" - "github.com/cosmos/cosmos-sdk/types/address" - - "github.com/CosmWasm/wasmd/x/wasm/keeper/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/module" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" @@ -24,6 +21,7 @@ import ( "github.com/tendermint/tendermint/crypto/ed25519" "github.com/CosmWasm/wasmd/x/wasm/keeper" + "github.com/CosmWasm/wasmd/x/wasm/keeper/testdata" "github.com/CosmWasm/wasmd/x/wasm/types" ) @@ -148,8 +146,7 @@ type state struct { func TestHandleInstantiate(t *testing.T) { data := setupTest(t) - creator := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len)) - data.faucet.Fund(data.ctx, creator, sdk.NewInt64Coin("denom", 100000)) + creator := data.faucet.NewFundedRandomAccount(data.ctx, sdk.NewInt64Coin("denom", 100000)) h := data.module.Route().Handler() q := data.module.LegacyQuerierHandler(nil) @@ -183,7 +180,7 @@ func TestHandleInstantiate(t *testing.T) { require.NoError(t, err) contractBech32Addr := parseInitResponse(t, res.Data) - require.Equal(t, "cosmos1400ax8h2dxe8ch64sus5sczqdhwv28hpjkkaphpa83he4fhz6k4qcm9kul", contractBech32Addr) + require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", contractBech32Addr) // this should be standard x/wasm init event, nothing from contract require.Equal(t, 3, len(res.Events), prettyEvents(res.Events)) require.Equal(t, "message", res.Events[0].Type) @@ -210,9 +207,7 @@ func TestHandleExecute(t *testing.T) { deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) - creator := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len)) - data.faucet.Fund(data.ctx, creator, sdk.NewInt64Coin("denom", 100000*2)) - + creator := data.faucet.NewFundedRandomAccount(data.ctx, deposit.Add(deposit...)...) fred := data.faucet.NewFundedRandomAccount(data.ctx, topUp...) h := data.module.Route().Handler() @@ -244,7 +239,7 @@ func TestHandleExecute(t *testing.T) { require.NoError(t, err) contractBech32Addr := parseInitResponse(t, res.Data) - require.Equal(t, "cosmos1400ax8h2dxe8ch64sus5sczqdhwv28hpjkkaphpa83he4fhz6k4qcm9kul", contractBech32Addr) + require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", contractBech32Addr) // this should be standard x/wasm message event, init event, plus a bank send event (2), with no custom contract events require.Equal(t, 6, len(res.Events), prettyEvents(res.Events)) require.Equal(t, "message", res.Events[0].Type) @@ -377,7 +372,7 @@ func TestHandleExecuteEscrow(t *testing.T) { res, err = h(data.ctx, &initCmd) require.NoError(t, err) contractBech32Addr := parseInitResponse(t, res.Data) - require.Equal(t, "cosmos1400ax8h2dxe8ch64sus5sczqdhwv28hpjkkaphpa83he4fhz6k4qcm9kul", contractBech32Addr) + require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", contractBech32Addr) handleMsg := map[string]interface{}{ "release": map[string]interface{}{}, diff --git a/x/wasm/types/codec.go b/x/wasm/types/codec.go index e7e578b7f8..f1cd6f557f 100644 --- a/x/wasm/types/codec.go +++ b/x/wasm/types/codec.go @@ -13,6 +13,7 @@ import ( func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { //nolint:staticcheck cdc.RegisterConcrete(&MsgStoreCode{}, "wasm/MsgStoreCode", nil) cdc.RegisterConcrete(&MsgInstantiateContract{}, "wasm/MsgInstantiateContract", nil) + cdc.RegisterConcrete(&MsgInstantiateContract2{}, "wasm/MsgInstantiateContract2", nil) cdc.RegisterConcrete(&MsgExecuteContract{}, "wasm/MsgExecuteContract", nil) cdc.RegisterConcrete(&MsgMigrateContract{}, "wasm/MsgMigrateContract", nil) cdc.RegisterConcrete(&MsgUpdateAdmin{}, "wasm/MsgUpdateAdmin", nil) @@ -35,6 +36,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { (*sdk.Msg)(nil), &MsgStoreCode{}, &MsgInstantiateContract{}, + &MsgInstantiateContract2{}, &MsgExecuteContract{}, &MsgMigrateContract{}, &MsgUpdateAdmin{}, diff --git a/x/wasm/types/exported_keepers.go b/x/wasm/types/exported_keepers.go index df09957915..e68df8ee7b 100644 --- a/x/wasm/types/exported_keepers.go +++ b/x/wasm/types/exported_keepers.go @@ -28,8 +28,27 @@ type ContractOpsKeeper interface { // Create uploads and compiles a WASM contract, returning a short identifier for the contract Create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, instantiateAccess *AccessConfig) (codeID uint64, checksum []byte, err error) - // Instantiate creates an instance of a WASM contract - Instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins) (sdk.AccAddress, []byte, error) + // Instantiate creates an instance of a WASM contract using the classic sequence based address generator + Instantiate( + ctx sdk.Context, + codeID uint64, + creator, admin sdk.AccAddress, + initMsg []byte, + label string, + deposit sdk.Coins, + ) (sdk.AccAddress, []byte, error) + + // Instantiate2 creates an instance of a WASM contract using the predictable address generator + Instantiate2( + ctx sdk.Context, + codeID uint64, + creator, admin sdk.AccAddress, + initMsg []byte, + label string, + deposit sdk.Coins, + salt []byte, + fixMsg bool, + ) (sdk.AccAddress, []byte, error) // Execute executes the contract instance Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) ([]byte, error) diff --git a/x/wasm/types/keys.go b/x/wasm/types/keys.go index 9660360cb8..fb636ef4f3 100644 --- a/x/wasm/types/keys.go +++ b/x/wasm/types/keys.go @@ -32,7 +32,8 @@ var ( PinnedCodeIndexPrefix = []byte{0x07} TXCounterPrefix = []byte{0x08} - KeyLastCodeID = append(SequenceKeyPrefix, []byte("lastCodeId")...) + KeyLastCodeID = append(SequenceKeyPrefix, []byte("lastCodeId")...) + KeyLastInstanceID = append(SequenceKeyPrefix, []byte("lastContractId")...) ) // GetCodeKey constructs the key for retreiving the ID for the WASM code diff --git a/x/wasm/types/tx.go b/x/wasm/types/tx.go index 0c83018df0..9630777f29 100644 --- a/x/wasm/types/tx.go +++ b/x/wasm/types/tx.go @@ -306,3 +306,56 @@ func (msg MsgIBCCloseChannel) GetSignBytes() []byte { func (msg MsgIBCCloseChannel) GetSigners() []sdk.AccAddress { return nil } + +var _ sdk.Msg = &MsgInstantiateContract2{} + +func (msg MsgInstantiateContract2) Route() string { + return RouterKey +} + +func (msg MsgInstantiateContract2) Type() string { + return "instantiate2" +} + +func (msg MsgInstantiateContract2) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Sender); err != nil { + return sdkerrors.Wrap(err, "sender") + } + + if msg.CodeID == 0 { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "code id is required") + } + + if err := ValidateLabel(msg.Label); err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "label is required") + } + + if !msg.Funds.IsValid() { + return sdkerrors.ErrInvalidCoins + } + + if len(msg.Admin) != 0 { + if _, err := sdk.AccAddressFromBech32(msg.Admin); err != nil { + return sdkerrors.Wrap(err, "admin") + } + } + if err := msg.Msg.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "payload msg") + } + if err := ValidateSalt(msg.Salt); err != nil { + return sdkerrors.Wrap(err, "salt") + } + return nil +} + +func (msg MsgInstantiateContract2) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg)) +} + +func (msg MsgInstantiateContract2) GetSigners() []sdk.AccAddress { + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { // should never happen as valid basic rejects invalid addresses + panic(err.Error()) + } + return []sdk.AccAddress{senderAddr} +} diff --git a/x/wasm/types/tx.pb.go b/x/wasm/types/tx.pb.go index 52d5098de4..cf90465b69 100644 --- a/x/wasm/types/tx.pb.go +++ b/x/wasm/types/tx.pb.go @@ -184,11 +184,71 @@ func (m *MsgInstantiateContract) XXX_DiscardUnknown() { var xxx_messageInfo_MsgInstantiateContract proto.InternalMessageInfo +// MsgInstantiateContract2 create a new smart contract instance for the given +// code id with a predicable address. +type MsgInstantiateContract2 struct { + // Sender is the that actor that signed the messages + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + // Admin is an optional address that can execute migrations + Admin string `protobuf:"bytes,2,opt,name=admin,proto3" json:"admin,omitempty"` + // CodeID is the reference to the stored WASM code + CodeID uint64 `protobuf:"varint,3,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // Label is optional metadata to be stored with a contract instance. + Label string `protobuf:"bytes,4,opt,name=label,proto3" json:"label,omitempty"` + // Msg json encoded message to be passed to the contract on instantiation + Msg RawContractMessage `protobuf:"bytes,5,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"` + // Funds coins that are transferred to the contract on instantiation + Funds github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,6,rep,name=funds,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"funds"` + // Salt is an arbitrary value provided by the sender. Size can be 1 to 64. + Salt []byte `protobuf:"bytes,7,opt,name=salt,proto3" json:"salt,omitempty"` + // FixMsg include the msg value into the hash for the predictable address. + // Default is false + FixMsg bool `protobuf:"varint,8,opt,name=fix_msg,json=fixMsg,proto3" json:"fix_msg,omitempty"` +} + +func (m *MsgInstantiateContract2) Reset() { *m = MsgInstantiateContract2{} } +func (m *MsgInstantiateContract2) String() string { return proto.CompactTextString(m) } +func (*MsgInstantiateContract2) ProtoMessage() {} +func (*MsgInstantiateContract2) Descriptor() ([]byte, []int) { + return fileDescriptor_4f74d82755520264, []int{3} +} + +func (m *MsgInstantiateContract2) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} + +func (m *MsgInstantiateContract2) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgInstantiateContract2.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} + +func (m *MsgInstantiateContract2) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgInstantiateContract2.Merge(m, src) +} + +func (m *MsgInstantiateContract2) XXX_Size() int { + return m.Size() +} + +func (m *MsgInstantiateContract2) XXX_DiscardUnknown() { + xxx_messageInfo_MsgInstantiateContract2.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgInstantiateContract2 proto.InternalMessageInfo + // MsgInstantiateContractResponse return instantiation result data type MsgInstantiateContractResponse struct { // Address is the bech32 address of the new contract instance. Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - // Data contains base64-encoded bytes to returned from the contract + // Data contains bytes to returned from the contract Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` } @@ -196,7 +256,7 @@ func (m *MsgInstantiateContractResponse) Reset() { *m = MsgInstantiateCo func (m *MsgInstantiateContractResponse) String() string { return proto.CompactTextString(m) } func (*MsgInstantiateContractResponse) ProtoMessage() {} func (*MsgInstantiateContractResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_4f74d82755520264, []int{3} + return fileDescriptor_4f74d82755520264, []int{4} } func (m *MsgInstantiateContractResponse) XXX_Unmarshal(b []byte) error { @@ -230,6 +290,52 @@ func (m *MsgInstantiateContractResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgInstantiateContractResponse proto.InternalMessageInfo +// MsgInstantiateContract2Response return instantiation result data +type MsgInstantiateContract2Response struct { + // Address is the bech32 address of the new contract instance. + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // Data contains bytes to returned from the contract + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *MsgInstantiateContract2Response) Reset() { *m = MsgInstantiateContract2Response{} } +func (m *MsgInstantiateContract2Response) String() string { return proto.CompactTextString(m) } +func (*MsgInstantiateContract2Response) ProtoMessage() {} +func (*MsgInstantiateContract2Response) Descriptor() ([]byte, []int) { + return fileDescriptor_4f74d82755520264, []int{5} +} + +func (m *MsgInstantiateContract2Response) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} + +func (m *MsgInstantiateContract2Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgInstantiateContract2Response.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} + +func (m *MsgInstantiateContract2Response) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgInstantiateContract2Response.Merge(m, src) +} + +func (m *MsgInstantiateContract2Response) XXX_Size() int { + return m.Size() +} + +func (m *MsgInstantiateContract2Response) XXX_DiscardUnknown() { + xxx_messageInfo_MsgInstantiateContract2Response.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgInstantiateContract2Response proto.InternalMessageInfo + // MsgExecuteContract submits the given message data to a smart contract type MsgExecuteContract struct { // Sender is the that actor that signed the messages @@ -246,7 +352,7 @@ func (m *MsgExecuteContract) Reset() { *m = MsgExecuteContract{} } func (m *MsgExecuteContract) String() string { return proto.CompactTextString(m) } func (*MsgExecuteContract) ProtoMessage() {} func (*MsgExecuteContract) Descriptor() ([]byte, []int) { - return fileDescriptor_4f74d82755520264, []int{4} + return fileDescriptor_4f74d82755520264, []int{6} } func (m *MsgExecuteContract) XXX_Unmarshal(b []byte) error { @@ -282,7 +388,7 @@ var xxx_messageInfo_MsgExecuteContract proto.InternalMessageInfo // MsgExecuteContractResponse returns execution result data. type MsgExecuteContractResponse struct { - // Data contains base64-encoded bytes to returned from the contract + // Data contains bytes to returned from the contract Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` } @@ -290,7 +396,7 @@ func (m *MsgExecuteContractResponse) Reset() { *m = MsgExecuteContractRe func (m *MsgExecuteContractResponse) String() string { return proto.CompactTextString(m) } func (*MsgExecuteContractResponse) ProtoMessage() {} func (*MsgExecuteContractResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_4f74d82755520264, []int{5} + return fileDescriptor_4f74d82755520264, []int{7} } func (m *MsgExecuteContractResponse) XXX_Unmarshal(b []byte) error { @@ -340,7 +446,7 @@ func (m *MsgMigrateContract) Reset() { *m = MsgMigrateContract{} } func (m *MsgMigrateContract) String() string { return proto.CompactTextString(m) } func (*MsgMigrateContract) ProtoMessage() {} func (*MsgMigrateContract) Descriptor() ([]byte, []int) { - return fileDescriptor_4f74d82755520264, []int{6} + return fileDescriptor_4f74d82755520264, []int{8} } func (m *MsgMigrateContract) XXX_Unmarshal(b []byte) error { @@ -385,7 +491,7 @@ func (m *MsgMigrateContractResponse) Reset() { *m = MsgMigrateContractRe func (m *MsgMigrateContractResponse) String() string { return proto.CompactTextString(m) } func (*MsgMigrateContractResponse) ProtoMessage() {} func (*MsgMigrateContractResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_4f74d82755520264, []int{7} + return fileDescriptor_4f74d82755520264, []int{9} } func (m *MsgMigrateContractResponse) XXX_Unmarshal(b []byte) error { @@ -433,7 +539,7 @@ func (m *MsgUpdateAdmin) Reset() { *m = MsgUpdateAdmin{} } func (m *MsgUpdateAdmin) String() string { return proto.CompactTextString(m) } func (*MsgUpdateAdmin) ProtoMessage() {} func (*MsgUpdateAdmin) Descriptor() ([]byte, []int) { - return fileDescriptor_4f74d82755520264, []int{8} + return fileDescriptor_4f74d82755520264, []int{10} } func (m *MsgUpdateAdmin) XXX_Unmarshal(b []byte) error { @@ -474,7 +580,7 @@ func (m *MsgUpdateAdminResponse) Reset() { *m = MsgUpdateAdminResponse{} func (m *MsgUpdateAdminResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateAdminResponse) ProtoMessage() {} func (*MsgUpdateAdminResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_4f74d82755520264, []int{9} + return fileDescriptor_4f74d82755520264, []int{11} } func (m *MsgUpdateAdminResponse) XXX_Unmarshal(b []byte) error { @@ -520,7 +626,7 @@ func (m *MsgClearAdmin) Reset() { *m = MsgClearAdmin{} } func (m *MsgClearAdmin) String() string { return proto.CompactTextString(m) } func (*MsgClearAdmin) ProtoMessage() {} func (*MsgClearAdmin) Descriptor() ([]byte, []int) { - return fileDescriptor_4f74d82755520264, []int{10} + return fileDescriptor_4f74d82755520264, []int{12} } func (m *MsgClearAdmin) XXX_Unmarshal(b []byte) error { @@ -561,7 +667,7 @@ func (m *MsgClearAdminResponse) Reset() { *m = MsgClearAdminResponse{} } func (m *MsgClearAdminResponse) String() string { return proto.CompactTextString(m) } func (*MsgClearAdminResponse) ProtoMessage() {} func (*MsgClearAdminResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_4f74d82755520264, []int{11} + return fileDescriptor_4f74d82755520264, []int{13} } func (m *MsgClearAdminResponse) XXX_Unmarshal(b []byte) error { @@ -599,7 +705,9 @@ func init() { proto.RegisterType((*MsgStoreCode)(nil), "cosmwasm.wasm.v1.MsgStoreCode") proto.RegisterType((*MsgStoreCodeResponse)(nil), "cosmwasm.wasm.v1.MsgStoreCodeResponse") proto.RegisterType((*MsgInstantiateContract)(nil), "cosmwasm.wasm.v1.MsgInstantiateContract") + proto.RegisterType((*MsgInstantiateContract2)(nil), "cosmwasm.wasm.v1.MsgInstantiateContract2") proto.RegisterType((*MsgInstantiateContractResponse)(nil), "cosmwasm.wasm.v1.MsgInstantiateContractResponse") + proto.RegisterType((*MsgInstantiateContract2Response)(nil), "cosmwasm.wasm.v1.MsgInstantiateContract2Response") proto.RegisterType((*MsgExecuteContract)(nil), "cosmwasm.wasm.v1.MsgExecuteContract") proto.RegisterType((*MsgExecuteContractResponse)(nil), "cosmwasm.wasm.v1.MsgExecuteContractResponse") proto.RegisterType((*MsgMigrateContract)(nil), "cosmwasm.wasm.v1.MsgMigrateContract") @@ -613,55 +721,60 @@ func init() { func init() { proto.RegisterFile("cosmwasm/wasm/v1/tx.proto", fileDescriptor_4f74d82755520264) } var fileDescriptor_4f74d82755520264 = []byte{ - // 766 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xcb, 0x6e, 0xd3, 0x40, - 0x14, 0x8d, 0x1b, 0x27, 0x4d, 0x6e, 0x43, 0x89, 0x4c, 0x1a, 0x52, 0x83, 0x9c, 0x28, 0xa0, 0xe2, - 0x05, 0xd8, 0x4d, 0x91, 0xd8, 0x37, 0x29, 0x8b, 0x56, 0x32, 0x42, 0xae, 0x4a, 0x05, 0x9b, 0x68, - 0x62, 0x4f, 0x5d, 0xab, 0xb5, 0x27, 0x78, 0x9c, 0xa6, 0xfd, 0x09, 0xc4, 0x8e, 0x7f, 0xe0, 0x2f, - 0xd8, 0x75, 0x85, 0xba, 0x41, 0x62, 0x15, 0x20, 0xfd, 0x0b, 0x56, 0xc8, 0xcf, 0xba, 0xa9, 0x93, - 0x06, 0x21, 0x36, 0xce, 0xdc, 0x99, 0x73, 0x5f, 0x27, 0x67, 0xee, 0xc0, 0xaa, 0x46, 0xa8, 0x35, - 0x44, 0xd4, 0x92, 0xfd, 0xcf, 0x49, 0x4b, 0x76, 0x4f, 0xa5, 0xbe, 0x43, 0x5c, 0xc2, 0x95, 0xa3, - 0x23, 0xc9, 0xff, 0x9c, 0xb4, 0x78, 0xc1, 0xdb, 0x21, 0x54, 0xee, 0x21, 0x8a, 0xe5, 0x93, 0x56, - 0x0f, 0xbb, 0xa8, 0x25, 0x6b, 0xc4, 0xb4, 0x03, 0x0f, 0xbe, 0x62, 0x10, 0x83, 0xf8, 0x4b, 0xd9, - 0x5b, 0x85, 0xbb, 0x0f, 0x6f, 0xa6, 0x38, 0xeb, 0x63, 0x1a, 0x9c, 0x36, 0xbf, 0x30, 0x50, 0x52, - 0xa8, 0xb1, 0xeb, 0x12, 0x07, 0x77, 0x88, 0x8e, 0xb9, 0x2a, 0xe4, 0x29, 0xb6, 0x75, 0xec, 0xd4, - 0x98, 0x06, 0x23, 0x16, 0xd5, 0xd0, 0xe2, 0x5e, 0xc0, 0xb2, 0xe7, 0xdf, 0xed, 0x9d, 0xb9, 0xb8, - 0xab, 0x11, 0x1d, 0xd7, 0x16, 0x1a, 0x8c, 0x58, 0x6a, 0x97, 0xc7, 0xa3, 0x7a, 0x69, 0x7f, 0x73, - 0x57, 0x69, 0x9f, 0xb9, 0x7e, 0x04, 0xb5, 0xe4, 0xe1, 0x22, 0x8b, 0xdb, 0x83, 0xaa, 0x69, 0x53, - 0x17, 0xd9, 0xae, 0x89, 0x5c, 0xdc, 0xed, 0x63, 0xc7, 0x32, 0x29, 0x35, 0x89, 0x5d, 0xcb, 0x35, - 0x18, 0x71, 0x69, 0x43, 0x90, 0x26, 0xfb, 0x94, 0x36, 0x35, 0x0d, 0x53, 0xda, 0x21, 0xf6, 0x81, - 0x69, 0xa8, 0x2b, 0x09, 0xef, 0xd7, 0xb1, 0xf3, 0x0e, 0x5b, 0xc8, 0x96, 0xd9, 0x1d, 0xb6, 0xc0, - 0x96, 0x73, 0xcd, 0x7d, 0xa8, 0x24, 0x5b, 0x50, 0x31, 0xed, 0x13, 0x9b, 0x62, 0xee, 0x11, 0x2c, - 0x7a, 0x85, 0x76, 0x4d, 0xdd, 0xef, 0x85, 0x6d, 0xc3, 0x78, 0x54, 0xcf, 0x7b, 0x90, 0xed, 0x2d, - 0x35, 0xef, 0x1d, 0x6d, 0xeb, 0x1c, 0x0f, 0x05, 0xed, 0x10, 0x6b, 0x47, 0x74, 0x60, 0x05, 0x1d, - 0xa9, 0xb1, 0xdd, 0xfc, 0xb0, 0x00, 0x55, 0x85, 0x1a, 0xdb, 0x57, 0x15, 0x74, 0x88, 0xed, 0x3a, - 0x48, 0x73, 0xa7, 0xd2, 0x54, 0x81, 0x1c, 0xd2, 0x2d, 0xd3, 0xf6, 0x63, 0x15, 0xd5, 0xc0, 0x48, - 0x56, 0x92, 0x9d, 0x5a, 0x49, 0x05, 0x72, 0xc7, 0xa8, 0x87, 0x8f, 0x6b, 0x6c, 0xe0, 0xea, 0x1b, - 0x9c, 0x08, 0x59, 0x8b, 0x1a, 0x3e, 0x59, 0xa5, 0x76, 0xf5, 0xf7, 0xa8, 0xce, 0xa9, 0x68, 0x18, - 0x95, 0xa1, 0x60, 0x4a, 0x91, 0x81, 0x55, 0x0f, 0xc2, 0x21, 0xc8, 0x1d, 0x0c, 0x6c, 0x9d, 0xd6, - 0xf2, 0x8d, 0xac, 0xb8, 0xb4, 0xb1, 0x2a, 0x05, 0x72, 0x91, 0x3c, 0xb9, 0x48, 0xa1, 0x5c, 0xa4, - 0x0e, 0x31, 0xed, 0xf6, 0xfa, 0xf9, 0xa8, 0x9e, 0xf9, 0xfc, 0xa3, 0x2e, 0x1a, 0xa6, 0x7b, 0x38, - 0xe8, 0x49, 0x1a, 0xb1, 0xe4, 0x50, 0x5b, 0xc1, 0xcf, 0x33, 0xaa, 0x1f, 0x85, 0x32, 0xf1, 0x1c, - 0xa8, 0x1a, 0x44, 0x6e, 0xbe, 0x02, 0x21, 0x9d, 0x8f, 0x98, 0xf3, 0x1a, 0x2c, 0x22, 0x5d, 0x77, - 0x30, 0xa5, 0x21, 0x31, 0x91, 0xc9, 0x71, 0xc0, 0xea, 0xc8, 0x45, 0x21, 0xc9, 0xfe, 0xba, 0xf9, - 0x8d, 0x01, 0x4e, 0xa1, 0xc6, 0xcb, 0x53, 0xac, 0x0d, 0xe6, 0x20, 0xd7, 0xfb, 0xaf, 0x42, 0x4c, - 0xc8, 0x6f, 0x6c, 0x47, 0x3c, 0x65, 0xff, 0x82, 0xa7, 0xdc, 0x7f, 0xe3, 0x69, 0x1d, 0xf8, 0x9b, - 0x6d, 0xc5, 0x1c, 0x45, 0x4c, 0x30, 0x09, 0x26, 0x3e, 0x05, 0x4c, 0x28, 0xa6, 0xe1, 0xa0, 0x7f, - 0x64, 0x62, 0x2e, 0xb1, 0x85, 0x74, 0xb1, 0xb7, 0xd2, 0x15, 0xf6, 0x32, 0x51, 0xd8, 0xcc, 0x5e, - 0x10, 0x2c, 0x2b, 0xd4, 0xd8, 0xeb, 0xeb, 0xc8, 0xc5, 0x9b, 0xbe, 0xfe, 0xa7, 0xb5, 0xf1, 0x00, - 0x8a, 0x36, 0x1e, 0x76, 0x93, 0x37, 0xa6, 0x60, 0xe3, 0x61, 0xe0, 0x94, 0xec, 0x31, 0x7b, 0xbd, - 0xc7, 0x66, 0xcd, 0xbf, 0x98, 0x89, 0x14, 0x51, 0x41, 0xcd, 0x0e, 0xdc, 0x51, 0xa8, 0xd1, 0x39, - 0xc6, 0xc8, 0x99, 0x9d, 0x7b, 0x56, 0xf8, 0xfb, 0xb0, 0x72, 0x2d, 0x48, 0x14, 0x7d, 0xe3, 0x2b, - 0x0b, 0x59, 0x85, 0x1a, 0xdc, 0x2e, 0x14, 0xaf, 0x46, 0x66, 0xca, 0x08, 0x4b, 0xce, 0x23, 0x7e, - 0x6d, 0xf6, 0x79, 0xcc, 0xe5, 0x7b, 0xb8, 0x97, 0x36, 0x6a, 0xc4, 0x54, 0xf7, 0x14, 0x24, 0xbf, - 0x3e, 0x2f, 0x32, 0x4e, 0x89, 0xe1, 0xee, 0xe4, 0xe5, 0x7b, 0x9c, 0x1a, 0x64, 0x02, 0xc5, 0x3f, - 0x9d, 0x07, 0x95, 0x4c, 0x33, 0xa9, 0xec, 0xf4, 0x34, 0x13, 0xa8, 0x29, 0x69, 0xa6, 0x89, 0xf1, - 0x2d, 0x2c, 0x25, 0x55, 0xd7, 0x48, 0x75, 0x4e, 0x20, 0x78, 0xf1, 0x36, 0x44, 0x1c, 0xfa, 0x0d, - 0x40, 0x42, 0x53, 0xf5, 0x54, 0xbf, 0x2b, 0x00, 0xff, 0xe4, 0x16, 0x40, 0x14, 0xb7, 0xbd, 0x75, - 0xfe, 0x4b, 0xc8, 0x9c, 0x8f, 0x05, 0xe6, 0x62, 0x2c, 0x30, 0x3f, 0xc7, 0x02, 0xf3, 0xf1, 0x52, - 0xc8, 0x5c, 0x5c, 0x0a, 0x99, 0xef, 0x97, 0x42, 0xe6, 0xdd, 0x5a, 0x62, 0xf0, 0x74, 0x08, 0xb5, - 0xf6, 0xa3, 0x67, 0x5c, 0x97, 0x4f, 0x83, 0xe7, 0xdc, 0x1f, 0x3e, 0xbd, 0xbc, 0xff, 0x98, 0x3f, - 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, 0xef, 0x6b, 0xa0, 0xa3, 0x4f, 0x08, 0x00, 0x00, + // 840 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x56, 0x4d, 0x6f, 0xe3, 0x44, + 0x18, 0x8e, 0x1b, 0xe7, 0xeb, 0x6d, 0x58, 0x22, 0x93, 0x4d, 0xbd, 0x06, 0x39, 0x91, 0x41, 0x8b, + 0x91, 0xc0, 0x6e, 0x82, 0xc4, 0xbd, 0xc9, 0x72, 0xe8, 0x4a, 0x06, 0xe4, 0x6a, 0xa9, 0xe0, 0x12, + 0x4d, 0xec, 0x89, 0xd7, 0xda, 0xd8, 0x13, 0x3c, 0x93, 0x26, 0xfd, 0x13, 0x88, 0x1b, 0xff, 0x81, + 0xdf, 0xc0, 0x05, 0x89, 0x43, 0x8f, 0x7b, 0x41, 0xe2, 0x14, 0x20, 0xfd, 0x17, 0x9c, 0x90, 0x3f, + 0xeb, 0xcd, 0x3a, 0x69, 0x00, 0x71, 0xe2, 0x92, 0xcc, 0xeb, 0x79, 0xde, 0xaf, 0x67, 0x9e, 0x77, + 0x6c, 0x78, 0x64, 0x11, 0xea, 0x2d, 0x11, 0xf5, 0xf4, 0xe8, 0xe7, 0xaa, 0xaf, 0xb3, 0x95, 0x36, + 0x0f, 0x08, 0x23, 0x42, 0x2b, 0xdd, 0xd2, 0xa2, 0x9f, 0xab, 0xbe, 0x24, 0x87, 0x4f, 0x08, 0xd5, + 0x27, 0x88, 0x62, 0xfd, 0xaa, 0x3f, 0xc1, 0x0c, 0xf5, 0x75, 0x8b, 0xb8, 0x7e, 0xec, 0x21, 0xb5, + 0x1d, 0xe2, 0x90, 0x68, 0xa9, 0x87, 0xab, 0xe4, 0xe9, 0x3b, 0xaf, 0xa7, 0xb8, 0x9e, 0x63, 0x1a, + 0xef, 0x2a, 0x3f, 0x71, 0xd0, 0x34, 0xa8, 0x73, 0xc1, 0x48, 0x80, 0x47, 0xc4, 0xc6, 0x42, 0x07, + 0xaa, 0x14, 0xfb, 0x36, 0x0e, 0x44, 0xae, 0xc7, 0xa9, 0x0d, 0x33, 0xb1, 0x84, 0x4f, 0xe0, 0x41, + 0xe8, 0x3f, 0x9e, 0x5c, 0x33, 0x3c, 0xb6, 0x88, 0x8d, 0xc5, 0xa3, 0x1e, 0xa7, 0x36, 0x87, 0xad, + 0xcd, 0xba, 0xdb, 0xbc, 0x3c, 0xbb, 0x30, 0x86, 0xd7, 0x2c, 0x8a, 0x60, 0x36, 0x43, 0x5c, 0x6a, + 0x09, 0xcf, 0xa0, 0xe3, 0xfa, 0x94, 0x21, 0x9f, 0xb9, 0x88, 0xe1, 0xf1, 0x1c, 0x07, 0x9e, 0x4b, + 0xa9, 0x4b, 0x7c, 0xb1, 0xd2, 0xe3, 0xd4, 0xe3, 0x81, 0xac, 0x6d, 0xf7, 0xa9, 0x9d, 0x59, 0x16, + 0xa6, 0x74, 0x44, 0xfc, 0xa9, 0xeb, 0x98, 0x0f, 0x73, 0xde, 0x5f, 0x64, 0xce, 0x4f, 0xf9, 0x7a, + 0xb9, 0xc5, 0x3f, 0xe5, 0xeb, 0x7c, 0xab, 0xa2, 0x5c, 0x42, 0x3b, 0xdf, 0x82, 0x89, 0xe9, 0x9c, + 0xf8, 0x14, 0x0b, 0xef, 0x42, 0x2d, 0x2c, 0x74, 0xec, 0xda, 0x51, 0x2f, 0xfc, 0x10, 0x36, 0xeb, + 0x6e, 0x35, 0x84, 0x9c, 0x3f, 0x31, 0xab, 0xe1, 0xd6, 0xb9, 0x2d, 0x48, 0x50, 0xb7, 0x9e, 0x63, + 0xeb, 0x05, 0x5d, 0x78, 0x71, 0x47, 0x66, 0x66, 0x2b, 0xdf, 0x1e, 0x41, 0xc7, 0xa0, 0xce, 0xf9, + 0x5d, 0x05, 0x23, 0xe2, 0xb3, 0x00, 0x59, 0x6c, 0x27, 0x4d, 0x6d, 0xa8, 0x20, 0xdb, 0x73, 0xfd, + 0x28, 0x56, 0xc3, 0x8c, 0x8d, 0x7c, 0x25, 0xe5, 0x9d, 0x95, 0xb4, 0xa1, 0x32, 0x43, 0x13, 0x3c, + 0x13, 0xf9, 0xd8, 0x35, 0x32, 0x04, 0x15, 0xca, 0x1e, 0x75, 0x22, 0xb2, 0x9a, 0xc3, 0xce, 0x9f, + 0xeb, 0xae, 0x60, 0xa2, 0x65, 0x5a, 0x86, 0x81, 0x29, 0x45, 0x0e, 0x36, 0x43, 0x88, 0x80, 0xa0, + 0x32, 0x5d, 0xf8, 0x36, 0x15, 0xab, 0xbd, 0xb2, 0x7a, 0x3c, 0x78, 0xa4, 0xc5, 0x72, 0xd1, 0x42, + 0xb9, 0x68, 0x89, 0x5c, 0xb4, 0x11, 0x71, 0xfd, 0xe1, 0xe9, 0xcd, 0xba, 0x5b, 0xfa, 0xe1, 0xb7, + 0xae, 0xea, 0xb8, 0xec, 0xf9, 0x62, 0xa2, 0x59, 0xc4, 0xd3, 0x13, 0x6d, 0xc5, 0x7f, 0x1f, 0x51, + 0xfb, 0x45, 0x22, 0x93, 0xd0, 0x81, 0x9a, 0x71, 0x64, 0xe5, 0xc7, 0x23, 0x38, 0x29, 0x26, 0x64, + 0xf0, 0xff, 0x64, 0x44, 0x10, 0x80, 0xa7, 0x68, 0xc6, 0xc4, 0x5a, 0x24, 0x9d, 0x68, 0x2d, 0x9c, + 0x40, 0x6d, 0xea, 0xae, 0xc6, 0x61, 0x91, 0xf5, 0x1e, 0xa7, 0xd6, 0xcd, 0xea, 0xd4, 0x5d, 0x19, + 0xd4, 0x51, 0x3e, 0x03, 0xb9, 0x98, 0xbd, 0x4c, 0xb2, 0x22, 0xd4, 0x90, 0x6d, 0x07, 0x98, 0xd2, + 0x84, 0xc5, 0xd4, 0x0c, 0x13, 0xd9, 0x88, 0xa1, 0x44, 0xa3, 0xd1, 0x5a, 0xf9, 0x1c, 0xba, 0x3b, + 0x4e, 0xe3, 0x1f, 0x06, 0xfc, 0x85, 0x03, 0xc1, 0xa0, 0xce, 0xa7, 0x2b, 0x6c, 0x2d, 0x0e, 0x10, + 0x7b, 0x38, 0x3b, 0x09, 0x26, 0x39, 0xdd, 0xcc, 0x4e, 0x4f, 0xa9, 0xfc, 0x37, 0x4e, 0xa9, 0xf2, + 0x9f, 0xe9, 0xf6, 0x14, 0xa4, 0xd7, 0xdb, 0xca, 0x38, 0x4a, 0x99, 0xe0, 0x72, 0x4c, 0x7c, 0x1f, + 0x33, 0x61, 0xb8, 0x4e, 0x80, 0xfe, 0x25, 0x13, 0x07, 0x49, 0x3d, 0xa1, 0x8b, 0xbf, 0x97, 0xae, + 0xa4, 0x97, 0xad, 0xc2, 0xf6, 0xf6, 0x82, 0xe0, 0x81, 0x41, 0x9d, 0x67, 0x73, 0x1b, 0x31, 0x7c, + 0x16, 0x4d, 0xdf, 0xae, 0x36, 0xde, 0x86, 0x86, 0x8f, 0x97, 0xe3, 0xfc, 0xbc, 0xd6, 0x7d, 0xbc, + 0x8c, 0x9d, 0xf2, 0x3d, 0x96, 0x5f, 0xed, 0x51, 0x11, 0xa3, 0x8b, 0x32, 0x97, 0x22, 0x2d, 0x48, + 0x19, 0xc1, 0x1b, 0x06, 0x75, 0x46, 0x33, 0x8c, 0x82, 0xfd, 0xb9, 0xf7, 0x85, 0x3f, 0x81, 0x87, + 0xaf, 0x04, 0x49, 0xa3, 0x0f, 0x7e, 0xae, 0x40, 0xd9, 0xa0, 0x8e, 0x70, 0x01, 0x8d, 0xbb, 0x57, + 0x58, 0xc1, 0x2b, 0x25, 0xff, 0x7e, 0x90, 0x1e, 0xef, 0xdf, 0xcf, 0xb8, 0xfc, 0x06, 0xde, 0x2a, + 0xba, 0xfa, 0xd5, 0x42, 0xf7, 0x02, 0xa4, 0x74, 0x7a, 0x28, 0x32, 0x4b, 0xc9, 0xa0, 0x5d, 0x78, + 0xb9, 0x7e, 0x70, 0x68, 0xa4, 0x81, 0xd4, 0x3f, 0x18, 0x9a, 0x65, 0xc5, 0xf0, 0xe6, 0xf6, 0xc8, + 0xbf, 0x57, 0x18, 0x65, 0x0b, 0x25, 0x7d, 0x78, 0x08, 0x2a, 0x9f, 0x66, 0x7b, 0x9e, 0x8a, 0xd3, + 0x6c, 0xa1, 0x76, 0xa4, 0xd9, 0x35, 0x02, 0x5f, 0xc1, 0x71, 0x5e, 0xeb, 0xbd, 0x42, 0xe7, 0x1c, + 0x42, 0x52, 0xef, 0x43, 0x64, 0xa1, 0xbf, 0x04, 0xc8, 0x29, 0xb9, 0x5b, 0xe8, 0x77, 0x07, 0x90, + 0xde, 0xbf, 0x07, 0x90, 0xc6, 0x1d, 0x3e, 0xb9, 0xf9, 0x43, 0x2e, 0xdd, 0x6c, 0x64, 0xee, 0xe5, + 0x46, 0xe6, 0x7e, 0xdf, 0xc8, 0xdc, 0x77, 0xb7, 0x72, 0xe9, 0xe5, 0xad, 0x5c, 0xfa, 0xf5, 0x56, + 0x2e, 0x7d, 0xfd, 0x38, 0x77, 0xdd, 0x8d, 0x08, 0xf5, 0x2e, 0xd3, 0x8f, 0x39, 0x5b, 0x5f, 0xc5, + 0x1f, 0x75, 0xd1, 0x95, 0x37, 0xa9, 0x46, 0x9f, 0x74, 0x1f, 0xff, 0x15, 0x00, 0x00, 0xff, 0xff, + 0x1a, 0x2c, 0xa2, 0xcd, 0x55, 0x0a, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -678,8 +791,12 @@ const _ = grpc.SupportPackageIsVersion4 type MsgClient interface { // StoreCode to submit Wasm code to the system StoreCode(ctx context.Context, in *MsgStoreCode, opts ...grpc.CallOption) (*MsgStoreCodeResponse, error) - // Instantiate creates a new smart contract instance for the given code id. + // InstantiateContract creates a new smart contract instance for the given + // code id. InstantiateContract(ctx context.Context, in *MsgInstantiateContract, opts ...grpc.CallOption) (*MsgInstantiateContractResponse, error) + // InstantiateContract2 creates a new smart contract instance for the given + // code id with a predictable address + InstantiateContract2(ctx context.Context, in *MsgInstantiateContract2, opts ...grpc.CallOption) (*MsgInstantiateContract2Response, error) // Execute submits the given message data to a smart contract ExecuteContract(ctx context.Context, in *MsgExecuteContract, opts ...grpc.CallOption) (*MsgExecuteContractResponse, error) // Migrate runs a code upgrade/ downgrade for a smart contract @@ -716,6 +833,15 @@ func (c *msgClient) InstantiateContract(ctx context.Context, in *MsgInstantiateC return out, nil } +func (c *msgClient) InstantiateContract2(ctx context.Context, in *MsgInstantiateContract2, opts ...grpc.CallOption) (*MsgInstantiateContract2Response, error) { + out := new(MsgInstantiateContract2Response) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Msg/InstantiateContract2", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) ExecuteContract(ctx context.Context, in *MsgExecuteContract, opts ...grpc.CallOption) (*MsgExecuteContractResponse, error) { out := new(MsgExecuteContractResponse) err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Msg/ExecuteContract", in, out, opts...) @@ -756,8 +882,12 @@ func (c *msgClient) ClearAdmin(ctx context.Context, in *MsgClearAdmin, opts ...g type MsgServer interface { // StoreCode to submit Wasm code to the system StoreCode(context.Context, *MsgStoreCode) (*MsgStoreCodeResponse, error) - // Instantiate creates a new smart contract instance for the given code id. + // InstantiateContract creates a new smart contract instance for the given + // code id. InstantiateContract(context.Context, *MsgInstantiateContract) (*MsgInstantiateContractResponse, error) + // InstantiateContract2 creates a new smart contract instance for the given + // code id with a predictable address + InstantiateContract2(context.Context, *MsgInstantiateContract2) (*MsgInstantiateContract2Response, error) // Execute submits the given message data to a smart contract ExecuteContract(context.Context, *MsgExecuteContract) (*MsgExecuteContractResponse, error) // Migrate runs a code upgrade/ downgrade for a smart contract @@ -779,6 +909,10 @@ func (*UnimplementedMsgServer) InstantiateContract(ctx context.Context, req *Msg return nil, status.Errorf(codes.Unimplemented, "method InstantiateContract not implemented") } +func (*UnimplementedMsgServer) InstantiateContract2(ctx context.Context, req *MsgInstantiateContract2) (*MsgInstantiateContract2Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method InstantiateContract2 not implemented") +} + func (*UnimplementedMsgServer) ExecuteContract(ctx context.Context, req *MsgExecuteContract) (*MsgExecuteContractResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ExecuteContract not implemented") } @@ -835,6 +969,24 @@ func _Msg_InstantiateContract_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Msg_InstantiateContract2_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgInstantiateContract2) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).InstantiateContract2(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Msg/InstantiateContract2", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).InstantiateContract2(ctx, req.(*MsgInstantiateContract2)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_ExecuteContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgExecuteContract) if err := dec(in); err != nil { @@ -919,6 +1071,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "InstantiateContract", Handler: _Msg_InstantiateContract_Handler, }, + { + MethodName: "InstantiateContract2", + Handler: _Msg_InstantiateContract2_Handler, + }, { MethodName: "ExecuteContract", Handler: _Msg_ExecuteContract_Handler, @@ -1094,6 +1250,93 @@ func (m *MsgInstantiateContract) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *MsgInstantiateContract2) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgInstantiateContract2) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgInstantiateContract2) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.FixMsg { + i-- + if m.FixMsg { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x40 + } + if len(m.Salt) > 0 { + i -= len(m.Salt) + copy(dAtA[i:], m.Salt) + i = encodeVarintTx(dAtA, i, uint64(len(m.Salt))) + i-- + dAtA[i] = 0x3a + } + if len(m.Funds) > 0 { + for iNdEx := len(m.Funds) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Funds[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintTx(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x2a + } + if len(m.Label) > 0 { + i -= len(m.Label) + copy(dAtA[i:], m.Label) + i = encodeVarintTx(dAtA, i, uint64(len(m.Label))) + i-- + dAtA[i] = 0x22 + } + if m.CodeID != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x18 + } + if len(m.Admin) > 0 { + i -= len(m.Admin) + copy(dAtA[i:], m.Admin) + i = encodeVarintTx(dAtA, i, uint64(len(m.Admin))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *MsgInstantiateContractResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1131,6 +1374,43 @@ func (m *MsgInstantiateContractResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *MsgInstantiateContract2Response) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgInstantiateContract2Response) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgInstantiateContract2Response) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x12 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTx(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *MsgExecuteContract) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1508,34 +1788,24 @@ func (m *MsgInstantiateContract) Size() (n int) { return n } -func (m *MsgInstantiateContractResponse) Size() (n int) { +func (m *MsgInstantiateContract2) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.Address) + l = len(m.Sender) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.Data) + l = len(m.Admin) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - return n -} - -func (m *MsgExecuteContract) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Sender) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if m.CodeID != 0 { + n += 1 + sovTx(uint64(m.CodeID)) } - l = len(m.Contract) + l = len(m.Label) if l > 0 { n += 1 + l + sovTx(uint64(l)) } @@ -1549,15 +1819,26 @@ func (m *MsgExecuteContract) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } } + l = len(m.Salt) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.FixMsg { + n += 2 + } return n } -func (m *MsgExecuteContractResponse) Size() (n int) { +func (m *MsgInstantiateContractResponse) Size() (n int) { if m == nil { return 0 } var l int _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } l = len(m.Data) if l > 0 { n += 1 + l + sovTx(uint64(l)) @@ -1565,25 +1846,82 @@ func (m *MsgExecuteContractResponse) Size() (n int) { return n } -func (m *MsgMigrateContract) Size() (n int) { +func (m *MsgInstantiateContract2Response) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.Sender) + l = len(m.Address) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.Contract) + l = len(m.Data) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - if m.CodeID != 0 { - n += 1 + sovTx(uint64(m.CodeID)) - } - l = len(m.Msg) - if l > 0 { + return n +} + +func (m *MsgExecuteContract) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Funds) > 0 { + for _, e := range m.Funds { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgExecuteContractResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgMigrateContract) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.CodeID != 0 { + n += 1 + sovTx(uint64(m.CodeID)) + } + l = len(m.Msg) + if l > 0 { n += 1 + l + sovTx(uint64(l)) } return n @@ -2157,6 +2495,294 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { return nil } +func (m *MsgInstantiateContract2) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgInstantiateContract2: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgInstantiateContract2: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Admin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Label", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Label = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...) + if m.Msg == nil { + m.Msg = []byte{} + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Funds", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Funds = append(m.Funds, types.Coin{}) + if err := m.Funds[len(m.Funds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Salt", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Salt = append(m.Salt[:0], dAtA[iNdEx:postIndex]...) + if m.Salt == nil { + m.Salt = []byte{} + } + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FixMsg", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.FixMsg = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} + func (m *MsgInstantiateContractResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -2274,6 +2900,123 @@ func (m *MsgInstantiateContractResponse) Unmarshal(dAtA []byte) error { return nil } +func (m *MsgInstantiateContract2Response) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgInstantiateContract2Response: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgInstantiateContract2Response: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} + func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/wasm/types/tx_test.go b/x/wasm/types/tx_test.go index b59ad7ce40..a3c29b4f8b 100644 --- a/x/wasm/types/tx_test.go +++ b/x/wasm/types/tx_test.go @@ -186,6 +186,142 @@ func TestInstantiateContractValidation(t *testing.T) { } } +func TestInstantiateContract2Validation(t *testing.T) { + bad, err := sdk.AccAddressFromHex("012345") + require.NoError(t, err) + badAddress := bad.String() + // proper address size + goodAddress := sdk.AccAddress(make([]byte, 20)).String() + sdk.GetConfig().SetAddressVerifier(VerifyAddressLen()) + + cases := map[string]struct { + msg MsgInstantiateContract2 + valid bool + }{ + "empty": { + msg: MsgInstantiateContract2{}, + valid: false, + }, + "correct minimal": { + msg: MsgInstantiateContract2{ + Sender: goodAddress, + CodeID: firstCodeID, + Label: "foo", + Msg: []byte("{}"), + Salt: []byte{0}, + }, + valid: true, + }, + "missing code": { + msg: MsgInstantiateContract2{ + Sender: goodAddress, + Label: "foo", + Msg: []byte("{}"), + Salt: []byte{0}, + }, + valid: false, + }, + "missing label": { + msg: MsgInstantiateContract2{ + Sender: goodAddress, + Msg: []byte("{}"), + Salt: []byte{0}, + }, + valid: false, + }, + "label too long": { + msg: MsgInstantiateContract2{ + Sender: goodAddress, + Label: strings.Repeat("food", 33), + Salt: []byte{0}, + }, + valid: false, + }, + "bad sender minimal": { + msg: MsgInstantiateContract2{ + Sender: badAddress, + CodeID: firstCodeID, + Label: "foo", + Msg: []byte("{}"), + Salt: []byte{0}, + }, + valid: false, + }, + "correct maximal": { + msg: MsgInstantiateContract2{ + Sender: goodAddress, + CodeID: firstCodeID, + Label: strings.Repeat("a", MaxLabelSize), + Msg: []byte(`{"some": "data"}`), + Funds: sdk.Coins{sdk.Coin{Denom: "foobar", Amount: sdk.NewInt(200)}}, + Salt: bytes.Repeat([]byte{0}, MaxSaltSize), + FixMsg: true, + }, + valid: true, + }, + "negative funds": { + msg: MsgInstantiateContract2{ + Sender: goodAddress, + CodeID: firstCodeID, + Label: "foo", + Msg: []byte(`{"some": "data"}`), + // we cannot use sdk.NewCoin() constructors as they panic on creating invalid data (before we can test) + Funds: sdk.Coins{sdk.Coin{Denom: "foobar", Amount: sdk.NewInt(-200)}}, + Salt: []byte{0}, + }, + valid: false, + }, + "non json init msg": { + msg: MsgInstantiateContract2{ + Sender: goodAddress, + CodeID: firstCodeID, + Label: "foo", + Msg: []byte("invalid-json"), + Salt: []byte{0}, + }, + valid: false, + }, + "empty init msg": { + msg: MsgInstantiateContract2{ + Sender: goodAddress, + CodeID: firstCodeID, + Label: "foo", + Salt: []byte{0}, + }, + valid: false, + }, + "empty salt": { + msg: MsgInstantiateContract2{ + Sender: goodAddress, + CodeID: firstCodeID, + Label: "foo", + Msg: []byte(`{"some": "data"}`), + }, + valid: false, + }, + "salt too long": { + msg: MsgInstantiateContract2{ + Sender: goodAddress, + CodeID: firstCodeID, + Label: "foo", + Msg: []byte(`{"some": "data"}`), + Salt: bytes.Repeat([]byte{0}, 65), + }, + valid: false, + }, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + if tc.valid { + assert.NoError(t, err) + } else { + assert.Error(t, err) + } + }) + } +} + func TestExecuteContractValidation(t *testing.T) { bad, err := sdk.AccAddressFromHex("012345") require.NoError(t, err) diff --git a/x/wasm/types/validation.go b/x/wasm/types/validation.go index 0619c7f082..908c525524 100644 --- a/x/wasm/types/validation.go +++ b/x/wasm/types/validation.go @@ -4,8 +4,11 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) +// MaxSaltSize is the longest salt that can be used when instantiating a contract +const MaxSaltSize = 64 + var ( - // MaxLabelSize is the longest label that can be used when Instantiating a contract + // MaxLabelSize is the longest label that can be used when instantiating a contract MaxLabelSize = 128 // extension point for chains to customize via compile flag. // MaxWasmSize is the largest a compiled contract code can be when storing code on chain @@ -28,7 +31,18 @@ func ValidateLabel(label string) error { return sdkerrors.Wrap(ErrEmpty, "is required") } if len(label) > MaxLabelSize { - return sdkerrors.Wrap(ErrLimit, "cannot be longer than 128 characters") + return ErrLimit.Wrapf("cannot be longer than %d characters", MaxLabelSize) + } + return nil +} + +// ValidateSalt ensure salt constraints +func ValidateSalt(salt []byte) error { + switch n := len(salt); { + case n == 0: + return sdkerrors.Wrap(ErrEmpty, "is required") + case n > MaxSaltSize: + return ErrLimit.Wrapf("cannot be longer than %d characters", MaxSaltSize) } return nil }