Electroneum
Loading...
Searching...
No Matches
daemon_handler.cpp
Go to the documentation of this file.
1// Copyright (c) 2017-2019, 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_handler.h"
30
31// likely included by daemon_handler.h's includes,
32// but including here for clarity
36#include "ringct/rctSigs.h"
37#include "version.h"
38
39namespace cryptonote
40{
41
42namespace rpc
43{
44
45 void DaemonHandler::handle(const GetHeight::Request& req, GetHeight::Response& res)
46 {
47 res.height = m_core.get_current_blockchain_height();
48
49 res.status = Message::STATUS_OK;
50 }
51
52 void DaemonHandler::handle(const GetBlocksFast::Request& req, GetBlocksFast::Response& res)
53 {
54 std::vector<std::pair<std::pair<blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, blobdata> > > > blocks;
55
56 if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, blocks, res.current_height, res.start_height, req.prune, true, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
57 {
59 res.error_details = "core::find_blockchain_supplement() returned false";
60 return;
61 }
62
63 res.blocks.resize(blocks.size());
64 res.output_indices.resize(blocks.size());
65
66 auto it = blocks.begin();
67
68 uint64_t block_count = 0;
69 while (it != blocks.end())
70 {
71 cryptonote::rpc::block_with_transactions& bwt = res.blocks[block_count];
72
73 if (!parse_and_validate_block_from_blob(it->first.first, bwt.block))
74 {
75 res.blocks.clear();
76 res.output_indices.clear();
78 res.error_details = "failed retrieving a requested block";
79 return;
80 }
81
82 if (it->second.size() != bwt.block.tx_hashes.size())
83 {
84 res.blocks.clear();
85 res.output_indices.clear();
87 res.error_details = "incorrect number of transactions retrieved for block";
88 return;
89 }
90
91 cryptonote::rpc::block_output_indices& indices = res.output_indices[block_count];
92
93 // miner tx output indices
94 {
96 if (!m_core.get_tx_outputs_gindexs(get_transaction_hash(bwt.block.miner_tx), tx_indices))
97 {
99 res.error_details = "core::get_tx_outputs_gindexs() returned false";
100 return;
101 }
102 indices.push_back(std::move(tx_indices));
103 }
104
105 auto hash_it = bwt.block.tx_hashes.begin();
106 bwt.transactions.reserve(it->second.size());
107 for (const auto& blob : it->second)
108 {
109 bwt.transactions.emplace_back();
110 if (!parse_and_validate_tx_from_blob(blob.second, bwt.transactions.back()))
111 {
112 res.blocks.clear();
113 res.output_indices.clear();
115 res.error_details = "failed retrieving a requested transaction";
116 return;
117 }
118
120 if (!m_core.get_tx_outputs_gindexs(*hash_it, tx_indices))
121 {
123 res.error_details = "core::get_tx_outputs_gindexs() returned false";
124 return;
125 }
126
127 indices.push_back(std::move(tx_indices));
128 ++hash_it;
129 }
130
131 it++;
132 block_count++;
133 }
134
135 res.status = Message::STATUS_OK;
136 }
137
138 void DaemonHandler::handle(const GetHashesFast::Request& req, GetHashesFast::Response& res)
139 {
140 res.start_height = req.start_height;
141
142 auto& chain = m_core.get_blockchain_storage();
143
144 if (!chain.find_blockchain_supplement(req.known_hashes, res.hashes, res.start_height, res.current_height, false))
145 {
147 res.error_details = "Blockchain::find_blockchain_supplement() returned false";
148 return;
149 }
150
151 res.status = Message::STATUS_OK;
152 }
153
154 void DaemonHandler::handle(const GetTransactions::Request& req, GetTransactions::Response& res)
155 {
156 std::vector<cryptonote::transaction> found_txs_vec;
157 std::vector<crypto::hash> missed_vec;
158
159 bool r = m_core.get_transactions(req.tx_hashes, found_txs_vec, missed_vec);
160
161 // TODO: consider fixing core::get_transactions to not hide exceptions
162 if (!r)
163 {
165 res.error_details = "core::get_transactions() returned false (exception caught there)";
166 return;
167 }
168
169 size_t num_found = found_txs_vec.size();
170
171 std::vector<uint64_t> heights(num_found);
172 std::vector<bool> in_pool(num_found, false);
173 std::vector<crypto::hash> found_hashes(num_found);
174
175 for (size_t i=0; i < num_found; i++)
176 {
177 found_hashes[i] = get_transaction_hash(found_txs_vec[i]);
178 heights[i] = m_core.get_blockchain_storage().get_db().get_tx_block_height(found_hashes[i]);
179 }
180
181 // if any missing from blockchain, check in tx pool
182 if (!missed_vec.empty())
183 {
184 std::vector<cryptonote::transaction> pool_txs;
185
186 m_core.get_pool_transactions(pool_txs);
187
188 for (const auto& tx : pool_txs)
189 {
191
192 auto itr = std::find(missed_vec.begin(), missed_vec.end(), h);
193
194 if (itr != missed_vec.end())
195 {
196 found_hashes.push_back(h);
197 found_txs_vec.push_back(tx);
198 heights.push_back(std::numeric_limits<uint64_t>::max());
199 in_pool.push_back(true);
200 missed_vec.erase(itr);
201 }
202 }
203 }
204
205 for (size_t i=0; i < found_hashes.size(); i++)
206 {
208 info.height = heights[i];
209 info.in_pool = in_pool[i];
210 info.transaction = std::move(found_txs_vec[i]);
211
212 res.txs.emplace(found_hashes[i], std::move(info));
213 }
214
215 res.missed_hashes = std::move(missed_vec);
216 res.status = Message::STATUS_OK;
217 }
218
219 void DaemonHandler::handle(const KeyImagesSpent::Request& req, KeyImagesSpent::Response& res)
220 {
221 res.spent_status.resize(req.key_images.size(), KeyImagesSpent::STATUS::UNSPENT);
222
223 std::vector<bool> chain_spent_status;
224 std::vector<bool> pool_spent_status;
225
226 m_core.are_key_images_spent(req.key_images, chain_spent_status);
227 m_core.are_key_images_spent_in_pool(req.key_images, pool_spent_status);
228
229 if ((chain_spent_status.size() != req.key_images.size()) || (pool_spent_status.size() != req.key_images.size()))
230 {
232 res.error_details = "tx_pool::have_key_images_as_spent() gave vectors of wrong size(s).";
233 return;
234 }
235
236 for(size_t i=0; i < req.key_images.size(); i++)
237 {
238 if ( chain_spent_status[i] )
239 {
240 res.spent_status[i] = KeyImagesSpent::STATUS::SPENT_IN_BLOCKCHAIN;
241 }
242 else if ( pool_spent_status[i] )
243 {
244 res.spent_status[i] = KeyImagesSpent::STATUS::SPENT_IN_POOL;
245 }
246 }
247
248 res.status = Message::STATUS_OK;
249 }
250
251 void DaemonHandler::handle(const GetTxGlobalOutputIndices::Request& req, GetTxGlobalOutputIndices::Response& res)
252 {
253 if (!m_core.get_tx_outputs_gindexs(req.tx_hash, res.output_indices))
254 {
256 res.error_details = "core::get_tx_outputs_gindexs() returned false";
257 return;
258 }
259
260 res.status = Message::STATUS_OK;
261
262 }
263
264 void DaemonHandler::handle(const SendRawTx::Request& req, SendRawTx::Response& res)
265 {
266 handleTxBlob(cryptonote::tx_to_blob(req.tx), req.relay, res);
267 }
268
269 void DaemonHandler::handle(const SendRawTxHex::Request& req, SendRawTxHex::Response& res)
270 {
271 std::string tx_blob;
272 if(!epee::string_tools::parse_hexstr_to_binbuff(req.tx_as_hex, tx_blob))
273 {
274 MERROR("[SendRawTxHex]: Failed to parse tx from hexbuff: " << req.tx_as_hex);
276 res.error_details = "Invalid hex";
277 return;
278 }
279 handleTxBlob(tx_blob, req.relay, res);
280 }
281
282 void DaemonHandler::handleTxBlob(const std::string& tx_blob, bool relay, SendRawTx::Response& res)
283 {
284 if (!m_p2p.get_payload_object().is_synchronized())
285 {
287 res.error_details = "Not ready to accept transactions; try again later";
288 return;
289 }
290
291 cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
293
294 if(!m_core.handle_incoming_tx(tx_blob, tvc, false, false, !relay) || tvc.m_verification_failed)
295 {
296 if (tvc.m_verification_failed)
297 {
298 MERROR("[SendRawTx]: tx verification failed");
299 }
300 else
301 {
302 MERROR("[SendRawTx]: Failed to process tx");
303 }
305 res.error_details = "";
306
307 if (tvc.m_low_mixin)
308 {
309 res.error_details = "mixin too low";
310 }
311 if (tvc.m_double_spend)
312 {
313 if (!res.error_details.empty()) res.error_details += " and ";
314 res.error_details = "double spend";
315 }
316 if (tvc.m_utxo_nonexistent)
317 {
318 if (!res.error_details.empty()) res.error_details += " and ";
319 res.error_details = "utxo is already spent or is nonexistent";
320 }
321 if (tvc.m_invalid_input)
322 {
323 if (!res.error_details.empty()) res.error_details += " and ";
324 res.error_details = "invalid input";
325 }
326 if (tvc.m_invalid_output)
327 {
328 if (!res.error_details.empty()) res.error_details += " and ";
329 res.error_details = "invalid output";
330 }
331 if (tvc.m_too_big)
332 {
333 if (!res.error_details.empty()) res.error_details += " and ";
334 res.error_details = "too big";
335 }
336 if (tvc.m_overspend)
337 {
338 if (!res.error_details.empty()) res.error_details += " and ";
339 res.error_details = "overspend";
340 }
341 if (tvc.m_fee_too_low)
342 {
343 if (!res.error_details.empty()) res.error_details += " and ";
344 res.error_details = "fee too low";
345 }
346 if (tvc.m_not_rct)
347 {
348 if (!res.error_details.empty()) res.error_details += " and ";
349 res.error_details = "tx is not ringct";
350 }
351 if (tvc.m_portal_outbound_tx)
352 {
353 if (!res.error_details.empty()) res.error_details += " and ";
354 res.error_details = "this is an outbound transaction from the smartchain bridge portal address";
355 }
357 {
358 if (!res.error_details.empty()) res.error_details += " and ";
359 res.error_details = "the bridge source address in the tx extra is invalid";
360 }
362 {
363 if (!res.error_details.empty()) res.error_details += " and ";
364 res.error_details = "the bridge smartchain address in the tx extra is invalid";
365 }
367 {
368 if (!res.error_details.empty()) res.error_details += " and ";
369 res.error_details = "the bridge ownership signature is missing or invalid";
370 }
371 if (res.error_details.empty())
372 {
373 res.error_details = "an unknown issue was found with the transaction";
374 }
375
376 return;
377 }
378
379 if(!tvc.m_should_be_relayed || !relay)
380 {
381 MERROR("[SendRawTx]: tx accepted, but not relayed");
382 res.error_details = "Not relayed";
383 res.relayed = false;
384 res.status = Message::STATUS_OK;
385
386 return;
387 }
388
390 r.txs.push_back(tx_blob);
391 m_core.get_protocol()->relay_transactions(r, fake_context);
392
393 //TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
394 res.status = Message::STATUS_OK;
395 res.relayed = true;
396
397 return;
398 }
399
400 void DaemonHandler::handle(const StartMining::Request& req, StartMining::Response& res)
401 {
403 if(!get_account_address_from_str(info, m_core.get_nettype(), req.miner_address))
404 {
405 res.error_details = "Failed, wrong address";
406 LOG_PRINT_L0(res.error_details);
408 return;
409 }
410 if (info.is_subaddress)
411 {
412 res.error_details = "Failed, mining to subaddress isn't supported yet";
413 LOG_PRINT_L0(res.error_details);
415 return;
416 }
417
418 unsigned int concurrency_count = boost::thread::hardware_concurrency() * 4;
419
420 // if we couldn't detect threads, set it to a ridiculously high number
421 if(concurrency_count == 0)
422 {
423 concurrency_count = 257;
424 }
425
426 // if there are more threads requested than the hardware supports
427 // then we fail and log that.
428 if(req.threads_count > concurrency_count)
429 {
430 res.error_details = "Failed, too many threads relative to CPU cores.";
431 LOG_PRINT_L0(res.error_details);
433 return;
434 }
435
436 if(!m_core.get_miner().start(info.address, static_cast<size_t>(req.threads_count), req.do_background_mining, req.ignore_battery))
437 {
438 res.error_details = "Failed, mining not started";
439 LOG_PRINT_L0(res.error_details);
441 return;
442 }
443 res.status = Message::STATUS_OK;
444 res.error_details = "";
445
446 }
447
448 void DaemonHandler::handle(const GetInfo::Request& req, GetInfo::Response& res)
449 {
450 res.info.height = m_core.get_current_blockchain_height();
451
452 res.info.target_height = m_core.get_target_blockchain_height();
453
454 if (res.info.height > res.info.target_height)
455 {
456 res.info.target_height = res.info.height;
457 }
458
459 auto& chain = m_core.get_blockchain_storage();
460
461 res.info.wide_difficulty = chain.get_difficulty_for_next_block();
462 res.info.difficulty = (res.info.wide_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
463
464 res.info.target = chain.get_difficulty_target();
465
466 res.info.tx_count = chain.get_total_transactions() - res.info.height; //without coinbase
467
468 res.info.tx_pool_size = m_core.get_pool_transactions_count();
469
470 res.info.alt_blocks_count = chain.get_alternative_blocks_count();
471
472 uint64_t total_conn = m_p2p.get_public_connections_count();
473 res.info.outgoing_connections_count = m_p2p.get_public_outgoing_connections_count();
474 res.info.incoming_connections_count = total_conn - res.info.outgoing_connections_count;
475
476 res.info.white_peerlist_size = m_p2p.get_public_white_peers_count();
477
478 res.info.grey_peerlist_size = m_p2p.get_public_gray_peers_count();
479
480 res.info.mainnet = m_core.get_nettype() == MAINNET;
481 res.info.testnet = m_core.get_nettype() == TESTNET;
482 res.info.stagenet = m_core.get_nettype() == STAGENET;
483 res.info.wide_cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.info.height - 1);
484 res.info.cumulative_difficulty = (res.info.wide_cumulative_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
485 res.info.block_size_limit = res.info.block_weight_limit = m_core.get_blockchain_storage().get_current_cumulative_block_weight_limit();
486 res.info.block_size_median = res.info.block_weight_median = m_core.get_blockchain_storage().get_current_cumulative_block_weight_median();
487 res.info.start_time = (uint64_t)m_core.get_start_time();
488 res.info.version = ELECTRONEUM_VERSION;
489
490 res.status = Message::STATUS_OK;
491 res.error_details = "";
492 }
493
494 void DaemonHandler::handle(const StopMining::Request& req, StopMining::Response& res)
495 {
496 if(!m_core.get_miner().stop())
497 {
498 res.error_details = "Failed, mining not stopped";
499 LOG_PRINT_L0(res.error_details);
501 return;
502 }
503
504 res.status = Message::STATUS_OK;
505 res.error_details = "";
506 }
507
508 void DaemonHandler::handle(const MiningStatus::Request& req, MiningStatus::Response& res)
509 {
510 const cryptonote::miner& lMiner = m_core.get_miner();
511 res.active = lMiner.is_mining();
512 res.is_background_mining_enabled = lMiner.get_is_background_mining_enabled();
513
514 if ( lMiner.is_mining() ) {
515 res.speed = lMiner.get_speed();
516 res.threads_count = lMiner.get_threads_count();
517 const account_public_address& lMiningAdr = lMiner.get_mining_address();
518 res.address = get_account_address_as_str(m_core.get_nettype(), false, lMiningAdr);
519 }
520
521 res.status = Message::STATUS_OK;
522 res.error_details = "";
523 }
524
525 void DaemonHandler::handle(const SaveBC::Request& req, SaveBC::Response& res)
526 {
527 if (!m_core.get_blockchain_storage().store_blockchain())
528 {
530 res.error_details = "Error storing the blockchain";
531 }
532 else
533 {
534 res.status = Message::STATUS_OK;
535 }
536 }
537
538 void DaemonHandler::handle(const GetBlockHash::Request& req, GetBlockHash::Response& res)
539 {
540 if (m_core.get_current_blockchain_height() <= req.height)
541 {
542 res.hash = crypto::null_hash;
544 res.error_details = "height given is higher than current chain height";
545 return;
546 }
547
548 res.hash = m_core.get_block_id_by_height(req.height);
549
550 res.status = Message::STATUS_OK;
551 }
552
553 void DaemonHandler::handle(const GetBlockTemplate::Request& req, GetBlockTemplate::Response& res)
554 {
556 res.error_details = "RPC method not yet implemented.";
557 }
558
559 void DaemonHandler::handle(const SubmitBlock::Request& req, SubmitBlock::Response& res)
560 {
562 res.error_details = "RPC method not yet implemented.";
563 }
564
565 void DaemonHandler::handle(const GetLastBlockHeader::Request& req, GetLastBlockHeader::Response& res)
566 {
567 const crypto::hash block_hash = m_core.get_tail_id();
568
569 if (!getBlockHeaderByHash(block_hash, res.header))
570 {
572 res.error_details = "Requested block does not exist";
573 return;
574 }
575
576 res.status = Message::STATUS_OK;
577 }
578
579 void DaemonHandler::handle(const GetBlockHeaderByHash::Request& req, GetBlockHeaderByHash::Response& res)
580 {
581 if (!getBlockHeaderByHash(req.hash, res.header))
582 {
584 res.error_details = "Requested block does not exist";
585 return;
586 }
587
588 res.status = Message::STATUS_OK;
589 }
590
591 void DaemonHandler::handle(const GetBlockHeaderByHeight::Request& req, GetBlockHeaderByHeight::Response& res)
592 {
593 const crypto::hash block_hash = m_core.get_block_id_by_height(req.height);
594
595 if (!getBlockHeaderByHash(block_hash, res.header))
596 {
598 res.error_details = "Requested block does not exist";
599 return;
600 }
601
602 res.status = Message::STATUS_OK;
603 }
604
605 void DaemonHandler::handle(const GetBlockHeadersByHeight::Request& req, GetBlockHeadersByHeight::Response& res)
606 {
607 res.headers.resize(req.heights.size());
608
609 for (size_t i=0; i < req.heights.size(); i++)
610 {
611 const crypto::hash block_hash = m_core.get_block_id_by_height(req.heights[i]);
612
613 if (!getBlockHeaderByHash(block_hash, res.headers[i]))
614 {
616 res.error_details = "A requested block does not exist";
617 return;
618 }
619 }
620
621 res.status = Message::STATUS_OK;
622 }
623
624 void DaemonHandler::handle(const GetBlock::Request& req, GetBlock::Response& res)
625 {
627 res.error_details = "RPC method not yet implemented.";
628 }
629
630 void DaemonHandler::handle(const GetPeerList::Request& req, GetPeerList::Response& res)
631 {
633 res.error_details = "RPC method not yet implemented.";
634 }
635
636 void DaemonHandler::handle(const SetLogHashRate::Request& req, SetLogHashRate::Response& res)
637 {
639 res.error_details = "RPC method not yet implemented.";
640 }
641
642 void DaemonHandler::handle(const SetLogLevel::Request& req, SetLogLevel::Response& res)
643 {
644 if (req.level < 0 || req.level > 4)
645 {
647 res.error_details = "Error: log level not valid";
648 }
649 else
650 {
651 res.status = Message::STATUS_OK;
652 mlog_set_log_level(req.level);
653 }
654 }
655
656 void DaemonHandler::handle(const GetTransactionPool::Request& req, GetTransactionPool::Response& res)
657 {
658 bool r = m_core.get_pool_for_rpc(res.transactions, res.key_images);
659
660 if (!r) res.status = Message::STATUS_FAILED;
661 else res.status = Message::STATUS_OK;
662 }
663
664 void DaemonHandler::handle(const GetConnections::Request& req, GetConnections::Response& res)
665 {
667 res.error_details = "RPC method not yet implemented.";
668 }
669
670 void DaemonHandler::handle(const GetBlockHeadersRange::Request& req, GetBlockHeadersRange::Response& res)
671 {
673 res.error_details = "RPC method not yet implemented.";
674 }
675
676 void DaemonHandler::handle(const StopDaemon::Request& req, StopDaemon::Response& res)
677 {
679 res.error_details = "RPC method not yet implemented.";
680 }
681
682 void DaemonHandler::handle(const StartSaveGraph::Request& req, StartSaveGraph::Response& res)
683 {
685 res.error_details = "RPC method not yet implemented.";
686 }
687
688 void DaemonHandler::handle(const StopSaveGraph::Request& req, StopSaveGraph::Response& res)
689 {
691 res.error_details = "RPC method not yet implemented.";
692 }
693
694 void DaemonHandler::handle(const HardForkInfo::Request& req, HardForkInfo::Response& res)
695 {
696 const Blockchain &blockchain = m_core.get_blockchain_storage();
697 uint8_t version = req.version > 0 ? req.version : blockchain.get_ideal_hard_fork_version();
698 res.info.version = blockchain.get_current_hard_fork_version();
699 res.info.enabled = blockchain.get_hard_fork_voting_info(version, res.info.window, res.info.votes, res.info.threshold, res.info.earliest_height, res.info.voting);
700 res.info.state = blockchain.get_hard_fork_state();
701 res.status = Message::STATUS_OK;
702 }
703
704 void DaemonHandler::handle(const GetBans::Request& req, GetBans::Response& res)
705 {
707 res.error_details = "RPC method not yet implemented.";
708 }
709
710 void DaemonHandler::handle(const SetBans::Request& req, SetBans::Response& res)
711 {
713 res.error_details = "RPC method not yet implemented.";
714 }
715
716 void DaemonHandler::handle(const FlushTransactionPool::Request& req, FlushTransactionPool::Response& res)
717 {
719 res.error_details = "RPC method not yet implemented.";
720 }
721
722 void DaemonHandler::handle(const GetOutputHistogram::Request& req, GetOutputHistogram::Response& res)
723 {
724 std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t> > histogram;
725 try
726 {
727 histogram = m_core.get_blockchain_storage().get_output_histogram(req.amounts, req.unlocked, req.recent_cutoff);
728 }
729 catch (const std::exception &e)
730 {
732 res.error_details = e.what();
733 return;
734 }
735
736 res.histogram.clear();
737 res.histogram.reserve(histogram.size());
738 for (const auto &i: histogram)
739 {
740 if (std::get<0>(i.second) >= req.min_count && (std::get<0>(i.second) <= req.max_count || req.max_count == 0))
741 res.histogram.emplace_back(output_amount_count{i.first, std::get<0>(i.second), std::get<1>(i.second), std::get<2>(i.second)});
742 }
743
744 res.status = Message::STATUS_OK;
745 }
746
747 void DaemonHandler::handle(const GetOutputKeys::Request& req, GetOutputKeys::Response& res)
748 {
749 try
750 {
751 for (const auto& i : req.outputs)
752 {
754 rct::key mask;
755 bool unlocked;
756 m_core.get_blockchain_storage().get_output_key_mask_unlocked(i.amount, i.index, key, mask, unlocked);
757 res.keys.emplace_back(output_key_mask_unlocked{key, mask, unlocked});
758 }
759 }
760 catch (const std::exception& e)
761 {
763 res.error_details = e.what();
764 return;
765 }
766
767 res.status = Message::STATUS_OK;
768 }
769
770 void DaemonHandler::handle(const GetRPCVersion::Request& req, GetRPCVersion::Response& res)
771 {
772 res.version = DAEMON_RPC_VERSION_ZMQ;
773 res.status = Message::STATUS_OK;
774 }
775
776 void DaemonHandler::handle(const GetFeeEstimate::Request& req, GetFeeEstimate::Response& res)
777 {
778 res.hard_fork_version = m_core.get_blockchain_storage().get_current_hard_fork_version();
779 res.estimated_base_fee = m_core.get_blockchain_storage().get_dynamic_base_fee_estimate(req.num_grace_blocks);
780
781 if (res.hard_fork_version < HF_VERSION_PER_BYTE_FEE)
782 {
783 res.size_scale = 1024; // per KiB fee
784 res.fee_mask = 1;
785 }
786 else
787 {
788 res.size_scale = 1; // per byte fee
790 }
791 res.status = Message::STATUS_OK;
792 }
793
794 void DaemonHandler::handle(const GetOutputDistribution::Request& req, GetOutputDistribution::Response& res)
795 {
796 try
797 {
798 res.distributions.reserve(req.amounts.size());
799
800 const uint64_t req_to_height = req.to_height ? req.to_height : (m_core.get_current_blockchain_height() - 1);
801 for (std::uint64_t amount : req.amounts)
802 {
803 auto data = rpc::RpcHandler::get_output_distribution([this](uint64_t amount, uint64_t from, uint64_t to, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) { return m_core.get_output_distribution(amount, from, to, start_height, distribution, base); }, amount, req.from_height, req_to_height, [this](uint64_t height) { return m_core.get_blockchain_storage().get_db().get_block_hash_from_height(height); }, req.cumulative, m_core.get_current_blockchain_height());
804 if (!data)
805 {
806 res.distributions.clear();
808 res.error_details = "Failed to get output distribution";
809 return;
810 }
811 res.distributions.push_back(output_distribution{std::move(*data), amount, req.cumulative});
812 }
813 res.status = Message::STATUS_OK;
814 }
815 catch (const std::exception& e)
816 {
817 res.distributions.clear();
819 res.error_details = e.what();
820 }
821 }
822
823 bool DaemonHandler::getBlockHeaderByHash(const crypto::hash& hash_in, cryptonote::rpc::BlockHeaderResponse& header)
824 {
825 block b;
826
827 if (!m_core.get_block_by_hash(hash_in, b))
828 {
829 return false;
830 }
831
832 header.hash = hash_in;
833 if (b.miner_tx.vin.size() != 1 || b.miner_tx.vin.front().type() != typeid(txin_gen))
834 {
835 return false;
836 }
837 header.height = boost::get<txin_gen>(b.miner_tx.vin.front()).height;
838
839 header.major_version = b.major_version;
840 header.minor_version = b.minor_version;
841 header.timestamp = b.timestamp;
842 header.nonce = b.nonce;
843 header.prev_id = b.prev_id;
844
845 header.depth = m_core.get_current_blockchain_height() - header.height - 1;
846
847 header.reward = 0;
848 for (const auto& out : b.miner_tx.vout)
849 {
850 header.reward += out.amount;
851 }
852
853 header.wide_difficulty = m_core.get_blockchain_storage().block_difficulty(header.height);
854 header.difficulty = (header.wide_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
855
856 return true;
857 }
858
859 std::string DaemonHandler::handle(const std::string& request)
860 {
861 MDEBUG("Handling RPC request: " << request);
862
863 Message* resp_message = NULL;
864
865 try
866 {
867 FullMessage req_full(request, true);
868
869 rapidjson::Value& req_json = req_full.getMessage();
870
871 const std::string request_type = req_full.getRequestType();
872
873 // create correct Message subclass and call handle() on it
874 REQ_RESP_TYPES_MACRO(request_type, GetHeight, req_json, resp_message, handle);
875 REQ_RESP_TYPES_MACRO(request_type, GetBlocksFast, req_json, resp_message, handle);
876 REQ_RESP_TYPES_MACRO(request_type, GetHashesFast, req_json, resp_message, handle);
877 REQ_RESP_TYPES_MACRO(request_type, GetTransactions, req_json, resp_message, handle);
878 REQ_RESP_TYPES_MACRO(request_type, KeyImagesSpent, req_json, resp_message, handle);
879 REQ_RESP_TYPES_MACRO(request_type, GetTxGlobalOutputIndices, req_json, resp_message, handle);
880 REQ_RESP_TYPES_MACRO(request_type, SendRawTx, req_json, resp_message, handle);
881 REQ_RESP_TYPES_MACRO(request_type, SendRawTxHex, req_json, resp_message, handle);
882 REQ_RESP_TYPES_MACRO(request_type, GetInfo, req_json, resp_message, handle);
883 REQ_RESP_TYPES_MACRO(request_type, StartMining, req_json, resp_message, handle);
884 REQ_RESP_TYPES_MACRO(request_type, StopMining, req_json, resp_message, handle);
885 REQ_RESP_TYPES_MACRO(request_type, MiningStatus, req_json, resp_message, handle);
886 REQ_RESP_TYPES_MACRO(request_type, SaveBC, req_json, resp_message, handle);
887 REQ_RESP_TYPES_MACRO(request_type, GetBlockHash, req_json, resp_message, handle);
888 REQ_RESP_TYPES_MACRO(request_type, GetLastBlockHeader, req_json, resp_message, handle);
889 REQ_RESP_TYPES_MACRO(request_type, GetBlockHeaderByHash, req_json, resp_message, handle);
890 REQ_RESP_TYPES_MACRO(request_type, GetBlockHeaderByHeight, req_json, resp_message, handle);
891 REQ_RESP_TYPES_MACRO(request_type, GetBlockHeadersByHeight, req_json, resp_message, handle);
892 REQ_RESP_TYPES_MACRO(request_type, GetPeerList, req_json, resp_message, handle);
893 REQ_RESP_TYPES_MACRO(request_type, SetLogLevel, req_json, resp_message, handle);
894 REQ_RESP_TYPES_MACRO(request_type, GetTransactionPool, req_json, resp_message, handle);
895 REQ_RESP_TYPES_MACRO(request_type, HardForkInfo, req_json, resp_message, handle);
896 REQ_RESP_TYPES_MACRO(request_type, GetOutputHistogram, req_json, resp_message, handle);
897 REQ_RESP_TYPES_MACRO(request_type, GetOutputKeys, req_json, resp_message, handle);
898 REQ_RESP_TYPES_MACRO(request_type, GetRPCVersion, req_json, resp_message, handle);
899 REQ_RESP_TYPES_MACRO(request_type, GetFeeEstimate, req_json, resp_message, handle);
900 REQ_RESP_TYPES_MACRO(request_type, GetOutputDistribution, req_json, resp_message, handle);
901
902 // if none of the request types matches
903 if (resp_message == NULL)
904 {
905 return BAD_REQUEST(request_type, req_full.getID());
906 }
907
908 FullMessage resp_full = FullMessage::responseMessage(resp_message, req_full.getID());
909
910 const std::string response = resp_full.getJson();
911 delete resp_message;
912 resp_message = NULL;
913
914 MDEBUG("Returning RPC response: " << response);
915
916 return response;
917 }
918 catch (const std::exception& e)
919 {
920 if (resp_message)
921 {
922 delete resp_message;
923 }
924
925 return BAD_JSON(e.what());
926 }
927 }
928
929} // namespace rpc
930
931} // namespace cryptonote
uint64_t height
uint8_t version
uint8_t get_current_hard_fork_version() const
gets the current hardfork version in use/voted for
Definition blockchain.h:825
HardFork::State get_hard_fork_state() const
gets the hardfork voting state object
static uint64_t get_fee_quantization_mask()
get fee quantization mask
uint8_t get_ideal_hard_fork_version() const
returns the newest hardfork version known to the blockchain
Definition blockchain.h:832
bool get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const
get information about hardfork voting for a version
uint64_t get_current_blockchain_height() const
get the current height of the blockchain
bool get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan=NULL) const
gets the block with a given hash
bool handle_incoming_tx(const blobdata &tx_blob, tx_verification_context &tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
handles an incoming transaction
const account_public_address & get_mining_address() const
Definition miner.cpp:364
bool is_mining() const
Definition miner.cpp:359
uint64_t get_speed() const
Definition miner.cpp:429
uint32_t get_threads_count() const
Definition miner.cpp:369
bool get_is_background_mining_enabled() const
Definition miner.cpp:611
void handle(const GetHeight::Request &req, GetHeight::Response &res)
rapidjson::Value & getID()
Definition message.cpp:182
rapidjson::Value & getMessage()
Definition message.cpp:158
static FullMessage responseMessage(Message *message)
Definition message.cpp:226
std::string getRequestType() const
Definition message.cpp:152
static const char * STATUS_FAILED
Definition message.h:64
static const char * STATUS_OK
Definition message.h:62
static boost::optional< output_distribution_data > get_output_distribution(const std::function< bool(uint64_t, uint64_t, uint64_t, uint64_t &, std::vector< uint64_t > &, uint64_t &)> &f, uint64_t amount, uint64_t from_height, uint64_t to_height, const std::function< crypto::hash(uint64_t)> &get_hash, bool cumulative, uint64_t blockchain_height)
#define HF_VERSION_PER_BYTE_FEE
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT
const char * res
const char * key
#define REQ_RESP_TYPES_MACRO(runtime_str, type, reqjson, resp_message_ptr, handler)
Definition message.h:39
#define AUTO_VAL_INIT(v)
#define MERROR(x)
Definition misc_log_ex.h:73
#define MDEBUG(x)
Definition misc_log_ex.h:76
void mlog_set_log_level(int level)
Definition mlog.cpp:282
#define LOG_PRINT_L0(x)
Definition misc_log_ex.h:99
POD_CLASS public_key
Definition crypto.h:79
POD_CLASS hash
Definition hash.h:50
std::string BAD_REQUEST(const std::string &request)
Definition message.cpp:259
std::string BAD_JSON(const std::string &error_details)
Definition message.cpp:281
std::vector< tx_output_indices > block_output_indices
std::vector< uint64_t > tx_output_indices
Holds cryptonote related classes and helpers.
Definition ban.cpp:40
bool get_account_address_from_str(address_parse_info &info, network_type nettype, std::string const &str)
bool parse_and_validate_block_from_blob(const blobdata &b_blob, block &b, crypto::hash *block_hash)
std::string get_account_address_as_str(network_type nettype, bool subaddress, account_public_address const &adr)
crypto::hash get_transaction_hash(const transaction &t)
blobdata tx_to_blob(const transaction &tx)
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
bool parse_hexstr_to_binbuff(const epee::span< const char > s, epee::span< char > &res)
CXA_THROW_INFO_T * info
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
epee::misc_utils::struct_init< request_t > request
std::vector< crypto::hash > tx_hashes
cryptonote::difficulty_type wide_difficulty
std::vector< cryptonote::transaction > transactions
const char *const ELECTRONEUM_VERSION