Merge branch 'master' into feature/#1476-add-styles-for-POSDAO-network

pull/1704/head
Ayrat Badykov 6 years ago committed by GitHub
commit 72a291ebf2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .circleci/config.yml
  2. 7
      CHANGELOG.md
  3. 17
      PULL_REQUEST_TEMPLATE.md
  4. 2
      apps/block_scout_web/lib/block_scout_web/notifier.ex
  5. 13
      apps/explorer/config/config.exs
  6. 9
      apps/explorer/lib/explorer/chain/block_number_cache.ex
  7. 4
      apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex
  8. 59
      apps/explorer/lib/explorer/counters/average_block_time.ex
  9. 38
      apps/explorer/test/explorer/counters/average_block_time_test.exs
  10. 3
      apps/indexer/lib/indexer/address_extraction.ex
  11. 14
      apps/indexer/test/indexer/coin_balance/on_demand_fetcher_test.exs

@ -189,7 +189,7 @@ jobs:
- restore_cache:
keys:
- v7-mix-dailyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.lock" }}
- v7-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.lock" }}
- v7-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.exs" }}
- v7-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}

@ -6,6 +6,7 @@
- [#1654](https://github.com/poanetwork/blockscout/pull/1654) - add decompiled code tab
- [#1661](https://github.com/poanetwork/blockscout/pull/1661) - try to compile smart contract with the latest evm version
- [#1665](https://github.com/poanetwork/blockscout/pull/1665) - Add contract verification RPC endpoint.
- [#1706](https://github.com/poanetwork/blockscout/pull/1706) - allow setting update interval for addresses with b
### Fixes
@ -16,9 +17,13 @@
- [#1684](https://github.com/poanetwork/blockscout/pull/1684) - Discard child block with parent_hash not matching hash of imported block
- [#1699](https://github.com/poanetwork/blockscout/pull/1699) - use seconds as transaction cache period measure
- [#1697](https://github.com/poanetwork/blockscout/pull/1697) - fix failing in rpc if balance is empty
- [#1711](https://github.com/poanetwork/blockscout/pull/1711) - rescue failing repo in block number cache update
- [#1714](https://github.com/poanetwork/blockscout/pull/1714) - fix average block time calculation
### Chore
- [#1693](https://github.com/poanetwork/blockscout/pull/1693) - Add a checklist to the PR template
## 1.3.8-beta

@ -18,3 +18,20 @@
## Upgrading
*If you have any Incompatible Changes in the above Changelog, outline how users of prior versions can upgrade once this PR lands or when reviewers are testing locally. A common upgrading step is "Database reset and re-index required".*
## Checklist for your PR
<!--
Ideally a PR has all of the checkmarks set.
If something in this list is irrelevant to your PR, you should still set this
checkmark indicating that you are sure it is dealt with (be that by irrelevance).
If you don't set a checkmark (e. g. don't add a test for new functionality),
you must be able to justify that.
-->
- [ ] I added an entry to `CHANGELOG.md` with this PR
- [ ] If I added new functionality, I added tests covering it.
- [ ] If I fixed a bug, I added a regression test to prevent the bug from silently reappearing again.
- [ ] I checked whether I should update the docs and did so if necessary

@ -116,7 +116,7 @@ defmodule BlockScoutWeb.Notifier do
defp broadcast_block(block) do
preloaded_block = Repo.preload(block, [[miner: :names], :transactions, :rewards])
average_block_time = AverageBlockTime.average_block_time(preloaded_block)
average_block_time = AverageBlockTime.average_block_time()
Endpoint.broadcast("blocks:new_block", "new_block", %{
block: preloaded_block,

@ -13,7 +13,18 @@ config :explorer,
config :explorer, Explorer.Counters.AverageBlockTime, enabled: true
config :explorer, Explorer.Counters.AddressesWithBalanceCounter, enabled: true, enable_consolidation: true
balances_update_interval =
if System.get_env("ADDRESS_WITH_BALANCES_UPDATE_INTERVAL") do
case Integer.parse(System.get_env("ADDRESS_WITH_BALANCES_UPDATE_INTERVAL")) do
{integer, ""} -> integer
_ -> nil
end
end
config :explorer, Explorer.Counters.AddressesWithBalanceCounter,
enabled: true,
enable_consolidation: true,
update_interval_in_seconds: balances_update_interval || 30 * 60
config :explorer, Explorer.ExchangeRates, enabled: true, store: :ets

@ -61,7 +61,7 @@ defmodule Explorer.Chain.BlockNumberCache do
defp update_cache do
current_time = current_time()
{min, max} = Chain.fetch_min_and_max_block_numbers()
{min, max} = min_and_max_from_db()
tuple = {min, max, current_time}
:ets.insert(@tab, {@key, tuple})
@ -85,6 +85,13 @@ defmodule Explorer.Chain.BlockNumberCache do
cache_period
end
defp min_and_max_from_db do
Chain.fetch_min_and_max_block_numbers()
rescue
_e ->
{0, 0}
end
defp current_time do
utc_now = DateTime.utc_now()

@ -29,6 +29,8 @@ defmodule Explorer.Counters.AddressesWithBalanceCounter do
config = Application.get_env(:explorer, Explorer.Counters.AddressesWithBalanceCounter)
@enable_consolidation Keyword.get(config, :enable_consolidation)
@update_interval_in_seconds Keyword.get(config, :update_interval_in_seconds)
@doc """
Starts a process to periodically update the counter of the token holders.
"""
@ -62,7 +64,7 @@ defmodule Explorer.Counters.AddressesWithBalanceCounter do
defp schedule_next_consolidation do
if enable_consolidation?() do
Process.send_after(self(), :consolidate, :timer.minutes(30))
Process.send_after(self(), :consolidate, :timer.seconds(@update_interval_in_seconds))
end
end

@ -11,6 +11,8 @@ defmodule Explorer.Counters.AverageBlockTime do
alias Explorer.Repo
alias Timex.Duration
@refresh_period 30 * 60 * 1_000
@doc """
Starts a process to periodically update the counter of the token holders.
"""
@ -19,27 +21,51 @@ defmodule Explorer.Counters.AverageBlockTime do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def average_block_time(block \\ nil) do
def average_block_time do
enabled? =
:explorer
|> Application.fetch_env!(__MODULE__)
|> Keyword.fetch!(:enabled)
if enabled? do
block = if block, do: {block.number, DateTime.to_unix(block.timestamp, :millisecond)}
GenServer.call(__MODULE__, {:average_block_time, block})
GenServer.call(__MODULE__, :average_block_time)
else
{:error, :disabled}
end
end
def refresh do
GenServer.call(__MODULE__, :refresh_timestamps)
end
## Server
@impl true
def init(_) do
Process.send_after(self(), :refresh_timestamps, @refresh_period)
{:ok, refresh_timestamps()}
end
@impl true
def handle_call(:average_block_time, _from, %{average: average} = state), do: {:reply, average, state}
@impl true
def handle_call(:refresh_timestamps, _, _) do
{:reply, :ok, refresh_timestamps()}
end
@impl true
def handle_info(:refresh_timestamps, _) do
Process.send_after(self(), :refresh_timestamps, @refresh_period)
{:noreply, refresh_timestamps()}
end
defp refresh_timestamps do
timestamps_query =
from(block in Block,
limit: 100,
offset: 1,
offset: 0,
order_by: [desc: block.number],
select: {block.number, block.timestamp}
)
@ -51,30 +77,7 @@ defmodule Explorer.Counters.AverageBlockTime do
{number, DateTime.to_unix(timestamp, :millisecond)}
end)
{:ok, %{timestamps: timestamps, average: average_distance(timestamps)}}
end
@impl true
def handle_call({:average_block_time, nil}, _from, %{average: average} = state), do: {:reply, average, state}
def handle_call({:average_block_time, block}, _from, state) do
state = add_block(state, block)
{:reply, state.average, state}
end
# This is pretty naive, but we'll only ever be sorting 100 dates so I don't think
# complex logic is really necessary here.
defp add_block(%{timestamps: timestamps} = state, {new_number, _} = block) do
if Enum.any?(timestamps, fn {number, _} -> number == new_number end) do
state
else
timestamps =
[block | timestamps]
|> Enum.sort_by(fn {number, _} -> number end, &Kernel.>/2)
|> Enum.take(100)
%{state | timestamps: timestamps, average: average_distance(timestamps)}
end
%{timestamps: timestamps, average: average_distance(timestamps)}
end
defp average_distance([]), do: Duration.from_milliseconds(0)

@ -5,8 +5,6 @@ defmodule Explorer.Counters.AverageBlockTimeTest do
alias Explorer.Counters.AverageBlockTime
defp block(number, last, duration), do: %{number: number, timestamp: Timex.shift(last, seconds: duration)}
setup do
start_supervised!(AverageBlockTime)
Application.put_env(:explorer, AverageBlockTime, enabled: true)
@ -26,41 +24,5 @@ defmodule Explorer.Counters.AverageBlockTimeTest do
test "without blocks duration is 0" do
assert AverageBlockTime.average_block_time() == Timex.Duration.parse!("PT0S")
end
test "with only one block, the duration is 0" do
now = Timex.now()
block = block(0, now, 0)
assert AverageBlockTime.average_block_time(block) == Timex.Duration.parse!("PT0S")
end
test "once there are two blocks, the duration is the average distance between them all" do
now = Timex.now()
block0 = block(0, now, 0)
block1 = block(1, now, 2)
block2 = block(2, now, 6)
AverageBlockTime.average_block_time(block0)
assert AverageBlockTime.average_block_time(block1) == Timex.Duration.parse!("PT2S")
assert AverageBlockTime.average_block_time(block2) == Timex.Duration.parse!("PT3S")
end
test "only the last 100 blocks are considered" do
now = Timex.now()
block0 = block(0, now, 0)
block1 = block(1, now, 2000)
AverageBlockTime.average_block_time(block0)
AverageBlockTime.average_block_time(block1)
for i <- 1..100 do
block = block(i + 1, now, 2000 + i)
AverageBlockTime.average_block_time(block)
end
assert AverageBlockTime.average_block_time() == Timex.Duration.parse!("PT1S")
end
end
end

@ -86,8 +86,7 @@ defmodule Indexer.AddressExtraction do
transactions: [
[
%{from: :block_number, to: :fetched_coin_balance_block_number},
%{from: :created_contract_address_hash, to: :hash},
%{from: :input, to: :contract_code}
%{from: :created_contract_address_hash, to: :hash}
],
[
%{from: :block_number, to: :fetched_coin_balance_block_number},

@ -41,10 +41,9 @@ defmodule Indexer.CoinBalance.OnDemandFetcherTest do
# we space these very far apart so that we know it will consider the 0th block stale (it calculates how far
# back we'd need to go to get 24 hours in the past)
block_0 = insert(:block, number: 0, timestamp: Timex.shift(now, hours: -50))
AverageBlockTime.average_block_time(block_0)
block_1 = insert(:block, number: 1, timestamp: now)
AverageBlockTime.average_block_time(block_1)
insert(:block, number: 0, timestamp: Timex.shift(now, hours: -50))
insert(:block, number: 1, timestamp: now)
AverageBlockTime.refresh()
stale_address = insert(:address, fetched_coin_balance: 1, fetched_coin_balance_block_number: 0)
current_address = insert(:address, fetched_coin_balance: 1, fetched_coin_balance_block_number: 1)
@ -89,10 +88,9 @@ defmodule Indexer.CoinBalance.OnDemandFetcherTest do
# we space these very far apart so that we know it will consider the 0th block stale (it calculates how far
# back we'd need to go to get 24 hours in the past)
block_0 = insert(:block, number: 0, timestamp: Timex.shift(now, hours: -50))
AverageBlockTime.average_block_time(block_0)
block_1 = insert(:block, number: 1, timestamp: now)
AverageBlockTime.average_block_time(block_1)
insert(:block, number: 0, timestamp: Timex.shift(now, hours: -50))
insert(:block, number: 1, timestamp: now)
AverageBlockTime.refresh()
:ok
end

Loading…
Cancel
Save