Validations are now viewable.

Validation count, only shows validations if has them.

Validated -> Blocks Validated, gettext(Validated)
pull/738/head
Lokraan 6 years ago
parent 40af46e47b
commit cbb88f18fe
  1. 6
      apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex
  2. 4
      apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex
  3. 6
      apps/block_scout_web/lib/block_scout_web/controllers/address_internal_transaction_controller.ex
  4. 5
      apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex
  5. 3
      apps/block_scout_web/lib/block_scout_web/controllers/address_token_controller.ex
  6. 5
      apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
  7. 43
      apps/block_scout_web/lib/block_scout_web/controllers/address_validation_controller.ex
  8. 7
      apps/block_scout_web/lib/block_scout_web/router.ex
  9. 12
      apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex
  10. 10
      apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex
  11. 32
      apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex
  12. 10
      apps/block_scout_web/lib/block_scout_web/templates/address_read_contract/index.html.eex
  13. 65
      apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex
  14. 46
      apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex
  15. 155
      apps/block_scout_web/lib/block_scout_web/templates/address_validation/index.html.eex
  16. 6
      apps/block_scout_web/lib/block_scout_web/views/address_validation_view.ex
  17. 49
      apps/explorer/lib/explorer/chain.ex

@ -1,7 +1,7 @@
defmodule BlockScoutWeb.AddressContractController do
use BlockScoutWeb, :controller
import BlockScoutWeb.AddressController, only: [transaction_count: 1]
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1]
alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token
@ -9,12 +9,14 @@ defmodule BlockScoutWeb.AddressContractController do
def index(conn, %{"address_id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.find_contract_address(address_hash) do
render(
conn,
"index.html",
address: address,
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address)
transaction_count: transaction_count(address),
validation_count: validation_count(address)
)
else
:error ->

@ -20,4 +20,8 @@ defmodule BlockScoutWeb.AddressController do
def transaction_count(%Address{} = address) do
Chain.address_to_transactions_estimated_count(address)
end
def validation_count(%Address{} = address) do
Chain.address_to_validation_count(address)
end
end

@ -5,7 +5,7 @@ defmodule BlockScoutWeb.AddressInternalTransactionController do
use BlockScoutWeb, :controller
import BlockScoutWeb.AddressController, only: [transaction_count: 1]
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1]
import BlockScoutWeb.Chain, only: [current_filter: 1, paging_options: 1, next_page_params: 3, split_list_by_page: 1]
alias Explorer.{Chain, Market}
@ -26,7 +26,6 @@ defmodule BlockScoutWeb.AddressInternalTransactionController do
|> Keyword.merge(current_filter(params))
internal_transactions_plus_one = Chain.address_to_internal_transactions(address, full_options)
{internal_transactions, next_page} = split_list_by_page(internal_transactions_plus_one)
render(
@ -37,7 +36,8 @@ defmodule BlockScoutWeb.AddressInternalTransactionController do
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
filter: params["filter"],
internal_transactions: internal_transactions,
transaction_count: transaction_count(address)
transaction_count: transaction_count(address),
validation_count: validation_count(address)
)
else
:error ->

@ -11,7 +11,7 @@ defmodule BlockScoutWeb.AddressReadContractController do
alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token
import BlockScoutWeb.AddressController, only: [transaction_count: 1]
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1]
def index(conn, %{"address_id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
@ -21,7 +21,8 @@ defmodule BlockScoutWeb.AddressReadContractController do
"index.html",
address: address,
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address)
transaction_count: transaction_count(address),
validation_count: validation_count(address)
)
else
:error ->

@ -4,7 +4,7 @@ defmodule BlockScoutWeb.AddressTokenController do
alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token
import BlockScoutWeb.AddressController, only: [transaction_count: 1]
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1]
import BlockScoutWeb.Chain, only: [next_page_params: 3, paging_options: 1, split_list_by_page: 1]
def index(conn, %{"address_id" => address_hash_string} = params) do
@ -19,6 +19,7 @@ defmodule BlockScoutWeb.AddressTokenController do
address: address,
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address),
validation_count: validation_count(address),
next_page_params: next_page_params(next_page, tokens, params),
tokens: tokens
)

@ -5,7 +5,7 @@ defmodule BlockScoutWeb.AddressTransactionController do
use BlockScoutWeb, :controller
import BlockScoutWeb.AddressController, only: [transaction_count: 1]
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1]
import BlockScoutWeb.Chain, only: [current_filter: 1, paging_options: 1, next_page_params: 3, split_list_by_page: 1]
alias Explorer.{Chain, Market}
@ -37,7 +37,8 @@ defmodule BlockScoutWeb.AddressTransactionController do
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
filter: params["filter"],
transactions: transactions,
transaction_count: transaction_count(address)
transaction_count: transaction_count(address),
validation_count: validation_count(address)
)
else
:error ->

@ -0,0 +1,43 @@
defmodule BlockScoutWeb.AddressValidationController do
@moduledoc """
Display all the blocks that this address validates.
"""
use BlockScoutWeb, :controller
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1]
import BlockScoutWeb.Chain, only:
[paging_options: 1, next_page_params: 3, split_list_by_page: 1]
alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token
def index(conn, %{"address_id" => address_hash_string} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do
full_options = Keyword.merge(
[necessity_by_association: %{miner: :required, transactions: :optional}],
paging_options(params)
)
blocks_plus_one = Chain.get_blocks_validated_by_address(full_options, address)
{blocks, next_page} = split_list_by_page(blocks_plus_one)
render(conn, "index.html",
address: address,
blocks: blocks,
transaction_count: transaction_count(address),
validation_count: validation_count(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
next_page_params: next_page_params(next_page, blocks, params)
)
else
:error ->
unprocessable_entity(conn)
{:error, :not_found} ->
not_found(conn)
end
end
end

@ -78,6 +78,13 @@ defmodule BlockScoutWeb.Router do
as: :internal_transaction
)
resources(
"/validations",
AddressValidationController,
only: [:index],
as: :validation
)
resources(
"/contracts",
AddressContractController,

@ -17,15 +17,19 @@
</div>
<h1 class="card-title"><%= address_title(@address) %> <%= gettext "Details" %> </h1>
<h3 class="<%= if BlockScoutWeb.AddressView.contract?(@address) do %>contract-address<% end %>" data-test="address_detail_hash"><%= @address.hash %></h3>
<div class="d-flex flex-column flex-lg-row justify-content-start text-muted">
<%= if address_name = primary_name(@address) do %>
<strong class="mr-4 mb-2 text-primary"><%= address_name %></strong>
<% end %>
<span class="mr-4 mb-2">
<span data-selector="transaction-count"><%= Cldr.Number.to_string!(@transaction_count, format: "#,###") %></span>
<%= gettext "Transactions" %>
<span data-selector="transaction-count">
<%= Cldr.Number.to_string!(@transaction_count, format: "#,###") %>
</span> <%= gettext("Transactions") %>
<%= if @validation_count > 0 do %>
<span data-selector="validation-count">
<%= Cldr.Number.to_string!(@validation_count, format: "#,###") %>
</span> <%= gettext("Blocks Validated") %>
<% end %>
</span>
<%= if @address.token do %>
<span class="mr-4 mb-2">

@ -29,6 +29,16 @@
to: address_internal_transaction_path(@conn, :index, @address.hash)
) %>
</li>
<%= if @validation_count > 0 do %>
<li class="nav-item">
<%= link(
"Blocks #{gettext("Validated")}",
class: "nav-link",
"data-test": "validations_tab_link",
to: address_validation_path(@conn, :index, @address.hash)
) %>
</li>
<% end %>
<li class="nav-item">
<%= link(
to: address_contract_path(@conn, :index, @address.hash),

@ -30,6 +30,16 @@
to: address_internal_transaction_path(@conn, :index, @address.hash)
) %>
</li>
<%= if @validation_count > 0 do %>
<li class="nav-item">
<%= link(
"Blocks #{gettext("Validated")}",
class: "nav-link",
"data-test": "validations_tab_link",
to: address_validation_path(@conn, :index, @address.hash)
) %>
</li>
<% end %>
<%= if contract?(@address) do %>
<li class="nav-item">
<%= link(
@ -76,13 +86,23 @@
"data-test": "internal_transactions_tab_link",
to: address_internal_transaction_path(@conn, :index, @address.hash)
) %>
<%= link(
to: address_contract_path(@conn, :index, @address.hash),
class: "dropdown-item") do %>
<%= gettext("Code") %>
<%= if @validation_count > 0 do %>
<%= link(
gettext("Blocks Validated"),
class: "nav-link",
"data-test": "validations_tab_link",
to: address_validation_path(@conn, :index, @address.hash)
) %>
<% end %>
<%= if contract?(@address) do %>
<%= link(
to: address_contract_path(@conn, :index, @address.hash),
class: "dropdown-item") do %>
<%= gettext("Code") %>
<%= if smart_contract_verified?(@address) do %>
<i class="far fa-check-circle"></i>
<%= if smart_contract_verified?(@address) do %>
<i class="far fa-check-circle"></i>
<% end %>
<% end %>
<% end %>
<%= link(

@ -29,6 +29,16 @@
to: address_internal_transaction_path(@conn, :index, @address.hash)
) %>
</li>
<%= if @validation_count > 0 do %>
<li class="nav-item">
<%= link(
"Blocks #{gettext("Validated")}",
class: "nav-link",
"data-test": "validations_tab_link",
to: address_validation_path(@conn, :index, @address.hash)
) %>
</li>
<% end %>
<li class="nav-item">
<%= link(
to: address_contract_path(@conn, :index, @address.hash),

@ -13,7 +13,6 @@
to: address_transaction_path(@conn, :index, @address.hash)
) %>
</li>
<li class="nav-item">
<%= link(
gettext("Tokens"),
@ -21,15 +20,24 @@
to: address_token_path(@conn, :index, @address.hash)
) %>
</li>
<li class="nav-item"> <%= link(
<li class="nav-item">
<%= link(
gettext("Internal Transactions"),
class: "nav-link",
"data-test": "internal_transactions_tab_link",
to: address_internal_transaction_path(@conn, :index, @address.hash)
) %>
</li>
<%= if @validation_count > 0 do %>
<li class="nav-item">
<%= link(
"Blocks #{gettext("Validated")}",
class: "nav-link",
"data-test": "validations_tab_link",
to: address_validation_path(@conn, :index, @address.hash)
) %>
</li>
<% end %>
<%= if AddressView.contract?(@address) do %>
<li class="nav-item">
<%= link(
@ -43,7 +51,6 @@
<% end %>
</li>
<% end %>
<%= if AddressView.smart_contract_with_read_only_functions?(@address) do %>
<li class="nav-item">
<%= link(
@ -70,28 +77,38 @@
</a>
<div class="dropdown-menu">
<%= link(
gettext("Transactions"),
class: "dropdown-item",
to: address_transaction_path(@conn, :index, @address.hash)
) %>
gettext("Transactions"),
class: "dropdown-item",
to: address_transaction_path(@conn, :index, @address.hash)
) %>
<%= link(
gettext("Tokens"),
class: "dropdown-item active",
to: address_token_path(@conn, :index, @address.hash)
) %>
gettext("Tokens"),
class: "dropdown-item",
to: address_token_path(@conn, :index, @address.hash)
) %>
<%= link(
gettext("Internal Transactions"),
class: "dropdown-item",
"data-test": "internal_transactions_tab_link",
to: address_internal_transaction_path(@conn, :index, @address.hash)
) %>
<%= link(
to: address_contract_path(@conn, :index, @address.hash),
class: "dropdown-item") do %>
<%= gettext("Code") %>
gettext("Internal Transactions"),
class: "dropdown-item",
"data-test": "internal_transactions_tab_link",
to: address_internal_transaction_path(@conn, :index, @address.hash)
) %>
<%= if @validation_count > 0 do %>
<%= link(
gettext("Blocks Validated"),
class: "nav-link",
"data-test": "validations_tab_link",
to: address_validation_path(@conn, :index, @address.hash)
) %>
<% end %>
<%= if AddressView.contract?(@address) do %>
<%= link(
to: address_contract_path(@conn, :index, @address.hash),
class: "dropdown-item") do %>
<%= gettext("Code") %>
<%= if AddressView.smart_contract_verified?(@address) do %>
<i class="far fa-check-circle"></i>
<%= if AddressView.smart_contract_verified?(@address) do %>
<i class="far fa-check-circle"></i>
<% end %>
<% end %>
<% end %>
<%= if AddressView.smart_contract_with_read_only_functions?(@address) do %>

@ -31,6 +31,16 @@
to: address_internal_transaction_path(@conn, :index, @address.hash)
) %>
</li>
<%= if @validation_count > 0 do %>
<li class="nav-item">
<%= link(
"Blocks #{gettext("Validated")}",
class: "nav-link",
"data-test": "validations_tab_link",
to: address_validation_path(@conn, :index, @address.hash)
) %>
</li>
<% end %>
<%= if contract?(@address) do %>
<li class="nav-item">
<%= link(
@ -60,21 +70,29 @@
<a class="nav-link active dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false"><%= gettext "Transactions" %></a>
<div class="dropdown-menu">
<%= link(
gettext("Transactions"),
class: "dropdown-item active",
to: address_transaction_path(@conn, :index, @address.hash)
) %>
gettext("Transactions"),
class: "dropdown-item",
to: address_transaction_path(@conn, :index, @address.hash)
) %>
<%= link(
gettext("Tokens"),
class: "dropdown-item",
to: address_token_path(@conn, :index, @address.hash)
) %>
gettext("Tokens"),
class: "dropdown-item",
to: address_token_path(@conn, :index, @address.hash)
) %>
<%= link(
gettext("Internal Transactions"),
class: "dropdown-item",
"data-test": "internal_transactions_tab_link",
to: address_internal_transaction_path(@conn, :index, @address.hash)
) %>
gettext("Internal Transactions"),
class: "dropdown-item",
"data-test": "internal_transactions_tab_link",
to: address_internal_transaction_path(@conn, :index, @address.hash)
) %>
<%= if @validation_count > 0 do %>
<%= link(
"Blocks #{gettext("Validated")}",
class: "nav-link",
"data-test": "validations_tab_link",
to: address_validation_path(@conn, :index, @address.hash)
) %>
<% end %>
<%= if contract?(@address) do %>
<%= link(
to: address_contract_path(@conn, :index, @address.hash),
@ -90,7 +108,7 @@
<%= link(
gettext("Read Contract"),
to: address_read_contract_path(@conn, :index, @address.hash),
class: "dropdown-item")%>
class: "dropdown-item") %>
<% end %>
</div>
</li>

@ -0,0 +1,155 @@
<section class="container">
<%= render BlockScoutWeb.AddressView, "overview.html", assigns %>
<section>
<div class="card">
<div class="card-header">
<!-- DESKTOP TAB NAV -->
<ul class="nav nav-tabs card-header-tabs d-none d-md-inline-flex">
<li class="nav-item">
<%= link(
gettext("Transactions"),
class: "nav-link",
to: address_transaction_path(@conn, :index, @address.hash)
) %>
</li>
<li class="nav-item">
<%= link(
gettext("Tokens"),
class: "nav-link",
to: address_token_path(@conn, :index, @address.hash)
) %>
</li>
<li class="nav-item"> <%= link(
gettext("Internal Transactions"),
class: "nav-link",
"data-test": "internal_transactions_tab_link",
to: address_internal_transaction_path(@conn, :index, @address.hash)
) %>
</li>
<%= if @validation_count > 0 do %>
<li class="nav-item">
<%= link(
"Blocks #{gettext("Validated")}",
class: "nav-link active",
"data-test": "validations_tab_link",
to: address_validation_path(@conn, :index, @address.hash)
) %>
</li>
<% end %>
<%= if contract?(@address) do %>
<li class="nav-item">
<%= link(
to: address_contract_path(@conn, :index, @address.hash),
class: "nav-link") do %>
<%= gettext("Code") %>
<%= if smart_contract_verified?(@address) do %>
<i class="far fa-check-circle"></i>
<% end %>
<% end %>
</li>
<% end %>
<%= if smart_contract_with_read_only_functions?(@address) do %>
<li class="nav-item">
<%= link(
gettext("Read Contract"),
to: address_read_contract_path(@conn, :index, @address.hash),
class: "nav-link")%>
</li>
<% end %>
<%= if smart_contract_with_read_only_functions?(@address) do %>
<li class="nav-item">
<%= link(
gettext("Read Contract"),
to: address_read_contract_path(@conn, :index, @address.hash),
class: "nav-link")%>
</li>
<% end %>
</ul>
<!-- MOBILE DROPDOWN NAV -->
<ul class="nav nav-tabs card-header-tabs d-md-none">
<li class="nav-item dropdown flex-fill text-center">
<a class="nav-link active dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false"><%= gettext "Tokens" %></a>
<div class="dropdown-menu">
<%= link(
gettext("Transactions"),
class: "dropdown-item",
to: address_transaction_path(@conn, :index, @address.hash)
) %>
<%= link(
gettext("Tokens"),
class: "dropdown-item",
to: address_token_path(@conn, :index, @address.hash)
) %>
<%= link(
gettext("Internal Transactions"),
class: "dropdown-item",
"data-test": "internal_transactions_tab_link",
to: address_internal_transaction_path(@conn, :index, @address.hash)
) %>
<%= if @validation_count > 0 do %>
<%= link(
"Blocks #{gettext("Validated")}",
class: "nav-link active",
"data-test": "validations_tab_link",
to: address_validation_path(@conn, :index, @address.hash)
) %>
<% end %>
<%= if contract?(@address) do %>
<%= link(
to: address_contract_path(@conn, :index, @address.hash),
class: "dropdown-item") do %>
<%= gettext("Code") %>
<%= if smart_contract_verified?(@address) do %>
<i class="far fa-check-circle"></i>
<% end %>
<% end %>
<% end %>
</div>
</li>
</ul>
</div>
<div class="card-body">
<div data-selector="channel-batching-message" style="display:none;">
<div data-selector="reload-button" class="alert alert-info">
<a href="#" class="alert-link"><span data-selector="channel-batching-count"></span> <%= gettext "More validations have come in." %></a>
</div>
</div>
<div data-selector="channel-disconnected-message" style="display:none;">
<div data-selector="reload-button" class="alert alert-danger">
<a href="#" class="alert-link"><%= gettext "Connection Lost, click to load newer validations" %></a>
</div>
</div>
<h2 class="card-title"><%="Blocks #{gettext("Validated")}"%></h2>
<%= if Enum.count(@blocks) > 0 do %>
<span data-selector="validations-list">
<%= for block <- @blocks do %>
<%= render BlockScoutWeb.BlockView, "_tile.html", block: block %>
<% end %>
</span>
<% else %>
<div class="tile tile-muted text-center">
<span data-selector="empty-validations-list"><%= gettext "There are no validations for this address." %></span>
</div>
<% end %>
<div>
<%= if @next_page_params do %>
<%= link(
gettext("Older"),
class: "button button-secondary button-sm float-right mt-3",
to: address_validation_path(
@conn,
:index,
@address,
@next_page_params
)
) %>
<% end %>
</div>
</div> <!-- Card Body -->
</div> <!-- Card -->
<section>
</section>

@ -0,0 +1,6 @@
defmodule BlockScoutWeb.AddressValidationView do
use BlockScoutWeb, :view
import BlockScoutWeb.AddressView,
only: [contract?: 1, smart_contract_verified?: 1, smart_contract_with_read_only_functions?: 1]
end

@ -826,7 +826,6 @@ defmodule Explorer.Chain do
@doc """
Lists the top 250 `t:Explorer.Chain.Address.t/0`'s' in descending order based on coin balance.
"""
@spec list_top_addresses :: [Address.t()]
def list_top_addresses do
@ -837,6 +836,54 @@ defmodule Explorer.Chain do
|> Repo.all()
end
@doc """
Counts the number of `t:Explorer.Chain.Block.t/0` validated by the `address`.
"""
@spec address_to_validation_count(Address.t()) :: non_neg_integer()
def address_to_validation_count(%Address{hash: hash}) do
{:ok, %{rows: [[result]]}} =
SQL.query(
Repo,
"""
SELECT COUNT(hash) FROM "blocks"
WHERE "miner_hash" = $1
""",
[hash.bytes]
)
result
end
@doc """
Finds all Blocks validated by the address given.
## Options
* `:necessity_by_association` - use to load `t:association/0` as `:required` or `:optional`. If an association is
`:required`, and the `t:Explorer.Chain.Block.t/0` has no associated record for that association, then the
`t:Explorer.Chain.Block.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` (a tuple of the lowest/oldest `{block_number}`) and. Results will be the internal
transactions older than the `block_number` that are passed.
Returns all blocks validated by the address given.
"""
@spec get_blocks_validated_by_address(
[paging_options | necessity_by_association_option],
Address.t()
) :: [Block.t()]
def get_blocks_validated_by_address(options \\ [], %Address{hash: hash}) when is_list(options) do
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
paging_options = Keyword.get(options, :paging_options, @default_paging_options)
Block
|> join_associations(necessity_by_association)
|> where(miner_hash: ^hash)
|> page_blocks(paging_options)
|> limit(^paging_options.page_size)
|> order_by(desc: :number)
|> Repo.all()
end
@doc """
Returns a stream of unfetched `t:Explorer.Chain.Address.CoinBalance.t/0`.

Loading…
Cancel
Save