Merge branch 'master' into json-rpc-error-messages

pull/1701/head
Zach Daniel 6 years ago committed by GitHub
commit ecb226d113
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .circleci/config.yml
  2. 28
      CHANGELOG.md
  3. 17
      PULL_REQUEST_TEMPLATE.md
  4. 16
      apps/block_scout_web/assets/css/_code.scss
  5. 2
      apps/block_scout_web/config/config.exs
  6. 6
      apps/block_scout_web/lib/block_scout_web/chain.ex
  7. 4
      apps/block_scout_web/lib/block_scout_web/controllers/address_coin_balance_controller.ex
  8. 4
      apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex
  9. 4
      apps/block_scout_web/lib/block_scout_web/controllers/address_decompiled_contract_controller.ex
  10. 4
      apps/block_scout_web/lib/block_scout_web/controllers/address_internal_transaction_controller.ex
  11. 4
      apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex
  12. 4
      apps/block_scout_web/lib/block_scout_web/controllers/address_token_controller.ex
  13. 4
      apps/block_scout_web/lib/block_scout_web/controllers/address_token_transfer_controller.ex
  14. 4
      apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
  15. 4
      apps/block_scout_web/lib/block_scout_web/controllers/address_validation_controller.ex
  16. 16
      apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex
  17. 8
      apps/block_scout_web/lib/block_scout_web/etherscan.ex
  18. 2
      apps/block_scout_web/lib/block_scout_web/notifier.ex
  19. 2
      apps/block_scout_web/lib/block_scout_web/templates/address/_tabs.html.eex
  20. 6
      apps/block_scout_web/lib/block_scout_web/templates/address_decompiled_contract/index.html.eex
  21. 2
      apps/block_scout_web/lib/block_scout_web/templates/layout/_footer.html.eex
  22. 41
      apps/block_scout_web/lib/block_scout_web/views/address_decompiled_contract_view.ex
  23. 8
      apps/block_scout_web/lib/block_scout_web/views/api/rpc/address_view.ex
  24. 14
      apps/block_scout_web/lib/block_scout_web/views/api/rpc/transaction_view.ex
  25. 18
      apps/block_scout_web/priv/gettext/default.pot
  26. 22
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  27. 56
      apps/block_scout_web/test/block_scout_web/controllers/api/rpc/transaction_controller_test.exs
  28. 74
      apps/block_scout_web/test/block_scout_web/views/address_decompiled_contract_view_test.exs
  29. 13
      apps/explorer/config/config.exs
  30. 9
      apps/explorer/lib/explorer/chain/block_number_cache.ex
  31. 2
      apps/explorer/lib/explorer/chain/transaction_count_cache.ex
  32. 4
      apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex
  33. 59
      apps/explorer/lib/explorer/counters/average_block_time.ex
  34. 38
      apps/explorer/test/explorer/counters/average_block_time_test.exs
  35. 8
      apps/indexer/config/config.exs
  36. 9
      apps/indexer/lib/indexer/application.ex
  37. 66
      apps/indexer/lib/indexer/block/catchup/fetcher.ex
  38. 6
      apps/indexer/lib/indexer/block/catchup/sequence.ex
  39. 104
      apps/indexer/lib/indexer/block/fetcher.ex
  40. 210
      apps/indexer/lib/indexer/block/realtime/fetcher.ex
  41. 46
      apps/indexer/lib/indexer/block/reward/supervisor.ex
  42. 78
      apps/indexer/lib/indexer/block/supervisor.ex
  43. 21
      apps/indexer/lib/indexer/block/transform.ex
  44. 38
      apps/indexer/lib/indexer/block/uncle/supervisor.ex
  45. 39
      apps/indexer/lib/indexer/code/supervisor.ex
  46. 39
      apps/indexer/lib/indexer/coin_balance/supervisor.ex
  47. 77
      apps/indexer/lib/indexer/fetcher.ex
  48. 20
      apps/indexer/lib/indexer/fetcher/block_reward.ex
  49. 7
      apps/indexer/lib/indexer/fetcher/coin_balance.ex
  50. 15
      apps/indexer/lib/indexer/fetcher/coin_balance_on_demand.ex
  51. 14
      apps/indexer/lib/indexer/fetcher/contract_code.ex
  52. 12
      apps/indexer/lib/indexer/fetcher/internal_transaction.ex
  53. 24
      apps/indexer/lib/indexer/fetcher/pending_transaction.ex
  54. 9
      apps/indexer/lib/indexer/fetcher/replaced_transaction.ex
  55. 7
      apps/indexer/lib/indexer/fetcher/token.ex
  56. 7
      apps/indexer/lib/indexer/fetcher/token_balance.ex
  57. 7
      apps/indexer/lib/indexer/fetcher/token_updater.ex
  58. 23
      apps/indexer/lib/indexer/fetcher/uncle_block.ex
  59. 39
      apps/indexer/lib/indexer/internal_transaction/supervisor.ex
  60. 39
      apps/indexer/lib/indexer/pending_transaction/supervisor.ex
  61. 47
      apps/indexer/lib/indexer/replaced_transaction/supervisor.ex
  62. 97
      apps/indexer/lib/indexer/shrinkable/supervisor.ex
  63. 137
      apps/indexer/lib/indexer/supervisor.ex
  64. 1
      apps/indexer/lib/indexer/temporary/addresses_without_code.ex
  65. 38
      apps/indexer/lib/indexer/temporary/addresses_without_code/supervisor.ex
  66. 4
      apps/indexer/lib/indexer/temporary/failed_created_addresses.ex
  67. 38
      apps/indexer/lib/indexer/temporary/failed_created_addresses/supervisor.ex
  68. 7
      apps/indexer/lib/indexer/temporary/uncataloged_token_transfers.ex
  69. 41
      apps/indexer/lib/indexer/token/supervisor.ex
  70. 38
      apps/indexer/lib/indexer/token_balance/supervisor.ex
  71. 7
      apps/indexer/lib/indexer/token_balances.ex
  72. 44
      apps/indexer/lib/indexer/token_transfer/uncataloged/supervisor.ex
  73. 9
      apps/indexer/lib/indexer/token_transfers.ex
  74. 2
      apps/indexer/lib/indexer/transform/address_coin_balances.ex
  75. 2
      apps/indexer/lib/indexer/transform/address_token_balances.ex
  76. 17
      apps/indexer/lib/indexer/transform/addresses.ex
  77. 20
      apps/indexer/lib/indexer/transform/blocks.ex
  78. 8
      apps/indexer/lib/indexer/transform/blocks/base.ex
  79. 10
      apps/indexer/lib/indexer/transform/blocks/clique.ex
  80. 4
      apps/indexer/lib/indexer/transform/mint_transfers.ex
  81. 2
      apps/indexer/lib/indexer/transform/token_transfers.ex
  82. 24
      apps/indexer/test/indexer/block/catchup/bound_interval_supervisor_test.exs
  83. 9
      apps/indexer/test/indexer/block/catchup/fetcher_test.exs
  84. 4
      apps/indexer/test/indexer/block/catchup/sequence_test.exs
  85. 30
      apps/indexer/test/indexer/block/fetcher_test.exs
  86. 66
      apps/indexer/test/indexer/block/realtime/fetcher_test.exs
  87. 40
      apps/indexer/test/indexer/block/util_test.exs
  88. 48
      apps/indexer/test/indexer/fetcher/block_reward_test.exs
  89. 32
      apps/indexer/test/indexer/fetcher/coin_balance_on_demand_test.exs
  90. 14
      apps/indexer/test/indexer/fetcher/coin_balance_test.exs
  91. 8
      apps/indexer/test/indexer/fetcher/contract_code_test.exs
  92. 31
      apps/indexer/test/indexer/fetcher/internal_transaction_test.exs
  93. 4
      apps/indexer/test/indexer/fetcher/pending_transaction_test.exs
  94. 8
      apps/indexer/test/indexer/fetcher/replaced_transaction_test.exs
  95. 18
      apps/indexer/test/indexer/fetcher/token_balance_test.exs
  96. 8
      apps/indexer/test/indexer/fetcher/token_test.exs
  97. 8
      apps/indexer/test/indexer/fetcher/token_updater_test.exs
  98. 9
      apps/indexer/test/indexer/fetcher/uncle_block_test.exs
  99. 7
      apps/indexer/test/indexer/temporary/addresses_without_code_test.exs
  100. 2
      apps/indexer/test/indexer/temporary/failed_created_addresses_test.exs
  101. Some files were not shown because too many files have changed in this diff Show More

@ -189,7 +189,7 @@ jobs:
- restore_cache: - restore_cache:
keys: keys:
- v7-mix-dailyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.lock" }} - v7-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.lock" }}
- v7-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.exs" }} - v7-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.exs" }}
- v7-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }} - v7-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}

@ -1,11 +1,32 @@
## Current ## Current
### Features
- [#1739](https://github.com/poanetwork/blockscout/pull/1739) - highlight decompiled source code
### Fixes
- [#1724](https://github.com/poanetwork/blockscout/pull/1724) - Remove internal tx and token balance fetching from realtime fetcher
- [#1727](https://github.com/poanetwork/blockscout/pull/1727) - add logs pagination in rpc api
- [#1740](https://github.com/poanetwork/blockscout/pull/1740) - fix empty block time
- [#1743](https://github.com/poanetwork/blockscout/pull/1743) - sort decompiled smart contracts in lexicographical order
### Chore
- [#1749](https://github.com/poanetwork/blockscout/pull/1749) - Replace the link in the footer with the official POA announcements tg channel link
- [#1718](https://github.com/poanetwork/blockscout/pull/1718) - Flatten indexer module hierarchy and supervisor tree
- [#1753](https://github.com/poanetwork/blockscout/pull/1753) - Add a check mark to decompiled contract tab
## 1.3.9-beta
### Features ### Features
- [#1662](https://github.com/poanetwork/blockscout/pull/1662) - allow specifying number of optimization runs - [#1662](https://github.com/poanetwork/blockscout/pull/1662) - allow specifying number of optimization runs
- [#1654](https://github.com/poanetwork/blockscout/pull/1654) - add decompiled code tab - [#1654](https://github.com/poanetwork/blockscout/pull/1654) - add decompiled code tab
- [#1661](https://github.com/poanetwork/blockscout/pull/1661) - try to compile smart contract with the latest evm version - [#1661](https://github.com/poanetwork/blockscout/pull/1661) - try to compile smart contract with the latest evm version
- [#1665](https://github.com/poanetwork/blockscout/pull/1665) - Add contract verification RPC endpoint. - [#1665](https://github.com/poanetwork/blockscout/pull/1665) - Add contract verification RPC endpoint.
- [#1706](https://github.com/poanetwork/blockscout/pull/1706) - allow setting update interval for addresses with b
### Fixes ### Fixes
@ -14,9 +35,16 @@
- [#1688](https://github.com/poanetwork/blockscout/pull/1688) - do not fail if failure reason is atom - [#1688](https://github.com/poanetwork/blockscout/pull/1688) - do not fail if failure reason is atom
- [#1692](https://github.com/poanetwork/blockscout/pull/1692) - exclude decompiled smart contract from encoding - [#1692](https://github.com/poanetwork/blockscout/pull/1692) - exclude decompiled smart contract from encoding
- [#1684](https://github.com/poanetwork/blockscout/pull/1684) - Discard child block with parent_hash not matching hash of imported block - [#1684](https://github.com/poanetwork/blockscout/pull/1684) - Discard child block with parent_hash not matching hash of imported block
- [#1699](https://github.com/poanetwork/blockscout/pull/1699) - use seconds as transaction cache period measure
- [#1697](https://github.com/poanetwork/blockscout/pull/1697) - fix failing in rpc if balance is empty
- [#1711](https://github.com/poanetwork/blockscout/pull/1711) - rescue failing repo in block number cache update
- [#1712](https://github.com/poanetwork/blockscout/pull/1712) - do not set contract code from transaction input
- [#1714](https://github.com/poanetwork/blockscout/pull/1714) - fix average block time calculation
### Chore ### Chore
- [#1693](https://github.com/poanetwork/blockscout/pull/1693) - Add a checklist to the PR template
## 1.3.8-beta ## 1.3.8-beta

@ -18,3 +18,20 @@
## Upgrading ## Upgrading
*If you have any Incompatible Changes in the above Changelog, outline how users of prior versions can upgrade once this PR lands or when reviewers are testing locally. A common upgrading step is "Database reset and re-index required".* *If you have any Incompatible Changes in the above Changelog, outline how users of prior versions can upgrade once this PR lands or when reviewers are testing locally. A common upgrading step is "Database reset and re-index required".*
## Checklist for your PR
<!--
Ideally a PR has all of the checkmarks set.
If something in this list is irrelevant to your PR, you should still set this
checkmark indicating that you are sure it is dealt with (be that by irrelevance).
If you don't set a checkmark (e. g. don't add a test for new functionality),
you must be able to justify that.
-->
- [ ] I added an entry to `CHANGELOG.md` with this PR
- [ ] If I added new functionality, I added tests covering it.
- [ ] If I fixed a bug, I added a regression test to prevent the bug from silently reappearing again.
- [ ] I checked whether I should update the docs and did so if necessary

@ -6,6 +6,22 @@ pre {
white-space: pre-wrap; white-space: pre-wrap;
} }
.pre-decompiled code {
white-space: pre-wrap;
counter-increment: line;
}
.pre-decompiled code::before {
content: counter(line);
display: inline-block;
width: 2.5em; /* Fixed width */
border-right: 1px solid #ddd;
padding: 0 .5em;
margin-right: .5em;
color: #888;
-webkit-user-select: none;
}
.pre-scrollable-shorty { .pre-scrollable-shorty {
max-height: $pre-scrollable-max-height / 7; max-height: $pre-scrollable-max-height / 7;
} }

@ -93,7 +93,7 @@ config :block_scout_web, BlockScoutWeb.Gettext, locales: ~w(en), default_locale:
config :block_scout_web, BlockScoutWeb.SocialMedia, config :block_scout_web, BlockScoutWeb.SocialMedia,
twitter: "PoaNetwork", twitter: "PoaNetwork",
telegram: "oraclesnetwork", telegram: "poa_network",
facebook: "PoaNetwork", facebook: "PoaNetwork",
instagram: "PoaNetwork" instagram: "PoaNetwork"

@ -115,7 +115,7 @@ defmodule BlockScoutWeb.Chain do
end end
end end
def paging_options(%{"index" => index_string}) do def paging_options(%{"index" => index_string}) when is_binary(index_string) do
with {index, ""} <- Integer.parse(index_string) do with {index, ""} <- Integer.parse(index_string) do
[paging_options: %{@default_paging_options | key: {index}}] [paging_options: %{@default_paging_options | key: {index}}]
else else
@ -124,6 +124,10 @@ defmodule BlockScoutWeb.Chain do
end end
end end
def paging_options(%{"index" => index}) when is_integer(index) do
[paging_options: %{@default_paging_options | key: {index}}]
end
def paging_options(%{"inserted_at" => inserted_at_string, "hash" => hash_string}) do def paging_options(%{"inserted_at" => inserted_at_string, "hash" => hash_string}) do
with {:ok, inserted_at, _} <- DateTime.from_iso8601(inserted_at_string), with {:ok, inserted_at, _} <- DateTime.from_iso8601(inserted_at_string),
{:ok, hash} <- string_to_transaction_hash(hash_string) do {:ok, hash} <- string_to_transaction_hash(hash_string) do

@ -11,7 +11,7 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do
alias BlockScoutWeb.AddressCoinBalanceView alias BlockScoutWeb.AddressCoinBalanceView
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Indexer.CoinBalance.OnDemandFetcher alias Indexer.Fetcher.CoinBalanceOnDemand
alias Phoenix.View alias Phoenix.View
def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do
@ -62,7 +62,7 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do
{:ok, address} <- Chain.hash_to_address(address_hash) do {:ok, address} <- Chain.hash_to_address(address_hash) do
render(conn, "index.html", render(conn, "index.html",
address: address, address: address,
coin_balance_status: OnDemandFetcher.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address), transaction_count: transaction_count(address),
validation_count: validation_count(address), validation_count: validation_count(address),

@ -5,7 +5,7 @@ defmodule BlockScoutWeb.AddressContractController do
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Indexer.CoinBalance.OnDemandFetcher alias Indexer.Fetcher.CoinBalanceOnDemand
def index(conn, %{"address_id" => address_hash_string}) do def index(conn, %{"address_id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
@ -14,7 +14,7 @@ defmodule BlockScoutWeb.AddressContractController do
conn, conn,
"index.html", "index.html",
address: address, address: address,
coin_balance_status: OnDemandFetcher.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address), transaction_count: transaction_count(address),
validation_count: validation_count(address) validation_count: validation_count(address)

@ -5,7 +5,7 @@ defmodule BlockScoutWeb.AddressDecompiledContractController do
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Indexer.CoinBalance.OnDemandFetcher alias Indexer.Fetcher.CoinBalanceOnDemand
def index(conn, %{"address_id" => address_hash_string}) do def index(conn, %{"address_id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
@ -14,7 +14,7 @@ defmodule BlockScoutWeb.AddressDecompiledContractController do
conn, conn,
"index.html", "index.html",
address: address, address: address,
coin_balance_status: OnDemandFetcher.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address), transaction_count: transaction_count(address),
validation_count: validation_count(address) validation_count: validation_count(address)

@ -11,7 +11,7 @@ defmodule BlockScoutWeb.AddressInternalTransactionController do
alias BlockScoutWeb.InternalTransactionView alias BlockScoutWeb.InternalTransactionView
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Indexer.CoinBalance.OnDemandFetcher alias Indexer.Fetcher.CoinBalanceOnDemand
alias Phoenix.View alias Phoenix.View
def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do
@ -67,7 +67,7 @@ defmodule BlockScoutWeb.AddressInternalTransactionController do
conn, conn,
"index.html", "index.html",
address: address, address: address,
coin_balance_status: OnDemandFetcher.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
current_path: current_path(conn), current_path: current_path(conn),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
filter: params["filter"], filter: params["filter"],

@ -10,7 +10,7 @@ defmodule BlockScoutWeb.AddressReadContractController do
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Indexer.CoinBalance.OnDemandFetcher alias Indexer.Fetcher.CoinBalanceOnDemand
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1]
@ -21,7 +21,7 @@ defmodule BlockScoutWeb.AddressReadContractController do
conn, conn,
"index.html", "index.html",
address: address, address: address,
coin_balance_status: OnDemandFetcher.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address), transaction_count: transaction_count(address),
validation_count: validation_count(address) validation_count: validation_count(address)

@ -3,7 +3,7 @@ defmodule BlockScoutWeb.AddressTokenController do
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Indexer.CoinBalance.OnDemandFetcher alias Indexer.Fetcher.CoinBalanceOnDemand
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1]
import BlockScoutWeb.Chain, only: [next_page_params: 3, paging_options: 1, split_list_by_page: 1] import BlockScoutWeb.Chain, only: [next_page_params: 3, paging_options: 1, split_list_by_page: 1]
@ -18,7 +18,7 @@ defmodule BlockScoutWeb.AddressTokenController do
conn, conn,
"index.html", "index.html",
address: address, address: address,
coin_balance_status: OnDemandFetcher.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address), transaction_count: transaction_count(address),
validation_count: validation_count(address), validation_count: validation_count(address),

@ -4,7 +4,7 @@ defmodule BlockScoutWeb.AddressTokenTransferController do
alias BlockScoutWeb.TransactionView alias BlockScoutWeb.TransactionView
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Indexer.CoinBalance.OnDemandFetcher alias Indexer.Fetcher.CoinBalanceOnDemand
alias Phoenix.View alias Phoenix.View
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1]
@ -81,7 +81,7 @@ defmodule BlockScoutWeb.AddressTokenTransferController do
conn, conn,
"index.html", "index.html",
address: address, address: address,
coin_balance_status: OnDemandFetcher.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
current_path: current_path(conn), current_path: current_path(conn),
token: token, token: token,

@ -11,7 +11,7 @@ defmodule BlockScoutWeb.AddressTransactionController do
alias BlockScoutWeb.TransactionView alias BlockScoutWeb.TransactionView
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Indexer.CoinBalance.OnDemandFetcher alias Indexer.Fetcher.CoinBalanceOnDemand
alias Phoenix.View alias Phoenix.View
@transaction_necessity_by_association [ @transaction_necessity_by_association [
@ -91,7 +91,7 @@ defmodule BlockScoutWeb.AddressTransactionController do
conn, conn,
"index.html", "index.html",
address: address, address: address,
coin_balance_status: OnDemandFetcher.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
filter: params["filter"], filter: params["filter"],
transaction_count: transaction_count(address), transaction_count: transaction_count(address),

@ -12,7 +12,7 @@ defmodule BlockScoutWeb.AddressValidationController do
alias BlockScoutWeb.BlockView alias BlockScoutWeb.BlockView
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Indexer.CoinBalance.OnDemandFetcher alias Indexer.Fetcher.CoinBalanceOnDemand
alias Phoenix.View alias Phoenix.View
def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do
@ -76,7 +76,7 @@ defmodule BlockScoutWeb.AddressValidationController do
conn, conn,
"index.html", "index.html",
address: address, address: address,
coin_balance_status: OnDemandFetcher.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
current_path: current_path(conn), current_path: current_path(conn),
transaction_count: transaction_count(address), transaction_count: transaction_count(address),
validation_count: validation_count(address), validation_count: validation_count(address),

@ -1,14 +1,24 @@
defmodule BlockScoutWeb.API.RPC.TransactionController do defmodule BlockScoutWeb.API.RPC.TransactionController do
use BlockScoutWeb, :controller use BlockScoutWeb, :controller
import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1]
alias Explorer.Chain alias Explorer.Chain
def gettxinfo(conn, params) do def gettxinfo(conn, params) do
with {:txhash_param, {:ok, txhash_param}} <- fetch_txhash(params), with {:txhash_param, {:ok, txhash_param}} <- fetch_txhash(params),
{:format, {:ok, transaction_hash}} <- to_transaction_hash(txhash_param), {:format, {:ok, transaction_hash}} <- to_transaction_hash(txhash_param),
{:transaction, {:ok, transaction}} <- transaction_from_hash(transaction_hash) do {:transaction, {:ok, transaction}} <- transaction_from_hash(transaction_hash),
logs = Chain.transaction_to_logs(transaction) paging_options <- paging_options(params) do
render(conn, :gettxinfo, %{transaction: transaction, block_height: Chain.block_height(), logs: logs}) logs = Chain.transaction_to_logs(transaction, paging_options)
{logs, next_page} = split_list_by_page(logs)
render(conn, :gettxinfo, %{
transaction: transaction,
block_height: Chain.block_height(),
logs: logs,
next_page_params: next_page_params(next_page, logs, params)
})
else else
{:transaction, :error} -> {:transaction, :error} ->
render(conn, :error, error: "Transaction not found") render(conn, :error, error: "Transaction not found")

@ -1995,7 +1995,13 @@ defmodule BlockScoutWeb.Etherscan do
description: "Transaction hash. Hash of contents of the transaction." description: "Transaction hash. Hash of contents of the transaction."
} }
], ],
optional_params: [], optional_params: [
%{
key: "index",
type: "integer",
description: "A nonnegative integer that represents the log index to be used for pagination."
}
],
responses: [ responses: [
%{ %{
code: "200", code: "200",

@ -116,7 +116,7 @@ defmodule BlockScoutWeb.Notifier do
defp broadcast_block(block) do defp broadcast_block(block) do
preloaded_block = Repo.preload(block, [[miner: :names], :transactions, :rewards]) preloaded_block = Repo.preload(block, [[miner: :names], :transactions, :rewards])
average_block_time = AverageBlockTime.average_block_time(preloaded_block) average_block_time = AverageBlockTime.average_block_time()
Endpoint.broadcast("blocks:new_block", "new_block", %{ Endpoint.broadcast("blocks:new_block", "new_block", %{
block: preloaded_block, block: preloaded_block,

@ -65,6 +65,7 @@
to: address_decompiled_contract_path(@conn, :index, @address.hash), to: address_decompiled_contract_path(@conn, :index, @address.hash),
class: "nav-link #{tab_status("decompiled_contracts", @conn.request_path)}") do %> class: "nav-link #{tab_status("decompiled_contracts", @conn.request_path)}") do %>
<%= gettext("Decompiled code") %> <%= gettext("Decompiled code") %>
<i class="far fa-check-circle text-success"></i>
<% end %> <% end %>
</li> </li>
<% end %> <% end %>
@ -131,6 +132,7 @@
to: address_decompiled_contract_path(@conn, :index, @address.hash), to: address_decompiled_contract_path(@conn, :index, @address.hash),
class: "dropdown-item #{tab_status("contracts", @conn.request_path)}") do %> class: "dropdown-item #{tab_status("contracts", @conn.request_path)}") do %>
<%= gettext("Decompiled code") %> <%= gettext("Decompiled code") %>
<i class="far fa-check-circle text-success"></i>
<% end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>

@ -6,11 +6,11 @@
<%= render BlockScoutWeb.AddressView, "_tabs.html", assigns %> <%= render BlockScoutWeb.AddressView, "_tabs.html", assigns %>
</div> </div>
<%= for {contract, _i} <- Enum.with_index(@address.decompiled_smart_contracts) do %> <%= for contract <- sort_contracts_by_version(@address.decompiled_smart_contracts) do %>
<div class="card-body"> <div class="card-body">
<h3><%= gettext "Decompiler version" %></h3> <h3><%= gettext "Decompiler version" %></h3>
<div class="tile tile-muted"> <div class="tile tile-muted">
<pre class="pre-wrap pre-scrollable"><code class="nohighlight"><%= contract.decompiler_version %></code></pre> <pre class="pre-wrap"><code class="nohighlight"><%= contract.decompiler_version %></code></pre>
</div> </div>
<br> <br>
<section> <section>
@ -21,7 +21,7 @@
</button> </button>
</div> </div>
<div class="tile tile-muted"> <div class="tile tile-muted">
<pre class="pre-wrap pre-scrollable"><code class="nohighlight"><%= contract.decompiled_source_code %></code></pre> <pre class="pre-decompiled pre-scrollable"><%= raw(highlight_decompiled_code(contract.decompiled_source_code)) %></pre>
</div> </div>
</section> </section>
</div> </div>

@ -17,7 +17,7 @@
<a href="https://www.twitter.com/PoaNetwork/" rel="noreferrer" target="_blank" class="icon-link" data-toggle="tooltip" data-placement="top" title="<%= gettext("Twitter") %>"> <a href="https://www.twitter.com/PoaNetwork/" rel="noreferrer" target="_blank" class="icon-link" data-toggle="tooltip" data-placement="top" title="<%= gettext("Twitter") %>">
<i class="fab fa-twitter"></i> <i class="fab fa-twitter"></i>
</a> </a>
<a href="http://t.me/oraclesnetwork" rel="noreferrer" target="_blank" class="icon-link" data-toggle="tooltip" data-placement="top" title="<%= gettext("Telegram") %>"> <a href="https://t.me/poa_network" rel="noreferrer" target="_blank" class="icon-link" data-toggle="tooltip" data-placement="top" title="<%= gettext("Telegram") %>">
<i class="fab fa-telegram-plane"></i> <i class="fab fa-telegram-plane"></i>
</a> </a>
</div> </div>

@ -1,3 +1,44 @@
defmodule BlockScoutWeb.AddressDecompiledContractView do defmodule BlockScoutWeb.AddressDecompiledContractView do
use BlockScoutWeb, :view use BlockScoutWeb, :view
@colors %{
"\e[95m" => "136, 0, 0",
# red
"\e[91m" => "236, 89, 58",
# gray
"\e[38;5;8m" => "111, 110, 111",
# green
"\e[32m" => "57, 115, 0",
# yellowgreen
"\e[93m" => "57, 115, 0",
# yellow
"\e[92m" => "119, 232, 81",
# red
"\e[94m" => "136, 0, 0"
}
def highlight_decompiled_code(code) do
@colors
|> Enum.reduce(code, fn {symbol, rgb}, acc ->
String.replace(acc, symbol, "<span style=\"color:rgb(#{rgb})\">")
end)
|> String.replace("\e[1m", "<span style=\"font-weight:bold\">")
|> String.replace("»", "&raquo;")
|> String.replace("\e[0m", "</span>")
|> add_line_numbers()
end
def sort_contracts_by_version(decompiled_contracts) do
decompiled_contracts
|> Enum.sort_by(& &1.decompiler_version)
|> Enum.reverse()
end
defp add_line_numbers(code) do
code
|> String.split("\n")
|> Enum.reduce("", fn line, acc ->
acc <> "<code>#{line}</code>\n"
end)
end
end end

@ -9,7 +9,7 @@ defmodule BlockScoutWeb.API.RPC.AddressView do
end end
def render("balance.json", %{addresses: [address]}) do def render("balance.json", %{addresses: [address]}) do
RPCView.render("show.json", data: "#{address.fetched_coin_balance.value}") RPCView.render("show.json", data: balance(address))
end end
def render("balance.json", assigns) do def render("balance.json", assigns) do
@ -21,7 +21,7 @@ defmodule BlockScoutWeb.API.RPC.AddressView do
Enum.map(addresses, fn address -> Enum.map(addresses, fn address ->
%{ %{
"account" => "#{address.hash}", "account" => "#{address.hash}",
"balance" => "#{address.fetched_coin_balance.value}" "balance" => balance(address)
} }
end) end)
@ -157,4 +157,8 @@ defmodule BlockScoutWeb.API.RPC.AddressView do
"symbol" => token.symbol "symbol" => token.symbol
} }
end end
defp balance(address) do
address.fetched_coin_balance && address.fetched_coin_balance.value && "#{address.fetched_coin_balance.value}"
end
end end

@ -3,8 +3,13 @@ defmodule BlockScoutWeb.API.RPC.TransactionView do
alias BlockScoutWeb.API.RPC.RPCView alias BlockScoutWeb.API.RPC.RPCView
def render("gettxinfo.json", %{transaction: transaction, block_height: block_height, logs: logs}) do def render("gettxinfo.json", %{
data = prepare_transaction(transaction, block_height, logs) transaction: transaction,
block_height: block_height,
logs: logs,
next_page_params: next_page_params
}) do
data = prepare_transaction(transaction, block_height, logs, next_page_params)
RPCView.render("show.json", data: data) RPCView.render("show.json", data: data)
end end
@ -50,7 +55,7 @@ defmodule BlockScoutWeb.API.RPC.TransactionView do
} }
end end
defp prepare_transaction(transaction, block_height, logs) do defp prepare_transaction(transaction, block_height, logs, next_page_params) do
%{ %{
"hash" => "#{transaction.hash}", "hash" => "#{transaction.hash}",
"timeStamp" => "#{DateTime.to_unix(transaction.block.timestamp)}", "timeStamp" => "#{DateTime.to_unix(transaction.block.timestamp)}",
@ -63,7 +68,8 @@ defmodule BlockScoutWeb.API.RPC.TransactionView do
"input" => "#{transaction.input}", "input" => "#{transaction.input}",
"gasLimit" => "#{transaction.gas}", "gasLimit" => "#{transaction.gas}",
"gasUsed" => "#{transaction.gas_used}", "gasUsed" => "#{transaction.gas_used}",
"logs" => Enum.map(logs, &prepare_log/1) "logs" => Enum.map(logs, &prepare_log/1),
"next_page_params" => next_page_params
} }
end end

@ -188,7 +188,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:40 #: lib/block_scout_web/templates/address/_tabs.html.eex:40
#: lib/block_scout_web/templates/address/_tabs.html.eex:113 #: lib/block_scout_web/templates/address/_tabs.html.eex:114
#: lib/block_scout_web/templates/address/overview.html.eex:59 #: lib/block_scout_web/templates/address/overview.html.eex:59
#: lib/block_scout_web/templates/address_validation/index.html.eex:30 #: lib/block_scout_web/templates/address_validation/index.html.eex:30
#: lib/block_scout_web/templates/address_validation/index.html.eex:57 #: lib/block_scout_web/templates/address_validation/index.html.eex:57
@ -218,7 +218,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:53 #: lib/block_scout_web/templates/address/_tabs.html.eex:53
#: lib/block_scout_web/templates/address/_tabs.html.eex:123 #: lib/block_scout_web/templates/address/_tabs.html.eex:124
#: lib/block_scout_web/templates/address_validation/index.html.eex:39 #: lib/block_scout_web/templates/address_validation/index.html.eex:39
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:119 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:119
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:141 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:141
@ -488,7 +488,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:21 #: lib/block_scout_web/templates/address/_tabs.html.eex:21
#: lib/block_scout_web/templates/address/_tabs.html.eex:100 #: lib/block_scout_web/templates/address/_tabs.html.eex:101
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:58 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:58
#: lib/block_scout_web/templates/address_validation/index.html.eex:24 #: lib/block_scout_web/templates/address_validation/index.html.eex:24
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:14 #: lib/block_scout_web/templates/transaction/_tabs.html.eex:14
@ -698,8 +698,8 @@ msgid "Query"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:75 #: lib/block_scout_web/templates/address/_tabs.html.eex:76
#: lib/block_scout_web/templates/address/_tabs.html.eex:140 #: lib/block_scout_web/templates/address/_tabs.html.eex:142
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:33 #: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:33
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:75 #: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:75
#: lib/block_scout_web/views/address_view.ex:298 #: lib/block_scout_web/views/address_view.ex:298
@ -891,7 +891,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:13 #: lib/block_scout_web/templates/address/_tabs.html.eex:13
#: lib/block_scout_web/templates/address/_tabs.html.eex:95 #: lib/block_scout_web/templates/address/_tabs.html.eex:96
#: lib/block_scout_web/templates/address_token/index.html.eex:11 #: lib/block_scout_web/templates/address_token/index.html.eex:11
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:12 #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:12
#: lib/block_scout_web/templates/address_validation/index.html.eex:11 #: lib/block_scout_web/templates/address_validation/index.html.eex:11
@ -948,7 +948,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:5 #: lib/block_scout_web/templates/address/_tabs.html.eex:5
#: lib/block_scout_web/templates/address/_tabs.html.eex:90 #: lib/block_scout_web/templates/address/_tabs.html.eex:91
#: lib/block_scout_web/templates/address_transaction/index.html.eex:53 #: lib/block_scout_web/templates/address_transaction/index.html.eex:53
#: lib/block_scout_web/templates/address_validation/index.html.eex:14 #: lib/block_scout_web/templates/address_validation/index.html.eex:14
#: lib/block_scout_web/templates/block_transaction/index.html.eex:13 #: lib/block_scout_web/templates/block_transaction/index.html.eex:13
@ -1399,7 +1399,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:30 #: lib/block_scout_web/templates/address/_tabs.html.eex:30
#: lib/block_scout_web/templates/address/_tabs.html.eex:106 #: lib/block_scout_web/templates/address/_tabs.html.eex:107
#: lib/block_scout_web/views/address_view.ex:299 #: lib/block_scout_web/views/address_view.ex:299
msgid "Coin Balance History" msgid "Coin Balance History"
msgstr "" msgstr ""
@ -1714,7 +1714,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:67 #: lib/block_scout_web/templates/address/_tabs.html.eex:67
#: lib/block_scout_web/templates/address/_tabs.html.eex:133 #: lib/block_scout_web/templates/address/_tabs.html.eex:134
msgid "Decompiled code" msgid "Decompiled code"
msgstr "" msgstr ""

@ -188,7 +188,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:40 #: lib/block_scout_web/templates/address/_tabs.html.eex:40
#: lib/block_scout_web/templates/address/_tabs.html.eex:113 #: lib/block_scout_web/templates/address/_tabs.html.eex:114
#: lib/block_scout_web/templates/address/overview.html.eex:59 #: lib/block_scout_web/templates/address/overview.html.eex:59
#: lib/block_scout_web/templates/address_validation/index.html.eex:30 #: lib/block_scout_web/templates/address_validation/index.html.eex:30
#: lib/block_scout_web/templates/address_validation/index.html.eex:57 #: lib/block_scout_web/templates/address_validation/index.html.eex:57
@ -218,7 +218,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:53 #: lib/block_scout_web/templates/address/_tabs.html.eex:53
#: lib/block_scout_web/templates/address/_tabs.html.eex:123 #: lib/block_scout_web/templates/address/_tabs.html.eex:124
#: lib/block_scout_web/templates/address_validation/index.html.eex:39 #: lib/block_scout_web/templates/address_validation/index.html.eex:39
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:119 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:119
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:141 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:141
@ -488,7 +488,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:21 #: lib/block_scout_web/templates/address/_tabs.html.eex:21
#: lib/block_scout_web/templates/address/_tabs.html.eex:100 #: lib/block_scout_web/templates/address/_tabs.html.eex:101
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:58 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:58
#: lib/block_scout_web/templates/address_validation/index.html.eex:24 #: lib/block_scout_web/templates/address_validation/index.html.eex:24
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:14 #: lib/block_scout_web/templates/transaction/_tabs.html.eex:14
@ -698,8 +698,8 @@ msgid "Query"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:75 #: lib/block_scout_web/templates/address/_tabs.html.eex:76
#: lib/block_scout_web/templates/address/_tabs.html.eex:140 #: lib/block_scout_web/templates/address/_tabs.html.eex:142
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:33 #: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:33
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:75 #: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:75
#: lib/block_scout_web/views/address_view.ex:298 #: lib/block_scout_web/views/address_view.ex:298
@ -891,7 +891,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:13 #: lib/block_scout_web/templates/address/_tabs.html.eex:13
#: lib/block_scout_web/templates/address/_tabs.html.eex:95 #: lib/block_scout_web/templates/address/_tabs.html.eex:96
#: lib/block_scout_web/templates/address_token/index.html.eex:11 #: lib/block_scout_web/templates/address_token/index.html.eex:11
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:12 #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:12
#: lib/block_scout_web/templates/address_validation/index.html.eex:11 #: lib/block_scout_web/templates/address_validation/index.html.eex:11
@ -948,7 +948,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:5 #: lib/block_scout_web/templates/address/_tabs.html.eex:5
#: lib/block_scout_web/templates/address/_tabs.html.eex:90 #: lib/block_scout_web/templates/address/_tabs.html.eex:91
#: lib/block_scout_web/templates/address_transaction/index.html.eex:53 #: lib/block_scout_web/templates/address_transaction/index.html.eex:53
#: lib/block_scout_web/templates/address_validation/index.html.eex:14 #: lib/block_scout_web/templates/address_validation/index.html.eex:14
#: lib/block_scout_web/templates/block_transaction/index.html.eex:13 #: lib/block_scout_web/templates/block_transaction/index.html.eex:13
@ -1399,7 +1399,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:30 #: lib/block_scout_web/templates/address/_tabs.html.eex:30
#: lib/block_scout_web/templates/address/_tabs.html.eex:106 #: lib/block_scout_web/templates/address/_tabs.html.eex:107
#: lib/block_scout_web/views/address_view.ex:299 #: lib/block_scout_web/views/address_view.ex:299
msgid "Coin Balance History" msgid "Coin Balance History"
msgstr "" msgstr ""
@ -1714,7 +1714,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:67 #: lib/block_scout_web/templates/address/_tabs.html.eex:67
#: lib/block_scout_web/templates/address/_tabs.html.eex:133 #: lib/block_scout_web/templates/address/_tabs.html.eex:134
msgid "Decompiled code" msgid "Decompiled code"
msgstr "" msgstr ""
@ -1723,12 +1723,12 @@ msgstr ""
msgid "Decompiled contract code" msgid "Decompiled contract code"
msgstr "" msgstr ""
#, elixir-format, fuzzy #, elixir-format
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:11 #: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:11
msgid "Decompiler version" msgid "Decompiler version"
msgstr "" msgstr ""
#, elixir-format, fuzzy #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:52 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:52
msgid "Optimization runs" msgid "Optimization runs"
msgstr "" msgstr ""

@ -367,6 +367,59 @@ defmodule BlockScoutWeb.API.RPC.TransactionControllerTest do
refute response["result"] refute response["result"]
end end
test "paginates logs", %{conn: conn} do
block = insert(:block, hash: "0x30d522bcf2d8e0cabc286e6e40623c475c3bc05d0ec484ea239c103b1ac0ded9", number: 99)
transaction =
:transaction
|> insert(hash: "0x13b6bb8e06322096dc83e8d7e6332ca19919ea642212cd259c6b20e7523a0599")
|> with_block(block, status: :ok)
address = insert(:address)
Enum.each(1..100, fn _ ->
insert(:log,
address: address,
transaction: transaction,
first_topic: "first topic",
second_topic: "second topic"
)
end)
params1 = %{
"module" => "transaction",
"action" => "gettxinfo",
"txhash" => "#{transaction.hash}"
}
assert response1 =
conn
|> get("/api", params1)
|> json_response(200)
assert response1["status"] == "1"
assert response1["message"] == "OK"
assert %{
"action" => "gettxinfo",
"index" => _,
"module" => "transaction",
"txhash" => _
} = response1["result"]["next_page_params"]
params2 = response1["result"]["next_page_params"]
assert response2 =
conn
|> get("/api", params2)
|> json_response(200)
assert response2["status"] == "1"
assert response2["message"] == "OK"
assert is_nil(response2["result"]["next_page_params"])
assert response1["result"]["logs"] != response2["result"]["logs"]
end
test "with a txhash with ok status", %{conn: conn} do test "with a txhash with ok status", %{conn: conn} do
block = insert(:block) block = insert(:block)
@ -409,7 +462,8 @@ defmodule BlockScoutWeb.API.RPC.TransactionControllerTest do
"data" => "#{log.data}", "data" => "#{log.data}",
"topics" => ["first topic", "second topic", nil, nil] "topics" => ["first topic", "second topic", nil, nil]
} }
] ],
"next_page_params" => nil
} }
assert response = assert response =

@ -0,0 +1,74 @@
defmodule BlockScoutWeb.AddressDecompiledContractViewTest do
use Explorer.DataCase
alias BlockScoutWeb.AddressDecompiledContractView
describe "highlight_decompiled_code/1" do
test "generate correct html code" do
code = """
#
# eveem.org 6 Feb 2019
# Decompiled source of 0x00Bd9e214FAb74d6fC21bf1aF34261765f57e875
#
# Let's make the world open source
# 
#
# I failed with these:
# - unknowne77c646d(?)
# - transferFromWithData(address _from, address _to, uint256 _value, bytes _data)
# All the rest is below.
#
# Storage definitions and getters
def storage:
allowance is uint256 => uint256 # mask(256, 0) at storage #2
stor4 is uint256 => uint8 # mask(8, 0) at storage #4
def allowance(address _owner, address _spender) payable: 
require (calldata.size - 4) >= 64
return allowance[sha3(((320 - 1) and (320 - 1) and _owner), 1), ((320 - 1) and _spender and (320 - 1))]
#
# Regular functions - see Tutorial for understanding quirks of the code
#
# folder failed in this function - may be terribly long, sorry
def unknownc47d033b(?) payable: 
if (calldata.size - 4) < 32:
revert
else:
if not (320 - 1) or not cd[4]:
revert
else:
mem[0] = (320 - 1) and (320 - 1) and cd[4]
mem[32] = 4
mem[96] = bool(stor4[((320 - 1) and (320 - 1) and cd[4])])
return bool(stor4[((320 - 1) and (320 - 1) and cd[4])])
def _fallback() payable: # default function
revert
"""
result = AddressDecompiledContractView.highlight_decompiled_code(code)
assert result ==
"<code> <span style=\"color:rgb(111, 110, 111)\">#</code>\n<code> # eveem.org 6 Feb 2019</code>\n<code> # Decompiled source of </span>0x00Bd9e214FAb74d6fC21bf1aF34261765f57e875<span style=\"color:rgb(111, 110, 111)\"></code>\n<code> #</code>\n<code> # Let's make the world open source</code>\n<code> # </span></code>\n<code> <span style=\"color:rgb(111, 110, 111)\">#</code>\n<code> # I failed with these:</code>\n<code> </span><span style=\"color:rgb(111, 110, 111)\"># - </span><span style=\"color:rgb(236, 89, 58)\">unknowne77c646d(?)</span><span style=\"color:rgb(111, 110, 111)\"></code>\n<code> </span><span style=\"color:rgb(111, 110, 111)\"># - </span><span style=\"color:rgb(236, 89, 58)\">transferFromWithData(address _from, address _to, uint256 _value, bytes _data)</span><span style=\"color:rgb(111, 110, 111)\"></code>\n<code> # All the rest is below.</code>\n<code> #</span></code>\n<code></code>\n<code></code>\n<code> <span style=\"color:rgb(111, 110, 111)\"># Storage definitions and getters</span></code>\n<code></code>\n<code> <span style=\"color:rgb(57, 115, 0)\">def</span> storage:</code>\n<code> <span style=\"color:rgb(57, 115, 0)\">allowance</span> is uint256 => uint256 <span style=\"color:rgb(111, 110, 111)\"># mask(256, 0) at storage #2</span></code>\n<code> <span style=\"color:rgb(57, 115, 0)\">stor4</span> is uint256 => uint8 <span style=\"color:rgb(111, 110, 111)\"># mask(8, 0) at storage #4</span></code>\n<code></code>\n<code> <span style=\"color:rgb(136, 0, 0)\">def </span>allowance(address <span style=\"color:rgb(57, 115, 0)\">_owner</span>, address <span style=\"color:rgb(57, 115, 0)\">_spender</span>) <span style=\"color:rgb(136, 0, 0)\">payable</span>: <span style=\"color:rgb(111, 110, 111)\"></span></code>\n<code> require (calldata.size - 4)<span style=\"font-weight:bold\"> >= </span>64</code>\n<code> return <span style=\"color:rgb(57, 115, 0)\">allowance</span><span style=\"color:rgb(57, 115, 0)\">[</span>sha3(((320 - 1)<span style=\"font-weight:bold\"> and </span>(320 - 1)<span style=\"font-weight:bold\"> and </span><span style=\"color:rgb(57, 115, 0)\">_owner</span>), 1), ((320 - 1)<span style=\"font-weight:bold\"> and </span><span style=\"color:rgb(57, 115, 0)\">_spender</span><span style=\"font-weight:bold\"> and </span>(320 - 1))<span style=\"color:rgb(57, 115, 0)\">]</span></code>\n<code></code>\n<code></code>\n<code> <span style=\"color:rgb(111, 110, 111)\">#</code>\n<code> # Regular functions - see Tutorial for understanding quirks of the code</code>\n<code> #</span></code>\n<code></code>\n<code></code>\n<code> <span style=\"color:rgb(111, 110, 111)\"># folder failed in this function - may be terribly long, sorry</span></code>\n<code> <span style=\"color:rgb(136, 0, 0)\">def </span>unknownc47d033b(?) <span style=\"color:rgb(136, 0, 0)\">payable</span>: <span style=\"color:rgb(111, 110, 111)\"></span></code>\n<code> if (calldata.size - 4)<span style=\"font-weight:bold\"> < </span>32:</code>\n<code> revert</code>\n<code> else:</code>\n<code> if not (320 - 1)<span style=\"font-weight:bold\"> or </span>not cd[4]:</code>\n<code> revert</code>\n<code> else:</code>\n<code> <span style=\"color:rgb(136, 0, 0)\">mem[</span>0<span style=\"color:rgb(136, 0, 0)\">]</span> = (320 - 1)<span style=\"font-weight:bold\"> and </span>(320 - 1)<span style=\"font-weight:bold\"> and </span>cd[4]</code>\n<code> <span style=\"color:rgb(136, 0, 0)\">mem[</span>32<span style=\"color:rgb(136, 0, 0)\">]</span> = 4</code>\n<code> <span style=\"color:rgb(136, 0, 0)\">mem[</span>96<span style=\"color:rgb(136, 0, 0)\">]</span> = bool(<span style=\"color:rgb(57, 115, 0)\">stor4</span><span style=\"color:rgb(57, 115, 0)\">[</span>((320 - 1)<span style=\"font-weight:bold\"> and </span>(320 - 1)<span style=\"font-weight:bold\"> and </span>cd[4])<span style=\"color:rgb(57, 115, 0)\">]</span>)</code>\n<code> return bool(<span style=\"color:rgb(57, 115, 0)\">stor4</span><span style=\"color:rgb(57, 115, 0)\">[</span>((320 - 1)<span style=\"font-weight:bold\"> and </span>(320 - 1)<span style=\"font-weight:bold\"> and </span>cd[4])<span style=\"color:rgb(57, 115, 0)\">]</span>)</code>\n<code></code>\n<code> <span style=\"color:rgb(136, 0, 0)\">def </span>_fallback() <span style=\"color:rgb(136, 0, 0)\">payable</span>: <span style=\"color:rgb(111, 110, 111)\"># default function</span></code>\n<code> revert</code>\n<code></code>\n"
end
end
describe "sort_contracts_by_version/1" do
test "sorts contracts in lexicographical order" do
contract2 = insert(:decompiled_smart_contract, decompiler_version: "v2")
contract1 = insert(:decompiled_smart_contract, decompiler_version: "v1")
contract3 = insert(:decompiled_smart_contract, decompiler_version: "v3")
result = AddressDecompiledContractView.sort_contracts_by_version([contract2, contract1, contract3])
assert result == [contract3, contract2, contract1]
end
end
end

@ -13,7 +13,18 @@ config :explorer,
config :explorer, Explorer.Counters.AverageBlockTime, enabled: true config :explorer, Explorer.Counters.AverageBlockTime, enabled: true
config :explorer, Explorer.Counters.AddressesWithBalanceCounter, enabled: true, enable_consolidation: true balances_update_interval =
if System.get_env("ADDRESS_WITH_BALANCES_UPDATE_INTERVAL") do
case Integer.parse(System.get_env("ADDRESS_WITH_BALANCES_UPDATE_INTERVAL")) do
{integer, ""} -> integer
_ -> nil
end
end
config :explorer, Explorer.Counters.AddressesWithBalanceCounter,
enabled: true,
enable_consolidation: true,
update_interval_in_seconds: balances_update_interval || 30 * 60
config :explorer, Explorer.ExchangeRates, enabled: true, store: :ets config :explorer, Explorer.ExchangeRates, enabled: true, store: :ets

@ -61,7 +61,7 @@ defmodule Explorer.Chain.BlockNumberCache do
defp update_cache do defp update_cache do
current_time = current_time() current_time = current_time()
{min, max} = Chain.fetch_min_and_max_block_numbers() {min, max} = min_and_max_from_db()
tuple = {min, max, current_time} tuple = {min, max, current_time}
:ets.insert(@tab, {@key, tuple}) :ets.insert(@tab, {@key, tuple})
@ -85,6 +85,13 @@ defmodule Explorer.Chain.BlockNumberCache do
cache_period cache_period
end end
defp min_and_max_from_db do
Chain.fetch_min_and_max_block_numbers()
rescue
_e ->
{0, 0}
end
defp current_time do defp current_time do
utc_now = DateTime.utc_now() utc_now = DateTime.utc_now()

@ -143,7 +143,7 @@ defmodule Explorer.Chain.TransactionCountCache do
case System.get_env("TXS_COUNT_CACHE_PERIOD") do case System.get_env("TXS_COUNT_CACHE_PERIOD") do
value when is_binary(value) -> value when is_binary(value) ->
case Integer.parse(value) do case Integer.parse(value) do
{integer, ""} -> integer * 1_000 * 60 * 60 {integer, ""} -> integer * 1_000
_ -> nil _ -> nil
end end

@ -29,6 +29,8 @@ defmodule Explorer.Counters.AddressesWithBalanceCounter do
config = Application.get_env(:explorer, Explorer.Counters.AddressesWithBalanceCounter) config = Application.get_env(:explorer, Explorer.Counters.AddressesWithBalanceCounter)
@enable_consolidation Keyword.get(config, :enable_consolidation) @enable_consolidation Keyword.get(config, :enable_consolidation)
@update_interval_in_seconds Keyword.get(config, :update_interval_in_seconds)
@doc """ @doc """
Starts a process to periodically update the counter of the token holders. Starts a process to periodically update the counter of the token holders.
""" """
@ -62,7 +64,7 @@ defmodule Explorer.Counters.AddressesWithBalanceCounter do
defp schedule_next_consolidation do defp schedule_next_consolidation do
if enable_consolidation?() do if enable_consolidation?() do
Process.send_after(self(), :consolidate, :timer.minutes(30)) Process.send_after(self(), :consolidate, :timer.seconds(@update_interval_in_seconds))
end end
end end

@ -11,6 +11,8 @@ defmodule Explorer.Counters.AverageBlockTime do
alias Explorer.Repo alias Explorer.Repo
alias Timex.Duration alias Timex.Duration
@refresh_period 30 * 60 * 1_000
@doc """ @doc """
Starts a process to periodically update the counter of the token holders. Starts a process to periodically update the counter of the token holders.
""" """
@ -19,27 +21,51 @@ defmodule Explorer.Counters.AverageBlockTime do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__) GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end end
def average_block_time(block \\ nil) do def average_block_time do
enabled? = enabled? =
:explorer :explorer
|> Application.fetch_env!(__MODULE__) |> Application.fetch_env!(__MODULE__)
|> Keyword.fetch!(:enabled) |> Keyword.fetch!(:enabled)
if enabled? do if enabled? do
block = if block, do: {block.number, DateTime.to_unix(block.timestamp, :millisecond)} GenServer.call(__MODULE__, :average_block_time)
GenServer.call(__MODULE__, {:average_block_time, block})
else else
{:error, :disabled} {:error, :disabled}
end end
end end
def refresh do
GenServer.call(__MODULE__, :refresh_timestamps)
end
## Server ## Server
@impl true @impl true
def init(_) do def init(_) do
Process.send_after(self(), :refresh_timestamps, @refresh_period)
{:ok, refresh_timestamps()}
end
@impl true
def handle_call(:average_block_time, _from, %{average: average} = state), do: {:reply, average, state}
@impl true
def handle_call(:refresh_timestamps, _, _) do
{:reply, :ok, refresh_timestamps()}
end
@impl true
def handle_info(:refresh_timestamps, _) do
Process.send_after(self(), :refresh_timestamps, @refresh_period)
{:noreply, refresh_timestamps()}
end
defp refresh_timestamps do
timestamps_query = timestamps_query =
from(block in Block, from(block in Block,
limit: 100, limit: 100,
offset: 1, offset: 0,
order_by: [desc: block.number], order_by: [desc: block.number],
select: {block.number, block.timestamp} select: {block.number, block.timestamp}
) )
@ -51,30 +77,7 @@ defmodule Explorer.Counters.AverageBlockTime do
{number, DateTime.to_unix(timestamp, :millisecond)} {number, DateTime.to_unix(timestamp, :millisecond)}
end) end)
{:ok, %{timestamps: timestamps, average: average_distance(timestamps)}} %{timestamps: timestamps, average: average_distance(timestamps)}
end
@impl true
def handle_call({:average_block_time, nil}, _from, %{average: average} = state), do: {:reply, average, state}
def handle_call({:average_block_time, block}, _from, state) do
state = add_block(state, block)
{:reply, state.average, state}
end
# This is pretty naive, but we'll only ever be sorting 100 dates so I don't think
# complex logic is really necessary here.
defp add_block(%{timestamps: timestamps} = state, {new_number, _} = block) do
if Enum.any?(timestamps, fn {number, _} -> number == new_number end) do
state
else
timestamps =
[block | timestamps]
|> Enum.sort_by(fn {number, _} -> number end, &Kernel.>/2)
|> Enum.take(100)
%{state | timestamps: timestamps, average: average_distance(timestamps)}
end
end end
defp average_distance([]), do: Duration.from_milliseconds(0) defp average_distance([]), do: Duration.from_milliseconds(0)

@ -5,8 +5,6 @@ defmodule Explorer.Counters.AverageBlockTimeTest do
alias Explorer.Counters.AverageBlockTime alias Explorer.Counters.AverageBlockTime
defp block(number, last, duration), do: %{number: number, timestamp: Timex.shift(last, seconds: duration)}
setup do setup do
start_supervised!(AverageBlockTime) start_supervised!(AverageBlockTime)
Application.put_env(:explorer, AverageBlockTime, enabled: true) Application.put_env(:explorer, AverageBlockTime, enabled: true)
@ -26,41 +24,5 @@ defmodule Explorer.Counters.AverageBlockTimeTest do
test "without blocks duration is 0" do test "without blocks duration is 0" do
assert AverageBlockTime.average_block_time() == Timex.Duration.parse!("PT0S") assert AverageBlockTime.average_block_time() == Timex.Duration.parse!("PT0S")
end end
test "with only one block, the duration is 0" do
now = Timex.now()
block = block(0, now, 0)
assert AverageBlockTime.average_block_time(block) == Timex.Duration.parse!("PT0S")
end
test "once there are two blocks, the duration is the average distance between them all" do
now = Timex.now()
block0 = block(0, now, 0)
block1 = block(1, now, 2)
block2 = block(2, now, 6)
AverageBlockTime.average_block_time(block0)
assert AverageBlockTime.average_block_time(block1) == Timex.Duration.parse!("PT2S")
assert AverageBlockTime.average_block_time(block2) == Timex.Duration.parse!("PT3S")
end
test "only the last 100 blocks are considered" do
now = Timex.now()
block0 = block(0, now, 0)
block1 = block(1, now, 2000)
AverageBlockTime.average_block_time(block0)
AverageBlockTime.average_block_time(block1)
for i <- 1..100 do
block = block(i + 1, now, 2000 + i)
AverageBlockTime.average_block_time(block)
end
assert AverageBlockTime.average_block_time() == Timex.Duration.parse!("PT1S")
end
end end
end end

@ -5,8 +5,8 @@ use Mix.Config
import Bitwise import Bitwise
block_transformers = %{ block_transformers = %{
"clique" => Indexer.Block.Transform.Clique, "clique" => Indexer.Transform.Blocks.Clique,
"base" => Indexer.Block.Transform.Base "base" => Indexer.Transform.Blocks.Base
} }
# Compile time environment variable access requires recompilation. # Compile time environment variable access requires recompilation.
@ -36,8 +36,8 @@ config :indexer,
memory_limit: 1 <<< 30, memory_limit: 1 <<< 30,
first_block: System.get_env("FIRST_BLOCK") || 0 first_block: System.get_env("FIRST_BLOCK") || 0
# config :indexer, Indexer.ReplacedTransaction.Supervisor, disabled?: true # config :indexer, Indexer.Fetcher.ReplacedTransaction.Supervisor, disabled?: true
# config :indexer, Indexer.Block.Reward.Supervisor, disabled?: true # config :indexer, Indexer.Fetcher.BlockReward.Supervisor, disabled?: true
config :indexer, Indexer.Tracer, config :indexer, Indexer.Tracer,
service: :indexer, service: :indexer,

@ -5,10 +5,7 @@ defmodule Indexer.Application do
use Application use Application
alias Indexer.{ alias Indexer.Memory
Memory,
Shrinkable
}
@impl Application @impl Application
def start(_type, _args) do def start(_type, _args) do
@ -22,13 +19,13 @@ defmodule Indexer.Application do
children = [ children = [
{Memory.Monitor, [memory_monitor_options, [name: memory_monitor_name]]}, {Memory.Monitor, [memory_monitor_options, [name: memory_monitor_name]]},
{Shrinkable.Supervisor, [%{memory_monitor: memory_monitor_name}]} {Indexer.Supervisor, [%{memory_monitor: memory_monitor_name}]}
] ]
opts = [ opts = [
# If the `Memory.Monitor` dies, it needs all the `Shrinkable`s to re-register, so restart them. # If the `Memory.Monitor` dies, it needs all the `Shrinkable`s to re-register, so restart them.
strategy: :rest_for_one, strategy: :rest_for_one,
name: Indexer.Supervisor name: Indexer.Application
] ]
Supervisor.start_link(children, opts) Supervisor.start_link(children, opts)

@ -11,16 +11,19 @@ defmodule Indexer.Block.Catchup.Fetcher do
only: [ only: [
async_import_block_rewards: 1, async_import_block_rewards: 1,
async_import_coin_balances: 2, async_import_coin_balances: 2,
async_import_created_contract_codes: 1,
async_import_internal_transactions: 2,
async_import_replaced_transactions: 1,
async_import_tokens: 1, async_import_tokens: 1,
async_import_token_balances: 1,
async_import_uncles: 1, async_import_uncles: 1,
fetch_and_import_range: 2, fetch_and_import_range: 2
async_import_replaced_transactions: 1
] ]
alias Ecto.Changeset alias Ecto.Changeset
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.{Hash, Transaction} alias Indexer.{Block, Tracer}
alias Indexer.{Block, Code, InternalTransaction, Sequence, TokenBalance, Tracer} alias Indexer.Block.Catchup.Sequence
alias Indexer.Memory.Shrinkable alias Indexer.Memory.Shrinkable
@behaviour Block.Fetcher @behaviour Block.Fetcher
@ -31,7 +34,6 @@ defmodule Indexer.Block.Catchup.Fetcher do
@blocks_batch_size 10 @blocks_batch_size 10
@blocks_concurrency 10 @blocks_concurrency 10
@sequence_name :block_catchup_sequencer @sequence_name :block_catchup_sequencer
@geth_block_limit 128
defstruct blocks_batch_size: @blocks_batch_size, defstruct blocks_batch_size: @blocks_batch_size,
blocks_concurrency: @blocks_concurrency, blocks_concurrency: @blocks_concurrency,
@ -157,60 +159,6 @@ defmodule Indexer.Block.Catchup.Fetcher do
async_import_replaced_transactions(imported) async_import_replaced_transactions(imported)
end end
defp async_import_created_contract_codes(%{transactions: transactions}) do
transactions
|> Enum.flat_map(fn
%Transaction{
block_number: block_number,
hash: hash,
created_contract_address_hash: %Hash{} = created_contract_address_hash,
created_contract_code_indexed_at: nil,
internal_transactions_indexed_at: nil
} ->
[%{block_number: block_number, hash: hash, created_contract_address_hash: created_contract_address_hash}]
%Transaction{internal_transactions_indexed_at: %DateTime{}} ->
[]
%Transaction{created_contract_address_hash: nil} ->
[]
end)
|> Code.Fetcher.async_fetch(10_000)
end
defp async_import_created_contract_codes(_), do: :ok
defp async_import_internal_transactions(%{blocks: blocks}, EthereumJSONRPC.Parity) do
blocks
|> Enum.map(fn %Chain.Block{number: block_number} -> %{number: block_number} end)
|> InternalTransaction.Fetcher.async_block_fetch(10_000)
end
defp async_import_internal_transactions(%{transactions: transactions}, EthereumJSONRPC.Geth) do
{_, max_block_number} = Chain.fetch_min_and_max_block_numbers()
transactions
|> Enum.flat_map(fn
%Transaction{block_number: block_number, index: index, hash: hash, internal_transactions_indexed_at: nil} ->
[%{block_number: block_number, index: index, hash: hash}]
%Transaction{internal_transactions_indexed_at: %DateTime{}} ->
[]
end)
|> Enum.filter(fn %{block_number: block_number} ->
max_block_number - block_number < @geth_block_limit
end)
|> InternalTransaction.Fetcher.async_fetch(10_000)
end
defp async_import_internal_transactions(_, _), do: :ok
defp async_import_token_balances(%{address_token_balances: token_balances}) do
TokenBalance.Fetcher.async_fetch(token_balances)
end
defp async_import_token_balances(_), do: :ok
defp stream_fetch_and_import(%__MODULE__{blocks_concurrency: blocks_concurrency} = state, sequence) defp stream_fetch_and_import(%__MODULE__{blocks_concurrency: blocks_concurrency} = state, sequence)
when is_pid(sequence) do when is_pid(sequence) do
sequence sequence

@ -1,4 +1,4 @@
defmodule Indexer.Sequence do defmodule Indexer.Block.Catchup.Sequence do
@moduledoc false @moduledoc false
use GenServer use GenServer
@ -71,11 +71,11 @@ defmodule Indexer.Sequence do
Infinite sequence Infinite sequence
Indexer.Sequence.start_link(first: 100, step: 10) Indexer.Block.Catchup.Sequence.start_link(first: 100, step: 10)
Finite sequence Finite sequence
Indexer.Sequence.start_link(ranges: [100..0]) Indexer.Block.Catchup.Sequence.start_link(ranges: [100..0])
""" """
@spec start_link(options(), Keyword.t()) :: GenServer.on_start() @spec start_link(options(), Keyword.t()) :: GenServer.on_start()

@ -10,11 +10,32 @@ defmodule Indexer.Block.Fetcher do
import EthereumJSONRPC, only: [quantity_to_integer: 1] import EthereumJSONRPC, only: [quantity_to_integer: 1]
alias EthereumJSONRPC.{Blocks, FetchedBeneficiaries} alias EthereumJSONRPC.{Blocks, FetchedBeneficiaries}
alias Explorer.Chain
alias Explorer.Chain.{Address, Block, Hash, Import, Transaction} alias Explorer.Chain.{Address, Block, Hash, Import, Transaction}
alias Indexer.{AddressExtraction, CoinBalance, MintTransfer, ReplacedTransaction, Token, TokenTransfers, Tracer}
alias Indexer.Address.{CoinBalances, TokenBalances}
alias Indexer.Block.Fetcher.Receipts alias Indexer.Block.Fetcher.Receipts
alias Indexer.Block.{Reward, Transform}
alias Indexer.Fetcher.{
BlockReward,
CoinBalance,
ContractCode,
InternalTransaction,
ReplacedTransaction,
Token,
TokenBalance,
UncleBlock
}
alias Indexer.Tracer
alias Indexer.Transform.{
AddressCoinBalances,
Addresses,
AddressTokenBalances,
MintTransfers,
TokenTransfers
}
alias Indexer.Transform.Blocks, as: TransformBlocks
@type address_hash_to_fetched_balance_block_number :: %{String.t() => Block.block_number()} @type address_hash_to_fetched_balance_block_number :: %{String.t() => Block.block_number()}
@ -46,6 +67,7 @@ defmodule Indexer.Block.Fetcher do
@receipts_batch_size 250 @receipts_batch_size 250
@receipts_concurrency 10 @receipts_concurrency 10
@geth_block_limit 128
@doc false @doc false
def default_receipts_batch_size, do: @receipts_batch_size def default_receipts_batch_size, do: @receipts_batch_size
@ -102,16 +124,16 @@ defmodule Indexer.Block.Fetcher do
block_second_degree_relations_params: block_second_degree_relations_params, block_second_degree_relations_params: block_second_degree_relations_params,
errors: blocks_errors errors: blocks_errors
}}} <- {:blocks, EthereumJSONRPC.fetch_blocks_by_range(range, json_rpc_named_arguments)}, }}} <- {:blocks, EthereumJSONRPC.fetch_blocks_by_range(range, json_rpc_named_arguments)},
blocks = Transform.transform_blocks(blocks_params), blocks = TransformBlocks.transform_blocks(blocks_params),
{:receipts, {:ok, receipt_params}} <- {:receipts, Receipts.fetch(state, transactions_params_without_receipts)}, {:receipts, {:ok, receipt_params}} <- {:receipts, Receipts.fetch(state, transactions_params_without_receipts)},
%{logs: logs, receipts: receipts} = receipt_params, %{logs: logs, receipts: receipts} = receipt_params,
transactions_with_receipts = Receipts.put(transactions_params_without_receipts, receipts), transactions_with_receipts = Receipts.put(transactions_params_without_receipts, receipts),
%{token_transfers: token_transfers, tokens: tokens} = TokenTransfers.parse(logs), %{token_transfers: token_transfers, tokens: tokens} = TokenTransfers.parse(logs),
%{mint_transfers: mint_transfers} = MintTransfer.parse(logs), %{mint_transfers: mint_transfers} = MintTransfers.parse(logs),
%FetchedBeneficiaries{params_set: beneficiary_params_set, errors: beneficiaries_errors} = %FetchedBeneficiaries{params_set: beneficiary_params_set, errors: beneficiaries_errors} =
fetch_beneficiaries(blocks, json_rpc_named_arguments), fetch_beneficiaries(blocks, json_rpc_named_arguments),
addresses = addresses =
AddressExtraction.extract_addresses(%{ Addresses.extract_addresses(%{
block_reward_contract_beneficiaries: MapSet.to_list(beneficiary_params_set), block_reward_contract_beneficiaries: MapSet.to_list(beneficiary_params_set),
blocks: blocks, blocks: blocks,
logs: logs, logs: logs,
@ -126,12 +148,12 @@ defmodule Indexer.Block.Fetcher do
logs_params: logs, logs_params: logs,
transactions_params: transactions_with_receipts transactions_params: transactions_with_receipts
} }
|> CoinBalances.params_set(), |> AddressCoinBalances.params_set(),
beneficiaries_with_gas_payment <- beneficiaries_with_gas_payment <-
beneficiary_params_set beneficiary_params_set
|> add_gas_payments(transactions_with_receipts) |> add_gas_payments(transactions_with_receipts)
|> Reward.Fetcher.reduce_uncle_rewards(), |> BlockReward.reduce_uncle_rewards(),
address_token_balances = TokenBalances.params_set(%{token_transfers_params: token_transfers}), address_token_balances = AddressTokenBalances.params_set(%{token_transfers_params: token_transfers}),
{:ok, inserted} <- {:ok, inserted} <-
__MODULE__.import( __MODULE__.import(
state, state,
@ -180,7 +202,7 @@ defmodule Indexer.Block.Fetcher do
def async_import_block_rewards(errors) when is_list(errors) do def async_import_block_rewards(errors) when is_list(errors) do
errors errors
|> block_reward_errors_to_block_numbers() |> block_reward_errors_to_block_numbers()
|> Indexer.Block.Reward.Fetcher.async_fetch() |> BlockReward.async_fetch()
end end
def async_import_coin_balances(%{addresses: addresses}, %{ def async_import_coin_balances(%{addresses: addresses}, %{
@ -191,23 +213,77 @@ 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.Fetcher.async_fetch_balances() |> CoinBalance.async_fetch_balances()
end end
def async_import_coin_balances(_, _), do: :ok def async_import_coin_balances(_, _), do: :ok
def async_import_created_contract_codes(%{transactions: transactions}) do
transactions
|> Enum.flat_map(fn
%Transaction{
block_number: block_number,
hash: hash,
created_contract_address_hash: %Hash{} = created_contract_address_hash,
created_contract_code_indexed_at: nil,
internal_transactions_indexed_at: nil
} ->
[%{block_number: block_number, hash: hash, created_contract_address_hash: created_contract_address_hash}]
%Transaction{internal_transactions_indexed_at: %DateTime{}} ->
[]
%Transaction{created_contract_address_hash: nil} ->
[]
end)
|> ContractCode.async_fetch(10_000)
end
def async_import_created_contract_codes(_), do: :ok
def async_import_internal_transactions(%{blocks: blocks}, EthereumJSONRPC.Parity) do
blocks
|> Enum.map(fn %Block{number: block_number} -> %{number: block_number} end)
|> InternalTransaction.async_block_fetch(10_000)
end
def async_import_internal_transactions(%{transactions: transactions}, EthereumJSONRPC.Geth) do
{_, max_block_number} = Chain.fetch_min_and_max_block_numbers()
transactions
|> Enum.flat_map(fn
%Transaction{block_number: block_number, index: index, hash: hash, internal_transactions_indexed_at: nil} ->
[%{block_number: block_number, index: index, hash: hash}]
%Transaction{internal_transactions_indexed_at: %DateTime{}} ->
[]
end)
|> Enum.filter(fn %{block_number: block_number} ->
max_block_number - block_number < @geth_block_limit
end)
|> InternalTransaction.async_fetch(10_000)
end
def async_import_internal_transactions(_, _), do: :ok
def async_import_tokens(%{tokens: tokens}) do def async_import_tokens(%{tokens: tokens}) do
tokens tokens
|> Enum.map(& &1.contract_address_hash) |> Enum.map(& &1.contract_address_hash)
|> Token.Fetcher.async_fetch() |> Token.async_fetch()
end end
def async_import_tokens(_), do: :ok def async_import_tokens(_), do: :ok
def async_import_token_balances(%{address_token_balances: token_balances}) do
TokenBalance.async_fetch(token_balances)
end
def async_import_token_balances(_), do: :ok
def async_import_uncles(%{block_second_degree_relations: block_second_degree_relations}) do def async_import_uncles(%{block_second_degree_relations: block_second_degree_relations}) do
block_second_degree_relations block_second_degree_relations
|> Enum.map(& &1.uncle_hash) |> Enum.map(& &1.uncle_hash)
|> Indexer.Block.Uncle.Fetcher.async_fetch_blocks() |> UncleBlock.async_fetch_blocks()
end end
def async_import_uncles(_), do: :ok def async_import_uncles(_), do: :ok
@ -221,7 +297,7 @@ defmodule Indexer.Block.Fetcher do
%Transaction{block_hash: nil} -> %Transaction{block_hash: nil} ->
[] []
end) end)
|> ReplacedTransaction.Fetcher.async_fetch(10_000) |> ReplacedTransaction.async_fetch(10_000)
end end
def async_import_replaced_transactions(_), do: :ok def async_import_replaced_transactions(_), do: :ok

@ -14,20 +14,22 @@ defmodule Indexer.Block.Realtime.Fetcher do
import Indexer.Block.Fetcher, import Indexer.Block.Fetcher,
only: [ only: [
async_import_block_rewards: 1, async_import_block_rewards: 1,
async_import_created_contract_codes: 1,
async_import_internal_transactions: 2,
async_import_replaced_transactions: 1,
async_import_tokens: 1, async_import_tokens: 1,
async_import_token_balances: 1,
async_import_uncles: 1, async_import_uncles: 1,
fetch_and_import_range: 2, fetch_and_import_range: 2
async_import_replaced_transactions: 1
] ]
alias ABI.TypeDecoder
alias Ecto.Changeset alias Ecto.Changeset
alias EthereumJSONRPC.{FetchedBalances, Subscription} alias EthereumJSONRPC.{FetchedBalances, Subscription}
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.TokenTransfer
alias Explorer.Counters.AverageBlockTime alias Explorer.Counters.AverageBlockTime
alias Indexer.{AddressExtraction, Block, TokenBalances, Tracer} alias Indexer.{Block, Tracer}
alias Indexer.Block.Realtime.TaskSupervisor alias Indexer.Block.Realtime.TaskSupervisor
alias Indexer.Transform.Addresses
alias Timex.Duration alias Timex.Duration
@behaviour Block.Fetcher @behaviour Block.Fetcher
@ -159,42 +161,21 @@ defmodule Indexer.Block.Realtime.Fetcher do
@impl Block.Fetcher @impl Block.Fetcher
def import( def import(
block_fetcher, %Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments} = block_fetcher,
%{ %{
address_coin_balances: %{params: address_coin_balances_params}, address_coin_balances: %{params: address_coin_balances_params},
address_hash_to_fetched_balance_block_number: address_hash_to_block_number, address_hash_to_fetched_balance_block_number: address_hash_to_block_number,
address_token_balances: %{params: address_token_balances_params},
addresses: %{params: addresses_params}, addresses: %{params: addresses_params},
blocks: %{params: blocks_params}, block_rewards: block_rewards
block_rewards: block_rewards,
transactions: %{params: transactions_params},
token_transfers: %{params: token_transfers_params}
} = options } = options
) do ) do
with {:internal_transactions, with {:balances, {:ok, %{addresses_params: balances_addresses_params, balances_params: balances_params}}} <-
{:ok,
%{
addresses_params: internal_transactions_addresses_params,
internal_transactions_params: internal_transactions_params,
internal_transactions_indexed_at_blocks_params: internal_transactions_indexed_at_blocks_params
}}} <-
{:internal_transactions,
internal_transactions(block_fetcher, %{
addresses_params: addresses_params,
blocks_params: blocks_params,
token_transfers_params: token_transfers_params,
transactions_params: transactions_params
})},
{:balances, {:ok, %{addresses_params: balances_addresses_params, balances_params: balances_params}}} <-
{:balances, {:balances,
balances(block_fetcher, %{ balances(block_fetcher, %{
address_hash_to_block_number: address_hash_to_block_number, address_hash_to_block_number: address_hash_to_block_number,
addresses_params: internal_transactions_addresses_params, addresses_params: addresses_params,
balances_params: address_coin_balances_params balances_params: address_coin_balances_params
})}, })},
{:address_token_balances, {:ok, address_token_balances}} <-
{:address_token_balances, fetch_token_balances(address_token_balances_params)},
address_current_token_balances = TokenBalances.to_address_current_token_balances(address_token_balances),
{block_reward_errors, chain_import_block_rewards} = Map.pop(block_rewards, :errors), {block_reward_errors, chain_import_block_rewards} = Map.pop(block_rewards, :errors),
chain_import_options = chain_import_options =
options options
@ -202,16 +183,14 @@ defmodule Indexer.Block.Realtime.Fetcher do
|> put_in([:addresses, :params], balances_addresses_params) |> put_in([:addresses, :params], balances_addresses_params)
|> put_in([:blocks, :params, Access.all(), :consensus], true) |> put_in([:blocks, :params, Access.all(), :consensus], true)
|> put_in([:block_rewards], chain_import_block_rewards) |> put_in([:block_rewards], chain_import_block_rewards)
|> put_in([Access.key(:address_coin_balances, %{}), :params], balances_params) |> put_in([Access.key(:address_coin_balances, %{}), :params], balances_params),
|> put_in([Access.key(:address_current_token_balances, %{}), :params], address_current_token_balances)
|> put_in([Access.key(:address_token_balances), :params], address_token_balances)
|> put_in([Access.key(:internal_transactions, %{}), :params], internal_transactions_params)
|> put_in([:internal_transactions_indexed_at_blocks], %{
params: internal_transactions_indexed_at_blocks_params,
with: :number_only_changeset
}),
{:import, {:ok, imported} = ok} <- {:import, Chain.import(chain_import_options)} do {:import, {:ok, imported} = ok} <- {:import, Chain.import(chain_import_options)} do
async_import_remaining_block_data(imported, %{block_rewards: %{errors: block_reward_errors}}) async_import_remaining_block_data(
imported,
%{block_rewards: %{errors: block_reward_errors}},
json_rpc_named_arguments
)
ok ok
end end
end end
@ -354,147 +333,20 @@ defmodule Indexer.Block.Realtime.Fetcher do
Enum.any?(changesets, &(Map.get(&1, :message) == "Unknown block number")) Enum.any?(changesets, &(Map.get(&1, :message) == "Unknown block number"))
end end
defp async_import_remaining_block_data(imported, %{block_rewards: %{errors: block_reward_errors}}) do defp async_import_remaining_block_data(
imported,
%{block_rewards: %{errors: block_reward_errors}},
json_rpc_named_arguments
) do
async_import_block_rewards(block_reward_errors) async_import_block_rewards(block_reward_errors)
async_import_created_contract_codes(imported)
async_import_internal_transactions(imported, Keyword.get(json_rpc_named_arguments, :variant))
async_import_tokens(imported) async_import_tokens(imported)
async_import_token_balances(imported)
async_import_uncles(imported) async_import_uncles(imported)
async_import_replaced_transactions(imported) async_import_replaced_transactions(imported)
end end
defp internal_transactions(
%Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments},
%{
addresses_params: addresses_params,
blocks_params: blocks_params,
token_transfers_params: token_transfers_params,
transactions_params: transactions_params
}
) do
variant = Keyword.fetch!(json_rpc_named_arguments, :variant)
internal_transactions_indexed_at_blocks_params =
case variant do
EthereumJSONRPC.Parity -> blocks_params
_ -> []
end
variant
|> case do
EthereumJSONRPC.Parity ->
blocks_params
|> Enum.map(fn %{number: block_number} -> block_number end)
|> EthereumJSONRPC.fetch_block_internal_transactions(json_rpc_named_arguments)
_ ->
transactions_params
|> transactions_params_to_fetch_internal_transactions_params(token_transfers_params, json_rpc_named_arguments)
|> EthereumJSONRPC.fetch_internal_transactions(json_rpc_named_arguments)
end
|> case do
{:ok, internal_transactions_params} ->
merged_addresses_params =
%{internal_transactions: internal_transactions_params}
|> AddressExtraction.extract_addresses()
|> Kernel.++(addresses_params)
|> AddressExtraction.merge_addresses()
{:ok,
%{
addresses_params: merged_addresses_params,
internal_transactions_params: internal_transactions_params,
internal_transactions_indexed_at_blocks_params: internal_transactions_indexed_at_blocks_params
}}
:ignore ->
{:ok,
%{
addresses_params: addresses_params,
internal_transactions_params: [],
internal_transactions_indexed_at_blocks_params: []
}}
{:error, _reason} = error ->
error
end
end
defp transactions_params_to_fetch_internal_transactions_params(
transactions_params,
token_transfers_params,
json_rpc_named_arguments
) do
token_transfer_transaction_hash_set = MapSet.new(token_transfers_params, & &1.transaction_hash)
Enum.flat_map(
transactions_params,
&transaction_params_to_fetch_internal_transaction_params_list(
&1,
token_transfer_transaction_hash_set,
json_rpc_named_arguments
)
)
end
defp transaction_params_to_fetch_internal_transaction_params_list(
%{block_number: block_number, transaction_index: transaction_index, hash: hash} = transaction_params,
token_transfer_transaction_hash_set,
json_rpc_named_arguments
)
when is_integer(block_number) and is_integer(transaction_index) and is_binary(hash) do
token_transfer? = hash in token_transfer_transaction_hash_set
if fetch_internal_transactions?(transaction_params, token_transfer?, json_rpc_named_arguments) do
[%{block_number: block_number, transaction_index: transaction_index, hash_data: hash}]
else
[]
end
end
# 0xa9059cbb - signature of the transfer(address,uint256) function from the ERC-20 token specification.
# Although transaction input data can be faked we use this heuristics to filter simple token transfer internal transactions from indexing because they slow down realtime fetcher
defp fetch_internal_transactions?(
%{
status: :ok,
created_contract_address_hash: nil,
input: unquote(TokenTransfer.transfer_function_signature()) <> params,
value: 0
},
_,
_
) do
types = [:address, {:uint, 256}]
try do
[_address, _value] =
params
|> Base.decode16!(case: :mixed)
|> TypeDecoder.decode_raw(types)
false
rescue
_ -> true
end
end
defp fetch_internal_transactions?(
%{
status: :ok,
created_contract_address_hash: nil,
input: "0x",
to_address_hash: to_address_hash,
block_number: block_number
},
_,
json_rpc_named_arguments
) do
Chain.contract_address?(to_address_hash, block_number, json_rpc_named_arguments)
end
# Token transfers not transferred during contract creation don't need internal transactions as the token transfers
# derive completely from the logs.
defp fetch_internal_transactions?(%{status: :ok, created_contract_address_hash: nil}, true, _), do: false
defp fetch_internal_transactions?(_, _, _), do: true
defp balances( defp balances(
%Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments}, %Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments},
%{addresses_params: addresses_params} = options %{addresses_params: addresses_params} = options
@ -505,9 +357,9 @@ defmodule Indexer.Block.Realtime.Fetcher do
{:ok, %FetchedBalances{params_list: params_list, errors: []}} -> {:ok, %FetchedBalances{params_list: params_list, errors: []}} ->
merged_addresses_params = merged_addresses_params =
%{address_coin_balances: params_list} %{address_coin_balances: params_list}
|> AddressExtraction.extract_addresses() |> Addresses.extract_addresses()
|> Kernel.++(addresses_params) |> Kernel.++(addresses_params)
|> AddressExtraction.merge_addresses() |> Addresses.merge_addresses()
value_fetched_at = DateTime.utc_now() value_fetched_at = DateTime.utc_now()
@ -557,10 +409,4 @@ defmodule Indexer.Block.Realtime.Fetcher do
%{hash_data: address_hash, block_quantity: integer_to_quantity(block_number)} %{hash_data: address_hash, block_quantity: integer_to_quantity(block_number)}
end) end)
end end
defp fetch_token_balances(address_token_balances_params) do
address_token_balances_params
|> MapSet.to_list()
|> TokenBalances.fetch_token_balances_from_blockchain()
end
end end

@ -1,46 +0,0 @@
defmodule Indexer.Block.Reward.Supervisor do
@moduledoc """
Supervises `Indexer.Block.Reward.Fetcher` and its batch tasks through `Indexer.Block.Reward.TaskSupervisor`
"""
use Supervisor
alias Indexer.Block.Reward.Fetcher
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(arguments, gen_server_options \\ []) do
if disabled?() do
:ignore
else
Supervisor.start_link(__MODULE__, arguments, Keyword.put_new(gen_server_options, :name, __MODULE__))
end
end
def disabled?() do
Application.get_env(:indexer, __MODULE__, [])[:disabled?] == true
end
@impl Supervisor
def init(fetcher_arguments) do
Supervisor.init(
[
{Task.Supervisor, name: Indexer.Block.Reward.TaskSupervisor},
{Fetcher, [fetcher_arguments, [name: Fetcher]]}
],
strategy: :one_for_one
)
end
end

@ -1,78 +0,0 @@
defmodule Indexer.Block.Supervisor do
@moduledoc """
Supervises `Indexer.Block.Catchup.Supervisor` and `Indexer.Block.Realtime.Supervisor`.
"""
alias Indexer.Block
alias Indexer.Block.{Catchup, Realtime, Reward, Uncle}
alias Indexer.Temporary.{AddressesWithoutCode, FailedCreatedAddresses}
use Supervisor
def start_link([arguments, gen_server_options]) do
Supervisor.start_link(__MODULE__, arguments, gen_server_options)
end
@impl Supervisor
def init(
%{
block_interval: block_interval,
json_rpc_named_arguments: json_rpc_named_arguments,
subscribe_named_arguments: subscribe_named_arguments,
realtime_overrides: realtime_overrides
} = named_arguments
) do
block_fetcher =
named_arguments
|> Map.drop(~w(block_interval memory_monitor subscribe_named_arguments realtime_overrides)a)
|> Block.Fetcher.new()
fixing_realtime_fetcher = %Block.Fetcher{
broadcast: false,
callback_module: Realtime.Fetcher,
json_rpc_named_arguments: json_rpc_named_arguments
}
realtime_block_fetcher =
named_arguments
|> Map.drop(~w(block_interval memory_monitor subscribe_named_arguments realtime_overrides)a)
|> Map.merge(Enum.into(realtime_overrides, %{}))
|> Block.Fetcher.new()
realtime_subscribe_named_arguments = realtime_overrides[:subscribe_named_arguments] || subscribe_named_arguments
memory_monitor = Map.get(named_arguments, :memory_monitor)
Supervisor.init(
[
{Catchup.Supervisor,
[
%{block_fetcher: block_fetcher, block_interval: block_interval, memory_monitor: memory_monitor},
[name: Catchup.Supervisor]
]},
{Realtime.Supervisor,
[
%{block_fetcher: realtime_block_fetcher, subscribe_named_arguments: realtime_subscribe_named_arguments},
[name: Realtime.Supervisor]
]},
{Uncle.Supervisor, [[block_fetcher: block_fetcher, memory_monitor: memory_monitor], [name: Uncle.Supervisor]]},
{Reward.Supervisor,
[
[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor],
[name: Reward.Supervisor]
]},
{FailedCreatedAddresses.Supervisor,
[
json_rpc_named_arguments,
[name: FailedCreatedAddresses.Supervisor]
]},
{AddressesWithoutCode.Supervisor,
[
fixing_realtime_fetcher,
[name: AddressesWithoutCode.Supervisor]
]}
],
strategy: :one_for_one
)
end
end

@ -1,21 +0,0 @@
defmodule Indexer.Block.Transform do
@moduledoc """
Protocol for transforming blocks.
"""
@type block :: map()
@doc """
Transforms a block.
"""
@callback transform(block :: block()) :: block()
@doc """
Runs a list of blocks through the configured block transformer.
"""
def transform_blocks(blocks) when is_list(blocks) do
transformer = Application.get_env(:indexer, :block_transformer)
Enum.map(blocks, &transformer.transform/1)
end
end

@ -1,38 +0,0 @@
defmodule Indexer.Block.Uncle.Supervisor do
@moduledoc """
Supervises `Indexer.Block.Uncle.Fetcher`.
"""
use Supervisor
alias Indexer.Block.Uncle.Fetcher
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(arguments, gen_server_options \\ []) do
Supervisor.start_link(__MODULE__, arguments, gen_server_options)
end
@impl Supervisor
def init(fetcher_arguments) do
Supervisor.init(
[
{Task.Supervisor, name: Indexer.Block.Uncle.TaskSupervisor},
{Fetcher, [fetcher_arguments, [name: Fetcher]]}
],
strategy: :rest_for_one
)
end
end

@ -1,39 +0,0 @@
defmodule Indexer.Code.Supervisor do
@moduledoc """
Supervises `Indexer.Code.Fetcher` and its batch tasks through
`Indexer.Code.TaskSupervisor`.
"""
use Supervisor
alias Indexer.Code.Fetcher
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(arguments, gen_server_options \\ []) do
Supervisor.start_link(__MODULE__, arguments, Keyword.put_new(gen_server_options, :name, __MODULE__))
end
@impl Supervisor
def init(fetcher_arguments) do
Supervisor.init(
[
{Task.Supervisor, name: Indexer.Code.TaskSupervisor},
{Fetcher, [fetcher_arguments, [name: Fetcher]]}
],
strategy: :one_for_one
)
end
end

@ -1,39 +0,0 @@
defmodule Indexer.CoinBalance.Supervisor do
@moduledoc """
Supervises `Indexer.CoinBalance.Fetcher` and its batch tasks through `Indexer.CoinBalance.TaskSupervisor`
"""
use Supervisor
alias Indexer.CoinBalance.{Fetcher, OnDemandFetcher}
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(arguments, gen_server_options \\ []) do
Supervisor.start_link(__MODULE__, arguments, Keyword.put_new(gen_server_options, :name, __MODULE__))
end
@impl Supervisor
def init(fetcher_arguments) do
Supervisor.init(
[
{Task.Supervisor, name: Indexer.CoinBalance.TaskSupervisor},
{Fetcher, [fetcher_arguments, [name: Fetcher]]},
{OnDemandFetcher, [fetcher_arguments[:json_rpc_named_arguments], [name: OnDemandFetcher]]}
],
strategy: :one_for_one
)
end
end

@ -0,0 +1,77 @@
defmodule Indexer.Fetcher do
@moduledoc """
General fetcher infrastructure.
"""
alias Macro.Env
defmacro __using__(opts \\ []) do
quote do
require Indexer.Fetcher
Indexer.Fetcher.defsupervisor(unquote(opts))
end
end
# credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity
defmacro defsupervisor(opts \\ []) do
quote location: :keep do
opts = unquote(opts)
strategy = Keyword.get(opts, :strategy, :one_for_one)
fetcher = __MODULE__
supervisor = Keyword.get(opts, :supervisor, Module.concat(fetcher, Supervisor))
task_supervisor = Keyword.get(opts, :task_supervisor, Module.concat(fetcher, TaskSupervisor))
Module.create(
supervisor,
quote bind_quoted: [strategy: strategy, fetcher: fetcher, task_supervisor: task_supervisor] do
use Supervisor
def child_spec([]), do: child_spec([[], []])
def child_spec([init_arguments]), do: child_spec([init_arguments, []])
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
restart: :transient,
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(arguments, gen_server_options \\ []) do
if disabled?() do
:ignore
else
Supervisor.start_link(__MODULE__, arguments, Keyword.put_new(gen_server_options, :name, __MODULE__))
end
end
def disabled?() do
Application.get_env(:indexer, __MODULE__, [])[:disabled?] == true
end
@impl Supervisor
def init(fetcher_arguments) do
children = [
{Task.Supervisor, name: unquote(task_supervisor)},
{unquote(fetcher), [put_supervisor_when_is_list(fetcher_arguments), [name: unquote(fetcher)]]}
]
Supervisor.init(children, strategy: unquote(strategy))
end
defp put_supervisor_when_is_list(arguments) when is_list(arguments) do
Keyword.put(arguments, :supervisor, self())
end
defp put_supervisor_when_is_list(arguments), do: arguments
end,
Env.location(__ENV__)
)
end
end
end

@ -1,4 +1,4 @@
defmodule Indexer.Block.Reward.Fetcher do defmodule Indexer.Fetcher.BlockReward do
@moduledoc """ @moduledoc """
Fetches `t:Explorer.Chain.Block.Reward.t/0` for a given `t:Explorer.Chain.Block.block_number/0`. Fetches `t:Explorer.Chain.Block.Reward.t/0` for a given `t:Explorer.Chain.Block.block_number/0`.
@ -6,6 +6,7 @@ defmodule Indexer.Block.Reward.Fetcher do
retrieved from the database and compared against that returned from `EthereumJSONRPC.` retrieved from the database and compared against that returned from `EthereumJSONRPC.`
""" """
use Indexer.Fetcher
use Spandex.Decorators use Spandex.Decorators
require Logger require Logger
@ -16,9 +17,10 @@ defmodule Indexer.Block.Reward.Fetcher do
alias EthereumJSONRPC.FetchedBeneficiaries alias EthereumJSONRPC.FetchedBeneficiaries
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.{Block, Wei} alias Explorer.Chain.{Block, Wei}
alias Indexer.Address.CoinBalances alias Indexer.{BufferedTask, Tracer}
alias Indexer.{AddressExtraction, BufferedTask, CoinBalance, Tracer} alias Indexer.Fetcher.BlockReward.Supervisor, as: BlockRewardSupervisor
alias Indexer.Block.Reward.Supervisor, as: BlockRewardSupervisor alias Indexer.Fetcher.CoinBalance
alias Indexer.Transform.{AddressCoinBalances, Addresses}
@behaviour BufferedTask @behaviour BufferedTask
@ -26,7 +28,7 @@ defmodule Indexer.Block.Reward.Fetcher do
flush_interval: :timer.seconds(3), flush_interval: :timer.seconds(3),
max_batch_size: 10, max_batch_size: 10,
max_concurrency: 4, max_concurrency: 4,
task_supervisor: Indexer.Block.Reward.TaskSupervisor, task_supervisor: Indexer.Fetcher.BlockReward.TaskSupervisor,
metadata: [fetcher: :block_reward] metadata: [fetcher: :block_reward]
] ]
@ -72,7 +74,7 @@ defmodule Indexer.Block.Reward.Fetcher do
end end
@impl BufferedTask @impl BufferedTask
@decorate trace(name: "fetch", resource: "Indexer.Block.Reward.Fetcher.run/2", service: :indexer, tracer: Tracer) @decorate trace(name: "fetch", resource: "Indexer.Fetcher.BlockReward.run/2", service: :indexer, tracer: Tracer)
def run(entries, json_rpc_named_arguments) do def run(entries, json_rpc_named_arguments) do
hash_string_by_number = hash_string_by_number =
entries entries
@ -129,7 +131,7 @@ defmodule Indexer.Block.Reward.Fetcher do
|> import_block_reward_params() |> import_block_reward_params()
|> case do |> case do
{:ok, %{address_coin_balances: address_coin_balances}} -> {:ok, %{address_coin_balances: address_coin_balances}} ->
CoinBalance.Fetcher.async_fetch_balances(address_coin_balances) CoinBalance.async_fetch_balances(address_coin_balances)
retry_errors(errors) retry_errors(errors)
@ -237,8 +239,8 @@ defmodule Indexer.Block.Reward.Fetcher do
end end
defp import_block_reward_params(block_rewards_params) when is_list(block_rewards_params) do defp import_block_reward_params(block_rewards_params) when is_list(block_rewards_params) do
addresses_params = AddressExtraction.extract_addresses(%{block_reward_contract_beneficiaries: block_rewards_params}) addresses_params = Addresses.extract_addresses(%{block_reward_contract_beneficiaries: block_rewards_params})
address_coin_balances_params_set = CoinBalances.params_set(%{beneficiary_params: block_rewards_params}) address_coin_balances_params_set = AddressCoinBalances.params_set(%{beneficiary_params: block_rewards_params})
Chain.import(%{ Chain.import(%{
addresses: %{params: addresses_params}, addresses: %{params: addresses_params},

@ -1,9 +1,10 @@
defmodule Indexer.CoinBalance.Fetcher do defmodule Indexer.Fetcher.CoinBalance do
@moduledoc """ @moduledoc """
Fetches `t:Explorer.Chain.Address.CoinBalance.t/0` and updates `t:Explorer.Chain.Address.t/0` `fetched_coin_balance` and 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`. `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
use Spandex.Decorators use Spandex.Decorators
require Logger require Logger
@ -21,7 +22,7 @@ defmodule Indexer.CoinBalance.Fetcher do
flush_interval: :timer.seconds(3), flush_interval: :timer.seconds(3),
max_batch_size: 500, max_batch_size: 500,
max_concurrency: 4, max_concurrency: 4,
task_supervisor: Indexer.CoinBalance.TaskSupervisor, task_supervisor: Indexer.Fetcher.CoinBalance.TaskSupervisor,
metadata: [fetcher: :coin_balance] metadata: [fetcher: :coin_balance]
] ]
@ -69,7 +70,7 @@ defmodule Indexer.CoinBalance.Fetcher do
end end
@impl BufferedTask @impl BufferedTask
@decorate trace(name: "fetch", resource: "Indexer.CoinBalance.Fetcher.run/2", service: :indexer, tracer: Tracer) @decorate trace(name: "fetch", resource: "Indexer.Fetcher.CoinBalance.run/2", service: :indexer, tracer: Tracer)
def run(entries, json_rpc_named_arguments) do 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

@ -1,4 +1,4 @@
defmodule Indexer.CoinBalance.OnDemandFetcher do defmodule Indexer.Fetcher.CoinBalanceOnDemand do
@moduledoc """ @moduledoc """
Ensures that we have a reasonably up to date coin balance for a given address. Ensures that we have a reasonably up to date coin balance for a given address.
@ -10,6 +10,7 @@ defmodule Indexer.CoinBalance.OnDemandFetcher do
@latest_balance_stale_threshold :timer.hours(24) @latest_balance_stale_threshold :timer.hours(24)
use GenServer use GenServer
use Indexer.Fetcher
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
import EthereumJSONRPC, only: [integer_to_quantity: 1] import EthereumJSONRPC, only: [integer_to_quantity: 1]
@ -19,7 +20,7 @@ defmodule Indexer.CoinBalance.OnDemandFetcher do
alias Explorer.Chain.{Address, BlockNumberCache} alias Explorer.Chain.{Address, BlockNumberCache}
alias Explorer.Chain.Address.CoinBalance alias Explorer.Chain.Address.CoinBalance
alias Explorer.Counters.AverageBlockTime alias Explorer.Counters.AverageBlockTime
alias Indexer.CoinBalance.Fetcher alias Indexer.Fetcher.CoinBalance, as: CoinBalanceFetcher
alias Timex.Duration alias Timex.Duration
@type block_number :: integer @type block_number :: integer
@ -42,7 +43,7 @@ defmodule Indexer.CoinBalance.OnDemandFetcher do
latest_block_number = latest_block_number() latest_block_number = latest_block_number()
case stale_balance_window(latest_block_number) do case stale_balance_window(latest_block_number) do
{:error, :no_average_block_time} -> {:error, _} ->
:current :current
stale_balance_window -> stale_balance_window ->
@ -134,7 +135,7 @@ defmodule Indexer.CoinBalance.OnDemandFetcher do
:ok :ok
{:ok, %{params_list: params_list}} -> {:ok, %{params_list: params_list}} ->
address_params = Fetcher.balances_params_to_address_params(params_list) address_params = CoinBalanceFetcher.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},
@ -153,7 +154,7 @@ defmodule Indexer.CoinBalance.OnDemandFetcher do
end end
defp do_import(%FetchedBalances{} = fetched_balances) do defp do_import(%FetchedBalances{} = fetched_balances) do
case Fetcher.import_fetched_balances(fetched_balances, :on_demand) do case CoinBalanceFetcher.import_fetched_balances(fetched_balances, :on_demand) do
{:ok, %{addresses: [address]}} -> {:ok, address} {:ok, %{addresses: [address]}} -> {:ok, address}
_ -> :error _ -> :error
end end
@ -174,7 +175,11 @@ defmodule Indexer.CoinBalance.OnDemandFetcher do
|> Duration.to_milliseconds() |> Duration.to_milliseconds()
|> round() |> round()
if average_block_time == 0 do
{:error, :empty_database}
else
block_number - div(@latest_balance_stale_threshold, average_block_time) block_number - div(@latest_balance_stale_threshold, average_block_time)
end end
end end
end end
end

@ -1,8 +1,9 @@
defmodule Indexer.Code.Fetcher do defmodule Indexer.Fetcher.ContractCode do
@moduledoc """ @moduledoc """
Fetches `contract_code` `t:Explorer.Chain.Address.t/0`. Fetches `contract_code` `t:Explorer.Chain.Address.t/0`.
""" """
use Indexer.Fetcher
use Spandex.Decorators use Spandex.Decorators
require Logger require Logger
@ -11,7 +12,8 @@ defmodule Indexer.Code.Fetcher do
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.{Block, Hash} alias Explorer.Chain.{Block, Hash}
alias Indexer.{AddressExtraction, BufferedTask, Tracer} alias Indexer.{BufferedTask, Tracer}
alias Indexer.Transform.Addresses
@behaviour BufferedTask @behaviour BufferedTask
@ -21,7 +23,7 @@ defmodule Indexer.Code.Fetcher do
flush_interval: :timer.seconds(3), flush_interval: :timer.seconds(3),
max_concurrency: @max_concurrency, max_concurrency: @max_concurrency,
max_batch_size: @max_batch_size, max_batch_size: @max_batch_size,
task_supervisor: Indexer.Code.TaskSupervisor, task_supervisor: Indexer.Fetcher.ContractCode.TaskSupervisor,
metadata: [fetcher: :code] metadata: [fetcher: :code]
] ]
@ -85,7 +87,7 @@ defmodule Indexer.Code.Fetcher do
@impl BufferedTask @impl BufferedTask
@decorate trace( @decorate trace(
name: "fetch", name: "fetch",
resource: "Indexer.Code.Fetcher.run/2", resource: "Indexer.Fetcher.ContractCode.run/2",
service: :indexer, service: :indexer,
tracer: Tracer tracer: Tracer
) )
@ -97,7 +99,7 @@ defmodule Indexer.Code.Fetcher do
|> EthereumJSONRPC.fetch_codes(json_rpc_named_arguments) |> EthereumJSONRPC.fetch_codes(json_rpc_named_arguments)
|> case do |> case do
{:ok, create_address_codes} -> {:ok, create_address_codes} ->
addresses_params = AddressExtraction.extract_addresses(%{codes: create_address_codes.params_list}) addresses_params = Addresses.extract_addresses(%{codes: create_address_codes.params_list})
import_with_balances(addresses_params, entries, json_rpc_named_arguments) import_with_balances(addresses_params, entries, json_rpc_named_arguments)
@ -118,7 +120,7 @@ defmodule Indexer.Code.Fetcher do
{:ok, fetched_balances} -> {:ok, fetched_balances} ->
balance_addresses_params = balances_params_to_address_params(fetched_balances.params_list) balance_addresses_params = balances_params_to_address_params(fetched_balances.params_list)
merged_addresses_params = AddressExtraction.merge_addresses(addresses_params ++ balance_addresses_params) merged_addresses_params = Addresses.merge_addresses(addresses_params ++ balance_addresses_params)
case Chain.import(%{ case Chain.import(%{
addresses: %{params: merged_addresses_params}, addresses: %{params: merged_addresses_params},

@ -1,10 +1,11 @@
defmodule Indexer.InternalTransaction.Fetcher do defmodule Indexer.Fetcher.InternalTransaction do
@moduledoc """ @moduledoc """
Fetches and indexes `t:Explorer.Chain.InternalTransaction.t/0`. Fetches and indexes `t:Explorer.Chain.InternalTransaction.t/0`.
See `async_fetch/1` for details on configuring limits. See `async_fetch/1` for details on configuring limits.
""" """
use Indexer.Fetcher
use Spandex.Decorators use Spandex.Decorators
require Logger require Logger
@ -13,7 +14,8 @@ defmodule Indexer.InternalTransaction.Fetcher do
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.{Block, Hash} alias Explorer.Chain.{Block, Hash}
alias Indexer.{AddressExtraction, BufferedTask, Tracer} alias Indexer.{BufferedTask, Tracer}
alias Indexer.Transform.Addresses
@behaviour BufferedTask @behaviour BufferedTask
@ -23,7 +25,7 @@ defmodule Indexer.InternalTransaction.Fetcher do
flush_interval: :timer.seconds(3), flush_interval: :timer.seconds(3),
max_concurrency: @max_concurrency, max_concurrency: @max_concurrency,
max_batch_size: @max_batch_size, max_batch_size: @max_batch_size,
task_supervisor: Indexer.InternalTransaction.TaskSupervisor, task_supervisor: Indexer.Fetcher.InternalTransaction.TaskSupervisor,
metadata: [fetcher: :internal_transaction] metadata: [fetcher: :internal_transaction]
] ]
@ -141,7 +143,7 @@ defmodule Indexer.InternalTransaction.Fetcher do
@impl BufferedTask @impl BufferedTask
@decorate trace( @decorate trace(
name: "fetch", name: "fetch",
resource: "Indexer.InternalTransaction.Fetcher.run/2", resource: "Indexer.Fetcher.InternalTransaction.run/2",
service: :indexer, service: :indexer,
tracer: Tracer tracer: Tracer
) )
@ -177,7 +179,7 @@ defmodule Indexer.InternalTransaction.Fetcher do
internal_transactions_params_without_failed_creations = remove_failed_creations(internal_transactions_params) internal_transactions_params_without_failed_creations = remove_failed_creations(internal_transactions_params)
addresses_params = addresses_params =
AddressExtraction.extract_addresses(%{ Addresses.extract_addresses(%{
internal_transactions: internal_transactions_params_without_failed_creations internal_transactions: internal_transactions_params_without_failed_creations
}) })

@ -1,4 +1,4 @@
defmodule Indexer.PendingTransaction.Fetcher do defmodule Indexer.Fetcher.PendingTransaction do
@moduledoc """ @moduledoc """
Fetches pending transactions and imports them. Fetches pending transactions and imports them.
@ -6,6 +6,7 @@ defmodule Indexer.PendingTransaction.Fetcher do
validated version that may make it to the database first. validated version that may make it to the database first.
""" """
use GenServer use GenServer
use Indexer.Fetcher
require Logger require Logger
@ -13,7 +14,8 @@ defmodule Indexer.PendingTransaction.Fetcher do
alias Ecto.Changeset alias Ecto.Changeset
alias Explorer.Chain alias Explorer.Chain
alias Indexer.{AddressExtraction, PendingTransaction} alias Indexer.Fetcher.PendingTransaction
alias Indexer.Transform.Addresses
@chunk_size 250 @chunk_size 250
@ -70,7 +72,7 @@ defmodule Indexer.PendingTransaction.Fetcher do
|> Keyword.merge(opts) |> Keyword.merge(opts)
state = state =
%PendingTransaction.Fetcher{ %__MODULE__{
json_rpc_named_arguments: Keyword.fetch!(opts, :json_rpc_named_arguments), json_rpc_named_arguments: Keyword.fetch!(opts, :json_rpc_named_arguments),
interval: opts[:pending_transaction_interval] || @default_interval interval: opts[:pending_transaction_interval] || @default_interval
} }
@ -80,12 +82,12 @@ defmodule Indexer.PendingTransaction.Fetcher do
end end
@impl GenServer @impl GenServer
def handle_info(:fetch, %PendingTransaction.Fetcher{} = state) do def handle_info(:fetch, %__MODULE__{} = state) do
task = Task.Supervisor.async_nolink(PendingTransaction.TaskSupervisor, fn -> task(state) end) task = Task.Supervisor.async_nolink(PendingTransaction.TaskSupervisor, fn -> task(state) end)
{:noreply, %PendingTransaction.Fetcher{state | task: task}} {:noreply, %__MODULE__{state | task: task}}
end end
def handle_info({ref, result}, %PendingTransaction.Fetcher{task: %Task{ref: ref}} = state) do def handle_info({ref, result}, %__MODULE__{task: %Task{ref: ref}} = state) do
Process.demonitor(ref, [:flush]) Process.demonitor(ref, [:flush])
case result do case result do
@ -99,19 +101,19 @@ defmodule Indexer.PendingTransaction.Fetcher do
def handle_info( def handle_info(
{:DOWN, ref, :process, pid, reason}, {:DOWN, ref, :process, pid, reason},
%PendingTransaction.Fetcher{task: %Task{pid: pid, ref: ref}} = state %__MODULE__{task: %Task{pid: pid, ref: ref}} = state
) do ) do
Logger.error(fn -> "pending transaction fetcher task exited due to #{inspect(reason)}. Rescheduling." end) Logger.error(fn -> "pending transaction fetcher task exited due to #{inspect(reason)}. Rescheduling." end)
{:noreply, schedule_fetch(state)} {:noreply, schedule_fetch(state)}
end end
defp schedule_fetch(%PendingTransaction.Fetcher{interval: interval} = state) do defp schedule_fetch(%__MODULE__{interval: interval} = state) do
Process.send_after(self(), :fetch, interval) Process.send_after(self(), :fetch, interval)
%PendingTransaction.Fetcher{state | task: nil} %__MODULE__{state | task: nil}
end end
defp task(%PendingTransaction.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments} = _state) do defp task(%__MODULE__{json_rpc_named_arguments: json_rpc_named_arguments} = _state) do
Logger.metadata(fetcher: :pending_transaction) Logger.metadata(fetcher: :pending_transaction)
case fetch_pending_transactions(json_rpc_named_arguments) do case fetch_pending_transactions(json_rpc_named_arguments) do
@ -136,7 +138,7 @@ defmodule Indexer.PendingTransaction.Fetcher do
end end
defp import_chunk(transactions_params) do defp import_chunk(transactions_params) do
addresses_params = AddressExtraction.extract_addresses(%{transactions: transactions_params}, pending: true) addresses_params = Addresses.extract_addresses(%{transactions: transactions_params}, pending: true)
# There's no need to queue up fetching the address balance since theses are pending transactions and cannot have # There's no need to queue up fetching the address balance since theses are pending transactions and cannot have
# affected the address balance yet since address balance is a balance at a given block and these transactions are # affected the address balance yet since address balance is a balance at a given block and these transactions are

@ -1,8 +1,9 @@
defmodule Indexer.ReplacedTransaction.Fetcher do defmodule Indexer.Fetcher.ReplacedTransaction do
@moduledoc """ @moduledoc """
Finds and updates replaced transactions. Finds and updates replaced transactions.
""" """
use Indexer.Fetcher
use Spandex.Decorators use Spandex.Decorators
require Logger require Logger
@ -10,7 +11,7 @@ defmodule Indexer.ReplacedTransaction.Fetcher do
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.Hash alias Explorer.Chain.Hash
alias Indexer.{BufferedTask, Tracer} alias Indexer.{BufferedTask, Tracer}
alias Indexer.ReplacedTransaction.Supervisor, as: ReplacedTransactionSupervisor alias Indexer.Fetcher.ReplacedTransaction.Supervisor, as: ReplacedTransactionSupervisor
@behaviour BufferedTask @behaviour BufferedTask
@ -20,7 +21,7 @@ defmodule Indexer.ReplacedTransaction.Fetcher do
flush_interval: :timer.seconds(3), flush_interval: :timer.seconds(3),
max_concurrency: @max_concurrency, max_concurrency: @max_concurrency,
max_batch_size: @max_batch_size, max_batch_size: @max_batch_size,
task_supervisor: Indexer.ReplacedTransaction.TaskSupervisor, task_supervisor: Indexer.Fetcher.ReplacedTransaction.TaskSupervisor,
metadata: [fetcher: :replaced_transaction] metadata: [fetcher: :replaced_transaction]
] ]
@ -94,7 +95,7 @@ defmodule Indexer.ReplacedTransaction.Fetcher do
@impl BufferedTask @impl BufferedTask
@decorate trace( @decorate trace(
name: "fetch", name: "fetch",
resource: "Indexer.ReplacedTransaction.Fetcher.run/2", resource: "Indexer.Fetcher.ReplacedTransaction.run/2",
service: :indexer, service: :indexer,
tracer: Tracer tracer: Tracer
) )

@ -1,8 +1,9 @@
defmodule Indexer.Token.Fetcher do defmodule Indexer.Fetcher.Token do
@moduledoc """ @moduledoc """
Fetches information about a token. Fetches information about a token.
""" """
use Indexer.Fetcher
use Spandex.Decorators use Spandex.Decorators
alias Explorer.Chain alias Explorer.Chain
@ -17,7 +18,7 @@ defmodule Indexer.Token.Fetcher do
flush_interval: 300, flush_interval: 300,
max_batch_size: 1, max_batch_size: 1,
max_concurrency: 10, max_concurrency: 10,
task_supervisor: Indexer.Token.TaskSupervisor task_supervisor: Indexer.Fetcher.Token.TaskSupervisor
] ]
@doc false @doc false
@ -49,7 +50,7 @@ defmodule Indexer.Token.Fetcher do
end end
@impl BufferedTask @impl BufferedTask
@decorate trace(name: "fetch", resource: "Indexer.Token.Fetcher.run/2", service: :indexer, tracer: Tracer) @decorate trace(name: "fetch", resource: "Indexer.Fetcher.Token.run/2", service: :indexer, tracer: Tracer)
def run([token_contract_address], _json_rpc_named_arguments) do def run([token_contract_address], _json_rpc_named_arguments) do
case Chain.token_from_address_hash(token_contract_address) do case Chain.token_from_address_hash(token_contract_address) do
{:ok, %Token{} = token} -> {:ok, %Token{} = token} ->

@ -1,4 +1,4 @@
defmodule Indexer.TokenBalance.Fetcher do defmodule Indexer.Fetcher.TokenBalance do
@moduledoc """ @moduledoc """
Fetches token balances and send the ones that were fetched to be imported in `Address.CurrentTokenBalance` and Fetches token balances and send the ones that were fetched to be imported in `Address.CurrentTokenBalance` and
`Address.TokenBalance`. `Address.TokenBalance`.
@ -13,6 +13,7 @@ defmodule Indexer.TokenBalance.Fetcher do
that always raise errors interacting with the Smart Contract. that always raise errors interacting with the Smart Contract.
""" """
use Indexer.Fetcher
use Spandex.Decorators use Spandex.Decorators
require Logger require Logger
@ -27,7 +28,7 @@ defmodule Indexer.TokenBalance.Fetcher do
flush_interval: 300, flush_interval: 300,
max_batch_size: 100, max_batch_size: 100,
max_concurrency: 10, max_concurrency: 10,
task_supervisor: Indexer.TokenBalance.TaskSupervisor task_supervisor: Indexer.Fetcher.TokenBalance.TaskSupervisor
] ]
@max_retries 3 @max_retries 3
@ -75,7 +76,7 @@ defmodule Indexer.TokenBalance.Fetcher do
when reading their balance in the Smart Contract. when reading their balance in the Smart Contract.
""" """
@impl BufferedTask @impl BufferedTask
@decorate trace(name: "fetch", resource: "Indexer.TokenBalance.Fetcher.run/2", tracer: Tracer, service: :indexer) @decorate trace(name: "fetch", resource: "Indexer.Fetcher.TokenBalance.run/2", tracer: Tracer, service: :indexer)
def run(entries, _json_rpc_named_arguments) do def run(entries, _json_rpc_named_arguments) do
result = result =
entries entries

@ -1,16 +1,17 @@
defmodule Indexer.Token.MetadataUpdater do defmodule Indexer.Fetcher.TokenUpdater do
@moduledoc """ @moduledoc """
Updates metadata for cataloged tokens Updates metadata for cataloged tokens
""" """
use GenServer use GenServer
use Indexer.Fetcher
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.Token alias Explorer.Chain.Token
alias Explorer.Token.MetadataRetriever alias Explorer.Token.MetadataRetriever
def start_link(initial_state) do def start_link([initial_state, gen_server_options]) do
GenServer.start_link(__MODULE__, initial_state, name: __MODULE__) GenServer.start_link(__MODULE__, initial_state, gen_server_options)
end end
@impl true @impl true

@ -1,9 +1,10 @@
defmodule Indexer.Block.Uncle.Fetcher do defmodule Indexer.Fetcher.UncleBlock do
@moduledoc """ @moduledoc """
Fetches `t:Explorer.Chain.Block.t/0` by `hash` and updates `t:Explorer.Chain.Block.SecondDegreeRelation.t/0` Fetches `t:Explorer.Chain.Block.t/0` by `hash` and updates `t:Explorer.Chain.Block.SecondDegreeRelation.t/0`
`uncle_fetched_at` where the `uncle_hash` matches `hash`. `uncle_fetched_at` where the `uncle_hash` matches `hash`.
""" """
use Indexer.Fetcher
use Spandex.Decorators use Spandex.Decorators
require Logger require Logger
@ -12,7 +13,9 @@ defmodule Indexer.Block.Uncle.Fetcher do
alias EthereumJSONRPC.Blocks alias EthereumJSONRPC.Blocks
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.Hash alias Explorer.Chain.Hash
alias Indexer.{AddressExtraction, Block, BufferedTask, Tracer} alias Indexer.{Block, BufferedTask, Tracer}
alias Indexer.Fetcher.UncleBlock
alias Indexer.Transform.Addresses
@behaviour Block.Fetcher @behaviour Block.Fetcher
@behaviour BufferedTask @behaviour BufferedTask
@ -21,7 +24,7 @@ defmodule Indexer.Block.Uncle.Fetcher do
flush_interval: :timer.seconds(3), flush_interval: :timer.seconds(3),
max_batch_size: 10, max_batch_size: 10,
max_concurrency: 10, max_concurrency: 10,
task_supervisor: Indexer.Block.Uncle.TaskSupervisor, task_supervisor: Indexer.Fetcher.UncleBlock.TaskSupervisor,
metadata: [fetcher: :block_uncle] metadata: [fetcher: :block_uncle]
] ]
@ -70,7 +73,7 @@ defmodule Indexer.Block.Uncle.Fetcher do
end end
@impl BufferedTask @impl BufferedTask
@decorate trace(name: "fetch", resource: "Indexer.Block.Uncle.Fetcher.run/2", service: :indexer, tracer: Tracer) @decorate trace(name: "fetch", resource: "Indexer.Fetcher.UncleBlock.run/2", service: :indexer, tracer: Tracer)
def run(hashes, %Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments} = block_fetcher) do def run(hashes, %Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments} = block_fetcher) do
# the same block could be included as an uncle on multiple blocks, but we only want to fetch it once # the same block could be included as an uncle on multiple blocks, but we only want to fetch it once
unique_hashes = Enum.uniq(hashes) unique_hashes = Enum.uniq(hashes)
@ -108,7 +111,7 @@ defmodule Indexer.Block.Uncle.Fetcher do
block_fetcher, block_fetcher,
original_entries original_entries
) do ) do
addresses_params = AddressExtraction.extract_addresses(%{blocks: blocks_params, transactions: transactions_params}) addresses_params = Addresses.extract_addresses(%{blocks: blocks_params, transactions: transactions_params})
case Block.Fetcher.import(block_fetcher, %{ case Block.Fetcher.import(block_fetcher, %{
addresses: %{params: addresses_params}, addresses: %{params: addresses_params},
@ -149,15 +152,15 @@ defmodule Indexer.Block.Uncle.Fetcher do
|> uncle_blocks() |> uncle_blocks()
|> fork_transactions() |> fork_transactions()
|> Chain.import() do |> Chain.import() do
# * CoinBalance.Fetcher.async_fetch_balances is not called because uncles don't affect balances # * CoinBalance.async_fetch_balances is not called because uncles don't affect balances
# * InternalTransaction.Fetcher.async_fetch is not called because internal transactions are based on transaction # * InternalTransaction.async_fetch is not called because internal transactions are based on transaction
# hash, which is shared with transaction on consensus blocks. # hash, which is shared with transaction on consensus blocks.
# * Token.Fetcher.async_fetch is not called because the tokens only matter on consensus blocks # * Token.async_fetch is not called because the tokens only matter on consensus blocks
# * TokenBalance.Fetcher.async_fetch is not called because it uses block numbers from consensus, not uncles # * TokenBalance.async_fetch is not called because it uses block numbers from consensus, not uncles
block_second_degree_relations block_second_degree_relations
|> Enum.map(& &1.uncle_hash) |> Enum.map(& &1.uncle_hash)
|> Block.Uncle.Fetcher.async_fetch_blocks() |> UncleBlock.async_fetch_blocks()
ok ok
end end

@ -1,39 +0,0 @@
defmodule Indexer.InternalTransaction.Supervisor do
@moduledoc """
Supervises `Indexer.InternalTransaction.Fetcher` and its batch tasks through
`Indexer.InternalTransaction.TaskSupervisor`.
"""
use Supervisor
alias Indexer.InternalTransaction.Fetcher
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(arguments, gen_server_options \\ []) do
Supervisor.start_link(__MODULE__, arguments, Keyword.put_new(gen_server_options, :name, __MODULE__))
end
@impl Supervisor
def init(fetcher_arguments) do
Supervisor.init(
[
{Task.Supervisor, name: Indexer.InternalTransaction.TaskSupervisor},
{Fetcher, [fetcher_arguments, [name: Fetcher]]}
],
strategy: :one_for_one
)
end
end

@ -1,39 +0,0 @@
defmodule Indexer.PendingTransaction.Supervisor do
@moduledoc """
Supervises `Indexer.PendingTransaction.Fetcher` and its batch tasks through
`Indexer.PendingTransaction.TaskSupervisor`.
"""
use Supervisor
alias Indexer.PendingTransaction.Fetcher
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(arguments, gen_server_options \\ []) do
Supervisor.start_link(__MODULE__, arguments, Keyword.put_new(gen_server_options, :name, __MODULE__))
end
@impl Supervisor
def init(fetcher_arguments) do
Supervisor.init(
[
{Task.Supervisor, name: Indexer.PendingTransaction.TaskSupervisor},
{Fetcher, [fetcher_arguments, [name: Fetcher]]}
],
strategy: :one_for_one
)
end
end

@ -1,47 +0,0 @@
defmodule Indexer.ReplacedTransaction.Supervisor do
@moduledoc """
Supervises `Indexer.ReplacedTransaction.Fetcher` and its batch tasks through
`Indexer.ReplacedTransaction.TaskSupervisor`.
"""
use Supervisor
alias Indexer.ReplacedTransaction.Fetcher
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(arguments, gen_server_options \\ []) do
if disabled?() do
:ignore
else
Supervisor.start_link(__MODULE__, arguments, Keyword.put_new(gen_server_options, :name, __MODULE__))
end
end
def disabled?() do
Application.get_env(:indexer, __MODULE__, [])[:disabled?] == true
end
@impl Supervisor
def init(fetcher_arguments) do
Supervisor.init(
[
{Task.Supervisor, name: Indexer.ReplacedTransaction.TaskSupervisor},
{Fetcher, [fetcher_arguments, [name: Fetcher]]}
],
strategy: :one_for_one
)
end
end

@ -1,97 +0,0 @@
defmodule Indexer.Shrinkable.Supervisor do
@moduledoc """
Supervisor of all supervision trees that depend on `Indexer.Alarm.Supervisor`.
"""
use Supervisor
alias Indexer.{
Block,
Code,
CoinBalance,
InternalTransaction,
PendingTransaction,
ReplacedTransaction,
Token,
TokenBalance,
TokenTransfer
}
def child_spec([]) do
child_spec([[]])
end
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(arguments, gen_server_options \\ []) do
Supervisor.start_link(__MODULE__, arguments, Keyword.put_new(gen_server_options, :name, __MODULE__))
end
@impl Supervisor
def init(%{memory_monitor: memory_monitor}) do
json_rpc_named_arguments = Application.fetch_env!(:indexer, :json_rpc_named_arguments)
block_fetcher_supervisor_named_arguments =
:indexer
|> Application.get_all_env()
|> Keyword.take(
~w(blocks_batch_size blocks_concurrency block_interval json_rpc_named_arguments receipts_batch_size
receipts_concurrency subscribe_named_arguments realtime_overrides)a
)
|> Enum.into(%{})
|> Map.put(:memory_monitor, memory_monitor)
|> Map.put_new(:realtime_overrides, %{})
Supervisor.init(
[
{CoinBalance.Supervisor,
[
[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor],
[name: CoinBalance.Supervisor]
]},
{PendingTransaction.Supervisor,
[[json_rpc_named_arguments: json_rpc_named_arguments], [name: PendingTransactionFetcher]]},
{Code.Supervisor,
[
[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor],
[name: Code.Supervisor]
]},
{ReplacedTransaction.Supervisor,
[
[memory_monitor: memory_monitor],
[name: ReplacedTransaction.Supervisor]
]},
{InternalTransaction.Supervisor,
[
[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor],
[name: InternalTransaction.Supervisor]
]},
{Token.Supervisor,
[
[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor],
[name: Token.Supervisor]
]},
{TokenBalance.Supervisor,
[
[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor],
[name: TokenBalance.Supervisor]
]},
{Block.Supervisor, [block_fetcher_supervisor_named_arguments, [name: Block.Supervisor]]},
{TokenTransfer.Uncataloged.Supervisor, [[], [name: TokenTransfer.Uncataloged.Supervisor]]}
],
strategy: :one_for_one
)
end
end

@ -0,0 +1,137 @@
defmodule Indexer.Supervisor do
@moduledoc """
Supervisor of all indexer worker supervision trees
"""
use Supervisor
alias Indexer.Block
alias Indexer.Block.{Catchup, Realtime}
alias Indexer.Fetcher.{
BlockReward,
CoinBalance,
CoinBalanceOnDemand,
ContractCode,
InternalTransaction,
PendingTransaction,
ReplacedTransaction,
Token,
TokenBalance,
TokenUpdater,
UncleBlock
}
alias Indexer.Temporary.{
AddressesWithoutCode,
FailedCreatedAddresses,
UncatalogedTokenTransfers
}
def child_spec([]) do
child_spec([[]])
end
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(arguments, gen_server_options \\ []) do
Supervisor.start_link(__MODULE__, arguments, Keyword.put_new(gen_server_options, :name, __MODULE__))
end
@impl Supervisor
def init(%{memory_monitor: memory_monitor}) do
json_rpc_named_arguments = Application.fetch_env!(:indexer, :json_rpc_named_arguments)
named_arguments =
:indexer
|> Application.get_all_env()
|> Keyword.take(
~w(blocks_batch_size blocks_concurrency block_interval json_rpc_named_arguments receipts_batch_size
receipts_concurrency subscribe_named_arguments realtime_overrides)a
)
|> Enum.into(%{})
|> Map.put(:memory_monitor, memory_monitor)
|> Map.put_new(:realtime_overrides, %{})
%{
block_interval: block_interval,
realtime_overrides: realtime_overrides,
subscribe_named_arguments: subscribe_named_arguments
} = named_arguments
metadata_updater_inverval = Application.get_env(:indexer, :metadata_updater_days_interval)
block_fetcher =
named_arguments
|> Map.drop(~w(block_interval memory_monitor subscribe_named_arguments realtime_overrides)a)
|> Block.Fetcher.new()
fixing_realtime_fetcher = %Block.Fetcher{
broadcast: false,
callback_module: Realtime.Fetcher,
json_rpc_named_arguments: json_rpc_named_arguments
}
realtime_block_fetcher =
named_arguments
|> Map.drop(~w(block_interval memory_monitor subscribe_named_arguments realtime_overrides)a)
|> Map.merge(Enum.into(realtime_overrides, %{}))
|> Block.Fetcher.new()
realtime_subscribe_named_arguments = realtime_overrides[:subscribe_named_arguments] || subscribe_named_arguments
Supervisor.init(
[
# Root fetchers
{PendingTransaction.Supervisor, [[json_rpc_named_arguments: json_rpc_named_arguments]]},
{Realtime.Supervisor,
[
%{block_fetcher: realtime_block_fetcher, subscribe_named_arguments: realtime_subscribe_named_arguments},
[name: Realtime.Supervisor]
]},
{Catchup.Supervisor,
[
%{block_fetcher: block_fetcher, block_interval: block_interval, memory_monitor: memory_monitor},
[name: Catchup.Supervisor]
]},
# Async catchup fetchers
{UncleBlock.Supervisor, [[block_fetcher: block_fetcher, memory_monitor: memory_monitor]]},
{BlockReward.Supervisor,
[[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]},
{InternalTransaction.Supervisor,
[[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]},
{CoinBalance.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]]},
{ContractCode.Supervisor,
[[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]},
{TokenBalance.Supervisor,
[[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]},
{ReplacedTransaction.Supervisor, [[memory_monitor: memory_monitor]]},
# Out-of-band fetchers
{CoinBalanceOnDemand.Supervisor, [json_rpc_named_arguments]},
{TokenUpdater.Supervisor, [%{update_interval: metadata_updater_inverval}]},
# Temporary workers
{AddressesWithoutCode.Supervisor, [fixing_realtime_fetcher]},
{FailedCreatedAddresses.Supervisor, [json_rpc_named_arguments]},
{UncatalogedTokenTransfers.Supervisor, [[]]}
],
strategy: :one_for_one
)
end
end

@ -4,6 +4,7 @@ defmodule Indexer.Temporary.AddressesWithoutCode do
""" """
use GenServer use GenServer
use Indexer.Fetcher
require Logger require Logger

@ -1,38 +0,0 @@
defmodule Indexer.Temporary.AddressesWithoutCode.Supervisor do
@moduledoc """
Supervises `Indexer.Temporary.FailedCreatedAddresses`.
"""
use Supervisor
alias Indexer.Temporary.AddressesWithoutCode
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(fetcher, gen_server_options \\ []) do
Supervisor.start_link(__MODULE__, fetcher, gen_server_options)
end
@impl Supervisor
def init(fetcher) do
Supervisor.init(
[
{Task.Supervisor, name: Indexer.Temporary.AddressesWithoutCode.TaskSupervisor},
{AddressesWithoutCode, [fetcher, [name: FailedCreatedAddresses]]}
],
strategy: :rest_for_one
)
end
end

@ -3,6 +3,7 @@ defmodule Indexer.Temporary.FailedCreatedAddresses do
Temporary module to fix internal transactions and their created transactions if a parent transaction has failed. Temporary module to fix internal transactions and their created transactions if a parent transaction has failed.
""" """
use GenServer use GenServer
use Indexer.Fetcher
require Logger require Logger
@ -10,6 +11,7 @@ defmodule Indexer.Temporary.FailedCreatedAddresses do
alias Explorer.Chain.{Address, Data, InternalTransaction, Transaction} alias Explorer.Chain.{Address, Data, InternalTransaction, Transaction}
alias Explorer.Repo alias Explorer.Repo
alias Indexer.Fetcher.ContractCode
alias Indexer.Temporary.FailedCreatedAddresses.TaskSupervisor alias Indexer.Temporary.FailedCreatedAddresses.TaskSupervisor
@task_options [max_concurrency: 3, timeout: :infinity] @task_options [max_concurrency: 3, timeout: :infinity]
@ -97,7 +99,7 @@ defmodule Indexer.Temporary.FailedCreatedAddresses do
:ok = :ok =
internal_transaction internal_transaction
|> code_entry() |> code_entry()
|> Indexer.Code.Fetcher.run(json_rpc_named_arguments) |> ContractCode.run(json_rpc_named_arguments)
end) end)
Logger.debug( Logger.debug(

@ -1,38 +0,0 @@
defmodule Indexer.Temporary.FailedCreatedAddresses.Supervisor do
@moduledoc """
Supervises `Indexer.Temporary.FailedCreatedAddresses`.
"""
use Supervisor
alias Indexer.Temporary.FailedCreatedAddresses
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(json_rpc_named_arguments, gen_server_options \\ []) do
Supervisor.start_link(__MODULE__, json_rpc_named_arguments, gen_server_options)
end
@impl Supervisor
def init(json_rpc_named_arguments) do
Supervisor.init(
[
{Task.Supervisor, name: Indexer.Temporary.FailedCreatedAddresses.TaskSupervisor},
{FailedCreatedAddresses, [json_rpc_named_arguments, [name: FailedCreatedAddresses]]}
],
strategy: :rest_for_one
)
end
end

@ -1,4 +1,4 @@
defmodule Indexer.TokenTransfer.Uncataloged.Worker do defmodule Indexer.Temporary.UncatalogedTokenTransfers do
@moduledoc """ @moduledoc """
Catalogs token tranfer logs missing an accompanying token transfer record. Catalogs token tranfer logs missing an accompanying token transfer record.
@ -8,12 +8,13 @@ defmodule Indexer.TokenTransfer.Uncataloged.Worker do
""" """
use GenServer use GenServer
use Indexer.Fetcher
require Logger require Logger
alias Explorer.Chain alias Explorer.Chain
alias Indexer.Block.Catchup.Fetcher alias Indexer.Block.Catchup.Fetcher
alias Indexer.TokenTransfer.Uncataloged alias Indexer.Temporary.UncatalogedTokenTransfers
def child_spec([init_arguments]) do def child_spec([init_arguments]) do
child_spec([init_arguments, []]) child_spec([init_arguments, []])
@ -93,6 +94,6 @@ defmodule Indexer.TokenTransfer.Uncataloged.Worker do
end end
defp async_push_front(block_numbers) do defp async_push_front(block_numbers) do
Task.Supervisor.async_nolink(Uncataloged.TaskSupervisor, Fetcher, :push_front, [block_numbers]) Task.Supervisor.async_nolink(UncatalogedTokenTransfers.TaskSupervisor, Fetcher, :push_front, [block_numbers])
end end
end end

@ -1,41 +0,0 @@
defmodule Indexer.Token.Supervisor do
@moduledoc """
Supervises `Indexer.Token.Fetcher` and its batch tasks through `Indexer.Token.TaskSupervisor`.
"""
use Supervisor
alias Indexer.Token.{Fetcher, MetadataUpdater}
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(arguments, gen_server_options \\ []) do
Supervisor.start_link(__MODULE__, arguments, Keyword.put_new(gen_server_options, :name, __MODULE__))
end
@impl Supervisor
def init(fetcher_arguments) do
metadata_updater_inverval = Application.get_env(:indexer, :metadata_updater_days_interval)
Supervisor.init(
[
{Task.Supervisor, name: Indexer.Token.TaskSupervisor},
{Fetcher, [fetcher_arguments, [name: Fetcher]]},
{MetadataUpdater, %{update_interval: metadata_updater_inverval}}
],
strategy: :one_for_one
)
end
end

@ -1,38 +0,0 @@
defmodule Indexer.TokenBalance.Supervisor do
@moduledoc """
Supervises `Indexer.TokenBalance.Fetcher` and its batch tasks through `Indexer.TokenBalance.TaskSupervisor`
"""
use Supervisor
alias Indexer.TokenBalance.Fetcher
def child_spec([init_arguments]) do
child_spec([init_arguments, []])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
default = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
type: :supervisor
}
Supervisor.child_spec(default, [])
end
def start_link(arguments, gen_server_options \\ []) do
Supervisor.start_link(__MODULE__, arguments, Keyword.put_new(gen_server_options, :name, __MODULE__))
end
@impl Supervisor
def init(fetcher_arguments) do
Supervisor.init(
[
{Task.Supervisor, name: Indexer.TokenBalance.TaskSupervisor},
{Fetcher, [fetcher_arguments, [name: Fetcher]]}
],
strategy: :one_for_one
)
end
end

@ -10,13 +10,14 @@ defmodule Indexer.TokenBalances do
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Token.BalanceReader alias Explorer.Token.BalanceReader
alias Indexer.{TokenBalance, Tracer} alias Indexer.Fetcher.TokenBalance
alias Indexer.Tracer
@doc """ @doc """
Fetches TokenBalances from specific Addresses and Blocks in the Blockchain Fetches TokenBalances from specific Addresses and Blocks in the Blockchain
In case an exception is raised during the RPC call the particular TokenBalance request In case an exception is raised during the RPC call the particular TokenBalance request
is ignored and sent to `TokenBalance.Fetcher` to be fetched again. is ignored and sent to `TokenBalance` to be fetched again.
## token_balances ## token_balances
@ -84,7 +85,7 @@ defmodule Indexer.TokenBalances do
block_number: token_balance.block_number block_number: token_balance.block_number
}) })
end) end)
|> TokenBalance.Fetcher.async_fetch() |> TokenBalance.async_fetch()
end end
defp ignore_request_with_errors(%{value: nil, value_fetched_at: nil, error: _error}), do: false defp ignore_request_with_errors(%{value: nil, value_fetched_at: nil, error: _error}), do: false

@ -1,44 +0,0 @@
defmodule Indexer.TokenTransfer.Uncataloged.Supervisor do
@moduledoc """
Supervises process for ensuring uncataloged token transfers get queued for indexing.
"""
use Supervisor
alias Indexer.TokenTransfer.Uncataloged.Worker
def child_spec([]) do
child_spec([[]])
end
def child_spec([init_arguments]) do
child_spec([init_arguments, [name: __MODULE__]])
end
def child_spec([_init_arguments, _gen_server_options] = start_link_arguments) do
spec = %{
id: __MODULE__,
start: {__MODULE__, :start_link, start_link_arguments},
restart: :transient,
type: :supervisor
}
Supervisor.child_spec(spec, [])
end
def start_link(init_arguments, gen_server_options \\ []) do
Supervisor.start_link(__MODULE__, init_arguments, gen_server_options)
end
@impl Supervisor
def init(_) do
children = [
{Worker, [[supervisor: self()], [name: Worker]]},
{Task.Supervisor, name: Indexer.TokenTransfer.Uncataloged.TaskSupervisor}
]
opts = [strategy: :one_for_all]
Supervisor.init(children, opts)
end
end

@ -1,9 +0,0 @@
defmodule Indexer.TokenTransfers do
@moduledoc """
Context for working with token transfers.
"""
alias Indexer.TokenTransfer.Parser
defdelegate parse(items), to: Parser
end

@ -1,4 +1,4 @@
defmodule Indexer.Address.CoinBalances do defmodule Indexer.Transform.AddressCoinBalances do
@moduledoc """ @moduledoc """
Extracts `Explorer.Chain.Address.CoinBalance` params from other schema's params. Extracts `Explorer.Chain.Address.CoinBalance` params from other schema's params.
""" """

@ -1,4 +1,4 @@
defmodule Indexer.Address.TokenBalances do defmodule Indexer.Transform.AddressTokenBalances do
@moduledoc """ @moduledoc """
Extracts `Explorer.Address.TokenBalance` params from other schema's params. Extracts `Explorer.Address.TokenBalance` params from other schema's params.
""" """

@ -1,4 +1,4 @@
defmodule Indexer.AddressExtraction do defmodule Indexer.Transform.Addresses do
@moduledoc """ @moduledoc """
Extract Addresses from data fetched from the Blockchain and structured as Blocks, InternalTransactions, Extract Addresses from data fetched from the Blockchain and structured as Blocks, InternalTransactions,
Transactions and Logs. Transactions and Logs.
@ -86,8 +86,7 @@ defmodule Indexer.AddressExtraction do
transactions: [ transactions: [
[ [
%{from: :block_number, to: :fetched_coin_balance_block_number}, %{from: :block_number, to: :fetched_coin_balance_block_number},
%{from: :created_contract_address_hash, to: :hash}, %{from: :created_contract_address_hash, to: :hash}
%{from: :input, to: :contract_code}
], ],
[ [
%{from: :block_number, to: :fetched_coin_balance_block_number}, %{from: :block_number, to: :fetched_coin_balance_block_number},
@ -155,7 +154,7 @@ defmodule Indexer.AddressExtraction do
Blocks have their `miner_hash` extracted. Blocks have their `miner_hash` extracted.
iex> Indexer.AddressExtraction.extract_addresses( iex> Indexer.Addresses.extract_addresses(
...> %{ ...> %{
...> blocks: [ ...> blocks: [
...> %{ ...> %{
@ -175,7 +174,7 @@ defmodule Indexer.AddressExtraction do
Internal transactions can have their `from_address_hash`, `to_address_hash` and/or `created_contract_address_hash` Internal transactions can have their `from_address_hash`, `to_address_hash` and/or `created_contract_address_hash`
extracted. extracted.
iex> Indexer.AddressExtraction.extract_addresses( iex> Indexer.Addresses.extract_addresses(
...> %{ ...> %{
...> internal_transactions: [ ...> internal_transactions: [
...> %{ ...> %{
@ -212,7 +211,7 @@ defmodule Indexer.AddressExtraction do
Transactions can have their `from_address_hash` and/or `to_address_hash` extracted. Transactions can have their `from_address_hash` and/or `to_address_hash` extracted.
iex> Indexer.AddressExtraction.extract_addresses( iex> Indexer.Addresses.extract_addresses(
...> %{ ...> %{
...> transactions: [ ...> transactions: [
...> %{ ...> %{
@ -248,7 +247,7 @@ defmodule Indexer.AddressExtraction do
Logs can have their `address_hash` extracted. Logs can have their `address_hash` extracted.
iex> Indexer.AddressExtraction.extract_addresses( iex> Indexer.Addresses.extract_addresses(
...> %{ ...> %{
...> logs: [ ...> logs: [
...> %{ ...> %{
@ -267,7 +266,7 @@ defmodule Indexer.AddressExtraction do
When the same address is mentioned multiple times, the greatest `block_number` is used When the same address is mentioned multiple times, the greatest `block_number` is used
iex> Indexer.AddressExtraction.extract_addresses( iex> Indexer.Addresses.extract_addresses(
...> %{ ...> %{
...> blocks: [ ...> blocks: [
...> %{ ...> %{
@ -320,7 +319,7 @@ defmodule Indexer.AddressExtraction do
When a contract is created and then used in internal transactions and transaction in the same fetched data, the When a contract is created and then used in internal transactions and transaction in the same fetched data, the
`created_contract_code` is merged with the greatest `block_number` `created_contract_code` is merged with the greatest `block_number`
iex> Indexer.AddressExtraction.extract_addresses( iex> Indexer.Addresses.extract_addresses(
...> %{ ...> %{
...> internal_transactions: [ ...> internal_transactions: [
...> %{ ...> %{

@ -1,8 +1,24 @@
defmodule Indexer.Block.Util do defmodule Indexer.Transform.Blocks do
@moduledoc """ @moduledoc """
Helper functions for parsing block information. Protocol for transforming blocks.
""" """
@type block :: map()
@doc """
Transforms a block.
"""
@callback transform(block :: block()) :: block()
@doc """
Runs a list of blocks through the configured block transformer.
"""
def transform_blocks(blocks) when is_list(blocks) do
transformer = Application.get_env(:indexer, :block_transformer)
Enum.map(blocks, &transformer.transform/1)
end
@doc """ @doc """
Calculates the signer's address by recovering the ECDSA public key. Calculates the signer's address by recovering the ECDSA public key.

@ -1,13 +1,13 @@
defmodule Indexer.Block.Transform.Base do defmodule Indexer.Transform.Blocks.Base do
@moduledoc """ @moduledoc """
Default block transformer to be used. Default block transformer to be used.
""" """
alias Indexer.Block.Transform alias Indexer.Transform.Blocks
@behaviour Transform @behaviour Blocks
@impl Transform @impl Blocks
def transform(block) when is_map(block) do def transform(block) when is_map(block) do
block block
end end

@ -1,17 +1,17 @@
defmodule Indexer.Block.Transform.Clique do defmodule Indexer.Transform.Blocks.Clique do
@moduledoc """ @moduledoc """
Handles block transforms for Clique chain. Handles block transforms for Clique chain.
""" """
alias Indexer.Block.{Transform, Util} alias Indexer.Transform.Blocks
@behaviour Transform @behaviour Blocks
@impl Transform @impl Blocks
def transform(%{number: 0} = block), do: block def transform(%{number: 0} = block), do: block
def transform(block) when is_map(block) do def transform(block) when is_map(block) do
miner_address = Util.signer(block) miner_address = Blocks.signer(block)
%{block | miner_hash: miner_address} %{block | miner_hash: miner_address}
end end

@ -1,4 +1,4 @@
defmodule Indexer.MintTransfer do defmodule Indexer.Transform.MintTransfers do
@moduledoc """ @moduledoc """
Helper functions to parse addresses from mint transfers. Helper functions to parse addresses from mint transfers.
@ -14,7 +14,7 @@ defmodule Indexer.MintTransfer do
## Examples ## Examples
iex> Indexer.MintTransfer.parse([ iex> Indexer.Transform.MintTransfers.parse([
...> %{ ...> %{
...> address_hash: "0x867305d19606aadba405ce534e303d0e225f9556", ...> address_hash: "0x867305d19606aadba405ce534e303d0e225f9556",
...> block_number: 137_194, ...> block_number: 137_194,

@ -1,4 +1,4 @@
defmodule Indexer.TokenTransfer.Parser do defmodule Indexer.Transform.TokenTransfers do
@moduledoc """ @moduledoc """
Helper functions for transforming data for ERC-20 and ERC-721 token transfers. Helper functions for transforming data for ERC-20 and ERC-721 token transfers.
""" """

@ -7,8 +7,18 @@ defmodule Indexer.Block.Catchup.BoundIntervalSupervisorTest do
import EthereumJSONRPC, only: [integer_to_quantity: 1] import EthereumJSONRPC, only: [integer_to_quantity: 1]
alias Explorer.Chain.Block alias Explorer.Chain.Block
alias Indexer.{BoundInterval, Code, CoinBalance, InternalTransaction, ReplacedTransaction, Token, TokenBalance} alias Indexer.BoundInterval
alias Indexer.Block.{Catchup, Uncle} alias Indexer.Block.Catchup
alias Indexer.Fetcher.{
CoinBalance,
ContractCode,
InternalTransaction,
ReplacedTransaction,
Token,
TokenBalance,
UncleBlock
}
@moduletag capture_log: true @moduletag capture_log: true
@ -204,12 +214,12 @@ defmodule Indexer.Block.Catchup.BoundIntervalSupervisorTest do
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalance.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)
Code.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)
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)
ReplacedTransaction.Supervisor.Case.start_supervised!() ReplacedTransaction.Supervisor.Case.start_supervised!()
Uncle.Supervisor.Case.start_supervised!( UncleBlock.Supervisor.Case.start_supervised!(
block_fetcher: %Indexer.Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments} block_fetcher: %Indexer.Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments}
) )
@ -410,7 +420,7 @@ defmodule Indexer.Block.Catchup.BoundIntervalSupervisorTest do
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) CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
Code.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)
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)
@ -504,12 +514,12 @@ defmodule Indexer.Block.Catchup.BoundIntervalSupervisorTest do
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) CoinBalance.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)
Code.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)
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)
ReplacedTransaction.Supervisor.Case.start_supervised!() ReplacedTransaction.Supervisor.Case.start_supervised!()
Uncle.Supervisor.Case.start_supervised!( UncleBlock.Supervisor.Case.start_supervised!(
block_fetcher: %Indexer.Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments} block_fetcher: %Indexer.Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments}
) )

@ -7,8 +7,9 @@ defmodule Indexer.Block.Catchup.FetcherTest do
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.Block.Reward alias Explorer.Chain.Block.Reward
alias Indexer.{Block, CoinBalance, InternalTransaction, Token, TokenBalance} alias Indexer.Block
alias Indexer.Block.Catchup.Fetcher alias Indexer.Block.Catchup.Fetcher
alias Indexer.Fetcher.{BlockReward, CoinBalance, InternalTransaction, Token, TokenBalance, UncleBlock}
@moduletag capture_log: true @moduletag capture_log: true
@ -48,7 +49,7 @@ defmodule Indexer.Block.Catchup.FetcherTest do
end end
end) end)
Process.register(pid, Block.Uncle.Fetcher) Process.register(pid, UncleBlock)
nephew_hash = block_hash() |> to_string() nephew_hash = block_hash() |> to_string()
uncle_hash = block_hash() |> to_string() uncle_hash = block_hash() |> to_string()
@ -315,7 +316,7 @@ defmodule Indexer.Block.Catchup.FetcherTest do
end end
end) end)
Process.register(pid, Indexer.Block.Reward.Fetcher) Process.register(pid, BlockReward)
assert %{first_block_number: ^block_number, missing_block_count: 1, shrunk: false} = assert %{first_block_number: ^block_number, missing_block_count: 1, shrunk: false} =
Fetcher.task(%Fetcher{ Fetcher.task(%Fetcher{
@ -414,7 +415,7 @@ defmodule Indexer.Block.Catchup.FetcherTest do
end end
end) end)
Process.register(pid, Indexer.Block.Reward.Fetcher) Process.register(pid, BlockReward)
assert %{first_block_number: ^block_number, missing_block_count: 1, shrunk: false} = assert %{first_block_number: ^block_number, missing_block_count: 1, shrunk: false} =
Fetcher.task(%Fetcher{ Fetcher.task(%Fetcher{

@ -1,8 +1,8 @@
defmodule Indexer.SequenceTest do defmodule Indexer.Block.Catchup.SequenceTest do
use ExUnit.Case use ExUnit.Case
alias Indexer.Block.Catchup.Sequence
alias Indexer.Memory.Shrinkable alias Indexer.Memory.Shrinkable
alias Indexer.Sequence
describe "start_link/1" do describe "start_link/1" do
test "without :ranges with :first with positive step pops infinitely" do test "without :ranges with :first with positive step pops infinitely" do

@ -9,8 +9,18 @@ defmodule Indexer.Block.FetcherTest do
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.{Address, Log, Transaction, Wei} alias Explorer.Chain.{Address, Log, Transaction, Wei}
alias Indexer.{CoinBalance, BufferedTask, Code, InternalTransaction, ReplacedTransaction, Token, TokenBalance} alias Indexer.Block.Fetcher
alias Indexer.Block.{Fetcher, Uncle} alias Indexer.BufferedTask
alias Indexer.Fetcher.{
CoinBalance,
ContractCode,
InternalTransaction,
ReplacedTransaction,
Token,
TokenBalance,
UncleBlock
}
@moduletag capture_log: true @moduletag capture_log: true
@ -41,13 +51,13 @@ 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) CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
Code.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)
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)
ReplacedTransaction.Supervisor.Case.start_supervised!() ReplacedTransaction.Supervisor.Case.start_supervised!()
Uncle.Supervisor.Case.start_supervised!( UncleBlock.Supervisor.Case.start_supervised!(
block_fetcher: %Fetcher{json_rpc_named_arguments: json_rpc_named_arguments} block_fetcher: %Fetcher{json_rpc_named_arguments: json_rpc_named_arguments}
) )
@ -226,8 +236,8 @@ defmodule Indexer.Block.FetcherTest do
errors: [] errors: []
}} = result }} = result
wait_for_tasks(InternalTransaction.Fetcher) wait_for_tasks(InternalTransaction)
wait_for_tasks(CoinBalance.Fetcher) wait_for_tasks(CoinBalance)
assert Repo.aggregate(Chain.Block, :count, :hash) == 1 assert Repo.aggregate(Chain.Block, :count, :hash) == 1
assert Repo.aggregate(Address, :count, :hash) == 1 assert Repo.aggregate(Address, :count, :hash) == 1
@ -492,8 +502,8 @@ 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.Fetcher) wait_for_tasks(InternalTransaction)
wait_for_tasks(CoinBalance.Fetcher) wait_for_tasks(CoinBalance)
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
@ -587,8 +597,8 @@ defmodule Indexer.Block.FetcherTest do
errors: [] errors: []
}} = 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.Fetcher) wait_for_tasks(InternalTransaction)
wait_for_tasks(CoinBalance.Fetcher) wait_for_tasks(CoinBalance)
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

@ -6,8 +6,9 @@ defmodule Indexer.Block.Realtime.FetcherTest do
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.{Address, Transaction} alias Explorer.Chain.{Address, Transaction}
alias Indexer.{Sequence, Token, TokenBalance, ReplacedTransaction} alias Indexer.Block.Catchup.Sequence
alias Indexer.Block.{Realtime, Uncle} alias Indexer.Block.Realtime
alias Indexer.Fetcher.{ContractCode, InternalTransaction, ReplacedTransaction, Token, TokenBalance, UncleBlock}
@moduletag capture_log: true @moduletag capture_log: true
@ -50,7 +51,11 @@ defmodule Indexer.Block.Realtime.FetcherTest do
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)
Uncle.Supervisor.Case.start_supervised!( 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)
UncleBlock.Supervisor.Case.start_supervised!(
block_fetcher: %Indexer.Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments} block_fetcher: %Indexer.Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments}
) )
@ -200,11 +205,18 @@ defmodule Indexer.Block.Realtime.FetcherTest do
} }
]} ]}
end) end)
|> expect(:json_rpc, fn [%{method: "trace_block"}, %{method: "trace_block"}] = requests, _options ->
responses = Enum.map(requests, fn %{id: id} -> %{id: id, result: []} end)
{:ok, responses}
end)
|> expect(:json_rpc, 2, fn |> expect(:json_rpc, 2, fn
[
%{id: 0, jsonrpc: "2.0", method: "trace_block", params: ["0x3C365F"]},
%{id: 1, jsonrpc: "2.0", method: "trace_block", params: ["0x3C3660"]}
],
_ ->
{:ok,
[
%{id: 0, jsonrpc: "2.0", result: []},
%{id: 1, jsonrpc: "2.0", result: []}
]}
[ [
%{ %{
id: 0, id: 0,
@ -346,28 +358,22 @@ defmodule Indexer.Block.Realtime.FetcherTest do
id: 0, id: 0,
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_getBalance", method: "eth_getBalance",
params: ["0x11c4469d974f8af5ba9ec99f3c42c07c848c861c", "0x3C365F"]
},
%{
id: 1,
jsonrpc: "2.0",
method: "eth_getBalance",
params: ["0x40b18103537c0f15d5e137dd8ddd019b84949d16", "0x3C365F"] params: ["0x40b18103537c0f15d5e137dd8ddd019b84949d16", "0x3C365F"]
}, },
%{ %{
id: 2, id: 1,
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_getBalance", method: "eth_getBalance",
params: ["0x5ee341ac44d344ade1ca3a771c59b98eb2a77df2", "0x3C365F"] params: ["0x5ee341ac44d344ade1ca3a771c59b98eb2a77df2", "0x3C365F"]
}, },
%{ %{
id: 3, id: 2,
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_getBalance", method: "eth_getBalance",
params: ["0x66c9343c7e8ca673a1fedf9dbf2cd7936dbbf7e3", "0x3C3660"] params: ["0x66c9343c7e8ca673a1fedf9dbf2cd7936dbbf7e3", "0x3C3660"]
}, },
%{ %{
id: 4, id: 3,
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_getBalance", method: "eth_getBalance",
params: ["0x698bf6943bab687b2756394624aa183f434f65da", "0x3C365F"] params: ["0x698bf6943bab687b2756394624aa183f434f65da", "0x3C365F"]
@ -376,11 +382,10 @@ defmodule Indexer.Block.Realtime.FetcherTest do
_ -> _ ->
{:ok, {:ok,
[ [
%{id: 0, jsonrpc: "2.0", result: "0x49e3de5187cf037d127"}, %{id: 0, jsonrpc: "2.0", result: "0x148adc763b603291685"},
%{id: 1, jsonrpc: "2.0", result: "0x148adc763b603291685"}, %{id: 1, jsonrpc: "2.0", result: "0x53474fa377a46000"},
%{id: 2, jsonrpc: "2.0", result: "0x53474fa377a46000"}, %{id: 2, jsonrpc: "2.0", result: "0x53507afe51f28000"},
%{id: 3, jsonrpc: "2.0", result: "0x53507afe51f28000"}, %{id: 3, jsonrpc: "2.0", result: "0x3e1a95d7517dc197108"}
%{id: 4, jsonrpc: "2.0", result: "0x3e1a95d7517dc197108"}
]} ]}
end) end)
end end
@ -391,9 +396,8 @@ defmodule Indexer.Block.Realtime.FetcherTest do
addresses: [ addresses: [
%Address{hash: first_address_hash, fetched_coin_balance_block_number: 3_946_079}, %Address{hash: first_address_hash, fetched_coin_balance_block_number: 3_946_079},
%Address{hash: second_address_hash, fetched_coin_balance_block_number: 3_946_079}, %Address{hash: second_address_hash, fetched_coin_balance_block_number: 3_946_079},
%Address{hash: third_address_hash, fetched_coin_balance_block_number: 3_946_079}, %Address{hash: third_address_hash, fetched_coin_balance_block_number: 3_946_080},
%Address{hash: fourth_address_hash, fetched_coin_balance_block_number: 3_946_080}, %Address{hash: fourth_address_hash, fetched_coin_balance_block_number: 3_946_079}
%Address{hash: fifth_address_hash, fetched_coin_balance_block_number: 3_946_079}
], ],
address_coin_balances: [ address_coin_balances: [
%{ %{
@ -406,26 +410,14 @@ defmodule Indexer.Block.Realtime.FetcherTest do
}, },
%{ %{
address_hash: third_address_hash, address_hash: third_address_hash,
block_number: 3_946_079
},
%{
address_hash: fourth_address_hash,
block_number: 3_946_080 block_number: 3_946_080
}, },
%{ %{
address_hash: fifth_address_hash, address_hash: fourth_address_hash,
block_number: 3_946_079 block_number: 3_946_079
} }
], ],
blocks: [%Chain.Block{number: 3_946_079}, %Chain.Block{number: 3_946_080}], blocks: [%Chain.Block{number: 3_946_079}, %Chain.Block{number: 3_946_080}],
internal_transactions: [
%{index: 0, transaction_hash: transaction_hash},
%{index: 1, transaction_hash: transaction_hash},
%{index: 2, transaction_hash: transaction_hash},
%{index: 3, transaction_hash: transaction_hash},
%{index: 4, transaction_hash: transaction_hash},
%{index: 5, transaction_hash: transaction_hash}
],
transactions: [%Transaction{hash: transaction_hash}] transactions: [%Transaction{hash: transaction_hash}]
}, },
errors: [] errors: []

@ -1,40 +0,0 @@
defmodule Indexer.Block.UtilTest do
use ExUnit.Case
alias Indexer.Block.Util
test "signer/1" do
data = %{
difficulty: 1,
extra_data:
"0xd68301080d846765746886676f312e3130856c696e7578000000000000000000773ab2ca8f47904a14739ad80a75b71d9d29b9fff8b7ecdcb73efffa6f74122f17d304b5dc8e6e5f256c9474dd115c8d4dae31b7a3d409e5c3270f8fde41cd8c00",
gas_limit: 7_753_377,
gas_used: 1_810_195,
hash: "0x7004c895e812c55b0c2be8a46d72ca300a683dc27d1d7917ee7742d4d0359c1f",
logs_bloom:
"0x00000000000000020000000000002000000400000000000000000000000000000000000000000000040000080004000020000010000000000000000000000000000000000000000008000008000000000000000000200000000000000000000000000000020000000000000000000800000000000000804000000010080000000800000000000000000000000000000000000000000000800000000000080000000008000400000000404000000000000000000000000200000000000000000000000002000000000000001002000000000000002000000008000000000020000000000000000000000000000000000000000000000000400000800000000000",
miner_hash: "0x0000000000000000000000000000000000000000",
mix_hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
nonce: "0x0000000000000000",
number: 2_848_394,
parent_hash: "0x20350fc367e19d3865be1ea7da72ab81f8f9941c43ac6bb24a34a0a7caa2f3df",
receipts_root: "0x6ade4ac1079ea50cfadcce2b75ffbe4f9b14bf69b4607bbf1739463076ca6246",
sha3_uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 6437,
state_root: "0x23f63347851bcd109059d007d71e19c4f5e73b7f0862bebcd04458333a004d92",
timestamp: DateTime.from_unix!(1_534_796_040),
total_difficulty: 5_353_647,
transactions: [
"0x7e3bb851fc74a436826d2af6b96e4db9484431811ef0d9c9e78370488d33d4e5",
"0x3976fd1e3d2a715c3cfcfde9bd3210798c26c017b8edb841d319227ecb3322fb",
"0xd8db124005bb8b6fda7b71fd56ac782552a66af58fe843ba3c4930423b87d1d2",
"0x10c1a1ca4d9f4b2bd5b89f7bbcbbc2d69e166fe23662b8db4f6beae0f50ac9fd",
"0xaa58a6545677c796a56b8bc874174c8cfd31a6c6e6ca3a87e086d4f66d52858a"
],
transactions_root: "0xde8d25c0b9b54310128a21601331094b43f910f9f96102869c2e2dca94884bf4",
uncles: []
}
assert Util.signer(data) == "0xfc18cbc391de84dbd87db83b20935d3e89f5dd91"
end
end

@ -1,4 +1,4 @@
defmodule Indexer.Block.Reward.FetcherTest do defmodule Indexer.Fetcher.BlockRewardTest 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
@ -9,8 +9,8 @@ defmodule Indexer.Block.Reward.FetcherTest do
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.{Block, Hash, Wei} alias Explorer.Chain.{Block, Hash, Wei}
alias Indexer.Block.Reward
alias Indexer.BufferedTask alias Indexer.BufferedTask
alias Indexer.Fetcher.BlockReward
@moduletag :capture_log @moduletag :capture_log
@ -37,32 +37,32 @@ defmodule Indexer.Block.Reward.FetcherTest do
describe "init/3" do describe "init/3" do
test "without blocks" do test "without blocks" do
assert [] = Reward.Fetcher.init([], &[&1 | &2], nil) assert [] = BlockReward.init([], &[&1 | &2], nil)
end end
test "with consensus block without reward" do test "with consensus block without reward" do
%Block{number: block_number} = insert(:block) %Block{number: block_number} = insert(:block)
assert [^block_number] = Reward.Fetcher.init([], &[&1 | &2], nil) assert [^block_number] = BlockReward.init([], &[&1 | &2], nil)
end end
test "with consensus block with reward" do test "with consensus block with reward" do
block = insert(:block) block = insert(:block)
insert(:reward, address_hash: block.miner_hash, block_hash: block.hash) insert(:reward, address_hash: block.miner_hash, block_hash: block.hash)
assert [] = Reward.Fetcher.init([], &[&1 | &2], nil) assert [] = BlockReward.init([], &[&1 | &2], nil)
end end
test "with non-consensus block" do test "with non-consensus block" do
insert(:block, consensus: false) insert(:block, consensus: false)
assert [] = Reward.Fetcher.init([], &[&1 | &2], nil) assert [] = BlockReward.init([], &[&1 | &2], nil)
end end
end end
describe "async_fetch/1" do describe "async_fetch/1" do
setup %{json_rpc_named_arguments: json_rpc_named_arguments} do setup %{json_rpc_named_arguments: json_rpc_named_arguments} do
Reward.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) BlockReward.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
block = insert(:block) block = insert(:block)
@ -130,11 +130,11 @@ defmodule Indexer.Block.Reward.FetcherTest do
end end
end) end)
Process.register(pid, Indexer.CoinBalance.Fetcher) Process.register(pid, Indexer.Fetcher.CoinBalance)
assert :ok = Reward.Fetcher.async_fetch([block_number]) assert :ok = BlockReward.async_fetch([block_number])
wait_for_tasks(Reward.Fetcher) wait_for_tasks(BlockReward)
assert count(Chain.Block.Reward) == 1 assert count(Chain.Block.Reward) == 1
assert_receive {:balance_fields, [{^miner_hash_bytes, ^block_number}]}, 500 assert_receive {:balance_fields, [{^miner_hash_bytes, ^block_number}]}, 500
@ -201,11 +201,11 @@ defmodule Indexer.Block.Reward.FetcherTest do
end end
end) end)
Process.register(pid, Indexer.CoinBalance.Fetcher) Process.register(pid, Indexer.Fetcher.CoinBalance)
assert :ok = Reward.Fetcher.async_fetch([block_number]) assert :ok = BlockReward.async_fetch([block_number])
wait_for_tasks(Reward.Fetcher) wait_for_tasks(BlockReward)
assert count(Chain.Block.Reward) == 1 assert count(Chain.Block.Reward) == 1
assert_receive {:balance_fields, [{^miner_hash_bytes, ^block_number}]}, 500 assert_receive {:balance_fields, [{^miner_hash_bytes, ^block_number}]}, 500
@ -256,9 +256,9 @@ defmodule Indexer.Block.Reward.FetcherTest do
} }
end) end)
assert :ok = Reward.Fetcher.async_fetch([block_number]) assert :ok = BlockReward.async_fetch([block_number])
wait_for_tasks(Reward.Fetcher) wait_for_tasks(BlockReward)
assert count(Chain.Block.Reward) == 0 assert count(Chain.Block.Reward) == 0
end end
@ -334,9 +334,9 @@ defmodule Indexer.Block.Reward.FetcherTest do
end end
end) end)
Process.register(pid, Indexer.CoinBalance.Fetcher) Process.register(pid, Indexer.Fetcher.CoinBalance)
assert :ok = Reward.Fetcher.run([block_number], json_rpc_named_arguments) assert :ok = BlockReward.run([block_number], json_rpc_named_arguments)
assert count(Chain.Block.Reward) == 1 assert count(Chain.Block.Reward) == 1
assert count(Chain.Address.CoinBalance) == 1 assert count(Chain.Address.CoinBalance) == 1
@ -422,9 +422,9 @@ defmodule Indexer.Block.Reward.FetcherTest do
end end
end) end)
Process.register(pid, Indexer.CoinBalance.Fetcher) Process.register(pid, Indexer.Fetcher.CoinBalance)
assert :ok = Reward.Fetcher.run([block_number], json_rpc_named_arguments) assert :ok = BlockReward.run([block_number], json_rpc_named_arguments)
assert count(Chain.Block.Reward) == 2 assert count(Chain.Block.Reward) == 2
assert count(Chain.Address.CoinBalance) == 2 assert count(Chain.Address.CoinBalance) == 2
@ -504,9 +504,9 @@ defmodule Indexer.Block.Reward.FetcherTest do
end end
end) end)
Process.register(pid, Indexer.CoinBalance.Fetcher) Process.register(pid, Indexer.Fetcher.CoinBalance)
assert :ok = Reward.Fetcher.run([block_number], json_rpc_named_arguments) assert :ok = BlockReward.run([block_number], json_rpc_named_arguments)
assert count(Chain.Block.Reward) == 1 assert count(Chain.Block.Reward) == 1
assert count(Chain.Address.CoinBalance) == 1 assert count(Chain.Address.CoinBalance) == 1
@ -565,7 +565,7 @@ defmodule Indexer.Block.Reward.FetcherTest do
} }
end) end)
assert :ok = Reward.Fetcher.run([block_number], json_rpc_named_arguments) assert :ok = BlockReward.run([block_number], json_rpc_named_arguments)
assert count(Chain.Block.Reward) == 0 assert count(Chain.Block.Reward) == 0
assert count(Chain.Address.CoinBalance) == 0 assert count(Chain.Address.CoinBalance) == 0
@ -639,10 +639,10 @@ defmodule Indexer.Block.Reward.FetcherTest do
end end
end) end)
Process.register(pid, Indexer.CoinBalance.Fetcher) Process.register(pid, Indexer.Fetcher.CoinBalance)
assert {:retry, [^error_block_number]} = assert {:retry, [^error_block_number]} =
Reward.Fetcher.run([block_number, error_block_number], json_rpc_named_arguments) BlockReward.run([block_number, error_block_number], json_rpc_named_arguments)
assert count(Chain.Block.Reward) == 1 assert count(Chain.Block.Reward) == 1
assert count(Chain.Address.CoinBalance) == 1 assert count(Chain.Address.CoinBalance) == 1

@ -1,4 +1,4 @@
defmodule Indexer.CoinBalance.OnDemandFetcherTest do defmodule Indexer.Fetcher.CoinBalanceOnDemandTest 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
@ -9,7 +9,7 @@ defmodule Indexer.CoinBalance.OnDemandFetcherTest do
alias Explorer.Chain.Events.Subscriber alias Explorer.Chain.Events.Subscriber
alias Explorer.Chain.Wei alias Explorer.Chain.Wei
alias Explorer.Counters.AverageBlockTime alias Explorer.Counters.AverageBlockTime
alias Indexer.CoinBalance.OnDemandFetcher alias Indexer.Fetcher.CoinBalanceOnDemand
@moduletag :capture_log @moduletag :capture_log
@ -24,7 +24,7 @@ defmodule Indexer.CoinBalance.OnDemandFetcherTest do
start_supervised!({Task.Supervisor, name: Indexer.TaskSupervisor}) start_supervised!({Task.Supervisor, name: Indexer.TaskSupervisor})
start_supervised!(AverageBlockTime) start_supervised!(AverageBlockTime)
start_supervised!({OnDemandFetcher, [mocked_json_rpc_named_arguments, [name: OnDemandFetcher]]}) start_supervised!({CoinBalanceOnDemand, [mocked_json_rpc_named_arguments, [name: CoinBalanceOnDemand]]})
Application.put_env(:explorer, AverageBlockTime, enabled: true) Application.put_env(:explorer, AverageBlockTime, enabled: true)
@ -41,10 +41,9 @@ defmodule Indexer.CoinBalance.OnDemandFetcherTest do
# we space these very far apart so that we know it will consider the 0th block stale (it calculates how far # we space these very far apart so that we know it will consider the 0th block stale (it calculates how far
# back we'd need to go to get 24 hours in the past) # back we'd need to go to get 24 hours in the past)
block_0 = insert(:block, number: 0, timestamp: Timex.shift(now, hours: -50)) insert(:block, number: 0, timestamp: Timex.shift(now, hours: -50))
AverageBlockTime.average_block_time(block_0) insert(:block, number: 1, timestamp: now)
block_1 = insert(:block, number: 1, timestamp: now) AverageBlockTime.refresh()
AverageBlockTime.average_block_time(block_1)
stale_address = insert(:address, fetched_coin_balance: 1, fetched_coin_balance_block_number: 0) stale_address = insert(:address, fetched_coin_balance: 1, fetched_coin_balance_block_number: 0)
current_address = insert(:address, fetched_coin_balance: 1, fetched_coin_balance_block_number: 1) current_address = insert(:address, fetched_coin_balance: 1, fetched_coin_balance_block_number: 1)
@ -58,25 +57,25 @@ defmodule Indexer.CoinBalance.OnDemandFetcherTest do
test "treats all addresses as current if the average block time is disabled", %{stale_address: address} do test "treats all addresses as current if the average block time is disabled", %{stale_address: address} do
Application.put_env(:explorer, AverageBlockTime, enabled: false) Application.put_env(:explorer, AverageBlockTime, enabled: false)
assert OnDemandFetcher.trigger_fetch(address) == :current assert CoinBalanceOnDemand.trigger_fetch(address) == :current
end end
test "if the address has not been fetched within the last 24 hours of blocks it is considered stale", %{ test "if the address has not been fetched within the last 24 hours of blocks it is considered stale", %{
stale_address: address stale_address: address
} do } do
assert OnDemandFetcher.trigger_fetch(address) == {:stale, 1} assert CoinBalanceOnDemand.trigger_fetch(address) == {:stale, 1}
end end
test "if the address has been fetched within the last 24 hours of blocks it is considered current", %{ test "if the address has been fetched within the last 24 hours of blocks it is considered current", %{
current_address: address current_address: address
} do } do
assert OnDemandFetcher.trigger_fetch(address) == :current assert CoinBalanceOnDemand.trigger_fetch(address) == :current
end end
test "if there is an unfetched balance within the window for an address, it is considered pending", %{ test "if there is an unfetched balance within the window for an address, it is considered pending", %{
pending_address: pending_address pending_address: pending_address
} do } do
assert OnDemandFetcher.trigger_fetch(pending_address) == {:pending, 2} assert CoinBalanceOnDemand.trigger_fetch(pending_address) == {:pending, 2}
end end
end end
@ -89,10 +88,9 @@ defmodule Indexer.CoinBalance.OnDemandFetcherTest do
# we space these very far apart so that we know it will consider the 0th block stale (it calculates how far # we space these very far apart so that we know it will consider the 0th block stale (it calculates how far
# back we'd need to go to get 24 hours in the past) # back we'd need to go to get 24 hours in the past)
block_0 = insert(:block, number: 0, timestamp: Timex.shift(now, hours: -50)) insert(:block, number: 0, timestamp: Timex.shift(now, hours: -50))
AverageBlockTime.average_block_time(block_0) insert(:block, number: 1, timestamp: now)
block_1 = insert(:block, number: 1, timestamp: now) AverageBlockTime.refresh()
AverageBlockTime.average_block_time(block_1)
:ok :ok
end end
@ -113,7 +111,7 @@ defmodule Indexer.CoinBalance.OnDemandFetcherTest do
{:ok, [%{id: id, jsonrpc: "2.0", result: "0x02"}]} {:ok, [%{id: id, jsonrpc: "2.0", result: "0x02"}]}
end) end)
assert OnDemandFetcher.trigger_fetch(address) == {:stale, 1} assert CoinBalanceOnDemand.trigger_fetch(address) == {:stale, 1}
{:ok, expected_wei} = Wei.cast(2) {:ok, expected_wei} = Wei.cast(2)
@ -140,7 +138,7 @@ defmodule Indexer.CoinBalance.OnDemandFetcherTest do
{:ok, [%{id: id, jsonrpc: "2.0", result: "0x02"}]} {:ok, [%{id: id, jsonrpc: "2.0", result: "0x02"}]}
end) end)
assert OnDemandFetcher.trigger_fetch(address) == {:pending, 2} assert CoinBalanceOnDemand.trigger_fetch(address) == {:pending, 2}
{:ok, expected_wei} = Wei.cast(2) {:ok, expected_wei} = Wei.cast(2)

@ -1,4 +1,4 @@
defmodule Indexer.CoinBalance.FetcherTest do defmodule Indexer.Fetcher.CoinBalanceTest 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.CoinBalance.FetcherTest do
import Mox import Mox
alias Explorer.Chain.{Address, Hash, Wei} alias Explorer.Chain.{Address, Hash, Wei}
alias Indexer.CoinBalance alias Indexer.Fetcher.CoinBalance
@moduletag :capture_log @moduletag :capture_log
@ -182,7 +182,7 @@ defmodule Indexer.CoinBalance.FetcherTest do
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
assert :ok = CoinBalance.Fetcher.async_fetch_balances([%{address_hash: hash, block_number: block_number}]) assert :ok = CoinBalance.async_fetch_balances([%{address_hash: hash, block_number: block_number}])
address = address =
wait(fn -> wait(fn ->
@ -254,7 +254,7 @@ defmodule Indexer.CoinBalance.FetcherTest do
{:ok, %Hash{bytes: address_hash_bytes}} = Hash.Address.cast(hash_data) {:ok, %Hash{bytes: address_hash_bytes}} = Hash.Address.cast(hash_data)
entries = Enum.map(block_quantities, &{address_hash_bytes, quantity_to_integer(&1)}) entries = Enum.map(block_quantities, &{address_hash_bytes, quantity_to_integer(&1)})
case CoinBalance.Fetcher.run(entries, json_rpc_named_arguments) do case CoinBalance.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))
@ -309,7 +309,7 @@ defmodule Indexer.CoinBalance.FetcherTest do
{:ok, [%{id: id, error: %{code: 1, message: "Bad"}}]} {:ok, [%{id: id, error: %{code: 1, message: "Bad"}}]}
end) end)
assert {:retry, ^entries} = CoinBalance.Fetcher.run(entries, json_rpc_named_arguments) assert {:retry, ^entries} = CoinBalance.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
@ -320,7 +320,7 @@ defmodule Indexer.CoinBalance.FetcherTest do
{:ok, [%{id: id, result: "0x1"}]} {:ok, [%{id: id, result: "0x1"}]}
end) end)
assert :ok = CoinBalance.Fetcher.run(entries, json_rpc_named_arguments) assert :ok = CoinBalance.run(entries, json_rpc_named_arguments)
end end
test "retries retries fetch errors if all imported", %{json_rpc_named_arguments: json_rpc_named_arguments} do test "retries retries fetch errors if all imported", %{json_rpc_named_arguments: json_rpc_named_arguments} do
@ -360,7 +360,7 @@ defmodule Indexer.CoinBalance.FetcherTest do
end) end)
assert {:retry, [{^address_hash_bytes, ^bad_block_number}]} = assert {:retry, [{^address_hash_bytes, ^bad_block_number}]} =
CoinBalance.Fetcher.run( CoinBalance.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
) )

@ -1,4 +1,4 @@
defmodule Indexer.Code.FetcherTest do defmodule Indexer.Fetcher.ContractCodeTest do
use EthereumJSONRPC.Case, async: false use EthereumJSONRPC.Case, async: false
use Explorer.DataCase use Explorer.DataCase
@ -7,7 +7,7 @@ defmodule Indexer.Code.FetcherTest do
import Mox import Mox
alias Explorer.Chain.{Address, Transaction} alias Explorer.Chain.{Address, Transaction}
alias Indexer.Code alias Indexer.Fetcher.ContractCode
@moduletag :capture_log @moduletag :capture_log
@ -83,10 +83,10 @@ defmodule Indexer.Code.FetcherTest do
insert(:address, hash: address) insert(:address, hash: address)
insert(:transaction, hash: hash, created_contract_address_hash: address) insert(:transaction, hash: hash, created_contract_address_hash: address)
Code.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)
assert :ok = assert :ok =
Code.Fetcher.async_fetch([ ContractCode.async_fetch([
%{created_contract_address_hash: address, block_number: block_number, hash: hash} %{created_contract_address_hash: address, block_number: block_number, hash: hash}
]) ])

@ -1,4 +1,4 @@
defmodule Indexer.InternalTransaction.FetcherTest do defmodule Indexer.Fetcher.InternalTransactionTest do
use EthereumJSONRPC.Case, async: false use EthereumJSONRPC.Case, async: false
use Explorer.DataCase use Explorer.DataCase
@ -6,8 +6,7 @@ defmodule Indexer.InternalTransaction.FetcherTest do
import Mox import Mox
alias Explorer.Chain.{Address, Hash, Transaction} alias Explorer.Chain.{Address, Hash, Transaction}
alias Indexer.Fetcher.{CoinBalance, InternalTransaction, PendingTransaction}
alias Indexer.{CoinBalance, 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.
@ -17,7 +16,7 @@ defmodule Indexer.InternalTransaction.FetcherTest do
@moduletag [capture_log: true, no_geth: true] @moduletag [capture_log: true, no_geth: true]
test "does not try to fetch pending transactions from Indexer.PendingTransaction.Fetcher", %{ test "does not try to fetch pending transactions from Indexer.Fetcher.PendingTransaction", %{
json_rpc_named_arguments: json_rpc_named_arguments json_rpc_named_arguments: json_rpc_named_arguments
} do } do
if json_rpc_named_arguments[:transport] == EthereumJSONRPC.Mox do if json_rpc_named_arguments[:transport] == EthereumJSONRPC.Mox do
@ -71,9 +70,9 @@ defmodule Indexer.InternalTransaction.FetcherTest do
end) end)
hash_strings = hash_strings =
InternalTransaction.Fetcher.init([], fn hash_string, acc -> [hash_string | acc] end, json_rpc_named_arguments) InternalTransaction.init([], fn hash_string, acc -> [hash_string | acc] end, json_rpc_named_arguments)
assert :ok = InternalTransaction.Fetcher.run(hash_strings, json_rpc_named_arguments) assert :ok = InternalTransaction.run(hash_strings, json_rpc_named_arguments)
end end
@tag :no_geth @tag :no_geth
@ -102,9 +101,9 @@ defmodule Indexer.InternalTransaction.FetcherTest do
block_number = 1_000_006 block_number = 1_000_006
insert(:block, number: block_number) insert(:block, number: block_number)
assert :ok = InternalTransaction.Fetcher.run([block_number], json_rpc_named_arguments) assert :ok = InternalTransaction.run([block_number], json_rpc_named_arguments)
assert InternalTransaction.Fetcher.init( assert InternalTransaction.init(
[], [],
fn block_number, acc -> [block_number | acc] end, fn block_number, acc -> [block_number | acc] end,
json_rpc_named_arguments json_rpc_named_arguments
@ -115,7 +114,7 @@ defmodule Indexer.InternalTransaction.FetcherTest do
test "does not buffer pending transactions", %{json_rpc_named_arguments: json_rpc_named_arguments} do test "does not buffer pending transactions", %{json_rpc_named_arguments: json_rpc_named_arguments} do
insert(:transaction) insert(:transaction)
assert InternalTransaction.Fetcher.init( assert InternalTransaction.init(
[], [],
fn hash_string, acc -> [hash_string | acc] end, fn hash_string, acc -> [hash_string | acc] end,
json_rpc_named_arguments json_rpc_named_arguments
@ -133,7 +132,7 @@ defmodule Indexer.InternalTransaction.FetcherTest do
|> insert() |> insert()
|> with_block(block) |> with_block(block)
assert InternalTransaction.Fetcher.init( assert InternalTransaction.init(
[], [],
fn hash_string, acc -> [hash_string | acc] end, fn hash_string, acc -> [hash_string | acc] end,
json_rpc_named_arguments json_rpc_named_arguments
@ -148,7 +147,7 @@ defmodule Indexer.InternalTransaction.FetcherTest do
|> insert() |> insert()
|> with_block(internal_transactions_indexed_at: DateTime.utc_now()) |> with_block(internal_transactions_indexed_at: DateTime.utc_now())
assert InternalTransaction.Fetcher.init( assert InternalTransaction.init(
[], [],
fn hash_string, acc -> [hash_string | acc] end, fn hash_string, acc -> [hash_string | acc] end,
json_rpc_named_arguments json_rpc_named_arguments
@ -161,7 +160,7 @@ defmodule Indexer.InternalTransaction.FetcherTest do
} do } do
block = insert(:block) block = insert(:block)
assert InternalTransaction.Fetcher.init( assert InternalTransaction.init(
[], [],
fn block_number, acc -> [block_number | acc] end, fn block_number, acc -> [block_number | acc] end,
json_rpc_named_arguments json_rpc_named_arguments
@ -174,7 +173,7 @@ defmodule Indexer.InternalTransaction.FetcherTest do
} do } do
insert(:block, internal_transactions_indexed_at: DateTime.utc_now()) insert(:block, internal_transactions_indexed_at: DateTime.utc_now())
assert InternalTransaction.Fetcher.init( assert InternalTransaction.init(
[], [],
fn block_number, acc -> [block_number | acc] end, fn block_number, acc -> [block_number | acc] end,
json_rpc_named_arguments json_rpc_named_arguments
@ -198,7 +197,7 @@ defmodule Indexer.InternalTransaction.FetcherTest do
log = log =
capture_log(fn -> capture_log(fn ->
InternalTransaction.Fetcher.run( InternalTransaction.run(
[ [
{1, bytes, 0}, {1, bytes, 0},
{1, bytes, 0} {1, bytes, 0}
@ -276,7 +275,7 @@ defmodule Indexer.InternalTransaction.FetcherTest do
|> with_block() |> with_block()
:ok = :ok =
InternalTransaction.Fetcher.run( InternalTransaction.run(
[ [
{7_202_692, bytes, 0} {7_202_692, bytes, 0}
], ],
@ -305,7 +304,7 @@ defmodule Indexer.InternalTransaction.FetcherTest do
%Transaction{hash: %Hash{bytes: bytes}} = %Transaction{hash: %Hash{bytes: bytes}} =
insert(:transaction, hash: "0x0000000000000000000000000000000000000000000000000000000000000001") insert(:transaction, hash: "0x0000000000000000000000000000000000000000000000000000000000000001")
assert InternalTransaction.Fetcher.run( assert InternalTransaction.run(
[ [
{1, bytes, 0}, {1, bytes, 0},
{1, bytes, 0} {1, bytes, 0}

@ -1,4 +1,4 @@
defmodule Indexer.PendingTransactionFetcherTest do defmodule Indexer.Fetcher.PendingTransactionTest do
# `async: false` due to use of named GenServer # `async: false` due to use of named GenServer
use EthereumJSONRPC.Case, async: false use EthereumJSONRPC.Case, async: false
use Explorer.DataCase use Explorer.DataCase
@ -6,7 +6,7 @@ defmodule Indexer.PendingTransactionFetcherTest do
import Mox import Mox
alias Explorer.Chain.Transaction alias Explorer.Chain.Transaction
alias Indexer.PendingTransaction alias Indexer.Fetcher.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.

@ -1,8 +1,8 @@
defmodule Indexer.ReplacedTransaction.FetcherTest do defmodule Indexer.Fetcher.ReplacedTransactionTest do
use Explorer.DataCase use Explorer.DataCase
alias Explorer.Chain.{Transaction} alias Explorer.Chain.{Transaction}
alias Indexer.ReplacedTransaction alias Indexer.Fetcher.ReplacedTransaction
@moduletag :capture_log @moduletag :capture_log
@ -71,7 +71,7 @@ defmodule Indexer.ReplacedTransaction.FetcherTest do
ReplacedTransaction.Supervisor.Case.start_supervised!() ReplacedTransaction.Supervisor.Case.start_supervised!()
assert :ok = assert :ok =
ReplacedTransaction.Fetcher.async_fetch([ ReplacedTransaction.async_fetch([
%{ %{
block_hash: mined_transaction.block_hash, block_hash: mined_transaction.block_hash,
nonce: mined_transaction.nonce, nonce: mined_transaction.nonce,
@ -160,7 +160,7 @@ defmodule Indexer.ReplacedTransaction.FetcherTest do
ReplacedTransaction.Supervisor.Case.start_supervised!() ReplacedTransaction.Supervisor.Case.start_supervised!()
# assert :ok = # assert :ok =
# ReplacedTransaction.Fetcher.async_fetch([ # ReplacedTransaction.async_fetch([
# %{ # %{
# block_hash: mined_transaction.block_hash, # block_hash: mined_transaction.block_hash,
# nonce: mined_transaction.nonce, # nonce: mined_transaction.nonce,

@ -1,11 +1,11 @@
defmodule Indexer.TokenBalance.FetcherTest do defmodule Indexer.Fetcher.TokenBalanceTest do
use EthereumJSONRPC.Case use EthereumJSONRPC.Case
use Explorer.DataCase use Explorer.DataCase
import Mox import Mox
alias Explorer.Chain.{Address, Hash} alias Explorer.Chain.{Address, Hash}
alias Indexer.TokenBalance alias Indexer.Fetcher.TokenBalance
@moduletag :capture_log @moduletag :capture_log
@ -22,7 +22,7 @@ defmodule Indexer.TokenBalance.FetcherTest do
insert(:token_balance, value_fetched_at: DateTime.utc_now()) insert(:token_balance, value_fetched_at: DateTime.utc_now())
assert TokenBalance.Fetcher.init([], &[&1 | &2], nil) == [ assert TokenBalance.init([], &[&1 | &2], nil) == [
{address_hash_bytes, token_contract_address_hash_bytes, block_number, 0} {address_hash_bytes, token_contract_address_hash_bytes, block_number, 0}
] ]
end end
@ -57,7 +57,7 @@ defmodule Indexer.TokenBalance.FetcherTest do
end end
) )
assert TokenBalance.Fetcher.run( assert TokenBalance.run(
[{address_hash_bytes, token_contract_address_hash_bytes, block_number, 0}], [{address_hash_bytes, token_contract_address_hash_bytes, block_number, 0}],
nil nil
) == :ok ) == :ok
@ -109,13 +109,13 @@ defmodule Indexer.TokenBalance.FetcherTest do
} }
] ]
assert TokenBalance.Fetcher.run(token_balances, nil) == :ok assert TokenBalance.run(token_balances, nil) == :ok
end end
end end
describe "import_token_balances/1" do describe "import_token_balances/1" do
test "ignores when it receives a empty list" do test "ignores when it receives a empty list" do
assert TokenBalance.Fetcher.import_token_balances([]) == :ok assert TokenBalance.import_token_balances([]) == :ok
end end
test "returns :error when the token balances has invalid data" do test "returns :error when the token balances has invalid data" do
@ -131,7 +131,7 @@ defmodule Indexer.TokenBalance.FetcherTest do
} }
] ]
assert TokenBalance.Fetcher.import_token_balances(token_balances_params) == :error assert TokenBalance.import_token_balances(token_balances_params) == :error
end end
test "insert the missing address, import the token balances and return :ok when the address does not exist yet" do test "insert the missing address, import the token balances and return :ok when the address does not exist yet" do
@ -147,7 +147,7 @@ defmodule Indexer.TokenBalance.FetcherTest do
] ]
{:ok, address_hash} = Explorer.Chain.string_to_address_hash("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") {:ok, address_hash} = Explorer.Chain.string_to_address_hash("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
assert TokenBalance.Fetcher.import_token_balances(token_balances_params) == :ok assert TokenBalance.import_token_balances(token_balances_params) == :ok
assert {:ok, _} = Explorer.Chain.hash_to_address(address_hash) assert {:ok, _} = Explorer.Chain.hash_to_address(address_hash)
end end
@ -169,7 +169,7 @@ defmodule Indexer.TokenBalance.FetcherTest do
} }
] ]
assert TokenBalance.Fetcher.import_token_balances(token_balances_params) == :ok assert TokenBalance.import_token_balances(token_balances_params) == :ok
end end
end end
end end

@ -1,4 +1,4 @@
defmodule Indexer.Token.FetcherTest do defmodule Indexer.Fetcher.TokenTest do
use EthereumJSONRPC.Case use EthereumJSONRPC.Case
use Explorer.DataCase use Explorer.DataCase
@ -6,7 +6,7 @@ defmodule Indexer.Token.FetcherTest do
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.Token alias Explorer.Chain.Token
alias Indexer.Token.Fetcher alias Indexer.Fetcher.Token, as: TokenFetcher
setup :verify_on_exit! setup :verify_on_exit!
@ -15,7 +15,7 @@ defmodule Indexer.Token.FetcherTest do
insert(:token, cataloged: true) insert(:token, cataloged: true)
%Token{contract_address_hash: uncatalog_address} = insert(:token, cataloged: false) %Token{contract_address_hash: uncatalog_address} = insert(:token, cataloged: false)
assert Fetcher.init([], &[&1 | &2], json_rpc_named_arguments) == [uncatalog_address] assert TokenFetcher.init([], &[&1 | &2], json_rpc_named_arguments) == [uncatalog_address]
end end
end end
@ -61,7 +61,7 @@ defmodule Indexer.Token.FetcherTest do
end end
) )
assert Fetcher.run([contract_address_hash], json_rpc_named_arguments) == :ok assert TokenFetcher.run([contract_address_hash], json_rpc_named_arguments) == :ok
expected_supply = Decimal.new(1_000_000_000_000_000_000) expected_supply = Decimal.new(1_000_000_000_000_000_000)

@ -1,11 +1,11 @@
defmodule Indexer.Token.MetadataUpdaterTest do defmodule Indexer.Fetcher.TokenUpdaterTest do
use Explorer.DataCase use Explorer.DataCase
import Mox import Mox
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.Token alias Explorer.Chain.Token
alias Indexer.Token.MetadataUpdater alias Indexer.Fetcher.TokenUpdater
setup :verify_on_exit! setup :verify_on_exit!
setup :set_mox_global setup :set_mox_global
@ -49,7 +49,7 @@ defmodule Indexer.Token.MetadataUpdaterTest do
end end
) )
pid = start_supervised!({MetadataUpdater, %{update_interval: 1}}) pid = start_supervised!({TokenUpdater, [%{update_interval: 1}, []]})
wait_for_results(fn -> wait_for_results(fn ->
updated = Repo.one!(from(t in Token, where: t.cataloged == true and not is_nil(t.name), limit: 1)) updated = Repo.one!(from(t in Token, where: t.cataloged == true and not is_nil(t.name), limit: 1))
@ -102,7 +102,7 @@ defmodule Indexer.Token.MetadataUpdaterTest do
end end
) )
MetadataUpdater.update_metadata([token.contract_address_hash]) TokenUpdater.update_metadata([token.contract_address_hash])
expected_supply = Decimal.new(1_000_000_000_000_000_000) expected_supply = Decimal.new(1_000_000_000_000_000_000)

@ -1,4 +1,4 @@
defmodule Indexer.Block.Uncle.FetcherTest do defmodule Indexer.Fetcher.UncleBlockTest 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
@ -6,6 +6,7 @@ defmodule Indexer.Block.Uncle.FetcherTest do
alias Explorer.Chain alias Explorer.Chain
alias Indexer.Block alias Indexer.Block
alias Indexer.Fetcher.UncleBlock
import Mox import Mox
@ -32,10 +33,10 @@ defmodule Indexer.Block.Uncle.FetcherTest do
describe "child_spec/1" do describe "child_spec/1" do
test "raises ArgumentError is `json_rpc_named_arguments is not provided" do test "raises ArgumentError is `json_rpc_named_arguments is not provided" do
assert_raise ArgumentError, assert_raise ArgumentError,
":json_rpc_named_arguments must be provided to `Elixir.Indexer.Block.Uncle.Fetcher.child_spec " <> ":json_rpc_named_arguments must be provided to `Elixir.Indexer.Fetcher.UncleBlock.child_spec " <>
"to allow for json_rpc calls when running.", "to allow for json_rpc calls when running.",
fn -> fn ->
start_supervised({Block.Uncle.Fetcher, [[], []]}) start_supervised({UncleBlock, [[], []]})
end end
end end
end end
@ -104,7 +105,7 @@ defmodule Indexer.Block.Uncle.FetcherTest do
]} ]}
end) end)
Block.Uncle.Supervisor.Case.start_supervised!( UncleBlock.Supervisor.Case.start_supervised!(
block_fetcher: %Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments} block_fetcher: %Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments}
) )

@ -8,11 +8,10 @@ defmodule Indexer.Temporary.AddressesWithoutCodeTest do
alias Explorer.Repo alias Explorer.Repo
alias Explorer.Chain.{Address, Transaction} alias Explorer.Chain.{Address, Transaction}
alias Indexer.Temporary.AddressesWithoutCode.Supervisor
alias Indexer.CoinBalance
alias Indexer.Block.Fetcher alias Indexer.Block.Fetcher
alias Indexer.Block.Realtime.Fetcher, as: RealtimeFetcher alias Indexer.Block.Realtime.Fetcher, as: RealtimeFetcher
alias Indexer.{CoinBalance, Code, InternalTransaction, ReplacedTransaction, Token, TokenBalance} alias Indexer.Fetcher.{CoinBalance, ContractCode, InternalTransaction, ReplacedTransaction, Token, TokenBalance}
alias Indexer.Temporary.AddressesWithoutCode.Supervisor
@moduletag capture_log: true @moduletag capture_log: true
@ -23,7 +22,7 @@ defmodule Indexer.Temporary.AddressesWithoutCodeTest do
describe "run/1" do describe "run/1" 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) CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
Code.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)
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)

@ -8,8 +8,8 @@ defmodule Indexer.Temporary.FailedCreatedAddressesTest do
alias Explorer.Repo alias Explorer.Repo
alias Explorer.Chain.Address alias Explorer.Chain.Address
alias Indexer.Fetcher.CoinBalance
alias Indexer.Temporary.FailedCreatedAddresses.Supervisor alias Indexer.Temporary.FailedCreatedAddresses.Supervisor
alias Indexer.CoinBalance
@moduletag capture_log: true @moduletag capture_log: true

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save