-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Warp sync part II #9284
Warp sync part II #9284
Conversation
4157e96 to
2a643d2
Compare
cheme
left a comment
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 did a first read, looks good, even if I am not sure IIUC a few points.
I also wonder how will behave state pruning for the blocks imported from the gap?
| load_decode::<_, EpochChangesFor<Block, EpochV0>>(backend, BABE_EPOCH_CHANGES_KEY)? | ||
| .map(|v1| v1.map(|_, _, epoch| epoch.migrate(config))), | ||
| Some(2) => | ||
| load_decode::<_, EpochChangesForV1<Block, Epoch>>(backend, BABE_EPOCH_CHANGES_KEY)? |
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.
Should we use EpochChangeForV2 instead of EpochChangeForV1 ?
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.
There's some confusion to versions here. V1 means version of the epoch definition, rather than epoch changes. I'll rename the type to indicate the version of epoch changes instead.
| load_decode::<_, EpochChangesForV0<Block, EpochV0>>(backend, BABE_EPOCH_CHANGES_KEY)? | ||
| .map(|v0| v0.migrate().map(|_, _, epoch| epoch.migrate(config))), | ||
| Some(1) => | ||
| load_decode::<_, EpochChangesFor<Block, EpochV0>>(backend, BABE_EPOCH_CHANGES_KEY)? |
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.
Is it EpochChangeForV1 now?
| .map(|v0| v0.migrate().map(|_, _, epoch| epoch.migrate(config))), | ||
| Some(1) => | ||
| load_decode::<_, EpochChangesFor<Block, EpochV0>>(backend, BABE_EPOCH_CHANGES_KEY)? | ||
| .map(|v1| v1.map(|_, _, epoch| epoch.migrate(config))), |
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 being called 'migrate' is confusing to me (fwiu it migrates from v2 to v1 and the new migrate does V2 to V3), maybe renaming it to 'migrate_to_previous_version' or anything could be better?
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.
both migrate functions migrate to the latest version, not the previous.
| Ok(()) => return Ok(()), | ||
| Err(e) => e, | ||
| } | ||
| } else if !self.epochs.is_empty() && matches!(epoch, PersistedEpoch::Genesis(_, _)) { |
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.
IIUC import genesis when already an epoch indicates warp sync case, maybe worth a comment if it is the case.
| &(start, end).encode(), | ||
| ); | ||
| } | ||
| } else if number > best_num + One::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.
The point checked here is first block imported after a warp sync triggers gap download?
I first thought it should be 'number > best_num',
but maybe here 'best_num' is not changed by warp_sync and is the start of gap (gap init suggests that).
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 point checked here is first block imported after a warp sync triggers gap download?
This is triggered when we import a warp block. I.e. we start at genesis and warp to block 10000. Block 10000 is imported with state. Gap is detected. No need to wait for the next block.
With number > best_num it would be a false detection. E.g. block 43 is imported after 42 is the normal case. Only if we import 44 after 42 there's a gap.
These blocks are not executed and don't have any state. Only headers are verified. State pruning starts working normally starting from the warp target block. |
| origin: block_data.origin, | ||
| allow_missing_state: true, | ||
| import_existing: self.import_existing, | ||
| skip_execution: true, |
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.
👍 (+ demonstrates babe/grandpa do not need chain state to run)
cheme
left a comment
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.
babe/grandpa warpsync LGTM.
andresilva
left a comment
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 logic for dealing with gaps on BABE and GRANDPA seems correct to me. I'd like to give this one more pass for the rest of the changes.
client/consensus/epochs/src/lib.rs
Outdated
| #[derive(Clone, Encode, Decode, Debug)] | ||
| pub struct GapEpochs<Hash, Number, E: Epoch> { | ||
| current: (Hash, Number, PersistedEpoch<E>), | ||
| next: Option<(Hash, Number, PersistedEpoch<E>)>, |
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.
Next is always guaranteed to be PersistedEpoch::Regular right? Maybe we can change the type to just take E.
|
|
||
| impl<E: Epoch> PersistedEpochHeader<E> { | ||
| /// Map the epoch header to a different type. | ||
| pub fn map<B>(self) -> PersistedEpochHeader<B> |
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.
Don't really have a strong opinion on this, map usually takes a function to do the mapping.
| /// catch up to the latest state while re-importing blocks. | ||
| import_existing: bool, | ||
| /// Gap download process. | ||
| gap_sync: Option<GapSync<B>>, |
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.
Would it be possible to somehow move this into warp_sync? If gap_sync is Some then we know we warp synced but we're still downloading the old blocks.
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 would prefer to keep them separate. I see warp sync and old block download as two independent features. Even though the only way you can currently end up with the block gap is the warp sync, this may change in the future. I.e. when importing the state from a file or chain spec snapshot. Or after disabling block body pruning.
utils/fork-tree/src/lib.rs
Outdated
| if *number < self.number { | ||
| return Ok(FindOutcome::Failure(false)) | ||
| } | ||
| if *number == self.number && hash == &self.hash { |
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 don't remember all the details to know the implications of this, could you just drop a line why this was needed?
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 not actually needed. Just an optimization I've made while fixing an unrelated issue. Saves a database query for the header. I guess it does not belong to this PR indeed, so I'll remove it.
|
Hey, is anyone still working on this? Due to the inactivity this issue has been automatically marked as stale. It will be closed if no further activity occurs. Thank you for your contributions. |
|
Still waiting for reviews |
| load_decode::<_, EpochChangesV1For<Block, Epoch>>(backend, BABE_EPOCH_CHANGES_KEY)? | ||
| .map(|v2| v2.migrate()), |
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.
Maybe a comment why we use EpochChangesV1For here as well?
| if number <= self.inner.info().finalized_number { | ||
| // Importing an old block. Just save justifications and authority set changes | ||
| if let Some(_) = self.check_new_change(&block.header, hash) { | ||
| assert!(block.justifications.is_some()); |
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.
A proper proof here would be nice
Co-authored-by: Bastian Köcher <[email protected]>
|
Companion approval would be appreciated |
|
bot merge |
|
Trying merge. |
This enables background block download after warp sync. The bulk of the changes is epoch management for GRANDPA to allow for verification and import of old blocks.
Polkadot companion: paritytech/polkadot#3564
Also required for warp sync to work properly on kusama: #9239