Skip to content

Commit 2e11a4b

Browse files
committed
feat: beacon client to fetch blob data
1 parent e3883d0 commit 2e11a4b

File tree

5 files changed

+77
-26
lines changed

5 files changed

+77
-26
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
defmodule Explorer.BeaconClient do
2+
@beacon_url System.get_env("BEACON_API_URL")
3+
# See https://eips.ethereum.org/EIPS/eip-4844#parameters
4+
@versioned_hash_version_kzg 0x01
5+
6+
def fetch_blob_by_versioned_hash(block_number, blob_versioned_hash) do
7+
case get_block_blobs(block_number) do
8+
{:ok, blobs} ->
9+
Enum.find(blobs, fn blob -> get_blob_versioned_hash(blob) == blob_versioned_hash end)
10+
11+
{:error, reason} ->
12+
{:error, reason}
13+
end
14+
end
15+
16+
def get_blob_versioned_hash(blob) do
17+
hash = Explorer.Utils.sha256_hash_raw(blob.kzg_commitment)
18+
# See https://eips.ethereum.org/EIPS/eip-4844#helpers
19+
<<_first::8, rest::binary>> = hash
20+
<<@versioned_hash_version_kzg::8>> <> rest
21+
end
22+
23+
def get_block_blobs(block_number) do
24+
case beacon_get("/eth/v1/beacon/blob_sidecars/" <> block_number) do
25+
{:ok, res} -> res.data
26+
{:error, reason} -> {:error, reason}
27+
end
28+
end
29+
30+
def beacon_get(method) do
31+
headers = [{"Content-Type", "application/json"}]
32+
request = Finch.build(:get, @beacon_url <> method, headers)
33+
response = Finch.request(request, Explorer.Finch)
34+
35+
case status do
36+
{:ok, %Finch.Response{status: 200, body: body}} ->
37+
case Jason.decode(body) do
38+
{:ok, decoded_body} -> {:ok, decoded_body}
39+
{:error, _} -> {:error, :invalid_json}
40+
end
41+
42+
{:ok, %Finch.Response{status: status}} ->
43+
{:error, status}
44+
45+
{:error, reason} ->
46+
{:error, reason}
47+
end
48+
end
49+
end

explorer/lib/explorer/contract_managers/aligned_proof_aggregation_service.ex

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,13 @@ defmodule AlignedProofAggregationService do
6767
end
6868
end
6969

70-
def get_blob_data_from_versioned_hash(versioned_hash) do
71-
# Fetch blob data from a beacon client
72-
"Getting blob data from blob versioned hash: #{versioned_hash}" |> Logger.debug()
73-
# List of bytes
74-
blob_data = []
75-
blob_data
70+
def get_blob_data_from_versioned_hash(aggregated_proof) do
71+
case BeaconClient.fetch_blob_by_versioned_hash(
72+
aggregated_proof.block_number,
73+
aggregated_proof.blob_versioned_hash
74+
) do
75+
{:ok, data} -> data.blob
76+
{:error, reason} -> {:error, reason}
77+
end
7678
end
7779
end

explorer/lib/explorer/periodically.ex

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,6 @@ defmodule Explorer.Periodically do
8080
latest_block_number = AlignedLayerServiceManager.get_latest_block_number()
8181
read_from_block = max(0, latest_block_number - read_block_qty)
8282

83-
## What we need to do:
84-
## 1. Calculate the logs to fetch from block number
85-
## 2. Fetch the events: NewAggregatedProof
86-
## 3. For the successful verifications query the blob from a beacon client
87-
## 4. When getting the blob data, split in chunks of 32,
88-
## 5. Store each hash in proof hash pointing to the aggregated proof number
89-
## 6. Store the info in db
90-
9183
process_aggregated_proofs(read_from_block, latest_block_number)
9284
end
9385

@@ -103,17 +95,15 @@ defmodule Explorer.Periodically do
10395
Map.merge(
10496
x,
10597
%{
106-
blob_data:
107-
AlignedProofAggregationService.get_blob_data_from_versioned_hash(
108-
x.blob_versioned_hash
109-
)
98+
blob_data: AlignedProofAggregationService.get_blob_data_from_versioned_hash(x)
11099
}
111100
)
112101
end)
113102

114103
# Split the blob data in chunks of 32 to get the number of leaves (number of proofs) in the aggregated proof
104+
## TODO fix this parsing
115105
proofs_leaves =
116-
Enum.map(aggregated_proofs, fn x -> chunk_every(x.blob_data, 2) end)
106+
Enum.map(aggregated_proofs, fn x -> chunk_every(x.blob_data, 32) end)
117107

118108
# Store aggregated proofs to db
119109
aggregated_proofs
@@ -127,13 +117,11 @@ defmodule Explorer.Periodically do
127117
aggregated_proofs
128118
|> Enum.zip(proofs_leaves)
129119
|> Enum.map(fn %{agg_proof, leaves} ->
130-
Enum.map(leaves, fn leaf ->
131-
%{
132-
AggregatedProof.insert_proof(%{
133-
aggregated_proof_number: agg_proof.number,
134-
proof_hash: leaf
135-
})
136-
}
120+
Enum.each(leaves, fn leaf ->
121+
AggregatedProof.insert_proof(%{
122+
aggregated_proof_number: agg_proof.number,
123+
proof_hash: leaf
124+
})
137125
end)
138126
end)
139127
end

explorer/lib/explorer/utils.ex

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
defmodule Explorer.Utils do
2+
def sha256_hash(data) do
3+
## Base 16 encoder needed as crypto.hash returns raw bytes
4+
:crypto.hash(:sha256, data) |> Base.encode16(case: :lower)
5+
end
6+
7+
## Returns hash raw bytes
8+
def sha256_hash_raw(data) do
9+
:crypto.hash(:sha256, data)
10+
end
11+
end

explorer/mix.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ defmodule Explorer.MixProject do
6464
{:mutex, "~> 2.0"},
6565
{:tails, "~> 0.1.5"},
6666
{:cors_plug, "~> 3.0"},
67+
{:crypto, "~> 1.11"}
6768
]
6869
end
6970

0 commit comments

Comments
 (0)