perf: replace individual queries with ecto preload (#10203)

pull/10216/head
Maxim Filonov 6 months ago committed by GitHub
parent eddaeadc05
commit 3bea0e842e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex
  2. 7
      apps/block_scout_web/lib/block_scout_web/controllers/api/v2/smart_contract_controller.ex
  3. 2
      apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex
  4. 6
      apps/block_scout_web/lib/block_scout_web/views/account/api/v2/user_view.ex
  5. 39
      apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex
  6. 3
      apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs
  7. 4
      apps/explorer/lib/explorer/chain/address.ex
  8. 8
      apps/explorer/lib/explorer/chain/smart_contract/proxy/models/implementation.ex

@ -38,7 +38,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
necessity_by_association: %{
[created_contract_address: :names] => :optional,
[from_address: :names] => :optional,
[to_address: :names] => :optional,
[to_address: [:names, :proxy_implementations]] => :optional,
:block => :optional,
[created_contract_address: :smart_contract] => :optional,
[from_address: :smart_contract] => :optional,
@ -71,7 +71,8 @@ defmodule BlockScoutWeb.API.V2.AddressController do
@contract_address_preloads [
:smart_contract,
:contracts_creation_internal_transaction,
:contracts_creation_transaction
:contracts_creation_transaction,
:proxy_implementations
]
@nft_necessity_by_association [

@ -235,7 +235,12 @@ defmodule BlockScoutWeb.API.V2.SmartContractController do
def smart_contracts_list(conn, params) do
full_options =
[necessity_by_association: %{[address: :token] => :optional, [address: :names] => :optional, address: :required}]
[
necessity_by_association: %{
[address: [:token, :names, :proxy_implementations]] => :optional,
address: :required
}
]
|> Keyword.merge(paging_options(params))
|> Keyword.merge(current_filter(params))
|> Keyword.merge(search_query(params))

@ -134,7 +134,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
{:not_found, false} <- {:not_found, Chain.erc_20_token?(token)},
{:format, {:ok, holder_address_hash}} <- {:format, Chain.string_to_address_hash(holder_address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(holder_address_hash_string, params) do
holder_address = Repo.get_by(Address, hash: holder_address_hash)
holder_address = %Address{Repo.get_by(Address, hash: holder_address_hash) | proxy_implementations: nil}
results_plus_one =
Instance.token_instances_by_holder_address_hash(

@ -186,7 +186,11 @@ defmodule BlockScoutWeb.Account.Api.V2.UserView do
end
defp get_address(address_hash) do
case Chain.hash_to_address(address_hash, [necessity_by_association: %{:smart_contract => :optional}], false) do
case Chain.hash_to_address(
address_hash,
[necessity_by_association: %{smart_contract: :optional, proxy_implementations: :optional}],
false
) do
{:ok, address} -> address
_ -> nil
end

@ -6,7 +6,6 @@ defmodule BlockScoutWeb.API.V2.Helper do
alias Ecto.Association.NotLoaded
alias Explorer.Chain
alias Explorer.Chain.{Address, Hash}
alias Explorer.Chain.SmartContract.Proxy.Models.Implementation
alias Explorer.Chain.Transaction.History.TransactionStats
import BlockScoutWeb.Account.AuthController, only: [current_user: 1]
@ -53,30 +52,34 @@ defmodule BlockScoutWeb.API.V2.Helper do
@doc """
Gets address with the additional info for api v2
"""
@spec address_with_info(any(), any()) :: nil | %{optional(<<_::32, _::_*8>>) => any()}
@spec address_with_info(any(), any()) :: nil | %{optional(String.t()) => any()}
def address_with_info(
%Address{proxy_implementations: %NotLoaded{}, contract_code: contract_code} = _address,
_address_hash
)
when not is_nil(contract_code) do
raise "proxy_implementations is not loaded for address"
end
def address_with_info(%Address{} = address, _address_hash) do
smart_contract? = Address.smart_contract?(address)
{implementation_address_hashes, implementation_names, implementation_address, implementation_name,
proxy_implementations} =
if smart_contract? do
proxy_implementations = Implementation.get_proxy_implementations(address.hash)
{proxy_implementations, implementation_address_hashes, implementation_names, implementation_address,
implementation_name} =
case address.proxy_implementations do
%NotLoaded{} ->
{nil, [], [], nil, nil}
implementation_address_hashes = (proxy_implementations && proxy_implementations.address_hashes) || []
implementation_names = (proxy_implementations && proxy_implementations.names) || []
nil ->
{nil, [], [], nil, nil}
implementation_address =
(Enum.count(implementation_address_hashes) > 0 &&
implementation_address_hashes
|> Enum.at(0)
|> Address.checksum()) || nil
proxy_implementations ->
address_hashes = proxy_implementations.address_hashes
names = proxy_implementations.names
implementation_name = implementation_names |> Enum.at(0)
address_hash = Enum.at(address_hashes, 0) && address_hashes |> Enum.at(0) |> Address.checksum()
{implementation_address_hashes, implementation_names, implementation_address, implementation_name,
proxy_implementations}
else
{[], [], nil, nil, nil}
{proxy_implementations, address_hashes, names, address_hash, Enum.at(names, 0)}
end
%{

@ -162,7 +162,8 @@ defmodule BlockScoutWeb.API.V2.AddressControllerTest do
{:ok, implementation_contract_address_hash} =
Chain.string_to_address_hash("0x" <> implementation_contract_address_hash_string)
checksummed_implementation_contract_address_hash = Address.checksum(implementation_contract_address_hash)
checksummed_implementation_contract_address_hash =
implementation_contract_address_hash && Address.checksum(implementation_contract_address_hash)
insert(:proxy_implementation,
proxy_address_hash: proxy_address.hash,

@ -26,6 +26,7 @@ defmodule Explorer.Chain.Address do
}
alias Explorer.Chain.Cache.{Accounts, NetVersion}
alias Explorer.Chain.SmartContract.Proxy.Models.Implementation
@optional_attrs ~w(contract_code fetched_coin_balance fetched_coin_balance_block_number nonce decompiled verified gas_used transactions_count token_transfers_count)a
@required_attrs ~w(hash)a
@ -96,6 +97,7 @@ defmodule Explorer.Chain.Address do
has_one(:smart_contract, SmartContract, references: :hash)
has_one(:token, Token, foreign_key: :contract_address_hash, references: :hash)
has_one(:proxy_implementations, Implementation, foreign_key: :proxy_address_hash, references: :hash)
has_one(
:contracts_creation_internal_transaction,
@ -359,7 +361,7 @@ defmodule Explorer.Chain.Address do
from(a in Address,
where: a.fetched_coin_balance > ^0,
order_by: [desc: a.fetched_coin_balance, asc: a.hash],
preload: [:names, :smart_contract],
preload: [:names, :smart_contract, :proxy_implementations],
select: {a, a.transactions_count}
)

@ -51,6 +51,14 @@ defmodule Explorer.Chain.SmartContract.Proxy.Models.Implementation do
field(:address_hashes, {:array, Hash.Address}, null: false)
field(:names, {:array, :string}, null: false)
belongs_to(
:address,
Address,
foreign_key: :proxy_address_hash,
references: :hash,
define_field: false
)
timestamps()
end

Loading…
Cancel
Save