Add reward value of a block in the tile and overview section

pull/1249/head
Amanda Sposito 6 years ago
parent d8a894c66a
commit de3520667f
  1. 3
      apps/block_scout_web/lib/block_scout_web/controllers/address_validation_controller.ex
  2. 9
      apps/block_scout_web/lib/block_scout_web/controllers/block_controller.ex
  3. 3
      apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex
  4. 2
      apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex
  5. 2
      apps/block_scout_web/lib/block_scout_web/notifier.ex
  6. 9
      apps/block_scout_web/lib/block_scout_web/templates/block/_tile.html.eex
  7. 38
      apps/block_scout_web/lib/block_scout_web/templates/block/overview.html.eex
  8. 8
      apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex
  9. 23
      apps/block_scout_web/lib/block_scout_web/views/block_view.ex
  10. 47
      apps/block_scout_web/test/block_scout_web/views/block_view_test.exs
  11. 20
      apps/explorer/lib/explorer/chain.ex
  12. 5
      apps/explorer/lib/explorer/chain/block.ex
  13. 22
      apps/explorer/lib/explorer/chain/block/reward.ex
  14. 38
      apps/explorer/test/explorer/chain_test.exs
  15. 11
      apps/explorer/test/support/factory.ex

@ -23,7 +23,8 @@ defmodule BlockScoutWeb.AddressValidationController do
necessity_by_association: %{
miner: :required,
nephews: :optional,
transactions: :optional
transactions: :optional,
rewards: :optional
}
],
paging_options(params)

@ -11,7 +11,8 @@ defmodule BlockScoutWeb.BlockController do
[
necessity_by_association: %{
:transactions => :optional,
[miner: :names] => :optional
[miner: :names] => :optional,
:rewards => :optional
}
]
|> handle_render(conn, params)
@ -25,7 +26,8 @@ defmodule BlockScoutWeb.BlockController do
[
necessity_by_association: %{
:transactions => :optional,
[miner: :names] => :optional
[miner: :names] => :optional,
:rewards => :optional
},
block_type: "Reorg"
]
@ -37,7 +39,8 @@ defmodule BlockScoutWeb.BlockController do
necessity_by_association: %{
:transactions => :optional,
[miner: :names] => :optional,
:nephews => :required
:nephews => :required,
:rewards => :optional
},
block_type: "Uncle"
]

@ -13,7 +13,8 @@ defmodule BlockScoutWeb.BlockTransactionController do
necessity_by_association: %{
[miner: :names] => :required,
:uncles => :optional,
:nephews => :optional
:nephews => :optional,
:rewards => :optional
}
) do
block_transaction_count = Chain.block_to_transaction_count(block)

@ -10,7 +10,7 @@ defmodule BlockScoutWeb.ChainController do
blocks =
[paging_options: %PagingOptions{page_size: 4}]
|> Chain.list_blocks()
|> Repo.preload([[miner: :names], :transactions])
|> Repo.preload([[miner: :names], :transactions, :rewards])
transaction_estimated_count = Chain.transaction_estimated_count()

@ -108,7 +108,7 @@ defmodule BlockScoutWeb.Notifier do
end
defp broadcast_block(block) do
preloaded_block = Repo.preload(block, [[miner: :names], :transactions])
preloaded_block = Repo.preload(block, [[miner: :names], :transactions, :rewards])
average_block_time = Chain.average_block_time()
Endpoint.broadcast("blocks:new_block", "new_block", %{

@ -42,6 +42,15 @@
contract: false %>
</span>
</div>
<%= if show_reward?(@block.rewards) do %>
<div class="text-nowrap text-truncate mt-3 mt-md-0">
<!-- validator reward -->
<%= gettext "Reward" %>
<span class="ml-2">
<%= combined_rewards_value(@block) %>
</span>
</div>
<% end %>
</div>
<div class="col-md-4 col-lg-3 text-md-right d-flex flex-column align-items-md-end justify-content-md-end mt-3 mt-md-0">
<!-- Gas Limit -->

@ -65,14 +65,14 @@
</dl>
<!-- Nonce -->
<dl class="row mb-0">
<dl class="row">
<dt class="col-sm-3 text-muted"> <%= gettext "Nonce" %> </dt>
<dd class="col-sm-9"> <%= to_string(@block.nonce) %> </dd>
</dl>
<%= if length(@block.uncle_relations) > 0 do %>
<!-- Uncles -->
<dl class="row mt-3 mb-0">
<dl class="row mt-3">
<dt class="col-sm-3 text-muted"> <%= gettext "Uncles" %> </dt>
<dd class="col-sm-9">
<%= for {relation, index} <- Enum.with_index(@block.uncle_relations) do %>
@ -87,6 +87,24 @@
</dd>
</dl>
<% end %>
<!-- Otherwise it will be displayed in its own block -->
<%= if show_reward?(@block.rewards) do %>
<dl class="row">
<dt class="col-sm-3 text-muted"><%= gettext "Gas Used" %></dt>
<dd class="col-sm-9">
<%= @block.gas_used |> Cldr.Number.to_string! %>
<span class="text-muted"> (<%= (Decimal.to_integer(@block.gas_used) / Decimal.to_integer(@block.gas_limit)) |> Cldr.Number.to_string!(format: "#.#%") %>) </span>
</dt>
</dl>
<dl class="row mb-0">
<dt class="col-sm-3 text-muted"><%= gettext "Gas Limit" %></dt>
<dd class="col-sm-9">
<%= Cldr.Number.to_string!(@block.gas_limit) %>
</dd>
</dl>
<% end %>
<% end %>
</div>
</div>
@ -112,10 +130,23 @@
</div>
</div>
<!-- Gas -->
<!-- Validator Reward or Gas-->
<div class="card flex-grow-1 ml-0 ml-md-5 ml-lg-0">
<div class="card-body">
<%= if show_reward?(@block.rewards) do %>
<h2 class="card-title"> <%= gettext "Block Rewards" %> </h2>
<%= for block_reward <- @block.rewards do %>
<dl class="row">
<dt class="col-sm-5 text-muted"><%= block_reward_text(block_reward) %></dt>
<dd class="col-sm-7">
<%= format_wei_value(block_reward.reward, :ether) %></dt>
</dd>
</dl>
<% end %>
<% else %>
<h2 class="card-title"> <%= gettext "Gas Used" %> </h2>
<div class="text-right">
<!-- Gas Used -->
<h3>
@ -125,6 +156,7 @@
<!-- Gas Limit -->
<span class="text-muted"> <%= @block.gas_limit |> Cldr.Number.to_string! %> <%= gettext "Gas Limit" %> </span>
</div>
<% end %>
</div>
</div>
</div>

@ -18,5 +18,13 @@
address: @block.miner,
contract: false %>
</span>
<%= if BlockScoutWeb.BlockView.show_reward?(@block.rewards) do %>
<span class="text-truncate">
<%= gettext "Reward" %>
<%= BlockScoutWeb.BlockView.combined_rewards_value(@block) %>
</span>
<% end %>
</div>
</div>

@ -3,7 +3,9 @@ defmodule BlockScoutWeb.BlockView do
import Math.Enum, only: [mean: 1]
alias Explorer.Chain
alias Explorer.Chain.{Block, Wei}
alias Explorer.Chain.Block.Reward
@dialyzer :no_match
@ -46,4 +48,25 @@ defmodule BlockScoutWeb.BlockView do
def formatted_timestamp(%Block{timestamp: timestamp}) do
Timex.format!(timestamp, "%b-%d-%Y %H:%M:%S %p %Z", :strftime)
end
def show_reward?([]), do: false
def show_reward?(_), do: true
def block_reward_text(%Reward{address_type: :validator}) do
gettext("Miner Reward")
end
def block_reward_text(%Reward{address_type: :emission_funds}) do
gettext("Emission Reward")
end
def block_reward_text(%Reward{address_type: :uncle}) do
gettext("Uncle Reward")
end
def combined_rewards_value(block) do
block
|> Chain.block_combined_rewards()
|> format_wei_value(:ether)
end
end

@ -47,4 +47,51 @@ defmodule BlockScoutWeb.BlockViewTest do
BlockView.formatted_timestamp(block)
end
end
describe "show_reward?/1" do
test "returns false when list of rewards is empty" do
assert BlockView.show_reward?([]) == false
end
test "returns true when list of rewards is not empty" do
block = insert(:block)
validator = insert(:reward, address_hash: block.miner_hash, block_hash: block.hash, address_type: :validator)
assert BlockView.show_reward?([validator]) == true
end
end
describe "combined_rewards_value/1" do
test "returns all the reward values summed up and formatted into a String" do
block = insert(:block)
insert(
:reward,
address_hash: block.miner_hash,
block_hash: block.hash,
address_type: :validator,
reward: Decimal.new(1_000_000_000_000_000_000)
)
insert(
:reward,
address_hash: block.miner_hash,
block_hash: block.hash,
address_type: :emission_funds,
reward: Decimal.new(1_000_000_000_000_000_000)
)
insert(
:reward,
address_hash: block.miner_hash,
block_hash: block.hash,
address_type: :uncle,
reward: Decimal.new(1_000_042_000_000_000_000)
)
block = Repo.preload(block, :rewards)
assert BlockView.combined_rewards_value(block) == "3.000042 POA"
end
end
end

@ -2156,4 +2156,24 @@ defmodule Explorer.Chain do
Repo.all(query, timeout: :infinity)
end
@doc """
Combined block reward from all the fees.
"""
@spec block_combined_rewards(Block.t()) :: Wei.t()
def block_combined_rewards(block) do
{:ok, value} =
block.rewards
|> Enum.reduce(
0,
fn block_reward, acc ->
{:ok, decimal} = Wei.dump(block_reward.reward)
Decimal.add(decimal, acc)
end
)
|> Wei.cast()
value
end
end

@ -7,7 +7,8 @@ defmodule Explorer.Chain.Block do
use Explorer.Schema
alias Explorer.Chain.{Address, Block.SecondDegreeRelation, Gas, Hash, Transaction}
alias Explorer.Chain.{Address, Gas, Hash, Transaction}
alias Explorer.Chain.Block.{Reward, SecondDegreeRelation}
@required_attrs ~w(consensus difficulty gas_limit gas_used hash miner_hash nonce number parent_hash size timestamp
total_difficulty)a
@ -87,6 +88,8 @@ defmodule Explorer.Chain.Block do
has_many(:uncles, through: [:uncle_relations, :uncle])
has_many(:transactions, Transaction)
has_many(:rewards, Reward, foreign_key: :block_hash)
end
def changeset(%__MODULE__{} = block, attrs) do

@ -6,7 +6,7 @@ defmodule Explorer.Chain.Block.Reward do
use Explorer.Schema
alias Explorer.Chain.Block.Reward.AddressType
alias Explorer.Chain.{Hash, Wei}
alias Explorer.Chain.{Address, Block, Hash, Wei}
@required_attrs ~w(address_hash address_type block_hash reward)a
@ -19,19 +19,35 @@ defmodule Explorer.Chain.Block.Reward do
* `:reward` - Total block reward
"""
@type t :: %__MODULE__{
address: %Ecto.Association.NotLoaded{} | Address.t() | nil,
address_hash: Hash.Address.t(),
address_type: AddressType.t(),
block: %Ecto.Association.NotLoaded{} | Block.t() | nil,
block_hash: Hash.Full.t(),
reward: Wei.t()
}
@primary_key false
schema "block_rewards" do
field(:address_hash, Hash.Address)
field(:address_type, AddressType)
field(:block_hash, Hash.Full)
field(:reward, Wei)
belongs_to(
:address,
Address,
foreign_key: :address_hash,
references: :hash,
type: Hash.Address
)
belongs_to(
:block,
Block,
foreign_key: :block_hash,
references: :hash,
type: Hash.Full
)
timestamps()
end

@ -22,6 +22,8 @@ defmodule Explorer.ChainTest do
Wei
}
alias Explorer.Chain.Block.Reward
alias Explorer.Chain.Supply.ProofOfAuthority
alias Explorer.Counters.{AddressesWithBalanceCounter, TokenHoldersCounter}
@ -3177,4 +3179,40 @@ defmodule Explorer.ChainTest do
[block2_with_invalid_consensus.number, block8_with_invalid_consensus.number]
end
end
describe "block_combined_rewards/1" do
test "sums the block_rewards values" do
block = insert(:block)
insert(
:reward,
address_hash: block.miner_hash,
block_hash: block.hash,
address_type: :validator,
reward: Decimal.new(1_000_000_000_000_000_000)
)
insert(
:reward,
address_hash: block.miner_hash,
block_hash: block.hash,
address_type: :emission_funds,
reward: Decimal.new(1_000_000_000_000_000_000)
)
insert(
:reward,
address_hash: block.miner_hash,
block_hash: block.hash,
address_type: :uncle,
reward: Decimal.new(1_000_000_000_000_000_000)
)
block = Repo.preload(block, :rewards)
{:ok, expected_value} = Wei.cast(3_000_000_000_000_000_000)
assert Chain.block_combined_rewards(block) == expected_value
end
end
end

@ -9,7 +9,7 @@ defmodule Explorer.Factory do
alias Comeonin.Bcrypt
alias Explorer.Accounts.{User, UserContact}
alias Explorer.Admin.Administrator
alias Explorer.Chain.Block.{EmissionReward, Range}
alias Explorer.Chain.Block.{EmissionReward, Range, Reward}
alias Explorer.Chain.{
Address,
@ -425,6 +425,15 @@ defmodule Explorer.Factory do
}
end
def reward_factory do
%Reward{
address_hash: build(:address).hash,
address_type: :validator,
block_hash: build(:block).hash,
reward: Decimal.new(3)
}
end
def transaction_factory do
%Transaction{
from_address: build(:address),

Loading…
Cancel
Save