Electroneum
Loading...
Searching...
No Matches
daemon.cpp
Go to the documentation of this file.
1// Copyright (c) 2014-2018, The Monero Project
2//
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without modification, are
6// permitted provided that the following conditions are met:
7//
8// 1. Redistributions of source code must retain the above copyright notice, this list of
9// conditions and the following disclaimer.
10//
11// 2. Redistributions in binary form must reproduce the above copyright notice, this list
12// of conditions and the following disclaimer in the documentation and/or other
13// materials provided with the distribution.
14//
15// 3. Neither the name of the copyright holder nor the names of its contributors may be
16// used to endorse or promote products derived from this software without specific
17// prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29#include "daemon.h"
30#include <common/command_line.h>
31
32using namespace std;
33using namespace daemonize;
34namespace po = boost::program_options;
35
42
43void mock_daemon::init_options(boost::program_options::options_description & option_spec)
44{
46 t_node_server::init_options(option_spec);
48
51}
52
53void mock_daemon::default_options(boost::program_options::variables_map & vm)
54{
55 std::vector<std::string> exclusive_nodes{"127.0.0.1:65525"};
56 tools::options::set_option(vm, nodetool::arg_p2p_add_exclusive_node, po::variable_value(exclusive_nodes, false));
57
58 tools::options::set_option(vm, nodetool::arg_p2p_bind_ip, po::variable_value(std::string("127.0.0.1"), false));
59 tools::options::set_option(vm, nodetool::arg_no_igd, po::variable_value(true, false));
60 tools::options::set_option(vm, cryptonote::arg_offline, po::variable_value(true, false));
61 tools::options::set_option(vm, "disable-dns-checkpoints", po::variable_value(true, false));
62
63 const char *test_mainnet = getenv("TEST_MAINNET");
64 if (!test_mainnet || atoi(test_mainnet) == 0)
65 {
66 tools::options::set_option(vm, cryptonote::arg_testnet_on, po::variable_value(true, false));
67 }
68
69 // By default pick non-standard ports to avoid confusion with possibly locally running daemons (mainnet/testnet)
70 const char *test_p2p_port = getenv("TEST_P2P_PORT");
71 auto p2p_port = std::string(test_p2p_port && strlen(test_p2p_port) > 0 ? test_p2p_port : "61340");
72 tools::options::set_option(vm, nodetool::arg_p2p_bind_port, po::variable_value(p2p_port, false));
73
74 const char *test_rpc_port = getenv("TEST_RPC_PORT");
75 auto rpc_port = std::string(test_rpc_port && strlen(test_rpc_port) > 0 ? test_rpc_port : "61341");
76 tools::options::set_option(vm, cryptonote::core_rpc_server::arg_rpc_bind_port, po::variable_value(rpc_port, false));
77
78 const char *test_zmq_port = getenv("TEST_ZMQ_PORT");
79 auto zmq_port = std::string(test_zmq_port && strlen(test_zmq_port) > 0 ? test_zmq_port : "61342");
80 tools::options::set_option(vm, daemon_args::arg_zmq_rpc_bind_port, po::variable_value(zmq_port, false));
81
82 po::notify(vm);
83}
84
85void mock_daemon::set_ports(boost::program_options::variables_map & vm, unsigned initial_port)
86{
87 CHECK_AND_ASSERT_THROW_MES(initial_port < 65535-2, "Invalid port number");
88 tools::options::set_option(vm, nodetool::arg_p2p_bind_port, po::variable_value(std::to_string(initial_port), false));
89 tools::options::set_option(vm, cryptonote::core_rpc_server::arg_rpc_bind_port, po::variable_value(std::to_string(initial_port + 1), false));
90 tools::options::set_option(vm, daemon_args::arg_zmq_rpc_bind_port, po::variable_value(std::to_string(initial_port + 2), false));
91 po::notify(vm);
92}
93
101
103{
104 if(m_http_client.is_connected())
105 m_http_client.disconnect();
106
107 if (!m_terminated)
108 {
109 try
110 {
111 stop();
112 }
113 catch (...)
114 {
115 MERROR("Failed to stop");
116 }
117 }
118
119 if (!m_deinitalized)
120 {
121 deinit();
122 }
123}
124
126{
127 m_deinitalized = false;
130
131 CHECK_AND_ASSERT_THROW_MES(m_protocol.init(m_vm), "Failed to initialize cryptonote protocol.");
132 CHECK_AND_ASSERT_THROW_MES(m_rpc_server.init(m_vm, false, main_rpc_port), "Failed to initialize RPC server.");
133
134 if (m_start_p2p)
135 CHECK_AND_ASSERT_THROW_MES(m_server.init(m_vm), "Failed to initialize p2p server.");
136
137 if(m_http_client.is_connected())
138 m_http_client.disconnect();
139
141}
142
144{
145 if(m_http_client.is_connected())
146 m_http_client.disconnect();
147
148 try
149 {
150 m_rpc_server.deinit();
151 }
152 catch (...)
153 {
154 MERROR("Failed to deinitialize RPC server...");
155 }
156
157 if (m_start_p2p)
158 {
159 try
160 {
161 m_server.deinit();
162 }
163 catch (...)
164 {
165 MERROR("Failed to deinitialize p2p...");
166 }
167 }
168
169 try
170 {
171 m_protocol.deinit();
172 m_protocol.set_p2p_endpoint(nullptr);
173 }
174 catch (...)
175 {
176 MERROR("Failed to stop cryptonote protocol!");
177 }
178
179 m_deinitalized = true;
180}
181
183{
184 init();
185 run();
186}
187
189{
190 stop();
191 deinit();
192}
193
194void mock_daemon::try_init_and_run(boost::optional<unsigned> initial_port)
195{
196 const unsigned max_attempts = 3;
197 for(unsigned attempts=0; attempts < max_attempts; ++attempts)
198 {
199 if (initial_port)
200 {
201 set_ports(m_vm, initial_port.get());
203 MDEBUG("Ports changed, RPC: " << rpc_addr());
204 }
205
206 try
207 {
208 init_and_run();
209 return;
210 }
211 catch(const std::exception &e)
212 {
213 MWARNING("Could not init and start, attempt: " << attempts << ", reason: " << e.what());
214 if (attempts + 1 >= max_attempts)
215 {
216 throw;
217 }
218 }
219 }
220}
221
223{
224 m_run_thread = boost::thread(boost::bind(&mock_daemon::run_main, this));
225}
226
228{
229 CHECK_AND_ASSERT_THROW_MES(!m_terminated, "Can't run stopped daemon");
230 CHECK_AND_ASSERT_THROW_MES(!m_start_zmq || m_start_p2p, "ZMQ requires P2P");
231 boost::thread stop_thread = boost::thread([this] {
232 while (!this->m_stopped)
234 this->stop_p2p();
235 });
236
238 m_stopped = true;
239 stop_thread.join();
240 });
241
242 try
243 {
244 CHECK_AND_ASSERT_THROW_MES(m_rpc_server.run(2, false), "Failed to start RPC");
245 cryptonote::rpc::DaemonHandler rpc_daemon_handler(*m_core, m_server);
246 cryptonote::rpc::ZmqServer zmq_server(rpc_daemon_handler);
247
248 if (m_start_zmq)
249 {
250 if (!zmq_server.addTCPSocket("127.0.0.1", m_zmq_bind_port))
251 {
252 MERROR("Failed to add TCP Socket (127.0.0.1:" << m_zmq_bind_port << ") to ZMQ RPC Server");
253
254 stop_rpc();
255 return false;
256 }
257
258 MINFO("Starting ZMQ server...");
259 zmq_server.run();
260
261 MINFO("ZMQ server started at 127.0.0.1: " << m_zmq_bind_port);
262 }
263
264 if (m_start_p2p)
265 {
266 m_server.run(); // blocks until p2p goes down
267 }
268 else
269 {
270 while (!this->m_stopped)
272 }
273
274 if (m_start_zmq)
275 zmq_server.stop();
276
277 stop_rpc();
278 return true;
279 }
280 catch (std::exception const & ex)
281 {
282 MFATAL("Uncaught exception! " << ex.what());
283 return false;
284 }
285 catch (...)
286 {
287 MFATAL("Uncaught exception!");
288 return false;
289 }
290}
291
293{
294 CHECK_AND_ASSERT_THROW_MES(!m_terminated, "Can't stop stopped daemon");
295 m_stopped = true;
296 m_terminated = true;
297 m_run_thread.join();
298}
299
301{
302 m_rpc_server.send_stop_signal();
303 m_rpc_server.timed_wait_server_stop(5000);
304}
305
307{
308 if (m_start_p2p)
309 m_server.send_stop_signal();
310}
311
312void mock_daemon::mine_blocks(size_t num_blocks, const std::string &miner_address)
313{
314 bool blocks_mined = false;
315 const uint64_t start_height = get_height();
316 const auto mining_timeout = std::chrono::seconds(30);
317 MDEBUG("Current height before mining: " << start_height);
318
319 start_mining(miner_address);
320 auto mining_started = std::chrono::system_clock::now();
321
322 while(true) {
324 const uint64_t cur_height = get_height();
325
326 if (cur_height - start_height >= num_blocks)
327 {
328 MDEBUG("Cur blocks: " << cur_height << " start: " << start_height);
329 blocks_mined = true;
330 break;
331 }
332
333 auto current_time = std::chrono::system_clock::now();
334 if (mining_timeout < current_time - mining_started)
335 {
336 break;
337 }
338 }
339
340 stop_mining();
341 CHECK_AND_ASSERT_THROW_MES(blocks_mined, "Mining failed in the time limit");
342}
343
344constexpr const std::chrono::seconds mock_daemon::rpc_timeout;
345
346void mock_daemon::start_mining(const std::string &miner_address, uint64_t threads_count, bool do_background_mining, bool ignore_battery)
347{
349 req.miner_address = miner_address;
350 req.threads_count = threads_count;
351 req.do_background_mining = do_background_mining;
352 req.ignore_battery = ignore_battery;
353
355 bool r = epee::net_utils::invoke_http_json("/start_mining", req, resp, m_http_client, rpc_timeout);
356 CHECK_AND_ASSERT_THROW_MES(r, "RPC error - start mining");
357 CHECK_AND_ASSERT_THROW_MES(resp.status != CORE_RPC_STATUS_BUSY, "Daemon busy");
358 CHECK_AND_ASSERT_THROW_MES(resp.status == CORE_RPC_STATUS_OK, "Daemon response invalid: " << resp.status);
359}
360
362{
365 bool r = epee::net_utils::invoke_http_json("/stop_mining", req, resp, m_http_client, rpc_timeout);
366 CHECK_AND_ASSERT_THROW_MES(r, "RPC error - stop mining");
367 CHECK_AND_ASSERT_THROW_MES(resp.status != CORE_RPC_STATUS_BUSY, "Daemon busy");
368 CHECK_AND_ASSERT_THROW_MES(resp.status == CORE_RPC_STATUS_OK, "Daemon response invalid: " << resp.status);
369}
370
372{
373 return m_core->get_blockchain_storage().get_current_blockchain_height();
374}
uint64_t num_blocks(const std::vector< test_event_entry > &events)
epee::net_utils::connection_context_base connection_context
bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request &req, COMMAND_RPC_SEND_RAW_TX::response &res, const connection_context *ctx=NULL)
static void init_options(boost::program_options::options_description &desc)
static const command_line::arg_descriptor< std::string, false, true, 2 > arg_rpc_bind_port
static void init_options(boost::program_options::options_description &desc)
adds command line options to the given options set
bool addTCPSocket(boost::string_ref address, boost::string_ref port)
void try_init_and_run(boost::optional< unsigned > initial_port=boost::none)
Definition daemon.cpp:194
uint64_t get_height()
Definition daemon.cpp:371
void stop()
Definition daemon.cpp:292
void mine_blocks(size_t num_blocks, const std::string &miner_address)
Definition daemon.cpp:312
void stop_rpc()
Definition daemon.cpp:300
bool m_start_zmq
Definition daemon.h:89
void deinit()
Definition daemon.cpp:143
virtual ~mock_daemon()
Definition daemon.cpp:102
std::string rpc_addr() const
Definition daemon.h:150
std::atomic< bool > m_deinitalized
Definition daemon.h:98
boost::program_options::variables_map m_vm
Definition daemon.h:90
void stop_mining()
Definition daemon.cpp:361
void init_and_run()
Definition daemon.cpp:182
std::atomic< bool > m_terminated
Definition daemon.h:97
std::string m_zmq_bind_port
Definition daemon.h:94
std::atomic< bool > m_stopped
Definition daemon.h:96
std::string m_rpc_bind_port
Definition daemon.h:93
t_protocol_raw m_protocol
Definition daemon.h:82
t_node_server m_server
Definition daemon.h:84
static void default_options(boost::program_options::variables_map &vm)
Definition daemon.cpp:53
cryptonote::network_type m_network_type
Definition daemon.h:85
void stop_p2p()
Definition daemon.cpp:306
epee::net_utils::http::http_simple_client m_http_client
Definition daemon.h:86
boost::thread m_run_thread
Definition daemon.h:99
static void set_ports(boost::program_options::variables_map &vm, unsigned initial_port)
Definition daemon.cpp:85
void load_params(boost::program_options::variables_map const &vm)
Definition daemon.cpp:94
void start_mining(const std::string &miner_address, uint64_t threads_count=1, bool do_background_mining=false, bool ignore_battery=true)
Definition daemon.cpp:346
std::string m_p2p_bind_port
Definition daemon.h:92
void stop_and_deinit()
Definition daemon.cpp:188
void init()
Definition daemon.cpp:125
mock_rpc_daemon m_rpc_server
Definition daemon.h:83
static void init_options(boost::program_options::options_description &option_spec)
Definition daemon.cpp:43
static constexpr const std::chrono::seconds rpc_timeout
Definition daemon.h:79
bool m_start_p2p
Definition daemon.h:88
void run()
Definition daemon.cpp:222
bool run_main()
Definition daemon.cpp:227
cryptonote::core * m_core
Definition daemon.h:81
bool on_send_raw_tx_2(const cryptonote::COMMAND_RPC_SEND_RAW_TX::request &req, cryptonote::COMMAND_RPC_SEND_RAW_TX::response &res, const cryptonote::core_rpc_server::connection_context *ctx)
Definition daemon.cpp:36
static void init_options(boost::program_options::options_description &desc)
static void set_option(boost::program_options::variables_map &vm, const std::string &key, const boost::program_options::variable_value &pv)
#define CORE_RPC_STATUS_OK
#define CORE_RPC_STATUS_BUSY
const char * res
#define MERROR(x)
Definition misc_log_ex.h:73
#define MFATAL(x)
Definition misc_log_ex.h:72
#define MWARNING(x)
Definition misc_log_ex.h:74
#define MDEBUG(x)
Definition misc_log_ex.h:76
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
#define MINFO(x)
Definition misc_log_ex.h:75
void add_arg(boost::program_options::options_description &description, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg, bool unique=true)
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
const command_line::arg_descriptor< bool > arg_offline
const command_line::arg_descriptor< bool, false > arg_testnet_on
const command_line::arg_descriptor< std::string, false, true, 2 > arg_zmq_rpc_bind_port
const command_line::arg_descriptor< std::string > arg_zmq_rpc_bind_ip
boost::shared_ptr< call_befor_die_base > auto_scope_leave_caller
bool sleep_no_w(long ms)
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
bool invoke_http_json(const boost::string_ref uri, const t_request &out_struct, t_response &result_struct, t_transport &transport, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref method="GET")
const command_line::arg_descriptor< bool > arg_no_igd
Definition net_node.cpp:137
const command_line::arg_descriptor< std::string, false, true, 2 > arg_p2p_bind_port
Definition net_node.cpp:112
const command_line::arg_descriptor< std::string > arg_p2p_bind_ip
Definition net_node.cpp:111
const command_line::arg_descriptor< std::vector< std::string > > arg_p2p_add_exclusive_node
Definition net_node.cpp:129
STL namespace.
unsigned __int64 uint64_t
Definition stdint.h:136
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request