-
Notifications
You must be signed in to change notification settings - Fork 2.6k
grandpa: fix early enactment of forced changes #7321
Conversation
b4ba8b9
to
23a90e1
Compare
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.
Looks good to me, nice tidy cleanups too!
Mind expanding a little about median_last_finalized
? What we use it for and what is solves?
@octol Whenever we apply a forced authority set change we do so because the current set has stopped finalizing (e.g. > 1/3 went offline). As such, when applying a forced authority set change we provide a block number as a hint of the last thing that was finalized, the new set will start finalizing from this point on (i.e. this will be used as the GRANDPA round base). The reason it is called |
bot merge |
Trying merge. |
In GRANDPA there are two mechanisms for switching the authority set:
While syncing the chain if we encounter a block that triggers a regular authority set change we need to have a justification for it so that we can finalize it. We support having multiple pending regular authority set changes, so that we can keep importing blocks while in the background we try to sync justifications from peers (in case they didn't come attached to the block in the first place).
This can lead to a situation where by the time we encounter a forced change we try to apply it immediately (remember that it is applied on block import rather than finality) without waiting to apply some previous standard changes that we are waiting to import justifications for. In this case we end up with an invalid authority set state and are unable to validate anything going further.
This PR makes it so that when trying to apply a forced change we will verify if there are any dependent standard changes that we should wait on, if there are then we refuse to import such a block. Specifically we wait for any pending change that is an ancestor of the forced changed and its effective block number is lower than the last finalized block (as signaled in the forced change) must be applied beforehand.
Note: my initial implementation made it so that we allowed multiple pending forced changes, which would be applied in-order the same way we do for standard changes. Unfortunately removing the invariant of only having one forced changed per fork at anytime introduced a couple of edge cases that I started fixing but realized wasn't worth it. Forced changes are uncommon and I'd rather err on the side of safety/correctness rather than performance.
Fixes paritytech/polkadot#1755.