Electroneum
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 
39 namespace cryptonote
40 {
41 
42 namespace 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  {
58  res.status = Message::STATUS_FAILED;
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();
77  res.status = Message::STATUS_FAILED;
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();
86  res.status = Message::STATUS_FAILED;
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  {
98  res.status = Message::STATUS_FAILED;
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();
114  res.status = Message::STATUS_FAILED;
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  {
122  res.status = Message::STATUS_FAILED;
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  {
146  res.status = Message::STATUS_FAILED;
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  {
164  res.status = Message::STATUS_FAILED;
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  {
231  res.status = Message::STATUS_FAILED;
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  {
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  {
255  res.status = Message::STATUS_FAILED;
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);
275  res.status = Message::STATUS_FAILED;
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  {
286  res.status = Message::STATUS_FAILED;
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  }
304  res.status = Message::STATUS_FAILED;
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 (res.error_details.empty())
352  {
353  res.error_details = "an unknown issue was found with the transaction";
354  }
355 
356  return;
357  }
358 
359  if(!tvc.m_should_be_relayed || !relay)
360  {
361  MERROR("[SendRawTx]: tx accepted, but not relayed");
362  res.error_details = "Not relayed";
363  res.relayed = false;
364  res.status = Message::STATUS_OK;
365 
366  return;
367  }
368 
370  r.txs.push_back(tx_blob);
371  m_core.get_protocol()->relay_transactions(r, fake_context);
372 
373  //TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
374  res.status = Message::STATUS_OK;
375  res.relayed = true;
376 
377  return;
378  }
379 
380  void DaemonHandler::handle(const StartMining::Request& req, StartMining::Response& res)
381  {
383  if(!get_account_address_from_str(info, m_core.get_nettype(), req.miner_address))
384  {
385  res.error_details = "Failed, wrong address";
386  LOG_PRINT_L0(res.error_details);
387  res.status = Message::STATUS_FAILED;
388  return;
389  }
390  if (info.is_subaddress)
391  {
392  res.error_details = "Failed, mining to subaddress isn't supported yet";
393  LOG_PRINT_L0(res.error_details);
394  res.status = Message::STATUS_FAILED;
395  return;
396  }
397 
398  unsigned int concurrency_count = boost::thread::hardware_concurrency() * 4;
399 
400  // if we couldn't detect threads, set it to a ridiculously high number
401  if(concurrency_count == 0)
402  {
403  concurrency_count = 257;
404  }
405 
406  // if there are more threads requested than the hardware supports
407  // then we fail and log that.
408  if(req.threads_count > concurrency_count)
409  {
410  res.error_details = "Failed, too many threads relative to CPU cores.";
411  LOG_PRINT_L0(res.error_details);
412  res.status = Message::STATUS_FAILED;
413  return;
414  }
415 
416  if(!m_core.get_miner().start(info.address, static_cast<size_t>(req.threads_count), req.do_background_mining, req.ignore_battery))
417  {
418  res.error_details = "Failed, mining not started";
419  LOG_PRINT_L0(res.error_details);
420  res.status = Message::STATUS_FAILED;
421  return;
422  }
423  res.status = Message::STATUS_OK;
424  res.error_details = "";
425 
426  }
427 
428  void DaemonHandler::handle(const GetInfo::Request& req, GetInfo::Response& res)
429  {
430  res.info.height = m_core.get_current_blockchain_height();
431 
432  res.info.target_height = m_core.get_target_blockchain_height();
433 
434  if (res.info.height > res.info.target_height)
435  {
436  res.info.target_height = res.info.height;
437  }
438 
439  auto& chain = m_core.get_blockchain_storage();
440 
441  res.info.wide_difficulty = chain.get_difficulty_for_next_block();
442  res.info.difficulty = (res.info.wide_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
443 
444  res.info.target = chain.get_difficulty_target();
445 
446  res.info.tx_count = chain.get_total_transactions() - res.info.height; //without coinbase
447 
448  res.info.tx_pool_size = m_core.get_pool_transactions_count();
449 
450  res.info.alt_blocks_count = chain.get_alternative_blocks_count();
451 
452  uint64_t total_conn = m_p2p.get_public_connections_count();
453  res.info.outgoing_connections_count = m_p2p.get_public_outgoing_connections_count();
454  res.info.incoming_connections_count = total_conn - res.info.outgoing_connections_count;
455 
456  res.info.white_peerlist_size = m_p2p.get_public_white_peers_count();
457 
458  res.info.grey_peerlist_size = m_p2p.get_public_gray_peers_count();
459 
460  res.info.mainnet = m_core.get_nettype() == MAINNET;
461  res.info.testnet = m_core.get_nettype() == TESTNET;
462  res.info.stagenet = m_core.get_nettype() == STAGENET;
463  res.info.wide_cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.info.height - 1);
464  res.info.cumulative_difficulty = (res.info.wide_cumulative_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
465  res.info.block_size_limit = res.info.block_weight_limit = m_core.get_blockchain_storage().get_current_cumulative_block_weight_limit();
466  res.info.block_size_median = res.info.block_weight_median = m_core.get_blockchain_storage().get_current_cumulative_block_weight_median();
467  res.info.start_time = (uint64_t)m_core.get_start_time();
468  res.info.version = ELECTRONEUM_VERSION;
469 
470  res.status = Message::STATUS_OK;
471  res.error_details = "";
472  }
473 
474  void DaemonHandler::handle(const StopMining::Request& req, StopMining::Response& res)
475  {
476  if(!m_core.get_miner().stop())
477  {
478  res.error_details = "Failed, mining not stopped";
479  LOG_PRINT_L0(res.error_details);
480  res.status = Message::STATUS_FAILED;
481  return;
482  }
483 
484  res.status = Message::STATUS_OK;
485  res.error_details = "";
486  }
487 
488  void DaemonHandler::handle(const MiningStatus::Request& req, MiningStatus::Response& res)
489  {
490  const cryptonote::miner& lMiner = m_core.get_miner();
491  res.active = lMiner.is_mining();
492  res.is_background_mining_enabled = lMiner.get_is_background_mining_enabled();
493 
494  if ( lMiner.is_mining() ) {
495  res.speed = lMiner.get_speed();
496  res.threads_count = lMiner.get_threads_count();
497  const account_public_address& lMiningAdr = lMiner.get_mining_address();
498  res.address = get_account_address_as_str(m_core.get_nettype(), false, lMiningAdr);
499  }
500 
501  res.status = Message::STATUS_OK;
502  res.error_details = "";
503  }
504 
505  void DaemonHandler::handle(const SaveBC::Request& req, SaveBC::Response& res)
506  {
508  {
509  res.status = Message::STATUS_FAILED;
510  res.error_details = "Error storing the blockchain";
511  }
512  else
513  {
514  res.status = Message::STATUS_OK;
515  }
516  }
517 
518  void DaemonHandler::handle(const GetBlockHash::Request& req, GetBlockHash::Response& res)
519  {
520  if (m_core.get_current_blockchain_height() <= req.height)
521  {
522  res.hash = crypto::null_hash;
523  res.status = Message::STATUS_FAILED;
524  res.error_details = "height given is higher than current chain height";
525  return;
526  }
527 
528  res.hash = m_core.get_block_id_by_height(req.height);
529 
530  res.status = Message::STATUS_OK;
531  }
532 
533  void DaemonHandler::handle(const GetBlockTemplate::Request& req, GetBlockTemplate::Response& res)
534  {
535  res.status = Message::STATUS_FAILED;
536  res.error_details = "RPC method not yet implemented.";
537  }
538 
539  void DaemonHandler::handle(const SubmitBlock::Request& req, SubmitBlock::Response& res)
540  {
541  res.status = Message::STATUS_FAILED;
542  res.error_details = "RPC method not yet implemented.";
543  }
544 
545  void DaemonHandler::handle(const GetLastBlockHeader::Request& req, GetLastBlockHeader::Response& res)
546  {
547  const crypto::hash block_hash = m_core.get_tail_id();
548 
549  if (!getBlockHeaderByHash(block_hash, res.header))
550  {
551  res.status = Message::STATUS_FAILED;
552  res.error_details = "Requested block does not exist";
553  return;
554  }
555 
556  res.status = Message::STATUS_OK;
557  }
558 
559  void DaemonHandler::handle(const GetBlockHeaderByHash::Request& req, GetBlockHeaderByHash::Response& res)
560  {
561  if (!getBlockHeaderByHash(req.hash, res.header))
562  {
563  res.status = Message::STATUS_FAILED;
564  res.error_details = "Requested block does not exist";
565  return;
566  }
567 
568  res.status = Message::STATUS_OK;
569  }
570 
571  void DaemonHandler::handle(const GetBlockHeaderByHeight::Request& req, GetBlockHeaderByHeight::Response& res)
572  {
573  const crypto::hash block_hash = m_core.get_block_id_by_height(req.height);
574 
575  if (!getBlockHeaderByHash(block_hash, res.header))
576  {
577  res.status = Message::STATUS_FAILED;
578  res.error_details = "Requested block does not exist";
579  return;
580  }
581 
582  res.status = Message::STATUS_OK;
583  }
584 
585  void DaemonHandler::handle(const GetBlockHeadersByHeight::Request& req, GetBlockHeadersByHeight::Response& res)
586  {
587  res.headers.resize(req.heights.size());
588 
589  for (size_t i=0; i < req.heights.size(); i++)
590  {
591  const crypto::hash block_hash = m_core.get_block_id_by_height(req.heights[i]);
592 
593  if (!getBlockHeaderByHash(block_hash, res.headers[i]))
594  {
595  res.status = Message::STATUS_FAILED;
596  res.error_details = "A requested block does not exist";
597  return;
598  }
599  }
600 
601  res.status = Message::STATUS_OK;
602  }
603 
604  void DaemonHandler::handle(const GetBlock::Request& req, GetBlock::Response& res)
605  {
606  res.status = Message::STATUS_FAILED;
607  res.error_details = "RPC method not yet implemented.";
608  }
609 
610  void DaemonHandler::handle(const GetPeerList::Request& req, GetPeerList::Response& res)
611  {
612  res.status = Message::STATUS_FAILED;
613  res.error_details = "RPC method not yet implemented.";
614  }
615 
616  void DaemonHandler::handle(const SetLogHashRate::Request& req, SetLogHashRate::Response& res)
617  {
618  res.status = Message::STATUS_FAILED;
619  res.error_details = "RPC method not yet implemented.";
620  }
621 
622  void DaemonHandler::handle(const SetLogLevel::Request& req, SetLogLevel::Response& res)
623  {
624  if (req.level < 0 || req.level > 4)
625  {
626  res.status = Message::STATUS_FAILED;
627  res.error_details = "Error: log level not valid";
628  }
629  else
630  {
631  res.status = Message::STATUS_OK;
632  mlog_set_log_level(req.level);
633  }
634  }
635 
636  void DaemonHandler::handle(const GetTransactionPool::Request& req, GetTransactionPool::Response& res)
637  {
638  bool r = m_core.get_pool_for_rpc(res.transactions, res.key_images);
639 
640  if (!r) res.status = Message::STATUS_FAILED;
641  else res.status = Message::STATUS_OK;
642  }
643 
644  void DaemonHandler::handle(const GetConnections::Request& req, GetConnections::Response& res)
645  {
646  res.status = Message::STATUS_FAILED;
647  res.error_details = "RPC method not yet implemented.";
648  }
649 
650  void DaemonHandler::handle(const GetBlockHeadersRange::Request& req, GetBlockHeadersRange::Response& res)
651  {
652  res.status = Message::STATUS_FAILED;
653  res.error_details = "RPC method not yet implemented.";
654  }
655 
656  void DaemonHandler::handle(const StopDaemon::Request& req, StopDaemon::Response& res)
657  {
658  res.status = Message::STATUS_FAILED;
659  res.error_details = "RPC method not yet implemented.";
660  }
661 
662  void DaemonHandler::handle(const StartSaveGraph::Request& req, StartSaveGraph::Response& res)
663  {
664  res.status = Message::STATUS_FAILED;
665  res.error_details = "RPC method not yet implemented.";
666  }
667 
668  void DaemonHandler::handle(const StopSaveGraph::Request& req, StopSaveGraph::Response& res)
669  {
670  res.status = Message::STATUS_FAILED;
671  res.error_details = "RPC method not yet implemented.";
672  }
673 
674  void DaemonHandler::handle(const HardForkInfo::Request& req, HardForkInfo::Response& res)
675  {
676  const Blockchain &blockchain = m_core.get_blockchain_storage();
677  uint8_t version = req.version > 0 ? req.version : blockchain.get_ideal_hard_fork_version();
678  res.info.version = blockchain.get_current_hard_fork_version();
679  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);
680  res.info.state = blockchain.get_hard_fork_state();
681  res.status = Message::STATUS_OK;
682  }
683 
684  void DaemonHandler::handle(const GetBans::Request& req, GetBans::Response& res)
685  {
686  res.status = Message::STATUS_FAILED;
687  res.error_details = "RPC method not yet implemented.";
688  }
689 
690  void DaemonHandler::handle(const SetBans::Request& req, SetBans::Response& res)
691  {
692  res.status = Message::STATUS_FAILED;
693  res.error_details = "RPC method not yet implemented.";
694  }
695 
696  void DaemonHandler::handle(const FlushTransactionPool::Request& req, FlushTransactionPool::Response& res)
697  {
698  res.status = Message::STATUS_FAILED;
699  res.error_details = "RPC method not yet implemented.";
700  }
701 
702  void DaemonHandler::handle(const GetOutputHistogram::Request& req, GetOutputHistogram::Response& res)
703  {
704  std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t> > histogram;
705  try
706  {
707  histogram = m_core.get_blockchain_storage().get_output_histogram(req.amounts, req.unlocked, req.recent_cutoff);
708  }
709  catch (const std::exception &e)
710  {
711  res.status = Message::STATUS_FAILED;
712  res.error_details = e.what();
713  return;
714  }
715 
716  res.histogram.clear();
717  res.histogram.reserve(histogram.size());
718  for (const auto &i: histogram)
719  {
720  if (std::get<0>(i.second) >= req.min_count && (std::get<0>(i.second) <= req.max_count || req.max_count == 0))
721  res.histogram.emplace_back(output_amount_count{i.first, std::get<0>(i.second), std::get<1>(i.second), std::get<2>(i.second)});
722  }
723 
724  res.status = Message::STATUS_OK;
725  }
726 
727  void DaemonHandler::handle(const GetOutputKeys::Request& req, GetOutputKeys::Response& res)
728  {
729  try
730  {
731  for (const auto& i : req.outputs)
732  {
734  rct::key mask;
735  bool unlocked;
736  m_core.get_blockchain_storage().get_output_key_mask_unlocked(i.amount, i.index, key, mask, unlocked);
737  res.keys.emplace_back(output_key_mask_unlocked{key, mask, unlocked});
738  }
739  }
740  catch (const std::exception& e)
741  {
742  res.status = Message::STATUS_FAILED;
743  res.error_details = e.what();
744  return;
745  }
746 
747  res.status = Message::STATUS_OK;
748  }
749 
750  void DaemonHandler::handle(const GetRPCVersion::Request& req, GetRPCVersion::Response& res)
751  {
752  res.version = DAEMON_RPC_VERSION_ZMQ;
753  res.status = Message::STATUS_OK;
754  }
755 
756  void DaemonHandler::handle(const GetFeeEstimate::Request& req, GetFeeEstimate::Response& res)
757  {
758  res.hard_fork_version = m_core.get_blockchain_storage().get_current_hard_fork_version();
759  res.estimated_base_fee = m_core.get_blockchain_storage().get_dynamic_base_fee_estimate(req.num_grace_blocks);
760 
761  if (res.hard_fork_version < HF_VERSION_PER_BYTE_FEE)
762  {
763  res.size_scale = 1024; // per KiB fee
764  res.fee_mask = 1;
765  }
766  else
767  {
768  res.size_scale = 1; // per byte fee
770  }
771  res.status = Message::STATUS_OK;
772  }
773 
774  void DaemonHandler::handle(const GetOutputDistribution::Request& req, GetOutputDistribution::Response& res)
775  {
776  try
777  {
778  res.distributions.reserve(req.amounts.size());
779 
780  const uint64_t req_to_height = req.to_height ? req.to_height : (m_core.get_current_blockchain_height() - 1);
781  for (std::uint64_t amount : req.amounts)
782  {
783  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());
784  if (!data)
785  {
786  res.distributions.clear();
787  res.status = Message::STATUS_FAILED;
788  res.error_details = "Failed to get output distribution";
789  return;
790  }
791  res.distributions.push_back(output_distribution{std::move(*data), amount, req.cumulative});
792  }
793  res.status = Message::STATUS_OK;
794  }
795  catch (const std::exception& e)
796  {
797  res.distributions.clear();
798  res.status = Message::STATUS_FAILED;
799  res.error_details = e.what();
800  }
801  }
802 
803  bool DaemonHandler::getBlockHeaderByHash(const crypto::hash& hash_in, cryptonote::rpc::BlockHeaderResponse& header)
804  {
805  block b;
806 
807  if (!m_core.get_block_by_hash(hash_in, b))
808  {
809  return false;
810  }
811 
812  header.hash = hash_in;
813  if (b.miner_tx.vin.size() != 1 || b.miner_tx.vin.front().type() != typeid(txin_gen))
814  {
815  return false;
816  }
817  header.height = boost::get<txin_gen>(b.miner_tx.vin.front()).height;
818 
819  header.major_version = b.major_version;
820  header.minor_version = b.minor_version;
821  header.timestamp = b.timestamp;
822  header.nonce = b.nonce;
823  header.prev_id = b.prev_id;
824 
825  header.depth = m_core.get_current_blockchain_height() - header.height - 1;
826 
827  header.reward = 0;
828  for (const auto& out : b.miner_tx.vout)
829  {
830  header.reward += out.amount;
831  }
832 
834  header.difficulty = (header.wide_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
835 
836  return true;
837  }
838 
840  {
841  MDEBUG("Handling RPC request: " << request);
842 
843  Message* resp_message = NULL;
844 
845  try
846  {
847  FullMessage req_full(request, true);
848 
849  rapidjson::Value& req_json = req_full.getMessage();
850 
851  const std::string request_type = req_full.getRequestType();
852 
853  // create correct Message subclass and call handle() on it
854  REQ_RESP_TYPES_MACRO(request_type, GetHeight, req_json, resp_message, handle);
855  REQ_RESP_TYPES_MACRO(request_type, GetBlocksFast, req_json, resp_message, handle);
856  REQ_RESP_TYPES_MACRO(request_type, GetHashesFast, req_json, resp_message, handle);
857  REQ_RESP_TYPES_MACRO(request_type, GetTransactions, req_json, resp_message, handle);
858  REQ_RESP_TYPES_MACRO(request_type, KeyImagesSpent, req_json, resp_message, handle);
859  REQ_RESP_TYPES_MACRO(request_type, GetTxGlobalOutputIndices, req_json, resp_message, handle);
860  REQ_RESP_TYPES_MACRO(request_type, SendRawTx, req_json, resp_message, handle);
861  REQ_RESP_TYPES_MACRO(request_type, SendRawTxHex, req_json, resp_message, handle);
862  REQ_RESP_TYPES_MACRO(request_type, GetInfo, req_json, resp_message, handle);
863  REQ_RESP_TYPES_MACRO(request_type, StartMining, req_json, resp_message, handle);
864  REQ_RESP_TYPES_MACRO(request_type, StopMining, req_json, resp_message, handle);
865  REQ_RESP_TYPES_MACRO(request_type, MiningStatus, req_json, resp_message, handle);
866  REQ_RESP_TYPES_MACRO(request_type, SaveBC, req_json, resp_message, handle);
867  REQ_RESP_TYPES_MACRO(request_type, GetBlockHash, req_json, resp_message, handle);
868  REQ_RESP_TYPES_MACRO(request_type, GetLastBlockHeader, req_json, resp_message, handle);
869  REQ_RESP_TYPES_MACRO(request_type, GetBlockHeaderByHash, req_json, resp_message, handle);
870  REQ_RESP_TYPES_MACRO(request_type, GetBlockHeaderByHeight, req_json, resp_message, handle);
871  REQ_RESP_TYPES_MACRO(request_type, GetBlockHeadersByHeight, req_json, resp_message, handle);
872  REQ_RESP_TYPES_MACRO(request_type, GetPeerList, req_json, resp_message, handle);
873  REQ_RESP_TYPES_MACRO(request_type, SetLogLevel, req_json, resp_message, handle);
874  REQ_RESP_TYPES_MACRO(request_type, GetTransactionPool, req_json, resp_message, handle);
875  REQ_RESP_TYPES_MACRO(request_type, HardForkInfo, req_json, resp_message, handle);
876  REQ_RESP_TYPES_MACRO(request_type, GetOutputHistogram, req_json, resp_message, handle);
877  REQ_RESP_TYPES_MACRO(request_type, GetOutputKeys, req_json, resp_message, handle);
878  REQ_RESP_TYPES_MACRO(request_type, GetRPCVersion, req_json, resp_message, handle);
879  REQ_RESP_TYPES_MACRO(request_type, GetFeeEstimate, req_json, resp_message, handle);
880  REQ_RESP_TYPES_MACRO(request_type, GetOutputDistribution, req_json, resp_message, handle);
881 
882  // if none of the request types matches
883  if (resp_message == NULL)
884  {
885  return BAD_REQUEST(request_type, req_full.getID());
886  }
887 
888  FullMessage resp_full = FullMessage::responseMessage(resp_message, req_full.getID());
889 
890  const std::string response = resp_full.getJson();
891  delete resp_message;
892  resp_message = NULL;
893 
894  MDEBUG("Returning RPC response: " << response);
895 
896  return response;
897  }
898  catch (const std::exception& e)
899  {
900  if (resp_message)
901  {
902  delete resp_message;
903  }
904 
905  return BAD_JSON(e.what());
906  }
907  }
908 
909 } // namespace rpc
910 
911 } // namespace cryptonote
uint64_t height
Definition: blockchain.cpp:91
virtual uint64_t get_tx_block_height(const crypto::hash &h) const =0
fetches the height of a transaction's block
virtual difficulty_type get_block_cumulative_difficulty(const uint64_t &height) const =0
fetch a block's cumulative difficulty
virtual crypto::hash get_block_hash_from_height(const uint64_t &height) const =0
fetch a block's hash
uint8_t get_current_hard_fork_version() const
gets the current hardfork version in use/voted for
Definition: blockchain.h:815
uint64_t get_dynamic_base_fee_estimate(uint64_t grace_blocks) const
get dynamic per kB or byte fee estimate for the next few blocks
HardFork::State get_hard_fork_state() const
gets the hardfork voting state object
uint64_t get_current_cumulative_block_weight_median() const
gets the block weight median based on recent blocks (same window as for the limit)
difficulty_type block_difficulty(uint64_t i) const
gets the difficulty of the block with a given height
uint64_t get_current_cumulative_block_weight_limit() const
gets the block weight limit based on recent blocks
bool store_blockchain()
stores the blockchain
Definition: blockchain.cpp:516
static uint64_t get_fee_quantization_mask()
get fee quantization mask
const BlockchainDB & get_db() const
get a reference to the BlockchainDB in use by Blockchain
Definition: blockchain.h:953
uint8_t get_ideal_hard_fork_version() const
returns the newest hardfork version known to the blockchain
Definition: blockchain.h:822
std::map< uint64_t, std::tuple< uint64_t, uint64_t, uint64_t > > get_output_histogram(const std::vector< uint64_t > &amounts, bool unlocked, uint64_t recent_cutoff, uint64_t min_count=0) const
return a histogram of outputs on the blockchain
void get_output_key_mask_unlocked(const uint64_t &amount, const uint64_t &index, crypto::public_key &key, rct::key &mask, bool &unlocked) const
gets an output's key and unlocked state
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
size_t get_pool_transactions_count() const
get the total number of transactions in the pool
bool get_transactions(const std::vector< crypto::hash > &txs_ids, std::vector< cryptonote::blobdata > &txs, std::vector< crypto::hash > &missed_txs) const
bool get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector< uint64_t > &distribution, uint64_t &base) const
gets per block distribution of outputs of a given amount
bool are_key_images_spent_in_pool(const std::vector< crypto::key_image > &key_im, std::vector< bool > &spent) const
check if multiple key images are spent in the transaction pool
uint64_t get_current_blockchain_height() const
get the current height of the blockchain
Blockchain & get_blockchain_storage()
gets the Blockchain instance
crypto::hash get_tail_id() const
get the hash of the most recent block on the blockchain
network_type get_nettype() const
get the network type we're on
std::time_t get_start_time() const
gets start_time
crypto::hash get_block_id_by_height(uint64_t height) const
gets a block's hash given a height
i_cryptonote_protocol * get_protocol()
get the cryptonote protocol instance
uint64_t get_target_blockchain_height() const
gets the target blockchain height
bool get_pool_for_rpc(std::vector< cryptonote::rpc::tx_in_pool > &tx_infos, cryptonote::rpc::key_images_with_tx_hashes &key_image_infos) const
get information about all transactions and key images in the pool
miner & get_miner()
gets the miner instance
bool find_blockchain_supplement(const std::list< crypto::hash > &qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request &resp) const
get recent block hashes for a foreign chain
bool get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan=NULL) const
gets the block with a given hash
bool are_key_images_spent(const std::vector< crypto::key_image > &key_im, std::vector< bool > &spent) const
check if multiple key images are spent
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
bool get_pool_transactions(std::vector< transaction > &txs, bool include_unrelayed_txes=true) const
get a list of all transactions in the pool
bool get_tx_outputs_gindexs(const crypto::hash &tx_id, std::vector< uint64_t > &indexs) const
gets the global indices for outputs from a given transaction
const account_public_address & get_mining_address() const
Definition: miner.cpp:357
bool is_mining() const
Definition: miner.cpp:352
uint64_t get_speed() const
Definition: miner.cpp:422
uint32_t get_threads_count() const
Definition: miner.cpp:362
bool get_is_background_mining_enabled() const
Definition: miner.cpp:604
bool start(const account_public_address &adr, size_t threads_count, bool do_background=false, bool ignore_battery=false)
Definition: miner.cpp:366
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)
Definition: rpc_handler.cpp:29
#define HF_VERSION_PER_BYTE_FEE
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT
GenericValue< UTF8<> > Value
GenericValue with UTF8 encoding.
Definition: document.h:2116
const char * res
Definition: hmac_keccak.cpp:41
const char * key
Definition: hmac_keccak.cpp:39
#define REQ_RESP_TYPES_MACRO(runtime_str, type, reqjson, resp_message_ptr, handler)
Definition: message.h:39
#define AUTO_VAL_INIT(v)
Definition: misc_language.h:53
#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:76
POD_CLASS hash
Definition: hash.h:50
SendRawTx::Response Response
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)
epee::misc_utils::struct_init< response_t > response
bool parse_hexstr_to_binbuff(const epee::span< const char > s, epee::span< char > &res)
Definition: string_tools.h:92
version
Supported socks variants.
Definition: socks.h:58
::std::string string
Definition: gtest-port.h:1097
const T & move(const T &t)
Definition: gtest-port.h:1317
CXA_THROW_INFO_T * info
Definition: stack_trace.cpp:91
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
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request &arg, cryptonote_connection_context &exclude_context)=0
cryptonote::difficulty_type wide_difficulty
std::vector< cryptonote::transaction > transactions
const char *const ELECTRONEUM_VERSION