diff --git a/apps/indexer/lib/indexer/internal_transaction/fetcher.ex b/apps/indexer/lib/indexer/internal_transaction/fetcher.ex index 5cf6df501e..d103e054c8 100644 --- a/apps/indexer/lib/indexer/internal_transaction/fetcher.ex +++ b/apps/indexer/lib/indexer/internal_transaction/fetcher.ex @@ -113,7 +113,12 @@ defmodule Indexer.InternalTransaction.Fetcher do |> EthereumJSONRPC.fetch_internal_transactions(json_rpc_named_arguments) |> case do {:ok, internal_transactions_params} -> - addresses_params = AddressExtraction.extract_addresses(%{internal_transactions: internal_transactions_params}) + internal_transactions_params_without_failed_creations = remove_failed_creations(internal_transactions_params) + + addresses_params = + AddressExtraction.extract_addresses(%{ + internal_transactions: internal_transactions_params_without_failed_creations + }) address_hash_to_block_number = Enum.into(addresses_params, %{}, fn %{fetched_coin_balance_block_number: block_number, hash: hash} -> @@ -123,7 +128,7 @@ defmodule Indexer.InternalTransaction.Fetcher do with {:ok, imported} <- Chain.import(%{ addresses: %{params: addresses_params}, - internal_transactions: %{params: internal_transactions_params}, + internal_transactions: %{params: internal_transactions_params_without_failed_creations}, timeout: :infinity }) do async_import_coin_balances(imported, %{ @@ -197,4 +202,31 @@ defmodule Indexer.InternalTransaction.Fetcher do end end) end + + defp remove_failed_creations(internal_transactions_params) do + internal_transactions_params + |> Enum.map(fn internal_transaction_params -> + internal_transaction_params[:trace_address] + + failed_parent_index = + Enum.find(internal_transaction_params[:trace_address], fn trace_address -> + parent = Enum.at(internal_transactions_params, trace_address) + + !is_nil(parent[:error]) + end) + + failed_parent = failed_parent_index && Enum.at(internal_transactions_params, failed_parent_index) + + if failed_parent do + internal_transaction_params + |> Map.delete(:created_contract_address_hash) + |> Map.delete(:created_contract_code) + |> Map.delete(:gas_used) + |> Map.delete(:output) + |> Map.put(:error, failed_parent[:error]) + else + internal_transaction_params + end + end) + end end diff --git a/apps/indexer/test/indexer/internal_transaction/fetcher_test.exs b/apps/indexer/test/indexer/internal_transaction/fetcher_test.exs index e81a5b4954..38213458e7 100644 --- a/apps/indexer/test/indexer/internal_transaction/fetcher_test.exs +++ b/apps/indexer/test/indexer/internal_transaction/fetcher_test.exs @@ -5,7 +5,7 @@ defmodule Indexer.InternalTransaction.FetcherTest do import ExUnit.CaptureLog import Mox - alias Explorer.Chain.{Hash, Transaction} + alias Explorer.Chain.{Address, Hash, Transaction} alias Indexer.{CoinBalance, InternalTransaction, PendingTransaction} @@ -151,6 +151,82 @@ defmodule Indexer.InternalTransaction.FetcherTest do """ end + @tag :no_parity + test "internal transactions with failed parent does not create a new address", %{ + json_rpc_named_arguments: json_rpc_named_arguments + } do + if json_rpc_named_arguments[:transport] == EthereumJSONRPC.Mox do + expect(EthereumJSONRPC.Mox, :json_rpc, fn _json, _options -> + {:ok, + [ + %{ + id: 0, + jsonrpc: "2.0", + result: %{ + "output" => "0x", + "stateDiff" => nil, + "trace" => [ + %{ + "action" => %{ + "callType" => "call", + "from" => "0xc73add416e2119d20ce80e0904fc1877e33ef246", + "gas" => "0x13388", + "input" => "0xc793bf97", + "to" => "0x2d07e106b5d280e4ccc2d10deee62441c91d4340", + "value" => "0x0" + }, + "error" => "Reverted", + "subtraces" => 1, + "traceAddress" => [], + "type" => "call" + }, + %{ + "action" => %{ + "from" => "0x2d07e106b5d280e4ccc2d10deee62441c91d4340", + "gas" => "0xb2ab", + "init" => + "0x608060405234801561001057600080fd5b5060d38061001f6000396000f3fe6080604052600436106038577c010000000000000000000000000000000000000000000000000000000060003504633ccfd60b8114604f575b336000908152602081905260409020805434019055005b348015605a57600080fd5b5060616063565b005b33600081815260208190526040808220805490839055905190929183156108fc02918491818181858888f1935050505015801560a3573d6000803e3d6000fd5b505056fea165627a7a72305820e9a226f249def650de957dd8b4127b85a3049d6bfa818cadc4e2d3c44b6a53530029", + "value" => "0x0" + }, + "result" => %{ + "address" => "0xf4a5afe28b91cf928c2568805cfbb36d477f0b75", + "code" => + "0x6080604052600436106038577c010000000000000000000000000000000000000000000000000000000060003504633ccfd60b8114604f575b336000908152602081905260409020805434019055005b348015605a57600080fd5b5060616063565b005b33600081815260208190526040808220805490839055905190929183156108fc02918491818181858888f1935050505015801560a3573d6000803e3d6000fd5b505056fea165627a7a72305820e9a226f249def650de957dd8b4127b85a3049d6bfa818cadc4e2d3c44b6a53530029", + "gasUsed" => "0xa535" + }, + "subtraces" => 0, + "traceAddress" => [0], + "type" => "create" + } + ], + "vmTrace" => nil + } + } + ]} + end) + + CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments) + + %Transaction{hash: %Hash{bytes: bytes}} = + insert(:transaction, hash: "0x03cd5899a63b6f6222afda8705d059fd5a7d126bcabe962fb654d9736e6bcafa") + |> with_block() + + :ok = + InternalTransaction.Fetcher.run( + [ + {7_202_692, bytes, 0} + ], + json_rpc_named_arguments + ) + + address = "0xf4a5afe28b91cf928c2568805cfbb36d477f0b75" + + fetched_address = Repo.one(from(address in Address, where: address.hash == ^address)) + + assert is_nil(fetched_address) + end + end + test "duplicate transaction hashes only retry uniques", %{json_rpc_named_arguments: json_rpc_named_arguments} do if json_rpc_named_arguments[:transport] == EthereumJSONRPC.Mox do expect(EthereumJSONRPC.Mox, :json_rpc, fn _json, _options ->