Unverified Commit 98b14b09 authored by Rahul Garg's avatar Rahul Garg Committed by GitHub
Browse files

Merge pull request #507 from helium/adt/data_aggregation_version_v2

Add support for POC V9
parents db48de61 0623b15b
Showing with 245 additions and 114 deletions
+245 -114
......@@ -4,7 +4,7 @@
{<<"base64url">>,{pkg,<<"base64url">>,<<"1.0.1">>},1},
{<<"blockchain">>,
{git,"https://github.com/helium/blockchain-core.git",
{ref,"a95a94d6d576920b58b62d69e382934bf6049228"}},
{ref,"833c155484a4b850c3351dd52c3e9d744964ddb0"}},
0},
{<<"clique">>,
{git,"https://github.com/helium/clique.git",
......@@ -73,7 +73,7 @@
0},
{<<"helium_proto">>,
{git,"https://github.com/helium/proto.git",
{ref,"5baedf16e08385684edd325c62cbf4b7490b033b"}},
{ref,"fba7ad5a7e23da3035c7ace8c5033af3a42528cc"}},
1},
{<<"inert">>,
{git,"https://github.com/msantos/inert",
......
......@@ -510,6 +510,7 @@ handle_packets([Packet|Tail], Gateway, #state{reg_region = Region} = State) ->
error ->
ok;
{onion, Payload} ->
Freq = maps:get(<<"freq">>, Packet),
%% onion server
miner_onion_server:decrypt_radio(
Payload,
......@@ -517,7 +518,8 @@ handle_packets([Packet|Tail], Gateway, #state{reg_region = Region} = State) ->
maps:get(<<"lsnr">>, Packet),
%% TODO we might want to send GPS time here, if available
maps:get(<<"tmst">>, Packet),
maps:get(<<"freq">>, Packet),
Freq,
channel(Freq, State#state.reg_freq_list),
maps:get(<<"datr">>, Packet)
);
{Type, RoutingInfo} ->
......@@ -639,3 +641,14 @@ csv_rows_to_ets(F) ->
lager:warning("failed to read file ~p, error: ~p", [F, Reason]),
{error, Reason}
end.
channel(Freq, Frequencies) ->
channel(Freq, Frequencies, 0).
channel(Freq, [H|T], Acc) ->
case abs(H - Freq) =< 0.001 of
true ->
Acc;
false ->
channel(Freq, T, Acc+1)
end.
......@@ -15,10 +15,10 @@
-export([
start_link/1,
decrypt_p2p/2,
decrypt_radio/6,
retry_decrypt/9,
send_receipt/9,
send_witness/7
decrypt_radio/7,
retry_decrypt/11,
send_receipt/11,
send_witness/9
]).
-ifdef(TEST).
......@@ -70,11 +70,11 @@ start_link(Args) ->
decrypt_p2p(Onion, Stream) ->
gen_server:cast(?MODULE, {decrypt_p2p, Onion, Stream}).
decrypt_radio(Packet, RSSI, SNR, Timestamp, Freq, Spreading) ->
gen_server:cast(?MODULE, {decrypt_radio, Packet, RSSI, SNR, Timestamp, Freq, Spreading}).
decrypt_radio(Packet, RSSI, SNR, Timestamp, Freq, Channel, Spreading) ->
gen_server:cast(?MODULE, {decrypt_radio, Packet, RSSI, SNR, Timestamp, Freq, Channel, Spreading}).
retry_decrypt(Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Stream) ->
gen_server:cast(?MODULE, {retry_decrypt, Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Stream}).
retry_decrypt(Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Channel, DataRate, Stream) ->
gen_server:cast(?MODULE, {retry_decrypt, Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Channel, DataRate, Stream}).
-spec send_receipt(Data :: binary(),
OnionCompactKey :: libp2p_crypto:pubkey_bin(),
......@@ -83,13 +83,15 @@ retry_decrypt(Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency,
RSSI :: integer(),
SNR :: float(),
Frequency :: float(),
Channel :: non_neg_integer(),
DataRate :: binary(),
Stream :: undefined | pid(),
State :: state()) -> ok | {error, any()}.
send_receipt(_Data, OnionCompactKey, Type, Time, RSSI, SNR, Frequency, Stream, State) ->
send_receipt(_Data, OnionCompactKey, Type, Time, RSSI, SNR, Frequency, Channel, DataRate, Stream, State) ->
case miner_lora:location_ok() of
true ->
lager:md([{poc_id, blockchain_utils:poc_id(OnionCompactKey)}]),
send_receipt(_Data, OnionCompactKey, Type, Time, RSSI, SNR, Frequency, Stream, State, ?BLOCK_RETRY_COUNT);
send_receipt(_Data, OnionCompactKey, Type, Time, RSSI, SNR, Frequency, Channel, DataRate, Stream, State, ?BLOCK_RETRY_COUNT);
false ->
ok
end.
......@@ -101,13 +103,15 @@ send_receipt(_Data, OnionCompactKey, Type, Time, RSSI, SNR, Frequency, Stream, S
RSSI :: integer(),
SNR :: float(),
Frequency :: float(),
Channel :: non_neg_integer(),
DataRate :: binary(),
Stream :: undefined | pid(),
State :: state(),
Retry :: non_neg_integer()) -> ok | {error, any()}.
send_receipt(_Data, _OnionCompactKey, _Type, _Time, _RSSI, _SNR, _Frequency, _Stream, _State, 0) ->
send_receipt(_Data, _OnionCompactKey, _Type, _Time, _RSSI, _SNR, _Frequency, _Channel, _DataRate, _Stream, _State, 0) ->
lager:error("failed to send receipts, max retry"),
{error, too_many_retries};
send_receipt(Data, OnionCompactKey, Type, Time, RSSI, SNR, Frequency, Stream, #state{chain=Chain}=State, Retry) ->
send_receipt(Data, OnionCompactKey, Type, Time, RSSI, SNR, Frequency, Channel, DataRate, Stream, #state{chain=Chain}=State, Retry) ->
Ledger = blockchain:ledger(Chain),
OnionKeyHash = crypto:hash(sha256, OnionCompactKey),
{ok, PoCs} = blockchain_ledger_v1:find_poc(OnionKeyHash, Ledger),
......@@ -119,6 +123,8 @@ send_receipt(Data, OnionCompactKey, Type, Time, RSSI, SNR, Frequency, Stream, #s
Receipt0 = case blockchain:config(?data_aggregation_version, Ledger) of
{ok, 1} ->
blockchain_poc_receipt_v1:new(Address, Time, RSSI, Data, Type, SNR, Frequency);
{ok, 2} ->
blockchain_poc_receipt_v1:new(Address, Time, RSSI, Data, Type, SNR, Frequency, Channel, DataRate);
_ ->
blockchain_poc_receipt_v1:new(Address, Time, RSSI, Data, Type)
end,
......@@ -150,7 +156,7 @@ send_receipt(Data, OnionCompactKey, Type, Time, RSSI, SNR, Frequency, Stream, #s
ok;
false ->
timer:sleep(timer:seconds(30)),
send_receipt(Data, OnionCompactKey, Type, Time, RSSI, SNR, Frequency, Stream, State, Retry-1)
send_receipt(Data, OnionCompactKey, Type, Time, RSSI, SNR, Frequency, Channel, DataRate, Stream, State, Retry-1)
end.
-spec send_witness(Data :: binary(),
......@@ -159,12 +165,14 @@ send_receipt(Data, OnionCompactKey, Type, Time, RSSI, SNR, Frequency, Stream, #s
RSSI :: integer(),
SNR :: float(),
Frequency :: float(),
Channel :: non_neg_integer(),
DataRate :: binary(),
State :: state()) -> ok.
send_witness(_Data, OnionCompactKey, Time, RSSI, SNR, Frequency, State) ->
send_witness(_Data, OnionCompactKey, Time, RSSI, SNR, Frequency, Channel, DataRate, State) ->
case miner_lora:location_ok() of
true ->
lager:md([{poc_id, blockchain_utils:poc_id(OnionCompactKey)}]),
send_witness(_Data, OnionCompactKey, Time, RSSI, SNR, Frequency, State, ?BLOCK_RETRY_COUNT);
send_witness(_Data, OnionCompactKey, Time, RSSI, SNR, Frequency, Channel, DataRate, State, ?BLOCK_RETRY_COUNT);
false ->
ok
end.
......@@ -175,11 +183,13 @@ send_witness(_Data, OnionCompactKey, Time, RSSI, SNR, Frequency, State) ->
RSSI :: integer(),
SNR :: float(),
Frequency :: float(),
Channel :: non_neg_integer(),
DataRate :: binary(),
State :: state(),
Retry :: non_neg_integer()) -> ok.
send_witness(_Data, _OnionCompactKey, _Time, _RSSI, _SNR, _Frequency, _State, 0) ->
send_witness(_Data, _OnionCompactKey, _Time, _RSSI, _SNR, _Frequency, _Channel, _DataRate, _State, 0) ->
lager:error("failed to send witness, max retry");
send_witness(Data, OnionCompactKey, Time, RSSI, SNR, Frequency, #state{chain=Chain}=State, Retry) ->
send_witness(Data, OnionCompactKey, Time, RSSI, SNR, Frequency, Channel, DataRate, #state{chain=Chain}=State, Retry) ->
Ledger = blockchain:ledger(Chain),
OnionKeyHash = crypto:hash(sha256, OnionCompactKey),
{ok, PoCs} = blockchain_ledger_v1:find_poc(OnionKeyHash, Ledger),
......@@ -191,6 +201,8 @@ send_witness(Data, OnionCompactKey, Time, RSSI, SNR, Frequency, #state{chain=Cha
Witness0 = case blockchain:config(?data_aggregation_version, Ledger) of
{ok, 1} ->
blockchain_poc_witness_v1:new(SelfPubKeyBin, Time, RSSI, Data, SNR, Frequency);
{ok, 2} ->
blockchain_poc_witness_v1:new(SelfPubKeyBin, Time, RSSI, Data, SNR, Frequency, Channel, DataRate);
_ ->
blockchain_poc_witness_v1:new(SelfPubKeyBin, Time, RSSI, Data)
end,
......@@ -208,7 +220,7 @@ send_witness(Data, OnionCompactKey, Time, RSSI, SNR, Frequency, #state{chain=Cha
{error, _Reason} ->
lager:warning("failed to dial challenger ~p: ~p", [P2P, _Reason]),
timer:sleep(timer:seconds(30)),
send_witness(Data, OnionCompactKey, Time, RSSI, SNR, Frequency, State, Retry-1);
send_witness(Data, OnionCompactKey, Time, RSSI, SNR, Frequency, Channel, DataRate, State, Retry-1);
{ok, Stream} ->
_ = miner_poc_handler:send(Stream, EncodedWitness)
end
......@@ -248,17 +260,17 @@ handle_cast({decrypt_p2p, <<IV:2/binary,
OnionCompactKey:33/binary,
Tag:4/binary,
CipherText/binary>>, Pid}, State) ->
NewState = decrypt(p2p, IV, OnionCompactKey, Tag, CipherText, 0, undefined, undefined, Pid, State),
NewState = decrypt(p2p, IV, OnionCompactKey, Tag, CipherText, 0, undefined, undefined, undefined, undefined, Pid, State),
{noreply, NewState};
handle_cast({decrypt_radio, <<IV:2/binary,
OnionCompactKey:33/binary,
Tag:4/binary,
CipherText/binary>>,
RSSI, SNR, _Timestamp, Frequency, _Spreading}, State) ->
NewState = decrypt(radio, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, undefined, State),
RSSI, SNR, _Timestamp, Frequency, Channel, DataRate}, State) ->
NewState = decrypt(radio, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Channel, DataRate, undefined, State),
{noreply, NewState};
handle_cast({retry_decrypt, Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Stream}, State) ->
NewState = decrypt(Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Stream, State),
handle_cast({retry_decrypt, Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Channel, DataRate, Stream}, State) ->
NewState = decrypt(Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Channel, DataRate, Stream, State),
{noreply, NewState};
handle_cast(_Msg, State) ->
{noreply, State}.
......@@ -294,7 +306,7 @@ wait_for_block_(Fun, Count) ->
wait_for_block_(Fun, Count - 1)
end.
decrypt(Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Stream, #state{ecdh_fun=ECDHFun, chain = Chain}=State) ->
decrypt(Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Channel, DataRate, Stream, #state{ecdh_fun=ECDHFun, chain = Chain}=State) ->
POCID = blockchain_utils:poc_id(OnionCompactKey),
OnionKeyHash = crypto:hash(sha256, OnionCompactKey),
NewState = case try_decrypt(IV, OnionCompactKey, OnionKeyHash, Tag, CipherText, ECDHFun, Chain) of
......@@ -309,7 +321,7 @@ decrypt(Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Stream
false
end
end, 10),
?MODULE:retry_decrypt(Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Stream)
?MODULE:retry_decrypt(Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Channel, DataRate, Stream)
end),
State;
{error, fail_decrypt} ->
......@@ -318,7 +330,7 @@ decrypt(Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Stream
send_witness,
[crypto:hash(sha256, <<Tag/binary, CipherText/binary>>),
OnionCompactKey,
os:system_time(nanosecond), RSSI, SNR, Frequency, State]
os:system_time(nanosecond), RSSI, SNR, Frequency, Channel, DataRate, State]
),
lager:info([{poc_id, POCID}], "could not decrypt packet received via ~p: treating as a witness", [Type]),
State;
......@@ -335,7 +347,7 @@ decrypt(Type, IV, OnionCompactKey, Tag, CipherText, RSSI, SNR, Frequency, Stream
ChannelSelectorFun = fun(FreqList) -> lists:nth((IntData rem 8) + 1, FreqList) end,
erlang:spawn(fun() -> miner_lora:send_poc(Packet, immediate, ChannelSelectorFun, "SF10BW125", ?TX_POWER) end),
erlang:spawn(fun() -> ?MODULE:send_receipt(Data, OnionCompactKey, Type, os:system_time(nanosecond),
RSSI, SNR, Frequency, Stream, State) end);
RSSI, SNR, Frequency, Channel, DataRate, Stream, State) end);
false ->
ok
end,
......
......@@ -629,6 +629,15 @@ init_per_testcase(Mod, TestCase, Config0) ->
ct_rpc:call(Miner, application, set_env, [miner, stabilization_period_start, 2]),
ct_rpc:call(Miner, application, set_env, [miner, default_routers, [DefaultRouters]]),
ct_rpc:call(Miner, application, set_env, [miner, region_override, 'US915']),
ct_rpc:call(Miner, application, set_env, [miner, frequency_data, #{'US915' => [903.9, 904.1, 904.3, 904.5, 904.7, 904.9, 905.1, 905.3],
'EU868' => [867.1, 867.3, 867.5, 867.7, 867.9, 868.1, 868.3, 868.5],
'EU433' => [433.175, 433.375, 433.575],
'CN470' => [486.3, 486.5, 486.7, 486.9, 487.1, 487.3, 487.5, 487.7 ],
'CN779' => [779.5, 779.7, 779.9],
'AU915' => [916.8, 917.0, 917.2, 917.4, 917.5, 917.6, 917.8, 918.0, 918.2],
'AS923' => [923.2, 923.4, 923.6, 923.8, 924.0, 924.2, 924.4, 924.5, 924.6, 924.8],
'KR920' => [922.1, 922.3, 922.5, 922.7, 922.9, 923.1, 923.3],
'IN865' => [865.0625, 865.4025, 865.985]}]),
{ok, _StartedApps} = ct_rpc:call(Miner, application, ensure_all_started, [miner]),
ok
end,
......@@ -721,7 +730,7 @@ init_per_testcase(Mod, TestCase, Config0) ->
{dkg_curve, Curve},
{election_interval, Interval},
{num_consensus_members, NumConsensusMembers},
{rpc_timeout, timer:seconds(5)}
{rpc_timeout, timer:seconds(30)}
| Config
].
......
......@@ -10,6 +10,8 @@
-include("miner_ct_macros.hrl").
-include("lora.hrl").
-include_lib("blockchain/include/blockchain_utils.hrl").
-record(state, {
udp_sock,
udp_ports,
......@@ -58,7 +60,9 @@ init([POCVersion, MyPort, UDPPorts, Status]) ->
%% just don't start the tick
ok
end,
{ok, #state{poc_version=POCVersion, udp_sock=Sock, udp_ports=UDPPorts}}.
State = #state{poc_version=POCVersion, udp_sock=Sock, udp_ports=UDPPorts},
ct:pal("starting fake_radio_backplane, state: ~p", [State]),
{ok, State}.
handle_call(Msg, _From, State) ->
lager:warning("unhandled call ~p", [Msg]),
......@@ -73,19 +77,32 @@ handle_cast({transmit, Payload, Frequency, TxLocation}, State = #state{udp_sock=
fun({Port, Location}) ->
Distance = blockchain_utils:distance(TxLocation, Location),
RSSI = case POCVersion of
V when V < 8 ->
FreeSpacePathLoss = ?TRANSMIT_POWER - (32.44 + 20*math:log10(?FREQUENCY) + 20*math:log10(Distance) - ?MAX_ANTENNA_GAIN - ?MAX_ANTENNA_GAIN),
FreeSpacePathLoss;
_ ->
%% Use approx_rssi poc_version 8 onwards
approx_rssi(Distance)
end,
V when V =< 9 ->
blockchain_utils:min_rcv_sig(blockchain_utils:free_space_path_loss(TxLocation, Location, Frequency));
V when V =< 8 ->
FreeSpacePathLoss = ?TRANSMIT_POWER - (32.44 + 20*math:log10(?FREQUENCY) + 20*math:log10(Distance) - ?MAX_ANTENNA_GAIN - ?MAX_ANTENNA_GAIN),
FreeSpacePathLoss;
_ ->
%% Use approx_rssi poc_version 8 onwards
approx_rssi(Distance)
end,
case Distance > 32 of
true -> ok;
false ->
NewJSON = #{<<"rxpk">> => [#{<<"rssi">> => RSSI, <<"lsnr">> => 1.0, <<"tmst">> => erlang:system_time(seconds), <<"data">> => base64:encode(Payload), <<"freq">> => Frequency, <<"datr">> => <<"SF8BW125">>}]},
NewJSON = #{<<"rxpk">> => [#{<<"rssi">> => RSSI,
<<"lsnr">> => approx_snr(RSSI),
<<"tmst">> => erlang:system_time(seconds),
<<"data">> => base64:encode(Payload),
<<"freq">> => Frequency,
<<"datr">> => <<"SF8BW125">>}]},
ct:pal("Sending ~p", [NewJSON]),
gen_udp:send(UDPSock, {127, 0, 0, 1}, Port, <<?PROTOCOL_2:8/integer-unsigned, Token:2/binary, ?PUSH_DATA:8/integer-unsigned, 16#deadbeef:64/integer, (jsx:encode(NewJSON))/binary>>)
gen_udp:send(UDPSock, {127, 0, 0, 1},
Port,
<<?PROTOCOL_2:8/integer-unsigned,
Token:2/binary,
?PUSH_DATA:8/integer-unsigned,
16#deadbeef:64/integer,
(jsx:encode(NewJSON))/binary>>)
end
end,
Ports
......@@ -104,6 +121,8 @@ handle_info({udp, UDPSock, IP, SrcPort, <<?PROTOCOL_2:8/integer-unsigned, Token:
State = #state{udp_sock=UDPSock, udp_ports=Ports, poc_version=POCVersion}) ->
gen_udp:send(UDPSock, IP, SrcPort, <<?PROTOCOL_2:8/integer-unsigned, Token:2/binary, ?TX_ACK:8/integer-unsigned, 16#deadbeef:64/integer>>),
#{<<"txpk">> := Packet} = jsx:decode(JSON, [return_maps]),
#{<<"freq">> := Frequency} = Packet,
case State#state.mirror of
Pid when is_pid(Pid) ->
Pid ! {fake_radio_backplane, Packet};
......@@ -116,14 +135,18 @@ handle_info({udp, UDPSock, IP, SrcPort, <<?PROTOCOL_2:8/integer-unsigned, Token:
fun({Port, Location}) ->
Distance = blockchain_utils:distance(OriginLocation, Location),
ToSend = case POCVersion of
V when V =< 9 ->
FSPL = blockchain_utils:min_rcv_sig(blockchain_utils:free_space_path_loss(OriginLocation, Location, Frequency)),
{FSPL, approx_snr(FSPL)};
V when V < 8 ->
FreeSpacePathLoss = ?TRANSMIT_POWER - (32.44 + 20*math:log10(?FREQUENCY) + 20*math:log10(Distance) - ?MAX_ANTENNA_GAIN - ?MAX_ANTENNA_GAIN),
FreeSpacePathLoss;
{FreeSpacePathLoss, 1.0};
_ ->
%% Use approx_rssi poc_version 8 onwards
approx_rssi(Distance)
{approx_rssi(Distance), 1.0}
end,
do_send(ToSend, Distance, OriginLocation, Location, Token, Packet, UDPSock, Port)
{ToSendRSSI, ToSendSNR} = ToSend,
do_send(ToSendRSSI, ToSendSNR, Distance, OriginLocation, Location, Token, Packet, UDPSock, Port)
end,
lists:keydelete(SrcPort, 1, Ports)
),
......@@ -163,13 +186,23 @@ send_status_packets(#state{udp_sock = Sock, udp_ports = UDPPorts}) ->
approx_rssi(Distance) ->
?ABS_RSSI - ?ETA * (10 * math:log10(Distance * 1000)).
do_send(ToSend, Distance, _OriginLocation, _Location, Token, Packet, UDPSock, Port) ->
do_send(ToSendRSSI, ToSendSNR, Distance, _OriginLocation, _Location, Token, Packet, UDPSock, Port) ->
case Distance > 32 of
true ->
ct:pal("NOT sending from ~p to ~p -> ~p km", [_OriginLocation, _Location, Distance]),
ok;
false ->
NewJSON = #{<<"rxpk">> => [maps:merge(maps:without([<<"imme">>, <<"rfch">>, <<"powe">>], Packet), #{<<"rssi">> => ToSend, <<"lsnr">> => 1.0, <<"tmst">> => erlang:system_time(seconds)})]},
ct:pal("sending ~p from ~p to ~p -> ~p km RSSI ~p", [NewJSON, _OriginLocation, _Location, Distance, ToSend]),
NewJSON = #{<<"rxpk">> => [maps:merge(maps:without([<<"imme">>, <<"rfch">>, <<"powe">>], Packet), #{<<"rssi">> => ToSendRSSI, <<"lsnr">> => ToSendSNR, <<"tmst">> => erlang:system_time(seconds)})]},
ct:pal("sending ~p from ~p to ~p -> ~p km RSSI ~p, SNR ~p", [NewJSON, _OriginLocation, _Location, Distance, ToSendRSSI, ToSendSNR]),
gen_udp:send(UDPSock, {127, 0, 0, 1}, Port, <<?PROTOCOL_2:8/integer-unsigned, Token:2/binary, ?PUSH_DATA:8/integer-unsigned, 16#deadbeef:64/integer, (jsx:encode(NewJSON))/binary>>)
end.
approx_snr(FSPL) ->
PotentialSNRs = maps:keys(maps:filter(
fun(_SNR, {Low, High}) ->
FSPL >= Low andalso FSPL =< High
end, ?SNR_CURVE)),
case PotentialSNRs of
[] -> -20;
SNRs -> hd(SNRs)
end.
......@@ -29,7 +29,10 @@
poc_dist_v8_partitioned_test/1,
poc_dist_v8_partitioned_lying_test/1,
no_status_v8_test/1,
restart_test/1
restart_test/1,
poc_dist_v9_test/1,
poc_dist_v9_partitioned_test/1,
poc_dist_v9_partitioned_lying_test/1
]).
-define(SFLOCS, [631210968910285823, 631210968909003263, 631210968912894463, 631210968907949567]).
......@@ -67,6 +70,7 @@ all() ->
poc_dist_v8_test,
poc_dist_v8_partitioned_test,
poc_dist_v8_partitioned_lying_test,
poc_dist_v9_test,
%% uncomment when poc placement enforcement starts.
%% no_status_v8_test,
restart_test].
......@@ -184,6 +188,21 @@ no_status_v8_test(Config) ->
ExtraVars = extra_vars(poc_v8),
run_dist_with_params(poc_dist_v8_test, Config, maps:merge(CommonPOCVars, ExtraVars), false).
poc_dist_v9_test(Config) ->
CommonPOCVars = common_poc_vars(Config),
ExtraVars = extra_vars(poc_v9),
run_dist_with_params(poc_dist_v9_test, Config, maps:merge(CommonPOCVars, ExtraVars)).
poc_dist_v9_partitioned_test(Config) ->
CommonPOCVars = common_poc_vars(Config),
ExtraVars = extra_vars(poc_v9),
run_dist_with_params(poc_dist_v9_partitioned_test, Config, maps:merge(CommonPOCVars, ExtraVars)).
poc_dist_v9_partitioned_lying_test(Config) ->
CommonPOCVars = common_poc_vars(Config),
ExtraVars = extra_vars(poc_v9),
run_dist_with_params(poc_dist_v9_partitioned_lying_test, Config, maps:merge(CommonPOCVars, ExtraVars)).
basic_test(Config) ->
BaseDir = ?config(base_dir, Config),
......@@ -615,10 +634,13 @@ run_dist_with_params(TestCase, Config, VarMap, Status) ->
%% show the final receipt counter
Miners = ?config(miners, Config),
FinalReceiptMap = challenger_receipts_map(find_receipts(Miners)),
ct:pal("FinalReceiptMap: ~p", [FinalReceiptMap]),
ct:pal("FinalReceiptCounter: ~p", [receipt_counter(FinalReceiptMap)]),
%% The test endeth here
ok.
exec_dist_test(poc_dist_v9_partitioned_lying_test, Config, _VarMap, _Status) ->
do_common_partition_lying_checks(poc_dist_v9_partitioned_lying_test, Config);
exec_dist_test(poc_dist_v8_partitioned_lying_test, Config, _VarMap, _Status) ->
do_common_partition_lying_checks(poc_dist_v8_partitioned_lying_test, Config);
exec_dist_test(poc_dist_v7_partitioned_lying_test, Config, _VarMap, _Status) ->
......@@ -627,6 +649,8 @@ exec_dist_test(poc_dist_v6_partitioned_lying_test, Config, _VarMap, _Status) ->
do_common_partition_lying_checks(poc_dist_v6_partitioned_lying_test, Config);
exec_dist_test(poc_dist_v5_partitioned_lying_test, Config, _VarMap, _Status) ->
do_common_partition_lying_checks(poc_dist_v5_partitioned_lying_test, Config);
exec_dist_test(poc_dist_v9_partitioned_test, Config, _VarMap, _Status) ->
do_common_partition_checks(poc_dist_v9_partitioned_test, Config);
exec_dist_test(poc_dist_v8_partitioned_test, Config, _VarMap, _Status) ->
do_common_partition_checks(poc_dist_v8_partitioned_test, Config);
exec_dist_test(poc_dist_v7_partitioned_test, Config, _VarMap, _Status) ->
......@@ -656,18 +680,25 @@ exec_dist_test(TestCase, Config, VarMap, Status) ->
%% a next hop.
case maps:get(?poc_version, VarMap, 1) of
V when V > 3 ->
miner_ct_utils:wait_until(
fun() ->
%% Check that we have atleast more than one request
%% If we have only one request, there's no guarantee
%% that the paths would eventually grow
check_multiple_requests(Miners) andalso
%% Now we can check whether we have path growth
check_eventual_path_growth(TestCase, Miners)
end,
40, 5000),
true = miner_ct_utils:wait_until(
fun() ->
%% Check that we have atleast more than one request
%% If we have only one request, there's no guarantee
%% that the paths would eventually grow
C1 = check_multiple_requests(Miners),
%% Now we can check whether we have path growth
C2 = (check_eventual_path_growth(TestCase, Miners) orelse
check_subsequent_path_growth(challenger_receipts_map(find_receipts(Miners)))),
%% Check there are some poc rewards
C3 = check_poc_rewards(get_rewards(Config)),
ct:pal("C1: ~p, C2: ~p, C3: ~p", [C1, C2, C3]),
C1 andalso C2 andalso C3
end,
40, 5000),
FinalScores = gateway_scores(Config),
ct:pal("FinalScores: ~p", [FinalScores]),
FinalRewards = get_rewards(Config),
ct:pal("FinalRewards: ~p", [FinalRewards]),
ok;
_ ->
%% By this point, we have ensured that every miner
......@@ -685,14 +716,16 @@ setup_dist_test(TestCase, Config, VarMap, Status) ->
{_, Locations} = lists:unzip(initialize_chain(Miners, TestCase, Config, VarMap)),
GenesisBlock = miner_ct_utils:get_genesis_block(Miners, Config),
RadioPorts = [ P || {_Miner, {_TP, P}} <- MinersAndPorts ],
miner_fake_radio_backplane:start_link(maps:get(?poc_version, VarMap), 45000,
lists:zip(RadioPorts, Locations), Status),
{ok, _FakeRadioPid} = miner_fake_radio_backplane:start_link(maps:get(?poc_version, VarMap), 45000,
lists:zip(RadioPorts, Locations), Status),
ok = miner_ct_utils:load_genesis_block(GenesisBlock, Miners, Config),
miner_fake_radio_backplane ! go,
%% wait till height 10
ok = miner_ct_utils:wait_for_gte(height, Miners, 10, all, 30),
ok.
gen_locations(poc_dist_v9_partitioned_lying_test, _, _) ->
{?AUSTINLOCS1 ++ ?LALOCS, lists:duplicate(4, hd(?AUSTINLOCS1)) ++ lists:duplicate(4, hd(?LALOCS))};
gen_locations(poc_dist_v8_partitioned_lying_test, _, _) ->
{?AUSTINLOCS1 ++ ?LALOCS, lists:duplicate(4, hd(?AUSTINLOCS1)) ++ lists:duplicate(4, hd(?LALOCS))};
gen_locations(poc_dist_v7_partitioned_lying_test, _, _) ->
......@@ -701,6 +734,9 @@ gen_locations(poc_dist_v6_partitioned_lying_test, _, _) ->
{?SFLOCS ++ ?NYLOCS, lists:duplicate(4, hd(?SFLOCS)) ++ lists:duplicate(4, hd(?NYLOCS))};
gen_locations(poc_dist_v5_partitioned_lying_test, _, _) ->
{?SFLOCS ++ ?NYLOCS, lists:duplicate(4, hd(?SFLOCS)) ++ lists:duplicate(4, hd(?NYLOCS))};
gen_locations(poc_dist_v9_partitioned_test, _, _) ->
%% These are taken from the ledger
{?AUSTINLOCS1 ++ ?LALOCS, ?AUSTINLOCS1 ++ ?LALOCS};
gen_locations(poc_dist_v8_partitioned_test, _, _) ->
%% These are taken from the ledger
{?AUSTINLOCS1 ++ ?LALOCS, ?AUSTINLOCS1 ++ ?LALOCS};
......@@ -719,6 +755,9 @@ gen_locations(poc_dist_v4_partitioned_test, _, _) ->
gen_locations(poc_dist_v8_test, _, _) ->
%% Actual locations are the same as the claimed locations for the dist test
{?AUSTINLOCS1 ++ ?AUSTINLOCS2, ?AUSTINLOCS1 ++ ?AUSTINLOCS2};
gen_locations(poc_dist_v9_test, _, _) ->
%% Actual locations are the same as the claimed locations for the dist test
{?AUSTINLOCS1 ++ ?AUSTINLOCS2, ?AUSTINLOCS1 ++ ?AUSTINLOCS2};
gen_locations(_TestCase, Addresses, VarMap) ->
LocationJitter = case maps:get(?poc_version, VarMap, 1) of
V when V > 3 ->
......@@ -831,15 +870,18 @@ check_all_miners_can_challenge(Miners) ->
check_eventual_path_growth(TestCase, Miners) ->
ReceiptMap = challenger_receipts_map(find_receipts(Miners)),
ct:pal("ReceiptMap: ~p", [ReceiptMap]),
check_growing_paths(TestCase, ReceiptMap, active_gateways(Miners), false).
check_partitioned_path_growth(TestCase, Miners) ->
check_partitioned_path_growth(_TestCase, Miners) ->
ReceiptMap = challenger_receipts_map(find_receipts(Miners)),
check_growing_paths(TestCase, ReceiptMap, active_gateways(Miners), true).
ct:pal("ReceiptMap: ~p", [ReceiptMap]),
check_subsequent_path_growth(ReceiptMap).
check_partitioned_lying_path_growth(TestCase, Miners) ->
check_partitioned_lying_path_growth(_TestCase, Miners) ->
ReceiptMap = challenger_receipts_map(find_receipts(Miners)),
not check_growing_paths(TestCase, ReceiptMap, active_gateways(Miners), true).
ct:pal("ReceiptMap: ~p", [ReceiptMap]),
not check_subsequent_path_growth(ReceiptMap).
check_growing_paths(TestCase, ReceiptMap, ActiveGateways, PartitionFlag) ->
Results = lists:foldl(fun({_Challenger, TaggedReceipts}, Acc) ->
......@@ -856,10 +898,10 @@ check_growing_paths(TestCase, ReceiptMap, ActiveGateways, PartitionFlag) ->
end,
[],
maps:to_list(ReceiptMap)),
lists:all(fun(R) -> R == true end, Results).
lists:all(fun(R) -> R == true end, Results) andalso maps:size(ReceiptMap) == maps:size(ActiveGateways).
check_remaining_grow([]) ->
true;
false;
check_remaining_grow(TaggedReceipts) ->
Res = lists:map(fun({_, Receipt}) ->
length(blockchain_txn_poc_receipts_v1:path(Receipt)) > 1
......@@ -870,14 +912,16 @@ check_remaining_grow(TaggedReceipts) ->
lists:any(fun(R) -> R == true end, Res).
check_remaining_partitioned_grow(_TestCase, [], _ActiveGateways) ->
true;
false;
check_remaining_partitioned_grow(TestCase, TaggedReceipts, ActiveGateways) ->
Res = lists:map(fun({_, Receipt}) ->
Path = blockchain_txn_poc_receipts_v1:path(Receipt),
PathLength = length(Path),
ct:pal("PathLength: ~p", [PathLength]),
PathLength > 1 andalso PathLength =< 4 andalso check_partitions(TestCase, Path, ActiveGateways)
end,
TaggedReceipts),
ct:pal("Res: ~p", [Res]),
%% It's possible that even some of the remaining receipts have single path
%% but there should eventually be some which have multi element paths
lists:any(fun(R) -> R == true end, Res).
......@@ -891,7 +935,6 @@ check_partitions(TestCase, Path, ActiveGateways) ->
end,
[],
Path)),
ct:pal("PathLocs: ~p", [sets:to_list(PathLocs)]),
{LocSet1, LocSet2} = location_sets(TestCase),
case sets:is_subset(PathLocs, LocSet1) of
true ->
......@@ -982,23 +1025,28 @@ do_common_partition_checks(TestCase, Config) ->
%% Print scores before we begin the test
InitialScores = gateway_scores(Config),
ct:pal("InitialScores: ~p", [InitialScores]),
miner_ct_utils:wait_until(
fun() ->
%% Check that every miner has issued a challenge
check_all_miners_can_challenge(Miners) andalso
%% Check that we have atleast more than one request
%% If we have only one request, there's no guarantee
%% that the paths would eventually grow
check_multiple_requests(Miners) andalso
%% Since we have two static location partitioned networks, we
%% can assert that the subsequent path lengths must never be greater
%% than 4.
check_partitioned_path_growth(TestCase, Miners)
end,
40, 5000),
true = miner_ct_utils:wait_until(
fun() ->
%% Check that every miner has issued a challenge
C1 = check_all_miners_can_challenge(Miners),
%% Check that we have atleast more than one request
%% If we have only one request, there's no guarantee
%% that the paths would eventually grow
C2 = check_multiple_requests(Miners),
%% Since we have two static location partitioned networks, we
%% can assert that the subsequent path lengths must never be greater
%% than 4.
C3 = check_partitioned_path_growth(TestCase, Miners),
%% Check there are some poc rewards
C4 = check_poc_rewards(get_rewards(Config)),
ct:pal("C1: ~p, C2: ~p, C3: ~p, C4: ~p", [C1, C2, C3, C4]),
C1 andalso C2 andalso C3 andalso C4
end, 60, 5000),
%% Print scores after execution
FinalScores = gateway_scores(Config),
ct:pal("FinalScores: ~p", [FinalScores]),
FinalRewards = get_rewards(Config),
ct:pal("FinalRewards: ~p", [FinalRewards]),
ok.
balances(Config) ->
......@@ -1025,7 +1073,7 @@ get_rewards(Config) ->
[],
Blocks).
check_no_poc_rewards(RewardsTxns) ->
check_poc_rewards(RewardsTxns) ->
%% Get all rewards types
RewardTypes = lists:foldl(fun(RewardTxn, Acc) ->
Types = [blockchain_txn_reward_v1:type(R) || R <- blockchain_txn_rewards_v1:rewards(RewardTxn)],
......@@ -1033,11 +1081,10 @@ check_no_poc_rewards(RewardsTxns) ->
end,
[],
RewardsTxns),
%% none of the reward types should be poc_challengees or poc_witnesses
not lists:any(fun(T) ->
T == poc_challengees orelse T == poc_witnesses
end,
RewardTypes).
lists:any(fun(T) ->
T == poc_challengees orelse T == poc_witnesses
end,
RewardTypes).
do_common_partition_lying_checks(TestCase, Config) ->
Miners = ?config(miners, Config),
......@@ -1048,20 +1095,20 @@ do_common_partition_lying_checks(TestCase, Config) ->
InitialBalances = balances(Config),
ct:pal("InitialBalances: ~p", [InitialBalances]),
miner_ct_utils:wait_until(
fun() ->
%% Check that every miner has issued a challenge
check_all_miners_can_challenge(Miners) andalso
%% Check that we have atleast more than one request
%% If we have only one request, there's no guarantee
%% that the paths would eventually grow
check_multiple_requests(Miners) andalso
%% Since we have two static location partitioned networks, where
%% both are lying about their distances, the paths should
%% never get longer than 1
check_partitioned_lying_path_growth(TestCase, Miners)
end,
40, 5000),
true = miner_ct_utils:wait_until(
fun() ->
%% Check that every miner has issued a challenge
check_all_miners_can_challenge(Miners) andalso
%% Check that we have atleast more than one request
%% If we have only one request, there's no guarantee
%% that the paths would eventually grow
check_multiple_requests(Miners) andalso
%% Since we have two static location partitioned networks, where
%% both are lying about their distances, the paths should
%% never get longer than 1
check_partitioned_lying_path_growth(TestCase, Miners)
end,
40, 5000),
%% Print scores after execution
FinalScores = gateway_scores(Config),
ct:pal("FinalScores: ~p", [FinalScores]),
......@@ -1072,14 +1119,33 @@ do_common_partition_lying_checks(TestCase, Config) ->
FinalBalances = balances(Config),
ct:pal("FinalBalances: ~p", [FinalBalances]),
%% There should be no poc_witness or poc_challengees rewards
?assert(check_no_poc_rewards(Rewards)),
%% also check that the scores have not changed at all
?assertEqual(lists:sort(maps:to_list(InitialScores)), lists:sort(maps:to_list(FinalScores))),
?assert(not check_poc_rewards(Rewards)),
ok.
extra_vars(poc_v9) ->
maps:merge(extra_poc_vars(),
#{?poc_version => 9,
?data_aggregation_version => 2,
?consensus_percent => 0.06,
?dc_percent => 0.325,
?poc_challengees_percent => 0.18,
?poc_challengers_percent => 0.0095,
?poc_witnesses_percent => 0.0855,
?securities_percent => 0.34});
extra_vars(poc_v8) ->
#{?poc_version => 8,
?poc_good_bucket_low => -132,
maps:merge(extra_poc_vars(), #{?poc_version => 8});
extra_vars(_) ->
{error, poc_v8_and_above_only}.
location_sets(poc_dist_v9_partitioned_test) ->
{sets:from_list(?AUSTINLOCS1), sets:from_list(?LALOCS)};
location_sets(poc_dist_v8_partitioned_test) ->
{sets:from_list(?AUSTINLOCS1), sets:from_list(?LALOCS)};
location_sets(_TestCase) ->
{sets:from_list(?SFLOCS), sets:from_list(?NYLOCS)}.
extra_poc_vars() ->
#{?poc_good_bucket_low => -132,
?poc_good_bucket_high => -80,
?poc_v5_target_prob_randomness_wt => 1.0,
?poc_v4_target_prob_edge_wt => 0.0,
......@@ -1089,11 +1155,9 @@ extra_vars(poc_v8) ->
?poc_v4_randomness_wt => 0.5,
?poc_v4_prob_count_wt => 0.0,
?poc_centrality_wt => 0.5,
?poc_max_hop_cells => 2000};
extra_vars(_) ->
{error, poc_v8_and_above_only}.
?poc_max_hop_cells => 2000}.
location_sets(poc_dist_v8_partitioned_test) ->
{sets:from_list(?AUSTINLOCS1), sets:from_list(?LALOCS)};
location_sets(_TestCase) ->
{sets:from_list(?SFLOCS), sets:from_list(?NYLOCS)}.
check_subsequent_path_growth(ReceiptMap) ->
PathLengths = [ length(blockchain_txn_poc_receipts_v1:path(Txn)) || {_, Txn} <- lists:flatten(maps:values(ReceiptMap)) ],
ct:pal("PathLengths: ~p", [PathLengths]),
lists:any(fun(L) -> L > 1 end, PathLengths).
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