From de3520667f8761d306e788b884622894cbd2b9a2 Mon Sep 17 00:00:00 2001 From: Amanda Sposito Date: Tue, 18 Dec 2018 15:04:33 -0200 Subject: [PATCH] Add reward value of a block in the tile and overview section --- .../address_validation_controller.ex | 3 +- .../controllers/block_controller.ex | 9 ++- .../block_transaction_controller.ex | 3 +- .../controllers/chain_controller.ex | 2 +- .../lib/block_scout_web/notifier.ex | 2 +- .../templates/block/_tile.html.eex | 9 +++ .../templates/block/overview.html.eex | 58 ++++++++++++++----- .../templates/chain/_block.html.eex | 8 +++ .../lib/block_scout_web/views/block_view.ex | 23 ++++++++ .../block_scout_web/views/block_view_test.exs | 47 +++++++++++++++ apps/explorer/lib/explorer/chain.ex | 20 +++++++ apps/explorer/lib/explorer/chain/block.ex | 5 +- .../lib/explorer/chain/block/reward.ex | 22 ++++++- apps/explorer/test/explorer/chain_test.exs | 38 ++++++++++++ apps/explorer/test/support/factory.ex | 11 +++- 15 files changed, 235 insertions(+), 25 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_validation_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_validation_controller.ex index 90944822ab..031467feb7 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_validation_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_validation_controller.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) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/block_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/block_controller.ex index c1246bcb7f..b2f6a89a68 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/block_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/block_controller.ex @@ -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" ] diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex index 554f696053..5599043728 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex @@ -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) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex index 1929bb352e..3110a5c669 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex @@ -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() diff --git a/apps/block_scout_web/lib/block_scout_web/notifier.ex b/apps/block_scout_web/lib/block_scout_web/notifier.ex index 4816c89dc2..f179d4891f 100644 --- a/apps/block_scout_web/lib/block_scout_web/notifier.ex +++ b/apps/block_scout_web/lib/block_scout_web/notifier.ex @@ -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", %{ diff --git a/apps/block_scout_web/lib/block_scout_web/templates/block/_tile.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/block/_tile.html.eex index e95f09728b..d714a92aa7 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/block/_tile.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/block/_tile.html.eex @@ -42,6 +42,15 @@ contract: false %> + <%= if show_reward?(@block.rewards) do %> +
+ + <%= gettext "Reward" %> + + <%= combined_rewards_value(@block) %> + +
+ <% end %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/block/overview.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/block/overview.html.eex index 345cc75377..cabd363a20 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/block/overview.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/block/overview.html.eex @@ -65,14 +65,14 @@ -
+
<%= gettext "Nonce" %>
<%= to_string(@block.nonce) %>
<%= if length(@block.uncle_relations) > 0 do %> -
+
<%= gettext "Uncles" %>
<%= for {relation, index} <- Enum.with_index(@block.uncle_relations) do %> @@ -87,6 +87,24 @@
<% end %> + + + <%= if show_reward?(@block.rewards) do %> +
+
<%= gettext "Gas Used" %>
+
+ <%= @block.gas_used |> Cldr.Number.to_string! %> + (<%= (Decimal.to_integer(@block.gas_used) / Decimal.to_integer(@block.gas_limit)) |> Cldr.Number.to_string!(format: "#.#%") %>) + +
+ +
+
<%= gettext "Gas Limit" %>
+
+ <%= Cldr.Number.to_string!(@block.gas_limit) %> +
+
+ <% end %> <% end %>
@@ -112,19 +130,33 @@ - +
-

<%= gettext "Gas Used" %>

-
- -

- <%= @block.gas_used |> Cldr.Number.to_string! %> - (<%= (Decimal.to_integer(@block.gas_used) / Decimal.to_integer(@block.gas_limit)) |> Cldr.Number.to_string!(format: "#.#%") %>) -

- - <%= @block.gas_limit |> Cldr.Number.to_string! %> <%= gettext "Gas Limit" %> -
+ <%= if show_reward?(@block.rewards) do %> +

<%= gettext "Block Rewards" %>

+ + <%= for block_reward <- @block.rewards do %> +
+
<%= block_reward_text(block_reward) %>
+
+ <%= format_wei_value(block_reward.reward, :ether) %> +
+
+ <% end %> + <% else %> +

<%= gettext "Gas Used" %>

+ +
+ +

+ <%= @block.gas_used |> Cldr.Number.to_string! %> + (<%= (Decimal.to_integer(@block.gas_used) / Decimal.to_integer(@block.gas_limit)) |> Cldr.Number.to_string!(format: "#.#%") %>) +

+ + <%= @block.gas_limit |> Cldr.Number.to_string! %> <%= gettext "Gas Limit" %> +
+ <% end %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex index 88443ccd0e..280b1c0549 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex @@ -18,5 +18,13 @@ address: @block.miner, contract: false %> + + <%= if BlockScoutWeb.BlockView.show_reward?(@block.rewards) do %> + + <%= gettext "Reward" %> + + <%= BlockScoutWeb.BlockView.combined_rewards_value(@block) %> + + <% end %> diff --git a/apps/block_scout_web/lib/block_scout_web/views/block_view.ex b/apps/block_scout_web/lib/block_scout_web/views/block_view.ex index b5308da4db..e475e7ace9 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/block_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/block_view.ex @@ -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 diff --git a/apps/block_scout_web/test/block_scout_web/views/block_view_test.exs b/apps/block_scout_web/test/block_scout_web/views/block_view_test.exs index 8c4c4c7c91..a25922cd07 100644 --- a/apps/block_scout_web/test/block_scout_web/views/block_view_test.exs +++ b/apps/block_scout_web/test/block_scout_web/views/block_view_test.exs @@ -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 diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index ec107ff540..5410ef9425 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -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 diff --git a/apps/explorer/lib/explorer/chain/block.ex b/apps/explorer/lib/explorer/chain/block.ex index 4b194587c9..f55f83b7df 100644 --- a/apps/explorer/lib/explorer/chain/block.ex +++ b/apps/explorer/lib/explorer/chain/block.ex @@ -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 diff --git a/apps/explorer/lib/explorer/chain/block/reward.ex b/apps/explorer/lib/explorer/chain/block/reward.ex index 06aa0d2b53..8189f33a98 100644 --- a/apps/explorer/lib/explorer/chain/block/reward.ex +++ b/apps/explorer/lib/explorer/chain/block/reward.ex @@ -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 diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index c102ba7e64..97743d6169 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -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 diff --git a/apps/explorer/test/support/factory.ex b/apps/explorer/test/support/factory.ex index 4572797e65..05ea2b4749 100644 --- a/apps/explorer/test/support/factory.ex +++ b/apps/explorer/test/support/factory.ex @@ -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),