Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ func New(
encodingConfig.TxConfig,
),
auth.NewAppModule(appCodec, app.AccountKeeper, nil),
vesting.NewAppModule(app.AccountKeeper, app.BankKeeper),
vesting.NewAppModule(app.AccountKeeper, app.BankKeeper, app.UpgradeKeeper),
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
Expand Down
4 changes: 4 additions & 0 deletions cmd/seid/cmd/genaccounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ The association between the sei address and the eth address will also be created
cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts")
cmd.Flags().Int64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts")
cmd.Flags().Int64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts")
deprecationNotice := "the vesting module is deprecated; vesting parameters are kept only for legacy genesis tooling"
_ = cmd.Flags().MarkDeprecated(flagVestingAmt, deprecationNotice)
_ = cmd.Flags().MarkDeprecated(flagVestingStart, deprecationNotice)
_ = cmd.Flags().MarkDeprecated(flagVestingEnd, deprecationNotice)
flags.AddQueryFlagsToCmd(cmd)

return cmd
Expand Down
5 changes: 3 additions & 2 deletions sei-cosmos/x/auth/vesting/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const (
func GetTxCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: types.ModuleName,
Short: "Vesting transaction subcommands",
Short: "Vesting transaction subcommands (deprecated)",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
Expand All @@ -46,7 +46,8 @@ account can either be a delayed or continuous vesting account, which is determin
by the '--delayed' flag. All vesting accouts created will have their start time
set by the committed block's time. The end_time must be provided as a UNIX epoch
timestamp. You can also optionally configure the 'admin' field using the flag '--admin {addr}. This admin will be able to perform some administrative actions on the vesting account if set.`,
Args: cobra.ExactArgs(3),
Deprecated: "the vesting module is deprecated; the chain rejects this message, so new vesting accounts can no longer be created.",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion sei-cosmos/x/auth/vesting/client/testutil/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

func TestIntegrationTestSuite(t *testing.T) {
cfg := network.DefaultConfig()
cfg := network.DefaultConfig(t)
cfg.NumValidators = 1
suite.Run(t, NewIntegrationTestSuite(cfg))
}
24 changes: 15 additions & 9 deletions sei-cosmos/x/auth/vesting/client/testutil/suite.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package testutil

import (
"bytes"
"fmt"

"github.com/gogo/protobuf/proto"
Expand All @@ -11,6 +12,7 @@ import (
"github.com/sei-protocol/sei-chain/sei-cosmos/testutil/network"
sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types"
"github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/vesting/client/cli"
"github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/vesting/types"
)

type IntegrationTestSuite struct {
Expand Down Expand Up @@ -47,21 +49,21 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() {
expectedCode uint32
respType proto.Message
}{
"create a continuous vesting account": {
"create a continuous vesting account is rejected as deprecated": {
args: []string{
sdk.AccAddress("addr2_______________").String(),
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String(),
"4070908800",
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(2000))).String()),
},
expectErr: false,
expectedCode: 0,
expectedCode: types.ErrVestingDeprecated.ABCICode(),
respType: &sdk.TxResponse{},
},
"create a delayed vesting account": {
"create a delayed vesting account is rejected as deprecated": {
args: []string{
sdk.AccAddress("addr3_______________").String(),
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String(),
Expand All @@ -70,10 +72,10 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() {
fmt.Sprintf("--%s=true", cli.FlagDelayed),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(2000))).String()),
},
expectErr: false,
expectedCode: 0,
expectedCode: types.ErrVestingDeprecated.ABCICode(),
respType: &sdk.TxResponse{},
},
"invalid address": {
Expand Down Expand Up @@ -112,8 +114,6 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() {
}

for name, tc := range testCases {
tc := tc

s.Run(name, func() {
clientCtx := val.ClientCtx

Expand All @@ -122,7 +122,13 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalAsJSON(bw.Bytes(), tc.respType), bw.String())
// the mock IO buffer captures cobra's deprecation notice ahead
// of the JSON response; skip past it before unmarshalling
out := bw.Bytes()
if i := bytes.IndexByte(out, '{'); i > 0 {
out = out[i:]
}
s.Require().NoError(clientCtx.Codec.UnmarshalAsJSON(out, tc.respType), bw.String())

txResp := tc.respType.(*sdk.TxResponse)
s.Require().Equal(tc.expectedCode, txResp.Code)
Expand Down
8 changes: 5 additions & 3 deletions sei-cosmos/x/auth/vesting/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/vesting/types"
)

// NewHandler returns a handler for x/auth message types.
func NewHandler(ak keeper.AccountKeeper, bk types.BankKeeper) sdk.Handler {
msgServer := NewMsgServerImpl(ak, bk)
// NewHandler returns a handler for x/auth message types. The vesting module is
// deprecated: once the deprecation gate is active, every message is rejected
// with types.ErrVestingDeprecated.
func NewHandler(ak keeper.AccountKeeper, bk types.BankKeeper, uk types.UpgradeKeeper) sdk.Handler {
msgServer := NewMsgServerImpl(ak, bk, uk)

return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
Expand Down
112 changes: 103 additions & 9 deletions sei-cosmos/x/auth/vesting/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/suite"

sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types"
authtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/types"
"github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/vesting"
"github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/vesting/types"
)
Expand All @@ -24,15 +25,86 @@ func (suite *HandlerTestSuite) SetupTest() {
checkTx := false
app := app.Setup(suite.T(), checkTx, false, false)

suite.handler = vesting.NewHandler(app.AccountKeeper, app.BankKeeper)
suite.handler = vesting.NewHandler(app.AccountKeeper, app.BankKeeper, app.UpgradeKeeper)
suite.app = app
}

func (suite *HandlerTestSuite) TestMsgCreateVestingAccount() {
ctx := suite.app.BaseApp.NewContext(false, tmproto.Header{Height: suite.app.LastBlockHeight() + 1})
func (suite *HandlerTestSuite) fundedContext(chainID string) (sdk.Context, sdk.AccAddress, sdk.Coins) {
ctx := suite.app.BaseApp.NewContext(false, tmproto.Header{Height: suite.app.LastBlockHeight() + 1, ChainID: chainID})

balances := sdk.NewCoins(sdk.NewInt64Coin("test", 1000))
addr1 := sdk.AccAddress([]byte("addr1_______________"))
funder := sdk.AccAddress([]byte("addr1_______________"))
acc := suite.app.AccountKeeper.NewAccountWithAddress(ctx, funder)
suite.app.AccountKeeper.SetAccount(ctx, acc)
suite.Require().NoError(apptesting.FundAccount(suite.app.BankKeeper, ctx, funder, balances))

return ctx, funder, balances
}

// TestMsgCreateVestingAccountDeprecated verifies that on chains without
// pre-deprecation history (any chain-id outside the allowlist) the deprecated
// vesting module rejects account creation without mutating any state.
func (suite *HandlerTestSuite) TestMsgCreateVestingAccountDeprecated() {
ctx, addr1, balances := suite.fundedContext("")
addr2 := sdk.AccAddress([]byte("addr2_______________"))

testCases := []struct {
name string
msg *types.MsgCreateVestingAccount
}{
{
name: "delayed vesting account",
msg: types.NewMsgCreateVestingAccount(addr1, addr2, sdk.NewCoins(sdk.NewInt64Coin("test", 100)), ctx.BlockTime().Unix()+10000, true, nil),
},
{
name: "continuous vesting account",
msg: types.NewMsgCreateVestingAccount(addr1, addr2, sdk.NewCoins(sdk.NewInt64Coin("test", 100)), ctx.BlockTime().Unix()+10000, false, nil),
},
{
name: "delayed vesting account with admin",
msg: types.NewMsgCreateVestingAccount(addr1, addr2, sdk.NewCoins(sdk.NewInt64Coin("test", 100)), ctx.BlockTime().Unix()+10000, true, addr1),
},
}

for _, tc := range testCases {
suite.Run(tc.name, func() {
res, err := suite.handler(ctx, tc.msg)
suite.Require().ErrorIs(err, types.ErrVestingDeprecated)
suite.Require().Nil(res)

// no account is created and no funds move
suite.Require().Nil(suite.app.AccountKeeper.GetAccount(ctx, addr2))
suite.Require().Equal(balances, suite.app.BankKeeper.GetAllBalances(ctx, addr1))
})
}
}

// TestMsgCreateVestingAccountPostUpgrade verifies that on chains with
// pre-deprecation history the gate activates once the deprecation upgrade has
// executed.
func (suite *HandlerTestSuite) TestMsgCreateVestingAccountPostUpgrade() {
ctx, addr1, balances := suite.fundedContext("pacific-1")
addr2 := sdk.AccAddress([]byte("addr2_______________"))

suite.app.UpgradeKeeper.SetDone(ctx, vesting.DeprecationUpgradeName)

msg := types.NewMsgCreateVestingAccount(addr1, addr2, sdk.NewCoins(sdk.NewInt64Coin("test", 100)), ctx.BlockTime().Unix()+10000, true, nil)
res, err := suite.handler(ctx, msg)
suite.Require().ErrorIs(err, types.ErrVestingDeprecated)
suite.Require().Nil(res)

// no account is created and no funds move

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] This test uses DeprecationUpgradeName for SetDone, so it verifies the gate mechanism but not that the constant names the real shipping upgrade — a wrong plan name (e.g. v6.7 vs v6.6) would still make this test pass while the gate never fires on mainnet. Consider asserting the constant against the registered upgrade tag list.

suite.Require().Nil(suite.app.AccountKeeper.GetAccount(ctx, addr2))
suite.Require().Equal(balances, suite.app.BankKeeper.GetAllBalances(ctx, addr1))
}

// TestMsgCreateVestingAccountPreUpgradeHistory verifies that on chains with
// pre-deprecation history the original behavior is preserved below the
// deprecation upgrade height, so replaying historical blocks yields identical
// state.
func (suite *HandlerTestSuite) TestMsgCreateVestingAccountPreUpgradeHistory() {
ctx, addr1, _ := suite.fundedContext("pacific-1")

addr2 := sdk.AccAddress([]byte("addr2_______________"))
addr3 := sdk.AccAddress([]byte("addr3_______________"))
addr4 := sdk.AccAddress([]byte("addr4_______________"))
Expand All @@ -41,9 +113,7 @@ func (suite *HandlerTestSuite) TestMsgCreateVestingAccount() {
addr7 := sdk.AccAddress([]byte("addr7_______________"))
addr8 := sdk.AccAddress([]byte("addr8_______________"))

acc1 := suite.app.AccountKeeper.NewAccountWithAddress(ctx, addr1)
suite.app.AccountKeeper.SetAccount(ctx, acc1)
suite.Require().NoError(apptesting.FundAccount(suite.app.BankKeeper, ctx, addr1, balances))
balances := sdk.NewCoins(sdk.NewInt64Coin("test", 1000))
acc4 := suite.app.AccountKeeper.NewAccountWithAddress(ctx, addr4)
suite.app.AccountKeeper.SetAccount(ctx, acc4)
suite.Require().NoError(apptesting.FundAccount(suite.app.BankKeeper, ctx, addr4, balances))
Expand Down Expand Up @@ -86,8 +156,6 @@ func (suite *HandlerTestSuite) TestMsgCreateVestingAccount() {
}

for _, tc := range testCases {
tc := tc

suite.Run(tc.name, func() {
res, err := suite.handler(ctx, tc.msg)
if tc.expectErr {
Expand Down Expand Up @@ -115,6 +183,32 @@ func (suite *HandlerTestSuite) TestMsgCreateVestingAccount() {
}
}

// TestExistingVestingAccountsStillSupported verifies that vesting accounts
// already in state remain decodable and keep vesting after the module's
// deprecation.
func (suite *HandlerTestSuite) TestExistingVestingAccountsStillSupported() {
ctx := suite.app.BaseApp.NewContext(false, tmproto.Header{Height: suite.app.LastBlockHeight() + 1})

addr := sdk.AccAddress([]byte("vestacct____________"))
origVesting := sdk.NewCoins(sdk.NewInt64Coin("test", 100))
endTime := ctx.BlockTime().Unix() + 10000

baseAcc, ok := suite.app.AccountKeeper.NewAccountWithAddress(ctx, addr).(*authtypes.BaseAccount)
suite.Require().True(ok)

vestingAcc := types.NewDelayedVestingAccountRaw(types.NewBaseVestingAccount(baseAcc, origVesting, endTime, nil))
suite.app.AccountKeeper.SetAccount(ctx, vestingAcc)
suite.Require().NoError(apptesting.FundAccount(suite.app.BankKeeper, ctx, addr, origVesting))

accI := suite.app.AccountKeeper.GetAccount(ctx, addr)
suite.Require().NotNil(accI)

acc, ok := accI.(*types.DelayedVestingAccount)
suite.Require().True(ok)
suite.Require().Equal(origVesting, acc.GetVestingCoins(ctx.BlockTime()))
suite.Require().True(suite.app.BankKeeper.SpendableCoins(ctx, addr).IsZero())
}

func TestHandlerTestSuite(t *testing.T) {
suite.Run(t, new(HandlerTestSuite))
}
33 changes: 0 additions & 33 deletions sei-cosmos/x/auth/vesting/metrics.go

This file was deleted.

19 changes: 16 additions & 3 deletions sei-cosmos/x/auth/vesting/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ var (
// AppModuleBasic defines the basic application module used by the sub-vesting
// module. The module itself contain no special logic or state other than message
// handling.
//
// The vesting module is deprecated: once the deprecation gate is active (the
// DeprecationUpgradeName upgrade on chains with pre-deprecation history,
// genesis everywhere else), its message handlers reject all messages, so new
// vesting accounts can no longer be created. The module must remain wired into
// the app so its codec and interface registrations stay in place: they are
// required to decode existing vesting accounts in the auth store and
// historical transactions.
type AppModuleBasic struct{}

// Name returns the module's name.
Expand Down Expand Up @@ -83,18 +91,23 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command {

// AppModule extends the AppModuleBasic implementation by implementing the
// AppModule interface.
//
// The vesting module is deprecated; see AppModuleBasic. Once the deprecation
// gate is active, all message handlers return types.ErrVestingDeprecated.
type AppModule struct {
AppModuleBasic

accountKeeper keeper.AccountKeeper
bankKeeper types.BankKeeper
upgradeKeeper types.UpgradeKeeper
}

func NewAppModule(ak keeper.AccountKeeper, bk types.BankKeeper) AppModule {
func NewAppModule(ak keeper.AccountKeeper, bk types.BankKeeper, uk types.UpgradeKeeper) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{},
accountKeeper: ak,
bankKeeper: bk,
upgradeKeeper: uk,
}
}

Expand All @@ -103,7 +116,7 @@ func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}

// Route returns the module's message router and handler.
func (am AppModule) Route() sdk.Route {
return sdk.NewRoute(types.RouterKey, NewHandler(am.accountKeeper, am.bankKeeper))
return sdk.NewRoute(types.RouterKey, NewHandler(am.accountKeeper, am.bankKeeper, am.upgradeKeeper))
}

// QuerierRoute returns an empty string as the module contains no query
Expand All @@ -112,7 +125,7 @@ func (AppModule) QuerierRoute() string { return "" }

// RegisterServices registers module services.
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), NewMsgServerImpl(am.accountKeeper, am.bankKeeper))
types.RegisterMsgServer(cfg.MsgServer(), NewMsgServerImpl(am.accountKeeper, am.bankKeeper, am.upgradeKeeper))
}

// LegacyQuerierHandler performs a no-op.
Expand Down
Loading
Loading