diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index a2a55dcbd5..efcd2af83d 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -899,12 +899,9 @@ defmodule Explorer.Chain do def list_top_addresses do query = from(a in Address, - left_join: t in Transaction, - on: a.hash == t.from_address_hash, where: a.fetched_coin_balance > ^0, - group_by: [a.hash, a.fetched_coin_balance], order_by: [desc: a.fetched_coin_balance, asc: a.hash], - select: {a, fragment("coalesce(1 + max(?), 0)", t.nonce)}, + select: {a, fragment("coalesce(1 + ?, 0)", a.nonce)}, limit: 250 ) diff --git a/apps/explorer/lib/explorer/chain/address.ex b/apps/explorer/lib/explorer/chain/address.ex index c5e2df3c9a..5777606d84 100644 --- a/apps/explorer/lib/explorer/chain/address.ex +++ b/apps/explorer/lib/explorer/chain/address.ex @@ -8,7 +8,7 @@ defmodule Explorer.Chain.Address do alias Ecto.Changeset alias Explorer.Chain.{Address, Block, Data, Hash, InternalTransaction, SmartContract, Token, Wei} - @optional_attrs ~w(contract_code fetched_coin_balance fetched_coin_balance_block_number)a + @optional_attrs ~w(contract_code fetched_coin_balance fetched_coin_balance_block_number nonce)a @required_attrs ~w(hash)a @allowed_attrs @optional_attrs ++ @required_attrs @@ -34,7 +34,8 @@ defmodule Explorer.Chain.Address do contract_code: Data.t() | nil, names: %Ecto.Association.NotLoaded{} | [Address.Name.t()], inserted_at: DateTime.t(), - updated_at: DateTime.t() + updated_at: DateTime.t(), + nonce: non_neg_integer() | nil } @primary_key {:hash, Hash.Address, autogenerate: false} @@ -42,6 +43,7 @@ defmodule Explorer.Chain.Address do field(:fetched_coin_balance, Wei) field(:fetched_coin_balance_block_number, :integer) field(:contract_code, Data) + field(:nonce, :integer) has_one(:smart_contract, SmartContract) has_one(:token, Token, foreign_key: :contract_address_hash) diff --git a/apps/explorer/lib/explorer/chain/import/addresses.ex b/apps/explorer/lib/explorer/chain/import/addresses.ex index ae6c92e887..fd0546ef3a 100644 --- a/apps/explorer/lib/explorer/chain/import/addresses.ex +++ b/apps/explorer/lib/explorer/chain/import/addresses.ex @@ -95,18 +95,10 @@ defmodule Explorer.Chain.Import.Addresses do # MAX on two columns fetched_coin_balance_block_number: fragment( - """ - CASE WHEN EXCLUDED.fetched_coin_balance_block_number IS NOT NULL AND - (? IS NULL OR - EXCLUDED.fetched_coin_balance_block_number >= ?) THEN - EXCLUDED.fetched_coin_balance_block_number - ELSE ? - END - """, - address.fetched_coin_balance_block_number, - address.fetched_coin_balance_block_number, + "GREATEST(EXCLUDED.fetched_coin_balance_block_number, ?)", address.fetched_coin_balance_block_number - ) + ), + nonce: fragment("GREATEST(EXCLUDED.nonce, ?)", address.nonce) ] ] ) diff --git a/apps/explorer/priv/repo/migrations/201811061523_add_nonce_to_addresses.exs b/apps/explorer/priv/repo/migrations/201811061523_add_nonce_to_addresses.exs new file mode 100644 index 0000000000..cbdfe4b1b9 --- /dev/null +++ b/apps/explorer/priv/repo/migrations/201811061523_add_nonce_to_addresses.exs @@ -0,0 +1,30 @@ +defmodule Explorer.Repo.Migrations.AddNonceToAddresses do + use Ecto.Migration + + def up do + # Add nonce + alter table(:addresses) do + add(:nonce, :integer) + end + + # Populate nonce field from transactions table + execute(""" + WITH t AS ( + SELECT from_address_hash AS hash, MAX(nonce) AS nonce + FROM transactions + GROUP BY hash + ) + UPDATE addresses AS a + SET nonce = t.nonce + FROM t + WHERE a.hash = t.hash + """) + end + + def down do + # Remove nonce + alter table(:addresses) do + remove(:nonce) + end + end +end diff --git a/apps/indexer/lib/indexer/address_extraction.ex b/apps/indexer/lib/indexer/address_extraction.ex index 995465589a..37e93e3987 100644 --- a/apps/indexer/lib/indexer/address_extraction.ex +++ b/apps/indexer/lib/indexer/address_extraction.ex @@ -84,7 +84,8 @@ defmodule Indexer.AddressExtraction do ], [ %{from: :block_number, to: :fetched_coin_balance_block_number}, - %{from: :from_address_hash, to: :hash} + %{from: :from_address_hash, to: :hash}, + %{from: :nonce, to: :nonce} ], [ %{from: :block_number, to: :fetched_coin_balance_block_number}, @@ -136,6 +137,7 @@ defmodule Indexer.AddressExtraction do required(:hash) => String.t(), required(:fetched_coin_balance_block_number) => non_neg_integer(), optional(:fetched_coin_balance) => non_neg_integer(), + optional(:nonce) => non_neg_integer(), optional(:contract_code) => String.t() } @@ -209,11 +211,13 @@ defmodule Indexer.AddressExtraction do ...> %{ ...> block_number: 1, ...> from_address_hash: "0x0000000000000000000000000000000000000001", - ...> to_address_hash: "0x0000000000000000000000000000000000000002" + ...> to_address_hash: "0x0000000000000000000000000000000000000002", + ...> nonce: 3 ...> }, ...> %{ ...> block_number: 2, - ...> from_address_hash: "0x0000000000000000000000000000000000000003" + ...> from_address_hash: "0x0000000000000000000000000000000000000003", + ...> nonce: 4 ...> } ...> ] ...> } @@ -221,7 +225,8 @@ defmodule Indexer.AddressExtraction do [ %{ fetched_coin_balance_block_number: 1, - hash: "0x0000000000000000000000000000000000000001" + hash: "0x0000000000000000000000000000000000000001", + nonce: 3 }, %{ fetched_coin_balance_block_number: 1, @@ -229,7 +234,8 @@ defmodule Indexer.AddressExtraction do }, %{ fetched_coin_balance_block_number: 2, - hash: "0x0000000000000000000000000000000000000003" + hash: "0x0000000000000000000000000000000000000003", + nonce: 4 } ] @@ -366,6 +372,7 @@ defmodule Indexer.AddressExtraction do %{ required(:block_number) => non_neg_integer(), required(:from_address_hash) => String.t(), + required(:nonce) => non_neg_integer(), optional(:to_address_hash) => String.t(), optional(:created_contract_address_hash) => String.t() } @@ -477,6 +484,7 @@ defmodule Indexer.AddressExtraction do Map.merge(first, second) end end + |> Map.put(:nonce, max_nil_last(first[:nonce], second[:nonce])) end # `nil > 5 == true`, but we want numbers instead