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(sequencer): hardforking when rotating to sentinel #1455

Conversation

mtsitrin
Copy link
Contributor

closes #1430

Copy link

codecov bot commented Nov 10, 2024

Codecov Report

Attention: Patch coverage is 73.41772% with 21 lines in your changes missing coverage. Please review.

Please upload report for BASE (mtsitrin/937-rollapp-hard-fork-hub-side@c25d2bc). Learn more about missing BASE report.

Files with missing lines Patch % Lines
x/sequencer/keeper/rotation.go 61.11% 9 Missing and 5 partials ⚠️
x/sequencer/keeper/fraud.go 75.00% 2 Missing and 2 partials ⚠️
x/sequencer/keeper/msg_server_create.go 0.00% 0 Missing and 1 partial ⚠️
x/sequencer/keeper/msg_server_update.go 0.00% 0 Missing and 1 partial ⚠️
x/sequencer/types/hooks.go 66.66% 1 Missing ⚠️
Additional details and impacted files
@@                            Coverage Diff                             @@
##             mtsitrin/937-rollapp-hard-fork-hub-side    #1455   +/-   ##
==========================================================================
  Coverage                                           ?   22.70%           
==========================================================================
  Files                                              ?      575           
  Lines                                              ?   124311           
  Branches                                           ?        0           
==========================================================================
  Hits                                               ?    28227           
  Misses                                             ?    92312           
  Partials                                           ?     3772           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@mtsitrin mtsitrin marked this pull request as ready for review November 10, 2024 18:28
@mtsitrin mtsitrin requested a review from a team as a code owner November 10, 2024 18:28
@mtsitrin mtsitrin linked an issue Nov 10, 2024 that may be closed by this pull request
Copy link
Contributor

@danwt danwt left a comment

Choose a reason for hiding this comment

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

TBH to me it's becoming a lot more complicated and coupling x/sequencer with hard fork

I'm not sure why you can't just trigger hard fork in AfterChooseNewProposer hook on rollapp keeper if after is sentinel

This is now drifting a lot from the original spec https://www.notion.so/dymension/Rollapp-Hard-Fork-Hub-POV-10aa4a51f86a80a6a1d2ca8fcca9e68b?pvs=4#c310c5683fff48b490a0a5e403aa5fc0

Which had a very clear decoupling, and was IMO, easy and simple

Comment on lines 43 to 49
func (k Keeper) RecoverFromSentinelProposerIfNeeded(ctx sdk.Context, rollapp string) error {
proposer := k.GetProposer(ctx, rollapp)
before := proposer

// a valid proposer is already set so there's no need to do anything
if !proposer.Sentinel() {
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I find this function name and inner condition rather confusing as it tries to encapsulate various use cases and do multiple things in one function which make it non reusable. and from some call site (like the kick) I find it cumbersome.

This function does:

  1. check if new proposer is needed
  2. set new proposer
  3. set new successor

for (1) - we can check it outside the function based on the callsite
for (2) - I think this all it should do
for (3) - we have the setSuccessorForRollapp. isn't it the same? shouldn't we just call it from callsite?

it's clearer to just make this function do one thing (i.e recoverFromSentinel/UpdateProposer) and simply check the condition and other work outside this function, where necessary.

Currently this function is being called from 3 callsites:

  1. create sequencer (need to check if current proposer is sentinel outside)
  2. update sequencer (need to check if current proposer is sentinel and opted in before call)
  3. kick (no need to check if current proposer is sentinel, as we're kicking)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

refactored

k.SetProposer(ctx, rollapp, successor.Address)
k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr)
if k.GetProposer(ctx, rollapp).Sentinel() {
// if successor is sentinel, we attempt to find a non sentinel successor
Copy link
Contributor

Choose a reason for hiding this comment

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

at what point will the successor be not sentinel, if we only reached this part if the proposer is sentinel?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah not sure
refactored

k.SetProposer(ctx, rollapp, successor.Address)
k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr)

if !successor.Sentinel() {
Copy link
Contributor

Choose a reason for hiding this comment

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

when will it not be the case given the call sites? (i.e we only call it from create/update/kick)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

refactored

k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr)

// if proposer is sentinel, prepare new revision for the rollapp
if successor.Sentinel() {
err := k.rollappKeeper.HardForkToLatest(ctx, rollapp)
Copy link
Contributor

Choose a reason for hiding this comment

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

why do we need to hard fork here? can't we just hard fork when the new sequencer bonds? otherwise we gonna bump 2 revisions when the sequencer will come.

if we don't hard fork here than already in the RecoverFromHaltIfNeeded should cover it no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't plan on hard forking on RecoverFromHaltIfNeeded, just to notify x/rollapp so it could update the last state info with nextProposer.
in case of fraud proposal, RecoverFromHaltIfNeeded will be called later on, so hard fork already happend


// setSuccessorForRollapp will assign a successor. It won't replace an existing one.
// It will prioritize non sentinel
func (k Keeper) setSuccessorForRollapp(ctx sdk.Context, rollapp string) 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 seems like a repeat of part of the RecoverFromHaltIfNeeded function.
also I suggest for standartization setSuccessorForRollapp -> chooseSuccessor

Comment on lines 112 to 116
successor := k.GetSuccessor(ctx, rollapp)
if !successor.Sentinel() {
// a valid successor is already set so there's no need to do anything
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

as to my other comment of the RecoverFromHaltIfNeeded would sugget to remove outside the function.

return types.Sequencer{}, gerrc.ErrInternal.Wrap("seqs must at least include sentinel")
}
// slices package is recommended over sort package
slices.SortStableFunc(seqs, func(a, b types.Sequencer) int {
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't we filter out the opted-out one?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it's filtered out in RollappPotentialProposers

@mtsitrin
Copy link
Contributor Author

TBH to me it's becoming a lot more complicated and coupling x/sequencer with hard fork

I'm not sure why you can't just trigger hard fork in AfterChooseNewProposer hook on rollapp keeper if after is sentinel

This is now drifting a lot from the original spec https://www.notion.so/dymension/Rollapp-Hard-Fork-Hub-POV-10aa4a51f86a80a6a1d2ca8fcca9e68b?pvs=4#c310c5683fff48b490a0a5e403aa5fc0

Which had a very clear decoupling, and was IMO, easy and simple

pls be more specific
what I did was:

  • when rollapp left with no proposer, prepare a new revision.
    it allows the L2 to sync to the expected revision and just wait for a new proposer
  • when new proposer bonds after halt, we only need to modify the last state info with nextProposer

we have the fraud proposal which leaves the rollapp with bumped revision and no proposer.
I've tried to have the other flows act similar

@danwt
Copy link
Contributor

danwt commented Nov 12, 2024

pls be more specific

Sorry I will try to be more specific

having another look

@mtsitrin mtsitrin merged commit 93a59c8 into mtsitrin/937-rollapp-hard-fork-hub-side Nov 12, 2024
5 checks passed
@mtsitrin mtsitrin deleted the mtsitrin/1430-force-hard-fork-when-going-into-halt branch November 12, 2024 11:29
Copy link
Contributor

@danwt danwt left a comment

Choose a reason for hiding this comment

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

Left a few concrete comments.

But I do have reservations about the factoring and architecture here now. In my opinion, things are now less dry, and there are more unique paths through the code, which makes things more difficult

Ive tried to illustrate how I can see things working, which is closer with the original flow as described in the research. Maybe it's interesting for you. LMK

image

Comment on lines +26 to 29
err := k.TryUnbond(ctx, &proposer, proposer.TokensCoin())
if err != nil {
return errorsmod.Wrap(err, "try unbond")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

why is it try unbond vs unbond?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll rethink and add comment on the main PR

Comment on lines +40 to +43
// RecoverFromHalt will assign a new proposer to the rollapp.
// It will choose a new proposer from the list of potential proposers.
// The rollapp must
func (k Keeper) RecoverFromHalt(ctx sdk.Context, rollapp string) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it called recover from halt?
It's just ensuring that there is a proposer

// The rollapp must

Unfinished sentence

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it's supposed to be called only when proposer == nil and successor != nil
so it's recover from halt

Comment on lines 57 to 63
// maybe set as proposer if one is needed
if err := k.UpdateProposerIfNeeded(ctx, seq.RollappId); err != nil {
return nil, errorsmod.Wrap(err, "choose proposer")
proposer := k.GetProposer(ctx, seq.RollappId)
if proposer.Sentinel() {
if err := k.RecoverFromHalt(ctx, seq.RollappId); err != nil {
return nil, err
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The original chooseProposer function did exactly this. It chose one if one is needed. Not sure why it's factored differently now

Copy link
Contributor Author

Choose a reason for hiding this comment

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

for clarity and readability. by @omritoptix 's suggestion
if one is needed. checked by the caller

Comment on lines +109 to +112
// setSuccessorForRotatingRollapp will assign a successor to the rollapp.
// It will prioritize non sentinel
// called when a proposer has finished their notice period.
func (k Keeper) setSuccessorForRotatingRollapp(ctx sdk.Context, rollapp string) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

can't this just be chooseSuccessor

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it's called only in rotation flow, so I thought it will be more clear

Comment on lines +109 to +113
proposer := k.GetProposer(ctx, msg.RollappId)
if proposer.Sentinel() {
if err := k.RecoverFromHalt(ctx, msg.RollappId); err != nil {
return nil, err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto my other comment
This was already encapsulated in the old chooseProposer func, not sure why it's factored differently now

}
k.SetSequencer(ctx, *seq)
Copy link
Contributor

Choose a reason for hiding this comment

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

why add this?
The function is taking pointer to sequencer, it should be caller responsibility to set it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this function does different stuff (e.g refund)
seems wrong to complete the function without storing the changes on the seq object
wdyt?
I see now that I have duplicate call to k.SetSequencer(ctx, *seq) by the caller as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

force hard fork when going into "halt"
3 participants