Add grant system tests (#1626)
* Add grant system tests * Add unpermissioned chain test case * Fix tests * Update cli and fix feedbacks * Revisit CLI and system tests (#1627) * Restructure CLI; fix system test * Review feedback --------- Co-authored-by: Alexander Peters <alpe@users.noreply.github.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package system
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -196,6 +197,10 @@ func (c WasmdCli) CustomQuery(args ...string) string {
|
|||||||
|
|
||||||
// execute shell command
|
// execute shell command
|
||||||
func (c WasmdCli) run(args []string) (output string, ok bool) {
|
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 {
|
if c.Debug {
|
||||||
c.t.Logf("+++ running `%s %s`", c.execBinary, strings.Join(args, " "))
|
c.t.Logf("+++ running `%s %s`", c.execBinary, strings.Join(args, " "))
|
||||||
}
|
}
|
||||||
@@ -207,6 +212,7 @@ func (c WasmdCli) run(args []string) (output string, ok bool) {
|
|||||||
}()
|
}()
|
||||||
cmd := exec.Command(locateExecutable("wasmd"), args...) //nolint:gosec
|
cmd := exec.Command(locateExecutable("wasmd"), args...) //nolint:gosec
|
||||||
cmd.Dir = workDir
|
cmd.Dir = workDir
|
||||||
|
cmd.Stdin = input
|
||||||
return cmd.CombinedOutput()
|
return cmd.CombinedOutput()
|
||||||
}()
|
}()
|
||||||
ok = c.assertErrorFn(c.t, gotErr, string(gotOut))
|
ok = c.assertErrorFn(c.t, gotErr, string(gotOut))
|
||||||
@@ -256,13 +262,22 @@ func (c WasmdCli) WasmExecute(contractAddr, msg, from string, args ...string) st
|
|||||||
|
|
||||||
// AddKey add key to default keyring. Returns address
|
// AddKey add key to default keyring. Returns address
|
||||||
func (c WasmdCli) AddKey(name string) string {
|
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)
|
out, _ := c.run(cmd)
|
||||||
addr := gjson.Get(out, "address").String()
|
addr := gjson.Get(out, "address").String()
|
||||||
require.NotEmpty(c.t, addr, "got %q", out)
|
require.NotEmpty(c.t, addr, "got %q", out)
|
||||||
return addr
|
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
|
// GetKeyAddr returns address
|
||||||
func (c WasmdCli) GetKeyAddr(name string) string {
|
func (c WasmdCli) GetKeyAddr(name string) string {
|
||||||
cmd := c.withKeyringFlags("keys", "show", name, "-a")
|
cmd := c.withKeyringFlags("keys", "show", name, "-a")
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestRecursiveMsgsExternalTrigger(t *testing.T) {
|
func TestRecursiveMsgsExternalTrigger(t *testing.T) {
|
||||||
|
sut.ResetChain(t)
|
||||||
const maxBlockGas = 2_000_000
|
const maxBlockGas = 2_000_000
|
||||||
sut.ModifyGenesisJSON(t, SetConsensusMaxGas(t, maxBlockGas))
|
sut.ModifyGenesisJSON(t, SetConsensusMaxGas(t, maxBlockGas))
|
||||||
sut.StartChain(t)
|
sut.StartChain(t)
|
||||||
|
|||||||
@@ -31,3 +31,15 @@ func GetGenesisBalance(rawGenesis []byte, addr string) sdk.Coins {
|
|||||||
}
|
}
|
||||||
return r
|
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
tests/system/permissioned_test.go
Normal file
62
tests/system/permissioned_test.go
Normal file
@@ -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)
|
||||||
|
}
|
||||||
@@ -67,8 +67,7 @@ func GetTxCmd() *cobra.Command {
|
|||||||
MigrateContractCmd(),
|
MigrateContractCmd(),
|
||||||
UpdateContractAdminCmd(),
|
UpdateContractAdminCmd(),
|
||||||
ClearContractAdminCmd(),
|
ClearContractAdminCmd(),
|
||||||
GrantAuthorizationCmd(),
|
GrantCmd(),
|
||||||
GrantStoreCodeAuthorizationCmd(),
|
|
||||||
UpdateInstantiateConfigCmd(),
|
UpdateInstantiateConfigCmd(),
|
||||||
SubmitProposalCmd(),
|
SubmitProposalCmd(),
|
||||||
)
|
)
|
||||||
@@ -415,17 +414,31 @@ func parseExecuteArgs(contractAddr, execMsg string, sender sdk.AccAddress, flags
|
|||||||
}, nil
|
}, 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 {
|
func GrantAuthorizationCmd() *cobra.Command {
|
||||||
cmd := &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",
|
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 an address",
|
Short: "Grant authorization to interact with a contract on behalf of you",
|
||||||
Long: fmt.Sprintf(`Grant authorization to an address.
|
Long: fmt.Sprintf(`Grant authorization to an address.
|
||||||
Examples:
|
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),
|
`, version.AppName, version.AppName, version.AppName),
|
||||||
Args: cobra.ExactArgs(3),
|
Args: cobra.ExactArgs(3),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
@@ -560,15 +573,15 @@ $ %s tx grant <grantee_addr> execution <contract_addr> --allow-all-messages --ma
|
|||||||
|
|
||||||
func GrantStoreCodeAuthorizationCmd() *cobra.Command {
|
func GrantStoreCodeAuthorizationCmd() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "grant [grantee] store-code [code_hash:permission]",
|
Use: "store-code [grantee] [code_hash:permission]",
|
||||||
Short: "Grant authorization to an address",
|
Short: "Grant authorization to upload contract code on behalf of you",
|
||||||
Long: fmt.Sprintf(`Grant authorization to an address.
|
Long: fmt.Sprintf(`Grant authorization to an address.
|
||||||
Examples:
|
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),
|
`, version.AppName, version.AppName, version.AppName, version.AppName),
|
||||||
Args: cobra.MinimumNArgs(3),
|
Args: cobra.MinimumNArgs(2),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
clientCtx, err := client.GetClientTxContext(cmd)
|
clientCtx, err := client.GetClientTxContext(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -580,11 +593,7 @@ $ %s tx grant <grantee_addr> store-code *:%s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx5
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if args[1] != "store-code" {
|
grants, err := parseStoreCodeGrants(args[1:])
|
||||||
return fmt.Errorf("%s authorization type not supported", args[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
grants, err := parseStoreCodeGrants(args[2:])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func (a *StoreCodeAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authztype
|
|||||||
}
|
}
|
||||||
|
|
||||||
code := storeMsg.WASMByteCode
|
code := storeMsg.WASMByteCode
|
||||||
permission := *storeMsg.InstantiatePermission
|
permission := storeMsg.InstantiatePermission
|
||||||
|
|
||||||
if ioutils.IsGzip(code) {
|
if ioutils.IsGzip(code) {
|
||||||
gasRegister, ok := GasRegisterFromContext(ctx)
|
gasRegister, ok := GasRegisterFromContext(ctx)
|
||||||
@@ -127,7 +127,7 @@ func (g CodeGrant) ValidateBasic() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Accept checks if checksum and permission match the grant
|
// Accept checks if checksum and permission match the grant
|
||||||
func (g CodeGrant) Accept(checksum []byte, permission AccessConfig) bool {
|
func (g CodeGrant) Accept(checksum []byte, permission *AccessConfig) bool {
|
||||||
if !strings.EqualFold(string(g.CodeHash), CodehashWildcard) && !bytes.EqualFold(g.CodeHash, checksum) {
|
if !strings.EqualFold(string(g.CodeHash), CodehashWildcard) && !bytes.EqualFold(g.CodeHash, checksum) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user