From 8fad87a0fec8fa0424cbb27e39b0ba9564189897 Mon Sep 17 00:00:00 2001 From: Lee *!* Clagett Date: Tue, 6 Aug 2024 19:04:55 -0400 Subject: [PATCH] Add (non-standard) 'daemon_status' endpoint to REST API (#124) --- src/rest_server.cpp | 56 ++++++++++++++++++++++++++++++++++++++++ src/rpc/light_wallet.cpp | 24 +++++++++++++++++ src/rpc/light_wallet.h | 44 +++++++++++++++++++++++++++++-- 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/src/rest_server.cpp b/src/rest_server.cpp index c9e9d50..ce502c2 100644 --- a/src/rest_server.cpp +++ b/src/rest_server.cpp @@ -37,6 +37,7 @@ #include "common/error.h" // monero/src #include "common/expect.h" // monero/src +#include "config.h" #include "crypto/crypto.h" // monero/src #include "cryptonote_config.h" // monero/src #include "db/data.h" @@ -211,6 +212,60 @@ namespace lws bool auto_accept_creation; }; + struct daemon_status + { + using request = rpc::daemon_status_request; + using response = rpc::daemon_status_response; + + static expect handle(request, const db::storage&, const rpc::client& gclient, const runtime_options&) + { + using info_rpc = cryptonote::rpc::GetInfo; + + const expect tclient = thread_client(gclient); + if (!tclient) + return tclient.error(); + if (*tclient == nullptr) + throw std::logic_error{"Unexpected rpc::client nullptr"}; + + // default to an unavailable daemon + response resp{ + .network = rpc::network_type(lws::config::network), + .state = rpc::daemon_state::unavailable + }; + + info_rpc::Request daemon_req{}; + epee::byte_slice message = rpc::client::make_message("get_info", daemon_req); + const expect sent = send_with_retry(**tclient, std::move(message), std::chrono::seconds{2}); + if (!sent) + { + if (sent.matches(std::errc::timed_out)) + return resp; + return sent.error(); + } + + const auto daemon_resp = (*tclient)->receive(std::chrono::seconds{4}, MLWS_CURRENT_LOCATION); + if (!daemon_resp) + { + if (daemon_resp.matches(std::errc::timed_out)) + return resp; + return daemon_resp.error(); + } + + resp.outgoing_connections_count = daemon_resp->info.outgoing_connections_count; + resp.incoming_connections_count = daemon_resp->info.incoming_connections_count; + resp.height = daemon_resp->info.height; + resp.target_height = daemon_resp->info.target_height; + + if (!resp.outgoing_connections_count && !resp.incoming_connections_count) + resp.state = rpc::daemon_state::no_connections; + else if (resp.target_height && (resp.target_height - resp.height) >= 5) + resp.state = rpc::daemon_state::synchronizing; + else + resp.state = rpc::daemon_state::ok; + return resp; + } + }; + struct get_address_info { using request = rpc::account_credentials; @@ -956,6 +1011,7 @@ namespace lws constexpr const endpoint endpoints[] = { + {"/daemon_status", call, 1024}, {"/get_address_info", call, 2 * 1024}, {"/get_address_txs", call, 2 * 1024}, {"/get_random_outs", call, 2 * 1024}, diff --git a/src/rpc/light_wallet.cpp b/src/rpc/light_wallet.cpp index 378d08c..926b7b7 100644 --- a/src/rpc/light_wallet.cpp +++ b/src/rpc/light_wallet.cpp @@ -40,6 +40,7 @@ #include "ringct/rctOps.h" // monero/src #include "span.h" // monero/contrib/epee/include #include "util/random_outputs.h" +#include "wire.h" #include "wire/adapted/crypto.h" #include "wire/error.h" #include "wire/json.h" @@ -195,6 +196,29 @@ namespace lws convert_address(address, self.address); } + namespace rpc + { + namespace + { + constexpr const char* map_daemon_state[] = {"ok", "no_connections", "synchronizing", "unavailable"}; + constexpr const char* map_network_type[] = {"main", "test", "stage", "fake"}; + } + WIRE_DEFINE_ENUM(daemon_state, map_daemon_state); + WIRE_DEFINE_ENUM(network_type, map_network_type); + } + + void rpc::write_bytes(wire::json_writer& dest, const daemon_status_response& self) + { + wire::object(dest, + WIRE_FIELD(outgoing_connections_count), + WIRE_FIELD(incoming_connections_count), + WIRE_FIELD(height), + WIRE_FIELD(target_height), + WIRE_FIELD(network), + WIRE_FIELD(state) + ); + } + void rpc::write_bytes(wire::json_writer& dest, const new_subaddrs_response& self) { wire::object(dest, WIRE_FIELD(new_subaddrs), WIRE_FIELD(all_subaddrs)); diff --git a/src/rpc/light_wallet.h b/src/rpc/light_wallet.h index 9e9708e..1fe8724 100644 --- a/src/rpc/light_wallet.h +++ b/src/rpc/light_wallet.h @@ -33,8 +33,10 @@ #include #include -#include "common/expect.h" // monero/src -#include "crypto/crypto.h" // monero/src +#include "common/expect.h" // monero/src +#include "cryptonote_config.h" // monero/src +#include "cryptonote_basic/difficulty.h" // monero/src +#include "crypto/crypto.h" // monero/src #include "db/data.h" #include "rpc/rates.h" #include "util/fwd.h" @@ -65,6 +67,44 @@ namespace rpc void read_bytes(wire::json_reader&, account_credentials&); + enum class daemon_state : std::uint8_t + { + ok = 0, + no_connections, + synchronizing, + unavailable + }; + WIRE_DECLARE_ENUM(daemon_state); + + enum class network_type : std::uint8_t + { + main = 0, + test, + stage, + fake + }; + WIRE_DECLARE_ENUM(network_type); + + struct daemon_status_request + { + daemon_status_request() = delete; + }; + inline void read_bytes(const wire::reader&, const daemon_status_request&) + {} + + struct daemon_status_response + { + daemon_status_response() = delete; + std::uint64_t outgoing_connections_count; + std::uint64_t incoming_connections_count; + std::uint64_t height; + std::uint64_t target_height; + network_type network; + daemon_state state; + }; + void write_bytes(wire::json_writer&, const daemon_status_response&); + + struct new_subaddrs_response { new_subaddrs_response() = delete;