Skip to content

Commit

Permalink
Merge e92d815 into 1dc8fa2
Browse files Browse the repository at this point in the history
  • Loading branch information
evanmcc committed Jan 31, 2019
2 parents 1dc8fa2 + e92d815 commit 64ff8ab
Show file tree
Hide file tree
Showing 8 changed files with 525 additions and 10 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ rebar3.crashdump
ct_run.*
*.js
*nohost
trace*
3 changes: 2 additions & 1 deletion src/hbbft_bba.erl
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ init(SK, N, F) ->
%% – bin_values {}
-spec input(bba_data(), 0 | 1) -> {bba_data(), ok | {send, [hbbft_utils:multicast(bval_msg())]}}.
input(Data = #bba_data{state=init}, BInput) ->
{Data#bba_data{est = BInput, broadcasted=add(BInput, Data#bba_data.broadcasted)}, {send, [{multicast, {bval, Data#bba_data.round, BInput}}]}};
{Data#bba_data{est = BInput, broadcasted=add(BInput, Data#bba_data.broadcasted)},
{send, [{multicast, {bval, Data#bba_data.round, BInput}}]}};
input(Data = #bba_data{state=done}, _BInput) ->
{Data, ok}.

Expand Down
80 changes: 78 additions & 2 deletions test/hbbft_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-include_lib("relcast/include/fakecast.hrl").

-export([all/0, init_per_testcase/2, end_per_testcase/2]).
-export([
Expand All @@ -13,7 +14,8 @@
encrypt_decrypt_test/1,
start_on_demand_test/1,
one_actor_wrong_key_test/1,
one_actor_corrupted_key_test/1
one_actor_corrupted_key_test/1,
initial_fakecast_test/1
]).

all() ->
Expand All @@ -26,7 +28,8 @@ all() ->
encrypt_decrypt_test,
start_on_demand_test,
one_actor_wrong_key_test,
one_actor_corrupted_key_test
one_actor_corrupted_key_test,
initial_fakecast_test
].

init_per_testcase(_, Config) ->
Expand Down Expand Up @@ -385,6 +388,79 @@ one_actor_corrupted_key_test(Config) ->
io:format("chain contains ~p distinct transactions~n", [length(BlockTxns)]),
ok.


-record(state,
{
node_count :: integer(),
stopped = false :: boolean(),
results = sets:new() :: sets:set()
}).

trivial(_Message, _From, _To, _NodeState, _NewState, _Actions,
#state{stopped = false} = State) ->
case rand:uniform(100) of
100 ->
{actions, [{stop_node, 2}], State#state{stopped = true}};
_ ->
{actions, [], State}
end;
trivial(_Message, _From, To, _NodeState, _NewState, {result, Result},
#state{results = Results0} = State) ->
Results = sets:add_element({result, {To, Result}}, Results0),
%% ct:pal("results len ~p ~p", [sets:size(Results), sets:to_list(Results)]),
case sets:size(Results) == State#state.node_count of
true ->
{result, Results};
false ->
{actions, [], State#state{results = Results}}
end;
trivial(_Message, _From, _To, _NodeState, _NewState, _Actions, ModelState) ->
{actions, [], ModelState}.

initial_fakecast_test(Config) ->
N = 4, % proplists:get_value(n, Config),
F = 1, % proplists:get_value(f, Config),
BatchSize = proplists:get_value(batchsize, Config),
Module = proplists:get_value(module, Config),
PrivateKeys0 = proplists:get_value(privatekeys, Config),
{PrivateKeys, _} = lists:split(N, PrivateKeys0),

Init = fun() ->
{ok,
#fc_conf{
test_mod = Module,
nodes = lists:seq(1, N),
configs = [[Sk, N, F, ID, BatchSize, infinity]
|| {ID, Sk} <- lists:zip(lists:seq(0, N - 1), PrivateKeys)]
},
#state{node_count = N - 2}
}
end,
Msgs = [ crypto:strong_rand_bytes(128) || _ <- lists:seq(1, N*10)],
%% send each message to a random subset of the HBBFT actors
Input =
fun() ->
lists:foldl(fun(ID, Acc) ->
Size = max(length(Msgs), BatchSize + (rand:uniform(length(Msgs)))),
Subset = hbbft_test_utils:random_n(Size, Msgs),
lists:append([{ID, Msg} || Msg <- Subset], Acc)
end, [], lists:seq(0, N - 1))
end,
%% start it on runnin'
{ok, ConvergedResults} = fakecast:start_test(Init, fun trivial/7,
os:timestamp(),
Input),

%% check all N actors returned a result
?assertEqual(N - 2, sets:size(ConvergedResults)),
DistinctResults = sets:from_list([BVal || {result, {_, BVal}} <- sets:to_list(ConvergedResults)]),
%% check all N actors returned the same result
?assertEqual(1, sets:size(DistinctResults)),
{_, _, AcceptedMsgs} = lists:unzip3(lists:flatten(sets:to_list(DistinctResults))),
%% check all the Msgs are actually from the original set
?assert(sets:is_subset(sets:from_list(lists:flatten(AcceptedMsgs)), sets:from_list(Msgs))),
ok.

%% helper functions

enumerate(List) ->
Expand Down
81 changes: 79 additions & 2 deletions test/hbbft_acs_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,24 @@

-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-include_lib("relcast/include/fakecast.hrl").

-export([all/0, init_per_testcase/2, end_per_testcase/2]).
-export([
init_test/1,
one_dead_test/1,
f_dead_test/1,
fplusone_dead_test/1
fplusone_dead_test/1,
fakecast_test/1
]).

all() ->
[
init_test,
one_dead_test,
f_dead_test,
fplusone_dead_test
fplusone_dead_test,
fakecast_test
].

init_per_testcase(_, Config) ->
Expand Down Expand Up @@ -114,3 +117,77 @@ fplusone_dead_test(Config) ->
ct:pal("ConvergedResultsList: ~p~n", [ConvergedResultsList]),
?assertEqual(0, sets:size(ConvergedResults)),
ok.

-record(state,
{
node_count :: integer(),
stopped = false :: boolean(),
results = sets:new() :: sets:set()
}).

trivial(_Message, _From, To, _NodeState, _NewState, {result, Result},
#state{results = Results0} = State) ->
Results = sets:add_element({result, {To, Result}}, Results0),
%% ct:pal("results len ~p ~p", [sets:size(Results), sets:to_list(Results)]),
case sets:size(Results) == State#state.node_count of
true ->
{result, Results};
false ->
{actions, [], State#state{results = Results}}
end;
trivial(_Message, _From, To, _NodeState, _NewState, {result_and_send, Result, _Msgs},
#state{results = Results0} = State) ->
Results = sets:add_element({result, {To, Result}}, Results0),
%% ct:pal("results len ~p ~p", [sets:size(Results), sets:to_list(Results)]),
case sets:size(Results) == State#state.node_count of
true ->
{result, Results};
false ->
{actions, [], State#state{results = Results}}
end;
trivial(_Message, _From, _To, _NodeState, _NewState, _Actions, ModelState) ->
{actions, [], ModelState}.

fakecast_test(Config) ->
N = 4, % proplists:get_value(n, Config),
F = 1, % proplists:get_value(f, Config),
Module = proplists:get_value(module, Config),
PrivateKeys0 = proplists:get_value(privatekeys, Config),

{PrivateKeys, _} = lists:split(N, PrivateKeys0),

Init = fun() ->
{ok,
#fc_conf{
test_mod = Module,
nodes = lists:seq(1, N), %% are names useful?
configs = [[Sk, N, F, ID]
|| {ID, Sk} <- lists:zip(lists:seq(0, N - 1), PrivateKeys)]
},
#state{node_count = N - F}
}
end,


Msgs = [ crypto:strong_rand_bytes(512) || _ <- lists:seq(1, N)],
Input =
fun() ->
lists:zip(lists:seq(0, N - 1), Msgs)
end,
Seed = os:timestamp(),
%% try
{ok, ConvergedResults} = fakecast:start_test(Init, fun trivial/7,
Seed,
Input),
ConvergedResultsList = sets:to_list(ConvergedResults),
ct:pal("ConvergedResultsList: ~p~n", [ConvergedResultsList]),
?assertEqual(N - F, sets:size(ConvergedResults)),
DistinctResults = sets:from_list([BVal || {result, {_, BVal}} <- sets:to_list(ConvergedResults)]),
?assertEqual(1, sets:size(DistinctResults)),
?assert(sets:is_subset(
sets:from_list([ X || {_, X} <- lists:flatten(sets:to_list(DistinctResults))]),
sets:from_list(Msgs))),
ok.
%% catch _:E ->
%% throw({fail, Seed, E})
%% end.
111 changes: 109 additions & 2 deletions test/hbbft_bba_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-include_lib("relcast/include/fakecast.hrl").

-export([all/0, init_per_testcase/2, end_per_testcase/2]).
-export([termination_test/1,
Expand All @@ -10,7 +11,8 @@
init_with_ones_test/1,
init_with_mixed_zeros_and_ones_test/1,
f_dead_test/1,
fplusone_dead_test/1
fplusone_dead_test/1,
fakecast_test/1
]).

all() ->
Expand All @@ -20,7 +22,8 @@ all() ->
init_with_ones_test,
init_with_mixed_zeros_and_ones_test,
f_dead_test,
fplusone_dead_test
fplusone_dead_test,
fakecast_test
].

init_per_testcase(_, Config) ->
Expand Down Expand Up @@ -194,3 +197,107 @@ fplusone_dead_test(Config) ->
%% should not converge
?assertEqual(0, sets:size(ConvergedResults)),
ok.


-record(state,
{
node_count :: integer(),
stopped = false :: boolean(),
results = sets:new() :: sets:set()
}).

neg(1) -> 0;
neg(0) -> 1.

alt(1) -> 2;
alt(0) -> 1;
alt(2) -> 3;
alt(3) -> 1.

trivial(_Message, _, 1, _NodeState, _NewState, {send, [{multicast, {bval, R, V}}]},
#state{} = State) ->
{actions, [{alter_actions, {send, [{unicast, 0, {bval, R, V}},
{unicast, 1, {bval, R, V}},
{unicast, 2, {bval, R, neg(V)}},
{unicast, 3, {bval, R, neg(V)}}]}}],
State};
trivial(_Message, _, 1, _NodeState, _NewState, {send, [{multicast, {aux, R, V}}]},
#state{} = State) ->
{actions, [{alter_actions, {send, [{unicast, 3, {aux, R, V}},
{unicast, 2, {aux, R, V}},
{unicast, 1, {aux, R, alt(V)}},
{unicast, 0, {aux, R, alt(V)}}]}}],
State};
trivial(_Message, _From, To, _NodeState, _NewState, {result, Result},
#state{results = Results0} = State) ->
Results = sets:add_element({result, {To, Result}}, Results0),
%% ct:pal("results len ~p ~p", [sets:size(Results), sets:to_list(Results)]),
case sets:size(Results) == State#state.node_count of
true ->
{result, Results};
false ->
{actions, [], State#state{results = Results}}
end;
trivial(_Message, _From, To, _NodeState, _NewState, {result_and_send, Result, _},
#state{results = Results0} = State) ->
Results = sets:add_element({result, {To, Result}}, Results0),
%% ct:pal("results len ~p ~p", [sets:size(Results), sets:to_list(Results)]),
case sets:size(Results) == State#state.node_count of
true ->
{result, Results};
false ->
{actions, [], State#state{results = Results}}
end;
trivial(_Message, _From, _To, _NodeState, _NewState, _Actions, ModelState) ->
%%fakecast:trace("act ~p", [_Actions]),
{actions, [], ModelState}.

fakecast_test(Config) ->
Module = proplists:get_value(module, Config),
N = 4,
F = 1,
{ok, Dealer} = dealer:new(N, F+1, 'SS512'),
{ok, {_PubKey, PrivateKeys}} = dealer:deal(Dealer),
Init = fun() ->
{ok,
#fc_conf{
test_mod = Module,
nodes = [aaa, bbb, ccc, ddd],
configs = [[Sk, N, F] || Sk <- PrivateKeys]
},
#state{node_count = N}
}
end,
Me = self(),
Input =
fun() ->
A = rand:uniform(2) - 1,
%%B = rand:uniform(2) - 1,
%%IVec = hbbft_test_utils:shuffle([A,A,A,B]),
IVec = [A,A,A,A],
Inputs = lists:zip(lists:seq(0, 3), IVec),

%% send this out to the running process for checking.
%% not 100% sure if this is safe
Me ! {input_vector, Inputs},
Inputs
end,

{ok, Results} = fakecast:start_test(Init, fun trivial/7,
{1544,461835,550446},
%%os:timestamp(),
Input),
Inputs = receive {input_vector, I} -> I after 10000 -> throw(timeout) end,
%% figure out which was the majority value
Majority =
case length(lists:filter(fun({_, X}) -> X =:= 1 end, Inputs)) of
4 -> 1;
3 -> 1;
1 -> 0;
0 -> 0
end,
%% make sure we got it and make sure there's just one distinct result
ResultsList = sets:to_list(Results),
ct:pal("ResultsList: ~p~nInputs: ~p", [ResultsList, Inputs]),
?assertMatch([Majority], lists:usort([BVal || {result, {_, BVal}} <- ResultsList])),
ok.
Loading

0 comments on commit 64ff8ab

Please sign in to comment.