From 75e5c99788f43b0ed3777dc43e4e8948e01b5975 Mon Sep 17 00:00:00 2001 From: Marcos Nicolau Date: Tue, 20 May 2025 18:34:07 -0300 Subject: [PATCH 1/4] feat: support aggregation mode in explorer search --- .../lib/explorer/models/aggregated_proofs.ex | 12 +++++++ .../explorer/models/aggregation_mode_proof.ex | 12 +++++++ .../lib/explorer_web/components/search.ex | 34 ++++++++++++++----- explorer/mix.lock | 2 +- 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/explorer/lib/explorer/models/aggregated_proofs.ex b/explorer/lib/explorer/models/aggregated_proofs.ex index d43dc34efd..08648df24f 100644 --- a/explorer/lib/explorer/models/aggregated_proofs.ex +++ b/explorer/lib/explorer/models/aggregated_proofs.ex @@ -67,6 +67,18 @@ defmodule AggregatedProofs do Explorer.Repo.get_by(AggregatedProofs, id: id) end + def get_newest_aggregated_proof_by_merkle_root(merkle_root) do + query = + from(proof in AggregatedProofs, + order_by: [desc: proof.block_number], + limit: 1, + where: proof.merkle_root == ^merkle_root, + select: proof + ) + + Explorer.Repo.one(query) + end + def get_paginated_proofs(%{page: page, page_size: size}) do query = from(proof in AggregatedProofs, diff --git a/explorer/lib/explorer/models/aggregation_mode_proof.ex b/explorer/lib/explorer/models/aggregation_mode_proof.ex index 947982cf4d..7de87a86af 100644 --- a/explorer/lib/explorer/models/aggregation_mode_proof.ex +++ b/explorer/lib/explorer/models/aggregation_mode_proof.ex @@ -58,4 +58,16 @@ defmodule AggregationModeProof do Explorer.Repo.all(query) end + + def get_newest_proof_by_hash(hash) do + query = + from(proof in AggregationModeProof, + limit: 1, + order_by: [desc: proof.inserted_at], + where: proof.proof_hash == ^hash, + select: proof + ) + + Explorer.Repo.one(query) + end end diff --git a/explorer/lib/explorer_web/components/search.ex b/explorer/lib/explorer_web/components/search.ex index 7babfcbd5d..04777943eb 100644 --- a/explorer/lib/explorer_web/components/search.ex +++ b/explorer/lib/explorer_web/components/search.ex @@ -1,24 +1,40 @@ defmodule SearchComponent do + require Logger use ExplorerWeb, :live_component @impl true - def handle_event("search_batch", %{"batch" => %{"merkle_root" => input_hash}}, socket) do - input_hash + def handle_event("search_batch", %{"search" => search}, socket) do + search |> (fn hash -> if String.match?(hash, ~r/^0x[a-fA-F0-9]+$/), do: {:ok, hash}, else: :invalid_hash end).() |> case do {:ok, hash} -> - case Proofs.get_number_of_batches_containing_proof(hash) do - 0 -> {:noreply, push_navigate(socket, to: ~p"/batches/#{hash}")} - _ -> {:noreply, push_navigate(socket, to: ~p"/search?q=#{hash}")} + cond do + # See if the hash belongs to a proof + Proofs.get_number_of_batches_containing_proof(hash) > 0 -> + {:noreply, push_navigate(socket, to: ~p"/batches/#{hash}")} + + # See if the hash belongs to an aggregated proof merkle root + (proof = AggregatedProofs.get_newest_aggregated_proof_by_merkle_root(hash)) != nil -> + Logger.debug(proof) + {:noreply, push_navigate(socket, to: ~p"/aggregated_proofs/#{proof.id}")} + + # Finally, see if the hash belongs to a proof of an aggregated proof + (proof = AggregationModeProof.get_newest_proof_by_hash(hash)) != nil -> + {:noreply, push_navigate(socket, to: ~p"/aggregated_proofs/#{proof.agg_proof_id}")} + + # Otherwise inform the user nothing was found + true -> + {:noreply, + socket + |> put_flash!(:error, "No batch or proof was found with the provided hash.")} end :invalid_hash -> {:noreply, socket - |> assign(batch_merkle_root: input_hash) - |> put_flash!(:error, "Please enter a valid proof batch hash (0x69...).")} + |> put_flash!(:error, "Please enter a valid hash (0x69...).")} end end @@ -42,8 +58,8 @@ defmodule SearchComponent do id={"input_#{assigns.id}"} class="pr-10 w-full text-foreground rounded-lg border-foreground/20 bg-card focus:border-foreground/20 focus:ring-accent text-sm" type="search" - placeholder="Search batch by batch hash or proof hash" - name="batch[merkle_root]" + placeholder="Search by batch hash or proof hash" + name="search" /> <.icon name="hero-magnifying-glass-solid" class="absolute right-3 text-foreground/20 size-5 hover:text-foreground" /> diff --git a/explorer/mix.lock b/explorer/mix.lock index 8a217d3ce0..35210e9d11 100644 --- a/explorer/mix.lock +++ b/explorer/mix.lock @@ -24,7 +24,7 @@ "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"}, "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"}, "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, - "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized"]}, + "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized", depth: 1]}, "hpax": {:hex, :hpax, "0.2.0", "5a58219adcb75977b2edce5eb22051de9362f08236220c9e859a47111c194ff5", [:mix], [], "hexpm", "bea06558cdae85bed075e6c036993d43cd54d447f76d8190a8db0dc5893fa2f1"}, "httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, From 0f94007e241b1c4cee7e16f876e64af461a0f1b5 Mon Sep 17 00:00:00 2001 From: Marcos Nicolau Date: Mon, 2 Jun 2025 11:40:22 -0300 Subject: [PATCH 2/4] fix: search for batches --- explorer/lib/explorer_web/components/search.ex | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/explorer/lib/explorer_web/components/search.ex b/explorer/lib/explorer_web/components/search.ex index 04777943eb..2b0cdd82b7 100644 --- a/explorer/lib/explorer_web/components/search.ex +++ b/explorer/lib/explorer_web/components/search.ex @@ -11,13 +11,17 @@ defmodule SearchComponent do |> case do {:ok, hash} -> cond do - # See if the hash belongs to a proof + # See if the hash belongs to a proof in a batch + # If so, redirect to search to show all the batches where this proofs exists Proofs.get_number_of_batches_containing_proof(hash) > 0 -> + {:noreply, push_navigate(socket, to: ~p"/search?q=#{hash}")} + + # See if the hash belongs to the root of a batch + Batches.get_batch(%{merkle_root: hash}) != nil -> {:noreply, push_navigate(socket, to: ~p"/batches/#{hash}")} # See if the hash belongs to an aggregated proof merkle root (proof = AggregatedProofs.get_newest_aggregated_proof_by_merkle_root(hash)) != nil -> - Logger.debug(proof) {:noreply, push_navigate(socket, to: ~p"/aggregated_proofs/#{proof.id}")} # Finally, see if the hash belongs to a proof of an aggregated proof From b8b509caca05aab039bfbf0a6ef90e46adffd54d Mon Sep 17 00:00:00 2001 From: Marcos Nicolau Date: Mon, 2 Jun 2025 11:44:43 -0300 Subject: [PATCH 3/4] fix: proof search results style --- .../explorer_web/live/pages/search/index.ex | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/explorer/lib/explorer_web/live/pages/search/index.ex b/explorer/lib/explorer_web/live/pages/search/index.ex index ad5abf20a4..37d83cb41a 100644 --- a/explorer/lib/explorer_web/live/pages/search/index.ex +++ b/explorer/lib/explorer_web/live/pages/search/index.ex @@ -52,25 +52,27 @@ defmodule ExplorerWeb.Search.Index do Search Results for "<%= @hash |> Helpers.shorten_hash() %>" <%= if @results != nil or @results != [] do %> - <.table id="results" rows={@results}> - <:col :let={result} label="Batch Hash" class="text-left"> - <.link - navigate={~p"/batches/#{result}"} - class="flex justify-between group group-hover:text-foreground/80" - > - - - <%= result |> Helpers.shorten_hash(12) %> - - <.right_arrow /> - <.tooltip> - <%= result %> - - - - + <.card_background> + <.table id="results" rows={@results}> + <:col :let={result} label="Batch Hash" class="text-left"> + <.link + navigate={~p"/batches/#{result}"} + class="flex justify-between group group-hover:text-foreground/80" + > + + + <%= result |> Helpers.shorten_hash(12) %> + + <.right_arrow /> + <.tooltip> + <%= result %> + + + + +
<%= if @current_page != 1 do %> <.link patch={~p"/search?q=#{@hash}&page=#{@current_page - 1}"}> From 7e8ad0a09e79cdec14a7a2c9db6ee7362d18b5e9 Mon Sep 17 00:00:00 2001 From: JuArce <52429267+JuArce@users.noreply.github.com> Date: Tue, 3 Jun 2025 14:24:57 -0300 Subject: [PATCH 4/4] fix: use same parameters orders for SQL queries --- explorer/lib/explorer/models/aggregated_proofs.ex | 10 +++++----- explorer/lib/explorer/models/aggregation_mode_proof.ex | 10 +++++----- explorer/mix.lock | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/explorer/lib/explorer/models/aggregated_proofs.ex b/explorer/lib/explorer/models/aggregated_proofs.ex index 08648df24f..df4e87b6c0 100644 --- a/explorer/lib/explorer/models/aggregated_proofs.ex +++ b/explorer/lib/explorer/models/aggregated_proofs.ex @@ -70,10 +70,10 @@ defmodule AggregatedProofs do def get_newest_aggregated_proof_by_merkle_root(merkle_root) do query = from(proof in AggregatedProofs, - order_by: [desc: proof.block_number], - limit: 1, + select: proof, where: proof.merkle_root == ^merkle_root, - select: proof + order_by: [desc: proof.block_number], + limit: 1 ) Explorer.Repo.one(query) @@ -82,10 +82,10 @@ defmodule AggregatedProofs do def get_paginated_proofs(%{page: page, page_size: size}) do query = from(proof in AggregatedProofs, + select: proof, order_by: [desc: proof.block_number], limit: ^size, - offset: ^((page - 1) * size), - select: proof + offset: ^((page - 1) * size) ) Explorer.Repo.all(query) diff --git a/explorer/lib/explorer/models/aggregation_mode_proof.ex b/explorer/lib/explorer/models/aggregation_mode_proof.ex index 7de87a86af..07e2ece6e7 100644 --- a/explorer/lib/explorer/models/aggregation_mode_proof.ex +++ b/explorer/lib/explorer/models/aggregation_mode_proof.ex @@ -52,8 +52,8 @@ defmodule AggregationModeProof do def get_all_proof_hashes(id) do query = from(proof in AggregationModeProof, - where: proof.agg_proof_id == ^id, - select: proof.proof_hash + select: proof.proof_hash, + where: proof.agg_proof_id == ^id ) Explorer.Repo.all(query) @@ -62,10 +62,10 @@ defmodule AggregationModeProof do def get_newest_proof_by_hash(hash) do query = from(proof in AggregationModeProof, - limit: 1, - order_by: [desc: proof.inserted_at], + select: proof, where: proof.proof_hash == ^hash, - select: proof + order_by: [desc: proof.inserted_at], + limit: 1 ) Explorer.Repo.one(query) diff --git a/explorer/mix.lock b/explorer/mix.lock index 35210e9d11..8a217d3ce0 100644 --- a/explorer/mix.lock +++ b/explorer/mix.lock @@ -24,7 +24,7 @@ "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"}, "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"}, "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, - "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized", depth: 1]}, + "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized"]}, "hpax": {:hex, :hpax, "0.2.0", "5a58219adcb75977b2edce5eb22051de9362f08236220c9e859a47111c194ff5", [:mix], [], "hexpm", "bea06558cdae85bed075e6c036993d43cd54d447f76d8190a8db0dc5893fa2f1"}, "httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},