Improve UI and delegators logic for banned pools (#2670)

Add ban reason, delegators' ban period, and make corresponding UI changes.
staking
Ed Man 5 years ago committed by Victor Baranov
parent e167996a7e
commit 888e56c13d
  1. 6
      apps/block_scout_web/assets/css/components/_stakes_table.scss
  2. 10
      apps/block_scout_web/assets/css/components/stakes/_modal_validator_info.scss
  3. 1
      apps/block_scout_web/assets/css/components/stakes/_stakes.scss
  4. 2
      apps/block_scout_web/lib/block_scout_web/channels/stakes_channel.ex
  5. 1
      apps/block_scout_web/lib/block_scout_web/controllers/stakes_controller.ex
  6. 15
      apps/block_scout_web/lib/block_scout_web/templates/stakes/_rows.html.eex
  7. 19
      apps/block_scout_web/lib/block_scout_web/templates/stakes/_stakes_modal_validator_info.html.eex
  8. 3
      apps/explorer/lib/explorer/chain/import/runner/staking_pools.ex
  9. 10
      apps/explorer/lib/explorer/chain/staking_pool.ex
  10. 3
      apps/explorer/lib/explorer/staking/contract_reader.ex
  11. 12
      apps/explorer/lib/explorer/staking/contract_state.ex
  12. 57
      apps/explorer/priv/contracts_abi/posdao/ValidatorSetAuRa.json
  13. 11
      apps/explorer/priv/repo/migrations/20190904170014_add_additional_ban_fields_to_staking_pools.exs
  14. 14
      apps/explorer/test/explorer/staking/contract_state_test.exs

@ -114,6 +114,12 @@ $stakes-table-cell-separation: 25px !default;
background-color: $stakes-banned-background; background-color: $stakes-banned-background;
color: $stakes-banned-color; color: $stakes-banned-color;
} }
.stakes-td-banned-info {
display: block;
float: left;
padding-right: 30px;
}
} }
.stakes-td-order { .stakes-td-order {

@ -47,3 +47,13 @@
padding: 0; padding: 0;
} }
} }
.modal-validator-alert {
padding: 10px 30px;
background-color: #fff3f7;
color: #ff7986;
border-top: 1px solid #fee6ef;
border-bottom: 1px solid #fee6ef;
line-height: 1.5;
font-size: 14px;
}

@ -95,6 +95,7 @@ $stakes-stats-item-border-color: #fff !default;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
padding-right: 30px; padding-right: 30px;
float: left;
} }
.stakes-control { .stakes-control {

@ -36,12 +36,14 @@ defmodule BlockScoutWeb.StakesChannel do
def handle_in("render_validator_info", %{"address" => staking_address}, socket) do def handle_in("render_validator_info", %{"address" => staking_address}, socket) do
pool = Chain.staking_pool(staking_address) pool = Chain.staking_pool(staking_address)
delegator = socket.assigns[:account] && Chain.staking_pool_delegator(staking_address, socket.assigns.account)
average_block_time = AverageBlockTime.average_block_time() average_block_time = AverageBlockTime.average_block_time()
token = ContractState.get(:token) token = ContractState.get(:token)
html = html =
View.render_to_string(StakesView, "_stakes_modal_validator_info.html", View.render_to_string(StakesView, "_stakes_modal_validator_info.html",
validator: pool, validator: pool,
delegator: delegator,
average_block_time: average_block_time, average_block_time: average_block_time,
token: token token: token
) )

@ -92,6 +92,7 @@ defmodule BlockScoutWeb.StakesController do
"_rows.html", "_rows.html",
token: token, token: token,
pool: pool, pool: pool,
delegator: delegator,
index: index, index: index,
average_block_time: average_block_time, average_block_time: average_block_time,
pools_type: filter, pools_type: filter,

@ -34,9 +34,20 @@
<td class="stakes-td"> <td class="stakes-td">
<%= if @pool.is_banned do %> <%= if @pool.is_banned do %>
<span class="stakes-td-banned-info"> <span class="stakes-td-banned-info">
Banned until block #<%= @pool.banned_until %> (<%= estimated_unban_day(@pool.banned_until, @average_block_time) %>) Banned until block #<%= @pool.banned_until %> (<%= estimated_unban_day(@pool.banned_until, @average_block_time) %>).
<%= if @delegator &&
@delegator.delegator_address_hash != @pool.staking_address_hash &&
@pool.are_delegators_banned &&
@pool.banned_until != @pool.banned_delegators_until do %>
You will be able to withdraw after block #<%= @pool.banned_delegators_until %> (<%= estimated_unban_day(@pool.banned_delegators_until, @average_block_time) %>)
<% end %>
</span> </span>
<% else %> <% end %>
<%= if !@pool.is_banned ||
(!@pool.are_delegators_banned &&
@delegator &&
@delegator.delegator_address_hash != @pool.staking_address_hash
) do %>
<div class="stakes-controls"> <div class="stakes-controls">
<%= if @buttons.move do %> <%= if @buttons.move do %>
<%= render BlockScoutWeb.StakesView, "_stakes_control_move.html", address: @pool.staking_address_hash %> <%= render BlockScoutWeb.StakesView, "_stakes_control_move.html", address: @pool.staking_address_hash %>

@ -10,6 +10,19 @@
</div> </div>
</div> </div>
</div> </div>
<%= if @validator.is_banned do %>
<div class="modal-validator-alert">
This pool is banned until block <%= "##{@validator.banned_until} (#{estimated_unban_day(@validator.banned_until, @average_block_time)})" %><br />
Reason for Ban: <%= String.capitalize(@validator.ban_reason) %>
<%= if @delegator &&
@delegator.delegator_address_hash != @validator.staking_address_hash &&
@validator.are_delegators_banned &&
@validator.banned_until != @validator.banned_delegators_until do %>
<br />
You will be able to withdraw after block #<%= @validator.banned_delegators_until %> (<%= estimated_unban_day(@validator.banned_delegators_until, @average_block_time) %>)
<% end %>
</div>
<% end %>
<%= render BlockScoutWeb.CommonComponentsView, "_modal_close_button.html" %> <%= render BlockScoutWeb.CommonComponentsView, "_modal_close_button.html" %>
<div class="modal-validator-info-content"> <div class="modal-validator-info-content">
<%= <%=
@ -48,12 +61,6 @@
title: "How Many Times this Address has been Banned", title: "How Many Times this Address has been Banned",
value: @validator.was_banned_count value: @validator.was_banned_count
%> %>
<%=
render BlockScoutWeb.StakesView,
"_stakes_validator_info_item.html",
title: "The Block Number and Approximate Date When the Address Will be Unbanned",
value: if(@validator.is_banned, do: "##{@validator.banned_until} (#{estimated_unban_day(@validator.banned_until, @average_block_time)})")
%>
<%= <%=
render BlockScoutWeb.StakesView, render BlockScoutWeb.StakesView,
"_stakes_validator_info_item.html", "_stakes_validator_info_item.html",

@ -128,15 +128,18 @@ defmodule Explorer.Chain.Import.Runner.StakingPools do
is_banned: fragment("EXCLUDED.is_banned"), is_banned: fragment("EXCLUDED.is_banned"),
is_validator: fragment("EXCLUDED.is_validator"), is_validator: fragment("EXCLUDED.is_validator"),
is_unremovable: fragment("EXCLUDED.is_unremovable"), is_unremovable: fragment("EXCLUDED.is_unremovable"),
are_delegators_banned: fragment("EXCLUDED.are_delegators_banned"),
likelihood: fragment("EXCLUDED.likelihood"), likelihood: fragment("EXCLUDED.likelihood"),
block_reward_ratio: fragment("EXCLUDED.block_reward_ratio"), block_reward_ratio: fragment("EXCLUDED.block_reward_ratio"),
staked_ratio: fragment("EXCLUDED.staked_ratio"), staked_ratio: fragment("EXCLUDED.staked_ratio"),
self_staked_amount: fragment("EXCLUDED.self_staked_amount"), self_staked_amount: fragment("EXCLUDED.self_staked_amount"),
staked_amount: fragment("EXCLUDED.staked_amount"), staked_amount: fragment("EXCLUDED.staked_amount"),
ban_reason: fragment("EXCLUDED.ban_reason"),
was_banned_count: fragment("EXCLUDED.was_banned_count"), was_banned_count: fragment("EXCLUDED.was_banned_count"),
was_validator_count: fragment("EXCLUDED.was_validator_count"), was_validator_count: fragment("EXCLUDED.was_validator_count"),
is_deleted: fragment("EXCLUDED.is_deleted"), is_deleted: fragment("EXCLUDED.is_deleted"),
banned_until: fragment("EXCLUDED.banned_until"), banned_until: fragment("EXCLUDED.banned_until"),
banned_delegators_until: fragment("EXCLUDED.banned_delegators_until"),
inserted_at: fragment("LEAST(?, EXCLUDED.inserted_at)", pool.inserted_at), inserted_at: fragment("LEAST(?, EXCLUDED.inserted_at)", pool.inserted_at),
updated_at: fragment("GREATEST(?, EXCLUDED.updated_at)", pool.updated_at) updated_at: fragment("GREATEST(?, EXCLUDED.updated_at)", pool.updated_at)
] ]

@ -15,17 +15,20 @@ defmodule Explorer.Chain.StakingPool do
@type t :: %__MODULE__{ @type t :: %__MODULE__{
staking_address_hash: Hash.Address.t(), staking_address_hash: Hash.Address.t(),
mining_address_hash: Hash.Address.t(), mining_address_hash: Hash.Address.t(),
banned_until: boolean, banned_until: integer,
banned_delegators_until: integer,
delegators_count: integer, delegators_count: integer,
is_active: boolean, is_active: boolean,
is_banned: boolean, is_banned: boolean,
is_validator: boolean, is_validator: boolean,
is_unremovable: boolean, is_unremovable: boolean,
are_delegators_banned: boolean,
likelihood: Decimal.t(), likelihood: Decimal.t(),
block_reward_ratio: Decimal.t(), block_reward_ratio: Decimal.t(),
staked_ratio: Decimal.t(), staked_ratio: Decimal.t(),
self_staked_amount: Decimal.t(), self_staked_amount: Decimal.t(),
staked_amount: Decimal.t(), staked_amount: Decimal.t(),
ban_reason: String.t(),
was_banned_count: integer, was_banned_count: integer,
was_validator_count: integer, was_validator_count: integer,
is_deleted: boolean is_deleted: boolean
@ -33,7 +36,7 @@ defmodule Explorer.Chain.StakingPool do
@attrs ~w( @attrs ~w(
is_active delegators_count staked_amount self_staked_amount is_validator is_active delegators_count staked_amount self_staked_amount is_validator
was_validator_count is_banned was_banned_count banned_until likelihood was_validator_count is_banned are_delegators_banned ban_reason was_banned_count banned_until banned_delegators_until likelihood
staked_ratio staking_address_hash mining_address_hash block_reward_ratio staked_ratio staking_address_hash mining_address_hash block_reward_ratio
is_unremovable is_unremovable
)a )a
@ -45,16 +48,19 @@ defmodule Explorer.Chain.StakingPool do
schema "staking_pools" do schema "staking_pools" do
field(:banned_until, :integer) field(:banned_until, :integer)
field(:banned_delegators_until, :integer)
field(:delegators_count, :integer) field(:delegators_count, :integer)
field(:is_active, :boolean, default: false) field(:is_active, :boolean, default: false)
field(:is_banned, :boolean, default: false) field(:is_banned, :boolean, default: false)
field(:is_validator, :boolean, default: false) field(:is_validator, :boolean, default: false)
field(:is_unremovable, :boolean, default: false) field(:is_unremovable, :boolean, default: false)
field(:are_delegators_banned, :boolean, default: false)
field(:likelihood, :decimal) field(:likelihood, :decimal)
field(:block_reward_ratio, :decimal) field(:block_reward_ratio, :decimal)
field(:staked_ratio, :decimal) field(:staked_ratio, :decimal)
field(:self_staked_amount, :decimal) field(:self_staked_amount, :decimal)
field(:staked_amount, :decimal) field(:staked_amount, :decimal)
field(:ban_reason, :string)
field(:was_banned_count, :integer) field(:was_banned_count, :integer)
field(:was_validator_count, :integer) field(:was_validator_count, :integer)
field(:is_deleted, :boolean, default: false) field(:is_deleted, :boolean, default: false)

@ -41,7 +41,10 @@ defmodule Explorer.Staking.ContractReader do
[ [
was_validator_count: {:validator_set, "validatorCounter", [mining_address]}, was_validator_count: {:validator_set, "validatorCounter", [mining_address]},
is_banned: {:validator_set, "isValidatorBanned", [mining_address]}, is_banned: {:validator_set, "isValidatorBanned", [mining_address]},
are_delegators_banned: {:validator_set, "areDelegatorsBanned", [mining_address]},
ban_reason: {:validator_set, "banReason", [mining_address]},
banned_until: {:validator_set, "bannedUntil", [mining_address]}, banned_until: {:validator_set, "bannedUntil", [mining_address]},
banned_delegators_until: {:validator_set, "bannedDelegatorsUntil", [mining_address]},
was_banned_count: {:validator_set, "banCounter", [mining_address]} was_banned_count: {:validator_set, "banCounter", [mining_address]}
] ]
end end

@ -186,7 +186,8 @@ defmodule Explorer.Staking.ContractState do
block_reward_ratio: staking_response.block_reward / 10_000, block_reward_ratio: staking_response.block_reward / 10_000,
is_deleted: false, is_deleted: false,
is_validator: is_validator[staking_response.mining_address_hash] || false, is_validator: is_validator[staking_response.mining_address_hash] || false,
is_unremovable: hash_to_string(staking_address) == unremovable_validator is_unremovable: hash_to_string(staking_address) == unremovable_validator,
ban_reason: binary_to_string(mining_response.ban_reason)
} }
|> Map.merge( |> Map.merge(
Map.take(staking_response, [ Map.take(staking_response, [
@ -200,7 +201,9 @@ defmodule Explorer.Staking.ContractState do
Map.take(mining_response, [ Map.take(mining_response, [
:was_validator_count, :was_validator_count,
:is_banned, :is_banned,
:are_delegators_banned,
:banned_until, :banned_until,
:banned_delegators_until,
:was_banned_count :was_banned_count
]) ])
) )
@ -318,4 +321,11 @@ defmodule Explorer.Staking.ContractState do
|> File.read!() |> File.read!()
|> Jason.decode!() |> Jason.decode!()
end end
defp binary_to_string(binary) do
binary
|> :binary.bin_to_list()
|> Enum.filter(fn x -> x != 0 end)
|> List.to_string()
end
end end

@ -126,6 +126,25 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"constant": true,
"inputs": [
{
"name": "",
"type": "address"
}
],
"name": "banReason",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{ {
"constant": true, "constant": true,
"inputs": [ "inputs": [
@ -145,6 +164,25 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"constant": true,
"inputs": [
{
"name": "",
"type": "address"
}
],
"name": "bannedDelegatorsUntil",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{ {
"constant": true, "constant": true,
"inputs": [], "inputs": [],
@ -630,6 +668,25 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"constant": true,
"inputs": [
{
"name": "_miningAddress",
"type": "address"
}
],
"name": "areDelegatorsBanned",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{ {
"constant": true, "constant": true,
"inputs": [ "inputs": [

@ -0,0 +1,11 @@
defmodule Explorer.Repo.Migrations.AddAdditionalBanFieldsToStakingPools do
use Ecto.Migration
def change do
alter table(:staking_pools) do
add(:are_delegators_banned, :boolean, default: false)
add(:ban_reason, :string)
add(:banned_delegators_until, :bigint)
end
end
end

@ -149,7 +149,7 @@ defmodule Explorer.Staking.ContractStateTest do
EthereumJSONRPC.Mox, EthereumJSONRPC.Mox,
:json_rpc, :json_rpc,
fn requests, _opts -> fn requests, _opts ->
assert length(requests) == 16 assert length(requests) == 28
{:ok, {:ok,
format_responses([ format_responses([
@ -157,17 +157,29 @@ defmodule Explorer.Staking.ContractStateTest do
"0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000002",
"0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x000000000000000000000000000000000000000000000000000000000000004a", "0x000000000000000000000000000000000000000000000000000000000000004a",
"0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x000000000000000000000000000000000000000000000000000000000000004a", "0x000000000000000000000000000000000000000000000000000000000000004a",
"0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000" "0x0000000000000000000000000000000000000000000000000000000000000000"
])} ])}
end end

Loading…
Cancel
Save