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),