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

Discard child block with parent_hash not matching hash of imported block #1684

Merged
merged 4 commits into from Apr 2, 2019

Conversation

goodsoft
Copy link
Contributor

@goodsoft goodsoft commented Mar 29, 2019

Motivation

Consider a root block A, old chain -- B -- C and new one -- B' -- C'. Due to asynchronous nature of realtime fetcher it is possible for block B to be imported later than the entire chain -- B' -- C'.

In this case we should discard block C' and let it be refetched. When that happens, block B gets discarded to make sure block B' gets eventually fetched and the chain becomes consistent.

Even though it may cause multiple refetches of the same blocks, it eventually forces the chain to be consistent despite asynchronous or failing imports.

Changelog

  • Add a regression test for the scenario outlined above
  • Make inconsistent child blocks get discarded along with inconsistent parents
  • Remove obsolete ConsensusEnsurer module from indexer, as forcing consensus loss is more reliable and doesn't leave us with inconsistent chain if refetch fails.
  • Remove obsolete InvalidConsensus worker from indexer, as it only handled one corner case in ideal conditions, and only ran once on launch.

Upgrading

As new inconsistent blocks could have appeared due to the possibility of race conditions described above, running priv/repo/migrations/scripts/20190326202921_lose_consensus_for_invalid_blocks.sql is highly recommended after deploying this fix.

@ghost ghost assigned goodsoft Mar 29, 2019
@ghost ghost added the in progress label Mar 29, 2019
@goodsoft goodsoft force-pushed the gs-fix-consensus-loss branch 2 times, most recently from 8c52ac5 to 32bae02 Compare March 29, 2019 15:51
@coveralls
Copy link

coveralls commented Mar 29, 2019

Pull Request Test Coverage Report for Build 2364a84d-8e6d-423f-8ee2-cbbe12f6f4a6

  • 4 of 4 (100.0%) changed or added relevant lines in 1 file are covered.
  • 3 unchanged lines in 2 files lost coverage.
  • Overall coverage increased (+0.2%) to 83.261%

Files with Coverage Reduction New Missed Lines %
apps/explorer/lib/explorer/chain.ex 1 86.26%
apps/indexer/lib/indexer/block/catchup/fetcher.ex 2 65.85%
Totals Coverage Status
Change from base Build 72617a30-ec72-46d9-bd66-bb6f47f92040: 0.2%
Covered Lines: 4442
Relevant Lines: 5335

💛 - Coveralls

@goodsoft goodsoft added ready for review This PR is ready for reviews. and removed in progress labels Mar 29, 2019
@ghost ghost added the in progress label Mar 29, 2019
@ghost ghost added the in progress label 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.
Consider a root block `A`, old chain `-- B -- C` and new one `-- B' -- C'`.
Due to asynchronous nature of realtime fetcher it is possible for block
`B` to be imported _later_ than the entire chain `-- B' -- C'`.

In this case we should discard block `C'` and let it be refetched.
When that happens, block `B` gets discarded to make sure block `B'` gets
eventually fetched and the chain becomes consistent.
Consider a root block `A`, old chain `-- B -- C` and new one `-- B' -- C'`.
Due to asynchronous nature of realtime fetcher it is possible for block
`B` to be imported _later_ than the entire chain `-- B' -- C'`.

In this case we should discard block `C'` and let it be refetched.
When that happens, block `B` gets discarded to make sure block `B'` gets
eventually fetched and the chain becomes consistent.
This worker only handled one of invalid consensus cases, i.e. when a parent
block lost consensus, but the child one didn't.
Even then it worked only when all blocks are reliably and sequentially
imported (certainly not our case), and only once on indexer launch.

Now this particular case is covered by previous commit, and we don't need
this worker at all.
@goodsoft goodsoft merged commit 313df94 into master Apr 2, 2019
@ghost ghost removed the in progress label Apr 2, 2019
@goodsoft goodsoft deleted the gs-fix-consensus-loss branch April 2, 2019 18:24
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.

None yet

4 participants