diff --git a/lib/starknet_explorer/block/block.ex b/lib/starknet_explorer/block/block.ex index 5d29d1cd..49f4f1c1 100644 --- a/lib/starknet_explorer/block/block.ex +++ b/lib/starknet_explorer/block/block.ex @@ -499,19 +499,24 @@ defmodule StarknetExplorer.Block do end def get_by_num(num, network, preload_transactions \\ true) do - query = - from b in Block, - where: b.number == ^num and b.network == ^network + try do + query = + from b in Block, + where: b.number == ^num and b.network == ^network - block = Repo.one(query) + block = Repo.one(query) - if preload_transactions and not is_nil(block) do - preload_query = - from tx in Transaction, where: tx.block_number == ^block.number and tx.network == ^network + if preload_transactions and not is_nil(block) do + preload_query = + from tx in Transaction, + where: tx.block_number == ^block.number and tx.network == ^network - Repo.preload(block, transactions: preload_query) - else - block + Repo.preload(block, transactions: preload_query) + else + block + end + rescue + DBConnection.EncodeError -> nil end end diff --git a/lib/starknet_explorer_web/live/pages/block_detail.ex b/lib/starknet_explorer_web/live/pages/block_detail.ex index 02119dbc..81af81a3 100644 --- a/lib/starknet_explorer_web/live/pages/block_detail.ex +++ b/lib/starknet_explorer_web/live/pages/block_detail.ex @@ -9,8 +9,16 @@ defmodule StarknetExplorerWeb.BlockDetailLive do alias StarknetExplorer.Transaction alias StarknetExplorer.Events - defp num_or_hash(<<"0x", _rest::binary>>), do: :hash - defp num_or_hash(_num), do: :num + defp parse_block_id(block_id) + + defp parse_block_id(<<"0x", _::binary>> = hash), do: {:hash, hash} + + defp parse_block_id(number?) do + case Integer.parse(number?) do + {number, ""} -> {:number, number} + _ -> :error + end + end defp get_block_proof(block_hash) do try do @@ -75,6 +83,89 @@ defmodule StarknetExplorerWeb.BlockDetailLive do end end + defp get_block({type, block_id}, socket) do + case :timer.tc(fn -> + Enum.find( + StarknetExplorer.IndexCache.latest_blocks(socket.assigns.network), + fn block -> + block.number == block_id or block.hash == block_id + end + ) + end) do + {time, block} = {_, %StarknetExplorer.Block{}} -> + Logger.debug( + "[Block Detail] Found block #{block.number} in cache in #{time} microseconds" + ) + + {:ok, block} + + {time, _} -> + case type do + :hash -> + {query_time, res} = + :timer.tc(fn -> Data.block_by_hash(block_id, socket.assigns.network, false) end) + + Logger.debug( + "[Block Detail] Fetched block #{block_id} in #{query_time} microseconds, query took #{time} microseconds, using :hash" + ) + + res + + :number -> + {query_time, res} = + :timer.tc(fn -> Data.block_by_number(block_id, socket.assigns.network, false) end) + + Logger.debug( + "[Block Detail] Fetched block #{block_id} in #{query_time} microseconds, query took #{time} microsecond, using :number" + ) + + res + end + end + end + + defp assign_block_data(socket, block) do + socket = assign(socket, :block, block) + + extra_assings = + if connected?(socket) do + transactions = block_transactions(socket) + + # note: most transactions receipt do not contain messages + l1_to_l2_messages = + transactions |> Enum.map(&Message.from_transaction/1) |> Enum.reject(&is_nil/1) + + messages = + (transactions + |> Enum.map(fn tx -> tx.receipt end) + |> Enum.flat_map(&Message.from_transaction_receipt/1)) ++ l1_to_l2_messages + + [ + transactions_count: length(transactions), + messages_count: length(messages), + events_count: Events.get_count_by_block(block.number, socket.assigns.network), + transactions: transactions, + messages: messages + ] + else + [] + end + + assigns = + [ + gas_price: Utils.hex_wei_to_eth(block.gas_fee_in_wei), + execution_resources: block.execution_resources, + block: block, + view: "overview", + verification: "Pending", + block_age: Utils.get_block_age(block), + tabs?: connected?(socket), + active_pagination_id: "" + ] ++ extra_assings + + assign(socket, assigns) + end + defp tab_name("transactions"), do: "Transactions" defp tab_name("messages"), do: "Messages" defp tab_name("events"), do: "Events" @@ -159,95 +250,16 @@ defmodule StarknetExplorerWeb.BlockDetailLive do @impl true def mount(_params = %{"number_or_hash" => param}, _session, socket) do - {type, param} = - case num_or_hash(param) do - :hash -> - {:hash, param} - - :num -> - {num, ""} = Integer.parse(param) - {:num, num} - end - - {:ok, block} = - case :timer.tc(fn -> - Enum.find( - StarknetExplorer.IndexCache.latest_blocks(socket.assigns.network), - fn block -> - block.number == param or block.hash == param - end - ) - end) do - {time, block} = {_, %StarknetExplorer.Block{}} -> - Logger.debug( - "[Block Detail] Found block #{block.number} in cache in #{time} microseconds" - ) - - {:ok, block} - - {time, _} -> - case type do - :hash -> - {query_time, res} = - :timer.tc(fn -> Data.block_by_hash(param, socket.assigns.network, false) end) - - Logger.debug( - "[Block Detail] Fetched block #{param} in #{query_time} microseconds, query took #{time} microseconds, using :hash" - ) - - res - - :num -> - {query_time, res} = - :timer.tc(fn -> Data.block_by_number(param, socket.assigns.network, false) end) - - Logger.debug( - "[Block Detail] Fetched block #{param} in #{query_time} microseconds, query took #{time} microsecond, using :num" - ) - - res - end - end - - socket = assign(socket, :block, block) - - extra_assings = - if connected?(socket) do - transactions = block_transactions(socket) - - # note: most transactions receipt do not contain messages - l1_to_l2_messages = - transactions |> Enum.map(&Message.from_transaction/1) |> Enum.reject(&is_nil/1) - - messages = - (transactions - |> Enum.map(fn tx -> tx.receipt end) - |> Enum.flat_map(&Message.from_transaction_receipt/1)) ++ l1_to_l2_messages - - [ - transactions_count: length(transactions), - messages_count: length(messages), - events_count: Events.get_count_by_block(block.number, socket.assigns.network), - transactions: transactions, - messages: messages - ] + socket = + with {_, _} = block_id <- parse_block_id(param), + {:ok, block} <- + get_block(block_id, socket) do + assign_block_data(socket, block) else - [] + _ -> assign(socket, :block, :error) end - assigns = - [ - gas_price: Utils.hex_wei_to_eth(block.gas_fee_in_wei), - execution_resources: block.execution_resources, - block: block, - view: "overview", - verification: "Pending", - block_age: Utils.get_block_age(block), - tabs?: connected?(socket), - active_pagination_id: "" - ] ++ extra_assings - - {:ok, assign(socket, assigns)} + {:ok, socket} end @impl true @@ -478,6 +490,29 @@ defmodule StarknetExplorerWeb.BlockDetailLive do end @impl true + def render(assigns) + + def render(%{block: :error} = assigns) do + ~H""" +
+
404
+

Block Not Found

+

The block you are looking could not be found or is invalid

+ + Go home Go home + +
+ Error image + """ + end + def render(assigns) do ~H"""