diff --git a/app/ante.go b/app/ante.go
index 844d2bdc0d..79a73822fa 100644
--- a/app/ante.go
+++ b/app/ante.go
@@ -21,6 +21,7 @@ type HandlerOptions struct {
ante.HandlerOptions
IBCKeeper *keeper.Keeper
+ WasmKeeper *wasmkeeper.Keeper
WasmConfig *wasmTypes.WasmConfig
TXCounterStoreKey storetypes.StoreKey
}
@@ -46,6 +47,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.TXCounterStoreKey),
+ wasmkeeper.NewGasRegisterDecorator(options.WasmKeeper.GetGasRegister()),
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
ante.NewValidateBasicDecorator(),
ante.NewTxTimeoutHeightDecorator(),
diff --git a/app/app.go b/app/app.go
index 4e8b8c7c70..aa1e321f15 100644
--- a/app/app.go
+++ b/app/app.go
@@ -833,6 +833,7 @@ func (app *WasmApp) setAnteHandler(txConfig client.TxConfig, wasmConfig wasmtype
IBCKeeper: app.IBCKeeper,
WasmConfig: &wasmConfig,
TXCounterStoreKey: txCounterStoreKey,
+ WasmKeeper: &app.WasmKeeper,
},
)
if err != nil {
diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md
index a6ded4f9c5..dd995a0c18 100644
--- a/docs/proto/proto-docs.md
+++ b/docs/proto/proto-docs.md
@@ -4,17 +4,6 @@
## Table of Contents
-- [cosmwasm/wasm/v1/authz.proto](#cosmwasm/wasm/v1/authz.proto)
- - [AcceptedMessageKeysFilter](#cosmwasm.wasm.v1.AcceptedMessageKeysFilter)
- - [AcceptedMessagesFilter](#cosmwasm.wasm.v1.AcceptedMessagesFilter)
- - [AllowAllMessagesFilter](#cosmwasm.wasm.v1.AllowAllMessagesFilter)
- - [CombinedLimit](#cosmwasm.wasm.v1.CombinedLimit)
- - [ContractExecutionAuthorization](#cosmwasm.wasm.v1.ContractExecutionAuthorization)
- - [ContractGrant](#cosmwasm.wasm.v1.ContractGrant)
- - [ContractMigrationAuthorization](#cosmwasm.wasm.v1.ContractMigrationAuthorization)
- - [MaxCallsLimit](#cosmwasm.wasm.v1.MaxCallsLimit)
- - [MaxFundsLimit](#cosmwasm.wasm.v1.MaxFundsLimit)
-
- [cosmwasm/wasm/v1/types.proto](#cosmwasm/wasm/v1/types.proto)
- [AbsoluteTxPosition](#cosmwasm.wasm.v1.AbsoluteTxPosition)
- [AccessConfig](#cosmwasm.wasm.v1.AccessConfig)
@@ -28,6 +17,19 @@
- [AccessType](#cosmwasm.wasm.v1.AccessType)
- [ContractCodeHistoryOperationType](#cosmwasm.wasm.v1.ContractCodeHistoryOperationType)
+- [cosmwasm/wasm/v1/authz.proto](#cosmwasm/wasm/v1/authz.proto)
+ - [AcceptedMessageKeysFilter](#cosmwasm.wasm.v1.AcceptedMessageKeysFilter)
+ - [AcceptedMessagesFilter](#cosmwasm.wasm.v1.AcceptedMessagesFilter)
+ - [AllowAllMessagesFilter](#cosmwasm.wasm.v1.AllowAllMessagesFilter)
+ - [CodeGrant](#cosmwasm.wasm.v1.CodeGrant)
+ - [CombinedLimit](#cosmwasm.wasm.v1.CombinedLimit)
+ - [ContractExecutionAuthorization](#cosmwasm.wasm.v1.ContractExecutionAuthorization)
+ - [ContractGrant](#cosmwasm.wasm.v1.ContractGrant)
+ - [ContractMigrationAuthorization](#cosmwasm.wasm.v1.ContractMigrationAuthorization)
+ - [MaxCallsLimit](#cosmwasm.wasm.v1.MaxCallsLimit)
+ - [MaxFundsLimit](#cosmwasm.wasm.v1.MaxFundsLimit)
+ - [StoreCodeAuthorization](#cosmwasm.wasm.v1.StoreCodeAuthorization)
+
- [cosmwasm/wasm/v1/genesis.proto](#cosmwasm/wasm/v1/genesis.proto)
- [Code](#cosmwasm.wasm.v1.Code)
- [Contract](#cosmwasm.wasm.v1.Contract)
@@ -121,159 +123,177 @@
-
+
Top
-## cosmwasm/wasm/v1/authz.proto
+## cosmwasm/wasm/v1/types.proto
-
+
-### AcceptedMessageKeysFilter
-AcceptedMessageKeysFilter accept only the specific contract message keys in
-the json object to be executed.
-Since: wasmd 0.30
+### AbsoluteTxPosition
+AbsoluteTxPosition is a unique transaction position that allows for global
+ordering of transactions.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `keys` | [string](#string) | repeated | Messages is the list of unique keys |
+| `block_height` | [uint64](#uint64) | | BlockHeight is the block the contract was created at |
+| `tx_index` | [uint64](#uint64) | | TxIndex is a monotonic counter within the block (actual transaction index, or gas consumed) |
-
+
-### AcceptedMessagesFilter
-AcceptedMessagesFilter accept only the specific raw contract messages to be
-executed.
-Since: wasmd 0.30
+### AccessConfig
+AccessConfig access control type.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `messages` | [bytes](#bytes) | repeated | Messages is the list of raw contract messages |
+| `permission` | [AccessType](#cosmwasm.wasm.v1.AccessType) | | |
+| `addresses` | [string](#string) | repeated | |
-
+
-### AllowAllMessagesFilter
-AllowAllMessagesFilter is a wildcard to allow any type of contract payload
-message.
-Since: wasmd 0.30
+### AccessTypeParam
+AccessTypeParam
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `value` | [AccessType](#cosmwasm.wasm.v1.AccessType) | | |
-
-### CombinedLimit
-CombinedLimit defines the maximal amounts that can be sent to a contract and
-the maximal number of calls executable. Both need to remain >0 to be valid.
-Since: wasmd 0.30
+
+
+
+### CodeInfo
+CodeInfo is data for the uploaded contract WASM code
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `calls_remaining` | [uint64](#uint64) | | Remaining number that is decremented on each execution |
-| `amounts` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Amounts is the maximal amount of tokens transferable to the contract. |
+| `code_hash` | [bytes](#bytes) | | CodeHash is the unique identifier created by wasmvm |
+| `creator` | [string](#string) | | Creator address who initially stored the code |
+| `instantiate_config` | [AccessConfig](#cosmwasm.wasm.v1.AccessConfig) | | InstantiateConfig access control to apply on contract creation, optional |
-
+
-### ContractExecutionAuthorization
-ContractExecutionAuthorization defines authorization for wasm execute.
-Since: wasmd 0.30
+### ContractCodeHistoryEntry
+ContractCodeHistoryEntry metadata to a contract.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `grants` | [ContractGrant](#cosmwasm.wasm.v1.ContractGrant) | repeated | Grants for contract executions |
+| `operation` | [ContractCodeHistoryOperationType](#cosmwasm.wasm.v1.ContractCodeHistoryOperationType) | | |
+| `code_id` | [uint64](#uint64) | | CodeID is the reference to the stored WASM code |
+| `updated` | [AbsoluteTxPosition](#cosmwasm.wasm.v1.AbsoluteTxPosition) | | Updated Tx position when the operation was executed. |
+| `msg` | [bytes](#bytes) | | |
-
+
-### ContractGrant
-ContractGrant a granted permission for a single contract
-Since: wasmd 0.30
+### ContractInfo
+ContractInfo stores a WASM contract instance
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `contract` | [string](#string) | | Contract is the bech32 address of the smart contract |
-| `limit` | [google.protobuf.Any](#google.protobuf.Any) | | Limit defines execution limits that are enforced and updated when the grant is applied. When the limit lapsed the grant is removed. |
-| `filter` | [google.protobuf.Any](#google.protobuf.Any) | | Filter define more fine-grained control on the message payload passed to the contract in the operation. When no filter applies on execution, the operation is prohibited. |
+| `code_id` | [uint64](#uint64) | | CodeID is the reference to the stored Wasm code |
+| `creator` | [string](#string) | | Creator address who initially instantiated the contract |
+| `admin` | [string](#string) | | Admin is an optional address that can execute migrations |
+| `label` | [string](#string) | | Label is optional metadata to be stored with a contract instance. |
+| `created` | [AbsoluteTxPosition](#cosmwasm.wasm.v1.AbsoluteTxPosition) | | Created Tx position when the contract was instantiated. |
+| `ibc_port_id` | [string](#string) | | |
+| `extension` | [google.protobuf.Any](#google.protobuf.Any) | | Extension is an extension point to store custom metadata within the persistence model. |
-
+
-### ContractMigrationAuthorization
-ContractMigrationAuthorization defines authorization for wasm contract
-migration. Since: wasmd 0.30
+### Model
+Model is a struct that holds a KV pair
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `grants` | [ContractGrant](#cosmwasm.wasm.v1.ContractGrant) | repeated | Grants for contract migrations |
+| `key` | [bytes](#bytes) | | hex-encode key to read it better (this is often ascii) |
+| `value` | [bytes](#bytes) | | base64-encode raw value |
-
+
-### MaxCallsLimit
-MaxCallsLimit limited number of calls to the contract. No funds transferable.
-Since: wasmd 0.30
+### Params
+Params defines the set of wasm parameters.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `remaining` | [uint64](#uint64) | | Remaining number that is decremented on each execution |
+| `code_upload_access` | [AccessConfig](#cosmwasm.wasm.v1.AccessConfig) | | |
+| `instantiate_default_permission` | [AccessType](#cosmwasm.wasm.v1.AccessType) | | |
+
-
-### MaxFundsLimit
-MaxFundsLimit defines the maximal amounts that can be sent to the contract.
-Since: wasmd 0.30
+
+### AccessType
+AccessType permission types
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| `amounts` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Amounts is the maximal amount of tokens transferable to the contract. |
+| Name | Number | Description |
+| ---- | ------ | ----------- |
+| ACCESS_TYPE_UNSPECIFIED | 0 | AccessTypeUnspecified placeholder for empty value |
+| ACCESS_TYPE_NOBODY | 1 | AccessTypeNobody forbidden |
+| ACCESS_TYPE_EVERYBODY | 3 | AccessTypeEverybody unrestricted |
+| ACCESS_TYPE_ANY_OF_ADDRESSES | 4 | AccessTypeAnyOfAddresses allow any of the addresses |
+
+### ContractCodeHistoryOperationType
+ContractCodeHistoryOperationType actions that caused a code change
+
+| Name | Number | Description |
+| ---- | ------ | ----------- |
+| CONTRACT_CODE_HISTORY_OPERATION_TYPE_UNSPECIFIED | 0 | ContractCodeHistoryOperationTypeUnspecified placeholder for empty value |
+| CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT | 1 | ContractCodeHistoryOperationTypeInit on chain contract instantiation |
+| CONTRACT_CODE_HISTORY_OPERATION_TYPE_MIGRATE | 2 | ContractCodeHistoryOperationTypeMigrate code migration |
+| CONTRACT_CODE_HISTORY_OPERATION_TYPE_GENESIS | 3 | ContractCodeHistoryOperationTypeGenesis based on genesis data |
-
@@ -283,177 +303,191 @@ Since: wasmd 0.30
-
+
Top
-## cosmwasm/wasm/v1/types.proto
+## cosmwasm/wasm/v1/authz.proto
-
+
-### AbsoluteTxPosition
-AbsoluteTxPosition is a unique transaction position that allows for global
-ordering of transactions.
+### AcceptedMessageKeysFilter
+AcceptedMessageKeysFilter accept only the specific contract message keys in
+the json object to be executed.
+Since: wasmd 0.30
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `block_height` | [uint64](#uint64) | | BlockHeight is the block the contract was created at |
-| `tx_index` | [uint64](#uint64) | | TxIndex is a monotonic counter within the block (actual transaction index, or gas consumed) |
+| `keys` | [string](#string) | repeated | Messages is the list of unique keys |
-
+
-### AccessConfig
-AccessConfig access control type.
+### AcceptedMessagesFilter
+AcceptedMessagesFilter accept only the specific raw contract messages to be
+executed.
+Since: wasmd 0.30
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `permission` | [AccessType](#cosmwasm.wasm.v1.AccessType) | | |
-| `addresses` | [string](#string) | repeated | |
+| `messages` | [bytes](#bytes) | repeated | Messages is the list of raw contract messages |
-
+
-### AccessTypeParam
-AccessTypeParam
+### AllowAllMessagesFilter
+AllowAllMessagesFilter is a wildcard to allow any type of contract payload
+message.
+Since: wasmd 0.30
+
+
+
+
+
+
+
+
+### CodeGrant
+CodeGrant a granted permission for a single code
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `value` | [AccessType](#cosmwasm.wasm.v1.AccessType) | | |
+| `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 |
-
+
-### CodeInfo
-CodeInfo is data for the uploaded contract WASM code
+### CombinedLimit
+CombinedLimit defines the maximal amounts that can be sent to a contract and
+the maximal number of calls executable. Both need to remain >0 to be valid.
+Since: wasmd 0.30
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `code_hash` | [bytes](#bytes) | | CodeHash is the unique identifier created by wasmvm |
-| `creator` | [string](#string) | | Creator address who initially stored the code |
-| `instantiate_config` | [AccessConfig](#cosmwasm.wasm.v1.AccessConfig) | | InstantiateConfig access control to apply on contract creation, optional |
+| `calls_remaining` | [uint64](#uint64) | | Remaining number that is decremented on each execution |
+| `amounts` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Amounts is the maximal amount of tokens transferable to the contract. |
-
+
-### ContractCodeHistoryEntry
-ContractCodeHistoryEntry metadata to a contract.
+### ContractExecutionAuthorization
+ContractExecutionAuthorization defines authorization for wasm execute.
+Since: wasmd 0.30
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `operation` | [ContractCodeHistoryOperationType](#cosmwasm.wasm.v1.ContractCodeHistoryOperationType) | | |
-| `code_id` | [uint64](#uint64) | | CodeID is the reference to the stored WASM code |
-| `updated` | [AbsoluteTxPosition](#cosmwasm.wasm.v1.AbsoluteTxPosition) | | Updated Tx position when the operation was executed. |
-| `msg` | [bytes](#bytes) | | |
+| `grants` | [ContractGrant](#cosmwasm.wasm.v1.ContractGrant) | repeated | Grants for contract executions |
-
+
-### ContractInfo
-ContractInfo stores a WASM contract instance
+### ContractGrant
+ContractGrant a granted permission for a single contract
+Since: wasmd 0.30
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `code_id` | [uint64](#uint64) | | CodeID is the reference to the stored Wasm code |
-| `creator` | [string](#string) | | Creator address who initially instantiated the contract |
-| `admin` | [string](#string) | | Admin is an optional address that can execute migrations |
-| `label` | [string](#string) | | Label is optional metadata to be stored with a contract instance. |
-| `created` | [AbsoluteTxPosition](#cosmwasm.wasm.v1.AbsoluteTxPosition) | | Created Tx position when the contract was instantiated. |
-| `ibc_port_id` | [string](#string) | | |
-| `extension` | [google.protobuf.Any](#google.protobuf.Any) | | Extension is an extension point to store custom metadata within the persistence model. |
+| `contract` | [string](#string) | | Contract is the bech32 address of the smart contract |
+| `limit` | [google.protobuf.Any](#google.protobuf.Any) | | Limit defines execution limits that are enforced and updated when the grant is applied. When the limit lapsed the grant is removed. |
+| `filter` | [google.protobuf.Any](#google.protobuf.Any) | | Filter define more fine-grained control on the message payload passed to the contract in the operation. When no filter applies on execution, the operation is prohibited. |
-
+
-### Model
-Model is a struct that holds a KV pair
+### ContractMigrationAuthorization
+ContractMigrationAuthorization defines authorization for wasm contract
+migration. Since: wasmd 0.30
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `key` | [bytes](#bytes) | | hex-encode key to read it better (this is often ascii) |
-| `value` | [bytes](#bytes) | | base64-encode raw value |
+| `grants` | [ContractGrant](#cosmwasm.wasm.v1.ContractGrant) | repeated | Grants for contract migrations |
-
+
-### Params
-Params defines the set of wasm parameters.
+### MaxCallsLimit
+MaxCallsLimit limited number of calls to the contract. No funds transferable.
+Since: wasmd 0.30
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `code_upload_access` | [AccessConfig](#cosmwasm.wasm.v1.AccessConfig) | | |
-| `instantiate_default_permission` | [AccessType](#cosmwasm.wasm.v1.AccessType) | | |
+| `remaining` | [uint64](#uint64) | | Remaining number that is decremented on each execution |
-
+
-
+### MaxFundsLimit
+MaxFundsLimit defines the maximal amounts that can be sent to the contract.
+Since: wasmd 0.30
-### AccessType
-AccessType permission types
-| Name | Number | Description |
-| ---- | ------ | ----------- |
-| ACCESS_TYPE_UNSPECIFIED | 0 | AccessTypeUnspecified placeholder for empty value |
-| ACCESS_TYPE_NOBODY | 1 | AccessTypeNobody forbidden |
-| ACCESS_TYPE_EVERYBODY | 3 | AccessTypeEverybody unrestricted |
-| ACCESS_TYPE_ANY_OF_ADDRESSES | 4 | AccessTypeAnyOfAddresses allow any of the addresses |
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `amounts` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Amounts is the maximal amount of tokens transferable to the contract. |
-
-### ContractCodeHistoryOperationType
-ContractCodeHistoryOperationType actions that caused a code change
-| Name | Number | Description |
-| ---- | ------ | ----------- |
-| CONTRACT_CODE_HISTORY_OPERATION_TYPE_UNSPECIFIED | 0 | ContractCodeHistoryOperationTypeUnspecified placeholder for empty value |
-| CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT | 1 | ContractCodeHistoryOperationTypeInit on chain contract instantiation |
-| CONTRACT_CODE_HISTORY_OPERATION_TYPE_MIGRATE | 2 | ContractCodeHistoryOperationTypeMigrate code migration |
-| CONTRACT_CODE_HISTORY_OPERATION_TYPE_GENESIS | 3 | ContractCodeHistoryOperationTypeGenesis based on genesis data |
+
+
+### StoreCodeAuthorization
+StoreCodeAuthorization defines authorization for wasm code upload.
+Since: wasmd 0.42
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `grants` | [CodeGrant](#cosmwasm.wasm.v1.CodeGrant) | repeated | Grants for code upload |
+
+
+
+
+
+
diff --git a/proto/cosmwasm/wasm/v1/authz.proto b/proto/cosmwasm/wasm/v1/authz.proto
index cca4f033d7..713369fb5c 100644
--- a/proto/cosmwasm/wasm/v1/authz.proto
+++ b/proto/cosmwasm/wasm/v1/authz.proto
@@ -4,12 +4,25 @@ package cosmwasm.wasm.v1;
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/base/v1beta1/coin.proto";
+import "cosmwasm/wasm/v1/types.proto";
import "google/protobuf/any.proto";
import "amino/amino.proto";
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) =
+ "cosmos.authz.v1beta1.Authorization";
+
+ // Grants for code upload
+ repeated CodeGrant grants = 1
+ [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
+}
+
// ContractExecutionAuthorization defines authorization for wasm execute.
// Since: wasmd 0.30
message ContractExecutionAuthorization {
@@ -34,6 +47,18 @@ message ContractMigrationAuthorization {
[ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
}
+// 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 is the superset access control to apply
+ // on contract creation.
+ // Optional
+ AccessConfig instantiate_permission = 2;
+}
+
// ContractGrant a granted permission for a single contract
// Since: wasmd 0.30
message ContractGrant {
diff --git a/tests/e2e/grants_test.go b/tests/e2e/grants_test.go
index 45a4b32b46..f7102d4133 100644
--- a/tests/e2e/grants_test.go
+++ b/tests/e2e/grants_test.go
@@ -2,9 +2,11 @@ package e2e_test
import (
"fmt"
+ "os"
"testing"
"time"
+ wasmvm "github.com/CosmWasm/wasmvm"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -119,3 +121,219 @@ func TestGrants(t *testing.T) {
})
}
}
+
+func TestStoreCodeGrant(t *testing.T) {
+ reflectWasmCode, err := os.ReadFile("../../x/wasm/keeper/testdata/reflect_1_1.wasm")
+ require.NoError(t, err)
+
+ reflectCodeChecksum, err := wasmvm.CreateChecksum(reflectWasmCode)
+ 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, sdk.NewInt(1_000_000))
+ chain.Fund(otherAddr, sdk.NewInt(1_000_000))
+ assert.Equal(t, sdk.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: reflectCodeChecksum,
+ 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)
+ 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: reflectWasmCode,
+ InstantiatePermission: &types.AllowEverybody,
+ }})
+ _, gotErr := chain.SendNonDefaultSenderMsgs(spec.senderKey, &execMsg)
+
+ // then
+ if spec.expErr != nil {
+ require.True(t, spec.expErr.Is(gotErr))
+ 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, sdk.NewInt(1_000_000))
+ chain.Fund(otherAddr, sdk.NewInt(1_000_000))
+ assert.Equal(t, sdk.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)
+ 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 {
+ require.True(t, spec.expErr.Is(gotErr))
+ return
+ }
+ require.NoError(t, gotErr)
+ })
+ }
+}
+
+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, sdk.NewInt(1_000_000))
+ chain.Fund(otherAddr, sdk.NewInt(1_000_000))
+ assert.Equal(t, sdk.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)
+}
diff --git a/x/wasm/client/cli/tx.go b/x/wasm/client/cli/tx.go
index 5e66492a91..2fa1b94165 100644
--- a/x/wasm/client/cli/tx.go
+++ b/x/wasm/client/cli/tx.go
@@ -6,6 +6,7 @@ import (
"fmt"
"os"
"strconv"
+ "strings"
"time"
"github.com/spf13/cobra"
@@ -67,6 +68,7 @@ func GetTxCmd() *cobra.Command {
UpdateContractAdminCmd(),
ClearContractAdminCmd(),
GrantAuthorizationCmd(),
+ GrantStoreCodeAuthorizationCmd(),
UpdateInstantiateConfigCmd(),
SubmitProposalCmd(),
)
@@ -556,6 +558,56 @@ $ %s tx grant execution --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 store-code 13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5:everybody 1wqrtry681b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5:nobody --expiration 1667979596
+
+$ %s tx grant 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 {
@@ -567,3 +619,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
+}
diff --git a/x/wasm/client/cli/tx_test.go b/x/wasm/client/cli/tx_test.go
index 75b6a4eadd..72e3967ab6 100644
--- a/x/wasm/client/cli/tx_test.go
+++ b/x/wasm/client/cli/tx_test.go
@@ -124,3 +124,106 @@ func TestParseAccessConfigFlags(t *testing.T) {
})
}
}
+
+func TestParseStoreCodeGrants(t *testing.T) {
+ specs := map[string]struct {
+ src []string
+ exp []types.CodeGrant
+ expErr bool
+ }{
+ "wildcard : nobody": {
+ src: []string{"*:nobody"},
+ exp: []types.CodeGrant{{
+ CodeHash: []byte("*"),
+ InstantiatePermission: &types.AccessConfig{Permission: types.AccessTypeNobody},
+ }},
+ },
+ "wildcard : wildcard": {
+ src: []string{"*:*"},
+ exp: []types.CodeGrant{{
+ CodeHash: []byte("*"),
+ }},
+ },
+ "wildcard : everybody": {
+ src: []string{"*:everybody"},
+ exp: []types.CodeGrant{{
+ CodeHash: []byte("*"),
+ InstantiatePermission: &types.AccessConfig{Permission: types.AccessTypeEverybody},
+ }},
+ },
+ "wildcard : any of addresses - single": {
+ src: []string{"*:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
+ exp: []types.CodeGrant{
+ {
+ CodeHash: []byte("*"),
+ InstantiatePermission: &types.AccessConfig{
+ Permission: types.AccessTypeAnyOfAddresses,
+ Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
+ },
+ },
+ },
+ },
+ "wildcard : any of addresses - multiple": {
+ src: []string{"*:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
+ exp: []types.CodeGrant{
+ {
+ CodeHash: []byte("*"),
+ InstantiatePermission: &types.AccessConfig{
+ Permission: types.AccessTypeAnyOfAddresses,
+ Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
+ },
+ },
+ },
+ },
+ "multiple code hashes with different permissions": {
+ src: []string{"any_checksum_1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", "any_checksum_2:nobody"},
+ exp: []types.CodeGrant{
+ {
+ CodeHash: []byte("any_checksum_1"),
+ InstantiatePermission: &types.AccessConfig{
+ Permission: types.AccessTypeAnyOfAddresses,
+ Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
+ },
+ }, {
+ CodeHash: []byte("any_checksum_2"),
+ InstantiatePermission: &types.AccessConfig{
+ Permission: types.AccessTypeNobody,
+ },
+ },
+ },
+ },
+ "code hash : wildcard": {
+ src: []string{"any_checksum_1:*"},
+ exp: []types.CodeGrant{{
+ CodeHash: []byte("any_checksum_1"),
+ }},
+ },
+ "code hash : any of addresses - empty list": {
+ src: []string{"any_checksum_1:"},
+ expErr: true,
+ },
+ "code hash : any of addresses - invalid address": {
+ src: []string{"any_checksum_1:foo"},
+ expErr: true,
+ },
+ "code hash : any of addresses - duplicate address": {
+ src: []string{"any_checksum_1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
+ expErr: true,
+ },
+ "empty code hash": {
+ src: []string{":everyone"},
+ expErr: true,
+ },
+ }
+ for name, spec := range specs {
+ t.Run(name, func(t *testing.T) {
+ got, gotErr := parseStoreCodeGrants(spec.src)
+ if spec.expErr {
+ require.Error(t, gotErr)
+ return
+ }
+ require.NoError(t, gotErr)
+ assert.Equal(t, spec.exp, got)
+ })
+ }
+}
diff --git a/x/wasm/ioutils/ioutil.go b/x/wasm/ioutils/ioutil.go
index 4478b03a37..7a037503e9 100644
--- a/x/wasm/ioutils/ioutil.go
+++ b/x/wasm/ioutils/ioutil.go
@@ -3,17 +3,18 @@ package ioutils
import (
"bytes"
"compress/gzip"
+ "errors"
"io"
errorsmod "cosmossdk.io/errors"
-
- "github.com/CosmWasm/wasmd/x/wasm/types"
)
+var errLimit = errors.New("exceeds limit")
+
// Uncompress expects a valid gzip source to unpack or fails. See IsGzip
func Uncompress(gzipSrc []byte, limit int64) ([]byte, error) {
if int64(len(gzipSrc)) > limit {
- return nil, types.ErrLimit.Wrapf("max %d bytes", limit)
+ return nil, errorsmod.Wrapf(errLimit, "max %d bytes", limit)
}
zr, err := gzip.NewReader(bytes.NewReader(gzipSrc))
if err != nil {
@@ -22,14 +23,14 @@ func Uncompress(gzipSrc []byte, limit int64) ([]byte, error) {
zr.Multistream(false)
defer zr.Close()
bz, err := io.ReadAll(LimitReader(zr, limit))
- if types.ErrLimit.Is(err) {
- return nil, errorsmod.Wrapf(err, "max %d bytes", limit)
+ if errors.Is(err, errLimit) {
+ return nil, errorsmod.Wrapf(errLimit, "max %d bytes", limit)
}
return bz, err
}
// LimitReader returns a Reader that reads from r
-// but stops with types.ErrLimit after n bytes.
+// but stops with "limit error" after n bytes.
// The underlying implementation is a *io.LimitedReader.
func LimitReader(r io.Reader, n int64) io.Reader {
return &LimitedReader{r: &io.LimitedReader{R: r, N: n}}
@@ -41,7 +42,7 @@ type LimitedReader struct {
func (l *LimitedReader) Read(p []byte) (n int, err error) {
if l.r.N <= 0 {
- return 0, types.ErrLimit
+ return 0, errLimit
}
return l.r.Read(p)
}
diff --git a/x/wasm/ioutils/ioutil_test.go b/x/wasm/ioutils/ioutil_test.go
index 0490aa0743..9a2e026dfe 100644
--- a/x/wasm/ioutils/ioutil_test.go
+++ b/x/wasm/ioutils/ioutil_test.go
@@ -11,8 +11,6 @@ import (
"github.com/cometbft/cometbft/libs/rand"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
-
- "github.com/CosmWasm/wasmd/x/wasm/types"
)
func TestUncompress(t *testing.T) {
@@ -51,17 +49,17 @@ func TestUncompress(t *testing.T) {
},
"handle big gzip output": {
src: asGzip(bytes.Repeat([]byte{0x1}, maxSize+1)),
- expError: types.ErrLimit,
+ expError: errLimit,
},
"handle big gzip archive": {
src: asGzip(rand.Bytes(2 * maxSize)),
- expError: types.ErrLimit,
+ expError: errLimit,
},
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
r, err := Uncompress(spec.src, maxSize)
- require.True(t, errors.Is(spec.expError, err), "exp %v got %+v", spec.expError, err)
+ require.True(t, errors.Is(err, spec.expError), "exp %v got %+v", spec.expError, err)
if spec.expError != nil {
return
}
diff --git a/x/wasm/keeper/ante.go b/x/wasm/keeper/ante.go
index 08dfdf64b4..1718c1ce11 100644
--- a/x/wasm/keeper/ante.go
+++ b/x/wasm/keeper/ante.go
@@ -95,3 +95,18 @@ func (d LimitSimulationGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu
}
return next(ctx, tx, simulate)
}
+
+// GasRegisterDecorator ante decorator to store gas register in the context
+type GasRegisterDecorator struct {
+ gasRegister types.GasRegister
+}
+
+// NewGasRegisterDecorator constructor.
+func NewGasRegisterDecorator(gr types.GasRegister) *GasRegisterDecorator {
+ return &GasRegisterDecorator{gasRegister: gr}
+}
+
+// AnteHandle adds the gas register to the context.
+func (g GasRegisterDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
+ return next(types.WithGasRegister(ctx, g.gasRegister), tx, simulate)
+}
diff --git a/x/wasm/keeper/ante_test.go b/x/wasm/keeper/ante_test.go
index df586426af..c1e59c4aa2 100644
--- a/x/wasm/keeper/ante_test.go
+++ b/x/wasm/keeper/ante_test.go
@@ -15,6 +15,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/CosmWasm/wasmd/x/wasm/keeper"
+ "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting"
"github.com/CosmWasm/wasmd/x/wasm/types"
)
@@ -30,7 +31,6 @@ func TestCountTxDecorator(t *testing.T) {
setupDB func(t *testing.T, ctx sdk.Context)
simulate bool
nextAssertAnte func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error)
- expErr bool
}{
"no initial counter set": {
setupDB: func(t *testing.T, ctx sdk.Context) {
@@ -107,10 +107,6 @@ func TestCountTxDecorator(t *testing.T) {
// when
ante := keeper.NewCountTXDecorator(keyWasm)
_, gotErr := ante.AnteHandle(ctx, anyTx, spec.simulate, spec.nextAssertAnte)
- if spec.expErr {
- require.Error(t, gotErr)
- return
- }
require.NoError(t, gotErr)
})
}
@@ -193,3 +189,48 @@ func consumeGasAnteHandler(gasToConsume sdk.Gas) sdk.AnteHandler {
return ctx, nil
}
}
+
+func TestGasRegisterDecorator(t *testing.T) {
+ db := dbm.NewMemDB()
+ ms := store.NewCommitMultiStore(db)
+
+ specs := map[string]struct {
+ simulate bool
+ nextAssertAnte func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error)
+ }{
+ "simulation": {
+ simulate: true,
+ nextAssertAnte: func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
+ _, ok := types.GasRegisterFromContext(ctx)
+ assert.True(t, ok)
+ require.True(t, simulate)
+ return ctx, nil
+ },
+ },
+ "not simulation": {
+ simulate: false,
+ nextAssertAnte: func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
+ _, ok := types.GasRegisterFromContext(ctx)
+ assert.True(t, ok)
+ require.False(t, simulate)
+ return ctx, nil
+ },
+ },
+ }
+ for name, spec := range specs {
+ t.Run(name, func(t *testing.T) {
+ ctx := sdk.NewContext(ms, tmproto.Header{
+ Height: 100,
+ Time: time.Now(),
+ }, false, log.NewNopLogger())
+ var anyTx sdk.Tx
+
+ // when
+ ante := keeper.NewGasRegisterDecorator(&wasmtesting.MockGasRegister{})
+ _, gotErr := ante.AnteHandle(ctx, anyTx, spec.simulate, spec.nextAssertAnte)
+
+ // then
+ require.NoError(t, gotErr)
+ })
+ }
+}
diff --git a/x/wasm/keeper/api.go b/x/wasm/keeper/api.go
index c9fc65ae39..0a6f37c123 100644
--- a/x/wasm/keeper/api.go
+++ b/x/wasm/keeper/api.go
@@ -5,6 +5,8 @@ import (
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
+
+ "github.com/CosmWasm/wasmd/x/wasm/types"
)
const (
@@ -18,10 +20,10 @@ const (
)
var (
- costHumanize = DefaultGasCostHumanAddress * DefaultGasMultiplier
- costCanonical = DefaultGasCostCanonicalAddress * DefaultGasMultiplier
+ costHumanize = DefaultGasCostHumanAddress * types.DefaultGasMultiplier
+ costCanonical = DefaultGasCostCanonicalAddress * types.DefaultGasMultiplier
costJSONDeserialization = wasmvmtypes.UFraction{
- Numerator: DefaultDeserializationCostPerByte * DefaultGasMultiplier,
+ Numerator: DefaultDeserializationCostPerByte * types.DefaultGasMultiplier,
Denominator: 1,
}
)
diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go
index f32f7cdef3..6862773b73 100644
--- a/x/wasm/keeper/keeper.go
+++ b/x/wasm/keeper/keeper.go
@@ -91,7 +91,7 @@ type Keeper struct {
messenger Messenger
// queryGasLimit is the max wasmvm gas that can be spent on executing a query with a contract
queryGasLimit uint64
- gasRegister GasRegister
+ gasRegister types.GasRegister
maxQueryStackSize uint32
acceptedAccountTypes map[reflect.Type]struct{}
accountPruner AccountPruner
@@ -145,6 +145,11 @@ func (k Keeper) GetAuthority() string {
return k.authority
}
+// GetGasRegister returns the x/wasm module's gas register.
+func (k Keeper) GetGasRegister() types.GasRegister {
+ return k.gasRegister
+}
+
func (k Keeper) create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, instantiateAccess *types.AccessConfig, authZ types.AuthorizationPolicy) (codeID uint64, checksum []byte, err error) {
if creator == nil {
return 0, checksum, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "cannot be nil")
@@ -1090,10 +1095,10 @@ func (k Keeper) newQueryHandler(ctx sdk.Context, contractAddress sdk.AccAddress)
// MultipliedGasMeter wraps the GasMeter from context and multiplies all reads by out defined multiplier
type MultipliedGasMeter struct {
originalMeter sdk.GasMeter
- GasRegister GasRegister
+ GasRegister types.GasRegister
}
-func NewMultipliedGasMeter(originalMeter sdk.GasMeter, gr GasRegister) MultipliedGasMeter {
+func NewMultipliedGasMeter(originalMeter sdk.GasMeter, gr types.GasRegister) MultipliedGasMeter {
return MultipliedGasMeter{originalMeter: originalMeter, GasRegister: gr}
}
diff --git a/x/wasm/keeper/keeper_cgo.go b/x/wasm/keeper/keeper_cgo.go
index 30d9e86e04..743ac64de4 100644
--- a/x/wasm/keeper/keeper_cgo.go
+++ b/x/wasm/keeper/keeper_cgo.go
@@ -46,7 +46,7 @@ func NewKeeper(
capabilityKeeper: capabilityKeeper,
messenger: NewDefaultMessageHandler(router, ics4Wrapper, channelKeeper, capabilityKeeper, bankKeeper, cdc, portSource),
queryGasLimit: wasmConfig.SmartQueryGasLimit,
- gasRegister: NewDefaultWasmGasRegister(),
+ gasRegister: types.NewDefaultWasmGasRegister(),
maxQueryStackSize: types.DefaultMaxQueryStackSize,
acceptedAccountTypes: defaultAcceptedAccountTypes,
propagateGovAuthorization: map[types.AuthorizationPolicyAction]struct{}{
diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go
index 53bf8617d2..8b4cce4227 100644
--- a/x/wasm/keeper/keeper_test.go
+++ b/x/wasm/keeper/keeper_test.go
@@ -1972,7 +1972,7 @@ func TestReply(t *testing.T) {
Bank: &wasmvmtypes.BankQuery{
Balance: &wasmvmtypes.BalanceQuery{Address: env.Contract.Address, Denom: "stake"},
},
- }, 10_000*DefaultGasMultiplier)
+ }, 10_000*types.DefaultGasMultiplier)
require.NoError(t, err)
var gotBankRsp wasmvmtypes.BalanceResponse
require.NoError(t, json.Unmarshal(bzRsp, &gotBankRsp))
@@ -2036,7 +2036,7 @@ func TestQueryIsolation(t *testing.T) {
mock.ReplyFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) {
_, err := querier.Query(wasmvmtypes.QueryRequest{
Custom: []byte(`{}`),
- }, 10000*DefaultGasMultiplier)
+ }, 10000*types.DefaultGasMultiplier)
require.NoError(t, err)
return &wasmvmtypes.Response{}, 0, nil
}
@@ -2436,31 +2436,31 @@ func TestSetContractAdmin(t *testing.T) {
func TestGasConsumed(t *testing.T) {
specs := map[string]struct {
originalMeter stypes.GasMeter
- gasRegister WasmGasRegister
+ gasRegister types.WasmGasRegister
consumeGas sdk.Gas
expPanic bool
expMultipliedGasConsumed uint64
}{
"all good": {
originalMeter: sdk.NewGasMeter(100),
- gasRegister: NewWasmGasRegister(DefaultGasRegisterConfig()),
+ gasRegister: types.NewWasmGasRegister(types.DefaultGasRegisterConfig()),
consumeGas: sdk.Gas(1),
expMultipliedGasConsumed: 140000000,
},
"consumeGas = limit": {
originalMeter: sdk.NewGasMeter(1),
- gasRegister: NewWasmGasRegister(DefaultGasRegisterConfig()),
+ gasRegister: types.NewWasmGasRegister(types.DefaultGasRegisterConfig()),
consumeGas: sdk.Gas(1),
expMultipliedGasConsumed: 140000000,
},
"consumeGas > limit": {
originalMeter: sdk.NewGasMeter(10),
- gasRegister: NewWasmGasRegister(DefaultGasRegisterConfig()),
+ gasRegister: types.NewWasmGasRegister(types.DefaultGasRegisterConfig()),
consumeGas: sdk.Gas(11),
expPanic: true,
},
"nil original meter": {
- gasRegister: NewWasmGasRegister(DefaultGasRegisterConfig()),
+ gasRegister: types.NewWasmGasRegister(types.DefaultGasRegisterConfig()),
consumeGas: sdk.Gas(1),
expPanic: true,
},
diff --git a/x/wasm/keeper/options.go b/x/wasm/keeper/options.go
index 2fb3d2ea4d..7ccf7d9e52 100644
--- a/x/wasm/keeper/options.go
+++ b/x/wasm/keeper/options.go
@@ -134,7 +134,7 @@ func WithVMCacheMetrics(r prometheus.Registerer) Option {
// WithGasRegister set a new gas register to implement custom gas costs.
// When the "gas multiplier" for wasmvm gas conversion is modified inside the new register,
// make sure to also use `WithApiCosts` option for non default values
-func WithGasRegister(x GasRegister) Option {
+func WithGasRegister(x types.GasRegister) Option {
if x == nil {
panic("must not be nil")
}
diff --git a/x/wasm/keeper/options_test.go b/x/wasm/keeper/options_test.go
index aedcc9396c..b26e1af7c2 100644
--- a/x/wasm/keeper/options_test.go
+++ b/x/wasm/keeper/options_test.go
@@ -160,8 +160,8 @@ func TestConstructorOptions(t *testing.T) {
}
func setAPIDefaults() {
- costHumanize = DefaultGasCostHumanAddress * DefaultGasMultiplier
- costCanonical = DefaultGasCostCanonicalAddress * DefaultGasMultiplier
+ costHumanize = DefaultGasCostHumanAddress * types.DefaultGasMultiplier
+ costCanonical = DefaultGasCostCanonicalAddress * types.DefaultGasMultiplier
}
func TestSplitOpts(t *testing.T) {
diff --git a/x/wasm/keeper/querier_test.go b/x/wasm/keeper/querier_test.go
index 70220bb5b0..af9a6e3f4f 100644
--- a/x/wasm/keeper/querier_test.go
+++ b/x/wasm/keeper/querier_test.go
@@ -176,7 +176,7 @@ func TestQuerySmartContractPanics(t *testing.T) {
CodeID: 1,
Created: types.NewAbsoluteTxPosition(ctx),
})
- ctx = ctx.WithGasMeter(sdk.NewGasMeter(DefaultInstanceCost)).WithLogger(log.TestingLogger())
+ ctx = ctx.WithGasMeter(sdk.NewGasMeter(types.DefaultInstanceCost)).WithLogger(log.TestingLogger())
specs := map[string]struct {
doInContract func()
diff --git a/x/wasm/keeper/query_plugins.go b/x/wasm/keeper/query_plugins.go
index 36290cad95..c1a958b299 100644
--- a/x/wasm/keeper/query_plugins.go
+++ b/x/wasm/keeper/query_plugins.go
@@ -27,10 +27,10 @@ type QueryHandler struct {
Ctx sdk.Context
Plugins WasmVMQueryHandler
Caller sdk.AccAddress
- gasRegister GasRegister
+ gasRegister types.GasRegister
}
-func NewQueryHandler(ctx sdk.Context, vmQueryHandler WasmVMQueryHandler, caller sdk.AccAddress, gasRegister GasRegister) QueryHandler {
+func NewQueryHandler(ctx sdk.Context, vmQueryHandler WasmVMQueryHandler, caller sdk.AccAddress, gasRegister types.GasRegister) QueryHandler {
return QueryHandler{
Ctx: ctx,
Plugins: vmQueryHandler,
diff --git a/x/wasm/keeper/query_plugins_test.go b/x/wasm/keeper/query_plugins_test.go
index d8e94ce8f9..bf76ec10fc 100644
--- a/x/wasm/keeper/query_plugins_test.go
+++ b/x/wasm/keeper/query_plugins_test.go
@@ -691,7 +691,7 @@ func TestQueryErrors(t *testing.T) {
return nil, spec.src
})
ctx := sdk.Context{}.WithGasMeter(sdk.NewInfiniteGasMeter()).WithMultiStore(store.NewCommitMultiStore(dbm.NewMemDB())).WithLogger(log.TestingLogger())
- q := keeper.NewQueryHandler(ctx, mock, sdk.AccAddress{}, keeper.NewDefaultWasmGasRegister())
+ q := keeper.NewQueryHandler(ctx, mock, sdk.AccAddress{}, types.NewDefaultWasmGasRegister())
_, gotErr := q.Query(wasmvmtypes.QueryRequest{}, 1)
assert.Equal(t, spec.expErr, gotErr)
})
diff --git a/x/wasm/keeper/recurse_test.go b/x/wasm/keeper/recurse_test.go
index 20deb38ef4..4d10d12e64 100644
--- a/x/wasm/keeper/recurse_test.go
+++ b/x/wasm/keeper/recurse_test.go
@@ -140,7 +140,7 @@ func TestGasCostOnQuery(t *testing.T) {
func TestGasOnExternalQuery(t *testing.T) {
const (
- GasWork50 uint64 = DefaultInstanceCost + 8_464
+ GasWork50 uint64 = types.DefaultInstanceCost + 8_464
)
cases := map[string]struct {
diff --git a/x/wasm/keeper/relay_test.go b/x/wasm/keeper/relay_test.go
index 928176591d..b1ee4f3438 100644
--- a/x/wasm/keeper/relay_test.go
+++ b/x/wasm/keeper/relay_test.go
@@ -39,8 +39,8 @@ func TestOnOpenChannel(t *testing.T) {
},
"consume max gas": {
contractAddr: example.Contract,
- contractGas: math.MaxUint64 / DefaultGasMultiplier,
- expGas: math.MaxUint64 / DefaultGasMultiplier,
+ contractGas: math.MaxUint64 / types.DefaultGasMultiplier,
+ expGas: math.MaxUint64 / types.DefaultGasMultiplier,
},
"consume gas on error": {
contractAddr: example.Contract,
@@ -59,7 +59,7 @@ func TestOnOpenChannel(t *testing.T) {
myMsg := wasmvmtypes.IBCChannelOpenMsg{OpenTry: &wasmvmtypes.IBCOpenTry{Channel: myChannel, CounterpartyVersion: "foo"}}
m.IBCChannelOpenFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) {
assert.Equal(t, myMsg, msg)
- return &wasmvmtypes.IBC3ChannelOpenResponse{}, spec.contractGas * DefaultGasMultiplier, spec.contractErr
+ return &wasmvmtypes.IBC3ChannelOpenResponse{}, spec.contractGas * types.DefaultGasMultiplier, spec.contractErr
}
ctx, _ := parentCtx.CacheContext()
@@ -156,7 +156,7 @@ func TestOnConnectChannel(t *testing.T) {
myMsg := wasmvmtypes.IBCChannelConnectMsg{OpenConfirm: &wasmvmtypes.IBCOpenConfirm{Channel: myChannel}}
m.IBCChannelConnectFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) {
assert.Equal(t, msg, myMsg)
- return spec.contractResp, myContractGas * DefaultGasMultiplier, spec.contractErr
+ return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr
}
ctx, _ := parentCtx.CacheContext()
@@ -268,7 +268,7 @@ func TestOnCloseChannel(t *testing.T) {
myMsg := wasmvmtypes.IBCChannelCloseMsg{CloseInit: &wasmvmtypes.IBCCloseInit{Channel: myChannel}}
m.IBCChannelCloseFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) {
assert.Equal(t, msg, myMsg)
- return spec.contractResp, myContractGas * DefaultGasMultiplier, spec.contractErr
+ return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr
}
ctx, _ := parentCtx.CacheContext()
@@ -441,7 +441,7 @@ func TestOnRecvPacket(t *testing.T) {
m.IBCPacketReceiveFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketReceiveMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCReceiveResult, uint64, error) {
assert.Equal(t, myPacket, msg.Packet)
- return spec.contractResp, myContractGas * DefaultGasMultiplier, spec.contractErr
+ return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr
}
if spec.mockReplyFn != nil {
m.ReplyFn = spec.mockReplyFn
@@ -567,7 +567,7 @@ func TestOnAckPacket(t *testing.T) {
myAck := wasmvmtypes.IBCPacketAckMsg{Acknowledgement: wasmvmtypes.IBCAcknowledgement{Data: []byte("myAck")}}
m.IBCPacketAckFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) {
assert.Equal(t, myAck, msg)
- return spec.contractResp, myContractGas * DefaultGasMultiplier, spec.contractErr
+ return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr
}
ctx, _ := parentCtx.CacheContext()
@@ -687,7 +687,7 @@ func TestOnTimeoutPacket(t *testing.T) {
myPacket := wasmvmtypes.IBCPacket{Data: []byte("my test packet")}
m.IBCPacketTimeoutFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) {
assert.Equal(t, myPacket, msg.Packet)
- return spec.contractResp, myContractGas * DefaultGasMultiplier, spec.contractErr
+ return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr
}
ctx, _ := parentCtx.CacheContext()
diff --git a/x/wasm/types/authz.go b/x/wasm/types/authz.go
index 1d06d7aa0d..7f49a8aea9 100644
--- a/x/wasm/types/authz.go
+++ b/x/wasm/types/authz.go
@@ -1,8 +1,10 @@
package types
import (
+ "bytes"
"strings"
+ wasmvm "github.com/CosmWasm/wasmvm"
"github.com/cosmos/gogoproto/proto"
errorsmod "cosmossdk.io/errors"
@@ -11,17 +13,130 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authztypes "github.com/cosmos/cosmos-sdk/x/authz"
+
+ "github.com/CosmWasm/wasmd/x/wasm/ioutils"
)
-const gasDeserializationCostPerByte = uint64(1)
+const (
+ gasDeserializationCostPerByte = uint64(1)
+ // CodehashWildcard matches any code hash
+ CodehashWildcard = "*"
+)
var (
+ _ authztypes.Authorization = &StoreCodeAuthorization{}
_ authztypes.Authorization = &ContractExecutionAuthorization{}
_ authztypes.Authorization = &ContractMigrationAuthorization{}
_ cdctypes.UnpackInterfacesMessage = &ContractExecutionAuthorization{}
_ cdctypes.UnpackInterfacesMessage = &ContractMigrationAuthorization{}
)
+// NewStoreCodeAuthorization constructor
+func NewStoreCodeAuthorization(grants ...CodeGrant) *StoreCodeAuthorization {
+ return &StoreCodeAuthorization{
+ Grants: grants,
+ }
+}
+
+// MsgTypeURL implements Authorization.MsgTypeURL.
+func (a StoreCodeAuthorization) MsgTypeURL() string {
+ return sdk.MsgTypeURL(&MsgStoreCode{})
+}
+
+// Accept implements Authorization.Accept.
+func (a *StoreCodeAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authztypes.AcceptResponse, error) {
+ storeMsg, ok := msg.(*MsgStoreCode)
+ if !ok {
+ return authztypes.AcceptResponse{}, sdkerrors.ErrInvalidRequest.Wrap("unknown msg type")
+ }
+
+ code := storeMsg.WASMByteCode
+ permission := *storeMsg.InstantiatePermission
+
+ if ioutils.IsGzip(code) {
+ gasRegister, ok := GasRegisterFromContext(ctx)
+ if !ok {
+ return authztypes.AcceptResponse{}, sdkerrors.ErrNotFound.Wrap("gas register")
+ }
+ ctx.GasMeter().ConsumeGas(gasRegister.UncompressCosts(len(code)), "Uncompress gzip bytecode")
+ wasmCode, err := ioutils.Uncompress(code, int64(MaxWasmSize))
+ if err != nil {
+ return authztypes.AcceptResponse{}, sdkerrors.ErrInvalidRequest.Wrap("uncompress wasm archive")
+ }
+ code = wasmCode
+ }
+
+ checksum, err := wasmvm.CreateChecksum(code)
+ if err != nil {
+ return authztypes.AcceptResponse{}, sdkerrors.ErrInvalidRequest.Wrap("checksum")
+ }
+
+ for _, grant := range a.Grants {
+ if grant.Accept(checksum, permission) {
+ return authztypes.AcceptResponse{Accept: true}, nil
+ }
+ }
+ return authztypes.AcceptResponse{Accept: false}, nil
+}
+
+// ValidateBasic implements Authorization.ValidateBasic.
+func (a StoreCodeAuthorization) ValidateBasic() error {
+ numberOfGrants := len(a.Grants)
+ switch numberOfGrants {
+ case 0:
+ return ErrEmpty.Wrap("grants")
+ case 1:
+ if err := a.Grants[0].ValidateBasic(); err != nil {
+ return errorsmod.Wrapf(err, "position %d", 0)
+ }
+ default:
+ uniqueGrants := make(map[string]struct{}, numberOfGrants)
+ for i, grant := range a.Grants {
+ if strings.EqualFold(string(grant.CodeHash), CodehashWildcard) {
+ return sdkerrors.ErrInvalidRequest.Wrap("cannot have multiple grants when wildcard grant is one of them")
+ }
+ if err := grant.ValidateBasic(); err != nil {
+ return errorsmod.Wrapf(err, "position %d", i)
+ }
+ uniqueGrants[strings.ToLower(string(grant.CodeHash))] = struct{}{}
+ }
+ if len(uniqueGrants) != numberOfGrants {
+ return sdkerrors.ErrInvalidRequest.Wrap("cannot have multiple grants with same code hash")
+ }
+ }
+ return nil
+}
+
+// NewCodeGrant constructor
+func NewCodeGrant(codeHash []byte, instantiatePermission *AccessConfig) (*CodeGrant, error) {
+ return &CodeGrant{
+ CodeHash: codeHash,
+ InstantiatePermission: instantiatePermission,
+ }, nil
+}
+
+// ValidateBasic validates the grant
+func (g CodeGrant) ValidateBasic() error {
+ if len(g.CodeHash) == 0 {
+ return ErrEmpty.Wrap("code hash")
+ }
+ if g.InstantiatePermission != nil {
+ return g.InstantiatePermission.ValidateBasic()
+ }
+ return nil
+}
+
+// Accept checks if checksum and permission match the grant
+func (g CodeGrant) Accept(checksum []byte, permission AccessConfig) bool {
+ if !strings.EqualFold(string(g.CodeHash), CodehashWildcard) && !bytes.EqualFold(g.CodeHash, checksum) {
+ return false
+ }
+ if g.InstantiatePermission == nil {
+ return true
+ }
+ return permission.IsSubset(*g.InstantiatePermission)
+}
+
// AuthzableWasmMsg is abstract wasm tx message that is supported in authz
type AuthzableWasmMsg interface {
GetFunds() sdk.Coins
diff --git a/x/wasm/types/authz.pb.go b/x/wasm/types/authz.pb.go
index 8bd25bfd3a..eb4110acd0 100644
--- a/x/wasm/types/authz.pb.go
+++ b/x/wasm/types/authz.pb.go
@@ -31,6 +31,51 @@ var (
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
+// StoreCodeAuthorization defines authorization for wasm code upload.
+// Since: wasmd 0.42
+type StoreCodeAuthorization struct {
+ // Grants for code upload
+ Grants []CodeGrant `protobuf:"bytes,1,rep,name=grants,proto3" json:"grants"`
+}
+
+func (m *StoreCodeAuthorization) Reset() { *m = StoreCodeAuthorization{} }
+func (m *StoreCodeAuthorization) String() string { return proto.CompactTextString(m) }
+func (*StoreCodeAuthorization) ProtoMessage() {}
+func (*StoreCodeAuthorization) Descriptor() ([]byte, []int) {
+ return fileDescriptor_36ff3a20cf32b258, []int{0}
+}
+
+func (m *StoreCodeAuthorization) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+
+func (m *StoreCodeAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_StoreCodeAuthorization.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalToSizedBuffer(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+
+func (m *StoreCodeAuthorization) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_StoreCodeAuthorization.Merge(m, src)
+}
+
+func (m *StoreCodeAuthorization) XXX_Size() int {
+ return m.Size()
+}
+
+func (m *StoreCodeAuthorization) XXX_DiscardUnknown() {
+ xxx_messageInfo_StoreCodeAuthorization.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_StoreCodeAuthorization proto.InternalMessageInfo
+
// ContractExecutionAuthorization defines authorization for wasm execute.
// Since: wasmd 0.30
type ContractExecutionAuthorization struct {
@@ -42,7 +87,7 @@ func (m *ContractExecutionAuthorization) Reset() { *m = ContractExecutio
func (m *ContractExecutionAuthorization) String() string { return proto.CompactTextString(m) }
func (*ContractExecutionAuthorization) ProtoMessage() {}
func (*ContractExecutionAuthorization) Descriptor() ([]byte, []int) {
- return fileDescriptor_36ff3a20cf32b258, []int{0}
+ return fileDescriptor_36ff3a20cf32b258, []int{1}
}
func (m *ContractExecutionAuthorization) XXX_Unmarshal(b []byte) error {
@@ -87,7 +132,7 @@ func (m *ContractMigrationAuthorization) Reset() { *m = ContractMigratio
func (m *ContractMigrationAuthorization) String() string { return proto.CompactTextString(m) }
func (*ContractMigrationAuthorization) ProtoMessage() {}
func (*ContractMigrationAuthorization) Descriptor() ([]byte, []int) {
- return fileDescriptor_36ff3a20cf32b258, []int{1}
+ return fileDescriptor_36ff3a20cf32b258, []int{2}
}
func (m *ContractMigrationAuthorization) XXX_Unmarshal(b []byte) error {
@@ -121,6 +166,55 @@ func (m *ContractMigrationAuthorization) XXX_DiscardUnknown() {
var xxx_messageInfo_ContractMigrationAuthorization proto.InternalMessageInfo
+// CodeGrant a granted permission for a single code
+type CodeGrant struct {
+ // CodeHash is the unique identifier created by wasmvm
+ // Wildcard "*" is used to specify any kind of grant.
+ CodeHash []byte `protobuf:"bytes,1,opt,name=code_hash,json=codeHash,proto3" json:"code_hash,omitempty"`
+ // InstantiatePermission is the superset access control to apply
+ // on contract creation.
+ // Optional
+ InstantiatePermission *AccessConfig `protobuf:"bytes,2,opt,name=instantiate_permission,json=instantiatePermission,proto3" json:"instantiate_permission,omitempty"`
+}
+
+func (m *CodeGrant) Reset() { *m = CodeGrant{} }
+func (m *CodeGrant) String() string { return proto.CompactTextString(m) }
+func (*CodeGrant) ProtoMessage() {}
+func (*CodeGrant) Descriptor() ([]byte, []int) {
+ return fileDescriptor_36ff3a20cf32b258, []int{3}
+}
+
+func (m *CodeGrant) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+
+func (m *CodeGrant) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_CodeGrant.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalToSizedBuffer(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+
+func (m *CodeGrant) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CodeGrant.Merge(m, src)
+}
+
+func (m *CodeGrant) XXX_Size() int {
+ return m.Size()
+}
+
+func (m *CodeGrant) XXX_DiscardUnknown() {
+ xxx_messageInfo_CodeGrant.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CodeGrant proto.InternalMessageInfo
+
// ContractGrant a granted permission for a single contract
// Since: wasmd 0.30
type ContractGrant struct {
@@ -139,7 +233,7 @@ func (m *ContractGrant) Reset() { *m = ContractGrant{} }
func (m *ContractGrant) String() string { return proto.CompactTextString(m) }
func (*ContractGrant) ProtoMessage() {}
func (*ContractGrant) Descriptor() ([]byte, []int) {
- return fileDescriptor_36ff3a20cf32b258, []int{2}
+ return fileDescriptor_36ff3a20cf32b258, []int{4}
}
func (m *ContractGrant) XXX_Unmarshal(b []byte) error {
@@ -184,7 +278,7 @@ func (m *MaxCallsLimit) Reset() { *m = MaxCallsLimit{} }
func (m *MaxCallsLimit) String() string { return proto.CompactTextString(m) }
func (*MaxCallsLimit) ProtoMessage() {}
func (*MaxCallsLimit) Descriptor() ([]byte, []int) {
- return fileDescriptor_36ff3a20cf32b258, []int{3}
+ return fileDescriptor_36ff3a20cf32b258, []int{5}
}
func (m *MaxCallsLimit) XXX_Unmarshal(b []byte) error {
@@ -229,7 +323,7 @@ func (m *MaxFundsLimit) Reset() { *m = MaxFundsLimit{} }
func (m *MaxFundsLimit) String() string { return proto.CompactTextString(m) }
func (*MaxFundsLimit) ProtoMessage() {}
func (*MaxFundsLimit) Descriptor() ([]byte, []int) {
- return fileDescriptor_36ff3a20cf32b258, []int{4}
+ return fileDescriptor_36ff3a20cf32b258, []int{6}
}
func (m *MaxFundsLimit) XXX_Unmarshal(b []byte) error {
@@ -277,7 +371,7 @@ func (m *CombinedLimit) Reset() { *m = CombinedLimit{} }
func (m *CombinedLimit) String() string { return proto.CompactTextString(m) }
func (*CombinedLimit) ProtoMessage() {}
func (*CombinedLimit) Descriptor() ([]byte, []int) {
- return fileDescriptor_36ff3a20cf32b258, []int{5}
+ return fileDescriptor_36ff3a20cf32b258, []int{7}
}
func (m *CombinedLimit) XXX_Unmarshal(b []byte) error {
@@ -320,7 +414,7 @@ func (m *AllowAllMessagesFilter) Reset() { *m = AllowAllMessagesFilter{}
func (m *AllowAllMessagesFilter) String() string { return proto.CompactTextString(m) }
func (*AllowAllMessagesFilter) ProtoMessage() {}
func (*AllowAllMessagesFilter) Descriptor() ([]byte, []int) {
- return fileDescriptor_36ff3a20cf32b258, []int{6}
+ return fileDescriptor_36ff3a20cf32b258, []int{8}
}
func (m *AllowAllMessagesFilter) XXX_Unmarshal(b []byte) error {
@@ -366,7 +460,7 @@ func (m *AcceptedMessageKeysFilter) Reset() { *m = AcceptedMessageKeysFi
func (m *AcceptedMessageKeysFilter) String() string { return proto.CompactTextString(m) }
func (*AcceptedMessageKeysFilter) ProtoMessage() {}
func (*AcceptedMessageKeysFilter) Descriptor() ([]byte, []int) {
- return fileDescriptor_36ff3a20cf32b258, []int{7}
+ return fileDescriptor_36ff3a20cf32b258, []int{9}
}
func (m *AcceptedMessageKeysFilter) XXX_Unmarshal(b []byte) error {
@@ -412,7 +506,7 @@ func (m *AcceptedMessagesFilter) Reset() { *m = AcceptedMessagesFilter{}
func (m *AcceptedMessagesFilter) String() string { return proto.CompactTextString(m) }
func (*AcceptedMessagesFilter) ProtoMessage() {}
func (*AcceptedMessagesFilter) Descriptor() ([]byte, []int) {
- return fileDescriptor_36ff3a20cf32b258, []int{8}
+ return fileDescriptor_36ff3a20cf32b258, []int{10}
}
func (m *AcceptedMessagesFilter) XXX_Unmarshal(b []byte) error {
@@ -447,8 +541,10 @@ func (m *AcceptedMessagesFilter) XXX_DiscardUnknown() {
var xxx_messageInfo_AcceptedMessagesFilter proto.InternalMessageInfo
func init() {
+ proto.RegisterType((*StoreCodeAuthorization)(nil), "cosmwasm.wasm.v1.StoreCodeAuthorization")
proto.RegisterType((*ContractExecutionAuthorization)(nil), "cosmwasm.wasm.v1.ContractExecutionAuthorization")
proto.RegisterType((*ContractMigrationAuthorization)(nil), "cosmwasm.wasm.v1.ContractMigrationAuthorization")
+ proto.RegisterType((*CodeGrant)(nil), "cosmwasm.wasm.v1.CodeGrant")
proto.RegisterType((*ContractGrant)(nil), "cosmwasm.wasm.v1.ContractGrant")
proto.RegisterType((*MaxCallsLimit)(nil), "cosmwasm.wasm.v1.MaxCallsLimit")
proto.RegisterType((*MaxFundsLimit)(nil), "cosmwasm.wasm.v1.MaxFundsLimit")
@@ -461,49 +557,93 @@ func init() {
func init() { proto.RegisterFile("cosmwasm/wasm/v1/authz.proto", fileDescriptor_36ff3a20cf32b258) }
var fileDescriptor_36ff3a20cf32b258 = []byte{
- // 665 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0x4d, 0x4f, 0xd4, 0x40,
- 0x18, 0xde, 0x01, 0x44, 0x76, 0x10, 0x3f, 0x1a, 0x42, 0x16, 0x24, 0x5d, 0x52, 0xbf, 0x56, 0x92,
- 0x6d, 0xb3, 0x18, 0x2f, 0x7b, 0x31, 0xbb, 0xab, 0x18, 0x23, 0x78, 0x68, 0x4c, 0x20, 0x5e, 0xc8,
- 0xb4, 0x3b, 0x94, 0x91, 0x76, 0x86, 0x74, 0xa6, 0xc0, 0x92, 0xf8, 0x07, 0x3c, 0x79, 0xf3, 0x2f,
- 0x18, 0x4f, 0x1c, 0xf6, 0xe8, 0x0f, 0x20, 0x9c, 0x38, 0x1a, 0x0f, 0xa8, 0x10, 0xc3, 0x7f, 0xf0,
- 0x64, 0x3a, 0x33, 0x5d, 0x58, 0x02, 0x1b, 0xe4, 0xc4, 0x65, 0xda, 0xf7, 0x7d, 0x67, 0x9e, 0xe7,
- 0x79, 0x3f, 0xda, 0x81, 0x93, 0x3e, 0xe3, 0xd1, 0x06, 0xe2, 0x91, 0x23, 0x97, 0xf5, 0x8a, 0x83,
- 0x12, 0xb1, 0xb2, 0x65, 0xaf, 0xc5, 0x4c, 0x30, 0xe3, 0x76, 0x16, 0xb5, 0xe5, 0xb2, 0x5e, 0x99,
- 0x18, 0x0d, 0x58, 0xc0, 0x64, 0xd0, 0x49, 0xdf, 0xd4, 0xbe, 0x89, 0xf1, 0x74, 0x1f, 0xe3, 0x4b,
- 0x2a, 0xa0, 0x0c, 0x1d, 0x32, 0x95, 0xe5, 0x78, 0x88, 0x63, 0x67, 0xbd, 0xe2, 0x61, 0x81, 0x2a,
- 0x8e, 0xcf, 0x08, 0xcd, 0x8e, 0x06, 0x8c, 0x05, 0x21, 0x76, 0xa4, 0xe5, 0x25, 0xcb, 0x0e, 0xa2,
- 0x2d, 0x1d, 0xba, 0x83, 0x22, 0x42, 0x99, 0x23, 0x57, 0xe5, 0xb2, 0xda, 0x00, 0x9a, 0x0d, 0x46,
- 0x45, 0x8c, 0x7c, 0xf1, 0x62, 0x13, 0xfb, 0x89, 0x20, 0x8c, 0xd6, 0x12, 0xb1, 0xc2, 0x62, 0xb2,
- 0x85, 0x52, 0xc3, 0xa8, 0xc3, 0xc1, 0x20, 0x46, 0x54, 0xf0, 0x02, 0x98, 0xea, 0x2f, 0x0d, 0xcf,
- 0x14, 0xed, 0xd3, 0x49, 0xd8, 0x19, 0xc2, 0xcb, 0x74, 0x5f, 0x3d, 0xbf, 0xb3, 0x5f, 0xcc, 0x7d,
- 0x39, 0xda, 0x9e, 0x06, 0xae, 0x3e, 0x59, 0x7d, 0xb3, 0xdb, 0x2e, 0x5b, 0x3a, 0x0d, 0x55, 0x0f,
- 0xad, 0xdc, 0xee, 0xe2, 0xfa, 0x78, 0xb4, 0x3d, 0x7d, 0x4f, 0xd6, 0xad, 0xb7, 0xa6, 0x2e, 0xd9,
- 0xf3, 0x24, 0x88, 0xd1, 0x15, 0x93, 0x7d, 0xb6, 0x26, 0xeb, 0x07, 0x80, 0x23, 0x5d, 0xa4, 0xc6,
- 0x04, 0x1c, 0xf2, 0xb5, 0xa3, 0x00, 0xa6, 0x40, 0x29, 0xef, 0x76, 0x6c, 0xe3, 0x2d, 0xbc, 0x16,
- 0x92, 0x88, 0x88, 0x42, 0xdf, 0x14, 0x28, 0x0d, 0xcf, 0x8c, 0xda, 0xaa, 0xb3, 0x76, 0xd6, 0x59,
- 0xbb, 0x46, 0x5b, 0xf5, 0xd2, 0x6e, 0xbb, 0x7c, 0xff, 0xdc, 0xcc, 0x52, 0xfa, 0xad, 0xb9, 0x14,
- 0x64, 0xd1, 0x55, 0x60, 0xc6, 0x02, 0x1c, 0x5c, 0x26, 0xa1, 0xc0, 0x71, 0xa1, 0xbf, 0x07, 0xec,
- 0xe3, 0xdd, 0x76, 0xf9, 0x41, 0x6f, 0xd8, 0x59, 0x89, 0xb2, 0xe8, 0x6a, 0x38, 0x8b, 0xc2, 0x91,
- 0x79, 0xb4, 0xd9, 0x40, 0x61, 0xc8, 0x25, 0xa3, 0x31, 0x09, 0xf3, 0x31, 0x8e, 0x10, 0xa1, 0x84,
- 0x06, 0x32, 0xb9, 0x01, 0xf7, 0xd8, 0x51, 0x7d, 0x76, 0x51, 0xe1, 0x69, 0x75, 0x0d, 0x59, 0xdd,
- 0x2e, 0x78, 0xeb, 0x1b, 0x90, 0x84, 0xb3, 0x09, 0x6d, 0x6a, 0xc2, 0xf7, 0xf0, 0x3a, 0x8a, 0x58,
- 0x72, 0xdc, 0xf3, 0x71, 0x5b, 0x37, 0x2f, 0xfd, 0x58, 0x3a, 0xbd, 0x6b, 0x30, 0x42, 0xeb, 0x4f,
- 0xd3, 0x6e, 0x7f, 0xfd, 0x59, 0x2c, 0x05, 0x44, 0xac, 0x24, 0x9e, 0xed, 0xb3, 0x48, 0x7f, 0x67,
- 0xfa, 0x51, 0xe6, 0xcd, 0x55, 0x47, 0xb4, 0xd6, 0x30, 0x97, 0x07, 0xb8, 0x9a, 0x8c, 0x8c, 0xe0,
- 0x92, 0xf2, 0x8f, 0xc5, 0x5a, 0x7f, 0xe4, 0x2c, 0x44, 0x1e, 0xa1, 0xb8, 0xa9, 0xe4, 0x3f, 0x82,
- 0xb7, 0xfc, 0x34, 0xbd, 0xa5, 0xd3, 0x55, 0xbb, 0x29, 0xdd, 0x6e, 0xe6, 0x3d, 0x99, 0x67, 0xdf,
- 0x15, 0xcc, 0xb3, 0x2b, 0x2b, 0xcb, 0x87, 0x63, 0xb5, 0x30, 0x64, 0x1b, 0xb5, 0x30, 0x9c, 0xc7,
- 0x9c, 0xa3, 0x00, 0x73, 0x35, 0x39, 0xd5, 0x57, 0x17, 0x9e, 0xb1, 0x14, 0xfb, 0xae, 0xc4, 0x3e,
- 0x1b, 0xca, 0xfa, 0x00, 0xc7, 0x6b, 0xbe, 0x8f, 0xd7, 0x04, 0x6e, 0xea, 0xc8, 0x6b, 0xdc, 0xd2,
- 0x41, 0xc3, 0x80, 0x03, 0xab, 0xb8, 0xa5, 0x66, 0x22, 0xef, 0xca, 0xf7, 0xea, 0xdc, 0x7f, 0x71,
- 0x9b, 0x8a, 0xfb, 0x3c, 0x06, 0xeb, 0x33, 0x80, 0x63, 0xa7, 0xa2, 0x19, 0xf9, 0x0c, 0x1c, 0x8a,
- 0xb4, 0x47, 0x0a, 0xb8, 0x51, 0x1f, 0xfb, 0xbb, 0x5f, 0x34, 0x5c, 0xb4, 0xd1, 0xf9, 0x57, 0xa8,
- 0xb0, 0xdb, 0xd9, 0x77, 0xb9, 0xc2, 0x9c, 0x49, 0x5f, 0x7f, 0xbe, 0xf3, 0xdb, 0xcc, 0xed, 0x1c,
- 0x98, 0x60, 0xef, 0xc0, 0x04, 0xbf, 0x0e, 0x4c, 0xf0, 0xe9, 0xd0, 0xcc, 0xed, 0x1d, 0x9a, 0xb9,
- 0xef, 0x87, 0x66, 0xee, 0xdd, 0xc3, 0x13, 0x43, 0xd1, 0x60, 0x3c, 0x5a, 0xc8, 0xee, 0xad, 0xa6,
- 0xb3, 0xa9, 0xee, 0x2f, 0x39, 0x18, 0xde, 0xa0, 0xfc, 0x37, 0x3c, 0xf9, 0x17, 0x00, 0x00, 0xff,
- 0xff, 0x84, 0xc4, 0x51, 0x3d, 0xdd, 0x06, 0x00, 0x00,
+ // 772 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0xcf, 0x4f, 0x13, 0x4d,
+ 0x18, 0xee, 0x02, 0x1f, 0x1f, 0x1d, 0xe0, 0xfb, 0xb1, 0xe1, 0x6b, 0x5a, 0x20, 0x5b, 0xb2, 0xdf,
+ 0xaf, 0x4a, 0xd2, 0xdd, 0x14, 0xe3, 0xa5, 0x07, 0x4d, 0x5b, 0x45, 0x8d, 0x60, 0xcc, 0xaa, 0x81,
+ 0x78, 0x69, 0xa6, 0xdb, 0x61, 0x3b, 0xb2, 0x3b, 0xd3, 0xec, 0x4c, 0x81, 0x92, 0x18, 0xef, 0x9e,
+ 0xbc, 0x79, 0xf5, 0x68, 0x3c, 0x71, 0xe8, 0xd1, 0x3f, 0x80, 0x70, 0xe2, 0x68, 0x3c, 0xa0, 0x42,
+ 0x0c, 0xff, 0x83, 0x27, 0xb3, 0x33, 0xd3, 0x96, 0x96, 0x42, 0x90, 0x13, 0x97, 0xed, 0xce, 0xfb,
+ 0xce, 0xfb, 0x3e, 0xcf, 0x33, 0xf3, 0xf4, 0x5d, 0x30, 0xeb, 0x52, 0x16, 0x6c, 0x42, 0x16, 0xd8,
+ 0xe2, 0xb1, 0x91, 0xb3, 0x61, 0x83, 0xd7, 0xb6, 0xad, 0x7a, 0x48, 0x39, 0xd5, 0xff, 0x68, 0x67,
+ 0x2d, 0xf1, 0xd8, 0xc8, 0x4d, 0x4f, 0x79, 0xd4, 0xa3, 0x22, 0x69, 0x47, 0x6f, 0x72, 0xdf, 0x74,
+ 0x2a, 0xda, 0x47, 0x59, 0x59, 0x26, 0xe4, 0x42, 0xa5, 0x0c, 0xb9, 0xb2, 0x2b, 0x90, 0x21, 0x7b,
+ 0x23, 0x57, 0x41, 0x1c, 0xe6, 0x6c, 0x97, 0x62, 0xa2, 0xf2, 0xa7, 0x09, 0xf0, 0x66, 0x1d, 0xb5,
+ 0xab, 0x53, 0x1e, 0xa5, 0x9e, 0x8f, 0x6c, 0xb1, 0xaa, 0x34, 0xd6, 0x6c, 0x48, 0x9a, 0x2a, 0xf5,
+ 0x27, 0x0c, 0x30, 0xa1, 0xb6, 0x78, 0xca, 0x90, 0xf9, 0x56, 0x03, 0x89, 0xc7, 0x9c, 0x86, 0xa8,
+ 0x44, 0xab, 0xa8, 0xd0, 0xe0, 0x35, 0x1a, 0xe2, 0x6d, 0xc8, 0x31, 0x25, 0xfa, 0x4d, 0x30, 0xea,
+ 0x85, 0x90, 0x70, 0x96, 0xd4, 0xe6, 0x86, 0x33, 0xe3, 0x0b, 0x33, 0x56, 0xbf, 0x34, 0x2b, 0x2a,
+ 0xba, 0x1b, 0xed, 0x29, 0xc6, 0x77, 0x0f, 0xd2, 0xb1, 0x77, 0xc7, 0x3b, 0xf3, 0x9a, 0xa3, 0xaa,
+ 0xf2, 0x8b, 0x7b, 0xad, 0xac, 0xa9, 0x84, 0xc9, 0x13, 0x52, 0x5a, 0xac, 0x1e, 0x9c, 0x57, 0xc7,
+ 0x3b, 0xf3, 0x33, 0x42, 0xc8, 0x60, 0x1e, 0x66, 0x4b, 0x03, 0x46, 0x89, 0x12, 0x1e, 0x42, 0x97,
+ 0xdf, 0xd9, 0x42, 0x6e, 0x23, 0x8a, 0xf6, 0x52, 0x2d, 0xf6, 0x51, 0x4d, 0x0f, 0xa2, 0x2a, 0x3b,
+ 0x9c, 0x49, 0xf7, 0xe1, 0xc5, 0xe9, 0xfe, 0x2d, 0xe8, 0x9e, 0xcf, 0xa9, 0x87, 0xf6, 0x32, 0xf6,
+ 0x42, 0x78, 0xc5, 0x68, 0x0f, 0xe6, 0x64, 0xbe, 0x04, 0xf1, 0xce, 0xad, 0xea, 0x33, 0x20, 0xee,
+ 0xd2, 0x2a, 0x2a, 0xd7, 0x20, 0xab, 0x25, 0xb5, 0x39, 0x2d, 0x33, 0xe1, 0x8c, 0x45, 0x81, 0x7b,
+ 0x90, 0xd5, 0xf4, 0xa7, 0x20, 0x81, 0x09, 0xe3, 0x90, 0x70, 0x0c, 0x39, 0x2a, 0xd7, 0x51, 0x18,
+ 0x60, 0xc6, 0x30, 0x25, 0xc9, 0xa1, 0x39, 0x2d, 0x33, 0xbe, 0x60, 0x9c, 0x56, 0x53, 0x70, 0x5d,
+ 0xc4, 0x58, 0x89, 0x92, 0x35, 0xec, 0x39, 0x7f, 0x9d, 0xa8, 0x7e, 0xd4, 0x29, 0x36, 0x3f, 0x69,
+ 0x60, 0xb2, 0x47, 0xb5, 0x3e, 0x0d, 0xc6, 0x5c, 0x15, 0x10, 0x24, 0xe2, 0x4e, 0x67, 0xad, 0x3f,
+ 0x01, 0xbf, 0xf8, 0x38, 0xc0, 0x5c, 0x61, 0x4e, 0x59, 0xd2, 0xfd, 0x56, 0xdb, 0xfd, 0x56, 0x81,
+ 0x34, 0x8b, 0x99, 0xbd, 0x56, 0xf6, 0x9f, 0x33, 0x8f, 0x36, 0xd2, 0xbf, 0xbd, 0x14, 0x35, 0x59,
+ 0x75, 0x64, 0x33, 0x7d, 0x05, 0x8c, 0xae, 0x61, 0x9f, 0xa3, 0x30, 0x39, 0x7c, 0x4e, 0xdb, 0x6b,
+ 0x7b, 0xad, 0xec, 0xbf, 0xe7, 0xb7, 0x5d, 0x14, 0x5d, 0x56, 0x1d, 0xd5, 0xce, 0x24, 0x60, 0x72,
+ 0x19, 0x6e, 0x95, 0xa0, 0xef, 0x33, 0x81, 0xa8, 0xcf, 0x82, 0x78, 0x88, 0x02, 0x88, 0x09, 0x26,
+ 0x9e, 0x10, 0x37, 0xe2, 0x74, 0x03, 0xf9, 0x5b, 0x17, 0x25, 0x1e, 0x5d, 0xaf, 0x2e, 0xae, 0xb7,
+ 0xa7, 0xbd, 0xf9, 0x41, 0x13, 0x80, 0x8b, 0x0d, 0x52, 0x55, 0x80, 0xcf, 0xc1, 0xaf, 0x30, 0xa0,
+ 0x8d, 0xae, 0xe9, 0x52, 0x96, 0x72, 0x4f, 0x34, 0x6e, 0x3a, 0xe6, 0x29, 0x51, 0x4c, 0x8a, 0x37,
+ 0x22, 0xbb, 0xbd, 0xff, 0x9c, 0xce, 0x78, 0x98, 0xd7, 0x1a, 0x15, 0xcb, 0xa5, 0x81, 0x9a, 0x54,
+ 0xea, 0x27, 0xcb, 0xaa, 0xeb, 0x6a, 0xf8, 0x44, 0x05, 0x4c, 0x5a, 0xb3, 0x0d, 0x70, 0x49, 0xfa,
+ 0x5d, 0xb2, 0xe6, 0x37, 0xe1, 0x85, 0xa0, 0x82, 0x09, 0xaa, 0x4a, 0xfa, 0xff, 0x83, 0xdf, 0xdd,
+ 0x48, 0x5e, 0xb9, 0xff, 0xd4, 0x7e, 0x13, 0x61, 0xa7, 0x1d, 0x3d, 0xa9, 0x73, 0xe8, 0x0a, 0xea,
+ 0xec, 0x51, 0x65, 0xba, 0x20, 0x51, 0xf0, 0x7d, 0xba, 0x59, 0xf0, 0xfd, 0x65, 0xc4, 0x18, 0xf4,
+ 0x10, 0x93, 0xce, 0xc9, 0xdf, 0xbf, 0xb0, 0xc7, 0xba, 0x73, 0x74, 0x70, 0x2b, 0xf3, 0x05, 0x48,
+ 0x45, 0xff, 0xbf, 0x3a, 0x47, 0x55, 0x95, 0x79, 0x80, 0x9a, 0x2a, 0xa9, 0xeb, 0x60, 0x64, 0x1d,
+ 0x35, 0xa5, 0x27, 0xe2, 0x8e, 0x78, 0xcf, 0x2f, 0xfd, 0x14, 0xb6, 0x21, 0xb1, 0xcf, 0x42, 0x30,
+ 0xdf, 0x68, 0x20, 0xd1, 0x97, 0x6d, 0x83, 0x2f, 0x80, 0xb1, 0x40, 0x45, 0x04, 0x81, 0x89, 0x62,
+ 0xe2, 0xfb, 0x41, 0x5a, 0x77, 0xe0, 0x66, 0x67, 0x58, 0xc9, 0xb4, 0xd3, 0xd9, 0x77, 0xb9, 0x83,
+ 0x19, 0x08, 0x5f, 0xbc, 0xbd, 0xfb, 0xd5, 0x88, 0xed, 0x1e, 0x1a, 0xda, 0xfe, 0xa1, 0xa1, 0x7d,
+ 0x39, 0x34, 0xb4, 0xd7, 0x47, 0x46, 0x6c, 0xff, 0xc8, 0x88, 0x7d, 0x3c, 0x32, 0x62, 0xcf, 0xfe,
+ 0x3b, 0x61, 0x8a, 0x12, 0x65, 0xc1, 0x4a, 0xfb, 0xc3, 0x5b, 0xb5, 0xb7, 0xe4, 0x07, 0x58, 0x18,
+ 0xa3, 0x32, 0x2a, 0x66, 0xc3, 0xf5, 0x1f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x55, 0xf8, 0x5e, 0x18,
+ 0x1f, 0x08, 0x00, 0x00,
+}
+
+func (m *StoreCodeAuthorization) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalToSizedBuffer(dAtA[:size])
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *StoreCodeAuthorization) MarshalTo(dAtA []byte) (int, error) {
+ size := m.Size()
+ return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *StoreCodeAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+ i := len(dAtA)
+ _ = i
+ var l int
+ _ = l
+ if len(m.Grants) > 0 {
+ for iNdEx := len(m.Grants) - 1; iNdEx >= 0; iNdEx-- {
+ {
+ size, err := m.Grants[iNdEx].MarshalToSizedBuffer(dAtA[:i])
+ if err != nil {
+ return 0, err
+ }
+ i -= size
+ i = encodeVarintAuthz(dAtA, i, uint64(size))
+ }
+ i--
+ dAtA[i] = 0xa
+ }
+ }
+ return len(dAtA) - i, nil
}
func (m *ContractExecutionAuthorization) Marshal() (dAtA []byte, err error) {
@@ -580,6 +720,48 @@ func (m *ContractMigrationAuthorization) MarshalToSizedBuffer(dAtA []byte) (int,
return len(dAtA) - i, nil
}
+func (m *CodeGrant) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalToSizedBuffer(dAtA[:size])
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *CodeGrant) MarshalTo(dAtA []byte) (int, error) {
+ size := m.Size()
+ return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *CodeGrant) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+ i := len(dAtA)
+ _ = i
+ var l int
+ _ = l
+ if m.InstantiatePermission != nil {
+ {
+ size, err := m.InstantiatePermission.MarshalToSizedBuffer(dAtA[:i])
+ if err != nil {
+ return 0, err
+ }
+ i -= size
+ i = encodeVarintAuthz(dAtA, i, uint64(size))
+ }
+ i--
+ dAtA[i] = 0x12
+ }
+ if len(m.CodeHash) > 0 {
+ i -= len(m.CodeHash)
+ copy(dAtA[i:], m.CodeHash)
+ i = encodeVarintAuthz(dAtA, i, uint64(len(m.CodeHash)))
+ i--
+ dAtA[i] = 0xa
+ }
+ return len(dAtA) - i, nil
+}
+
func (m *ContractGrant) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -840,6 +1022,21 @@ func encodeVarintAuthz(dAtA []byte, offset int, v uint64) int {
return base
}
+func (m *StoreCodeAuthorization) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ if len(m.Grants) > 0 {
+ for _, e := range m.Grants {
+ l = e.Size()
+ n += 1 + l + sovAuthz(uint64(l))
+ }
+ }
+ return n
+}
+
func (m *ContractExecutionAuthorization) Size() (n int) {
if m == nil {
return 0
@@ -870,6 +1067,23 @@ func (m *ContractMigrationAuthorization) Size() (n int) {
return n
}
+func (m *CodeGrant) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = len(m.CodeHash)
+ if l > 0 {
+ n += 1 + l + sovAuthz(uint64(l))
+ }
+ if m.InstantiatePermission != nil {
+ l = m.InstantiatePermission.Size()
+ n += 1 + l + sovAuthz(uint64(l))
+ }
+ return n
+}
+
func (m *ContractGrant) Size() (n int) {
if m == nil {
return 0
@@ -983,6 +1197,91 @@ func sozAuthz(x uint64) (n int) {
return sovAuthz(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
+func (m *StoreCodeAuthorization) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowAuthz
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: StoreCodeAuthorization: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: StoreCodeAuthorization: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Grants", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowAuthz
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthAuthz
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthAuthz
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Grants = append(m.Grants, CodeGrant{})
+ if err := m.Grants[len(m.Grants)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipAuthz(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if (skippy < 0) || (iNdEx+skippy) < 0 {
+ return ErrInvalidLengthAuthz
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+
func (m *ContractExecutionAuthorization) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
@@ -1153,6 +1452,127 @@ func (m *ContractMigrationAuthorization) Unmarshal(dAtA []byte) error {
return nil
}
+func (m *CodeGrant) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowAuthz
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: CodeGrant: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: CodeGrant: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field CodeHash", wireType)
+ }
+ var byteLen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowAuthz
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ byteLen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if byteLen < 0 {
+ return ErrInvalidLengthAuthz
+ }
+ postIndex := iNdEx + byteLen
+ if postIndex < 0 {
+ return ErrInvalidLengthAuthz
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.CodeHash = append(m.CodeHash[:0], dAtA[iNdEx:postIndex]...)
+ if m.CodeHash == nil {
+ m.CodeHash = []byte{}
+ }
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field InstantiatePermission", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowAuthz
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthAuthz
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthAuthz
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if m.InstantiatePermission == nil {
+ m.InstantiatePermission = &AccessConfig{}
+ }
+ if err := m.InstantiatePermission.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipAuthz(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if (skippy < 0) || (iNdEx+skippy) < 0 {
+ return ErrInvalidLengthAuthz
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+
func (m *ContractGrant) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
diff --git a/x/wasm/types/authz_test.go b/x/wasm/types/authz_test.go
index b02abea936..65667218b9 100644
--- a/x/wasm/types/authz_test.go
+++ b/x/wasm/types/authz_test.go
@@ -2,8 +2,10 @@ package types
import (
"math"
+ "strings"
"testing"
+ wasmvm "github.com/CosmWasm/wasmvm"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -397,20 +399,17 @@ func TestValidateContractGrant(t *testing.T) {
}{
"all good": {
setup: func(t *testing.T) ContractGrant {
- t.Helper()
return mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(1), NewAllowAllMessagesFilter())
},
},
"invalid address": {
setup: func(t *testing.T) ContractGrant {
- t.Helper()
return mustGrant([]byte{}, NewMaxCallsLimit(1), NewAllowAllMessagesFilter())
},
expErr: true,
},
"invalid limit": {
setup: func(t *testing.T) ContractGrant {
- t.Helper()
return mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(0), NewAllowAllMessagesFilter())
},
expErr: true,
@@ -418,14 +417,12 @@ func TestValidateContractGrant(t *testing.T) {
"invalid filter ": {
setup: func(t *testing.T) ContractGrant {
- t.Helper()
return mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(1), NewAcceptedMessageKeysFilter())
},
expErr: true,
},
"empty limit": {
setup: func(t *testing.T) ContractGrant {
- t.Helper()
r := mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(0), NewAllowAllMessagesFilter())
r.Limit = nil
return r
@@ -435,7 +432,6 @@ func TestValidateContractGrant(t *testing.T) {
"empty filter ": {
setup: func(t *testing.T) ContractGrant {
- t.Helper()
r := mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(1), NewAcceptedMessageKeysFilter())
r.Filter = nil
return r
@@ -444,7 +440,6 @@ func TestValidateContractGrant(t *testing.T) {
},
"wrong limit type": {
setup: func(t *testing.T) ContractGrant {
- t.Helper()
r := mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(0), NewAllowAllMessagesFilter())
r.Limit = r.Filter
return r
@@ -454,7 +449,6 @@ func TestValidateContractGrant(t *testing.T) {
"wrong filter type": {
setup: func(t *testing.T) ContractGrant {
- t.Helper()
r := mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(1), NewAcceptedMessageKeysFilter())
r.Filter = r.Limit
return r
@@ -487,52 +481,44 @@ func TestValidateContractAuthorization(t *testing.T) {
}{
"contract execution": {
setup: func(t *testing.T) validatable {
- t.Helper()
- return NewContractMigrationAuthorization(*validGrant)
+ return NewContractExecutionAuthorization(*validGrant)
},
},
"contract execution - duplicate grants": {
setup: func(t *testing.T) validatable {
- t.Helper()
- return NewContractMigrationAuthorization(*validGrant, *validGrant)
+ return NewContractExecutionAuthorization(*validGrant, *validGrant)
},
},
"contract execution - invalid grant": {
setup: func(t *testing.T) validatable {
- t.Helper()
- return NewContractMigrationAuthorization(*validGrant, *invalidGrant)
+ return NewContractExecutionAuthorization(*validGrant, *invalidGrant)
},
expErr: true,
},
"contract execution - empty grants": {
setup: func(t *testing.T) validatable {
- t.Helper()
- return NewContractMigrationAuthorization()
+ return NewContractExecutionAuthorization()
},
expErr: true,
},
"contract migration": {
setup: func(t *testing.T) validatable {
- t.Helper()
return NewContractMigrationAuthorization(*validGrant)
},
},
"contract migration - duplicate grants": {
setup: func(t *testing.T) validatable {
- t.Helper()
return NewContractMigrationAuthorization(*validGrant, *validGrant)
},
},
"contract migration - invalid grant": {
setup: func(t *testing.T) validatable {
- t.Helper()
return NewContractMigrationAuthorization(*validGrant, *invalidGrant)
},
expErr: true,
},
"contract migration - empty grant": {
setup: func(t *testing.T) validatable {
- t.Helper()
return NewContractMigrationAuthorization()
},
expErr: true,
@@ -744,3 +730,243 @@ func mustGrant(contract sdk.AccAddress, limit ContractAuthzLimitX, filter Contra
}
return *g
}
+
+func TestValidateCodeGrant(t *testing.T) {
+ specs := map[string]struct {
+ codeHash []byte
+ instantiatePermission *AccessConfig
+ expErr bool
+ }{
+ "all good": {
+ codeHash: []byte("any_valid_checksum"),
+ instantiatePermission: &AllowEverybody,
+ },
+ "empty permission": {
+ codeHash: []byte("any_valid_checksum"),
+ expErr: false,
+ },
+ "empty code hash": {
+ codeHash: []byte{},
+ instantiatePermission: &AllowEverybody,
+ expErr: true,
+ },
+ "nil code hash": {
+ codeHash: nil,
+ instantiatePermission: &AllowEverybody,
+ expErr: true,
+ },
+ "invalid permission": {
+ codeHash: []byte("any_valid_checksum"),
+ instantiatePermission: &AccessConfig{Permission: AccessTypeUnspecified},
+ expErr: true,
+ },
+ }
+ for name, spec := range specs {
+ t.Run(name, func(t *testing.T) {
+ grant, err := NewCodeGrant(spec.codeHash, spec.instantiatePermission)
+ require.NoError(t, err)
+
+ gotErr := grant.ValidateBasic()
+ if spec.expErr {
+ require.Error(t, gotErr)
+ return
+ }
+ require.NoError(t, gotErr)
+ })
+ }
+}
+
+func TestValidateStoreCodeAuthorization(t *testing.T) {
+ validGrant, err := NewCodeGrant([]byte("any_valid_checksum"), &AllowEverybody)
+ require.NoError(t, err)
+ validGrantUpperCase, err := NewCodeGrant([]byte("ANY_VALID_CHECKSUM"), &AllowEverybody)
+ require.NoError(t, err)
+ invalidGrant, err := NewCodeGrant(nil, &AllowEverybody)
+ require.NoError(t, err)
+ wildcardGrant, err := NewCodeGrant([]byte("*"), &AllowEverybody)
+ require.NoError(t, err)
+ emptyPermissionGrant, err := NewCodeGrant([]byte("any_valid_checksum"), nil)
+ require.NoError(t, err)
+
+ specs := map[string]struct {
+ setup func(t *testing.T) []CodeGrant
+ expErr bool
+ }{
+ "all good": {
+ setup: func(t *testing.T) []CodeGrant {
+ return []CodeGrant{*validGrant}
+ },
+ },
+ "wildcard grant": {
+ setup: func(t *testing.T) []CodeGrant {
+ return []CodeGrant{*wildcardGrant}
+ },
+ },
+ "empty permission grant": {
+ setup: func(t *testing.T) []CodeGrant {
+ return []CodeGrant{*emptyPermissionGrant}
+ },
+ },
+ "duplicate grants - wildcard": {
+ setup: func(t *testing.T) []CodeGrant {
+ return []CodeGrant{*wildcardGrant, *validGrant}
+ },
+ expErr: true,
+ },
+ "duplicate grants - same case code hash": {
+ setup: func(t *testing.T) []CodeGrant {
+ return []CodeGrant{*validGrant, *validGrant}
+ },
+ expErr: true,
+ },
+ "duplicate grants - different case code hash": {
+ setup: func(t *testing.T) []CodeGrant {
+ return []CodeGrant{*validGrant, *validGrantUpperCase}
+ },
+ expErr: true,
+ },
+ "invalid grant": {
+ setup: func(t *testing.T) []CodeGrant {
+ return []CodeGrant{*validGrant, *invalidGrant}
+ },
+ expErr: true,
+ },
+ "empty grants": {
+ setup: func(t *testing.T) []CodeGrant {
+ return []CodeGrant{}
+ },
+ expErr: true,
+ },
+ }
+ for name, spec := range specs {
+ t.Run(name, func(t *testing.T) {
+ gotErr := NewStoreCodeAuthorization(spec.setup(t)...).ValidateBasic()
+ if spec.expErr {
+ require.Error(t, gotErr)
+ return
+ }
+ require.NoError(t, gotErr)
+ })
+ }
+}
+
+func TestStoreCodeAuthorizationAccept(t *testing.T) {
+ reflectCodeHash, err := wasmvm.CreateChecksum(reflectWasmCode)
+ require.NoError(t, err)
+
+ reflectCodeHashUpperCase := strings.ToUpper(string(reflectCodeHash))
+
+ grantWildcard, err := NewCodeGrant([]byte("*"), &AllowEverybody)
+ require.NoError(t, err)
+
+ grantReflectCode, err := NewCodeGrant(reflectCodeHash, &AllowNobody)
+ require.NoError(t, err)
+
+ grantReflectCodeUpperCase, err := NewCodeGrant([]byte(reflectCodeHashUpperCase), &AllowNobody)
+ require.NoError(t, err)
+
+ grantOtherCode, err := NewCodeGrant([]byte("any_valid_checksum"), &AllowEverybody)
+ require.NoError(t, err)
+
+ emptyPermissionReflectCodeGrant, err := NewCodeGrant(reflectCodeHash, nil)
+ require.NoError(t, err)
+
+ specs := map[string]struct {
+ auth authztypes.Authorization
+ msg sdk.Msg
+ expResult authztypes.AcceptResponse
+ expErr *errorsmod.Error
+ }{
+ "accepted wildcard": {
+ auth: NewStoreCodeAuthorization(*grantWildcard),
+ msg: &MsgStoreCode{
+ Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(),
+ WASMByteCode: reflectWasmCode,
+ InstantiatePermission: &AllowEverybody,
+ },
+ expResult: authztypes.AcceptResponse{
+ Accept: true,
+ },
+ },
+ "accepted reflect code": {
+ auth: NewStoreCodeAuthorization(*grantReflectCode),
+ msg: &MsgStoreCode{
+ Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(),
+ WASMByteCode: reflectWasmCode,
+ InstantiatePermission: &AllowNobody,
+ },
+ expResult: authztypes.AcceptResponse{
+ Accept: true,
+ },
+ },
+ "accepted reflect code - empty permission": {
+ auth: NewStoreCodeAuthorization(*emptyPermissionReflectCodeGrant),
+ msg: &MsgStoreCode{
+ Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(),
+ WASMByteCode: reflectWasmCode,
+ InstantiatePermission: &AllowNobody,
+ },
+ expResult: authztypes.AcceptResponse{
+ Accept: true,
+ },
+ },
+ "accepted reflect code - different case": {
+ auth: NewStoreCodeAuthorization(*grantReflectCodeUpperCase),
+ msg: &MsgStoreCode{
+ Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(),
+ WASMByteCode: reflectWasmCode,
+ InstantiatePermission: &AllowNobody,
+ },
+ expResult: authztypes.AcceptResponse{
+ Accept: true,
+ },
+ },
+ "not accepted - no matching code": {
+ auth: NewStoreCodeAuthorization(*grantOtherCode),
+ msg: &MsgStoreCode{
+ Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(),
+ WASMByteCode: reflectWasmCode,
+ InstantiatePermission: &AllowEverybody,
+ },
+ expResult: authztypes.AcceptResponse{
+ Accept: false,
+ },
+ },
+ "not accepted - no matching permission": {
+ auth: NewStoreCodeAuthorization(*grantReflectCode),
+ msg: &MsgStoreCode{
+ Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(),
+ WASMByteCode: reflectWasmCode,
+ InstantiatePermission: &AllowEverybody,
+ },
+ expResult: authztypes.AcceptResponse{
+ Accept: false,
+ },
+ },
+ "invalid msg type": {
+ auth: NewStoreCodeAuthorization(*grantWildcard),
+ msg: &MsgMigrateContract{
+ Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(),
+ Contract: sdk.AccAddress(randBytes(SDKAddrLen)).String(),
+ CodeID: 1,
+ Msg: []byte(`{"foo":"bar"}`),
+ },
+ expResult: authztypes.AcceptResponse{
+ Accept: false,
+ },
+ expErr: sdkerrors.ErrInvalidRequest,
+ },
+ }
+ for name, spec := range specs {
+ t.Run(name, func(t *testing.T) {
+ ctx := sdk.Context{}.WithGasMeter(sdk.NewInfiniteGasMeter())
+ gotResult, gotErr := spec.auth.Accept(ctx, spec.msg)
+ if spec.expErr != nil {
+ require.ErrorIs(t, gotErr, spec.expErr)
+ return
+ }
+ require.NoError(t, gotErr)
+ assert.Equal(t, spec.expResult, gotResult)
+ })
+ }
+}
diff --git a/x/wasm/types/codec.go b/x/wasm/types/codec.go
index 073a7a1494..3b0a823623 100644
--- a/x/wasm/types/codec.go
+++ b/x/wasm/types/codec.go
@@ -57,6 +57,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
cdc.RegisterConcrete(&MaxFundsLimit{}, "wasm/MaxFundsLimit", nil)
cdc.RegisterConcrete(&CombinedLimit{}, "wasm/CombinedLimit", nil)
+ cdc.RegisterConcrete(&StoreCodeAuthorization{}, "wasm/StoreCodeAuthorization", nil)
cdc.RegisterConcrete(&ContractExecutionAuthorization{}, "wasm/ContractExecutionAuthorization", nil)
cdc.RegisterConcrete(&ContractMigrationAuthorization{}, "wasm/ContractMigrationAuthorization", nil)
}
@@ -119,6 +120,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterImplementations(
(*authz.Authorization)(nil),
+ &StoreCodeAuthorization{},
&ContractExecutionAuthorization{},
&ContractMigrationAuthorization{},
)
diff --git a/x/wasm/types/context.go b/x/wasm/types/context.go
index 0463e3ae1a..006e397624 100644
--- a/x/wasm/types/context.go
+++ b/x/wasm/types/context.go
@@ -14,6 +14,8 @@ const (
contextKeyQueryStackSize contextKey = iota
// authorization policy for sub-messages
contextKeySubMsgAuthzPolicy = iota
+ // gas register
+ contextKeyGasRegister = iota
)
// WithTXCounter stores a transaction counter value in the context
@@ -52,3 +54,17 @@ func SubMsgAuthzPolicy(ctx sdk.Context) (AuthorizationPolicy, bool) {
val, ok := ctx.Value(contextKeySubMsgAuthzPolicy).(AuthorizationPolicy)
return val, ok
}
+
+// WithGasRegister stores the gas register into the context returned
+func WithGasRegister(ctx sdk.Context, gr GasRegister) sdk.Context {
+ if gr == nil {
+ panic("gas register must not be nil")
+ }
+ return ctx.WithValue(contextKeyGasRegister, gr)
+}
+
+// GasRegisterFromContext reads the gas register from the context
+func GasRegisterFromContext(ctx sdk.Context) (GasRegister, bool) {
+ val, ok := ctx.Value(contextKeyGasRegister).(GasRegister)
+ return val, ok
+}
diff --git a/x/wasm/keeper/gas_register.go b/x/wasm/types/gas_register.go
similarity index 97%
rename from x/wasm/keeper/gas_register.go
rename to x/wasm/types/gas_register.go
index 6ae95d874c..da5e989149 100644
--- a/x/wasm/keeper/gas_register.go
+++ b/x/wasm/types/gas_register.go
@@ -1,4 +1,4 @@
-package keeper
+package types
import (
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
@@ -8,8 +8,6 @@ import (
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
-
- "github.com/CosmWasm/wasmd/x/wasm/types"
)
const (
@@ -162,7 +160,7 @@ func (g WasmGasRegister) NewContractInstanceCosts(pinned bool, msgLen int) store
// CompileCosts costs to persist and "compile" a new wasm contract
func (g WasmGasRegister) CompileCosts(byteLength int) storetypes.Gas {
if byteLength < 0 {
- panic(errorsmod.Wrap(types.ErrInvalid, "negative length"))
+ panic(errorsmod.Wrap(ErrInvalid, "negative length"))
}
return g.c.CompileCost * uint64(byteLength)
}
@@ -170,7 +168,7 @@ func (g WasmGasRegister) CompileCosts(byteLength int) storetypes.Gas {
// UncompressCosts costs to unpack a new wasm contract
func (g WasmGasRegister) UncompressCosts(byteLength int) sdk.Gas {
if byteLength < 0 {
- panic(errorsmod.Wrap(types.ErrInvalid, "negative length"))
+ panic(errorsmod.Wrap(ErrInvalid, "negative length"))
}
return g.c.UncompressCost.Mul(uint64(byteLength)).Floor()
}
@@ -178,7 +176,7 @@ func (g WasmGasRegister) UncompressCosts(byteLength int) sdk.Gas {
// InstantiateContractCosts costs when interacting with a wasm contract
func (g WasmGasRegister) InstantiateContractCosts(pinned bool, msgLen int) sdk.Gas {
if msgLen < 0 {
- panic(errorsmod.Wrap(types.ErrInvalid, "negative length"))
+ panic(errorsmod.Wrap(ErrInvalid, "negative length"))
}
dataCosts := sdk.Gas(msgLen) * g.c.ContractMessageDataCost
if pinned {
diff --git a/x/wasm/keeper/gas_register_test.go b/x/wasm/types/gas_register_test.go
similarity index 99%
rename from x/wasm/keeper/gas_register_test.go
rename to x/wasm/types/gas_register_test.go
index 521ff17cc5..34155d4784 100644
--- a/x/wasm/keeper/gas_register_test.go
+++ b/x/wasm/types/gas_register_test.go
@@ -1,4 +1,4 @@
-package keeper
+package types
import (
"math"
@@ -10,8 +10,6 @@ import (
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
-
- "github.com/CosmWasm/wasmd/x/wasm/types"
)
func TestCompileCosts(t *testing.T) {
@@ -452,7 +450,7 @@ func TestUncompressCosts(t *testing.T) {
exp: 2,
},
"max len": {
- lenIn: types.MaxWasmSize,
+ lenIn: MaxWasmSize,
exp: 122880,
},
"invalid len": {