fix: proper lookup of confirmed Arbitrum cross-chain messages (#10322)

* extended types documentation

* proper query for confirmed messages
test-new-armbuilders
Alexander Kolotov 5 months ago committed by GitHub
parent e7fa979c15
commit bd09249c17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 29
      apps/explorer/lib/explorer/chain/arbitrum/batch_block.ex
  2. 21
      apps/explorer/lib/explorer/chain/arbitrum/batch_transaction.ex
  3. 40
      apps/explorer/lib/explorer/chain/arbitrum/l1_batch.ex
  4. 24
      apps/explorer/lib/explorer/chain/arbitrum/l1_execution.ex
  5. 40
      apps/explorer/lib/explorer/chain/arbitrum/lifecycle_transaction.ex
  6. 47
      apps/explorer/lib/explorer/chain/arbitrum/message.ex
  7. 30
      apps/explorer/lib/explorer/chain/arbitrum/reader.ex
  8. 19
      apps/indexer/lib/indexer/fetcher/arbitrum/utils/db.ex
  9. 25
      apps/indexer/lib/indexer/fetcher/arbitrum/workers/new_batches.ex
  10. 25
      apps/indexer/lib/indexer/fetcher/arbitrum/workers/new_confirmations.ex
  11. 32
      apps/indexer/lib/indexer/fetcher/arbitrum/workers/new_l1_executions.ex
  12. 10
      apps/indexer/lib/indexer/fetcher/arbitrum/workers/new_messages_to_l2.ex

@ -17,16 +17,31 @@ defmodule Explorer.Chain.Arbitrum.BatchBlock do
@required_attrs ~w(batch_number block_number)a
@type t :: %__MODULE__{
batch_number: non_neg_integer(),
batch: %Ecto.Association.NotLoaded{} | L1Batch.t() | nil,
block_number: non_neg_integer(),
confirmation_id: non_neg_integer() | nil,
confirmation_transaction: %Ecto.Association.NotLoaded{} | LifecycleTransaction.t() | nil
@typedoc """
Descriptor of the a rollup block included in an Arbitrum batch:
* `batch_number` - The number of the Arbitrum batch.
* `block_number` - The number of the rollup block.
* `confirmation_id` - The ID of the confirmation L1 transaction from
`Explorer.Chain.LifecycleTransaction`, or `nil` if the
block is not confirmed yet.
"""
@type to_import :: %{
:batch_number => non_neg_integer(),
:block_number => non_neg_integer(),
:confirmation_id => non_neg_integer() | nil
}
@typedoc """
* `batch_number` - The number of the Arbitrum batch.
* `block_number` - The number of the rollup block.
* `confirmation_id` - The ID of the confirmation L1 transaction from
`Explorer.Chain.Arbitrum.LifecycleTransaction`, or `nil`
if the block is not confirmed yet.
* `confirmation_transaction` - An instance of `Explorer.Chain.Arbitrum.LifecycleTransaction`
referenced by `confirmation_id`.
"""
@primary_key {:block_number, :integer, autogenerate: false}
schema "arbitrum_batch_l2_blocks" do
typed_schema "arbitrum_batch_l2_blocks" do
belongs_to(:batch, L1Batch, foreign_key: :batch_number, references: :number, type: :integer)
belongs_to(:confirmation_transaction, LifecycleTransaction,

@ -16,15 +16,24 @@ defmodule Explorer.Chain.Arbitrum.BatchTransaction do
@required_attrs ~w(batch_number tx_hash)a
@type t :: %__MODULE__{
batch_number: non_neg_integer(),
batch: %Ecto.Association.NotLoaded{} | L1Batch.t() | nil,
tx_hash: Hash.t(),
l2_transaction: %Ecto.Association.NotLoaded{} | Transaction.t() | nil
@typedoc """
Descriptor of the a rollup transaction included in an Arbitrum batch:
* `batch_number` - The number of the Arbitrum batch.
* `tx_hash` - The hash of the rollup transaction.
"""
@type to_import :: %{
:batch_number => non_neg_integer(),
:tx_hash => binary()
}
@typedoc """
* `tx_hash` - The hash of the rollup transaction.
* `l2_transaction` - An instance of `Explorer.Chain.Transaction` referenced by `tx_hash`.
* `batch_number` - The number of the Arbitrum batch.
* `batch` - An instance of `Explorer.Chain.Arbitrum.L1Batch` referenced by `batch_number`.
"""
@primary_key false
schema "arbitrum_batch_l2_transactions" do
typed_schema "arbitrum_batch_l2_transactions" do
belongs_to(:batch, L1Batch, foreign_key: :batch_number, references: :number, type: :integer)
belongs_to(:l2_transaction, Transaction,

@ -11,28 +11,44 @@ defmodule Explorer.Chain.Arbitrum.L1Batch do
use Explorer.Schema
alias Explorer.Chain.{
Block,
Hash
}
alias Explorer.Chain.Hash
alias Explorer.Chain.Arbitrum.LifecycleTransaction
@required_attrs ~w(number transactions_count start_block end_block before_acc after_acc commitment_id)a
@type t :: %__MODULE__{
@typedoc """
Descriptor of the a L1 batch for Arbitrum rollups:
* `number` - The number of the Arbitrum batch.
* `transactions_count` - The number of transactions in the batch.
* `start_block` - The number of the first block in the batch.
* `end_block` - The number of the last block in the batch.
* `before_acc` - The hash of the state before the batch.
* `after_acc` - The hash of the state after the batch.
* `commitment_id` - The ID of the commitment L1 transaction from Explorer.Chain.LifecycleTransaction.
"""
@type to_import :: %{
number: non_neg_integer(),
transactions_count: non_neg_integer(),
start_block: Block.block_number(),
end_block: Block.block_number(),
before_acc: Hash.t(),
after_acc: Hash.t(),
commitment_id: non_neg_integer(),
commitment_transaction: %Ecto.Association.NotLoaded{} | LifecycleTransaction.t() | nil
start_block: non_neg_integer(),
end_block: non_neg_integer(),
before_acc: binary(),
after_acc: binary(),
commitment_id: non_neg_integer()
}
@typedoc """
* `number` - The number of the Arbitrum batch.
* `transactions_count` - The number of transactions in the batch.
* `start_block` - The number of the first block in the batch.
* `end_block` - The number of the last block in the batch.
* `before_acc` - The hash of the state before the batch.
* `after_acc` - The hash of the state after the batch.
* `commitment_id` - The ID of the commitment L1 transaction from `Explorer.Chain.Arbitrum.LifecycleTransaction`.
* `commitment_transaction` - An instance of `Explorer.Chain.Arbitrum.LifecycleTransaction` referenced by `commitment_id`.
"""
@primary_key {:number, :integer, autogenerate: false}
schema "arbitrum_l1_batches" do
typed_schema "arbitrum_l1_batches" do
field(:transactions_count, :integer)
field(:start_block, :integer)
field(:end_block, :integer)

@ -15,14 +15,28 @@ defmodule Explorer.Chain.Arbitrum.L1Execution do
@required_attrs ~w(message_id execution_id)a
@type t :: %__MODULE__{
message_id: non_neg_integer(),
execution_id: non_neg_integer(),
execution_transaction: %Ecto.Association.NotLoaded{} | LifecycleTransaction.t() | nil
@typedoc """
Descriptor of the a L1 execution transaction related to a L2 to L1 message on Arbitrum rollups:
* `message_id` - The ID of the message from `Explorer.Chain.Arbitrum.Message`.
There could be situations when an execution of a message is
discovered, but the message itself is not indexed yet.
* `execution_id` - The ID of the execution transaction from `Explorer.Chain.Arbitrum.LifecycleTransaction`.
"""
@type to_import :: %{
:message_id => non_neg_integer(),
:execution_id => non_neg_integer()
}
@typedoc """
* `message_id` - The ID of the message from `Explorer.Chain.Arbitrum.Message`.
There could be situations when an execution of a message is
discovered, but the message itself is not indexed yet.
* `execution_id` - The ID of the execution transaction from `Explorer.Chain.Arbitrum.LifecycleTransaction`.
* `execution_transaction` - An instance of `Explorer.Chain.Arbitrum.LifecycleTransaction`
referenced by `execution_id`.
"""
@primary_key {:message_id, :integer, autogenerate: false}
schema "arbitrum_l1_executions" do
typed_schema "arbitrum_l1_executions" do
belongs_to(:execution_transaction, LifecycleTransaction,
foreign_key: :execution_id,
references: :id,

@ -1,6 +1,6 @@
defmodule Explorer.Chain.Arbitrum.LifecycleTransaction do
@moduledoc """
Models an L1 lifecycle transaction for Arbitrum.
Models an L1 lifecycle transaction for Arbitrum. Lifecycle transactions are transactions that change the state of transactions and blocks on Arbitrum rollups.
Changes in the schema should be reflected in the bulk import module:
- Explorer.Chain.Import.Runner.Arbitrum.LifecycleTransactions
@ -11,25 +11,41 @@ defmodule Explorer.Chain.Arbitrum.LifecycleTransaction do
use Explorer.Schema
alias Explorer.Chain.{
Block,
Hash
}
alias Explorer.Chain.Hash
alias Explorer.Chain.Arbitrum.{BatchBlock, L1Batch}
@required_attrs ~w(id hash block_number timestamp status)a
@type t :: %__MODULE__{
id: non_neg_integer(),
hash: Hash.t(),
block_number: Block.block_number(),
timestamp: DateTime.t(),
status: String.t()
@typedoc """
Descriptor of the a L1 transaction changing state of transactions and blocks of Arbitrum rollups:
* `id` - The ID of the transaction used for referencing.
* `hash` - The hash of the L1 transaction.
* `block_number` - The number of the L1 block where the transaction is included.
* `timestamp` - The timestamp of the block in which the transaction is included.
* `status` - The status of the transaction: `:unfinalized` or `:finalized`
"""
@type to_import :: %{
:id => non_neg_integer(),
:hash => binary(),
:block_number => non_neg_integer(),
:timestamp => DateTime.t(),
:status => :unfinalized | :finalized
}
@typedoc """
* `id` - The ID of the transaction used for referencing.
* `hash` - The hash of the L1 transaction.
* `block_number` - The number of the L1 block where the transaction is included.
* `timestamp` - The timestamp of the block in which the transaction is included.
* `status` - The status of the transaction: `:unfinalized` or `:finalized`.
* `committed_batches` - A list of `Explorer.Chain.Arbitrum.L1Batch` instances
that are committed by the transaction.
* `confirmed_blocks` - A list of `Explorer.Chain.Arbitrum.BatchBlock` instances
that are confirmed by the transaction.
"""
@primary_key {:id, :integer, autogenerate: false}
schema "arbitrum_lifecycle_l1_transactions" do
typed_schema "arbitrum_lifecycle_l1_transactions" do
field(:hash, Hash.Full)
field(:block_number, :integer)
field(:timestamp, :utc_datetime_usec)

@ -11,7 +11,7 @@ defmodule Explorer.Chain.Arbitrum.Message do
use Explorer.Schema
alias Explorer.Chain.{Block, Hash}
alias Explorer.Chain.Hash
@optional_attrs ~w(originator_address originating_transaction_hash origination_timestamp originating_transaction_block_number completion_transaction_hash)a
@ -19,19 +19,48 @@ defmodule Explorer.Chain.Arbitrum.Message do
@allowed_attrs @optional_attrs ++ @required_attrs
@type t :: %__MODULE__{
direction: String.t(),
@typedoc """
Descriptor of the a L1<->L2 message on Arbitrum rollups:
* `direction` - The direction of the message: `:to_l2` or `:from_l2`.
* `message_id` - The ID of the message used for referencing.
* `originator_address` - The address of the message originator. The fields
related to the origination can be `nil` if a completion
transaction is discovered when the originating
transaction is not indexed yet.
* `originating_transaction_hash` - The hash of the originating transaction.
* `origination_timestamp` - The timestamp of the origination.
* `originating_transaction_block_number` - The number of the block where the
originating transaction is included.
* `completion_transaction_hash` - The hash of the completion transaction.
* `status` - The status of the message: `:initiated`, `:sent`, `:confirmed`, `:relayed`
"""
@type to_import :: %{
direction: :to_l2 | :from_l2,
message_id: non_neg_integer(),
originator_address: Hash.Address.t() | nil,
originating_transaction_hash: Hash.t() | nil,
originator_address: binary() | nil,
originating_transaction_hash: binary() | nil,
origination_timestamp: DateTime.t() | nil,
originating_transaction_block_number: Block.block_number() | nil,
completion_transaction_hash: Hash.t() | nil,
status: String.t()
originating_transaction_block_number: non_neg_integer() | nil,
completion_transaction_hash: binary() | nil,
status: :initiated | :sent | :confirmed | :relayed
}
@typedoc """
* `direction` - The direction of the message: `:to_l2` or `:from_l2`.
* `message_id` - The ID of the message used for referencing.
* `originator_address` - The address of the message originator. The fields
related to the origination can be `nil` if a completion
transaction is discovered when the originating
transaction is not indexed yet.
* `originating_transaction_hash` - The hash of the originating transaction.
* `origination_timestamp` - The timestamp of the origination.
* `originating_transaction_block_number` - The number of the block where the
originating transaction is included.
* `completion_transaction_hash` - The hash of the completion transaction.
* `status` - The status of the message: `:initiated`, `:sent`, `:confirmed`, `:relayed`.
"""
@primary_key false
schema "arbitrum_crosslevel_messages" do
typed_schema "arbitrum_crosslevel_messages" do
field(:direction, Ecto.Enum, values: [:to_l2, :from_l2], primary_key: true)
field(:message_id, :integer, primary_key: true)
field(:originator_address, Hash.Address)

@ -504,18 +504,24 @@ defmodule Explorer.Chain.Arbitrum.Reader do
end
@doc """
Retrieves all L2-to-L1 messages with the specified status that originated in rollup blocks with numbers not higher than `block_number`.
Retrieves all L2-to-L1 messages with the specified status.
If `block_number` is not `nil`, only messages originating in rollup blocks with
numbers not higher than the specified block are considered. Otherwise, all
messages are considered.
## Parameters
- `status`: The status of the messages to retrieve, such as `:initiated`, `:sent`, `:confirmed`, or `:relayed`.
- `block_number`: The number of a rollup block that limits the messages lookup.
- `status`: The status of the messages to retrieve, such as `:initiated`,
`:sent`, `:confirmed`, or `:relayed`.
- `block_number`: The number of a rollup block that limits the messages lookup,
or `nil`.
## Returns
- Instances of `Explorer.Chain.Arbitrum.Message` corresponding to the criteria, or `[]` if no messages
with the given status are found in the rollup blocks up to the specified number.
- Instances of `Explorer.Chain.Arbitrum.Message` corresponding to the criteria,
or `[]` if no messages with the given status are found.
"""
@spec l2_to_l1_messages(:confirmed | :initiated | :relayed | :sent, FullBlock.block_number()) :: [
Message
@spec l2_to_l1_messages(:confirmed | :initiated | :relayed | :sent, FullBlock.block_number() | nil) :: [
Message.t()
]
def l2_to_l1_messages(status, block_number)
when status in [:initiated, :sent, :confirmed, :relayed] and
@ -532,6 +538,16 @@ defmodule Explorer.Chain.Arbitrum.Reader do
Repo.all(query, timeout: :infinity)
end
def l2_to_l1_messages(status, nil) when status in [:initiated, :sent, :confirmed, :relayed] do
query =
from(msg in Message,
where: msg.direction == :from_l2 and msg.status == ^status,
order_by: [desc: msg.message_id]
)
Repo.all(query, timeout: :infinity)
end
@doc """
Retrieves the numbers of the L1 blocks containing the confirmation transactions
bounding the first interval where missed confirmation transactions could be found.

@ -8,6 +8,7 @@ defmodule Indexer.Fetcher.Arbitrum.Utils.Db do
import Indexer.Fetcher.Arbitrum.Utils.Logging, only: [log_warning: 1]
alias Explorer.{Chain, Repo}
alias Explorer.Chain.Arbitrum
alias Explorer.Chain.Arbitrum.Reader
alias Explorer.Chain.Block, as: FullBlock
alias Explorer.Chain.{Data, Hash, Log}
@ -558,21 +559,10 @@ defmodule Indexer.Fetcher.Arbitrum.Utils.Db do
database import operation. If no messages with the 'confirmed' status are found by
the specified block number, an empty list is returned.
"""
@spec confirmed_l2_to_l1_messages(FullBlock.block_number()) :: [
%{
direction: :from_l2,
message_id: non_neg_integer(),
originator_address: binary(),
originating_transaction_hash: binary(),
originating_transaction_block_number: FullBlock.block_number(),
completion_transaction_hash: nil,
status: :confirmed
}
]
def confirmed_l2_to_l1_messages(block_number)
when is_integer(block_number) and block_number >= 0 do
@spec confirmed_l2_to_l1_messages() :: [Arbitrum.Message.to_import()]
def confirmed_l2_to_l1_messages do
# credo:disable-for-lines:2 Credo.Check.Refactor.PipeChainStart
Reader.l2_to_l1_messages(:confirmed, block_number)
Reader.l2_to_l1_messages(:confirmed, nil)
|> Enum.map(&message_to_map/1)
end
@ -739,6 +729,7 @@ defmodule Indexer.Fetcher.Arbitrum.Utils.Db do
|> db_record_to_map(block)
end
@spec message_to_map(Arbitrum.Message.t()) :: Arbitrum.Message.to_import()
defp message_to_map(message) do
[
:direction,

@ -33,6 +33,7 @@ defmodule Indexer.Fetcher.Arbitrum.Workers.NewBatches do
alias Indexer.Fetcher.Arbitrum.Utils.{Db, Logging, Rpc}
alias Explorer.Chain
alias Explorer.Chain.Arbitrum
require Logger
@ -409,6 +410,30 @@ defmodule Indexer.Fetcher.Arbitrum.Workers.NewBatches do
# - A tuple containing lists of batches, lifecycle transactions, rollup blocks,
# rollup transactions, and committed messages (with the status `:sent`), all
# ready for database import.
@spec handle_batches_from_logs(
[%{String.t() => any()}],
non_neg_integer(),
%{
:json_rpc_named_arguments => EthereumJSONRPC.json_rpc_named_arguments(),
:chunk_size => non_neg_integer(),
optional(any()) => any()
},
%{
:json_rpc_named_arguments => EthereumJSONRPC.json_rpc_named_arguments(),
:chunk_size => non_neg_integer(),
optional(any()) => any()
}
) :: {
[Arbitrum.L1Batch.to_import()],
[Arbitrum.LifecycleTransaction.to_import()],
[Arbitrum.BatchBlock.to_import()],
[Arbitrum.BatchTransaction.to_import()],
[Arbitrum.Message.to_import()]
}
defp handle_batches_from_logs(logs, msg_to_block_shift, l1_rpc_config, rollup_rpc_config)
defp handle_batches_from_logs([], _, _, _), do: {[], [], [], [], []}
defp handle_batches_from_logs(
logs,
msg_to_block_shift,

@ -41,6 +41,7 @@ defmodule Indexer.Fetcher.Arbitrum.Workers.NewConfirmations do
alias Indexer.Fetcher.Arbitrum.Utils.Helper, as: ArbitrumHelper
alias Explorer.Chain
alias Explorer.Chain.Arbitrum
require Logger
@ -313,8 +314,24 @@ defmodule Indexer.Fetcher.Arbitrum.Workers.NewConfirmations do
# rollup
# - `rollup_blocks` is a list of rollup blocks associated with the corresponding
# lifecycle transactions
# - `confirmed_txs` is a list of L2-to-L1 messages identified up to the highest
# confirmed block number, to be imported with the new status `:confirmed`
# - `confirmed_messages` is a list of L2-to-L1 messages identified up to the
# highest confirmed block number, to be imported with the new status
# `:confirmed`
@spec handle_confirmations_from_logs(
[%{String.t() => any()}],
%{
:json_rpc_named_arguments => EthereumJSONRPC.json_rpc_named_arguments(),
:logs_block_range => non_neg_integer(),
:chunk_size => non_neg_integer(),
:finalized_confirmations => boolean()
},
binary()
) ::
{:ok | :confirmation_missed,
{[Arbitrum.LifecycleTransaction.to_import()], [Arbitrum.BatchBlock.to_import()],
[Arbitrum.Message.to_import()]}}
defp handle_confirmations_from_logs(logs, l1_rpc_config, outbox_address)
defp handle_confirmations_from_logs([], _, _) do
{:ok, {[], [], []}}
end
@ -359,9 +376,9 @@ defmodule Indexer.Fetcher.Arbitrum.Workers.NewConfirmations do
# Drawback of marking messages as confirmed during a new confirmation handling
# is that the status change could become stuck if confirmations are not handled.
# For example, due to DB inconsistency: some blocks/batches are missed.
confirmed_txs = get_confirmed_l2_to_l1_messages(highest_confirmed_block_number)
confirmed_messages = get_confirmed_l2_to_l1_messages(highest_confirmed_block_number)
{retcode, {lifecycle_txs, rollup_blocks, confirmed_txs}}
{retcode, {lifecycle_txs, rollup_blocks, confirmed_messages}}
end
end

@ -29,6 +29,7 @@ defmodule Indexer.Fetcher.Arbitrum.Workers.NewL1Executions do
alias Indexer.Helper, as: IndexerHelper
alias Explorer.Chain
alias Explorer.Chain.Arbitrum
require Logger
@ -216,7 +217,7 @@ defmodule Indexer.Fetcher.Arbitrum.Workers.NewL1Executions do
# that have not yet been indexed. This ensures that as soon as a new unexecuted
# message is added to the database, it can be marked as relayed, considering
# the execution transactions that have already been indexed.
messages = get_relayed_messages(end_block)
messages = get_relayed_messages()
unless messages == [] do
log_info("Marking #{length(messages)} l2-to-l1 messages as completed")
@ -269,6 +270,19 @@ defmodule Indexer.Fetcher.Arbitrum.Workers.NewL1Executions do
# statuses, and unique identifiers.
# - A list of detailed execution information for L2-to-L1 messages.
# Both lists are prepared for database importation.
@spec get_executions_from_logs(
[%{String.t() => any()}],
%{
:json_rpc_named_arguments => EthereumJSONRPC.json_rpc_named_arguments(),
:chunk_size => non_neg_integer(),
:track_finalization => boolean(),
optional(any()) => any()
}
) :: {[Arbitrum.LifecycleTransaction.to_import()], [Arbitrum.L1Execution.to_import()]}
defp get_executions_from_logs(logs, l1_rpc_config)
defp get_executions_from_logs([], _), do: {[], []}
defp get_executions_from_logs(
logs,
%{
@ -370,23 +384,19 @@ defmodule Indexer.Fetcher.Arbitrum.Workers.NewL1Executions do
# Retrieves unexecuted messages from L2 to L1, marking them as completed if their
# corresponding execution transactions are identified.
#
# This function fetches messages confirmed on L1 up to the specified rollup block
# number and matches these messages with their corresponding execution transactions.
# For matched pairs, it updates the message status to `:relayed` and links them with
# the execution transactions.
#
# ## Parameters
# - `block_number`: The block number up to which messages are considered for
# completion.
# This function fetches messages confirmed on L1 and matches these messages with
# their corresponding execution transactions. For matched pairs, it updates the
# message status to `:relayed` and links them with the execution transactions.
#
# ## Returns
# - A list of messages marked as completed, ready for database import.
defp get_relayed_messages(block_number) do
@spec get_relayed_messages() :: [Arbitrum.Message.to_import()]
defp get_relayed_messages do
# Assuming that both catchup block fetcher and historical messages catchup fetcher
# will check all discovered historical messages to be marked as executed it is not
# needed to handle :initiated and :sent of historical messages here, only for
# new messages discovered and changed their status from `:sent` to `:confirmed`
confirmed_messages = Db.confirmed_l2_to_l1_messages(block_number)
confirmed_messages = Db.confirmed_l2_to_l1_messages()
if Enum.empty?(confirmed_messages) do
[]

@ -24,6 +24,7 @@ defmodule Indexer.Fetcher.Arbitrum.Workers.NewMessagesToL2 do
alias Indexer.Helper, as: IndexerHelper
alias Explorer.Chain
alias Explorer.Chain.Arbitrum
require Logger
@ -260,6 +261,15 @@ defmodule Indexer.Fetcher.Arbitrum.Workers.NewMessagesToL2 do
# ## Returns
# - A list of maps describing discovered messages compatible with the database
# import operation.
@spec get_messages_from_logs(
[%{String.t() => any()}],
EthereumJSONRPC.json_rpc_named_arguments(),
non_neg_integer()
) :: [Arbitrum.Message.to_import()]
defp get_messages_from_logs(logs, json_rpc_named_arguments, chunk_size)
defp get_messages_from_logs([], _, _), do: []
defp get_messages_from_logs(logs, json_rpc_named_arguments, chunk_size) do
{messages, txs_requests} = parse_logs_for_l1_to_l2_messages(logs)

Loading…
Cancel
Save