Skip to content
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

Client: Warning on not possible further block execution #1065

Merged
merged 3 commits into from
Jan 22, 2021

Conversation

holgerd77
Copy link
Member

My own client (blockchain) DB is currently in a state where block execution is not further done due to a somewhat inconsistent db state. In the client this gets noticeable by the execution messages not further showing up, there are only the block import logs displayed.

I could identify the root cause of the no-execution behavior: in the Blockchain iterator function there is no block found in the DB following the current iterator head. Therefore no blocks are executed. I have no idea though how and when the blockchain DB got into this state. I do know though that I've been there (in this state) a couple of times before with block execution stopping.

This PR is approaching this on a low level by not changing any logic or behavior but as a first step providing feedback when block execution is not further processing. For this it:

  • Expands the Blockchain.iterator() interface to allow for a number value to be returned (so now allowing Promise<void | number>, keeping void is for backwards compatibility) and changing our own interface implementation in the blockchain class to return the number of blocks which have been actually iterated. This will likely generally be useful for a number of use cases.
  • The VM.runBlockchain() method now similarly also returns the number of iterated blocks
  • This allows in the client to give an instant warning feedback message together with the current latest head hash and number and stop further block execution

Output looks like this:

image

This should allow to better tracing/debugging this in the future and there is now a clear consumer feedback if this behavior occurs.

We might want to decide if we want to further act upon this case, a possibility would be to set the latest blockchain head to the VM iterator head, so that sync will restart from there. I hesitated to directly integrate since it is not clear what corrupted the DB in the first place. We can decide this independently from this PR though.

@codecov
Copy link

codecov bot commented Jan 20, 2021

Codecov Report

Merging #1065 (f2bbb08) into master (ea2a09e) will increase coverage by 0.34%.
The diff coverage is 80.00%.

Impacted file tree graph

Flag Coverage Δ
block 77.93% <91.30%> (+<0.01%) ⬆️
blockchain 78.52% <91.30%> (+0.59%) ⬆️
client 88.03% <20.00%> (+0.05%) ⬆️
common 92.37% <ø> (+0.43%) ⬆️
devp2p 82.48% <ø> (+0.16%) ⬆️
ethash 82.08% <ø> (ø)
tx 90.00% <ø> (?)
vm 83.09% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

return await this.initAndLock<number>(
async (): Promise<number> => {
const headHash = this._heads[name] || this._genesis
let lastBlock: Block | undefined
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've also renamed some variable names for better clarity, not sure why this is show with such a large gap here, might be a bit confusing, but code flow remains the same here.


if (!block) {
break
}
Copy link
Member Author

@holgerd77 holgerd77 Jan 20, 2021

Choose a reason for hiding this comment

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

This could be removed since _getBlock() is not allowing for an undefined or null return but is just throwing a NotFoundError when no block is found (which is caught later on).

Apart from this code flow is the same here as well (just switched the if clause order in the catch block for better readability, that's all).

@@ -5,13 +5,13 @@ import VM from './index'
/**
* @ignore
*/
export default async function runBlockchain(this: VM, blockchain?: Blockchain, maxBlocks?: number) {
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 argue that return value can be changed this way here (remaining non-breaking), since no one will have done something with the void return value before and just used await vm.runBlockchain(). So the updated return value is more of an optional extra thing now which now can be used if makes sense.

Copy link
Contributor

Choose a reason for hiding this comment

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

great, sounds good, could the same reasoning be used for the return type of iterator? I think I would find void | number confusing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, not for the interface I guess, since this would mean that if someone implements that interface it would break their implementation. 😕 I've added this (remove void return type part) to #1024 though, and the iterator implementation itself has no void return type.

Copy link
Member Author

Choose a reason for hiding this comment

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

When thinking about it I'm afraid that it's rather the other way around and we need to also return Promise<void | number> in the VM for the non-breaking release. Otherwise if someone keeps their own Blockchain implementation with the void return and uses this for the VM.runBlockchain() method, this will break on TypeScript since the method is expecting a chained return value of number for the output.

…re capable iterator result evaluation, expand interface (backwards-compatible)
@holgerd77 holgerd77 force-pushed the improve-blockchain-iterator branch from 8b0693b to e88af94 Compare January 20, 2021 18:04
…nBlockchain(), client logger warning on no further block execution
@holgerd77 holgerd77 force-pushed the improve-blockchain-iterator branch 3 times, most recently from 52c8071 to 617d62f Compare January 21, 2021 11:47
… with Blockchain implemenations with an iterator void return value
@holgerd77 holgerd77 force-pushed the improve-blockchain-iterator branch from 617d62f to f2bbb08 Compare January 21, 2021 12:01
@jochem-brouwer
Copy link
Member

It would be nice to figure out how the DB got corrupted. It could possibly be that we do not explicitly flush the blockchain DB once we kill the client, so part of it stays in memory? We'd have to explicitly flush the DB once we get a kill signal.

if (error.type !== 'NotFoundError') {
throw error
const headBlockNumber = await this.dbManager.hashToNumber(headHash)
const nextBlockNumber = headBlockNumber.addn(1)
Copy link
Contributor

@cgewecke cgewecke Jan 21, 2021

Choose a reason for hiding this comment

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

Suggested change
const nextBlockNumber = headBlockNumber.addn(1)
const nextBlockNumber = headBlockNumber.iaddn(1)

...not sure this change would be meaningful but iaddn is used in the loop below to increment nextBlockNumber

[EDIT - this difference pre-dates the PR fwiw)

Copy link
Contributor

@cgewecke cgewecke left a comment

Choose a reason for hiding this comment

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

LGTM!!

@jochem-brouwer
Copy link
Member

Doesn't this bug also indicate we have a problem in our block fetcher? If the 'bad block' gets deleted from the chain, then we should re-request the block from our peers (by block number, not by block hash). So, if a block gets deleted, send a request to our peers to retrieve the deleted block number(s).

@jochem-brouwer
Copy link
Member

What will happen if we are at the tip of the chain? Won't we then get this warning, which should not get logged, as there simply is no valid block available at this point in time?

@holgerd77 holgerd77 merged commit 9a3b800 into master Jan 22, 2021
@holgerd77 holgerd77 deleted the improve-blockchain-iterator branch January 22, 2021 10:57
@holgerd77
Copy link
Member Author

Need to merge for some subsequent work, will answer the remaining questions.

@holgerd77
Copy link
Member Author

@jochem-brouwer I think "tip of the chain" behavior generally needs some dedicated work on its own - once we reach a tip 😋 - would very much expect this not to work on first run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants