From a0befb0b86ec186790d1d09042393bc98973a33e Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 6 Jun 2018 13:10:04 -0500 Subject: [PATCH] Exclude pending transactions for unfetched internal transactions Parity doesn't support asking for the internal transactions of pending transactions. --- apps/explorer/lib/explorer/chain.ex | 37 ++++++++++++++++++- .../lib/explorer/chain/transaction.ex | 4 +- .../internal_transaction_fetcher_test.exs | 32 ++++++++++++++++ apps/explorer/test/support/factory.ex | 2 + coveralls.json | 2 +- 5 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 apps/explorer/test/explorer/indexer/internal_transaction_fetcher_test.exs diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 05d9a9c68b..4428f45e67 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -1109,7 +1109,34 @@ defmodule Explorer.Chain do end @doc """ - Returns a stream of all transactions with unfetched internal transactions. + Returns a stream of all collated transactions with unfetched internal transactions. + + Only transactions that have been collated into a block are returned; pending transactions not in a block are filtered + out. + + iex> pending = insert(:transaction) + iex> unfetched_collated = + ...> :transaction |> + ...> insert() |> + ...> with_block() + iex> fetched_collated = + ...> :transaction |> + ...> insert() |> + ...> with_block(internal_transactions_indexed_at: DateTime.utc_now()) + iex> {:ok, hash_set} = Explorer.Chain.stream_transactions_with_unfetched_internal_transactions( + ...> [:hash], + ...> MapSet.new(), + ...> fn %Explorer.Chain.Transaction{hash: hash}, acc -> + ...> MapSet.put(acc, hash) + ...> end + ...> ) + iex> pending.hash in hash_set + false + iex> unfetched_collated.hash in hash_set + true + iex> fetched_collated.hash in hash_set + false + """ @spec stream_transactions_with_unfetched_internal_transactions( fields :: [ @@ -1137,7 +1164,13 @@ defmodule Explorer.Chain do def stream_transactions_with_unfetched_internal_transactions(fields, initial, reducer) when is_function(reducer, 2) do Repo.transaction( fn -> - query = from(t in Transaction, where: is_nil(t.internal_transactions_indexed_at), select: ^fields) + query = + from( + t in Transaction, + # exclude pending transactions + where: not is_nil(t.block_hash) and is_nil(t.internal_transactions_indexed_at), + select: ^fields + ) query |> Repo.stream(timeout: :infinity) diff --git a/apps/explorer/lib/explorer/chain/transaction.ex b/apps/explorer/lib/explorer/chain/transaction.ex index a751c827df..a3065ce0b2 100644 --- a/apps/explorer/lib/explorer/chain/transaction.ex +++ b/apps/explorer/lib/explorer/chain/transaction.ex @@ -7,8 +7,8 @@ defmodule Explorer.Chain.Transaction do alias Explorer.Chain.{Address, Block, Data, Gas, Hash, InternalTransaction, Log, Wei} alias Explorer.Chain.Transaction.Status - @optional_attrs ~w(block_hash block_number cumulative_gas_used from_address_hash gas_used index status - to_address_hash)a + @optional_attrs ~w(block_hash block_number cumulative_gas_used from_address_hash gas_used index + internal_transactions_indexed_at status to_address_hash)a @required_attrs ~w(gas gas_price hash input nonce public_key r s standard_v v value)a @typedoc """ diff --git a/apps/explorer/test/explorer/indexer/internal_transaction_fetcher_test.exs b/apps/explorer/test/explorer/indexer/internal_transaction_fetcher_test.exs new file mode 100644 index 0000000000..b65cc7b489 --- /dev/null +++ b/apps/explorer/test/explorer/indexer/internal_transaction_fetcher_test.exs @@ -0,0 +1,32 @@ +defmodule Explorer.Indexer.InternalTransactionFetcherTest do + use Explorer.DataCase, async: true + + alias Explorer.Indexer.InternalTransactionFetcher + + describe "init/2" do + test "does not buffer pending transactions" do + insert(:transaction) + + assert InternalTransactionFetcher.init([], fn hash_string, acc -> [hash_string | acc] end) == [] + end + + test "buffers collated transactions with unfetched internal transactions" do + collated_unfetched_transaction = + :transaction + |> insert() + |> with_block() + + assert InternalTransactionFetcher.init([], fn hash_string, acc -> [hash_string | acc] end) == [ + to_string(collated_unfetched_transaction.hash) + ] + end + + test "does not buffer collated transactions with fetched internal transactions" do + :transaction + |> insert() + |> with_block(internal_transactions_indexed_at: DateTime.utc_now()) + + assert InternalTransactionFetcher.init([], fn hash_string, acc -> [hash_string | acc] end) == [] + end + end +end diff --git a/apps/explorer/test/support/factory.ex b/apps/explorer/test/support/factory.ex index ac32ee8c8d..28c98d2cc4 100644 --- a/apps/explorer/test/support/factory.ex +++ b/apps/explorer/test/support/factory.ex @@ -95,6 +95,7 @@ defmodule Explorer.Factory do cumulative_gas_used = collated_params[:cumulative_gas_used] || Enum.random(21_000..100_000) gas_used = collated_params[:gas_used] || Enum.random(21_000..100_000) + internal_transactions_indexed_at = collated_params[:internal_transactions_indexed_at] status = collated_params[:status] || Enum.random(0..1) transaction @@ -104,6 +105,7 @@ defmodule Explorer.Factory do cumulative_gas_used: cumulative_gas_used, gas_used: gas_used, index: next_transaction_index, + internal_transactions_indexed_at: internal_transactions_indexed_at, status: status }) |> Repo.update!() diff --git a/coveralls.json b/coveralls.json index 64029d5e0f..eee206f9b2 100644 --- a/coveralls.json +++ b/coveralls.json @@ -1,7 +1,7 @@ { "coverage_options": { "treat_no_relevant_lines_as_covered": true, - "minimum_coverage": 92.7 + "minimum_coverage": 92.9 }, "terminal_options": { "file_column_width": 120