Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat (l2): hard fork #591

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
22 changes: 22 additions & 0 deletions proto/sequencers/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ service Msg {

// Consensus Messages
rpc UpsertSequencer(ConsensusMsgUpsertSequencer) returns (ConsensusMsgUpsertSequencerResponse);
rpc BumpAccountSequences(MsgBumpAccountSequences) returns (MsgBumpAccountSequencesResponse);
rpc UpgradeDRS(MsgUpgradeDRS) returns (MsgUpgradeDRSResponse);
}

message MsgUpdateRewardAddress {
Expand Down Expand Up @@ -55,3 +57,23 @@ message ConsensusMsgUpsertSequencer {
}

message ConsensusMsgUpsertSequencerResponse {}

message MsgBumpAccountSequences {
option (cosmos.msg.v1.signer) = "authority";
// authority defines the address of the authority that is allowed to bump the account sequences.
// this is gov but it can be triggered by a consensus message.
string authority = 1;
}

message MsgBumpAccountSequencesResponse {}

message MsgUpgradeDRS {
option (cosmos.msg.v1.signer) = "authority";
// authority defines the address of the authority that is allowed to bump the account sequences.
// this is gov but it can be triggered by a consensus message.
string authority = 1;

uint64 drs_version = 2;
}

message MsgUpgradeDRSResponse {}
4 changes: 4 additions & 0 deletions testutil/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,10 @@ func NewRollapp(
keys[seqtypes.StoreKey],
app.GetSubspace(seqtypes.ModuleName),
authtypes.NewModuleAddress(seqtypes.ModuleName).String(),
app.AccountKeeper,
app.RollappParamsKeeper,
app.UpgradeKeeper,
nil,
)

app.IBCKeeper = ibckeeper.NewKeeper(
Expand Down
29 changes: 25 additions & 4 deletions x/sequencers/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import (
"fmt"
"time"

upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper"

"cosmossdk.io/collections"
"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/tendermint/tendermint/libs/log"
Expand All @@ -25,12 +28,22 @@ type StakingKeeper interface {

var _ StakingKeeper = (*Keeper)(nil)

// AccountBumpFilterFunc is a function signature that filters accounts whose sequence should be bumped.
// IT is passed the account proto name to avoid re-computing it, it is also passed the account in case
// casting is needed.
type AccountBumpFilterFunc = func(accountProtoName string, account authtypes.AccountI) (bool, error)

type Keeper struct {
cdc codec.BinaryCodec
storeKey storetypes.StoreKey
paramstore paramtypes.Subspace
authority string // address of the authorized actor that can execute consensus msgs

accountKeeper types.AccountKeeper
rollapParamsKeeper types.RollappParamsKeeper
accountBumpFilters []AccountBumpFilterFunc
upgradeKeeper upgradekeeper.Keeper

whitelistedRelayers collections.Map[sdk.ValAddress, types.WhitelistedRelayers]
}

Expand All @@ -39,6 +52,10 @@ func NewKeeper(
storeKey storetypes.StoreKey,
ps paramtypes.Subspace,
authority string,
accountKeeper types.AccountKeeper,
rollapParamsKeeper types.RollappParamsKeeper,
upgradeKeeper upgradekeeper.Keeper,
accountBumpFilters []AccountBumpFilterFunc,
) *Keeper {
// set KeyTable if it has not already been set
if !ps.HasKeyTable() {
Expand All @@ -48,10 +65,14 @@ func NewKeeper(
sb := collections.NewSchemaBuilder(collcompat.NewKVStoreService(storeKey))

return &Keeper{
cdc: cdc,
storeKey: storeKey,
paramstore: ps,
authority: authority,
cdc: cdc,
storeKey: storeKey,
paramstore: ps,
authority: authority,
accountKeeper: accountKeeper,
rollapParamsKeeper: rollapParamsKeeper,
accountBumpFilters: accountBumpFilters,
upgradeKeeper: upgradeKeeper,
whitelistedRelayers: collections.NewMap(
sb,
types.WhitelistedRelayersPrefix(),
Expand Down
99 changes: 99 additions & 0 deletions x/sequencers/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

import (
"context"
"errors"
"fmt"

Check failure on line 6 in x/sequencers/keeper/msg_server.go

View workflow job for this annotation

GitHub Actions / golangci-lint

File is not `goimports`-ed (goimports)
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
"github.com/dymensionxyz/gerr-cosmos/gerrc"
"github.com/gogo/protobuf/proto"

"github.com/dymensionxyz/dymension-rdk/utils/uevent"
"github.com/dymensionxyz/dymension-rdk/x/sequencers/types"
Expand Down Expand Up @@ -113,3 +118,97 @@

return &types.ConsensusMsgUpsertSequencerResponse{}, nil
}

// defines the list of accounts we want to bump the sequence
var handleAccounts = map[string]struct{}{
proto.MessageName(&authtypes.BaseAccount{}): {},
proto.MessageName(&vestingtypes.BaseVestingAccount{}): {},
proto.MessageName(&vestingtypes.ContinuousVestingAccount{}): {},
proto.MessageName(&vestingtypes.DelayedVestingAccount{}): {},
proto.MessageName(&vestingtypes.PeriodicVestingAccount{}): {},
proto.MessageName(&vestingtypes.PermanentLockedAccount{}): {},
}

const BumpSequence = 10_000_000_000

func (m msgServer) BumpAccountSequences(goCtx context.Context, msg *types.MsgBumpAccountSequences) (*types.MsgBumpAccountSequencesResponse, error) {
if msg.Authority != m.authority {
return nil, sdkerrors.ErrorInvalidSigner.Wrapf("only an authorized actor can bump account sequences")
}

ctx := sdk.UnwrapSDKContext(goCtx)

var allErrors error
Copy link
Contributor

Choose a reason for hiding this comment

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

This is weird, you're making a stack of errors
You should only call Join once

m.accountKeeper.IterateAccounts(ctx, func(account authtypes.AccountI) bool {
Copy link
Collaborator

Choose a reason for hiding this comment

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

why u not breaking with error on the first error?

// handle well known accounts
accType := proto.MessageName(account)
_, toHandle := handleAccounts[accType]
if toHandle {
err := m.bumpAccountSequence(ctx, account)
allErrors = errors.Join(allErrors, err)
} else {
// check if it can be handled by something custom
for _, f := range m.accountBumpFilters {
toBump, err := f(accType, account)
if err != nil {
allErrors = errors.Join(allErrors, fmt.Errorf("filter account: %w", err))
return false
}
if toBump {
err := m.bumpAccountSequence(ctx, account)
allErrors = errors.Join(allErrors, err)
break
}
Comment on lines +147 to +161
Copy link
Contributor

Choose a reason for hiding this comment

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

Can refac to only call bump once

}
}
return false
})

// we could decide to stop or continue
return &types.MsgBumpAccountSequencesResponse{}, allErrors
}

func (m msgServer) bumpAccountSequence(ctx sdk.Context, acc authtypes.AccountI) error {
err := acc.SetSequence(acc.GetSequence() + BumpSequence)
if err != nil {
return fmt.Errorf("set account sequence: %w", err)
}
m.accountKeeper.SetAccount(ctx, acc)
return nil
}

func (m msgServer) UpgradeDRS(goCtx context.Context, drs *types.MsgUpgradeDRS) (*types.MsgUpgradeDRSResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

needUpgrade := m.updateDrsVersion(ctx, drs.DrsVersion)

if needUpgrade {
err := m.upgradeKeeper.ScheduleUpgrade(ctx, upgradetypes.Plan{
Name: fmt.Sprintf("upgrade-drs-%d", drs.DrsVersion),
Height: ctx.BlockHeight(),
Info: fmt.Sprintf("upgrade to DRS version %d", drs.DrsVersion),
})
if err != nil {
return nil, fmt.Errorf("schedule upgrade: %w", err)
}
}

return &types.MsgUpgradeDRSResponse{}, nil
}

// updateDrsVersion updates the DRS (Dynamic Rollup System) protocol version if it differs from the current version.
// The function compares the new version against the existing one and updates the parameters if they differ.
//
// Returns:
// - bool: true if the version was updated, false if no update was needed (versions were identical)
func (m msgServer) updateDrsVersion(ctx sdk.Context, newVersion uint64) bool {
currentParams := m.rollapParamsKeeper.GetParams(ctx)
if currentParams.DrsVersion == uint32(newVersion) {
return false
}

currentParams.DrsVersion = uint32(newVersion)
m.rollapParamsKeeper.SetParams(ctx, currentParams)

return true
}
121 changes: 119 additions & 2 deletions x/sequencers/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/dymensionxyz/dymension-rdk/x/sequencers/keeper"
"github.com/stretchr/testify/require"

testkeepers "github.com/dymensionxyz/dymension-rdk/testutil/keepers"
Expand All @@ -19,10 +20,9 @@ func TestHappyPath(t *testing.T) {
app = utils.Setup(t, false)
_, ctx = testkeepers.NewTestSequencerKeeperFromApp(app)
authority = authtypes.NewModuleAddress(types.ModuleName).String()
msgServer = keeper.NewMsgServerImpl(app.SequencersKeeper)
)

t.Log(authority)

// prepare test data
var (
operator = utils.Proposer.GetOperator()
Expand Down Expand Up @@ -135,4 +135,121 @@ func TestHappyPath(t *testing.T) {
// validate results
validateResults(rewardAddr2.String(), relayers2)
})

t.Run("MsgBumpAccountSequences", func(t *testing.T) {
// all accounts are module accounts. this ensures if the assumption
// change in the future we will realize it.
accs := app.AccountKeeper.GetAllAccounts(ctx)
for _, acc := range accs {
require.IsType(t, acc, &authtypes.ModuleAccount{})
}

// add a new account
newAcc := utils.AccAddress()
acc := app.AccountKeeper.NewAccountWithAddress(ctx, newAcc)
app.AccountKeeper.SetAccount(ctx, acc)

// now we invoke bump account sequences and we should see this new acc
// sequence bumped.
msg := &types.MsgBumpAccountSequences{
Authority: authority,
}
resp, err := msgServer.BumpAccountSequences(sdk.WrapSDKContext(ctx), msg)
require.NoError(t, err)
require.NotNil(t, resp)

// ensure accounts are correctly bumped
accs = app.AccountKeeper.GetAllAccounts(ctx)
for _, acc := range accs {
switch concreteAccount := acc.(type) {
case *authtypes.ModuleAccount:
// module accounts should not be bumped
require.Zero(t, concreteAccount.GetSequence())
case *authtypes.BaseAccount:
// base accounts should be bumped
require.Equal(t, uint64(keeper.BumpSequence), concreteAccount.GetSequence())
}
}
})
}

func TestUpgradeDRS(t *testing.T) {
// prepare test
var (
app = utils.Setup(t, false)
_, ctx = testkeepers.NewTestSequencerKeeperFromApp(app)
)

tests := []struct {
name string
drsVersion uint64
expectError bool
}{
{
name: "Success: Update DRS version",
drsVersion: 2,
expectError: false,
},
{
name: "Success: Update to higher version",
drsVersion: 10,
expectError: false,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// Get initial params
initialParams := app.RollappParamsKeeper.GetParams(ctx)

// Create message
msg := &types.MsgUpgradeDRS{
Authority: authtypes.NewModuleAddress("gov").String(),
DrsVersion: tc.drsVersion,
}

// Validate basic
err := msg.ValidateBasic()
require.NoError(t, err)

// Execute message
handler := app.MsgServiceRouter().Handler(new(types.MsgUpgradeDRS))
_, err = handler(ctx, msg)

if tc.expectError {
require.Error(t, err)
// Verify params haven't changed
currentParams := app.RollappParamsKeeper.GetParams(ctx)
require.Equal(t, initialParams.DrsVersion, currentParams.DrsVersion)
} else {
require.NoError(t, err)
// Verify params have been updated
currentParams := app.RollappParamsKeeper.GetParams(ctx)
require.Equal(t, uint32(tc.drsVersion), currentParams.DrsVersion)
require.NotEqual(t, initialParams.DrsVersion, currentParams.DrsVersion)
}
})
}

t.Run("Multiple updates", func(t *testing.T) {
versions := []uint64{3, 5, 8}

for _, version := range versions {
msg := &types.MsgUpgradeDRS{
Authority: authtypes.NewModuleAddress("gov").String(),
DrsVersion: version,
}

err := msg.ValidateBasic()
require.NoError(t, err)

handler := app.MsgServiceRouter().Handler(new(types.MsgUpgradeDRS))
_, err = handler(ctx, msg)
require.NoError(t, err)

// Verify version was updated
currentParams := app.RollappParamsKeeper.GetParams(ctx)
require.Equal(t, uint32(version), currentParams.DrsVersion)
}
})
}
17 changes: 17 additions & 0 deletions x/sequencers/types/expected_keepers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package types

import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/dymensionxyz/dymension-rdk/x/rollappparams/types"
)

type AccountKeeper interface {
IterateAccounts(ctx sdk.Context, do func(i authtypes.AccountI) bool)
SetAccount(ctx sdk.Context, acc authtypes.AccountI)
}

type RollappParamsKeeper interface {
GetParams(ctx sdk.Context) (params types.Params)
SetParams(ctx sdk.Context, params types.Params)
}
Loading
Loading