From 083e5d3278942c2603bf52932119385b6adb37f3 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 10 Jan 2019 08:37:12 -0600 Subject: [PATCH] Ensure min and max block number is for consensus blocks Adding `WHERE consensus = true` both fixes the bug that `min_block_number` and `max_block_number` were including non-consensus blocks, but it also makes the query faster because there is an index for consensus blocks. Times from Eth Mainnet production: ``` ether=> SELECT min(b0."number") FROM "blocks" AS b0; min ----- 0 (1 row) Time: 414.218 ms ether=> EXPLAIN SELECT min(b0."number") FROM "blocks" AS b0; QUERY PLAN ----------------------------------------------------------------------------------------------- Finalize Aggregate (cost=223454.95..223454.96 rows=1 width=8) -> Gather (cost=223454.73..223454.95 rows=2 width=8) Workers Planned: 2 -> Partial Aggregate (cost=222454.73..222454.74 rows=1 width=8) -> Parallel Seq Scan on blocks b0 (cost=0.00..215051.99 rows=2961099 width=8) (5 rows) Time: 1.040 ms ether=> EXPLAIN SELECT min(b0."number") FROM "blocks" AS b0 WHERE b0.consensus = true; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- Result (cost=0.45..0.46 rows=1 width=8) InitPlan 1 (returns $0) -> Limit (cost=0.43..0.45 rows=1 width=8) -> Index Only Scan using one_consensus_block_at_height on blocks b0 (cost=0.43..158050.90 rows=7045520 width=8) Index Cond: (number IS NOT NULL) (5 rows) Time: 3.350 ms ether=> SELECT min(b0."number") FROM "blocks" AS b0 WHERE b0.consensus = true; min ----- 0 (1 row) Time: 1.059 ms ``` --- .../controllers/api/rpc/logs_controller.ex | 2 +- .../api/rpc/transaction_controller.ex | 2 +- .../block_transaction_controller.ex | 2 +- ...saction_internal_transaction_controller.ex | 2 +- .../controllers/transaction_log_controller.ex | 2 +- .../transaction_token_transfer_controller.ex | 2 +- apps/explorer/lib/explorer/chain.ex | 54 ++++++++----------- .../chain/supply/proof_of_authority.ex | 2 +- apps/explorer/lib/explorer/etherscan.ex | 4 +- apps/explorer/test/explorer/chain_test.exs | 2 +- .../explorer/test/explorer/etherscan_test.exs | 4 +- apps/indexer/lib/indexer.ex | 2 +- 12 files changed, 36 insertions(+), 44 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/logs_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/logs_controller.ex index ee35f992cd..8f7257bc8e 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/logs_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/logs_controller.ex @@ -183,7 +183,7 @@ defmodule BlockScoutWeb.API.RPC.LogsController do defp to_block_number(params, param_key) do case params[param_key] do "latest" -> - Chain.max_block_number() + Chain.consensus_block_number(:max) _ -> to_integer(params, param_key) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex index 7b5104a458..cfbf7cbede 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex @@ -83,7 +83,7 @@ defmodule BlockScoutWeb.API.RPC.TransactionController do end defp max_block_number do - case Chain.max_block_number() do + case Chain.consensus_block_number(:max) do {:ok, number} -> number {:error, :not_found} -> 0 end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex index 5599043728..bf66ff33f4 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex @@ -82,7 +82,7 @@ defmodule BlockScoutWeb.BlockTransactionController do defp block_above_tip?("0x" <> _), do: nil defp block_above_tip?(block_hash_or_number) when is_binary(block_hash_or_number) do - with {:ok, max_block_number} <- Chain.max_block_number() do + with {:ok, max_block_number} <- Chain.consensus_block_number(:max) do {block_number, _} = Integer.parse(block_hash_or_number) block_number > max_block_number else diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex index 1d96952f75..c118cb5124 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex @@ -65,7 +65,7 @@ defmodule BlockScoutWeb.TransactionInternalTransactionController do end defp max_block_number do - case Chain.max_block_number() do + case Chain.consensus_block_number(:max) do {:ok, number} -> number {:error, :not_found} -> 0 end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex index 16d1177f30..66f467210b 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex @@ -61,7 +61,7 @@ defmodule BlockScoutWeb.TransactionLogController do end defp max_block_number do - case Chain.max_block_number() do + case Chain.consensus_block_number(:max) do {:ok, number} -> number {:error, :not_found} -> 0 end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex index b8d8d4fba1..fe669b8da6 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex @@ -65,7 +65,7 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do end defp max_block_number do - case Chain.max_block_number() do + case Chain.consensus_block_number(:max) do {:ok, number} -> number {:error, :not_found} -> 0 end diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 1e7f9bbd8e..2406b3df27 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -845,8 +845,8 @@ defmodule Explorer.Chain do """ @spec indexed_ratio() :: float() def indexed_ratio do - with {:ok, min_block_number} <- min_block_number(), - {:ok, max_block_number} <- max_block_number() do + with {:ok, min_block_number} <- consensus_block_number(:min), + {:ok, max_block_number} <- consensus_block_number(:max) do indexed_blocks = max_block_number - min_block_number + 1 indexed_blocks / (max_block_number + 1) else @@ -1156,48 +1156,40 @@ defmodule Explorer.Chain do end @doc """ - The maximum `t:Explorer.Chain.Block.t/0` `number` + Aggregate of consensus block numbers. - If blocks are skipped and inserted out of number order, the max number is still returned + If blocks are skipped and inserted out of number order, the `:max` and `:min` numbers are still returned iex> insert(:block, number: 2) iex> insert(:block, number: 1) - iex> Explorer.Chain.max_block_number() + iex> Explorer.Chain.consensus_block_number(:min) + {:ok, 1} + iex> Explorer.Chain.consensus_block_number(:max) {:ok, 2} - If there are no blocks, `{:error, :not_found}` is returned - - iex> Explorer.Chain.max_block_number() - {:error, :not_found} - - """ - @spec max_block_number() :: {:ok, Block.block_number()} | {:error, :not_found} - def max_block_number do - case Repo.aggregate(Block, :max, :number) do - nil -> {:error, :not_found} - number -> {:ok, number} - end - end - - @doc """ - The minimum `t:Explorer.Chain.Block.t/0` `number` (used to show loading status while indexing) - - If blocks are skipped and inserted out of number order, the min number is still returned + Non-consensus blocks are ignored - iex> insert(:block, number: 2) - iex> insert(:block, number: 1) - iex> Explorer.Chain.min_block_number() - {:ok, 1} + iex> insert(:block, number: 3, consensus: false) + iex> insert(:block, number: 2, consensus: true) + iex> insert(:block, number: 1, consensus: false) + iex> Explorer.Chain.consensus_block_number(:min) + {:ok, 2} + iex> Explorer.Chain.consensus_block_number(:max) + {:ok, 2} If there are no blocks, `{:error, :not_found}` is returned - iex> Explorer.Chain.min_block_number() + iex> Explorer.Chain.consensus_block_number(:min) + {:error, :not_found} + iex> Explorer.Chain.consensus_block_number(:max) {:error, :not_found} """ - @spec min_block_number() :: {:ok, Block.block_number()} | {:error, :not_found} - def min_block_number do - case Repo.aggregate(Block, :min, :number) do + def consensus_block_number(aggregate) do + Block + |> where(consensus: true) + |> Repo.aggregate(aggregate, :number) + |> case do nil -> {:error, :not_found} number -> {:ok, number} end diff --git a/apps/explorer/lib/explorer/chain/supply/proof_of_authority.ex b/apps/explorer/lib/explorer/chain/supply/proof_of_authority.ex index f9923eeca3..0a43750f30 100644 --- a/apps/explorer/lib/explorer/chain/supply/proof_of_authority.ex +++ b/apps/explorer/lib/explorer/chain/supply/proof_of_authority.ex @@ -41,7 +41,7 @@ defmodule Explorer.Chain.Supply.ProofOfAuthority do end defp block_height do - case Chain.max_block_number() do + case Chain.consensus_block_number(:max) do {:ok, height} -> height _ -> 0 end diff --git a/apps/explorer/lib/explorer/etherscan.ex b/apps/explorer/lib/explorer/etherscan.ex index a4d4649d97..4156314632 100644 --- a/apps/explorer/lib/explorer/etherscan.ex +++ b/apps/explorer/lib/explorer/etherscan.ex @@ -43,7 +43,7 @@ defmodule Explorer.Etherscan do %Hash{byte_count: unquote(Hash.Address.byte_count())} = address_hash, options \\ @default_options ) do - case Chain.max_block_number() do + case Chain.consensus_block_number(:max) do {:ok, max_block_number} -> merged_options = Map.merge(@default_options, options) list_transactions(address_hash, max_block_number, merged_options) @@ -152,7 +152,7 @@ defmodule Explorer.Etherscan do contract_address_hash, options \\ @default_options ) do - case Chain.max_block_number() do + case Chain.consensus_block_number(:max) do {:ok, max_block_number} -> merged_options = Map.merge(@default_options, options) list_token_transfers(address_hash, contract_address_hash, max_block_number, merged_options) diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index 3db16239eb..0435889f43 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -594,7 +594,7 @@ defmodule Explorer.ChainTest do describe "confirmations/1" do test "with block.number == max_block_number " do block = insert(:block) - {:ok, max_block_number} = Chain.max_block_number() + {:ok, max_block_number} = Chain.consensus_block_number(:max) assert block.number == max_block_number assert Chain.confirmations(block, max_block_number: max_block_number) == 0 diff --git a/apps/explorer/test/explorer/etherscan_test.exs b/apps/explorer/test/explorer/etherscan_test.exs index cb6ff93005..2476fc2e59 100644 --- a/apps/explorer/test/explorer/etherscan_test.exs +++ b/apps/explorer/test/explorer/etherscan_test.exs @@ -122,7 +122,7 @@ defmodule Explorer.EtherscanTest do [found_transaction] = Etherscan.list_transactions(address.hash) - {:ok, max_block_number} = Chain.max_block_number() + {:ok, max_block_number} = Chain.consensus_block_number(:max) expected_confirmations = max_block_number - transaction.block_number assert found_transaction.confirmations == expected_confirmations @@ -888,7 +888,7 @@ defmodule Explorer.EtherscanTest do [found_token_transfer] = Etherscan.list_token_transfers(token_transfer.from_address_hash, nil) - {:ok, max_block_number} = Chain.max_block_number() + {:ok, max_block_number} = Chain.consensus_block_number(:max) expected_confirmations = max_block_number - transaction.block_number assert found_token_transfer.confirmations == expected_confirmations diff --git a/apps/indexer/lib/indexer.ex b/apps/indexer/lib/indexer.ex index 47c0d7b9a8..552963e0a9 100644 --- a/apps/indexer/lib/indexer.ex +++ b/apps/indexer/lib/indexer.ex @@ -22,7 +22,7 @@ defmodule Indexer do """ def max_block_number do - case Chain.max_block_number() do + case Chain.consensus_block_number(:max) do {:ok, number} -> number {:error, :not_found} -> 0 end