diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs index 4b1fa454a8..6d1626d554 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs @@ -81,7 +81,9 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do :internal_transaction, transaction: transaction_1, from_address: address, - index: index + index: index, + block_number: transaction_1.block_number, + transaction_index: transaction_1.index ) end) |> Enum.map(&"#{&1.transaction_hash}.#{&1.index}") @@ -93,7 +95,9 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do :internal_transaction, transaction: transaction_2, from_address: address, - index: index + index: index, + block_number: transaction_2.block_number, + transaction_index: transaction_2.index ) end) |> Enum.map(&"#{&1.transaction_hash}.#{&1.index}") @@ -105,7 +109,9 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do :internal_transaction, transaction: transaction_3, from_address: address, - index: index + index: index, + block_number: transaction_3.block_number, + transaction_index: transaction_3.index ) end) |> Enum.map(&"#{&1.transaction_hash}.#{&1.index}") @@ -113,8 +119,14 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do second_page_hashes = transaction_1_hashes ++ transaction_2_hashes ++ transaction_3_hashes %InternalTransaction{index: index} = - :internal_transaction - |> insert(transaction: transaction_3, from_address: address, index: 11) + insert( + :internal_transaction, + transaction: transaction_3, + from_address: address, + index: 11, + block_number: transaction_3.block_number, + transaction_index: transaction_3.index + ) conn = get(conn, address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash), %{ diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs index 8cb719bb34..8bf9d851a2 100644 --- a/apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs @@ -62,7 +62,7 @@ defmodule BlockScoutWeb.ViewingAddressesTest do internal_transaction = insert( :internal_transaction_create, - index: 0, + index: 1, transaction: transaction, from_address: address, created_contract_address: contract @@ -84,7 +84,7 @@ defmodule BlockScoutWeb.ViewingAddressesTest do insert( :internal_transaction, - index: 0, + index: 1, transaction: transaction, from_address: lincoln, to_address: contract, @@ -95,7 +95,7 @@ defmodule BlockScoutWeb.ViewingAddressesTest do internal_transaction = insert( :internal_transaction_create, - index: 1, + index: 2, transaction: transaction, from_address: contract, created_contract_address: another_contract @@ -198,7 +198,7 @@ defmodule BlockScoutWeb.ViewingAddressesTest do |> insert( transaction: from_lincoln, from_address: lincoln, - index: 0 + index: 1 ) |> with_contract_creation(contract_address) @@ -225,9 +225,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do transaction = transactions.from_lincoln internal_transaction_lincoln_to_address = - insert(:internal_transaction, transaction: transaction, to_address: address, index: 0) + insert(:internal_transaction, transaction: transaction, to_address: address, index: 1) - insert(:internal_transaction, transaction: transaction, from_address: address, index: 1) + insert(:internal_transaction, transaction: transaction, from_address: address, index: 2) {:ok, %{internal_transaction_lincoln_to_address: internal_transaction_lincoln_to_address}} end @@ -278,7 +278,7 @@ defmodule BlockScoutWeb.ViewingAddressesTest do |> assert_has(AddressPage.internal_transactions(count: 2)) internal_transaction = - insert(:internal_transaction, transaction: transaction, index: 0, from_address: addresses.lincoln) + insert(:internal_transaction, transaction: transaction, index: 2, from_address: addresses.lincoln) Notifier.handle_event({:chain_event, :internal_transactions, :realtime, [internal_transaction]}) @@ -307,7 +307,7 @@ defmodule BlockScoutWeb.ViewingAddressesTest do |> insert( transaction: from_lincoln, from_address: lincoln, - index: 0 + index: 1 ) |> with_contract_creation(contract_address) diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity.ex index aabae7548f..043d8191ac 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity.ex @@ -142,13 +142,19 @@ defmodule EthereumJSONRPC.Parity do defp trace_replay_transaction_response_to_traces(%{id: id, result: %{"trace" => traces}}, id_to_params) when is_list(traces) and is_map(id_to_params) do - %{block_number: block_number, hash_data: transaction_hash} = Map.fetch!(id_to_params, id) + %{block_number: block_number, hash_data: transaction_hash, transaction_index: transaction_index} = + Map.fetch!(id_to_params, id) annotated_traces = traces |> Stream.with_index() |> Enum.map(fn {trace, index} -> - Map.merge(trace, %{"blockNumber" => block_number, "index" => index, "transactionHash" => transaction_hash}) + Map.merge(trace, %{ + "blockNumber" => block_number, + "index" => index, + "transactionIndex" => transaction_index, + "transactionHash" => transaction_hash + }) end) {:ok, annotated_traces} @@ -156,9 +162,15 @@ defmodule EthereumJSONRPC.Parity do defp trace_replay_transaction_response_to_traces(%{id: id, error: error}, id_to_params) when is_map(id_to_params) do - %{block_number: block_number, hash_data: transaction_hash} = Map.fetch!(id_to_params, id) - - annotated_error = Map.put(error, :data, %{"blockNumber" => block_number, "transactionHash" => transaction_hash}) + %{block_number: block_number, hash_data: transaction_hash, transaction_index: transaction_index} = + Map.fetch!(id_to_params, id) + + annotated_error = + Map.put(error, :data, %{ + "blockNumber" => block_number, + "transactionIndex" => transaction_index, + "transactionHash" => transaction_hash + }) {:error, annotated_error} end diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity/trace.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity/trace.ex index 865eba82ea..42dcfe9b30 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity/trace.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity/trace.ex @@ -28,7 +28,8 @@ defmodule EthereumJSONRPC.Parity.Trace do ...> "subtraces" => 0, ...> "traceAddress" => [], ...> "transactionHash" => "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6", - ...> "type" => "create" + ...> "type" => "create", + ...> "transactionIndex" => 0 ...> } ...> ) %{ @@ -43,7 +44,8 @@ defmodule EthereumJSONRPC.Parity.Trace do trace_address: [], transaction_hash: "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6", type: "create", - value: 0 + value: 0, + transaction_index: 0 } A create can fail due to a Bad Instruction in the `init` that is meant to form the `code` of the contract @@ -62,7 +64,8 @@ defmodule EthereumJSONRPC.Parity.Trace do ...> "subtraces" => 0, ...> "traceAddress" => [], ...> "transactionHash" => "0x3c624bb4852fb5e35a8f45644cec7a486211f6ba89034768a2b763194f22f97d", - ...> "type" => "create" + ...> "type" => "create", + ...> "transactionIndex" => 0 ...> } ...> ) %{ @@ -75,7 +78,8 @@ defmodule EthereumJSONRPC.Parity.Trace do trace_address: [], transaction_hash: "0x3c624bb4852fb5e35a8f45644cec7a486211f6ba89034768a2b763194f22f97d", type: "create", - value: 0 + value: 0, + transaction_index: 0 } Call type traces are generated when a method is called. Calls are further divided by call type. @@ -99,7 +103,8 @@ defmodule EthereumJSONRPC.Parity.Trace do ...> "subtraces" => 0, ...> "traceAddress" => [], ...> "transactionHash" => "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6", - ...> "type" => "call" + ...> "type" => "call", + ...> "transactionIndex" => 0 ...> } ...> ) %{ @@ -114,7 +119,8 @@ defmodule EthereumJSONRPC.Parity.Trace do trace_address: [], transaction_hash: "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6", type: "call", - value: 0 + value: 0, + transaction_index: 0 } Calls can error and be reverted @@ -135,7 +141,8 @@ defmodule EthereumJSONRPC.Parity.Trace do ...> "subtraces" => 7, ...> "traceAddress" => [], ...> "transactionHash" => "0xcd7c15dbbc797722bef6e1d551edfd644fc7f4fb2ccd6a7947b2d1ade9ed140b", - ...> "type" => "call" + ...> "type" => "call", + ...> "transactionIndex" => 0 ...> } ...> ) %{ @@ -149,7 +156,8 @@ defmodule EthereumJSONRPC.Parity.Trace do trace_address: [], transaction_hash: "0xcd7c15dbbc797722bef6e1d551edfd644fc7f4fb2ccd6a7947b2d1ade9ed140b", type: "call", - value: 10000000000000000 + value: 10000000000000000, + transaction_index: 0 } Suicides transfer a `"balance"` from `"address"` to `"refundAddress"`. These suicide-unique fields can be mapped to @@ -174,7 +182,8 @@ defmodule EthereumJSONRPC.Parity.Trace do ...> "subtraces" => 0, ...> "traceAddress" => [0], ...> "transactionHash" => "0xb012b8c53498c669d87d85ed90f57385848b86d3f44ed14b2784ec685d6fda98", - ...> "type" => "suicide" + ...> "type" => "suicide", + ...> "transactionIndex" => 0 ...> } ...> ) %{ @@ -185,7 +194,8 @@ defmodule EthereumJSONRPC.Parity.Trace do trace_address: [0], transaction_hash: "0xb012b8c53498c669d87d85ed90f57385848b86d3f44ed14b2784ec685d6fda98", type: "suicide", - value: 0 + value: 0, + transaction_index: 0 } """ @@ -202,7 +212,8 @@ defmodule EthereumJSONRPC.Parity.Trace do "blockNumber" => block_number, "index" => index, "traceAddress" => trace_address, - "transactionHash" => transaction_hash + "transactionHash" => transaction_hash, + "transactionIndex" => transaction_index } = elixir %{ @@ -215,7 +226,8 @@ defmodule EthereumJSONRPC.Parity.Trace do trace_address: trace_address, transaction_hash: transaction_hash, type: type, - value: value + value: value, + transaction_index: transaction_index } |> put_call_error_or_result(elixir) end @@ -226,7 +238,8 @@ defmodule EthereumJSONRPC.Parity.Trace do "blockNumber" => block_number, "index" => index, "traceAddress" => trace_address, - "transactionHash" => transaction_hash + "transactionHash" => transaction_hash, + "transactionIndex" => transaction_index } = elixir %{ @@ -238,7 +251,8 @@ defmodule EthereumJSONRPC.Parity.Trace do trace_address: trace_address, transaction_hash: transaction_hash, type: type, - value: value + value: value, + transaction_index: transaction_index } |> put_create_error_or_result(elixir) end @@ -253,7 +267,8 @@ defmodule EthereumJSONRPC.Parity.Trace do "blockNumber" => block_number, "index" => index, "traceAddress" => trace_address, - "transactionHash" => transaction_hash + "transactionHash" => transaction_hash, + "transactionIndex" => transaction_index } = elixir %{ @@ -264,7 +279,8 @@ defmodule EthereumJSONRPC.Parity.Trace do trace_address: trace_address, transaction_hash: transaction_hash, type: type, - value: value + value: value, + transaction_index: transaction_index } end @@ -289,6 +305,7 @@ defmodule EthereumJSONRPC.Parity.Trace do ...> "subtraces" => 0, ...> "traceAddress" => [], ...> "transactionHash" => "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6", + ...> "transactionIndex" => 0, ...> "type" => "create" ...> } ...> ) @@ -309,6 +326,7 @@ defmodule EthereumJSONRPC.Parity.Trace do "subtraces" => 0, "traceAddress" => [], "transactionHash" => "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6", + "transactionIndex" => 0, "type" => "create" } @@ -330,10 +348,11 @@ defmodule EthereumJSONRPC.Parity.Trace do ...> }, ...> "subtraces" => 0, ...> "traceAddress" => [], + ...> "transactionIndex" => 0, ...> "type" => "create" ...> } ...> ) - ** (ArgumentError) Caller must `Map.put/2` `"blockNumber"`, `"index"`, and `"transactionHash"` in trace + ** (ArgumentError) Caller must `Map.put/2` `"blockNumber"`, `"index"`, `"transactionHash"` and `"transactionIndex"` in trace `"suicide"` `"type"` traces are different in that they have a `nil` `"result"`. This is because the `"result"` key is used to indicate success from Parity. @@ -351,6 +370,7 @@ defmodule EthereumJSONRPC.Parity.Trace do ...> "subtraces" => 0, ...> "traceAddress" => [0], ...> "transactionHash" => "0xb012b8c53498c669d87d85ed90f57385848b86d3f44ed14b2784ec685d6fda98", + ...> "transactionIndex" => 0, ...> "type" => "suicide" ...> } ...> ) @@ -366,6 +386,7 @@ defmodule EthereumJSONRPC.Parity.Trace do "subtraces" => 0, "traceAddress" => [0], "transactionHash" => "0xb012b8c53498c669d87d85ed90f57385848b86d3f44ed14b2784ec685d6fda98", + "transactionIndex" => 0, "type" => "suicide" } @@ -387,6 +408,7 @@ defmodule EthereumJSONRPC.Parity.Trace do ...> "subtraces" => 7, ...> "traceAddress" => [], ...> "transactionHash" => "0xcd7c15dbbc797722bef6e1d551edfd644fc7f4fb2ccd6a7947b2d1ade9ed140b", + ...> "transactionIndex" => 0, ...> "type" => "call" ...> } ...> ) @@ -405,19 +427,20 @@ defmodule EthereumJSONRPC.Parity.Trace do "subtraces" => 7, "traceAddress" => [], "transactionHash" => "0xcd7c15dbbc797722bef6e1d551edfd644fc7f4fb2ccd6a7947b2d1ade9ed140b", + "transactionIndex" => 0, "type" => "call" } """ - def to_elixir(%{"blockNumber" => _, "index" => _, "transactionHash" => _} = trace) + def to_elixir(%{"blockNumber" => _, "index" => _, "transactionHash" => _, "transactionIndex" => _} = trace) when is_map(trace) do Enum.into(trace, %{}, &entry_to_elixir/1) end def to_elixir(_) do raise ArgumentError, - ~S|Caller must `Map.put/2` `"blockNumber"`, `"index"`, and `"transactionHash"` in trace| + ~S|Caller must `Map.put/2` `"blockNumber"`, `"index"`, `"transactionHash"` and `"transactionIndex"` in trace| end # subtraces is an actual integer in JSON and not hex-encoded @@ -441,6 +464,8 @@ defmodule EthereumJSONRPC.Parity.Trace do {key, Result.to_elixir(result)} end + defp entry_to_elixir({"transactionIndex", index} = entry) when is_integer(index), do: entry + defp put_call_error_or_result(params, %{ "result" => %{"gasUsed" => gas_used, "output" => output} }) do diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex index 4cd2f0191d..72aeca20fc 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex @@ -60,7 +60,8 @@ defmodule EthereumJSONRPC.Transaction do s: non_neg_integer(), to_address_hash: EthereumJSONRPC.address(), v: non_neg_integer(), - value: non_neg_integer() + value: non_neg_integer(), + transaction_index: non_neg_integer() } @doc """ @@ -98,7 +99,8 @@ defmodule EthereumJSONRPC.Transaction do s: 31606574786494953692291101914709926755545765281581808821704454381804773090106, to_address_hash: "0x5df9b87991262f6ba471f09758cde1c0fc1de734", v: 28, - value: 31337 + value: 31337, + transaction_index: 0 } """ @@ -133,7 +135,8 @@ defmodule EthereumJSONRPC.Transaction do s: s, to_address_hash: to_address_hash, v: v, - value: value + value: value, + transaction_index: index } end diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transactions.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transactions.ex index c0642d1f61..cae14b1cd8 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transactions.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transactions.ex @@ -55,7 +55,8 @@ defmodule EthereumJSONRPC.Transactions do s: "0x72caddc0371451a58de2ca6ab64e0f586ccdb9465ff54e1c82564940e89291e3", to_address_hash: nil, v: "0xbd", - value: 0 + value: 0, + transaction_index: 0 } ] diff --git a/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/http/mox_test.exs b/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/http/mox_test.exs index 49dacf2b57..5eb12fd550 100644 --- a/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/http/mox_test.exs +++ b/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/http/mox_test.exs @@ -179,7 +179,9 @@ defmodule EthereumJSONRPC.HTTP.MoxTest do end transactions_params = - Enum.map(transaction_hashes, fn hash_data -> %{block_number: 0, hash_data: hash_data, gas: 1_000_000} end) + Enum.map(transaction_hashes, fn hash_data -> + %{block_number: 0, hash_data: hash_data, gas: 1_000_000, transaction_index: 0} + end) assert {:ok, responses} = EthereumJSONRPC.fetch_internal_transactions(transactions_params, json_rpc_named_arguments) diff --git a/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/parity_test.exs b/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/parity_test.exs index a0f4b8262b..c3e84db531 100644 --- a/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/parity_test.exs +++ b/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/parity_test.exs @@ -32,6 +32,7 @@ defmodule EthereumJSONRPC.ParityTest do gas_used = 382_953 trace_address = [] transaction_hash = "0x0fa6f723216dba694337f9bb37d8870725655bdf2573526a39454685659e39b1" + transaction_index = 0 type = "create" if json_rpc_named_arguments[:transport] == EthereumJSONRPC.Mox do @@ -58,6 +59,7 @@ defmodule EthereumJSONRPC.ParityTest do }, "traceAddress" => trace_address, "transactionHash" => transaction_hash, + "transactionIndex" => transaction_index, "type" => type } ] @@ -71,7 +73,8 @@ defmodule EthereumJSONRPC.ParityTest do [ %{ block_number: block_number, - hash_data: transaction_hash + hash_data: transaction_hash, + transaction_index: transaction_index } ], json_rpc_named_arguments @@ -90,7 +93,8 @@ defmodule EthereumJSONRPC.ParityTest do trace_address: trace_address, transaction_hash: transaction_hash, type: type, - value: value + value: value, + transaction_index: transaction_index } ] } @@ -118,7 +122,8 @@ defmodule EthereumJSONRPC.ParityTest do [ %{ block_number: 1, - hash_data: "0x0000000000000000000000000000000000000000000000000000000000000001" + hash_data: "0x0000000000000000000000000000000000000000000000000000000000000001", + transaction_index: 0 } ], json_rpc_named_arguments @@ -129,7 +134,8 @@ defmodule EthereumJSONRPC.ParityTest do code: -32603, data: %{ "blockNumber" => 1, - "transactionHash" => "0x0000000000000000000000000000000000000000000000000000000000000001" + "transactionHash" => "0x0000000000000000000000000000000000000000000000000000000000000001", + "transactionIndex" => 0 }, message: "Internal error occurred: {}, this should not be the case with eth_call, most likely a bug." @@ -179,22 +185,26 @@ defmodule EthereumJSONRPC.ParityTest do # start with :ok %{ block_number: 1, - hash_data: "0x0fa6f723216dba694337f9bb37d8870725655bdf2573526a39454685659e39b1" + hash_data: "0x0fa6f723216dba694337f9bb37d8870725655bdf2573526a39454685659e39b1", + transaction_index: 0 }, # :ok, :ok clause %{ block_number: 34, - hash_data: "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6" + hash_data: "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6", + transaction_index: 0 }, # :ok, :error clause %{ block_number: 1, - hash_data: "0x0000000000000000000000000000000000000000000000000000000000000001" + hash_data: "0x0000000000000000000000000000000000000000000000000000000000000001", + transaction_index: 0 }, # :error, :error clause %{ block_number: 2, - hash_data: "0x0000000000000000000000000000000000000000000000000000000000000002" + hash_data: "0x0000000000000000000000000000000000000000000000000000000000000002", + transaction_index: 0 } ], json_rpc_named_arguments @@ -205,7 +215,8 @@ defmodule EthereumJSONRPC.ParityTest do code: -32603, data: %{ "blockNumber" => 1, - "transactionHash" => "0x0000000000000000000000000000000000000000000000000000000000000001" + "transactionHash" => "0x0000000000000000000000000000000000000000000000000000000000000001", + "transactionIndex" => 0 }, message: "Internal error occurred: {}, this should not be the case with eth_call, most likely a bug." @@ -214,7 +225,8 @@ defmodule EthereumJSONRPC.ParityTest do code: -32603, data: %{ "blockNumber" => 2, - "transactionHash" => "0x0000000000000000000000000000000000000000000000000000000000000002" + "transactionHash" => "0x0000000000000000000000000000000000000000000000000000000000000002", + "transactionIndex" => 0 }, message: "Internal error occurred: {}, this should not be the case with eth_call, most likely a bug." diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 9538a862c5..d671181600 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -96,8 +96,8 @@ defmodule Explorer.Chain do @doc """ `t:Explorer.Chain.InternalTransaction/0`s from `address`. - This function excludes any internal transactions in the results where the internal transaction has no siblings within - the parent transaction. + This function excludes any internal transactions in the results where the + internal transaction has no siblings within the parent transaction. ## Options @@ -122,20 +122,14 @@ defmodule Explorer.Chain do paging_options = Keyword.get(options, :paging_options, @default_paging_options) InternalTransaction - |> join( - :inner, - [internal_transaction], - transaction in assoc(internal_transaction, :transaction) - ) - |> join(:left, [internal_transaction, transaction], block in assoc(transaction, :block)) |> InternalTransaction.where_address_fields_match(hash, direction) - |> where_transaction_has_multiple_internal_transactions() + |> InternalTransaction.where_is_different_from_parent_transaction() |> page_internal_transaction(paging_options) |> limit(^paging_options.page_size) |> order_by( - [it, transaction, block], - desc: block.number, - desc: transaction.index, + [it], + desc: it.block_number, + desc: it.transaction_index, desc: it.index ) |> preload(transaction: :block) @@ -1838,11 +1832,12 @@ defmodule Explorer.Chain do defp page_internal_transaction(query, %PagingOptions{key: {block_number, transaction_index, index}}) do where( query, - [internal_transaction, transaction], - transaction.block_number < ^block_number or - (transaction.block_number == ^block_number and transaction.index < ^transaction_index) or - (transaction.block_number == ^block_number and transaction.index == ^transaction_index and - internal_transaction.index < ^index) + [internal_transaction], + internal_transaction.block_number < ^block_number or + (internal_transaction.block_number == ^block_number and + internal_transaction.transaction_index < ^transaction_index) or + (internal_transaction.block_number == ^block_number and + internal_transaction.transaction_index == ^transaction_index and internal_transaction.index < ^index) ) end diff --git a/apps/explorer/lib/explorer/chain/import/blocks.ex b/apps/explorer/lib/explorer/chain/import/blocks.ex index 4f4004ca38..a1fa43d395 100644 --- a/apps/explorer/lib/explorer/chain/import/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/blocks.ex @@ -9,7 +9,7 @@ defmodule Explorer.Chain.Import.Blocks do alias Ecto.{Changeset, Multi} alias Ecto.Adapters.SQL - alias Explorer.Chain.{Block, Import, Transaction} + alias Explorer.Chain.{Block, Import, InternalTransaction, Transaction} alias Explorer.Repo @behaviour Import.Runner @@ -72,6 +72,31 @@ defmodule Explorer.Chain.Import.Blocks do } ) end) + |> Multi.run( + :internal_transaction_transaction_block_number, + fn %{blocks: blocks} -> + blocks_hashes = Enum.map(blocks, & &1.hash) + + query = + from( + internal_transaction in InternalTransaction, + join: transaction in Transaction, + on: internal_transaction.transaction_hash == transaction.hash, + join: block in Block, + on: block.hash == transaction.block_hash, + where: block.hash in ^blocks_hashes, + update: [ + set: [ + block_number: block.number + ] + ] + ) + + {total, _} = Repo.update_all(query, []) + + {:ok, total} + end + ) end @impl Import.Runner diff --git a/apps/explorer/lib/explorer/chain/internal_transaction.ex b/apps/explorer/lib/explorer/chain/internal_transaction.ex index c9611de932..d57ea5a1d1 100644 --- a/apps/explorer/lib/explorer/chain/internal_transaction.ex +++ b/apps/explorer/lib/explorer/chain/internal_transaction.ex @@ -62,6 +62,8 @@ defmodule Explorer.Chain.InternalTransaction do field(:trace_address, {:array, :integer}) field(:type, Type) field(:value, Wei) + field(:block_number, :integer) + field(:transaction_index, :integer) timestamps() @@ -112,7 +114,8 @@ defmodule Explorer.Chain.InternalTransaction do ...> trace_address: [], ...> transaction_hash: "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6", ...> type: "create", - ...> value: 0 + ...> value: 0, + ...> block_number: 35 ...> } ...> ) iex> changeset.valid? @@ -150,7 +153,9 @@ defmodule Explorer.Chain.InternalTransaction do ...> trace_address: [], ...> transaction_hash: "0x3c624bb4852fb5e35a8f45644cec7a486211f6ba89034768a2b763194f22f97d", ...> type: "create", - ...> value: 0 + ...> value: 0, + ...> block_number: 35, + ...> transaction_index: 0 ...> } iex> ) iex> changeset.valid? @@ -176,7 +181,9 @@ defmodule Explorer.Chain.InternalTransaction do ...> trace_address: [], ...> transaction_hash: "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6", ...> type: "call", - ...> value: 0 + ...> value: 0, + ...> block_number: 35, + ...> transaction_index: 0 ...> } ...> ) iex> changeset.valid? @@ -196,7 +203,9 @@ defmodule Explorer.Chain.InternalTransaction do ...> trace_address: [], ...> transaction_hash: "0xcd7c15dbbc797722bef6e1d551edfd644fc7f4fb2ccd6a7947b2d1ade9ed140b", ...> type: "call", - ...> value: 10000000000000000 + ...> value: 10000000000000000, + ...> block_number: 35, + ...> transaction_index: 0 ...> } ...> ) iex> changeset.valid? @@ -219,7 +228,9 @@ defmodule Explorer.Chain.InternalTransaction do ...> trace_address: [], ...> transaction_hash: "0xcd7c15dbbc797722bef6e1d551edfd644fc7f4fb2ccd6a7947b2d1ade9ed140b", ...> type: "call", - ...> value: 10000000000000000 + ...> value: 10000000000000000, + ...> block_number: 35, + ...> transaction_index: 0 ...> } ...> ) iex> changeset.valid? @@ -243,7 +254,9 @@ defmodule Explorer.Chain.InternalTransaction do ...> trace_address: [], ...> transaction_hash: "0xcd7c15dbbc797722bef6e1d551edfd644fc7f4fb2ccd6a7947b2d1ade9ed140b", ...> type: "call", - ...> value: 10000000000000000 + ...> value: 10000000000000000, + ...> block_number: 35, + ...> transaction_index: 0 ...> } ...> ) iex> changeset.valid? @@ -271,7 +284,9 @@ defmodule Explorer.Chain.InternalTransaction do ...> trace_address: [], ...> transaction_hash: "0x3c624bb4852fb5e35a8f45644cec7a486211f6ba89034768a2b763194f22f97d", ...> type: "create", - ...> value: 0 + ...> value: 0, + ...> block_number: 35, + ...> transaction_index: 0 ...> } iex> ) iex> changeset.valid? @@ -295,7 +310,9 @@ defmodule Explorer.Chain.InternalTransaction do ...> trace_address: [], ...> transaction_hash: "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6", ...> type: "create", - ...> value: 0 + ...> value: 0, + ...> block_number: 35, + ...> transaction_index: 0 ...> } ...> ) iex> changeset.valid? @@ -318,7 +335,9 @@ defmodule Explorer.Chain.InternalTransaction do ...> trace_address: [0], ...> transaction_hash: "0xb012b8c53498c669d87d85ed90f57385848b86d3f44ed14b2784ec685d6fda98", ...> type: "suicide", - ...> value: 0 + ...> value: 0, + ...> block_number: 35, + ...> transaction_index: 0 ...> } ...> ) iex> changeset.valid? @@ -338,7 +357,7 @@ defmodule Explorer.Chain.InternalTransaction do type_changeset(changeset, attrs, type) end - @call_optional_fields ~w(error gas_used output) + @call_optional_fields ~w(error gas_used output block_number transaction_index) @call_required_fields ~w(call_type from_address_hash gas index to_address_hash trace_address transaction_hash value)a @call_allowed_fields @call_optional_fields ++ @call_required_fields @@ -353,7 +372,7 @@ defmodule Explorer.Chain.InternalTransaction do |> unique_constraint(:index) end - @create_optional_fields ~w(error created_contract_code created_contract_address_hash gas_used) + @create_optional_fields ~w(error created_contract_code created_contract_address_hash gas_used block_number transaction_index) @create_required_fields ~w(from_address_hash gas index init trace_address transaction_hash value)a @create_allowed_fields @create_optional_fields ++ @create_required_fields @@ -368,8 +387,9 @@ defmodule Explorer.Chain.InternalTransaction do |> unique_constraint(:index) end + @suicide_optional_fields ~w(block_number transaction_index) @suicide_required_fields ~w(from_address_hash index to_address_hash trace_address transaction_hash type value)a - @suicide_allowed_fields @suicide_required_fields + @suicide_allowed_fields @suicide_optional_fields ++ @suicide_required_fields defp type_changeset(changeset, attrs, :suicide) do changeset @@ -448,4 +468,12 @@ defmodule Explorer.Chain.InternalTransaction do it.created_contract_address_hash == ^address_hash ) end + + def where_is_different_from_parent_transaction(query) do + where( + query, + [it], + (it.type == ^:call and it.index > 0) or it.type != ^:call + ) + end end diff --git a/apps/explorer/lib/mix/tasks/migrate.transaction.info.ex b/apps/explorer/lib/mix/tasks/migrate.transaction.info.ex new file mode 100644 index 0000000000..5bb00b8675 --- /dev/null +++ b/apps/explorer/lib/mix/tasks/migrate.transaction.info.ex @@ -0,0 +1,32 @@ +defmodule Mix.Tasks.Migrate.Transaction.Info do + use Mix.Task + + alias Explorer.Repo + alias Ecto.Adapters.SQL + + @shortdoc "Migrates transaction info to internal transaction" + + @moduledoc """ + This task is reponsible to populate the `transaction_index` and + `block_number` at the `internal_transactions` table, using the + `transactions` info. + """ + + def run(_args) do + {:ok, _} = Application.ensure_all_started(:explorer) + + SQL.query( + Repo, + """ + UPDATE internal_transactions + SET + block_number = transactions.block_number, + transaction_index = transactions.index + FROM transactions + WHERE internal_transactions.transaction_hash = transactions.hash; + """, + [], + timeout: :infinity + ) + end +end diff --git a/apps/explorer/mix.exs b/apps/explorer/mix.exs index 417b978c70..366289e06d 100644 --- a/apps/explorer/mix.exs +++ b/apps/explorer/mix.exs @@ -97,7 +97,8 @@ defmodule Explorer.Mixfile do {:prometheus_ecto, "~> 1.3"}, {:sobelow, ">= 0.7.0", only: [:dev, :test], runtime: false}, {:timex, "~> 3.1.24"}, - {:timex_ecto, "~> 3.2.1"} + {:timex_ecto, "~> 3.2.1"}, + {:cowboy, "~> 1.0"} ] end diff --git a/apps/explorer/priv/repo/migrations/20181011193212_add_fields_to_internal_transactions.exs b/apps/explorer/priv/repo/migrations/20181011193212_add_fields_to_internal_transactions.exs new file mode 100644 index 0000000000..9eda36fe32 --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20181011193212_add_fields_to_internal_transactions.exs @@ -0,0 +1,17 @@ +defmodule Explorer.Repo.Migrations.AddFieldsToInternalTransactions do + use Ecto.Migration + + def up do + alter table("internal_transactions") do + add(:block_number, :integer) + add(:transaction_index, :integer) + end + end + + def down do + alter table("internal_transactions") do + remove(:block_number) + remove(:transaction_index) + end + end +end diff --git a/apps/explorer/priv/repo/migrations/20181017141409_add_index_to_internal_transaction_table.exs b/apps/explorer/priv/repo/migrations/20181017141409_add_index_to_internal_transaction_table.exs new file mode 100644 index 0000000000..0f7e6c1837 --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20181017141409_add_index_to_internal_transaction_table.exs @@ -0,0 +1,17 @@ +defmodule Explorer.Repo.Migrations.AddIndexToInternalTransactionTable do + use Ecto.Migration + + def change do + create( + index("internal_transactions", [ + :to_address_hash, + :from_address_hash, + :created_contract_address_hash, + :type, + :index + ]) + ) + + create(index(:internal_transactions, ["block_number DESC, transaction_index DESC, index DESC"])) + end +end diff --git a/apps/explorer/test/explorer/chain/import_test.exs b/apps/explorer/test/explorer/chain/import_test.exs index 49198560a0..21b493ca76 100644 --- a/apps/explorer/test/explorer/chain/import_test.exs +++ b/apps/explorer/test/explorer/chain/import_test.exs @@ -56,7 +56,9 @@ defmodule Explorer.Chain.ImportTest do trace_address: [], transaction_hash: "0x53bd884872de3e488692881baeec262e7b95234d3965248c39fe992fffd433e5", type: "call", - value: 0 + value: 0, + block_number: 35, + transaction_index: 0 }, %{ call_type: "call", @@ -69,7 +71,9 @@ defmodule Explorer.Chain.ImportTest do trace_address: [], transaction_hash: "0x53bd884872de3e488692881baeec262e7b95234d3965248c39fe992fffd433e5", type: "call", - value: 0 + value: 0, + block_number: 35, + transaction_index: 1 } ], timeout: 5 @@ -497,7 +501,9 @@ defmodule Explorer.Chain.ImportTest do trace_address: [], transaction_hash: transaction_string_hash, type: "create", - value: 0 + value: 0, + block_number: 35, + transaction_index: 0 } ] } @@ -579,7 +585,9 @@ defmodule Explorer.Chain.ImportTest do trace_address: [], transaction_hash: transaction_hash, type: "call", - value: 0 + value: 0, + transaction_block_number: 35, + transaction_index: 0 } ] } @@ -672,7 +680,8 @@ defmodule Explorer.Chain.ImportTest do trace_address: [], transaction_hash: transaction_hash, type: "create", - value: 0 + value: 0, + transaction_index: 0 } ] } @@ -763,7 +772,9 @@ defmodule Explorer.Chain.ImportTest do trace_address: [], transaction_hash: "0x53bd884872de3e488692881baeec262e7b95234d3965248c39fe992fffd433e5", type: "create", - value: 0 + value: 0, + block_number: 35, + transaction_index: 0 }, %{ created_contract_address_hash: "0xffc87239eb0267bc3ca2cd51d12fbf278e02ccb5", @@ -778,7 +789,9 @@ defmodule Explorer.Chain.ImportTest do trace_address: [], transaction_hash: "0x53bd884872de3e488692881baeec262e7b95234d3965248c39fe992fffd433e5", type: "create", - value: 0 + value: 0, + block_number: 35, + transaction_index: 1 } ], timeout: 5 @@ -948,7 +961,9 @@ defmodule Explorer.Chain.ImportTest do trace_address: [], transaction_hash: "0x1a263224a95275d77bc30a7e131bc64d948777946a790c0915ab293791fbcb61", type: "create", - value: 0 + value: 0, + transaction_index: 0, + transaction_block_number: 35 }, %{ block_number: 6_546_180, @@ -960,7 +975,9 @@ defmodule Explorer.Chain.ImportTest do trace_address: [], transaction_hash: "0xab349efbe1ddc6d85d84a993aa52bdaadce66e8ee166dd10013ce3f2a94ca724", type: "create", - value: 0 + value: 0, + transaction_index: 0, + transaction_block_number: 35 } ] } @@ -1441,7 +1458,9 @@ defmodule Explorer.Chain.ImportTest do transaction_hash: transaction_hash, index: 0, from_address_hash: from_address_hash, - to_address_hash: to_address_hash + to_address_hash: to_address_hash, + block_number: 35, + transaction_index: 0 ) ], timeout: 1 @@ -1707,7 +1726,9 @@ defmodule Explorer.Chain.ImportTest do to_address_hash: to_address_hash_before, trace_address: [], value: 0, - error: error + error: error, + block_number: 35, + transaction_index: 0 } ] } diff --git a/apps/explorer/test/explorer/chain/internal_transaction_test.exs b/apps/explorer/test/explorer/chain/internal_transaction_test.exs index b82bfa908c..2b92339515 100644 --- a/apps/explorer/test/explorer/chain/internal_transaction_test.exs +++ b/apps/explorer/test/explorer/chain/internal_transaction_test.exs @@ -22,7 +22,8 @@ defmodule Explorer.Chain.InternalTransactionTest do trace_address: [0, 1], transaction_hash: transaction.hash, type: "call", - value: 100 + value: 100, + block_number: 35 }) assert changeset.valid? diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index 22e6842cd3..3c0fd8bc9b 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -193,7 +193,12 @@ defmodule Explorer.ChainTest do |> with_block() %InternalTransaction{created_contract_address: address} = - insert(:internal_transaction_create, transaction: transaction, index: 0) + insert(:internal_transaction_create, + transaction: transaction, + index: 0, + block_number: transaction.block_number, + transaction_index: transaction.index + ) assert [] == Chain.address_to_transactions(address) end @@ -687,10 +692,20 @@ defmodule Explorer.ChainTest do |> insert() |> with_block() - insert(:internal_transaction, transaction: transaction, index: 0) + insert(:internal_transaction, + transaction: transaction, + index: 0, + block_number: transaction.block_number, + transaction_index: transaction.index + ) Enum.each(1..3, fn index -> - insert(:internal_transaction_create, transaction: transaction, index: index) + insert(:internal_transaction_create, + transaction: transaction, + index: index, + block_number: transaction.block_number, + transaction_index: transaction.index + ) end) assert {:ok, %Transaction{hash: ^hash_with_block}} = Chain.hash_to_transaction(hash_with_block) @@ -1250,12 +1265,28 @@ defmodule Explorer.ChainTest do transaction = insert(:transaction) %InternalTransaction{id: first_id} = - insert(:internal_transaction, index: 0, transaction: transaction, to_address: address) + insert(:internal_transaction, + index: 1, + transaction: transaction, + to_address: address, + block_number: transaction.block_number, + transaction_index: transaction.index + ) %InternalTransaction{id: second_id} = - insert(:internal_transaction, index: 1, transaction: transaction, to_address: address) + insert(:internal_transaction, + index: 2, + transaction: transaction, + to_address: address, + block_number: transaction.block_number, + transaction_index: transaction.index + ) + + result = + address + |> Chain.address_to_internal_transactions() + |> Enum.map(& &1.id) - result = address |> Chain.address_to_internal_transactions() |> Enum.map(& &1.id) assert Enum.member?(result, first_id) assert Enum.member?(result, second_id) end @@ -1263,8 +1294,22 @@ defmodule Explorer.ChainTest do test "loads associations in necessity_by_association" do address = insert(:address) transaction = insert(:transaction, to_address: address) - insert(:internal_transaction, transaction: transaction, to_address: address, index: 0) - insert(:internal_transaction, transaction: transaction, to_address: address, index: 1) + + insert(:internal_transaction, + transaction: transaction, + to_address: address, + index: 0, + block_number: transaction.block_number, + transaction_index: transaction.index + ) + + insert(:internal_transaction, + transaction: transaction, + to_address: address, + index: 1, + block_number: transaction.block_number, + transaction_index: transaction.index + ) assert [ %InternalTransaction{ @@ -1303,7 +1348,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: pending_transaction, to_address: address, - index: 0 + index: 1, + block_number: pending_transaction.block_number, + transaction_index: pending_transaction.index ) %InternalTransaction{id: second_pending} = @@ -1311,7 +1358,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: pending_transaction, to_address: address, - index: 1 + index: 2, + block_number: pending_transaction.block_number, + transaction_index: pending_transaction.index ) a_block = insert(:block, number: 2000) @@ -1326,7 +1375,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: first_a_transaction, to_address: address, - index: 0 + index: 1, + block_number: first_a_transaction.block_number, + transaction_index: first_a_transaction.index ) %InternalTransaction{id: second} = @@ -1334,7 +1385,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: first_a_transaction, to_address: address, - index: 1 + index: 2, + block_number: first_a_transaction.block_number, + transaction_index: first_a_transaction.index ) second_a_transaction = @@ -1347,7 +1400,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: second_a_transaction, to_address: address, - index: 0 + index: 1, + block_number: second_a_transaction.block_number, + transaction_index: second_a_transaction.index ) %InternalTransaction{id: fourth} = @@ -1355,7 +1410,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: second_a_transaction, to_address: address, - index: 1 + index: 2, + block_number: second_a_transaction.block_number, + transaction_index: second_a_transaction.index ) b_block = insert(:block, number: 6000) @@ -1370,7 +1427,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: first_b_transaction, to_address: address, - index: 0 + index: 1, + block_number: first_b_transaction.block_number, + transaction_index: first_b_transaction.index ) %InternalTransaction{id: sixth} = @@ -1378,7 +1437,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: first_b_transaction, to_address: address, - index: 1 + index: 2, + block_number: first_b_transaction.block_number, + transaction_index: first_b_transaction.index ) result = @@ -1398,14 +1459,14 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: pending_transaction, to_address: address, - index: 0 + index: 1 ) insert( :internal_transaction, transaction: pending_transaction, to_address: address, - index: 1 + index: 2 ) a_block = insert(:block, number: 2000) @@ -1420,7 +1481,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: first_a_transaction, to_address: address, - index: 0 + index: 1, + block_number: first_a_transaction.block_number, + transaction_index: first_a_transaction.index ) %InternalTransaction{id: second} = @@ -1428,7 +1491,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: first_a_transaction, to_address: address, - index: 1 + index: 2, + block_number: first_a_transaction.block_number, + transaction_index: first_a_transaction.index ) second_a_transaction = @@ -1441,7 +1506,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: second_a_transaction, to_address: address, - index: 0 + index: 1, + block_number: second_a_transaction.block_number, + transaction_index: second_a_transaction.index ) %InternalTransaction{id: fourth} = @@ -1449,7 +1516,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: second_a_transaction, to_address: address, - index: 1 + index: 2, + block_number: second_a_transaction.block_number, + transaction_index: second_a_transaction.index ) b_block = insert(:block, number: 6000) @@ -1464,7 +1533,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: first_b_transaction, to_address: address, - index: 0 + index: 1, + block_number: first_b_transaction.block_number, + transaction_index: first_b_transaction.index ) %InternalTransaction{id: sixth} = @@ -1472,7 +1543,9 @@ defmodule Explorer.ChainTest do :internal_transaction, transaction: first_b_transaction, to_address: address, - index: 1 + index: 2, + block_number: first_b_transaction.block_number, + transaction_index: first_b_transaction.index ) # When paged, internal transactions need an associated block number, so `second_pending` and `first_pending` are @@ -1485,7 +1558,7 @@ defmodule Explorer.ChainTest do |> Enum.map(& &1.id) # block number ==, transaction index ==, internal transaction index < - assert [fifth, fourth, third, second, first] == + assert [fourth, third, second, first] == address |> Chain.address_to_internal_transactions( paging_options: %PagingOptions{key: {6000, 0, 1}, page_size: 8} @@ -1517,7 +1590,13 @@ defmodule Explorer.ChainTest do |> insert(to_address: address) |> with_block() - insert(:internal_transaction, index: 0, to_address: address, transaction: transaction) + insert(:internal_transaction, + index: 0, + to_address: address, + transaction: transaction, + block_number: transaction.block_number, + transaction_index: transaction.index + ) assert Enum.empty?(Chain.address_to_internal_transactions(address)) end @@ -1535,7 +1614,9 @@ defmodule Explorer.ChainTest do :internal_transaction_create, index: 0, from_address: address, - transaction: transaction + transaction: transaction, + block_number: transaction.block_number, + transaction_index: transaction.index ) actual = Enum.at(Chain.address_to_internal_transactions(address), 0) @@ -1592,8 +1673,21 @@ defmodule Explorer.ChainTest do |> insert() |> with_block(block) - first = insert(:internal_transaction, transaction: transaction, index: 0) - second = insert(:internal_transaction, transaction: transaction, index: 1) + first = + insert(:internal_transaction, + transaction: transaction, + index: 0, + block_number: transaction.block_number, + transaction_index: transaction.index + ) + + second = + insert(:internal_transaction, + transaction: transaction, + index: 1, + block_number: transaction.block_number, + transaction_index: transaction.index + ) results = [internal_transaction | _] = Chain.transaction_to_internal_transactions(transaction) @@ -1604,7 +1698,13 @@ defmodule Explorer.ChainTest do test "with transaction with internal transactions loads associations with in necessity_by_association" do transaction = insert(:transaction) - insert(:internal_transaction_create, transaction: transaction, index: 0) + + insert(:internal_transaction_create, + transaction: transaction, + index: 0, + block_number: transaction.block_number, + transaction_index: transaction.index + ) assert [ %InternalTransaction{ @@ -1637,7 +1737,12 @@ defmodule Explorer.ChainTest do |> insert() |> with_block() - insert(:internal_transaction, transaction: transaction, index: 0) + insert(:internal_transaction, + transaction: transaction, + index: 0, + block_number: transaction.block_number, + transaction_index: transaction.index + ) result = Chain.transaction_to_internal_transactions(transaction) @@ -1650,7 +1755,13 @@ defmodule Explorer.ChainTest do |> insert() |> with_block() - expected = insert(:internal_transaction_create, index: 0, transaction: transaction) + expected = + insert(:internal_transaction_create, + index: 0, + transaction: transaction, + block_number: transaction.block_number, + transaction_index: transaction.index + ) actual = Enum.at(Chain.transaction_to_internal_transactions(transaction), 0) @@ -1663,7 +1774,14 @@ defmodule Explorer.ChainTest do |> insert() |> with_block() - expected = insert(:internal_transaction, index: 0, transaction: transaction, type: :reward) + expected = + insert(:internal_transaction, + index: 0, + transaction: transaction, + type: :reward, + block_number: transaction.block_number, + transaction_index: transaction.index + ) actual = Enum.at(Chain.transaction_to_internal_transactions(transaction), 0) @@ -1676,7 +1794,15 @@ defmodule Explorer.ChainTest do |> insert() |> with_block() - expected = insert(:internal_transaction, index: 0, transaction: transaction, gas: nil, type: :suicide) + expected = + insert(:internal_transaction, + index: 0, + transaction: transaction, + gas: nil, + type: :suicide, + block_number: transaction.block_number, + transaction_index: transaction.index + ) actual = Enum.at(Chain.transaction_to_internal_transactions(transaction), 0) @@ -1689,8 +1815,21 @@ defmodule Explorer.ChainTest do |> insert() |> with_block() - %InternalTransaction{id: first_id} = insert(:internal_transaction, transaction: transaction, index: 0) - %InternalTransaction{id: second_id} = insert(:internal_transaction, transaction: transaction, index: 1) + %InternalTransaction{id: first_id} = + insert(:internal_transaction, + transaction: transaction, + index: 0, + block_number: transaction.block_number, + transaction_index: transaction.index + ) + + %InternalTransaction{id: second_id} = + insert(:internal_transaction, + transaction: transaction, + index: 1, + block_number: transaction.block_number, + transaction_index: transaction.index + ) result = transaction @@ -1706,8 +1845,21 @@ defmodule Explorer.ChainTest do |> insert() |> with_block() - %InternalTransaction{id: first_id} = insert(:internal_transaction, transaction: transaction, index: 0) - %InternalTransaction{id: second_id} = insert(:internal_transaction, transaction: transaction, index: 1) + %InternalTransaction{id: first_id} = + insert(:internal_transaction, + transaction: transaction, + index: 0, + block_number: transaction.block_number, + transaction_index: transaction.index + ) + + %InternalTransaction{id: second_id} = + insert(:internal_transaction, + transaction: transaction, + index: 1, + block_number: transaction.block_number, + transaction_index: transaction.index + ) assert [^first_id, ^second_id] = transaction @@ -1993,7 +2145,9 @@ defmodule Explorer.ChainTest do transaction: transaction, index: 0, created_contract_address: created_contract_address, - created_contract_code: smart_contract_bytecode + created_contract_code: smart_contract_bytecode, + block_number: transaction.block_number, + transaction_index: transaction.index ) assert Chain.smart_contract_bytecode(created_contract_address.hash) == smart_contract_bytecode @@ -2022,7 +2176,9 @@ defmodule Explorer.ChainTest do transaction: transaction, index: 0, created_contract_address: created_contract_address, - created_contract_code: smart_contract_bytecode + created_contract_code: smart_contract_bytecode, + block_number: transaction.block_number, + transaction_index: transaction.index ) valid_attrs = %{ @@ -2220,7 +2376,9 @@ defmodule Explorer.ChainTest do :internal_transaction_create, created_contract_address: created_contract_address, index: 0, - transaction: transaction + transaction: transaction, + block_number: transaction.block_number, + transaction_index: transaction.index ) balance = insert(:unfetched_balance, address_hash: created_contract_address.hash, block_number: block.number) @@ -2264,7 +2422,9 @@ defmodule Explorer.ChainTest do :internal_transaction_create, from_address: from_address, index: 0, - transaction: transaction + transaction: transaction, + block_number: transaction.block_number, + transaction_index: transaction.index ) balance = insert(:unfetched_balance, address_hash: from_address.hash, block_number: block.number) @@ -2302,7 +2462,9 @@ defmodule Explorer.ChainTest do :internal_transaction_create, to_address: to_address, index: 0, - transaction: transaction + transaction: transaction, + block_number: transaction.block_number, + transaction_index: transaction.index ) balance = insert(:unfetched_balance, address_hash: to_address.hash, block_number: block.number) @@ -2369,7 +2531,9 @@ defmodule Explorer.ChainTest do :internal_transaction_create, from_address: miner, index: 0, - transaction: from_internal_transaction_transaction + transaction: from_internal_transaction_transaction, + block_number: from_internal_transaction_transaction.block_number, + transaction_index: from_internal_transaction_transaction.index ) insert(:unfetched_balance, address_hash: miner.hash, block_number: from_internal_transaction_block.number) @@ -2385,7 +2549,9 @@ defmodule Explorer.ChainTest do :internal_transaction_create, index: 0, to_address: miner, - transaction: to_internal_transaction_transaction + transaction: to_internal_transaction_transaction, + block_number: to_internal_transaction_transaction.block_number, + transaction_index: to_internal_transaction_transaction.index ) insert(:unfetched_balance, address_hash: miner.hash, block_number: to_internal_transaction_block.number) @@ -2439,7 +2605,9 @@ defmodule Explorer.ChainTest do :internal_transaction_create, from_address: miner, index: 0, - transaction: from_internal_transaction_transaction + transaction: from_internal_transaction_transaction, + block_number: from_internal_transaction_transaction.block_number, + transaction_index: from_internal_transaction_transaction.index ) to_internal_transaction_transaction = @@ -2451,7 +2619,9 @@ defmodule Explorer.ChainTest do :internal_transaction_create, to_address: miner, index: 0, - transaction: to_internal_transaction_transaction + transaction: to_internal_transaction_transaction, + block_number: to_internal_transaction_transaction.block_number, + transaction_index: to_internal_transaction_transaction.index ) {:ok, balance_fields_list} = diff --git a/apps/explorer/test/explorer/etherscan_test.exs b/apps/explorer/test/explorer/etherscan_test.exs index b192eebf5b..c100edabe3 100644 --- a/apps/explorer/test/explorer/etherscan_test.exs +++ b/apps/explorer/test/explorer/etherscan_test.exs @@ -64,7 +64,12 @@ defmodule Explorer.EtherscanTest do %{created_contract_address_hash: contract_address_hash} = :internal_transaction_create - |> insert(transaction: transaction, index: 0) + |> insert( + transaction: transaction, + index: 0, + block_number: transaction.block_number, + transaction_index: transaction.index + ) |> with_contract_creation(contract_address) [found_transaction] = Etherscan.list_transactions(contract_address_hash) @@ -135,7 +140,12 @@ defmodule Explorer.EtherscanTest do %{created_contract_address_hash: contract_hash} = :internal_transaction_create - |> insert(transaction: transaction, index: 0) + |> insert( + transaction: transaction, + index: 0, + block_number: transaction.block_number, + transaction_index: transaction.index + ) |> with_contract_creation(contract_address) [found_transaction] = Etherscan.list_transactions(address.hash) @@ -470,7 +480,13 @@ defmodule Explorer.EtherscanTest do internal_transaction = :internal_transaction_create - |> insert(transaction: transaction, index: 0, from_address: address) + |> insert( + transaction: transaction, + index: 0, + from_address: address, + block_number: transaction.block_number, + transaction_index: transaction.index + ) |> with_contract_creation(contract_address) [found_internal_transaction] = Etherscan.list_internal_transactions(transaction.hash) @@ -507,7 +523,12 @@ defmodule Explorer.EtherscanTest do |> with_block() for index <- 0..2 do - insert(:internal_transaction, transaction: transaction, index: index) + insert(:internal_transaction, + transaction: transaction, + index: index, + block_number: transaction.block_number, + transaction_index: transaction.index + ) end found_internal_transactions = Etherscan.list_internal_transactions(transaction.hash) @@ -526,9 +547,27 @@ defmodule Explorer.EtherscanTest do |> insert() |> with_block() - insert(:internal_transaction, transaction: transaction1, index: 0) - insert(:internal_transaction, transaction: transaction1, index: 1) - insert(:internal_transaction, transaction: transaction2, index: 0, type: :reward) + insert(:internal_transaction, + transaction: transaction1, + index: 0, + block_number: transaction1.block_number, + transaction_index: transaction1.index + ) + + insert(:internal_transaction, + transaction: transaction1, + index: 1, + block_number: transaction1.block_number, + transaction_index: transaction1.index + ) + + insert(:internal_transaction, + transaction: transaction2, + index: 0, + type: :reward, + block_number: transaction2.block_number, + transaction_index: transaction2.index + ) internal_transactions1 = Etherscan.list_internal_transactions(transaction1.hash) @@ -573,7 +612,13 @@ defmodule Explorer.EtherscanTest do internal_transaction = :internal_transaction_create - |> insert(transaction: transaction, index: 0, from_address: address) + |> insert( + transaction: transaction, + index: 0, + from_address: address, + block_number: transaction.block_number, + transaction_index: transaction.index + ) |> with_contract_creation(contract_address) [found_internal_transaction] = Etherscan.list_internal_transactions(address.hash) @@ -616,7 +661,9 @@ defmodule Explorer.EtherscanTest do internal_transaction_details = %{ transaction: transaction, index: index, - from_address: address + from_address: address, + block_number: transaction.block_number, + transaction_index: transaction.index } insert(:internal_transaction, internal_transaction_details) @@ -636,10 +683,37 @@ defmodule Explorer.EtherscanTest do |> insert() |> with_block() - insert(:internal_transaction, transaction: transaction, index: 0, created_contract_address: address1) - insert(:internal_transaction, transaction: transaction, index: 1, from_address: address1) - insert(:internal_transaction, transaction: transaction, index: 2, to_address: address1) - insert(:internal_transaction, transaction: transaction, index: 3, from_address: address2) + insert(:internal_transaction, + transaction: transaction, + index: 0, + block_number: transaction.block_number, + transaction_index: transaction.index, + created_contract_address: address1 + ) + + insert(:internal_transaction, + transaction: transaction, + index: 1, + block_number: transaction.block_number, + transaction_index: transaction.index, + from_address: address1 + ) + + insert(:internal_transaction, + transaction: transaction, + index: 2, + block_number: transaction.block_number, + transaction_index: transaction.index, + to_address: address1 + ) + + insert(:internal_transaction, + transaction: transaction, + index: 3, + block_number: transaction.block_number, + transaction_index: transaction.index, + from_address: address2 + ) internal_transactions1 = Etherscan.list_internal_transactions(address1.hash) @@ -662,7 +736,9 @@ defmodule Explorer.EtherscanTest do internal_transaction_details = %{ transaction: transaction, index: index, - from_address: address + from_address: address, + block_number: transaction.block_number, + transaction_index: transaction.index } insert(:internal_transaction, internal_transaction_details) @@ -700,7 +776,9 @@ defmodule Explorer.EtherscanTest do internal_transaction_details = %{ transaction: transaction, index: index, - from_address: address + from_address: address, + block_number: transaction.block_number, + transaction_index: transaction.index } insert(:internal_transaction, internal_transaction_details) diff --git a/apps/explorer/test/explorer/repo_test.exs b/apps/explorer/test/explorer/repo_test.exs index 4a417f0c70..81e3325a70 100644 --- a/apps/explorer/test/explorer/repo_test.exs +++ b/apps/explorer/test/explorer/repo_test.exs @@ -18,7 +18,9 @@ defmodule Explorer.RepoTest do from_address_hash: insert(:address).hash, to_address_hash: insert(:address).hash, transaction_hash: transaction.hash, - index: 0 + index: 0, + block_number: 35, + transaction_index: 0 ) %Changeset{valid?: true, changes: changes} = InternalTransaction.changeset(%InternalTransaction{}, params) diff --git a/apps/indexer/lib/indexer/block/catchup/fetcher.ex b/apps/indexer/lib/indexer/block/catchup/fetcher.ex index 4db603b108..36ee5a90d5 100644 --- a/apps/indexer/lib/indexer/block/catchup/fetcher.ex +++ b/apps/indexer/lib/indexer/block/catchup/fetcher.ex @@ -127,8 +127,9 @@ defmodule Indexer.Block.Catchup.Fetcher do }) do transactions |> Enum.map(fn transaction_hash -> - block_number = Map.fetch!(transaction_hash_to_block_number, to_string(transaction_hash)) - %{block_number: block_number, hash: transaction_hash} + transaction = Map.fetch!(transaction_hash_to_block_number, to_string(transaction_hash)) + + %{block_number: transaction[:block_number], hash: transaction_hash, index: transaction[:index]} end) |> InternalTransaction.Fetcher.async_fetch(10_000) end diff --git a/apps/indexer/lib/indexer/block/fetcher.ex b/apps/indexer/lib/indexer/block/fetcher.ex index 02a665e3ff..76fccbdfa2 100644 --- a/apps/indexer/lib/indexer/block/fetcher.ex +++ b/apps/indexer/lib/indexer/block/fetcher.ex @@ -218,8 +218,8 @@ defmodule Indexer.Block.Fetcher do defp get_transaction_hash_to_block_number(options) do options |> get_in([:transactions, :params, Access.all()]) - |> Enum.into(%{}, fn %{block_number: block_number, hash: hash} -> - {hash, block_number} + |> Enum.into(%{}, fn %{block_number: block_number, hash: hash, index: index} -> + {hash, %{block_number: block_number, index: index}} end) end diff --git a/apps/indexer/lib/indexer/block/realtime/fetcher.ex b/apps/indexer/lib/indexer/block/realtime/fetcher.ex index 5c66110545..f84e19ffc1 100644 --- a/apps/indexer/lib/indexer/block/realtime/fetcher.ex +++ b/apps/indexer/lib/indexer/block/realtime/fetcher.ex @@ -234,9 +234,13 @@ defmodule Indexer.Block.Realtime.Fetcher do Enum.map(transactions_params, &transaction_params_to_fetch_internal_transaction_params/1) end - defp transaction_params_to_fetch_internal_transaction_params(%{block_number: block_number, hash: hash}) + defp transaction_params_to_fetch_internal_transaction_params(%{ + block_number: block_number, + hash: hash, + transaction_index: transaction_index + }) when is_integer(block_number) do - %{block_number: block_number, hash_data: to_string(hash)} + %{block_number: block_number, hash_data: to_string(hash), transaction_index: transaction_index} end defp balances( diff --git a/apps/indexer/lib/indexer/internal_transaction/fetcher.ex b/apps/indexer/lib/indexer/internal_transaction/fetcher.ex index 5840af7217..a5bc18fa66 100644 --- a/apps/indexer/lib/indexer/internal_transaction/fetcher.ex +++ b/apps/indexer/lib/indexer/internal_transaction/fetcher.ex @@ -70,7 +70,7 @@ defmodule Indexer.InternalTransaction.Fetcher do def init(initial, reducer, _) do {:ok, final} = Chain.stream_transactions_with_unfetched_internal_transactions( - [:block_number, :hash], + [:block_number, :hash, :index], initial, fn transaction_fields, acc -> transaction_fields @@ -82,13 +82,13 @@ defmodule Indexer.InternalTransaction.Fetcher do final end - defp entry(%{block_number: block_number, hash: %Hash{bytes: bytes}}) when is_integer(block_number) do - {block_number, bytes} + defp entry(%{block_number: block_number, hash: %Hash{bytes: bytes}, index: index}) when is_integer(block_number) do + {block_number, bytes, index} end - defp params({block_number, hash_bytes}) when is_integer(block_number) do + defp params({block_number, hash_bytes, index}) when is_integer(block_number) do {:ok, hash} = Hash.Full.cast(hash_bytes) - %{block_number: block_number, hash_data: to_string(hash)} + %{block_number: block_number, hash_data: to_string(hash), transaction_index: index} end @impl BufferedTask diff --git a/apps/indexer/test/indexer/internal_transaction/fetcher_test.exs b/apps/indexer/test/indexer/internal_transaction/fetcher_test.exs index ec7db54b93..cb861b522d 100644 --- a/apps/indexer/test/indexer/internal_transaction/fetcher_test.exs +++ b/apps/indexer/test/indexer/internal_transaction/fetcher_test.exs @@ -101,7 +101,7 @@ defmodule Indexer.InternalTransaction.FetcherTest do [], fn hash_string, acc -> [hash_string | acc] end, json_rpc_named_arguments - ) == [{block.number, collated_unfetched_transaction.hash.bytes}] + ) == [{block.number, collated_unfetched_transaction.hash.bytes, collated_unfetched_transaction.index}] end test "does not buffer collated transactions with fetched internal transactions", %{ @@ -136,8 +136,8 @@ defmodule Indexer.InternalTransaction.FetcherTest do capture_log(fn -> InternalTransaction.Fetcher.run( [ - {1, bytes}, - {1, bytes} + {1, bytes, 0}, + {1, bytes, 0} ], 0, json_rpc_named_arguments @@ -147,8 +147,8 @@ defmodule Indexer.InternalTransaction.FetcherTest do assert log =~ """ Duplicate entries being used to fetch internal transactions: - 1. {1, <<3, 205, 88, 153, 166, 59, 111, 98, 34, 175, 218, 135, 5, 208, 89, 253, 90, 125, 18, 107, 202, 190, 150, 47, 182, 84, 217, 115, 110, 107, 202, 250>>} - 2. {1, <<3, 205, 88, 153, 166, 59, 111, 98, 34, 175, 218, 135, 5, 208, 89, 253, 90, 125, 18, 107, 202, 190, 150, 47, 182, 84, 217, 115, 110, 107, 202, 250>>} + 1. {1, <<3, 205, 88, 153, 166, 59, 111, 98, 34, 175, 218, 135, 5, 208, 89, 253, 90, 125, 18, 107, 202, 190, 150, 47, 182, 84, 217, 115, 110, 107, 202, 250>>, 0} + 2. {1, <<3, 205, 88, 153, 166, 59, 111, 98, 34, 175, 218, 135, 5, 208, 89, 253, 90, 125, 18, 107, 202, 190, 150, 47, 182, 84, 217, 115, 110, 107, 202, 250>>, 0} """ end @@ -167,12 +167,12 @@ defmodule Indexer.InternalTransaction.FetcherTest do assert InternalTransaction.Fetcher.run( [ - {1, bytes}, - {1, bytes} + {1, bytes, 0}, + {1, bytes, 0} ], 0, json_rpc_named_arguments - ) == {:retry, [{1, bytes}]} + ) == {:retry, [{1, bytes, 0}]} end end end