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

Force consensus loss for parent block if its hash mismatches parent_hash #1657

Merged
merged 4 commits into from
Mar 27, 2019

Conversation

goodsoft
Copy link
Contributor

@goodsoft goodsoft commented Mar 26, 2019

Fixes #1644

When reorg occurs and the older of new blocks fails to be imported, the old consensus block remains in the database. Catchup fetcher ignores it, and we get a discontinuity in the main chain.

This commit adds an additional consensus loss step during block import: the parent block with hash not matching parent_hash of current block is marked non-consensus, thus creating a hole in main chain, forcing catchup fetcher to retry fetching it.

Upgrading

A query from scripts/20190326202921_lose_consensus_for_invalid_blocks.sql should be run to mark existing invalid blocks as non-consensus.

@ghost ghost assigned goodsoft Mar 26, 2019
@ghost ghost added the in progress label Mar 26, 2019
@goodsoft goodsoft added ready for review This PR is ready for reviews. and removed in progress labels Mar 26, 2019
@coveralls
Copy link

coveralls commented Mar 26, 2019

Pull Request Test Coverage Report for Build bd8a7233-3139-4749-8a9c-f395900cf229

  • 14 of 15 (93.33%) changed or added relevant lines in 1 file are covered.
  • 28 unchanged lines in 9 files lost coverage.
  • Overall coverage decreased (-0.5%) to 82.858%

Changes Missing Coverage Covered Lines Changed/Added Lines %
apps/explorer/lib/explorer/chain/import/runner/blocks.ex 14 15 93.33%
Files with Coverage Reduction New Missed Lines %
apps/indexer/lib/indexer/coin_balance/fetcher.ex 1 92.31%
apps/indexer/lib/indexer/token/fetcher.ex 1 78.57%
apps/ethereum_jsonrpc/test/support/ethereum_jsonrpc/case/parity/http_websocket.ex 1 0.0%
apps/indexer/lib/indexer/token_balance/fetcher.ex 2 87.1%
apps/indexer/lib/indexer/internal_transaction/fetcher.ex 3 58.62%
apps/ethereum_jsonrpc/test/support/ethereum_jsonrpc/web_socket/case/parity.ex 4 0.0%
apps/indexer/lib/indexer/block/catchup/fetcher.ex 5 65.85%
apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/web_socket/web_socket_client.ex 5 76.92%
apps/indexer/lib/indexer/block/fetcher.ex 6 86.67%
Totals Coverage Status
Change from base Build fcb71c04-7c59-42c0-b451-dd4c065c6c03: -0.5%
Covered Lines: 4413
Relevant Lines: 5326

💛 - Coveralls

SELECT b0.number - 1 FROM "blocks" AS b0
LEFT JOIN "blocks" AS b1 ON (b0."parent_hash" = b1."hash") AND b1."consensus"
WHERE b0."number" > 0 AND b0."consensus" AND b1."hash" IS NULL
);
Copy link
Member

Choose a reason for hiding this comment

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

@goodsoft
I think we should add at the end and consensus = true; clause to be sure that b0.number - 1 has not already marked as non-consensus before. Otherwise, the where query will return non-empty list every time

Copy link
Member

@vbaranov vbaranov Mar 27, 2019

Choose a reason for hiding this comment

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

And I believe we should also update updated_at in the query above

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

initial = from(b in Block, where: false)

Enum.reduce(blocks_changes, initial, fn %{consensus: consensus, parent_hash: parent_hash, number: number}, acc ->
case consensus do
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it is much cleaner to use if instead of case here

if consensus do

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like copy-pasting code from neighboring functions :D

Copy link
Contributor

@ayrat555 ayrat555 left a comment

Choose a reason for hiding this comment

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

one style comment. otherwise looks good

Fixes #1644

When reorg occurs and the older of new blocks fails to be imported, the old
consensus block remains in the database. Catchup fetcher ignores it, and we
get a discontinuity in the main chain.

This commit adds an additional consensus loss step during block import:
the parent block with hash not matching parent_hash of current block is
marked non-consensus, thus creating a hole in main chain, forcing catchup
fetcher to retry fetching it.
@vbaranov vbaranov merged commit 5438798 into master Mar 27, 2019
@ghost ghost removed the in progress label Mar 27, 2019
@vbaranov vbaranov deleted the gs-fix-consensus-loss branch March 27, 2019 14:23
goodsoft added a commit that referenced this pull request Mar 29, 2019
As a result of #1657 out-of-place parent blocks are marked as non-consensus
more reliably, i.e. they will eventually be fetched even if first attempt is
unsuccessful.

The `ConsensusEnsurer` module, on the contrary, only tried refetching block
once, and left it as-is if the refetch failed. Now it is not needed anymore.
goodsoft added a commit that referenced this pull request Mar 29, 2019
As a result of #1657 out-of-place parent blocks are marked as non-consensus
more reliably, i.e. they will eventually be fetched even if first attempt is
unsuccessful.

The `ConsensusEnsurer` module, on the contrary, only tried refetching block
once, and left it as-is if the refetch failed. Now it is not needed anymore.
goodsoft added a commit that referenced this pull request Mar 29, 2019
As a result of #1657 out-of-place parent blocks are marked as non-consensus
more reliably, i.e. they will eventually be fetched even if first attempt is
unsuccessful.

The `ConsensusEnsurer` module, on the contrary, only tried refetching block
once, and left it as-is if the refetch failed. Now it is not needed anymore.
goodsoft added a commit that referenced this pull request Apr 2, 2019
As a result of #1657 out-of-place parent blocks are marked as non-consensus
more reliably, i.e. they will eventually be fetched even if first attempt is
unsuccessful.

The `ConsensusEnsurer` module, on the contrary, only tried refetching block
once, and left it as-is if the refetch failed. Now it is not needed anymore.
goodsoft added a commit that referenced this pull request Apr 2, 2019
As a result of #1657 out-of-place parent blocks are marked as non-consensus
more reliably, i.e. they will eventually be fetched even if first attempt is
unsuccessful.

The `ConsensusEnsurer` module, on the contrary, only tried refetching block
once, and left it as-is if the refetch failed. Now it is not needed anymore.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ready for review This PR is ready for reviews.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants