Merge branch 'master' into ab-fix-error-interpolation

pull/2299/head
Victor Baranov 5 years ago committed by GitHub
commit 6e27ad92de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      CHANGELOG.md
  2. 49
      apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex
  3. 2
      apps/block_scout_web/lib/block_scout_web/router.ex
  4. 2
      apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex
  5. 10
      apps/block_scout_web/lib/block_scout_web/templates/layout/_footer.html.eex
  6. 4
      apps/block_scout_web/lib/block_scout_web/views/api/rpc/address_view.ex
  7. 50
      apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs
  8. 3
      apps/explorer/config/config.exs
  9. 25
      apps/explorer/lib/explorer/chain.ex
  10. 18
      apps/explorer/test/explorer/chain_test.exs

@ -2,8 +2,12 @@
### Features ### Features
- [#2294](https://github.com/poanetwork/blockscout/pull/2294) - add healthy block period checking endpoint
### Fixes ### Fixes
- [#2299](https://github.com/poanetwork/blockscout/pull/2299) - fix interpolation in error message - [#2299](https://github.com/poanetwork/blockscout/pull/2299) - fix interpolation in error message
- [#2303](https://github.com/poanetwork/blockscout/pull/2303) - fix transaction csv download link
- [#2304](https://github.com/poanetwork/blockscout/pull/2304) - footer grid fix for md resolution
- [#2291](https://github.com/poanetwork/blockscout/pull/2291) - dashboard fix for md resolution, transactions load fix, block info row fix, addresses page issue, check mark issue - [#2291](https://github.com/poanetwork/blockscout/pull/2291) - dashboard fix for md resolution, transactions load fix, block info row fix, addresses page issue, check mark issue
### Chore ### Chore
@ -27,6 +31,7 @@
- [#2266](https://github.com/poanetwork/blockscout/pull/2266) - allow excluding uncles from average block time calculation - [#2266](https://github.com/poanetwork/blockscout/pull/2266) - allow excluding uncles from average block time calculation
### Fixes ### Fixes
- [#2290](https://github.com/poanetwork/blockscout/pull/2290) - Add eth_get_balance.json to AddressView's render
- [#2286](https://github.com/poanetwork/blockscout/pull/2286) - banner stats issues on sm resolutions, transactions title issue - [#2286](https://github.com/poanetwork/blockscout/pull/2286) - banner stats issues on sm resolutions, transactions title issue
- [#2284](https://github.com/poanetwork/blockscout/pull/2284) - add 404 status for not existing pages - [#2284](https://github.com/poanetwork/blockscout/pull/2284) - add 404 status for not existing pages
- [#2244](https://github.com/poanetwork/blockscout/pull/2244) - fix internal transactions failing to be indexed because of constraint - [#2244](https://github.com/poanetwork/blockscout/pull/2244) - fix internal transactions failing to be indexed because of constraint

@ -0,0 +1,49 @@
defmodule BlockScoutWeb.API.V1.HealthController do
use BlockScoutWeb, :controller
alias Explorer.Chain
def health(conn, _) do
with {:ok, number, timestamp} <- Chain.last_block_status() do
send_resp(conn, :ok, result(number, timestamp))
else
status -> send_resp(conn, :internal_server_error, error(status))
end
end
def result(number, timestamp) do
%{
"healthy" => true,
"data" => %{
"latest_block_number" => to_string(number),
"latest_block_inserted_at" => to_string(timestamp)
}
}
|> Jason.encode!()
end
def error({:error, :no_blocks}) do
%{
"healthy" => false,
"error_code" => 5002,
"error_title" => "no blocks in db",
"error_description" => "There are no blocks in the DB"
}
|> Jason.encode!()
end
def error({:error, number, timestamp}) do
%{
"healthy" => false,
"error_code" => 5001,
"error_title" => "blocks fetching is stuck",
"error_description" =>
"There are no new blocks in the DB for the last 5 mins. Check the healthiness of Ethereum archive node or the Blockscout DB instance",
"data" => %{
"latest_block_number" => to_string(number),
"latest_block_inserted_at" => to_string(timestamp)
}
}
|> Jason.encode!()
end
end

@ -23,6 +23,8 @@ defmodule BlockScoutWeb.Router do
get("/supply", SupplyController, :supply) get("/supply", SupplyController, :supply)
get("/health", HealthController, :health)
resources("/decompiled_smart_contract", DecompiledSmartContractController, only: [:create]) resources("/decompiled_smart_contract", DecompiledSmartContractController, only: [:create])
resources("/verified_smart_contracts", VerifiedSmartContractController, only: [:create]) resources("/verified_smart_contracts", VerifiedSmartContractController, only: [:create])
end end

@ -69,7 +69,7 @@
<div class="transaction-bottom-panel"> <div class="transaction-bottom-panel">
<div class="download-all-transactions"> <div class="download-all-transactions">
Download <a class="download-all-transactions-link" href=<%= address_transaction_path(@conn, :token_transfers_csv, %{"address_id" => to_string(@address.hash)}) %>><%= gettext("CSV") %></span> Download <a class="download-all-transactions-link" href=<%= address_transaction_path(@conn, :transactions_csv, %{"address_id" => to_string(@address.hash)}) %>><%= gettext("CSV") %></span>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="16"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="16">
<path fill="#333333" fill-rule="evenodd" d="M13 16H1c-.999 0-1-1-1-1V1s-.004-1 1-1h6l7 7v8s-.032 1-1 1zm-1-8c0-.99-1-1-1-1H8s-1 .001-1-1V3c0-.999-1-1-1-1H2v12h10V8z"/> <path fill="#333333" fill-rule="evenodd" d="M13 16H1c-.999 0-1-1-1-1V1s-.004-1 1-1h6l7 7v8s-.032 1-1 1zm-1-8c0-.99-1-1-1-1H8s-1 .001-1-1V3c0-.999-1-1-1-1H2v12h10V8z"/>
</svg> </svg>

@ -13,7 +13,7 @@
<% col_size = if Enum.empty?(other_explorers), do: 3, else: 2 %> <% col_size = if Enum.empty?(other_explorers), do: 3, else: 2 %>
<div class="row"> <div class="row">
<div class="col-md-3"> <div class="col-xs-12 col-lg-3">
<p class="footer-info-text"><%= gettext("Blockscout is a tool for inspecting and analyzing EVM based blockchains. Blockchain explorer for Ethereum Networks.") %></p> <p class="footer-info-text"><%= gettext("Blockscout is a tool for inspecting and analyzing EVM based blockchains. Blockchain explorer for Ethereum Networks.") %></p>
<div class="footer-social-icons"> <div class="footer-social-icons">
<a href="https://github.com/poanetwork/blockscout" rel="noreferrer" target="_blank" class="footer-social-icon" title='<%= gettext("Github") %>'> <a href="https://github.com/poanetwork/blockscout" rel="noreferrer" target="_blank" class="footer-social-icon" title='<%= gettext("Github") %>'>
@ -28,7 +28,7 @@
</div> </div>
</div> </div>
<div class="col-md-<%= col_size %> footer-list"> <div class="col-xs-12 col-md-4 col-lg-<%= col_size %> footer-list">
<h3>BlockScout</h3> <h3>BlockScout</h3>
<ul> <ul>
<li><a href="<%= issue_link(@conn) %>" rel="noreferrer" class="footer-link" target="_blank"><%= gettext("Submit an Issue") %></a></li> <li><a href="<%= issue_link(@conn) %>" rel="noreferrer" class="footer-link" target="_blank"><%= gettext("Submit an Issue") %></a></li>
@ -40,7 +40,7 @@
<% main_nets = main_nets(other_networks()) %> <% main_nets = main_nets(other_networks()) %>
<%= unless Enum.empty?(main_nets) do %> <%= unless Enum.empty?(main_nets) do %>
<div class="col-md-<%= col_size %> footer-list"> <div class="col-xs-12 col-md-4 col-lg-<%= col_size %> footer-list">
<h3><%= gettext("Main Networks") %></h3> <h3><%= gettext("Main Networks") %></h3>
<ul> <ul>
<%= for %{title: title, url: url} <- main_nets do %> <%= for %{title: title, url: url} <- main_nets do %>
@ -53,7 +53,7 @@
<% test_nets = test_nets(other_networks()) %> <% test_nets = test_nets(other_networks()) %>
<%= unless Enum.empty?(test_nets) do %> <%= unless Enum.empty?(test_nets) do %>
<div class="col-md-<%= col_size %> footer-list"> <div class="col-xs-12 col-md-4 col-lg-<%= col_size %> footer-list">
<h3><%= gettext("Test Networks") %></h3> <h3><%= gettext("Test Networks") %></h3>
<ul> <ul>
<%= for %{title: title, url: url} <- test_nets do %> <%= for %{title: title, url: url} <- test_nets do %>
@ -64,7 +64,7 @@
<% end %> <% end %>
<%= unless Enum.empty?(other_explorers) do %> <%= unless Enum.empty?(other_explorers) do %>
<div class="col-md-<%= col_size %> footer-list"> <div class="col-xs-12 col-md-4 col-lg-<%= col_size %> footer-list">
<h3><%= gettext("Other Explorers") %></h3> <h3><%= gettext("Other Explorers") %></h3>
<ul> <ul>
<%= for {name, url} <- other_explorers do %> <%= for {name, url} <- other_explorers do %>

@ -51,6 +51,10 @@ defmodule BlockScoutWeb.API.RPC.AddressView do
RPCView.render("show.json", data: data) RPCView.render("show.json", data: data)
end end
def render("eth_get_balance.json", %{balance: balance}) do
EthRPCView.render("show.json", %{result: balance, id: 0})
end
def render("eth_get_balance_error.json", %{error: message}) do def render("eth_get_balance_error.json", %{error: message}) do
EthRPCView.render("error.json", %{error: message, id: 0}) EthRPCView.render("error.json", %{error: message, id: 0})
end end

@ -0,0 +1,50 @@
defmodule BlockScoutWeb.API.V1.HealthControllerTest do
use BlockScoutWeb.ConnCase
describe "GET last_block_status/0" do
test "returns error when there are no blocks in db", %{conn: conn} do
request = get(conn, api_v1_health_path(conn, :health))
assert request.status == 500
assert request.resp_body ==
"{\"error_code\":5002,\"error_description\":\"There are no blocks in the DB\",\"error_title\":\"no blocks in db\",\"healthy\":false}"
end
test "returns error when last block is stale", %{conn: conn} do
insert(:block, consensus: true, timestamp: Timex.shift(DateTime.utc_now(), hours: -50))
request = get(conn, api_v1_health_path(conn, :health))
assert request.status == 500
assert %{
"healthy" => false,
"error_code" => 5001,
"error_title" => "blocks fetching is stuck",
"error_description" =>
"There are no new blocks in the DB for the last 5 mins. Check the healthiness of Ethereum archive node or the Blockscout DB instance",
"data" => %{
"latest_block_number" => _,
"latest_block_inserted_at" => _
}
} = Poison.decode!(request.resp_body)
end
test "returns ok when last block is not stale", %{conn: conn} do
insert(:block, consensus: true, timestamp: DateTime.utc_now())
request = get(conn, api_v1_health_path(conn, :health))
assert request.status == 200
assert %{
"healthy" => true,
"data" => %{
"latest_block_number" => _,
"latest_block_inserted_at" => _
}
} = Poison.decode!(request.resp_body)
end
end
end

@ -14,7 +14,8 @@ config :explorer,
System.get_env("ALLOWED_EVM_VERSIONS") || System.get_env("ALLOWED_EVM_VERSIONS") ||
"homestead,tangerineWhistle,spuriousDragon,byzantium,constantinople,petersburg", "homestead,tangerineWhistle,spuriousDragon,byzantium,constantinople,petersburg",
include_uncles_in_average_block_time: include_uncles_in_average_block_time:
if(System.get_env("UNCLES_IN_AVERAGE_BLOCK_TIME") == "false", do: false, else: true) if(System.get_env("UNCLES_IN_AVERAGE_BLOCK_TIME") == "false", do: false, else: true),
healthy_blocks_period: System.get_env("HEALTHY_BLOCKS_PERIOD") || :timer.minutes(5)
config :explorer, Explorer.Counters.AverageBlockTime, enabled: true config :explorer, Explorer.Counters.AverageBlockTime, enabled: true

@ -1769,6 +1769,31 @@ defmodule Explorer.Chain do
Repo.one!(query) Repo.one!(query)
end end
def last_block_status do
query =
from(block in Block,
select: {block.number, block.timestamp},
where: block.consensus == true,
order_by: [desc: block.number],
limit: 1
)
case Repo.one(query) do
nil ->
{:error, :no_blocks}
{number, timestamp} ->
now = DateTime.utc_now()
last_block_period = DateTime.diff(now, timestamp, :millisecond)
if last_block_period > Application.get_env(:explorer, :healthy_blocks_period) do
{:error, number, timestamp}
else
{:ok, number, timestamp}
end
end
end
@doc """ @doc """
Calculates the ranges of missing consensus blocks in `range`. Calculates the ranges of missing consensus blocks in `range`.

@ -50,6 +50,24 @@ defmodule Explorer.ChainTest do
end end
end end
describe "last_block_status/0" do
test "return no_blocks errors if db is empty" do
assert {:error, :no_blocks} = Chain.last_block_status()
end
test "returns {:ok, last_block_period} if block is in healthy period" do
insert(:block, consensus: true)
assert {:ok, _, _} = Chain.last_block_status()
end
test "return {:ok, last_block_period} if block is not in healthy period" do
insert(:block, consensus: true, timestamp: Timex.shift(DateTime.utc_now(), hours: -50))
assert {:error, _, _} = Chain.last_block_status()
end
end
describe "address_to_logs/2" do describe "address_to_logs/2" do
test "fetches logs" do test "fetches logs" do
address = insert(:address) address = insert(:address)

Loading…
Cancel
Save