implement x/authz module (#7629)

* WIP: Msg authorization module added

* fixing errors

* fixed errors

* fixed module.go

* Add msg_tests

* fixes compile issues

* fix test

* fix test

* Add msg types tests

* Fix Getmsgs

* fixed codec issue

* Fix syntax issues

* Fix keeper

* fixed proto issues

* Fix keeper tests

* fixed router in keeper

* Fix query proto

* Fix cli txs

* Add grpc query client implementation

* Add grpc-keeper test

* Add grpc query tests
Add revoke and exec authorization cli commands

* Fix linting issues

* Fix cli query

* fix lint errors

* Add Genesis state

* Fix query authorization

* Review changes

* Fix grant authorization handler

* Add cli tests

* Add cli tests

* Fix genesis test

* Fix issues

* update module to use proto msg services

* Add simultion tests

* Fix lint

* fix lint

* WIP simulations

* WIP simulations

* add msg tests

* Fix simulation

* Fix errors

* fix genesis import export

* fix sim tests

* fix sim

* fix test

* Register RegisterMsgServer

* WIP

* WIP

* Update keeper test

* change msg_authorization module name to authz

* changed type conversion for serviceMsg

* serviceMsg change to any

* Fix issues

* fix msg tests

* fix errors

* proto format

* remove LegacyQuerierHandler

* Use MsgServiceRouter

* fix keeper-test

* fix query authorizations

* fix NewCmdSendAs

* fix simtests

* fix error

* fix lint

* fix lint

* add tests for generic authorization

* fix imports

* format

* Update error message

* remove println

* add query all grants

* Add pagination for queries

* format

* fix lint

* review changes

* fix grpc tests

* add pagination to cli query

* review changes

* replace panic with error

* lint

* fix errors

* fix tests

* remove gogoproto extensions

* update function doc

* review changes

* fix errors

* fix query flags

* fix grpc query test

* init service-msg

* remove unsed field

* add proto-codec for simulations

* fix codec issue

* update authz simulations

* change msgauth to authz

* add check for invalid msg-type

* change expiration flag to Unix

* doc

* update module.go

* fix sims

* fix grant-authorization sims

* fix error

* fix error

* add build flag

* fix codec issue

* rename

* review changes

* format

* review changes

* go.mod

* refactor

* proto-gen

* Update x/authz/keeper/grpc_query_test.go

Co-authored-by: Amaury <amaury.martiny@protonmail.com>

* Update x/authz/keeper/grpc_query_test.go

Co-authored-by: Amaury <amaury.martiny@protonmail.com>

* Update x/authz/keeper/grpc_query_test.go

Co-authored-by: Amaury <amaury.martiny@protonmail.com>

* Fix review comments

* fix protogen

* Follow Msg...Request style for msg requests

* update comment

* Fix error codes

* fix review comment

* improve msg validations

* Handle error in casting msgs

* rename actor => grantStoreKey

* add godoc

* add godoc

* Fix simulations

* Fix cli, cli_tests

* Fix simulations

* rename to GetOrRevokeAuthorization

* Move events to keeper

* Fix fmt

* Update x/authz/client/cli/tx.go

Co-authored-by: Amaury <amaury.martiny@protonmail.com>

* rename actor

* fix lint

Co-authored-by: atheesh <atheesh@vitwit.com>
Co-authored-by: atheeshp <59333759+atheeshp@users.noreply.github.com>
Co-authored-by: Amaury Martiny <amaury.martiny@protonmail.com>
Co-authored-by: MD Aleem <72057206+aleem1413@users.noreply.github.com>
Co-authored-by: Anil Kumar Kammari <anil@vitwit.com>
This commit is contained in:
MD Aleem 2021-01-25 22:11:30 +05:30 committed by GitHub
parent bdd7fa9712
commit c95de9c417
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 9322 additions and 337 deletions

View File

@ -26,6 +26,49 @@
- [DecProto](#cosmos.base.v1beta1.DecProto)
- [IntProto](#cosmos.base.v1beta1.IntProto)
- [cosmos/authz/v1beta1/authz.proto](#cosmos/authz/v1beta1/authz.proto)
- [AuthorizationGrant](#cosmos.authz.v1beta1.AuthorizationGrant)
- [GenericAuthorization](#cosmos.authz.v1beta1.GenericAuthorization)
- [SendAuthorization](#cosmos.authz.v1beta1.SendAuthorization)
- [cosmos/base/abci/v1beta1/abci.proto](#cosmos/base/abci/v1beta1/abci.proto)
- [ABCIMessageLog](#cosmos.base.abci.v1beta1.ABCIMessageLog)
- [Attribute](#cosmos.base.abci.v1beta1.Attribute)
- [GasInfo](#cosmos.base.abci.v1beta1.GasInfo)
- [MsgData](#cosmos.base.abci.v1beta1.MsgData)
- [Result](#cosmos.base.abci.v1beta1.Result)
- [SearchTxsResult](#cosmos.base.abci.v1beta1.SearchTxsResult)
- [SimulationResponse](#cosmos.base.abci.v1beta1.SimulationResponse)
- [StringEvent](#cosmos.base.abci.v1beta1.StringEvent)
- [TxMsgData](#cosmos.base.abci.v1beta1.TxMsgData)
- [TxResponse](#cosmos.base.abci.v1beta1.TxResponse)
- [cosmos/authz/v1beta1/tx.proto](#cosmos/authz/v1beta1/tx.proto)
- [MsgExecAuthorizedRequest](#cosmos.authz.v1beta1.MsgExecAuthorizedRequest)
- [MsgExecAuthorizedResponse](#cosmos.authz.v1beta1.MsgExecAuthorizedResponse)
- [MsgGrantAuthorizationRequest](#cosmos.authz.v1beta1.MsgGrantAuthorizationRequest)
- [MsgGrantAuthorizationResponse](#cosmos.authz.v1beta1.MsgGrantAuthorizationResponse)
- [MsgRevokeAuthorizationRequest](#cosmos.authz.v1beta1.MsgRevokeAuthorizationRequest)
- [MsgRevokeAuthorizationResponse](#cosmos.authz.v1beta1.MsgRevokeAuthorizationResponse)
- [Msg](#cosmos.authz.v1beta1.Msg)
- [cosmos/authz/v1beta1/genesis.proto](#cosmos/authz/v1beta1/genesis.proto)
- [GenesisState](#cosmos.authz.v1beta1.GenesisState)
- [GrantAuthorization](#cosmos.authz.v1beta1.GrantAuthorization)
- [cosmos/base/query/v1beta1/pagination.proto](#cosmos/base/query/v1beta1/pagination.proto)
- [PageRequest](#cosmos.base.query.v1beta1.PageRequest)
- [PageResponse](#cosmos.base.query.v1beta1.PageResponse)
- [cosmos/authz/v1beta1/query.proto](#cosmos/authz/v1beta1/query.proto)
- [QueryAuthorizationRequest](#cosmos.authz.v1beta1.QueryAuthorizationRequest)
- [QueryAuthorizationResponse](#cosmos.authz.v1beta1.QueryAuthorizationResponse)
- [QueryAuthorizationsRequest](#cosmos.authz.v1beta1.QueryAuthorizationsRequest)
- [QueryAuthorizationsResponse](#cosmos.authz.v1beta1.QueryAuthorizationsResponse)
- [Query](#cosmos.authz.v1beta1.Query)
- [cosmos/bank/v1beta1/bank.proto](#cosmos/bank/v1beta1/bank.proto)
- [DenomUnit](#cosmos.bank.v1beta1.DenomUnit)
- [Input](#cosmos.bank.v1beta1.Input)
@ -39,10 +82,6 @@
- [Balance](#cosmos.bank.v1beta1.Balance)
- [GenesisState](#cosmos.bank.v1beta1.GenesisState)
- [cosmos/base/query/v1beta1/pagination.proto](#cosmos/base/query/v1beta1/pagination.proto)
- [PageRequest](#cosmos.base.query.v1beta1.PageRequest)
- [PageResponse](#cosmos.base.query.v1beta1.PageResponse)
- [cosmos/bank/v1beta1/query.proto](#cosmos/bank/v1beta1/query.proto)
- [QueryAllBalancesRequest](#cosmos.bank.v1beta1.QueryAllBalancesRequest)
- [QueryAllBalancesResponse](#cosmos.bank.v1beta1.QueryAllBalancesResponse)
@ -69,18 +108,6 @@
- [Msg](#cosmos.bank.v1beta1.Msg)
- [cosmos/base/abci/v1beta1/abci.proto](#cosmos/base/abci/v1beta1/abci.proto)
- [ABCIMessageLog](#cosmos.base.abci.v1beta1.ABCIMessageLog)
- [Attribute](#cosmos.base.abci.v1beta1.Attribute)
- [GasInfo](#cosmos.base.abci.v1beta1.GasInfo)
- [MsgData](#cosmos.base.abci.v1beta1.MsgData)
- [Result](#cosmos.base.abci.v1beta1.Result)
- [SearchTxsResult](#cosmos.base.abci.v1beta1.SearchTxsResult)
- [SimulationResponse](#cosmos.base.abci.v1beta1.SimulationResponse)
- [StringEvent](#cosmos.base.abci.v1beta1.StringEvent)
- [TxMsgData](#cosmos.base.abci.v1beta1.TxMsgData)
- [TxResponse](#cosmos.base.abci.v1beta1.TxResponse)
- [cosmos/base/kv/v1beta1/kv.proto](#cosmos/base/kv/v1beta1/kv.proto)
- [Pair](#cosmos.base.kv.v1beta1.Pair)
- [Pairs](#cosmos.base.kv.v1beta1.Pairs)
@ -960,6 +987,589 @@ IntProto defines a Protobuf wrapper around an Int object.
<a name="cosmos/authz/v1beta1/authz.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/authz/v1beta1/authz.proto
<a name="cosmos.authz.v1beta1.AuthorizationGrant"></a>
### AuthorizationGrant
AuthorizationGrant gives permissions to execute
the provide method with expiration time.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `authorization` | [google.protobuf.Any](#google.protobuf.Any) | | |
| `expiration` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | |
<a name="cosmos.authz.v1beta1.GenericAuthorization"></a>
### GenericAuthorization
GenericAuthorization gives the grantee unrestricted permissions to execute
the provided method on behalf of the granter's account.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `method_name` | [string](#string) | | method name to grant unrestricted permissions to execute Note: MethodName() is already a method on `GenericAuthorization` type, we need some custom naming here so using `MessageName` |
<a name="cosmos.authz.v1beta1.SendAuthorization"></a>
### SendAuthorization
SendAuthorization allows the grantee to spend up to spend_limit coins from
the granter's account.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `spend_limit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | |
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<!-- end services -->
<a name="cosmos/base/abci/v1beta1/abci.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/base/abci/v1beta1/abci.proto
<a name="cosmos.base.abci.v1beta1.ABCIMessageLog"></a>
### ABCIMessageLog
ABCIMessageLog defines a structure containing an indexed tx ABCI message log.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `msg_index` | [uint32](#uint32) | | |
| `log` | [string](#string) | | |
| `events` | [StringEvent](#cosmos.base.abci.v1beta1.StringEvent) | repeated | Events contains a slice of Event objects that were emitted during some execution. |
<a name="cosmos.base.abci.v1beta1.Attribute"></a>
### Attribute
Attribute defines an attribute wrapper where the key and value are
strings instead of raw bytes.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `key` | [string](#string) | | |
| `value` | [string](#string) | | |
<a name="cosmos.base.abci.v1beta1.GasInfo"></a>
### GasInfo
GasInfo defines tx execution gas context.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `gas_wanted` | [uint64](#uint64) | | GasWanted is the maximum units of work we allow this tx to perform. |
| `gas_used` | [uint64](#uint64) | | GasUsed is the amount of gas actually consumed. |
<a name="cosmos.base.abci.v1beta1.MsgData"></a>
### MsgData
MsgData defines the data returned in a Result object during message
execution.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `msg_type` | [string](#string) | | |
| `data` | [bytes](#bytes) | | |
<a name="cosmos.base.abci.v1beta1.Result"></a>
### Result
Result is the union of ResponseFormat and ResponseCheckTx.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `data` | [bytes](#bytes) | | Data is any data returned from message or handler execution. It MUST be length prefixed in order to separate data from multiple message executions. |
| `log` | [string](#string) | | Log contains the log information from message or handler execution. |
| `events` | [tendermint.abci.Event](#tendermint.abci.Event) | repeated | Events contains a slice of Event objects that were emitted during message or handler execution. |
<a name="cosmos.base.abci.v1beta1.SearchTxsResult"></a>
### SearchTxsResult
SearchTxsResult defines a structure for querying txs pageable
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `total_count` | [uint64](#uint64) | | Count of all txs |
| `count` | [uint64](#uint64) | | Count of txs in current page |
| `page_number` | [uint64](#uint64) | | Index of current page, start from 1 |
| `page_total` | [uint64](#uint64) | | Count of total pages |
| `limit` | [uint64](#uint64) | | Max count txs per page |
| `txs` | [TxResponse](#cosmos.base.abci.v1beta1.TxResponse) | repeated | List of txs in current page |
<a name="cosmos.base.abci.v1beta1.SimulationResponse"></a>
### SimulationResponse
SimulationResponse defines the response generated when a transaction is
successfully simulated.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `gas_info` | [GasInfo](#cosmos.base.abci.v1beta1.GasInfo) | | |
| `result` | [Result](#cosmos.base.abci.v1beta1.Result) | | |
<a name="cosmos.base.abci.v1beta1.StringEvent"></a>
### StringEvent
StringEvent defines en Event object wrapper where all the attributes
contain key/value pairs that are strings instead of raw bytes.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `type` | [string](#string) | | |
| `attributes` | [Attribute](#cosmos.base.abci.v1beta1.Attribute) | repeated | |
<a name="cosmos.base.abci.v1beta1.TxMsgData"></a>
### TxMsgData
TxMsgData defines a list of MsgData. A transaction will have a MsgData object
for each message.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `data` | [MsgData](#cosmos.base.abci.v1beta1.MsgData) | repeated | |
<a name="cosmos.base.abci.v1beta1.TxResponse"></a>
### TxResponse
TxResponse defines a structure containing relevant tx data and metadata. The
tags are stringified and the log is JSON decoded.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `height` | [int64](#int64) | | The block height |
| `txhash` | [string](#string) | | The transaction hash. |
| `codespace` | [string](#string) | | Namespace for the Code |
| `code` | [uint32](#uint32) | | Response code. |
| `data` | [string](#string) | | Result bytes, if any. |
| `raw_log` | [string](#string) | | The output of the application's logger (raw string). May be non-deterministic. |
| `logs` | [ABCIMessageLog](#cosmos.base.abci.v1beta1.ABCIMessageLog) | repeated | The output of the application's logger (typed). May be non-deterministic. |
| `info` | [string](#string) | | Additional information. May be non-deterministic. |
| `gas_wanted` | [int64](#int64) | | Amount of gas requested for transaction. |
| `gas_used` | [int64](#int64) | | Amount of gas consumed by transaction. |
| `tx` | [google.protobuf.Any](#google.protobuf.Any) | | The request transaction bytes. |
| `timestamp` | [string](#string) | | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time. |
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<!-- end services -->
<a name="cosmos/authz/v1beta1/tx.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/authz/v1beta1/tx.proto
<a name="cosmos.authz.v1beta1.MsgExecAuthorizedRequest"></a>
### MsgExecAuthorizedRequest
MsgExecAuthorizedRequest attempts to execute the provided messages using
authorizations granted to the grantee. Each message should have only
one signer corresponding to the granter of the authorization.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `grantee` | [string](#string) | | |
| `msgs` | [google.protobuf.Any](#google.protobuf.Any) | repeated | |
<a name="cosmos.authz.v1beta1.MsgExecAuthorizedResponse"></a>
### MsgExecAuthorizedResponse
MsgExecAuthorizedResponse defines the Msg/MsgExecAuthorizedResponse response type.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `result` | [cosmos.base.abci.v1beta1.Result](#cosmos.base.abci.v1beta1.Result) | | |
<a name="cosmos.authz.v1beta1.MsgGrantAuthorizationRequest"></a>
### MsgGrantAuthorizationRequest
MsgGrantAuthorizationRequest grants the provided authorization to the grantee on the granter's
account with the provided expiration time.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `granter` | [string](#string) | | |
| `grantee` | [string](#string) | | |
| `authorization` | [google.protobuf.Any](#google.protobuf.Any) | | |
| `expiration` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | |
<a name="cosmos.authz.v1beta1.MsgGrantAuthorizationResponse"></a>
### MsgGrantAuthorizationResponse
MsgGrantAuthorizationResponse defines the Msg/MsgGrantAuthorization response type.
<a name="cosmos.authz.v1beta1.MsgRevokeAuthorizationRequest"></a>
### MsgRevokeAuthorizationRequest
MsgRevokeAuthorizationRequest revokes any authorization with the provided sdk.Msg type on the
granter's account with that has been granted to the grantee.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `granter` | [string](#string) | | |
| `grantee` | [string](#string) | | |
| `method_name` | [string](#string) | | |
<a name="cosmos.authz.v1beta1.MsgRevokeAuthorizationResponse"></a>
### MsgRevokeAuthorizationResponse
MsgRevokeAuthorizationResponse defines the Msg/MsgRevokeAuthorizationResponse response type.
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<a name="cosmos.authz.v1beta1.Msg"></a>
### Msg
Msg defines the authz Msg service.
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `GrantAuthorization` | [MsgGrantAuthorizationRequest](#cosmos.authz.v1beta1.MsgGrantAuthorizationRequest) | [MsgGrantAuthorizationResponse](#cosmos.authz.v1beta1.MsgGrantAuthorizationResponse) | GrantAuthorization grants the provided authorization to the grantee on the granter's account with the provided expiration time. | |
| `ExecAuthorized` | [MsgExecAuthorizedRequest](#cosmos.authz.v1beta1.MsgExecAuthorizedRequest) | [MsgExecAuthorizedResponse](#cosmos.authz.v1beta1.MsgExecAuthorizedResponse) | ExecAuthorized attempts to execute the provided messages using authorizations granted to the grantee. Each message should have only one signer corresponding to the granter of the authorization. | |
| `RevokeAuthorization` | [MsgRevokeAuthorizationRequest](#cosmos.authz.v1beta1.MsgRevokeAuthorizationRequest) | [MsgRevokeAuthorizationResponse](#cosmos.authz.v1beta1.MsgRevokeAuthorizationResponse) | RevokeAuthorization revokes any authorization corresponding to the provided method name on the granter's account that has been granted to the grantee. | |
<!-- end services -->
<a name="cosmos/authz/v1beta1/genesis.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/authz/v1beta1/genesis.proto
<a name="cosmos.authz.v1beta1.GenesisState"></a>
### GenesisState
GenesisState defines the authz module's genesis state.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `authorization` | [GrantAuthorization](#cosmos.authz.v1beta1.GrantAuthorization) | repeated | |
<a name="cosmos.authz.v1beta1.GrantAuthorization"></a>
### GrantAuthorization
GrantAuthorization defines the GenesisState/GrantAuthorization type.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `granter` | [string](#string) | | |
| `grantee` | [string](#string) | | |
| `authorization` | [google.protobuf.Any](#google.protobuf.Any) | | |
| `expiration` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | |
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<!-- end services -->
<a name="cosmos/base/query/v1beta1/pagination.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/base/query/v1beta1/pagination.proto
<a name="cosmos.base.query.v1beta1.PageRequest"></a>
### PageRequest
PageRequest is to be embedded in gRPC request messages for efficient
pagination. Ex:
message SomeRequest {
Foo some_parameter = 1;
PageRequest pagination = 2;
}
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `key` | [bytes](#bytes) | | key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set. |
| `offset` | [uint64](#uint64) | | offset is a numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set. |
| `limit` | [uint64](#uint64) | | limit is the total number of results to be returned in the result page. If left empty it will default to a value to be set by each app. |
| `count_total` | [bool](#bool) | | count_total is set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. count_total is only respected when offset is used. It is ignored when key is set. |
<a name="cosmos.base.query.v1beta1.PageResponse"></a>
### PageResponse
PageResponse is to be embedded in gRPC response messages where the
corresponding request message has used PageRequest.
message SomeResponse {
repeated Bar results = 1;
PageResponse page = 2;
}
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `next_key` | [bytes](#bytes) | | next_key is the key to be passed to PageRequest.key to query the next page most efficiently |
| `total` | [uint64](#uint64) | | total is total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<!-- end services -->
<a name="cosmos/authz/v1beta1/query.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/authz/v1beta1/query.proto
<a name="cosmos.authz.v1beta1.QueryAuthorizationRequest"></a>
### QueryAuthorizationRequest
QueryAuthorizationRequest is the request type for the Query/Authorization RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `granter` | [string](#string) | | |
| `grantee` | [string](#string) | | |
| `method_name` | [string](#string) | | |
<a name="cosmos.authz.v1beta1.QueryAuthorizationResponse"></a>
### QueryAuthorizationResponse
QueryAuthorizationResponse is the response type for the Query/Authorization RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `authorization` | [AuthorizationGrant](#cosmos.authz.v1beta1.AuthorizationGrant) | | authorization is a authorization granted for grantee by granter. |
<a name="cosmos.authz.v1beta1.QueryAuthorizationsRequest"></a>
### QueryAuthorizationsRequest
QueryAuthorizationsRequest is the request type for the Query/Authorizations RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `granter` | [string](#string) | | |
| `grantee` | [string](#string) | | |
| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an pagination for the request. |
<a name="cosmos.authz.v1beta1.QueryAuthorizationsResponse"></a>
### QueryAuthorizationsResponse
QueryAuthorizationsResponse is the response type for the Query/Authorizations RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `authorizations` | [AuthorizationGrant](#cosmos.authz.v1beta1.AuthorizationGrant) | repeated | authorizations is a list of grants granted for grantee by granter. |
| `pagination` | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines an pagination for the response. |
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<a name="cosmos.authz.v1beta1.Query"></a>
### Query
Query defines the gRPC querier service.
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `Authorization` | [QueryAuthorizationRequest](#cosmos.authz.v1beta1.QueryAuthorizationRequest) | [QueryAuthorizationResponse](#cosmos.authz.v1beta1.QueryAuthorizationResponse) | Returns any `Authorization` (or `nil`), with the expiration time, granted to the grantee by the granter for the provided msg type. | GET|/cosmos/authz/v1beta1/granters/{granter}/grantees/{grantee}/grant|
| `Authorizations` | [QueryAuthorizationsRequest](#cosmos.authz.v1beta1.QueryAuthorizationsRequest) | [QueryAuthorizationsResponse](#cosmos.authz.v1beta1.QueryAuthorizationsResponse) | Returns list of `Authorization`, granted to the grantee by the granter. | GET|/cosmos/authz/v1beta1/granters/{granter}/grantees/{grantee}/grants|
<!-- end services -->
<a name="cosmos/bank/v1beta1/bank.proto"></a>
<p align="right"><a href="#top">Top</a></p>
@ -1135,68 +1745,6 @@ GenesisState defines the bank module's genesis state.
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<!-- end services -->
<a name="cosmos/base/query/v1beta1/pagination.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/base/query/v1beta1/pagination.proto
<a name="cosmos.base.query.v1beta1.PageRequest"></a>
### PageRequest
PageRequest is to be embedded in gRPC request messages for efficient
pagination. Ex:
message SomeRequest {
Foo some_parameter = 1;
PageRequest pagination = 2;
}
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `key` | [bytes](#bytes) | | key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set. |
| `offset` | [uint64](#uint64) | | offset is a numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set. |
| `limit` | [uint64](#uint64) | | limit is the total number of results to be returned in the result page. If left empty it will default to a value to be set by each app. |
| `count_total` | [bool](#bool) | | count_total is set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. count_total is only respected when offset is used. It is ignored when key is set. |
<a name="cosmos.base.query.v1beta1.PageResponse"></a>
### PageResponse
PageResponse is to be embedded in gRPC response messages where the
corresponding request message has used PageRequest.
message SomeResponse {
repeated Bar results = 1;
PageResponse page = 2;
}
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `next_key` | [bytes](#bytes) | | next_key is the key to be passed to PageRequest.key to query the next page most efficiently |
| `total` | [uint64](#uint64) | | total is total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
<!-- end messages -->
<!-- end enums -->
@ -1528,203 +2076,6 @@ Msg defines the bank Msg service.
<a name="cosmos/base/abci/v1beta1/abci.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/base/abci/v1beta1/abci.proto
<a name="cosmos.base.abci.v1beta1.ABCIMessageLog"></a>
### ABCIMessageLog
ABCIMessageLog defines a structure containing an indexed tx ABCI message log.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `msg_index` | [uint32](#uint32) | | |
| `log` | [string](#string) | | |
| `events` | [StringEvent](#cosmos.base.abci.v1beta1.StringEvent) | repeated | Events contains a slice of Event objects that were emitted during some execution. |
<a name="cosmos.base.abci.v1beta1.Attribute"></a>
### Attribute
Attribute defines an attribute wrapper where the key and value are
strings instead of raw bytes.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `key` | [string](#string) | | |
| `value` | [string](#string) | | |
<a name="cosmos.base.abci.v1beta1.GasInfo"></a>
### GasInfo
GasInfo defines tx execution gas context.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `gas_wanted` | [uint64](#uint64) | | GasWanted is the maximum units of work we allow this tx to perform. |
| `gas_used` | [uint64](#uint64) | | GasUsed is the amount of gas actually consumed. |
<a name="cosmos.base.abci.v1beta1.MsgData"></a>
### MsgData
MsgData defines the data returned in a Result object during message
execution.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `msg_type` | [string](#string) | | |
| `data` | [bytes](#bytes) | | |
<a name="cosmos.base.abci.v1beta1.Result"></a>
### Result
Result is the union of ResponseFormat and ResponseCheckTx.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `data` | [bytes](#bytes) | | Data is any data returned from message or handler execution. It MUST be length prefixed in order to separate data from multiple message executions. |
| `log` | [string](#string) | | Log contains the log information from message or handler execution. |
| `events` | [tendermint.abci.Event](#tendermint.abci.Event) | repeated | Events contains a slice of Event objects that were emitted during message or handler execution. |
<a name="cosmos.base.abci.v1beta1.SearchTxsResult"></a>
### SearchTxsResult
SearchTxsResult defines a structure for querying txs pageable
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `total_count` | [uint64](#uint64) | | Count of all txs |
| `count` | [uint64](#uint64) | | Count of txs in current page |
| `page_number` | [uint64](#uint64) | | Index of current page, start from 1 |
| `page_total` | [uint64](#uint64) | | Count of total pages |
| `limit` | [uint64](#uint64) | | Max count txs per page |
| `txs` | [TxResponse](#cosmos.base.abci.v1beta1.TxResponse) | repeated | List of txs in current page |
<a name="cosmos.base.abci.v1beta1.SimulationResponse"></a>
### SimulationResponse
SimulationResponse defines the response generated when a transaction is
successfully simulated.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `gas_info` | [GasInfo](#cosmos.base.abci.v1beta1.GasInfo) | | |
| `result` | [Result](#cosmos.base.abci.v1beta1.Result) | | |
<a name="cosmos.base.abci.v1beta1.StringEvent"></a>
### StringEvent
StringEvent defines en Event object wrapper where all the attributes
contain key/value pairs that are strings instead of raw bytes.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `type` | [string](#string) | | |
| `attributes` | [Attribute](#cosmos.base.abci.v1beta1.Attribute) | repeated | |
<a name="cosmos.base.abci.v1beta1.TxMsgData"></a>
### TxMsgData
TxMsgData defines a list of MsgData. A transaction will have a MsgData object
for each message.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `data` | [MsgData](#cosmos.base.abci.v1beta1.MsgData) | repeated | |
<a name="cosmos.base.abci.v1beta1.TxResponse"></a>
### TxResponse
TxResponse defines a structure containing relevant tx data and metadata. The
tags are stringified and the log is JSON decoded.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `height` | [int64](#int64) | | The block height |
| `txhash` | [string](#string) | | The transaction hash. |
| `codespace` | [string](#string) | | Namespace for the Code |
| `code` | [uint32](#uint32) | | Response code. |
| `data` | [string](#string) | | Result bytes, if any. |
| `raw_log` | [string](#string) | | The output of the application's logger (raw string). May be non-deterministic. |
| `logs` | [ABCIMessageLog](#cosmos.base.abci.v1beta1.ABCIMessageLog) | repeated | The output of the application's logger (typed). May be non-deterministic. |
| `info` | [string](#string) | | Additional information. May be non-deterministic. |
| `gas_wanted` | [int64](#int64) | | Amount of gas requested for transaction. |
| `gas_used` | [int64](#int64) | | Amount of gas consumed by transaction. |
| `tx` | [google.protobuf.Any](#google.protobuf.Any) | | The request transaction bytes. |
| `timestamp` | [string](#string) | | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time. |
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<!-- end services -->
<a name="cosmos/base/kv/v1beta1/kv.proto"></a>
<p align="right"><a href="#top">Top</a></p>

View File

@ -0,0 +1,37 @@
syntax = "proto3";
package cosmos.authz.v1beta1;
import "cosmos/base/v1beta1/coin.proto";
import "cosmos_proto/cosmos.proto";
import "google/protobuf/timestamp.proto";
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/authz/types";
// SendAuthorization allows the grantee to spend up to spend_limit coins from
// the granter's account.
message SendAuthorization {
option (cosmos_proto.implements_interface) = "Authorization";
repeated cosmos.base.v1beta1.Coin spend_limit = 1
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
}
// GenericAuthorization gives the grantee unrestricted permissions to execute
// the provided method on behalf of the granter's account.
message GenericAuthorization {
option (cosmos_proto.implements_interface) = "Authorization";
// method name to grant unrestricted permissions to execute
// Note: MethodName() is already a method on `GenericAuthorization` type,
// we need some custom naming here so using `MessageName`
string method_name = 1 [(gogoproto.customname) = "MessageName"];
}
// AuthorizationGrant gives permissions to execute
// the provide method with expiration time.
message AuthorizationGrant {
google.protobuf.Any authorization = 1 [(cosmos_proto.accepts_interface) = "Authorization"];
google.protobuf.Timestamp expiration = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
}

View File

@ -0,0 +1,24 @@
syntax = "proto3";
package cosmos.authz.v1beta1;
import "google/protobuf/timestamp.proto";
import "google/protobuf/any.proto";
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/authz/v1beta1/tx.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/authz/types";
// GenesisState defines the authz module's genesis state.
message GenesisState {
repeated GrantAuthorization authorization = 1 [(gogoproto.nullable) = false];
}
// GrantAuthorization defines the GenesisState/GrantAuthorization type.
message GrantAuthorization {
string granter = 1;
string grantee = 2;
google.protobuf.Any authorization = 3 [(cosmos_proto.accepts_interface) = "Authorization"];
google.protobuf.Timestamp expiration = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
}

View File

@ -0,0 +1,54 @@
syntax = "proto3";
package cosmos.authz.v1beta1;
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "google/api/annotations.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "cosmos/authz/v1beta1/authz.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/authz/types";
// Query defines the gRPC querier service.
service Query {
// Returns any `Authorization` (or `nil`), with the expiration time, granted to the grantee by the granter for the
// provided msg type.
rpc Authorization(QueryAuthorizationRequest) returns (QueryAuthorizationResponse) {
option (google.api.http).get = "/cosmos/authz/v1beta1/granters/{granter}/grantees/{grantee}/grant";
}
// Returns list of `Authorization`, granted to the grantee by the granter.
rpc Authorizations(QueryAuthorizationsRequest) returns (QueryAuthorizationsResponse) {
option (google.api.http).get = "/cosmos/authz/v1beta1/granters/{granter}/grantees/{grantee}/grants";
}
}
// QueryAuthorizationRequest is the request type for the Query/Authorization RPC method.
message QueryAuthorizationRequest {
string granter = 1;
string grantee = 2;
string method_name = 3;
}
// QueryAuthorizationResponse is the response type for the Query/Authorization RPC method.
message QueryAuthorizationResponse {
// authorization is a authorization granted for grantee by granter.
cosmos.authz.v1beta1.AuthorizationGrant authorization = 1;
}
// QueryAuthorizationsRequest is the request type for the Query/Authorizations RPC method.
message QueryAuthorizationsRequest {
string granter = 1;
string grantee = 2;
// pagination defines an pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 3;
}
// QueryAuthorizationsResponse is the response type for the Query/Authorizations RPC method.
message QueryAuthorizationsResponse {
// authorizations is a list of grants granted for grantee by granter.
repeated cosmos.authz.v1beta1.AuthorizationGrant authorizations = 1;
// pagination defines an pagination for the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

View File

@ -0,0 +1,62 @@
syntax = "proto3";
package cosmos.authz.v1beta1;
import "cosmos_proto/cosmos.proto";
import "gogoproto/gogo.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/any.proto";
import "cosmos/base/abci/v1beta1/abci.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/authz/types";
// Msg defines the authz Msg service.
service Msg {
// GrantAuthorization grants the provided authorization to the grantee on the granter's
// account with the provided expiration time.
rpc GrantAuthorization(MsgGrantAuthorizationRequest) returns (MsgGrantAuthorizationResponse);
// ExecAuthorized attempts to execute the provided messages using
// authorizations granted to the grantee. Each message should have only
// one signer corresponding to the granter of the authorization.
rpc ExecAuthorized(MsgExecAuthorizedRequest) returns (MsgExecAuthorizedResponse);
// RevokeAuthorization revokes any authorization corresponding to the provided method name on the
// granter's account that has been granted to the grantee.
rpc RevokeAuthorization(MsgRevokeAuthorizationRequest) returns (MsgRevokeAuthorizationResponse);
}
// MsgGrantAuthorizationRequest grants the provided authorization to the grantee on the granter's
// account with the provided expiration time.
message MsgGrantAuthorizationRequest {
string granter = 1;
string grantee = 2;
google.protobuf.Any authorization = 3 [(cosmos_proto.accepts_interface) = "Authorization"];
google.protobuf.Timestamp expiration = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
}
// MsgExecAuthorizedResponse defines the Msg/MsgExecAuthorizedResponse response type.
message MsgExecAuthorizedResponse {
cosmos.base.abci.v1beta1.Result result = 1;
}
// MsgExecAuthorizedRequest attempts to execute the provided messages using
// authorizations granted to the grantee. Each message should have only
// one signer corresponding to the granter of the authorization.
message MsgExecAuthorizedRequest {
string grantee = 1;
repeated google.protobuf.Any msgs = 2;
}
// MsgGrantAuthorizationResponse defines the Msg/MsgGrantAuthorization response type.
message MsgGrantAuthorizationResponse {}
// MsgRevokeAuthorizationRequest revokes any authorization with the provided sdk.Msg type on the
// granter's account with that has been granted to the grantee.
message MsgRevokeAuthorizationRequest {
string granter = 1;
string grantee = 2;
string method_name = 3;
}
// MsgRevokeAuthorizationResponse defines the Msg/MsgRevokeAuthorizationResponse response type.
message MsgRevokeAuthorizationResponse {}

View File

@ -44,6 +44,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/capability"
capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
"github.com/cosmos/cosmos-sdk/x/crisis"
crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper"
crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types"
@ -87,6 +88,10 @@ import (
upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
authz "github.com/cosmos/cosmos-sdk/x/authz"
authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
authztypes "github.com/cosmos/cosmos-sdk/x/authz/types"
// unnamed import of statik for swagger UI support
_ "github.com/cosmos/cosmos-sdk/client/docs/statik"
)
@ -118,6 +123,7 @@ var (
upgrade.AppModuleBasic{},
evidence.AppModuleBasic{},
transfer.AppModuleBasic{},
authz.AppModuleBasic{},
vesting.AppModuleBasic{},
)
@ -171,6 +177,7 @@ type SimApp struct {
CrisisKeeper crisiskeeper.Keeper
UpgradeKeeper upgradekeeper.Keeper
ParamsKeeper paramskeeper.Keeper
AuthzKeeper authzkeeper.Keeper
IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly
EvidenceKeeper evidencekeeper.Keeper
TransferKeeper ibctransferkeeper.Keeper
@ -217,6 +224,7 @@ func NewSimApp(
minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey,
govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey,
evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey,
authztypes.StoreKey,
)
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey)
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
@ -282,6 +290,8 @@ func NewSimApp(
appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, scopedIBCKeeper,
)
app.AuthzKeeper = authzkeeper.NewKeeper(keys[authztypes.StoreKey], appCodec, app.BaseApp.MsgServiceRouter())
// register the proposal types
govRouter := govtypes.NewRouter()
govRouter.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler).
@ -346,6 +356,7 @@ func NewSimApp(
evidence.NewAppModule(app.EvidenceKeeper),
ibc.NewAppModule(app.IBCKeeper),
params.NewAppModule(app.ParamsKeeper),
authz.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
transferModule,
)
@ -367,7 +378,7 @@ func NewSimApp(
app.mm.SetOrderInitGenesis(
capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, stakingtypes.ModuleName,
slashingtypes.ModuleName, govtypes.ModuleName, minttypes.ModuleName, crisistypes.ModuleName,
ibchost.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, ibctransfertypes.ModuleName,
ibchost.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, authztypes.ModuleName, ibctransfertypes.ModuleName,
)
app.mm.RegisterInvariants(&app.CrisisKeeper)
@ -392,6 +403,7 @@ func NewSimApp(
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
params.NewAppModule(app.ParamsKeeper),
evidence.NewAppModule(app.EvidenceKeeper),
authz.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
ibc.NewAppModule(app.IBCKeeper),
transferModule,
)

View File

@ -19,6 +19,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
authztypes "github.com/cosmos/cosmos-sdk/x/authz/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
@ -177,6 +178,7 @@ func TestAppImportExport(t *testing.T) {
{app.keys[capabilitytypes.StoreKey], newApp.keys[capabilitytypes.StoreKey], [][]byte{}},
{app.keys[ibchost.StoreKey], newApp.keys[ibchost.StoreKey], [][]byte{}},
{app.keys[ibctransfertypes.StoreKey], newApp.keys[ibctransfertypes.StoreKey], [][]byte{}},
{app.keys[authztypes.StoreKey], newApp.keys[authztypes.StoreKey], [][]byte{}},
}
for _, skp := range storeKeysPrefixes {

View File

@ -135,6 +135,9 @@ var (
// supported.
ErrNotSupported = Register(RootCodespace, 37, "feature not supported")
// ErrNotFound defines an error when requested entity doesn't exist in the state.
ErrNotFound = Register(RootCodespace, 38, "not found")
// ErrPanic is only set when we recover from a panic, so we know to
// redact potentially sensitive system info
ErrPanic = Register(UndefinedCodespace, 111222, "panic")

View File

@ -0,0 +1,50 @@
package msgservice
import (
"context"
"fmt"
gogogrpc "github.com/gogo/protobuf/grpc"
grpc "google.golang.org/grpc"
sdk "github.com/cosmos/cosmos-sdk/types"
)
var _ gogogrpc.ClientConn = &ServiceMsgClientConn{}
// ServiceMsgClientConn is an instance of grpc.ClientConn that is used to test building
// transactions with MsgClient's. It is intended to be replaced by the work in
// https://github.com/cosmos/cosmos-sdk/issues/7541 when that is ready.
type ServiceMsgClientConn struct {
msgs []sdk.Msg
}
// Invoke implements the grpc ClientConn.Invoke method
func (t *ServiceMsgClientConn) Invoke(_ context.Context, method string, args, _ interface{}, _ ...grpc.CallOption) error {
req, ok := args.(sdk.MsgRequest)
if !ok {
return fmt.Errorf("%T should implement %T", args, (*sdk.MsgRequest)(nil))
}
err := req.ValidateBasic()
if err != nil {
return err
}
t.msgs = append(t.msgs, sdk.ServiceMsg{
MethodName: method,
Request: req,
})
return nil
}
// NewStream implements the grpc ClientConn.NewStream method
func (t *ServiceMsgClientConn) NewStream(context.Context, *grpc.StreamDesc, string, ...grpc.CallOption) (grpc.ClientStream, error) {
return nil, fmt.Errorf("not supported")
}
// GetMsgs returns ServiceMsgClientConn.msgs
func (t *ServiceMsgClientConn) GetMsgs() []sdk.Msg {
return t.msgs
}

View File

@ -2,7 +2,9 @@ package simulation
import (
"encoding/json"
"fmt"
"math/rand"
"reflect"
"time"
"github.com/cosmos/cosmos-sdk/baseapp"
@ -75,7 +77,16 @@ func NewOperationMsgBasic(route, name, comment string, ok bool, msg []byte) Oper
}
// NewOperationMsg - create a new operation message from sdk.Msg
func NewOperationMsg(msg sdk.Msg, ok bool, comment string) OperationMsg {
func NewOperationMsg(msg sdk.Msg, ok bool, comment string, cdc *codec.ProtoCodec) OperationMsg {
if reflect.TypeOf(msg) == reflect.TypeOf(sdk.ServiceMsg{}) {
srvMsg, ok := msg.(sdk.ServiceMsg)
if !ok {
panic(fmt.Sprintf("Expecting %T to implement sdk.ServiceMsg", msg))
}
bz := cdc.MustMarshalJSON(srvMsg.Request)
return NewOperationMsgBasic(srvMsg.MethodName, srvMsg.MethodName, comment, ok, bz)
}
return NewOperationMsgBasic(msg.Route(), msg.Type(), comment, ok, msg.GetSignBytes())
}

View File

@ -0,0 +1,727 @@
// +build norace
package cli_test
import (
"fmt"
"strings"
"testing"
"time"
"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
tmcli "github.com/tendermint/tendermint/libs/cli"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz/client/cli"
govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli"
govtestutil "github.com/cosmos/cosmos-sdk/x/gov/client/testutil"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/cosmos-sdk/x/authz/types"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
)
type IntegrationTestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
grantee sdk.AccAddress
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
cfg := network.DefaultConfig()
cfg.NumValidators = 1
s.cfg = cfg
s.network = network.New(s.T(), cfg)
val := s.network.Validators[0]
// Create new account in the keyring.
info, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
s.Require().NoError(err)
newAddr := sdk.AccAddress(info.GetPubKey().Address())
// Send some funds to the new account.
_, err = banktestutil.MsgSendExec(
val.ClientCtx,
val.Address,
newAddr,
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(200))), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
)
s.Require().NoError(err)
s.grantee = newAddr
// create a proposal with deposit
_, err = govtestutil.MsgSubmitProposal(val.ClientCtx, val.Address.String(),
"Text Proposal 1", "Where is the title!?", govtypes.ProposalTypeText,
fmt.Sprintf("--%s=%s", govcli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, govtypes.DefaultMinDepositTokens).String()))
s.Require().NoError(err)
_, err = s.network.WaitForHeight(1)
s.Require().NoError(err)
}
func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.network.Cleanup()
}
var typeMsgSend = types.SendAuthorization{}.MethodName()
var typeMsgVote = "/cosmos.gov.v1beta1.Msg/Vote"
func (s *IntegrationTestSuite) TestQueryAuthorizations() {
val := s.network.Validators[0]
grantee := s.grantee
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
_, err := execGrantAuthorization(
val,
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
)
s.Require().NoError(err)
testCases := []struct {
name string
args []string
expectErr bool
expErrMsg string
}{
{
"Error: Invalid grantee",
[]string{
val.Address.String(),
"invalid grantee",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
"decoding bech32 failed: invalid character in string: ' '",
},
{
"Error: Invalid granter",
[]string{
"invalid granter",
grantee.String(),
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
"decoding bech32 failed: invalid character in string: ' '",
},
{
"Valid txn (json)",
[]string{
val.Address.String(),
grantee.String(),
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
false,
``,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryAuthorizations()
clientCtx := val.ClientCtx
resp, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
s.Require().Contains(string(resp.Bytes()), tc.expErrMsg)
} else {
s.Require().NoError(err)
var grants types.QueryAuthorizationsResponse
err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &grants)
s.Require().NoError(err)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryAuthorization() {
val := s.network.Validators[0]
grantee := s.grantee
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
_, err := execGrantAuthorization(
val,
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
)
s.Require().NoError(err)
testCases := []struct {
name string
args []string
expectErr bool
expectedOutput string
}{
{
"Error: Invalid grantee",
[]string{
val.Address.String(),
"invalid grantee",
typeMsgSend,
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
"",
},
{
"Error: Invalid granter",
[]string{
"invalid granter",
grantee.String(),
typeMsgSend,
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
"",
},
{
"no authorization found",
[]string{
val.Address.String(),
grantee.String(),
"typeMsgSend",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
"",
},
{
"Valid txn (json)",
[]string{
val.Address.String(),
grantee.String(),
typeMsgSend,
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
false,
`{"@type":"/cosmos.authz.v1beta1.SendAuthorization","spend_limit":[{"denom":"steak","amount":"100"}]}`,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryAuthorization()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().Contains(strings.TrimSpace(out.String()), tc.expectedOutput)
}
})
}
}
func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
val := s.network.Validators[0]
grantee := s.grantee
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
pastHour := time.Now().Add(time.Minute * time.Duration(-60)).Unix()
testCases := []struct {
name string
args []string
respType proto.Message
expectedCode uint32
expectErr bool
}{
{
"Invalid granter Address",
[]string{
"grantee_addr",
"send",
fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
fmt.Sprintf("--%s=%s", flags.FlagFrom, "granter"),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
},
nil,
0,
true,
},
{
"Invalid grantee Address",
[]string{
"grantee_addr",
"send",
fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
},
nil, 0,
true,
},
{
"Invalid expiration time",
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, pastHour),
},
nil, 0,
true,
},
{
"fail with error invalid msg-type",
[]string{
grantee.String(),
"generic",
fmt.Sprintf("--%s=invalid-msg-type", cli.FlagMsgType),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
&sdk.TxResponse{}, 29,
false,
},
{
"Valid tx send authorization",
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
&sdk.TxResponse{}, 0,
false,
},
{
"Valid tx generic authorization",
[]string{
grantee.String(),
"generic",
fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
&sdk.TxResponse{}, 0,
false,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
clientCtx := val.ClientCtx
out, err := execGrantAuthorization(
val,
tc.args,
)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
txResp := tc.respType.(*sdk.TxResponse)
s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
}
})
}
}
func execGrantAuthorization(val *network.Validator, args []string) (testutil.BufferWriter, error) {
cmd := cli.NewCmdGrantAuthorization()
clientCtx := val.ClientCtx
return clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
}
func (s *IntegrationTestSuite) TestCmdRevokeAuthorizations() {
val := s.network.Validators[0]
grantee := s.grantee
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
// send-authorization
_, err := execGrantAuthorization(
val,
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
)
s.Require().NoError(err)
// generic-authorization
_, err = execGrantAuthorization(
val,
[]string{
grantee.String(),
"generic",
fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
)
s.Require().NoError(err)
testCases := []struct {
name string
args []string
respType proto.Message
expectedCode uint32
expectErr bool
}{
{
"invalid grantee address",
[]string{
"invlid grantee",
typeMsgSend,
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
},
nil,
0,
true,
},
{
"invalid granter address",
[]string{
grantee.String(),
typeMsgSend,
fmt.Sprintf("--%s=%s", flags.FlagFrom, "granter"),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
},
nil,
0,
true,
},
{
"Valid tx send authorization",
[]string{
grantee.String(),
typeMsgSend,
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
&sdk.TxResponse{}, 0,
false,
},
{
"Valid tx generic authorization",
[]string{
grantee.String(),
typeMsgVote,
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
&sdk.TxResponse{}, 0,
false,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.NewCmdRevokeAuthorization()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
txResp := tc.respType.(*sdk.TxResponse)
s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
}
})
}
}
func (s *IntegrationTestSuite) TestExecAuthorizationWithExpiration() {
val := s.network.Validators[0]
grantee := s.grantee
tenSeconds := time.Now().Add(time.Second * time.Duration(10)).Unix()
_, err := execGrantAuthorization(
val,
[]string{
grantee.String(),
"generic",
fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, tenSeconds),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
)
s.Require().NoError(err)
// msg vote
voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.gov.v1beta1.Msg/Vote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String())
execMsg := testutil.WriteToNewTempFile(s.T(), voteTx)
// waiting for authorization to expires
time.Sleep(12 * time.Second)
cmd := cli.NewCmdExecAuthorization()
clientCtx := val.ClientCtx
res, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, []string{
execMsg.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
})
s.Require().NoError(err)
s.Require().Contains(res.String(), "authorization not found")
}
func (s *IntegrationTestSuite) TestNewExecGenericAuthorized() {
val := s.network.Validators[0]
grantee := s.grantee
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
_, err := execGrantAuthorization(
val,
[]string{
grantee.String(),
"generic",
fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
)
s.Require().NoError(err)
// msg vote
voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.gov.v1beta1.Msg/Vote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String())
execMsg := testutil.WriteToNewTempFile(s.T(), voteTx)
testCases := []struct {
name string
args []string
respType proto.Message
expectedCode uint32
expectErr bool
}{
{
"fail invalid grantee",
[]string{
execMsg.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, "grantee"),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
},
nil,
0,
true,
},
{
"fail invalid json path",
[]string{
"/invalid/file.txt",
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
},
nil,
0,
true,
},
{
"valid txn",
[]string{
execMsg.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
},
&sdk.TxResponse{},
0,
false,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.NewCmdExecAuthorization()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
txResp := tc.respType.(*sdk.TxResponse)
s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
}
})
}
}
func (s *IntegrationTestSuite) TestNewExecGrantAuthorized() {
val := s.network.Validators[0]
grantee := s.grantee
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
_, err := execGrantAuthorization(
val,
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=12%stoken", cli.FlagSpendLimit, val.Moniker),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
)
s.Require().NoError(err)
tokens := sdk.NewCoins(
sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(12)),
)
normalGeneratedTx, err := bankcli.ServiceMsgSendExec(
val.ClientCtx,
val.Address,
grantee,
tokens,
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
)
s.Require().NoError(err)
execMsg := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String())
testCases := []struct {
name string
args []string
respType proto.Message
expectedCode uint32
expectErr bool
}{
{
"fail invalid grantee",
[]string{
execMsg.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, "grantee"),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
},
nil,
0,
true,
},
{
"fail invalid json path",
[]string{
"/invalid/file.txt",
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
},
nil,
0,
true,
},
{
"valid txn",
[]string{
execMsg.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
},
&sdk.TxResponse{},
0,
false,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.NewCmdExecAuthorization()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
txResp := tc.respType.(*sdk.TxResponse)
s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
}
})
}
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}

138
x/authz/client/cli/query.go Normal file
View File

@ -0,0 +1,138 @@
package cli
import (
"context"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
// GetQueryCmd returns the cli query commands for this module
func GetQueryCmd() *cobra.Command {
authorizationQueryCmd := &cobra.Command{
Use: types.ModuleName,
Short: "Querying commands for the authz module",
Long: "",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
authorizationQueryCmd.AddCommand(
GetCmdQueryAuthorization(),
GetCmdQueryAuthorizations(),
)
return authorizationQueryCmd
}
// GetCmdQueryAuthorizations implements the query authorizations command.
func GetCmdQueryAuthorizations() *cobra.Command {
cmd := &cobra.Command{
Use: "authorizations [granter-addr] [grantee-addr]",
Args: cobra.ExactArgs(2),
Short: "query list of authorizations for a granter-grantee pair",
Long: strings.TrimSpace(
fmt.Sprintf(`Query list of authorizations for a granter-grantee pair:
Example:
$ %s query %s authorizations cosmos1skj.. cosmos1skjwj..
`, version.AppName, types.ModuleName),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
granterAddr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
}
granteeAddr, err := sdk.AccAddressFromBech32(args[1])
if err != nil {
return err
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
res, err := queryClient.Authorizations(
context.Background(),
&types.QueryAuthorizationsRequest{
Granter: granterAddr.String(),
Grantee: granteeAddr.String(),
Pagination: pageReq,
},
)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "authorizations")
return cmd
}
// GetCmdQueryAuthorization implements the query authorization command.
func GetCmdQueryAuthorization() *cobra.Command {
cmd := &cobra.Command{
Use: "authorization [granter-addr] [grantee-addr] [msg-type]",
Args: cobra.ExactArgs(3),
Short: "query authorization for a granter-grantee pair",
Long: strings.TrimSpace(
fmt.Sprintf(`Query authorization for a granter-grantee pair that matches the given msg-type:
Example:
$ %s query %s authorization cosmos1skjw.. cosmos1skjwj.. %s
`, version.AppName, types.ModuleName, types.SendAuthorization{}.MethodName()),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
granter, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
}
grantee, err := sdk.AccAddressFromBech32(args[1])
if err != nil {
return err
}
msgAuthorized := args[2]
res, err := queryClient.Authorization(
context.Background(),
&types.QueryAuthorizationRequest{
Granter: granter.String(),
Grantee: grantee.String(),
MethodName: msgAuthorized,
},
)
if err != nil {
return err
}
return clientCtx.PrintProto(res.Authorization)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}

222
x/authz/client/cli/tx.go Normal file
View File

@ -0,0 +1,222 @@
package cli
import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/msgservice"
"github.com/cosmos/cosmos-sdk/version"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
const FlagSpendLimit = "spend-limit"
const FlagMsgType = "msg-type"
const FlagExpiration = "expiration"
// GetTxCmd returns the transaction commands for this module
func GetTxCmd() *cobra.Command {
AuthorizationTxCmd := &cobra.Command{
Use: types.ModuleName,
Short: "Authorization transactions subcommands",
Long: "Authorize and revoke access to execute transactions on behalf of your address",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
AuthorizationTxCmd.AddCommand(
NewCmdGrantAuthorization(),
NewCmdRevokeAuthorization(),
NewCmdExecAuthorization(),
)
return AuthorizationTxCmd
}
func NewCmdGrantAuthorization() *cobra.Command {
cmd := &cobra.Command{
Use: "grant <grantee> <authorization_type=\"send\"|\"generic\"> --from <granter>",
Short: "Grant authorization to an address",
Long: strings.TrimSpace(
fmt.Sprintf(`Grant authorization to an address to execute a transaction on your behalf:
Examples:
$ %s tx %s grant cosmos1skjw.. send %s --spend-limit=1000stake --from=cosmos1skl..
$ %s tx %s grant cosmos1skjw.. generic --msg-type=/cosmos.gov.v1beta1.Msg/Vote --from=cosmos1sk..
`, version.AppName, types.ModuleName, types.SendAuthorization{}.MethodName(), version.AppName, types.ModuleName),
),
Args: cobra.RangeArgs(2, 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
}
var authorization types.Authorization
switch args[1] {
case "send":
limit, err := cmd.Flags().GetString(FlagSpendLimit)
if err != nil {
return err
}
spendLimit, err := sdk.ParseCoinsNormalized(limit)
if err != nil {
return err
}
if !spendLimit.IsAllPositive() {
return fmt.Errorf("spend-limit should be greater than zero")
}
authorization = &types.SendAuthorization{
SpendLimit: spendLimit,
}
case "generic":
msgType, err := cmd.Flags().GetString(FlagMsgType)
if err != nil {
return err
}
authorization = types.NewGenericAuthorization(msgType)
default:
return fmt.Errorf("invalid authorization type, %s", args[1])
}
exp, err := cmd.Flags().GetInt64(FlagExpiration)
if err != nil {
return err
}
msg, err := types.NewMsgGrantAuthorization(clientCtx.GetFromAddress(), grantee, authorization, time.Unix(exp, 0))
if err != nil {
return err
}
svcMsgClientConn := &msgservice.ServiceMsgClientConn{}
authzMsgClient := types.NewMsgClient(svcMsgClientConn)
_, err = authzMsgClient.GrantAuthorization(context.Background(), msg)
if err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), svcMsgClientConn.GetMsgs()...)
},
}
flags.AddTxFlagsToCmd(cmd)
cmd.Flags().String(FlagMsgType, "", "The Msg method name for which we are creating a GenericAuthorization")
cmd.Flags().String(FlagSpendLimit, "", "SpendLimit for Send Authorization, an array of Coins allowed spend")
cmd.Flags().Int64(FlagExpiration, time.Now().AddDate(1, 0, 0).Unix(), "The Unix timestamp. Default is one year.")
return cmd
}
func NewCmdRevokeAuthorization() *cobra.Command {
cmd := &cobra.Command{
Use: "revoke [grantee_address] [msg_type] --from=[granter_address]",
Short: "revoke authorization",
Long: strings.TrimSpace(
fmt.Sprintf(`revoke authorization from a granter to a grantee:
Example:
$ %s tx %s revoke cosmos1skj.. %s --from=cosmos1skj..
`, version.AppName, types.ModuleName, types.SendAuthorization{}.MethodName()),
),
Args: cobra.ExactArgs(2),
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
}
granter := clientCtx.GetFromAddress()
msgAuthorized := args[1]
msg := types.NewMsgRevokeAuthorization(granter, grantee, msgAuthorized)
svcMsgClientConn := &msgservice.ServiceMsgClientConn{}
authzMsgClient := types.NewMsgClient(svcMsgClientConn)
_, err = authzMsgClient.RevokeAuthorization(context.Background(), &msg)
if err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), svcMsgClientConn.GetMsgs()...)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
func NewCmdExecAuthorization() *cobra.Command {
cmd := &cobra.Command{
Use: "exec [msg_tx_json_file] --from [grantee]",
Short: "execute tx on behalf of granter account",
Long: strings.TrimSpace(
fmt.Sprintf(`execute tx on behalf of granter account:
Example:
$ %s tx %s exec tx.json --from grantee
$ %s tx bank send <granter> <recipient> --from <granter> --chain-id <chain-id> --generate-only > tx.json && %s tx %s exec tx.json --from grantee
`, version.AppName, types.ModuleName, version.AppName, version.AppName, types.ModuleName),
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
grantee := clientCtx.GetFromAddress()
if offline, _ := cmd.Flags().GetBool(flags.FlagOffline); offline {
return errors.New("cannot broadcast tx during offline mode")
}
theTx, err := authclient.ReadTxFromFile(clientCtx, args[0])
if err != nil {
return err
}
msgs := theTx.GetMsgs()
serviceMsgs := make([]sdk.ServiceMsg, len(msgs))
for i, msg := range msgs {
srvMsg, ok := msg.(sdk.ServiceMsg)
if !ok {
return fmt.Errorf("tx contains %T which is not a sdk.ServiceMsg", msg)
}
serviceMsgs[i] = srvMsg
}
msg := types.NewMsgExecAuthorized(grantee, serviceMsgs)
svcMsgClientConn := &msgservice.ServiceMsgClientConn{}
authzMsgClient := types.NewMsgClient(svcMsgClientConn)
_, err = authzMsgClient.ExecAuthorized(context.Background(), &msg)
if err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), svcMsgClientConn.GetMsgs()...)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}

View File

@ -0,0 +1,235 @@
// +build norace
package rest_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest"
authztestutil "github.com/cosmos/cosmos-sdk/x/authz/client/testutil"
types "github.com/cosmos/cosmos-sdk/x/authz/types"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
)
type IntegrationTestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
grantee sdk.AccAddress
}
var typeMsgSend = types.SendAuthorization{}.MethodName()
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
cfg := network.DefaultConfig()
cfg.NumValidators = 1
s.cfg = cfg
s.network = network.New(s.T(), cfg)
val := s.network.Validators[0]
// Create new account in the keyring.
info, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
s.Require().NoError(err)
newAddr := sdk.AccAddress(info.GetPubKey().Address())
// Send some funds to the new account.
_, err = banktestutil.MsgSendExec(
val.ClientCtx,
val.Address,
newAddr,
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(200))), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
)
s.Require().NoError(err)
// grant authorization
_, err = authztestutil.MsgGrantAuthorizationExec(val.ClientCtx, val.Address.String(), newAddr.String(), typeMsgSend, "100stake")
s.Require().NoError(err)
s.grantee = newAddr
_, err = s.network.WaitForHeight(1)
s.Require().NoError(err)
}
func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.network.Cleanup()
}
func (s *IntegrationTestSuite) TestQueryAuthorizationGRPC() {
val := s.network.Validators[0]
baseURL := val.APIAddress
testCases := []struct {
name string
url string
expectErr bool
errorMsg string
}{
{
"fail invalid granter address",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grant?msg_type=%s", baseURL, "invalid_granter", s.grantee.String(), typeMsgSend),
true,
"decoding bech32 failed: invalid index of 1: invalid request",
},
{
"fail invalid grantee address",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grant?msg_type=%s", baseURL, val.Address.String(), "invalid_grantee", typeMsgSend),
true,
"decoding bech32 failed: invalid index of 1: invalid request",
},
{
"fail with empty granter",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grant?msg_type=%s", baseURL, "", s.grantee.String(), typeMsgSend),
true,
"Not Implemented",
},
{
"fail with empty grantee",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grant?msg_type=%s", baseURL, val.Address.String(), "", typeMsgSend),
true,
"Not Implemented",
},
{
"fail invalid msg-type",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grant?msg_type=%s", baseURL, val.Address.String(), s.grantee.String(), "invalidMsg"),
true,
"rpc error: code = NotFound desc = no authorization found for invalidMsg type: key not found",
},
{
"valid query",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grant?msg_type=%s", baseURL, val.Address.String(), s.grantee.String(), typeMsgSend),
false,
"",
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
resp, _ := rest.GetRequest(tc.url)
if tc.expectErr {
s.Require().Contains(string(resp), tc.errorMsg)
} else {
var authorization types.QueryAuthorizationResponse
err := val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &authorization)
s.Require().NoError(err)
authorization.Authorization.UnpackInterfaces(val.ClientCtx.InterfaceRegistry)
auth := authorization.Authorization.GetAuthorizationGrant()
s.Require().Equal(auth.MethodName(), types.SendAuthorization{}.MethodName())
}
})
}
}
func (s *IntegrationTestSuite) TestQueryAuthorizationsGRPC() {
val := s.network.Validators[0]
baseURL := val.APIAddress
testCases := []struct {
name string
url string
expectErr bool
errMsg string
preRun func()
postRun func(*types.QueryAuthorizationsResponse)
}{
{
"fail invalid granter address",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grants", baseURL, "invalid_granter", s.grantee.String()),
true,
"decoding bech32 failed: invalid index of 1: invalid request",
func() {},
func(_ *types.QueryAuthorizationsResponse) {},
},
{
"fail invalid grantee address",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grants", baseURL, val.Address.String(), "invalid_grantee"),
true,
"decoding bech32 failed: invalid index of 1: invalid request",
func() {},
func(_ *types.QueryAuthorizationsResponse) {},
},
{
"fail empty grantee address",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grants", baseURL, "", "invalid_grantee"),
true,
"Not Implemented",
func() {},
func(_ *types.QueryAuthorizationsResponse) {},
},
{
"valid query: expect single grant",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grants", baseURL, val.Address.String(), s.grantee.String()),
false,
"",
func() {
},
func(authorizations *types.QueryAuthorizationsResponse) {
s.Require().Equal(len(authorizations.Authorizations), 1)
},
},
{
"valid query: expect two grants",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grants", baseURL, val.Address.String(), s.grantee.String()),
false,
"",
func() {
_, err := authztestutil.MsgGrantAuthorizationExec(val.ClientCtx, val.Address.String(), s.grantee.String(), "/cosmos.gov.v1beta1.Msg/Vote", "")
s.Require().NoError(err)
},
func(authorizations *types.QueryAuthorizationsResponse) {
s.Require().Equal(len(authorizations.Authorizations), 2)
},
},
{
"valid query: expect single grant with pagination",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grants?pagination.limit=1", baseURL, val.Address.String(), s.grantee.String()),
false,
"",
func() {},
func(authorizations *types.QueryAuthorizationsResponse) {
s.Require().Equal(len(authorizations.Authorizations), 1)
},
},
{
"valid query: expect two grants with pagination",
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grants?pagination.limit=2", baseURL, val.Address.String(), s.grantee.String()),
false,
"",
func() {},
func(authorizations *types.QueryAuthorizationsResponse) {
s.Require().Equal(len(authorizations.Authorizations), 2)
},
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
tc.preRun()
resp, _ := rest.GetRequest(tc.url)
if tc.expectErr {
s.Require().Contains(string(resp), tc.errMsg)
} else {
var authorizations types.QueryAuthorizationsResponse
err := val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &authorizations)
s.Require().NoError(err)
tc.postRun(&authorizations)
}
})
}
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}

View File

@ -0,0 +1,34 @@
package testutil
import (
"fmt"
"time"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
authzcli "github.com/cosmos/cosmos-sdk/x/authz/client/cli"
)
var commonArgs = []string{
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))).String()),
}
func MsgGrantAuthorizationExec(clientCtx client.Context, granter, grantee, msgName, limit string, extraArgs ...string) (testutil.BufferWriter, error) {
args := []string{
grantee,
msgName,
}
if limit != "" {
args = append(args, limit)
}
args = append(args, fmt.Sprintf("--%s=%s", flags.FlagFrom, granter))
args = append(args, fmt.Sprintf("--%s=%d", authzcli.FlagExpiration, time.Now().Add(time.Minute*time.Duration(120)).Unix()))
args = append(args, commonArgs...)
return clitestutil.ExecTestCLICmd(clientCtx, authzcli.NewCmdGrantAuthorization(), args)
}

View File

@ -0,0 +1,26 @@
package exported
import (
"time"
"github.com/cosmos/cosmos-sdk/x/authz/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
type Keeper interface {
// DispatchActions executes the provided messages via authorization grants from the message signer to the grantee
DispatchActions(ctx sdk.Context, grantee sdk.AccAddress, msgs []sdk.ServiceMsg) sdk.Result
// Grants the provided authorization to the grantee on the granter's account with the provided expiration time
// If there is an existing authorization grant for the same sdk.Msg type, this grant overwrites that.
Grant(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress, authorization types.Authorization, expiration time.Time) error
// Revokes any authorization for the provided message type granted to the grantee by the granter.
Revoke(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress, msgType string)
// Returns any Authorization (or nil), with the expiration time,
// granted to the grantee by the granter for the provided msg type.
// If the Authorization is expired already, it will revoke the authorization and return nil
GetOrRevokeAuthorization(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) (cap types.Authorization, expiration time.Time)
}

47
x/authz/genesis.go Normal file
View File

@ -0,0 +1,47 @@
package authz
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz/keeper"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
// InitGenesis new authz genesis
func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, data *types.GenesisState) {
for _, entry := range data.Authorization {
grantee, err := sdk.AccAddressFromBech32(entry.Grantee)
if err != nil {
panic(err)
}
granter, err := sdk.AccAddressFromBech32(entry.Granter)
if err != nil {
panic(err)
}
authorization, ok := entry.Authorization.GetCachedValue().(types.Authorization)
if !ok {
panic("expected authorization")
}
err = keeper.Grant(ctx, grantee, granter, authorization, entry.Expiration)
if err != nil {
panic(err)
}
}
}
// ExportGenesis returns a GenesisState for a given context and keeper.
func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState {
var entries []types.GrantAuthorization
keeper.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant types.AuthorizationGrant) bool {
exp := grant.Expiration
entries = append(entries, types.GrantAuthorization{
Granter: granter.String(),
Grantee: grantee.String(),
Expiration: exp,
Authorization: grant.Authorization,
})
return false
})
return types.NewGenesisState(entries)
}

59
x/authz/genesis_test.go Normal file
View File

@ -0,0 +1,59 @@
package authz_test
import (
"testing"
"time"
"github.com/stretchr/testify/suite"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
authz "github.com/cosmos/cosmos-sdk/x/authz"
"github.com/cosmos/cosmos-sdk/x/authz/keeper"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
type GenesisTestSuite struct {
suite.Suite
ctx sdk.Context
keeper keeper.Keeper
}
func (suite *GenesisTestSuite) SetupTest() {
checkTx := false
app := simapp.Setup(checkTx)
suite.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1})
suite.keeper = app.AuthzKeeper
}
var (
granteePub = secp256k1.GenPrivKey().PubKey()
granterPub = secp256k1.GenPrivKey().PubKey()
granteeAddr = sdk.AccAddress(granteePub.Address())
granterAddr = sdk.AccAddress(granterPub.Address())
)
func (suite *GenesisTestSuite) TestImportExportGenesis() {
coins := sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(1_000)))
now := suite.ctx.BlockHeader().Time
grant := &types.SendAuthorization{SpendLimit: coins}
err := suite.keeper.Grant(suite.ctx, granteeAddr, granterAddr, grant, now.Add(time.Hour))
suite.Require().NoError(err)
genesis := authz.ExportGenesis(suite.ctx, suite.keeper)
// Clear keeper
suite.keeper.Revoke(suite.ctx, granteeAddr, granterAddr, grant.MethodName())
authz.InitGenesis(suite.ctx, suite.keeper, genesis)
newGenesis := authz.ExportGenesis(suite.ctx, suite.keeper)
suite.Require().Equal(genesis, newGenesis)
}
func TestGenesisTestSuite(t *testing.T) {
suite.Run(t, new(GenesisTestSuite))
}

View File

@ -0,0 +1,120 @@
package keeper
import (
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
proto "github.com/gogo/protobuf/proto"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
var _ types.QueryServer = Keeper{}
// Authorizations implements the Query/Authorizations gRPC method.
func (k Keeper) Authorizations(c context.Context, req *types.QueryAuthorizationsRequest) (*types.QueryAuthorizationsResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}
granter, err := sdk.AccAddressFromBech32(req.Granter)
if err != nil {
return nil, err
}
grantee, err := sdk.AccAddressFromBech32(req.Grantee)
if err != nil {
return nil, err
}
ctx := sdk.UnwrapSDKContext(c)
store := ctx.KVStore(k.storeKey)
key := types.GetAuthorizationStoreKey(grantee, granter, "")
authStore := prefix.NewStore(store, key)
var authorizations []*types.AuthorizationGrant
pageRes, err := query.FilteredPaginate(authStore, req.Pagination, func(key []byte, value []byte, accumulate bool) (bool, error) {
auth, err := unmarshalAuthorization(k.cdc, value)
if err != nil {
return false, err
}
auth1 := auth.GetAuthorizationGrant()
if accumulate {
msg, ok := auth1.(proto.Message)
if !ok {
return false, status.Errorf(codes.Internal, "can't protomarshal %T", msg)
}
authorizationAny, err := codectypes.NewAnyWithValue(msg)
if err != nil {
return false, status.Errorf(codes.Internal, err.Error())
}
authorizations = append(authorizations, &types.AuthorizationGrant{
Authorization: authorizationAny,
Expiration: auth.Expiration,
})
}
return true, nil
})
if err != nil {
return nil, err
}
return &types.QueryAuthorizationsResponse{
Authorizations: authorizations,
Pagination: pageRes,
}, nil
}
// unmarshal an authorization from a store value
func unmarshalAuthorization(cdc codec.BinaryMarshaler, value []byte) (v types.AuthorizationGrant, err error) {
err = cdc.UnmarshalBinaryBare(value, &v)
return v, err
}
// Authorization implements the Query/Authorization gRPC method.
func (k Keeper) Authorization(c context.Context, req *types.QueryAuthorizationRequest) (*types.QueryAuthorizationResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}
if req.MethodName == "" {
return nil, status.Errorf(codes.InvalidArgument, "empty method-name")
}
granter, err := sdk.AccAddressFromBech32(req.Granter)
if err != nil {
return nil, err
}
grantee, err := sdk.AccAddressFromBech32(req.Grantee)
if err != nil {
return nil, err
}
ctx := sdk.UnwrapSDKContext(c)
authorization, expiration := k.GetOrRevokeAuthorization(ctx, grantee, granter, req.MethodName)
if authorization == nil {
return nil, status.Errorf(codes.NotFound, "no authorization found for %s type", req.MethodName)
}
authorizationAny, err := codectypes.NewAnyWithValue(authorization)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
return &types.QueryAuthorizationResponse{
Authorization: &types.AuthorizationGrant{
Authorization: authorizationAny,
Expiration: expiration,
},
}, nil
}

View File

@ -0,0 +1,157 @@
package keeper_test
import (
gocontext "context"
"fmt"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
func (suite *TestSuite) TestGRPCQueryAuthorization() {
app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs
var (
req *types.QueryAuthorizationRequest
expAuthorization types.Authorization
)
testCases := []struct {
msg string
malleate func()
expPass bool
postTest func(res *types.QueryAuthorizationResponse)
}{
{
"fail invalid granter addr",
func() {
req = &types.QueryAuthorizationRequest{}
},
false,
func(res *types.QueryAuthorizationResponse) {},
},
{
"fail invalid grantee addr",
func() {
req = &types.QueryAuthorizationRequest{
Granter: addrs[0].String(),
}
},
false,
func(res *types.QueryAuthorizationResponse) {},
},
{
"fail invalid msg-type",
func() {
req = &types.QueryAuthorizationRequest{
Granter: addrs[0].String(),
Grantee: addrs[1].String(),
}
},
false,
func(res *types.QueryAuthorizationResponse) {},
},
{
"Success",
func() {
now := ctx.BlockHeader().Time
newCoins := sdk.NewCoins(sdk.NewInt64Coin("steak", 100))
expAuthorization = &types.SendAuthorization{SpendLimit: newCoins}
err := app.AuthzKeeper.Grant(ctx, addrs[0], addrs[1], expAuthorization, now.Add(time.Hour))
suite.Require().NoError(err)
req = &types.QueryAuthorizationRequest{
Granter: addrs[1].String(),
Grantee: addrs[0].String(),
MethodName: expAuthorization.MethodName(),
}
},
true,
func(res *types.QueryAuthorizationResponse) {
var auth types.Authorization
err := suite.app.InterfaceRegistry().UnpackAny(res.Authorization.Authorization, &auth)
suite.Require().NoError(err)
suite.Require().NotNil(auth)
suite.Require().Equal(auth.String(), expAuthorization.String())
},
},
}
for _, testCase := range testCases {
suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() {
testCase.malleate()
result, err := queryClient.Authorization(gocontext.Background(), req)
if testCase.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
testCase.postTest(result)
})
}
}
func (suite *TestSuite) TestGRPCQueryAuthorizations() {
app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs
var (
req *types.QueryAuthorizationsRequest
expAuthorization types.Authorization
)
testCases := []struct {
msg string
malleate func()
expPass bool
postTest func(res *types.QueryAuthorizationsResponse)
}{
{
"fail invalid granter addr",
func() {
req = &types.QueryAuthorizationsRequest{}
},
false,
func(res *types.QueryAuthorizationsResponse) {},
},
{
"fail invalid grantee addr",
func() {
req = &types.QueryAuthorizationsRequest{
Granter: addrs[0].String(),
}
},
false,
func(res *types.QueryAuthorizationsResponse) {},
},
{
"Success",
func() {
now := ctx.BlockHeader().Time
newCoins := sdk.NewCoins(sdk.NewInt64Coin("steak", 100))
expAuthorization = &types.SendAuthorization{SpendLimit: newCoins}
err := app.AuthzKeeper.Grant(ctx, addrs[0], addrs[1], expAuthorization, now.Add(time.Hour))
suite.Require().NoError(err)
req = &types.QueryAuthorizationsRequest{
Granter: addrs[1].String(),
Grantee: addrs[0].String(),
}
},
true,
func(res *types.QueryAuthorizationsResponse) {
var auth types.Authorization
suite.Require().Equal(1, len(res.Authorizations))
err := suite.app.InterfaceRegistry().UnpackAny(res.Authorizations[0].Authorization, &auth)
suite.Require().NoError(err)
suite.Require().NotNil(auth)
suite.Require().Equal(auth.String(), expAuthorization.String())
},
},
}
for _, testCase := range testCases {
suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() {
testCase.malleate()
result, err := queryClient.Authorizations(gocontext.Background(), req)
if testCase.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
testCase.postTest(result)
})
}
}

210
x/authz/keeper/keeper.go Normal file
View File

@ -0,0 +1,210 @@
package keeper
import (
"fmt"
"time"
"github.com/gogo/protobuf/proto"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
type Keeper struct {
storeKey sdk.StoreKey
cdc codec.BinaryMarshaler
router *baseapp.MsgServiceRouter
}
// NewKeeper constructs a message authorization Keeper
func NewKeeper(storeKey sdk.StoreKey, cdc codec.BinaryMarshaler, router *baseapp.MsgServiceRouter) Keeper {
return Keeper{
storeKey: storeKey,
cdc: cdc,
router: router,
}
}
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
}
// getAuthorizationGrant returns grant between granter and grantee for the given msg type
func (k Keeper) getAuthorizationGrant(ctx sdk.Context, grantStoreKey []byte) (grant types.AuthorizationGrant, found bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(grantStoreKey)
if bz == nil {
return grant, false
}
k.cdc.MustUnmarshalBinaryBare(bz, &grant)
return grant, true
}
func (k Keeper) update(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress, updated types.Authorization) error {
grantStoreKey := types.GetAuthorizationStoreKey(grantee, granter, updated.MethodName())
grant, found := k.getAuthorizationGrant(ctx, grantStoreKey)
if !found {
return sdkerrors.Wrapf(sdkerrors.ErrNotFound, "authorization not found")
}
msg, ok := updated.(proto.Message)
if !ok {
sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", updated)
}
any, err := codectypes.NewAnyWithValue(msg)
if err != nil {
return err
}
grant.Authorization = any
store := ctx.KVStore(k.storeKey)
store.Set(grantStoreKey, k.cdc.MustMarshalBinaryBare(&grant))
return nil
}
// DispatchActions attempts to execute the provided messages via authorization
// grants from the message signer to the grantee.
func (k Keeper) DispatchActions(ctx sdk.Context, grantee sdk.AccAddress, serviceMsgs []sdk.ServiceMsg) (*sdk.Result, error) {
var msgResult *sdk.Result
var err error
for _, serviceMsg := range serviceMsgs {
signers := serviceMsg.GetSigners()
if len(signers) != 1 {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "authorization can be given to msg with only one signer")
}
granter := signers[0]
if !granter.Equals(grantee) {
authorization, _ := k.GetOrRevokeAuthorization(ctx, grantee, granter, serviceMsg.MethodName)
if authorization == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "authorization not found")
}
allow, updated, del := authorization.Accept(serviceMsg, ctx.BlockHeader())
if !allow {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "requested amount is more than spend limit")
}
if del {
k.Revoke(ctx, grantee, granter, serviceMsg.Type())
} else if updated != nil {
err = k.update(ctx, grantee, granter, updated)
if err != nil {
return nil, err
}
}
}
handler := k.router.Handler(serviceMsg.Route())
if handler == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s", serviceMsg.Route())
}
msgResult, err = handler(ctx, serviceMsg.Request)
if err != nil {
return nil, sdkerrors.Wrapf(err, "failed to execute message; message %s", serviceMsg.MethodName)
}
}
return msgResult, nil
}
// Grant method grants the provided authorization to the grantee on the granter's account with the provided expiration
// time. If there is an existing authorization grant for the same `sdk.Msg` type, this grant
// overwrites that.
func (k Keeper) Grant(ctx sdk.Context, grantee, granter sdk.AccAddress, authorization types.Authorization, expiration time.Time) error {
store := ctx.KVStore(k.storeKey)
grant, err := types.NewAuthorizationGrant(authorization, expiration)
if err != nil {
return err
}
bz := k.cdc.MustMarshalBinaryBare(&grant)
grantStoreKey := types.GetAuthorizationStoreKey(grantee, granter, authorization.MethodName())
store.Set(grantStoreKey, bz)
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventGrantAuthorization,
sdk.NewAttribute(types.AttributeKeyGrantType, authorization.MethodName()),
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(types.AttributeKeyGranterAddress, granter.String()),
sdk.NewAttribute(types.AttributeKeyGranteeAddress, grantee.String()),
),
)
return nil
}
// Revoke method revokes any authorization for the provided message type granted to the grantee by the granter.
func (k Keeper) Revoke(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) error {
store := ctx.KVStore(k.storeKey)
grantStoreKey := types.GetAuthorizationStoreKey(grantee, granter, msgType)
_, found := k.getAuthorizationGrant(ctx, grantStoreKey)
if !found {
return sdkerrors.Wrap(sdkerrors.ErrNotFound, "authorization not found")
}
store.Delete(grantStoreKey)
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventRevokeAuthorization,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(types.AttributeKeyGrantType, msgType),
sdk.NewAttribute(types.AttributeKeyGranterAddress, granter.String()),
sdk.NewAttribute(types.AttributeKeyGranteeAddress, grantee.String()),
),
)
return nil
}
// GetAuthorizations Returns list of `Authorizations` granted to the grantee by the granter.
func (k Keeper) GetAuthorizations(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress) (authorizations []types.Authorization) {
store := ctx.KVStore(k.storeKey)
key := types.GetAuthorizationStoreKey(grantee, granter, "")
iter := sdk.KVStorePrefixIterator(store, key)
defer iter.Close()
var authorization types.AuthorizationGrant
for ; iter.Valid(); iter.Next() {
k.cdc.MustUnmarshalBinaryBare(iter.Value(), &authorization)
authorizations = append(authorizations, authorization.GetAuthorizationGrant())
}
return authorizations
}
// GetOrRevokeAuthorization Returns any `Authorization` (or `nil`), with the expiration time,
// granted to the grantee by the granter for the provided msg type.
// If the Authorization is expired already, it will revoke the authorization and return nil
func (k Keeper) GetOrRevokeAuthorization(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) (cap types.Authorization, expiration time.Time) {
grant, found := k.getAuthorizationGrant(ctx, types.GetAuthorizationStoreKey(grantee, granter, msgType))
if !found {
return nil, time.Time{}
}
if grant.Expiration.Before(ctx.BlockHeader().Time) {
k.Revoke(ctx, grantee, granter, msgType)
return nil, time.Time{}
}
return grant.GetAuthorizationGrant(), grant.Expiration
}
// IterateGrants iterates over all authorization grants
func (k Keeper) IterateGrants(ctx sdk.Context,
handler func(granterAddr sdk.AccAddress, granteeAddr sdk.AccAddress, grant types.AuthorizationGrant) bool) {
store := ctx.KVStore(k.storeKey)
iter := sdk.KVStorePrefixIterator(store, types.GrantKey)
defer iter.Close()
for ; iter.Valid(); iter.Next() {
var grant types.AuthorizationGrant
granterAddr, granteeAddr := types.ExtractAddressesFromGrantKey(iter.Key())
k.cdc.MustUnmarshalBinaryBare(iter.Value(), &grant)
if handler(granterAddr, granteeAddr, grant) {
break
}
}
}

View File

@ -0,0 +1,218 @@
package keeper_test
import (
"testing"
"time"
"github.com/cosmos/cosmos-sdk/baseapp"
proto "github.com/gogo/protobuf/proto"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/stretchr/testify/suite"
)
type TestSuite struct {
suite.Suite
app *simapp.SimApp
ctx sdk.Context
addrs []sdk.AccAddress
queryClient types.QueryClient
}
func (s *TestSuite) SetupTest() {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
now := tmtime.Now()
ctx = ctx.WithBlockHeader(tmproto.Header{Time: now})
queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, app.AuthzKeeper)
queryClient := types.NewQueryClient(queryHelper)
s.queryClient = queryClient
s.app = app
s.ctx = ctx
s.queryClient = queryClient
s.addrs = simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(30000000))
}
func (s *TestSuite) TestKeeper() {
app, ctx, addrs := s.app, s.ctx, s.addrs
granterAddr := addrs[0]
granteeAddr := addrs[1]
recipientAddr := addrs[2]
err := app.BankKeeper.SetBalances(ctx, granterAddr, sdk.NewCoins(sdk.NewInt64Coin("steak", 10000)))
s.Require().Nil(err)
s.Require().True(app.BankKeeper.GetBalance(ctx, granterAddr, "steak").IsEqual(sdk.NewCoin("steak", sdk.NewInt(10000))))
s.T().Log("verify that no authorization returns nil")
authorization, expiration := app.AuthzKeeper.GetOrRevokeAuthorization(ctx, granteeAddr, granterAddr, types.SendAuthorization{}.MethodName())
s.Require().Nil(authorization)
s.Require().Equal(expiration, time.Time{})
now := s.ctx.BlockHeader().Time
s.Require().NotNil(now)
newCoins := sdk.NewCoins(sdk.NewInt64Coin("steak", 100))
s.T().Log("verify if expired authorization is rejected")
x := &types.SendAuthorization{SpendLimit: newCoins}
err = app.AuthzKeeper.Grant(ctx, granterAddr, granteeAddr, x, now.Add(-1*time.Hour))
s.Require().NoError(err)
authorization, _ = app.AuthzKeeper.GetOrRevokeAuthorization(ctx, granteeAddr, granterAddr, types.SendAuthorization{}.MethodName())
s.Require().Nil(authorization)
s.T().Log("verify if authorization is accepted")
x = &types.SendAuthorization{SpendLimit: newCoins}
err = app.AuthzKeeper.Grant(ctx, granteeAddr, granterAddr, x, now.Add(time.Hour))
s.Require().NoError(err)
authorization, _ = app.AuthzKeeper.GetOrRevokeAuthorization(ctx, granteeAddr, granterAddr, types.SendAuthorization{}.MethodName())
s.Require().NotNil(authorization)
s.Require().Equal(authorization.MethodName(), types.SendAuthorization{}.MethodName())
s.T().Log("verify fetching authorization with wrong msg type fails")
authorization, _ = app.AuthzKeeper.GetOrRevokeAuthorization(ctx, granteeAddr, granterAddr, proto.MessageName(&banktypes.MsgMultiSend{}))
s.Require().Nil(authorization)
s.T().Log("verify fetching authorization with wrong grantee fails")
authorization, _ = app.AuthzKeeper.GetOrRevokeAuthorization(ctx, recipientAddr, granterAddr, types.SendAuthorization{}.MethodName())
s.Require().Nil(authorization)
s.T().Log("verify revoke fails with wrong information")
err = app.AuthzKeeper.Revoke(ctx, recipientAddr, granterAddr, types.SendAuthorization{}.MethodName())
s.Require().Error(err)
authorization, _ = app.AuthzKeeper.GetOrRevokeAuthorization(ctx, recipientAddr, granterAddr, types.SendAuthorization{}.MethodName())
s.Require().Nil(authorization)
s.T().Log("verify revoke executes with correct information")
err = app.AuthzKeeper.Revoke(ctx, granteeAddr, granterAddr, types.SendAuthorization{}.MethodName())
s.Require().NoError(err)
authorization, _ = app.AuthzKeeper.GetOrRevokeAuthorization(ctx, granteeAddr, granterAddr, types.SendAuthorization{}.MethodName())
s.Require().Nil(authorization)
}
func (s *TestSuite) TestKeeperIter() {
app, ctx, addrs := s.app, s.ctx, s.addrs
granterAddr := addrs[0]
granteeAddr := addrs[1]
err := app.BankKeeper.SetBalances(ctx, granterAddr, sdk.NewCoins(sdk.NewInt64Coin("steak", 10000)))
s.Require().Nil(err)
s.Require().True(app.BankKeeper.GetBalance(ctx, granterAddr, "steak").IsEqual(sdk.NewCoin("steak", sdk.NewInt(10000))))
s.T().Log("verify that no authorization returns nil")
authorization, expiration := app.AuthzKeeper.GetOrRevokeAuthorization(ctx, granteeAddr, granterAddr, "Abcd")
s.Require().Nil(authorization)
s.Require().Equal(time.Time{}, expiration)
now := s.ctx.BlockHeader().Time
s.Require().NotNil(now)
newCoins := sdk.NewCoins(sdk.NewInt64Coin("steak", 100))
s.T().Log("verify if expired authorization is rejected")
x := &types.SendAuthorization{SpendLimit: newCoins}
err = app.AuthzKeeper.Grant(ctx, granteeAddr, granterAddr, x, now.Add(-1*time.Hour))
s.Require().NoError(err)
authorization, _ = app.AuthzKeeper.GetOrRevokeAuthorization(ctx, granteeAddr, granterAddr, "abcd")
s.Require().Nil(authorization)
app.AuthzKeeper.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant types.AuthorizationGrant) bool {
s.Require().Equal(granter, granterAddr)
s.Require().Equal(grantee, granteeAddr)
return true
})
}
func (s *TestSuite) TestKeeperFees() {
app, addrs := s.app, s.addrs
granterAddr := addrs[0]
granteeAddr := addrs[1]
recipientAddr := addrs[2]
err := app.BankKeeper.SetBalances(s.ctx, granterAddr, sdk.NewCoins(sdk.NewInt64Coin("steak", 10000)))
s.Require().Nil(err)
s.Require().True(app.BankKeeper.GetBalance(s.ctx, granterAddr, "steak").IsEqual(sdk.NewCoin("steak", sdk.NewInt(10000))))
now := s.ctx.BlockHeader().Time
s.Require().NotNil(now)
smallCoin := sdk.NewCoins(sdk.NewInt64Coin("steak", 20))
someCoin := sdk.NewCoins(sdk.NewInt64Coin("steak", 123))
msgs := types.NewMsgExecAuthorized(granteeAddr, []sdk.ServiceMsg{
{
MethodName: types.SendAuthorization{}.MethodName(),
Request: &banktypes.MsgSend{
Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)),
FromAddress: granterAddr.String(),
ToAddress: recipientAddr.String(),
},
},
})
s.Require().NoError(msgs.UnpackInterfaces(app.AppCodec()))
s.T().Log("verify dispatch fails with invalid authorization")
executeMsgs, err := msgs.GetServiceMsgs()
s.Require().NoError(err)
result, err := app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs)
s.Require().Nil(result)
s.Require().NotNil(err)
s.T().Log("verify dispatch executes with correct information")
// grant authorization
err = app.AuthzKeeper.Grant(s.ctx, granteeAddr, granterAddr, &types.SendAuthorization{SpendLimit: smallCoin}, now)
s.Require().NoError(err)
authorization, _ := app.AuthzKeeper.GetOrRevokeAuthorization(s.ctx, granteeAddr, granterAddr, types.SendAuthorization{}.MethodName())
s.Require().NotNil(authorization)
s.Require().Equal(authorization.MethodName(), types.SendAuthorization{}.MethodName())
executeMsgs, err = msgs.GetServiceMsgs()
s.Require().NoError(err)
result, err = app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs)
s.Require().NotNil(result)
s.Require().Nil(err)
authorization, _ = app.AuthzKeeper.GetOrRevokeAuthorization(s.ctx, granteeAddr, granterAddr, types.SendAuthorization{}.MethodName())
s.Require().NotNil(authorization)
s.T().Log("verify dispatch fails with overlimit")
// grant authorization
msgs = types.NewMsgExecAuthorized(granteeAddr, []sdk.ServiceMsg{
{
MethodName: types.SendAuthorization{}.MethodName(),
Request: &banktypes.MsgSend{
Amount: someCoin,
FromAddress: granterAddr.String(),
ToAddress: recipientAddr.String(),
},
},
})
s.Require().NoError(msgs.UnpackInterfaces(app.AppCodec()))
executeMsgs, err = msgs.GetServiceMsgs()
s.Require().NoError(err)
result, err = app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs)
s.Require().Nil(result)
s.Require().NotNil(err)
authorization, _ = app.AuthzKeeper.GetOrRevokeAuthorization(s.ctx, granteeAddr, granterAddr, types.SendAuthorization{}.MethodName())
s.Require().NotNil(authorization)
}
func TestTestSuite(t *testing.T) {
suite.Run(t, new(TestSuite))
}

View File

@ -0,0 +1,75 @@
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
var _ types.MsgServer = Keeper{}
// GrantAuthorization implements the MsgServer.GrantAuthorization method.
func (k Keeper) GrantAuthorization(goCtx context.Context, msg *types.MsgGrantAuthorizationRequest) (*types.MsgGrantAuthorizationResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
grantee, err := sdk.AccAddressFromBech32(msg.Grantee)
if err != nil {
return nil, err
}
granter, err := sdk.AccAddressFromBech32(msg.Granter)
if err != nil {
return nil, err
}
authorization := msg.GetGrantAuthorization()
// If the granted service Msg doesn't exist, we throw an error.
if k.router.Handler(authorization.MethodName()) == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "%s doesn't exist.", authorization.MethodName())
}
err = k.Grant(ctx, grantee, granter, authorization, msg.Expiration)
if err != nil {
return nil, err
}
return &types.MsgGrantAuthorizationResponse{}, nil
}
// RevokeAuthorization implements the MsgServer.RevokeAuthorization method.
func (k Keeper) RevokeAuthorization(goCtx context.Context, msg *types.MsgRevokeAuthorizationRequest) (*types.MsgRevokeAuthorizationResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
grantee, err := sdk.AccAddressFromBech32(msg.Grantee)
if err != nil {
return nil, err
}
granter, err := sdk.AccAddressFromBech32(msg.Granter)
if err != nil {
return nil, err
}
err = k.Revoke(ctx, grantee, granter, msg.MethodName)
if err != nil {
return nil, err
}
return &types.MsgRevokeAuthorizationResponse{}, nil
}
// ExecAuthorized implements the MsgServer.ExecAuthorized method.
func (k Keeper) ExecAuthorized(goCtx context.Context, msg *types.MsgExecAuthorizedRequest) (*types.MsgExecAuthorizedResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
grantee, err := sdk.AccAddressFromBech32(msg.Grantee)
if err != nil {
return nil, err
}
msgs, err := msg.GetServiceMsgs()
if err != nil {
return nil, err
}
result, err := k.DispatchActions(ctx, grantee, msgs)
if err != nil {
return nil, err
}
return &types.MsgExecAuthorizedResponse{Result: result}, nil
}

194
x/authz/module.go Normal file
View File

@ -0,0 +1,194 @@
package authz
import (
"context"
"encoding/json"
"math/rand"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
sdkclient "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/authz/keeper"
"github.com/cosmos/cosmos-sdk/x/authz/types"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/authz/client/cli"
"github.com/cosmos/cosmos-sdk/x/authz/simulation"
)
var (
_ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{}
_ module.AppModuleSimulation = AppModule{}
)
// AppModuleBasic defines the basic application module used by the authz module.
type AppModuleBasic struct {
cdc codec.Marshaler
}
// Name returns the authz module's name.
func (AppModuleBasic) Name() string {
return types.ModuleName
}
// RegisterServices registers a gRPC query service to respond to the
// module-specific gRPC queries.
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
types.RegisterMsgServer(cfg.MsgServer(), am.keeper)
}
// RegisterLegacyAminoCodec registers the authz module's types for the given codec.
func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {}
// RegisterInterfaces registers the authz module's interface types
func (AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
types.RegisterInterfaces(registry)
}
// DefaultGenesis returns default genesis state as raw bytes for the authz
// module.
func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage {
return cdc.MustMarshalJSON(types.DefaultGenesisState())
}
// ValidateGenesis performs genesis state validation for the authz module.
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config sdkclient.TxEncodingConfig, bz json.RawMessage) error {
var data types.GenesisState
if err := cdc.UnmarshalJSON(bz, &data); err != nil {
return sdkerrors.Wrapf(err, "failed to unmarshal %s genesis state", types.ModuleName)
}
return types.ValidateGenesis(data)
}
// RegisterRESTRoutes registers the REST routes for the authz module.
func (AppModuleBasic) RegisterRESTRoutes(clientCtx sdkclient.Context, r *mux.Router) {
}
// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the authz module.
func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx sdkclient.Context, mux *runtime.ServeMux) {
types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx))
}
// GetQueryCmd returns the cli query commands for the authz module
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
return cli.GetQueryCmd()
}
// GetTxCmd returns the transaction commands for the authz module
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.GetTxCmd()
}
// AppModule implements the sdk.AppModule interface
type AppModule struct {
AppModuleBasic
keeper keeper.Keeper
accountKeeper types.AccountKeeper
bankKeeper types.BankKeeper
registry cdctypes.InterfaceRegistry
}
// NewAppModule creates a new AppModule object
func NewAppModule(cdc codec.Marshaler, keeper keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper, registry cdctypes.InterfaceRegistry) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{cdc: cdc},
keeper: keeper,
accountKeeper: ak,
bankKeeper: bk,
registry: registry,
}
}
// Name returns the authz module's name.
func (AppModule) Name() string {
return types.ModuleName
}
// RegisterInvariants does nothing, there are no invariants to enforce
func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
// Route returns the message routing key for the staking module.
func (am AppModule) Route() sdk.Route {
return sdk.NewRoute(types.RouterKey, nil)
}
func (am AppModule) NewHandler() sdk.Handler {
return nil
}
// QuerierRoute returns the route we respond to for abci queries
func (AppModule) QuerierRoute() string { return "" }
// LegacyQuerierHandler returns the authz module sdk.Querier.
func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier {
return nil
}
// InitGenesis performs genesis initialization for the authz module. It returns
// no validator updates.
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState types.GenesisState
cdc.MustUnmarshalJSON(data, &genesisState)
InitGenesis(ctx, am.keeper, &genesisState)
return []abci.ValidatorUpdate{}
}
// ExportGenesis returns the exported genesis state as raw bytes for the authz
// module.
func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage {
gs := ExportGenesis(ctx, am.keeper)
return cdc.MustMarshalJSON(gs)
}
func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {}
// EndBlock does nothing
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{}
}
// ____________________________________________________________________________
// AppModuleSimulation functions
// GenerateGenesisState creates a randomized GenState of the authz module.
func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
simulation.RandomizedGenState(simState)
}
// ProposalContents returns all the authz content functions used to
// simulate governance proposals.
func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent {
return nil
}
// RandomizedParams creates randomized authz param changes for the simulator.
func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
return nil
}
// RegisterStoreDecoder registers a decoder for authz module's types
func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc)
}
// WeightedOperations returns the all the gov module operations with their respective weights.
func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
protoCdc := codec.NewProtoCodec(am.registry)
return simulation.WeightedOperations(
simState.AppParams, simState.Cdc,
am.accountKeeper, am.bankKeeper, am.keeper, am.cdc, protoCdc,
)
}

View File

@ -0,0 +1,26 @@
package simulation
import (
"bytes"
"fmt"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/types/kv"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
// NewDecodeStore returns a decoder function closure that umarshals the KVPair's
// Value to the corresponding authz type.
func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string {
return func(kvA, kvB kv.Pair) string {
switch {
case bytes.Equal(kvA.Key[:1], types.GrantKey):
var grantA, grantB types.AuthorizationGrant
cdc.MustUnmarshalBinaryBare(kvA.Value, &grantA)
cdc.MustUnmarshalBinaryBare(kvB.Value, &grantB)
return fmt.Sprintf("%v\n%v", grantA, grantB)
default:
panic(fmt.Sprintf("invalid authz key %X", kvA.Key))
}
}
}

View File

@ -0,0 +1,50 @@
package simulation_test
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/kv"
"github.com/cosmos/cosmos-sdk/x/authz/simulation"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
func TestDecodeStore(t *testing.T) {
cdc := simapp.MakeTestEncodingConfig().Marshaler
dec := simulation.NewDecodeStore(cdc)
grant, _ := types.NewAuthorizationGrant(types.NewSendAuthorization(sdk.NewCoins(sdk.NewInt64Coin("foo", 123))), time.Now().UTC())
grantBz, err := cdc.MarshalBinaryBare(&grant)
require.NoError(t, err)
kvPairs := kv.Pairs{
Pairs: []kv.Pair{
{Key: []byte(types.GrantKey), Value: grantBz},
{Key: []byte{0x99}, Value: []byte{0x99}},
},
}
tests := []struct {
name string
expectedLog string
}{
{"Grant", fmt.Sprintf("%v\n%v", grant, grant)},
{"other", ""},
}
for i, tt := range tests {
i, tt := i, tt
t.Run(tt.name, func(t *testing.T) {
switch i {
case len(tests) - 1:
require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name)
default:
require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name)
}
})
}
}

View File

@ -0,0 +1,38 @@
package simulation
import (
"encoding/json"
"fmt"
"math/rand"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
// Simulation parameter constant.
const authz = "authz"
// GenAuthorizationGrant returns an empty slice of authorization grants.
func GenAuthorizationGrant(_ *rand.Rand, _ []simtypes.Account) []types.GrantAuthorization {
return []types.GrantAuthorization{}
}
// RandomizedGenState generates a random GenesisState for authz.
func RandomizedGenState(simState *module.SimulationState) {
var grants []types.GrantAuthorization
simState.AppParams.GetOrGenerate(
simState.Cdc, authz, &grants, simState.Rand,
func(r *rand.Rand) { grants = GenAuthorizationGrant(r, simState.Accounts) },
)
authzGrantsGenesis := types.NewGenesisState(grants)
bz, err := json.MarshalIndent(&authzGrantsGenesis, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, bz)
simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(authzGrantsGenesis)
}

View File

@ -0,0 +1,40 @@
package simulation_test
import (
"encoding/json"
"math/rand"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/authz/simulation"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
func TestRandomizedGenState(t *testing.T) {
interfaceRegistry := codectypes.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(interfaceRegistry)
s := rand.NewSource(1)
r := rand.New(s)
simState := module.SimulationState{
AppParams: make(simtypes.AppParams),
Cdc: cdc,
Rand: r,
NumBonded: 3,
Accounts: simtypes.RandomAccounts(r, 3),
InitialStake: 1000,
GenState: make(map[string]json.RawMessage),
}
simulation.RandomizedGenState(&simState)
var authzGenesis types.GenesisState
simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &authzGenesis)
require.Len(t, authzGenesis.Authorization, 0)
}

View File

@ -0,0 +1,291 @@
package simulation
import (
"context"
"math/rand"
"strings"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/simapp/helpers"
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/msgservice"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/authz/keeper"
"github.com/cosmos/cosmos-sdk/x/authz/types"
banktype "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/simulation"
)
// authz message types
const (
TypeMsgGrantAuthorization = "/cosmos.authz.v1beta1.Msg/GrantAuthorization"
TypeMsgRevokeAuthorization = "/cosmos.authz.v1beta1.Msg/RevokeAuthorization"
TypeMsgExecDelegated = "/cosmos.authz.v1beta1.Msg/ExecAuthorized"
)
// Simulation operation weights constants
const (
OpWeightMsgGrantAuthorization = "op_weight_msg_grant_authorization"
OpWeightRevokeAuthorization = "op_weight_msg_revoke_authorization"
OpWeightExecAuthorized = "op_weight_msg_execute_authorized"
)
// WeightedOperations returns all the operations from the module with their respective weights
func WeightedOperations(
appParams simtypes.AppParams, cdc codec.JSONMarshaler, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, appCdc cdctypes.AnyUnpacker, protoCdc *codec.ProtoCodec) simulation.WeightedOperations {
var (
weightMsgGrantAuthorization int
weightRevokeAuthorization int
weightExecAuthorized int
)
appParams.GetOrGenerate(cdc, OpWeightMsgGrantAuthorization, &weightMsgGrantAuthorization, nil,
func(_ *rand.Rand) {
weightMsgGrantAuthorization = simappparams.DefaultWeightMsgDelegate
},
)
appParams.GetOrGenerate(cdc, OpWeightRevokeAuthorization, &weightRevokeAuthorization, nil,
func(_ *rand.Rand) {
weightRevokeAuthorization = simappparams.DefaultWeightMsgUndelegate
},
)
appParams.GetOrGenerate(cdc, OpWeightExecAuthorized, &weightExecAuthorized, nil,
func(_ *rand.Rand) {
weightExecAuthorized = simappparams.DefaultWeightMsgSend
},
)
return simulation.WeightedOperations{
simulation.NewWeightedOperation(
weightMsgGrantAuthorization,
SimulateMsgGrantAuthorization(ak, bk, k, protoCdc),
),
simulation.NewWeightedOperation(
weightRevokeAuthorization,
SimulateMsgRevokeAuthorization(ak, bk, k, protoCdc),
),
simulation.NewWeightedOperation(
weightExecAuthorized,
SimulateMsgExecuteAuthorized(ak, bk, k, appCdc, protoCdc),
),
}
}
// SimulateMsgGrantAuthorization generates a MsgGrantAuthorization with random values.
// nolint: funlen
func SimulateMsgGrantAuthorization(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper,
protoCdc *codec.ProtoCodec) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
granter := accs[0]
grantee := accs[1]
account := ak.GetAccount(ctx, granter.Address)
spendableCoins := bk.SpendableCoins(ctx, account.GetAddress())
fees, err := simtypes.RandomFees(r, ctx, spendableCoins)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgGrantAuthorization, err.Error()), nil, err
}
blockTime := ctx.BlockTime()
msg, err := types.NewMsgGrantAuthorization(granter.Address, grantee.Address,
types.NewSendAuthorization(spendableCoins.Sub(fees)), blockTime.AddDate(1, 0, 0))
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgGrantAuthorization, err.Error()), nil, err
}
txGen := simappparams.MakeTestEncodingConfig().TxConfig
svcMsgClientConn := &msgservice.ServiceMsgClientConn{}
authzMsgClient := types.NewMsgClient(svcMsgClientConn)
_, err = authzMsgClient.GrantAuthorization(context.Background(), msg)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgGrantAuthorization, err.Error()), nil, err
}
tx, err := helpers.GenTx(
txGen,
svcMsgClientConn.GetMsgs(),
fees,
helpers.DefaultGenTxGas,
chainID,
[]uint64{account.GetAccountNumber()},
[]uint64{account.GetSequence()},
granter.PrivKey,
)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgGrantAuthorization, "unable to generate mock tx"), nil, err
}
_, _, err = app.Deliver(txGen.TxEncoder(), tx)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, svcMsgClientConn.GetMsgs()[0].Type(), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(svcMsgClientConn.GetMsgs()[0], true, "", protoCdc), nil, err
}
}
// SimulateMsgRevokeAuthorization generates a MsgRevokeAuthorization with random values.
// nolint: funlen
func SimulateMsgRevokeAuthorization(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, protoCdc *codec.ProtoCodec) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
hasGrant := false
var targetGrant types.AuthorizationGrant
var granterAddr sdk.AccAddress
var granteeAddr sdk.AccAddress
k.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant types.AuthorizationGrant) bool {
targetGrant = grant
granterAddr = granter
granteeAddr = grantee
hasGrant = true
return true
})
if !hasGrant {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgRevokeAuthorization, "no grants"), nil, nil
}
granter, ok := simtypes.FindAccount(accs, granterAddr)
if !ok {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgRevokeAuthorization, "Account not found"), nil, nil
}
account := ak.GetAccount(ctx, granter.Address)
spendableCoins := bk.SpendableCoins(ctx, account.GetAddress())
fees, err := simtypes.RandomFees(r, ctx, spendableCoins)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgRevokeAuthorization, "fee error"), nil, err
}
auth := targetGrant.GetAuthorizationGrant()
msg := types.NewMsgRevokeAuthorization(granterAddr, granteeAddr, auth.MethodName())
txGen := simappparams.MakeTestEncodingConfig().TxConfig
svcMsgClientConn := &msgservice.ServiceMsgClientConn{}
authzMsgClient := types.NewMsgClient(svcMsgClientConn)
_, err = authzMsgClient.RevokeAuthorization(context.Background(), &msg)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgRevokeAuthorization, err.Error()), nil, err
}
tx, err := helpers.GenTx(
txGen,
svcMsgClientConn.GetMsgs(),
fees,
helpers.DefaultGenTxGas,
chainID,
[]uint64{account.GetAccountNumber()},
[]uint64{account.GetSequence()},
granter.PrivKey,
)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgRevokeAuthorization, err.Error()), nil, err
}
_, _, err = app.Deliver(txGen.TxEncoder(), tx)
return simtypes.NewOperationMsg(svcMsgClientConn.GetMsgs()[0], true, "", protoCdc), nil, err
}
}
// SimulateMsgExecuteAuthorized generates a MsgExecuteAuthorized with random values.
// nolint: funlen
func SimulateMsgExecuteAuthorized(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, cdc cdctypes.AnyUnpacker, protoCdc *codec.ProtoCodec) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
hasGrant := false
var targetGrant types.AuthorizationGrant
var granterAddr sdk.AccAddress
var granteeAddr sdk.AccAddress
k.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant types.AuthorizationGrant) bool {
targetGrant = grant
granterAddr = granter
granteeAddr = grantee
hasGrant = true
return true
})
if !hasGrant {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, "Not found"), nil, nil
}
grantee, _ := simtypes.FindAccount(accs, granteeAddr)
granterAccount := ak.GetAccount(ctx, granterAddr)
granteeAccount := ak.GetAccount(ctx, granteeAddr)
granterspendableCoins := bk.SpendableCoins(ctx, granterAccount.GetAddress())
if granterspendableCoins.Empty() {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, "no coins"), nil, nil
}
if targetGrant.Expiration.Before(ctx.BlockHeader().Time) {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, "grant expired"), nil, nil
}
granteespendableCoins := bk.SpendableCoins(ctx, granteeAccount.GetAddress())
fees, err := simtypes.RandomFees(r, ctx, granteespendableCoins)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, "fee error"), nil, err
}
sendCoins := sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(10)))
execMsg := sdk.ServiceMsg{
MethodName: types.SendAuthorization{}.MethodName(),
Request: banktype.NewMsgSend(
granterAddr,
granteeAddr,
sendCoins,
),
}
msg := types.NewMsgExecAuthorized(grantee.Address, []sdk.ServiceMsg{execMsg})
sendGrant := targetGrant.Authorization.GetCachedValue().(*types.SendAuthorization)
allow, _, _ := sendGrant.Accept(execMsg, ctx.BlockHeader())
if !allow {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, "not allowed"), nil, nil
}
txGen := simappparams.MakeTestEncodingConfig().TxConfig
svcMsgClientConn := &msgservice.ServiceMsgClientConn{}
authzMsgClient := types.NewMsgClient(svcMsgClientConn)
_, err = authzMsgClient.ExecAuthorized(context.Background(), &msg)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, err.Error()), nil, err
}
tx, err := helpers.GenTx(
txGen,
svcMsgClientConn.GetMsgs(),
fees,
helpers.DefaultGenTxGas,
chainID,
[]uint64{granteeAccount.GetAccountNumber()},
[]uint64{granteeAccount.GetSequence()},
grantee.PrivKey,
)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, err.Error()), nil, err
}
_, _, err = app.Deliver(txGen.TxEncoder(), tx)
if err != nil {
if strings.Contains(err.Error(), "insufficient fee") {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, "insufficient fee"), nil, nil
}
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, err.Error()), nil, err
}
msg.UnpackInterfaces(cdc)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, "unmarshal error"), nil, err
}
return simtypes.NewOperationMsg(svcMsgClientConn.GetMsgs()[0], true, "success", protoCdc), nil, nil
}
}

View File

@ -0,0 +1,197 @@
package simulation_test
import (
"math/rand"
"testing"
"time"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp"
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
sdk "github.com/cosmos/cosmos-sdk/types"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/authz/simulation"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
type SimTestSuite struct {
suite.Suite
ctx sdk.Context
app *simapp.SimApp
protoCdc *codec.ProtoCodec
}
func (suite *SimTestSuite) SetupTest() {
checkTx := false
app := simapp.Setup(checkTx)
suite.app = app
suite.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{})
suite.protoCdc = codec.NewProtoCodec(suite.app.InterfaceRegistry())
}
func (suite *SimTestSuite) TestWeightedOperations() {
cdc := suite.app.AppCodec()
appParams := make(simtypes.AppParams)
weightesOps := simulation.WeightedOperations(appParams, cdc, suite.app.AccountKeeper,
suite.app.BankKeeper, suite.app.AuthzKeeper, cdc, suite.protoCdc,
)
// setup 3 accounts
s := rand.NewSource(1)
r := rand.New(s)
accs := suite.getTestingAccounts(r, 3)
expected := []struct {
weight int
opMsgRoute string
opMsgName string
}{
{simappparams.DefaultWeightMsgDelegate, types.ModuleName, simulation.TypeMsgGrantAuthorization},
{simappparams.DefaultWeightMsgUndelegate, types.ModuleName, simulation.TypeMsgRevokeAuthorization},
{simappparams.DefaultWeightMsgSend, types.ModuleName, simulation.TypeMsgExecDelegated},
}
for i, w := range weightesOps {
operationMsg, _, _ := w.Op()(r, suite.app.BaseApp, suite.ctx, accs, "")
// the following checks are very much dependent from the ordering of the output given
// by WeightedOperations. if the ordering in WeightedOperations changes some tests
// will fail
suite.Require().Equal(expected[i].weight, w.Weight(), "weight should be the same")
suite.Require().Equal(expected[i].opMsgRoute, operationMsg.Route, "route should be the same")
suite.Require().Equal(expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same")
}
}
func (suite *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account {
accounts := simtypes.RandomAccounts(r, n)
initAmt := sdk.TokensFromConsensusPower(200000)
initCoins := sdk.NewCoins(sdk.NewCoin("foo", initAmt))
// add coins to the accounts
for _, account := range accounts {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, account.Address)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
err := suite.app.BankKeeper.SetBalances(suite.ctx, account.Address, initCoins)
suite.Require().NoError(err)
}
return accounts
}
func (suite *SimTestSuite) TestSimulateGrantAuthorization() {
// setup 3 accounts
s := rand.NewSource(1)
r := rand.New(s)
accounts := suite.getTestingAccounts(r, 2)
blockTime := time.Now().UTC()
ctx := suite.ctx.WithBlockTime(blockTime)
// begin a new block
suite.app.BeginBlock(abci.RequestBeginBlock{
Header: tmproto.Header{
Height: suite.app.LastBlockHeight() + 1,
AppHash: suite.app.LastCommitID().Hash,
},
})
granter := accounts[0]
grantee := accounts[1]
// execute operation
op := simulation.SimulateMsgGrantAuthorization(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.AuthzKeeper, suite.protoCdc)
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, ctx, accounts, "")
suite.Require().NoError(err)
var msg types.MsgGrantAuthorizationRequest
suite.app.AppCodec().UnmarshalJSON(operationMsg.Msg, &msg)
suite.Require().True(operationMsg.OK)
suite.Require().Equal(granter.Address.String(), msg.Granter)
suite.Require().Equal(grantee.Address.String(), msg.Grantee)
suite.Require().Len(futureOperations, 0)
}
func (suite *SimTestSuite) TestSimulateRevokeAuthorization() {
// setup 3 accounts
s := rand.NewSource(1)
r := rand.New(s)
accounts := suite.getTestingAccounts(r, 3)
// begin a new block
suite.app.BeginBlock(abci.RequestBeginBlock{
Header: tmproto.Header{
Height: suite.app.LastBlockHeight() + 1,
AppHash: suite.app.LastCommitID().Hash,
}})
initAmt := sdk.TokensFromConsensusPower(200000)
initCoins := sdk.NewCoins(sdk.NewCoin("foo", initAmt))
granter := accounts[0]
grantee := accounts[1]
authorization := types.NewSendAuthorization(initCoins)
err := suite.app.AuthzKeeper.Grant(suite.ctx, grantee.Address, granter.Address, authorization, time.Now().Add(30*time.Hour))
suite.Require().NoError(err)
// execute operation
op := simulation.SimulateMsgRevokeAuthorization(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.AuthzKeeper, suite.protoCdc)
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
suite.Require().NoError(err)
var msg types.MsgRevokeAuthorizationRequest
suite.app.AppCodec().UnmarshalJSON(operationMsg.Msg, &msg)
suite.Require().True(operationMsg.OK)
suite.Require().Equal(granter.Address.String(), msg.Granter)
suite.Require().Equal(grantee.Address.String(), msg.Grantee)
suite.Require().Equal(types.SendAuthorization{}.MethodName(), msg.MethodName)
suite.Require().Len(futureOperations, 0)
}
func (suite *SimTestSuite) TestSimulateExecAuthorization() {
// setup 3 accounts
s := rand.NewSource(1)
r := rand.New(s)
accounts := suite.getTestingAccounts(r, 3)
// begin a new block
suite.app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}})
initAmt := sdk.TokensFromConsensusPower(200000)
initCoins := sdk.NewCoins(sdk.NewCoin("foo", initAmt))
granter := accounts[0]
grantee := accounts[1]
authorization := types.NewSendAuthorization(initCoins)
err := suite.app.AuthzKeeper.Grant(suite.ctx, grantee.Address, granter.Address, authorization, time.Now().Add(30*time.Hour))
suite.Require().NoError(err)
// execute operation
op := simulation.SimulateMsgExecuteAuthorized(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.AuthzKeeper, suite.app.AppCodec(), suite.protoCdc)
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
suite.Require().NoError(err)
var msg types.MsgExecAuthorizedRequest
suite.app.AppCodec().UnmarshalJSON(operationMsg.Msg, &msg)
suite.Require().True(operationMsg.OK)
suite.Require().Equal(grantee.Address.String(), msg.Grantee)
suite.Require().Len(futureOperations, 0)
}
func TestSimTestSuite(t *testing.T) {
suite.Run(t, new(SimTestSuite))
}

View File

@ -0,0 +1,63 @@
package types
import (
"time"
"github.com/gogo/protobuf/proto"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
type Authorization interface {
proto.Message
// MethodName returns the fully-qualified Msg service method name as described in ADR 031.
MethodName() string
// Accept determines whether this grant permits the provided sdk.ServiceMsg to be performed, and if
// so provides an upgraded authorization instance.
Accept(msg sdk.ServiceMsg, block tmproto.Header) (allow bool, updated Authorization, delete bool)
}
// NewAuthorizationGrant returns new AuthrizationGrant
func NewAuthorizationGrant(authorization Authorization, expiration time.Time) (AuthorizationGrant, error) {
auth := AuthorizationGrant{
Expiration: expiration,
}
msg, ok := authorization.(proto.Message)
if !ok {
return AuthorizationGrant{}, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", authorization)
}
any, err := types.NewAnyWithValue(msg)
if err != nil {
return AuthorizationGrant{}, err
}
auth.Authorization = any
return auth, nil
}
var (
_ types.UnpackInterfacesMessage = &AuthorizationGrant{}
)
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
func (auth AuthorizationGrant) UnpackInterfaces(unpacker types.AnyUnpacker) error {
var authorization Authorization
return unpacker.UnpackAny(auth.Authorization, &authorization)
}
// GetAuthorizationGrant returns the cached value from the AuthorizationGrant.Authorization if present.
func (auth AuthorizationGrant) GetAuthorizationGrant() Authorization {
authorization, ok := auth.Authorization.GetCachedValue().(Authorization)
if !ok {
return nil
}
return authorization
}

759
x/authz/types/authz.pb.go Normal file
View File

@ -0,0 +1,759 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: cosmos/authz/v1beta1/authz.proto
package types
import (
fmt "fmt"
types1 "github.com/cosmos/cosmos-sdk/codec/types"
github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types"
types "github.com/cosmos/cosmos-sdk/types"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
_ "github.com/golang/protobuf/ptypes/timestamp"
_ "github.com/regen-network/cosmos-proto"
io "io"
math "math"
math_bits "math/bits"
time "time"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
var _ = time.Kitchen
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// SendAuthorization allows the grantee to spend up to spend_limit coins from
// the granter's account.
type SendAuthorization struct {
SpendLimit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=spend_limit,json=spendLimit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"spend_limit"`
}
func (m *SendAuthorization) Reset() { *m = SendAuthorization{} }
func (m *SendAuthorization) String() string { return proto.CompactTextString(m) }
func (*SendAuthorization) ProtoMessage() {}
func (*SendAuthorization) Descriptor() ([]byte, []int) {
return fileDescriptor_544dc2e84b61c637, []int{0}
}
func (m *SendAuthorization) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *SendAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_SendAuthorization.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 *SendAuthorization) XXX_Merge(src proto.Message) {
xxx_messageInfo_SendAuthorization.Merge(m, src)
}
func (m *SendAuthorization) XXX_Size() int {
return m.Size()
}
func (m *SendAuthorization) XXX_DiscardUnknown() {
xxx_messageInfo_SendAuthorization.DiscardUnknown(m)
}
var xxx_messageInfo_SendAuthorization proto.InternalMessageInfo
func (m *SendAuthorization) GetSpendLimit() github_com_cosmos_cosmos_sdk_types.Coins {
if m != nil {
return m.SpendLimit
}
return nil
}
// GenericAuthorization gives the grantee unrestricted permissions to execute
// the provided method on behalf of the granter's account.
type GenericAuthorization struct {
// method name to grant unrestricted permissions to execute
// Note: MethodName() is already a method on `GenericAuthorization` type,
// we need some custom naming here so using `MessageName`
MessageName string `protobuf:"bytes,1,opt,name=method_name,json=methodName,proto3" json:"method_name,omitempty"`
}
func (m *GenericAuthorization) Reset() { *m = GenericAuthorization{} }
func (m *GenericAuthorization) String() string { return proto.CompactTextString(m) }
func (*GenericAuthorization) ProtoMessage() {}
func (*GenericAuthorization) Descriptor() ([]byte, []int) {
return fileDescriptor_544dc2e84b61c637, []int{1}
}
func (m *GenericAuthorization) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *GenericAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_GenericAuthorization.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 *GenericAuthorization) XXX_Merge(src proto.Message) {
xxx_messageInfo_GenericAuthorization.Merge(m, src)
}
func (m *GenericAuthorization) XXX_Size() int {
return m.Size()
}
func (m *GenericAuthorization) XXX_DiscardUnknown() {
xxx_messageInfo_GenericAuthorization.DiscardUnknown(m)
}
var xxx_messageInfo_GenericAuthorization proto.InternalMessageInfo
func (m *GenericAuthorization) GetMessageName() string {
if m != nil {
return m.MessageName
}
return ""
}
// AuthorizationGrant gives permissions to execute
// the provide method with expiration time.
type AuthorizationGrant struct {
Authorization *types1.Any `protobuf:"bytes,1,opt,name=authorization,proto3" json:"authorization,omitempty"`
Expiration time.Time `protobuf:"bytes,2,opt,name=expiration,proto3,stdtime" json:"expiration"`
}
func (m *AuthorizationGrant) Reset() { *m = AuthorizationGrant{} }
func (m *AuthorizationGrant) String() string { return proto.CompactTextString(m) }
func (*AuthorizationGrant) ProtoMessage() {}
func (*AuthorizationGrant) Descriptor() ([]byte, []int) {
return fileDescriptor_544dc2e84b61c637, []int{2}
}
func (m *AuthorizationGrant) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *AuthorizationGrant) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_AuthorizationGrant.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 *AuthorizationGrant) XXX_Merge(src proto.Message) {
xxx_messageInfo_AuthorizationGrant.Merge(m, src)
}
func (m *AuthorizationGrant) XXX_Size() int {
return m.Size()
}
func (m *AuthorizationGrant) XXX_DiscardUnknown() {
xxx_messageInfo_AuthorizationGrant.DiscardUnknown(m)
}
var xxx_messageInfo_AuthorizationGrant proto.InternalMessageInfo
func (m *AuthorizationGrant) GetAuthorization() *types1.Any {
if m != nil {
return m.Authorization
}
return nil
}
func (m *AuthorizationGrant) GetExpiration() time.Time {
if m != nil {
return m.Expiration
}
return time.Time{}
}
func init() {
proto.RegisterType((*SendAuthorization)(nil), "cosmos.authz.v1beta1.SendAuthorization")
proto.RegisterType((*GenericAuthorization)(nil), "cosmos.authz.v1beta1.GenericAuthorization")
proto.RegisterType((*AuthorizationGrant)(nil), "cosmos.authz.v1beta1.AuthorizationGrant")
}
func init() { proto.RegisterFile("cosmos/authz/v1beta1/authz.proto", fileDescriptor_544dc2e84b61c637) }
var fileDescriptor_544dc2e84b61c637 = []byte{
// 410 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xbf, 0x8e, 0xd3, 0x30,
0x1c, 0xc7, 0x63, 0x90, 0x10, 0x38, 0x3a, 0xa1, 0x46, 0x19, 0xee, 0x3a, 0x24, 0xd5, 0x4d, 0x15,
0xd2, 0x39, 0x77, 0xc7, 0xc6, 0x76, 0xe1, 0xa4, 0x5b, 0x38, 0x86, 0xc0, 0x04, 0x43, 0xe5, 0x24,
0x26, 0xb1, 0xa8, 0xed, 0x28, 0x76, 0xd0, 0xf5, 0x9e, 0xa2, 0x03, 0x2f, 0x01, 0x33, 0x0f, 0x51,
0x31, 0x55, 0x4c, 0x4c, 0x2d, 0x4a, 0x5f, 0x04, 0xc5, 0x76, 0x50, 0x53, 0x10, 0x53, 0xfc, 0xfb,
0xf3, 0xfd, 0xe4, 0x9b, 0x6f, 0x0c, 0x27, 0x99, 0x90, 0x4c, 0xc8, 0x08, 0x37, 0xaa, 0xbc, 0x8f,
0x3e, 0x5d, 0xa4, 0x44, 0xe1, 0x0b, 0x53, 0xa1, 0xaa, 0x16, 0x4a, 0x78, 0xbe, 0xd9, 0x40, 0xa6,
0x67, 0x37, 0xc6, 0x81, 0xd5, 0xa5, 0x58, 0x92, 0x3f, 0xb2, 0x4c, 0x50, 0x6e, 0x54, 0xe3, 0x13,
0x33, 0x9f, 0xe9, 0x2a, 0xb2, 0x08, 0x33, 0x0a, 0x0b, 0x21, 0x8a, 0x39, 0x89, 0x74, 0x95, 0x36,
0x1f, 0x22, 0x45, 0x19, 0x91, 0x0a, 0xb3, 0xca, 0x2e, 0xf8, 0x85, 0x28, 0x84, 0x11, 0x76, 0xa7,
0x9e, 0x78, 0x28, 0xc3, 0x7c, 0x61, 0x46, 0xa7, 0x9f, 0x01, 0x1c, 0xbd, 0x21, 0x3c, 0xbf, 0x6a,
0x54, 0x29, 0x6a, 0x7a, 0x8f, 0x15, 0x15, 0xdc, 0x9b, 0x43, 0x57, 0x56, 0x84, 0xe7, 0xb3, 0x39,
0x65, 0x54, 0x1d, 0x83, 0xc9, 0xc3, 0xa9, 0x7b, 0x79, 0x82, 0xac, 0x97, 0xce, 0x78, 0xff, 0x35,
0xe8, 0xa5, 0xa0, 0x3c, 0x3e, 0x5f, 0x6d, 0x42, 0xe7, 0xeb, 0x36, 0x9c, 0x16, 0x54, 0x95, 0x4d,
0x8a, 0x32, 0xc1, 0xac, 0x71, 0xfb, 0x38, 0x93, 0xf9, 0xc7, 0x48, 0x2d, 0x2a, 0x22, 0xb5, 0x40,
0x26, 0x50, 0xf3, 0x5f, 0x75, 0xf8, 0x17, 0xa3, 0x1f, 0xdf, 0xce, 0x8e, 0x06, 0x06, 0x4e, 0xdf,
0x43, 0xff, 0x86, 0x70, 0x52, 0xd3, 0x6c, 0x68, 0xec, 0x1c, 0xba, 0x8c, 0xa8, 0x52, 0xe4, 0x33,
0x8e, 0x19, 0x39, 0x06, 0x13, 0x30, 0x7d, 0x12, 0x3f, 0x6d, 0x37, 0xa1, 0x7b, 0x4b, 0xa4, 0xc4,
0x05, 0x79, 0x8d, 0x19, 0x49, 0xa0, 0xd9, 0xe9, 0xce, 0xff, 0x82, 0x7f, 0x01, 0xd0, 0x1b, 0x74,
0x6e, 0x6a, 0xcc, 0x95, 0x77, 0x0b, 0x8f, 0xf0, 0x7e, 0x57, 0xd3, 0xdd, 0x4b, 0x1f, 0x99, 0xf4,
0x50, 0x9f, 0x1e, 0xba, 0xe2, 0x8b, 0x78, 0xf4, 0xfd, 0x10, 0x9b, 0x0c, 0xd5, 0xde, 0x35, 0x84,
0xe4, 0xae, 0xa2, 0xb5, 0x61, 0x3d, 0xd0, 0xac, 0xf1, 0x5f, 0xac, 0xb7, 0xfd, 0x0f, 0x8c, 0x1f,
0x77, 0x19, 0x2e, 0xb7, 0x21, 0x48, 0xf6, 0x74, 0xf1, 0xf5, 0xaa, 0x0d, 0xc0, 0xba, 0x0d, 0xc0,
0xaf, 0x36, 0x00, 0xcb, 0x5d, 0xe0, 0xac, 0x77, 0x81, 0xf3, 0x73, 0x17, 0x38, 0xef, 0x9e, 0xfd,
0x37, 0xeb, 0x3b, 0x7b, 0x2d, 0x75, 0xe6, 0xe9, 0x23, 0xfd, 0xbe, 0xe7, 0xbf, 0x03, 0x00, 0x00,
0xff, 0xff, 0x87, 0x61, 0xb9, 0xa8, 0xb3, 0x02, 0x00, 0x00,
}
func (m *SendAuthorization) 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 *SendAuthorization) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *SendAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.SpendLimit) > 0 {
for iNdEx := len(m.SpendLimit) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.SpendLimit[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 *GenericAuthorization) 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 *GenericAuthorization) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GenericAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.MessageName) > 0 {
i -= len(m.MessageName)
copy(dAtA[i:], m.MessageName)
i = encodeVarintAuthz(dAtA, i, uint64(len(m.MessageName)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *AuthorizationGrant) 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 *AuthorizationGrant) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *AuthorizationGrant) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expiration, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Expiration):])
if err1 != nil {
return 0, err1
}
i -= n1
i = encodeVarintAuthz(dAtA, i, uint64(n1))
i--
dAtA[i] = 0x12
if m.Authorization != nil {
{
size, err := m.Authorization.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 encodeVarintAuthz(dAtA []byte, offset int, v uint64) int {
offset -= sovAuthz(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *SendAuthorization) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if len(m.SpendLimit) > 0 {
for _, e := range m.SpendLimit {
l = e.Size()
n += 1 + l + sovAuthz(uint64(l))
}
}
return n
}
func (m *GenericAuthorization) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.MessageName)
if l > 0 {
n += 1 + l + sovAuthz(uint64(l))
}
return n
}
func (m *AuthorizationGrant) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Authorization != nil {
l = m.Authorization.Size()
n += 1 + l + sovAuthz(uint64(l))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Expiration)
n += 1 + l + sovAuthz(uint64(l))
return n
}
func sovAuthz(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozAuthz(x uint64) (n int) {
return sovAuthz(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *SendAuthorization) 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: SendAuthorization: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: SendAuthorization: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field SpendLimit", 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.SpendLimit = append(m.SpendLimit, types.Coin{})
if err := m.SpendLimit[len(m.SpendLimit)-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 *GenericAuthorization) 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: GenericAuthorization: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GenericAuthorization: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field MessageName", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAuthz
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthAuthz
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthAuthz
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.MessageName = string(dAtA[iNdEx:postIndex])
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 *AuthorizationGrant) 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: AuthorizationGrant: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: AuthorizationGrant: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Authorization", 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.Authorization == nil {
m.Authorization = &types1.Any{}
}
if err := m.Authorization.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Expiration", 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 err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Expiration, 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 skipAuthz(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowAuthz
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowAuthz
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowAuthz
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthAuthz
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupAuthz
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthAuthz
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthAuthz = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowAuthz = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupAuthz = fmt.Errorf("proto: unexpected end of group")
)

25
x/authz/types/codec.go Normal file
View File

@ -0,0 +1,25 @@
package types
import (
types "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/msgservice"
)
// RegisterInterfaces registers the interfaces types with the interface registry
func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterImplementations((*sdk.MsgRequest)(nil),
&MsgGrantAuthorizationRequest{},
&MsgRevokeAuthorizationRequest{},
&MsgExecAuthorizedRequest{},
)
registry.RegisterInterface(
"cosmos.authz.v1beta1.Authorization",
(*Authorization)(nil),
&SendAuthorization{},
&GenericAuthorization{},
)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}

10
x/authz/types/errors.go Normal file
View File

@ -0,0 +1,10 @@
package types
import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// x/authz module sentinel errors
var (
ErrInvalidExpirationTime = sdkerrors.Register(ModuleName, 3, "expiration time of authorization should be more than current time")
)

14
x/authz/types/events.go Normal file
View File

@ -0,0 +1,14 @@
package types
// authz module events
const (
EventGrantAuthorization = "grant-authorization"
EventRevokeAuthorization = "revoke-authorization"
EventExecuteAuthorization = "execute-authorization"
AttributeKeyGrantType = "grant-type"
AttributeKeyGranteeAddress = "grantee"
AttributeKeyGranterAddress = "granter"
AttributeValueCategory = ModuleName
)

View File

@ -0,0 +1,16 @@
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
// AccountKeeper defines the expected account keeper (noalias)
type AccountKeeper interface {
GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI
}
// BankKeeper defines the expected interface needed to retrieve account balances.
type BankKeeper interface {
SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
}

View File

@ -0,0 +1,28 @@
package types
import (
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
var (
_ Authorization = &GenericAuthorization{}
)
// NewGenericAuthorization creates a new GenericAuthorization object.
func NewGenericAuthorization(methodName string) *GenericAuthorization {
return &GenericAuthorization{
MessageName: methodName,
}
}
// MethodName implements Authorization.MethodName.
func (cap GenericAuthorization) MethodName() string {
return cap.MessageName
}
// Accept implements Authorization.Accept.
func (cap GenericAuthorization) Accept(msg sdk.ServiceMsg, block tmproto.Header) (allow bool, updated Authorization, delete bool) {
return true, &cap, false
}

41
x/authz/types/genesis.go Normal file
View File

@ -0,0 +1,41 @@
package types
import (
"github.com/cosmos/cosmos-sdk/codec/types"
)
// NewGenesisState creates new GenesisState object
func NewGenesisState(entries []GrantAuthorization) *GenesisState {
return &GenesisState{
Authorization: entries,
}
}
// ValidateGenesis check the given genesis state has no integrity issues
func ValidateGenesis(data GenesisState) error {
return nil
}
// DefaultGenesisState - Return a default genesis state
func DefaultGenesisState() *GenesisState {
return &GenesisState{}
}
var _ types.UnpackInterfacesMessage = GenesisState{}
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
func (data GenesisState) UnpackInterfaces(unpacker types.AnyUnpacker) error {
for _, authorization := range data.Authorization {
err := authorization.UnpackInterfaces(unpacker)
if err != nil {
return err
}
}
return nil
}
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
func (msg GrantAuthorization) UnpackInterfaces(unpacker types.AnyUnpacker) error {
var authorization Authorization
return unpacker.UnpackAny(msg.Authorization, &authorization)
}

680
x/authz/types/genesis.pb.go Normal file
View File

@ -0,0 +1,680 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: cosmos/authz/v1beta1/genesis.proto
package types
import (
fmt "fmt"
types "github.com/cosmos/cosmos-sdk/codec/types"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
_ "github.com/golang/protobuf/ptypes/timestamp"
_ "github.com/regen-network/cosmos-proto"
io "io"
math "math"
math_bits "math/bits"
time "time"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
var _ = time.Kitchen
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// GenesisState defines the authz module's genesis state.
type GenesisState struct {
Authorization []GrantAuthorization `protobuf:"bytes,1,rep,name=authorization,proto3" json:"authorization"`
}
func (m *GenesisState) Reset() { *m = GenesisState{} }
func (m *GenesisState) String() string { return proto.CompactTextString(m) }
func (*GenesisState) ProtoMessage() {}
func (*GenesisState) Descriptor() ([]byte, []int) {
return fileDescriptor_4c2fbb971da7c892, []int{0}
}
func (m *GenesisState) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_GenesisState.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 *GenesisState) XXX_Merge(src proto.Message) {
xxx_messageInfo_GenesisState.Merge(m, src)
}
func (m *GenesisState) XXX_Size() int {
return m.Size()
}
func (m *GenesisState) XXX_DiscardUnknown() {
xxx_messageInfo_GenesisState.DiscardUnknown(m)
}
var xxx_messageInfo_GenesisState proto.InternalMessageInfo
func (m *GenesisState) GetAuthorization() []GrantAuthorization {
if m != nil {
return m.Authorization
}
return nil
}
// GrantAuthorization defines the GenesisState/GrantAuthorization type.
type GrantAuthorization struct {
Granter string `protobuf:"bytes,1,opt,name=granter,proto3" json:"granter,omitempty"`
Grantee string `protobuf:"bytes,2,opt,name=grantee,proto3" json:"grantee,omitempty"`
Authorization *types.Any `protobuf:"bytes,3,opt,name=authorization,proto3" json:"authorization,omitempty"`
Expiration time.Time `protobuf:"bytes,4,opt,name=expiration,proto3,stdtime" json:"expiration"`
}
func (m *GrantAuthorization) Reset() { *m = GrantAuthorization{} }
func (m *GrantAuthorization) String() string { return proto.CompactTextString(m) }
func (*GrantAuthorization) ProtoMessage() {}
func (*GrantAuthorization) Descriptor() ([]byte, []int) {
return fileDescriptor_4c2fbb971da7c892, []int{1}
}
func (m *GrantAuthorization) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *GrantAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_GrantAuthorization.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 *GrantAuthorization) XXX_Merge(src proto.Message) {
xxx_messageInfo_GrantAuthorization.Merge(m, src)
}
func (m *GrantAuthorization) XXX_Size() int {
return m.Size()
}
func (m *GrantAuthorization) XXX_DiscardUnknown() {
xxx_messageInfo_GrantAuthorization.DiscardUnknown(m)
}
var xxx_messageInfo_GrantAuthorization proto.InternalMessageInfo
func (m *GrantAuthorization) GetGranter() string {
if m != nil {
return m.Granter
}
return ""
}
func (m *GrantAuthorization) GetGrantee() string {
if m != nil {
return m.Grantee
}
return ""
}
func (m *GrantAuthorization) GetAuthorization() *types.Any {
if m != nil {
return m.Authorization
}
return nil
}
func (m *GrantAuthorization) GetExpiration() time.Time {
if m != nil {
return m.Expiration
}
return time.Time{}
}
func init() {
proto.RegisterType((*GenesisState)(nil), "cosmos.authz.v1beta1.GenesisState")
proto.RegisterType((*GrantAuthorization)(nil), "cosmos.authz.v1beta1.GrantAuthorization")
}
func init() {
proto.RegisterFile("cosmos/authz/v1beta1/genesis.proto", fileDescriptor_4c2fbb971da7c892)
}
var fileDescriptor_4c2fbb971da7c892 = []byte{
// 346 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0xbb, 0x6e, 0xc2, 0x30,
0x14, 0x86, 0xe3, 0x82, 0x7a, 0x31, 0x65, 0x68, 0xc4, 0x90, 0x22, 0x35, 0x20, 0xa6, 0xa8, 0x12,
0xb6, 0xa0, 0x4f, 0x40, 0x84, 0xc4, 0xd4, 0x85, 0x32, 0x75, 0xa9, 0x1c, 0x70, 0x4d, 0xd4, 0x26,
0x8e, 0xe2, 0x43, 0x05, 0x3c, 0x05, 0x0f, 0xd3, 0x87, 0x40, 0x9d, 0x18, 0xbb, 0xf4, 0x22, 0x78,
0x91, 0x2a, 0x71, 0xa2, 0x72, 0x9b, 0xe2, 0xf8, 0xff, 0xce, 0xf9, 0x7f, 0x9f, 0x83, 0x1b, 0x43,
0xa9, 0x02, 0xa9, 0x28, 0x9b, 0xc0, 0x78, 0x4e, 0xdf, 0x5a, 0x1e, 0x07, 0xd6, 0xa2, 0x82, 0x87,
0x5c, 0xf9, 0x8a, 0x44, 0xb1, 0x04, 0x69, 0x56, 0x34, 0x43, 0x52, 0x86, 0x64, 0x4c, 0xb5, 0x26,
0xa4, 0x14, 0xaf, 0x9c, 0xa6, 0x8c, 0x37, 0x79, 0xa6, 0xe0, 0x07, 0x5c, 0x01, 0x0b, 0x22, 0x5d,
0x56, 0xbd, 0xde, 0x07, 0x58, 0x38, 0xcb, 0xa4, 0x8a, 0x90, 0x42, 0xa6, 0x47, 0x9a, 0x9c, 0xf2,
0x02, 0xed, 0xf3, 0xa4, 0x85, 0xcc, 0x54, 0x4b, 0x37, 0x47, 0x63, 0xc2, 0x54, 0xcb, 0x8d, 0x11,
0xbe, 0xec, 0xe9, 0xc8, 0x0f, 0xc0, 0x80, 0x9b, 0x03, 0x5c, 0x4e, 0x48, 0x19, 0xfb, 0x73, 0x06,
0xbe, 0x0c, 0x2d, 0x54, 0x2f, 0x38, 0xa5, 0xb6, 0x43, 0x8e, 0xbd, 0x84, 0xf4, 0x62, 0x16, 0x42,
0x67, 0x9b, 0x77, 0x8b, 0xcb, 0xef, 0x9a, 0xd1, 0xdf, 0x6d, 0xd2, 0xf8, 0x42, 0xd8, 0x3c, 0x64,
0x4d, 0x0b, 0x9f, 0x89, 0xe4, 0x96, 0xc7, 0x16, 0xaa, 0x23, 0xe7, 0xa2, 0x9f, 0xff, 0xfe, 0x2b,
0xdc, 0x3a, 0xd9, 0x56, 0xb8, 0x79, 0xbf, 0x1f, 0xb0, 0x50, 0x47, 0x4e, 0xa9, 0x5d, 0x21, 0x7a,
0x66, 0x24, 0x9f, 0x19, 0xe9, 0x84, 0x33, 0xf7, 0xea, 0xe3, 0xbd, 0x59, 0xde, 0xf1, 0xdc, 0x4b,
0x66, 0x76, 0x31, 0xe6, 0xd3, 0xc8, 0x8f, 0x75, 0xaf, 0x62, 0xda, 0xab, 0x7a, 0xd0, 0x6b, 0x90,
0x2f, 0xc8, 0x3d, 0x4f, 0x9e, 0xb7, 0xf8, 0xa9, 0xa1, 0xfe, 0x56, 0x9d, 0xdb, 0x5d, 0xae, 0x6d,
0xb4, 0x5a, 0xdb, 0xe8, 0x77, 0x6d, 0xa3, 0xc5, 0xc6, 0x36, 0x56, 0x1b, 0xdb, 0xf8, 0xdc, 0xd8,
0xc6, 0xe3, 0xad, 0xf0, 0x61, 0x3c, 0xf1, 0xc8, 0x50, 0x06, 0xd9, 0x5e, 0xb2, 0x4f, 0x53, 0x8d,
0x5e, 0xe8, 0x34, 0x5b, 0x0b, 0xcc, 0x22, 0xae, 0xbc, 0xd3, 0xd4, 0xef, 0xee, 0x2f, 0x00, 0x00,
0xff, 0xff, 0x52, 0x9c, 0x43, 0x7a, 0x5a, 0x02, 0x00, 0x00,
}
func (m *GenesisState) 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 *GenesisState) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Authorization) > 0 {
for iNdEx := len(m.Authorization) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.Authorization[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
func (m *GrantAuthorization) 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 *GrantAuthorization) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GrantAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expiration, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Expiration):])
if err1 != nil {
return 0, err1
}
i -= n1
i = encodeVarintGenesis(dAtA, i, uint64(n1))
i--
dAtA[i] = 0x22
if m.Authorization != nil {
{
size, err := m.Authorization.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x1a
}
if len(m.Grantee) > 0 {
i -= len(m.Grantee)
copy(dAtA[i:], m.Grantee)
i = encodeVarintGenesis(dAtA, i, uint64(len(m.Grantee)))
i--
dAtA[i] = 0x12
}
if len(m.Granter) > 0 {
i -= len(m.Granter)
copy(dAtA[i:], m.Granter)
i = encodeVarintGenesis(dAtA, i, uint64(len(m.Granter)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int {
offset -= sovGenesis(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *GenesisState) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if len(m.Authorization) > 0 {
for _, e := range m.Authorization {
l = e.Size()
n += 1 + l + sovGenesis(uint64(l))
}
}
return n
}
func (m *GrantAuthorization) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Granter)
if l > 0 {
n += 1 + l + sovGenesis(uint64(l))
}
l = len(m.Grantee)
if l > 0 {
n += 1 + l + sovGenesis(uint64(l))
}
if m.Authorization != nil {
l = m.Authorization.Size()
n += 1 + l + sovGenesis(uint64(l))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Expiration)
n += 1 + l + sovGenesis(uint64(l))
return n
}
func sovGenesis(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozGenesis(x uint64) (n int) {
return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *GenesisState) 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 ErrIntOverflowGenesis
}
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: GenesisState: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Authorization", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Authorization = append(m.Authorization, GrantAuthorization{})
if err := m.Authorization[len(m.Authorization)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenesis(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *GrantAuthorization) 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 ErrIntOverflowGenesis
}
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: GrantAuthorization: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GrantAuthorization: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Granter", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Granter = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Grantee", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Grantee = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Authorization", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Authorization == nil {
m.Authorization = &types.Any{}
}
if err := m.Authorization.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Expiration", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Expiration, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenesis(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipGenesis(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenesis
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenesis
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenesis
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthGenesis
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupGenesis
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthGenesis
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group")
)

41
x/authz/types/keys.go Normal file
View File

@ -0,0 +1,41 @@
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
const (
// ModuleName is the module name constant used in many places
ModuleName = "authz"
// StoreKey is the store key string for authz
StoreKey = ModuleName
// RouterKey is the message route for authz
RouterKey = ModuleName
// QuerierRoute is the querier route for authz
QuerierRoute = ModuleName
)
// Keys for authz store
// Items are stored with the following key: values
//
// - 0x01<granterAddress_Bytes><granteeAddress_Bytes><msgType_Bytes>: Grant
var (
// Keys for store prefixes
GrantKey = []byte{0x01} // prefix for each key
)
// GetAuthorizationStoreKey - return authorization store key
func GetAuthorizationStoreKey(grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) []byte {
return append(append(append(GrantKey, granter.Bytes()...), grantee.Bytes()...), []byte(msgType)...)
}
// ExtractAddressesFromGrantKey - split granter & grantee address from the authorization key
func ExtractAddressesFromGrantKey(key []byte) (granterAddr, granteeAddr sdk.AccAddress) {
granterAddr = sdk.AccAddress(key[1 : sdk.AddrLen+1])
granteeAddr = sdk.AccAddress(key[sdk.AddrLen+1 : sdk.AddrLen*2+1])
return granterAddr, granteeAddr
}

View File

@ -0,0 +1,20 @@
package types
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
)
var granter = sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
var grantee = sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
var msgType = SendAuthorization{}.MethodName()
func TestGrantkey(t *testing.T) {
granter1, grantee1 := ExtractAddressesFromGrantKey(GetAuthorizationStoreKey(grantee, granter, msgType))
require.Equal(t, granter, granter1)
require.Equal(t, grantee, grantee1)
}

215
x/authz/types/msgs.go Normal file
View File

@ -0,0 +1,215 @@
package types
import (
"time"
"github.com/gogo/protobuf/proto"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
var (
_ sdk.MsgRequest = &MsgGrantAuthorizationRequest{}
_ sdk.MsgRequest = &MsgRevokeAuthorizationRequest{}
_ sdk.MsgRequest = &MsgExecAuthorizedRequest{}
_ types.UnpackInterfacesMessage = &MsgGrantAuthorizationRequest{}
_ types.UnpackInterfacesMessage = &MsgExecAuthorizedRequest{}
)
// NewMsgGrantAuthorization creates a new MsgGrantAuthorization
//nolint:interfacer
func NewMsgGrantAuthorization(granter sdk.AccAddress, grantee sdk.AccAddress, authorization Authorization, expiration time.Time) (*MsgGrantAuthorizationRequest, error) {
m := &MsgGrantAuthorizationRequest{
Granter: granter.String(),
Grantee: grantee.String(),
Expiration: expiration,
}
err := m.SetAuthorization(authorization)
if err != nil {
return nil, err
}
return m, nil
}
// GetSigners implements Msg
func (msg MsgGrantAuthorizationRequest) GetSigners() []sdk.AccAddress {
granter, err := sdk.AccAddressFromBech32(msg.Granter)
if err != nil {
panic(err)
}
return []sdk.AccAddress{granter}
}
// ValidateBasic implements Msg
func (msg MsgGrantAuthorizationRequest) ValidateBasic() error {
granter, err := sdk.AccAddressFromBech32(msg.Granter)
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid granter address")
}
grantee, err := sdk.AccAddressFromBech32(msg.Grantee)
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid granter address")
}
if granter.Equals(grantee) {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "granter and grantee cannot be same")
}
if msg.Expiration.Unix() < time.Now().Unix() {
return sdkerrors.Wrap(ErrInvalidExpirationTime, "Time can't be in the past")
}
return nil
}
// GetGrantAuthorization returns the cache value from the MsgGrantAuthorization.Authorization if present.
func (msg *MsgGrantAuthorizationRequest) GetGrantAuthorization() Authorization {
authorization, ok := msg.Authorization.GetCachedValue().(Authorization)
if !ok {
return nil
}
return authorization
}
// SetAuthorization converts Authorization to any and adds it to MsgGrantAuthorization.Authorization.
func (msg *MsgGrantAuthorizationRequest) SetAuthorization(authorization Authorization) error {
m, ok := authorization.(proto.Message)
if !ok {
return sdkerrors.Wrapf(sdkerrors.ErrPackAny, "can't proto marshal %T", m)
}
any, err := types.NewAnyWithValue(m)
if err != nil {
return err
}
msg.Authorization = any
return nil
}
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
func (msg MsgExecAuthorizedRequest) UnpackInterfaces(unpacker types.AnyUnpacker) error {
for _, x := range msg.Msgs {
var msgExecAuthorized sdk.MsgRequest
err := unpacker.UnpackAny(x, &msgExecAuthorized)
if err != nil {
return err
}
}
return nil
}
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
func (msg MsgGrantAuthorizationRequest) UnpackInterfaces(unpacker types.AnyUnpacker) error {
var authorization Authorization
return unpacker.UnpackAny(msg.Authorization, &authorization)
}
// NewMsgRevokeAuthorization creates a new MsgRevokeAuthorization
//nolint:interfacer
func NewMsgRevokeAuthorization(granter sdk.AccAddress, grantee sdk.AccAddress, methodName string) MsgRevokeAuthorizationRequest {
return MsgRevokeAuthorizationRequest{
Granter: granter.String(),
Grantee: grantee.String(),
MethodName: methodName,
}
}
// GetSigners implements Msg
func (msg MsgRevokeAuthorizationRequest) GetSigners() []sdk.AccAddress {
granter, err := sdk.AccAddressFromBech32(msg.Granter)
if err != nil {
panic(err)
}
return []sdk.AccAddress{granter}
}
// ValidateBasic implements MsgRequest.ValidateBasic
func (msg MsgRevokeAuthorizationRequest) ValidateBasic() error {
granter, err := sdk.AccAddressFromBech32(msg.Granter)
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid granter address")
}
grantee, err := sdk.AccAddressFromBech32(msg.Grantee)
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid grantee address")
}
if granter.Equals(grantee) {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "granter and grantee cannot be same")
}
if msg.MethodName == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "missing method name")
}
return nil
}
// NewMsgExecAuthorized creates a new MsgExecAuthorized
//nolint:interfacer
func NewMsgExecAuthorized(grantee sdk.AccAddress, msgs []sdk.ServiceMsg) MsgExecAuthorizedRequest {
msgsAny := make([]*types.Any, len(msgs))
for i, msg := range msgs {
bz, err := proto.Marshal(msg.Request)
if err != nil {
panic(err)
}
anyMsg := &types.Any{
TypeUrl: msg.MethodName,
Value: bz,
}
msgsAny[i] = anyMsg
}
return MsgExecAuthorizedRequest{
Grantee: grantee.String(),
Msgs: msgsAny,
}
}
// GetServiceMsgs returns the cache values from the MsgExecAuthorized.Msgs if present.
func (msg MsgExecAuthorizedRequest) GetServiceMsgs() ([]sdk.ServiceMsg, error) {
msgs := make([]sdk.ServiceMsg, len(msg.Msgs))
for i, msgAny := range msg.Msgs {
msgReq, ok := msgAny.GetCachedValue().(sdk.MsgRequest)
if !ok {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "messages contains %T which is not a sdk.MsgRequest", msgAny)
}
srvMsg := sdk.ServiceMsg{
MethodName: msgAny.TypeUrl,
Request: msgReq,
}
msgs[i] = srvMsg
}
return msgs, nil
}
// GetSigners implements Msg
func (msg MsgExecAuthorizedRequest) GetSigners() []sdk.AccAddress {
grantee, err := sdk.AccAddressFromBech32(msg.Grantee)
if err != nil {
panic(err)
}
return []sdk.AccAddress{grantee}
}
// ValidateBasic implements Msg
func (msg MsgExecAuthorizedRequest) ValidateBasic() error {
_, err := sdk.AccAddressFromBech32(msg.Grantee)
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid grantee address")
}
if len(msg.Msgs) == 0 {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "messages cannot be empty")
}
return nil
}

103
x/authz/types/msgs_test.go Normal file
View File

@ -0,0 +1,103 @@
package types_test
import (
"testing"
"time"
"github.com/stretchr/testify/require"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)
var (
coinsPos = sdk.NewCoins(sdk.NewInt64Coin("steak", 100))
granter = sdk.AccAddress("_______granter______")
grantee = sdk.AccAddress("_______grantee______")
)
func TestMsgExecAuthorized(t *testing.T) {
tests := []struct {
title string
grantee sdk.AccAddress
msgs []sdk.ServiceMsg
expectPass bool
}{
{"nil grantee address", nil, []sdk.ServiceMsg{}, false},
{"zero-messages test: should fail", grantee, []sdk.ServiceMsg{}, false},
{"valid test: msg type", grantee, []sdk.ServiceMsg{
{
MethodName: types.SendAuthorization{}.MethodName(),
Request: &banktypes.MsgSend{
Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)),
FromAddress: granter.String(),
ToAddress: grantee.String(),
},
},
}, true},
}
for i, tc := range tests {
msg := types.NewMsgExecAuthorized(tc.grantee, tc.msgs)
if tc.expectPass {
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
} else {
require.Error(t, msg.ValidateBasic(), "test: %v", i)
}
}
}
func TestMsgRevokeAuthorization(t *testing.T) {
tests := []struct {
title string
granter, grantee sdk.AccAddress
msgType string
expectPass bool
}{
{"nil Granter address", nil, grantee, "hello", false},
{"nil Grantee address", granter, nil, "hello", false},
{"nil Granter and Grantee address", nil, nil, "hello", false},
{"valid test case", granter, grantee, "hello", true},
}
for i, tc := range tests {
msg := types.NewMsgRevokeAuthorization(tc.granter, tc.grantee, tc.msgType)
if tc.expectPass {
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
} else {
require.Error(t, msg.ValidateBasic(), "test: %v", i)
}
}
}
func TestMsgGrantAuthorization(t *testing.T) {
tests := []struct {
title string
granter, grantee sdk.AccAddress
authorization types.Authorization
expiration time.Time
expectErr bool
expectPass bool
}{
{"nil granter address", nil, grantee, &types.SendAuthorization{SpendLimit: coinsPos}, time.Now(), false, false},
{"nil grantee address", granter, nil, &types.SendAuthorization{SpendLimit: coinsPos}, time.Now(), false, false},
{"nil granter and grantee address", nil, nil, &types.SendAuthorization{SpendLimit: coinsPos}, time.Now(), false, false},
{"nil authorization", granter, grantee, nil, time.Now(), true, false},
{"valid test case", granter, grantee, &types.SendAuthorization{SpendLimit: coinsPos}, time.Now().AddDate(0, 1, 0), false, true},
{"past time", granter, grantee, &types.SendAuthorization{SpendLimit: coinsPos}, time.Now().AddDate(0, 0, -1), false, false},
}
for i, tc := range tests {
msg, err := types.NewMsgGrantAuthorization(
tc.granter, tc.grantee, tc.authorization, tc.expiration,
)
if !tc.expectErr {
require.NoError(t, err)
} else {
continue
}
if tc.expectPass {
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
} else {
require.Error(t, msg.ValidateBasic(), "test: %v", i)
}
}
}

1278
x/authz/types/query.pb.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,362 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: cosmos/authz/v1beta1/query.proto
/*
Package types is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package types
import (
"context"
"io"
"net/http"
"github.com/golang/protobuf/descriptor"
"github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/status"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
var (
filter_Query_Authorization_0 = &utilities.DoubleArray{Encoding: map[string]int{"granter": 0, "grantee": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}}
)
func request_Query_Authorization_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryAuthorizationRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["granter"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "granter")
}
protoReq.Granter, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "granter", err)
}
val, ok = pathParams["grantee"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "grantee")
}
protoReq.Grantee, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "grantee", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Authorization_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.Authorization(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_Authorization_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryAuthorizationRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["granter"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "granter")
}
protoReq.Granter, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "granter", err)
}
val, ok = pathParams["grantee"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "grantee")
}
protoReq.Grantee, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "grantee", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Authorization_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.Authorization(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_Query_Authorizations_0 = &utilities.DoubleArray{Encoding: map[string]int{"granter": 0, "grantee": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}}
)
func request_Query_Authorizations_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryAuthorizationsRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["granter"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "granter")
}
protoReq.Granter, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "granter", err)
}
val, ok = pathParams["grantee"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "grantee")
}
protoReq.Grantee, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "grantee", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Authorizations_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.Authorizations(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_Authorizations_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryAuthorizationsRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["granter"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "granter")
}
protoReq.Granter, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "granter", err)
}
val, ok = pathParams["grantee"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "grantee")
}
protoReq.Grantee, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "grantee", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Authorizations_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.Authorizations(ctx, &protoReq)
return msg, metadata, err
}
// RegisterQueryHandlerServer registers the http handlers for service Query to "mux".
// UnaryRPC :call QueryServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead.
func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error {
mux.Handle("GET", pattern_Query_Authorization_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_Authorization_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Authorization_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Authorizations_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_Authorizations_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Authorizations_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterQueryHandler(ctx, mux, conn)
}
// RegisterQueryHandler registers the http handlers for service Query to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn))
}
// RegisterQueryHandlerClient registers the http handlers for service Query
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "QueryClient" to call the correct interceptors.
func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error {
mux.Handle("GET", pattern_Query_Authorization_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_Authorization_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Authorization_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Authorizations_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_Authorizations_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Authorizations_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_Query_Authorization_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7}, []string{"cosmos", "authz", "v1beta1", "granters", "granter", "grantees", "grantee", "grant"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_Authorizations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7}, []string{"cosmos", "authz", "v1beta1", "granters", "granter", "grantees", "grantee", "grants"}, "", runtime.AssumeColonVerbOpt(true)))
)
var (
forward_Query_Authorization_0 = runtime.ForwardResponseMessage
forward_Query_Authorizations_0 = runtime.ForwardResponseMessage
)

View File

@ -0,0 +1,45 @@
package types
import (
"reflect"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
bank "github.com/cosmos/cosmos-sdk/x/bank/types"
)
var (
_ Authorization = &SendAuthorization{}
)
// NewSendAuthorization creates a new SendAuthorization object.
func NewSendAuthorization(spendLimit sdk.Coins) *SendAuthorization {
return &SendAuthorization{
SpendLimit: spendLimit,
}
}
// MethodName implements Authorization.MethodName.
func (authorization SendAuthorization) MethodName() string {
return "/cosmos.bank.v1beta1.Msg/Send"
}
// Accept implements Authorization.Accept.
func (authorization SendAuthorization) Accept(msg sdk.ServiceMsg, block tmproto.Header) (allow bool, updated Authorization, delete bool) {
if reflect.TypeOf(msg.Request) == reflect.TypeOf(&bank.MsgSend{}) {
msg, ok := msg.Request.(*bank.MsgSend)
if ok {
limitLeft, isNegative := authorization.SpendLimit.SafeSub(msg.Amount)
if isNegative {
return false, nil, false
}
if limitLeft.IsZero() {
return true, nil, true
}
return true, &SendAuthorization{SpendLimit: limitLeft}, false
}
}
return false, nil, false
}

1609
x/authz/types/tx.pb.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,10 +4,8 @@ import (
"context"
"fmt"
gogogrpc "github.com/gogo/protobuf/grpc"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/libs/cli"
grpc "google.golang.org/grpc"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
@ -15,6 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/msgservice"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
"github.com/cosmos/cosmos-sdk/x/bank/types"
)
@ -33,38 +32,6 @@ func QueryBalancesExec(clientCtx client.Context, address fmt.Stringer, extraArgs
return clitestutil.ExecTestCLICmd(clientCtx, bankcli.GetBalancesCmd(), args)
}
// serviceMsgClientConn is an instance of grpc.ClientConn that is used to test building
// transactions with MsgClient's. It is intended to be replaced by the work in
// https://github.com/cosmos/cosmos-sdk/issues/7541 when that is ready.
type serviceMsgClientConn struct {
msgs []sdk.Msg
}
func (t *serviceMsgClientConn) Invoke(_ context.Context, method string, args, _ interface{}, _ ...grpc.CallOption) error {
req, ok := args.(sdk.MsgRequest)
if !ok {
return fmt.Errorf("%T should implement %T", args, (*sdk.MsgRequest)(nil))
}
err := req.ValidateBasic()
if err != nil {
return err
}
t.msgs = append(t.msgs, sdk.ServiceMsg{
MethodName: method,
Request: req,
})
return nil
}
func (t *serviceMsgClientConn) NewStream(context.Context, *grpc.StreamDesc, string, ...grpc.CallOption) (grpc.ClientStream, error) {
return nil, fmt.Errorf("not supported")
}
var _ gogogrpc.ClientConn = &serviceMsgClientConn{}
// newSendTxMsgServiceCmd is just for the purpose of testing ServiceMsg's in an end-to-end case. It is effectively
// NewSendTxCmd but using MsgClient.
func newSendTxMsgServiceCmd() *cobra.Command {
@ -90,14 +57,14 @@ ignored as it is implied from [from_key_or_address].`,
}
msg := types.NewMsgSend(clientCtx.GetFromAddress(), toAddr, coins)
svcMsgClientConn := &serviceMsgClientConn{}
svcMsgClientConn := &msgservice.ServiceMsgClientConn{}
bankMsgClient := types.NewMsgClient(svcMsgClientConn)
_, err = bankMsgClient.Send(context.Background(), msg)
if err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), svcMsgClientConn.msgs...)
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), svcMsgClientConn.GetMsgs()...)
},
}

View File

@ -76,7 +76,7 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Operatio
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}
@ -217,7 +217,7 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}

View File

@ -120,7 +120,7 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, bk types.BankKeeper,
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}
@ -172,7 +172,7 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, bk types.BankKee
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}
@ -227,7 +227,7 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, bk types.Ban
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}
@ -282,6 +282,6 @@ func SimulateMsgFundCommunityPool(ak types.AccountKeeper, bk types.BankKeeper, k
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}

View File

@ -162,7 +162,7 @@ func SimulateMsgSubmitProposal(
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err
}
opMsg := simtypes.NewOperationMsg(msg, true, "")
opMsg := simtypes.NewOperationMsg(msg, true, "", nil)
// get the submitted proposal ID
proposalID, err := k.GetProposalID(ctx)
@ -248,7 +248,7 @@ func SimulateMsgDeposit(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Ke
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}
@ -311,7 +311,7 @@ func operationSimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k kee
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}

View File

@ -115,23 +115,23 @@ func SimulateMsgUnjail(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Kee
validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) {
if res != nil && err == nil {
if info.Tombstoned {
return simtypes.NewOperationMsg(msg, true, ""), nil, errors.New("validator should not have been unjailed if validator tombstoned")
return simtypes.NewOperationMsg(msg, true, "", nil), nil, errors.New("validator should not have been unjailed if validator tombstoned")
}
if ctx.BlockHeader().Time.Before(info.JailedUntil) {
return simtypes.NewOperationMsg(msg, true, ""), nil, errors.New("validator unjailed while validator still in jail period")
return simtypes.NewOperationMsg(msg, true, "", nil), nil, errors.New("validator unjailed while validator still in jail period")
}
if validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) {
return simtypes.NewOperationMsg(msg, true, ""), nil, errors.New("validator unjailed even though self-delegation too low")
return simtypes.NewOperationMsg(msg, true, "", nil), nil, errors.New("validator unjailed even though self-delegation too low")
}
}
// msg failed as expected
return simtypes.NewOperationMsg(msg, false, ""), nil, nil
return simtypes.NewOperationMsg(msg, false, "", nil), nil, nil
}
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, errors.New(res.Log)
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}

View File

@ -173,7 +173,7 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k k
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}
@ -244,7 +244,7 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k kee
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}
@ -317,7 +317,7 @@ func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.K
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}
@ -407,7 +407,7 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}
@ -520,6 +520,6 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k k
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(msg, true, ""), nil, nil
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
}
}

View File

@ -6,11 +6,6 @@ package types
import (
context "context"
fmt "fmt"
io "io"
math "math"
math_bits "math/bits"
time "time"
types "github.com/cosmos/cosmos-sdk/codec/types"
github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types"
types1 "github.com/cosmos/cosmos-sdk/types"
@ -23,6 +18,10 @@ import (
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
io "io"
math "math"
math_bits "math/bits"
time "time"
)
// Reference imports to suppress errors if they are not otherwise used.