Address logs decoding fix

pull/3188/head
Victor Baranov 4 years ago
parent a0fb02bf53
commit 20f3aab0cb
  1. 2
      apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex
  2. 4
      apps/block_scout_web/lib/block_scout_web/views/transaction_log_view.ex
  3. 51
      apps/explorer/lib/explorer/chain/log.ex
  4. 35
      apps/explorer/test/explorer/chain/log_test.exs

@ -1,5 +1,5 @@
<div data-test="transaction_log" class="tile tile-muted">
<% decoded_result = decode(@log, @transaction, @log.address) %>
<% decoded_result = decode(@log, @transaction) %>
<%= case decoded_result do %>
<%= {:error, :contract_not_verified, _cadidates} -> %>
<div class="alert alert-info">

@ -4,7 +4,7 @@ defmodule BlockScoutWeb.TransactionLogView do
alias Explorer.Chain.Log
def decode(log, transaction, address) do
Log.decode(log, transaction, address)
def decode(log, transaction) do
Log.decode(log, transaction)
end
end

@ -119,25 +119,35 @@ defmodule Explorer.Chain.Log do
@doc """
Decode transaction log data.
"""
def decode(_log, %Transaction{to_address: nil}), do: {:error, :no_to_address}
def decode(log, transaction = %Transaction{to_address: %{smart_contract: %{abi: abi, address_hash: address_hash}}})
when not is_nil(abi) do
full_abi = Chain.combine_proxy_implementation_abi(address_hash, abi)
def decode(log, transaction) do
address_options = [
necessity_by_association: %{
:smart_contract => :optional
}
]
with {:ok, selector, mapping} <- find_and_decode(full_abi, log, transaction),
identifier <- Base.encode16(selector.method_id, case: :lower),
text <- function_call(selector.function, mapping),
do: {:ok, identifier, text, mapping}
case Chain.find_contract_address(log.address_hash, address_options, true) do
{:ok, %{smart_contract: %{abi: abi}}} ->
full_abi = Chain.combine_proxy_implementation_abi(log.address_hash, abi)
with {:ok, selector, mapping} <- find_and_decode(full_abi, log, transaction),
identifier <- Base.encode16(selector.method_id, case: :lower),
text <- function_call(selector.function, mapping),
do: {:ok, identifier, text, mapping}
_ ->
find_candidates(log, transaction)
end
end
def decode(log, transaction) do
defp find_candidates(log, transaction) do
case log.first_topic do
"0x" <> hex_part ->
case Integer.parse(hex_part, 16) do
{number, ""} ->
<<method_id::binary-size(4), _rest::binary>> = :binary.encode_unsigned(number)
find_candidates(method_id, log, transaction)
find_candidates_query(method_id, log, transaction)
_ ->
{:error, :could_not_decode}
@ -148,26 +158,7 @@ defmodule Explorer.Chain.Log do
end
end
def decode(log, transaction, %Address{hash: address_hash}) do
address_options = [
necessity_by_association: %{
:smart_contract => :optional
}
]
with {:ok, %{smart_contract: %{abi: abi}}} <- Chain.find_contract_address(address_hash, address_options, true) do
full_abi = Chain.combine_proxy_implementation_abi(address_hash, abi)
with {:ok, selector, mapping} <- find_and_decode(full_abi, log, transaction),
identifier <- Base.encode16(selector.method_id, case: :lower),
text <- function_call(selector.function, mapping),
do: {:ok, identifier, text, mapping}
end
end
def decode(_log, _transaction, nil), do: {:error, :no_to_address}
defp find_candidates(method_id, log, transaction) do
defp find_candidates_query(method_id, log, transaction) do
candidates_query =
from(
contract_method in ContractMethod,

@ -58,29 +58,29 @@ defmodule Explorer.Chain.LogTest do
end
test "that a contract call transaction that has a verified contract returns the decoded input data" do
smart_contract =
insert(:smart_contract,
abi: [
%{
"anonymous" => false,
"inputs" => [
%{"indexed" => true, "name" => "_from_human", "type" => "string"},
%{"indexed" => false, "name" => "_number", "type" => "uint256"},
%{"indexed" => true, "name" => "_belly", "type" => "bool"}
],
"name" => "WantsPets",
"type" => "event"
}
]
)
to_address = insert(:address, contract_code: "0x")
insert(:smart_contract,
abi: [
%{
"anonymous" => false,
"inputs" => [
%{"indexed" => true, "name" => "_from_human", "type" => "string"},
%{"indexed" => false, "name" => "_number", "type" => "uint256"},
%{"indexed" => true, "name" => "_belly", "type" => "bool"}
],
"name" => "WantsPets",
"type" => "event"
}
],
address_hash: to_address.hash
)
topic1 = "0x" <> Base.encode16(:keccakf1600.hash(:sha3_256, "WantsPets(string,uint256,bool)"), case: :lower)
topic2 = "0x" <> Base.encode16(:keccakf1600.hash(:sha3_256, "bob"), case: :lower)
topic3 = "0x0000000000000000000000000000000000000000000000000000000000000001"
data = "0x0000000000000000000000000000000000000000000000000000000000000000"
to_address = insert(:address, smart_contract: smart_contract)
transaction =
:transaction_to_verified_contract
|> insert(to_address: to_address)
@ -88,6 +88,7 @@ defmodule Explorer.Chain.LogTest do
log =
insert(:log,
address: to_address,
transaction: transaction,
first_topic: topic1,
second_topic: topic2,

Loading…
Cancel
Save