diff --git a/CHANGELOG.md b/CHANGELOG.md index effe7e8100..8924e7eede 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ ### Features - [#2376](https://github.com/poanetwork/blockscout/pull/2376) - Split API and WebApp routes + +### Fixes + +### Chore +- [#2434](https://github.com/poanetwork/blockscout/pull/2434) - get rid of timex warnings + + +## 2.0.2-beta + +### Features - [#2412](https://github.com/poanetwork/blockscout/pull/2412) - dark theme - [#2399](https://github.com/poanetwork/blockscout/pull/2399) - decode verified smart contract's logs - [#2391](https://github.com/poanetwork/blockscout/pull/2391) - Controllers Improvements @@ -14,12 +24,15 @@ - [#2324](https://github.com/poanetwork/blockscout/pull/2324) - set timeout for loading message on the main page ### Fixes +- [#2421](https://github.com/poanetwork/blockscout/pull/2421) - Fix hiding of loader for txs on the main page +- [#2420](https://github.com/poanetwork/blockscout/pull/2420) - fetch data from cache in healthy endpoint - [#2416](https://github.com/poanetwork/blockscout/pull/2416) - Fix "page not found" handling in the router +- [#2413](https://github.com/poanetwork/blockscout/pull/2413) - remove outer tables for decoded data - [#2410](https://github.com/poanetwork/blockscout/pull/2410) - preload smart contract for logs decoding - [#2405](https://github.com/poanetwork/blockscout/pull/2405) - added templates for table loader and tile loader - [#2398](https://github.com/poanetwork/blockscout/pull/2398) - show only one decoded candidate -- [#2395](https://github.com/poanetwork/blockscout/pull/2395) - new block loading animation - [#2389](https://github.com/poanetwork/blockscout/pull/2389) - Reduce Lodash lib size (86% of lib methods are not used) +- [#2388](https://github.com/poanetwork/blockscout/pull/2388) - add create2 support to geth's js tracer - [#2387](https://github.com/poanetwork/blockscout/pull/2387) - fix not existing keys in transaction json rpc - [#2378](https://github.com/poanetwork/blockscout/pull/2378) - Page performance: exclude moment.js localization files except EN, remove unused css - [#2368](https://github.com/poanetwork/blockscout/pull/2368) - add two columns of smart contract info @@ -38,6 +51,7 @@ - [#2326](https://github.com/poanetwork/blockscout/pull/2326) - fix nested constructor arguments ### Chore +- [#2422](https://github.com/poanetwork/blockscout/pull/2422) - check if address_id is binary in token_transfers_csv endpoint - [#2418](https://github.com/poanetwork/blockscout/pull/2418) - Remove parentheses in market cap percentage - [#2401](https://github.com/poanetwork/blockscout/pull/2401) - add ENV vars to manage updating period of average block time and market history cache - [#2363](https://github.com/poanetwork/blockscout/pull/2363) - add parameters example for eth rpc diff --git a/apps/block_scout_web/assets/css/components/_tile.scss b/apps/block_scout_web/assets/css/components/_tile.scss index 501533ce05..e621e4fd6d 100644 --- a/apps/block_scout_web/assets/css/components/_tile.scss +++ b/apps/block_scout_web/assets/css/components/_tile.scss @@ -340,6 +340,9 @@ $tile-body-a-color: #5959d8 !default; padding-right: 6px; } } + .tile-type-block { + overflow: hidden; + } .row { @include media-breakpoint-down(lg) { margin-left: -6px; diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex index ba29c766c1..8f5e5d96d5 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex @@ -110,7 +110,7 @@ defmodule BlockScoutWeb.AddressTransactionController do end end - def token_transfers_csv(conn, %{"address_id" => address_hash_string}) do + def token_transfers_csv(conn, %{"address_id" => address_hash_string}) when is_binary(address_hash_string) do with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), {:ok, address} <- Chain.hash_to_address(address_hash) do address diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex index 957dc797be..1e65fa75ba 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex @@ -4,19 +4,22 @@ defmodule BlockScoutWeb.API.V1.HealthController do alias Explorer.Chain def health(conn, _) do - with {:ok, number, timestamp} <- Chain.last_block_status() do - send_resp(conn, :ok, result(number, timestamp)) + with {:ok, number, timestamp} <- Chain.last_db_block_status(), + {:ok, cache_number, cache_timestamp} <- Chain.last_cache_block_status() do + send_resp(conn, :ok, result(number, timestamp, cache_number, cache_timestamp)) else status -> send_resp(conn, :internal_server_error, error(status)) end end - def result(number, timestamp) do + def result(number, timestamp, cache_number, cache_timestamp) do %{ "healthy" => true, "data" => %{ "latest_block_number" => to_string(number), - "latest_block_inserted_at" => to_string(timestamp) + "latest_block_inserted_at" => to_string(timestamp), + "cache_latest_block_number" => to_string(cache_number), + "cache_latest_block_inserted_at" => to_string(cache_timestamp) } } |> Jason.encode!() diff --git a/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex index 729df59a3c..706d18ec47 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex @@ -1,172 +1,5 @@
-
-
- Block Validated, processing... -
-
-
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
-
-
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
-
-
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
-
-
-
-
<%= link( @block, class: "tile-title", diff --git a/apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex index 69d1f8b6ed..53b21cb3fa 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex @@ -117,7 +117,9 @@ <%= gettext "Something went wrong, click to retry." %> - <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex index f009eeb2b3..9e68d7e1bd 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex @@ -1,4 +1,5 @@ -" class="table thead-light table-bordered table-responsive transaction-info-table"> +
+
" class="table thead-light table-bordered"> @@ -7,49 +8,52 @@ -
<%= gettext "Method Id" %> 0x<%= @method_id %>Call <%= @text %>
+ + <%= unless Enum.empty?(@mapping) do %> - " class="table thead-light table-bordered table-responsive"> - - - - - - - <%= for {name, type, value} <- @mapping do %> +
+
<%= gettext "Name" %><%= gettext "Type" %><%= gettext "Data" %>
" class="table thead-light table-bordered"> + + + + + - - - - + - <% end %> -
<%= gettext "Name" %><%= gettext "Type" %><%= gettext "Data" %>
- <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %> - <% :error -> %> - <%= nil %> - <% copy_text -> %> - - - - - - <% end %> - <%= name %><%= type %> - <%= case BlockScoutWeb.ABIEncodedValueView.value_html(type, value) do %> - <% :error -> %> -
- <%= gettext "Error rendering value" %> -
- <% value -> %> -
<%= value %>
+ <%= for {name, type, value} <- @mapping do %> +
+ <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %> + <% :error -> %> + <%= nil %> + <% copy_text -> %> + + + + + <% end %> - -
+ + <%= name %> + <%= type %> + + <%= case BlockScoutWeb.ABIEncodedValueView.value_html(type, value) do %> + <% :error -> %> +
+ <%= gettext "Error rendering value" %> +
+ <% value -> %> +
<%= value %>
+ <% end %> + + + <% end %> + + <% end %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex index 5a52821601..ff3e46d42a 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex @@ -39,43 +39,45 @@ <%= text %> - " class="table thead-light table-bordered table-responsive"> - - - - - - - - <%= for {name, type, indexed?, value} <- mapping do %> +
+
<%= gettext "Name" %><%= gettext "Type" %><%= gettext "Indexed?" %><%= gettext "Data" %>
" class="table thead-light table-bordered"> - - - - - - - <% end %> -
- <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %> - <% :error -> %> - <%= nil %> - <% copy_text -> %> - - - - - - <% end %> - <%= name %><%= type %><%= indexed? %> -
<%= BlockScoutWeb.ABIEncodedValueView.value_html(type, value) %>
-
+ + <%= gettext "Name" %> + <%= gettext "Type" %> + <%= gettext "Indexed?" %> + <%= gettext "Data" %> + + <%= for {name, type, indexed?, value} <- mapping do %> + + + <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %> + <% :error -> %> + <%= nil %> + <% copy_text -> %> + + + + + + <% end %> + + <%= name %> + <%= type %> + <%= indexed? %> + +
<%= BlockScoutWeb.ABIEncodedValueView.value_html(type, value) %>
+ + + <% end %> + + <% _ -> %> <%= nil %> <% end %> diff --git a/apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex b/apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex index fe12f04302..46252f72ce 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex @@ -23,6 +23,7 @@ defmodule BlockScoutWeb.InternalTransactionView do def type(%InternalTransaction{type: :call, call_type: :delegatecall}), do: gettext("Delegate Call") def type(%InternalTransaction{type: :call, call_type: :staticcall}), do: gettext("Static Call") def type(%InternalTransaction{type: :create}), do: gettext("Create") + def type(%InternalTransaction{type: :create2}), do: gettext("Create2") def type(%InternalTransaction{type: :selfdestruct}), do: gettext("Self-Destruct") def type(%InternalTransaction{type: :reward}), do: gettext("Reward") end diff --git a/apps/block_scout_web/mix.exs b/apps/block_scout_web/mix.exs index e431d4ecf5..623aba2089 100644 --- a/apps/block_scout_web/mix.exs +++ b/apps/block_scout_web/mix.exs @@ -125,7 +125,7 @@ defmodule BlockScoutWeb.Mixfile do {:spandex_datadog, "~> 0.4.0"}, # `:spandex` tracing of `:phoenix` {:spandex_phoenix, "~> 0.3.1"}, - {:timex, "~> 3.4"}, + {:timex, "~> 3.6"}, {:wallaby, "~> 0.22", only: [:test], runtime: false}, # `:cowboy` `~> 2.0` and Phoenix 1.4 compatibility {:wobserver, "~> 0.2.0", github: "poanetwork/wobserver", branch: "support-https"}, diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index f3f57e5ac4..f2c8d12fea 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -34,7 +34,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/block/overview.html.eex:21 -#: lib/block_scout_web/templates/chain/_block.html.eex:178 +#: lib/block_scout_web/templates/chain/_block.html.eex:11 msgid "%{count} Transactions" msgstr "" @@ -328,15 +328,6 @@ msgstr "" msgid "Curl" msgstr "" -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:49 -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:114 -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:18 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:48 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:113 -msgid "Data" -msgstr "" - #, elixir-format #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:53 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:188 @@ -523,7 +514,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/block/_tile.html.eex:38 #: lib/block_scout_web/templates/block/overview.html.eex:121 -#: lib/block_scout_web/templates/chain/_block.html.eex:182 +#: lib/block_scout_web/templates/chain/_block.html.eex:15 msgid "Miner" msgstr "" @@ -558,8 +549,8 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_logs/_logs.html.eex:46 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:52 -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:16 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:45 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:19 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:46 msgid "Name" msgstr "" @@ -827,12 +818,6 @@ msgstr "" msgid "Top Accounts - %{subnetwork} Explorer" msgstr "" -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:84 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:83 -msgid "Topics" -msgstr "" - #, elixir-format #: lib/block_scout_web/templates/block/overview.html.eex:67 msgid "Total Difficulty" @@ -1041,14 +1026,7 @@ msgid "Delegate Call" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/block/_tile.html.eex:47 -#: lib/block_scout_web/templates/chain/_block.html.eex:190 #: lib/block_scout_web/views/internal_transaction_view.ex:27 -msgid "Reward" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/views/internal_transaction_view.ex:26 msgid "Self-Destruct" msgstr "" @@ -1136,20 +1114,7 @@ msgid "Decoded" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:48 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47 -msgid "Indexed?" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:47 -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:17 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:46 -msgid "Type" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:3 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:4 msgid "Method Id" msgstr "" @@ -1160,12 +1125,8 @@ msgid "To see decoded input data, the contract must be verified." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:1 -msgid "Transaction Info" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:13 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:2 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:16 msgid "Transaction Inputs" msgstr "" @@ -1189,29 +1150,10 @@ msgid "Failed to decode input data." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:46 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:49 msgid "Error rendering value" msgstr "" -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:59 -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:28 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:58 -msgid "Copy Value" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:29 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:29 -msgid "Failed to decode log data." -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:43 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:42 -msgid "Log Data" -msgstr "" - #, elixir-format #: lib/block_scout_web/templates/address_coin_balance/index.html.eex:34 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:61 @@ -1809,3 +1751,62 @@ msgstr "" #: lib/block_scout_web/templates/address_contract/index.html.eex:53 msgid "Constructor Arguments" msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:59 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:31 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:59 +msgid "Copy Value" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/views/internal_transaction_view.ex:26 +msgid "Create2" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:49 +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:114 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:21 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:49 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:115 +msgid "Data" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:29 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:29 +msgid "Failed to decode log data." +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:48 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:48 +msgid "Indexed?" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:43 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:43 +msgid "Log Data" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/block/_tile.html.eex:47 +#: lib/block_scout_web/templates/chain/_block.html.eex:23 +#: lib/block_scout_web/views/internal_transaction_view.ex:28 +msgid "Reward" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:84 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:85 +msgid "Topics" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:47 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:20 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47 +msgid "Type" +msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index b721c4642e..cfc8225e50 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -34,7 +34,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/block/overview.html.eex:21 -#: lib/block_scout_web/templates/chain/_block.html.eex:178 +#: lib/block_scout_web/templates/chain/_block.html.eex:11 msgid "%{count} Transactions" msgstr "" @@ -328,15 +328,6 @@ msgstr "" msgid "Curl" msgstr "" -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:49 -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:114 -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:18 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:48 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:113 -msgid "Data" -msgstr "" - #, elixir-format #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:53 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:188 @@ -523,7 +514,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/block/_tile.html.eex:38 #: lib/block_scout_web/templates/block/overview.html.eex:121 -#: lib/block_scout_web/templates/chain/_block.html.eex:182 +#: lib/block_scout_web/templates/chain/_block.html.eex:15 msgid "Miner" msgstr "" @@ -558,8 +549,8 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_logs/_logs.html.eex:46 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:52 -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:16 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:45 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:19 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:46 msgid "Name" msgstr "" @@ -827,12 +818,6 @@ msgstr "" msgid "Top Accounts - %{subnetwork} Explorer" msgstr "" -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:84 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:83 -msgid "Topics" -msgstr "" - #, elixir-format #: lib/block_scout_web/templates/block/overview.html.eex:67 msgid "Total Difficulty" @@ -1041,14 +1026,7 @@ msgid "Delegate Call" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/block/_tile.html.eex:47 -#: lib/block_scout_web/templates/chain/_block.html.eex:190 #: lib/block_scout_web/views/internal_transaction_view.ex:27 -msgid "Reward" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/views/internal_transaction_view.ex:26 msgid "Self-Destruct" msgstr "" @@ -1136,20 +1114,7 @@ msgid "Decoded" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:48 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47 -msgid "Indexed?" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:47 -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:17 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:46 -msgid "Type" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:3 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:4 msgid "Method Id" msgstr "" @@ -1160,12 +1125,8 @@ msgid "To see decoded input data, the contract must be verified." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:1 -msgid "Transaction Info" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:13 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:2 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:16 msgid "Transaction Inputs" msgstr "" @@ -1189,28 +1150,10 @@ msgid "Failed to decode input data." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:46 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:49 msgid "Error rendering value" msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:59 -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:28 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:58 -msgid "Copy Value" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:29 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:29 -msgid "Failed to decode log data." -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:43 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:42 -msgid "Log Data" -msgstr "" +"" #, elixir-format #: lib/block_scout_web/templates/address_coin_balance/index.html.eex:34 @@ -1809,3 +1752,62 @@ msgstr "" #: lib/block_scout_web/templates/address_contract/index.html.eex:53 msgid "Constructor Arguments" msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:59 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:31 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:59 +msgid "Copy Value" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/views/internal_transaction_view.ex:26 +msgid "Create2" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:49 +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:114 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:21 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:49 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:115 +msgid "Data" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:29 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:29 +msgid "Failed to decode log data." +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:48 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:48 +msgid "Indexed?" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:43 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:43 +msgid "Log Data" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/block/_tile.html.eex:47 +#: lib/block_scout_web/templates/chain/_block.html.eex:23 +#: lib/block_scout_web/views/internal_transaction_view.ex:28 +msgid "Reward" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:84 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:85 +msgid "Topics" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:47 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:20 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47 +msgid "Type" +msgstr "" diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs index 41735f685a..19631ff746 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs @@ -1,6 +1,15 @@ defmodule BlockScoutWeb.API.V1.HealthControllerTest do use BlockScoutWeb.ConnCase + alias Explorer.{Chain, PagingOptions} + + setup do + Supervisor.terminate_child(Explorer.Supervisor, {ConCache, Explorer.Chain.Cache.Blocks.cache_name()}) + Supervisor.restart_child(Explorer.Supervisor, {ConCache, Explorer.Chain.Cache.Blocks.cache_name()}) + + :ok + end + 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)) @@ -32,19 +41,50 @@ defmodule BlockScoutWeb.API.V1.HealthControllerTest do end test "returns ok when last block is not stale", %{conn: conn} do - insert(:block, consensus: true, timestamp: DateTime.utc_now()) + block1 = insert(:block, consensus: true, timestamp: DateTime.utc_now(), number: 2) + insert(:block, consensus: true, timestamp: DateTime.utc_now(), number: 1) request = get(conn, api_v1_health_path(conn, :health)) assert request.status == 200 + result = Poison.decode!(request.resp_body) + + assert result["healthy"] == true + assert %{ - "healthy" => true, - "data" => %{ - "latest_block_number" => _, - "latest_block_inserted_at" => _ - } - } = Poison.decode!(request.resp_body) + "latest_block_number" => to_string(block1.number), + "latest_block_inserted_at" => to_string(block1.timestamp), + "cache_latest_block_number" => to_string(block1.number), + "cache_latest_block_inserted_at" => to_string(block1.timestamp) + } == result["data"] end end + + test "return error when cache is stale", %{conn: conn} do + stale_block = insert(:block, consensus: true, timestamp: Timex.shift(DateTime.utc_now(), hours: -50), number: 3) + state_block_hash = stale_block.hash + + assert [%{hash: ^state_block_hash}] = Chain.list_blocks(paging_options: %PagingOptions{page_size: 1}) + + insert(:block, consensus: true, timestamp: DateTime.utc_now(), number: 1) + + assert [%{hash: ^state_block_hash}] = Chain.list_blocks(paging_options: %PagingOptions{page_size: 1}) + + 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 end diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex index 1555ea6c8f..c83b157324 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex @@ -426,13 +426,14 @@ defmodule EthereumJSONRPC.Geth.Call do "transactionHash" => transaction_hash, "index" => index, "traceAddress" => trace_address, - "type" => "create" = type, + "type" => type, "from" => from_address_hash, "error" => error, "gas" => gas, "init" => init, "value" => value - }) do + }) + when type in ~w(create create2) do %{ block_number: block_number, transaction_index: transaction_index, @@ -454,7 +455,7 @@ defmodule EthereumJSONRPC.Geth.Call do "transactionHash" => transaction_hash, "index" => index, "traceAddress" => trace_address, - "type" => "create", + "type" => type, "from" => from_address_hash, "createdContractAddressHash" => created_contract_address_hash, "gas" => gas, @@ -462,14 +463,15 @@ defmodule EthereumJSONRPC.Geth.Call do "init" => init, "createdContractCode" => created_contract_code, "value" => value - }) do + }) + when type in ~w(create create2) do %{ block_number: block_number, transaction_index: transaction_index, transaction_hash: transaction_hash, index: index, trace_address: trace_address, - type: "create", + type: type, from_address_hash: from_address_hash, gas: gas, gas_used: gas_used, diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex index 6545250b4a..cbc43fa71d 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex @@ -113,6 +113,7 @@ defmodule EthereumJSONRPC.Geth.Tracer do end defp op(%{"op" => "CREATE"} = log, ctx), do: create_op(log, ctx) + defp op(%{"op" => "CREATE2"} = log, ctx), do: create_op(log, ctx, "create2") defp op(%{"op" => "SELFDESTRUCT"} = log, ctx), do: self_destruct_op(log, ctx) defp op(%{"op" => "CALL"} = log, ctx), do: call_op(log, "call", ctx) defp op(%{"op" => "CALLCODE"} = log, ctx), do: call_op(log, "callcode", ctx) @@ -155,7 +156,8 @@ defmodule EthereumJSONRPC.Geth.Tracer do defp create_op( %{"stack" => log_stack, "memory" => log_memory}, - %{depth: stack_depth, stack: stack, trace_address: trace_address, calls: calls} = ctx + %{depth: stack_depth, stack: stack, trace_address: trace_address, calls: calls} = ctx, + type \\ "create" ) do [value, input_offset, input_length | _] = Enum.reverse(log_stack) @@ -165,7 +167,7 @@ defmodule EthereumJSONRPC.Geth.Tracer do |> String.slice(quantity_to_integer("0x" <> input_offset) * 2, quantity_to_integer("0x" <> input_length) * 2) call = %{ - "type" => "create", + "type" => type, "from" => nil, "traceAddress" => Enum.reverse(trace_address), "init" => "0x" <> init, diff --git a/apps/ethereum_jsonrpc/mix.exs b/apps/ethereum_jsonrpc/mix.exs index 7c2299c4a8..58dcff8fd5 100644 --- a/apps/ethereum_jsonrpc/mix.exs +++ b/apps/ethereum_jsonrpc/mix.exs @@ -82,7 +82,7 @@ defmodule EthereumJsonrpc.MixProject do # `:spandex` integration with Datadog {:spandex_datadog, "~> 0.4.0"}, # Convert unix timestamps in JSONRPC to DateTimes - {:timex, "~> 3.4"}, + {:timex, "~> 3.6"}, # Encode/decode function names and arguments {:ex_abi, "~> 0.1.18"}, # `:verify_fun` for `Socket.Web.connect` diff --git a/apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js b/apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js index 15db7d8ff9..5c3c98f871 100644 --- a/apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js +++ b/apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js @@ -91,6 +91,9 @@ case 'CREATE': this.createOp(log); break; + case 'CREATE2': + this.create2Op(log); + break; case 'SELFDESTRUCT': this.selfDestructOp(log, db); break; @@ -127,7 +130,7 @@ const ret = log.stack.peek(0); if (!ret.equals(0)) { - if (call.type === 'create') { + if (call.type === 'create' || call.type === 'create2') { call.createdContractAddressHash = toHex(toAddress(ret.toString(16))); call.createdContractCode = toHex(db.getCode(toAddress(ret.toString(16)))); } else { @@ -162,6 +165,21 @@ this.callStack.push(call); }, + create2Op(log) { + const inputOffset = log.stack.peek(1).valueOf(); + const inputLength = log.stack.peek(2).valueOf(); + const inputEnd = inputOffset + inputLength; + const stackValue = log.stack.peek(0); + + const call = { + type: 'create2', + from: toHex(log.contract.getAddress()), + init: toHex(log.memory.slice(inputOffset, inputEnd)), + valueBigInt: bigInt(stackValue.toString(10)) + }; + this.callStack.push(call); + }, + selfDestructOp(log, db) { const contractAddress = log.contract.getAddress(); @@ -243,6 +261,9 @@ case 'CREATE': result = this.ctxToCreate(ctx, db); break; + case 'CREATE2': + result = this.ctxToCreate2(ctx, db); + break; } return result; @@ -292,6 +313,22 @@ return result; }, + ctxToCreate2(ctx, db) { + const result = { + type: 'create2', + from: toHex(ctx.from), + init: toHex(ctx.input), + valueBigInt: bigInt(ctx.value.toString(10)), + gasBigInt: bigInt(ctx.gas), + gasUsedBigInt: bigInt(ctx.gasUsed) + }; + + this.putBottomChildCalls(result); + this.putErrorOrCreatedContract(result, ctx, db); + + return result; + }, + putBottomChildCalls(result) { const bottomCall = this.bottomCall(); const bottomChildCalls = bottomCall.calls; @@ -422,4 +459,3 @@ call.gasUsed = '0x' + gasUsedBigInt.toString(16); } } - diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 46eda15b62..c2e480957d 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -1818,7 +1818,7 @@ defmodule Explorer.Chain do Repo.one!(query) end - def last_block_status do + def last_db_block_status do query = from(block in Block, select: {block.number, block.timestamp}, @@ -1827,22 +1827,39 @@ defmodule Explorer.Chain do limit: 1 ) - case Repo.one(query) do - nil -> - {:error, :no_blocks} + query + |> Repo.one() + |> block_status() + end - {number, timestamp} -> - now = DateTime.utc_now() - last_block_period = DateTime.diff(now, timestamp, :millisecond) + def last_cache_block_status do + [ + paging_options: %PagingOptions{page_size: 1} + ] + |> list_blocks() + |> List.last() + |> case do + %{timestamp: timestamp, number: number} -> + block_status({number, timestamp}) - if last_block_period > Application.get_env(:explorer, :healthy_blocks_period) do - {:error, number, timestamp} - else - {:ok, number, timestamp} - end + _ -> + block_status(nil) end end + defp block_status({number, timestamp}) do + 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 + + defp block_status(nil), do: {:error, :no_blocks} + @doc """ Calculates the ranges of missing consensus blocks in `range`. diff --git a/apps/explorer/lib/explorer/chain/internal_transaction.ex b/apps/explorer/lib/explorer/chain/internal_transaction.ex index 1231677a57..77f7d15da2 100644 --- a/apps/explorer/lib/explorer/chain/internal_transaction.ex +++ b/apps/explorer/lib/explorer/chain/internal_transaction.ex @@ -392,7 +392,7 @@ defmodule Explorer.Chain.InternalTransaction do @create_required_fields ~w(from_address_hash gas index init trace_address transaction_hash value)a @create_allowed_fields @create_optional_fields ++ @create_required_fields - defp type_changeset(changeset, attrs, :create) do + defp type_changeset(changeset, attrs, type) when type in [:create, :create2] do changeset |> cast(attrs, @create_allowed_fields) |> validate_required(@create_required_fields) @@ -537,7 +537,7 @@ defmodule Explorer.Chain.InternalTransaction do |> put_raw_call_error_or_result(transaction) end - defp internal_transaction_to_raw(%{type: :create} = transaction) do + defp internal_transaction_to_raw(%{type: type} = transaction) when type in [:create, :create2] do %{ from_address_hash: from_address_hash, gas: gas, @@ -549,7 +549,7 @@ defmodule Explorer.Chain.InternalTransaction do action = %{"from" => from_address_hash, "gas" => gas, "init" => init, "value" => value} %{ - "type" => "create", + "type" => Atom.to_string(type), "action" => Action.to_raw(action), "traceAddress" => trace_address } diff --git a/apps/explorer/lib/explorer/chain/internal_transaction/type.ex b/apps/explorer/lib/explorer/chain/internal_transaction/type.ex index 4133dcf45f..0a13587afe 100644 --- a/apps/explorer/lib/explorer/chain/internal_transaction/type.ex +++ b/apps/explorer/lib/explorer/chain/internal_transaction/type.ex @@ -11,7 +11,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do * `:reward` * `:selfdestruct` """ - @type t :: :call | :create | :reward | :selfdestruct + @type t :: :call | :create | :create2 | :reward | :selfdestruct @doc """ Casts `term` to `t:t/0` @@ -22,6 +22,8 @@ defmodule Explorer.Chain.InternalTransaction.Type do {:ok, :call} iex> Explorer.Chain.InternalTransaction.Type.cast(:create) {:ok, :create} + iex> Explorer.Chain.InternalTransaction.Type.cast(:create2) + {:ok, :create2} iex> Explorer.Chain.InternalTransaction.Type.cast(:reward) {:ok, :reward} iex> Explorer.Chain.InternalTransaction.Type.cast(:selfdestruct) @@ -33,6 +35,8 @@ defmodule Explorer.Chain.InternalTransaction.Type do {:ok, :call} iex> Explorer.Chain.InternalTransaction.Type.cast("create") {:ok, :create} + iex> Explorer.Chain.InternalTransaction.Type.cast("create2") + {:ok, :create2} iex> Explorer.Chain.InternalTransaction.Type.cast("reward") {:ok, :reward} iex> Explorer.Chain.InternalTransaction.Type.cast("selfdestruct") @@ -53,9 +57,10 @@ defmodule Explorer.Chain.InternalTransaction.Type do """ @impl Ecto.Type @spec cast(term()) :: {:ok, t()} | :error - def cast(t) when t in ~w(call create selfdestruct reward)a, do: {:ok, t} + def cast(t) when t in ~w(call create create2 selfdestruct reward)a, do: {:ok, t} def cast("call"), do: {:ok, :call} def cast("create"), do: {:ok, :create} + def cast("create2"), do: {:ok, :create2} def cast("reward"), do: {:ok, :reward} def cast("selfdestruct"), do: {:ok, :selfdestruct} def cast(_), do: :error @@ -67,6 +72,8 @@ defmodule Explorer.Chain.InternalTransaction.Type do {:ok, "call"} iex> Explorer.Chain.InternalTransaction.Type.dump(:create) {:ok, "create"} + iex> Explorer.Chain.InternalTransaction.Type.dump(:create2) + {:ok, "create2"} iex> Explorer.Chain.InternalTransaction.Type.dump(:reward) {:ok, "reward"} iex> Explorer.Chain.InternalTransaction.Type.dump(:selfdestruct) @@ -87,6 +94,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do @spec dump(term()) :: {:ok, String.t()} | :error def dump(:call), do: {:ok, "call"} def dump(:create), do: {:ok, "create"} + def dump(:create2), do: {:ok, "create2"} def dump(:reward), do: {:ok, "reward"} def dump(:selfdestruct), do: {:ok, "selfdestruct"} def dump(_), do: :error @@ -98,6 +106,8 @@ defmodule Explorer.Chain.InternalTransaction.Type do {:ok, :call} iex> Explorer.Chain.InternalTransaction.Type.load("create") {:ok, :create} + iex> Explorer.Chain.InternalTransaction.Type.load("create2") + {:ok, :create2} iex> Explorer.Chain.InternalTransaction.Type.load("reward") {:ok, :reward} iex> Explorer.Chain.InternalTransaction.Type.load("selfdestruct") @@ -118,6 +128,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do @spec load(term()) :: {:ok, t()} | :error def load("call"), do: {:ok, :call} def load("create"), do: {:ok, :create} + def load("create2"), do: {:ok, :create2} def load("reward"), do: {:ok, :reward} def load("selfdestruct"), do: {:ok, :selfdestruct} # deprecated diff --git a/apps/explorer/mix.exs b/apps/explorer/mix.exs index 4956363cc4..b9b887f838 100644 --- a/apps/explorer/mix.exs +++ b/apps/explorer/mix.exs @@ -117,7 +117,7 @@ defmodule Explorer.Mixfile do # Attach `:prometheus_ecto` to `:ecto` {:telemetry, "~> 0.3.0"}, # `Timex.Duration` for `Explorer.Counters.AverageBlockTime.average_block_time/0` - {:timex, "~> 3.4"}, + {:timex, "~> 3.6"}, {:con_cache, "~> 0.13"} ] end diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index 5ee506982b..234252dbe4 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -50,21 +50,35 @@ defmodule Explorer.ChainTest do end end - describe "last_block_status/0" do + describe "last_db_block_status/0" do test "return no_blocks errors if db is empty" do - assert {:error, :no_blocks} = Chain.last_block_status() + assert {:error, :no_blocks} = Chain.last_db_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() + assert {:ok, _, _} = Chain.last_db_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() + assert {:error, _, _} = Chain.last_db_block_status() + end + end + + describe "last_cache_block_status/0" do + test "returns success if cache is not stale" do + insert(:block, consensus: true) + + assert {:ok, _, _} = Chain.last_cache_block_status() + end + + test "return error if cache is stale" do + insert(:block, consensus: true, timestamp: Timex.shift(DateTime.utc_now(), hours: -50)) + + assert {:error, _, _} = Chain.last_cache_block_status() end end