Commit 7539cc69 authored by Jeremy Cooper's avatar Jeremy Cooper
Browse files

Implement hbbft_perf for JSONRPC.

Implement the `hbbft_perf` for JSON/RPC use, as requested in
helium/miner #873.

A large portion of this code originally lived entirely within
`miner_cli_hbbft.erl`, so rather than duplicate it, the essential
information gathering now happens in `miner_util.erl` (per Evan's
suggestion) and is then parsed and formatted in different ways
by the CLI (`miner_cli_hbbft.erl`) and the JSON/RPC handler
(`miner_jsronrpc_hbbft.erl`).

This is a cherry-pick commit to rescue a branch that has been
screwed up by a bad rebase/merge.
parent ae143b3c
Showing with 78 additions and 57 deletions
+78 -57
......@@ -6,8 +6,6 @@
-behavior(clique_handler).
-include_lib("blockchain/include/blockchain_vars.hrl").
-export([register_cli/0]).
register_cli() ->
......@@ -234,53 +232,8 @@ hbbft_perf_usage() ->
].
hbbft_perf(["hbbft", "perf"], [], Flags) ->
%% calculate the current election start height
Chain = blockchain_worker:blockchain(),
Ledger = blockchain:ledger(Chain),
{ok, ConsensusAddrs} = blockchain_ledger_v1:consensus_members(Ledger),
InitMap = maps:from_list([ {Addr, {0, 0}} || Addr <- ConsensusAddrs]),
#{start_height := Start0, curr_height := End} = blockchain_election:election_info(Ledger),
{Start, GroupWithPenalties} =
case blockchain:config(?election_version, Ledger) of
{ok, N} when N >= 5 ->
Penalties = blockchain_election:validator_penalties(ConsensusAddrs, Ledger),
Start1 = case End > (Start0 + 2) of
true -> Start0 + 2;
false -> End + 1
end,
Penalties1 =
maps:map(
fun(Addr, Pen) ->
{ok, V} = blockchain_ledger_v1:get_validator(Addr, Ledger),
Pens = blockchain_ledger_validator_v1:calculate_penalties(V, Ledger),
{Pen + lists:sum(maps:values(Pens)), maps:get(tenure, Pens, 0.0)}
end, Penalties),
{Start1, maps:to_list(Penalties1)};
_ ->
{Start0 + 1,
[{A, {S, 0.0}}
|| {S, _L, A} <- blockchain_election:adjust_old_group(
[{0, 0, A} || A <- ConsensusAddrs], Ledger)]}
end,
Blocks = [begin {ok, Block} = blockchain:get_block(Ht, Chain), Block end
|| Ht <- lists:seq(Start, End)],
{BBATotals, SeenTotals, TotalCount} =
lists:foldl(
fun(Blk, {BBAAcc, SeenAcc, Count}) ->
H = blockchain_block:height(Blk),
BBAs = blockchain_utils:bitvector_to_map(
length(ConsensusAddrs),
blockchain_block_v1:bba_completion(Blk)),
SeenVotes = blockchain_block_v1:seen_votes(Blk),
Seen = lists:foldl(
fun({_Idx, Votes0}, Acc) ->
Votes = blockchain_utils:bitvector_to_map(
length(ConsensusAddrs), Votes0),
merge_map(ConsensusAddrs, Votes, H, Acc)
end,SeenAcc, SeenVotes),
{merge_map(ConsensusAddrs, BBAs, H, BBAAcc), Seen, Count + length(SeenVotes)}
end, {InitMap, InitMap, 0}, Blocks),
{ConsensusAddrs, BBATotals, SeenTotals, TotalCount, GroupWithPenalties, Start0, Start, End} =
miner_util:hbbft_perf(),
[clique_status:table(
[[{name, element(2, erl_angry_purple_tiger:animal_name(libp2p_crypto:bin_to_b58(A)))} ] ++
[ {address, libp2p_crypto:pubkey_bin_to_p2p(A)} || lists:keymember(verbose, 1, Flags)] ++
......@@ -294,10 +247,3 @@ hbbft_perf(["hbbft", "perf"], [], Flags) ->
] || A <- ConsensusAddrs])];
hbbft_perf([], [], []) ->
usage.
merge_map(Addrs, Votes, Height, Acc) ->
maps:fold(fun(K, true, A) ->
maps:update_with(lists:nth(K, Addrs), fun({_, V}) -> {Height, V+1} end, {Height, 1}, A);
(_, false, A) ->
A
end, Acc, Votes).
......@@ -53,5 +53,21 @@ handle_rpc(<<"hbbft_queue">>, []) ->
inbound => length(Inbound),
outbound => Outbound1
};
handle_rpc(<<"hbbft_perf">>, []) ->
{ConsensusAddrs, BBATotals, SeenTotals, TotalCount, GroupWithPenalties, Start0, Start, End} =
miner_util:hbbft_perf(),
[
#{
name => ?TO_VALUE(?TO_ANIMAL_NAME(A)),
address => ?TO_VALUE(?TO_B58(A)),
bba_completions => [element(2, maps:get(A, BBATotals)), End+1 - Start],
seen_votes => [element(2, maps:get(A, SeenTotals)), TotalCount],
last_bba => End - max(Start0 + 1, element(1, maps:get(A, BBATotals))),
last_seen => End - max(Start0 + 1, element(1, maps:get(A, SeenTotals))),
tenure => [element(2, element(2, lists:keyfind(A, 1, GroupWithPenalties)))],
penalty => [element(1, element(2, lists:keyfind(A, 1, GroupWithPenalties)))]
}
|| A <- ConsensusAddrs
];
handle_rpc(_, _) ->
?jsonrpc_error(method_not_found).
......@@ -14,13 +14,16 @@
mark/2,
metadata_fun/0,
random_peer_predicate/1,
has_valid_local_capability/2
has_valid_local_capability/2,
hbbft_perf/0
]).
%% get the firmware release data from a hotspot
-define(LSB_FILE, "/etc/lsb_release").
-define(RELEASE_CMD, "cat " ++ ?LSB_FILE ++ " | grep RELEASE | cut -d'=' -f2").
-include_lib("blockchain/include/blockchain_vars.hrl").
%%-----------------------------------------------------------------------------
%% @doc Count the number of occurrences of each element in the list.
%% @end
......@@ -136,3 +139,59 @@ has_valid_local_capability(Capability, Ledger) ->
ok
end
end.
hbbft_perf() ->
%% calculate the current election start height
Chain = blockchain_worker:blockchain(),
Ledger = blockchain:ledger(Chain),
{ok, ConsensusAddrs} = blockchain_ledger_v1:consensus_members(Ledger),
InitMap = maps:from_list([ {Addr, {0, 0}} || Addr <- ConsensusAddrs]),
#{start_height := Start0, curr_height := End} = blockchain_election:election_info(Ledger),
{Start, GroupWithPenalties} =
case blockchain:config(?election_version, Ledger) of
{ok, N} when N >= 5 ->
Penalties = blockchain_election:validator_penalties(ConsensusAddrs, Ledger),
Start1 = case End > (Start0 + 2) of
true -> Start0 + 2;
false -> End + 1
end,
Penalties1 =
maps:map(
fun(Addr, Pen) ->
{ok, V} = blockchain_ledger_v1:get_validator(Addr, Ledger),
Pens = blockchain_ledger_validator_v1:calculate_penalties(V, Ledger),
{Pen + lists:sum(maps:values(Pens)), maps:get(tenure, Pens, 0.0)}
end, Penalties),
{Start1, maps:to_list(Penalties1)};
_ ->
{Start0 + 1,
[{A, {S, 0.0}}
|| {S, _L, A} <- blockchain_election:adjust_old_group(
[{0, 0, A} || A <- ConsensusAddrs], Ledger)]}
end,
Blocks = [begin {ok, Block} = blockchain:get_block(Ht, Chain), Block end
|| Ht <- lists:seq(Start, End)],
{BBATotals, SeenTotals, TotalCount} =
lists:foldl(
fun(Blk, {BBAAcc, SeenAcc, Count}) ->
H = blockchain_block:height(Blk),
BBAs = blockchain_utils:bitvector_to_map(
length(ConsensusAddrs),
blockchain_block_v1:bba_completion(Blk)),
SeenVotes = blockchain_block_v1:seen_votes(Blk),
Seen = lists:foldl(
fun({_Idx, Votes0}, Acc) ->
Votes = blockchain_utils:bitvector_to_map(
length(ConsensusAddrs), Votes0),
merge_map(ConsensusAddrs, Votes, H, Acc)
end,SeenAcc, SeenVotes),
{merge_map(ConsensusAddrs, BBAs, H, BBAAcc), Seen, Count + length(SeenVotes)}
end, {InitMap, InitMap, 0}, Blocks),
{ConsensusAddrs, BBATotals, SeenTotals, TotalCount, GroupWithPenalties, Start0, Start, End}.
merge_map(Addrs, Votes, Height, Acc) ->
maps:fold(fun(K, true, A) ->
maps:update_with(lists:nth(K, Addrs), fun({_, V}) -> {Height, V+1} end, {Height, 1}, A);
(_, false, A) ->
A
end, Acc, Votes).
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment