aboutsummaryrefslogtreecommitdiff
path: root/src/rpc/bootstrap_daemon.cpp
blob: ffea906d5dfee63a53bb4b4c186d4dce233fc1bc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "bootstrap_daemon.h"

#include <stdexcept>

#include <boost/thread/locks.hpp>

#include "crypto/crypto.h"
#include "cryptonote_core/cryptonote_core.h"
#include "misc_log_ex.h"
#include "net/parse.h"

#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "daemon.rpc.bootstrap_daemon"

namespace cryptonote
{

  bootstrap_daemon::bootstrap_daemon(
    std::function<std::map<std::string, bool>()> get_public_nodes,
    bool rpc_payment_enabled,
    const std::string &proxy)
    : m_selector(new bootstrap_node::selector_auto(std::move(get_public_nodes)))
    , m_rpc_payment_enabled(rpc_payment_enabled)
  {
    set_proxy(proxy);
  }

  bootstrap_daemon::bootstrap_daemon(
    const std::string &address,
    boost::optional<epee::net_utils::http::login> credentials,
    bool rpc_payment_enabled,
    const std::string &proxy)
    : m_selector(nullptr)
    , m_rpc_payment_enabled(rpc_payment_enabled)
  {
    set_proxy(proxy);
    if (!set_server(address, std::move(credentials)))
    {
      throw std::runtime_error("invalid bootstrap daemon address or credentials");
    }
  }

  std::string bootstrap_daemon::address() const noexcept
  {
    const auto& host = m_http_client.get_host();
    if (host.empty())
    {
      return std::string();
    }
    return host + ":" + m_http_client.get_port();
  }

  boost::optional<std::pair<uint64_t, uint64_t>> bootstrap_daemon::get_height()
  {
    cryptonote::COMMAND_RPC_GET_INFO::request req;
    cryptonote::COMMAND_RPC_GET_INFO::response res;

    if (!invoke_http_json("/getinfo", req, res))
    {
      return boost::none;
    }

    if (res.status != CORE_RPC_STATUS_OK)
    {
      return boost::none;
    }

    return {{res.height, res.target_height}};
  }

  bool bootstrap_daemon::handle_result(bool success, const std::string &status)
  {
    const bool failed = !success || (!m_rpc_payment_enabled && status == CORE_RPC_STATUS_PAYMENT_REQUIRED);
    if (failed && m_selector)
    {
      const std::string current_address = address();
      m_http_client.disconnect();

      const boost::unique_lock<boost::mutex> lock(m_selector_mutex);
      m_selector->handle_result(current_address, !failed);
    }

    return success;
  }

  void bootstrap_daemon::set_proxy(const std::string &address)
  {
    if (!address.empty() && !net::get_tcp_endpoint(address))
    {
      throw std::runtime_error("invalid proxy address format");
    }
    if (!m_http_client.set_proxy(address))
    {
      throw std::runtime_error("failed to set proxy address");
    }
  }

  bool bootstrap_daemon::set_server(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials /* = boost::none */)
  {
    if (!m_http_client.set_server(address, credentials))
    {
      MERROR("Failed to set bootstrap daemon address " << address);
      return false;
    }

    MINFO("Changed bootstrap daemon address to " << address);
    return true;
  }


  bool bootstrap_daemon::switch_server_if_needed()
  {
    if (m_http_client.is_connected() || !m_selector)
    {
      return true;
    }

    boost::optional<bootstrap_node::node_info> node;
    {
      const boost::unique_lock<boost::mutex> lock(m_selector_mutex);
      node = m_selector->next_node();
    }
    if (node) {
      return set_server(node->address, node->credentials);
    }

    return false;
  }

}