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

Wait for block import in parachain consensus #271

Merged
3 commits merged into from
Jan 5, 2021

Conversation

bkchr
Copy link
Member

@bkchr bkchr commented Dec 26, 2020

There was a bug in the parachain consensus that when importing a relay
chain block that sets a new best parachain block, but the required
parachain block was not yet imported. This pr fixes this by waiting for
the block to be imported.

Closes: #203

There was a bug in the parachain consensus that when importing a relay
chain block that sets a new best parachain block, but the required
parachain block was not yet imported. This pr fixes this by waiting for
the block to be imported.
fn finalize_block<T, Block, B>(client: &T, hash: Block::Hash) -> ClientResult<bool>
/// Follow the finalized head of the given parachain.
///
/// For every finalized block of the relay chain,
Copy link
Contributor

Choose a reason for hiding this comment

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

trailing doc

}
};

let hash = header.hash();
Copy link
Contributor

Choose a reason for hiding this comment

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

does the header actually need to be decoded for this? blake2(&finalized_head[..]) should give the same hash. We would get an UnknownBlock error if it's an invalid header or we haven't yet seen the header.

Copy link
Member Author

Choose a reason for hiding this comment

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

As the header is generic, a user could have whatever implementation for hash() they wants.

if parachain.usage_info().chain.finalized_hash != hash {
if let Err(e) = parachain.finalize_block(BlockId::hash(hash), None, true) {
match e {
ClientError::UnknownBlock(_) => tracing::debug!(
Copy link
Contributor

Choose a reason for hiding this comment

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

I suppose here there is a similar error to the one that the PR fixes. If the relay chain informs us about a finalized header before we've imported that header, then we won't finalize it, even if we import that same header immediately afterwards.

We will correctly finalize probably soon after, when we get a finality notification corresponding to a header we have already imported.

Copy link
Member Author

Choose a reason for hiding this comment

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

That is right, but also done intentionally by me. I do not expect that we are that much behind the tip that we can not finalize the block, because we did not have this block yet. If that is happening, we probably have other problems.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe should be filed for the "wishlist" but yeah I agree. Even the slight lag in finality should mean that blocks are well propagated before finality.

// The unset best header of the parachain. Will be `Some(_)` when we have imported a relay chain
// block before the parachain block it included. In this case we need to wait for this block to
// be imported to set it as new best.
let mut unset_best_header = None;
Copy link
Contributor

Choose a reason for hiding this comment

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

Down the line, we may even need to trigger an availability request to recover the PoV. It is possible that the initial collator is withholding the block.

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 thought that we don't wanted to prevent to ask the relay chain validators to recover the povblocks?

But yeah, in general you are right. However this is not yet implemented anywhere.

tracing::debug!(
target: "cumulus-consensus",
block_hash = ?hash,
"Skipping set new best block, because block is already the best.",
Copy link
Contributor

Choose a reason for hiding this comment

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

i'm curious if we do see duplicate notifications like this often.

Copy link
Contributor

Choose a reason for hiding this comment

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

Anecdotally, I've never noticed it.

Copy link
Member Author

Choose a reason for hiding this comment

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

Every relay chain block that does not includes a new parachain block, will trigger this log line. So, with rococo v1 at least every second block.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, yeah, it's a debug line. I've never seen it because I never run with that debug target.

Ok(BlockStatus::InChainWithState) => {
unset_best_header.take();

import_block_as_new_best(hash, parachain_head, parachain, announce_block);
Copy link
Contributor

@rphmeier rphmeier Dec 27, 2020

Choose a reason for hiding this comment

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

why do we import as new best even though it's already InChainWithState? Is it a fork-choice rule thing? is there no other API?

Copy link
Member Author

Choose a reason for hiding this comment

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

AFAIK there is no other API for this. In the end we just import the header a second time and say that it should be imported as best block.

There once existed an API for this, but it was removed at some point.

tracing::error!(
target: "cumulus-collator",
block_hash = ?hash,
"Trying to set pruned block as new best!",
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess this might happen as a chain reversion, but probably not since pruning happens after finality

Copy link
Contributor

@rphmeier rphmeier left a comment

Choose a reason for hiding this comment

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

Thanks for tests

@rphmeier
Copy link
Contributor

What was the downside of that bug? I suppose collators would still build on the right head because that's determined by the collation generation subsystem. So the RPC would show incorrect data as the "best block" was not updated?

@bkchr
Copy link
Member Author

bkchr commented Dec 27, 2020

What was the downside of that bug? I suppose collators would still build on the right head because that's determined by the collation generation subsystem. So the RPC would show incorrect data as the "best block" was not updated?

This is not mainly about collators. Collators would still not be able to build a block, if they don't know the parachain block yet. So, we may need a similar fix for the collation as well. We already have something similar for block announcement validation, but there we need to wait for a relay chain block.

This is fix is more for full nodes like rpc or whatever nodes. With rococo v0 we had seen slow nodes like raspberry pi suffering under this problem that one of the blocks was always imported first. Maybe it was a combination of multiple things that lead to this to the seen problems. However, I more like to have this thing fixed to be sure we don't see this.
This could for example also lead to observations of a higher block time with rococo v1, because the rpc parachain rpc node imported the relay chain block before the parachain block.

@bkchr
Copy link
Member Author

bkchr commented Jan 5, 2021

bot merge

@ghost
Copy link

ghost commented Jan 5, 2021

Waiting for commit status.

@ghost ghost merged commit 9f0085c into master Jan 5, 2021
@ghost ghost deleted the bkchr-fix-some-import-new-best-stuff branch January 5, 2021 22:14
This pull request was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Best block is not updated if relay chain block is import before parachain block
3 participants