Merge pull request #3140 from poanetwork/vb-fix-performance-coin-balance-history-nnew-wave-under-chart

Fix performance of the balance changing history list loading
pull/3142/head
Victor Baranov 4 years ago committed by GitHub
commit 02ac0a3ecd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 12
      apps/block_scout_web/lib/block_scout_web/controllers/address_coin_balance_controller.ex
  3. 70
      apps/explorer/lib/explorer/chain.ex
  4. 5
      apps/explorer/lib/explorer/chain/address/coin_balance.ex
  5. 26
      apps/explorer/test/explorer/chain_test.exs

@ -1,8 +1,10 @@
## Current
### Features
- [#3125](https://github.com/poanetwork/blockscout/pull/3125) - Availability to configure a number of days to consider at coin balance history chart via environment variable
### Fixes
- [#3140](https://github.com/poanetwork/blockscout/pull/3140) - Fix performance of the balance changing history list loading
- [#3133](https://github.com/poanetwork/blockscout/pull/3133) - Take into account FIRST_BLOCK in trace_ReplayBlockTransactions requests
- [#3132](https://github.com/poanetwork/blockscout/pull/3132) - Fix performance of coin supply API endpoints
- [#3130](https://github.com/poanetwork/blockscout/pull/3130) - Take into account FIRST_BLOCK for block rewards fetching

@ -23,6 +23,16 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do
{coin_balances, next_page} = split_list_by_page(coin_balances_plus_one)
deduplicated_coin_balances =
coin_balances
|> Enum.dedup_by(fn record ->
if record.delta == Decimal.new(0) do
:dup
else
System.unique_integer()
end
end)
next_page_url =
case next_page_params(next_page, coin_balances, params) do
nil ->
@ -38,7 +48,7 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do
end
coin_balances_json =
Enum.map(coin_balances, fn coin_balance ->
Enum.map(deduplicated_coin_balances, fn coin_balance ->
View.render_to_string(
AddressCoinBalanceView,
"_coin_balances.html",

@ -3493,17 +3493,62 @@ defmodule Explorer.Chain do
def address_to_coin_balances(address_hash, options) do
paging_options = Keyword.get(options, :paging_options, @default_paging_options)
address_hash
|> CoinBalance.fetch_coin_balances(paging_options)
|> page_coin_balances(paging_options)
|> Repo.all()
|> Enum.dedup_by(fn record ->
if record.delta == Decimal.new(0) do
:dup
balances_raw =
address_hash
|> CoinBalance.fetch_coin_balances(paging_options)
|> page_coin_balances(paging_options)
|> Repo.all()
min_block_number =
balances_raw
|> Enum.min_by(fn balance -> balance.block_number end)
|> Map.get(:block_number)
max_block_number =
balances_raw
|> Enum.max_by(fn balance -> balance.block_number end)
|> Map.get(:block_number)
min_block_timestamp = find_block_timestamp(min_block_number)
max_block_timestamp = find_block_timestamp(max_block_number)
min_block_unix_timestamp =
min_block_timestamp
|> Timex.to_unix()
max_block_unix_timestamp =
max_block_timestamp
|> Timex.to_unix()
blocks_delta = max_block_number - min_block_number
balances_with_dates =
if blocks_delta > 0 do
balances_raw
|> Enum.map(fn balance ->
date =
trunc(
min_block_unix_timestamp +
(balance.block_number - min_block_number) * (max_block_unix_timestamp - min_block_unix_timestamp) /
blocks_delta
)
formatted_date = Timex.from_unix(date)
%{balance | block_timestamp: formatted_date}
end)
else
System.unique_integer()
balances_raw
|> Enum.map(fn balance ->
date = min_block_unix_timestamp
formatted_date = Timex.from_unix(date)
%{balance | block_timestamp: formatted_date}
end)
end
end)
balances_with_dates
|> Enum.filter(fn balance -> balance.value end)
|> Enum.sort(fn balance1, balance2 -> balance1.block_timestamp >= balance2.block_timestamp end)
end
def get_coin_balance(address_hash, block_number) do
@ -4334,4 +4379,11 @@ defmodule Explorer.Chain do
block_index
end
end
defp find_block_timestamp(number) do
Block
|> where([b], b.number == ^number)
|> select([b], b.timestamp)
|> Repo.one()
end
end

@ -76,12 +76,9 @@ defmodule Explorer.Chain.Address.CoinBalance do
cb in CoinBalance,
where: cb.address_hash == ^address_hash,
where: not is_nil(cb.value),
inner_join: b in Block,
on: cb.block_number == b.number,
order_by: [desc: :block_number],
limit: ^page_size,
select_merge: %{delta: fragment("value - coalesce(lag(value, 1) over (order by block_number), 0)")},
select_merge: %{block_timestamp: b.timestamp}
select_merge: %{delta: fragment("value - coalesce(lead(value, 1) over (order by block_number desc), 0)")}
)
end

@ -5025,32 +5025,6 @@ defmodule Explorer.ChainTest do
end
end
describe "address_to_coin_balances/2" do
test "deduplicates records by zero delta" do
address = insert(:address)
1..5
|> Enum.each(fn block_number ->
insert(:block, number: block_number)
insert(:fetched_balance, value: 1, block_number: block_number, address_hash: address.hash)
end)
insert(:block, number: 6)
insert(:fetched_balance, value: 2, block_number: 6, address_hash: address.hash)
assert [first, second, third] = Chain.address_to_coin_balances(address.hash, [])
assert first.block_number == 6
assert first.delta == Decimal.new(1)
assert second.block_number == 5
assert second.delta == Decimal.new(0)
assert third.block_number == 1
assert third.delta == Decimal.new(1)
end
end
describe "extract_db_name/1" do
test "extracts correct db name" do
db_url = "postgresql://viktor:@localhost:5432/blockscout-dev-1"

Loading…
Cancel
Save