From decfc08a54e3b11057450b0251d9a8c2ea960936 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 3 Sep 2019 12:46:33 +0300 Subject: [PATCH 01/24] fetch coin gecko id based on coin symbol Coin Gecko provides API with all listed coins. We can use this API to find coin id instead of setting it by hand. --- .../exchange_rates/source/coin_gecko.ex | 32 ++++++++++++++-- .../exchange_rates/source/coin_gecko_test.exs | 37 +++++++++++++++++++ docs/env-variables.md | 1 - 3 files changed, 66 insertions(+), 4 deletions(-) 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..5a6199acb2 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 + {:errpr, :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/test/explorer/exchange_rates/source/coin_gecko_test.exs b/apps/explorer/test/explorer/exchange_rates/source/coin_gecko_test.exs index b4b3313d6c..3072099cbc 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,26 @@ 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" + } + ] + """ + describe "format_data/1" do setup do bypass = Bypass.open() @@ -62,4 +82,21 @@ 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}") + + {:ok, bypass: bypass} + end + + test "fetches coin id", %{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 + end end diff --git a/docs/env-variables.md b/docs/env-variables.md index dd01cbe26f..39f90f6336 100644 --- a/docs/env-variables.md +++ b/docs/env-variables.md @@ -65,4 +65,3 @@ $ 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) | master | | | -| `COIN_GECKO_ID` | | CoinGecko coin id required for fetching an exchange rate | poa-network | master | | | From 39c01bc8a2b44b2fe5bedd9d6f43ad131ca8d9b3 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 3 Sep 2019 12:49:13 +0300 Subject: [PATCH 02/24] add CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca60257372..7000f890fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - [#2538](https://github.com/poanetwork/blockscout/pull/2538) - fetch the last not empty coin balance records ### 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 From 213395ec32cd1d8201bd849aa94399f1cc425b7f Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 3 Sep 2019 12:50:29 +0300 Subject: [PATCH 03/24] remove config entry --- apps/explorer/config/config.exs | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index 10e8a66e82..9923625359 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -31,8 +31,6 @@ config :explorer, Explorer.ChainSpec.GenesisData, enabled: false, chain_spec_pat config :explorer, Explorer.Chain.Cache.BlockNumber, enabled: true -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 From b1ac8c69ef165380e2f368f9d7401cc5445e129d Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Fri, 6 Sep 2019 11:38:50 +0300 Subject: [PATCH 04/24] add test for all supported chains --- .../exchange_rates/source/coin_gecko_test.exs | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) 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 3072099cbc..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 @@ -34,6 +34,26 @@ defmodule Explorer.ExchangeRates.Source.CoinGeckoTest do "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" } ] """ @@ -88,15 +108,59 @@ defmodule Explorer.ExchangeRates.Source.CoinGeckoTest 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 coin id", %{bypass: bypass} do + 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 From d7f7ad64cc856bbc0ff9656c4a9109a7b4963ada Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Fri, 6 Sep 2019 12:15:25 +0300 Subject: [PATCH 05/24] fix typo --- apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5a6199acb2..9d4cfba3f4 100644 --- a/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex +++ b/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex @@ -70,7 +70,7 @@ defmodule Explorer.ExchangeRates.Source.CoinGecko do if symbol_data do {:ok, symbol_data["id"]} else - {:errpr, :not_found} + {:error, :not_found} end {:ok, %Response{body: body, status_code: status_code}} when status_code in 400..499 -> From 5aa8d5c456241bba041f00cbb23a6dcb37ae0149 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 10 Sep 2019 12:07:16 +0300 Subject: [PATCH 06/24] remove nonconsensus token transfers --- .../explorer/chain/import/runner/blocks.ex | 55 ++++++++++++++- .../chain/import/runner/blocks_test.exs | 68 +++++++++++++++---- 2 files changed, 110 insertions(+), 13 deletions(-) diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index 209d5d2fa6..3c949270cf 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, Transaction, TokenTransfer} alias Explorer.Chain.Block.Reward alias Explorer.Chain.Import.Runner alias Explorer.Chain.Import.Runner.Address.CurrentTokenBalances @@ -73,6 +73,21 @@ defmodule Explorer.Chain.Import.Runner.Blocks do |> 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 + |> Kernel.++(lost_consensus_neighbours) + |> Enum.map(fn %{number: number} -> + number + end) + |> Enum.sort() + + remove_nonconsensus_data(repo, nonconsensus_block_numbers, 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 +357,44 @@ 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) do + {:ok, %{token_transfers: deleted_token_transfers}} + 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]), + 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 delete_address_token_balances(_, [], _), do: {:ok, []} defp delete_address_token_balances(repo, ordered_consensus_block_numbers, %{timeout: timeout}) do 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..f1ebaa4c77 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, 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,47 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do assert count(Address.CurrentTokenBalance) == count end + test "remove_nonconsensus_data deletes 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 "delete_token_transfers does not delete rows with matching block number when consensus is false", + %{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 "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 +214,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 +246,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 +278,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 +304,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 +329,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 +409,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 From c195428634d9d2f917ee4f21f1dc0fde36023b62 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 10 Sep 2019 13:04:15 +0300 Subject: [PATCH 07/24] remove nonconsensus logs --- .../explorer/chain/import/runner/blocks.ex | 79 +++++++++++++++---- .../chain/import/runner/blocks_test.exs | 28 ++++++- 2 files changed, 88 insertions(+), 19 deletions(-) diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index 3c949270cf..5c4c42d898 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, TokenTransfer} + 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,15 +58,6 @@ defmodule Explorer.Chain.Import.Runner.Blocks do where_forked: where_forked }) end) - # MUST be after `:derive_transaction_forks`, which depends on values in `transactions` table - |> Multi.run(:fork_transactions, fn repo, _ -> - fork_transactions(%{ - repo: repo, - timeout: options[Runner.Transactions.option_key()][:timeout] || Runner.Transactions.timeout(), - timestamps: timestamps, - where_forked: where_forked - }) - end) |> Multi.run(:lose_consensus, fn repo, _ -> lose_consensus(repo, ordered_consensus_block_numbers, insert_options) end) @@ -86,7 +77,20 @@ defmodule Explorer.Chain.Import.Runner.Blocks do end) |> Enum.sort() - remove_nonconsensus_data(repo, nonconsensus_block_numbers, insert_options) + 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(%{ + repo: repo, + timeout: options[Runner.Transactions.option_key()][:timeout] || Runner.Transactions.timeout(), + timestamps: timestamps, + where_forked: where_forked + }) end) |> Multi.run(:delete_address_token_balances, fn repo, _ -> delete_address_token_balances(repo, ordered_consensus_block_numbers, insert_options) @@ -357,10 +361,15 @@ defmodule Explorer.Chain.Import.Runner.Blocks do end end - defp remove_nonconsensus_data(repo, nonconsensus_block_numbers, insert_options) do + 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) do - {:ok, %{token_transfers: 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) do + {:ok, %{token_transfers: deleted_token_transfers, logs: deleted_logs}} end end @@ -381,8 +390,8 @@ defmodule Explorer.Chain.Import.Runner.Blocks do 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.transaction_hash == + token_transfer.transaction_hash and ordered_token_transfer.log_index == token_transfer.log_index ) @@ -395,6 +404,44 @@ defmodule Explorer.Chain.Import.Runner.Blocks do {: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]), + order_by: [ + log.transaction_hash, + log.index + ], + lock: "FOR UPDATE" + ) + + 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/test/explorer/chain/import/runner/blocks_test.exs b/apps/explorer/test/explorer/chain/import/runner/blocks_test.exs index f1ebaa4c77..459363839b 100644 --- a/apps/explorer/test/explorer/chain/import/runner/blocks_test.exs +++ b/apps/explorer/test/explorer/chain/import/runner/blocks_test.exs @@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do alias Ecto.Multi alias Explorer.Chain.Import.Runner.{Blocks, Transactions} - alias Explorer.Chain.{Address, Block, Transaction, TokenTransfer} + alias Explorer.Chain.{Address, Block, Log, Transaction, TokenTransfer} alias Explorer.Chain alias Explorer.Repo @@ -116,7 +116,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do assert count(Address.CurrentTokenBalance) == count end - test "remove_nonconsensus_data deletes rows with matching block number when new consensus block is inserted", + 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) @@ -137,7 +137,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do assert count(TokenTransfer) == 0 end - test "delete_token_transfers does not delete rows with matching block number when consensus is false", + 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)) @@ -155,6 +155,28 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do 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 "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: %{number: block_number} = block, options: options} do token = insert(:token) From ab655103f60ccce8427224e5649d576b9671ba29 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 10 Sep 2019 13:11:13 +0300 Subject: [PATCH 08/24] use existing forked transactions query --- .../lib/explorer/chain/import/runner/blocks.ex | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index 5c4c42d898..cbf7532ca2 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex @@ -79,7 +79,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do remove_nonconsensus_data( repo, - nonconsensus_block_numbers, + %{nonconsensus_block_numbers: nonconsensus_block_numbers, forked_transactions_query: where_forked}, insert_options ) end) @@ -363,12 +363,15 @@ defmodule Explorer.Chain.Import.Runner.Blocks do defp remove_nonconsensus_data( repo, - nonconsensus_block_numbers, + %{ + nonconsensus_block_numbers: nonconsensus_block_numbers, + forked_transactions_query: forked_transactions_query + }, 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) do + {:ok, deleted_logs} <- remove_nonconsensus_logs(repo, forked_transactions_query, insert_options) do {:ok, %{token_transfers: deleted_token_transfers, logs: deleted_logs}} end end @@ -405,11 +408,9 @@ defmodule Explorer.Chain.Import.Runner.Blocks do end end - defp remove_nonconsensus_logs(repo, nonconsensus_block_numbers, %{timeout: timeout}) do + defp remove_nonconsensus_logs(repo, forked_transactions_query, %{timeout: timeout}) do transaction_query = - from(transaction in Transaction, - where: transaction.block_number in ^nonconsensus_block_numbers, - select: map(transaction, [:hash]), + from(transaction in subquery(forked_transactions_query), order_by: transaction.hash ) @@ -438,7 +439,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do {:ok, deleted_logs} rescue postgrex_error in Postgrex.Error -> - {:error, %{exception: postgrex_error, block_numbers: nonconsensus_block_numbers}} + {:error, %{exception: postgrex_error, forked_transactions_query: forked_transactions_query}} end end From c038511cf2c99f244f4502d2c3491e748aaae89c Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 10 Sep 2019 13:58:00 +0300 Subject: [PATCH 09/24] use query across all inserted blocks --- .../lib/explorer/chain/import/runner/blocks.ex | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index cbf7532ca2..5c4c42d898 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex @@ -79,7 +79,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do remove_nonconsensus_data( repo, - %{nonconsensus_block_numbers: nonconsensus_block_numbers, forked_transactions_query: where_forked}, + nonconsensus_block_numbers, insert_options ) end) @@ -363,15 +363,12 @@ defmodule Explorer.Chain.Import.Runner.Blocks do defp remove_nonconsensus_data( repo, - %{ - nonconsensus_block_numbers: nonconsensus_block_numbers, - forked_transactions_query: forked_transactions_query - }, + 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, forked_transactions_query, insert_options) do + {:ok, deleted_logs} <- remove_nonconsensus_logs(repo, nonconsensus_block_numbers, insert_options) do {:ok, %{token_transfers: deleted_token_transfers, logs: deleted_logs}} end end @@ -408,9 +405,11 @@ defmodule Explorer.Chain.Import.Runner.Blocks do end end - defp remove_nonconsensus_logs(repo, forked_transactions_query, %{timeout: timeout}) do + defp remove_nonconsensus_logs(repo, nonconsensus_block_numbers, %{timeout: timeout}) do transaction_query = - from(transaction in subquery(forked_transactions_query), + from(transaction in Transaction, + where: transaction.block_number in ^nonconsensus_block_numbers, + select: map(transaction, [:hash]), order_by: transaction.hash ) @@ -439,7 +438,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do {:ok, deleted_logs} rescue postgrex_error in Postgrex.Error -> - {:error, %{exception: postgrex_error, forked_transactions_query: forked_transactions_query}} + {:error, %{exception: postgrex_error, block_numbers: nonconsensus_block_numbers}} end end From 9f04a12d31fa52035b1908fc3a64c5aab7252a19 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 10 Sep 2019 14:38:59 +0300 Subject: [PATCH 10/24] fix CR issues --- apps/explorer/lib/explorer/chain/import/runner/blocks.ex | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index 5c4c42d898..08ad720a0f 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex @@ -70,8 +70,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do lose_invalid_neighbour_consensus: lost_consensus_neighbours } -> nonconsensus_block_numbers = - lost_consensus_blocks - |> Kernel.++(lost_consensus_neighbours) + (lost_consensus_blocks ++ lost_consensus_neighbours) |> Enum.map(fn %{number: number} -> number end) @@ -378,6 +377,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do 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 @@ -418,11 +418,12 @@ defmodule Explorer.Chain.Import.Runner.Blocks do 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" + lock: "FOR UPDATE OF l0" ) query = From ddfec17f604c3e8e752be8ddabdfe1dc391411f8 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 10 Sep 2019 14:40:09 +0300 Subject: [PATCH 11/24] add CHANGELOG entry --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 343301eb65..f942ada294 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,14 @@ ## Current ### Features -- [#2679](https://github.com/poanetwork/blockscout/pull/2679) - added fixed height for card chain blocks and card chain transactions +- [#2679](https://github.com/poanetwork/blockscout/pull/2679) - added fixed height for card chain blocks and card chain transactions - [#2678](https://github.com/poanetwork/blockscout/pull/2678) - fixed dashboard banner height bug -- [#2672](https://github.com/poanetwork/blockscout/pull/2672) - added new theme for xUSDT +- [#2672](https://github.com/poanetwork/blockscout/pull/2672) - added new theme for xUSDT - [#2663](https://github.com/poanetwork/blockscout/pull/2663) - Fetch address counters in parallel ### Fixes - [#2682](https://github.com/poanetwork/blockscout/pull/2682) - Use Task.start instead of Task.async in caches +- [#2687](https://github.com/poanetwork/blockscout/pull/2687) - remove non-consensus token transfers, logs when inserting new consensus blocks ### Chore From e569c5a7987de95b910a6393d17d12e32a6e0015 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 10 Sep 2019 20:10:06 +0300 Subject: [PATCH 12/24] add block_number index --- ...r_block_number_in_token_transfers_and_transactions.exs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 apps/explorer/priv/repo/migrations/20190910170703_create_indexes_for_block_number_in_token_transfers_and_transactions.exs 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..ac15f632d5 --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20190910170703_create_indexes_for_block_number_in_token_transfers_and_transactions.exs @@ -0,0 +1,8 @@ +defmodule Explorer.Repo.Migrations.CreateIndexesForBlockNumberInTokenTransfersAndTransactions do + use Ecto.Migration + + def change do + create_if_not_exists(index(:token_transfers, [:block_number])) + create_if_not_exists(index(:transactions, [:block_number])) + end +end From 71ee060f3f1d77222eea2ea21f3deb323c4c56b5 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 10 Sep 2019 20:19:55 +0300 Subject: [PATCH 13/24] remove transaction index creation --- ...exes_for_block_number_in_token_transfers_and_transactions.exs | 1 - 1 file changed, 1 deletion(-) 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 index ac15f632d5..b718224622 100644 --- 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 @@ -3,6 +3,5 @@ defmodule Explorer.Repo.Migrations.CreateIndexesForBlockNumberInTokenTransfersAn def change do create_if_not_exists(index(:token_transfers, [:block_number])) - create_if_not_exists(index(:transactions, [:block_number])) end end From a883e4ac68f351a5f7c98d4300b89326dc6dacd2 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Wed, 11 Sep 2019 15:20:16 +0300 Subject: [PATCH 14/24] deduplicate numbers --- apps/explorer/lib/explorer/chain/import/runner/blocks.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index 08ad720a0f..aa80e6c251 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex @@ -75,6 +75,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do number end) |> Enum.sort() + |> Enum.uniq() remove_nonconsensus_data( repo, From b674fa675e943ed888aa212b10a6ddd859922cdd Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Wed, 11 Sep 2019 16:08:23 +0300 Subject: [PATCH 15/24] Update blocks.ex --- apps/explorer/lib/explorer/chain/import/runner/blocks.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index aa80e6c251..825a533743 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex @@ -75,7 +75,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do number end) |> Enum.sort() - |> Enum.uniq() + |> Enum.dedup() remove_nonconsensus_data( repo, From fe7115b0e270b5018028ccaf513630dc448b518d Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Wed, 11 Sep 2019 16:11:10 +0300 Subject: [PATCH 16/24] fix exchange rate websocket update for Rootstock Rootstock has custom logic for market cap calculation that uses data from DB. This PR add required feilds to exchange_rate when sending it through a web socket. --- apps/block_scout_web/lib/block_scout_web/notifier.ex | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) 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..03e46cf38b 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: RSK.circulating(), 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 From df7c043d6a9c45959e2d83358b764e41bf9a7b7b Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Wed, 11 Sep 2019 16:14:51 +0300 Subject: [PATCH 17/24] add CHANGELOG entry --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c85224762..9084f2de1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Features - [#2665](https://github.com/poanetwork/blockscout/pull/2665) - new menu layout for mobile devices -- [#2679](https://github.com/poanetwork/blockscout/pull/2679) - added fixed height for card chain blocks and card chain transactions +- [#2679](https://github.com/poanetwork/blockscout/pull/2679) - added fixed height for card chain blocks and card chain transactions - [#2678](https://github.com/poanetwork/blockscout/pull/2678) - fixed dashboard banner height bug - [#2672](https://github.com/poanetwork/blockscout/pull/2672) - added new theme for xUSDT - [#2663](https://github.com/poanetwork/blockscout/pull/2663) - Fetch address counters in parallel @@ -10,7 +10,8 @@ ### Fixes - [#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 +- [#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 From 7c660b472ba894bf48fdf5460d75dc547ccde566 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Thu, 12 Sep 2019 12:49:18 +0300 Subject: [PATCH 18/24] do not update chart --- apps/block_scout_web/lib/block_scout_web/notifier.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 03e46cf38b..7c07c8524e 100644 --- a/apps/block_scout_web/lib/block_scout_web/notifier.ex +++ b/apps/block_scout_web/lib/block_scout_web/notifier.ex @@ -80,7 +80,7 @@ defmodule BlockScoutWeb.Notifier do exchange_rate_with_available_supply = case Application.get_env(:explorer, :supply) do RSK -> - %{exchange_rate | available_supply: RSK.circulating(), market_cap_usd: RSK.market_cap(exchange_rate)} + %{exchange_rate | available_supply: nil, market_cap_usd: RSK.market_cap(exchange_rate)} _ -> exchange_rate From 9e4b2344120f1f184a855939654057b1c71a06e8 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Thu, 12 Sep 2019 15:31:45 +0300 Subject: [PATCH 19/24] remove nonconsensus internal transactions --- .../explorer/chain/import/runner/blocks.ex | 51 ++++++++++++++++++- .../chain/import/runner/blocks_test.exs | 26 +++++++++- 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index 825a533743..9cfb771736 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex @@ -368,8 +368,15 @@ defmodule Explorer.Chain.Import.Runner.Blocks do ) 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) do - {:ok, %{token_transfers: deleted_token_transfers, logs: deleted_logs}} + {: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 @@ -406,6 +413,46 @@ defmodule Explorer.Chain.Import.Runner.Blocks do 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 Log 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, 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 459363839b..96104a0528 100644 --- a/apps/explorer/test/explorer/chain/import/runner/blocks_test.exs +++ b/apps/explorer/test/explorer/chain/import/runner/blocks_test.exs @@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do alias Ecto.Multi alias Explorer.Chain.Import.Runner.{Blocks, Transactions} - alias Explorer.Chain.{Address, Block, Log, Transaction, TokenTransfer} + alias Explorer.Chain.{Address, Block, InternalTransaction, Log, Transaction, TokenTransfer} alias Explorer.Chain alias Explorer.Repo @@ -177,6 +177,30 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do assert count(Log) == 0 end + test "remove_nonconsensus_date 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: %{number: block_number} = block, options: options} do token = insert(:token) From d7c62b2a5ae7fa6373e243a3b0c3f79661ac3abc Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Thu, 12 Sep 2019 15:33:21 +0300 Subject: [PATCH 20/24] remove update of block number for internal transactions --- .../explorer/chain/import/runner/blocks.ex | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index 9cfb771736..5a69e1778a 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex @@ -131,31 +131,6 @@ defmodule Explorer.Chain.Import.Runner.Blocks do } ) end) - |> Multi.run( - :internal_transaction_transaction_block_number, - fn repo, %{blocks: blocks} -> - blocks_hashes = Enum.map(blocks, & &1.hash) - - query = - from( - internal_transaction in InternalTransaction, - join: transaction in Transaction, - on: internal_transaction.transaction_hash == transaction.hash, - join: block in Block, - on: block.hash == transaction.block_hash, - where: block.hash in ^blocks_hashes, - update: [ - set: [ - block_number: block.number - ] - ] - ) - - {total, _} = repo.update_all(query, []) - - {:ok, total} - end - ) end @impl Runner From fdecb070623211bfcfa6f7194e8c6fc7ead03fa9 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Thu, 12 Sep 2019 15:36:47 +0300 Subject: [PATCH 21/24] add CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e0fd3e1b9..bc9ed39546 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [#2663](https://github.com/poanetwork/blockscout/pull/2663) - Fetch address counters in parallel ### Fixes +- [#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 From 26b05b184f2484ca4e2d978a90f58e00fa4c79de Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Thu, 12 Sep 2019 15:50:29 +0300 Subject: [PATCH 22/24] fix typo --- .../explorer/chain/import/runner/blocks.ex | 25 +++++++++++++++++++ .../chain/import/runner/blocks_test.exs | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index 5a69e1778a..9cfb771736 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex @@ -131,6 +131,31 @@ defmodule Explorer.Chain.Import.Runner.Blocks do } ) end) + |> Multi.run( + :internal_transaction_transaction_block_number, + fn repo, %{blocks: blocks} -> + blocks_hashes = Enum.map(blocks, & &1.hash) + + query = + from( + internal_transaction in InternalTransaction, + join: transaction in Transaction, + on: internal_transaction.transaction_hash == transaction.hash, + join: block in Block, + on: block.hash == transaction.block_hash, + where: block.hash in ^blocks_hashes, + update: [ + set: [ + block_number: block.number + ] + ] + ) + + {total, _} = repo.update_all(query, []) + + {:ok, total} + end + ) end @impl Runner 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 96104a0528..5a5d547068 100644 --- a/apps/explorer/test/explorer/chain/import/runner/blocks_test.exs +++ b/apps/explorer/test/explorer/chain/import/runner/blocks_test.exs @@ -177,7 +177,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do assert count(Log) == 0 end - test "remove_nonconsensus_date deletes nonconsensus internal transactions", %{ + test "remove_nonconsensus_data deletes nonconsensus internal transactions", %{ consensus_block: %{number: block_number} = block, options: options } do From 86d9786f55701562d670c3a58205c8367d4200e0 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 16 Sep 2019 13:39:11 +0300 Subject: [PATCH 23/24] Update blocks.ex --- apps/explorer/lib/explorer/chain/import/runner/blocks.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex index 9cfb771736..1c58446292 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex @@ -426,7 +426,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do inner_join: transaction in subquery(transaction_query), on: internal_transaction.transaction_hash == transaction.hash, select: map(internal_transaction, [:transaction_hash, :index]), - # Enforce Log ShareLocks order (see docs: sharelocks.md) + # Enforce InternalTransaction ShareLocks order (see docs: sharelocks.md) order_by: [ internal_transaction.transaction_hash, internal_transaction.index From 5d9f7d0c20528437e8976d55ad3dd7e804bd41ef Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Mon, 16 Sep 2019 17:53:35 +0300 Subject: [PATCH 24/24] Exclude nonconsensus blocks from avg block time calculation by default --- CHANGELOG.md | 1 + apps/explorer/config/config.exs | 2 +- docs/env-variables.md | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e0fd3e1b9..72877501b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [#2663](https://github.com/poanetwork/blockscout/pull/2663) - Fetch address counters in parallel ### Fixes +- [#2701](https://github.com/poanetwork/blockscout/pull/2701) - Exclude nonconsensus blocks from avg block time calculation by default - [#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 diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index deefc9e3da..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 = diff --git a/docs/env-variables.md b/docs/env-variables.md index 5eef49d07d..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: | |