Merge pull request #2538 from poanetwork/ab-fetch-last-coin-balance-records

fetch the last not empty coin balance records
pull/2497/head
Ayrat Badykov 5 years ago committed by GitHub
commit 6a9aa65e44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 10
      apps/block_scout_web/assets/js/lib/coin_balance_history_chart.js
  3. 9
      apps/explorer/lib/explorer/chain.ex
  4. 22
      apps/explorer/lib/explorer/chain/address/coin_balance.ex
  5. 32
      apps/explorer/test/explorer/chain/address/coin_balance_test.exs
  6. 4
      apps/explorer/test/explorer/chain_test.exs

@ -5,6 +5,7 @@
### Fixes
- [#2564](https://github.com/poanetwork/blockscout/pull/2564) - fix first page button for uncles and reorgs
- [#2563](https://github.com/poanetwork/blockscout/pull/2563) - Fix view less transfers button
- [#2538](https://github.com/poanetwork/blockscout/pull/2538) - fetch the last not empty coin balance records
### Chore
- [#2566](https://github.com/poanetwork/blockscout/pull/2566) - upgrade absinthe phoenix

@ -18,6 +18,14 @@ export function createCoinBalanceHistoryChart (el) {
y: balance.value
}))
var stepSize = 3
if (data.length > 1) {
var diff = Math.abs(new Date(data[data.length - 1].date) - new Date(data[data.length - 2].date))
var periodInDays = diff / (1000 * 60 * 60 * 24)
stepSize = periodInDays
}
return new Chart(el, {
type: 'line',
data: {
@ -36,7 +44,7 @@ export function createCoinBalanceHistoryChart (el) {
type: 'time',
time: {
unit: 'day',
stepSize: 3
stepSize: stepSize
}
}],
yAxes: [{

@ -2975,8 +2975,13 @@ defmodule Explorer.Chain do
@spec address_to_balances_by_day(Hash.Address.t()) :: [balance_by_day]
def address_to_balances_by_day(address_hash) do
latest_block_timestamp =
address_hash
|> CoinBalance.last_coin_balance_timestamp()
|> Repo.one()
address_hash
|> CoinBalance.balances_by_day()
|> CoinBalance.balances_by_day(latest_block_timestamp)
|> Repo.all()
|> normalize_balances_by_day()
end
@ -2992,7 +2997,7 @@ defmodule Explorer.Chain do
today = Date.to_string(NaiveDateTime.utc_now())
if Enum.count(result) > 0 && !Enum.any?(result, fn map -> map[:date] == today end) do
[%{date: today, value: List.last(result)[:value]} | result]
List.flatten([result | [%{date: today, value: List.last(result)[:value]}]])
else
result
end

@ -75,7 +75,7 @@ defmodule Explorer.Chain.Address.CoinBalance do
from(
cb in CoinBalance,
where: cb.address_hash == ^address_hash,
where: cb.value > ^0,
where: not is_nil(cb.value),
inner_join: b in Block,
on: cb.block_number == b.number,
order_by: [desc: :block_number],
@ -89,16 +89,32 @@ defmodule Explorer.Chain.Address.CoinBalance do
Builds an `Ecto.Query` to fetch a series of balances by day for the given account. Each element in the series
corresponds to the maximum balance in that day. Only the last 90 days of data are used.
"""
def balances_by_day(address_hash) do
def balances_by_day(address_hash, block_timestamp \\ nil) do
CoinBalance
|> join(:inner, [cb], b in Block, on: cb.block_number == b.number)
|> where([cb], cb.address_hash == ^address_hash)
|> where([cb, b], b.timestamp >= fragment("date_trunc('day', now()) - interval '90 days'"))
|> limit_time_interval(block_timestamp)
|> group_by([cb, b], fragment("date_trunc('day', ?)", b.timestamp))
|> order_by([cb, b], fragment("date_trunc('day', ?)", b.timestamp))
|> select([cb, b], %{date: type(fragment("date_trunc('day', ?)", b.timestamp), :date), value: max(cb.value)})
end
def limit_time_interval(query, nil) do
query |> where([cb, b], b.timestamp >= fragment("date_trunc('day', now()) - interval '90 days'"))
end
def limit_time_interval(query, %{timestamp: timestamp}) do
query |> where([cb, b], b.timestamp >= fragment("(? AT TIME ZONE ?) - interval '90 days'", ^timestamp, ^"Etc/UTC"))
end
def last_coin_balance_timestamp(address_hash) do
CoinBalance
|> join(:inner, [cb], b in Block, on: cb.block_number == b.number)
|> where([cb], cb.address_hash == ^address_hash)
|> last(:block_number)
|> select([cb, b], %{timestamp: b.timestamp})
end
def changeset(%__MODULE__{} = balance, params) do
balance
|> cast(params, @allowed_fields)

@ -2,8 +2,8 @@ defmodule Explorer.Chain.Address.CoinBalanceTest do
use Explorer.DataCase
alias Ecto.Changeset
alias Explorer.Chain.{Block, Wei}
alias Explorer.Chain.Address.CoinBalance
alias Explorer.Chain.{Block, Wei}
alias Explorer.PagingOptions
describe "changeset/2" do
@ -225,7 +225,7 @@ defmodule Explorer.Chain.Address.CoinBalanceTest do
assert(length(result) == 1)
value = List.first(result) |> Map.get(:value)
value = result |> List.first() |> Map.get(:value)
assert(value == Wei.from(Decimal.new(3000), :wei))
end
@ -247,7 +247,7 @@ defmodule Explorer.Chain.Address.CoinBalanceTest do
assert(length(result) == 1)
value = List.first(result) |> Map.get(:value)
value = result |> List.first() |> Map.get(:value)
assert(value == Wei.from(Decimal.new(3000), :wei))
end
@ -269,9 +269,33 @@ defmodule Explorer.Chain.Address.CoinBalanceTest do
assert(length(result) == 1)
value = List.first(result) |> Map.get(:value)
value = result |> List.first() |> Map.get(:value)
assert(value == Wei.from(Decimal.new(3000), :wei))
end
test "fetches old records" do
address = insert(:address)
noon = Timex.now() |> Timex.beginning_of_day() |> Timex.set(hour: 12)
old_block = insert(:block, timestamp: Timex.shift(noon, days: -700))
insert(:fetched_balance, address_hash: address.hash, value: 2000, block_number: old_block.number)
latest_block_timestamp =
address.hash
|> CoinBalance.last_coin_balance_timestamp()
|> Repo.one()
result =
address.hash
|> CoinBalance.balances_by_day(latest_block_timestamp)
|> Repo.all()
assert(length(result) == 1)
value = result |> List.first() |> Map.get(:value)
assert(value == Wei.from(Decimal.new(2000), :wei))
end
end
end

@ -3896,8 +3896,8 @@ defmodule Explorer.ChainTest do
balances = Chain.address_to_balances_by_day(address.hash)
assert balances == [
%{date: today |> NaiveDateTime.to_date() |> Date.to_string(), value: Decimal.new("1E-15")},
%{date: yesterday |> NaiveDateTime.to_date() |> Date.to_string(), value: Decimal.new("1E-15")}
%{date: yesterday |> NaiveDateTime.to_date() |> Date.to_string(), value: Decimal.new("1E-15")},
%{date: today |> NaiveDateTime.to_date() |> Date.to_string(), value: Decimal.new("1E-15")}
]
end
end

Loading…
Cancel
Save