Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 968f9d92f2 | |||
| 34f3c93aaa | |||
| c37ee1c3af | |||
| 408bd9fc18 | |||
| 2a33d06bd6 | |||
| 8cb2c76614 | |||
| 07b658d509 | |||
| 8a68244c90 | |||
| e31a8dd2f1 | |||
| 2ea84ee4b2 | |||
| 8d99f55377 | |||
| 6939ae2fd1 | |||
| 196a2d9949 | |||
| d61f103945 | |||
| 0a76bada43 | |||
| 36a11575d2 | |||
| 5bc0fc5ff8 | |||
| c61ce6df1a |
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
BUILD="_build/default/lib/gmhive_client"
|
||||||
|
SCHEMA_OUT=$(BUILD)/priv/gmhc_schema.json
|
||||||
|
|
||||||
|
schema:
|
||||||
|
ERL_LIBS=_build/default/lib \
|
||||||
|
erl -run gmhc_config_schema export $(SCHEMA_OUT) -run init stop
|
||||||
|
scripts/update_readme_json.sh README.md $(SCHEMA_OUT)
|
||||||
|
|
||||||
|
|
||||||
@@ -155,6 +155,16 @@ server. (For `"testnet"` this will be `"test.gajumining.com"`.)
|
|||||||
"pattern": "^ak_[1-9A-HJ-NP-Za-km-z]*$",
|
"pattern": "^ak_[1-9A-HJ-NP-Za-km-z]*$",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"report": {
|
||||||
|
"default": "silent",
|
||||||
|
"description": "Progress reporting",
|
||||||
|
"enum": [
|
||||||
|
"debug",
|
||||||
|
"progress",
|
||||||
|
"silent"
|
||||||
|
],
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"default": "worker",
|
"default": "worker",
|
||||||
"description": "monitor mode can be used to see if a pool is alive",
|
"description": "monitor mode can be used to see if a pool is alive",
|
||||||
@@ -174,7 +184,7 @@ server. (For `"testnet"` this will be `"test.gajumining.com"`.)
|
|||||||
"properties": {
|
"properties": {
|
||||||
"executable": {
|
"executable": {
|
||||||
"default": "mean29-generic",
|
"default": "mean29-generic",
|
||||||
"description": "Executable binary of the worker. Can be a fully qualified path, but the software may apply default logic to locate a plain basename.",
|
"description": "Executable binary of the worker. Can be a fully qualified path, \nbut the software may apply default logic to locate a plain basename.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"extra_args": {
|
"extra_args": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{application,gmhive_client,
|
{application,gmhive_client,
|
||||||
[{description,"Gajumaru Hive Client"},
|
[{description,"Gajumaru Hive Client"},
|
||||||
{vsn,"0.4.4"},
|
{vsn,"0.6.3"},
|
||||||
{registered,[]},
|
{registered,[]},
|
||||||
{applications,[kernel,stdlib,sasl,gproc,inets,ssl,enoise,
|
{applications,[kernel,stdlib,sasl,gproc,inets,ssl,enoise,
|
||||||
gmconfig,gmhive_protocol,gmhive_worker]},
|
gmconfig,gmhive_protocol,gmhive_worker]},
|
||||||
|
|||||||
+3
-1
@@ -5,12 +5,14 @@
|
|||||||
{erl_opts, [debug_info]}.
|
{erl_opts, [debug_info]}.
|
||||||
{plugins, [rebar3_hex]}.
|
{plugins, [rebar3_hex]}.
|
||||||
|
|
||||||
|
{post_hooks, [{compile, "make schema"}]}.
|
||||||
|
|
||||||
{deps, [
|
{deps, [
|
||||||
{enoise, {git, "https://git.qpq.swiss/QPQ-AG/enoise.git", {ref, "029292817e"}}},
|
{enoise, {git, "https://git.qpq.swiss/QPQ-AG/enoise.git", {ref, "029292817e"}}},
|
||||||
{gmhive_protocol,
|
{gmhive_protocol,
|
||||||
{git, "https://git.qpq.swiss/QPQ-AG/gmhive_protocol.git",
|
{git, "https://git.qpq.swiss/QPQ-AG/gmhive_protocol.git",
|
||||||
{ref, "818ce33"}}},
|
{ref, "818ce33"}}},
|
||||||
{gmhive_worker, {git, "https://git.qpq.swiss/QPQ-AG/gmhive_worker", {ref, "255ef59"}}},
|
{gmhive_worker, {git, "https://git.qpq.swiss/QPQ-AG/gmhive_worker", {ref, "cabd104114"}}},
|
||||||
{gmconfig, {git, "https://git.qpq.swiss/QPQ-AG/gmconfig.git",
|
{gmconfig, {git, "https://git.qpq.swiss/QPQ-AG/gmconfig.git",
|
||||||
{ref, "38620ff9e2"}}},
|
{ref, "38620ff9e2"}}},
|
||||||
{gproc, "1.0.0"},
|
{gproc, "1.0.0"},
|
||||||
|
|||||||
+2
-2
@@ -21,7 +21,7 @@
|
|||||||
0},
|
0},
|
||||||
{<<"gmcuckoo">>,
|
{<<"gmcuckoo">>,
|
||||||
{git,"https://git.qpq.swiss/QPQ-AG/gmcuckoo.git",
|
{git,"https://git.qpq.swiss/QPQ-AG/gmcuckoo.git",
|
||||||
{ref,"106e1cd2e4ff81286f6bc7d7c85f83bc20e14b82"}},
|
{ref,"256e14e7c88043132245be902ff9756070d285b4"}},
|
||||||
1},
|
1},
|
||||||
{<<"gmhive_protocol">>,
|
{<<"gmhive_protocol">>,
|
||||||
{git,"https://git.qpq.swiss/QPQ-AG/gmhive_protocol.git",
|
{git,"https://git.qpq.swiss/QPQ-AG/gmhive_protocol.git",
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
0},
|
0},
|
||||||
{<<"gmhive_worker">>,
|
{<<"gmhive_worker">>,
|
||||||
{git,"https://git.qpq.swiss/QPQ-AG/gmhive_worker",
|
{git,"https://git.qpq.swiss/QPQ-AG/gmhive_worker",
|
||||||
{ref,"255ef59ccd7f795d2d25f2d0ebcf24e3251b6f36"}},
|
{ref,"cabd104114691edb925aacd7e04d431d47bac420"}},
|
||||||
0},
|
0},
|
||||||
{<<"gmserialization">>,
|
{<<"gmserialization">>,
|
||||||
{git,"https://git.qpq.swiss/QPQ-AG/gmserialization.git",
|
{git,"https://git.qpq.swiss/QPQ-AG/gmserialization.git",
|
||||||
|
|||||||
Executable
+51
@@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
README="$1"
|
||||||
|
SCHEMA="$2"
|
||||||
|
|
||||||
|
if [[ ! -f "$README" || ! -f "$SCHEMA" ]]; then
|
||||||
|
echo "Usage: $0 README.md schema.json"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
tmpfile=$(mktemp)
|
||||||
|
|
||||||
|
awk -v schema_file="$SCHEMA" '
|
||||||
|
BEGIN {
|
||||||
|
in_json_block = 0
|
||||||
|
in_schema_section = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/^##[[:space:]]+JSON[[:space:]]+Schema/ {
|
||||||
|
in_schema_section = 1
|
||||||
|
print
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
/^##[[:space:]]+/ && in_schema_section {
|
||||||
|
# Another section starts, end the schema section
|
||||||
|
in_schema_section = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
in_schema_section && /^```json/ {
|
||||||
|
print "```json"
|
||||||
|
while ((getline line < schema_file) > 0) print line
|
||||||
|
close(schema_file)
|
||||||
|
in_json_block = 1
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
in_json_block && /^```$/ {
|
||||||
|
print "```"
|
||||||
|
in_json_block = 0
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
!(in_schema_section && in_json_block) {
|
||||||
|
print
|
||||||
|
}
|
||||||
|
' "$README" > "$tmpfile"
|
||||||
|
|
||||||
|
mv "$tmpfile" "$README"
|
||||||
|
echo "✅ Updated JSON schema block in $README"
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
%% -*- mode: erlang; erlang-indent-level: 4; indent-tabs-mode: nil -*-
|
%% -*- mode: erlang; erlang-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
-module(gmhc_app).
|
-module(gmhc_app).
|
||||||
|
-vsn("0.6.1").
|
||||||
|
|
||||||
-behaviour(application).
|
-behaviour(application).
|
||||||
|
|
||||||
@@ -44,8 +45,31 @@ stop(_State) ->
|
|||||||
ok.
|
ok.
|
||||||
|
|
||||||
set_things_up() ->
|
set_things_up() ->
|
||||||
|
maybe_add_logger_handler(),
|
||||||
gmhc_counters:initialize(),
|
gmhc_counters:initialize(),
|
||||||
gmhc_config:load_config(),
|
gmhc_config:load_config(),
|
||||||
logger:set_module_level([gmhw_pow_cuckoo], notice),
|
logger:set_module_level([gmhw_pow_cuckoo], notice),
|
||||||
?LOG_DEBUG("Config: ~p", [gmconfig:user_config()]),
|
?LOG_DEBUG("Config: ~p", [gmconfig:user_config()]),
|
||||||
|
case gmhc_config:get_config([<<"report">>]) of
|
||||||
|
<<"debug">> ->
|
||||||
|
?LOG_NOTICE("Starting debug reporter", []),
|
||||||
|
gmhc_events:debug();
|
||||||
|
<<"progress">> ->
|
||||||
|
?LOG_NOTICE("Starting progress reporter", []),
|
||||||
|
gmhc_events:progress();
|
||||||
|
_ -> ok
|
||||||
|
end,
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
maybe_add_logger_handler() ->
|
||||||
|
case is_headless() orelse application:get_env(gmhive_client, tty_logger, false) of
|
||||||
|
true ->
|
||||||
|
Level = application:get_env(gmhive_client, tty_logger_level, error),
|
||||||
|
io:fwrite("Adding logger handler: ~p~n", [Level]),
|
||||||
|
logger:add_handler(gmhc_tty, logger_std_h, #{level => Level});
|
||||||
|
false ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
is_headless() ->
|
||||||
|
undefined == application:get_key(gajumine, vsn).
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
-module(gmhc_config).
|
-module(gmhc_config).
|
||||||
|
-vsn("0.6.1").
|
||||||
|
|
||||||
-export([ load_config/0
|
-export([ load_config/0
|
||||||
, get_config/1
|
, get_config/1
|
||||||
@@ -13,8 +14,20 @@ load_config() ->
|
|||||||
gmconfig:apply_os_env(),
|
gmconfig:apply_os_env(),
|
||||||
gmconfig:process_plain_args(),
|
gmconfig:process_plain_args(),
|
||||||
check_application_env(),
|
check_application_env(),
|
||||||
|
check_final_config(),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
check_final_config() ->
|
||||||
|
ExtraPubkeys = get_config([<<"extra_pubkeys">>]),
|
||||||
|
AllKeys = [get_config([<<"pubkey">>]) | ExtraPubkeys],
|
||||||
|
case AllKeys -- lists:usort(AllKeys) of
|
||||||
|
[] ->
|
||||||
|
ok;
|
||||||
|
Duplicates ->
|
||||||
|
?LOG_ERROR("Duplicate account ids found: ~p", [Duplicates]),
|
||||||
|
error({duplicate_account_ids, Duplicates})
|
||||||
|
end.
|
||||||
|
|
||||||
instrument_gmconfig() ->
|
instrument_gmconfig() ->
|
||||||
gmconfig:set_gmconfig_env(gmconfig_env()).
|
gmconfig:set_gmconfig_env(gmconfig_env()).
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
-module(gmhc_config_schema).
|
-module(gmhc_config_schema).
|
||||||
|
-vsn("0.6.1").
|
||||||
|
|
||||||
-export([ schema/0
|
-export([ schema/0
|
||||||
, to_json/0 ]).
|
, to_json/0
|
||||||
|
, export/1 ]).
|
||||||
|
|
||||||
-import(gmconfig_schema_helpers,
|
-import(gmconfig_schema_helpers,
|
||||||
[ str/1
|
[ str/1
|
||||||
@@ -21,6 +23,17 @@
|
|||||||
to_json() ->
|
to_json() ->
|
||||||
json:encode(schema()).
|
json:encode(schema()).
|
||||||
|
|
||||||
|
export(ToFile) ->
|
||||||
|
case file:open(ToFile, [write]) of
|
||||||
|
{ok, Fd} ->
|
||||||
|
try ok = io:put_chars(Fd, json:format(schema(), #{indent => 4}))
|
||||||
|
after
|
||||||
|
file:close(Fd)
|
||||||
|
end;
|
||||||
|
{error, _} = Error ->
|
||||||
|
Error
|
||||||
|
end.
|
||||||
|
|
||||||
schema() ->
|
schema() ->
|
||||||
obj(schema_init(),
|
obj(schema_init(),
|
||||||
#{
|
#{
|
||||||
@@ -38,6 +51,9 @@ schema() ->
|
|||||||
, pool => pool()
|
, pool => pool()
|
||||||
, pool_admin => pool_admin()
|
, pool_admin => pool_admin()
|
||||||
, workers => workers()
|
, workers => workers()
|
||||||
|
, report => str(#{ enum => [<<"debug">>, <<"progress">>, <<"silent">>]
|
||||||
|
, default => <<"silent">>
|
||||||
|
, description => <<"Progress reporting">> })
|
||||||
}).
|
}).
|
||||||
|
|
||||||
pool() ->
|
pool() ->
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
-module(gmhc_connector).
|
-module(gmhc_connector).
|
||||||
|
-vsn("0.6.1").
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
-module(gmhc_connectors_sup).
|
-module(gmhc_connectors_sup).
|
||||||
|
-vsn("0.6.1").
|
||||||
-behavior(supervisor).
|
-behavior(supervisor).
|
||||||
|
|
||||||
-export([ start_link/0
|
-export([ start_link/0
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
-module(gmhc_counters).
|
-module(gmhc_counters).
|
||||||
|
-vsn("0.6.1").
|
||||||
|
|
||||||
-export([ initialize/0 ]).
|
-export([ initialize/0 ]).
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
-module(gmhc_eureka).
|
-module(gmhc_eureka).
|
||||||
|
-vsn("0.6.1").
|
||||||
|
|
||||||
-export([get_pool_address/0]).
|
-export([get_pool_address/0]).
|
||||||
|
|
||||||
|
|||||||
+103
-14
@@ -1,4 +1,5 @@
|
|||||||
-module(gmhc_events).
|
-module(gmhc_events).
|
||||||
|
-vsn("0.6.1").
|
||||||
|
|
||||||
-export([subscribe/1,
|
-export([subscribe/1,
|
||||||
ensure_subscribed/1,
|
ensure_subscribed/1,
|
||||||
@@ -6,7 +7,17 @@
|
|||||||
ensure_unsubscribed/1,
|
ensure_unsubscribed/1,
|
||||||
publish/2]).
|
publish/2]).
|
||||||
|
|
||||||
-export([debug/0]).
|
-export([debug/0,
|
||||||
|
progress/0,
|
||||||
|
stop/0]).
|
||||||
|
|
||||||
|
-export([rpt_debug/2,
|
||||||
|
rpt_progress/2]).
|
||||||
|
|
||||||
|
%% internal
|
||||||
|
-export([init_reporter/2]).
|
||||||
|
|
||||||
|
-include_lib("kernel/include/logger.hrl").
|
||||||
|
|
||||||
-export_type([event/0]).
|
-export_type([event/0]).
|
||||||
|
|
||||||
@@ -59,22 +70,100 @@ ensure_unsubscribed(Event) ->
|
|||||||
|
|
||||||
debug() ->
|
debug() ->
|
||||||
ok = application:ensure_started(gproc),
|
ok = application:ensure_started(gproc),
|
||||||
spawn(fun() ->
|
spawn_reporter(fun() ->
|
||||||
subscribe(pool_notification),
|
sub(),
|
||||||
subscribe({pool_notification, new_generation}),
|
gmhive_worker:subscribe_returns(),
|
||||||
subscribe(connected),
|
loop(fun rpt_debug/2, false)
|
||||||
subscribe(puzzle),
|
end).
|
||||||
subscribe(result),
|
|
||||||
subscribe(error),
|
|
||||||
subscribe(disconnected),
|
|
||||||
loop()
|
|
||||||
end).
|
|
||||||
|
|
||||||
loop() ->
|
progress() ->
|
||||||
|
ok = application:ensure_started(gproc),
|
||||||
|
spawn_reporter(fun() ->
|
||||||
|
sub(),
|
||||||
|
loop(fun rpt_progress/2, true)
|
||||||
|
end).
|
||||||
|
|
||||||
|
spawn_reporter(F) ->
|
||||||
|
Parent = self(),
|
||||||
|
proc_lib:start_link(?MODULE, init_reporter, [F, Parent]).
|
||||||
|
|
||||||
|
init_reporter(F, Parent) ->
|
||||||
|
try_register_reporter(),
|
||||||
|
proc_lib:init_ack(Parent, self()),
|
||||||
|
F().
|
||||||
|
|
||||||
|
stop() ->
|
||||||
|
case whereis(gmhc_reporter) of
|
||||||
|
undefined ->
|
||||||
|
not_running;
|
||||||
|
Pid ->
|
||||||
|
exit(Pid, kill)
|
||||||
|
end.
|
||||||
|
|
||||||
|
sub() ->
|
||||||
|
subscribe(pool_notification),
|
||||||
|
subscribe({pool_notification, new_generation}),
|
||||||
|
subscribe(connected),
|
||||||
|
subscribe(puzzle),
|
||||||
|
subscribe(result),
|
||||||
|
subscribe(error),
|
||||||
|
subscribe(disconnected).
|
||||||
|
|
||||||
|
loop(F, Ts) ->
|
||||||
receive
|
receive
|
||||||
stop -> ok;
|
stop -> ok;
|
||||||
{gproc_ps_event, E, Data} ->
|
{gproc_ps_event, E, Data} ->
|
||||||
io:fwrite("EVENT ~p: ~p~n", [E, Data]),
|
maybe_print(F(E, Data), Ts),
|
||||||
loop()
|
loop(F, Ts)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
try_register_reporter() ->
|
||||||
|
try register(gmhc_reporter, self())
|
||||||
|
catch
|
||||||
|
error:_ ->
|
||||||
|
?LOG_ERROR("Reporter already running. Try gmhc_events:stop().", []),
|
||||||
|
error(already_running)
|
||||||
|
end.
|
||||||
|
|
||||||
|
maybe_print([], _) ->
|
||||||
|
ok;
|
||||||
|
maybe_print(String, Ts) when is_boolean(Ts) ->
|
||||||
|
TSstr = [[ts(), " "] || Ts],
|
||||||
|
io:put_chars([TSstr, String, "\n"]).
|
||||||
|
|
||||||
|
ts() ->
|
||||||
|
calendar:system_time_to_rfc3339(erlang:system_time(millisecond),
|
||||||
|
[{unit, millisecond}, {offset, "Z"}]).
|
||||||
|
|
||||||
|
rpt_debug(E, Data) ->
|
||||||
|
io_lib:fwrite("EVENT ~p: ~p", [E, Data]).
|
||||||
|
|
||||||
|
rpt_progress(puzzle, #{info := {_Data, _Target, Nonce, _Config}}) ->
|
||||||
|
w("Trying nonce: ~p", [Nonce]);
|
||||||
|
rpt_progress(result, #{info := Info}) ->
|
||||||
|
case Info of
|
||||||
|
{error, no_solution} ->
|
||||||
|
[];
|
||||||
|
{ok, Cycles} ->
|
||||||
|
w("Found! Reporting ~w cycles to leader.", [length(Cycles)]);
|
||||||
|
Other ->
|
||||||
|
w("Unexpected 'result': ~tp", [Other])
|
||||||
|
end;
|
||||||
|
rpt_progress(pool_notification, #{info := #{msg := Msg}}) ->
|
||||||
|
case Msg of
|
||||||
|
#{solution_accepted := #{seq := Seq}} ->
|
||||||
|
w("The hive has produced a solution! Sequence: ~w", [Seq]);
|
||||||
|
#{new_generation := _} -> [];
|
||||||
|
#{candidate := _} -> [];
|
||||||
|
Other ->
|
||||||
|
w("Unexpected 'pool_notification': ~tp", [Other])
|
||||||
|
end;
|
||||||
|
rpt_progress(connected, _) ->
|
||||||
|
w("Connected!", []);
|
||||||
|
rpt_progress(disconnected, _) ->
|
||||||
|
w("Disconnected!", []);
|
||||||
|
rpt_progress(_, _) ->
|
||||||
|
[].
|
||||||
|
|
||||||
|
w(Fmt, Args) ->
|
||||||
|
io_lib:fwrite(Fmt, Args).
|
||||||
|
|||||||
+37
-11
@@ -1,4 +1,5 @@
|
|||||||
-module(gmhc_handler).
|
-module(gmhc_handler).
|
||||||
|
-vsn("0.6.1").
|
||||||
-behavior(gen_server).
|
-behavior(gen_server).
|
||||||
|
|
||||||
-export([ start_link/0
|
-export([ start_link/0
|
||||||
@@ -11,6 +12,7 @@
|
|||||||
]).
|
]).
|
||||||
|
|
||||||
-export([ call/1
|
-export([ call/1
|
||||||
|
, async_call/1
|
||||||
, notify/1
|
, notify/1
|
||||||
, pool_connected/2
|
, pool_connected/2
|
||||||
, from_pool/1 ]).
|
, from_pool/1 ]).
|
||||||
@@ -37,6 +39,13 @@ call(Req) ->
|
|||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
async_call(Req) ->
|
||||||
|
try gen_server:call(?MODULE, {async_call, Req}, ?CALL_TIMEOUT)
|
||||||
|
catch
|
||||||
|
exit:Reason ->
|
||||||
|
{error, Reason}
|
||||||
|
end.
|
||||||
|
|
||||||
notify(Msg) ->
|
notify(Msg) ->
|
||||||
gen_server:cast(?MODULE, {notify, Msg}).
|
gen_server:cast(?MODULE, {notify, Msg}).
|
||||||
|
|
||||||
@@ -55,6 +64,8 @@ init([]) ->
|
|||||||
|
|
||||||
handle_call({call, Req}, _From, #st{} = S) ->
|
handle_call({call, Req}, _From, #st{} = S) ->
|
||||||
{reply, call_connector(Req), S};
|
{reply, call_connector(Req), S};
|
||||||
|
handle_call({async_call, Req}, _From, #st{} = S) ->
|
||||||
|
{reply, call_connector(Req, false), S};
|
||||||
handle_call(_Req, _From, S) ->
|
handle_call(_Req, _From, S) ->
|
||||||
{reply, {error, unknown_method}, S}.
|
{reply, {error, unknown_method}, S}.
|
||||||
|
|
||||||
@@ -118,24 +129,39 @@ maybe_publish(_) ->
|
|||||||
maybe_via(#{via := Via}, Info) ->
|
maybe_via(#{via := Via}, Info) ->
|
||||||
Info#{via => Via}.
|
Info#{via => Via}.
|
||||||
|
|
||||||
call_connector(Req0) ->
|
call_connector(Req) ->
|
||||||
|
call_connector(Req, true).
|
||||||
|
|
||||||
|
call_connector(Req0, Wait) ->
|
||||||
{ViaId, Req} = maps:take(via, Req0),
|
{ViaId, Req} = maps:take(via, Req0),
|
||||||
case gmhc_connector:whereis_id(ViaId) of
|
case gmhc_connector:whereis_id(ViaId) of
|
||||||
undefined ->
|
undefined ->
|
||||||
{error, no_connection};
|
{error, no_connection};
|
||||||
Pid when is_pid(Pid) ->
|
Pid when is_pid(Pid) ->
|
||||||
Id = erlang:unique_integer(),
|
Id = erlang:unique_integer(),
|
||||||
MRef = erlang:monitor(process, Pid),
|
MRef = case Wait of
|
||||||
|
true -> erlang:monitor(process, Pid);
|
||||||
|
false -> none
|
||||||
|
end,
|
||||||
gmhc_connector:send(ViaId, #{call => Req#{ id => Id }}),
|
gmhc_connector:send(ViaId, #{call => Req#{ id => Id }}),
|
||||||
receive
|
case Wait of
|
||||||
{from_pool, #{reply := #{ id := Id, result := Result }}} ->
|
true ->
|
||||||
Result;
|
receive
|
||||||
{from_pool, #{error := #{ id := Id } = Error}} ->
|
{from_pool, #{reply := #{ id := Id
|
||||||
{error, maps:remove(id, Error)};
|
, result := Result }}} ->
|
||||||
{'DOWN', MRef, _, _, _} ->
|
erlang:demonitor(MRef),
|
||||||
{error, no_connection}
|
Result;
|
||||||
after 5000 ->
|
{from_pool, #{error := #{ id := Id } = Error}} ->
|
||||||
{error, {timeout, process_info(self(), messages)}}
|
erlang:demonitor(MRef),
|
||||||
|
{error, maps:remove(id, Error)};
|
||||||
|
{'DOWN', MRef, _, _, _} ->
|
||||||
|
{error, no_connection}
|
||||||
|
after 5000 ->
|
||||||
|
erlang:demonitor(MRef),
|
||||||
|
{error, {timeout, process_info(self(), messages)}}
|
||||||
|
end;
|
||||||
|
false ->
|
||||||
|
ok
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|||||||
+49
-22
@@ -1,4 +1,5 @@
|
|||||||
-module(gmhc_server).
|
-module(gmhc_server).
|
||||||
|
-vsn("0.6.1").
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@
|
|||||||
|
|
||||||
-define(CONNECTED(S), map_size(S#st.connected) > 0).
|
-define(CONNECTED(S), map_size(S#st.connected) > 0).
|
||||||
|
|
||||||
-define(MAX_ERRORS, 5).
|
-define(MAX_ERRORS, 50).
|
||||||
|
|
||||||
connected(Id, Type) ->
|
connected(Id, Type) ->
|
||||||
gen_server:call(?MODULE, {connected, Id, Type}).
|
gen_server:call(?MODULE, {connected, Id, Type}).
|
||||||
@@ -107,17 +108,20 @@ handle_cast({from_pool, #{via := Connector,
|
|||||||
%% We could check whether we have already received the candidate ...
|
%% We could check whether we have already received the candidate ...
|
||||||
%% For now, stop all workers, restart with new candidate
|
%% For now, stop all workers, restart with new candidate
|
||||||
try
|
try
|
||||||
% Most of the time we don't want to stop the worker. If we do, though, then
|
%% Most of the time we don't want to stop the worker. If we do, though, then
|
||||||
% we need to do it more carefully than this, or memory usage will triple.
|
%% we need to do it more carefully than this, or memory usage will triple.
|
||||||
% Workers1 = stop_workers(Workers),
|
%% Workers1 = stop_workers(Workers),
|
||||||
{Workers2, Cand1} = assign_nonces(Workers, Cand),
|
%%
|
||||||
#st{candidate = Cand2} = S1 = maybe_request_nonces(S#st{candidate = Cand1}),
|
%% Nonces may be [], in which case we need to request new nonces first.
|
||||||
NewWorkers = [spawn_worker(W, Cand2) || W <- Workers2],
|
#st{candidate = Cand1} = S1 = maybe_request_nonces(S#st{candidate = Cand}),
|
||||||
{noreply, S1#st{workers = NewWorkers}}
|
{Workers2, Cand2} = assign_nonces(Workers, Cand1),
|
||||||
|
#st{candidate = Cand3} = S2 = maybe_request_nonces(S1#st{candidate = Cand2}),
|
||||||
|
NewWorkers = [spawn_worker(W, Cand3) || W <- Workers2],
|
||||||
|
{noreply, S2#st{workers = NewWorkers}}
|
||||||
catch
|
catch
|
||||||
Cat:Err:St ->
|
Cat:Err:St ->
|
||||||
?LOG_ERROR("CAUGHT ~p:~p / ~p", [Cat, Err, St]),
|
?LOG_ERROR("CAUGHT ~p:~p / ~p", [Cat, Err, St]),
|
||||||
{noreply, S}
|
{noreply, S}
|
||||||
end;
|
end;
|
||||||
handle_cast({disconnected, Id}, #st{connected = Conn} = S) ->
|
handle_cast({disconnected, Id}, #st{connected = Conn} = S) ->
|
||||||
?LOG_DEBUG("disconnected: ~p", [Id]),
|
?LOG_DEBUG("disconnected: ~p", [Id]),
|
||||||
@@ -151,11 +155,23 @@ handle_info({'EXIT', Pid, Reason}, #st{ workers = Workers
|
|||||||
gmhc_events:publish(error, ?ERR_EVT(#{error => worker_error,
|
gmhc_events:publish(error, ?ERR_EVT(#{error => worker_error,
|
||||||
data => Reason})),
|
data => Reason})),
|
||||||
Ws1 = incr_worker_error(W, Workers),
|
Ws1 = incr_worker_error(W, Workers),
|
||||||
|
erlang:start_timer(100, self(), check_workers),
|
||||||
{noreply, S#st{workers = Ws1}};
|
{noreply, S#st{workers = Ws1}};
|
||||||
false ->
|
false ->
|
||||||
%% ?LOG_DEBUG("EXIT apparently not from worker?? (~p)", [Pid]),
|
%% ?LOG_DEBUG("EXIT apparently not from worker?? (~p)", [Pid]),
|
||||||
{noreply, S}
|
{noreply, S}
|
||||||
end;
|
end;
|
||||||
|
handle_info({timeout, _, check_workers}, #st{workers = Workers} = S) ->
|
||||||
|
case [W || #worker{cand = undefined} = W <- Workers] of
|
||||||
|
[] ->
|
||||||
|
{noreply, S};
|
||||||
|
Idle ->
|
||||||
|
S1 = maybe_request_nonces(S),
|
||||||
|
S2 = lists:foldl(fun(W, Sx) ->
|
||||||
|
maybe_restart_worker(W, Sx)
|
||||||
|
end, S1, Idle),
|
||||||
|
{noreply, S2}
|
||||||
|
end;
|
||||||
handle_info(Msg, St) ->
|
handle_info(Msg, St) ->
|
||||||
?LOG_DEBUG("Unknown msg: ~p", [Msg]),
|
?LOG_DEBUG("Unknown msg: ~p", [Msg]),
|
||||||
{noreply, St}.
|
{noreply, St}.
|
||||||
@@ -168,6 +184,9 @@ code_change(_FromVsn, S, _Extra) ->
|
|||||||
|
|
||||||
report_solutions(Solutions, W, #st{} = S) when ?CONNECTED(S) ->
|
report_solutions(Solutions, W, #st{} = S) when ?CONNECTED(S) ->
|
||||||
#{via := Via, seq := Seq} = W#worker.cand,
|
#{via := Via, seq := Seq} = W#worker.cand,
|
||||||
|
Nonces = all_nonces(W),
|
||||||
|
[report_no_solution_(Via, Seq, N)
|
||||||
|
|| N <- Nonces, not lists:keymember(N, 1, Solutions)],
|
||||||
gmhc_handler:call(
|
gmhc_handler:call(
|
||||||
#{via => Via,
|
#{via => Via,
|
||||||
solutions => #{ seq => Seq
|
solutions => #{ seq => Seq
|
||||||
@@ -175,18 +194,23 @@ report_solutions(Solutions, W, #st{} = S) when ?CONNECTED(S) ->
|
|||||||
, evidence => Evd }
|
, evidence => Evd }
|
||||||
|| {Nonce, Evd} <- Solutions] }}).
|
|| {Nonce, Evd} <- Solutions] }}).
|
||||||
|
|
||||||
%% report_solution(Nonce, Solution, W, #st{connected = true}) ->
|
report_no_solution(_Nonce, W, #st{} = S) when ?CONNECTED(S) ->
|
||||||
%% #{seq := Seq} = W#worker.cand,
|
|
||||||
%% gmhc_handler:call(#{solution => #{ seq => Seq
|
|
||||||
%% , nonce => Nonce
|
|
||||||
%% , evidence => Solution }}).
|
|
||||||
|
|
||||||
report_no_solution(Nonce, W, #st{} = S) when ?CONNECTED(S) ->
|
|
||||||
#{via := Via, seq := Seq} = W#worker.cand,
|
#{via := Via, seq := Seq} = W#worker.cand,
|
||||||
|
Nonces = all_nonces(W),
|
||||||
%% ?LOG_DEBUG("report no_solution Seq = ~p, Nonce = ~p", [Seq, Nonce]),
|
%% ?LOG_DEBUG("report no_solution Seq = ~p, Nonce = ~p", [Seq, Nonce]),
|
||||||
gmhc_handler:call(#{via => Via,
|
[report_no_solution_(Via, Seq, Nonce1) || Nonce1 <- Nonces],
|
||||||
no_solution => #{ seq => Seq
|
ok.
|
||||||
, nonce => Nonce}}).
|
|
||||||
|
report_no_solution_(Via, Seq, Nonce) ->
|
||||||
|
gmhc_handler:async_call(#{via => Via,
|
||||||
|
no_solution => #{ seq => Seq
|
||||||
|
, nonce => Nonce}}).
|
||||||
|
|
||||||
|
all_nonces(#worker{nonce = Nonce, config = Config}) ->
|
||||||
|
case gmhw_pow_cuckoo:repeats(Config) of
|
||||||
|
1 -> [Nonce];
|
||||||
|
Rs -> lists:seq(Nonce, Nonce + Rs - 1)
|
||||||
|
end.
|
||||||
|
|
||||||
maybe_request_nonces(#st{ candidate = #{via := Via, seq := Seq, nonces := Nonces}
|
maybe_request_nonces(#st{ candidate = #{via := Via, seq := Seq, nonces := Nonces}
|
||||||
, nonces = N} = S) when ?CONNECTED(S) ->
|
, nonces = N} = S) when ?CONNECTED(S) ->
|
||||||
@@ -223,14 +247,14 @@ handle_worker_result({worker_result, Result}, W, S) ->
|
|||||||
case Result of
|
case Result of
|
||||||
{solutions, Solutions} ->
|
{solutions, Solutions} ->
|
||||||
{Cont, S1} = report_solutions_(Solutions, W, S),
|
{Cont, S1} = report_solutions_(Solutions, W, S),
|
||||||
maybe_continue(Cont, W, S1);
|
maybe_continue(Cont, reset_errors(W), S1);
|
||||||
{solution, Nonce, Solution} ->
|
{solution, Nonce, Solution} ->
|
||||||
%% report_solution(Nonce, Solution, W, S),
|
%% report_solution(Nonce, Solution, W, S),
|
||||||
{Cont, S1} = report_solutions_([{Nonce, Solution}], W, S),
|
{Cont, S1} = report_solutions_([{Nonce, Solution}], W, S),
|
||||||
maybe_continue(Cont, W, S1);
|
maybe_continue(Cont, reset_errors(W), S1);
|
||||||
{no_solution, Nonce} ->
|
{no_solution, Nonce} ->
|
||||||
report_no_solution(Nonce, W, S),
|
report_no_solution(Nonce, W, S),
|
||||||
maybe_restart_worker(W, S);
|
maybe_restart_worker(reset_errors(W), S);
|
||||||
{error, S} ->
|
{error, S} ->
|
||||||
?LOG_DEBUG("Worker ~p reported error as normal", [W#worker.index]),
|
?LOG_DEBUG("Worker ~p reported error as normal", [W#worker.index]),
|
||||||
gmhc_events:publish(error, ?ERR_EVT(#{error => worker_error,
|
gmhc_events:publish(error, ?ERR_EVT(#{error => worker_error,
|
||||||
@@ -258,6 +282,9 @@ report_solutions_(Solutions, W, S) ->
|
|||||||
{error, S}
|
{error, S}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
reset_errors(#worker{} = W) ->
|
||||||
|
W#worker{errors = 0}.
|
||||||
|
|
||||||
reset_worker(#worker{index = I} = W, Ws) ->
|
reset_worker(#worker{index = I} = W, Ws) ->
|
||||||
W1 = reset_worker_(W),
|
W1 = reset_worker_(W),
|
||||||
lists:keyreplace(I, #worker.index, Ws, W1).
|
lists:keyreplace(I, #worker.index, Ws, W1).
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
%% -*- mode: erlang; erlang-indent-level: 4; indent-tabs-mode: nil -*-
|
%% -*- mode: erlang; erlang-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
-module(gmhc_sup).
|
-module(gmhc_sup).
|
||||||
|
-vsn("0.6.1").
|
||||||
|
|
||||||
-behaviour(supervisor).
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(gmhc_workers).
|
-module(gmhc_workers).
|
||||||
|
-vsn("0.6.1").
|
||||||
|
|
||||||
-export([
|
-export([
|
||||||
get_worker_configs/0
|
get_worker_configs/0
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
%% -*- mode: erlang; erlang-indent-level: 4; indent-tabs-mode: nil -*-
|
%% -*- mode: erlang; erlang-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
{application, gmhive_client,
|
{application, gmhive_client,
|
||||||
[{description, "Gajumaru Hive Client"},
|
[{description, "Gajumaru Hive Client"},
|
||||||
{vsn, "0.1.0"},
|
{vsn, "zomp"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications,
|
{applications,
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
%% -*- erlang-mode; erlang-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
[{application, Name, Opts}] = CONFIG.
|
||||||
|
case lists:keyfind(vsn, 1, Opts) of
|
||||||
|
{vsn, "zomp"} ->
|
||||||
|
ZompMetaF = filename:join(filename:dirname(filename:dirname(SCRIPT)), "zomp.meta"),
|
||||||
|
{ok, ZMeta} = file:consult(ZompMetaF),
|
||||||
|
{_, {_, _, {Vmaj,Vmin,Vpatch}}} = lists:keyfind(package_id, 1, ZMeta),
|
||||||
|
VsnStr = unicode:characters_to_list(io_lib:fwrite("~w.~w.~w", [Vmaj, Vmin, Vpatch])),
|
||||||
|
Opts1 = lists:keyreplace(vsn, 1, Opts, {vsn, VsnStr}),
|
||||||
|
[{application, Name, Opts1}];
|
||||||
|
_ ->
|
||||||
|
CONFIG
|
||||||
|
end.
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
-module(gmhive_client).
|
-module(gmhive_client).
|
||||||
|
-vsn("0.6.1").
|
||||||
|
|
||||||
-export([ connect/1
|
-export([ connect/1
|
||||||
, disconnect/1
|
, disconnect/1
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
{prefix,"gmhc"}.
|
{prefix,"gmhc"}.
|
||||||
{desc,"Gajumaru Hive Client"}.
|
{desc,"Gajumaru Hive Client"}.
|
||||||
{author,"Ulf Wiger, QPQ AG"}.
|
{author,"Ulf Wiger, QPQ AG"}.
|
||||||
{package_id,{"uwiger","gmhive_client",{0,4,4}}}.
|
{package_id,{"uwiger","gmhive_client",{0,6,3}}}.
|
||||||
{deps,[{"uwiger","gmcuckoo",{1,2,3}},
|
{deps,[{"uwiger","gmhive_worker",{0,5,1}},
|
||||||
{"uwiger","gmhive_worker",{0,3,0}},
|
{"uwiger","gmcuckoo",{1,2,4}},
|
||||||
{"otpr","eblake2",{1,0,1}},
|
{"otpr","eblake2",{1,0,1}},
|
||||||
{"otpr","base58",{0,1,1}},
|
{"otpr","base58",{0,1,1}},
|
||||||
{"otpr","gmserialization",{0,1,3}},
|
{"otpr","gmserialization",{0,1,3}},
|
||||||
|
|||||||
@@ -38,5 +38,12 @@ rm "$IGNORE_TEMP"
|
|||||||
cp "$PWD/zomp.meta" "$DST/"
|
cp "$PWD/zomp.meta" "$DST/"
|
||||||
cp "$PWD/Emakefile" "$DST/"
|
cp "$PWD/Emakefile" "$DST/"
|
||||||
|
|
||||||
|
# copy generated schema
|
||||||
|
SCHEMA="$SRC/priv/gmhc_schema.json"
|
||||||
|
if [ -e "$SCHEMA" ]; then
|
||||||
|
mkdir -p "$DST/priv"
|
||||||
|
cp -a "$SCHEMA" "$DST/priv/$(basename "$SCHEMA")"
|
||||||
|
fi
|
||||||
|
|
||||||
# Clean up beam files just in case
|
# Clean up beam files just in case
|
||||||
[ -d "$DST/ebin" ] && find "$DST/ebin" -name '*.beam' -exec rm -f {} + || true
|
[ -d "$DST/ebin" ] && find "$DST/ebin" -name '*.beam' -exec rm -f {} + || true
|
||||||
|
|||||||
Reference in New Issue
Block a user