Line data Source code
1 : /**
2 : * Copyright (c) Libmonero
3 : *
4 : * Permission is hereby granted, free of charge, to any person obtaining a copy
5 : * of this software and associated documentation files (the "Software"), to deal
6 : * in the Software without restriction, including without limitation the rights
7 : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : * copies of the Software, and to permit persons to whom the Software is
9 : * furnished to do so, subject to the following conditions:
10 : *
11 : * The above copyright notice and this permission notice shall be included in all
12 : * copies or substantial portions of the Software.
13 : *
14 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 : * SOFTWARE.
21 : */
22 :
23 : #include "daemon/monero_c_daemon.h"
24 : #include "common/monero_c_common.h"
25 : #include "daemon/monero_daemon_model.h"
26 : #include "daemon/monero_daemon_rpc.h"
27 : #include "utils/gen_utils.h"
28 :
29 : #include "misc_language.h"
30 : #include "rapidjson/document.h"
31 : #include "rapidjson/stringbuffer.h"
32 : #include "rapidjson/writer.h"
33 :
34 : #include <algorithm>
35 : #include <boost/optional.hpp>
36 : #include <cstdio>
37 : #include <map>
38 : #include <memory>
39 : #include <mutex>
40 : #include <stdexcept>
41 : #include <string>
42 : #include <vector>
43 :
44 : struct monero_daemon_listener;
45 :
46 : namespace monero_c {
47 :
48 : // the handles of the listeners that are added to one daemon. get_listeners() reads this list, and not the set of monero-cpp, which holds the
49 : // adapters inside the handles: another thread can free a listener after the copy of that set, and the read of the adapter that follows would
50 : // be a read of freed memory. The handles are only compared and returned here, never read
51 : struct daemon_listener_registry {
52 : std::mutex mutex;
53 : std::vector<monero_daemon_listener*> handles;
54 :
55 253 : void add(monero_daemon_listener* handle) {
56 253 : std::lock_guard<std::mutex> lock(mutex);
57 253 : if (std::find(handles.begin(), handles.end(), handle) == handles.end()) handles.push_back(handle);
58 253 : }
59 :
60 250 : void remove(monero_daemon_listener* handle) {
61 250 : std::lock_guard<std::mutex> lock(mutex);
62 250 : handles.erase(std::remove(handles.begin(), handles.end(), handle), handles.end());
63 250 : }
64 :
65 7 : void clear() {
66 7 : std::lock_guard<std::mutex> lock(mutex);
67 7 : handles.clear();
68 7 : }
69 :
70 255 : std::vector<monero_daemon_listener*> copy() {
71 255 : std::lock_guard<std::mutex> lock(mutex);
72 510 : return handles;
73 255 : }
74 : };
75 :
76 : } // namespace monero_c
77 :
78 : // state behind a monero_daemon handle
79 : struct monero_daemon {
80 : std::shared_ptr<monero::monero_daemon_rpc> rpc;
81 : std::shared_ptr<monero_c::daemon_listener_registry> registry = std::make_shared<monero_c::daemon_listener_registry>();
82 : };
83 :
84 : namespace {
85 :
86 : using monero_c::array_of;
87 : using monero_c::check_json_depth;
88 : using monero_c::check_period_ms;
89 : using monero_c::dup_array;
90 : using monero_c::dup_string;
91 : using monero_c::guard;
92 : using monero_c::json_of_list;
93 : using monero_c::json_of_strings;
94 : using monero_c::optional_of;
95 : using monero_c::require;
96 : using monero_c::reset_out;
97 : using monero_c::safe_str;
98 : using monero_c::set_last_error;
99 : using monero_c::string_array;
100 :
101 : // monero-cpp lists the height of every block in the range before the first request, so a range
102 : // with no real end, such as UINT64_MAX, never finishes. The chunked variant has no such limit
103 : const uint64_t MAX_BLOCKS_BY_RANGE = 100000;
104 :
105 : // splits a JSON array into its elements, each serialized again as a JSON document
106 474 : std::vector<std::string> split_json_array(const std::string& json) {
107 474 : check_json_depth(json);
108 465 : rapidjson::Document doc;
109 465 : doc.Parse(json.c_str());
110 465 : if (doc.HasParseError() || !doc.IsArray()) throw std::invalid_argument("expected a JSON array");
111 :
112 174 : std::vector<std::string> items;
113 376 : for (const auto& value : doc.GetArray()) {
114 202 : rapidjson::StringBuffer buffer;
115 202 : rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
116 202 : value.Accept(writer);
117 202 : items.push_back(buffer.GetString());
118 376 : }
119 348 : return items;
120 465 : }
121 :
122 : // deserializes each element of a JSON array into a monero-cpp object
123 : template <class T>
124 474 : std::vector<std::shared_ptr<T>> parse_list(const std::string& json) {
125 474 : std::vector<std::shared_ptr<T>> items;
126 669 : for (const std::string& item : split_json_array(json)) {
127 195 : items.push_back(gen_utils::deserialize<T>(item));
128 : }
129 160 : return items;
130 314 : }
131 :
132 : // monero-cpp's monero_tx_backlog_entry has no fields yet, so each entry is an empty object
133 0 : std::string json_of_backlog(const std::vector<monero::monero_tx_backlog_entry>& entries) {
134 0 : std::string json = "[";
135 0 : for (size_t i = 0; i < entries.size(); i++) {
136 0 : if (i > 0) json += ",";
137 0 : json += "{}";
138 : }
139 0 : return json + "]";
140 0 : }
141 :
142 : // serializes one result object. A null result (the daemon has no such item) becomes NULL
143 : template <class T>
144 31 : char* dup_json(const std::shared_ptr<T>& item) {
145 31 : return item ? dup_string(item->serialize()) : nullptr;
146 : }
147 :
148 : // serializes one result object held by value
149 : template <class T>
150 1 : char* dup_json_value(const T& item) {
151 1 : return dup_string(item.serialize());
152 : }
153 :
154 : // the models of monero-cpp point to their parents with shared_ptr (a tx to its block, an input or an output to its tx), so a block
155 : // or a tx that nobody releases is never freed. release_models() resets those pointers once the result is serialized. monero_utils::free()
156 : // does it for the wallet models, and it leaves the miner tx of a block and the inputs and outputs of a plain tx
157 26 : void release_models(const std::shared_ptr<monero::monero_tx>& tx) {
158 26 : if (tx == nullptr) return;
159 26 : tx->m_block.reset();
160 46 : for (const std::shared_ptr<monero::monero_output>& input : tx->m_inputs) {
161 20 : if (input != nullptr) input->m_tx.reset();
162 : }
163 62 : for (const std::shared_ptr<monero::monero_output>& output : tx->m_outputs) {
164 36 : if (output != nullptr) output->m_tx.reset();
165 : }
166 : }
167 :
168 16 : void release_models(const std::shared_ptr<monero::monero_block>& block) {
169 16 : if (block == nullptr) return;
170 16 : release_models(block->m_miner_tx);
171 16 : for (const std::shared_ptr<monero::monero_tx>& tx : block->m_txs) release_models(tx);
172 : }
173 :
174 : template <class T>
175 15 : void release_models(const std::vector<std::shared_ptr<T>>& items) {
176 37 : for (const std::shared_ptr<T>& item : items) release_models(item);
177 15 : }
178 :
179 : // serializes one block or tx and then releases it, with a scope handler so that it also runs when the call throws
180 : template <class T>
181 4 : char* dup_json_released(const std::shared_ptr<T>& item) {
182 8 : auto release_item = epee::misc_utils::create_scope_leave_handler([&] { release_models(item); });
183 8 : return dup_json(item);
184 4 : }
185 :
186 : // serializes a list of blocks or txs and then releases them
187 : template <class T>
188 3 : char* dup_json_list_released(const std::vector<std::shared_ptr<T>>& items) {
189 6 : auto release_items = epee::misc_utils::create_scope_leave_handler([&] { release_models(items); });
190 6 : return dup_string(json_of_list(items));
191 3 : }
192 :
193 : // the blocks that hold txs of the daemon, so that each tx has its height and its timestamp. monero-cpp reads them into a block that each tx
194 : // has for itself, so the txs of one block are put in one block, in the order that the blocks first appear, and the txs that are in the
195 : // pool, which have no height, in one block that has none
196 11 : std::vector<std::shared_ptr<monero::monero_block>> blocks_of_txs(const std::vector<std::shared_ptr<monero::monero_tx>>& txs) {
197 11 : std::vector<std::shared_ptr<monero::monero_block>> blocks;
198 11 : std::map<uint64_t, std::shared_ptr<monero::monero_block>> confirmed;
199 11 : std::shared_ptr<monero::monero_block> pool;
200 21 : for (const std::shared_ptr<monero::monero_tx>& tx : txs) {
201 10 : if (tx == nullptr) continue;
202 10 : if (tx->m_block != nullptr && tx->m_block->m_height != boost::none) {
203 7 : std::shared_ptr<monero::monero_block>& block = confirmed[*tx->m_block->m_height];
204 7 : if (block == nullptr) {
205 6 : block = std::make_shared<monero::monero_block>();
206 6 : block->m_height = tx->m_block->m_height;
207 6 : block->m_timestamp = tx->m_block->m_timestamp;
208 6 : blocks.push_back(block);
209 : }
210 7 : block->m_txs.push_back(tx);
211 : } else {
212 3 : if (pool == nullptr) {
213 3 : pool = std::make_shared<monero::monero_block>();
214 3 : blocks.push_back(pool);
215 : }
216 3 : pool->m_txs.push_back(tx);
217 : }
218 : }
219 22 : return blocks;
220 11 : }
221 :
222 : // serializes txs as the blocks that hold them, {"blocks":[...]}, and releases them. The new blocks point to no parent, and they go when the
223 : // call returns
224 11 : char* dup_json_blocks_released(const std::vector<std::shared_ptr<monero::monero_tx>>& txs) {
225 22 : auto release_txs = epee::misc_utils::create_scope_leave_handler([&] { release_models(txs); });
226 22 : return dup_string("{\"blocks\":" + json_of_list(blocks_of_txs(txs)) + "}");
227 11 : }
228 :
229 : // converts monero-cpp's key image status to the C enum, which has the same values
230 2 : monero_key_image_spent_status to_c_status(monero::monero_key_image_spent_status status) {
231 2 : return static_cast<monero_key_image_spent_status>(static_cast<int>(status));
232 : }
233 :
234 : // forwards the daemon's block header notifications to the C callbacks of a listener
235 : class listener_adapter : public monero::monero_daemon_listener {
236 : public:
237 : monero_daemon_listener_callbacks callbacks = {};
238 :
239 1 : void on_block_header(const std::shared_ptr<monero::monero_block_header>& header) override {
240 1 : monero::monero_daemon_listener::on_block_header(header);
241 1 : if (callbacks.on_block_header == nullptr || !header) return;
242 1 : std::string json = header->serialize();
243 1 : callbacks.on_block_header(callbacks.user_data, json.c_str());
244 1 : }
245 : };
246 :
247 : } // namespace
248 :
249 : struct monero_daemon_listener {
250 : listener_adapter adapter;
251 : std::weak_ptr<monero::monero_daemon_rpc> registered_with;
252 : std::weak_ptr<monero_c::daemon_listener_registry> registry; // the list of the daemon that it is added to, set with registered_with
253 : std::mutex registration_mutex; // guards registered_with and registry, so the check and the registration in add_listener are one step
254 : };
255 :
256 : extern "C" {
257 :
258 : // ------------------------------ CONNECTION ----------------------------------
259 :
260 19 : monero_result monero_daemon_connect(const char* uri, const char* username, const char* password, const char* proxy_uri, uint32_t timeout_ms, monero_daemon** out_daemon) {
261 19 : reset_out(out_daemon);
262 19 : if (!require(out_daemon, "out_daemon")) return MONERO_ERROR;
263 16 : std::string uri_str = safe_str(uri);
264 16 : if (uri_str.empty()) { set_last_error("uri must not be empty"); return MONERO_ERROR; }
265 26 : return guard([&] {
266 13 : boost::optional<uint32_t> timeout;
267 13 : if (timeout_ms != 0) timeout = timeout_ms;
268 13 : std::unique_ptr<monero_daemon> daemon(new monero_daemon());
269 21 : daemon->rpc = std::make_shared<monero::monero_daemon_rpc>(uri_str, safe_str(username), safe_str(password), safe_str(proxy_uri), std::string(), timeout);
270 11 : *out_daemon = daemon.release();
271 26 : });
272 16 : }
273 :
274 15 : monero_result monero_daemon_connect_with(::monero_rpc_connection* connection, monero_daemon** out_daemon) {
275 15 : reset_out(out_daemon);
276 15 : if (!require(connection, "connection") || !require(out_daemon, "out_daemon")) return MONERO_ERROR;
277 20 : return guard([&] {
278 10 : std::unique_ptr<monero_daemon> daemon(new monero_daemon());
279 10 : daemon->rpc = std::make_shared<monero::monero_daemon_rpc>(monero_c::connection_of(connection));
280 10 : *out_daemon = daemon.release();
281 20 : });
282 : }
283 :
284 24 : void monero_daemon_free(monero_daemon* daemon) {
285 24 : delete daemon;
286 24 : }
287 :
288 9 : monero_result monero_daemon_get_rpc_connection(monero_daemon* daemon, char** out_json) {
289 9 : reset_out(out_json);
290 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
291 10 : return guard([&] { *out_json = dup_string(daemon->rpc->get_rpc_connection()->serialize()); });
292 : }
293 :
294 13 : monero_result monero_daemon_set_poll_period(monero_daemon* daemon, uint64_t period_ms) {
295 13 : if (!require(daemon, "daemon")) return MONERO_ERROR;
296 20 : return guard([&] {
297 10 : check_period_ms(period_ms);
298 6 : daemon->rpc->set_poll_period_in_ms(period_ms);
299 10 : });
300 : }
301 :
302 : // -------------------------------- LISTENERS ---------------------------------
303 :
304 256 : monero_result monero_daemon_listener_create(const monero_daemon_listener_callbacks* callbacks, monero_daemon_listener** out_listener) {
305 256 : reset_out(out_listener);
306 256 : if (!require(callbacks, "callbacks") || !require(out_listener, "out_listener")) return MONERO_ERROR;
307 500 : return guard([&] {
308 250 : std::unique_ptr<monero_daemon_listener> listener(new monero_daemon_listener());
309 250 : listener->adapter.callbacks = *callbacks;
310 250 : *out_listener = listener.release();
311 500 : });
312 : }
313 :
314 253 : void monero_daemon_listener_free(monero_daemon_listener* listener) {
315 253 : if (listener == nullptr) return;
316 250 : std::shared_ptr<monero::monero_daemon_rpc> rpc;
317 250 : std::shared_ptr<monero_c::daemon_listener_registry> registry;
318 : {
319 250 : std::lock_guard<std::mutex> lock(listener->registration_mutex);
320 250 : rpc = listener->registered_with.lock();
321 250 : registry = listener->registry.lock();
322 250 : }
323 250 : if (rpc) {
324 : try {
325 125 : rpc->remove_listener(listener->adapter);
326 0 : } catch (...) {
327 : // release the listener either way, since the caller can't act on a failed removal
328 0 : }
329 : }
330 250 : if (registry) registry->remove(listener);
331 250 : delete listener;
332 250 : }
333 :
334 261 : monero_result monero_daemon_add_listener(monero_daemon* daemon, monero_daemon_listener* listener) {
335 261 : if (!require(daemon, "daemon") || !require(listener, "listener")) return MONERO_ERROR;
336 510 : return guard([&] {
337 : // free unregisters from one daemon only, so a listener can't be registered with two
338 255 : std::lock_guard<std::mutex> lock(listener->registration_mutex);
339 255 : std::shared_ptr<monero::monero_daemon_rpc> current = listener->registered_with.lock();
340 : // remove_listeners() of that daemon leaves the link of the listener as it was, so the set of the daemon says if it still holds it
341 255 : if (current && current != daemon->rpc && current->get_listeners().count(&listener->adapter) != 0) throw std::runtime_error("listener is already registered with another daemon");
342 253 : daemon->rpc->add_listener(listener->adapter);
343 253 : listener->registered_with = daemon->rpc;
344 253 : listener->registry = daemon->registry;
345 253 : daemon->registry->add(listener);
346 512 : });
347 : }
348 :
349 129 : monero_result monero_daemon_remove_listener(monero_daemon* daemon, monero_daemon_listener* listener) {
350 129 : if (!require(daemon, "daemon") || !require(listener, "listener")) return MONERO_ERROR;
351 250 : return guard([&] {
352 : // remove_listener waits for callbacks, so the lock is taken after it returns
353 125 : daemon->rpc->remove_listener(listener->adapter);
354 125 : daemon->registry->remove(listener);
355 125 : std::lock_guard<std::mutex> lock(listener->registration_mutex);
356 125 : if (listener->registered_with.lock() == daemon->rpc) {
357 125 : listener->registered_with.reset();
358 125 : listener->registry.reset();
359 : }
360 250 : });
361 : }
362 :
363 263 : monero_result monero_daemon_get_listeners(monero_daemon* daemon, monero_daemon_listener*** out_listeners, size_t* out_count) {
364 263 : reset_out(out_listeners);
365 263 : reset_out(out_count);
366 263 : if (!require(daemon, "daemon") || !require(out_listeners, "out_listeners") || !require(out_count, "out_count")) return MONERO_ERROR;
367 510 : return guard([&] { *out_listeners = dup_array(daemon->registry->copy(), out_count); });
368 : }
369 :
370 10 : monero_result monero_daemon_remove_listeners(monero_daemon* daemon) {
371 10 : if (!require(daemon, "daemon")) return MONERO_ERROR;
372 14 : return guard([&] {
373 7 : daemon->rpc->remove_listeners();
374 7 : daemon->registry->clear();
375 7 : });
376 : }
377 :
378 : // ---------------------------------- GENERAL ---------------------------------
379 :
380 9 : monero_result monero_daemon_get_version(monero_daemon* daemon, char** out_json) {
381 9 : reset_out(out_json);
382 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
383 8 : return guard([&] { *out_json = dup_json_value(daemon->rpc->get_version()); });
384 : }
385 :
386 9 : monero_result monero_daemon_is_trusted(monero_daemon* daemon, bool* out_trusted) {
387 9 : if (!require(daemon, "daemon") || !require(out_trusted, "out_trusted")) return MONERO_ERROR;
388 8 : return guard([&] { *out_trusted = daemon->rpc->is_trusted(); });
389 : }
390 :
391 258 : monero_result monero_daemon_get_height(monero_daemon* daemon, uint64_t* out_height) {
392 258 : if (!require(daemon, "daemon") || !require(out_height, "out_height")) return MONERO_ERROR;
393 502 : return guard([&] { *out_height = daemon->rpc->get_height(); });
394 : }
395 :
396 12 : monero_result monero_daemon_get_block_hash(monero_daemon* daemon, uint64_t height, char** out_hash) {
397 12 : reset_out(out_hash);
398 12 : if (!require(daemon, "daemon") || !require(out_hash, "out_hash")) return MONERO_ERROR;
399 12 : return guard([&] { *out_hash = dup_string(daemon->rpc->get_block_hash(height)); });
400 : }
401 :
402 12 : monero_result monero_daemon_get_info(monero_daemon* daemon, char** out_json) {
403 12 : reset_out(out_json);
404 12 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
405 12 : return guard([&] { *out_json = dup_json(daemon->rpc->get_info()); });
406 : }
407 :
408 9 : monero_result monero_daemon_get_sync_info(monero_daemon* daemon, char** out_json) {
409 9 : reset_out(out_json);
410 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
411 8 : return guard([&] { *out_json = dup_json(daemon->rpc->get_sync_info()); });
412 : }
413 :
414 9 : monero_result monero_daemon_get_network_stats(monero_daemon* daemon, char** out_json) {
415 9 : reset_out(out_json);
416 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
417 8 : return guard([&] { *out_json = dup_json(daemon->rpc->get_network_stats()); });
418 : }
419 :
420 9 : monero_result monero_daemon_get_hard_fork_info(monero_daemon* daemon, char** out_json) {
421 9 : reset_out(out_json);
422 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
423 8 : return guard([&] { *out_json = dup_json(daemon->rpc->get_hard_fork_info()); });
424 : }
425 :
426 9 : monero_result monero_daemon_get_alt_chains(monero_daemon* daemon, char** out_json) {
427 9 : reset_out(out_json);
428 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
429 8 : return guard([&] { *out_json = dup_string(json_of_list(daemon->rpc->get_alt_chains())); });
430 : }
431 :
432 9 : monero_result monero_daemon_get_alt_block_hashes(monero_daemon* daemon, char** out_json) {
433 9 : reset_out(out_json);
434 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
435 8 : return guard([&] { *out_json = dup_string(json_of_strings(daemon->rpc->get_alt_block_hashes())); });
436 : }
437 :
438 : // ---------------------------------- MINING ----------------------------------
439 :
440 11 : monero_result monero_daemon_get_block_template(monero_daemon* daemon, const char* wallet_address, const int32_t* reserve_size, char** out_json) {
441 11 : reset_out(out_json);
442 11 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
443 17 : return guard([&] { *out_json = dup_json(daemon->rpc->get_block_template(safe_str(wallet_address), optional_of(reserve_size))); });
444 : }
445 :
446 9 : monero_result monero_daemon_get_miner_data(monero_daemon* daemon, char** out_json) {
447 9 : reset_out(out_json);
448 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
449 8 : return guard([&] { *out_json = dup_json(daemon->rpc->get_miner_data()); });
450 : }
451 :
452 11 : monero_result monero_daemon_calculate_pow(monero_daemon* daemon, uint32_t major_version, uint64_t height, const char* block_blob, const char* seed_hash, char** out_pow_hash) {
453 11 : reset_out(out_pow_hash);
454 11 : if (!require(daemon, "daemon") || !require(out_pow_hash, "out_pow_hash")) return MONERO_ERROR;
455 22 : return guard([&] { *out_pow_hash = dup_string(daemon->rpc->calculate_pow(major_version, height, safe_str(block_blob), safe_str(seed_hash))); });
456 : }
457 :
458 162 : monero_result monero_daemon_add_auxiliary_pow(monero_daemon* daemon, const char* block_template_blob, const char* aux_pow_json, char** out_json) {
459 162 : reset_out(out_json);
460 162 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
461 314 : return guard([&] {
462 440 : *out_json = dup_json(daemon->rpc->add_auxiliary_pow(safe_str(block_template_blob), parse_list<monero::monero_auxiliary_pow>(safe_str(aux_pow_json))));
463 157 : });
464 : }
465 :
466 9 : monero_result monero_daemon_get_mining_status(monero_daemon* daemon, char** out_json) {
467 9 : reset_out(out_json);
468 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
469 8 : return guard([&] { *out_json = dup_json(daemon->rpc->get_mining_status()); });
470 : }
471 :
472 11 : monero_result monero_daemon_start_mining(monero_daemon* daemon, const char* address, const uint64_t* num_threads, const bool* is_background, const bool* ignore_battery) {
473 11 : if (!require(daemon, "daemon")) return MONERO_ERROR;
474 16 : return guard([&] { daemon->rpc->start_mining(safe_str(address), optional_of(num_threads), optional_of(is_background), optional_of(ignore_battery)); });
475 : }
476 :
477 7 : monero_result monero_daemon_stop_mining(monero_daemon* daemon) {
478 7 : if (!require(daemon, "daemon")) return MONERO_ERROR;
479 8 : return guard([&] { daemon->rpc->stop_mining(); });
480 : }
481 :
482 17 : monero_result monero_daemon_generate_blocks(monero_daemon* daemon, const char* wallet_address, uint64_t num_blocks, const char* prev_block_hash, const uint32_t* starting_nonce, char** out_json) {
483 17 : reset_out(out_json);
484 17 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
485 24 : return guard([&] {
486 12 : boost::optional<std::string> prev_hash;
487 12 : if (prev_block_hash != nullptr) prev_hash = std::string(prev_block_hash);
488 18 : *out_json = dup_json(daemon->rpc->generate_blocks(safe_str(wallet_address), num_blocks, prev_hash, optional_of(starting_nonce)));
489 24 : });
490 : }
491 :
492 8 : monero_result monero_daemon_submit_block(monero_daemon* daemon, const char* block_blob) {
493 8 : if (!require(daemon, "daemon")) return MONERO_ERROR;
494 10 : return guard([&] { daemon->rpc->submit_block(safe_str(block_blob)); });
495 : }
496 :
497 11 : monero_result monero_daemon_submit_blocks(monero_daemon* daemon, const char* const* block_blobs, size_t num_block_blobs) {
498 11 : if (!require(daemon, "daemon")) return MONERO_ERROR;
499 16 : return guard([&] { daemon->rpc->submit_blocks(string_array(block_blobs, num_block_blobs, "block_blobs")); });
500 : }
501 :
502 : // ----------------------------------- BLOCKS ---------------------------------
503 :
504 9 : monero_result monero_daemon_get_last_block_header(monero_daemon* daemon, char** out_json) {
505 9 : reset_out(out_json);
506 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
507 8 : return guard([&] { *out_json = dup_json(daemon->rpc->get_last_block_header()); });
508 : }
509 :
510 160 : monero_result monero_daemon_get_block_header_by_hash(monero_daemon* daemon, const char* block_hash, char** out_json) {
511 160 : reset_out(out_json);
512 160 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
513 464 : return guard([&] { *out_json = dup_json(daemon->rpc->get_block_header_by_hash(safe_str(block_hash))); });
514 : }
515 :
516 9 : monero_result monero_daemon_get_block_header_by_height(monero_daemon* daemon, uint64_t height, char** out_json) {
517 9 : reset_out(out_json);
518 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
519 8 : return guard([&] { *out_json = dup_json(daemon->rpc->get_block_header_by_height(height)); });
520 : }
521 :
522 9 : monero_result monero_daemon_get_block_headers_by_range(monero_daemon* daemon, uint64_t start_height, uint64_t end_height, char** out_json) {
523 9 : reset_out(out_json);
524 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
525 8 : return guard([&] { *out_json = dup_string(json_of_list(daemon->rpc->get_block_headers_by_range(start_height, end_height))); });
526 : }
527 :
528 11 : monero_result monero_daemon_get_block_by_hash(monero_daemon* daemon, const char* block_hash, char** out_json) {
529 11 : reset_out(out_json);
530 11 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
531 16 : return guard([&] { *out_json = dup_json_released(daemon->rpc->get_block_by_hash(safe_str(block_hash))); });
532 : }
533 :
534 13 : monero_result monero_daemon_get_blocks_by_hash(monero_daemon* daemon, const char* const* block_hashes, size_t num_block_hashes, uint64_t start_height, bool prune, uint64_t max_block_count, char** out_json) {
535 13 : reset_out(out_json);
536 13 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
537 16 : return guard([&] {
538 13 : auto result = daemon->rpc->get_blocks_by_hash(string_array(block_hashes, num_block_hashes, "block_hashes"), start_height, prune, max_block_count);
539 2 : auto release_result = epee::misc_utils::create_scope_leave_handler([&] { if (result != nullptr) release_models(result->m_blocks); });
540 1 : *out_json = dup_json(result);
541 9 : });
542 : }
543 :
544 10 : monero_result monero_daemon_get_block_by_height(monero_daemon* daemon, uint64_t height, char** out_json) {
545 10 : reset_out(out_json);
546 10 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
547 10 : return guard([&] { *out_json = dup_json_released(daemon->rpc->get_block_by_height(height)); });
548 : }
549 :
550 12 : monero_result monero_daemon_get_blocks_by_height(monero_daemon* daemon, const uint64_t* heights, size_t num_heights, char** out_json) {
551 12 : reset_out(out_json);
552 12 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
553 19 : return guard([&] { *out_json = dup_json_list_released(daemon->rpc->get_blocks_by_height(array_of(heights, num_heights, "heights"))); });
554 : }
555 :
556 19 : monero_result monero_daemon_get_blocks_by_range(monero_daemon* daemon, const uint64_t* start_height, const uint64_t* end_height, char** out_json) {
557 19 : reset_out(out_json);
558 19 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
559 28 : return guard([&] {
560 14 : uint64_t start = start_height != nullptr ? *start_height : 0;
561 14 : if (end_height != nullptr && *end_height >= start && *end_height - start >= MAX_BLOCKS_BY_RANGE) {
562 4 : throw std::invalid_argument("range is longer than " + std::to_string(MAX_BLOCKS_BY_RANGE) + " blocks, use monero_daemon_get_blocks_by_range_chunked()");
563 : }
564 10 : *out_json = dup_json_list_released(daemon->rpc->get_blocks_by_range(optional_of(start_height), optional_of(end_height)));
565 15 : });
566 : }
567 :
568 12 : monero_result monero_daemon_get_blocks_by_range_chunked(monero_daemon* daemon, const uint64_t* start_height, const uint64_t* end_height, const uint64_t* max_chunk_size, char** out_json) {
569 12 : reset_out(out_json);
570 12 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
571 14 : return guard([&] {
572 7 : *out_json = dup_json_list_released(daemon->rpc->get_blocks_by_range_chunked(optional_of(start_height), optional_of(end_height), optional_of(max_chunk_size)));
573 8 : });
574 : }
575 :
576 13 : monero_result monero_daemon_get_block_hashes(monero_daemon* daemon, const char* const* block_hashes, size_t num_block_hashes, char** out_json) {
577 13 : reset_out(out_json);
578 13 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
579 20 : return guard([&] { *out_json = dup_json(daemon->rpc->get_block_hashes(string_array(block_hashes, num_block_hashes, "block_hashes"))); });
580 : }
581 :
582 6 : monero_result monero_daemon_wait_for_next_block_header(monero_daemon* daemon, char** out_json) {
583 6 : reset_out(out_json);
584 6 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
585 2 : return guard([&] { *out_json = dup_json(daemon->rpc->wait_for_next_block_header()); });
586 : }
587 :
588 : // ---------------------------- TRANSACTIONS ----------------------------------
589 :
590 14 : monero_result monero_daemon_get_tx(monero_daemon* daemon, const char* tx_hash, bool prune, char** out_json) {
591 14 : reset_out(out_json);
592 14 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
593 18 : return guard([&] {
594 13 : std::shared_ptr<monero::monero_tx> tx = daemon->rpc->get_tx(safe_str(tx_hash), prune);
595 11 : if (tx != nullptr) *out_json = dup_json_blocks_released({tx});
596 17 : });
597 : }
598 :
599 16 : monero_result monero_daemon_get_txs(monero_daemon* daemon, const char* const* tx_hashes, size_t num_tx_hashes, bool prune, char** out_json) {
600 16 : reset_out(out_json);
601 16 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
602 27 : return guard([&] { *out_json = dup_json_blocks_released(daemon->rpc->get_txs(string_array(tx_hashes, num_tx_hashes, "tx_hashes"), prune)); });
603 : }
604 :
605 160 : monero_result monero_daemon_get_tx_hex(monero_daemon* daemon, const char* tx_hash, bool prune, char** out_tx_hex) {
606 160 : reset_out(out_tx_hex);
607 160 : if (!require(daemon, "daemon") || !require(out_tx_hex, "out_tx_hex")) return MONERO_ERROR;
608 310 : return guard([&] {
609 309 : boost::optional<std::string> hex = daemon->rpc->get_tx_hex(safe_str(tx_hash), prune);
610 1 : *out_tx_hex = hex ? dup_string(*hex) : nullptr;
611 156 : });
612 : }
613 :
614 13 : monero_result monero_daemon_get_tx_hexes(monero_daemon* daemon, const char* const* tx_hashes, size_t num_tx_hashes, bool prune, char** out_json) {
615 13 : reset_out(out_json);
616 13 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
617 21 : return guard([&] { *out_json = dup_string(json_of_strings(daemon->rpc->get_tx_hexes(string_array(tx_hashes, num_tx_hashes, "tx_hashes"), prune))); });
618 : }
619 :
620 9 : monero_result monero_daemon_get_miner_tx_sum(monero_daemon* daemon, uint64_t height, uint64_t num_blocks, char** out_json) {
621 9 : reset_out(out_json);
622 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
623 8 : return guard([&] { *out_json = dup_json(daemon->rpc->get_miner_tx_sum(height, num_blocks)); });
624 : }
625 :
626 9 : monero_result monero_daemon_get_fee_estimate(monero_daemon* daemon, uint64_t grace_blocks, char** out_json) {
627 9 : reset_out(out_json);
628 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
629 8 : return guard([&] { *out_json = dup_json(daemon->rpc->get_fee_estimate(grace_blocks)); });
630 : }
631 :
632 10 : monero_result monero_daemon_submit_tx_hex(monero_daemon* daemon, const char* tx_hex, bool do_not_relay, char** out_json) {
633 10 : reset_out(out_json);
634 10 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
635 14 : return guard([&] { *out_json = dup_json(daemon->rpc->submit_tx_hex(safe_str(tx_hex), do_not_relay)); });
636 : }
637 :
638 158 : monero_result monero_daemon_relay_tx_by_hash(monero_daemon* daemon, const char* tx_hash) {
639 158 : if (!require(daemon, "daemon")) return MONERO_ERROR;
640 310 : return guard([&] { daemon->rpc->relay_tx_by_hash(safe_str(tx_hash)); });
641 : }
642 :
643 11 : monero_result monero_daemon_relay_txs_by_hash(monero_daemon* daemon, const char* const* tx_hashes, size_t num_tx_hashes) {
644 11 : if (!require(daemon, "daemon")) return MONERO_ERROR;
645 16 : return guard([&] { daemon->rpc->relay_txs_by_hash(string_array(tx_hashes, num_tx_hashes, "tx_hashes")); });
646 : }
647 :
648 : // -------------------------------- TX POOL -----------------------------------
649 :
650 12 : monero_result monero_daemon_get_tx_pool(monero_daemon* daemon, char** out_json) {
651 12 : reset_out(out_json);
652 12 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
653 14 : return guard([&] { *out_json = dup_json_blocks_released(daemon->rpc->get_tx_pool()); });
654 : }
655 :
656 9 : monero_result monero_daemon_get_tx_pool_hashes(monero_daemon* daemon, char** out_json) {
657 9 : reset_out(out_json);
658 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
659 8 : return guard([&] { *out_json = dup_string(json_of_strings(daemon->rpc->get_tx_pool_hashes())); });
660 : }
661 :
662 11 : monero_result monero_daemon_get_tx_pool_backlog(monero_daemon* daemon, char** out_json) {
663 11 : reset_out(out_json);
664 11 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
665 12 : return guard([&] { *out_json = dup_string(json_of_backlog(daemon->rpc->get_tx_pool_backlog())); });
666 : }
667 :
668 9 : monero_result monero_daemon_get_tx_pool_stats(monero_daemon* daemon, char** out_json) {
669 9 : reset_out(out_json);
670 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
671 8 : return guard([&] { *out_json = dup_json(daemon->rpc->get_tx_pool_stats()); });
672 : }
673 :
674 7 : monero_result monero_daemon_flush_tx_pool(monero_daemon* daemon) {
675 7 : if (!require(daemon, "daemon")) return MONERO_ERROR;
676 8 : return guard([&] { daemon->rpc->flush_tx_pool(); });
677 : }
678 :
679 11 : monero_result monero_daemon_flush_tx_pool_hashes(monero_daemon* daemon, const char* const* tx_hashes, size_t num_tx_hashes) {
680 11 : if (!require(daemon, "daemon")) return MONERO_ERROR;
681 16 : return guard([&] { daemon->rpc->flush_tx_pool(string_array(tx_hashes, num_tx_hashes, "tx_hashes")); });
682 : }
683 :
684 158 : monero_result monero_daemon_flush_tx_pool_hash(monero_daemon* daemon, const char* tx_hash) {
685 158 : if (!require(daemon, "daemon")) return MONERO_ERROR;
686 310 : return guard([&] { daemon->rpc->flush_tx_pool(safe_str(tx_hash)); });
687 : }
688 :
689 : // --------------------------- KEY IMAGES AND OUTPUTS -------------------------
690 :
691 10 : monero_result monero_daemon_get_key_image_spent_status(monero_daemon* daemon, const char* key_image, monero_key_image_spent_status* out_status) {
692 10 : if (!require(daemon, "daemon") || !require(out_status, "out_status")) return MONERO_ERROR;
693 10 : return guard([&] { *out_status = to_c_status(daemon->rpc->get_key_image_spent_status(safe_str(key_image))); });
694 : }
695 :
696 17 : monero_result monero_daemon_get_key_image_spent_statuses(monero_daemon* daemon, const char* const* key_images, size_t num_key_images, monero_key_image_spent_status** out_statuses, size_t* out_count) {
697 17 : reset_out(out_statuses);
698 17 : reset_out(out_count);
699 17 : if (!require(daemon, "daemon") || !require(out_statuses, "out_statuses") || !require(out_count, "out_count")) return MONERO_ERROR;
700 18 : return guard([&] {
701 9 : std::vector<monero_key_image_spent_status> statuses;
702 15 : for (monero::monero_key_image_spent_status status : daemon->rpc->get_key_image_spent_statuses(string_array(key_images, num_key_images, "key_images"))) {
703 1 : statuses.push_back(to_c_status(status));
704 1 : }
705 1 : *out_statuses = dup_array(statuses, out_count);
706 18 : });
707 : }
708 :
709 14 : monero_result monero_daemon_get_output_indices(monero_daemon* daemon, const char* tx_hash, uint64_t** out_indices, size_t* out_count) {
710 14 : reset_out(out_indices);
711 14 : reset_out(out_count);
712 14 : if (!require(daemon, "daemon") || !require(out_indices, "out_indices") || !require(out_count, "out_count")) return MONERO_ERROR;
713 15 : return guard([&] { *out_indices = dup_array(daemon->rpc->get_output_indices(safe_str(tx_hash)), out_count); });
714 : }
715 :
716 162 : monero_result monero_daemon_get_outputs(monero_daemon* daemon, const char* outputs_json, char** out_json) {
717 162 : reset_out(out_json);
718 162 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
719 314 : return guard([&] {
720 157 : std::vector<monero::monero_output> outputs;
721 311 : for (const auto& output : parse_list<monero::monero_output>(safe_str(outputs_json))) outputs.push_back(*output);
722 66 : *out_json = dup_string(json_of_list(daemon->rpc->get_outputs(outputs)));
723 314 : });
724 : }
725 :
726 16 : monero_result monero_daemon_get_output_histogram(monero_daemon* daemon, const uint64_t* amounts, size_t num_amounts, const int32_t* min_count, const int32_t* max_count, const bool* is_unlocked, const int32_t* recent_cutoff, char** out_json) {
727 16 : reset_out(out_json);
728 16 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
729 22 : return guard([&] {
730 19 : *out_json = dup_string(json_of_list(daemon->rpc->get_output_histogram(array_of(amounts, num_amounts, "amounts"), optional_of(min_count), optional_of(max_count), optional_of(is_unlocked), optional_of(recent_cutoff))));
731 12 : });
732 : }
733 :
734 15 : monero_result monero_daemon_get_output_distribution(monero_daemon* daemon, const uint64_t* amounts, size_t num_amounts, const bool* is_cumulative, const uint64_t* start_height, const uint64_t* end_height, char** out_json) {
735 15 : reset_out(out_json);
736 15 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
737 20 : return guard([&] {
738 18 : *out_json = dup_string(json_of_list(daemon->rpc->get_output_distribution(array_of(amounts, num_amounts, "amounts"), optional_of(is_cumulative), optional_of(start_height), optional_of(end_height))));
739 11 : });
740 : }
741 :
742 : // ---------------------------------- BANDWIDTH -------------------------------
743 :
744 9 : monero_result monero_daemon_get_download_limit(monero_daemon* daemon, int32_t* out_limit) {
745 9 : if (!require(daemon, "daemon") || !require(out_limit, "out_limit")) return MONERO_ERROR;
746 8 : return guard([&] { *out_limit = daemon->rpc->get_download_limit(); });
747 : }
748 :
749 9 : monero_result monero_daemon_set_download_limit(monero_daemon* daemon, int32_t limit, int32_t* out_limit) {
750 9 : if (!require(daemon, "daemon") || !require(out_limit, "out_limit")) return MONERO_ERROR;
751 8 : return guard([&] { *out_limit = daemon->rpc->set_download_limit(limit); });
752 : }
753 :
754 9 : monero_result monero_daemon_reset_download_limit(monero_daemon* daemon, int32_t* out_limit) {
755 9 : if (!require(daemon, "daemon") || !require(out_limit, "out_limit")) return MONERO_ERROR;
756 8 : return guard([&] { *out_limit = daemon->rpc->reset_download_limit(); });
757 : }
758 :
759 9 : monero_result monero_daemon_get_upload_limit(monero_daemon* daemon, int32_t* out_limit) {
760 9 : if (!require(daemon, "daemon") || !require(out_limit, "out_limit")) return MONERO_ERROR;
761 8 : return guard([&] { *out_limit = daemon->rpc->get_upload_limit(); });
762 : }
763 :
764 9 : monero_result monero_daemon_set_upload_limit(monero_daemon* daemon, int32_t limit, int32_t* out_limit) {
765 9 : if (!require(daemon, "daemon") || !require(out_limit, "out_limit")) return MONERO_ERROR;
766 8 : return guard([&] { *out_limit = daemon->rpc->set_upload_limit(limit); });
767 : }
768 :
769 9 : monero_result monero_daemon_reset_upload_limit(monero_daemon* daemon, int32_t* out_limit) {
770 9 : if (!require(daemon, "daemon") || !require(out_limit, "out_limit")) return MONERO_ERROR;
771 8 : return guard([&] { *out_limit = daemon->rpc->reset_upload_limit(); });
772 : }
773 :
774 : // ----------------------------------- PEERS ----------------------------------
775 :
776 9 : monero_result monero_daemon_get_peers(monero_daemon* daemon, char** out_json) {
777 9 : reset_out(out_json);
778 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
779 8 : return guard([&] { *out_json = dup_string(json_of_list(daemon->rpc->get_peers())); });
780 : }
781 :
782 9 : monero_result monero_daemon_get_known_peers(monero_daemon* daemon, char** out_json) {
783 9 : reset_out(out_json);
784 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
785 8 : return guard([&] { *out_json = dup_string(json_of_list(daemon->rpc->get_known_peers())); });
786 : }
787 :
788 9 : monero_result monero_daemon_get_public_peers(monero_daemon* daemon, bool include_offline, char** out_json) {
789 9 : reset_out(out_json);
790 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
791 8 : return guard([&] { *out_json = dup_string(json_of_list(daemon->rpc->get_public_peers(include_offline))); });
792 : }
793 :
794 7 : monero_result monero_daemon_set_outgoing_peer_limit(monero_daemon* daemon, int32_t limit) {
795 7 : if (!require(daemon, "daemon")) return MONERO_ERROR;
796 8 : return guard([&] { daemon->rpc->set_outgoing_peer_limit(limit); });
797 : }
798 :
799 7 : monero_result monero_daemon_set_incoming_peer_limit(monero_daemon* daemon, int32_t limit) {
800 7 : if (!require(daemon, "daemon")) return MONERO_ERROR;
801 8 : return guard([&] { daemon->rpc->set_incoming_peer_limit(limit); });
802 : }
803 :
804 9 : monero_result monero_daemon_get_peer_bans(monero_daemon* daemon, char** out_json) {
805 9 : reset_out(out_json);
806 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
807 8 : return guard([&] { *out_json = dup_string(json_of_list(daemon->rpc->get_peer_bans())); });
808 : }
809 :
810 163 : monero_result monero_daemon_set_peer_bans(monero_daemon* daemon, const char* bans_json) {
811 163 : if (!require(daemon, "daemon")) return MONERO_ERROR;
812 509 : return guard([&] { daemon->rpc->set_peer_bans(parse_list<monero::monero_ban>(safe_str(bans_json))); });
813 : }
814 :
815 161 : monero_result monero_daemon_set_peer_ban(monero_daemon* daemon, const char* ban_json) {
816 161 : if (!require(daemon, "daemon")) return MONERO_ERROR;
817 316 : return guard([&] {
818 158 : std::string json = safe_str(ban_json);
819 158 : check_json_depth(json);
820 189 : daemon->rpc->set_peer_ban(gen_utils::deserialize<monero::monero_ban>(json));
821 316 : });
822 : }
823 :
824 12 : monero_result monero_daemon_get_peer_ban(monero_daemon* daemon, const char* address, char** out_json) {
825 12 : reset_out(out_json);
826 12 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
827 19 : return guard([&] { *out_json = dup_json(daemon->rpc->get_peer_ban(safe_str(address))); });
828 : }
829 :
830 : // ----------------------------------- ADMIN ----------------------------------
831 :
832 9 : monero_result monero_daemon_prune_blockchain(monero_daemon* daemon, bool check, char** out_json) {
833 9 : reset_out(out_json);
834 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
835 8 : return guard([&] { *out_json = dup_json(daemon->rpc->prune_blockchain(check)); });
836 : }
837 :
838 7 : monero_result monero_daemon_save_blockchain(monero_daemon* daemon) {
839 7 : if (!require(daemon, "daemon")) return MONERO_ERROR;
840 8 : return guard([&] { daemon->rpc->save_blockchain(); });
841 : }
842 :
843 9 : monero_result monero_daemon_pop_blocks(monero_daemon* daemon, uint64_t num_blocks, uint64_t* out_height) {
844 9 : if (!require(daemon, "daemon") || !require(out_height, "out_height")) return MONERO_ERROR;
845 8 : return guard([&] { *out_height = daemon->rpc->pop_blocks(num_blocks); });
846 : }
847 :
848 7 : monero_result monero_daemon_flush_cache(monero_daemon* daemon, bool bad_blocks) {
849 7 : if (!require(daemon, "daemon")) return MONERO_ERROR;
850 8 : return guard([&] { daemon->rpc->flush_cache(bad_blocks); });
851 : }
852 :
853 161 : monero_result monero_daemon_set_bootstrap_daemon(monero_daemon* daemon, const char* address, const char* username, const char* password, const char* proxy) {
854 161 : if (!require(daemon, "daemon")) return MONERO_ERROR;
855 787 : return guard([&] { daemon->rpc->set_bootstrap_daemon(safe_str(address), safe_str(username), safe_str(password), safe_str(proxy)); });
856 : }
857 :
858 7 : monero_result monero_daemon_remove_bootstrap_daemon(monero_daemon* daemon) {
859 7 : if (!require(daemon, "daemon")) return MONERO_ERROR;
860 8 : return guard([&] { daemon->rpc->remove_bootstrap_daemon(); });
861 : }
862 :
863 9 : monero_result monero_daemon_set_log_hash_rate(monero_daemon* daemon, bool is_visible) {
864 9 : if (!require(daemon, "daemon")) return MONERO_ERROR;
865 12 : return guard([&] { daemon->rpc->set_log_hash_rate(is_visible); });
866 : }
867 :
868 7 : monero_result monero_daemon_set_log_level(monero_daemon* daemon, int32_t level) {
869 7 : if (!require(daemon, "daemon")) return MONERO_ERROR;
870 8 : return guard([&] { daemon->rpc->set_log_level(level); });
871 : }
872 :
873 10 : monero_result monero_daemon_set_log_categories(monero_daemon* daemon, const char* categories, char** out_categories) {
874 10 : reset_out(out_categories);
875 10 : if (!require(daemon, "daemon") || !require(out_categories, "out_categories")) return MONERO_ERROR;
876 14 : return guard([&] { *out_categories = dup_string(daemon->rpc->set_log_categories(safe_str(categories))); });
877 : }
878 :
879 8 : monero_result monero_daemon_check_for_update(monero_daemon* daemon, char** out_json) {
880 8 : reset_out(out_json);
881 8 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
882 6 : return guard([&] { *out_json = dup_json(daemon->rpc->check_for_update()); });
883 : }
884 :
885 9 : monero_result monero_daemon_download_update(monero_daemon* daemon, const char* path, char** out_json) {
886 9 : reset_out(out_json);
887 9 : if (!require(daemon, "daemon") || !require(out_json, "out_json")) return MONERO_ERROR;
888 12 : return guard([&] { *out_json = dup_json(daemon->rpc->download_update(safe_str(path))); });
889 : }
890 :
891 6 : monero_result monero_daemon_stop(monero_daemon* daemon) {
892 6 : if (!require(daemon, "daemon")) return MONERO_ERROR;
893 6 : return guard([&] { daemon->rpc->stop(); });
894 : }
895 :
896 : } // extern "C"
|