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": {