From 56c30ce6480f1da02fd31716a2f69d8e3e5fdc25 Mon Sep 17 00:00:00 2001 From: Marcos Nicolau Date: Mon, 28 Apr 2025 19:41:21 -0300 Subject: [PATCH 1/6] feat: aggregator field for aggregated proofs --- explorer/lib/explorer/models/aggregated_proofs.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/explorer/lib/explorer/models/aggregated_proofs.ex b/explorer/lib/explorer/models/aggregated_proofs.ex index 639603843c..d43dc34efd 100644 --- a/explorer/lib/explorer/models/aggregated_proofs.ex +++ b/explorer/lib/explorer/models/aggregated_proofs.ex @@ -12,6 +12,7 @@ defmodule AggregatedProofs do field(:block_timestamp, :utc_datetime) field(:tx_hash, :string) field(:number_of_proofs, :integer) + field(:aggregator, Ecto.Enum, values: [:sp1, :risc0]) has_many(:proofs_agg_mode, AggregationModeProof, foreign_key: :agg_proof_id, @@ -33,7 +34,8 @@ defmodule AggregatedProofs do :block_number, :block_timestamp, :tx_hash, - :number_of_proofs + :number_of_proofs, + :aggregator ]) |> validate_required([ :merkle_root, From 814db3e3a52b4a26c8a75cbdd1136b0bf27df2d4 Mon Sep 17 00:00:00 2001 From: Marcos Nicolau Date: Mon, 28 Apr 2025 19:41:43 -0300 Subject: [PATCH 2/6] feat: fetch aggregator from tx input signature for agg proofs --- .../aligned_proof_aggregation_service.ex | 20 +++++++++++++++++++ explorer/lib/explorer/eth_client.ex | 15 +++++++++++--- explorer/lib/explorer/periodically.ex | 9 ++++++--- ...0428144500_add_aggegator_to_agg_proofs.exs | 9 +++++++++ 4 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 explorer/priv/repo/migrations/20250428144500_add_aggegator_to_agg_proofs.exs diff --git a/explorer/lib/explorer/contract_managers/aligned_proof_aggregation_service.ex b/explorer/lib/explorer/contract_managers/aligned_proof_aggregation_service.ex index 4040370a2c..57da298ba5 100644 --- a/explorer/lib/explorer/contract_managers/aligned_proof_aggregation_service.ex +++ b/explorer/lib/explorer/contract_managers/aligned_proof_aggregation_service.ex @@ -2,6 +2,8 @@ defmodule AlignedProofAggregationService do require Logger @aligned_config_file System.get_env("ALIGNED_PROOF_AGG_CONFIG_FILE") + @verifyRisc0_solidity_signature "0x015f8668" + @verifySp1_solidity_signature "0x39c94cbf" config_file_path = case @aligned_config_file do @@ -66,6 +68,24 @@ defmodule AlignedProofAggregationService do end end + # From a given aggregated proof event, it fetches the transaction + # and returns the aggregator (:sp1, :risc0) based on the function signature + def get_aggregator!(agg_proof) do + tx_hash = agg_proof.tx_hash + {:ok, tx} = Explorer.EthClient.get_transaction_by_hash(tx_hash) + input = Map.get(tx, "input") + # In solidity, the function signatures are the first 4 bytes of the input + # Note: first two characters are the 0x + function_signature = String.slice(input, 0..9) + IO.inspect(function_signature, label: "SIGNATURE") + + case function_signature do + @verifyRisc0_solidity_signature -> :risc0 + @verifySp1_solidity_signature -> :sp1 + _ -> nil + end + end + def get_block_timestamp(block_number) do case Ethers.Utils.get_block_timestamp(block_number) do {:ok, timestamp} -> DateTime.from_unix!(timestamp) diff --git a/explorer/lib/explorer/eth_client.ex b/explorer/lib/explorer/eth_client.ex index 61756e01ac..4c790374ca 100644 --- a/explorer/lib/explorer/eth_client.ex +++ b/explorer/lib/explorer/eth_client.ex @@ -6,6 +6,10 @@ defmodule Explorer.EthClient do eth_send("eth_getBlockByNumber", [block_number, false]) end + def get_transaction_by_hash(tx_hash) do + eth_send("eth_getTransactionByHash", [tx_hash]) + end + defp eth_send(method, params, id \\ 1) do headers = [{"Content-Type", "application/json"}] body = Jason.encode!(%{jsonrpc: "2.0", method: method, params: params, id: id}) @@ -15,9 +19,14 @@ defmodule Explorer.EthClient do case response do {:ok, %Finch.Response{status: 200, body: body}} -> case Jason.decode(body) do - {:ok, %{error: error} = _} -> {:error, error.message} - {:ok, body} -> {:ok, Map.get(body, "result")} - {:error, _} -> {:error, :invalid_json} + {:ok, %{"error" => %{"message" => message}}} -> + {:error, message} + + {:ok, body} -> + {:ok, Map.get(body, "result")} + + {:error, _} -> + {:error, :invalid_json} end {:ok, %Finch.Response{status: status}} -> diff --git a/explorer/lib/explorer/periodically.ex b/explorer/lib/explorer/periodically.ex index 077519a46c..f4093f5a50 100644 --- a/explorer/lib/explorer/periodically.ex +++ b/explorer/lib/explorer/periodically.ex @@ -24,7 +24,7 @@ defmodule Explorer.Periodically do :timer.send_interval(one_second * seconds_in_an_hour, :restakings) # Fetch new aggregated proofs every 1 minute - :timer.send_interval(one_second * 60, :aggregated_proofs) + :timer.send_interval(one_second * 12, :aggregated_proofs) end # Reads and process last blocks for operators and restaking changes @@ -78,11 +78,11 @@ defmodule Explorer.Periodically do def handle_info(:aggregated_proofs, state) do # This task runs every hour # We read a bit more than 300 blocks (1hr) to make sure we don't lose any event - read_block_qty = 310 + read_block_qty = 5000 latest_block_number = AlignedLayerServiceManager.get_latest_block_number() read_from_block = max(0, latest_block_number - read_block_qty) - Task.start(fn -> process_aggregated_proofs(read_from_block, latest_block_number) end) + Task.start(fn -> process_aggregated_proofs(3_734_200, 3_734_500) end) {:noreply, state} end @@ -113,8 +113,11 @@ defmodule Explorer.Periodically do proofs |> Enum.zip(proof_hashes) |> Enum.map(fn {agg_proof, hashes} -> + aggregator = AlignedProofAggregationService.get_aggregator!(agg_proof) + agg_proof = agg_proof + |> Map.merge(%{aggregator: aggregator}) |> Map.merge(%{number_of_proofs: length(hashes)}) {:ok, %{id: id}} = AggregatedProofs.insert_or_update(agg_proof) diff --git a/explorer/priv/repo/migrations/20250428144500_add_aggegator_to_agg_proofs.exs b/explorer/priv/repo/migrations/20250428144500_add_aggegator_to_agg_proofs.exs new file mode 100644 index 0000000000..c9f49aa18e --- /dev/null +++ b/explorer/priv/repo/migrations/20250428144500_add_aggegator_to_agg_proofs.exs @@ -0,0 +1,9 @@ +defmodule Explorer.Repo.Migrations.AddAggregatorToAggProofs do + use Ecto.Migration + + def change do + alter table(:aggregated_proofs) do + add(:aggregator, :string, default: nil) + end + end +end From c7de9fd45f1d9d0c00335bb8aff91b0f578d65ae Mon Sep 17 00:00:00 2001 From: Marcos Nicolau Date: Tue, 29 Apr 2025 11:00:58 -0300 Subject: [PATCH 3/6] feat: risc0 and sp1 badges components --- .../components/agg_proofs_table.ex | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/explorer/lib/explorer_web/components/agg_proofs_table.ex b/explorer/lib/explorer_web/components/agg_proofs_table.ex index 727f51cb4f..312fb6a92b 100644 --- a/explorer/lib/explorer_web/components/agg_proofs_table.ex +++ b/explorer/lib/explorer_web/components/agg_proofs_table.ex @@ -44,7 +44,34 @@ defmodule ExplorerWeb.AggProofsTable do <:col :let={proof} label="Number of proofs"> <%= proof.number_of_proofs |> Helpers.format_number() %> + + <:col :let={proof} label="Aggregator"> + <%= case proof.aggregator do %> + <% :sp1 -> %> + <.sp1_badge /> + <% :risc0 -> %> + <.risc0_badge /> + <% _ -> %> + Unknown + <% end %> + """ end + + defp sp1_badge(assigns) do + ~H""" +
+

SP1

+
+ """ + end + + defp risc0_badge(assigns) do + ~H""" +
+

RISC0

+
+ """ + end end From b2989a98028a2c4a228590cfe06fd1cf5f2a4856 Mon Sep 17 00:00:00 2001 From: Marcos Nicolau Date: Tue, 29 Apr 2025 11:17:14 -0300 Subject: [PATCH 4/6] feat: aggregator column on agg proof detail --- .../explorer_web/components/agg_proofs_table.ex | 4 ++-- .../live/pages/agg_proof/index.html.heex | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/explorer/lib/explorer_web/components/agg_proofs_table.ex b/explorer/lib/explorer_web/components/agg_proofs_table.ex index 312fb6a92b..6f39e53891 100644 --- a/explorer/lib/explorer_web/components/agg_proofs_table.ex +++ b/explorer/lib/explorer_web/components/agg_proofs_table.ex @@ -61,7 +61,7 @@ defmodule ExplorerWeb.AggProofsTable do defp sp1_badge(assigns) do ~H""" -
+

SP1

""" @@ -69,7 +69,7 @@ defmodule ExplorerWeb.AggProofsTable do defp risc0_badge(assigns) do ~H""" -
+

RISC0

""" diff --git a/explorer/lib/explorer_web/live/pages/agg_proof/index.html.heex b/explorer/lib/explorer_web/live/pages/agg_proof/index.html.heex index 0a7012b995..f45c91450a 100644 --- a/explorer/lib/explorer_web/live/pages/agg_proof/index.html.heex +++ b/explorer/lib/explorer_web/live/pages/agg_proof/index.html.heex @@ -22,6 +22,18 @@

+
+

+ Aggregator: +

+ <%= case @agg_proof.aggregator do %> + <% :sp1 -> %> +

SP1

+ <% :risc0 -> %> +

RISC0

+ <% end %> +
+

Number of Proofs included: @@ -110,7 +122,7 @@

Oops!

- The batch you are looking for
doesn't exist. + The aggregated proof you are looking for
doesn't exist.

Date: Tue, 29 Apr 2025 11:51:46 -0300 Subject: [PATCH 5/6] chore: remove debug logs --- .../contract_managers/aligned_proof_aggregation_service.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/explorer/lib/explorer/contract_managers/aligned_proof_aggregation_service.ex b/explorer/lib/explorer/contract_managers/aligned_proof_aggregation_service.ex index 57da298ba5..a290201fdb 100644 --- a/explorer/lib/explorer/contract_managers/aligned_proof_aggregation_service.ex +++ b/explorer/lib/explorer/contract_managers/aligned_proof_aggregation_service.ex @@ -77,7 +77,6 @@ defmodule AlignedProofAggregationService do # In solidity, the function signatures are the first 4 bytes of the input # Note: first two characters are the 0x function_signature = String.slice(input, 0..9) - IO.inspect(function_signature, label: "SIGNATURE") case function_signature do @verifyRisc0_solidity_signature -> :risc0 From 0092970be29b0deb6344852e034d782a9a6f0e46 Mon Sep 17 00:00:00 2001 From: Marcos Nicolau Date: Tue, 29 Apr 2025 18:49:40 -0300 Subject: [PATCH 6/6] chore: remove hardcoded values in agg proof periodic work --- explorer/lib/explorer/periodically.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/explorer/lib/explorer/periodically.ex b/explorer/lib/explorer/periodically.ex index f4093f5a50..377870e6fa 100644 --- a/explorer/lib/explorer/periodically.ex +++ b/explorer/lib/explorer/periodically.ex @@ -24,7 +24,7 @@ defmodule Explorer.Periodically do :timer.send_interval(one_second * seconds_in_an_hour, :restakings) # Fetch new aggregated proofs every 1 minute - :timer.send_interval(one_second * 12, :aggregated_proofs) + :timer.send_interval(one_second * 60, :aggregated_proofs) end # Reads and process last blocks for operators and restaking changes @@ -78,11 +78,11 @@ defmodule Explorer.Periodically do def handle_info(:aggregated_proofs, state) do # This task runs every hour # We read a bit more than 300 blocks (1hr) to make sure we don't lose any event - read_block_qty = 5000 + read_block_qty = 310 latest_block_number = AlignedLayerServiceManager.get_latest_block_number() read_from_block = max(0, latest_block_number - read_block_qty) - Task.start(fn -> process_aggregated_proofs(3_734_200, 3_734_500) end) + Task.start(fn -> process_aggregated_proofs(read_from_block, latest_block_number) end) {:noreply, state} end