From 57808d6b238acdbfbbc80581d50b65ca407b74ec Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 10 Jan 2019 15:55:15 -0600 Subject: [PATCH] Separate usage of max consensus block number and block height The block height should be used when calculating confirmations while the max consensus block number when a block number is needed and you want to tell if the chain is empty or only the genesis block is available. The block height is 0 if there are no blocks or if there is only the genesis block. --- .../controllers/api/rpc/logs_controller.ex | 2 +- .../api/rpc/transaction_controller.ex | 11 +- .../block_transaction_controller.ex | 8 +- ...saction_internal_transaction_controller.ex | 11 +- .../controllers/transaction_log_controller.ex | 9 +- .../transaction_token_transfer_controller.ex | 11 +- .../templates/transaction/overview.html.eex | 2 +- .../views/api/rpc/transaction_view.ex | 8 +- .../block_scout_web/views/transaction_view.ex | 8 +- apps/block_scout_web/priv/gettext/default.pot | 28 ++--- .../priv/gettext/en/LC_MESSAGES/default.po | 28 ++--- .../api/rpc/address_controller_test.exs | 4 +- .../api/rpc/logs_controller_test.exs | 6 +- .../api/rpc/transaction_controller_test.exs | 2 + .../views/transaction_view_test.exs | 2 +- apps/explorer/lib/explorer/chain.ex | 110 +++++++++++++++--- .../chain/supply/proof_of_authority.ex | 12 +- apps/explorer/lib/explorer/etherscan.ex | 12 +- apps/explorer/test/explorer/chain_test.exs | 18 +-- .../explorer/test/explorer/etherscan_test.exs | 8 +- apps/indexer/lib/indexer.ex | 50 -------- 21 files changed, 166 insertions(+), 184 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/logs_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/logs_controller.ex index 8f7257bc8e..388b99df25 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/logs_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/logs_controller.ex @@ -183,7 +183,7 @@ defmodule BlockScoutWeb.API.RPC.LogsController do defp to_block_number(params, param_key) do case params[param_key] do "latest" -> - Chain.consensus_block_number(:max) + Chain.max_consensus_block_number() _ -> to_integer(params, param_key) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex index cfbf7cbede..edb86f753e 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex @@ -7,10 +7,8 @@ defmodule BlockScoutWeb.API.RPC.TransactionController do with {:txhash_param, {:ok, txhash_param}} <- fetch_txhash(params), {:format, {:ok, transaction_hash}} <- to_transaction_hash(txhash_param), {:transaction, {:ok, transaction}} <- transaction_from_hash(transaction_hash) do - max_block_number = max_block_number() - logs = Chain.transaction_to_logs(transaction) - render(conn, :gettxinfo, %{transaction: transaction, max_block_number: max_block_number, logs: logs}) + render(conn, :gettxinfo, %{transaction: transaction, block_height: Chain.block_height(), logs: logs}) else {:transaction, :error} -> render(conn, :error, error: "Transaction not found") @@ -81,11 +79,4 @@ defmodule BlockScoutWeb.API.RPC.TransactionController do _ -> "" end end - - defp max_block_number do - case Chain.consensus_block_number(:max) do - {:ok, number} -> number - {:error, :not_found} -> 0 - end - end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex index bf66ff33f4..1e4fe3bc53 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex @@ -82,11 +82,7 @@ defmodule BlockScoutWeb.BlockTransactionController do defp block_above_tip?("0x" <> _), do: nil defp block_above_tip?(block_hash_or_number) when is_binary(block_hash_or_number) do - with {:ok, max_block_number} <- Chain.consensus_block_number(:max) do - {block_number, _} = Integer.parse(block_hash_or_number) - block_number > max_block_number - else - _ -> true - end + {block_number, ""} = Integer.parse(block_hash_or_number) + block_number > Chain.block_height() end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex index c118cb5124..af011e3745 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex @@ -37,14 +37,12 @@ defmodule BlockScoutWeb.TransactionInternalTransactionController do {internal_transactions, next_page} = split_list_by_page(internal_transactions_plus_one) - max_block_number = max_block_number() - render( conn, "index.html", exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), internal_transactions: internal_transactions, - max_block_number: max_block_number, + block_height: Chain.block_height(), show_token_transfers: Chain.transaction_has_token_transfers?(hash), next_page_params: next_page_params(next_page, internal_transactions, params), transaction: transaction @@ -63,11 +61,4 @@ defmodule BlockScoutWeb.TransactionInternalTransactionController do |> render("not_found.html", transaction_hash: hash_string) end end - - defp max_block_number do - case Chain.consensus_block_number(:max) do - {:ok, number} -> number - {:error, :not_found} -> 0 - end - end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex index 66f467210b..8b4e3877e0 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex @@ -39,7 +39,7 @@ defmodule BlockScoutWeb.TransactionLogController do conn, "index.html", logs: logs, - max_block_number: max_block_number(), + block_height: Chain.block_height(), show_token_transfers: Chain.transaction_has_token_transfers?(transaction_hash), next_page_params: next_page_params(next_page, logs, params), transaction: transaction, @@ -59,11 +59,4 @@ defmodule BlockScoutWeb.TransactionLogController do |> render("not_found.html", transaction_hash: transaction_hash_string) end end - - defp max_block_number do - case Chain.consensus_block_number(:max) do - {:ok, number} -> number - {:error, :not_found} -> 0 - end - end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex index fe669b8da6..baa36f1a2f 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex @@ -37,13 +37,11 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do {token_transfers, next_page} = split_list_by_page(token_transfers_plus_one) - max_block_number = max_block_number() - render( conn, "index.html", exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), - max_block_number: max_block_number, + block_height: Chain.block_height(), next_page_params: next_page_params(next_page, token_transfers, params), token_transfers: token_transfers, show_token_transfers: true, @@ -63,11 +61,4 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do |> render("not_found.html", transaction_hash: hash_string) end end - - defp max_block_number do - case Chain.consensus_block_number(:max) do - {:ok, number} -> number - {:error, :not_found} -> 0 - end - end end diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex index c6a154f3fd..94d39e9d34 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex @@ -59,7 +59,7 @@
<%= gettext "Block Confirmations" %>
- <%= confirmations(@transaction, max_block_number: @max_block_number) %> + <%= confirmations(@transaction, block_height: @block_height) %>
diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/transaction_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/transaction_view.ex index 73dae614e6..70211907c6 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/transaction_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/transaction_view.ex @@ -3,8 +3,8 @@ defmodule BlockScoutWeb.API.RPC.TransactionView do alias BlockScoutWeb.API.RPC.RPCView - def render("gettxinfo.json", %{transaction: transaction, max_block_number: max_block_number, logs: logs}) do - data = prepare_transaction(transaction, max_block_number, logs) + def render("gettxinfo.json", %{transaction: transaction, block_height: block_height, logs: logs}) do + data = prepare_transaction(transaction, block_height, logs) RPCView.render("show.json", data: data) end @@ -50,12 +50,12 @@ defmodule BlockScoutWeb.API.RPC.TransactionView do } end - defp prepare_transaction(transaction, max_block_number, logs) do + defp prepare_transaction(transaction, block_height, logs) do %{ "hash" => "#{transaction.hash}", "timeStamp" => "#{DateTime.to_unix(transaction.block.timestamp)}", "blockNumber" => "#{transaction.block_number}", - "confirmations" => "#{max_block_number - transaction.block_number}", + "confirmations" => "#{block_height - transaction.block_number}", "success" => if(transaction.status == :ok, do: true, else: false), "from" => "#{transaction.from_address_hash}", "to" => "#{transaction.to_address_hash}", diff --git a/apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex b/apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex index c749c7fee1..f943e2b760 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex @@ -31,8 +31,12 @@ defmodule BlockScoutWeb.TransactionView do def confirmations(%Transaction{block: block}, named_arguments) when is_list(named_arguments) do case block do - nil -> 0 - _ -> block |> Chain.confirmations(named_arguments) |> Cldr.Number.to_string!(format: "#,###") + nil -> + 0 + + %Block{consensus: true} -> + {:ok, confirmations} = Chain.confirmations(block, named_arguments) + Cldr.Number.to_string!(confirmations, format: "#,###") end end diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index 1ff3fb39f4..e5a36abd74 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -49,7 +49,7 @@ msgid "%{subnetwork} Explorer - BlockScout" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:67 +#: lib/block_scout_web/views/transaction_view.ex:71 msgid "(Awaiting internal transactions for status)" msgstr "" @@ -278,12 +278,12 @@ msgid "Contract Address Pending" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:144 +#: lib/block_scout_web/views/transaction_view.ex:148 msgid "Contract Call" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:143 +#: lib/block_scout_web/views/transaction_view.ex:147 msgid "Contract Creation" msgstr "" @@ -389,12 +389,12 @@ msgid "Error trying to fetch balances." msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:71 +#: lib/block_scout_web/views/transaction_view.ex:75 msgid "Error: %{reason}" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:69 +#: lib/block_scout_web/views/transaction_view.ex:73 msgid "Error: (Awaiting internal transactions for reason)" msgstr "" @@ -507,7 +507,7 @@ msgstr "" #: lib/block_scout_web/templates/transaction/_tabs.html.eex:43 #: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:10 #: lib/block_scout_web/views/address_view.ex:254 -#: lib/block_scout_web/views/transaction_view.ex:197 +#: lib/block_scout_web/views/transaction_view.ex:201 msgid "Internal Transactions" msgstr "" @@ -533,7 +533,7 @@ msgstr "" #: lib/block_scout_web/templates/transaction/_tabs.html.eex:21 #: lib/block_scout_web/templates/transaction/_tabs.html.eex:48 #: lib/block_scout_web/templates/transaction_log/index.html.eex:10 -#: lib/block_scout_web/views/transaction_view.ex:198 +#: lib/block_scout_web/views/transaction_view.ex:202 msgid "Logs" msgstr "" @@ -545,7 +545,7 @@ msgid "Market Cap" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:58 +#: lib/block_scout_web/views/transaction_view.ex:62 msgid "Max of" msgstr "" @@ -684,8 +684,8 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/layout/_topnav.html.eex:44 #: lib/block_scout_web/templates/transaction/overview.html.eex:55 -#: lib/block_scout_web/views/transaction_view.ex:66 -#: lib/block_scout_web/views/transaction_view.ex:100 +#: lib/block_scout_web/views/transaction_view.ex:70 +#: lib/block_scout_web/views/transaction_view.ex:104 msgid "Pending" msgstr "" @@ -790,7 +790,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/transaction/_emission_reward_tile.html.eex:8 -#: lib/block_scout_web/views/transaction_view.ex:68 +#: lib/block_scout_web/views/transaction_view.ex:72 msgid "Success" msgstr "" @@ -901,7 +901,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:4 #: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:4 -#: lib/block_scout_web/views/transaction_view.ex:142 +#: lib/block_scout_web/views/transaction_view.ex:146 msgid "Token Transfer" msgstr "" @@ -913,7 +913,7 @@ msgstr "" #: lib/block_scout_web/templates/transaction/_tabs.html.eex:36 #: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:10 #: lib/block_scout_web/views/tokens/overview_view.ex:35 -#: lib/block_scout_web/views/transaction_view.ex:196 +#: lib/block_scout_web/views/transaction_view.ex:200 msgid "Token Transfers" msgstr "" @@ -954,7 +954,7 @@ msgid "Total transactions" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:145 +#: lib/block_scout_web/views/transaction_view.ex:149 msgid "Transaction" 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 1f62cecf73..68ad37cee8 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 @@ -49,7 +49,7 @@ msgid "%{subnetwork} Explorer - BlockScout" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:67 +#: lib/block_scout_web/views/transaction_view.ex:71 msgid "(Awaiting internal transactions for status)" msgstr "" @@ -278,12 +278,12 @@ msgid "Contract Address Pending" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:144 +#: lib/block_scout_web/views/transaction_view.ex:148 msgid "Contract Call" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:143 +#: lib/block_scout_web/views/transaction_view.ex:147 msgid "Contract Creation" msgstr "" @@ -389,12 +389,12 @@ msgid "Error trying to fetch balances." msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:71 +#: lib/block_scout_web/views/transaction_view.ex:75 msgid "Error: %{reason}" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:69 +#: lib/block_scout_web/views/transaction_view.ex:73 msgid "Error: (Awaiting internal transactions for reason)" msgstr "" @@ -507,7 +507,7 @@ msgstr "" #: lib/block_scout_web/templates/transaction/_tabs.html.eex:43 #: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:10 #: lib/block_scout_web/views/address_view.ex:254 -#: lib/block_scout_web/views/transaction_view.ex:197 +#: lib/block_scout_web/views/transaction_view.ex:201 msgid "Internal Transactions" msgstr "" @@ -533,7 +533,7 @@ msgstr "" #: lib/block_scout_web/templates/transaction/_tabs.html.eex:21 #: lib/block_scout_web/templates/transaction/_tabs.html.eex:48 #: lib/block_scout_web/templates/transaction_log/index.html.eex:10 -#: lib/block_scout_web/views/transaction_view.ex:198 +#: lib/block_scout_web/views/transaction_view.ex:202 msgid "Logs" msgstr "" @@ -545,7 +545,7 @@ msgid "Market Cap" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:58 +#: lib/block_scout_web/views/transaction_view.ex:62 msgid "Max of" msgstr "" @@ -684,8 +684,8 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/layout/_topnav.html.eex:44 #: lib/block_scout_web/templates/transaction/overview.html.eex:55 -#: lib/block_scout_web/views/transaction_view.ex:66 -#: lib/block_scout_web/views/transaction_view.ex:100 +#: lib/block_scout_web/views/transaction_view.ex:70 +#: lib/block_scout_web/views/transaction_view.ex:104 msgid "Pending" msgstr "" @@ -790,7 +790,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/transaction/_emission_reward_tile.html.eex:8 -#: lib/block_scout_web/views/transaction_view.ex:68 +#: lib/block_scout_web/views/transaction_view.ex:72 msgid "Success" msgstr "" @@ -901,7 +901,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:4 #: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:4 -#: lib/block_scout_web/views/transaction_view.ex:142 +#: lib/block_scout_web/views/transaction_view.ex:146 msgid "Token Transfer" msgstr "" @@ -913,7 +913,7 @@ msgstr "" #: lib/block_scout_web/templates/transaction/_tabs.html.eex:36 #: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:10 #: lib/block_scout_web/views/tokens/overview_view.ex:35 -#: lib/block_scout_web/views/transaction_view.ex:196 +#: lib/block_scout_web/views/transaction_view.ex:200 msgid "Token Transfers" msgstr "" @@ -954,7 +954,7 @@ msgid "Total transactions" msgstr "" #, elixir-format -#: lib/block_scout_web/views/transaction_view.ex:145 +#: lib/block_scout_web/views/transaction_view.ex:149 msgid "Transaction" msgstr "" diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs index 4fc27546ee..2e42c9829c 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs @@ -436,8 +436,8 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do "address" => "#{address.hash}" } - {:ok, max_block_number} = Chain.max_block_number() - expected_confirmations = max_block_number - transaction.block_number + block_height = Chain.block_height() + expected_confirmations = block_height - transaction.block_number assert %{"result" => [returned_transaction]} = conn diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/logs_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/logs_controller_test.exs index 563a5d28ad..758e37e801 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/logs_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/logs_controller_test.exs @@ -741,11 +741,11 @@ defmodule BlockScoutWeb.API.RPC.LogsControllerTest do # We insert a block, try again, and assert 'latest' points to the latest # block number. insert(:block) - {:ok, max_block_number} = Explorer.Chain.max_block_number() + {:ok, max_consensus_block_number} = Explorer.Chain.max_consensus_block_number() assert {_, {:ok, validated_params}} = LogsController.to_valid_format(params) - assert validated_params.from_block == max_block_number - assert validated_params.to_block == max_block_number + assert validated_params.from_block == max_consensus_block_number + assert validated_params.to_block == max_consensus_block_number end end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/transaction_controller_test.exs index bc0cfcca96..eefe7ed1c8 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/transaction_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/transaction_controller_test.exs @@ -1,6 +1,8 @@ defmodule BlockScoutWeb.API.RPC.TransactionControllerTest do use BlockScoutWeb.ConnCase + @moduletag capture_log: true + describe "gettxreceiptstatus" do test "with missing txhash", %{conn: conn} do params = %{ diff --git a/apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs b/apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs index 1139b85a36..52846bb057 100644 --- a/apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs +++ b/apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs @@ -62,7 +62,7 @@ defmodule BlockScoutWeb.TransactionViewTest do |> insert() |> with_block(block) - assert "1" == TransactionView.confirmations(transaction, max_block_number: block.number + 1) + assert "1" == TransactionView.confirmations(transaction, block_height: block.number + 1) end end diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 7875127a77..d095bf8e05 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -52,6 +52,11 @@ defmodule Explorer.Chain do """ @type association :: atom() + @typedoc """ + The max `t:Explorer.Chain.Block.block_number/0` for `consensus` `true` `t:Explorer.Chain.Block.t/0`s. + """ + @type block_height :: Block.block_number() + @typedoc """ Event type where data is broadcasted whenever data is inserted from chain indexing. """ @@ -415,14 +420,48 @@ defmodule Explorer.Chain do @doc """ How many blocks have confirmed `block` based on the current `max_block_number` + + A consensus block's number of confirmations is the difference between its number and the current block height. + + iex> block = insert(:block, number: 1) + iex> Explorer.Chain.confirmations(block, block_height: 2) + {:ok, 1} + + The newest block at the block height has no confirmations. + + iex> block = insert(:block, number: 1) + iex> Explorer.Chain.confirmations(block, block_height: 1) + {:ok, 0} + + A non-consensus block has no confirmations and is orphaned even if there are child blocks of it on an orphaned chain. + + iex> parent_block = insert(:block, consensus: false, number: 1) + iex> insert( + ...> :block, + ...> parent_hash: parent_block.hash, + ...> consensus: false, + ...> number: parent_block.number + 1 + ...> ) + iex> Explorer.Chain.confirmations(parent_block, block_height: 3) + {:error, :non_consensus} + + If you calculate the block height and then get a newer block, the confirmations will be `0` instead of negative. + + iex> block = insert(:block, number: 1) + iex> Explorer.Chain.confirmations(block, block_height: 0) + {:ok, 0} """ - @spec confirmations(Block.t(), [{:max_block_number, Block.block_number()}]) :: non_neg_integer() - def confirmations(%Block{number: number}, named_arguments) when is_list(named_arguments) do - max_block_number = Keyword.fetch!(named_arguments, :max_block_number) + @spec confirmations(Block.t(), [{:block_height, block_height()}]) :: + {:ok, non_neg_integer()} | {:error, :non_consensus} + + def confirmations(%Block{consensus: true, number: number}, named_arguments) when is_list(named_arguments) do + max_consensus_block_number = Keyword.fetch!(named_arguments, :block_height) - max_block_number - number + {:ok, max(max_consensus_block_number - number, 0)} end + def confirmations(%Block{consensus: false}, _), do: {:error, :non_consensus} + @doc """ Creates an address. @@ -1164,45 +1203,80 @@ defmodule Explorer.Chain do end @doc """ - Aggregate of consensus block numbers. + Max consensus block numbers. - If blocks are skipped and inserted out of number order, the `:max` and `:min` numbers are still returned + If blocks are skipped and inserted out of number order, the max number is still returned iex> insert(:block, number: 2) iex> insert(:block, number: 1) - iex> Explorer.Chain.consensus_block_number(:min) - {:ok, 1} - iex> Explorer.Chain.consensus_block_number(:max) + iex> Explorer.Chain.max_consensus_block_number() {:ok, 2} Non-consensus blocks are ignored iex> insert(:block, number: 3, consensus: false) iex> insert(:block, number: 2, consensus: true) - iex> insert(:block, number: 1, consensus: false) - iex> Explorer.Chain.consensus_block_number(:min) - {:ok, 2} - iex> Explorer.Chain.consensus_block_number(:max) + iex> Explorer.Chain.max_consensus_block_number() {:ok, 2} If there are no blocks, `{:error, :not_found}` is returned - iex> Explorer.Chain.consensus_block_number(:min) - {:error, :not_found} - iex> Explorer.Chain.consensus_block_number(:max) + iex> Explorer.Chain.max_consensus_block_number() {:error, :not_found} """ - def consensus_block_number(aggregate) do + @spec max_consensus_block_number() :: {:ok, Block.block_number()} | {:error, :not_found} + def max_consensus_block_number do Block |> where(consensus: true) - |> Repo.aggregate(aggregate, :number) + |> Repo.aggregate(:max, :number) |> case do nil -> {:error, :not_found} number -> {:ok, number} end end + @doc """ + The height of the chain. + + iex> insert(:block, number: 0) + iex> Explorer.Chain.block_height() + 0 + iex> insert(:block, number: 1) + iex> Explorer.Chain.block_height() + 1 + + If there are no blocks, then the `t:block_height/0` is `0`, unlike `max_consensus_block_chain/0` where it is not found. + + iex> Explorer.Chain.block_height() + 0 + iex> Explorer.Chain.max_consensus_block_number() + {:error, :not_found} + + It is not possible to differentiate only the genesis block (`number` `0`) and no blocks. Use + `max_consensus_block_chain/0` if you need to differentiate those two scenarios. + + iex> Explorer.Chain.block_height() + 0 + iex> insert(:block, number: 0) + iex> Explorer.Chain.block_height() + 0 + + Non-consensus blocks are ignored. + + iex> insert(:block, number: 2, consensus: false) + iex> insert(:block, number: 1, consensus: true) + iex> Explorer.Chain.block_height() + 1 + + """ + @spec block_height() :: block_height() + def block_height do + query = from(block in Block, select: coalesce(max(block.number), 0), where: block.consensus == true) + + Repo.one!(query) + end + @doc """ Calculates the ranges of missing consensus blocks in `range`. diff --git a/apps/explorer/lib/explorer/chain/supply/proof_of_authority.ex b/apps/explorer/lib/explorer/chain/supply/proof_of_authority.ex index 0a43750f30..bb8e625740 100644 --- a/apps/explorer/lib/explorer/chain/supply/proof_of_authority.ex +++ b/apps/explorer/lib/explorer/chain/supply/proof_of_authority.ex @@ -34,17 +34,7 @@ defmodule Explorer.Chain.Supply.ProofOfAuthority do end def total do - initial_supply = initial_supply() - block_height = block_height() - - initial_supply + block_height - end - - defp block_height do - case Chain.consensus_block_number(:max) do - {:ok, height} -> height - _ -> 0 - end + initial_supply() + Chain.block_height() end @doc false diff --git a/apps/explorer/lib/explorer/etherscan.ex b/apps/explorer/lib/explorer/etherscan.ex index 4156314632..0df941271e 100644 --- a/apps/explorer/lib/explorer/etherscan.ex +++ b/apps/explorer/lib/explorer/etherscan.ex @@ -43,7 +43,7 @@ defmodule Explorer.Etherscan do %Hash{byte_count: unquote(Hash.Address.byte_count())} = address_hash, options \\ @default_options ) do - case Chain.consensus_block_number(:max) do + case Chain.max_consensus_block_number() do {:ok, max_block_number} -> merged_options = Map.merge(@default_options, options) list_transactions(address_hash, max_block_number, merged_options) @@ -152,10 +152,10 @@ defmodule Explorer.Etherscan do contract_address_hash, options \\ @default_options ) do - case Chain.consensus_block_number(:max) do - {:ok, max_block_number} -> + case Chain.max_consensus_block_number() do + {:ok, block_height} -> merged_options = Map.merge(@default_options, options) - list_token_transfers(address_hash, contract_address_hash, max_block_number, merged_options) + list_token_transfers(address_hash, contract_address_hash, block_height, merged_options) _ -> [] @@ -319,7 +319,7 @@ defmodule Explorer.Etherscan do amount )a - defp list_token_transfers(address_hash, contract_address_hash, max_block_number, options) do + defp list_token_transfers(address_hash, contract_address_hash, block_height, options) do query = from( t in Transaction, @@ -343,7 +343,7 @@ defmodule Explorer.Etherscan do block_hash: b.hash, block_number: b.number, block_timestamp: b.timestamp, - confirmations: fragment("? - ?", ^max_block_number, t.block_number), + confirmations: fragment("? - ?", ^block_height, t.block_number), token_id: tt.token_id, token_name: tkn.name, token_symbol: tkn.symbol, diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index c4c23796e0..476a6d0783 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -592,21 +592,21 @@ defmodule Explorer.ChainTest do end describe "confirmations/1" do - test "with block.number == max_block_number " do + test "with block.number == block_height " do block = insert(:block) - {:ok, max_block_number} = Chain.consensus_block_number(:max) + block_height = Chain.block_height() - assert block.number == max_block_number - assert Chain.confirmations(block, max_block_number: max_block_number) == 0 + assert block.number == block_height + assert {:ok, 0} = Chain.confirmations(block, block_height: block_height) end - test "with block.number < max_block_number" do + test "with block.number < block_height" do block = insert(:block) - max_block_number = block.number + 2 + block_height = block.number + 2 - assert block.number < max_block_number - - assert Chain.confirmations(block, max_block_number: max_block_number) == max_block_number - block.number + assert block.number < block_height + assert {:ok, confirmations} = Chain.confirmations(block, block_height: block_height) + assert confirmations == block_height - block.number end end diff --git a/apps/explorer/test/explorer/etherscan_test.exs b/apps/explorer/test/explorer/etherscan_test.exs index 2476fc2e59..8153ccc25c 100644 --- a/apps/explorer/test/explorer/etherscan_test.exs +++ b/apps/explorer/test/explorer/etherscan_test.exs @@ -122,8 +122,8 @@ defmodule Explorer.EtherscanTest do [found_transaction] = Etherscan.list_transactions(address.hash) - {:ok, max_block_number} = Chain.consensus_block_number(:max) - expected_confirmations = max_block_number - transaction.block_number + block_height = Chain.block_height() + expected_confirmations = block_height - transaction.block_number assert found_transaction.confirmations == expected_confirmations end @@ -888,8 +888,8 @@ defmodule Explorer.EtherscanTest do [found_token_transfer] = Etherscan.list_token_transfers(token_transfer.from_address_hash, nil) - {:ok, max_block_number} = Chain.consensus_block_number(:max) - expected_confirmations = max_block_number - transaction.block_number + block_height = Chain.block_height() + expected_confirmations = block_height - transaction.block_number assert found_token_transfer.confirmations == expected_confirmations end diff --git a/apps/indexer/lib/indexer.ex b/apps/indexer/lib/indexer.ex index 552963e0a9..34335d12aa 100644 --- a/apps/indexer/lib/indexer.ex +++ b/apps/indexer/lib/indexer.ex @@ -2,54 +2,4 @@ defmodule Indexer do @moduledoc """ Indexes an Ethereum-based chain using JSONRPC. """ - - alias Explorer.Chain - - @doc """ - The maximum `t:Explorer.Chain.Block.t/0` `number` that was indexed - - If blocks are skipped and inserted out of number order, the max number is still returned - - iex> insert(:block, number: 2) - iex> insert(:block, number: 1) - iex> Indexer.max_block_number() - 2 - - If there are no blocks, `0` is returned to indicate to index from genesis block. - - iex> Indexer.max_block_number() - 0 - - """ - def max_block_number do - case Chain.consensus_block_number(:max) do - {:ok, number} -> number - {:error, :not_found} -> 0 - end - end - - @doc """ - The next `t:Explorer.Chain.Block.t/0` `number` that needs to be indexed (excluding skipped blocks) - - When there are no blocks the next block is the 0th block - - iex> Indexer.max_block_number() - 0 - iex> Indexer.next_block_number() - 0 - - When there is a block, it is the successive block number - - iex> insert(:block, number: 2) - iex> insert(:block, number: 1) - iex> Indexer.next_block_number() - 3 - - """ - def next_block_number do - case max_block_number() do - 0 -> 0 - num -> num + 1 - end - end end