find decoding candidates for logs

pull/2555/head
Ayrat Badykov 5 years ago
parent 4573fc44ad
commit 17816e1fb0
No known key found for this signature in database
GPG Key ID: B44668E265E9396F
  1. 37
      apps/explorer/lib/explorer/chain/log.ex
  2. 42
      apps/explorer/test/explorer/chain/log_test.exs

@ -5,8 +5,9 @@ defmodule Explorer.Chain.Log do
require Logger
alias ABI.{Event, FunctionSelector}
alias Explorer.Chain.{Address, Data, Hash, Transaction}
alias ABI.{Event, FunctionSelector, Util}
alias Explorer.Chain.{Address, ContractMethod, Data, Hash, Transaction}
alias Explorer.Repo
@required_attrs ~w(address_hash data index transaction_hash)a
@optional_attrs ~w(first_topic second_topic third_topic fourth_topic type)a
@ -114,7 +115,37 @@ defmodule Explorer.Chain.Log do
do: {:ok, identifier, text, mapping}
end
def decode(_log, _transaction), do: {:error, :contract_not_verified}
def decode(log, transaction) do
IO.inspect(" case Util.split_method_id(log.first_topic) do")
case Util.split_method_id(log.first_topic) |> IO.inspect do
{:ok, method_id, _rest} ->
find_candidates(method_id, log, transaction) |> IO.inspect
_ ->
{:error, :could_not_decode}
end
end
defp find_candidates(_method_id, log, transaction) do
candidates_query =
from(
contract_method in ContractMethod,
# where: contract_method.identifier == ^method_id,
limit: 3
)
candidates =
candidates_query
|> Repo.all()
|> IO.inspect
|> Enum.flat_map(fn contract_method ->
case find_and_decode(contract_method.abi, log, transaction) do
{:ok, _, _} = result -> [result]
_ -> []
end
end)
{:error, :contract_not_verified, candidates}
end
defp find_and_decode(abi, log, transaction) do
with {%FunctionSelector{} = selector, mapping} <-

@ -2,7 +2,8 @@ defmodule Explorer.Chain.LogTest do
use Explorer.DataCase
alias Ecto.Changeset
alias Explorer.Chain.Log
alias Explorer.Chain.{ContractMethod, Log, SmartContract}
alias Explorer.Repo
doctest Log
@ -100,5 +101,44 @@ defmodule Explorer.Chain.LogTest do
{"_belly", "bool", true, true}
]}
end
test "finds decoding candidates" do
params = params_for(: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"
}
]})
# changeset has a callback to insert contract methods
%SmartContract{}
|> SmartContract.changeset(params)
|> Repo.insert!()
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"
transaction = insert(:transaction)
log =
insert(:log,
transaction: transaction,
first_topic: topic1 <> "00",
second_topic: topic2,
third_topic: topic3,
fourth_topic: nil,
data: data
)
assert Log.decode(log, transaction)
end
end
end

Loading…
Cancel
Save