Merge branch 'master' into powerreduction_param

This commit is contained in:
Sunny Aggarwal 2021-04-10 16:26:50 -04:00
commit 10b2b08ece
58 changed files with 1985 additions and 169 deletions

View File

@ -20,12 +20,10 @@ linters:
- gosimple
- govet
- ineffassign
- interfacer
- maligned
- misspell
- nakedret
- prealloc
- scopelint
- exportloopref
- staticcheck
- structcheck
- stylecheck

View File

@ -53,7 +53,6 @@ Ref: https://keepachangelog.com/en/1.0.0/
* updated the keyring display structure (it uses protobuf JSON serialization) - the output is more verbose.
* Renamed `MarshalAny` and `UnmarshalAny` to `MarshalInterface` and `UnmarshalInterface` respectively. These functions must take an interface as parameter (not a concrete type nor `Any` object). Underneath they use `Any` wrapping for correct protobuf serialization.
* CLI: removed `--text` flag from `show-node-id` command; the text format for public keys is not used any more - instead we use ProtoJSON.
* [\#9026](https://github.com/cosmos/cosmos-sdk/pull/9026) The `tx sign` and `tx sign-batch` CLI commands use SIGN_MODE_DIRECT by default for local pubkeys. For multisigs and ledger keys, the default LEGACY_AMINO_JSON is kept.
### API Breaking Changes
@ -106,13 +105,34 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Bug Fixes
* (gRPC) [\#9015](https://github.com/cosmos/cosmos-sdk/pull/9015) Fix invalid status code when accessing gRPC endpoints.
* (gRPC) [\#8945](https://github.com/cosmos/cosmos-sdk/pull/8945) gRPC reflection now works correctly.
* (keyring) [#\8635](https://github.com/cosmos/cosmos-sdk/issues/8635) Remove hardcoded default passphrase value on `NewMnemonic`
* (x/bank) [\#8434](https://github.com/cosmos/cosmos-sdk/pull/8434) Fix legacy REST API `GET /bank/total` and `GET /bank/total/{denom}` in swagger
* (x/slashing) [\#8427](https://github.com/cosmos/cosmos-sdk/pull/8427) Fix query signing infos command
* (server) [\#8399](https://github.com/cosmos/cosmos-sdk/pull/8399) fix gRPC-web flag default value
* [\#9026](https://github.com/cosmos/cosmos-sdk/pull/9026) Fix bug of `gentx` command not working with ledger keys.
### Deprecated
* (grpc) [\#8926](https://github.com/cosmos/cosmos-sdk/pull/8926) The `tx` field in `SimulateRequest` has been deprecated, prefer to pass `tx_bytes` instead.
## [v0.42.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.42.4) - 2021-04-08
### Client Breaking Changes
* [\#9026](https://github.com/cosmos/cosmos-sdk/pull/9026) By default, the `tx sign` and `tx sign-batch` CLI commands use SIGN_MODE_DIRECT to sign transactions for local pubkeys. For multisigs and ledger keys, the default LEGACY_AMINO_JSON is used.
### Bug Fixes
* (gRPC) [\#9015](https://github.com/cosmos/cosmos-sdk/pull/9015) Fix invalid status code when accessing gRPC endpoints.
* [\#9026](https://github.com/cosmos/cosmos-sdk/pull/9026) Fixed the bug that caused the `gentx` command to fail for Ledger keys.
### Improvements
* [\#9081](https://github.com/cosmos/cosmos-sdk/pull/9081) Upgrade Tendermint to v0.34.9 that includes a security issue fix for Tendermint light clients.
## [v0.42.3](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.42.3) - 2021-03-24
This release fixes a security vulnerability identified in x/bank.
## [v0.42.2](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.42.2) - 2021-03-19
@ -131,10 +151,6 @@ Ref: https://keepachangelog.com/en/1.0.0/
This release fixes security vulnerability identified in the simapp.
### Deprecated
* (grpc) [\#8926](https://github.com/cosmos/cosmos-sdk/pull/8926) The `tx` field in `SimulateRequest` has been deprecated, prefer to pass `tx_bytes` instead.
## [v0.42.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.42.0) - 2021-03-08
**IMPORTANT**: This release contains an important security fix for all non Cosmos Hub chains running Stargate version of the Cosmos SDK (>0.40). Non-hub chains should not be using any version of the SDK in the v0.40.x or v0.41.x release series. See [#8461](https://github.com/cosmos/cosmos-sdk/pull/8461) for more details.

View File

@ -12,6 +12,7 @@ import (
"strings"
"github.com/hashicorp/go-getter"
"github.com/otiai10/copy"
)
// DoUpgrade will be called after the log message has been parsed and the process has terminated.
@ -62,10 +63,19 @@ func DownloadBinary(cfg *Config, info *UpgradeInfo) error {
if err != nil {
dirPath := cfg.UpgradeDir(info.Name)
err = getter.Get(dirPath, url)
if err != nil {
return err
}
err = EnsureBinary(binPath)
// copy binary to binPath from dirPath if zipped directory don't contain bin directory to wrap the binary
if err != nil {
err = copy.Copy(filepath.Join(dirPath, cfg.Name), binPath)
if err != nil {
return err
}
}
}
if err != nil {
return err
}
// if it is successful, let's ensure the binary is executable
return MarkExecutable(binPath)
}

View File

@ -307,6 +307,7 @@
- [Msg](#cosmos.evidence.v1beta1.Msg)
- [cosmos/feegrant/v1beta1/feegrant.proto](#cosmos/feegrant/v1beta1/feegrant.proto)
- [AllowedMsgFeeAllowance](#cosmos.feegrant.v1beta1.AllowedMsgFeeAllowance)
- [BasicFeeAllowance](#cosmos.feegrant.v1beta1.BasicFeeAllowance)
- [Duration](#cosmos.feegrant.v1beta1.Duration)
- [ExpiresAt](#cosmos.feegrant.v1beta1.ExpiresAt)
@ -4543,6 +4544,22 @@ Msg defines the evidence Msg service.
<a name="cosmos.feegrant.v1beta1.AllowedMsgFeeAllowance"></a>
### AllowedMsgFeeAllowance
AllowedMsgFeeAllowance creates allowance only for specified message types.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `allowance` | [google.protobuf.Any](#google.protobuf.Any) | | allowance can be any of basic and filtered fee allowance. |
| `allowed_messages` | [string](#string) | repeated | allowed_messages are the messages for which the grantee has the access. |
<a name="cosmos.feegrant.v1beta1.BasicFeeAllowance"></a>
### BasicFeeAllowance

4
go.mod
View File

@ -30,7 +30,7 @@ require (
github.com/jhump/protoreflect v1.8.2
github.com/magiconair/properties v1.8.5
github.com/mattn/go-isatty v0.0.12
github.com/otiai10/copy v1.5.0
github.com/otiai10/copy v1.5.1
github.com/pelletier/go-toml v1.8.1 // indirect
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.10.0
@ -49,7 +49,7 @@ require (
github.com/tendermint/cosmos-rosetta-gateway v0.3.0-rc2.0.20210304154332-87d6ca4410df
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15
github.com/tendermint/go-amino v0.16.0
github.com/tendermint/tendermint v0.34.8
github.com/tendermint/tendermint v0.34.9
github.com/tendermint/tm-db v0.6.4
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f

10
go.sum
View File

@ -284,6 +284,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64=
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us=
github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
@ -507,8 +509,8 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/otiai10/copy v1.5.0 h1:SoXDGnlTUZoqB/wSuj/Y5L6T5i6iN4YRAcMCd+JnLNU=
github.com/otiai10/copy v1.5.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E=
github.com/otiai10/copy v1.5.1 h1:a/cs2E1/1V0az8K5nblbl+ymEa4E11AfaOLMar8V34w=
github.com/otiai10/copy v1.5.1/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0 h1:TJIWdbX0B+kpNagQrjgq8bCMrbhiuX73M2XwgtDMoOI=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
@ -678,8 +680,8 @@ github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoM
github.com/tendermint/tendermint v0.34.0-rc4/go.mod h1:yotsojf2C1QBOw4dZrTcxbyxmPUrT4hNuOQWX9XUwB4=
github.com/tendermint/tendermint v0.34.0-rc6/go.mod h1:ugzyZO5foutZImv0Iyx/gOFCX6mjJTgbLHTwi17VDVg=
github.com/tendermint/tendermint v0.34.0/go.mod h1:Aj3PIipBFSNO21r+Lq3TtzQ+uKESxkbA3yo/INM4QwQ=
github.com/tendermint/tendermint v0.34.8 h1:PMWgUx47FrNTsfhxCWzoiIlVAC1SE9+WBlnsF9oQW0I=
github.com/tendermint/tendermint v0.34.8/go.mod h1:JVuu3V1ZexOaZG8VJMRl8lnfrGw6hEB2TVnoUwKRbss=
github.com/tendermint/tendermint v0.34.9 h1:9P2MXDEPOcPW0NBcHQ/HDSfvczZm+q5nUUw7AZ6f1Vc=
github.com/tendermint/tendermint v0.34.9/go.mod h1:kl4Z1JwGx1I+u1SXIzMDy7Z3T8LiMeCAOnzNn6AIMT4=
github.com/tendermint/tm-db v0.6.2/go.mod h1:GYtQ67SUvATOcoY8/+x6ylk8Qo02BQyLrAs+yAcLvGI=
github.com/tendermint/tm-db v0.6.3/go.mod h1:lfA1dL9/Y/Y8wwyPp2NMLyn5P5Ptr/gvDFNWtrCWSf8=
github.com/tendermint/tm-db v0.6.4 h1:3N2jlnYQkXNQclQwd/eKV/NzlqPlfK21cpRRIx80XXQ=

View File

@ -52,6 +52,18 @@ message PeriodicFeeAllowance {
ExpiresAt period_reset = 5 [(gogoproto.nullable) = false];
}
// AllowedMsgFeeAllowance creates allowance only for specified message types.
message AllowedMsgFeeAllowance {
option (gogoproto.goproto_getters) = false;
option (cosmos_proto.implements_interface) = "FeeAllowanceI";
// allowance can be any of basic and filtered fee allowance.
google.protobuf.Any allowance = 1 [(cosmos_proto.accepts_interface) = "FeeAllowanceI"];
// allowed_messages are the messages for which the grantee has the access.
repeated string allowed_messages = 2;
}
// Duration is a span of a clock time or number of blocks.
// This is designed to be added to an ExpiresAt struct.
message Duration {

View File

@ -4,9 +4,10 @@ import (
"bytes"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/stretchr/testify/require"
)
func TestNewStoreKVPairWriteListener(t *testing.T) {

View File

@ -3,11 +3,12 @@ package testdata
import (
"encoding/json"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
// KeyTestPubAddr generates a new secp256k1 keypair.

View File

@ -3,6 +3,7 @@ package msgservice
import (
"context"
"fmt"
"strings"
"github.com/gogo/protobuf/proto"
"google.golang.org/grpc"
@ -42,3 +43,9 @@ func RegisterMsgServiceDesc(registry codectypes.InterfaceRegistry, sd *grpc.Serv
func noopInterceptor(_ context.Context, _ interface{}, _ *grpc.UnaryServerInfo, _ grpc.UnaryHandler) (interface{}, error) {
return nil, nil
}
// IsServiceMsg checks if a type URL corresponds to a service method name,
// i.e. /cosmos.bank.Msg/Send vs /cosmos.bank.MsgSend
func IsServiceMsg(typeURL string) bool {
return strings.Count(typeURL, "/") >= 2
}

View File

@ -7,8 +7,9 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/cosmos/cosmos-sdk/store/types"
db "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/store/types"
)
// DefaultLimit is the default `limit` for queries

View File

@ -2,12 +2,12 @@ package tx
import (
"fmt"
"strings"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/msgservice"
)
// MaxGasWanted defines the max gas allowed.
@ -27,7 +27,7 @@ func (t *Tx) GetMsgs() []sdk.Msg {
res := make([]sdk.Msg, len(anys))
for i, any := range anys {
var msg sdk.Msg
if isServiceMsg(any.TypeUrl) {
if msgservice.IsServiceMsg(any.TypeUrl) {
req := any.GetCachedValue()
if req == nil {
panic("Any cached value is nil. Transaction messages must be correctly packed Any values.")
@ -183,7 +183,7 @@ func (m *TxBody) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
for _, any := range m.Messages {
// If the any's typeUrl contains 2 slashes, then we unpack the any into
// a ServiceMsg struct as per ADR-031.
if isServiceMsg(any.TypeUrl) {
if msgservice.IsServiceMsg(any.TypeUrl) {
var req sdk.MsgRequest
err := unpacker.UnpackAny(any, &req)
if err != nil {
@ -222,9 +222,3 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
registry.RegisterInterface("cosmos.tx.v1beta1.Tx", (*sdk.Tx)(nil))
registry.RegisterImplementations((*sdk.Tx)(nil), &Tx{})
}
// isServiceMsg checks if a type URL corresponds to a service method name,
// i.e. /cosmos.bank.Msg/Send vs /cosmos.bank.MsgSend
func isServiceMsg(typeURL string) bool {
return strings.Count(typeURL, "/") >= 2
}

View File

@ -16,5 +16,5 @@ type AccountKeeper interface {
// FeegrantKeeper defines the expected feegrant keeper.
type FeegrantKeeper interface {
UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins) error
UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins, msgs []sdk.Msg) error
}

View File

@ -94,7 +94,7 @@ func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo
if dfd.feegrantKeeper == nil {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "fee grants are not enabled")
} else if !feeGranter.Equals(feePayer) {
err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee)
err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, tx.GetMsgs())
if err != nil {
return ctx, sdkerrors.Wrapf(err, "%s not allowed to pay fees from %s", feeGranter, feePayer)

View File

@ -206,7 +206,7 @@ func (ak AccountKeeper) GetModuleAccount(ctx sdk.Context, moduleName string) typ
}
// SetModuleAccount sets the module account to the auth account store
func (ak AccountKeeper) SetModuleAccount(ctx sdk.Context, macc types.ModuleAccountI) { //nolint:interfacer
func (ak AccountKeeper) SetModuleAccount(ctx sdk.Context, macc types.ModuleAccountI) {
ak.SetAccount(ctx, macc)
}

View File

@ -0,0 +1,43 @@
package keeper
import (
"github.com/gogo/protobuf/grpc"
v043 "github.com/cosmos/cosmos-sdk/x/auth/legacy/v043"
"github.com/cosmos/cosmos-sdk/x/auth/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper AccountKeeper
queryServer grpc.Server
}
// NewMigrator returns a new Migrator.
func NewMigrator(keeper AccountKeeper, queryServer grpc.Server) Migrator {
return Migrator{keeper: keeper, queryServer: queryServer}
}
// Migrate1to2 migrates from version 1 to 2.
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
var iterErr error
m.keeper.IterateAccounts(ctx, func(account types.AccountI) (stop bool) {
wb, err := v043.MigrateAccount(ctx, account, m.queryServer)
if err != nil {
iterErr = err
return true
}
if wb == nil {
return false
}
m.keeper.SetAccount(ctx, wb)
return false
})
return iterErr
}

269
x/auth/legacy/v043/store.go Normal file
View File

@ -0,0 +1,269 @@
package v043
import (
"errors"
"fmt"
"github.com/gogo/protobuf/grpc"
"github.com/gogo/protobuf/proto"
abci "github.com/tendermint/tendermint/abci/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/auth/vesting/exported"
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
const (
delegatorDelegationPath = "/cosmos.staking.v1beta1.Query/DelegatorDelegations"
stakingParamsPath = "/cosmos.staking.v1beta1.Query/Params"
delegatorUnbondingDelegationsPath = "/cosmos.staking.v1beta1.Query/DelegatorUnbondingDelegations"
balancesPath = "/cosmos.bank.v1beta1.Query/AllBalances"
)
func migrateVestingAccounts(ctx sdk.Context, account types.AccountI, queryServer grpc.Server) (types.AccountI, error) {
bondDenom, err := getBondDenom(ctx, queryServer)
if err != nil {
return nil, err
}
asVesting, ok := account.(exported.VestingAccount)
if !ok {
return nil, nil
}
addr := account.GetAddress().String()
balance, err := getBalance(
ctx,
addr,
queryServer,
)
if err != nil {
return nil, err
}
delegations, err := getDelegatorDelegationsSum(
ctx,
addr,
queryServer,
)
if err != nil {
return nil, err
}
unbondingDelegations, err := getDelegatorUnbondingDelegationsSum(
ctx,
addr,
bondDenom,
queryServer,
)
if err != nil {
return nil, err
}
delegations = delegations.Add(unbondingDelegations...)
asVesting, ok = resetVestingDelegatedBalances(asVesting)
if !ok {
return nil, nil
}
// balance before any delegation includes balance of delegation
for _, coin := range delegations {
balance = balance.Add(coin)
}
asVesting.TrackDelegation(ctx.BlockTime(), balance, delegations)
return asVesting.(types.AccountI), nil
}
func resetVestingDelegatedBalances(evacct exported.VestingAccount) (exported.VestingAccount, bool) {
// reset `DelegatedVesting` and `DelegatedFree` to zero
df := sdk.NewCoins()
dv := sdk.NewCoins()
switch vacct := evacct.(type) {
case *vestingtypes.ContinuousVestingAccount:
vacct.DelegatedVesting = dv
vacct.DelegatedFree = df
return vacct, true
case *vestingtypes.DelayedVestingAccount:
vacct.DelegatedVesting = dv
vacct.DelegatedFree = df
return vacct, true
case *vestingtypes.PeriodicVestingAccount:
vacct.DelegatedVesting = dv
vacct.DelegatedFree = df
return vacct, true
default:
return nil, false
}
}
func getDelegatorDelegationsSum(ctx sdk.Context, address string, queryServer grpc.Server) (sdk.Coins, error) {
querier, ok := queryServer.(*baseapp.GRPCQueryRouter)
if !ok {
return nil, fmt.Errorf("unexpected type: %T wanted *baseapp.GRPCQueryRouter", queryServer)
}
queryFn := querier.Route(delegatorDelegationPath)
q := &stakingtypes.QueryDelegatorDelegationsRequest{
DelegatorAddr: address,
}
b, err := proto.Marshal(q)
if err != nil {
return nil, fmt.Errorf("cannot marshal staking type query request, %w", err)
}
req := abci.RequestQuery{
Data: b,
Path: delegatorDelegationPath,
}
resp, err := queryFn(ctx, req)
if err != nil {
e, ok := status.FromError(err)
if ok && e.Code() == codes.NotFound {
return nil, nil
}
return nil, fmt.Errorf("staking query error, %w", err)
}
balance := new(stakingtypes.QueryDelegatorDelegationsResponse)
if err := proto.Unmarshal(resp.Value, balance); err != nil {
return nil, fmt.Errorf("unable to unmarshal delegator query delegations: %w", err)
}
res := sdk.NewCoins()
for _, i := range balance.DelegationResponses {
res = res.Add(i.Balance)
}
return res, nil
}
func getDelegatorUnbondingDelegationsSum(ctx sdk.Context, address, bondDenom string, queryServer grpc.Server) (sdk.Coins, error) {
querier, ok := queryServer.(*baseapp.GRPCQueryRouter)
if !ok {
return nil, fmt.Errorf("unexpected type: %T wanted *baseapp.GRPCQueryRouter", queryServer)
}
queryFn := querier.Route(delegatorUnbondingDelegationsPath)
q := &stakingtypes.QueryDelegatorUnbondingDelegationsRequest{
DelegatorAddr: address,
}
b, err := proto.Marshal(q)
if err != nil {
return nil, fmt.Errorf("cannot marshal staking type query request, %w", err)
}
req := abci.RequestQuery{
Data: b,
Path: delegatorUnbondingDelegationsPath,
}
resp, err := queryFn(ctx, req)
if err != nil && !errors.Is(err, sdkerrors.ErrNotFound) {
e, ok := status.FromError(err)
if ok && e.Code() == codes.NotFound {
return nil, nil
}
return nil, fmt.Errorf("staking query error, %w", err)
}
balance := new(stakingtypes.QueryDelegatorUnbondingDelegationsResponse)
if err := proto.Unmarshal(resp.Value, balance); err != nil {
return nil, fmt.Errorf("unable to unmarshal delegator query delegations: %w", err)
}
res := sdk.NewCoins()
for _, i := range balance.UnbondingResponses {
for _, r := range i.Entries {
res = res.Add(sdk.NewCoin(bondDenom, r.Balance))
}
}
return res, nil
}
func getBalance(ctx sdk.Context, address string, queryServer grpc.Server) (sdk.Coins, error) {
querier, ok := queryServer.(*baseapp.GRPCQueryRouter)
if !ok {
return nil, fmt.Errorf("unexpected type: %T wanted *baseapp.GRPCQueryRouter", queryServer)
}
queryFn := querier.Route(balancesPath)
q := &banktypes.QueryAllBalancesRequest{
Address: address,
Pagination: nil,
}
b, err := proto.Marshal(q)
if err != nil {
return nil, fmt.Errorf("cannot marshal bank type query request, %w", err)
}
req := abci.RequestQuery{
Data: b,
Path: balancesPath,
}
resp, err := queryFn(ctx, req)
if err != nil {
return nil, fmt.Errorf("bank query error, %w", err)
}
balance := new(banktypes.QueryAllBalancesResponse)
if err := proto.Unmarshal(resp.Value, balance); err != nil {
return nil, fmt.Errorf("unable to unmarshal bank balance response: %w", err)
}
return balance.Balances, nil
}
func getBondDenom(ctx sdk.Context, queryServer grpc.Server) (string, error) {
querier, ok := queryServer.(*baseapp.GRPCQueryRouter)
if !ok {
return "", fmt.Errorf("unexpected type: %T wanted *baseapp.GRPCQueryRouter", queryServer)
}
queryFn := querier.Route(stakingParamsPath)
q := &stakingtypes.QueryParamsRequest{}
b, err := proto.Marshal(q)
if err != nil {
return "", fmt.Errorf("cannot marshal staking params query request, %w", err)
}
req := abci.RequestQuery{
Data: b,
Path: stakingParamsPath,
}
resp, err := queryFn(ctx, req)
if err != nil {
return "", fmt.Errorf("staking query error, %w", err)
}
params := new(stakingtypes.QueryParamsResponse)
if err := proto.Unmarshal(resp.Value, params); err != nil {
return "", fmt.Errorf("unable to unmarshal delegator query delegations: %w", err)
}
return params.Params.BondDenom, nil
}
// MigrateAccount migrates vesting account to make the DelegatedVesting and DelegatedFree fields correctly
// track delegations.
// References: https://github.com/cosmos/cosmos-sdk/issues/8601, https://github.com/cosmos/cosmos-sdk/issues/8812
func MigrateAccount(ctx sdk.Context, account types.AccountI, queryServer grpc.Server) (types.AccountI, error) {
return migrateVestingAccounts(ctx, account, queryServer)
}

View File

@ -0,0 +1,687 @@
package v043_test
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/auth/vesting/exported"
"github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
func TestMigrateVestingAccounts(t *testing.T) {
testCases := []struct {
name string
prepareFunc func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress)
garbageFunc func(ctx sdk.Context, vesting exported.VestingAccount, app *simapp.SimApp) error
tokenAmount int64
expVested int64
expFree int64
blockTime int64
}{
{
"delayed vesting has vested, multiple delegations less than the total account balance",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(200)))
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
app.AccountKeeper.SetAccount(ctx, delayedAccount)
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
0,
300,
0,
},
{
"delayed vesting has vested, single delegations which exceed the vested amount",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(200)))
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
app.AccountKeeper.SetAccount(ctx, delayedAccount)
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
0,
300,
0,
},
{
"delayed vesting has vested, multiple delegations which exceed the vested amount",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(200)))
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
app.AccountKeeper.SetAccount(ctx, delayedAccount)
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
0,
300,
0,
},
{
"delayed vesting has not vested, single delegations which exceed the vested amount",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(200)))
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
app.AccountKeeper.SetAccount(ctx, delayedAccount)
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
200,
100,
0,
},
{
"delayed vesting has not vested, multiple delegations which exceed the vested amount",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(200)))
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
app.AccountKeeper.SetAccount(ctx, delayedAccount)
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
200,
100,
0,
},
{
"not end time",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
app.AccountKeeper.SetAccount(ctx, delayedAccount)
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
300,
0,
0,
},
{
"delayed vesting has not vested, single delegation greater than the total account balance",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
app.AccountKeeper.SetAccount(ctx, delayedAccount)
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
300,
0,
0,
},
{
"delayed vesting has vested, single delegation greater than the total account balance",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
app.AccountKeeper.SetAccount(ctx, delayedAccount)
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
0,
300,
0,
},
{
"continuous vesting, start time after blocktime",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
startTime := ctx.BlockTime().AddDate(1, 0, 0).Unix()
endTime := ctx.BlockTime().AddDate(2, 0, 0).Unix()
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
delayedAccount := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
app.AccountKeeper.SetAccount(ctx, delayedAccount)
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
300,
0,
0,
},
{
"continuous vesting, start time passed but not ended",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
startTime := ctx.BlockTime().AddDate(-1, 0, 0).Unix()
endTime := ctx.BlockTime().AddDate(2, 0, 0).Unix()
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
delayedAccount := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
app.AccountKeeper.SetAccount(ctx, delayedAccount)
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
200,
100,
0,
},
{
"continuous vesting, start time and endtime passed",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
startTime := ctx.BlockTime().AddDate(-2, 0, 0).Unix()
endTime := ctx.BlockTime().AddDate(-1, 0, 0).Unix()
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
delayedAccount := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
app.AccountKeeper.SetAccount(ctx, delayedAccount)
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
0,
300,
0,
},
{
"periodic vesting account, yet to be vested, some rewards delegated",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(100)))
start := ctx.BlockTime().Unix() + int64(time.Hour/time.Second)
periods := []types.Period{
{
Length: int64((24 * time.Hour) / time.Second),
Amount: vestedCoins,
},
}
account := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, start, periods)
app.AccountKeeper.SetAccount(ctx, account)
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(150), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
100,
50,
0,
},
{
"periodic vesting account, nothing has vested yet",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
/*
Test case:
- periodic vesting account starts at time 1601042400
- account balance and original vesting: 3666666670000
- nothing has vested, we put the block time slightly after start time
- expected vested: original vesting amount
- expected free: zero
- we're delegating the full original vesting
*/
startTime := int64(1601042400)
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(3666666670000)))
periods := []types.Period{
{
Length: 31536000,
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(1833333335000))),
},
{
Length: 15638400,
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
},
{
Length: 15897600,
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
},
}
delayedAccount := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
app.AccountKeeper.SetAccount(ctx, delayedAccount)
// delegation of the original vesting
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
3666666670000,
3666666670000,
0,
1601042400 + 1,
},
{
"periodic vesting account, all has vested",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
/*
Test case:
- periodic vesting account starts at time 1601042400
- account balance and original vesting: 3666666670000
- all has vested, so we set the block time at initial time + sum of all periods times + 1 => 1601042400 + 31536000 + 15897600 + 15897600 + 1
- expected vested: zero
- expected free: original vesting amount
- we're delegating the full original vesting
*/
startTime := int64(1601042400)
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(3666666670000)))
periods := []types.Period{
{
Length: 31536000,
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(1833333335000))),
},
{
Length: 15638400,
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
},
{
Length: 15897600,
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
},
}
delayedAccount := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
ctx = ctx.WithBlockTime(time.Unix(1601042400+31536000+15897600+15897600+1, 0))
app.AccountKeeper.SetAccount(ctx, delayedAccount)
// delegation of the original vesting
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
3666666670000,
0,
3666666670000,
1601042400 + 31536000 + 15897600 + 15897600 + 1,
},
{
"periodic vesting account, first period has vested",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
/*
Test case:
- periodic vesting account starts at time 1601042400
- account balance and original vesting: 3666666670000
- first period have vested, so we set the block time at initial time + time of the first periods + 1 => 1601042400 + 31536000 + 1
- expected vested: original vesting - first period amount
- expected free: first period amount
- we're delegating the full original vesting
*/
startTime := int64(1601042400)
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(3666666670000)))
periods := []types.Period{
{
Length: 31536000,
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(1833333335000))),
},
{
Length: 15638400,
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
},
{
Length: 15897600,
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
},
}
delayedAccount := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
ctx = ctx.WithBlockTime(time.Unix(1601042400+31536000+1, 0))
app.AccountKeeper.SetAccount(ctx, delayedAccount)
// delegation of the original vesting
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
3666666670000,
3666666670000 - 1833333335000,
1833333335000,
1601042400 + 31536000 + 1,
},
{
"periodic vesting account, first 2 period has vested",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
/*
Test case:
- periodic vesting account starts at time 1601042400
- account balance and original vesting: 3666666670000
- first 2 periods have vested, so we set the block time at initial time + time of the two periods + 1 => 1601042400 + 31536000 + 15638400 + 1
- expected vested: original vesting - (sum of the first two periods amounts)
- expected free: sum of the first two periods
- we're delegating the full original vesting
*/
startTime := int64(1601042400)
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(3666666670000)))
periods := []types.Period{
{
Length: 31536000,
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(1833333335000))),
},
{
Length: 15638400,
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
},
{
Length: 15897600,
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
},
}
delayedAccount := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
ctx = ctx.WithBlockTime(time.Unix(1601042400+31536000+15638400+1, 0))
app.AccountKeeper.SetAccount(ctx, delayedAccount)
// delegation of the original vesting
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
3666666670000,
3666666670000 - 1833333335000 - 916666667500,
1833333335000 + 916666667500,
1601042400 + 31536000 + 15638400 + 1,
},
{
"vesting account has unbonding delegations in place",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix())
app.AccountKeeper.SetAccount(ctx, delayedAccount)
// delegation of the original vesting
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
valAddr, err := sdk.ValAddressFromBech32(validator.OperatorAddress)
require.NoError(t, err)
// un-delegation of the original vesting
_, err = app.StakingKeeper.Undelegate(ctx, delegatorAddr, valAddr, sdk.NewDecFromInt(sdk.NewInt(300)))
require.NoError(t, err)
},
cleartTrackingFields,
450,
300,
0,
0,
},
{
"vesting account has never delegated anything",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix())
app.AccountKeeper.SetAccount(ctx, delayedAccount)
},
cleartTrackingFields,
450,
0,
0,
0,
},
{
"vesting account has no delegation but dirty DelegatedFree and DelegatedVesting fields",
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix())
app.AccountKeeper.SetAccount(ctx, delayedAccount)
},
dirtyTrackingFields,
450,
0,
0,
0,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{
Time: time.Now(),
})
addrs := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(tc.tokenAmount))
delegatorAddr := addrs[0]
_, valAddr := createValidator(t, ctx, app, tc.tokenAmount*2)
validator, found := app.StakingKeeper.GetValidator(ctx, valAddr)
require.True(t, found)
tc.prepareFunc(app, ctx, validator, delegatorAddr)
if tc.blockTime != 0 {
ctx = ctx.WithBlockTime(time.Unix(tc.blockTime, 0))
}
// We introduce the bug
savedAccount := app.AccountKeeper.GetAccount(ctx, delegatorAddr)
vestingAccount, ok := savedAccount.(exported.VestingAccount)
require.True(t, ok)
require.NoError(t, tc.garbageFunc(ctx, vestingAccount, app))
m := authkeeper.NewMigrator(app.AccountKeeper, app.GRPCQueryRouter())
require.NoError(t, m.Migrate1to2(ctx))
var expVested sdk.Coins
var expFree sdk.Coins
if tc.expVested != 0 {
expVested = sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(tc.expVested)))
}
if tc.expFree != 0 {
expFree = sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(tc.expFree)))
}
trackingCorrected(
ctx,
t,
app.AccountKeeper,
savedAccount.GetAddress(),
expVested,
expFree,
)
})
}
}
func trackingCorrected(ctx sdk.Context, t *testing.T, ak authkeeper.AccountKeeper, addr sdk.AccAddress, expDelVesting sdk.Coins, expDelFree sdk.Coins) {
t.Helper()
baseAccount := ak.GetAccount(ctx, addr)
vDA, ok := baseAccount.(exported.VestingAccount)
require.True(t, ok)
vestedOk := expDelVesting.IsEqual(vDA.GetDelegatedVesting())
freeOk := expDelFree.IsEqual(vDA.GetDelegatedFree())
require.True(t, vestedOk, vDA.GetDelegatedVesting().String())
require.True(t, freeOk, vDA.GetDelegatedFree().String())
}
func cleartTrackingFields(ctx sdk.Context, vesting exported.VestingAccount, app *simapp.SimApp) error {
switch t := vesting.(type) {
case *types.DelayedVestingAccount:
t.DelegatedFree = nil
t.DelegatedVesting = nil
app.AccountKeeper.SetAccount(ctx, t)
case *types.ContinuousVestingAccount:
t.DelegatedFree = nil
t.DelegatedVesting = nil
app.AccountKeeper.SetAccount(ctx, t)
case *types.PeriodicVestingAccount:
t.DelegatedFree = nil
t.DelegatedVesting = nil
app.AccountKeeper.SetAccount(ctx, t)
default:
return fmt.Errorf("expected vesting account, found %t", t)
}
return nil
}
func dirtyTrackingFields(ctx sdk.Context, vesting exported.VestingAccount, app *simapp.SimApp) error {
dirt := sdk.NewCoins(sdk.NewInt64Coin("stake", 42))
switch t := vesting.(type) {
case *types.DelayedVestingAccount:
t.DelegatedFree = dirt
t.DelegatedVesting = dirt
app.AccountKeeper.SetAccount(ctx, t)
case *types.ContinuousVestingAccount:
t.DelegatedFree = dirt
t.DelegatedVesting = dirt
app.AccountKeeper.SetAccount(ctx, t)
case *types.PeriodicVestingAccount:
t.DelegatedFree = dirt
t.DelegatedVesting = dirt
app.AccountKeeper.SetAccount(ctx, t)
default:
return fmt.Errorf("expected vesting account, found %t", t)
}
return nil
}
func createValidator(t *testing.T, ctx sdk.Context, app *simapp.SimApp, powers int64) (sdk.AccAddress, sdk.ValAddress) {
valTokens := sdk.TokensFromConsensusPower(powers)
addrs := simapp.AddTestAddrsIncremental(app, ctx, 1, valTokens)
valAddrs := simapp.ConvertAddrsToValAddrs(addrs)
pks := simapp.CreateTestPubKeys(1)
cdc := simapp.MakeTestEncodingConfig().Marshaler
app.StakingKeeper = stakingkeeper.NewKeeper(
cdc,
app.GetKey(stakingtypes.StoreKey),
app.AccountKeeper,
app.BankKeeper,
app.GetSubspace(stakingtypes.ModuleName),
)
val1, err := stakingtypes.NewValidator(valAddrs[0], pks[0], stakingtypes.Description{})
require.NoError(t, err)
app.StakingKeeper.SetValidator(ctx, val1)
require.NoError(t, app.StakingKeeper.SetValidatorByConsAddr(ctx, val1))
app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val1)
_, err = app.StakingKeeper.Delegate(ctx, addrs[0], valTokens, stakingtypes.Unbonded, val1, true)
require.NoError(t, err)
_ = staking.EndBlocker(ctx, app.StakingKeeper)
return addrs[0], valAddrs[0]
}

View File

@ -129,6 +129,11 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
// module-specific GRPC queries.
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterQueryServer(cfg.QueryServer(), am.accountKeeper)
m := keeper.NewMigrator(am.accountKeeper, cfg.QueryServer())
err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2)
if err != nil {
panic(err)
}
}
// InitGenesis performs genesis initialization for the auth module. It returns
@ -148,7 +153,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return 1 }
func (AppModule) ConsensusVersion() uint64 { return 2 }
// BeginBlock returns the begin blocker for the auth module.
func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}

View File

@ -6,7 +6,7 @@ import (
"strings"
gogogrpc "github.com/gogo/protobuf/grpc"
"github.com/golang/protobuf/proto" //nolint:staticcheck
"github.com/golang/protobuf/proto" // nolint: staticcheck
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

View File

@ -8,6 +8,8 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
clienttx "github.com/cosmos/cosmos-sdk/client/tx"
@ -28,7 +30,6 @@ import (
authtest "github.com/cosmos/cosmos-sdk/x/auth/client/testutil"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/stretchr/testify/suite"
)
type IntegrationTestSuite struct {

View File

@ -156,8 +156,8 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
},
&sdk.TxResponse{}, 29,
false,
nil, 0,
true,
},
{
"failed with error both validators not allowed",

View File

@ -3,8 +3,6 @@ package exported
import (
"github.com/gogo/protobuf/proto"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -17,5 +15,9 @@ type Authorization interface {
// 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) (updated Authorization, delete bool, err error)
Accept(ctx sdk.Context, msg sdk.ServiceMsg) (updated Authorization, delete bool, err error)
// ValidateBasic does a simple validation check that
// doesn't require access to any other information.
ValidateBasic() error
}

View File

@ -87,7 +87,7 @@ func (k Keeper) DispatchActions(ctx sdk.Context, grantee sdk.AccAddress, service
if authorization == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "authorization not found")
}
updated, del, err := authorization.Accept(serviceMsg, ctx.BlockHeader())
updated, del, err := authorization.Accept(ctx, serviceMsg)
if err != nil {
return nil, err
}

View File

@ -96,8 +96,12 @@ func SimulateMsgGrantAuthorization(ak types.AccountKeeper, bk types.BankKeeper,
}
blockTime := ctx.BlockTime()
spendLimit := spendableCoins.Sub(fees)
if spendLimit == nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgGrantAuthorization, "spend limit is nil"), nil, nil
}
msg, err := types.NewMsgGrantAuthorization(granter.Address, grantee.Address,
banktype.NewSendAuthorization(spendableCoins.Sub(fees)), blockTime.AddDate(1, 0, 0))
banktype.NewSendAuthorization(spendLimit), blockTime.AddDate(1, 0, 0))
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgGrantAuthorization, err.Error()), nil, err
@ -249,7 +253,7 @@ func SimulateMsgExecuteAuthorized(ak types.AccountKeeper, bk types.BankKeeper, k
msg := types.NewMsgExecAuthorized(grantee.Address, []sdk.ServiceMsg{execMsg})
sendGrant := targetGrant.Authorization.GetCachedValue().(*banktype.SendAuthorization)
_, _, err = sendGrant.Accept(execMsg, ctx.BlockHeader())
_, _, err = sendGrant.Accept(ctx, execMsg)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, err.Error()), nil, nil
}

View File

@ -1,9 +1,9 @@
package types
import (
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/msgservice"
"github.com/cosmos/cosmos-sdk/x/authz/exported"
)
@ -19,11 +19,19 @@ func NewGenericAuthorization(methodName string) *GenericAuthorization {
}
// MethodName implements Authorization.MethodName.
func (cap GenericAuthorization) MethodName() string {
return cap.MessageName
func (authorization GenericAuthorization) MethodName() string {
return authorization.MessageName
}
// Accept implements Authorization.Accept.
func (cap GenericAuthorization) Accept(msg sdk.ServiceMsg, block tmproto.Header) (updated exported.Authorization, delete bool, err error) {
return &cap, false, nil
func (authorization GenericAuthorization) Accept(ctx sdk.Context, msg sdk.ServiceMsg) (updated exported.Authorization, delete bool, err error) {
return &authorization, false, nil
}
// ValidateBasic implements Authorization.ValidateBasic.
func (authorization GenericAuthorization) ValidateBasic() error {
if !msgservice.IsServiceMsg(authorization.MessageName) {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, " %s is not a valid service msg", authorization.MessageName)
}
return nil
}

View File

@ -0,0 +1,20 @@
package types_test
import (
"testing"
"github.com/cosmos/cosmos-sdk/x/authz/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/stretchr/testify/require"
)
func TestGenericAuthorization(t *testing.T) {
t.Log("verify ValidateBasic returns error for non-service msg")
authorization := types.NewGenericAuthorization(banktypes.TypeMsgSend)
require.Error(t, authorization.ValidateBasic())
t.Log("verify ValidateBasic returns nil for service msg")
authorization = types.NewGenericAuthorization(banktypes.SendAuthorization{}.MethodName())
require.NoError(t, authorization.ValidateBasic())
require.Equal(t, banktypes.SendAuthorization{}.MethodName(), authorization.MessageName)
}

View File

@ -63,7 +63,11 @@ func (msg MsgGrantAuthorizationRequest) ValidateBasic() error {
return sdkerrors.Wrap(ErrInvalidExpirationTime, "Time can't be in the past")
}
return nil
authorization, ok := msg.Authorization.GetCachedValue().(exported.Authorization)
if !ok {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", (exported.Authorization)(nil), msg.Authorization.GetCachedValue())
}
return authorization.ValidateBasic()
}
// GetGrantAuthorization returns the cache value from the MsgGrantAuthorization.Authorization if present.

View File

@ -446,6 +446,7 @@ func (k BaseKeeper) trackDelegation(ctx sdk.Context, addr sdk.AccAddress, balanc
if ok {
// TODO: return error on account.TrackDelegation
vacc.TrackDelegation(ctx.BlockHeader().Time, balance, amt)
k.ak.SetAccount(ctx, acc)
}
return nil
@ -461,6 +462,7 @@ func (k BaseKeeper) trackUndelegation(ctx sdk.Context, addr sdk.AccAddress, amt
if ok {
// TODO: return error on account.TrackUndelegation
vacc.TrackUndelegation(amt)
k.ak.SetAccount(ctx, acc)
}
return nil

View File

@ -1,10 +1,12 @@
package keeper_test
import (
"github.com/cosmos/cosmos-sdk/types/query"
"testing"
"time"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/x/auth/vesting/exported"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
"github.com/stretchr/testify/suite"
@ -905,6 +907,12 @@ func (suite *IntegrationTestSuite) TestDelegateCoins() {
// require the ability for a vesting account to delegate
suite.Require().NoError(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins))
suite.Require().Equal(delCoins, app.BankKeeper.GetAllBalances(ctx, addr1))
// require that delegated vesting amount is equal to what was delegated with DelegateCoins
acc = app.AccountKeeper.GetAccount(ctx, addr1)
vestingAcc, ok := acc.(exported.VestingAccount)
suite.Require().True(ok)
suite.Require().Equal(delCoins, vestingAcc.GetDelegatedVesting())
}
func (suite *IntegrationTestSuite) TestDelegateCoins_Invalid() {
@ -979,6 +987,12 @@ func (suite *IntegrationTestSuite) TestUndelegateCoins() {
suite.Require().Equal(origCoins, app.BankKeeper.GetAllBalances(ctx, addr1))
suite.Require().True(app.BankKeeper.GetAllBalances(ctx, addrModule).Empty())
// require that delegated vesting amount is completely empty, since they were completely undelegated
acc = app.AccountKeeper.GetAccount(ctx, addr1)
vestingAcc, ok := acc.(exported.VestingAccount)
suite.Require().True(ok)
suite.Require().Empty(vestingAcc.GetDelegatedVesting())
}
func (suite *IntegrationTestSuite) TestUndelegateCoins_Invalid() {

View File

@ -3,8 +3,6 @@ package types
import (
"reflect"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authz "github.com/cosmos/cosmos-sdk/x/authz/exported"
@ -27,7 +25,7 @@ func (authorization SendAuthorization) MethodName() string {
}
// Accept implements Authorization.Accept.
func (authorization SendAuthorization) Accept(msg sdk.ServiceMsg, block tmproto.Header) (updated authz.Authorization, delete bool, err error) {
func (authorization SendAuthorization) Accept(ctx sdk.Context, msg sdk.ServiceMsg) (updated authz.Authorization, delete bool, err error) {
if reflect.TypeOf(msg.Request) == reflect.TypeOf(&MsgSend{}) {
msg, ok := msg.Request.(*MsgSend)
if ok {
@ -44,3 +42,14 @@ func (authorization SendAuthorization) Accept(msg sdk.ServiceMsg, block tmproto.
}
return nil, false, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "type mismatch")
}
// ValidateBasic implements Authorization.ValidateBasic.
func (authorization SendAuthorization) ValidateBasic() error {
if authorization.SpendLimit == nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "spend limit cannot be nil")
}
if !authorization.SpendLimit.IsAllPositive() {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "spend limit cannot be negitive")
}
return nil
}

View File

@ -0,0 +1,64 @@
package types_test
import (
"testing"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/stretchr/testify/require"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)
var (
coins1000 = sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000)))
coins500 = sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(500)))
fromAddr = sdk.AccAddress("_____from _____")
toAddr = sdk.AccAddress("_______to________")
)
func TestSendAuthorization(t *testing.T) {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
authorization := types.NewSendAuthorization(coins1000)
t.Log("verify authorization returns valid method name")
require.Equal(t, authorization.MethodName(), "/cosmos.bank.v1beta1.Msg/Send")
require.NoError(t, authorization.ValidateBasic())
send := types.NewMsgSend(fromAddr, toAddr, coins1000)
srvMsg := sdk.ServiceMsg{
MethodName: "/cosmos.bank.v1beta1.Msg/Send",
Request: send,
}
require.NoError(t, authorization.ValidateBasic())
t.Log("verify updated authorization returns nil")
updated, del, err := authorization.Accept(ctx, srvMsg)
require.NoError(t, err)
require.True(t, del)
require.Nil(t, updated)
authorization = types.NewSendAuthorization(coins1000)
require.Equal(t, authorization.MethodName(), "/cosmos.bank.v1beta1.Msg/Send")
require.NoError(t, authorization.ValidateBasic())
send = types.NewMsgSend(fromAddr, toAddr, coins500)
srvMsg = sdk.ServiceMsg{
MethodName: "/cosmos.bank.v1beta1.Msg/Send",
Request: send,
}
require.NoError(t, authorization.ValidateBasic())
updated, del, err = authorization.Accept(ctx, srvMsg)
t.Log("verify updated authorization returns remaining spent limit")
require.NoError(t, err)
require.False(t, del)
require.NotNil(t, updated)
sendAuth := types.NewSendAuthorization(coins500)
require.Equal(t, sendAuth.String(), updated.String())
t.Log("expect updated authorization nil after spending remaining amount")
updated, del, err = updated.Accept(ctx, srvMsg)
require.NoError(t, err)
require.True(t, del)
require.Nil(t, updated)
}

View File

@ -1,4 +1,3 @@
//nolint
package types
import (

View File

@ -13,6 +13,7 @@ import (
"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"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -40,7 +41,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
}
cfg := network.DefaultConfig()
cfg.NumValidators = 2
cfg.NumValidators = 3
s.cfg = cfg
s.network = network.New(s.T(), cfg)
@ -137,7 +138,7 @@ func (s *IntegrationTestSuite) TestCmdGetFeeGrant() {
grantee.String(),
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
"no fee allowance found",
"no allowance",
true, nil, nil,
},
{
@ -169,9 +170,13 @@ func (s *IntegrationTestSuite) TestCmdGetFeeGrant() {
s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
s.Require().Equal(tc.respType.Grantee, tc.respType.Grantee)
s.Require().Equal(tc.respType.Granter, tc.respType.Granter)
grant, err := tc.respType.GetFeeGrant()
s.Require().NoError(err)
grant1, err1 := tc.resp.GetFeeGrant()
s.Require().NoError(err1)
s.Require().Equal(
tc.respType.GetFeeGrant().(*types.BasicFeeAllowance).SpendLimit,
tc.resp.GetFeeGrant().(*types.BasicFeeAllowance).SpendLimit,
grant.(*types.BasicFeeAllowance).SpendLimit,
grant1.(*types.BasicFeeAllowance).SpendLimit,
)
}
})
@ -617,6 +622,181 @@ func (s *IntegrationTestSuite) TestTxWithFeeGrant() {
s.Require().Equal(uint32(0), resp.Code)
}
func (s *IntegrationTestSuite) TestFilteredFeeAllowance() {
val := s.network.Validators[0]
granter := val.Address
info, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee1", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
s.Require().NoError(err)
grantee := sdk.AccAddress(info.GetPubKey().Address())
clientCtx := val.ClientCtx
commonFlags := []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()),
}
spendLimit := sdk.NewCoin("stake", sdk.NewInt(1000))
allowMsgs := "/cosmos.gov.v1beta1.Msg/SubmitProposal"
testCases := []struct {
name string
args []string
expectErr bool
respType proto.Message
expectedCode uint32
}{
{
"wrong granter",
append(
[]string{
"wrong granter",
"cosmos1nph3cfzk6trsmfxkeu943nvach5qw4vwstnvkl",
fmt.Sprintf("--%s=%s", cli.FlagAllowedMsgs, allowMsgs),
fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, spendLimit.String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
},
commonFlags...,
),
true, &sdk.TxResponse{}, 0,
},
{
"wrong grantee",
append(
[]string{
granter.String(),
"wrong grantee",
fmt.Sprintf("--%s=%s", cli.FlagAllowedMsgs, allowMsgs),
fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, spendLimit.String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
},
commonFlags...,
),
true, &sdk.TxResponse{}, 0,
},
{
"valid filter fee grant",
append(
[]string{
granter.String(),
grantee.String(),
fmt.Sprintf("--%s=%s", cli.FlagAllowedMsgs, allowMsgs),
fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, spendLimit.String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
},
commonFlags...,
),
false, &sdk.TxResponse{}, 0,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.NewCmdFeeGrant()
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())
}
})
}
args := []string{
granter.String(),
grantee.String(),
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
}
// get filtered fee allowance and check info
cmd := cli.GetCmdQueryFeeGrant()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
s.Require().NoError(err)
resp := &types.FeeAllowanceGrant{}
s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), resp), out.String())
s.Require().Equal(resp.Grantee, resp.Grantee)
s.Require().Equal(resp.Granter, resp.Granter)
grant, err := resp.GetFeeGrant()
s.Require().NoError(err)
filteredFeeGrant, err := grant.(*types.AllowedMsgFeeAllowance).GetAllowance()
s.Require().NoError(err)
s.Require().Equal(
filteredFeeGrant.(*types.BasicFeeAllowance).SpendLimit.String(),
spendLimit.String(),
)
// exec filtered fee allowance
cases := []struct {
name string
malleate func() (testutil.BufferWriter, error)
expectErr bool
respType proto.Message
expectedCode uint32
}{
{
"valid tx",
func() (testutil.BufferWriter, error) {
return govtestutil.MsgSubmitProposal(val.ClientCtx, grantee.String(),
"Text Proposal", "No desc", govtypes.ProposalTypeText,
fmt.Sprintf("--%s=%s", flags.FlagFeeAccount, granter.String()),
)
},
false,
&sdk.TxResponse{},
0,
},
{
"should fail with unauthorized msgs",
func() (testutil.BufferWriter, error) {
args := append(
[]string{
grantee.String(),
"cosmos14cm33pvnrv2497tyt8sp9yavhmw83nwej3m0e8",
fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"),
fmt.Sprintf("--%s=%s", flags.FlagFeeAccount, granter),
},
commonFlags...,
)
cmd := cli.NewCmdFeeGrant()
return clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
},
false, &sdk.TxResponse{}, 7,
},
}
for _, tc := range cases {
tc := tc
s.Run(tc.name, func() {
out, err := tc.malleate()
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))
}

View File

@ -22,6 +22,7 @@ const (
FlagPeriod = "period"
FlagPeriodLimit = "period-limit"
FlagSpendLimit = "spend-limit"
FlagAllowedMsgs = "allowed-messages"
)
// GetTxCmd returns the transaction commands for this module
@ -55,8 +56,10 @@ func NewCmdFeeGrant() *cobra.Command {
Examples:
%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --expiration 36000 or
%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --period 3600 --period-limit 10stake --expiration 36000
`, version.AppName, types.ModuleName, version.AppName, types.ModuleName,
%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --period 3600 --period-limit 10stake --expiration 36000 or
%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --expiration 36000
--allowed-messages "/cosmos.gov.v1beta1.Msg/SubmitProposal,/cosmos.gov.v1beta1.Msg/Vote"
`, version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName,
),
),
Args: cobra.ExactArgs(2),
@ -143,6 +146,18 @@ Examples:
}
}
allowedMsgs, err := cmd.Flags().GetStringSlice(FlagAllowedMsgs)
if err != nil {
return err
}
if len(allowedMsgs) > 0 {
grant, err = types.NewAllowedMsgFeeAllowance(grant, allowedMsgs)
if err != nil {
return err
}
}
msg, err := types.NewMsgGrantFeeAllowance(grant, granter, grantee)
if err != nil {
return err
@ -160,10 +175,11 @@ Examples:
}
flags.AddTxFlagsToCmd(cmd)
cmd.Flags().StringSlice(FlagAllowedMsgs, []string{}, "Set of allowed messages for fee allowance")
cmd.Flags().Int64(FlagExpiration, 0, "The second unit of time duration which the grant is active for the user")
cmd.Flags().String(FlagSpendLimit, "", "Spend limit specifies the max limit can be used, if not mentioned there is no limit")
cmd.Flags().Int64(FlagPeriod, 0, "period specifies the time duration in which period_spend_limit coins can be spent before that allowance is reset")
cmd.Flags().String(FlagPeriodLimit, "", "// period limit specifies the maximum number of coins that can be spent in the period")
cmd.Flags().String(FlagPeriodLimit, "", "period limit specifies the maximum number of coins that can be spent in the period")
return cmd
}

View File

@ -92,7 +92,7 @@ func (s *IntegrationTestSuite) TestQueryFeeAllowance() {
"fail: no grants",
fmt.Sprintf("%s/cosmos/feegrant/v1beta1/fee_allowance/%s/%s", baseURL, val.Address.String(), s.grantee.String()),
true,
"no fee allowance found",
"no allowance",
func() {},
func(types.QueryFeeAllowanceResponse) {},
},

View File

@ -12,7 +12,11 @@ type GenesisState []types.FeeAllowanceGrant
// ValidateBasic ensures all grants in the genesis state are valid
func (g GenesisState) ValidateBasic() error {
for _, f := range g {
err := f.GetFeeGrant().ValidateBasic()
grant, err := f.GetFeeGrant()
if err != nil {
return err
}
err = grant.ValidateBasic()
if err != nil {
return err
}
@ -32,7 +36,12 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, data *types.GenesisState) {
panic(err)
}
err = k.GrantFeeAllowance(ctx, granter, grantee, f.GetFeeGrant())
grant, err := f.GetFeeGrant()
if err != nil {
panic(err)
}
err = k.GrantFeeAllowance(ctx, granter, grantee, grant)
if err != nil {
panic(err)
}

View File

@ -34,9 +34,9 @@ func (q Keeper) FeeAllowance(c context.Context, req *types.QueryFeeAllowanceRequ
ctx := sdk.UnwrapSDKContext(c)
feeAllowance := q.GetFeeAllowance(ctx, granterAddr, granteeAddr)
if feeAllowance == nil {
return nil, status.Errorf(codes.NotFound, "no fee allowance found")
feeAllowance, err := q.GetFeeAllowance(ctx, granterAddr, granteeAddr)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
msg, ok := feeAllowance.(proto.Message)

View File

@ -95,10 +95,10 @@ func (k Keeper) RevokeFeeAllowance(ctx sdk.Context, granter, grantee sdk.AccAddr
// GetFeeAllowance returns the allowance between the granter and grantee.
// If there is none, it returns nil, nil.
// Returns an error on parsing issues
func (k Keeper) GetFeeAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress) types.FeeAllowanceI {
func (k Keeper) GetFeeAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress) (types.FeeAllowanceI, error) {
grant, found := k.GetFeeGrant(ctx, granter, grantee)
if !found {
return nil
return nil, sdkerrors.Wrapf(types.ErrNoAllowance, "grant missing")
}
return grant.GetFeeGrant()
@ -161,13 +161,18 @@ func (k Keeper) IterateAllFeeAllowances(ctx sdk.Context, cb func(types.FeeAllowa
}
// UseGrantedFees will try to pay the given fee from the granter's account as requested by the grantee
func (k Keeper) UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins) error {
grant, found := k.GetFeeGrant(ctx, granter, grantee)
if !found || grant.GetFeeGrant() == nil {
func (k Keeper) UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins, msgs []sdk.Msg) error {
f, found := k.GetFeeGrant(ctx, granter, grantee)
if !found {
return sdkerrors.Wrapf(types.ErrNoAllowance, "grant missing")
}
remove, err := grant.GetFeeGrant().Accept(fee, ctx.BlockTime(), ctx.BlockHeight())
grant, err := f.GetFeeGrant()
if err != nil {
return err
}
remove, err := grant.Accept(ctx, fee, msgs)
if err == nil {
ctx.EventManager().EmitEvent(
sdk.NewEvent(
@ -189,5 +194,5 @@ func (k Keeper) UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress,
}
// if we accepted, store the updated state of the allowance
return k.GrantFeeAllowance(ctx, granter, grantee, grant.GetFeeGrant())
return k.GrantFeeAllowance(ctx, granter, grantee, grant)
}

View File

@ -109,7 +109,8 @@ func (suite *KeeperTestSuite) TestKeeperCrud() {
for name, tc := range cases {
tc := tc
suite.Run(name, func() {
allow := k.GetFeeAllowance(ctx, tc.granter, tc.grantee)
allow, _ := k.GetFeeAllowance(ctx, tc.granter, tc.grantee)
if tc.allowance == nil {
suite.Nil(allow)
return
@ -242,14 +243,14 @@ func (suite *KeeperTestSuite) TestUseGrantedFee() {
err = k.GrantFeeAllowance(ctx, suite.addrs[0], suite.addrs[3], expired)
suite.Require().NoError(err)
err = k.UseGrantedFees(ctx, tc.granter, tc.grantee, tc.fee)
err = k.UseGrantedFees(ctx, tc.granter, tc.grantee, tc.fee, []sdk.Msg{})
if tc.allowed {
suite.NoError(err)
} else {
suite.Error(err)
}
loaded := k.GetFeeAllowance(ctx, tc.granter, tc.grantee)
loaded, _ := k.GetFeeAllowance(ctx, tc.granter, tc.grantee)
suite.Equal(tc.final, loaded)
})

View File

@ -37,12 +37,16 @@ func (k msgServer) GrantFeeAllowance(goCtx context.Context, msg *types.MsgGrantF
}
// Checking for duplicate entry
f := k.Keeper.GetFeeAllowance(ctx, granter, grantee)
if f != nil {
if f, _ := k.Keeper.GetFeeAllowance(ctx, granter, grantee); f != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "fee allowance already exists")
}
err = k.Keeper.GrantFeeAllowance(ctx, granter, grantee, msg.GetFeeAllowanceI())
allowance, err := msg.GetFeeAllowanceI()
if err != nil {
return nil, err
}
err = k.Keeper.GrantFeeAllowance(ctx, granter, grantee, allowance)
if err != nil {
return nil, err
}

View File

@ -71,8 +71,7 @@ func SimulateMsgGrantFeeAllowance(ak types.AccountKeeper, bk types.BankKeeper, k
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgGrantFeeAllowance, "grantee and granter cannot be same"), nil, nil
}
f := k.GetFeeAllowance(ctx, granter.Address, grantee.Address)
if f != nil {
if f, _ := k.GetFeeAllowance(ctx, granter.Address, grantee.Address); f != nil {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgGrantFeeAllowance, "fee allowance exists"), nil, nil
}

View File

@ -19,7 +19,10 @@ var _ FeeAllowanceI = (*BasicFeeAllowance)(nil)
//
// If remove is true (regardless of the error), the FeeAllowance will be deleted from storage
// (eg. when it is used up). (See call to RevokeFeeAllowance in Keeper.UseGrantedFees)
func (a *BasicFeeAllowance) Accept(fee sdk.Coins, blockTime time.Time, blockHeight int64) (bool, error) {
func (a *BasicFeeAllowance) Accept(ctx sdk.Context, fee sdk.Coins, _ []sdk.Msg) (bool, error) {
blockTime := ctx.BlockTime()
blockHeight := ctx.BlockHeight()
if a.Expiration.IsExpired(&blockTime, blockHeight) {
return true, sdkerrors.Wrap(ErrFeeLimitExpired, "basic allowance")
}

View File

@ -2,16 +2,19 @@ package types_test
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/feegrant/types"
)
func TestBasicFeeValidAllow(t *testing.T) {
app := simapp.Setup(false)
eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 10))
atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555))
smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 43))
@ -22,7 +25,6 @@ func TestBasicFeeValidAllow(t *testing.T) {
allow *types.BasicFeeAllowance
// all other checks are ignored if valid=false
fee sdk.Coins
blockTime time.Time
blockHeight int64
valid bool
accept bool
@ -124,8 +126,10 @@ func TestBasicFeeValidAllow(t *testing.T) {
}
require.NoError(t, err)
ctx := app.BaseApp.NewContext(false, tmproto.Header{}).WithBlockHeight(tc.blockHeight)
// now try to deduct
remove, err := tc.allow.Accept(tc.fee, tc.blockTime, tc.blockHeight)
remove, err := tc.allow.Accept(ctx, tc.fee, []sdk.Msg{})
if !tc.accept {
require.Error(t, err)
return

View File

@ -18,6 +18,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
(*FeeAllowanceI)(nil),
&BasicFeeAllowance{},
&PeriodicFeeAllowance{},
&AllowedMsgFeeAllowance{},
)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)

View File

@ -18,4 +18,8 @@ var (
ErrInvalidDuration = sdkerrors.Register(DefaultCodespace, 4, "invalid duration")
// ErrNoAllowance error if there is no allowance for that pair
ErrNoAllowance = sdkerrors.Register(DefaultCodespace, 5, "no allowance")
// ErrNoMessages error if there is no message
ErrNoMessages = sdkerrors.Register(DefaultCodespace, 6, "allowed messages are empty")
// ErrMessageNotAllowed error if message is not allowed
ErrMessageNotAllowed = sdkerrors.Register(DefaultCodespace, 7, "message not allowed")
)

View File

@ -177,6 +177,47 @@ func (m *PeriodicFeeAllowance) GetPeriodReset() ExpiresAt {
return ExpiresAt{}
}
// AllowedMsgFeeAllowance creates allowance only for specified message types.
type AllowedMsgFeeAllowance struct {
// allowance can be any of basic and filtered fee allowance.
Allowance *types1.Any `protobuf:"bytes,1,opt,name=allowance,proto3" json:"allowance,omitempty"`
// allowed_messages are the messages for which the grantee has the access.
AllowedMessages []string `protobuf:"bytes,2,rep,name=allowed_messages,json=allowedMessages,proto3" json:"allowed_messages,omitempty"`
}
func (m *AllowedMsgFeeAllowance) Reset() { *m = AllowedMsgFeeAllowance{} }
func (m *AllowedMsgFeeAllowance) String() string { return proto.CompactTextString(m) }
func (*AllowedMsgFeeAllowance) ProtoMessage() {}
func (*AllowedMsgFeeAllowance) Descriptor() ([]byte, []int) {
return fileDescriptor_7279582900c30aea, []int{2}
}
func (m *AllowedMsgFeeAllowance) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *AllowedMsgFeeAllowance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_AllowedMsgFeeAllowance.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 *AllowedMsgFeeAllowance) XXX_Merge(src proto.Message) {
xxx_messageInfo_AllowedMsgFeeAllowance.Merge(m, src)
}
func (m *AllowedMsgFeeAllowance) XXX_Size() int {
return m.Size()
}
func (m *AllowedMsgFeeAllowance) XXX_DiscardUnknown() {
xxx_messageInfo_AllowedMsgFeeAllowance.DiscardUnknown(m)
}
var xxx_messageInfo_AllowedMsgFeeAllowance proto.InternalMessageInfo
// Duration is a span of a clock time or number of blocks.
// This is designed to be added to an ExpiresAt struct.
type Duration struct {
@ -192,7 +233,7 @@ func (m *Duration) Reset() { *m = Duration{} }
func (m *Duration) String() string { return proto.CompactTextString(m) }
func (*Duration) ProtoMessage() {}
func (*Duration) Descriptor() ([]byte, []int) {
return fileDescriptor_7279582900c30aea, []int{2}
return fileDescriptor_7279582900c30aea, []int{3}
}
func (m *Duration) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -281,7 +322,7 @@ func (m *ExpiresAt) Reset() { *m = ExpiresAt{} }
func (m *ExpiresAt) String() string { return proto.CompactTextString(m) }
func (*ExpiresAt) ProtoMessage() {}
func (*ExpiresAt) Descriptor() ([]byte, []int) {
return fileDescriptor_7279582900c30aea, []int{3}
return fileDescriptor_7279582900c30aea, []int{4}
}
func (m *ExpiresAt) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -366,7 +407,7 @@ func (m *FeeAllowanceGrant) Reset() { *m = FeeAllowanceGrant{} }
func (m *FeeAllowanceGrant) String() string { return proto.CompactTextString(m) }
func (*FeeAllowanceGrant) ProtoMessage() {}
func (*FeeAllowanceGrant) Descriptor() ([]byte, []int) {
return fileDescriptor_7279582900c30aea, []int{4}
return fileDescriptor_7279582900c30aea, []int{5}
}
func (m *FeeAllowanceGrant) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -419,6 +460,7 @@ func (m *FeeAllowanceGrant) GetAllowance() *types1.Any {
func init() {
proto.RegisterType((*BasicFeeAllowance)(nil), "cosmos.feegrant.v1beta1.BasicFeeAllowance")
proto.RegisterType((*PeriodicFeeAllowance)(nil), "cosmos.feegrant.v1beta1.PeriodicFeeAllowance")
proto.RegisterType((*AllowedMsgFeeAllowance)(nil), "cosmos.feegrant.v1beta1.AllowedMsgFeeAllowance")
proto.RegisterType((*Duration)(nil), "cosmos.feegrant.v1beta1.Duration")
proto.RegisterType((*ExpiresAt)(nil), "cosmos.feegrant.v1beta1.ExpiresAt")
proto.RegisterType((*FeeAllowanceGrant)(nil), "cosmos.feegrant.v1beta1.FeeAllowanceGrant")
@ -429,45 +471,48 @@ func init() {
}
var fileDescriptor_7279582900c30aea = []byte{
// 599 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0x4f, 0x6e, 0xd3, 0x40,
0x14, 0xc6, 0x6d, 0x9c, 0x96, 0x76, 0x02, 0x88, 0x8c, 0x22, 0xe1, 0x64, 0xe1, 0x94, 0x2c, 0x50,
0x84, 0x14, 0x9b, 0x16, 0x89, 0x05, 0x12, 0x42, 0x71, 0x69, 0x1b, 0x04, 0x0b, 0x64, 0x58, 0xb1,
0x89, 0x6c, 0x67, 0xea, 0x0c, 0xb5, 0x3d, 0x96, 0x67, 0x02, 0xcd, 0x25, 0x50, 0x97, 0x9c, 0x81,
0x35, 0x87, 0xa8, 0x58, 0x55, 0xac, 0x58, 0xb5, 0x28, 0x39, 0x01, 0x37, 0x40, 0xf3, 0xc7, 0x4e,
0x94, 0x10, 0x24, 0xa4, 0xae, 0xe2, 0x99, 0x79, 0xef, 0xfb, 0xbd, 0xf7, 0xbd, 0x99, 0x80, 0x07,
0x21, 0xa1, 0x09, 0xa1, 0xce, 0x31, 0x42, 0x51, 0xee, 0xa7, 0xcc, 0xf9, 0xb8, 0x1b, 0x20, 0xe6,
0xef, 0x96, 0x1b, 0x76, 0x96, 0x13, 0x46, 0xe0, 0x3d, 0x19, 0x67, 0x97, 0xdb, 0x2a, 0xae, 0x59,
0x8f, 0x48, 0x44, 0x44, 0x8c, 0xc3, 0xbf, 0x64, 0x78, 0xb3, 0x11, 0x11, 0x12, 0xc5, 0xc8, 0x11,
0xab, 0x60, 0x7c, 0xec, 0xf8, 0xe9, 0xa4, 0x38, 0x92, 0x4a, 0x03, 0x99, 0xa3, 0x64, 0xe5, 0x91,
0xa5, 0x8a, 0x09, 0x7c, 0x8a, 0xca, 0x42, 0x42, 0x82, 0x53, 0x75, 0xde, 0x5a, 0x56, 0x65, 0x38,
0x41, 0x94, 0xf9, 0x49, 0x56, 0x08, 0x2c, 0x07, 0x0c, 0xc7, 0xb9, 0xcf, 0x30, 0x51, 0x02, 0xed,
0x4b, 0x1d, 0xd4, 0x5c, 0x9f, 0xe2, 0xf0, 0x10, 0xa1, 0x5e, 0x1c, 0x93, 0x4f, 0x7e, 0x1a, 0x22,
0x18, 0x83, 0x2a, 0xcd, 0x50, 0x3a, 0x1c, 0xc4, 0x38, 0xc1, 0xcc, 0xd4, 0x77, 0x8c, 0x4e, 0x75,
0xaf, 0x61, 0xab, 0xd2, 0x78, 0x31, 0x45, 0xb7, 0xf6, 0x3e, 0xc1, 0xa9, 0xfb, 0xe8, 0xfc, 0xb2,
0xa5, 0x7d, 0xbd, 0x6a, 0x75, 0x22, 0xcc, 0x46, 0xe3, 0xc0, 0x0e, 0x49, 0xa2, 0xfa, 0x50, 0x3f,
0x5d, 0x3a, 0x3c, 0x71, 0xd8, 0x24, 0x43, 0x54, 0x24, 0x50, 0x0f, 0x08, 0xfd, 0xd7, 0x5c, 0x1e,
0xf6, 0x01, 0x40, 0xa7, 0x19, 0x96, 0x75, 0x99, 0x37, 0x76, 0xf4, 0x4e, 0x75, 0xaf, 0x6d, 0xaf,
0xb1, 0xd7, 0x3e, 0xe0, 0xa1, 0x88, 0xf6, 0x98, 0x5b, 0xe1, 0x54, 0x6f, 0x21, 0xf7, 0x69, 0xed,
0xc7, 0xb7, 0xee, 0xed, 0xc5, 0x4e, 0x5e, 0xb6, 0x7f, 0x1b, 0xa0, 0xfe, 0x06, 0xe5, 0x98, 0x0c,
0x97, 0x7a, 0x3c, 0x04, 0x1b, 0x01, 0x6f, 0xdc, 0xd4, 0x05, 0xf0, 0xe1, 0x5a, 0xe0, 0x8a, 0x3d,
0x0a, 0x2c, 0xd3, 0xe1, 0x73, 0xb0, 0x99, 0x09, 0x7d, 0x55, 0xf9, 0xfd, 0xb5, 0x42, 0x2f, 0x94,
0xf5, 0x2a, 0x5f, 0xa5, 0xc1, 0x09, 0x80, 0xf2, 0x6b, 0xb0, 0xe8, 0xb9, 0x71, 0xfd, 0x9e, 0xdf,
0x95, 0x98, 0xb7, 0x73, 0xe7, 0xc7, 0x40, 0xed, 0x0d, 0x42, 0x3f, 0x95, 0x78, 0xb3, 0x72, 0xfd,
0xe0, 0x3b, 0x12, 0xb2, 0xef, 0xa7, 0x82, 0x0d, 0x5f, 0x81, 0x5b, 0x0a, 0x9b, 0x23, 0x8a, 0x98,
0xb9, 0xf1, 0x9f, 0x23, 0xaf, 0xca, 0x6c, 0x8f, 0x27, 0xff, 0x6d, 0xe6, 0x1f, 0xc0, 0x56, 0xe1,
0x35, 0x7c, 0x06, 0xb6, 0x8a, 0x2b, 0xaf, 0x26, 0xdd, 0xb0, 0xe5, 0x9b, 0xb0, 0x8b, 0x37, 0xb1,
0x30, 0x98, 0x2f, 0x57, 0x2d, 0xbd, 0xaf, 0x79, 0x65, 0x0a, 0x34, 0xc1, 0x66, 0x10, 0x93, 0xf0,
0x84, 0x8a, 0xe9, 0x56, 0xfa, 0x9a, 0xa7, 0xd6, 0xee, 0x06, 0x30, 0xe8, 0x38, 0x69, 0x0f, 0xc1,
0x76, 0x59, 0x1e, 0x7c, 0x02, 0x2a, 0xfc, 0x01, 0x2a, 0x50, 0x73, 0x05, 0xf4, 0xae, 0x78, 0x9d,
0x6e, 0xe5, 0x4c, 0x92, 0x44, 0x3c, 0xa7, 0x8c, 0x10, 0x8e, 0x46, 0x4c, 0x50, 0x0c, 0x4e, 0x91,
0xeb, 0x82, 0xf2, 0x59, 0x07, 0xb5, 0xc5, 0x1e, 0x8f, 0xb8, 0x3f, 0xd0, 0x04, 0x37, 0x85, 0x51,
0x28, 0x17, 0xc4, 0x6d, 0xaf, 0x58, 0xce, 0x4f, 0x90, 0x50, 0x2c, 0x4f, 0x10, 0x3c, 0x00, 0xdb,
0x7e, 0xa1, 0x62, 0x1a, 0xa2, 0xce, 0xfa, 0x4a, 0x9d, 0xbd, 0x74, 0xe2, 0xd6, 0xbe, 0x2f, 0xfb,
0xea, 0xcd, 0x33, 0xdd, 0xa3, 0xf3, 0xa9, 0xa5, 0x5f, 0x4c, 0x2d, 0xfd, 0xd7, 0xd4, 0xd2, 0xcf,
0x66, 0x96, 0x76, 0x31, 0xb3, 0xb4, 0x9f, 0x33, 0x4b, 0x7b, 0xdf, 0xfd, 0xe7, 0xb5, 0x38, 0x9d,
0xff, 0xaf, 0x8a, 0x1b, 0x12, 0x6c, 0x0a, 0xe8, 0xe3, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x74,
0x27, 0xe6, 0x00, 0x77, 0x05, 0x00, 0x00,
// 650 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0x4d, 0x6f, 0xd3, 0x30,
0x18, 0xc7, 0x93, 0xa5, 0x1b, 0xab, 0xcb, 0xcb, 0x6a, 0x0d, 0xc8, 0x76, 0x48, 0x47, 0x0f, 0xa8,
0x20, 0x2d, 0x61, 0x43, 0xe2, 0x30, 0x09, 0xa1, 0x65, 0xec, 0x05, 0xc1, 0x24, 0x14, 0x38, 0x71,
0xa9, 0x9c, 0xc4, 0x4b, 0xc3, 0x92, 0x38, 0x8a, 0x5d, 0x58, 0xbf, 0x01, 0x27, 0xb4, 0x23, 0x47,
0xb8, 0x72, 0xe6, 0x43, 0x4c, 0x9c, 0x26, 0x4e, 0x9c, 0x36, 0xd4, 0x7e, 0x02, 0xbe, 0x01, 0x8a,
0xed, 0xa4, 0xa5, 0xa5, 0x48, 0xa0, 0x9d, 0x92, 0xc7, 0x7e, 0x9e, 0xff, 0xef, 0x79, 0xb1, 0x0d,
0x6e, 0x7b, 0x84, 0xc6, 0x84, 0x5a, 0x07, 0x18, 0x07, 0x19, 0x4a, 0x98, 0xf5, 0x66, 0xcd, 0xc5,
0x0c, 0xad, 0x95, 0x0b, 0x66, 0x9a, 0x11, 0x46, 0xe0, 0x4d, 0xe1, 0x67, 0x96, 0xcb, 0xd2, 0x6f,
0x79, 0x31, 0x20, 0x01, 0xe1, 0x3e, 0x56, 0xfe, 0x27, 0xdc, 0x97, 0x97, 0x02, 0x42, 0x82, 0x08,
0x5b, 0xdc, 0x72, 0xbb, 0x07, 0x16, 0x4a, 0x7a, 0xc5, 0x96, 0x50, 0x6a, 0x8b, 0x18, 0x29, 0x2b,
0xb6, 0x0c, 0x99, 0x8c, 0x8b, 0x28, 0x2e, 0x13, 0xf1, 0x48, 0x98, 0xc8, 0xfd, 0xc6, 0xb8, 0x2a,
0x0b, 0x63, 0x4c, 0x19, 0x8a, 0xd3, 0x42, 0x60, 0xdc, 0xc1, 0xef, 0x66, 0x88, 0x85, 0x44, 0x0a,
0x34, 0xcf, 0x54, 0x50, 0xb7, 0x11, 0x0d, 0xbd, 0x1d, 0x8c, 0x37, 0xa3, 0x88, 0xbc, 0x45, 0x89,
0x87, 0x61, 0x04, 0x6a, 0x34, 0xc5, 0x89, 0xdf, 0x8e, 0xc2, 0x38, 0x64, 0xba, 0xba, 0xa2, 0xb5,
0x6a, 0xeb, 0x4b, 0xa6, 0x4c, 0x2d, 0x4f, 0xa6, 0xa8, 0xd6, 0xdc, 0x22, 0x61, 0x62, 0xdf, 0x3b,
0x39, 0x6b, 0x28, 0x9f, 0xcf, 0x1b, 0xad, 0x20, 0x64, 0x9d, 0xae, 0x6b, 0x7a, 0x24, 0x96, 0x75,
0xc8, 0xcf, 0x2a, 0xf5, 0x0f, 0x2d, 0xd6, 0x4b, 0x31, 0xe5, 0x01, 0xd4, 0x01, 0x5c, 0xff, 0x59,
0x2e, 0x0f, 0xf7, 0x00, 0xc0, 0x47, 0x69, 0x28, 0xf2, 0xd2, 0x67, 0x56, 0xd4, 0x56, 0x6d, 0xbd,
0x69, 0x4e, 0x69, 0xaf, 0xb9, 0x9d, 0xbb, 0x62, 0xba, 0xc9, 0xec, 0x4a, 0x4e, 0x75, 0x46, 0x62,
0x37, 0xea, 0xdf, 0xbe, 0xac, 0x5e, 0x19, 0xad, 0xe4, 0x49, 0xf3, 0xa7, 0x06, 0x16, 0x9f, 0xe3,
0x2c, 0x24, 0xfe, 0x58, 0x8d, 0x3b, 0x60, 0xd6, 0xcd, 0x0b, 0xd7, 0x55, 0x0e, 0xbc, 0x3b, 0x15,
0x38, 0xd1, 0x1e, 0x09, 0x16, 0xe1, 0xf0, 0x11, 0x98, 0x4b, 0xb9, 0xbe, 0xcc, 0xfc, 0xd6, 0x54,
0xa1, 0xc7, 0xb2, 0xf5, 0x32, 0x5e, 0x86, 0xc1, 0x1e, 0x80, 0xe2, 0xaf, 0x3d, 0xda, 0x73, 0xed,
0xe2, 0x7b, 0xbe, 0x20, 0x30, 0x2f, 0x86, 0x9d, 0xef, 0x02, 0xb9, 0xd6, 0xf6, 0x50, 0x22, 0xf0,
0x7a, 0xe5, 0xe2, 0xc1, 0x57, 0x05, 0x64, 0x0b, 0x25, 0x9c, 0x0d, 0x9f, 0x82, 0xcb, 0x12, 0x9b,
0x61, 0x8a, 0x99, 0x3e, 0xfb, 0x8f, 0x23, 0xaf, 0x89, 0x68, 0x27, 0x0f, 0xfe, 0xd3, 0xcc, 0x3f,
0xa9, 0xe0, 0x06, 0x37, 0xb1, 0xbf, 0x4f, 0x83, 0xdf, 0xa6, 0xbe, 0x0d, 0xaa, 0xa8, 0x30, 0xe4,
0xe4, 0x17, 0x4d, 0x71, 0x47, 0xcc, 0xe2, 0x8e, 0x98, 0x9b, 0x49, 0xcf, 0xae, 0x7f, 0x1d, 0x97,
0x75, 0x86, 0x91, 0xf0, 0x0e, 0x58, 0x40, 0x02, 0xd0, 0x8e, 0x31, 0xa5, 0x28, 0xc0, 0x54, 0x9f,
0x59, 0xd1, 0x5a, 0x55, 0xe7, 0x9a, 0x5c, 0xdf, 0x97, 0xcb, 0x1b, 0xd7, 0xdf, 0x7d, 0x6c, 0x28,
0x93, 0x39, 0xbe, 0x06, 0xf3, 0xc5, 0x79, 0x80, 0x0f, 0xc1, 0x7c, 0x71, 0x2d, 0x65, 0x4e, 0x4b,
0x13, 0x39, 0x0d, 0x0f, 0xcf, 0x87, 0xf3, 0x86, 0xba, 0xa7, 0x38, 0x65, 0x08, 0xd4, 0xc1, 0x9c,
0x1b, 0x11, 0xef, 0x90, 0xf2, 0x13, 0x58, 0xd9, 0x53, 0x1c, 0x69, 0xdb, 0xb3, 0x40, 0xa3, 0xdd,
0xb8, 0xe9, 0x83, 0x6a, 0xd9, 0x42, 0xf8, 0x00, 0x54, 0xf2, 0x47, 0x42, 0x82, 0x96, 0x27, 0x40,
0x2f, 0x8b, 0x17, 0xc4, 0xae, 0x1c, 0x0b, 0x12, 0xf7, 0xcf, 0x29, 0x1d, 0x1c, 0x06, 0x1d, 0xc6,
0x29, 0x5a, 0x4e, 0x11, 0x76, 0x41, 0x79, 0xaf, 0x82, 0xfa, 0x68, 0x8d, 0xbb, 0xf9, 0x0c, 0xa1,
0x0e, 0x2e, 0xf1, 0x61, 0xe2, 0x8c, 0x13, 0xab, 0x4e, 0x61, 0x0e, 0x77, 0x30, 0x57, 0x2c, 0x77,
0xc6, 0x86, 0xa4, 0xfd, 0xef, 0x90, 0xec, 0xdd, 0x93, 0xbe, 0xa1, 0x9e, 0xf6, 0x0d, 0xf5, 0x47,
0xdf, 0x50, 0x8f, 0x07, 0x86, 0x72, 0x3a, 0x30, 0x94, 0xef, 0x03, 0x43, 0x79, 0xb5, 0xfa, 0xd7,
0xa3, 0x7b, 0x34, 0x7c, 0xfb, 0xf9, 0x29, 0x76, 0xe7, 0x38, 0xf4, 0xfe, 0xaf, 0x00, 0x00, 0x00,
0xff, 0xff, 0xfc, 0x05, 0xa9, 0xc7, 0x1b, 0x06, 0x00, 0x00,
}
func (m *BasicFeeAllowance) Marshal() (dAtA []byte, err error) {
@ -598,6 +643,50 @@ func (m *PeriodicFeeAllowance) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *AllowedMsgFeeAllowance) 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 *AllowedMsgFeeAllowance) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *AllowedMsgFeeAllowance) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.AllowedMessages) > 0 {
for iNdEx := len(m.AllowedMessages) - 1; iNdEx >= 0; iNdEx-- {
i -= len(m.AllowedMessages[iNdEx])
copy(dAtA[i:], m.AllowedMessages[iNdEx])
i = encodeVarintFeegrant(dAtA, i, uint64(len(m.AllowedMessages[iNdEx])))
i--
dAtA[i] = 0x12
}
}
if m.Allowance != nil {
{
size, err := m.Allowance.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintFeegrant(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *Duration) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@ -638,12 +727,12 @@ func (m *Duration_Duration) MarshalTo(dAtA []byte) (int, error) {
func (m *Duration_Duration) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
if m.Duration != nil {
n5, err5 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.Duration, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.Duration):])
if err5 != nil {
return 0, err5
n6, err6 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.Duration, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.Duration):])
if err6 != nil {
return 0, err6
}
i -= n5
i = encodeVarintFeegrant(dAtA, i, uint64(n5))
i -= n6
i = encodeVarintFeegrant(dAtA, i, uint64(n6))
i--
dAtA[i] = 0xa
}
@ -701,12 +790,12 @@ func (m *ExpiresAt_Time) MarshalTo(dAtA []byte) (int, error) {
func (m *ExpiresAt_Time) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
if m.Time != nil {
n6, err6 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.Time):])
if err6 != nil {
return 0, err6
n7, err7 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.Time):])
if err7 != nil {
return 0, err7
}
i -= n6
i = encodeVarintFeegrant(dAtA, i, uint64(n6))
i -= n7
i = encodeVarintFeegrant(dAtA, i, uint64(n7))
i--
dAtA[i] = 0xa
}
@ -828,6 +917,25 @@ func (m *PeriodicFeeAllowance) Size() (n int) {
return n
}
func (m *AllowedMsgFeeAllowance) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Allowance != nil {
l = m.Allowance.Size()
n += 1 + l + sovFeegrant(uint64(l))
}
if len(m.AllowedMessages) > 0 {
for _, s := range m.AllowedMessages {
l = len(s)
n += 1 + l + sovFeegrant(uint64(l))
}
}
return n
}
func (m *Duration) Size() (n int) {
if m == nil {
return 0
@ -1255,6 +1363,124 @@ func (m *PeriodicFeeAllowance) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *AllowedMsgFeeAllowance) 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 ErrIntOverflowFeegrant
}
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: AllowedMsgFeeAllowance: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: AllowedMsgFeeAllowance: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Allowance", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowFeegrant
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthFeegrant
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthFeegrant
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Allowance == nil {
m.Allowance = &types1.Any{}
}
if err := m.Allowance.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AllowedMessages", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowFeegrant
}
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 ErrInvalidLengthFeegrant
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthFeegrant
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.AllowedMessages = append(m.AllowedMessages, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipFeegrant(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthFeegrant
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *Duration) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0

View File

@ -19,7 +19,7 @@ type FeeAllowanceI interface {
//
// If remove is true (regardless of the error), the FeeAllowance will be deleted from storage
// (eg. when it is used up). (See call to RevokeFeeAllowance in Keeper.UseGrantedFees)
Accept(fee sdk.Coins, blockTime time.Time, blockHeight int64) (remove bool, err error)
Accept(ctx sdk.Context, fee sdk.Coins, msgs []sdk.Msg) (remove bool, err error)
// If we export fee allowances the timing info will be quite off (eg. go from height 100000 to 0)
// This callback allows the fee-allowance to change it's state and return a copy that is adjusted

View File

@ -0,0 +1,123 @@
package types
import (
"time"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
proto "github.com/gogo/protobuf/proto"
)
// TODO: Revisit this once we have propoer gas fee framework.
// Tracking issues https://github.com/cosmos/cosmos-sdk/issues/9054, https://github.com/cosmos/cosmos-sdk/discussions/9072
const (
gasCostPerIteration = uint64(10)
)
var _ FeeAllowanceI = (*AllowedMsgFeeAllowance)(nil)
var _ types.UnpackInterfacesMessage = (*AllowedMsgFeeAllowance)(nil)
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
func (a *AllowedMsgFeeAllowance) UnpackInterfaces(unpacker types.AnyUnpacker) error {
var allowance FeeAllowanceI
return unpacker.UnpackAny(a.Allowance, &allowance)
}
// NewAllowedMsgFeeAllowance creates new filtered fee allowance.
func NewAllowedMsgFeeAllowance(allowance FeeAllowanceI, allowedMsgs []string) (*AllowedMsgFeeAllowance, error) {
msg, ok := allowance.(proto.Message)
if !ok {
return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", msg)
}
any, err := types.NewAnyWithValue(msg)
if err != nil {
return nil, err
}
return &AllowedMsgFeeAllowance{
Allowance: any,
AllowedMessages: allowedMsgs,
}, nil
}
// GetAllowance returns allowed fee allowance.
func (a *AllowedMsgFeeAllowance) GetAllowance() (FeeAllowanceI, error) {
allowance, ok := a.Allowance.GetCachedValue().(FeeAllowanceI)
if !ok {
return nil, sdkerrors.Wrap(ErrNoAllowance, "failed to get allowance")
}
return allowance, nil
}
// Accept method checks for the filtered messages has valid expiry
func (a *AllowedMsgFeeAllowance) Accept(ctx sdk.Context, fee sdk.Coins, msgs []sdk.Msg) (bool, error) {
if !a.allMsgTypesAllowed(ctx, msgs) {
return false, sdkerrors.Wrap(ErrMessageNotAllowed, "message does not exist in allowed messages")
}
allowance, err := a.GetAllowance()
if err != nil {
return false, err
}
return allowance.Accept(ctx, fee, msgs)
}
func (a *AllowedMsgFeeAllowance) allowedMsgsToMap(ctx sdk.Context) map[string]bool {
msgsMap := make(map[string]bool, len(a.AllowedMessages))
for _, msg := range a.AllowedMessages {
ctx.GasMeter().ConsumeGas(gasCostPerIteration, "check msg")
msgsMap[msg] = true
}
return msgsMap
}
func (a *AllowedMsgFeeAllowance) allMsgTypesAllowed(ctx sdk.Context, msgs []sdk.Msg) bool {
msgsMap := a.allowedMsgsToMap(ctx)
for _, msg := range msgs {
ctx.GasMeter().ConsumeGas(gasCostPerIteration, "check msg")
if !msgsMap[msg.Type()] {
return false
}
}
return true
}
// PrepareForExport will adjust the expiration based on export time. In particular,
// it will subtract the dumpHeight from any height-based expiration to ensure that
// the elapsed number of blocks this allowance is valid for is fixed.
func (a *AllowedMsgFeeAllowance) PrepareForExport(dumpTime time.Time, dumpHeight int64) FeeAllowanceI {
allowance, err := a.GetAllowance()
if err != nil {
panic("failed to get allowance")
}
f, err := NewAllowedMsgFeeAllowance(allowance.PrepareForExport(dumpTime, dumpHeight), a.AllowedMessages)
if err != nil {
panic("failed to export filtered fee allowance")
}
return f
}
// ValidateBasic implements FeeAllowance and enforces basic sanity checks
func (a *AllowedMsgFeeAllowance) ValidateBasic() error {
if a.Allowance == nil {
return sdkerrors.Wrap(ErrNoAllowance, "allowance should not be empty")
}
if len(a.AllowedMessages) == 0 {
return sdkerrors.Wrap(ErrNoMessages, "allowed messages shouldn't be empty")
}
allowance, err := a.GetAllowance()
if err != nil {
return err
}
return allowance.ValidateBasic()
}

View File

@ -14,7 +14,11 @@ func NewGenesisState(entries []FeeAllowanceGrant) *GenesisState {
// ValidateGenesis ensures all grants in the genesis state are valid
func ValidateGenesis(data GenesisState) error {
for _, f := range data.FeeAllowances {
err := f.GetFeeGrant().ValidateBasic()
grant, err := f.GetFeeGrant()
if err != nil {
return err
}
err = grant.ValidateBasic()
if err != nil {
return err
}

View File

@ -47,17 +47,22 @@ func (a FeeAllowanceGrant) ValidateBasic() error {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "cannot self-grant fee authorization")
}
return a.GetFeeGrant().ValidateBasic()
f, err := a.GetFeeGrant()
if err != nil {
return err
}
return f.ValidateBasic()
}
// GetFeeGrant unpacks allowance
func (a FeeAllowanceGrant) GetFeeGrant() FeeAllowanceI {
func (a FeeAllowanceGrant) GetFeeGrant() (FeeAllowanceI, error) {
allowance, ok := a.Allowance.GetCachedValue().(FeeAllowanceI)
if !ok {
return nil
return nil, sdkerrors.Wrap(ErrNoAllowance, "failed to get allowance")
}
return allowance
return allowance, nil
}
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
@ -69,7 +74,12 @@ func (a FeeAllowanceGrant) UnpackInterfaces(unpacker types.AnyUnpacker) error {
// PrepareForExport will make all needed changes to the allowance to prepare to be
// re-imported at height 0, and return a copy of this grant.
func (a FeeAllowanceGrant) PrepareForExport(dumpTime time.Time, dumpHeight int64) FeeAllowanceGrant {
feegrant := a.GetFeeGrant().PrepareForExport(dumpTime, dumpHeight)
f, err := a.GetFeeGrant()
if err != nil {
return FeeAllowanceGrant{}
}
feegrant := f.PrepareForExport(dumpTime, dumpHeight)
if feegrant == nil {
return FeeAllowanceGrant{}
}

View File

@ -50,7 +50,12 @@ func (msg MsgGrantFeeAllowance) ValidateBasic() error {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "cannot self-grant fee authorization")
}
return msg.GetFeeAllowanceI().ValidateBasic()
allowance, err := msg.GetFeeAllowanceI()
if err != nil {
return err
}
return allowance.ValidateBasic()
}
func (msg MsgGrantFeeAllowance) GetSigners() []sdk.AccAddress {
@ -62,13 +67,13 @@ func (msg MsgGrantFeeAllowance) GetSigners() []sdk.AccAddress {
}
// GetFeeAllowanceI returns unpacked FeeAllowance
func (msg MsgGrantFeeAllowance) GetFeeAllowanceI() FeeAllowanceI {
func (msg MsgGrantFeeAllowance) GetFeeAllowanceI() (FeeAllowanceI, error) {
allowance, ok := msg.Allowance.GetCachedValue().(FeeAllowanceI)
if !ok {
return nil
return nil, sdkerrors.Wrap(ErrNoAllowance, "failed to get allowance")
}
return allowance
return allowance, nil
}
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces

View File

@ -19,7 +19,10 @@ var _ FeeAllowanceI = (*PeriodicFeeAllowance)(nil)
//
// If remove is true (regardless of the error), the FeeAllowance will be deleted from storage
// (eg. when it is used up). (See call to RevokeFeeAllowance in Keeper.UseGrantedFees)
func (a *PeriodicFeeAllowance) Accept(fee sdk.Coins, blockTime time.Time, blockHeight int64) (bool, error) {
func (a *PeriodicFeeAllowance) Accept(ctx sdk.Context, fee sdk.Coins, _ []sdk.Msg) (bool, error) {
blockTime := ctx.BlockTime()
blockHeight := ctx.BlockHeight()
if a.Basic.Expiration.IsExpired(&blockTime, blockHeight) {
return true, sdkerrors.Wrap(ErrFeeLimitExpired, "absolute limit")
}

View File

@ -2,16 +2,18 @@ package types_test
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/feegrant/types"
)
func TestPeriodicFeeValidAllow(t *testing.T) {
app := simapp.Setup(false)
atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555))
smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 43))
leftAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 512))
@ -22,7 +24,6 @@ func TestPeriodicFeeValidAllow(t *testing.T) {
allow types.PeriodicFeeAllowance
// all other checks are ignored if valid=false
fee sdk.Coins
blockTime time.Time
blockHeight int64
valid bool
accept bool
@ -187,8 +188,9 @@ func TestPeriodicFeeValidAllow(t *testing.T) {
}
require.NoError(t, err)
ctx := app.BaseApp.NewContext(false, tmproto.Header{}).WithBlockHeight(tc.blockHeight)
// now try to deduct
remove, err := tc.allow.Accept(tc.fee, tc.blockTime, tc.blockHeight)
remove, err := tc.allow.Accept(ctx, tc.fee, []sdk.Msg{})
if !tc.accept {
require.Error(t, err)
return

View File

@ -1,18 +1,21 @@
package types
import (
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authz "github.com/cosmos/cosmos-sdk/x/authz/exported"
)
// TODO: Revisit this once we have propoer gas fee framework.
// Tracking issues https://github.com/cosmos/cosmos-sdk/issues/9054, https://github.com/cosmos/cosmos-sdk/discussions/9072
const gasCostPerIteration = uint64(10)
var (
_ authz.Authorization = &StakeAuthorization{}
TypeDelegate = "/cosmos.staking.v1beta1.Msg/Delegate"
TypeUndelegate = "/cosmos.staking.v1beta1.Msg/Undelegate"
TypeBeginRedelegate = "/cosmos.staking.v1beta1.Msg/BeginRedelegate"
_ authz.Authorization = &StakeAuthorization{}
TypeDelegate = "/cosmos.staking.v1beta1.Msg/Delegate"
TypeUndelegate = "/cosmos.staking.v1beta1.Msg/Undelegate"
TypeBeginRedelegate = "/cosmos.staking.v1beta1.Msg/BeginRedelegate"
)
// NewStakeAuthorization creates a new StakeAuthorization object.
@ -46,8 +49,19 @@ func (authorization StakeAuthorization) MethodName() string {
return authzType
}
func (authorization StakeAuthorization) ValidateBasic() error {
if authorization.MaxTokens != nil && authorization.MaxTokens.IsNegative() {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "negative coin amount: %v", authorization.MaxTokens)
}
if authorization.AuthorizationType == AuthorizationType_AUTHORIZATION_TYPE_UNSPECIFIED {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "unknown authorization type")
}
return nil
}
// Accept implements Authorization.Accept.
func (authorization StakeAuthorization) Accept(msg sdk.ServiceMsg, block tmproto.Header) (updated authz.Authorization, delete bool, err error) {
func (authorization StakeAuthorization) Accept(ctx sdk.Context, msg sdk.ServiceMsg) (updated authz.Authorization, delete bool, err error) {
var validatorAddress string
var amount sdk.Coin
@ -68,13 +82,16 @@ func (authorization StakeAuthorization) Accept(msg sdk.ServiceMsg, block tmproto
isValidatorExists := false
allowedList := authorization.GetAllowList().GetAddress()
for _, validator := range allowedList {
ctx.GasMeter().ConsumeGas(gasCostPerIteration, "stake authorization")
if validator == validatorAddress {
isValidatorExists = true
break
}
}
denyList := authorization.GetDenyList().GetAddress()
for _, validator := range denyList {
ctx.GasMeter().ConsumeGas(gasCostPerIteration, "stake authorization")
if validator == validatorAddress {
return nil, false, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, " cannot delegate/undelegate to %s validator", validator)
}

View File

@ -7,6 +7,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
@ -21,13 +22,21 @@ var (
)
func TestAuthzAuthorizations(t *testing.T) {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
// verify ValidateBasic returns error for the AUTHORIZATION_TYPE_UNSPECIFIED authorization type
delAuth, err := stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNSPECIFIED, &coin100)
require.NoError(t, err)
require.Error(t, delAuth.ValidateBasic())
// verify MethodName
delAuth, _ := stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, &coin100)
delAuth, err = stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, &coin100)
require.NoError(t, err)
require.Equal(t, delAuth.MethodName(), stakingtypes.TypeDelegate)
// error both allow & deny list
_, err := stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{val1}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, &coin100)
_, err = stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{val1}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, &coin100)
require.Error(t, err)
// verify MethodName
@ -243,7 +252,7 @@ func TestAuthzAuthorizations(t *testing.T) {
t.Run(tc.msg, func(t *testing.T) {
delAuth, err := stakingtypes.NewStakeAuthorization(tc.allowed, tc.denied, tc.msgType, tc.limit)
require.NoError(t, err)
updated, del, err := delAuth.Accept(tc.srvMsg, tmproto.Header{})
updated, del, err := delAuth.Accept(ctx, tc.srvMsg)
if tc.expectErr {
require.Error(t, err)
require.Equal(t, tc.isDelete, del)

View File

@ -8,6 +8,9 @@ import (
"path"
"path/filepath"
"github.com/tendermint/tendermint/libs/log"
tmos "github.com/tendermint/tendermint/libs/os"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store/prefix"
store "github.com/cosmos/cosmos-sdk/store/types"
@ -16,8 +19,6 @@ import (
"github.com/cosmos/cosmos-sdk/types/module"
xp "github.com/cosmos/cosmos-sdk/x/upgrade/exported"
"github.com/cosmos/cosmos-sdk/x/upgrade/types"
"github.com/tendermint/tendermint/libs/log"
tmos "github.com/tendermint/tendermint/libs/os"
)
// UpgradeInfoFileName file to store upgrade information

View File

@ -195,7 +195,7 @@ func (s *KeeperTestSuite) TestSetUpgradedClient() {
}
// Test that the protocol version successfully increments after an
// upgrade and is succesfully set on BaseApp's appVersion.
// upgrade and is successfully set on BaseApp's appVersion.
func (s *KeeperTestSuite) TestIncrementProtocolVersion() {
oldProtocolVersion := s.app.BaseApp.AppVersion()
s.app.UpgradeKeeper.SetUpgradeHandler("dummy", func(_ sdk.Context, _ types.Plan, vm module.VersionMap) (module.VersionMap, error) { return vm, nil })