Merge pull request #928 from poanetwork/ams-internal-transaction-performance

Improve Internal Transactions listing performance
pull/945/head
Andrew Cravenho 6 years ago committed by GitHub
commit bcc340eb70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 22
      apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs
  2. 16
      apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs
  3. 22
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity.ex
  4. 63
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity/trace.ex
  5. 9
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex
  6. 3
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transactions.ex
  7. 4
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/http/mox_test.exs
  8. 32
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/parity_test.exs
  9. 29
      apps/explorer/lib/explorer/chain.ex
  10. 27
      apps/explorer/lib/explorer/chain/import/blocks.ex
  11. 52
      apps/explorer/lib/explorer/chain/internal_transaction.ex
  12. 32
      apps/explorer/lib/mix/tasks/migrate.transaction.info.ex
  13. 3
      apps/explorer/mix.exs
  14. 17
      apps/explorer/priv/repo/migrations/20181011193212_add_fields_to_internal_transactions.exs
  15. 17
      apps/explorer/priv/repo/migrations/20181017141409_add_index_to_internal_transaction_table.exs
  16. 43
      apps/explorer/test/explorer/chain/import_test.exs
  17. 3
      apps/explorer/test/explorer/chain/internal_transaction_test.exs
  18. 264
      apps/explorer/test/explorer/chain_test.exs
  19. 108
      apps/explorer/test/explorer/etherscan_test.exs
  20. 4
      apps/explorer/test/explorer/repo_test.exs
  21. 5
      apps/indexer/lib/indexer/block/catchup/fetcher.ex
  22. 4
      apps/indexer/lib/indexer/block/fetcher.ex
  23. 8
      apps/indexer/lib/indexer/block/realtime/fetcher.ex
  24. 10
      apps/indexer/lib/indexer/internal_transaction/fetcher.ex
  25. 16
      apps/indexer/test/indexer/internal_transaction/fetcher_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), %{

@ -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)

@ -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

@ -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

@ -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

@ -55,7 +55,8 @@ defmodule EthereumJSONRPC.Transactions do
s: "0x72caddc0371451a58de2ca6ab64e0f586ccdb9465ff54e1c82564940e89291e3",
to_address_hash: nil,
v: "0xbd",
value: 0
value: 0,
transaction_index: 0
}
]

@ -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)

@ -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."

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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
}
]
}

@ -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?

@ -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} =

@ -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)

@ -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)

@ -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

@ -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

@ -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(

@ -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

@ -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

Loading…
Cancel
Save