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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
<a name="cosmwasm.wasm.v1.MsgInstantiateContract2"></a>
|
||||
|
||||
### 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 |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="cosmwasm.wasm.v1.MsgInstantiateContract2Response"></a>
|
||||
|
||||
### 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 |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="cosmwasm.wasm.v1.MsgInstantiateContractResponse"></a>
|
||||
|
||||
### 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 |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
}),
|
||||
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()}},
|
||||
},
|
||||
},
|
||||
mutator: func(cmd *cobra.Command) {
|
||||
cmd.SetArgs([]string{myFirstContractAddress, `{}`})
|
||||
cmd.SetArgs([]string{firstContractAddress, `{}`})
|
||||
flagSet := cmd.Flags()
|
||||
flagSet.Set("run-as", myWellFundedAccount)
|
||||
},
|
||||
expMsgCount: 2,
|
||||
},
|
||||
"all good with contract from genesis store messages and contract sequence set": {
|
||||
srcGenesis: types.GenesisState{
|
||||
Params: types.DefaultParams(),
|
||||
Codes: []types.Code{
|
||||
{
|
||||
CodeID: 1,
|
||||
CodeInfo: types.CodeInfoFixture(),
|
||||
CodeBytes: wasmIdent,
|
||||
},
|
||||
},
|
||||
GenMsgs: []types.GenesisState_GenMsgs{
|
||||
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: types.MsgInstantiateContractFixture()}},
|
||||
},
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: types.KeyLastInstanceID, Value: 100},
|
||||
},
|
||||
},
|
||||
mutator: func(cmd *cobra.Command) {
|
||||
// See TestBuildContractAddress in keeper_test.go
|
||||
cmd.SetArgs([]string{"cosmos1mujpjkwhut9yjw4xueyugc02evfv46y0dtmnz4lh8xxkkdapym9stu5qm8", `{}`})
|
||||
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 message state with contract sequence": {
|
||||
src: types.GenesisState{
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: types.KeyLastInstanceID, Value: 100},
|
||||
},
|
||||
GenMsgs: []types.GenesisState_GenMsgs{
|
||||
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "hundred"}}},
|
||||
},
|
||||
},
|
||||
exp: []ContractMeta{
|
||||
{
|
||||
ContractAddress: keeper.BuildContractAddressClassic(0, 100).String(),
|
||||
Info: types.ContractInfo{Label: "hundred"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"read from contract and message state with contract sequence": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{
|
||||
{CodeID: 1, CodeInfo: types.CodeInfo{CodeHash: []byte("firstCodeHash")}},
|
||||
{CodeID: 100, CodeInfo: types.CodeInfo{CodeHash: []byte("otherCodeHash")}},
|
||||
},
|
||||
Contracts: []types.Contract{
|
||||
{
|
||||
ContractAddress: 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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
cmd.Println(keeper.BuildContractAddress(codeHash, creator, label).String())
|
||||
|
||||
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.BuildContractAddressPredictable(codeHash, creator, salt, msg).String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
decoder.RegisterFlags(cmd.PersistentFlags(), "salt")
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
||||
@@ -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]",
|
||||
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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
76
x/wasm/keeper/addresses.go
Normal file
76
x/wasm/keeper/addresses.go
Normal file
@@ -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...)
|
||||
}
|
||||
432
x/wasm/keeper/addresses_test.go
Normal file
432
x/wasm/keeper/addresses_test.go
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
`
|
||||
@@ -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) {
|
||||
|
||||
168
x/wasm/keeper/contract_keeper_test.go
Normal file
168
x/wasm/keeper/contract_keeper_test.go
Normal file
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
var (
|
||||
otherAddress sdk.AccAddress = bytes.Repeat([]byte{0x2}, types.ContractAddrLen)
|
||||
contractAddr = BuildContractAddressClassic(1, 1)
|
||||
)
|
||||
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), "")
|
||||
)
|
||||
|
||||
specs := map[string]struct {
|
||||
state types.ContractInfo
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
28
x/wasm/keeper/wasmtesting/extension_mocks.go
Normal file
28
x/wasm/keeper/wasmtesting/extension_mocks.go
Normal file
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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{}{},
|
||||
|
||||
@@ -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{},
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -33,6 +33,7 @@ var (
|
||||
TXCounterPrefix = []byte{0x08}
|
||||
|
||||
KeyLastCodeID = append(SequenceKeyPrefix, []byte("lastCodeId")...)
|
||||
KeyLastInstanceID = append(SequenceKeyPrefix, []byte("lastContractId")...)
|
||||
)
|
||||
|
||||
// GetCodeKey constructs the key for retreiving the ID for the WASM code
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user