Fetch coin balances in async mode in realtime fetcher (#9182)

* Fetch coin balances in async mode in realtime fetcher

* Coin balances fetcher refactor

* Don't filter non-traceable blocks in realtime coin balances fetcher
pull/9439/head
Qwerty5Uiop 9 months ago committed by GitHub
parent f554b0d3f5
commit e7d2dd0ee4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 4
      apps/block_scout_web/test/block_scout_web/controllers/transaction_state_controller_test.exs
  3. 11
      apps/indexer/lib/indexer/block/fetcher.ex
  4. 105
      apps/indexer/lib/indexer/block/realtime/fetcher.ex
  5. 4
      apps/indexer/lib/indexer/fetcher/block_reward.ex
  6. 77
      apps/indexer/lib/indexer/fetcher/coin_balance/catchup.ex
  7. 90
      apps/indexer/lib/indexer/fetcher/coin_balance/helper.ex
  8. 61
      apps/indexer/lib/indexer/fetcher/coin_balance/realtime.ex
  9. 68
      apps/indexer/lib/indexer/fetcher/coin_balance_daily_updater.ex
  10. 8
      apps/indexer/lib/indexer/fetcher/coin_balance_on_demand.ex
  11. 4
      apps/indexer/lib/indexer/fetcher/contract_code.ex
  12. 9
      apps/indexer/lib/indexer/supervisor.ex
  13. 8
      apps/indexer/test/indexer/block/catchup/bound_interval_supervisor_test.exs
  14. 11
      apps/indexer/test/indexer/block/catchup/fetcher_test.exs
  15. 8
      apps/indexer/test/indexer/block/fetcher_test.exs
  16. 391
      apps/indexer/test/indexer/block/realtime/fetcher_test.exs
  17. 12
      apps/indexer/test/indexer/fetcher/block_reward_test.exs
  18. 20
      apps/indexer/test/indexer/fetcher/coin_balance/catchup_test.exs
  19. 7
      apps/indexer/test/indexer/fetcher/internal_transaction_test.exs
  20. 6
      apps/indexer/test/support/indexer/fetcher/coin_balance_catchup_supervisor_case.ex
  21. 17
      apps/indexer/test/support/indexer/fetcher/coin_balance_realtime_supervisor_case.ex
  22. 20
      config/runtime.exs
  23. 1
      docker-compose/envs/common-blockscout.env

@ -14,6 +14,7 @@
- [#9351](https://github.com/blockscout/blockscout/pull/9351) - Noves.fi: add proxy endpoint for describeTxs endpoint - [#9351](https://github.com/blockscout/blockscout/pull/9351) - Noves.fi: add proxy endpoint for describeTxs endpoint
- [#9282](https://github.com/blockscout/blockscout/pull/9282) - Add `license_type` to smart contracts - [#9282](https://github.com/blockscout/blockscout/pull/9282) - Add `license_type` to smart contracts
- [#9202](https://github.com/blockscout/blockscout/pull/9202) - Add base and priority fee to gas oracle response - [#9202](https://github.com/blockscout/blockscout/pull/9202) - Add base and priority fee to gas oracle response
- [#9182](https://github.com/blockscout/blockscout/pull/9182) - Fetch coin balances in async mode in realtime fetcher
- [#9168](https://github.com/blockscout/blockscout/pull/9168) - Support EIP4844 blobs indexing & API - [#9168](https://github.com/blockscout/blockscout/pull/9168) - Support EIP4844 blobs indexing & API
- [#9098](https://github.com/blockscout/blockscout/pull/9098) - Polygon zkEVM Bridge indexer and API v2 extension - [#9098](https://github.com/blockscout/blockscout/pull/9098) - Polygon zkEVM Bridge indexer and API v2 extension

@ -7,7 +7,7 @@ defmodule BlockScoutWeb.TransactionStateControllerTest do
import BlockScoutWeb.WeiHelper, only: [format_wei_value: 2] import BlockScoutWeb.WeiHelper, only: [format_wei_value: 2]
import EthereumJSONRPC, only: [integer_to_quantity: 1] import EthereumJSONRPC, only: [integer_to_quantity: 1]
alias Explorer.Chain.Wei alias Explorer.Chain.Wei
alias Indexer.Fetcher.CoinBalance alias Indexer.Fetcher.CoinBalance.Catchup, as: CoinBalanceCatchup
alias Explorer.Counters.{AddressesCounter, AverageBlockTime} alias Explorer.Counters.{AddressesCounter, AverageBlockTime}
alias Indexer.Fetcher.CoinBalanceOnDemand alias Indexer.Fetcher.CoinBalanceOnDemand
@ -182,7 +182,7 @@ defmodule BlockScoutWeb.TransactionStateControllerTest do
test "fetch coin balances if needed", %{conn: conn} do test "fetch coin balances if needed", %{conn: conn} do
json_rpc_named_arguments = Application.fetch_env!(:indexer, :json_rpc_named_arguments) json_rpc_named_arguments = Application.fetch_env!(:indexer, :json_rpc_named_arguments)
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
EthereumJSONRPC.Mox EthereumJSONRPC.Mox
|> stub(:json_rpc, fn |> stub(:json_rpc, fn

@ -16,13 +16,14 @@ defmodule Indexer.Block.Fetcher do
alias Explorer.Chain.Cache.Blocks, as: BlocksCache alias Explorer.Chain.Cache.Blocks, as: BlocksCache
alias Explorer.Chain.Cache.{Accounts, BlockNumber, Transactions, Uncles} alias Explorer.Chain.Cache.{Accounts, BlockNumber, Transactions, Uncles}
alias Indexer.Block.Fetcher.Receipts alias Indexer.Block.Fetcher.Receipts
alias Indexer.Fetcher.CoinBalance.Catchup, as: CoinBalanceCatchup
alias Indexer.Fetcher.CoinBalance.Realtime, as: CoinBalanceRealtime
alias Indexer.Fetcher.PolygonZkevm.BridgeL1Tokens, as: PolygonZkevmBridgeL1Tokens alias Indexer.Fetcher.PolygonZkevm.BridgeL1Tokens, as: PolygonZkevmBridgeL1Tokens
alias Indexer.Fetcher.TokenInstance.Realtime, as: TokenInstanceRealtime alias Indexer.Fetcher.TokenInstance.Realtime, as: TokenInstanceRealtime
alias Indexer.Fetcher.{ alias Indexer.Fetcher.{
Beacon.Blob, Beacon.Blob,
BlockReward, BlockReward,
CoinBalance,
ContractCode, ContractCode,
InternalTransaction, InternalTransaction,
ReplacedTransaction, ReplacedTransaction,
@ -371,11 +372,17 @@ defmodule Indexer.Block.Fetcher do
block_number = Map.fetch!(address_hash_to_block_number, to_string(address_hash)) block_number = Map.fetch!(address_hash_to_block_number, to_string(address_hash))
%{address_hash: address_hash, block_number: block_number} %{address_hash: address_hash, block_number: block_number}
end) end)
|> CoinBalance.async_fetch_balances() |> CoinBalanceCatchup.async_fetch_balances()
end end
def async_import_coin_balances(_, _), do: :ok def async_import_coin_balances(_, _), do: :ok
def async_import_realtime_coin_balances(%{address_coin_balances: balances}) do
CoinBalanceRealtime.async_fetch_balances(balances)
end
def async_import_realtime_coin_balances(_), do: :ok
def async_import_created_contract_codes(%{transactions: transactions}) do def async_import_created_contract_codes(%{transactions: transactions}) do
transactions transactions
|> Enum.flat_map(fn |> Enum.flat_map(fn

@ -9,10 +9,11 @@ defmodule Indexer.Block.Realtime.Fetcher do
require Indexer.Tracer require Indexer.Tracer
require Logger require Logger
import EthereumJSONRPC, only: [integer_to_quantity: 1, quantity_to_integer: 1] import EthereumJSONRPC, only: [quantity_to_integer: 1]
import Indexer.Block.Fetcher, import Indexer.Block.Fetcher,
only: [ only: [
async_import_realtime_coin_balances: 1,
async_import_blobs: 1, async_import_blobs: 1,
async_import_block_rewards: 1, async_import_block_rewards: 1,
async_import_created_contract_codes: 1, async_import_created_contract_codes: 1,
@ -27,20 +28,17 @@ defmodule Indexer.Block.Realtime.Fetcher do
] ]
alias Ecto.Changeset alias Ecto.Changeset
alias EthereumJSONRPC.{FetchedBalances, Subscription} alias EthereumJSONRPC.Subscription
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.Cache.Accounts
alias Explorer.Chain.Events.Publisher alias Explorer.Chain.Events.Publisher
alias Explorer.Counters.AverageBlockTime alias Explorer.Counters.AverageBlockTime
alias Explorer.Utility.MissingRangesManipulator alias Explorer.Utility.MissingRangesManipulator
alias Indexer.{Block, Tracer} alias Indexer.{Block, Tracer}
alias Indexer.Block.Realtime.TaskSupervisor alias Indexer.Block.Realtime.TaskSupervisor
alias Indexer.Fetcher.{CoinBalance, CoinBalanceDailyUpdater}
alias Indexer.Fetcher.PolygonEdge.{DepositExecute, Withdrawal} alias Indexer.Fetcher.PolygonEdge.{DepositExecute, Withdrawal}
alias Indexer.Fetcher.PolygonZkevm.BridgeL2, as: PolygonZkevmBridgeL2 alias Indexer.Fetcher.PolygonZkevm.BridgeL2, as: PolygonZkevmBridgeL2
alias Indexer.Fetcher.Shibarium.L2, as: ShibariumBridgeL2 alias Indexer.Fetcher.Shibarium.L2, as: ShibariumBridgeL2
alias Indexer.Prometheus alias Indexer.Prometheus
alias Indexer.Transform.Addresses
alias Timex.Duration alias Timex.Duration
@behaviour Block.Fetcher @behaviour Block.Fetcher
@ -195,43 +193,21 @@ defmodule Indexer.Block.Realtime.Fetcher do
@import_options ~w(address_hash_to_fetched_balance_block_number)a @import_options ~w(address_hash_to_fetched_balance_block_number)a
@impl Block.Fetcher @impl Block.Fetcher
def import( def import(_block_fetcher, %{block_rewards: block_rewards} = options) do
block_fetcher, {block_reward_errors, chain_import_block_rewards} = Map.pop(block_rewards, :errors)
%{
address_coin_balances: %{params: address_coin_balances_params}, chain_import_options =
addresses: %{params: addresses_params}, options
block_rewards: block_rewards |> Map.drop(@import_options)
} = options |> put_in([:blocks, :params, Access.all(), :consensus], true)
) do |> put_in([:block_rewards], chain_import_block_rewards)
with {:balances,
{:ok, with {:import, {:ok, imported} = ok} <- {:import, Chain.import(chain_import_options)} do
%{
addresses_params: balances_addresses_params,
balances_params: balances_params,
balances_daily_params: balances_daily_params
}}} <-
{:balances,
balances(block_fetcher, %{
addresses_params: addresses_params,
balances_params: address_coin_balances_params
})},
{block_reward_errors, chain_import_block_rewards} = Map.pop(block_rewards, :errors),
chain_import_options =
options
|> Map.drop(@import_options)
|> put_in([:addresses, :params], balances_addresses_params)
|> put_in([:blocks, :params, Access.all(), :consensus], true)
|> put_in([:block_rewards], chain_import_block_rewards)
|> put_in([Access.key(:address_coin_balances, %{}), :params], balances_params),
CoinBalanceDailyUpdater.add_daily_balances_params(balances_daily_params),
{:import, {:ok, imported} = ok} <- {:import, Chain.import(chain_import_options)} do
async_import_remaining_block_data( async_import_remaining_block_data(
imported, imported,
%{block_rewards: %{errors: block_reward_errors}} %{block_rewards: %{errors: block_reward_errors}}
) )
Accounts.drop(imported[:addresses])
ok ok
end end
end end
@ -443,6 +419,7 @@ defmodule Indexer.Block.Realtime.Fetcher do
imported, imported,
%{block_rewards: %{errors: block_reward_errors}} %{block_rewards: %{errors: block_reward_errors}}
) do ) do
async_import_realtime_coin_balances(imported)
async_import_block_rewards(block_reward_errors) async_import_block_rewards(block_reward_errors)
async_import_created_contract_codes(imported) async_import_created_contract_codes(imported)
async_import_internal_transactions(imported) async_import_internal_transactions(imported)
@ -454,58 +431,4 @@ defmodule Indexer.Block.Realtime.Fetcher do
async_import_blobs(imported) async_import_blobs(imported)
async_import_polygon_zkevm_bridge_l1_tokens(imported) async_import_polygon_zkevm_bridge_l1_tokens(imported)
end end
defp balances(
%Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments},
%{addresses_params: addresses_params} = options
) do
case options
|> fetch_balances_params_list()
|> EthereumJSONRPC.fetch_balances(json_rpc_named_arguments, CoinBalance.batch_size()) do
{:ok, %FetchedBalances{params_list: params_list, errors: []}} ->
merged_addresses_params =
%{address_coin_balances: params_list}
|> Addresses.extract_addresses()
|> Kernel.++(addresses_params)
|> Addresses.merge_addresses()
value_fetched_at = DateTime.utc_now()
importable_balances_params = Enum.map(params_list, &Map.put(&1, :value_fetched_at, value_fetched_at))
block_timestamp_map = CoinBalance.block_timestamp_map(params_list, json_rpc_named_arguments)
importable_balances_daily_params =
Enum.map(params_list, fn param ->
day = Map.get(block_timestamp_map, "#{param.block_number}")
(day && Map.put(param, :day, day)) || param
end)
{:ok,
%{
addresses_params: merged_addresses_params,
balances_params: importable_balances_params,
balances_daily_params: importable_balances_daily_params
}}
{:error, _} = error ->
error
{:ok, %FetchedBalances{errors: errors}} ->
{:error, errors}
end
end
defp fetch_balances_params_list(%{balances_params: balances_params}) do
balances_params
|> balances_params_to_fetch_balances_params_set()
# stable order for easier moxing
|> Enum.sort_by(fn %{hash_data: hash_data, block_quantity: block_quantity} -> {hash_data, block_quantity} end)
end
defp balances_params_to_fetch_balances_params_set(balances_params) do
Enum.into(balances_params, MapSet.new(), fn %{address_hash: address_hash, block_number: block_number} ->
%{hash_data: address_hash, block_quantity: integer_to_quantity(block_number)}
end)
end
end end

@ -20,7 +20,7 @@ defmodule Indexer.Fetcher.BlockReward do
alias Explorer.Chain.Cache.Accounts alias Explorer.Chain.Cache.Accounts
alias Indexer.{BufferedTask, Tracer} alias Indexer.{BufferedTask, Tracer}
alias Indexer.Fetcher.BlockReward.Supervisor, as: BlockRewardSupervisor alias Indexer.Fetcher.BlockReward.Supervisor, as: BlockRewardSupervisor
alias Indexer.Fetcher.CoinBalance alias Indexer.Fetcher.CoinBalance.Catchup, as: CoinBalanceCatchup
alias Indexer.Transform.{AddressCoinBalances, Addresses} alias Indexer.Transform.{AddressCoinBalances, Addresses}
@behaviour BufferedTask @behaviour BufferedTask
@ -133,7 +133,7 @@ defmodule Indexer.Fetcher.BlockReward do
{:ok, %{address_coin_balances: address_coin_balances, addresses: addresses}} -> {:ok, %{address_coin_balances: address_coin_balances, addresses: addresses}} ->
Accounts.drop(addresses) Accounts.drop(addresses)
CoinBalance.async_fetch_balances(address_coin_balances) CoinBalanceCatchup.async_fetch_balances(address_coin_balances)
retry_errors(errors) retry_errors(errors)

@ -0,0 +1,77 @@
defmodule Indexer.Fetcher.CoinBalance.Catchup do
@moduledoc """
Fetches `t:Explorer.Chain.Address.CoinBalance.t/0` and updates `t:Explorer.Chain.Address.t/0` `fetched_coin_balance` and
`fetched_coin_balance_block_number` to value at max `t:Explorer.Chain.Address.CoinBalance.t/0` `block_number` for the given `t:Explorer.Chain.Address.t/` `hash`.
"""
use Indexer.Fetcher, restart: :permanent
use Spandex.Decorators
alias Explorer.Chain
alias Explorer.Chain.{Block, Hash}
alias Indexer.{BufferedTask, Tracer}
alias Indexer.Fetcher.CoinBalance.Catchup.Supervisor, as: CoinBalanceSupervisor
alias Indexer.Fetcher.CoinBalance.Helper
@behaviour BufferedTask
@default_max_batch_size 500
@default_max_concurrency 4
@doc """
Asynchronously fetches balances for each address `hash` at the `block_number`.
"""
@spec async_fetch_balances([
%{required(:address_hash) => Hash.Address.t(), required(:block_number) => Block.block_number()}
]) :: :ok
def async_fetch_balances(balance_fields) when is_list(balance_fields) do
if CoinBalanceSupervisor.disabled?() do
:ok
else
entries = Enum.map(balance_fields, &Helper.entry/1)
BufferedTask.buffer(__MODULE__, entries)
end
end
def child_spec(params) do
Helper.child_spec(params, defaults(), __MODULE__)
end
@impl BufferedTask
def init(initial, reducer, _) do
{:ok, final} =
Chain.stream_unfetched_balances(
initial,
fn address_fields, acc ->
address_fields
|> Helper.entry()
|> reducer.(acc)
end,
true
)
final
end
@impl BufferedTask
@decorate trace(
name: "fetch",
resource: "Indexer.Fetcher.CoinBalance.Catchup.run/2",
service: :indexer,
tracer: Tracer
)
def run(entries, json_rpc_named_arguments) do
Helper.run(entries, json_rpc_named_arguments, true)
end
defp defaults do
[
flush_interval: :timer.seconds(3),
max_batch_size: Application.get_env(:indexer, __MODULE__)[:batch_size] || @default_max_batch_size,
max_concurrency: Application.get_env(:indexer, __MODULE__)[:concurrency] || @default_max_concurrency,
task_supervisor: Indexer.Fetcher.CoinBalance.Catchup.TaskSupervisor,
metadata: [fetcher: :coin_balance_catchup]
]
end
end

@ -1,90 +1,48 @@
defmodule Indexer.Fetcher.CoinBalance do defmodule Indexer.Fetcher.CoinBalance.Helper do
@moduledoc """ @moduledoc """
Fetches `t:Explorer.Chain.Address.CoinBalance.t/0` and updates `t:Explorer.Chain.Address.t/0` `fetched_coin_balance` and Common functions for `Indexer.Fetcher.CoinBalance.Catchup` and `Indexer.Fetcher.CoinBalance.Realtime` modules
`fetched_coin_balance_block_number` to value at max `t:Explorer.Chain.Address.CoinBalance.t/0` `block_number` for the given `t:Explorer.Chain.Address.t/` `hash`.
""" """
use Indexer.Fetcher, restart: :permanent import EthereumJSONRPC, only: [integer_to_quantity: 1, quantity_to_integer: 1]
use Spandex.Decorators
require Logger require Logger
import EthereumJSONRPC, only: [integer_to_quantity: 1, quantity_to_integer: 1]
alias EthereumJSONRPC.{Blocks, FetchedBalances, Utility.RangesHelper} alias EthereumJSONRPC.{Blocks, FetchedBalances, Utility.RangesHelper}
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.{Block, Hash}
alias Explorer.Chain.Cache.Accounts alias Explorer.Chain.Cache.Accounts
alias Indexer.{BufferedTask, Tracer} alias Explorer.Chain.Hash
alias Indexer.Fetcher.CoinBalance.Supervisor, as: CoinBalanceSupervisor alias Indexer.BufferedTask
@behaviour BufferedTask
@default_max_batch_size 500
@default_max_concurrency 4
def batch_size, do: defaults()[:max_batch_size]
@doc """
Asynchronously fetches balances for each address `hash` at the `block_number`.
"""
@spec async_fetch_balances([
%{required(:address_hash) => Hash.Address.t(), required(:block_number) => Block.block_number()}
]) :: :ok
def async_fetch_balances(balance_fields) when is_list(balance_fields) do
if CoinBalanceSupervisor.disabled?() do
:ok
else
entries = Enum.map(balance_fields, &entry/1)
BufferedTask.buffer(__MODULE__, entries)
end
end
@doc false @doc false
# credo:disable-for-next-line Credo.Check.Design.DuplicatedCode # credo:disable-for-next-line Credo.Check.Design.DuplicatedCode
def child_spec([init_options, gen_server_options]) do def child_spec([init_options, gen_server_options], defaults, module) do
{state, mergeable_init_options} = Keyword.pop(init_options, :json_rpc_named_arguments) {state, mergeable_init_options} = Keyword.pop(init_options, :json_rpc_named_arguments)
unless state do unless state do
raise ArgumentError, raise ArgumentError,
":json_rpc_named_arguments must be provided to `#{__MODULE__}.child_spec " <> ":json_rpc_named_arguments must be provided to `#{module}.child_spec " <>
"to allow for json_rpc calls when running." "to allow for json_rpc calls when running."
end end
merged_init_options = merged_init_options =
defaults() defaults
|> Keyword.merge(mergeable_init_options) |> Keyword.merge(mergeable_init_options)
|> Keyword.put(:state, state) |> Keyword.put(:state, state)
Supervisor.child_spec({BufferedTask, [{__MODULE__, merged_init_options}, gen_server_options]}, id: __MODULE__) Supervisor.child_spec({BufferedTask, [{module, merged_init_options}, gen_server_options]}, id: module)
end
@impl BufferedTask
def init(initial, reducer, _) do
{:ok, final} =
Chain.stream_unfetched_balances(
initial,
fn address_fields, acc ->
address_fields
|> entry()
|> reducer.(acc)
end,
true
)
final
end end
@impl BufferedTask def run(entries, json_rpc_named_arguments, filter_non_traceable_blocks? \\ true) do
@decorate trace(name: "fetch", resource: "Indexer.Fetcher.CoinBalance.run/2", service: :indexer, tracer: Tracer)
def run(entries, json_rpc_named_arguments) do
# the same address may be used more than once in the same block, but we only want one `Balance` for a given # the same address may be used more than once in the same block, but we only want one `Balance` for a given
# `{address, block}`, so take unique params only # `{address, block}`, so take unique params only
unique_entries = Enum.uniq(entries) unique_entries = Enum.uniq(entries)
unique_filtered_entries = unique_filtered_entries =
Enum.filter(unique_entries, fn {_hash, block_number} -> RangesHelper.traceable_block_number?(block_number) end) if filter_non_traceable_blocks? do
Enum.filter(unique_entries, fn {_hash, block_number} -> RangesHelper.traceable_block_number?(block_number) end)
else
unique_entries
end
unique_entry_count = Enum.count(unique_filtered_entries) unique_entry_count = Enum.count(unique_filtered_entries)
Logger.metadata(count: unique_entry_count) Logger.metadata(count: unique_entry_count)
@ -110,15 +68,15 @@ defmodule Indexer.Fetcher.CoinBalance do
end end
end end
def entry(%{address_hash: %Hash{bytes: address_hash_bytes}, block_number: block_number}) do
{address_hash_bytes, block_number}
end
defp entry_to_params({address_hash_bytes, block_number}) when is_integer(block_number) do defp entry_to_params({address_hash_bytes, block_number}) when is_integer(block_number) do
{:ok, address_hash} = Hash.Address.cast(address_hash_bytes) {:ok, address_hash} = Hash.Address.cast(address_hash_bytes)
%{block_quantity: integer_to_quantity(block_number), hash_data: to_string(address_hash)} %{block_quantity: integer_to_quantity(block_number), hash_data: to_string(address_hash)}
end end
defp entry(%{address_hash: %Hash{bytes: address_hash_bytes}, block_number: block_number}) do
{address_hash_bytes, block_number}
end
# We want to record all historical balances for an address, but have the address itself have balance from the # We want to record all historical balances for an address, but have the address itself have balance from the
# `Balance` with the greatest block_number for that address. # `Balance` with the greatest block_number for that address.
def balances_params_to_address_params(balances_params) do def balances_params_to_address_params(balances_params) do
@ -263,14 +221,4 @@ defmodule Indexer.Fetcher.CoinBalance do
end end
end) end)
end end
defp defaults do
[
flush_interval: :timer.seconds(3),
max_batch_size: Application.get_env(:indexer, __MODULE__)[:batch_size] || @default_max_batch_size,
max_concurrency: Application.get_env(:indexer, __MODULE__)[:concurrency] || @default_max_concurrency,
task_supervisor: Indexer.Fetcher.CoinBalance.TaskSupervisor,
metadata: [fetcher: :coin_balance]
]
end
end end

@ -0,0 +1,61 @@
defmodule Indexer.Fetcher.CoinBalance.Realtime do
@moduledoc """
Separate version of `Indexer.Fetcher.CoinBalance.Catchup` for fetching balances from realtime block fetcher
"""
use Indexer.Fetcher, restart: :permanent
use Spandex.Decorators
alias Explorer.Chain.{Block, Hash}
alias Indexer.{BufferedTask, Tracer}
alias Indexer.Fetcher.CoinBalance.Helper
alias Indexer.Fetcher.CoinBalance.Realtime.Supervisor, as: CoinBalanceSupervisor
@behaviour BufferedTask
@default_max_batch_size 500
@default_max_concurrency 4
@doc """
Asynchronously fetches balances for each address `hash` at the `block_number`.
"""
@spec async_fetch_balances([
%{required(:address_hash) => Hash.Address.t(), required(:block_number) => Block.block_number()}
]) :: :ok
def async_fetch_balances(balance_fields) when is_list(balance_fields) do
entries = Enum.map(balance_fields, &Helper.entry/1)
BufferedTask.buffer(__MODULE__, entries)
end
def child_spec(params) do
Helper.child_spec(params, defaults(), __MODULE__)
end
@impl BufferedTask
def init(_, _, _) do
{0, []}
end
@impl BufferedTask
@decorate trace(
name: "fetch",
resource: "Indexer.Fetcher.CoinBalance.Realtime.run/2",
service: :indexer,
tracer: Tracer
)
def run(entries, json_rpc_named_arguments) do
Helper.run(entries, json_rpc_named_arguments, false)
end
defp defaults do
[
poll: false,
flush_interval: :timer.seconds(3),
max_batch_size: Application.get_env(:indexer, __MODULE__)[:batch_size] || @default_max_batch_size,
max_concurrency: Application.get_env(:indexer, __MODULE__)[:concurrency] || @default_max_concurrency,
task_supervisor: Indexer.Fetcher.CoinBalance.Realtime.TaskSupervisor,
metadata: [fetcher: :coin_balance_realtime]
]
end
end

@ -1,68 +0,0 @@
defmodule Indexer.Fetcher.CoinBalanceDailyUpdater do
@moduledoc """
Accumulates and periodically updates daily coin balances
"""
use GenServer
alias Explorer.Chain
alias Explorer.Counters.AverageBlockTime
alias Timex.Duration
@default_update_interval :timer.seconds(10)
def start_link(_) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
@impl true
def init(_) do
schedule_next_update()
{:ok, %{}}
end
def add_daily_balances_params(daily_balances_params) do
GenServer.cast(__MODULE__, {:add_daily_balances_params, daily_balances_params})
end
@impl true
def handle_cast({:add_daily_balances_params, daily_balances_params}, state) do
{:noreply, Enum.reduce(daily_balances_params, state, &put_new_param/2)}
end
defp put_new_param(%{day: day, address_hash: address_hash, value: value} = param, acc) do
Map.update(acc, {address_hash, day}, param, fn %{value: old_value} = old_param ->
if is_nil(old_value) or value > old_value, do: param, else: old_param
end)
end
@impl true
def handle_info(:update, state) when state == %{} do
schedule_next_update()
{:noreply, %{}}
end
def handle_info(:update, state) do
Chain.import(%{address_coin_balances_daily: %{params: Map.values(state)}})
schedule_next_update()
{:noreply, %{}}
end
def handle_info(_, state) do
{:noreply, state}
end
defp schedule_next_update do
update_interval =
case AverageBlockTime.average_block_time() do
{:error, :disabled} -> @default_update_interval
block_time -> round(Duration.to_milliseconds(block_time))
end
Process.send_after(self(), :update, update_interval)
end
end

@ -19,7 +19,7 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemand do
alias Explorer.Chain.Address.{CoinBalance, CoinBalanceDaily} alias Explorer.Chain.Address.{CoinBalance, CoinBalanceDaily}
alias Explorer.Chain.Cache.{Accounts, BlockNumber} alias Explorer.Chain.Cache.{Accounts, BlockNumber}
alias Explorer.Counters.AverageBlockTime alias Explorer.Counters.AverageBlockTime
alias Indexer.Fetcher.CoinBalance, as: CoinBalanceFetcher alias Indexer.Fetcher.CoinBalance.Helper, as: CoinBalanceHelper
alias Timex.Duration alias Timex.Duration
@type block_number :: integer @type block_number :: integer
@ -205,7 +205,7 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemand do
:ok :ok
{:ok, %{params_list: params_list}} -> {:ok, %{params_list: params_list}} ->
address_params = CoinBalanceFetcher.balances_params_to_address_params(params_list) address_params = CoinBalanceHelper.balances_params_to_address_params(params_list)
Chain.import(%{ Chain.import(%{
addresses: %{params: address_params, with: :balance_changeset}, addresses: %{params: address_params, with: :balance_changeset},
@ -224,14 +224,14 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemand do
end end
defp do_import(%FetchedBalances{} = fetched_balances) do defp do_import(%FetchedBalances{} = fetched_balances) do
case CoinBalanceFetcher.import_fetched_balances(fetched_balances, :on_demand) do case CoinBalanceHelper.import_fetched_balances(fetched_balances, :on_demand) do
{:ok, %{addresses: [address]}} -> {:ok, address} {:ok, %{addresses: [address]}} -> {:ok, address}
_ -> :error _ -> :error
end end
end end
defp do_import_daily_balances(%FetchedBalances{} = fetched_balances) do defp do_import_daily_balances(%FetchedBalances{} = fetched_balances) do
case CoinBalanceFetcher.import_fetched_daily_balances(fetched_balances, :on_demand) do case CoinBalanceHelper.import_fetched_daily_balances(fetched_balances, :on_demand) do
{:ok, %{addresses: [address]}} -> {:ok, address} {:ok, %{addresses: [address]}} -> {:ok, address}
_ -> :error _ -> :error
end end

@ -14,7 +14,7 @@ defmodule Indexer.Fetcher.ContractCode do
alias Explorer.Chain.{Block, Hash} alias Explorer.Chain.{Block, Hash}
alias Explorer.Chain.Cache.Accounts alias Explorer.Chain.Cache.Accounts
alias Indexer.{BufferedTask, Tracer} alias Indexer.{BufferedTask, Tracer}
alias Indexer.Fetcher.CoinBalance, as: CoinBalanceFetcher alias Indexer.Fetcher.CoinBalance.Helper, as: CoinBalanceHelper
alias Indexer.Transform.Addresses alias Indexer.Transform.Addresses
@behaviour BufferedTask @behaviour BufferedTask
@ -122,7 +122,7 @@ defmodule Indexer.Fetcher.ContractCode do
|> EthereumJSONRPC.fetch_balances(json_rpc_named_arguments) |> EthereumJSONRPC.fetch_balances(json_rpc_named_arguments)
|> case do |> case do
{:ok, fetched_balances} -> {:ok, fetched_balances} ->
balance_addresses_params = CoinBalanceFetcher.balances_params_to_address_params(fetched_balances.params_list) balance_addresses_params = CoinBalanceHelper.balances_params_to_address_params(fetched_balances.params_list)
merged_addresses_params = Addresses.merge_addresses(addresses_params ++ balance_addresses_params) merged_addresses_params = Addresses.merge_addresses(addresses_params ++ balance_addresses_params)

@ -18,6 +18,8 @@ defmodule Indexer.Supervisor do
alias Indexer.Block.Catchup, as: BlockCatchup alias Indexer.Block.Catchup, as: BlockCatchup
alias Indexer.Block.Realtime, as: BlockRealtime alias Indexer.Block.Realtime, as: BlockRealtime
alias Indexer.Fetcher.CoinBalance.Catchup, as: CoinBalanceCatchup
alias Indexer.Fetcher.CoinBalance.Realtime, as: CoinBalanceRealtime
alias Indexer.Fetcher.TokenInstance.LegacySanitize, as: TokenInstanceLegacySanitize alias Indexer.Fetcher.TokenInstance.LegacySanitize, as: TokenInstanceLegacySanitize
alias Indexer.Fetcher.TokenInstance.Realtime, as: TokenInstanceRealtime alias Indexer.Fetcher.TokenInstance.Realtime, as: TokenInstanceRealtime
alias Indexer.Fetcher.TokenInstance.Retry, as: TokenInstanceRetry alias Indexer.Fetcher.TokenInstance.Retry, as: TokenInstanceRetry
@ -27,8 +29,6 @@ defmodule Indexer.Supervisor do
alias Indexer.Fetcher.{ alias Indexer.Fetcher.{
BlockReward, BlockReward,
CoinBalance,
CoinBalanceDailyUpdater,
ContractCode, ContractCode,
EmptyBlocksSanitizer, EmptyBlocksSanitizer,
InternalTransaction, InternalTransaction,
@ -118,7 +118,9 @@ defmodule Indexer.Supervisor do
[[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]}, [[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]},
{InternalTransaction.Supervisor, {InternalTransaction.Supervisor,
[[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]}, [[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]},
{CoinBalance.Supervisor, {CoinBalanceCatchup.Supervisor,
[[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]},
{CoinBalanceRealtime.Supervisor,
[[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]}, [[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]},
{Token.Supervisor, [[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]}, {Token.Supervisor, [[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]},
{TokenInstanceRealtime.Supervisor, [[memory_monitor: memory_monitor]]}, {TokenInstanceRealtime.Supervisor, [[memory_monitor: memory_monitor]]},
@ -162,7 +164,6 @@ defmodule Indexer.Supervisor do
{EmptyBlocksSanitizer.Supervisor, [[json_rpc_named_arguments: json_rpc_named_arguments]]}, {EmptyBlocksSanitizer.Supervisor, [[json_rpc_named_arguments: json_rpc_named_arguments]]},
{PendingTransactionsSanitizer, [[json_rpc_named_arguments: json_rpc_named_arguments]]}, {PendingTransactionsSanitizer, [[json_rpc_named_arguments: json_rpc_named_arguments]]},
{TokenTotalSupplyUpdater, [[]]}, {TokenTotalSupplyUpdater, [[]]},
{CoinBalanceDailyUpdater, [[]]},
# Temporary workers # Temporary workers
{UncatalogedTokenTransfers.Supervisor, [[]]}, {UncatalogedTokenTransfers.Supervisor, [[]]},

@ -11,9 +11,9 @@ defmodule Indexer.Block.Catchup.BoundIntervalSupervisorTest do
alias Indexer.BoundInterval alias Indexer.BoundInterval
alias Indexer.Block.Catchup alias Indexer.Block.Catchup
alias Indexer.Block.Catchup.MissingRangesCollector alias Indexer.Block.Catchup.MissingRangesCollector
alias Indexer.Fetcher.CoinBalance.Catchup, as: CoinBalanceCatchup
alias Indexer.Fetcher.{ alias Indexer.Fetcher.{
CoinBalance,
ContractCode, ContractCode,
InternalTransaction, InternalTransaction,
ReplacedTransaction, ReplacedTransaction,
@ -228,7 +228,7 @@ defmodule Indexer.Block.Catchup.BoundIntervalSupervisorTest do
previous_batch_block_number = first_catchup_block_number - default_blocks_batch_size previous_batch_block_number = first_catchup_block_number - default_blocks_batch_size
Application.put_env(:indexer, :block_ranges, "#{previous_batch_block_number}..#{first_catchup_block_number}") Application.put_env(:indexer, :block_ranges, "#{previous_batch_block_number}..#{first_catchup_block_number}")
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
ContractCode.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) ContractCode.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
@ -431,7 +431,7 @@ defmodule Indexer.Block.Catchup.BoundIntervalSupervisorTest do
MissingRangesCollector.start_link([]) MissingRangesCollector.start_link([])
start_supervised!({Task.Supervisor, name: Indexer.Block.Catchup.TaskSupervisor}) start_supervised!({Task.Supervisor, name: Indexer.Block.Catchup.TaskSupervisor})
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
ContractCode.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) ContractCode.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
@ -523,7 +523,7 @@ defmodule Indexer.Block.Catchup.BoundIntervalSupervisorTest do
Application.put_env(:indexer, :block_ranges, "0..0") Application.put_env(:indexer, :block_ranges, "0..0")
MissingRangesCollector.start_link([]) MissingRangesCollector.start_link([])
start_supervised({Task.Supervisor, name: Indexer.Block.Catchup.TaskSupervisor}) start_supervised({Task.Supervisor, name: Indexer.Block.Catchup.TaskSupervisor})
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
ContractCode.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) ContractCode.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)

@ -13,7 +13,8 @@ defmodule Indexer.Block.Catchup.FetcherTest do
alias Indexer.Block alias Indexer.Block
alias Indexer.Block.Catchup.Fetcher alias Indexer.Block.Catchup.Fetcher
alias Indexer.Block.Catchup.MissingRangesCollector alias Indexer.Block.Catchup.MissingRangesCollector
alias Indexer.Fetcher.{BlockReward, CoinBalance, InternalTransaction, Token, TokenBalance, UncleBlock} alias Indexer.Fetcher.CoinBalance.Catchup, as: CoinBalanceCatchup
alias Indexer.Fetcher.{BlockReward, InternalTransaction, Token, TokenBalance, UncleBlock}
@moduletag capture_log: true @moduletag capture_log: true
@ -46,7 +47,7 @@ defmodule Indexer.Block.Catchup.FetcherTest do
end end
test "fetches uncles asynchronously", %{json_rpc_named_arguments: json_rpc_named_arguments} do test "fetches uncles asynchronously", %{json_rpc_named_arguments: json_rpc_named_arguments} do
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
TokenBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) TokenBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
@ -148,7 +149,7 @@ defmodule Indexer.Block.Catchup.FetcherTest do
Application.put_env(:indexer, Indexer.Block.Catchup.Fetcher, batch_size: 1, concurrency: 10) Application.put_env(:indexer, Indexer.Block.Catchup.Fetcher, batch_size: 1, concurrency: 10)
Application.put_env(:indexer, :block_ranges, "0..1") Application.put_env(:indexer, :block_ranges, "0..1")
start_supervised!({Task.Supervisor, name: Indexer.Block.Catchup.TaskSupervisor}) start_supervised!({Task.Supervisor, name: Indexer.Block.Catchup.TaskSupervisor})
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
TokenBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) TokenBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
@ -308,7 +309,7 @@ defmodule Indexer.Block.Catchup.FetcherTest do
Application.put_env(:indexer, Indexer.Block.Catchup.Fetcher, batch_size: 1, concurrency: 10) Application.put_env(:indexer, Indexer.Block.Catchup.Fetcher, batch_size: 1, concurrency: 10)
Application.put_env(:indexer, :block_ranges, "0..1") Application.put_env(:indexer, :block_ranges, "0..1")
start_supervised!({Task.Supervisor, name: Indexer.Block.Catchup.TaskSupervisor}) start_supervised!({Task.Supervisor, name: Indexer.Block.Catchup.TaskSupervisor})
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
TokenBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) TokenBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
@ -465,7 +466,7 @@ defmodule Indexer.Block.Catchup.FetcherTest do
Application.put_env(:indexer, Indexer.Block.Catchup.Fetcher, batch_size: 1, concurrency: 10) Application.put_env(:indexer, Indexer.Block.Catchup.Fetcher, batch_size: 1, concurrency: 10)
Application.put_env(:indexer, :block_ranges, "0..1") Application.put_env(:indexer, :block_ranges, "0..1")
start_supervised!({Task.Supervisor, name: Indexer.Block.Catchup.TaskSupervisor}) start_supervised!({Task.Supervisor, name: Indexer.Block.Catchup.TaskSupervisor})
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
TokenBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) TokenBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)

@ -10,9 +10,9 @@ defmodule Indexer.Block.FetcherTest do
alias Explorer.Chain.{Address, Log, Transaction, Wei} alias Explorer.Chain.{Address, Log, Transaction, Wei}
alias Indexer.Block.Fetcher alias Indexer.Block.Fetcher
alias Indexer.BufferedTask alias Indexer.BufferedTask
alias Indexer.Fetcher.CoinBalance.Catchup, as: CoinBalanceCatchup
alias Indexer.Fetcher.{ alias Indexer.Fetcher.{
CoinBalance,
ContractCode, ContractCode,
InternalTransaction, InternalTransaction,
ReplacedTransaction, ReplacedTransaction,
@ -49,7 +49,7 @@ defmodule Indexer.Block.FetcherTest do
describe "import_range/2" do describe "import_range/2" do
setup %{json_rpc_named_arguments: json_rpc_named_arguments} do setup %{json_rpc_named_arguments: json_rpc_named_arguments} do
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
ContractCode.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) ContractCode.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) InternalTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) Token.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
@ -581,7 +581,7 @@ defmodule Indexer.Block.FetcherTest do
}} = Fetcher.fetch_and_import_range(block_fetcher, block_number..block_number) }} = Fetcher.fetch_and_import_range(block_fetcher, block_number..block_number)
wait_for_tasks(InternalTransaction) wait_for_tasks(InternalTransaction)
wait_for_tasks(CoinBalance) wait_for_tasks(CoinBalanceCatchup)
assert Repo.aggregate(Block, :count, :hash) == 1 assert Repo.aggregate(Block, :count, :hash) == 1
assert Repo.aggregate(Address, :count, :hash) == 5 assert Repo.aggregate(Address, :count, :hash) == 5
@ -675,7 +675,7 @@ defmodule Indexer.Block.FetcherTest do
}} = Fetcher.fetch_and_import_range(block_fetcher, block_number..block_number) }} = Fetcher.fetch_and_import_range(block_fetcher, block_number..block_number)
wait_for_tasks(InternalTransaction) wait_for_tasks(InternalTransaction)
wait_for_tasks(CoinBalance) wait_for_tasks(CoinBalanceCatchup)
assert Repo.aggregate(Chain.Block, :count, :hash) == 1 assert Repo.aggregate(Chain.Block, :count, :hash) == 1
assert Repo.aggregate(Address, :count, :hash) == 2 assert Repo.aggregate(Address, :count, :hash) == 2

@ -8,6 +8,7 @@ defmodule Indexer.Block.Realtime.FetcherTest do
alias Explorer.Chain.{Address, Transaction, Wei} alias Explorer.Chain.{Address, Transaction, Wei}
alias Indexer.Block.Catchup.Sequence alias Indexer.Block.Catchup.Sequence
alias Indexer.Block.Realtime alias Indexer.Block.Realtime
alias Indexer.Fetcher.CoinBalance.Realtime, as: CoinBalanceRealtime
alias Indexer.Fetcher.{ContractCode, InternalTransaction, ReplacedTransaction, Token, TokenBalance, UncleBlock} alias Indexer.Fetcher.{ContractCode, InternalTransaction, ReplacedTransaction, Token, TokenBalance, UncleBlock}
@moduletag capture_log: true @moduletag capture_log: true
@ -36,6 +37,7 @@ defmodule Indexer.Block.Realtime.FetcherTest do
} }
TokenBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) TokenBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
CoinBalanceRealtime.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
%{block_fetcher: block_fetcher, json_rpc_named_arguments: core_json_rpc_named_arguments} %{block_fetcher: block_fetcher, json_rpc_named_arguments: core_json_rpc_named_arguments}
end end
@ -205,7 +207,7 @@ defmodule Indexer.Block.Realtime.FetcherTest do
} }
]} ]}
end) end)
|> expect(:json_rpc, 4, fn |> expect(:json_rpc, 1, fn
[ [
%{id: 0, jsonrpc: "2.0", method: "trace_block", params: ["0x3C365F"]}, %{id: 0, jsonrpc: "2.0", method: "trace_block", params: ["0x3C365F"]},
%{id: 1, jsonrpc: "2.0", method: "trace_block", params: ["0x3C3660"]} %{id: 1, jsonrpc: "2.0", method: "trace_block", params: ["0x3C3660"]}
@ -470,43 +472,6 @@ defmodule Indexer.Block.Realtime.FetcherTest do
] ]
} }
]} ]}
[
[
%{
id: 0,
jsonrpc: "2.0",
method: "eth_getBalance",
params: ["0x40b18103537c0f15d5e137dd8ddd019b84949d16", "0x3C365F"]
},
%{
id: 1,
jsonrpc: "2.0",
method: "eth_getBalance",
params: ["0x5ee341ac44d344ade1ca3a771c59b98eb2a77df2", "0x3C365F"]
},
%{
id: 2,
jsonrpc: "2.0",
method: "eth_getBalance",
params: ["0x66c9343c7e8ca673a1fedf9dbf2cd7936dbbf7e3", "0x3C3660"]
},
%{
id: 3,
jsonrpc: "2.0",
method: "eth_getBalance",
params: ["0x698bf6943bab687b2756394624aa183f434f65da", "0x3C365F"]
}
]
],
_ ->
{:ok,
[
%{id: 0, jsonrpc: "2.0", result: "0x148adc763b603291685"},
%{id: 1, jsonrpc: "2.0", result: "0x53474fa377a46000"},
%{id: 2, jsonrpc: "2.0", result: "0x53507afe51f28000"},
%{id: 3, jsonrpc: "2.0", result: "0x3e1a95d7517dc197108"}
]}
end) end)
end end
@ -514,10 +479,10 @@ defmodule Indexer.Block.Realtime.FetcherTest do
%{ %{
inserted: %{ inserted: %{
addresses: [ addresses: [
%Address{hash: first_address_hash, fetched_coin_balance_block_number: 3_946_079}, %Address{hash: first_address_hash},
%Address{hash: second_address_hash, fetched_coin_balance_block_number: 3_946_079}, %Address{hash: second_address_hash},
%Address{hash: third_address_hash, fetched_coin_balance_block_number: 3_946_080}, %Address{hash: third_address_hash},
%Address{hash: fourth_address_hash, fetched_coin_balance_block_number: 3_946_079} %Address{hash: fourth_address_hash}
], ],
address_coin_balances: [ address_coin_balances: [
%{ %{
@ -710,298 +675,6 @@ defmodule Indexer.Block.Realtime.FetcherTest do
} }
]} ]}
end) end)
|> expect(:json_rpc, 3, fn
[
%{
id: 0,
jsonrpc: "2.0",
method: "eth_getBlockByNumber",
params: ["0x3C365F", true]
}
],
_ ->
{:ok,
[
%{
id: 0,
jsonrpc: "2.0",
result: %{
"author" => "0x5ee341ac44d344ade1ca3a771c59b98eb2a77df2",
"difficulty" => "0xfffffffffffffffffffffffffffffffe",
"extraData" => "0xd583010b088650617269747986312e32372e32826c69",
"gasLimit" => "0x7a1200",
"gasUsed" => "0x2886e",
"hash" => "0xa4ec735cabe1510b5ae081b30f17222580b4588dbec52830529753a688b046cc",
"logsBloom" =>
"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner" => "0x5ee341ac44d344ade1ca3a771c59b98eb2a77df2",
"number" => "0x3c365f",
"parentHash" => "0x57f6d66e07488defccd5216c4d2968dd6afd3bd32415e284de3b02af6535e8dc",
"receiptsRoot" => "0x111be72e682cea9c93e02f1ef503fb64aa821b2ef510fd9177c49b37d0af98b5",
"sealFields" => [
"0x841246c63f",
"0xb841ba3d11db672fd7893d1b7906275fa7c4c7f4fbcc8fa29eab0331480332361516545ef10a36d800ad2be2b449dde8d5703125156a9cf8a035f5a8623463e051b700"
],
"sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"signature" =>
"ba3d11db672fd7893d1b7906275fa7c4c7f4fbcc8fa29eab0331480332361516545ef10a36d800ad2be2b449dde8d5703125156a9cf8a035f5a8623463e051b700",
"size" => "0x33e",
"stateRoot" => "0x7f73f5fb9f891213b671356126c31e9795d038844392c7aa8800ed4f52307209",
"step" => "306628159",
"timestamp" => "0x5b61df3b",
"totalDifficulty" => "0x3c365effffffffffffffffffffffffed7f0362",
"transactions" => [
%{
"blockHash" => "0xa4ec735cabe1510b5ae081b30f17222580b4588dbec52830529753a688b046cc",
"blockNumber" => "0x3c365f",
"chainId" => "0x63",
"condition" => nil,
"creates" => nil,
"from" => "0x40b18103537c0f15d5e137dd8ddd019b84949d16",
"gas" => "0x3d9c5",
"gasPrice" => "0x3b9aca00",
"hash" => "0xd3937e70fab3fb2bfe8feefac36815408bf07de3b9e09fe81114b9a6b17f55c8",
"input" =>
"0x8841ac11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000005",
"nonce" => "0x65b",
"publicKey" =>
"0x89c2123ed4b5d141cf1f4b6f5f3d754418f03aea2e870a1c50888d94bf5531f74237e2fea72d0bc198ef213272b62c6869615720757255e6cba087f9db6e759f",
"r" => "0x55a1a93541d7f782f97f6699437bb60fa4606d63760b30c1ee317e648f93995",
"raw" =>
"0xf8f582065b843b9aca008303d9c594698bf6943bab687b2756394624aa183f434f65da8901158e4f216242a000b8848841ac11000000000000000000000000000000000000000000000000000000000000006c00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000581eaa0055a1a93541d7f782f97f6699437bb60fa4606d63760b30c1ee317e648f93995a06affd4da5eca84fbca2b016c980f861e0af1f8d6535e2fe29d8f96dc0ce358f7",
"s" => "0x6affd4da5eca84fbca2b016c980f861e0af1f8d6535e2fe29d8f96dc0ce358f7",
"standardV" => "0x1",
"to" => "0x698bf6943bab687b2756394624aa183f434f65da",
"transactionIndex" => "0x0",
"v" => "0xea",
"value" => "0x1158e4f216242a000"
}
],
"transactionsRoot" => "0xd7c39a93eafe0bdcbd1324c13dcd674bed8c9fa8adbf8f95bf6a59788985da6f",
"uncles" => ["0xa4ec735cabe1510b5ae081b30f17222580b4588dbec52830529753a688b046cd"]
}
}
]}
[
%{
id: 0,
jsonrpc: "2.0",
method: "eth_getBlockByNumber",
params: ["0x3C3660", true]
}
],
_ ->
{:ok,
[
%{
id: 0,
jsonrpc: "2.0",
result: %{
"author" => "0x66c9343c7e8ca673a1fedf9dbf2cd7936dbbf7e3",
"difficulty" => "0xfffffffffffffffffffffffffffffffe",
"extraData" => "0xd583010a068650617269747986312e32362e32826c69",
"gasLimit" => "0x7a1200",
"gasUsed" => "0x0",
"hash" => "0xfb483e511d316fa4072694da3f7abc94b06286406af45061e5e681395bdc6815",
"logsBloom" =>
"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner" => "0x66c9343c7e8ca673a1fedf9dbf2cd7936dbbf7e3",
"number" => "0x3c3660",
"parentHash" => "0xa4ec735cabe1510b5ae081b30f17222580b4588dbec52830529753a688b046cc",
"receiptsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"sealFields" => [
"0x841246c640",
"0xb84114db3fd7526b7ea3635f5c85c30dd8a645453aa2f8afe5fd33fe0ec663c9c7b653b0fb5d8dc7d0b809674fa9dca9887d1636a586bf62191da22255eb068bf20800"
],
"sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"signature" =>
"14db3fd7526b7ea3635f5c85c30dd8a645453aa2f8afe5fd33fe0ec663c9c7b653b0fb5d8dc7d0b809674fa9dca9887d1636a586bf62191da22255eb068bf20800",
"size" => "0x243",
"stateRoot" => "0x3174c461989e9f99e08fa9b4ffb8bce8d9a281c8fc9f80694bb9d3acd4f15559",
"step" => "306628160",
"timestamp" => "0x5b61df40",
"totalDifficulty" => "0x3c365fffffffffffffffffffffffffed7f0360",
"transactions" => [],
"transactionsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncles" => []
}
}
]}
[
%{
id: 0,
jsonrpc: "2.0",
method: "trace_replayBlockTransactions",
params: [
"0x3C3660",
["trace"]
]
},
%{
id: 1,
jsonrpc: "2.0",
method: "trace_replayBlockTransactions",
params: [
"0x3C365F",
["trace"]
]
}
],
_ ->
{:ok,
[
%{id: 0, jsonrpc: "2.0", result: []},
%{
id: 1,
jsonrpc: "2.0",
result: [
%{
"output" => "0x",
"stateDiff" => nil,
"trace" => [
%{
"action" => %{
"callType" => "call",
"from" => "0x40b18103537c0f15d5e137dd8ddd019b84949d16",
"gas" => "0x383ad",
"input" =>
"0x8841ac11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000005",
"to" => "0x698bf6943bab687b2756394624aa183f434f65da",
"value" => "0x1158e4f216242a000"
},
"result" => %{"gasUsed" => "0x23256", "output" => "0x"},
"subtraces" => 5,
"traceAddress" => [],
"type" => "call"
},
%{
"action" => %{
"callType" => "call",
"from" => "0x698bf6943bab687b2756394624aa183f434f65da",
"gas" => "0x36771",
"input" => "0x6352211e000000000000000000000000000000000000000000000000000000000000006c",
"to" => "0x11c4469d974f8af5ba9ec99f3c42c07c848c861c",
"value" => "0x0"
},
"result" => %{
"gasUsed" => "0x495",
"output" => "0x00000000000000000000000040b18103537c0f15d5e137dd8ddd019b84949d16"
},
"subtraces" => 0,
"traceAddress" => [0],
"type" => "call"
},
%{
"action" => %{
"callType" => "call",
"from" => "0x698bf6943bab687b2756394624aa183f434f65da",
"gas" => "0x35acb",
"input" => "0x33f30a43000000000000000000000000000000000000000000000000000000000000006c",
"to" => "0x11c4469d974f8af5ba9ec99f3c42c07c848c861c",
"value" => "0x0"
},
"result" => %{
"gasUsed" => "0x52d2",
"output" =>
"0x00000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000058000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004e000000000000000000000000000000000000000000000000000000000000004f000000000000000000000000000000000000000000000000000000000000004d000000000000000000000000000000000000000000000000000000000000004b000000000000000000000000000000000000000000000000000000000000004f00000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000005b61df09000000000000000000000000000000000000000000000000000000005b61df5e000000000000000000000000000000000000000000000000000000005b61df8b000000000000000000000000000000000000000000000000000000005b61df2c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c00000000000000000000000000000000000000000000000000000000000000fd000000000000000000000000000000000000000000000000000000000000004e000000000000000000000000000000000000000000000000000000000000007a000000000000000000000000000000000000000000000000000000000000004e0000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000054c65696c61000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002566303430313037303331343330303332333036303933333235303131323036303730373131000000000000000000000000000000000000000000000000000000"
},
"subtraces" => 0,
"traceAddress" => [1],
"type" => "call"
},
%{
"action" => %{
"callType" => "call",
"from" => "0x698bf6943bab687b2756394624aa183f434f65da",
"gas" => "0x2fc79",
"input" => "0x1b8ef0bb000000000000000000000000000000000000000000000000000000000000006c",
"to" => "0x11c4469d974f8af5ba9ec99f3c42c07c848c861c",
"value" => "0x0"
},
"result" => %{
"gasUsed" => "0x10f2",
"output" => "0x0000000000000000000000000000000000000000000000000000000000000013"
},
"subtraces" => 0,
"traceAddress" => [2],
"type" => "call"
},
%{
"action" => %{
"callType" => "call",
"from" => "0x698bf6943bab687b2756394624aa183f434f65da",
"gas" => "0x2e21f",
"input" =>
"0xcf5f87d0000000000000000000000000000000000000000000000000000000000000006c0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000a",
"to" => "0x11c4469d974f8af5ba9ec99f3c42c07c848c861c",
"value" => "0x0"
},
"result" => %{"gasUsed" => "0x1ca1", "output" => "0x"},
"subtraces" => 0,
"traceAddress" => [3],
"type" => "call"
},
%{
"action" => %{
"callType" => "call",
"from" => "0x698bf6943bab687b2756394624aa183f434f65da",
"gas" => "0x8fc",
"input" => "0x",
"to" => "0x40b18103537c0f15d5e137dd8ddd019b84949d16",
"value" => "0x9184e72a000"
},
"result" => %{"gasUsed" => "0x0", "output" => "0x"},
"subtraces" => 0,
"traceAddress" => [4],
"type" => "call"
}
],
"transactionHash" => "0xd3937e70fab3fb2bfe8feefac36815408bf07de3b9e09fe81114b9a6b17f55c8",
"vmTrace" => nil
}
]
}
]}
[
[
%{
id: 0,
jsonrpc: "2.0",
method: "eth_getBalance",
params: ["0x40b18103537c0f15d5e137dd8ddd019b84949d16", "0x3C365F"]
},
%{
id: 1,
jsonrpc: "2.0",
method: "eth_getBalance",
params: ["0x5ee341ac44d344ade1ca3a771c59b98eb2a77df2", "0x3C365F"]
},
%{
id: 2,
jsonrpc: "2.0",
method: "eth_getBalance",
params: ["0x66c9343c7e8ca673a1fedf9dbf2cd7936dbbf7e3", "0x3C3660"]
},
%{
id: 3,
jsonrpc: "2.0",
method: "eth_getBalance",
params: ["0x698bf6943bab687b2756394624aa183f434f65da", "0x3C365F"]
}
]
],
_ ->
{:ok,
[
%{id: 0, jsonrpc: "2.0", result: "0x148adc763b603291685"},
%{id: 1, jsonrpc: "2.0", result: "0x53474fa377a46000"},
%{id: 2, jsonrpc: "2.0", result: "0x53507afe51f28000"},
%{id: 3, jsonrpc: "2.0", result: "0x3e1a95d7517dc197108"}
]}
end)
end end
first_expected_reward = %Wei{value: Decimal.new(165_998_000_000_000)} first_expected_reward = %Wei{value: Decimal.new(165_998_000_000_000)}
@ -1011,10 +684,10 @@ defmodule Indexer.Block.Realtime.FetcherTest do
%{ %{
inserted: %{ inserted: %{
addresses: [ addresses: [
%Address{hash: first_address_hash, fetched_coin_balance_block_number: 3_946_079}, %Address{hash: first_address_hash},
%Address{hash: second_address_hash, fetched_coin_balance_block_number: 3_946_079}, %Address{hash: second_address_hash},
%Address{hash: third_address_hash, fetched_coin_balance_block_number: 3_946_080}, %Address{hash: third_address_hash},
%Address{hash: fourth_address_hash, fetched_coin_balance_block_number: 3_946_079} %Address{hash: fourth_address_hash}
], ],
address_coin_balances: [ address_coin_balances: [
%{ %{
@ -1187,27 +860,23 @@ defmodule Indexer.Block.Realtime.FetcherTest do
]} ]}
[ [
[ %{
%{ id: 0,
id: 0, jsonrpc: "2.0",
jsonrpc: "2.0", method: "eth_getBalance",
method: "eth_getBalance", params: ["0x5ee341ac44d344ade1ca3a771c59b98eb2a77df2", "0x3C365F"]
params: ["0x5ee341ac44d344ade1ca3a771c59b98eb2a77df2", "0x3C365F"] }
}
]
], ],
_ -> _ ->
{:ok, [%{id: 0, jsonrpc: "2.0", result: "0x53474fa377a46000"}]} {:ok, [%{id: 0, jsonrpc: "2.0", result: "0x53474fa377a46000"}]}
[ [
[ %{
%{ id: 0,
id: 0, jsonrpc: "2.0",
jsonrpc: "2.0", method: "eth_getBalance",
method: "eth_getBalance", params: ["0x66c9343c7e8ca673a1fedf9dbf2cd7936dbbf7e3", "0x3C3660"]
params: ["0x66c9343c7e8ca673a1fedf9dbf2cd7936dbbf7e3", "0x3C3660"] }
}
]
], ],
_ -> _ ->
{:ok, [%{id: 0, jsonrpc: "2.0", result: "0x53507afe51f28000"}]} {:ok, [%{id: 0, jsonrpc: "2.0", result: "0x53507afe51f28000"}]}
@ -1232,14 +901,12 @@ defmodule Indexer.Block.Realtime.FetcherTest do
]} ]}
[ [
[ %{
%{ id: 0,
id: 0, jsonrpc: "2.0",
jsonrpc: "2.0", method: "eth_getBalance",
method: "eth_getBalance", params: ["0x5ee341ac44d344ade1ca3a771c59b98eb2a77df2", "0x3C365F"]
params: ["0x5ee341ac44d344ade1ca3a771c59b98eb2a77df2", "0x3C365F"] }
}
]
], ],
_ -> _ ->
{:ok, [%{id: 0, jsonrpc: "2.0", result: "0x53474fa377a46000"}]} {:ok, [%{id: 0, jsonrpc: "2.0", result: "0x53474fa377a46000"}]}

@ -132,7 +132,7 @@ defmodule Indexer.Fetcher.BlockRewardTest do
end end
end) end)
Process.register(pid, Indexer.Fetcher.CoinBalance) Process.register(pid, Indexer.Fetcher.CoinBalance.Catchup)
assert :ok = BlockReward.async_fetch([block_number]) assert :ok = BlockReward.async_fetch([block_number])
@ -205,7 +205,7 @@ defmodule Indexer.Fetcher.BlockRewardTest do
end end
end) end)
Process.register(pid, Indexer.Fetcher.CoinBalance) Process.register(pid, Indexer.Fetcher.CoinBalance.Catchup)
assert :ok = BlockReward.async_fetch([block_number]) assert :ok = BlockReward.async_fetch([block_number])
@ -340,7 +340,7 @@ defmodule Indexer.Fetcher.BlockRewardTest do
end end
end) end)
Process.register(pid, Indexer.Fetcher.CoinBalance) Process.register(pid, Indexer.Fetcher.CoinBalance.Catchup)
assert :ok = BlockReward.run([block_number], json_rpc_named_arguments) assert :ok = BlockReward.run([block_number], json_rpc_named_arguments)
@ -430,7 +430,7 @@ defmodule Indexer.Fetcher.BlockRewardTest do
end end
end) end)
Process.register(pid, Indexer.Fetcher.CoinBalance) Process.register(pid, Indexer.Fetcher.CoinBalance.Catchup)
assert :ok = BlockReward.run([block_number], json_rpc_named_arguments) assert :ok = BlockReward.run([block_number], json_rpc_named_arguments)
@ -514,7 +514,7 @@ defmodule Indexer.Fetcher.BlockRewardTest do
end end
end) end)
Process.register(pid, Indexer.Fetcher.CoinBalance) Process.register(pid, Indexer.Fetcher.CoinBalance.Catchup)
assert :ok = BlockReward.run([block_number], json_rpc_named_arguments) assert :ok = BlockReward.run([block_number], json_rpc_named_arguments)
@ -651,7 +651,7 @@ defmodule Indexer.Fetcher.BlockRewardTest do
end end
end) end)
Process.register(pid, Indexer.Fetcher.CoinBalance) Process.register(pid, Indexer.Fetcher.CoinBalance.Catchup)
assert {:retry, [^error_block_number]} = assert {:retry, [^error_block_number]} =
BlockReward.run([block_number, error_block_number], json_rpc_named_arguments) BlockReward.run([block_number, error_block_number], json_rpc_named_arguments)

@ -1,4 +1,4 @@
defmodule Indexer.Fetcher.CoinBalanceTest do defmodule Indexer.Fetcher.CoinBalance.CatchupTest do
# MUST be `async: false` so that {:shared, pid} is set for connection to allow CoinBalanceFetcher's self-send to have # MUST be `async: false` so that {:shared, pid} is set for connection to allow CoinBalanceFetcher's self-send to have
# connection allowed immediately. # connection allowed immediately.
use EthereumJSONRPC.Case, async: false use EthereumJSONRPC.Case, async: false
@ -8,7 +8,7 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
import Mox import Mox
alias Explorer.Chain.{Address, Hash, Wei} alias Explorer.Chain.{Address, Hash, Wei}
alias Indexer.Fetcher.CoinBalance alias Indexer.Fetcher.CoinBalance.Catchup, as: CoinBalanceCatchup
@moduletag :capture_log @moduletag :capture_log
@ -83,7 +83,7 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
assert miner.fetched_coin_balance == nil assert miner.fetched_coin_balance == nil
assert miner.fetched_coin_balance_block_number == nil assert miner.fetched_coin_balance_block_number == nil
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
fetched_address = fetched_address =
wait(fn -> wait(fn ->
@ -151,7 +151,7 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
block = insert(:block, miner: miner, number: block_number) block = insert(:block, miner: miner, number: block_number)
insert(:unfetched_balance, address_hash: miner.hash, block_number: block_number) insert(:unfetched_balance, address_hash: miner.hash, block_number: block_number)
CoinBalance.Supervisor.Case.start_supervised!( CoinBalanceCatchup.Supervisor.Case.start_supervised!(
json_rpc_named_arguments: json_rpc_named_arguments, json_rpc_named_arguments: json_rpc_named_arguments,
max_batch_size: 2 max_batch_size: 2
) )
@ -225,9 +225,9 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
end) end)
end end
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
assert :ok = CoinBalance.async_fetch_balances([%{address_hash: hash, block_number: block_number}]) assert :ok = CoinBalanceCatchup.async_fetch_balances([%{address_hash: hash, block_number: block_number}])
address = address =
wait(fn -> wait(fn ->
@ -318,7 +318,7 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
{:ok, [res2]} {:ok, [res2]}
end) end)
case CoinBalance.run(entries, json_rpc_named_arguments) do case CoinBalanceCatchup.run(entries, json_rpc_named_arguments) do
:ok -> :ok ->
balances = Repo.all(from(balance in Address.CoinBalance, where: balance.address_hash == ^hash_data)) balances = Repo.all(from(balance in Address.CoinBalance, where: balance.address_hash == ^hash_data))
@ -373,7 +373,7 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
{:ok, [%{id: id, error: %{code: 1, message: "Bad"}}]} {:ok, [%{id: id, error: %{code: 1, message: "Bad"}}]}
end) end)
assert {:retry, ^entries} = CoinBalance.run(entries, json_rpc_named_arguments) assert {:retry, ^entries} = CoinBalanceCatchup.run(entries, json_rpc_named_arguments)
end end
test "retries none if all imported and no fetch errors", %{json_rpc_named_arguments: json_rpc_named_arguments} do test "retries none if all imported and no fetch errors", %{json_rpc_named_arguments: json_rpc_named_arguments} do
@ -401,7 +401,7 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
{:ok, [res]} {:ok, [res]}
end) end)
assert :ok = CoinBalance.run(entries, json_rpc_named_arguments) assert :ok = CoinBalanceCatchup.run(entries, json_rpc_named_arguments)
end end
test "retries fetch errors if all imported", %{json_rpc_named_arguments: json_rpc_named_arguments} do test "retries fetch errors if all imported", %{json_rpc_named_arguments: json_rpc_named_arguments} do
@ -457,7 +457,7 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
end) end)
assert {:retry, [{^address_hash_bytes, ^bad_block_number}]} = assert {:retry, [{^address_hash_bytes, ^bad_block_number}]} =
CoinBalance.run( CoinBalanceCatchup.run(
[{address_hash_bytes, good_block_number}, {address_hash_bytes, bad_block_number}], [{address_hash_bytes, good_block_number}, {address_hash_bytes, bad_block_number}],
json_rpc_named_arguments json_rpc_named_arguments
) )

@ -9,7 +9,8 @@ defmodule Indexer.Fetcher.InternalTransactionTest do
alias Explorer.{Chain, Repo} alias Explorer.{Chain, Repo}
alias Explorer.Chain.{Block, PendingBlockOperation} alias Explorer.Chain.{Block, PendingBlockOperation}
alias Explorer.Chain.Import.Runner.Blocks alias Explorer.Chain.Import.Runner.Blocks
alias Indexer.Fetcher.{CoinBalance, InternalTransaction, PendingTransaction} alias Indexer.Fetcher.CoinBalance.Catchup, as: CoinBalanceCatchup
alias Indexer.Fetcher.{InternalTransaction, PendingTransaction}
# MUST use global mode because we aren't guaranteed to get PendingTransactionFetcher's pid back fast enough to `allow` # MUST use global mode because we aren't guaranteed to get PendingTransactionFetcher's pid back fast enough to `allow`
# it to use expectations and stubs from test's pid. # it to use expectations and stubs from test's pid.
@ -65,7 +66,7 @@ defmodule Indexer.Fetcher.InternalTransactionTest do
end end
end end
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
PendingTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) PendingTransaction.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
wait_for_results(fn -> wait_for_results(fn ->
@ -276,7 +277,7 @@ defmodule Indexer.Fetcher.InternalTransactionTest do
end end
end end
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalanceCatchup.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
assert %{block_hash: block_hash} = Repo.get(PendingBlockOperation, block_hash) assert %{block_hash: block_hash} = Repo.get(PendingBlockOperation, block_hash)

@ -1,5 +1,5 @@
defmodule Indexer.Fetcher.CoinBalance.Supervisor.Case do defmodule Indexer.Fetcher.CoinBalance.Catchup.Supervisor.Case do
alias Indexer.Fetcher.CoinBalance alias Indexer.Fetcher.CoinBalance.Catchup
def start_supervised!(fetcher_arguments \\ []) when is_list(fetcher_arguments) do def start_supervised!(fetcher_arguments \\ []) when is_list(fetcher_arguments) do
merged_fetcher_arguments = merged_fetcher_arguments =
@ -11,7 +11,7 @@ defmodule Indexer.Fetcher.CoinBalance.Supervisor.Case do
) )
[merged_fetcher_arguments] [merged_fetcher_arguments]
|> CoinBalance.Supervisor.child_spec() |> Catchup.Supervisor.child_spec()
|> ExUnit.Callbacks.start_supervised!() |> ExUnit.Callbacks.start_supervised!()
end end
end end

@ -0,0 +1,17 @@
defmodule Indexer.Fetcher.CoinBalance.Realtime.Supervisor.Case do
alias Indexer.Fetcher.CoinBalance.Realtime
def start_supervised!(fetcher_arguments \\ []) when is_list(fetcher_arguments) do
merged_fetcher_arguments =
Keyword.merge(
fetcher_arguments,
flush_interval: 50,
max_batch_size: 1,
max_concurrency: 1
)
[merged_fetcher_arguments]
|> Realtime.Supervisor.child_spec()
|> ExUnit.Callbacks.start_supervised!()
end
end

@ -573,8 +573,11 @@ config :indexer, Indexer.Fetcher.BlockReward.Supervisor,
config :indexer, Indexer.Fetcher.InternalTransaction.Supervisor, config :indexer, Indexer.Fetcher.InternalTransaction.Supervisor,
disabled?: ConfigHelper.parse_bool_env_var("INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER") disabled?: ConfigHelper.parse_bool_env_var("INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER")
config :indexer, Indexer.Fetcher.CoinBalance.Supervisor, disable_coin_balances_fetcher? = ConfigHelper.parse_bool_env_var("INDEXER_DISABLE_ADDRESS_COIN_BALANCE_FETCHER")
disabled?: ConfigHelper.parse_bool_env_var("INDEXER_DISABLE_ADDRESS_COIN_BALANCE_FETCHER")
config :indexer, Indexer.Fetcher.CoinBalance.Catchup.Supervisor, disabled?: disable_coin_balances_fetcher?
config :indexer, Indexer.Fetcher.CoinBalance.Realtime.Supervisor, disabled?: disable_coin_balances_fetcher?
config :indexer, Indexer.Fetcher.TokenUpdater.Supervisor, config :indexer, Indexer.Fetcher.TokenUpdater.Supervisor,
disabled?: ConfigHelper.parse_bool_env_var("INDEXER_DISABLE_CATALOGED_TOKEN_UPDATER_FETCHER") disabled?: ConfigHelper.parse_bool_env_var("INDEXER_DISABLE_CATALOGED_TOKEN_UPDATER_FETCHER")
@ -659,9 +662,16 @@ config :indexer, Indexer.Fetcher.InternalTransaction,
indexing_finished_threshold: indexing_finished_threshold:
ConfigHelper.parse_integer_env_var("INDEXER_INTERNAL_TRANSACTIONS_INDEXING_FINISHED_THRESHOLD", 1000) ConfigHelper.parse_integer_env_var("INDEXER_INTERNAL_TRANSACTIONS_INDEXING_FINISHED_THRESHOLD", 1000)
config :indexer, Indexer.Fetcher.CoinBalance, coin_balances_batch_size = ConfigHelper.parse_integer_env_var("INDEXER_COIN_BALANCES_BATCH_SIZE", 100)
batch_size: ConfigHelper.parse_integer_env_var("INDEXER_COIN_BALANCES_BATCH_SIZE", 500), coin_balances_concurrency = ConfigHelper.parse_integer_env_var("INDEXER_COIN_BALANCES_CONCURRENCY", 4)
concurrency: ConfigHelper.parse_integer_env_var("INDEXER_COIN_BALANCES_CONCURRENCY", 4)
config :indexer, Indexer.Fetcher.CoinBalance.Catchup,
batch_size: coin_balances_batch_size,
concurrency: coin_balances_concurrency
config :indexer, Indexer.Fetcher.CoinBalance.Realtime,
batch_size: coin_balances_batch_size,
concurrency: coin_balances_concurrency
config :indexer, Indexer.Fetcher.Withdrawal.Supervisor, config :indexer, Indexer.Fetcher.Withdrawal.Supervisor,
disabled?: System.get_env("INDEXER_DISABLE_WITHDRAWALS_FETCHER", "true") == "true" disabled?: System.get_env("INDEXER_DISABLE_WITHDRAWALS_FETCHER", "true") == "true"

@ -117,6 +117,7 @@ API_RATE_LIMIT_BY_IP=3000
DISABLE_INDEXER=false DISABLE_INDEXER=false
DISABLE_REALTIME_INDEXER=false DISABLE_REALTIME_INDEXER=false
DISABLE_CATCHUP_INDEXER=false DISABLE_CATCHUP_INDEXER=false
INDEXER_DISABLE_ADDRESS_COIN_BALANCE_FETCHER=false
INDEXER_DISABLE_TOKEN_INSTANCE_REALTIME_FETCHER=false INDEXER_DISABLE_TOKEN_INSTANCE_REALTIME_FETCHER=false
INDEXER_DISABLE_TOKEN_INSTANCE_RETRY_FETCHER=false INDEXER_DISABLE_TOKEN_INSTANCE_RETRY_FETCHER=false
INDEXER_DISABLE_TOKEN_INSTANCE_SANITIZE_FETCHER=false INDEXER_DISABLE_TOKEN_INSTANCE_SANITIZE_FETCHER=false

Loading…
Cancel
Save