Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: indexer for cross level messages on Arbitrum #9312

Merged
merged 84 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
42f39e9
Initial version of x-level messages indexer
akolotov Feb 2, 2024
f9e9a81
fixes for cspell and credo
akolotov Feb 2, 2024
95417b2
new state of x-level messages
akolotov Feb 2, 2024
7437e82
Monitoring of new L1-to-L2 messages on L1
akolotov Feb 8, 2024
73de8b8
new batches discovery
akolotov Feb 14, 2024
1ce0957
fetcher workers in separate modules
akolotov Feb 15, 2024
aabfcc1
proper name
akolotov Feb 15, 2024
63d9e2b
Fix for responses without "id", e.g. "Too Many Requests"
akolotov Feb 18, 2024
9f40882
update DB with new batches and corresponding data
akolotov Feb 19, 2024
6f316b5
update DB with confirmed blocks
akolotov Feb 28, 2024
1298fa0
fixes for cspell and credo
akolotov Feb 28, 2024
e3d4ee5
tracking commitments confirmations for L1 to L2 messages
akolotov Mar 1, 2024
3329742
Proper usign of max function
akolotov Mar 1, 2024
cf477f1
tracking completion of L2 to L1 messages
akolotov Mar 1, 2024
6b4bbb0
catchup historical messages to L2
akolotov Mar 6, 2024
b75e7dc
incorrect version of committed file
akolotov Mar 6, 2024
a38bd02
catchup historical messages from L2 and completion of L1-to-L2 messages
akolotov Mar 6, 2024
3f92409
historical batches catchup
akolotov Mar 7, 2024
b540efa
status for historical l2-to-l1 messages
akolotov Mar 7, 2024
695ba8b
address matching issue
akolotov Mar 7, 2024
c7cd0d8
catchup historical executions of L2-to-L1 messages
akolotov Mar 8, 2024
3dc4e2e
db query to find unconfirmed blocks gaps
akolotov Mar 12, 2024
3988b87
first changes to catchup historical confirmations
akolotov Mar 13, 2024
8368931
finalized catchup of historical confirmations
akolotov Mar 15, 2024
36bab5e
Merge branch 'master' into feature/arbitrum/bridge
akolotov Mar 15, 2024
f51493b
4844 blobs support
akolotov Mar 18, 2024
fbc2f03
Merge branch 'master' into feature/arbitrum/bridge
akolotov Mar 18, 2024
3965e3a
fix for the issue with multiple confirmations
akolotov Mar 18, 2024
56db5b1
limit amount of batches to handle at once
akolotov Mar 18, 2024
49bf214
Use latest L1 block by fetchers if start block is not configured
akolotov Mar 20, 2024
0d60e2f
merge issue fix
akolotov Mar 20, 2024
53df4f2
missed file
akolotov Mar 20, 2024
2734987
historical messages discovery
akolotov Mar 26, 2024
dc101ad
Merge branch 'master' into feature/arbitrum/bridge
akolotov Mar 26, 2024
28668e2
reduce logs severity
akolotov Mar 28, 2024
cbd02b8
first iteration to improve documentation for new functionality
akolotov Mar 28, 2024
d90f5a9
Merge branch 'master' into feature/arbitrum/bridge
akolotov Mar 28, 2024
75d3a3c
second iteration to improve documentation for new functionality
akolotov Mar 29, 2024
ec50967
Merge branch 'master' into feature/arbitrum/bridge
akolotov Mar 29, 2024
14e9a46
third iteration to improve documentation for new functionality
akolotov Apr 1, 2024
4ab9034
fourth iteration to improve documentation for new functionality
akolotov Apr 4, 2024
1879c60
Merge branch 'master' into feature/arbitrum/bridge
akolotov Apr 4, 2024
a268c90
fifth iteration to improve documentation for new functionality
akolotov Apr 4, 2024
6ccf897
final iteration to improve documentation for new functionality
akolotov Apr 10, 2024
6eac50d
Merge branch 'master' into feature/arbitrum/bridge
akolotov Apr 10, 2024
e84a9e4
Merge branch 'master' into feature/arbitrum/bridge
akolotov Apr 17, 2024
c280488
Merge branch 'master' into feature/arbitrum/bridge
akolotov Apr 26, 2024
3fbb9f6
merge issues addressed
akolotov Apr 26, 2024
414fd2b
Merge branch 'master' into feature/arbitrum/bridge
akolotov Apr 29, 2024
4cc6f1d
code review issues addressed
akolotov Apr 30, 2024
f411222
Merge branch 'master' into feature/arbitrum/bridge
akolotov Apr 30, 2024
8156d20
code review issues addressed
akolotov May 1, 2024
f36495d
fix merge issue
akolotov May 1, 2024
79e5936
Merge branch 'master' into feature/arbitrum/bridge
akolotov May 1, 2024
d57aad4
raising exception in the case of DB inconsistency
akolotov May 1, 2024
685fdff
fix formatting issue
akolotov May 1, 2024
77383ab
termination case for RollupMessagesCatchup
akolotov May 1, 2024
2219173
code review comments addressed
akolotov May 2, 2024
1b93945
Merge branch 'master' into feature/arbitrum/bridge
akolotov May 2, 2024
8912b3d
code review comments addressed
akolotov May 6, 2024
cda998c
consistency in primary keys
akolotov May 6, 2024
62352bd
Merge branch 'master' into feature/arbitrum/bridge
akolotov May 7, 2024
4745c53
dialyzer fix
akolotov May 7, 2024
9f26bec
code review comments addressed
akolotov May 7, 2024
e3a50d1
missed doc comment
akolotov May 7, 2024
d98e0c7
code review comments addressed
akolotov May 7, 2024
dcff53b
Merge branch 'master' into feature/arbitrum/bridge
akolotov May 8, 2024
3a2110c
Merge branch 'master' into feature/arbitrum/bridge
akolotov May 14, 2024
d104114
updated indices creation as per code review comments
akolotov May 14, 2024
f6c9d8a
Merge branch 'master' into feature/arbitrum/bridge
akolotov May 15, 2024
550fe5e
Merge branch 'master' into feature/arbitrum/bridge
akolotov May 17, 2024
343efe5
fix merge issue
akolotov May 17, 2024
4e1dc66
configuration of intervals as time variables
akolotov May 20, 2024
deceef2
TODO added to reflect improvement ability
akolotov May 20, 2024
66544a2
database fields refactoring
akolotov May 20, 2024
e7670d3
Merge branch 'master' into feature/arbitrum/bridge
akolotov May 20, 2024
3d81e76
association renaming
akolotov May 21, 2024
944a4b7
feat: APIv2 endpoints for Arbitrum messages and batches (#9963)
akolotov May 22, 2024
2effba4
feat: Arbitrum-specific fields in the block and transaction API endpo…
akolotov May 22, 2024
d0225b0
fix credo issue
akolotov May 22, 2024
0cff89b
fix tests issues
akolotov May 22, 2024
2afb86f
ethereumjsonrpc test fail investigation
akolotov May 22, 2024
717c495
test issues fixes
akolotov May 23, 2024
b87be60
Merge branch 'master' into feature/arbitrum/bridge
akolotov May 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 24 additions & 0 deletions apps/block_scout_web/lib/block_scout_web/api_router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ defmodule BlockScoutWeb.ApiRouter do
get("/zksync-batch/:batch_number", V2.TransactionController, :zksync_batch)
end

if Application.compile_env(:explorer, :chain_type) == :arbitrum do
get("/arbitrum-batch/:batch_number", V2.TransactionController, :arbitrum_batch)
end

if Application.compile_env(:explorer, :chain_type) == :suave do
get("/execution-node/:execution_node_hash_param", V2.TransactionController, :execution_node)
end
Expand All @@ -219,6 +223,10 @@ defmodule BlockScoutWeb.ApiRouter do
get("/:block_hash_or_number/transactions", V2.BlockController, :transactions)
get("/:block_hash_or_number/internal-transactions", V2.BlockController, :internal_transactions)
get("/:block_hash_or_number/withdrawals", V2.BlockController, :withdrawals)

if Application.compile_env(:explorer, :chain_type) == :arbitrum do
get("/arbitrum-batch/:batch_number", V2.BlockController, :arbitrum_batch)
end
end

scope "/addresses" do
Expand Down Expand Up @@ -277,6 +285,12 @@ defmodule BlockScoutWeb.ApiRouter do
get("/zksync/batches/confirmed", V2.ZkSyncController, :batches_confirmed)
get("/zksync/batches/latest-number", V2.ZkSyncController, :batch_latest_number)
end

if Application.compile_env(:explorer, :chain_type) == :arbitrum do
get("/arbitrum/messages/to-rollup", V2.ArbitrumController, :recent_messages_to_l2)
get("/arbitrum/batches/committed", V2.ArbitrumController, :batches_committed)
get("/arbitrum/batches/latest-number", V2.ArbitrumController, :batch_latest_number)
end
end

scope "/stats" do
Expand Down Expand Up @@ -402,6 +416,16 @@ defmodule BlockScoutWeb.ApiRouter do
get("/worlds/:world/tables/:table_id/records/:record_id", V2.MudController, :world_table_record)
end
end

scope "/arbitrum" do
if Application.compile_env(:explorer, :chain_type) == :arbitrum do
get("/messages/:direction", V2.ArbitrumController, :messages)
get("/messages/:direction/count", V2.ArbitrumController, :messages_count)
get("/batches", V2.ArbitrumController, :batches)
get("/batches/count", V2.ArbitrumController, :batches_count)
get("/batches/:batch_number", V2.ArbitrumController, :batch)
end
end
end

scope "/v1/graphql" do
Expand Down
12 changes: 10 additions & 2 deletions apps/block_scout_web/lib/block_scout_web/chain.ex
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,11 @@ defmodule BlockScoutWeb.Chain do
end
end

# clause for Polygon Edge Deposits and Withdrawals and for account's entities pagination
# clause for pagination of entities:
# - Account's entities
# - Polygon Edge Deposits
# - Polygon Edge Withdrawals
# - Arbitrum cross chain messages
def paging_options(%{"id" => id_string}) when is_binary(id_string) do
case Integer.parse(id_string) do
{id, ""} ->
Expand All @@ -444,7 +448,11 @@ defmodule BlockScoutWeb.Chain do
end
end

# clause for Polygon Edge Deposits and Withdrawals and for account's entities pagination
# clause for pagination of entities:
# - Account's entities
# - Polygon Edge Deposits
# - Polygon Edge Withdrawals
# - Arbitrum cross chain messages
def paging_options(%{"id" => id}) when is_integer(id) do
[paging_options: %{@default_paging_options | key: {id}}]
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
defmodule BlockScoutWeb.API.V2.ArbitrumController do
use BlockScoutWeb, :controller

import BlockScoutWeb.Chain,
only: [
next_page_params: 4,
paging_options: 1,
split_list_by_page: 1
]

alias Explorer.PagingOptions
alias Explorer.Chain.Arbitrum.{L1Batch, Message, Reader}

action_fallback(BlockScoutWeb.API.V2.FallbackController)

@batch_necessity_by_association %{:commitment_transaction => :optional}

@doc """
Function to handle GET requests to `/api/v2/arbitrum/messages/:direction` endpoint.
"""
@spec messages(Plug.Conn.t(), map()) :: Plug.Conn.t()
def messages(conn, %{"direction" => direction} = params) do
options =
params
|> paging_options()
|> Keyword.put(:api?, true)

{messages, next_page} =
direction
|> Reader.messages(options)
|> split_list_by_page()

next_page_params =
next_page_params(
next_page,
messages,
params,
fn %Message{message_id: msg_id} -> %{"id" => msg_id} end
)

conn
|> put_status(200)
|> render(:arbitrum_messages, %{
messages: messages,
next_page_params: next_page_params
})
end

@doc """
Function to handle GET requests to `/api/v2/arbitrum/messages/:direction/count` endpoint.
"""
@spec messages_count(Plug.Conn.t(), map()) :: Plug.Conn.t()
def messages_count(conn, %{"direction" => direction} = _params) do
conn
|> put_status(200)
|> render(:arbitrum_messages_count, %{count: Reader.messages_count(direction, api?: true)})
end

@doc """
Function to handle GET requests to `/api/v2/arbitrum/batches/:batch_number` endpoint.
"""
@spec batch(Plug.Conn.t(), map()) :: Plug.Conn.t()
def batch(conn, %{"batch_number" => batch_number} = _params) do
case Reader.batch(
batch_number,
necessity_by_association: @batch_necessity_by_association,
api?: true
) do
{:ok, batch} ->
conn
|> put_status(200)
|> render(:arbitrum_batch, %{batch: batch})

{:error, :not_found} = res ->
res
end
end

@doc """
Function to handle GET requests to `/api/v2/arbitrum/batches/count` endpoint.
"""
@spec batches_count(Plug.Conn.t(), map()) :: Plug.Conn.t()
def batches_count(conn, _params) do
conn
|> put_status(200)
|> render(:arbitrum_batches_count, %{count: Reader.batches_count(api?: true)})
end

@doc """
Function to handle GET requests to `/api/v2/arbitrum/batches` endpoint.
"""
@spec batches(Plug.Conn.t(), map()) :: Plug.Conn.t()
def batches(conn, params) do
{batches, next_page} =
params
|> paging_options()
|> Keyword.put(:necessity_by_association, @batch_necessity_by_association)
|> Keyword.put(:api?, true)
|> Reader.batches()
|> split_list_by_page()

next_page_params =
next_page_params(
next_page,
batches,
params,
fn %L1Batch{number: number} -> %{"number" => number} end
)

conn
|> put_status(200)
|> render(:arbitrum_batches, %{
batches: batches,
next_page_params: next_page_params
})
end

@doc """
Function to handle GET requests to `/api/v2/main-page/arbitrum/batches/committed` endpoint.
"""
@spec batches_committed(Plug.Conn.t(), map()) :: Plug.Conn.t()
def batches_committed(conn, _params) do
batches =
[]
|> Keyword.put(:necessity_by_association, @batch_necessity_by_association)
|> Keyword.put(:api?, true)
|> Keyword.put(:committed?, true)
|> Reader.batches()

conn
|> put_status(200)
|> render(:arbitrum_batches, %{batches: batches})
end

@doc """
Function to handle GET requests to `/api/v2/main-page/arbitrum/batches/latest-number` endpoint.
"""
@spec batch_latest_number(Plug.Conn.t(), map()) :: Plug.Conn.t()
def batch_latest_number(conn, _params) do
conn
|> put_status(200)
|> render(:arbitrum_batch_latest_number, %{number: batch_latest_number()})
end

defp batch_latest_number do
case Reader.batch(:latest, api?: true) do
{:ok, batch} -> batch.number
{:error, :not_found} -> 0
end
end

@doc """
Function to handle GET requests to `/api/v2/main-page/arbitrum/messages/to-rollup` endpoint.
"""
@spec recent_messages_to_l2(Plug.Conn.t(), map()) :: Plug.Conn.t()
def recent_messages_to_l2(conn, _params) do
messages = Reader.relayed_l1_to_l2_messages(paging_options: %PagingOptions{page_size: 6}, api?: true)

conn
|> put_status(200)
|> render(:arbitrum_messages, %{messages: messages})
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ defmodule BlockScoutWeb.API.V2.BlockController do

alias BlockScoutWeb.API.V2.{TransactionView, WithdrawalView}
alias Explorer.Chain
alias Explorer.Chain.Arbitrum.Reader, as: ArbitrumReader
alias Explorer.Chain.InternalTransaction

case Application.compile_env(:explorer, :chain_type) do
Expand All @@ -39,6 +40,14 @@ defmodule BlockScoutWeb.API.V2.BlockController do
:zksync_execute_transaction => :optional
}

:arbitrum ->
@chain_type_transaction_necessity_by_association %{}
@chain_type_block_necessity_by_association %{
:arbitrum_batch => :optional,
:arbitrum_commitment_transaction => :optional,
:arbitrum_confirmation_transaction => :optional
}

_ ->
@chain_type_transaction_necessity_by_association %{}
@chain_type_block_necessity_by_association %{}
Expand Down Expand Up @@ -85,20 +94,6 @@ defmodule BlockScoutWeb.API.V2.BlockController do
api?: true
]

@block_params [
necessity_by_association:
%{
[miner: :names] => :optional,
:uncles => :optional,
:nephews => :optional,
:rewards => :optional,
:transactions => :optional,
:withdrawals => :optional
}
|> Map.merge(@chain_type_block_necessity_by_association),
api?: true
]

action_fallback(BlockScoutWeb.API.V2.FallbackController)

@doc """
Expand Down Expand Up @@ -155,6 +150,33 @@ defmodule BlockScoutWeb.API.V2.BlockController do
})
end

@doc """
Function to handle GET requests to `/api/v2/blocks/arbitrum-batch/:batch_number` endpoint.
It renders the list of L2 blocks bound to the specified batch.
"""
@spec arbitrum_batch(Plug.Conn.t(), any()) :: Plug.Conn.t()
def arbitrum_batch(conn, %{"batch_number" => batch_number} = params) do
full_options =
params
|> select_block_type()
|> Keyword.merge(paging_options(params))
|> Keyword.merge(@api_true)

{blocks, next_page} =
batch_number
|> ArbitrumReader.batch_blocks(full_options)
|> split_list_by_page()

next_page_params = next_page |> next_page_params(blocks, delete_parameters_from_next_page_params(params))

conn
|> put_status(200)
|> render(:blocks, %{
blocks: blocks |> maybe_preload_ens() |> maybe_preload_metadata(),
next_page_params: next_page_params
})
end

@doc """
Function to handle GET requests to `/api/v2/blocks/:block_hash_or_number/transactions` endpoint.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
alias BlockScoutWeb.MicroserviceInterfaces.TransactionInterpretation, as: TransactionInterpretationService
alias BlockScoutWeb.Models.TransactionStateHelper
alias Explorer.Chain
alias Explorer.Chain.Arbitrum.Reader, as: ArbitrumReader
alias Explorer.Chain.Beacon.Reader, as: BeaconReader
alias Explorer.Chain.{Hash, InternalTransaction, Transaction}
alias Explorer.Chain.PolygonZkevm.Reader, as: PolygonZkevmReader
Expand Down Expand Up @@ -114,6 +115,14 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
|> Map.put(:zksync_prove_transaction, :optional)
|> Map.put(:zksync_execute_transaction, :optional)

:arbitrum ->
necessity_by_association_with_actions
|> Map.put(:arbitrum_batch, :optional)
|> Map.put(:arbitrum_commitment_transaction, :optional)
|> Map.put(:arbitrum_confirmation_transaction, :optional)
|> Map.put(:arbitrum_message_to_l2, :optional)
|> Map.put(:arbitrum_message_from_l2, :optional)

:suave ->
necessity_by_association_with_actions
|> Map.put(:logs, :optional)
Expand Down Expand Up @@ -194,7 +203,35 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
It renders the list of L2 transactions bound to the specified batch.
"""
@spec zksync_batch(Plug.Conn.t(), map()) :: Plug.Conn.t()
def zksync_batch(conn, %{"batch_number" => batch_number} = params) do
def zksync_batch(conn, params) do
handle_batch_transactions(conn, params, &ZkSyncReader.batch_transactions/2)
end

@doc """
Function to handle GET requests to `/api/v2/transactions/arbitrum-batch/:batch_number` endpoint.
It renders the list of L2 transactions bound to the specified batch.
"""
@spec arbitrum_batch(Plug.Conn.t(), map()) :: Plug.Conn.t()
def arbitrum_batch(conn, params) do
handle_batch_transactions(conn, params, &ArbitrumReader.batch_transactions/2)
end

# Processes and renders transactions for a specified batch into an HTTP response.
#
# This function retrieves a list of transactions for a given batch using a specified function,
# then extracts the transaction hashes. These hashes are used to retrieve the corresponding
# `Explorer.Chain.Transaction` records according to the given pagination options. It formats
# these transactions into an HTTP response.
#
# ## Parameters
# - `conn`: The connection object.
# - `params`: Parameters from the request, including the batch number.
# - `batch_transactions_fun`: A function to fetch transaction descriptions for the given batch.
#
# ## Returns
# - Updated connection object with the transactions data rendered.
@spec handle_batch_transactions(Plug.Conn.t(), map(), function()) :: Plug.Conn.t()
defp handle_batch_transactions(conn, %{"batch_number" => batch_number} = params, batch_transactions_fun) do
full_options =
[
necessity_by_association: @transaction_necessity_by_association
Expand All @@ -206,13 +243,13 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
# it will require to re-implement all pagination logic existing in Explorer.Chain.Transaction
# In order to simplify the code, all transaction are requested from the batch and then
# only subset of them is returned from `hashes_to_transactions`.
raw_transactions_list =
transactions_plus_one =
batch_number
|> ZkSyncReader.batch_transactions(api?: true)
|> Enum.map(fn tx -> tx.hash end)
|> batch_transactions_fun.(@api_true)
|> Enum.map(fn tx -> tx.tx_hash end)
|> Chain.hashes_to_transactions(full_options)

{transactions, next_page} = split_list_by_page(raw_transactions_list)
{transactions, next_page} = split_list_by_page(transactions_plus_one)
next_page_params = next_page |> next_page_params(transactions, delete_parameters_from_next_page_params(params))

conn
Expand Down