diff --git a/CHANGELOG.md b/CHANGELOG.md index 799bef2872..0effc628ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,9 +9,13 @@ ### Fixes - [#2688](https://github.com/poanetwork/blockscout/pull/2688) - fix try it out section +- [#2701](https://github.com/poanetwork/blockscout/pull/2701) - Exclude nonconsensus blocks from avg block time calculation by default +- [#2693](https://github.com/poanetwork/blockscout/pull/2693) - remove non consensus internal transactions +- [#2687](https://github.com/poanetwork/blockscout/pull/2687) - remove non-consensus token transfers, logs when inserting new consensus blocks - [#2684](https://github.com/poanetwork/blockscout/pull/2684) - do not filter pending logs - [#2682](https://github.com/poanetwork/blockscout/pull/2682) - Use Task.start instead of Task.async in caches - [#2671](https://github.com/poanetwork/blockscout/pull/2671) - fixed buttons color at smart contract section +- [#2691](https://github.com/poanetwork/blockscout/pull/2691) - fix exchange rate websocket update for Rootstock ### Chore @@ -51,6 +55,7 @@ - [#2468](https://github.com/poanetwork/blockscout/pull/2468) - fix confirmations for non consensus blocks ### Chore +- [#2662](https://github.com/poanetwork/blockscout/pull/2662) - fetch coin gecko id based on the coin symbol - [#2646](https://github.com/poanetwork/blockscout/pull/2646) - Added Xerom to list of Additional Chains using BlockScout - [#2634](https://github.com/poanetwork/blockscout/pull/2634) - add Lukso to networks dropdown - [#2617](https://github.com/poanetwork/blockscout/pull/2617) - skip cache update if there are no blocks inserted diff --git a/apps/block_scout_web/lib/block_scout_web/notifier.ex b/apps/block_scout_web/lib/block_scout_web/notifier.ex index aa47163c98..7c07c8524e 100644 --- a/apps/block_scout_web/lib/block_scout_web/notifier.ex +++ b/apps/block_scout_web/lib/block_scout_web/notifier.ex @@ -7,6 +7,7 @@ defmodule BlockScoutWeb.Notifier do alias BlockScoutWeb.{AddressContractVerificationView, Endpoint} alias Explorer.{Chain, Market, Repo} alias Explorer.Chain.{Address, InternalTransaction, Transaction} + alias Explorer.Chain.Supply.RSK alias Explorer.Counters.AverageBlockTime alias Explorer.ExchangeRates.Token alias Explorer.SmartContract.{Solidity.CodeCompiler, Solidity.CompilerVersion} @@ -76,8 +77,17 @@ defmodule BlockScoutWeb.Notifier do data -> data end + exchange_rate_with_available_supply = + case Application.get_env(:explorer, :supply) do + RSK -> + %{exchange_rate | available_supply: nil, market_cap_usd: RSK.market_cap(exchange_rate)} + + _ -> + exchange_rate + end + Endpoint.broadcast("exchange_rate:new_rate", "new_rate", %{ - exchange_rate: exchange_rate, + exchange_rate: exchange_rate_with_available_supply, market_history_data: Enum.map(market_history_data, fn day -> Map.take(day, [:closing_price, :date]) end) }) end diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index 056c3a991c..8a264eaf33 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -14,7 +14,7 @@ config :explorer, System.get_env("ALLOWED_EVM_VERSIONS") || "homestead,tangerineWhistle,spuriousDragon,byzantium,constantinople,petersburg,default", include_uncles_in_average_block_time: - if(System.get_env("UNCLES_IN_AVERAGE_BLOCK_TIME") == "false", do: false, else: true), + if(System.get_env("UNCLES_IN_AVERAGE_BLOCK_TIME") == "true", do: true, else: false), healthy_blocks_period: System.get_env("HEALTHY_BLOCKS_PERIOD") || :timer.minutes(5) average_block_period = @@ -38,8 +38,6 @@ config :explorer, Explorer.Chain.Cache.BlockNumber, ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false), global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5)) -config :explorer, Explorer.ExchangeRates.Source.CoinGecko, coin_id: System.get_env("COIN_GECKO_ID", "poa-network") - 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 diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index 209d5d2fa6..1c58446292 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex @@ -9,7 +9,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do alias Ecto.Adapters.SQL alias Ecto.{Changeset, Multi, Repo} - alias Explorer.Chain.{Address, Block, Hash, Import, InternalTransaction, Transaction} + alias Explorer.Chain.{Address, Block, Hash, Import, InternalTransaction, Log, TokenTransfer, Transaction} alias Explorer.Chain.Block.Reward alias Explorer.Chain.Import.Runner alias Explorer.Chain.Import.Runner.Address.CurrentTokenBalances @@ -58,6 +58,31 @@ defmodule Explorer.Chain.Import.Runner.Blocks do where_forked: where_forked }) end) + |> Multi.run(:lose_consensus, fn repo, _ -> + lose_consensus(repo, ordered_consensus_block_numbers, insert_options) + end) + |> Multi.run(:lose_invalid_neighbour_consensus, fn repo, _ -> + lose_invalid_neighbour_consensus(repo, where_invalid_neighbour, insert_options) + end) + |> Multi.run(:remove_nonconsensus_data, fn repo, + %{ + lose_consensus: lost_consensus_blocks, + lose_invalid_neighbour_consensus: lost_consensus_neighbours + } -> + nonconsensus_block_numbers = + (lost_consensus_blocks ++ lost_consensus_neighbours) + |> Enum.map(fn %{number: number} -> + number + end) + |> Enum.sort() + |> Enum.dedup() + + remove_nonconsensus_data( + repo, + nonconsensus_block_numbers, + insert_options + ) + end) # MUST be after `:derive_transaction_forks`, which depends on values in `transactions` table |> Multi.run(:fork_transactions, fn repo, _ -> fork_transactions(%{ @@ -67,12 +92,6 @@ defmodule Explorer.Chain.Import.Runner.Blocks do where_forked: where_forked }) end) - |> Multi.run(:lose_consensus, fn repo, _ -> - lose_consensus(repo, ordered_consensus_block_numbers, insert_options) - end) - |> Multi.run(:lose_invalid_neighbour_consensus, fn repo, _ -> - lose_invalid_neighbour_consensus(repo, where_invalid_neighbour, insert_options) - end) |> Multi.run(:delete_address_token_balances, fn repo, _ -> delete_address_token_balances(repo, ordered_consensus_block_numbers, insert_options) end) @@ -342,6 +361,136 @@ defmodule Explorer.Chain.Import.Runner.Blocks do end end + defp remove_nonconsensus_data( + repo, + nonconsensus_block_numbers, + insert_options + ) do + with {:ok, deleted_token_transfers} <- + remove_nonconsensus_token_transfers(repo, nonconsensus_block_numbers, insert_options), + {:ok, deleted_logs} <- remove_nonconsensus_logs(repo, nonconsensus_block_numbers, insert_options), + {:ok, deleted_internal_transactions} <- + remove_nonconsensus_internal_transactions(repo, nonconsensus_block_numbers, insert_options) do + {:ok, + %{ + token_transfers: deleted_token_transfers, + logs: deleted_logs, + internal_transactions: deleted_internal_transactions + }} + end + end + + defp remove_nonconsensus_token_transfers(repo, nonconsensus_block_numbers, %{timeout: timeout}) do + ordered_token_transfers = + from(token_transfer in TokenTransfer, + where: token_transfer.block_number in ^nonconsensus_block_numbers, + select: map(token_transfer, [:transaction_hash, :log_index]), + # Enforce TokenTransfer ShareLocks order (see docs: sharelocks.md) + order_by: [ + token_transfer.transaction_hash, + token_transfer.log_index + ], + lock: "FOR UPDATE" + ) + + query = + from(token_transfer in TokenTransfer, + select: map(token_transfer, [:transaction_hash, :log_index]), + inner_join: ordered_token_transfer in subquery(ordered_token_transfers), + on: + ordered_token_transfer.transaction_hash == + token_transfer.transaction_hash and + ordered_token_transfer.log_index == token_transfer.log_index + ) + + try do + {_count, deleted_token_transfers} = repo.delete_all(query, timeout: timeout) + + {:ok, deleted_token_transfers} + rescue + postgrex_error in Postgrex.Error -> + {:error, %{exception: postgrex_error, block_numbers: nonconsensus_block_numbers}} + end + end + + defp remove_nonconsensus_internal_transactions(repo, nonconsensus_block_numbers, %{timeout: timeout}) do + transaction_query = + from(transaction in Transaction, + where: transaction.block_number in ^nonconsensus_block_numbers, + select: map(transaction, [:hash]), + order_by: transaction.hash + ) + + ordered_internal_transactions = + from(internal_transaction in InternalTransaction, + inner_join: transaction in subquery(transaction_query), + on: internal_transaction.transaction_hash == transaction.hash, + select: map(internal_transaction, [:transaction_hash, :index]), + # Enforce InternalTransaction ShareLocks order (see docs: sharelocks.md) + order_by: [ + internal_transaction.transaction_hash, + internal_transaction.index + ], + lock: "FOR UPDATE OF i0" + ) + + query = + from(internal_transaction in InternalTransaction, + select: map(internal_transaction, [:transaction_hash, :index]), + inner_join: ordered_internal_transaction in subquery(ordered_internal_transactions), + on: + ordered_internal_transaction.transaction_hash == internal_transaction.transaction_hash and + ordered_internal_transaction.index == internal_transaction.index + ) + + try do + {_count, deleted_internal_transactions} = repo.delete_all(query, timeout: timeout) + + {:ok, deleted_internal_transactions} + rescue + postgrex_error in Postgrex.Error -> + {:error, %{exception: postgrex_error, block_numbers: nonconsensus_block_numbers}} + end + end + + defp remove_nonconsensus_logs(repo, nonconsensus_block_numbers, %{timeout: timeout}) do + transaction_query = + from(transaction in Transaction, + where: transaction.block_number in ^nonconsensus_block_numbers, + select: map(transaction, [:hash]), + order_by: transaction.hash + ) + + ordered_logs = + from(log in Log, + inner_join: transaction in subquery(transaction_query), + on: log.transaction_hash == transaction.hash, + select: map(log, [:transaction_hash, :index]), + # Enforce Log ShareLocks order (see docs: sharelocks.md) + order_by: [ + log.transaction_hash, + log.index + ], + lock: "FOR UPDATE OF l0" + ) + + query = + from(log in Log, + select: map(log, [:transaction_hash, :index]), + inner_join: ordered_log in subquery(ordered_logs), + on: ordered_log.transaction_hash == log.transaction_hash and ordered_log.index == log.index + ) + + try do + {_count, deleted_logs} = repo.delete_all(query, timeout: timeout) + + {:ok, deleted_logs} + rescue + postgrex_error in Postgrex.Error -> + {:error, %{exception: postgrex_error, block_numbers: nonconsensus_block_numbers}} + end + end + defp delete_address_token_balances(_, [], _), do: {:ok, []} defp delete_address_token_balances(repo, ordered_consensus_block_numbers, %{timeout: timeout}) do diff --git a/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex b/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex index 95ecafb046..9d4cfba3f4 100644 --- a/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex +++ b/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex @@ -44,15 +44,41 @@ defmodule Explorer.ExchangeRates.Source.CoinGecko do @impl Source def source_url do - "#{base_url()}/coins/#{coin_id()}" + {:ok, id} = coin_id() + + "#{base_url()}/coins/#{id}" end defp base_url do config(:base_url) || "https://api.coingecko.com/api/v3" end - defp coin_id do - Application.get_env(:explorer, __MODULE__)[:coin_id] + def coin_id do + url = "#{base_url()}/coins/list" + + symbol = String.downcase(Explorer.coin()) + + case HTTPoison.get(url, headers()) do + {:ok, %Response{body: body, status_code: 200}} -> + data = decode_json(body) + + symbol_data = + Enum.find(data, fn item -> + item["symbol"] == symbol + end) + + if symbol_data do + {:ok, symbol_data["id"]} + else + {:error, :not_found} + end + + {:ok, %Response{body: body, status_code: status_code}} when status_code in 400..499 -> + {:error, decode_json(body)["error"]} + + {:error, %Error{reason: reason}} -> + {:error, reason} + end end defp get_btc_price(currency \\ "usd") do diff --git a/apps/explorer/priv/repo/migrations/20190910170703_create_indexes_for_block_number_in_token_transfers_and_transactions.exs b/apps/explorer/priv/repo/migrations/20190910170703_create_indexes_for_block_number_in_token_transfers_and_transactions.exs new file mode 100644 index 0000000000..b718224622 --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20190910170703_create_indexes_for_block_number_in_token_transfers_and_transactions.exs @@ -0,0 +1,7 @@ +defmodule Explorer.Repo.Migrations.CreateIndexesForBlockNumberInTokenTransfersAndTransactions do + use Ecto.Migration + + def change do + create_if_not_exists(index(:token_transfers, [:block_number])) + end +end diff --git a/apps/explorer/test/explorer/chain/import/runner/blocks_test.exs b/apps/explorer/test/explorer/chain/import/runner/blocks_test.exs index 63110cba40..5a5d547068 100644 --- a/apps/explorer/test/explorer/chain/import/runner/blocks_test.exs +++ b/apps/explorer/test/explorer/chain/import/runner/blocks_test.exs @@ -7,13 +7,14 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do alias Ecto.Multi alias Explorer.Chain.Import.Runner.{Blocks, Transactions} - alias Explorer.Chain.{Address, Block, Transaction} + alias Explorer.Chain.{Address, Block, InternalTransaction, Log, Transaction, TokenTransfer} alias Explorer.Chain alias Explorer.Repo describe "run/1" do setup do - block = insert(:block, consensus: true) + miner = insert(:address) + block = params_for(:block, consensus: true, miner_hash: miner.hash) timestamp = DateTime.utc_now() options = %{timestamps: %{inserted_at: timestamp, updated_at: timestamp}} @@ -22,9 +23,11 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do end test "derive_transaction_forks replaces hash on conflicting (uncle_hash, index)", %{ - consensus_block: %Block{hash: block_hash, miner_hash: miner_hash, number: block_number} = consensus_block, + consensus_block: %{hash: block_hash, miner_hash: miner_hash, number: block_number}, options: options } do + consensus_block = insert(:block, %{hash: block_hash, number: block_number}) + transaction = :transaction |> insert() @@ -81,7 +84,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do end test "delete_address_current_token_balances deletes rows with matching block number when consensus is true", - %{consensus_block: %Block{number: block_number} = block, options: options} do + %{consensus_block: %{number: block_number} = block, options: options} do %Address.CurrentTokenBalance{address_hash: address_hash, token_contract_address_hash: token_contract_address_hash} = insert(:address_current_token_balance, block_number: block_number) @@ -98,7 +101,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do end test "delete_address_current_token_balances does not delete rows with matching block number when consensus is false", - %{consensus_block: %Block{number: block_number} = block, options: options} do + %{consensus_block: %{number: block_number} = block, options: options} do %Address.CurrentTokenBalance{} = insert(:address_current_token_balance, block_number: block_number) count = 1 @@ -113,8 +116,93 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do assert count(Address.CurrentTokenBalance) == count end + test "remove_nonconsensus_data deletes token transfer rows with matching block number when new consensus block is inserted", + %{consensus_block: %{number: block_number} = block, options: options} do + insert(:block, number: block_number, consensus: true) + + %TokenTransfer{transaction_hash: transaction_hash, log_index: log_index} = + insert(:token_transfer, block_number: block_number, transaction: insert(:transaction)) + + assert count(TokenTransfer) == 1 + + assert {:ok, + %{ + remove_nonconsensus_data: %{ + token_transfers: [ + %{transaction_hash: ^transaction_hash, log_index: ^log_index} + ] + } + }} = run_block_consensus_change(block, true, options) + + assert count(TokenTransfer) == 0 + end + + test "remove_nonconsensus_data does not delete token transfer rows with matching block number when new consensus block wasn't inserted", + %{consensus_block: %{number: block_number} = block, options: options} do + insert(:token_transfer, block_number: block_number, transaction: insert(:transaction)) + + count = 1 + + assert count(TokenTransfer) == count + + assert {:ok, + %{ + remove_nonconsensus_data: %{ + token_transfers: [] + } + }} = run_block_consensus_change(block, false, options) + + assert count(TokenTransfer) == count + end + + test "remove_nonconsensus_data deletes nonconsensus logs", %{ + consensus_block: %{number: block_number} = block, + options: options + } do + old_block = insert(:block, number: block_number, consensus: true) + forked_transaction = :transaction |> insert() |> with_block(old_block) + %Log{transaction_hash: hash, index: index} = insert(:log, transaction: forked_transaction) + + assert count(Log) == 1 + + assert {:ok, + %{ + remove_nonconsensus_data: %{ + logs: [ + %{transaction_hash: ^hash, index: ^index} + ] + } + }} = run_block_consensus_change(block, true, options) + + assert count(Log) == 0 + end + + test "remove_nonconsensus_data deletes nonconsensus internal transactions", %{ + consensus_block: %{number: block_number} = block, + options: options + } do + old_block = insert(:block, number: block_number, consensus: true) + forked_transaction = :transaction |> insert() |> with_block(old_block) + + %InternalTransaction{index: index, transaction_hash: hash} = + insert(:internal_transaction, index: 0, transaction: forked_transaction) + + assert count(InternalTransaction) == 1 + + assert {:ok, + %{ + remove_nonconsensus_data: %{ + internal_transactions: [ + %{transaction_hash: ^hash, index: ^index} + ] + } + }} = run_block_consensus_change(block, true, options) + + assert count(InternalTransaction) == 0 + end + test "derive_address_current_token_balances inserts rows if there is an address_token_balance left for the rows deleted by delete_address_current_token_balances", - %{consensus_block: %Block{number: block_number} = block, options: options} do + %{consensus_block: %{number: block_number} = block, options: options} do token = insert(:token) token_contract_address_hash = token.contract_address_hash @@ -172,7 +260,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do end test "a non-holder reverting to a holder increases the holder_count", - %{consensus_block: %Block{hash: block_hash, miner_hash: miner_hash, number: block_number}, options: options} do + %{consensus_block: %{hash: block_hash, miner_hash: miner_hash, number: block_number}, options: options} do token = insert(:token) token_contract_address_hash = token.contract_address_hash @@ -204,7 +292,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do end test "a holder reverting to a non-holder decreases the holder_count", - %{consensus_block: %Block{hash: block_hash, miner_hash: miner_hash, number: block_number}, options: options} do + %{consensus_block: %{hash: block_hash, miner_hash: miner_hash, number: block_number}, options: options} do token = insert(:token) token_contract_address_hash = token.contract_address_hash @@ -236,7 +324,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do end test "a non-holder becoming and a holder becoming while a holder becomes a non-holder cancels out and holder_count does not change", - %{consensus_block: %Block{number: block_number} = block, options: options} do + %{consensus_block: %{number: block_number} = block, options: options} do token = insert(:token) token_contract_address_hash = token.contract_address_hash @@ -262,7 +350,8 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do # Regression test for https://github.com/poanetwork/blockscout/issues/1644 test "discards neighbouring blocks if they aren't related to the current one because of reorg and/or import timeout", - %{consensus_block: %Block{number: block_number, hash: block_hash, miner_hash: miner_hash}, options: options} do + %{consensus_block: %{number: block_number, hash: block_hash, miner_hash: miner_hash}, options: options} do + insert(:block, %{number: block_number, hash: block_hash}) old_block1 = params_for(:block, miner_hash: miner_hash, parent_hash: block_hash, number: block_number + 1) new_block1 = params_for(:block, miner_hash: miner_hash, parent_hash: block_hash, number: block_number + 1) @@ -286,7 +375,8 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do # Regression test for https://github.com/poanetwork/blockscout/issues/1911 test "forces block refetch if transaction is re-collated in a different block", - %{consensus_block: %Block{number: block_number, hash: block_hash, miner_hash: miner_hash}, options: options} do + %{consensus_block: %{number: block_number, hash: block_hash, miner_hash: miner_hash}, options: options} do + insert(:block, %{number: block_number, hash: block_hash}) new_block1 = params_for(:block, miner_hash: miner_hash, parent_hash: block_hash, number: block_number + 1) new_block2 = params_for(:block, miner_hash: miner_hash, parent_hash: new_block1.hash, number: block_number + 2) @@ -365,7 +455,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do end defp run_block_consensus_change( - %Block{hash: block_hash, miner_hash: miner_hash, number: block_number}, + %{hash: block_hash, miner_hash: miner_hash, number: block_number}, consensus, options ) do diff --git a/apps/explorer/test/explorer/exchange_rates/source/coin_gecko_test.exs b/apps/explorer/test/explorer/exchange_rates/source/coin_gecko_test.exs index b4b3313d6c..76d210cd02 100644 --- a/apps/explorer/test/explorer/exchange_rates/source/coin_gecko_test.exs +++ b/apps/explorer/test/explorer/exchange_rates/source/coin_gecko_test.exs @@ -18,6 +18,46 @@ defmodule Explorer.ExchangeRates.Source.CoinGeckoTest do } """ + @coins_list """ + [ + { + "id": "poa-network", + "symbol": "poa", + "name": "POA Network" + }, + { + "id": "poc-chain", + "symbol": "pocc", + "name": "POC Chain" + }, + { + "id": "pocket-arena", + "symbol": "poc", + "name": "Pocket Arena" + }, + { + "id": "ethereum", + "symbol": "eth", + "name": "Ethereum" + }, + { + "id": "rootstock", + "symbol": "rbtc", + "name": "Rootstock RSK" + }, + { + "id": "dai", + "symbol": "dai", + "name": "Dai" + }, + { + "id": "callisto", + "symbol": "clo", + "name": "Callisto Network" + } + ] + """ + describe "format_data/1" do setup do bypass = Bypass.open() @@ -62,4 +102,65 @@ defmodule Explorer.ExchangeRates.Source.CoinGeckoTest do assert [] = CoinGecko.format_data(bad_data) end end + + describe "coin_id/0" do + setup do + bypass = Bypass.open() + Application.put_env(:explorer, CoinGecko, base_url: "http://localhost:#{bypass.port}") + + on_exit(fn -> + Application.put_env(:explorer, :coin, "POA") + end) + + {:ok, bypass: bypass} + end + + test "fetches poa coin id by default", %{bypass: bypass} do + Bypass.expect(bypass, "GET", "/coins/list", fn conn -> + Conn.resp(conn, 200, @coins_list) + end) + + assert CoinGecko.coin_id() == {:ok, "poa-network"} + end + + test "fetches eth coin id", %{bypass: bypass} do + Application.put_env(:explorer, :coin, "ETH") + + Bypass.expect(bypass, "GET", "/coins/list", fn conn -> + Conn.resp(conn, 200, @coins_list) + end) + + assert CoinGecko.coin_id() == {:ok, "ethereum"} + end + + test "fetches rbtc coin id", %{bypass: bypass} do + Application.put_env(:explorer, :coin, "RBTC") + + Bypass.expect(bypass, "GET", "/coins/list", fn conn -> + Conn.resp(conn, 200, @coins_list) + end) + + assert CoinGecko.coin_id() == {:ok, "rootstock"} + end + + test "fetches dai coin id", %{bypass: bypass} do + Application.put_env(:explorer, :coin, "DAI") + + Bypass.expect(bypass, "GET", "/coins/list", fn conn -> + Conn.resp(conn, 200, @coins_list) + end) + + assert CoinGecko.coin_id() == {:ok, "dai"} + end + + test "fetches callisto coin id", %{bypass: bypass} do + Application.put_env(:explorer, :coin, "CLO") + + Bypass.expect(bypass, "GET", "/coins/list", fn conn -> + Conn.resp(conn, 200, @coins_list) + end) + + assert CoinGecko.coin_id() == {:ok, "callisto"} + end + end end diff --git a/docs/env-variables.md b/docs/env-variables.md index 7e023ef621..503689d091 100644 --- a/docs/env-variables.md +++ b/docs/env-variables.md @@ -56,6 +56,7 @@ $ export NETWORK=POA | `SUPPORTED_CHAINS` | | Array of supported chains that displays in the footer and in the chains dropdown. This var was introduced in this PR [#1900](https://github.com/poanetwork/blockscout/pull/1900) and looks like an array of JSON objects. | (empty) | v2.0.0+ | | | | `BLOCK_COUNT_CACHE_PERIOD ` | | time to live of cache in seconds. This var was introduced in [#1876](https://github.com/poanetwork/blockscout/pull/1876) | 600 | v2.0.0+ | | | | `ALLOWED_EVM_VERSIONS ` | | the comma-separated list of allowed EVM versions for contracts verification. This var was introduced in [#1964](https://github.com/poanetwork/blockscout/pull/1964) | "homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg" | v2.0.0+ | | | +| `UNCLES_IN_AVERAGE_BLOCK_TIME` | Include or exclude nonconsensus blocks in avg block time calculation. Exclude if `false`. | false | v2.0.1+ | | | | `AVERAGE_BLOCK_CACHE_PERIOD` | | Update of average block cache, in seconds | 30 minutes | v2.0.2+ | | | `MARKET_HISTORY_CACHE_PERIOD` | | Update of market history cache, in seconds | 6 hours | v2.0.2+ | | | `DISABLE_WEBAPP` | | If `true`, endpoints to webapp are hidden (compile-time) | `false` | v2.0.3+ | :white_check_mark: | | @@ -65,6 +66,6 @@ $ export NETWORK=POA | `WEBAPP_URL` | | Link to web application instance, e.g. `http://host/path` | (empty) | v2.0.3+ | | | | `API_URL` | | Link to API instance, e.g. `http://host/path` | (empty) | v2.0.3+ | | | | `CHAIN_SPEC_PATH` | | Chain specification path (absolute file system path or url) to import block emission reward ranges and genesis account balances from | (empty) | v2.0.4+ | | | -| `COIN_GECKO_ID` | | CoinGecko coin id required for fetching an exchange rate | poa-network | v2.0.4+ | | | +| `COIN_GECKO_ID` | | CoinGecko coin id required for fetching an exchange rate | poa-network | v2.0.4+ | | master | | `EMISSION_FORMAT` | | Should be set to `POA` if you have block emission indentical to POA Network. This env var is used only if `CHAIN_SPEC_PATH` is set | `STANDARD` | v2.0.4+ | | | | `REWARDS_CONTRACT_ADDRESS` | | Emission rewards contract address. This env var is used only if `EMISSION_FORMAT` is set to `POA` | `0xeca443e8e1ab29971a45a9c57a6a9875701698a5` | v2.0.4+ | | |