From 17816e1fb0905fb88e955f0896ebe7ec15d7a5d3 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 12 Aug 2019 17:16:32 +0300 Subject: [PATCH] find decoding candidates for logs --- apps/explorer/lib/explorer/chain/log.ex | 37 ++++++++++++++-- .../explorer/test/explorer/chain/log_test.exs | 42 ++++++++++++++++++- 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/apps/explorer/lib/explorer/chain/log.ex b/apps/explorer/lib/explorer/chain/log.ex index b6c5c00a2d..027f3ce1ed 100644 --- a/apps/explorer/lib/explorer/chain/log.ex +++ b/apps/explorer/lib/explorer/chain/log.ex @@ -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} <- diff --git a/apps/explorer/test/explorer/chain/log_test.exs b/apps/explorer/test/explorer/chain/log_test.exs index 28be44a1af..d77922b06b 100644 --- a/apps/explorer/test/explorer/chain/log_test.exs +++ b/apps/explorer/test/explorer/chain/log_test.exs @@ -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