chore: Add API endpoint for OP batch blocks (#10566)

* API endpoint for OP batch blocks

* Minor refactoring

* mix format

---------

Co-authored-by: POA <33550681+poa@users.noreply.github.com>
pull/10590/head
varasev 3 months ago committed by GitHub
parent 1fd2a8f3a2
commit c846237ac8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 28
      apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex
  2. 13
      apps/block_scout_web/lib/block_scout_web/controllers/api/v2/optimism_controller.ex
  3. 4
      apps/block_scout_web/lib/block_scout_web/routers/api_router.ex
  4. 3
      apps/block_scout_web/lib/block_scout_web/views/api/v2/optimism_view.ex
  5. 51
      apps/explorer/lib/explorer/chain/optimism/txn_batch.ex

@ -35,6 +35,7 @@ defmodule BlockScoutWeb.API.V2.BlockController do
alias Explorer.Chain.Celo.EpochReward, as: CeloEpochReward
alias Explorer.Chain.Celo.Reader, as: CeloReader
alias Explorer.Chain.InternalTransaction
alias Explorer.Chain.Optimism.TxnBatch, as: OptimismTxnBatch
case Application.compile_env(:explorer, :chain_type) do
:ethereum ->
@ -197,6 +198,33 @@ defmodule BlockScoutWeb.API.V2.BlockController do
})
end
@doc """
Function to handle GET requests to `/api/v2/blocks/optimism-batch/:batch_number` endpoint.
It renders the list of L2 blocks bound to the specified batch.
"""
@spec optimism_batch(Plug.Conn.t(), any()) :: Plug.Conn.t()
def optimism_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
|> OptimismTxnBatch.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.
"""

@ -15,7 +15,16 @@ defmodule BlockScoutWeb.API.V2.OptimismController do
alias Explorer.Chain
alias Explorer.Chain.Transaction
alias Explorer.Chain.Optimism.{Deposit, DisputeGame, FrameSequence, OutputRoot, TxnBatch, Withdrawal}
alias Explorer.Chain.Optimism.{
Deposit,
DisputeGame,
FrameSequence,
FrameSequenceBlob,
OutputRoot,
TxnBatch,
Withdrawal
}
action_fallback(BlockScoutWeb.API.V2.FallbackController)
@ -74,10 +83,12 @@ defmodule BlockScoutWeb.API.V2.OptimismController do
l2_block_number_from = TxnBatch.edge_l2_block_number(fs.id, :min)
l2_block_number_to = TxnBatch.edge_l2_block_number(fs.id, :max)
tx_count = Transaction.tx_count_for_block_range(l2_block_number_from..l2_block_number_to)
{batch_data_container, _} = FrameSequenceBlob.list(fs.id, api?: true)
fs
|> Map.put(:l2_block_range, l2_block_number_from..l2_block_number_to)
|> Map.put(:tx_count, tx_count)
|> Map.put(:batch_data_container, batch_data_container)
end)
end)
|> Task.yield_many(:infinity)

@ -164,6 +164,10 @@ defmodule BlockScoutWeb.Routers.ApiRouter do
get("/:block_hash_or_number/epoch", V2.BlockController, :celo_epoch)
get("/:block_hash_or_number/election-rewards/:reward_type", V2.BlockController, :celo_election_rewards)
end
if Application.compile_env(:explorer, :chain_type) == :optimism do
get("/optimism-batch/:batch_number", V2.BlockController, :optimism_batch)
end
end
scope "/addresses" do

@ -68,7 +68,8 @@ defmodule BlockScoutWeb.API.V2.OptimismView do
"l2_block_start" => from,
"l2_block_end" => to,
"tx_count" => batch.tx_count,
"l1_tx_hashes" => batch.l1_transaction_hashes
"l1_tx_hashes" => batch.l1_transaction_hashes,
"batch_data_container" => batch.batch_data_container
}
end)

@ -16,8 +16,9 @@ defmodule Explorer.Chain.Optimism.TxnBatch do
use Explorer.Schema
import Explorer.Chain, only: [default_paging_options: 0, join_association: 3, select_repo: 1]
import Explorer.Chain, only: [default_paging_options: 0, join_association: 3, join_associations: 2, select_repo: 1]
alias Explorer.Chain.Block
alias Explorer.Chain.Optimism.FrameSequence
alias Explorer.{PagingOptions, Repo}
@ -136,6 +137,54 @@ defmodule Explorer.Chain.Optimism.TxnBatch do
end
end
@doc """
Retrieves a list of rollup blocks included into a specified batch.
This function constructs and executes a database query to retrieve a list of rollup blocks,
considering pagination options specified in the `options` parameter. These options dictate
the number of items to retrieve and how many items to skip from the top.
## Parameters
- `batch_number`: The batch number whose transactions are included on L1.
- `options`: A keyword list of options specifying pagination, association necessity, and
whether to use a replica database.
## Returns
- A list of `Explorer.Chain.Block` entries belonging to the specified batch.
"""
@spec batch_blocks(non_neg_integer() | binary(),
necessity_by_association: %{atom() => :optional | :required},
api?: boolean(),
paging_options: PagingOptions.t()
) :: [Block.t()]
def batch_blocks(batch_number, options) do
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
paging_options = Keyword.get(options, :paging_options, default_paging_options())
query =
from(
b in Block,
inner_join: tb in __MODULE__,
on: tb.l2_block_number == b.number and tb.frame_sequence_id == ^batch_number,
where: b.consensus == true
)
query
|> page_blocks(paging_options)
|> limit(^paging_options.page_size)
|> order_by(desc: :number)
|> join_associations(necessity_by_association)
|> select_repo(options).all()
end
defp page_blocks(query, %PagingOptions{key: nil}), do: query
defp page_blocks(query, %PagingOptions{key: {0}}), do: query
defp page_blocks(query, %PagingOptions{key: {block_number}}) do
where(query, [block], block.number < ^block_number)
end
@doc """
Decodes EIP-4844 blob to the raw data. Returns `nil` if the blob is invalid.
"""

Loading…
Cancel
Save