From 21ca08b8994e56f1b329900e79d9927ee52d9351 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Tue, 18 Feb 2020 13:05:29 +0300 Subject: [PATCH] Speedup token transfers list query --- CHANGELOG.md | 1 + apps/explorer/lib/explorer/etherscan.ex | 65 +++++++++++++++++-------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de3fb1fa3d..3d520d4677 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [#2834](https://github.com/poanetwork/blockscout/pull/2834) - always redirect to checksummed hash ### Fixes +- [#3012](https://github.com/poanetwork/blockscout/pull/3012) - Speedup token transfers list query - [#3009](https://github.com/poanetwork/blockscout/pull/3009) - Fix broken export to CSV - [#3007](https://github.com/poanetwork/blockscout/pull/3007) - Fix copy UTF8 tx input action - [#2996](https://github.com/poanetwork/blockscout/pull/2996) - Fix awesomplete lib loading in Firefox diff --git a/apps/explorer/lib/explorer/etherscan.ex b/apps/explorer/lib/explorer/etherscan.ex index 14bd208db5..1caf9f7e64 100644 --- a/apps/explorer/lib/explorer/etherscan.ex +++ b/apps/explorer/lib/explorer/etherscan.ex @@ -3,7 +3,7 @@ defmodule Explorer.Etherscan do The etherscan context. """ - import Ecto.Query, only: [from: 2, where: 3, or_where: 3, union: 2] + import Ecto.Query, only: [from: 2, where: 3, or_where: 3, union: 2, subquery: 1] alias Explorer.Etherscan.Logs alias Explorer.{Chain, Repo} @@ -374,6 +374,8 @@ defmodule Explorer.Etherscan do end @token_transfer_fields ~w( + block_number + block_hash token_contract_address_hash transaction_hash from_address_hash @@ -382,31 +384,17 @@ defmodule Explorer.Etherscan do )a defp list_token_transfers(address_hash, contract_address_hash, block_height, options) do - query = + tt_query = from( - t in Transaction, - inner_join: tt in TokenTransfer, - on: tt.transaction_hash == t.hash and tt.block_number == t.block_number and tt.block_hash == t.block_hash, + tt in TokenTransfer, inner_join: tkn in assoc(tt, :token), - inner_join: b in assoc(t, :block), where: tt.from_address_hash == ^address_hash, or_where: tt.to_address_hash == ^address_hash, - order_by: [{^options.order_by_direction, t.block_number}], + order_by: [{^options.order_by_direction, tt.block_number}, {^options.order_by_direction, tt.log_index}], limit: ^options.page_size, offset: ^offset(options), select: merge(map(tt, ^@token_transfer_fields), %{ - transaction_nonce: t.nonce, - transaction_index: t.index, - transaction_gas: t.gas, - transaction_gas_price: t.gas_price, - transaction_gas_used: t.gas_used, - transaction_cumulative_gas_used: t.cumulative_gas_used, - transaction_input: t.input, - block_hash: b.hash, - block_number: b.number, - block_timestamp: b.timestamp, - confirmations: fragment("? - ?", ^block_height, t.block_number), token_id: tt.token_id, token_name: tkn.name, token_symbol: tkn.symbol, @@ -416,10 +404,45 @@ defmodule Explorer.Etherscan do }) ) - query + tt_specific_token_query = + tt_query + |> where_contract_address_match(contract_address_hash) + + wrapped_query = + from( + tt in subquery(tt_specific_token_query), + inner_join: t in Transaction, + on: tt.transaction_hash == t.hash and tt.block_number == t.block_number and tt.block_hash == t.block_hash, + inner_join: b in assoc(t, :block), + select: %{ + token_contract_address_hash: tt.token_contract_address_hash, + transaction_hash: tt.transaction_hash, + from_address_hash: tt.from_address_hash, + to_address_hash: tt.to_address_hash, + amount: tt.amount, + transaction_nonce: t.nonce, + transaction_index: t.index, + transaction_gas: t.gas, + transaction_gas_price: t.gas_price, + transaction_gas_used: t.gas_used, + transaction_cumulative_gas_used: t.cumulative_gas_used, + transaction_input: t.input, + block_hash: b.hash, + block_number: b.number, + block_timestamp: b.timestamp, + confirmations: fragment("? - ?", ^block_height, t.block_number), + token_id: tt.token_id, + token_name: tt.token_name, + token_symbol: tt.token_symbol, + token_decimals: tt.token_decimals, + token_type: tt.token_type, + token_log_index: tt.token_log_index + } + ) + + wrapped_query |> where_start_block_match(options) |> where_end_block_match(options) - |> where_contract_address_match(contract_address_hash) |> Repo.all() end @@ -450,7 +473,7 @@ defmodule Explorer.Etherscan do defp where_contract_address_match(query, nil), do: query defp where_contract_address_match(query, contract_address_hash) do - where(query, [_, tt], tt.token_contract_address_hash == ^contract_address_hash) + where(query, [tt, _], tt.token_contract_address_hash == ^contract_address_hash) end defp offset(options), do: (options.page_number - 1) * options.page_size