Skip to content

Commit

Permalink
perf: Improve performance of transactions list page (blockscout#10734)
Browse files Browse the repository at this point in the history
* perf: Improve performance of the transactions list page

* Update apps/explorer/lib/explorer/chain/transaction.ex

Co-authored-by: Qwerty5Uiop <[email protected]>

* Mix format

* Update apps/explorer/lib/explorer/chain/smart_contract/proxy.ex

Co-authored-by: Qwerty5Uiop <[email protected]>

* Refactoring

* Process review comment

* Second refactoring

* Revert latest refactoring

* Fix nil address_hash

* Update apps/explorer/lib/explorer/chain/transaction.ex

Co-authored-by: Kirill Fedoseev <[email protected]>

* Remove credo comment

* Update apps/explorer/lib/explorer/chain/smart_contract/proxy.ex

Co-authored-by: Kirill Fedoseev <[email protected]>

* tuple list to map

---------

Co-authored-by: Qwerty5Uiop <[email protected]>
Co-authored-by: Kirill Fedoseev <[email protected]>
  • Loading branch information
3 people authored Sep 13, 2024
1 parent 889d511 commit 680bb09
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,6 @@ defmodule BlockScoutWeb.TransactionTokenTransferControllerTest do
end

test "preloads to_address smart contract verified", %{conn: conn} do
TestHelper.get_eip1967_implementation_zero_addresses()

transaction = insert(:transaction_to_verified_contract)

conn = get(conn, transaction_token_transfer_path(BlockScoutWeb.Endpoint, :index, transaction.hash))
Expand Down
2 changes: 1 addition & 1 deletion apps/explorer/lib/explorer/chain/log.ex
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ defmodule Explorer.Chain.Log do
else
case Chain.find_contract_address(address_hash, address_options, false) do
{:ok, %{smart_contract: smart_contract}} ->
full_abi = Proxy.combine_proxy_implementation_abi(smart_contract, options)
full_abi = Proxy.combine_proxy_implementation_abi(smart_contract, %{}, true, options)
{full_abi, Map.put(acc, address_hash, full_abi)}

_ ->
Expand Down
49 changes: 43 additions & 6 deletions apps/explorer/lib/explorer/chain/smart_contract/proxy.ex
Original file line number Diff line number Diff line change
Expand Up @@ -480,17 +480,54 @@ defmodule Explorer.Chain.SmartContract.Proxy do
@doc """
Returns combined ABI from proxy and implementation smart-contracts
"""
@spec combine_proxy_implementation_abi(any(), any()) :: SmartContract.abi()
def combine_proxy_implementation_abi(smart_contract, options \\ [])
@spec combine_proxy_implementation_abi(any(), map(), boolean(), any()) :: SmartContract.abi()
def combine_proxy_implementation_abi(
smart_contract,
proxy_implementation_addresses_map \\ %{},
fetch_proxy?,
options \\ []
)

def combine_proxy_implementation_abi(%SmartContract{abi: abi} = smart_contract, options) when not is_nil(abi) do
implementation_abi = Proxy.get_implementation_abi_from_proxy(smart_contract, options)
def combine_proxy_implementation_abi(
%SmartContract{abi: abi} = smart_contract,
proxy_implementation_addresses_map,
fetch_proxy?,
options
)
when not is_nil(abi) do
implementation_abi =
get_implementation_abi(smart_contract, options, proxy_implementation_addresses_map, fetch_proxy?)

if Enum.empty?(implementation_abi), do: abi, else: implementation_abi ++ abi
end

def combine_proxy_implementation_abi(_, _) do
[]
def combine_proxy_implementation_abi(smart_contract, proxy_implementation_addresses_map, fetch_proxy?, options) do
get_implementation_abi(smart_contract, options, proxy_implementation_addresses_map, fetch_proxy?)
end

defp get_implementation_abi(smart_contract, options, proxy_implementation_addresses_map, fetch_proxy?) do
if fetch_proxy? do
Proxy.get_implementation_abi_from_proxy(smart_contract, options)
else
implementations =
proxy_implementation_addresses_map
|> Map.get(smart_contract.address_hash)

parse_abi_from_proxy_implementations(implementations)
end
end

defp parse_abi_from_proxy_implementations(nil), do: []

defp parse_abi_from_proxy_implementations(implementations) do
implementations
|> Enum.reduce([], fn implementation, acc ->
if implementation.smart_contract && implementation.smart_contract.abi do
acc ++ implementation.smart_contract.abi
else
acc
end
end)
end

defp find_input_by_name(inputs, name) do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ defmodule Explorer.Chain.SmartContract.Proxy.Models.Implementation do

alias Explorer.Chain.{Address, Hash, SmartContract}
alias Explorer.Chain.SmartContract.Proxy
alias Explorer.Chain.SmartContract.Proxy.Models.Implementation
alias Explorer.Counters.AverageBlockTime
alias Explorer.Repo
alias Timex.Duration
Expand Down Expand Up @@ -91,6 +90,16 @@ defmodule Explorer.Chain.SmartContract.Proxy.Models.Implementation do
|> select_repo(options).one()
end

@doc """
Returns all implementations for the given smart-contract address hashes
"""
@spec get_proxy_implementations_for_multiple_proxies([Hash.Address.t()], Keyword.t()) :: __MODULE__.t() | nil
def get_proxy_implementations_for_multiple_proxies(proxy_address_hashes, options \\ []) do
proxy_address_hashes
|> get_proxy_implementations_by_multiple_hashes_query()
|> select_repo(options).all()
end

@doc """
Returns the last implementation updated_at for the given smart-contract address hash
"""
Expand All @@ -109,6 +118,13 @@ defmodule Explorer.Chain.SmartContract.Proxy.Models.Implementation do
)
end

defp get_proxy_implementations_by_multiple_hashes_query(proxy_address_hashes) do
from(
p in __MODULE__,
where: p.proxy_address_hash in ^proxy_address_hashes
)
end

@doc """
Returns implementation address, name and proxy type for the given SmartContract
"""
Expand Down Expand Up @@ -210,7 +226,7 @@ defmodule Explorer.Chain.SmartContract.Proxy.Models.Implementation do
{:ok, :error} ->
format_proxy_implementations_response(proxy_implementations)

{:ok, %Implementation{} = result} ->
{:ok, %__MODULE__{} = result} ->
format_proxy_implementations_response(result)

_ ->
Expand Down Expand Up @@ -289,7 +305,7 @@ defmodule Explorer.Chain.SmartContract.Proxy.Models.Implementation do
Saves proxy's implementation into the DB
"""
@spec save_implementation_data([String.t()], Hash.Address.t(), atom() | nil, Keyword.t()) ::
Implementation.t() | :empty | :error
__MODULE__.t() | :empty | :error
def save_implementation_data(:error, _proxy_address_hash, _proxy_type, _options) do
:error
end
Expand Down
Loading

0 comments on commit 680bb09

Please sign in to comment.