Skip to content

Commit

Permalink
feat(migrations): next proposer in state info (#1482)
Browse files Browse the repository at this point in the history
  • Loading branch information
keruch authored Nov 15, 2024
1 parent 0bc444c commit a308fd0
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 41 deletions.
46 changes: 46 additions & 0 deletions app/upgrades/v4/rollapp_state_info_next_proposer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package v4

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/dymensionxyz/gerr-cosmos/gerrc"

rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper"
sequencerkeeper "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper"
)

// migrateRollappStateInfoNextProposer should be called
// - after migrateSequencerIndices: it uses the proposer index
// - before migrateRollappFinalizationQueue: it uses the old queue to reduce store reads
func migrateRollappStateInfoNextProposer(ctx sdk.Context, rk *rollappkeeper.Keeper, sk *sequencerkeeper.Keeper) error {
// use old queue since it requires less store reads
q := rk.GetAllBlockHeightToFinalizationQueue(ctx)

// map rollappID to proposer address to avoid multiple reads from the sequencer keeper
// safe since the map is used only for existence checks
rollappProposers := make(map[string]string)

for _, queue := range q {
for _, stateInfoIndex := range queue.FinalizationQueue {
// get current proposer address
proposer, ok := rollappProposers[stateInfoIndex.RollappId]
if !ok {
p := sk.GetProposer(ctx, stateInfoIndex.RollappId)
if p.Sentinel() {
return gerrc.ErrInternal.Wrapf("proposer cannot be sentinel: rollappID %s", stateInfoIndex.RollappId)
}
rollappProposers[stateInfoIndex.RollappId] = p.Address
proposer = p.Address
}

// update state info
stateInfo, found := rk.GetStateInfo(ctx, stateInfoIndex.RollappId, stateInfoIndex.Index)
if !found {
return gerrc.ErrInternal.Wrapf("state info not found: rollappID %s, index %d", stateInfoIndex.RollappId, stateInfoIndex.Index)
}
stateInfo.NextProposer = proposer
rk.SetStateInfo(ctx, stateInfo)
}
}

return nil
}
4 changes: 4 additions & 0 deletions app/upgrades/v4/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ func CreateUpgradeHandler(
return nil, err
}

if err := migrateRollappStateInfoNextProposer(ctx, keepers.RollappKeeper, keepers.SequencerKeeper); err != nil {
return nil, err
}

if err := migrateRollappFinalizationQueue(ctx, keepers.RollappKeeper); err != nil {
return nil, err
}
Expand Down
121 changes: 82 additions & 39 deletions app/upgrades/v4/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ func (s *UpgradeTestSuite) TestUpgrade() {
// Check rollapp finalization queue
s.validateRollappFinalizationQueue()

s.validateNonFinalizedStateInfos()

s.validateStreamerMigration()

return
Expand Down Expand Up @@ -333,51 +335,67 @@ func (s *UpgradeTestSuite) validateRollappFinalizationQueue() {
{
CreationHeight: 1,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp1", Index: 1},
{RollappId: "rollapp1", Index: 2},
{RollappId: rollappIDFromIdx(1), Index: 1},
{RollappId: rollappIDFromIdx(1), Index: 2},
},
RollappId: "rollapp1",
RollappId: rollappIDFromIdx(1),
},
{
CreationHeight: 1,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp2", Index: 1},
{RollappId: "rollapp2", Index: 2},
{RollappId: rollappIDFromIdx(2), Index: 1},
{RollappId: rollappIDFromIdx(2), Index: 2},
},
RollappId: "rollapp2",
RollappId: rollappIDFromIdx(2),
},
{
CreationHeight: 1,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp3", Index: 1},
{RollappId: rollappIDFromIdx(3), Index: 1},
},
RollappId: "rollapp3",
RollappId: rollappIDFromIdx(3),
},
{
CreationHeight: 2,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp1", Index: 3},
{RollappId: rollappIDFromIdx(1), Index: 3},
},
RollappId: "rollapp1",
RollappId: rollappIDFromIdx(1),
},
{
CreationHeight: 2,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp3", Index: 2},
{RollappId: rollappIDFromIdx(3), Index: 2},
},
RollappId: "rollapp3",
RollappId: rollappIDFromIdx(3),
},
{
CreationHeight: 3,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp3", Index: 3},
{RollappId: "rollapp3", Index: 4},
{RollappId: rollappIDFromIdx(3), Index: 3},
{RollappId: rollappIDFromIdx(3), Index: 4},
},
RollappId: "rollapp3",
RollappId: rollappIDFromIdx(3),
},
}, queue)
}

func (s *UpgradeTestSuite) validateNonFinalizedStateInfos() {
queue, err := s.App.RollappKeeper.GetEntireFinalizationQueue(s.Ctx)
s.Require().NoError(err)

for _, q := range queue {
proposer := s.App.SequencerKeeper.GetProposer(s.Ctx, q.RollappId)
for _, stateInfoIndex := range q.FinalizationQueue {
stateInfo, found := s.App.RollappKeeper.GetStateInfo(s.Ctx, stateInfoIndex.RollappId, stateInfoIndex.Index)
s.Require().True(found)

// Verify that all non-finalized state infos contain the correct proposer (the same that's set in x/sequencer)
s.Require().Equal(proposer.Address, stateInfo.NextProposer)
}
}
}

func (s *UpgradeTestSuite) seedAndStoreRollapps(numRollapps int) {
for _, rollapp := range s.seedRollapps(numRollapps) {
s.App.RollappKeeper.SetRollapp(s.Ctx, rollapp)
Expand Down Expand Up @@ -448,46 +466,71 @@ func (s *UpgradeTestSuite) seedRollappFinalizationQueue() {
q1 := rollapptypes.BlockHeightToFinalizationQueue{
CreationHeight: 1,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp1", Index: 1},
{RollappId: "rollapp1", Index: 2},
{RollappId: "rollapp2", Index: 1},
{RollappId: "rollapp2", Index: 2},
{RollappId: "rollapp3", Index: 1},
{RollappId: rollappIDFromIdx(1), Index: 1},
{RollappId: rollappIDFromIdx(1), Index: 2},
{RollappId: rollappIDFromIdx(2), Index: 1},
{RollappId: rollappIDFromIdx(2), Index: 2},
{RollappId: rollappIDFromIdx(3), Index: 1},
},
RollappId: "",
}
q2 := rollapptypes.BlockHeightToFinalizationQueue{
CreationHeight: 2,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp1", Index: 3},
{RollappId: "rollapp3", Index: 2},
{RollappId: rollappIDFromIdx(1), Index: 3},
{RollappId: rollappIDFromIdx(3), Index: 2},
},
RollappId: "",
}
q3 := rollapptypes.BlockHeightToFinalizationQueue{
CreationHeight: 3,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp3", Index: 3},
{RollappId: "rollapp3", Index: 4},
{RollappId: rollappIDFromIdx(3), Index: 3},
{RollappId: rollappIDFromIdx(3), Index: 4},
},
RollappId: "",
}

s.App.RollappKeeper.SetBlockHeightToFinalizationQueue(s.Ctx, q1)
s.App.RollappKeeper.SetBlockHeightToFinalizationQueue(s.Ctx, q2)
s.App.RollappKeeper.SetBlockHeightToFinalizationQueue(s.Ctx, q3)

stateInfos := []rollapptypes.StateInfo{
generateStateInfo(1, 1),
generateStateInfo(1, 2),
generateStateInfo(1, 3),
generateStateInfo(2, 1),
generateStateInfo(2, 2),
generateStateInfo(3, 1),
generateStateInfo(3, 2),
generateStateInfo(3, 3),
generateStateInfo(3, 4),
}

for _, stateInfo := range stateInfos {
s.App.RollappKeeper.SetStateInfo(s.Ctx, stateInfo)
}
}

func generateStateInfo(rollappIdx, stateIdx int) rollapptypes.StateInfo {
return rollapptypes.StateInfo{
StateInfoIndex: rollapptypes.StateInfoIndex{
RollappId: rollappIDFromIdx(rollappIdx),
Index: uint64(stateIdx),
},
}
}

func TestReformatFinalizationQueue(t *testing.T) {
q := rollapptypes.BlockHeightToFinalizationQueue{
CreationHeight: 1,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp1", Index: 1},
{RollappId: "rollapp1", Index: 2},
{RollappId: "rollapp1", Index: 3},
{RollappId: "rollapp2", Index: 1},
{RollappId: "rollapp2", Index: 2},
{RollappId: "rollapp3", Index: 1},
{RollappId: rollappIDFromIdx(1), Index: 1},
{RollappId: rollappIDFromIdx(1), Index: 2},
{RollappId: rollappIDFromIdx(1), Index: 3},
{RollappId: rollappIDFromIdx(2), Index: 1},
{RollappId: rollappIDFromIdx(2), Index: 2},
{RollappId: rollappIDFromIdx(3), Index: 1},
},
RollappId: "", // empty for old-style queues
}
Expand All @@ -498,26 +541,26 @@ func TestReformatFinalizationQueue(t *testing.T) {
{
CreationHeight: 1,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp1", Index: 1},
{RollappId: "rollapp1", Index: 2},
{RollappId: "rollapp1", Index: 3},
{RollappId: rollappIDFromIdx(1), Index: 1},
{RollappId: rollappIDFromIdx(1), Index: 2},
{RollappId: rollappIDFromIdx(1), Index: 3},
},
RollappId: "rollapp1",
RollappId: rollappIDFromIdx(1),
},
{
CreationHeight: 1,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp2", Index: 1},
{RollappId: "rollapp2", Index: 2},
{RollappId: rollappIDFromIdx(2), Index: 1},
{RollappId: rollappIDFromIdx(2), Index: 2},
},
RollappId: "rollapp2",
RollappId: rollappIDFromIdx(2),
},
{
CreationHeight: 1,
FinalizationQueue: []rollapptypes.StateInfoIndex{
{RollappId: "rollapp3", Index: 1},
{RollappId: rollappIDFromIdx(3), Index: 1},
},
RollappId: "rollapp3",
RollappId: rollappIDFromIdx(3),
},
}, newQueues)
}
3 changes: 2 additions & 1 deletion proto/dymensionxyz/dymension/rollapp/state_info.proto
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ message StateInfo {
(gogoproto.moretags) = "yaml:\"created_at\""
];

// next sequencer is the bech32-encoded address of the next sequencer after the current sequencer
// NextProposer is the bech32-encoded address of the proposer that we expect to see in the next state info.
// Most of the time NextProposer is the current proposer. In case of rotation it is changed to the successor.
string nextProposer = 11;
}

Expand Down
3 changes: 2 additions & 1 deletion x/rollapp/types/state_info.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a308fd0

Please sign in to comment.