Merge branch 'master' into ab-fetch-address-balances-with-code

pull/1458/head
Andrew Cravenho 6 years ago committed by GitHub
commit a1026a4a33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      apps/block_scout_web/lib/block_scout_web/controllers/address_validation_controller.ex
  2. 14
      apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex
  3. 49
      apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex
  4. 47
      apps/block_scout_web/priv/gettext/default.pot
  5. 49
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  6. 48
      apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs
  7. 14
      apps/explorer/lib/explorer/chain/transaction.ex
  8. 1
      apps/explorer/lib/explorer/counters/average_block_time_duration_format.ex
  9. 9
      apps/explorer/priv/repo/migrations/20190213180502_add_earliest_processing_start_to_transactions.exs
  10. 18
      apps/indexer/lib/indexer/pending_transaction/fetcher.ex

@ -12,6 +12,7 @@ defmodule BlockScoutWeb.AddressValidationController do
alias BlockScoutWeb.BlockView
alias Explorer.ExchangeRates.Token
alias Explorer.{Chain, Market}
alias Indexer.CoinBalance.OnDemandFetcher
alias Phoenix.View
def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do
@ -75,6 +76,7 @@ defmodule BlockScoutWeb.AddressValidationController do
conn,
"index.html",
address: address,
coin_balance_status: OnDemandFetcher.trigger_fetch(address),
current_path: current_path(conn),
transaction_count: transaction_count(address),
validation_count: validation_count(address),

@ -74,6 +74,20 @@
<%= formatted_fee(@transaction, denomination: :ether) %> (<span data-wei-value=<%= fee(@transaction) %> data-usd-exchange-rate=<%= @exchange_rate.usd_value %>></span>)
</dd>
</dl>
<!-- Processing Time -->
<%= case processing_time_duration(@transaction) do %>
<% :pending -> %>
<% nil %>
<% :unknown -> %>
<% nil %>
<% {:ok, interval_string} -> %>
<dl class="row">
<dt class="col-sm-3 text-muted"> <%= gettext "Transaction Speed" %> </dt>
<dd class="col-sm-9">
<%= interval_string %>
</dd>
</dl>
<% end %>
<%= unless value_transfer?(@transaction) do %>
<dl class="row">

@ -1,11 +1,12 @@
defmodule BlockScoutWeb.TransactionView do
use BlockScoutWeb, :view
alias BlockScoutWeb.{AddressView, BlockView, TabHelpers}
alias Cldr.Number
alias Explorer.Chain
alias Explorer.Chain.Block.Reward
alias Explorer.Chain.{Address, Block, InternalTransaction, Transaction, Wei}
alias BlockScoutWeb.{AddressView, BlockView, TabHelpers}
alias Timex.Duration
import BlockScoutWeb.Gettext
@ -29,6 +30,52 @@ defmodule BlockScoutWeb.TransactionView do
def value_transfer?(_), do: false
def processing_time_duration(%Transaction{block: nil}) do
:pending
end
def processing_time_duration(%Transaction{earliest_processing_start: nil}) do
:unknown
end
def processing_time_duration(%Transaction{
block: %Block{timestamp: end_time},
earliest_processing_start: earliest_processing_start,
inserted_at: inserted_at
}) do
with {:ok, long_interval} <- humanized_diff(earliest_processing_start, end_time),
{:ok, short_interval} <- humanized_diff(inserted_at, end_time) do
{:ok, merge_intervals(short_interval, long_interval)}
else
_ ->
:ignore
end
end
defp merge_intervals(short, long) when short == long, do: short
defp merge_intervals(short, long) do
[short_time, short_unit] = String.split(short, " ")
[long_time, long_unit] = String.split(long, " ")
if short_unit == long_unit do
short_time <> "-" <> long_time <> " " <> short_unit
else
short <> " - " <> long
end
end
defp humanized_diff(left, right) do
left
|> Timex.diff(right, :milliseconds)
|> Duration.from_milliseconds()
|> Timex.format_duration(Explorer.Counters.AverageBlockTimeDurationFormat)
|> case do
{:error, _} = error -> error
duration -> {:ok, duration}
end
end
def confirmations(%Transaction{block: block}, named_arguments) when is_list(named_arguments) do
case block do
nil ->

@ -49,7 +49,7 @@ msgid "%{subnetwork} Explorer - BlockScout"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:71
#: lib/block_scout_web/views/transaction_view.ex:118
msgid "(Awaiting internal transactions for status)"
msgstr ""
@ -165,7 +165,7 @@ msgid "Block Number"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:18
#: lib/block_scout_web/views/transaction_view.ex:19
msgid "Block Pending"
msgstr ""
@ -278,12 +278,12 @@ msgid "Contract Address Pending"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:148
#: lib/block_scout_web/views/transaction_view.ex:195
msgid "Contract Call"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:147
#: lib/block_scout_web/views/transaction_view.ex:194
msgid "Contract Creation"
msgstr ""
@ -377,12 +377,12 @@ msgid "Error trying to fetch balances."
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:75
#: lib/block_scout_web/views/transaction_view.ex:122
msgid "Error: %{reason}"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:73
#: lib/block_scout_web/views/transaction_view.ex:120
msgid "Error: (Awaiting internal transactions for reason)"
msgstr ""
@ -392,7 +392,7 @@ msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:51
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:19
#: lib/block_scout_web/templates/transaction/_tile.html.eex:26
#: lib/block_scout_web/templates/transaction/overview.html.eex:104
#: lib/block_scout_web/templates/transaction/overview.html.eex:118
#: lib/block_scout_web/views/wei_helpers.ex:72
msgid "Ether"
msgstr ""
@ -431,7 +431,7 @@ msgid "GET"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:117
#: lib/block_scout_web/templates/transaction/overview.html.eex:131
msgid "Gas"
msgstr ""
@ -495,7 +495,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:43
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:10
#: lib/block_scout_web/views/address_view.ex:270
#: lib/block_scout_web/views/transaction_view.ex:201
#: lib/block_scout_web/views/transaction_view.ex:248
msgid "Internal Transactions"
msgstr ""
@ -513,7 +513,7 @@ msgid "Less than"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:129
#: lib/block_scout_web/templates/transaction/overview.html.eex:143
msgid "Limit"
msgstr ""
@ -521,7 +521,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:21
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:48
#: lib/block_scout_web/templates/transaction_log/index.html.eex:10
#: lib/block_scout_web/views/transaction_view.ex:202
#: lib/block_scout_web/views/transaction_view.ex:249
msgid "Logs"
msgstr ""
@ -533,7 +533,7 @@ msgid "Market Cap"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:62
#: lib/block_scout_web/views/transaction_view.ex:109
msgid "Max of"
msgstr ""
@ -662,8 +662,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:44
#: lib/block_scout_web/templates/transaction/overview.html.eex:55
#: lib/block_scout_web/views/transaction_view.ex:70
#: lib/block_scout_web/views/transaction_view.ex:104
#: lib/block_scout_web/views/transaction_view.ex:117
#: lib/block_scout_web/views/transaction_view.ex:151
msgid "Pending"
msgstr ""
@ -768,7 +768,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_emission_reward_tile.html.eex:8
#: lib/block_scout_web/views/transaction_view.ex:72
#: lib/block_scout_web/views/transaction_view.ex:119
msgid "Success"
msgstr ""
@ -879,7 +879,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:4
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:4
#: lib/block_scout_web/views/transaction_view.ex:146
#: lib/block_scout_web/views/transaction_view.ex:193
msgid "Token Transfer"
msgstr ""
@ -891,7 +891,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:36
#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:10
#: lib/block_scout_web/views/tokens/overview_view.ex:35
#: lib/block_scout_web/views/transaction_view.ex:200
#: lib/block_scout_web/views/transaction_view.ex:247
msgid "Token Transfers"
msgstr ""
@ -932,7 +932,7 @@ msgid "Total transactions"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:149
#: lib/block_scout_web/views/transaction_view.ex:196
msgid "Transaction"
msgstr ""
@ -999,7 +999,7 @@ msgid "Unique Token"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:122
#: lib/block_scout_web/templates/transaction/overview.html.eex:136
msgid "Used"
msgstr ""
@ -1020,7 +1020,7 @@ msgid "Validations"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:104
#: lib/block_scout_web/templates/transaction/overview.html.eex:118
msgid "Value"
msgstr ""
@ -1216,7 +1216,7 @@ msgid "This API is provided for developers transitioning their applications from
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:80
#: lib/block_scout_web/templates/transaction/overview.html.eex:94
msgid "Raw Input"
msgstr ""
@ -1637,3 +1637,8 @@ msgstr ""
#: lib/block_scout_web/templates/address/overview.html.eex:41
msgid "Transactions Sent"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:85
msgid "Transaction Speed"
msgstr ""

@ -49,7 +49,7 @@ msgid "%{subnetwork} Explorer - BlockScout"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:71
#: lib/block_scout_web/views/transaction_view.ex:118
msgid "(Awaiting internal transactions for status)"
msgstr ""
@ -165,7 +165,7 @@ msgid "Block Number"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:18
#: lib/block_scout_web/views/transaction_view.ex:19
msgid "Block Pending"
msgstr ""
@ -278,12 +278,12 @@ msgid "Contract Address Pending"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:148
#: lib/block_scout_web/views/transaction_view.ex:195
msgid "Contract Call"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:147
#: lib/block_scout_web/views/transaction_view.ex:194
msgid "Contract Creation"
msgstr ""
@ -377,12 +377,12 @@ msgid "Error trying to fetch balances."
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:75
#: lib/block_scout_web/views/transaction_view.ex:122
msgid "Error: %{reason}"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:73
#: lib/block_scout_web/views/transaction_view.ex:120
msgid "Error: (Awaiting internal transactions for reason)"
msgstr ""
@ -392,7 +392,7 @@ msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:51
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:19
#: lib/block_scout_web/templates/transaction/_tile.html.eex:26
#: lib/block_scout_web/templates/transaction/overview.html.eex:104
#: lib/block_scout_web/templates/transaction/overview.html.eex:118
#: lib/block_scout_web/views/wei_helpers.ex:72
msgid "Ether"
msgstr "POA"
@ -431,7 +431,7 @@ msgid "GET"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:117
#: lib/block_scout_web/templates/transaction/overview.html.eex:131
msgid "Gas"
msgstr ""
@ -495,7 +495,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:43
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:10
#: lib/block_scout_web/views/address_view.ex:270
#: lib/block_scout_web/views/transaction_view.ex:201
#: lib/block_scout_web/views/transaction_view.ex:248
msgid "Internal Transactions"
msgstr ""
@ -513,7 +513,7 @@ msgid "Less than"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:129
#: lib/block_scout_web/templates/transaction/overview.html.eex:143
msgid "Limit"
msgstr ""
@ -521,7 +521,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:21
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:48
#: lib/block_scout_web/templates/transaction_log/index.html.eex:10
#: lib/block_scout_web/views/transaction_view.ex:202
#: lib/block_scout_web/views/transaction_view.ex:249
msgid "Logs"
msgstr ""
@ -533,7 +533,7 @@ msgid "Market Cap"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:62
#: lib/block_scout_web/views/transaction_view.ex:109
msgid "Max of"
msgstr ""
@ -662,8 +662,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:44
#: lib/block_scout_web/templates/transaction/overview.html.eex:55
#: lib/block_scout_web/views/transaction_view.ex:70
#: lib/block_scout_web/views/transaction_view.ex:104
#: lib/block_scout_web/views/transaction_view.ex:117
#: lib/block_scout_web/views/transaction_view.ex:151
msgid "Pending"
msgstr ""
@ -768,7 +768,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_emission_reward_tile.html.eex:8
#: lib/block_scout_web/views/transaction_view.ex:72
#: lib/block_scout_web/views/transaction_view.ex:119
msgid "Success"
msgstr ""
@ -879,7 +879,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:4
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:4
#: lib/block_scout_web/views/transaction_view.ex:146
#: lib/block_scout_web/views/transaction_view.ex:193
msgid "Token Transfer"
msgstr ""
@ -891,7 +891,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:36
#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:10
#: lib/block_scout_web/views/tokens/overview_view.ex:35
#: lib/block_scout_web/views/transaction_view.ex:200
#: lib/block_scout_web/views/transaction_view.ex:247
msgid "Token Transfers"
msgstr ""
@ -932,7 +932,7 @@ msgid "Total transactions"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:149
#: lib/block_scout_web/views/transaction_view.ex:196
msgid "Transaction"
msgstr ""
@ -999,7 +999,7 @@ msgid "Unique Token"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:122
#: lib/block_scout_web/templates/transaction/overview.html.eex:136
msgid "Used"
msgstr ""
@ -1020,7 +1020,7 @@ msgid "Validations"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:104
#: lib/block_scout_web/templates/transaction/overview.html.eex:118
msgid "Value"
msgstr ""
@ -1216,7 +1216,7 @@ msgid "This API is provided for developers transitioning their applications from
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:80
#: lib/block_scout_web/templates/transaction/overview.html.eex:94
msgid "Raw Input"
msgstr ""
@ -1633,7 +1633,12 @@ msgstr ""
msgid "Last Balance Update: Block #"
msgstr ""
#, elixir-format, fuzzy
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:41
msgid "Transactions Sent"
msgstr ""
#, elixir-format, fuzzy
#: lib/block_scout_web/templates/transaction/overview.html.eex:85
msgid "Transaction Speed"
msgstr ""

@ -47,6 +47,54 @@ defmodule BlockScoutWeb.TransactionViewTest do
end
end
describe "processing_time_duration/2" do
test "returns :pending if the transaction has no block" do
transaction = build(:transaction, block: nil)
assert TransactionView.processing_time_duration(transaction) == :pending
end
test "returns :unknown if the transaction has no `earliest_processing_start`" do
block = insert(:block)
transaction =
:transaction
|> insert(earliest_processing_start: nil)
|> with_block(block)
assert TransactionView.processing_time_duration(transaction) == :unknown
end
test "returns a single number when the timestamps are the same" do
now = Timex.now()
ten_seconds_ago = Timex.shift(now, seconds: -10)
block = insert(:block, timestamp: now)
transaction =
:transaction
|> insert(earliest_processing_start: ten_seconds_ago, inserted_at: ten_seconds_ago)
|> with_block(block)
assert TransactionView.processing_time_duration(transaction) == {:ok, "10 seconds"}
end
test "returns a range when the timestamps are not the same" do
now = Timex.now()
ten_seconds_ago = Timex.shift(now, seconds: -10)
five_seconds_ago = Timex.shift(now, seconds: -5)
block = insert(:block, timestamp: now)
transaction =
:transaction
|> insert(earliest_processing_start: ten_seconds_ago, inserted_at: five_seconds_ago)
|> with_block(block)
assert TransactionView.processing_time_duration(transaction) == {:ok, "5-10 seconds"}
end
end
describe "confirmations/2" do
test "returns 0 if pending transaction" do
transaction = build(:transaction, block: nil)

@ -26,8 +26,10 @@ defmodule Explorer.Chain.Transaction do
alias Explorer.Chain.Transaction.{Fork, Status}
@optional_attrs ~w(block_hash block_number created_contract_address_hash cumulative_gas_used error gas_used index
internal_transactions_indexed_at created_contract_code_indexed_at status to_address_hash)a
@optional_attrs ~w(block_hash block_number created_contract_address_hash cumulative_gas_used earliest_processing_start
error gas_used index internal_transactions_indexed_at created_contract_code_indexed_at status
to_address_hash)a
@required_attrs ~w(from_address_hash gas gas_price hash input nonce r s v value)a
@typedoc """
@ -80,7 +82,11 @@ defmodule Explorer.Chain.Transaction do
* `created_contract_address_hash` - Denormalized `internal_transaction` `created_contract_address_hash`
populated only when `to_address_hash` is nil.
* `cumulative_gas_used` - the cumulative gas used in `transaction`'s `t:Explorer.Chain.Block.t/0` before
`transaction`'s `index`. `nil` when transaction is pending.
`transaction`'s `index`. `nil` when transaction is pending
* `earliest_processing_start` - If the pending transaction fetcher was alive and received this transaction, we can
be sure that this transaction did not start processing until after the last time we fetched pending transactions,
so we annotate that with this field. If it is `nil`, that means we don't have a lower bound for when it started
processing.
* `error` - the `error` from the last `t:Explorer.Chain.InternalTransaction.t/0` in `internal_transactions` that
caused `status` to be `:error`. Only set after `internal_transactions_index_at` is set AND if there was an error.
Also, `error` is set if transaction is replaced/dropped
@ -132,6 +138,7 @@ defmodule Explorer.Chain.Transaction do
created_contract_address_hash: Hash.Address.t() | nil,
created_contract_code_indexed_at: DateTime.t() | nil,
cumulative_gas_used: Gas.t() | nil,
earliest_processing_start: DateTime.t() | nil,
error: String.t() | nil,
forks: %Ecto.Association.NotLoaded{} | [Fork.t()],
from_address: %Ecto.Association.NotLoaded{} | Address.t(),
@ -180,6 +187,7 @@ defmodule Explorer.Chain.Transaction do
schema "transactions" do
field(:block_number, :integer)
field(:cumulative_gas_used, :decimal)
field(:earliest_processing_start, :utc_datetime_usec)
field(:error, :string)
field(:gas, :decimal)
field(:gas_price, Wei)

@ -67,6 +67,7 @@ defmodule Explorer.Counters.AverageBlockTimeDurationFormat do
duration
|> Duration.to_milliseconds()
|> round()
|> abs()
|> do_format(locale)
end

@ -0,0 +1,9 @@
defmodule Explorer.Repo.Migrations.AddEarliestProcessingStartToTransactions do
use Ecto.Migration
def change do
alter table(:transactions) do
add(:earliest_processing_start, :utc_datetime_usec)
end
end
end

@ -22,6 +22,7 @@ defmodule Indexer.PendingTransaction.Fetcher do
defstruct interval: @default_interval,
json_rpc_named_arguments: [],
last_fetch_at: nil,
task: nil
def child_spec([init_arguments]) do
@ -84,10 +85,16 @@ defmodule Indexer.PendingTransaction.Fetcher do
{:noreply, %PendingTransaction.Fetcher{state | task: task}}
end
def handle_info({ref, _}, %PendingTransaction.Fetcher{task: %Task{ref: ref}} = state) do
def handle_info({ref, result}, %PendingTransaction.Fetcher{task: %Task{ref: ref}} = state) do
Process.demonitor(ref, [:flush])
{:noreply, schedule_fetch(state)}
case result do
{:ok, new_last_fetch_at} ->
{:noreply, schedule_fetch(%{state | last_fetch_at: new_last_fetch_at})}
_ ->
{:noreply, schedule_fetch(state)}
end
end
def handle_info(
@ -109,10 +116,15 @@ defmodule Indexer.PendingTransaction.Fetcher do
case fetch_pending_transactions(json_rpc_named_arguments) do
{:ok, transactions_params} ->
new_last_fetched_at = NaiveDateTime.utc_now()
transactions_params
|> Stream.map(&Map.put(&1, :earliest_processing_start, new_last_fetched_at))
|> Stream.chunk_every(@chunk_size)
|> Enum.each(&import_chunk/1)
{:ok, new_last_fetched_at}
:ignore ->
:ok
@ -127,7 +139,7 @@ defmodule Indexer.PendingTransaction.Fetcher do
addresses_params = AddressExtraction.extract_addresses(%{transactions: transactions_params}, pending: true)
# There's no need to queue up fetching the address balance since theses are pending transactions and cannot have
# affected the address balance yet since address balance is a balance at a give block and these transactions are
# affected the address balance yet since address balance is a balance at a given block and these transactions are
# blockless.
case Chain.import(%{
addresses: %{params: addresses_params, on_conflict: :nothing},

Loading…
Cancel
Save