Merge pull request #2908 from poanetwork/vb-block-rewards

Fix performance of address page for validators
pull/2936/head
Victor Baranov 5 years ago committed by GitHub
commit 0b60078045
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 69
      apps/explorer/lib/explorer/chain.ex
  3. 28
      apps/explorer/lib/explorer/chain/block/reward.ex
  4. 2
      apps/explorer/test/explorer/chain/import/runner/blocks_test.exs
  5. 31
      apps/explorer/test/explorer/chain_test.exs

@ -12,6 +12,7 @@
- [#2924](https://github.com/poanetwork/blockscout/pull/2924) - Speedup address to logs query
- [#2915](https://github.com/poanetwork/blockscout/pull/2915) - Speedup of blocks_without_reward_query
- [#2914](https://github.com/poanetwork/blockscout/pull/2914) - Reduce execution time of stream_unfetched_token_instances query
- [#2908](https://github.com/poanetwork/blockscout/pull/2908) - Fix performance of address page
- [#2906](https://github.com/poanetwork/blockscout/pull/2906) - fix address sum cache
- [#2902](https://github.com/poanetwork/blockscout/pull/2902) - Offset in blocks retrieval for average block time
- [#2900](https://github.com/poanetwork/blockscout/pull/2900) - check fetched instance metadata in multiple places

@ -263,10 +263,10 @@ defmodule Explorer.Chain do
paging_options = Keyword.get(options, :paging_options, @default_paging_options)
if Application.get_env(:block_scout_web, BlockScoutWeb.Chain)[:has_emission_funds] do
blocks_range = address_to_transactions_tasks_range_of_blocks(address_hash, options)
rewards_task =
Task.async(fn ->
Reward.fetch_emission_rewards_tuples(address_hash, paging_options)
end)
Task.async(fn -> Reward.fetch_emission_rewards_tuples(address_hash, paging_options, blocks_range) end)
[rewards_task | address_to_transactions_tasks(address_hash, options)]
|> wait_for_address_transactions()
@ -305,21 +305,72 @@ defmodule Explorer.Chain do
|> Enum.take(paging_options.page_size)
end
defp address_to_transactions_tasks_query(options) do
options
|> Keyword.get(:paging_options, @default_paging_options)
|> fetch_transactions()
end
defp address_to_transactions_tasks(address_hash, options) do
paging_options = Keyword.get(options, :paging_options, @default_paging_options)
direction = Keyword.get(options, :direction)
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
base_query =
paging_options
|> fetch_transactions()
options
|> address_to_transactions_tasks_query()
|> join_associations(necessity_by_association)
base_query
|> Transaction.matching_address_queries_list(direction, address_hash)
|> Enum.map(fn query -> Task.async(fn -> Repo.all(query) end) end)
end
defp address_to_transactions_tasks_range_of_blocks(address_hash, options) do
direction = Keyword.get(options, :direction)
extremums_list =
options
|> address_to_transactions_tasks_query()
|> Transaction.matching_address_queries_list(direction, address_hash)
|> Enum.map(fn query ->
max_query =
from(
q in subquery(query),
select: %{min_block_number: min(q.block_number), max_block_number: max(q.block_number)}
)
max_query
|> Repo.one!()
end)
extremums_list
|> Enum.reduce(%{min_block_number: nil, max_block_number: 0}, fn %{
min_block_number: min_number,
max_block_number: max_number
},
extremums_result ->
current_min_number = Map.get(extremums_result, :min_block_number)
current_max_number = Map.get(extremums_result, :max_block_number)
extremums_result =
if is_number(current_min_number) do
if is_number(min_number) and min_number > 0 and min_number < current_min_number do
extremums_result
|> Map.put(:min_block_number, min_number)
else
extremums_result
end
else
extremums_result
|> Map.put(:min_block_number, min_number)
end
if is_number(max_number) and max_number > 0 and max_number > current_max_number do
extremums_result
|> Map.put(:max_block_number, max_number)
else
extremums_result
end
end)
end
defp wait_for_address_transactions(tasks) do
tasks
|> Task.yield_many(:timer.seconds(20))

@ -68,8 +68,10 @@ defmodule Explorer.Chain.Block.Reward do
Returns a list of tuples representing rewards by the EmissionFunds on POA chains.
The tuples have the format {EmissionFunds, Validator}
"""
@spec fetch_emission_rewards_tuples(Hash.Address.t(), PagingOptions.t()) :: [{t(), t()}]
def fetch_emission_rewards_tuples(address_hash, paging_options) do
def fetch_emission_rewards_tuples(address_hash, paging_options, %{
min_block_number: min_block_number,
max_block_number: max_block_number
}) do
address_rewards =
__MODULE__
|> join_associations()
@ -77,6 +79,7 @@ defmodule Explorer.Chain.Block.Reward do
|> limit(^paging_options.page_size)
|> order_by([_, block], desc: block.number)
|> where([reward], reward.address_hash == ^address_hash)
|> address_rewards_blocks_ranges_clause(min_block_number, max_block_number, paging_options)
|> Repo.all()
case List.first(address_rewards) do
@ -117,4 +120,25 @@ defmodule Explorer.Chain.Block.Reward do
|> join(:inner, [reward], block in assoc(reward, :block))
|> preload(:block)
end
defp address_rewards_blocks_ranges_clause(query, min_block_number, max_block_number, paging_options) do
if is_number(min_block_number) and max_block_number > 0 and min_block_number > 0 do
cond do
paging_options.page_number == 1 ->
query
|> where([_, block], block.number >= ^min_block_number)
min_block_number == max_block_number ->
query
|> where([_, block], block.number == ^min_block_number)
true ->
query
|> where([_, block], block.number >= ^min_block_number)
|> where([_, block], block.number <= ^max_block_number)
end
else
query
end
end
end

@ -312,7 +312,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do
end
test "removes duplicate blocks (by hash) before inserting",
%{consensus_block: %{number: block_number, hash: block_hash, miner_hash: miner_hash}, options: options} do
%{consensus_block: %{number: _, hash: block_hash, miner_hash: miner_hash}, options: options} do
new_block = params_for(:block, miner_hash: miner_hash, consensus: true)
%Ecto.Changeset{valid?: true, changes: block_changes} = Block.changeset(%Block{}, new_block)

@ -615,7 +615,7 @@ defmodule Explorer.ChainTest do
:transaction
|> insert(from_address: block.miner)
|> with_block()
|> with_block(block)
|> Repo.preload(:token_transfers)
assert [_, {_, _}] = Chain.address_to_transactions_with_rewards(block.miner.hash, direction: :from)
@ -623,6 +623,35 @@ defmodule Explorer.ChainTest do
Application.put_env(:block_scout_web, BlockScoutWeb.Chain, has_emission_funds: false)
end
test "with transactions if rewards are not in the range of blocks" do
Application.put_env(:block_scout_web, BlockScoutWeb.Chain, has_emission_funds: true)
block = insert(:block)
insert(
:reward,
address_hash: block.miner_hash,
block_hash: block.hash,
address_type: :validator
)
insert(
:reward,
address_hash: block.miner_hash,
block_hash: block.hash,
address_type: :emission_funds
)
:transaction
|> insert(from_address: block.miner)
|> with_block()
|> Repo.preload(:token_transfers)
assert [_] = Chain.address_to_transactions_with_rewards(block.miner.hash, direction: :from)
Application.put_env(:block_scout_web, BlockScoutWeb.Chain, has_emission_funds: false)
end
test "with emissions rewards, but feature disabled" do
Application.put_env(:block_scout_web, BlockScoutWeb.Chain, has_emission_funds: false)

Loading…
Cancel
Save