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 1e4fe3bc53..c61dff29b2 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
@@ -57,7 +57,7 @@ defmodule BlockScoutWeb.BlockTransactionController do
|> render(
"404.html",
block: nil,
- block_above_tip: block_above_tip?(formatted_block_hash_or_number)
+ block_above_tip: block_above_tip(formatted_block_hash_or_number)
)
end
end
@@ -79,10 +79,16 @@ defmodule BlockScoutWeb.BlockTransactionController do
end
end
- defp block_above_tip?("0x" <> _), do: nil
+ defp block_above_tip("0x" <> _), do: {:error, :hash}
- defp block_above_tip?(block_hash_or_number) when is_binary(block_hash_or_number) do
- {block_number, ""} = Integer.parse(block_hash_or_number)
- block_number > Chain.block_height()
+ defp block_above_tip(block_hash_or_number) when is_binary(block_hash_or_number) do
+ case Chain.max_consensus_block_number() do
+ {:ok, max_consensus_block_number} ->
+ {block_number, _} = Integer.parse(block_hash_or_number)
+ {:ok, block_number > max_consensus_block_number}
+
+ {:error, :not_found} ->
+ {:ok, true}
+ end
end
end
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/block_transaction/404.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/block_transaction/404.html.eex
index 015abcae09..68faa6fb73 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/block_transaction/404.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/block_transaction/404.html.eex
@@ -6,7 +6,7 @@
+
<%= block_not_found_message(@block_above_tip) %>
diff --git a/apps/block_scout_web/lib/block_scout_web/views/block_transaction_view.ex b/apps/block_scout_web/lib/block_scout_web/views/block_transaction_view.ex
index be0e4a3d02..aef7f4124d 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/block_transaction_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/block_transaction_view.ex
@@ -3,16 +3,15 @@ defmodule BlockScoutWeb.BlockTransactionView do
import BlockScoutWeb.Gettext, only: [gettext: 1]
- def block_not_found_message(block_above_tip) do
- case block_above_tip do
- true ->
- gettext("Easy Cowboy! This block does not exist yet!")
+ def block_not_found_message({:ok, true}) do
+ gettext("Easy Cowboy! This block does not exist yet!")
+ end
- false ->
- gettext("This block has not been processed yet.")
+ def block_not_found_message({:ok, false}) do
+ gettext("This block has not been processed yet.")
+ end
- _ ->
- gettext("Block not found, please try again later.")
- end
+ def block_not_found_message({:error, :hash}) do
+ gettext("Block not found, please try again later.")
end
end
diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot
index e5a36abd74..e2513bf670 100644
--- a/apps/block_scout_web/priv/gettext/default.pot
+++ b/apps/block_scout_web/priv/gettext/default.pot
@@ -1254,12 +1254,12 @@ msgid "Block not found, please try again later."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/block_transaction_view.ex:9
+#: lib/block_scout_web/views/block_transaction_view.ex:7
msgid "Easy Cowboy! This block does not exist yet!"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/block_transaction_view.ex:12
+#: lib/block_scout_web/views/block_transaction_view.ex:11
msgid "This block has not been processed yet."
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 68ad37cee8..05c4540264 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
@@ -1254,12 +1254,12 @@ msgid "Block not found, please try again later."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/block_transaction_view.ex:9
+#: lib/block_scout_web/views/block_transaction_view.ex:7
msgid "Easy Cowboy! This block does not exist yet!"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/block_transaction_view.ex:12
+#: lib/block_scout_web/views/block_transaction_view.ex:11
msgid "This block has not been processed yet."
msgstr ""
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/block_transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/block_transaction_controller_test.exs
index bedd644ba4..6a4e2ebf32 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/block_transaction_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/block_transaction_controller_test.exs
@@ -45,16 +45,29 @@ defmodule BlockScoutWeb.BlockTransactionControllerTest do
assert 2 == Enum.count(conn.assigns.transactions)
end
- test "does not return transactions for non-consensus block number", %{conn: conn} do
+ test "non-consensus block number without consensus blocks is treated as consensus number above tip", %{conn: conn} do
block = insert(:block, consensus: false)
- :transaction
- |> insert()
- |> with_block(block)
+ transaction = insert(:transaction)
+ insert(:transaction_fork, hash: transaction.hash, uncle_hash: block.hash)
conn = get(conn, block_transaction_path(conn, :index, block.number))
- assert html_response(conn, 404) =~ "This block has not been processed yet."
+ assert_block_above_tip(conn)
+ end
+
+ test "non-consensus block number above consensus block number is treated as consensus number above tip", %{
+ conn: conn
+ } do
+ consensus_block = insert(:block, consensus: true, number: 1)
+ block = insert(:block, consensus: false, number: consensus_block.number + 1)
+
+ transaction = insert(:transaction)
+ insert(:transaction_fork, hash: transaction.hash, uncle_hash: block.hash)
+
+ conn = get(conn, block_transaction_path(conn, :index, block.number))
+
+ assert_block_above_tip(conn)
end
test "returns transactions for consensus block hash", %{conn: conn} do
@@ -70,17 +83,16 @@ defmodule BlockScoutWeb.BlockTransactionControllerTest do
assert Enum.count(conn.assigns.transactions) == 1
end
- test "returns transactions for non-consensus block hash", %{conn: conn} do
+ test "does not return transactions for non-consensus block hash", %{conn: conn} do
block = insert(:block, consensus: false)
- :transaction
- |> insert()
- |> with_block(block)
+ transaction = insert(:transaction)
+ insert(:transaction_fork, hash: transaction.hash, uncle_hash: block.hash)
conn = get(conn, block_transaction_path(conn, :index, block.hash))
assert html_response(conn, 200)
- assert Enum.count(conn.assigns.transactions) == 1
+ assert Enum.count(conn.assigns.transactions) == 0
end
test "does not return transactions for invalid block hash", %{conn: conn} do
@@ -149,4 +161,12 @@ defmodule BlockScoutWeb.BlockTransactionControllerTest do
assert html_response(conn, 200) =~ miner_name
end
end
+
+ defp assert_block_above_tip(conn) do
+ assert conn
+ |> html_response(404)
+ |> Floki.find(~S|[data-selector="block-not-found-message"|)
+ |> Floki.text()
+ |> String.trim() == "Easy Cowboy! This block does not exist yet!"
+ end
end
diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_blocks_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_blocks_test.exs
index eb5e24e8c4..208fe1bd65 100644
--- a/apps/block_scout_web/test/block_scout_web/features/viewing_blocks_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/features/viewing_blocks_test.exs
@@ -149,9 +149,8 @@ defmodule BlockScoutWeb.ViewingBlocksTest do
uncle = insert(:block, consensus: false)
insert(:block_second_degree_relation, uncle_hash: uncle.hash)
- :transaction
- |> insert()
- |> with_block(uncle)
+ transaction = insert(:transaction)
+ insert(:transaction_fork, hash: transaction.hash, uncle_hash: uncle.hash)
uncle
end
diff --git a/apps/explorer/lib/explorer/chain/block.ex b/apps/explorer/lib/explorer/chain/block.ex
index a9069aa828..f636447f2e 100644
--- a/apps/explorer/lib/explorer/chain/block.ex
+++ b/apps/explorer/lib/explorer/chain/block.ex
@@ -88,6 +88,7 @@ defmodule Explorer.Chain.Block do
has_many(:uncles, through: [:uncle_relations, :uncle])
has_many(:transactions, Transaction)
+ has_many(:transaction_forks, Transaction.Fork, foreign_key: :uncle_hash)
has_many(:rewards, Reward, foreign_key: :block_hash)
end
diff --git a/apps/explorer/test/support/factory.ex b/apps/explorer/test/support/factory.ex
index 05ea2b4749..ba907424db 100644
--- a/apps/explorer/test/support/factory.ex
+++ b/apps/explorer/test/support/factory.ex
@@ -176,7 +176,9 @@ defmodule Explorer.Factory do
with_block(transaction, block, [])
end
- def with_block(transactions, %Block{} = block) when is_list(transactions) do
+ # The `transaction.block` must be consensus. Non-consensus blocks can only be associated with the
+ # `transaction_forks`.
+ def with_block(transactions, %Block{consensus: true} = block) when is_list(transactions) do
Enum.map(transactions, &with_block(&1, block))
end
@@ -187,7 +189,9 @@ defmodule Explorer.Factory do
def with_block(
%Transaction{index: nil} = transaction,
- %Block{hash: block_hash, number: block_number},
+ # The `transaction.block` must be consensus. Non-consensus blocks can only be associated with the
+ # `transaction_forks`.
+ %Block{consensus: true, hash: block_hash, number: block_number},
collated_params
)
when is_list(collated_params) do