Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Warp sync part II #9284

Merged
12 commits merged into from
Oct 7, 2021
Merged

Warp sync part II #9284

12 commits merged into from
Oct 7, 2021

Conversation

arkpar
Copy link
Member

@arkpar arkpar commented Jul 6, 2021

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

@github-actions github-actions bot added the A3-in_progress Pull request is in progress. No review needed at this stage. label Jul 6, 2021
@arkpar arkpar force-pushed the a-warp-sync2 branch 2 times, most recently from 4157e96 to 2a643d2 Compare August 3, 2021 07:37
@arkpar arkpar marked this pull request as ready for review August 3, 2021 14:54
@arkpar arkpar requested a review from andresilva as a code owner August 3, 2021 14:54
@arkpar arkpar added A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes C1-low PR touches the given topic and has a low impact on builders. D3-trivial 🧸 PR contains trivial changes in a runtime directory that do not require an audit and removed A3-in_progress Pull request is in progress. No review needed at this stage. labels Aug 3, 2021
@arkpar arkpar requested review from bkchr and cheme August 3, 2021 15:01
Copy link
Contributor

@cheme cheme left a 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?

client/cli/src/commands/check_block_cmd.rs Show resolved Hide resolved
@@ -65,6 +68,9 @@ pub fn load_epoch_changes<Block: BlockT, B: AuxStore>(
Some(1) =>
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)?
Copy link
Contributor

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 ?

Copy link
Member Author

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.

@@ -65,6 +68,9 @@ pub fn load_epoch_changes<Block: BlockT, B: AuxStore>(
Some(1) =>
load_decode::<_, EpochChangesFor<Block, EpochV0>>(backend, BABE_EPOCH_CHANGES_KEY)?
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it EpochChangeForV1 now?

@@ -65,6 +68,9 @@ pub fn load_epoch_changes<Block: BlockT, B: AuxStore>(
Some(1) =>
load_decode::<_, EpochChangesFor<Block, EpochV0>>(backend, BABE_EPOCH_CHANGES_KEY)?
.map(|v1| v1.map(|_, _, epoch| epoch.migrate(config))),
Copy link
Contributor

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?

Copy link
Member Author

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.

client/consensus/epochs/src/lib.rs Show resolved Hide resolved
Ok(()) => return Ok(()),
Err(e) => e,
}
} else if !self.epochs.is_empty() && matches!(epoch, PersistedEpoch::Genesis(_, _)) {
Copy link
Contributor

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.

client/db/src/utils.rs Outdated Show resolved Hide resolved
&(start, end).encode(),
);
}
} else if number > best_num + One::one() &&
Copy link
Contributor

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).

Copy link
Member Author

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.

client/finality-grandpa/src/authorities.rs Show resolved Hide resolved
client/network/test/src/sync.rs Show resolved Hide resolved
@arkpar
Copy link
Member Author

arkpar commented Aug 6, 2021

I also wonder how will behave state pruning for the blocks imported from the 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,
Copy link
Contributor

@cheme cheme Aug 6, 2021

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)

Copy link
Contributor

@cheme cheme left a 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.

Copy link
Contributor

@andresilva andresilva left a 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.

#[derive(Clone, Encode, Decode, Debug)]
pub struct GapEpochs<Hash, Number, E: Epoch> {
current: (Hash, Number, PersistedEpoch<E>),
next: Option<(Hash, Number, PersistedEpoch<E>)>,
Copy link
Contributor

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.

@@ -264,6 +279,25 @@ impl<E: Epoch> Clone for PersistedEpochHeader<E> {
}
}

impl<E: Epoch> PersistedEpochHeader<E> {
/// Map the epoch header to a different type.
pub fn map<B>(self) -> PersistedEpochHeader<B>
Copy link
Contributor

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.

@@ -230,6 +236,8 @@ pub struct ChainSync<B: BlockT> {
/// Enable importing existing blocks. This is used used after the state download to
/// catch up to the latest state while re-importing blocks.
import_existing: bool,
/// Gap download process.
gap_sync: Option<GapSync<B>>,
Copy link
Contributor

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.

Copy link
Member Author

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.

@@ -744,6 +744,10 @@ mod node_implementation {
if *number < self.number {
return Ok(FindOutcome::Failure(false))
}
if *number == self.number && hash == &self.hash {
Copy link
Contributor

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?

Copy link
Member Author

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.

@stale
Copy link

stale bot commented Sep 18, 2021

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.

@stale stale bot added the A5-stale Pull request did not receive any updates in a long time. No review needed at this stage. Close it. label Sep 18, 2021
@arkpar
Copy link
Member Author

arkpar commented Sep 29, 2021

Still waiting for reviews

@stale stale bot removed the A5-stale Pull request did not receive any updates in a long time. No review needed at this stage. Close it. label Sep 29, 2021
utils/fork-tree/src/lib.rs Outdated Show resolved Hide resolved
Comment on lines 72 to 73
load_decode::<_, EpochChangesV1For<Block, Epoch>>(backend, BABE_EPOCH_CHANGES_KEY)?
.map(|v2| v2.migrate()),
Copy link
Member

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?

client/consensus/epochs/src/lib.rs Outdated Show resolved Hide resolved
client/finality-grandpa/src/import.rs Outdated Show resolved Hide resolved
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());
Copy link
Member

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

arkpar and others added 2 commits October 6, 2021 12:12
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
@arkpar
Copy link
Member Author

arkpar commented Oct 6, 2021

Companion approval would be appreciated

@arkpar
Copy link
Member Author

arkpar commented Oct 7, 2021

bot merge

@ghost
Copy link

ghost commented Oct 7, 2021

Trying merge.

This pull request was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes C1-low PR touches the given topic and has a low impact on builders. D3-trivial 🧸 PR contains trivial changes in a runtime directory that do not require an audit
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants