-
Notifications
You must be signed in to change notification settings - Fork 340
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
feat(sequencer): hardforking when rotating to sentinel #1455
Conversation
Codecov ReportAttention: Patch coverage is
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. |
#1457) Co-authored-by: danwt <[email protected]>
There was a problem hiding this 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
x/sequencer/keeper/proposer.go
Outdated
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 | ||
} |
There was a problem hiding this comment.
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:
- check if new proposer is needed
- set new proposer
- 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:
- create sequencer (need to check if current proposer is sentinel outside)
- update sequencer (need to check if current proposer is sentinel and opted in before call)
- kick (no need to check if current proposer is sentinel, as we're kicking)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
refactored
x/sequencer/keeper/proposer.go
Outdated
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah not sure
refactored
x/sequencer/keeper/proposer.go
Outdated
k.SetProposer(ctx, rollapp, successor.Address) | ||
k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr) | ||
|
||
if !successor.Sentinel() { |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
x/sequencer/keeper/rotation.go
Outdated
|
||
// 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 { |
There was a problem hiding this comment.
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
x/sequencer/keeper/rotation.go
Outdated
successor := k.GetSuccessor(ctx, rollapp) | ||
if !successor.Sentinel() { | ||
// a valid successor is already set so there's no need to do anything | ||
return nil | ||
} |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
pls be more specific
we have the fraud proposal which leaves the rollapp with bumped revision and no proposer. |
Sorry I will try to be more specific having another look |
93a59c8
into
mtsitrin/937-rollapp-hard-fork-hub-side
There was a problem hiding this 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
err := k.TryUnbond(ctx, &proposer, proposer.TokensCoin()) | ||
if err != nil { | ||
return errorsmod.Wrap(err, "try unbond") | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
// 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 { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
// 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 | ||
} | ||
} |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
// 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 { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
proposer := k.GetProposer(ctx, msg.RollappId) | ||
if proposer.Sentinel() { | ||
if err := k.RecoverFromHalt(ctx, msg.RollappId); err != nil { | ||
return nil, err | ||
} |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
closes #1430