Skip to content

Commit

Permalink
Merge branch 'main' into sdk-upgrade050_rebased3
Browse files Browse the repository at this point in the history
* main:
  Set default query limit and ensure constraints (#1632)
  Fix genesis import with predictable addresses
  Add grant system tests (#1626)
  Ensure some contraints and limits on pin/unpin code ids
  • Loading branch information
alpe committed Sep 19, 2023
2 parents 53b6b3e + afa85da commit 902b901
Show file tree
Hide file tree
Showing 13 changed files with 352 additions and 80 deletions.
17 changes: 16 additions & 1 deletion tests/system/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package system

import (
"fmt"
"io"
"os/exec"
"path/filepath"
"strconv"
Expand Down Expand Up @@ -196,6 +197,10 @@ func (c WasmdCli) CustomQuery(args ...string) string {

// execute shell command
func (c WasmdCli) run(args []string) (output string, ok bool) {
return c.runWithInput(args, nil)
}

func (c WasmdCli) runWithInput(args []string, input io.Reader) (output string, ok bool) {
if c.Debug {
c.t.Logf("+++ running `%s %s`", c.execBinary, strings.Join(args, " "))
}
Expand All @@ -207,6 +212,7 @@ func (c WasmdCli) run(args []string) (output string, ok bool) {
}()
cmd := exec.Command(locateExecutable("wasmd"), args...) //nolint:gosec
cmd.Dir = workDir
cmd.Stdin = input
return cmd.CombinedOutput()
}()
ok = c.assertErrorFn(c.t, gotErr, string(gotOut))
Expand Down Expand Up @@ -256,13 +262,22 @@ func (c WasmdCli) WasmExecute(contractAddr, msg, from string, args ...string) st

// AddKey add key to default keyring. Returns address
func (c WasmdCli) AddKey(name string) string {
cmd := c.withKeyringFlags("keys", "add", name, "--no-backup")
cmd := c.withKeyringFlags("keys", "add", name) //, "--no-backup")
out, _ := c.run(cmd)
addr := gjson.Get(out, "address").String()
require.NotEmpty(c.t, addr, "got %q", out)
return addr
}

// AddKeyFromSeed recovers the key from given seed and add it to default keyring. Returns address
func (c WasmdCli) AddKeyFromSeed(name, mnemoic string) string {
cmd := c.withKeyringFlags("keys", "add", name, "--recover")
out, _ := c.runWithInput(cmd, strings.NewReader(mnemoic))
addr := gjson.Get(out, "address").String()
require.NotEmpty(c.t, addr, "got %q", out)
return addr
}

// GetKeyAddr returns address
func (c WasmdCli) GetKeyAddr(name string) string {
cmd := c.withKeyringFlags("keys", "show", name, "-a")
Expand Down
1 change: 1 addition & 0 deletions tests/system/fraud_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
)

func TestRecursiveMsgsExternalTrigger(t *testing.T) {
sut.ResetChain(t)
const maxBlockGas = 2_000_000
sut.ModifyGenesisJSON(t, SetConsensusMaxGas(t, maxBlockGas))
sut.StartChain(t)
Expand Down
12 changes: 12 additions & 0 deletions tests/system/genesis_io.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,15 @@ func GetGenesisBalance(rawGenesis []byte, addr string) sdk.Coins {
}
return r
}

// SetCodeUploadPermission sets the code upload permissions
func SetCodeUploadPermission(t *testing.T, permission string, addresses ...string) GenesisMutator {
return func(genesis []byte) []byte {
t.Helper()
state, err := sjson.Set(string(genesis), "app_state.wasm.params.code_upload_access.permission", permission)
require.NoError(t, err)
state, err = sjson.Set(state, "app_state.wasm.params.code_upload_access.addresses", addresses)
require.NoError(t, err)
return []byte(state)
}
}
62 changes: 62 additions & 0 deletions tests/system/permissioned_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//go:build system_test

package system

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
)

func TestGrantStoreCodePermissionedChain(t *testing.T) {
cli := NewWasmdCLI(t, sut, verbose)
// set params to restrict chain
const chainAuthorityAddress = "wasm1pvuujjdk0xt043ga0j9nrfh5u8pzj4rpplyqkm"
sut.ModifyGenesisJSON(t, SetCodeUploadPermission(t, "AnyOfAddresses", chainAuthorityAddress))

recoveredAddress := cli.AddKeyFromSeed("chain_authority", "aisle ship absurd wedding arch admit fringe foam cluster tide trim aisle salad shiver tackle palm glance wrist valley hamster couch crystal frozen chronic")
require.Equal(t, chainAuthorityAddress, recoveredAddress)
devAccount := cli.AddKey("dev_account")

sut.ModifyGenesisCLI(t,
[]string{"genesis", "add-genesis-account", chainAuthorityAddress, "100000000stake"},
)
sut.ModifyGenesisCLI(t,
[]string{"genesis", "add-genesis-account", devAccount, "100000000stake"},
)

sut.StartChain(t)

// query params
rsp := cli.CustomQuery("q", "wasm", "params")
permission := gjson.Get(rsp, "code_upload_access.permission").String()
addrRes := gjson.Get(rsp, "code_upload_access.addresses").Array()
require.Equal(t, 1, len(addrRes))

require.Equal(t, permission, "AnyOfAddresses")
require.Equal(t, chainAuthorityAddress, addrRes[0].Str)

// chain_authority grant upload permission to dev_account
rsp = cli.CustomCommand("tx", "wasm", "grant", "store-code", devAccount, "*:*", "--from="+chainAuthorityAddress)
RequireTxSuccess(t, rsp)

// dev_account store code fails as the address is not in the code-upload accept-list
rsp = cli.CustomCommand("tx", "wasm", "store", "./testdata/hackatom.wasm.gzip", "--from="+devAccount, "--gas=1500000", "--fees=2stake")
RequireTxFailure(t, rsp)

// create tx should work for addresses in the accept-list
args := cli.withTXFlags("tx", "wasm", "store", "./testdata/hackatom.wasm.gzip", "--from="+chainAuthorityAddress, "--generate-only")
tx, ok := cli.run(args)
require.True(t, ok)

pathToTx := filepath.Join(t.TempDir(), "tx.json")
err := os.WriteFile(pathToTx, []byte(tx), os.FileMode(0o744))
require.NoError(t, err)

// store code via authz execution uses the given grant and should succeed
rsp = cli.CustomCommand("tx", "authz", "exec", pathToTx, "--from="+devAccount, "--gas=1500000", "--fees=2stake")
RequireTxSuccess(t, rsp)
}
22 changes: 13 additions & 9 deletions x/wasm/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func GetCmdListCode() *cobra.Command {
SilenceUsage: true,
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "list codes")
addPaginationFlags(cmd, "list codes")
return cmd
}

Expand Down Expand Up @@ -190,7 +190,7 @@ func GetCmdListContractByCode() *cobra.Command {
SilenceUsage: true,
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "list contracts by code")
addPaginationFlags(cmd, "list contracts by code")
return cmd
}

Expand Down Expand Up @@ -368,10 +368,7 @@ func GetCmdGetContractStateAll() *cobra.Command {
SilenceUsage: true,
}
flags.AddQueryFlagsToCmd(cmd)
cmd.Flags().String(flags.FlagPageKey, "", "pagination page-key of contract state to query for")
cmd.Flags().Uint64(flags.FlagLimit, 100, "pagination limit of contract state to query for")
cmd.Flags().Bool(flags.FlagReverse, false, "results are sorted in descending order")

addPaginationFlags(cmd, "contract state")
return cmd
}

Expand Down Expand Up @@ -507,7 +504,7 @@ func GetCmdGetContractHistory() *cobra.Command {
}

flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "contract history")
addPaginationFlags(cmd, "contract history")
return cmd
}

Expand Down Expand Up @@ -543,7 +540,7 @@ func GetCmdListPinnedCode() *cobra.Command {
SilenceUsage: true,
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "list codes")
addPaginationFlags(cmd, "list codes")
return cmd
}

Expand Down Expand Up @@ -584,7 +581,7 @@ func GetCmdListContractsByCreator() *cobra.Command {
SilenceUsage: true,
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "list contracts by creator")
addPaginationFlags(cmd, "list contracts by creator")
return cmd
}

Expand Down Expand Up @@ -677,3 +674,10 @@ func GetCmdQueryParams() *cobra.Command {

return cmd
}

// supports a subset of the SDK pagination params for better resource utilization
func addPaginationFlags(cmd *cobra.Command, query string) {
cmd.Flags().String(flags.FlagPageKey, "", fmt.Sprintf("pagination page-key of %s to query for", query))
cmd.Flags().Uint64(flags.FlagLimit, 100, fmt.Sprintf("pagination limit of %s to query for", query))
cmd.Flags().Bool(flags.FlagReverse, false, "results are sorted in descending order")
}
43 changes: 26 additions & 17 deletions x/wasm/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ func GetTxCmd() *cobra.Command {
MigrateContractCmd(),
UpdateContractAdminCmd(),
ClearContractAdminCmd(),
GrantAuthorizationCmd(),
GrantStoreCodeAuthorizationCmd(),
GrantCmd(),
UpdateInstantiateConfigCmd(),
SubmitProposalCmd(),
)
Expand Down Expand Up @@ -404,17 +403,31 @@ func parseExecuteArgs(contractAddr, execMsg string, sender sdk.AccAddress, flags
}, nil
}

func GrantCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: "grant",
Short: "Grant a authz permission",
DisableFlagParsing: true,
SilenceUsage: true,
}
txCmd.AddCommand(
GrantAuthorizationCmd(),
GrantStoreCodeAuthorizationCmd(),
)
return txCmd
}

func GrantAuthorizationCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "grant [grantee] [message_type=\"execution\"|\"migration\"] [contract_addr_bech32] --allow-raw-msgs [msg1,msg2,...] --allow-msg-keys [key1,key2,...] --allow-all-messages",
Short: "Grant authorization to an address",
Use: "contract [message_type=\"execution\"|\"migration\"] [grantee] [contract_addr_bech32] --allow-raw-msgs [msg1,msg2,...] --allow-msg-keys [key1,key2,...] --allow-all-messages",
Short: "Grant authorization to interact with a contract on behalf of you",
Long: fmt.Sprintf(`Grant authorization to an address.
Examples:
$ %s tx grant <grantee_addr> execution <contract_addr> --allow-all-messages --max-calls 1 --no-token-transfer --expiration 1667979596
$ %s tx grant contract execution <grantee_addr> <contract_addr> --allow-all-messages --max-calls 1 --no-token-transfer --expiration 1667979596
$ %s tx grant <grantee_addr> execution <contract_addr> --allow-all-messages --max-funds 100000uwasm --expiration 1667979596
$ %s tx grant contract execution <grantee_addr> <contract_addr> --allow-all-messages --max-funds 100000uwasm --expiration 1667979596
$ %s tx grant <grantee_addr> execution <contract_addr> --allow-all-messages --max-calls 5 --max-funds 100000uwasm --expiration 1667979596
$ %s tx grant contract execution <grantee_addr> <contract_addr> --allow-all-messages --max-calls 5 --max-funds 100000uwasm --expiration 1667979596
`, version.AppName, version.AppName, version.AppName),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
Expand Down Expand Up @@ -549,15 +562,15 @@ $ %s tx grant <grantee_addr> execution <contract_addr> --allow-all-messages --ma

func GrantStoreCodeAuthorizationCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "grant [grantee] store-code [code_hash:permission]",
Short: "Grant authorization to an address",
Use: "store-code [grantee] [code_hash:permission]",
Short: "Grant authorization to upload contract code on behalf of you",
Long: fmt.Sprintf(`Grant authorization to an address.
Examples:
$ %s tx grant <grantee_addr> store-code 13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5:everybody 1wqrtry681b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5:nobody --expiration 1667979596
$ %s tx grant store-code <grantee_addr> 13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5:everybody 1wqrtry681b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5:nobody --expiration 1667979596
$ %s tx grant <grantee_addr> store-code *:%s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm,%s1vx8knpllrj7n963p9ttd80w47kpacrhuts497x
$ %s tx grant store-code <grantee_addr> *:%s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm,%s1vx8knpllrj7n963p9ttd80w47kpacrhuts497x
`, version.AppName, version.AppName, version.AppName, version.AppName),
Args: cobra.MinimumNArgs(3),
Args: cobra.MinimumNArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
Expand All @@ -569,11 +582,7 @@ $ %s tx grant <grantee_addr> store-code *:%s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx5
return err
}

if args[1] != "store-code" {
return fmt.Errorf("%s authorization type not supported", args[1])
}

grants, err := parseStoreCodeGrants(args[2:])
grants, err := parseStoreCodeGrants(args[1:])
if err != nil {
return err
}
Expand Down
13 changes: 7 additions & 6 deletions x/wasm/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState) ([]ab
}
}

var maxContractID int
for i, contract := range data.Contracts {
contractAddr, err := sdk.AccAddressFromBech32(contract.ContractAddress)
if err != nil {
Expand All @@ -53,7 +52,6 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState) ([]ab
if err != nil {
return nil, errorsmod.Wrapf(err, "contract number %d", i)
}
maxContractID = i + 1 // not ideal but max(contractID) is not persisted otherwise
}

for i, seq := range data.Sequences {
Expand All @@ -71,12 +69,15 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState) ([]ab
if seqVal <= maxCodeID {
return nil, errorsmod.Wrapf(types.ErrInvalid, "seq %s with value: %d must be greater than: %d ", string(types.KeySequenceCodeID), seqVal, maxCodeID)
}
seqVal, err = keeper.PeekAutoIncrementID(ctx, types.KeySequenceInstanceID)
// ensure next classic address is unused so that we know the sequence is good
rCtx, _ := ctx.CacheContext()
seqVal, err = keeper.PeekAutoIncrementID(rCtx, types.KeySequenceInstanceID)
if err != nil {
return nil, nil
return nil, err
}
if seqVal <= uint64(maxContractID) {
return nil, errorsmod.Wrapf(types.ErrInvalid, "seq %s with value: %d must be greater than: %d ", string(types.KeySequenceInstanceID), seqVal, maxContractID)
addr := keeper.ClassicAddressGenerator()(rCtx, seqVal, nil)
if keeper.HasContractInfo(ctx, addr) {
return nil, errorsmod.Wrapf(types.ErrInvalid, "value: %d for seq %s was used already", seqVal, string(types.KeySequenceInstanceID))
}
return nil, nil
}
Expand Down
16 changes: 15 additions & 1 deletion x/wasm/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,20 @@ func TestGenesisExportImport(t *testing.T) {
}
}

func TestGenesisExportImportWithPredictableAddress(t *testing.T) {
ctx, keepers := CreateTestInput(t, false, AvailableCapabilities)
k := keepers.WasmKeeper
eCtx, _ := ctx.CacheContext()
codeID := StoreReflectContract(t, eCtx, keepers).CodeID
creator := RandomAccountAddress(t)
_, _, err := keepers.ContractKeeper.Instantiate2(eCtx, codeID, creator, nil, []byte("{}"), "testing", nil, []byte("my_salt"), false)
require.NoError(t, err)
genesisState := ExportGenesis(eCtx, k)
// when imported
_, err = InitGenesis(ctx, k, *genesisState)
require.NoError(t, err)
}

func TestGenesisInit(t *testing.T) {
wasmCode, err := os.ReadFile("./testdata/hackatom.wasm")
require.NoError(t, err)
Expand Down Expand Up @@ -445,7 +459,7 @@ func TestGenesisInit(t *testing.T) {
Params: types.DefaultParams(),
},
},
"prevent contract id seq init value == count contracts": {
"prevent contract id seq init value not high enough": {
src: types.GenesisState{
Codes: []types.Code{{
CodeID: firstCodeID,
Expand Down
Loading

0 comments on commit 902b901

Please sign in to comment.