fix: Eliminate from_address_hash == #{address_hash} clause for transactions query in case of smart-contracts (#9469)

* Eliminate from_address_hash equal to address clause for transactions query in case of smart-contracts

* Fix tests

* Fix web tests

* Fix web tests

* Process review comments

* Update apps/explorer/lib/explorer/etherscan/logs.ex

Co-authored-by: Kirill Fedoseev <kirill@blockscout.com>

* mix format

* Remove or_where import

* Update smart-contract controller test

---------

Co-authored-by: Kirill Fedoseev <kirill@blockscout.com>
mf-only-health-webapp
Victor Baranov 6 months ago committed by GitHub
parent 379e81afc2
commit 4d4f355b0d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      apps/block_scout_web/test/block_scout_web/controllers/api/v2/smart_contract_controller_test.exs
  2. 8
      apps/explorer/lib/explorer/chain/address/counters.ex
  3. 18
      apps/explorer/lib/explorer/chain/transaction.ex
  4. 19
      apps/explorer/lib/explorer/etherscan/logs.ex
  5. 5
      apps/explorer/lib/explorer/graphql.ex

@ -671,7 +671,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"is_verified_via_verifier_alliance" => implementation_contract.verified_via_verifier_alliance,
"language" => smart_contract_language(implementation_contract),
"license_type" => "bsd_3_clause",
"certified" => false
"certified" => false,
"is_blueprint" => false
}
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(proxy_address.hash)}")

@ -128,10 +128,10 @@ defmodule Explorer.Chain.Address.Counters do
end
def address_hash_to_transaction_count_query(address_hash) do
from(
transaction in Transaction,
where: transaction.to_address_hash == ^address_hash or transaction.from_address_hash == ^address_hash
)
dynamic = Transaction.where_transactions_to_from(address_hash)
Transaction
|> where([transaction], ^dynamic)
end
@spec address_hash_to_transaction_count(Hash.Address.t()) :: non_neg_integer()

@ -1749,4 +1749,22 @@ defmodule Explorer.Chain.Transaction do
|> Decimal.min(max_fee_per_gas |> Wei.sub(base_fee_per_gas) |> Wei.to(:wei))
|> Wei.from(:wei)
end
@doc """
Dynamically adds to/from for `transactions` query based on whether the target address EOA or smart-contract
todo: pay attention to [EIP-5003](https://eips.ethereum.org/EIPS/eip-5003): if it will be included, this logic should be rolled back.
"""
@spec where_transactions_to_from(Hash.Address.t()) :: any()
def where_transactions_to_from(address_hash) do
with {:ok, address} <- Chain.hash_to_address(address_hash),
true <- Chain.contract?(address) do
dynamic([transaction], transaction.to_address_hash == ^address_hash)
else
_ ->
dynamic(
[transaction],
transaction.from_address_hash == ^address_hash or transaction.to_address_hash == ^address_hash
)
end
end
end

@ -5,7 +5,7 @@ defmodule Explorer.Etherscan.Logs do
"""
import Ecto.Query, only: [from: 2, limit: 2, where: 3, subquery: 1, order_by: 3, union: 2]
import Ecto.Query, only: [dynamic: 2, from: 2, limit: 2, where: 3, subquery: 1, order_by: 3, union: 2]
alias Explorer.{Chain, Repo}
alias Explorer.Chain.{Block, DenormalizationHelper, InternalTransaction, Log, Transaction}
@ -145,16 +145,12 @@ defmodule Explorer.Etherscan.Logs do
|> union(^query_from_address_hash_wrapped)
|> union(^query_created_contract_address_hash_wrapped)
all_transaction_logs_query =
all_transaction_logs_query_base =
from(transaction in Transaction,
join: log in ^logs_query,
on: log.transaction_hash == transaction.hash,
where: transaction.block_number >= ^prepared_filter.from_block,
where: transaction.block_number <= ^prepared_filter.to_block,
where:
transaction.to_address_hash == ^address_hash or
transaction.from_address_hash == ^address_hash or
transaction.created_contract_address_hash == ^address_hash,
select: map(log, ^@log_fields),
select_merge: %{
gas_price: transaction.gas_price,
@ -165,6 +161,17 @@ defmodule Explorer.Etherscan.Logs do
union: ^internal_transaction_log_query
)
dynamic =
dynamic(
[transaction],
^Transaction.where_transactions_to_from(address_hash) or
transaction.created_contract_address_hash == ^address_hash
)
all_transaction_logs_query =
all_transaction_logs_query_base
|> where([transaction], ^dynamic)
query_with_blocks =
from(log_transaction_data in subquery(all_transaction_logs_query),
join: block in Block,

@ -28,9 +28,10 @@ defmodule Explorer.GraphQL do
"""
@spec address_to_transactions_query(Hash.Address.t(), :desc | :asc) :: Ecto.Query.t()
def address_to_transactions_query(address_hash, order) do
dynamic = Transaction.where_transactions_to_from(address_hash)
Transaction
|> where([transaction], transaction.to_address_hash == ^address_hash)
|> or_where([transaction], transaction.from_address_hash == ^address_hash)
|> where([transaction], ^dynamic)
|> or_where([transaction], transaction.created_contract_address_hash == ^address_hash)
|> order_by([transaction], [{^order, transaction.block_number}, {^order, transaction.index}])
end

Loading…
Cancel
Save