Skip to content

Commit

Permalink
Merge branch 'main' into sdk-upgrade050_rebased3
Browse files Browse the repository at this point in the history
* main:
  Add store code authz (#1591)
  Handle query for non ibc contracts
  Test channels query
  Start rework channel query
  Restrict pagination on all state query
  • Loading branch information
alpe committed Sep 15, 2023
2 parents b17cec2 + e0bfaa5 commit dbc9460
Show file tree
Hide file tree
Showing 33 changed files with 836 additions and 279 deletions.
2 changes: 2 additions & 0 deletions app/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type HandlerOptions struct {

IBCKeeper *keeper.Keeper
WasmConfig *wasmTypes.WasmConfig
WasmKeeper *wasmkeeper.Keeper
TXCounterStoreService corestoretypes.KVStoreService
CircuitKeeper *circuitkeeper.Keeper
}
Expand Down Expand Up @@ -52,6 +53,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit), // after setup context to enforce limits early
wasmkeeper.NewCountTXDecorator(options.TXCounterStoreService),
wasmkeeper.NewGasRegisterDecorator(options.WasmKeeper.GetGasRegister()),
circuitante.NewCircuitBreakerDecorator(options.CircuitKeeper),
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
ante.NewValidateBasicDecorator(),
Expand Down
1 change: 1 addition & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,7 @@ func (app *WasmApp) setAnteHandler(txConfig client.TxConfig, wasmConfig wasmtype
},
IBCKeeper: app.IBCKeeper,
WasmConfig: &wasmConfig,
WasmKeeper: &app.WasmKeeper,
TXCounterStoreService: runtime.NewKVStoreService(txCounterStoreKey),
CircuitKeeper: &app.CircuitKeeper,
},
Expand Down
5 changes: 3 additions & 2 deletions docs/proto/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@ CodeGrant a granted permission for a single code

| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `code_hash` | [bytes](#bytes) | | CodeHash is the unique identifier created by wasmvm |
| `instantiate_permission` | [AccessConfig](#cosmwasm.wasm.v1.AccessConfig) | | InstantiatePermission access control to apply on contract creation, optional |
| `code_hash` | [bytes](#bytes) | | CodeHash is the unique identifier created by wasmvm Wildcard "*" is used to specify any kind of grant. |
| `instantiate_permission` | [AccessConfig](#cosmwasm.wasm.v1.AccessConfig) | | InstantiatePermission is the superset access control to apply on contract creation. Optional |



Expand Down Expand Up @@ -476,6 +476,7 @@ Since: wasmd 0.30

### StoreCodeAuthorization
StoreCodeAuthorization defines authorization for wasm code upload.
Since: wasmd 0.42


| Field | Type | Label | Description |
Expand Down
7 changes: 5 additions & 2 deletions proto/cosmwasm/wasm/v1/authz.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ option go_package = "github.com/CosmWasm/wasmd/x/wasm/types";
option (gogoproto.goproto_getters_all) = false;

// StoreCodeAuthorization defines authorization for wasm code upload.
// Since: wasmd 0.42
message StoreCodeAuthorization {
option (amino.name) = "wasm/StoreCodeAuthorization";
option (cosmos_proto.implements_interface) =
Expand Down Expand Up @@ -49,10 +50,12 @@ message ContractMigrationAuthorization {
// CodeGrant a granted permission for a single code
message CodeGrant {
// CodeHash is the unique identifier created by wasmvm
// Wildcard "*" is used to specify any kind of grant.
bytes code_hash = 1;

// InstantiatePermission access control to apply on contract creation,
// optional
// InstantiatePermission is the superset access control to apply
// on contract creation.
// Optional
AccessConfig instantiate_permission = 2;
}

Expand Down
150 changes: 134 additions & 16 deletions tests/e2e/grants_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,6 @@ func TestGrants(t *testing.T) {
}

func TestStoreCodeGrant(t *testing.T) {
// Given a grant for address B by A created
// When B uploads code from A
// Then the grant is executed as defined
// And
// - balance A reduced (on success)
// - balance B not touched

reflectWasmCode, err := os.ReadFile("../../x/wasm/keeper/testdata/reflect_1_1.wasm")
require.NoError(t, err)

Expand Down Expand Up @@ -167,7 +160,7 @@ func TestStoreCodeGrant(t *testing.T) {
senderKey: granteePrivKey,
},
"not match code hash": {
codeHash: []byte("ABC"),
codeHash: []byte("any_valid_checksum"),
instantiatePermission: types.AllowEverybody,
senderKey: granteePrivKey,
expErr: sdkerrors.ErrUnauthorized,
Expand All @@ -188,7 +181,7 @@ func TestStoreCodeGrant(t *testing.T) {
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
// setup grant
grant, err := types.NewCodeGrant(spec.codeHash, spec.instantiatePermission)
grant, err := types.NewCodeGrant(spec.codeHash, &spec.instantiatePermission) //nolint:gosec
require.NoError(t, err)
authorization := types.NewStoreCodeAuthorization(*grant)
expiry := time.Now().Add(time.Hour)
Expand All @@ -197,8 +190,6 @@ func TestStoreCodeGrant(t *testing.T) {
_, err = chain.SendMsgs(grantMsg)
require.NoError(t, err)

granterStartBalance := chain.Balance(granterAddr, sdk.DefaultBondDenom).Amount

// when
execMsg := authz.NewMsgExec(spec.senderKey.PubKey().Address().Bytes(), []sdk.Msg{&types.MsgStoreCode{
Sender: granterAddr.String(),
Expand All @@ -209,14 +200,141 @@ func TestStoreCodeGrant(t *testing.T) {

// then
if spec.expErr != nil {
require.Contains(t, gotErr.Error(), spec.expErr.Error())
assert.Equal(t, sdkmath.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount)
assert.Equal(t, granterStartBalance, chain.Balance(granterAddr, sdk.DefaultBondDenom).Amount)
assert.ErrorContains(t, gotErr, fmt.Sprintf("%s/%d:", spec.expErr.Codespace(), spec.expErr.ABCICode()))
return
}
require.NoError(t, gotErr)
})
}
}

func TestGzipStoreCodeGrant(t *testing.T) {
hackatomWasmCode, err := os.ReadFile("../../x/wasm/keeper/testdata/hackatom.wasm")
require.NoError(t, err)

hackatomGzipWasmCode, err := os.ReadFile("../../x/wasm/keeper/testdata/hackatom.wasm.gzip")
require.NoError(t, err)

hackatomCodeChecksum, err := wasmvm.CreateChecksum(hackatomWasmCode)
require.NoError(t, err)

coord := ibctesting.NewCoordinator(t, 1)
chain := coord.GetChain(ibctesting.GetChainID(1))

granterAddr := chain.SenderAccount.GetAddress()
granteePrivKey := secp256k1.GenPrivKey()
granteeAddr := sdk.AccAddress(granteePrivKey.PubKey().Address().Bytes())
otherPrivKey := secp256k1.GenPrivKey()
otherAddr := sdk.AccAddress(otherPrivKey.PubKey().Address().Bytes())

chain.Fund(granteeAddr, sdkmath.NewInt(1_000_000))
chain.Fund(otherAddr, sdkmath.NewInt(1_000_000))
assert.Equal(t, sdkmath.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount)

specs := map[string]struct {
codeHash []byte
instantiatePermission types.AccessConfig
senderKey cryptotypes.PrivKey
expErr *errorsmod.Error
}{
"any code hash": {
codeHash: []byte("*"),
instantiatePermission: types.AllowEverybody,
senderKey: granteePrivKey,
},
"match code hash and permission": {
codeHash: hackatomCodeChecksum,
instantiatePermission: types.AllowEverybody,
senderKey: granteePrivKey,
},
"not match code hash": {
codeHash: []byte("any_valid_checksum"),
instantiatePermission: types.AllowEverybody,
senderKey: granteePrivKey,
expErr: sdkerrors.ErrUnauthorized,
},
"not match permission": {
codeHash: []byte("*"),
instantiatePermission: types.AllowNobody,
senderKey: granteePrivKey,
expErr: sdkerrors.ErrUnauthorized,
},
"non authorized sender address": {
codeHash: []byte("*"),
instantiatePermission: types.AllowEverybody,
senderKey: otherPrivKey,
expErr: authz.ErrNoAuthorizationFound,
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
// setup grant
grant, err := types.NewCodeGrant(spec.codeHash, &spec.instantiatePermission) //nolint:gosec
require.NoError(t, err)
authorization := types.NewStoreCodeAuthorization(*grant)
expiry := time.Now().Add(time.Hour)
grantMsg, err := authz.NewMsgGrant(granterAddr, granteeAddr, authorization, &expiry)
require.NoError(t, err)
_, err = chain.SendMsgs(grantMsg)
require.NoError(t, err)

// when
execMsg := authz.NewMsgExec(spec.senderKey.PubKey().Address().Bytes(), []sdk.Msg{&types.MsgStoreCode{
Sender: granterAddr.String(),
WASMByteCode: hackatomGzipWasmCode,
InstantiatePermission: &types.AllowEverybody,
}})
_, gotErr := chain.SendNonDefaultSenderMsgs(spec.senderKey, &execMsg)

// then
if spec.expErr != nil {
assert.ErrorContains(t, gotErr, fmt.Sprintf("%s/%d:", spec.expErr.Codespace(), spec.expErr.ABCICode()))
return
}
require.NoError(t, gotErr)
assert.Equal(t, sdkmath.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount)
// assert.True(t, granterStartBalance.GT(chain.Balance(granterAddr, sdk.DefaultBondDenom).Amount))
})
}
}

func TestBrokenGzipStoreCodeGrant(t *testing.T) {
brokenGzipWasmCode, err := os.ReadFile("../../x/wasm/keeper/testdata/broken_crc.gzip")
require.NoError(t, err)

coord := ibctesting.NewCoordinator(t, 1)
chain := coord.GetChain(ibctesting.GetChainID(1))

granterAddr := chain.SenderAccount.GetAddress()
granteePrivKey := secp256k1.GenPrivKey()
granteeAddr := sdk.AccAddress(granteePrivKey.PubKey().Address().Bytes())
otherPrivKey := secp256k1.GenPrivKey()
otherAddr := sdk.AccAddress(otherPrivKey.PubKey().Address().Bytes())

chain.Fund(granteeAddr, sdkmath.NewInt(1_000_000))
chain.Fund(otherAddr, sdkmath.NewInt(1_000_000))
assert.Equal(t, sdkmath.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount)

codeHash := []byte("*")
instantiatePermission := types.AllowEverybody
senderKey := granteePrivKey

// setup grant
grant, err := types.NewCodeGrant(codeHash, &instantiatePermission)
require.NoError(t, err)
authorization := types.NewStoreCodeAuthorization(*grant)
expiry := time.Now().Add(time.Hour)
grantMsg, err := authz.NewMsgGrant(granterAddr, granteeAddr, authorization, &expiry)
require.NoError(t, err)
_, err = chain.SendMsgs(grantMsg)
require.NoError(t, err)

// when
execMsg := authz.NewMsgExec(senderKey.PubKey().Address().Bytes(), []sdk.Msg{&types.MsgStoreCode{
Sender: granterAddr.String(),
WASMByteCode: brokenGzipWasmCode,
InstantiatePermission: &types.AllowEverybody,
}})
_, gotErr := chain.SendNonDefaultSenderMsgs(senderKey, &execMsg)

// then
require.Error(t, gotErr)
}
5 changes: 4 additions & 1 deletion x/wasm/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,10 @@ func GetCmdGetContractStateAll() *cobra.Command {
SilenceUsage: true,
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "contract state")
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")

return cmd
}

Expand Down
81 changes: 81 additions & 0 deletions x/wasm/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"os"
"strconv"
"strings"
"time"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -68,6 +69,7 @@ func GetTxCmd() *cobra.Command {
UpdateContractAdminCmd(),
ClearContractAdminCmd(),
GrantAuthorizationCmd(),
GrantStoreCodeAuthorizationCmd(),
UpdateInstantiateConfigCmd(),
SubmitProposalCmd(),
)
Expand Down Expand Up @@ -545,6 +547,56 @@ $ %s tx grant <grantee_addr> execution <contract_addr> --allow-all-messages --ma
return cmd
}

func GrantStoreCodeAuthorizationCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "grant [grantee] store-code [code_hash:permission]",
Short: "Grant authorization to an address",
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 <grantee_addr> store-code *:%s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm,%s1vx8knpllrj7n963p9ttd80w47kpacrhuts497x
`, version.AppName, version.AppName, version.AppName, version.AppName),
Args: cobra.MinimumNArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

grantee, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
}

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

grants, err := parseStoreCodeGrants(args[2:])
if err != nil {
return err
}

authorization := types.NewStoreCodeAuthorization(grants...)

expire, err := getExpireTime(cmd)
if err != nil {
return err
}

grantMsg, err := authz.NewMsgGrant(clientCtx.GetFromAddress(), grantee, authorization, expire)
if err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), grantMsg)
},
}
flags.AddTxFlagsToCmd(cmd)
cmd.Flags().Int64(flagExpiration, 0, "The Unix timestamp.")
return cmd
}

func getExpireTime(cmd *cobra.Command) (*time.Time, error) {
exp, err := cmd.Flags().GetInt64(flagExpiration)
if err != nil {
Expand All @@ -556,3 +608,32 @@ func getExpireTime(cmd *cobra.Command) (*time.Time, error) {
e := time.Unix(exp, 0)
return &e, nil
}

func parseStoreCodeGrants(args []string) ([]types.CodeGrant, error) {
grants := make([]types.CodeGrant, len(args))
for i, c := range args {
// format: code_hash:access_config
// access_config: nobody|everybody|address(es)
parts := strings.Split(c, ":")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid format")
}

if parts[1] == "*" {
grants[i] = types.CodeGrant{
CodeHash: []byte(parts[0]),
}
continue
}

accessConfig, err := parseAccessConfig(parts[1])
if err != nil {
return nil, err
}
grants[i] = types.CodeGrant{
CodeHash: []byte(parts[0]),
InstantiatePermission: &accessConfig,
}
}
return grants, nil
}
Loading

0 comments on commit dbc9460

Please sign in to comment.