Discard child block with parent_hash not matching hash of imported block

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.
pull/1684/head
goodsoft 6 years ago
parent 89430a5b53
commit 6450c3ac61
No known key found for this signature in database
GPG Key ID: DF5159A3A5F09D21
  1. 1
      CHANGELOG.md
  2. 28
      apps/explorer/lib/explorer/chain/import/runner/blocks.ex

@ -12,6 +12,7 @@
- [#1691](https://github.com/poanetwork/blockscout/pull/1691) - decrease token metadata update interval
- [#1688](https://github.com/poanetwork/blockscout/pull/1688) - do not fail if failure reason is atom
- [#1692](https://github.com/poanetwork/blockscout/pull/1692) - exclude decompiled smart contract from encoding
- [#1684](https://github.com/poanetwork/blockscout/pull/1684) - Discard child block with parent_hash not matching hash of imported block
### Chore

@ -46,7 +46,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
|> Map.put(:timestamps, timestamps)
ordered_consensus_block_numbers = ordered_consensus_block_numbers(changes_list)
where_invalid_parent = where_invalid_parent(changes_list)
where_invalid_neighbour = where_invalid_neighbour(changes_list)
where_forked = where_forked(changes_list)
multi
@ -70,8 +70,8 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
|> Multi.run(:lose_consensus, fn repo, _ ->
lose_consensus(repo, ordered_consensus_block_numbers, insert_options)
end)
|> Multi.run(:lose_invalid_parent_consensus, fn repo, _ ->
lose_invalid_parent_consensus(repo, where_invalid_parent, insert_options)
|> Multi.run(:lose_invalid_neighbour_consensus, fn repo, _ ->
lose_invalid_neighbour_consensus(repo, where_invalid_neighbour, insert_options)
end)
|> Multi.run(:delete_address_token_balances, fn repo, _ ->
delete_address_token_balances(repo, ordered_consensus_block_numbers, insert_options)
@ -316,13 +316,13 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
end
end
defp lose_invalid_parent_consensus(repo, where_invalid_parent, %{
defp lose_invalid_neighbour_consensus(repo, where_invalid_neighbour, %{
timeout: timeout,
timestamps: %{updated_at: updated_at}
}) do
query =
from(
block in where_invalid_parent,
block in where_invalid_neighbour,
update: [
set: [
consensus: false,
@ -338,7 +338,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
{:ok, result}
rescue
postgrex_error in Postgrex.Error ->
{:error, %{exception: postgrex_error, where_invalid_parent: where_invalid_parent}}
{:error, %{exception: postgrex_error, where_invalid_neighbour: where_invalid_neighbour}}
end
end
@ -581,12 +581,22 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
end)
end
defp where_invalid_parent(blocks_changes) when is_list(blocks_changes) do
defp where_invalid_neighbour(blocks_changes) when is_list(blocks_changes) do
initial = from(b in Block, where: false)
Enum.reduce(blocks_changes, initial, fn %{consensus: consensus, parent_hash: parent_hash, number: number}, acc ->
Enum.reduce(blocks_changes, initial, fn %{
consensus: consensus,
hash: hash,
parent_hash: parent_hash,
number: number
},
acc ->
if consensus do
from(block in acc, or_where: block.number == ^(number - 1) and block.hash != ^parent_hash)
from(
block in acc,
or_where: block.number == ^(number - 1) and block.hash != ^parent_hash,
or_where: block.number == ^(number + 1) and block.parent_hash != ^hash
)
else
acc
end

Loading…
Cancel
Save