Calculate loading status triggered by catchup block event

pull/916/head
Stamates 6 years ago
parent a9be1d4da6
commit 0e7ee4ee96
  1. 25
      apps/block_scout_web/lib/block_scout_web/notifier.ex
  2. 17
      apps/block_scout_web/test/block_scout_web/channels/block_channel_test.exs
  3. 4
      apps/block_scout_web/test/block_scout_web/features/pages/block_list_page.ex
  4. 15
      apps/block_scout_web/test/block_scout_web/features/viewing_blocks_test.exs
  5. 66
      apps/explorer/lib/explorer/chain.ex
  6. 20
      apps/explorer/test/explorer/chain_test.exs

@ -16,6 +16,31 @@ defmodule BlockScoutWeb.Notifier do
|> Enum.each(&broadcast_balance/1)
end
def handle_event({:chain_event, :blocks, :catchup, _blocks}) do
min_block_number = Chain.min_block_number()
percentage =
if min_block_number > 1 do
max_block_number = Chain.max_block_number()
indexed_blocks = max_block_number - min_block_number + 1
indexed_blocks / max_block_number * 100
else
1.0
end
finished? =
if percentage < 1 do
false
else
Chain.finished_indexing?()
end
Endpoint.broadcast("blocks:indexing", "block_percentage", %{
percentage: percentage,
finished: finished?
})
end
def handle_event({:chain_event, :blocks, :realtime, blocks}) do
Enum.each(blocks, &broadcast_block/1)
end

@ -19,4 +19,21 @@ defmodule BlockScoutWeb.BlockChannelTest do
assert false, "Expected message received nothing."
end
end
test "subscribed user is notified of new_block event for catchup" do
topic = "blocks:new_block"
@endpoint.subscribe(topic)
block = insert(:block, number: 1)
Notifier.handle_event({:chain_event, :blocks, :catchup, [block]})
receive do
%Phoenix.Socket.Broadcast{topic: ^topic, event: "new_block", payload: %{block: _}} ->
assert true
after
5_000 ->
assert false, "Expected message received nothing."
end
end
end

@ -23,6 +23,10 @@ defmodule BlockScoutWeb.BlockListPage do
css("[data-block-number='#{block_number}']")
end
def loading_percentage(percentage) do
css("[data-selector='loading-percentage'][data-loading-percentage='#{percentage}']")
end
def place_holder_blocks(count) do
css("[data-selector='place-holder']", count: count)
end

@ -177,4 +177,19 @@ defmodule BlockScoutWeb.ViewingBlocksTest do
|> assert_has(BlockListPage.blocks(10))
end
end
describe "loading bar when indexing" do
test "shows blocks indexed percentage", %{
first_shown_block: newest_block,
last_shown_block: oldest_block,
session: session
} do
indexed_blocks = newest_block.number - oldest_block.number + 1
percentage = indexed_blocks / newest_block.number * 100
session
|> BlockListPage.visit_page()
|> BlockListPage.loading_percentage(percentage)
end
end
end

@ -555,6 +555,23 @@ defmodule Explorer.Chain do
{:actual, fee}
end
@doc """
Checks to see if the chain is down indexing based on the transaction from the oldest block having
an `internal_transactions_indexed_at` date.
"""
@spec finished_indexing?() :: boolean()
def finished_indexing? do
min_block_number_transaction = Repo.aggregate(Transaction, :min, :block_number)
Transaction
|> where([t], t.block_number == ^min_block_number_transaction and is_nil(t.internal_transactions_indexed_at))
|> limit(1)
|> Repo.one()
|> case do
nil -> true
_ -> false
end
end
@doc """
The `t:Explorer.Chain.Transaction.t/0` `gas_price` of the `transaction` in `unit`.
"""
@ -822,31 +839,6 @@ defmodule Explorer.Chain do
Repo.aggregate(InternalTransaction, :count, :id)
end
@doc """
Finds block with greatest number.
iex> insert(:block, number: 2)
iex> insert(:block, number: 1)
iex> {:ok, %Explorer.Chain.Block{number: number}} = Explorer.Chain.max_numbered_block()
iex> number
2
If there are no blocks `{:error, :not_found}` is returned.
iex> Explorer.Chain.max_numbered_block()
{:error, :not_found}
"""
@spec max_numbered_block() :: {:ok, Block.t()} | {:error, :not_found}
def max_numbered_block do
query = from(block in Block, order_by: [desc: block.number], limit: 1)
case Repo.one(query) do
nil -> {:error, :not_found}
block -> {:ok, block}
end
end
@doc """
Finds all `t:Explorer.Chain.Transaction.t/0` in the `t:Explorer.Chain.Block.t/0`.
@ -1142,6 +1134,30 @@ defmodule Explorer.Chain do
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
iex> insert(:block, number: 2)
iex> insert(:block, number: 1)
iex> Explorer.Chain.min_block_number()
{:ok, 1}
If there are no blocks, `{:error, :not_found}` is returned
iex> Explorer.Chain.min_block_number()
{: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
nil -> {:error, :not_found}
number -> {:ok, number}
end
end
@doc """
Calculates the ranges of missing consensus blocks in `range`.

@ -558,6 +558,26 @@ defmodule Explorer.ChainTest do
end
end
describe "finished_indexing?/0"
test "finished indexing" do
block = insert(:block, number: 1)
:transaction
|> insert()
|> with_block(block)
assert Chain.finished_indexing?()
end
test "not finished indexing" do
block = insert(:block, number: 1)
:transaction
|> insert(internal_transactions_index_at: nil)
|> with_block(block)
refute Chain.finished_indexing?()
end
end
describe "gas_price/2" do
test ":wei unit" do
assert Chain.gas_price(%Transaction{gas_price: %Wei{value: Decimal.new(1)}}, :wei) == Decimal.new(1)

Loading…
Cancel
Save