Remove pagination and return top 250 addresses by balance

pull/744/head
Stamates 6 years ago
parent 6ee50a6993
commit cfac04336d
  1. 8
      apps/block_scout_web/lib/block_scout_web/chain.ex
  2. 15
      apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex
  3. 23
      apps/block_scout_web/lib/block_scout_web/templates/address/index.html.eex
  4. 2
      apps/block_scout_web/lib/block_scout_web/views/address_view.ex
  5. 43
      apps/block_scout_web/test/block_scout_web/controllers/address_controller_test.exs
  6. 35
      apps/explorer/lib/explorer/chain.ex
  7. 16
      apps/explorer/test/explorer/chain_test.exs

@ -20,8 +20,7 @@ defmodule BlockScoutWeb.Chain do
Log,
Token,
TokenTransfer,
Transaction,
Wei
Transaction
}
alias Explorer.PagingOptions
@ -155,11 +154,6 @@ defmodule BlockScoutWeb.Chain do
end
end
defp paging_params(%Address{fetched_coin_balance: value, hash: hash}) do
integer_value = value |> Wei.to(:wei) |> Decimal.to_integer()
%{"address_hash" => to_string(hash), "value" => integer_value}
end
defp paging_params(%Block{number: number}) do
%{"block_number" => number}
end

@ -1,26 +1,17 @@
defmodule BlockScoutWeb.AddressController do
use BlockScoutWeb, :controller
import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1]
alias Explorer.{Chain, Market}
alias Explorer.Chain.Address
alias Explorer.ExchangeRates.Token
def index(conn, params) do
def index(conn, _params) do
address_count_module = Application.get_env(:block_scout_web, :fake_adapter) || Chain
full_options = paging_options(params)
addresses_plus_one = Chain.list_top_addresses(full_options)
{addresses, next_page} = split_list_by_page(addresses_plus_one)
render(conn, "index.html",
addresses: addresses,
addresses: Chain.list_top_addresses(),
address_estimated_count: address_count_module.address_estimated_count(),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
next_page_params: next_page_params(next_page, addresses, params)
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null()
)
end

@ -3,7 +3,7 @@
<div class="card-body">
<h1><%= gettext "Addresses" %></h1>
<p>
<%= gettext "Showing 50 addresses of" %>
<%= gettext "Showing 250 addresses of" %>
<%= Cldr.Number.to_string!(@address_estimated_count, format: "#,###") %>
<%= gettext "total addresses with a balance" %>
</p>
@ -13,12 +13,12 @@
<div class="tile">
<div class="row">
<!-- rank -->
<!-- <div class="col-2 col-md-1 d-flex justify-content-center align-items-center"> -->
<div class="col-2 col-md-1 d-flex justify-content-center align-items-center">
<!-- incremented number by order in the list -->
<!-- <span><%= index %></span> -->
<!-- </div> -->
<span><%= index %></span>
</div>
<div class="col-12 col-md-12">
<div class="col-10 col-md-11">
<div class="row">
<div class="col-md-7 d-flex flex-column mt-3 mt-md-0">
<%= address |> BlockScoutWeb.AddressView.address_partial_selector(nil, nil) |> BlockScoutWeb.AddressView.render_partial() %>
@ -49,19 +49,6 @@
</div>
<% end %>
</span>
<!-- paging -->
<%= if @next_page_params do %>
<%= link(
gettext("Next Page"),
class: "button button-secondary button-sm float-right mt-3",
to: address_path(
@conn,
:index,
@next_page_params
)
) %>
<% end %>
</div>
</div>

@ -164,7 +164,7 @@ defmodule BlockScoutWeb.AddressView do
def token_title(%Token{name: name, symbol: symbol}), do: "#{name} (#{symbol})"
def transaction_count(%Address{} = address) do
Chain.address_to_transaction_count(address)
Chain.address_to_transaction_count_estimate(address)
end
def trimmed_hash(%Hash{} = hash) do

@ -14,49 +14,6 @@ defmodule BlockScoutWeb.AddressControllerTest do
assert conn.assigns.addresses |> Enum.map(& &1.hash) == address_hashes
end
test "returns next page of results based on last seen address", %{conn: conn} do
second_page_address_hashes =
50..1
|> Enum.map(&insert(:address, fetched_coin_balance: &1))
|> Enum.map(& &1.hash)
%Address{fetched_coin_balance: value, hash: address_hash} = insert(:address, fetched_coin_balance: 51)
conn =
get(conn, address_path(conn, :index), %{
"address_hash" => to_string(address_hash),
"value" => value |> Wei.to(:wei) |> Decimal.to_integer()
})
actual_address_hashes =
conn.assigns.addresses
|> Enum.map(& &1.hash)
assert second_page_address_hashes == actual_address_hashes
end
test "next_page_params exist if not on last page", %{conn: conn} do
%Address{fetched_coin_balance: value, hash: address_hash} =
60..1
|> Enum.map(&insert(:address, fetched_coin_balance: &1))
|> Enum.fetch!(49)
conn = get(conn, address_path(conn, :index))
assert %{
"address_hash" => to_string(address_hash),
"value" => value |> Wei.to(:wei) |> Decimal.to_integer()
} == conn.assigns.next_page_params
end
test "next_page_params are empty if on last page", %{conn: conn} do
insert(:address)
conn = get(conn, address_path(conn, :index))
refute conn.assigns.next_page_params
end
end
describe "GET show/3" do

@ -760,30 +760,15 @@ defmodule Explorer.Chain do
end
@doc """
Lists `t:Explorer.Chain.Address.t/0`'s' in descending order based on coin balance.
## Options
* `:necessity_by_association` - use to load `t:association/0` as `:required` or `:optional`. If an association is
`:required`, and the `t:Explorer.Chain.Address.t/0` has no associated record for that association, then the
`t:Explorer.Chain.Address.t/0` will not be included in the page `entries`.
* `:paging_options` - a `t:Explorer.PagingOptions.t/0` used to specify the `:page_size`
and`:key` (`{value, address_hash}` of the last seen address). Results will be the addresses with lesser
`fetched_coin_balance` (or equal `fetched_coin_balance` and greater alphabetical 'hash') than the last seen address.
Lists the top 250 `t:Explorer.Chain.Address.t/0`'s' in descending order based on coin balance.
"""
@spec list_top_addresses([paging_options | necessity_by_association_option]) :: [Address.t()]
def list_top_addresses(options \\ []) when is_list(options) do
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
paging_options = Keyword.get(options, :paging_options, @default_paging_options)
{:ok, zero_wei} = Wei.cast(Decimal.new(0))
@spec list_top_addresses :: [Address.t()]
def list_top_addresses do
Address
|> join_associations(necessity_by_association)
|> page_addresses(paging_options)
|> limit(^paging_options.page_size)
|> limit(250)
|> order_by(desc: :fetched_coin_balance, asc: :hash)
|> where([address], address.fetched_coin_balance > ^zero_wei)
|> where([address], address.fetched_coin_balance > ^0)
|> Repo.all()
end
@ -1563,16 +1548,6 @@ defmodule Explorer.Chain do
end)
end
defp page_addresses(query, %PagingOptions{key: nil}), do: query
defp page_addresses(query, %PagingOptions{key: {value, hash}}) do
where(
query,
[address],
address.fetched_coin_balance < ^value or (address.fetched_coin_balance == ^value and address.hash > ^hash)
)
end
defp page_blocks(query, %PagingOptions{key: nil}), do: query
defp page_blocks(query, %PagingOptions{key: {block_number}}) do

@ -979,7 +979,7 @@ defmodule Explorer.ChainTest do
end
end
describe "list_top_addresses/2" do
describe "list_top_addresses/0" do
test "without addresses with balance > 0" do
insert(:address, fetched_coin_balance: 0)
assert [] = Chain.list_top_addresses()
@ -1012,20 +1012,6 @@ defmodule Explorer.ChainTest do
assert [first_result_hash | tail] == Enum.map(Chain.list_top_addresses(), & &1.hash)
end
test "with addresses can be paginated" do
second_page_address_hashes =
50..1
|> Enum.map(&insert(:address, fetched_coin_balance: &1))
|> Enum.map(& &1.hash)
%Address{fetched_coin_balance: value, hash: address_hash} = insert(:address, fetched_coin_balance: 51)
assert second_page_address_hashes ==
[paging_options: %PagingOptions{key: {value, address_hash}, page_size: 50}]
|> Chain.list_top_addresses()
|> Enum.map(& &1.hash)
end
end
describe "number_to_block/1" do

Loading…
Cancel
Save