Bitcoin ABC  0.22.13
P2P Digital Currency
rpcconsole.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2019 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #if defined(HAVE_CONFIG_H)
6 #include <config/bitcoin-config.h>
7 #endif
8 
9 #include <qt/rpcconsole.h>
10 
11 #include <chainparams.h>
12 #include <config.h>
13 #include <interfaces/node.h>
14 #include <netbase.h>
15 #include <qt/bantablemodel.h>
16 #include <qt/clientmodel.h>
17 #include <qt/forms/ui_debugwindow.h>
18 #include <qt/platformstyle.h>
19 #include <qt/walletmodel.h>
20 #include <rpc/client.h>
21 #include <rpc/server.h>
22 #include <util/strencodings.h>
23 #include <util/system.h>
24 
25 #ifdef ENABLE_WALLET
26 #include <wallet/bdb.h>
27 #include <wallet/wallet.h>
28 
29 #include <db_cxx.h>
30 #endif
31 
32 #include <univalue.h>
33 
34 #include <QKeyEvent>
35 #include <QMenu>
36 #include <QMessageBox>
37 #include <QScreen>
38 #include <QScrollBar>
39 #include <QSettings>
40 #include <QStringList>
41 #include <QTime>
42 #include <QTimer>
43 
44 // TODO: add a scrollback limit, as there is currently none
45 // TODO: make it possible to filter out categories (esp debug messages when
46 // implemented)
47 // TODO: receive errors and debug messages through ClientModel
48 
49 const int CONSOLE_HISTORY = 50;
51 const QSize FONT_RANGE(4, 40);
52 const char fontSizeSettingsKey[] = "consoleFontSize";
53 
54 const struct {
55  const char *url;
56  const char *source;
57 } ICON_MAPPING[] = {{"cmd-request", ":/icons/tx_input"},
58  {"cmd-reply", ":/icons/tx_output"},
59  {"cmd-error", ":/icons/tx_output"},
60  {"misc", ":/icons/tx_inout"},
61  {nullptr, nullptr}};
62 
63 namespace {
64 
65 // don't add private key handling cmd's to the history
66 const QStringList historyFilter = QStringList() << "importprivkey"
67  << "importmulti"
68  << "sethdseed"
69  << "signmessagewithprivkey"
70  << "signrawtransactionwithkey"
71  << "walletpassphrase"
72  << "walletpassphrasechange"
73  << "encryptwallet";
74 } // namespace
75 
76 /* Object for executing console RPC commands in a separate thread.
77  */
78 class RPCExecutor : public QObject {
79  Q_OBJECT
80 public:
81  explicit RPCExecutor(interfaces::Node &node) : m_node(node) {}
82 
83 public Q_SLOTS:
84  void request(const QString &command, const WalletModel *wallet_model);
85 
86 Q_SIGNALS:
87  void reply(int category, const QString &command);
88 
89 private:
91 };
92 
96 class QtRPCTimerBase : public QObject, public RPCTimerBase {
97  Q_OBJECT
98 public:
99  QtRPCTimerBase(std::function<void()> &_func, int64_t millis) : func(_func) {
100  timer.setSingleShot(true);
101  connect(&timer, &QTimer::timeout, [this] { func(); });
102  timer.start(millis);
103  }
105 
106 private:
107  QTimer timer;
108  std::function<void()> func;
109 };
110 
112 public:
114  const char *Name() override { return "Qt"; }
115  RPCTimerBase *NewTimer(std::function<void()> &func,
116  int64_t millis) override {
117  return new QtRPCTimerBase(func, millis);
118  }
119 };
120 
121 #include <qt/rpcconsole.moc>
122 
150  std::string &strResult,
151  const std::string &strCommand,
152  const bool fExecute,
153  std::string *const pstrFilteredOut,
154  const WalletModel *wallet_model) {
155  std::vector<std::vector<std::string>> stack;
156  stack.push_back(std::vector<std::string>());
157 
158  enum CmdParseState {
159  STATE_EATING_SPACES,
160  STATE_EATING_SPACES_IN_ARG,
161  STATE_EATING_SPACES_IN_BRACKETS,
162  STATE_ARGUMENT,
163  STATE_SINGLEQUOTED,
164  STATE_DOUBLEQUOTED,
165  STATE_ESCAPE_OUTER,
166  STATE_ESCAPE_DOUBLEQUOTED,
167  STATE_COMMAND_EXECUTED,
168  STATE_COMMAND_EXECUTED_INNER
169  } state = STATE_EATING_SPACES;
170  std::string curarg;
171  UniValue lastResult;
172  unsigned nDepthInsideSensitive = 0;
173  size_t filter_begin_pos = 0, chpos;
174  std::vector<std::pair<size_t, size_t>> filter_ranges;
175 
176  auto add_to_current_stack = [&](const std::string &strArg) {
177  if (stack.back().empty() && (!nDepthInsideSensitive) &&
178  historyFilter.contains(QString::fromStdString(strArg),
179  Qt::CaseInsensitive)) {
180  nDepthInsideSensitive = 1;
181  filter_begin_pos = chpos;
182  }
183  // Make sure stack is not empty before adding something
184  if (stack.empty()) {
185  stack.push_back(std::vector<std::string>());
186  }
187  stack.back().push_back(strArg);
188  };
189 
190  auto close_out_params = [&]() {
191  if (nDepthInsideSensitive) {
192  if (!--nDepthInsideSensitive) {
193  assert(filter_begin_pos);
194  filter_ranges.push_back(
195  std::make_pair(filter_begin_pos, chpos));
196  filter_begin_pos = 0;
197  }
198  }
199  stack.pop_back();
200  };
201 
202  std::string strCommandTerminated = strCommand;
203  if (strCommandTerminated.back() != '\n') {
204  strCommandTerminated += "\n";
205  }
206  for (chpos = 0; chpos < strCommandTerminated.size(); ++chpos) {
207  char ch = strCommandTerminated[chpos];
208  switch (state) {
209  case STATE_COMMAND_EXECUTED_INNER:
210  case STATE_COMMAND_EXECUTED: {
211  bool breakParsing = true;
212  switch (ch) {
213  case '[':
214  curarg.clear();
215  state = STATE_COMMAND_EXECUTED_INNER;
216  break;
217  default:
218  if (state == STATE_COMMAND_EXECUTED_INNER) {
219  if (ch != ']') {
220  // append char to the current argument (which is
221  // also used for the query command)
222  curarg += ch;
223  break;
224  }
225  if (curarg.size() && fExecute) {
226  // if we have a value query, query arrays with
227  // index and objects with a string key
228  UniValue subelement;
229  if (lastResult.isArray()) {
230  for (char argch : curarg) {
231  if (!IsDigit(argch)) {
232  throw std::runtime_error(
233  "Invalid result query");
234  }
235  }
236  subelement =
237  lastResult[atoi(curarg.c_str())];
238  } else if (lastResult.isObject()) {
239  subelement = find_value(lastResult, curarg);
240  } else {
241  // no array or object: abort
242  throw std::runtime_error(
243  "Invalid result query");
244  }
245  lastResult = subelement;
246  }
247 
248  state = STATE_COMMAND_EXECUTED;
249  break;
250  }
251  // don't break parsing when the char is required for the
252  // next argument
253  breakParsing = false;
254 
255  // pop the stack and return the result to the current
256  // command arguments
257  close_out_params();
258 
259  // don't stringify the json in case of a string to avoid
260  // doublequotes
261  if (lastResult.isStr()) {
262  curarg = lastResult.get_str();
263  } else {
264  curarg = lastResult.write(2);
265  }
266 
267  // if we have a non empty result, use it as stack
268  // argument otherwise as general result
269  if (curarg.size()) {
270  if (stack.size()) {
271  add_to_current_stack(curarg);
272  } else {
273  strResult = curarg;
274  }
275  }
276  curarg.clear();
277  // assume eating space state
278  state = STATE_EATING_SPACES;
279  }
280 
281  if (breakParsing) {
282  break;
283  }
284  }
285  // FALLTHROUGH
286  case STATE_ARGUMENT: // In or after argument
287  case STATE_EATING_SPACES_IN_ARG:
288  case STATE_EATING_SPACES_IN_BRACKETS:
289  case STATE_EATING_SPACES: // Handle runs of whitespace
290  switch (ch) {
291  case '"':
292  state = STATE_DOUBLEQUOTED;
293  break;
294  case '\'':
295  state = STATE_SINGLEQUOTED;
296  break;
297  case '\\':
298  state = STATE_ESCAPE_OUTER;
299  break;
300  case '(':
301  case ')':
302  case '\n':
303  if (state == STATE_EATING_SPACES_IN_ARG) {
304  throw std::runtime_error("Invalid Syntax");
305  }
306  if (state == STATE_ARGUMENT) {
307  if (ch == '(' && stack.size() &&
308  stack.back().size() > 0) {
309  if (nDepthInsideSensitive) {
310  ++nDepthInsideSensitive;
311  }
312  stack.push_back(std::vector<std::string>());
313  }
314 
315  // don't allow commands after executed commands on
316  // baselevel
317  if (!stack.size()) {
318  throw std::runtime_error("Invalid Syntax");
319  }
320 
321  add_to_current_stack(curarg);
322  curarg.clear();
323  state = STATE_EATING_SPACES_IN_BRACKETS;
324  }
325  if ((ch == ')' || ch == '\n') && stack.size() > 0) {
326  if (fExecute) {
327  // Convert argument list to JSON objects in
328  // method-dependent way, and pass it along with
329  // the method name to the dispatcher.
330  UniValue params = RPCConvertValues(
331  stack.back()[0],
332  std::vector<std::string>(
333  stack.back().begin() + 1,
334  stack.back().end()));
335  std::string method = stack.back()[0];
336  std::string uri;
337 
338 #ifdef ENABLE_WALLET
339  if (wallet_model) {
340  QByteArray encodedName =
341  QUrl::toPercentEncoding(
342  wallet_model->getWalletName());
343  uri = "/wallet/" +
344  std::string(encodedName.constData(),
345  encodedName.length());
346  }
347 #endif
348 
349  GlobalConfig config;
350  assert(node);
351  lastResult = node->executeRpc(config, method,
352  params, uri);
353  }
354 
355  state = STATE_COMMAND_EXECUTED;
356  curarg.clear();
357  }
358  break;
359  case ' ':
360  case ',':
361  case '\t':
362  if (state == STATE_EATING_SPACES_IN_ARG &&
363  curarg.empty() && ch == ',') {
364  throw std::runtime_error("Invalid Syntax");
365  } else if (state == STATE_ARGUMENT) {
366  // Space ends argument
367  add_to_current_stack(curarg);
368  curarg.clear();
369  }
370  if ((state == STATE_EATING_SPACES_IN_BRACKETS ||
371  state == STATE_ARGUMENT) &&
372  ch == ',') {
373  state = STATE_EATING_SPACES_IN_ARG;
374  break;
375  }
376  state = STATE_EATING_SPACES;
377  break;
378  default:
379  curarg += ch;
380  state = STATE_ARGUMENT;
381  }
382  break;
383  case STATE_SINGLEQUOTED: // Single-quoted string
384  switch (ch) {
385  case '\'':
386  state = STATE_ARGUMENT;
387  break;
388  default:
389  curarg += ch;
390  }
391  break;
392  case STATE_DOUBLEQUOTED: // Double-quoted string
393  switch (ch) {
394  case '"':
395  state = STATE_ARGUMENT;
396  break;
397  case '\\':
398  state = STATE_ESCAPE_DOUBLEQUOTED;
399  break;
400  default:
401  curarg += ch;
402  }
403  break;
404  case STATE_ESCAPE_OUTER: // '\' outside quotes
405  curarg += ch;
406  state = STATE_ARGUMENT;
407  break;
408  case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
409  if (ch != '"' && ch != '\\') {
410  // keep '\' for everything but the quote and '\' itself
411  curarg += '\\';
412  }
413  curarg += ch;
414  state = STATE_DOUBLEQUOTED;
415  break;
416  }
417  }
418  if (pstrFilteredOut) {
419  if (STATE_COMMAND_EXECUTED == state) {
420  assert(!stack.empty());
421  close_out_params();
422  }
423  *pstrFilteredOut = strCommand;
424  for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) {
425  pstrFilteredOut->replace(i->first, i->second - i->first, "(…)");
426  }
427  }
428 
429  // final state
430  switch (state) {
431  case STATE_COMMAND_EXECUTED:
432  if (lastResult.isStr()) {
433  strResult = lastResult.get_str();
434  } else {
435  strResult = lastResult.write(2);
436  }
437  // FALLTHROUGH
438  case STATE_ARGUMENT:
439  case STATE_EATING_SPACES:
440  return true;
441  default: // ERROR to end in one of the other states
442  return false;
443  }
444 }
445 
446 void RPCExecutor::request(const QString &command,
447  const WalletModel *wallet_model) {
448  try {
449  std::string result;
450  std::string executableCommand = command.toStdString() + "\n";
451 
452  // Catch the console-only-help command before RPC call is executed and
453  // reply with help text as-if a RPC reply.
454  if (executableCommand == "help-console\n") {
455  Q_EMIT reply(
457  QString(("\n"
458  "This console accepts RPC commands using the standard "
459  "syntax.\n"
460  " example: getblockhash 0\n\n"
461 
462  "This console can also accept RPC commands using "
463  "parenthesized syntax.\n"
464  " example: getblockhash(0)\n\n"
465 
466  "Commands may be nested when specified with the "
467  "parenthesized syntax.\n"
468  " example: getblock(getblockhash(0) 1)\n\n"
469 
470  "A space or a comma can be used to delimit arguments "
471  "for either syntax.\n"
472  " example: getblockhash 0\n"
473  " getblockhash,0\n\n"
474 
475  "Named results can be queried with a non-quoted key "
476  "string in brackets.\n"
477  " example: getblock(getblockhash(0) true)[tx]\n\n"
478 
479  "Results without keys can be queried using an integer "
480  "in brackets.\n"
481  " example: "
482  "getblock(getblockhash(0),true)[tx][0]\n\n")));
483  return;
484  }
486  m_node, result, executableCommand, nullptr, wallet_model)) {
488  QString("Parse error: unbalanced ' or \""));
489  return;
490  }
491 
492  Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(result));
493  } catch (UniValue &objError) {
494  // Nice formatting for standard-format error
495  try {
496  int code = find_value(objError, "code").get_int();
497  std::string message = find_value(objError, "message").get_str();
499  QString::fromStdString(message) + " (code " +
500  QString::number(code) + ")");
501  } catch (const std::runtime_error &) {
502  // raised when converting to invalid type, i.e. missing code or
503  // message. Show raw JSON object.
505  QString::fromStdString(objError.write()));
506  }
507  } catch (const std::exception &e) {
509  QString("Error: ") + QString::fromStdString(e.what()));
510  }
511 }
512 
514  const PlatformStyle *_platformStyle, QWidget *parent)
515  : QWidget(parent), m_node(node), ui(new Ui::RPCConsole),
516  platformStyle(_platformStyle) {
517  ui->setupUi(this);
518  QSettings settings;
519  if (!restoreGeometry(
520  settings.value("RPCConsoleWindowGeometry").toByteArray())) {
521  // Restore failed (perhaps missing setting), center the window
522  move(QGuiApplication::primaryScreen()->availableGeometry().center() -
523  frameGeometry().center());
524  }
525 
526  QChar nonbreaking_hyphen(8209);
527  ui->dataDir->setToolTip(
528  ui->dataDir->toolTip().arg(QString(nonbreaking_hyphen) + "datadir"));
529  ui->blocksDir->setToolTip(ui->blocksDir->toolTip().arg(
530  QString(nonbreaking_hyphen) + "blocksdir"));
531  ui->openDebugLogfileButton->setToolTip(
532  ui->openDebugLogfileButton->toolTip().arg(PACKAGE_NAME));
533 
535  ui->openDebugLogfileButton->setIcon(
536  platformStyle->SingleColorIcon(":/icons/export"));
537  }
538  ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
539  ui->fontBiggerButton->setIcon(
540  platformStyle->SingleColorIcon(":/icons/fontbigger"));
541  ui->fontSmallerButton->setIcon(
542  platformStyle->SingleColorIcon(":/icons/fontsmaller"));
543 
544  // Install event filter for up and down arrow
545  ui->lineEdit->installEventFilter(this);
546  ui->messagesWidget->installEventFilter(this);
547 
548  connect(ui->clearButton, &QPushButton::clicked, this, &RPCConsole::clear);
549  connect(ui->fontBiggerButton, &QPushButton::clicked, this,
551  connect(ui->fontSmallerButton, &QPushButton::clicked, this,
553  connect(ui->btnClearTrafficGraph, &QPushButton::clicked, ui->trafficGraph,
555 
556  // disable the wallet selector by default
557  ui->WalletSelector->setVisible(false);
558  ui->WalletSelectorLabel->setVisible(false);
559 
560 // set library version labels
561 #ifdef ENABLE_WALLET
562  ui->berkeleyDBVersion->setText(DbEnv::version(nullptr, nullptr, nullptr));
563 #else
564  ui->label_berkeleyDBVersion->hide();
565  ui->berkeleyDBVersion->hide();
566 #endif
567  // Register RPC timer interface
569  // avoid accidentally overwriting an existing, non QTThread
570  // based timer interface
572 
574 
575  ui->detailWidget->hide();
576  ui->peerHeading->setText(tr("Select a peer to view detailed information."));
577 
579  settings.value(fontSizeSettingsKey, QFontInfo(QFont()).pointSize())
580  .toInt();
581  clear();
582 
584 }
585 
587  QSettings settings;
588  settings.setValue("RPCConsoleWindowGeometry", saveGeometry());
590  delete rpcTimerInterface;
591  delete ui;
592 }
593 
594 bool RPCConsole::eventFilter(QObject *obj, QEvent *event) {
595  // Special key handling
596  if (event->type() == QEvent::KeyPress) {
597  QKeyEvent *keyevt = static_cast<QKeyEvent *>(event);
598  int key = keyevt->key();
599  Qt::KeyboardModifiers mod = keyevt->modifiers();
600  switch (key) {
601  case Qt::Key_Up:
602  if (obj == ui->lineEdit) {
603  browseHistory(-1);
604  return true;
605  }
606  break;
607  case Qt::Key_Down:
608  if (obj == ui->lineEdit) {
609  browseHistory(1);
610  return true;
611  }
612  break;
613  case Qt::Key_PageUp: /* pass paging keys to messages widget */
614  case Qt::Key_PageDown:
615  if (obj == ui->lineEdit) {
616  QApplication::postEvent(ui->messagesWidget,
617  new QKeyEvent(*keyevt));
618  return true;
619  }
620  break;
621  case Qt::Key_Return:
622  case Qt::Key_Enter:
623  // forward these events to lineEdit
624  if (obj == autoCompleter->popup()) {
625  QApplication::postEvent(ui->lineEdit,
626  new QKeyEvent(*keyevt));
627  return true;
628  }
629  break;
630  default:
631  // Typing in messages widget brings focus to line edit, and
632  // redirects key there. Exclude most combinations and keys that
633  // emit no text, except paste shortcuts.
634  if (obj == ui->messagesWidget &&
635  ((!mod && !keyevt->text().isEmpty() &&
636  key != Qt::Key_Tab) ||
637  ((mod & Qt::ControlModifier) && key == Qt::Key_V) ||
638  ((mod & Qt::ShiftModifier) && key == Qt::Key_Insert))) {
639  ui->lineEdit->setFocus();
640  QApplication::postEvent(ui->lineEdit,
641  new QKeyEvent(*keyevt));
642  return true;
643  }
644  }
645  }
646  return QWidget::eventFilter(obj, event);
647 }
648 
650  clientModel = model;
651 
652  bool wallet_enabled{false};
653 #ifdef ENABLE_WALLET
654  wallet_enabled = WalletModel::isWalletEnabled();
655 #endif // ENABLE_WALLET
656  if (model && !wallet_enabled) {
657  // Show warning, for example if this is a prerelease version
658  connect(model, &ClientModel::alertsChanged, this,
661  }
662 
663  ui->trafficGraph->setClientModel(model);
664  if (model && clientModel->getPeerTableModel() &&
666  // Keep up to date with client
668  connect(model, &ClientModel::numConnectionsChanged, this,
670 
671  interfaces::Node &node = clientModel->node();
672  setNumBlocks(node.getNumBlocks(),
673  QDateTime::fromTime_t(node.getLastBlockTime()),
674  node.getVerificationProgress(), false);
675  connect(model, &ClientModel::numBlocksChanged, this,
677 
679  connect(model, &ClientModel::networkActiveChanged, this,
681 
683  connect(model, &ClientModel::bytesChanged, this,
685 
686  connect(model, &ClientModel::mempoolSizeChanged, this,
688 
689  // set up peer table
690  ui->peerWidget->setModel(model->getPeerTableModel());
691  ui->peerWidget->verticalHeader()->hide();
692  ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
693  ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
694  ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
695  ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
696  ui->peerWidget->setColumnWidth(PeerTableModel::Address,
698  ui->peerWidget->setColumnWidth(PeerTableModel::Subversion,
700  ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH);
701  ui->peerWidget->horizontalHeader()->setStretchLastSection(true);
702 
703  // create peer table context menu actions
704  QAction *disconnectAction = new QAction(tr("&Disconnect"), this);
705  QAction *banAction1h =
706  new QAction(tr("Ban for") + " " + tr("1 &hour"), this);
707  QAction *banAction24h =
708  new QAction(tr("Ban for") + " " + tr("1 &day"), this);
709  QAction *banAction7d =
710  new QAction(tr("Ban for") + " " + tr("1 &week"), this);
711  QAction *banAction365d =
712  new QAction(tr("Ban for") + " " + tr("1 &year"), this);
713 
714  // create peer table context menu
715  peersTableContextMenu = new QMenu(this);
716  peersTableContextMenu->addAction(disconnectAction);
717  peersTableContextMenu->addAction(banAction1h);
718  peersTableContextMenu->addAction(banAction24h);
719  peersTableContextMenu->addAction(banAction7d);
720  peersTableContextMenu->addAction(banAction365d);
721 
722  connect(banAction1h, &QAction::triggered,
723  [this] { banSelectedNode(60 * 60); });
724  connect(banAction24h, &QAction::triggered,
725  [this] { banSelectedNode(60 * 60 * 24); });
726  connect(banAction7d, &QAction::triggered,
727  [this] { banSelectedNode(60 * 60 * 24 * 7); });
728  connect(banAction365d, &QAction::triggered,
729  [this] { banSelectedNode(60 * 60 * 24 * 365); });
730 
731  // peer table context menu signals
732  connect(ui->peerWidget, &QTableView::customContextMenuRequested, this,
734  connect(disconnectAction, &QAction::triggered, this,
736 
737  // peer table signal handling - update peer details when selecting new
738  // node
739  connect(ui->peerWidget->selectionModel(),
740  &QItemSelectionModel::selectionChanged, this,
742  // peer table signal handling - update peer details when new nodes are
743  // added to the model
744  connect(model->getPeerTableModel(), &PeerTableModel::layoutChanged,
746  // peer table signal handling - cache selected node ids
747  connect(model->getPeerTableModel(),
748  &PeerTableModel::layoutAboutToBeChanged, this,
750 
751  // set up ban table
752  ui->banlistWidget->setModel(model->getBanTableModel());
753  ui->banlistWidget->verticalHeader()->hide();
754  ui->banlistWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
755  ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
756  ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection);
757  ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu);
758  ui->banlistWidget->setColumnWidth(BanTableModel::Address,
760  ui->banlistWidget->setColumnWidth(BanTableModel::Bantime,
762  ui->banlistWidget->horizontalHeader()->setStretchLastSection(true);
763 
764  // create ban table context menu action
765  QAction *unbanAction = new QAction(tr("&Unban"), this);
766 
767  // create ban table context menu
768  banTableContextMenu = new QMenu(this);
769  banTableContextMenu->addAction(unbanAction);
770 
771  // ban table context menu signals
772  connect(ui->banlistWidget, &QTableView::customContextMenuRequested,
774  connect(unbanAction, &QAction::triggered, this,
776 
777  // ban table signal handling - clear peer details when clicking a peer
778  // in the ban table
779  connect(ui->banlistWidget, &QTableView::clicked, this,
781  // ban table signal handling - ensure ban table is shown or hidden (if
782  // empty)
783  connect(model->getBanTableModel(), &BanTableModel::layoutChanged, this,
786 
787  // Provide initial values
788  ui->clientVersion->setText(model->formatFullVersion());
789  ui->clientUserAgent->setText(model->formatSubVersion());
790  ui->dataDir->setText(model->dataDir());
791  ui->blocksDir->setText(model->blocksDir());
792  ui->startupTime->setText(model->formatClientStartupTime());
793  ui->networkName->setText(
794  QString::fromStdString(Params().NetworkIDString()));
795 
796  // Setup autocomplete and attach it
797  QStringList wordList;
798  std::vector<std::string> commandList = m_node.listRpcCommands();
799  for (size_t i = 0; i < commandList.size(); ++i) {
800  wordList << commandList[i].c_str();
801  wordList << ("help " + commandList[i]).c_str();
802  }
803 
804  wordList << "help-console";
805  wordList.sort();
806  autoCompleter = new QCompleter(wordList, this);
807  autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
808  // ui->lineEdit is initially disabled because running commands is only
809  // possible from now on.
810  ui->lineEdit->setEnabled(true);
811  ui->lineEdit->setCompleter(autoCompleter);
812  autoCompleter->popup()->installEventFilter(this);
813  // Start thread to execute RPC commands.
814  startExecutor();
815  }
816  if (!model) {
817  // Client model is being set to 0, this means shutdown() is about to be
818  // called.
819  thread.quit();
820  thread.wait();
821  }
822 }
823 
824 #ifdef ENABLE_WALLET
825 void RPCConsole::addWallet(WalletModel *const walletModel) {
826  // use name for text and wallet model for internal data object (to allow to
827  // move to a wallet id later)
828  ui->WalletSelector->addItem(walletModel->getDisplayName(),
829  QVariant::fromValue(walletModel));
830  if (ui->WalletSelector->count() == 2 && !isVisible()) {
831  // First wallet added, set to default so long as the window isn't
832  // presently visible (and potentially in use)
833  ui->WalletSelector->setCurrentIndex(1);
834  }
835  if (ui->WalletSelector->count() > 2) {
836  ui->WalletSelector->setVisible(true);
837  ui->WalletSelectorLabel->setVisible(true);
838  }
839 }
840 
841 void RPCConsole::removeWallet(WalletModel *const walletModel) {
842  ui->WalletSelector->removeItem(
843  ui->WalletSelector->findData(QVariant::fromValue(walletModel)));
844  if (ui->WalletSelector->count() == 2) {
845  ui->WalletSelector->setVisible(false);
846  ui->WalletSelectorLabel->setVisible(false);
847  }
848 }
849 #endif
850 
851 static QString categoryClass(int category) {
852  switch (category) {
854  return "cmd-request";
855  break;
857  return "cmd-reply";
858  break;
860  return "cmd-error";
861  break;
862  default:
863  return "misc";
864  }
865 }
866 
869 }
870 
873 }
874 
875 void RPCConsole::setFontSize(int newSize) {
876  QSettings settings;
877 
878  // don't allow an insane font size
879  if (newSize < FONT_RANGE.width() || newSize > FONT_RANGE.height()) {
880  return;
881  }
882 
883  // temp. store the console content
884  QString str = ui->messagesWidget->toHtml();
885 
886  // replace font tags size in current content
887  str.replace(QString("font-size:%1pt").arg(consoleFontSize),
888  QString("font-size:%1pt").arg(newSize));
889 
890  // store the new font size
891  consoleFontSize = newSize;
892  settings.setValue(fontSizeSettingsKey, consoleFontSize);
893 
894  // clear console (reset icon sizes, default stylesheet) and re-add the
895  // content
896  float oldPosFactor = 1.0 /
897  ui->messagesWidget->verticalScrollBar()->maximum() *
898  ui->messagesWidget->verticalScrollBar()->value();
899  clear(false);
900  ui->messagesWidget->setHtml(str);
901  ui->messagesWidget->verticalScrollBar()->setValue(
902  oldPosFactor * ui->messagesWidget->verticalScrollBar()->maximum());
903 }
904 
905 void RPCConsole::clear(bool clearHistory) {
906  ui->messagesWidget->clear();
907  if (clearHistory) {
908  history.clear();
909  historyPtr = 0;
910  }
911  ui->lineEdit->clear();
912  ui->lineEdit->setFocus();
913 
914  // Add smoothly scaled icon images.
915  // (when using width/height on an img, Qt uses nearest instead of linear
916  // interpolation)
917  for (int i = 0; ICON_MAPPING[i].url; ++i) {
918  ui->messagesWidget->document()->addResource(
919  QTextDocument::ImageResource, QUrl(ICON_MAPPING[i].url),
921  .scaled(QSize(consoleFontSize * 2, consoleFontSize * 2),
922  Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
923  }
924 
925  // Set default style sheet
926  QFontInfo fixedFontInfo(GUIUtil::fixedPitchFont());
927  ui->messagesWidget->document()->setDefaultStyleSheet(
928  QString("table { }"
929  "td.time { color: #808080; font-size: %2; padding-top: 3px; } "
930  "td.message { font-family: %1; font-size: %2; "
931  "white-space:pre-wrap; } "
932  "td.cmd-request { color: #006060; } "
933  "td.cmd-error { color: red; } "
934  ".secwarning { color: red; }"
935  "b { color: #006060; } ")
936  .arg(fixedFontInfo.family(), QString("%1pt").arg(consoleFontSize)));
937 
938 #ifdef Q_OS_MAC
939  QString clsKey = "(⌘)-L";
940 #else
941  QString clsKey = "Ctrl-L";
942 #endif
943 
945  (tr("Welcome to the %1 RPC console.").arg(PACKAGE_NAME) + "<br>" +
946  tr("Use up and down arrows to navigate history, and "
947  "%1 to clear screen.")
948  .arg("<b>" + clsKey + "</b>") +
949  "<br>" +
950  tr("Type %1 for an overview of available commands.")
951  .arg("<b>help</b>") +
952  "<br>" +
953  tr("For more information on using this console type %1.")
954  .arg("<b>help-console</b>") +
955  "<br><span class=\"secwarning\"><br>" +
956  tr("WARNING: Scammers have been active, telling users to type "
957  "commands here, stealing their wallet contents. Do not use "
958  "this console without fully understanding the ramifications "
959  "of a command.") +
960  "</span>"),
961  true);
962 }
963 
964 void RPCConsole::keyPressEvent(QKeyEvent *event) {
965  if (windowType() != Qt::Widget && event->key() == Qt::Key_Escape) {
966  close();
967  }
968 }
969 
970 void RPCConsole::message(int category, const QString &message, bool html) {
971  QTime time = QTime::currentTime();
972  QString timeString = time.toString();
973  QString out;
974  out += "<table><tr><td class=\"time\" width=\"65\">" + timeString + "</td>";
975  out += "<td class=\"icon\" width=\"32\"><img src=\"" +
976  categoryClass(category) + "\"></td>";
977  out += "<td class=\"message " + categoryClass(category) +
978  "\" valign=\"middle\">";
979  if (html) {
980  out += message;
981  } else {
982  out += GUIUtil::HtmlEscape(message, false);
983  }
984  out += "</td></tr></table>";
985  ui->messagesWidget->append(out);
986 }
987 
989  QString connections =
990  QString::number(clientModel->getNumConnections()) + " (";
991  connections += tr("In:") + " " +
992  QString::number(clientModel->getNumConnections(
994  " / ";
995  connections += tr("Out:") + " " +
996  QString::number(clientModel->getNumConnections(
998  ")";
999 
1000  if (!clientModel->node().getNetworkActive()) {
1001  connections += " (" + tr("Network activity disabled") + ")";
1002  }
1003 
1004  ui->numberOfConnections->setText(connections);
1005 }
1006 
1008  if (!clientModel) {
1009  return;
1010  }
1011 
1013 }
1014 
1015 void RPCConsole::setNetworkActive(bool networkActive) {
1017 }
1018 
1019 void RPCConsole::setNumBlocks(int count, const QDateTime &blockDate,
1020  double nVerificationProgress, bool headers) {
1021  if (!headers) {
1022  ui->numberOfBlocks->setText(QString::number(count));
1023  ui->lastBlockTime->setText(blockDate.toString());
1024  }
1025 }
1026 
1027 void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage) {
1028  ui->mempoolNumberTxs->setText(QString::number(numberOfTxs));
1029 
1030  if (dynUsage < 1000000) {
1031  ui->mempoolSize->setText(QString::number(dynUsage / 1000.0, 'f', 2) +
1032  " KB");
1033  } else {
1034  ui->mempoolSize->setText(QString::number(dynUsage / 1000000.0, 'f', 2) +
1035  " MB");
1036  }
1037 }
1038 
1040  QString cmd = ui->lineEdit->text();
1041 
1042  if (!cmd.isEmpty()) {
1043  std::string strFilteredCmd;
1044  try {
1045  std::string dummy;
1046  if (!RPCParseCommandLine(nullptr, dummy, cmd.toStdString(), false,
1047  &strFilteredCmd)) {
1048  // Failed to parse command, so we cannot even filter it for the
1049  // history
1050  throw std::runtime_error("Invalid command line");
1051  }
1052  } catch (const std::exception &e) {
1053  QMessageBox::critical(this, "Error",
1054  QString("Error: ") +
1055  QString::fromStdString(e.what()));
1056  return;
1057  }
1058 
1059  ui->lineEdit->clear();
1060 
1061  cmdBeforeBrowsing = QString();
1062 
1063 #ifdef ENABLE_WALLET
1064  WalletModel *wallet_model =
1065  ui->WalletSelector->currentData().value<WalletModel *>();
1066 
1067  if (m_last_wallet_model != wallet_model) {
1068  if (wallet_model) {
1069  message(CMD_REQUEST, tr("Executing command using \"%1\" wallet")
1070  .arg(wallet_model->getWalletName()));
1071  } else {
1073  tr("Executing command without any wallet"));
1074  }
1075  m_last_wallet_model = wallet_model;
1076  }
1077 #endif
1078 
1079  message(CMD_REQUEST, QString::fromStdString(strFilteredCmd));
1080  Q_EMIT cmdRequest(cmd, m_last_wallet_model);
1081 
1082  cmd = QString::fromStdString(strFilteredCmd);
1083 
1084  // Remove command, if already in history
1085  history.removeOne(cmd);
1086  // Append command to history
1087  history.append(cmd);
1088  // Enforce maximum history size
1089  while (history.size() > CONSOLE_HISTORY) {
1090  history.removeFirst();
1091  }
1092  // Set pointer to end of history
1093  historyPtr = history.size();
1094 
1095  // Scroll console view to end
1096  scrollToEnd();
1097  }
1098 }
1099 
1100 void RPCConsole::browseHistory(int offset) {
1101  // store current text when start browsing through the history
1102  if (historyPtr == history.size()) {
1103  cmdBeforeBrowsing = ui->lineEdit->text();
1104  }
1105 
1106  historyPtr += offset;
1107  if (historyPtr < 0) {
1108  historyPtr = 0;
1109  }
1110  if (historyPtr > history.size()) {
1111  historyPtr = history.size();
1112  }
1113  QString cmd;
1114  if (historyPtr < history.size()) {
1115  cmd = history.at(historyPtr);
1116  } else if (!cmdBeforeBrowsing.isNull()) {
1117  cmd = cmdBeforeBrowsing;
1118  }
1119  ui->lineEdit->setText(cmd);
1120 }
1121 
1123  RPCExecutor *executor = new RPCExecutor(m_node);
1124  executor->moveToThread(&thread);
1125 
1126  // Replies from executor object must go to this object
1127  connect(executor, &RPCExecutor::reply, this,
1128  static_cast<void (RPCConsole::*)(int, const QString &)>(
1130 
1131  // Requests from this object must go to executor
1132  connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request);
1133 
1134  // Make sure executor object is deleted in its own thread
1135  connect(&thread, &QThread::finished, executor, &RPCExecutor::deleteLater);
1136 
1137  // Default implementation of QThread::run() simply spins up an event loop in
1138  // the thread, which is what we want.
1139  thread.start();
1140 }
1141 
1143  if (ui->tabWidget->widget(index) == ui->tab_console) {
1144  ui->lineEdit->setFocus();
1145  }
1146 }
1147 
1150 }
1151 
1153  QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar();
1154  scrollbar->setValue(scrollbar->maximum());
1155 }
1156 
1158  const int multiplier = 5; // each position on the slider represents 5 min
1159  int mins = value * multiplier;
1160  setTrafficGraphRange(mins);
1161 }
1162 
1164  ui->trafficGraph->setGraphRangeMins(mins);
1165  ui->lblGraphRange->setText(GUIUtil::formatDurationStr(mins * 60));
1166 }
1167 
1168 void RPCConsole::updateTrafficStats(quint64 totalBytesIn,
1169  quint64 totalBytesOut) {
1170  ui->lblBytesIn->setText(GUIUtil::formatBytes(totalBytesIn));
1171  ui->lblBytesOut->setText(GUIUtil::formatBytes(totalBytesOut));
1172 }
1173 
1174 void RPCConsole::peerSelected(const QItemSelection &selected,
1175  const QItemSelection &deselected) {
1176  Q_UNUSED(deselected);
1177 
1179  selected.indexes().isEmpty()) {
1180  return;
1181  }
1182 
1183  const CNodeCombinedStats *stats =
1185  selected.indexes().first().row());
1186  if (stats) {
1187  updateNodeDetail(stats);
1188  }
1189 }
1190 
1192  QModelIndexList selected =
1193  ui->peerWidget->selectionModel()->selectedIndexes();
1194  cachedNodeids.clear();
1195  for (int i = 0; i < selected.size(); i++) {
1196  const CNodeCombinedStats *stats =
1198  selected.at(i).row());
1199  cachedNodeids.append(stats->nodeStats.nodeid);
1200  }
1201 }
1202 
1205  return;
1206  }
1207 
1208  const CNodeCombinedStats *stats = nullptr;
1209  bool fUnselect = false;
1210  bool fReselect = false;
1211 
1212  // no node selected yet
1213  if (cachedNodeids.empty()) {
1214  return;
1215  }
1216 
1217  // find the currently selected row
1218  int selectedRow = -1;
1219  QModelIndexList selectedModelIndex =
1220  ui->peerWidget->selectionModel()->selectedIndexes();
1221  if (!selectedModelIndex.isEmpty()) {
1222  selectedRow = selectedModelIndex.first().row();
1223  }
1224 
1225  // check if our detail node has a row in the table (it may not necessarily
1226  // be at selectedRow since its position can change after a layout change)
1227  int detailNodeRow =
1229 
1230  if (detailNodeRow < 0) {
1231  // detail node disappeared from table (node disconnected)
1232  fUnselect = true;
1233  } else {
1234  if (detailNodeRow != selectedRow) {
1235  // detail node moved position
1236  fUnselect = true;
1237  fReselect = true;
1238  }
1239 
1240  // get fresh stats on the detail node.
1241  stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
1242  }
1243 
1244  if (fUnselect && selectedRow >= 0) {
1246  }
1247 
1248  if (fReselect) {
1249  for (int i = 0; i < cachedNodeids.size(); i++) {
1250  ui->peerWidget->selectRow(
1252  cachedNodeids.at(i)));
1253  }
1254  }
1255 
1256  if (stats) {
1257  updateNodeDetail(stats);
1258  }
1259 }
1260 
1262  // update the detail ui with latest node information
1263  QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) +
1264  " ");
1265  peerAddrDetails +=
1266  tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid));
1267  if (!stats->nodeStats.addrLocal.empty()) {
1268  peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(
1269  stats->nodeStats.addrLocal));
1270  }
1271  ui->peerHeading->setText(peerAddrDetails);
1272  ui->peerServices->setText(
1274  ui->peerLastSend->setText(
1275  stats->nodeStats.nLastSend
1277  stats->nodeStats.nLastSend)
1278  : tr("never"));
1279  ui->peerLastRecv->setText(
1280  stats->nodeStats.nLastRecv
1282  stats->nodeStats.nLastRecv)
1283  : tr("never"));
1284  ui->peerBytesSent->setText(
1286  ui->peerBytesRecv->setText(
1288  ui->peerConnTime->setText(GUIUtil::formatDurationStr(
1290  ui->peerPingTime->setText(
1292  ui->peerPingWait->setText(
1294  ui->peerMinPing->setText(
1296  ui->timeoffset->setText(
1298  ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion));
1299  ui->peerSubversion->setText(
1300  QString::fromStdString(stats->nodeStats.cleanSubVer));
1301  ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound")
1302  : tr("Outbound"));
1303  ui->peerHeight->setText(QString::number(stats->nodeStats.nStartingHeight));
1304  ui->peerWhitelisted->setText(
1305  stats->nodeStats.m_legacyWhitelisted ? tr("Yes") : tr("No"));
1306  ui->peerMappedAS->setText(
1307  stats->nodeStats.m_mapped_as != 0
1308  ? QString::number(stats->nodeStats.m_mapped_as)
1309  : tr("N/A"));
1310 
1311  // This check fails for example if the lock was busy and
1312  // nodeStateStats couldn't be fetched.
1313  if (stats->fNodeStateStatsAvailable) {
1314  // Sync height is init to -1
1315  if (stats->nodeStateStats.nSyncHeight > -1) {
1316  ui->peerSyncHeight->setText(
1317  QString("%1").arg(stats->nodeStateStats.nSyncHeight));
1318  } else {
1319  ui->peerSyncHeight->setText(tr("Unknown"));
1320  }
1321 
1322  // Common height is init to -1
1323  if (stats->nodeStateStats.nCommonHeight > -1) {
1324  ui->peerCommonHeight->setText(
1325  QString("%1").arg(stats->nodeStateStats.nCommonHeight));
1326  } else {
1327  ui->peerCommonHeight->setText(tr("Unknown"));
1328  }
1329  }
1330 
1331  ui->detailWidget->show();
1332 }
1333 
1334 void RPCConsole::resizeEvent(QResizeEvent *event) {
1335  QWidget::resizeEvent(event);
1336 }
1337 
1338 void RPCConsole::showEvent(QShowEvent *event) {
1339  QWidget::showEvent(event);
1340 
1342  return;
1343  }
1344 
1345  // start PeerTableModel auto refresh
1347 }
1348 
1349 void RPCConsole::hideEvent(QHideEvent *event) {
1350  QWidget::hideEvent(event);
1351 
1353  return;
1354  }
1355 
1356  // stop PeerTableModel auto refresh
1358 }
1359 
1360 void RPCConsole::showPeersTableContextMenu(const QPoint &point) {
1361  QModelIndex index = ui->peerWidget->indexAt(point);
1362  if (index.isValid()) {
1363  peersTableContextMenu->exec(QCursor::pos());
1364  }
1365 }
1366 
1367 void RPCConsole::showBanTableContextMenu(const QPoint &point) {
1368  QModelIndex index = ui->banlistWidget->indexAt(point);
1369  if (index.isValid()) {
1370  banTableContextMenu->exec(QCursor::pos());
1371  }
1372 }
1373 
1375  // Get selected peer addresses
1376  QList<QModelIndex> nodes =
1378  for (int i = 0; i < nodes.count(); i++) {
1379  // Get currently selected peer address
1380  NodeId id = nodes.at(i).data().toLongLong();
1381  // Find the node, disconnect it and clear the selected node
1382  if (m_node.disconnectById(id)) {
1384  }
1385  }
1386 }
1387 
1388 void RPCConsole::banSelectedNode(int bantime) {
1389  if (!clientModel) {
1390  return;
1391  }
1392 
1393  // Get selected peer addresses
1394  QList<QModelIndex> nodes =
1396  for (int i = 0; i < nodes.count(); i++) {
1397  // Get currently selected peer address
1398  NodeId id = nodes.at(i).data().toLongLong();
1399 
1400  // Get currently selected peer address
1401  int detailNodeRow =
1403  if (detailNodeRow < 0) {
1404  return;
1405  }
1406 
1407  // Find possible nodes, ban it and clear the selected node
1408  const CNodeCombinedStats *stats =
1409  clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
1410  if (stats) {
1411  m_node.ban(stats->nodeStats.addr, bantime);
1413  }
1414  }
1417 }
1418 
1420  if (!clientModel) {
1421  return;
1422  }
1423 
1424  // Get selected ban addresses
1425  QList<QModelIndex> nodes =
1427  for (int i = 0; i < nodes.count(); i++) {
1428  // Get currently selected ban address
1429  QString strNode = nodes.at(i).data().toString();
1430  CSubNet possibleSubnet;
1431 
1432  LookupSubNet(strNode.toStdString(), possibleSubnet);
1433  if (possibleSubnet.IsValid() && m_node.unban(possibleSubnet)) {
1435  }
1436  }
1437 }
1438 
1440  ui->peerWidget->selectionModel()->clearSelection();
1441  cachedNodeids.clear();
1442  ui->detailWidget->hide();
1443  ui->peerHeading->setText(tr("Select a peer to view detailed information."));
1444 }
1445 
1447  if (!clientModel) {
1448  return;
1449  }
1450 
1451  bool visible = clientModel->getBanTableModel()->shouldShow();
1452  ui->banlistWidget->setVisible(visible);
1453  ui->banHeading->setVisible(visible);
1454 }
1455 
1456 void RPCConsole::setTabFocus(enum TabTypes tabType) {
1457  ui->tabWidget->setCurrentIndex(int(tabType));
1458 }
1459 
1460 QString RPCConsole::tabTitle(TabTypes tab_type) const {
1461  return ui->tabWidget->tabText(int(tab_type));
1462 }
1463 
1464 QKeySequence RPCConsole::tabShortcut(TabTypes tab_type) const {
1465  switch (tab_type) {
1466  case TabTypes::INFO:
1467  return QKeySequence(Qt::CTRL + Qt::Key_I);
1468  case TabTypes::CONSOLE:
1469  return QKeySequence(Qt::CTRL + Qt::Key_T);
1470  case TabTypes::GRAPH:
1471  return QKeySequence(Qt::CTRL + Qt::Key_N);
1472  case TabTypes::PEERS:
1473  return QKeySequence(Qt::CTRL + Qt::Key_P);
1474  } // no default case, so the compiler can warn about missing cases
1475 
1476  assert(false);
1477 }
1478 
1479 void RPCConsole::updateAlerts(const QString &warnings) {
1480  this->ui->label_alerts->setVisible(!warnings.isEmpty());
1481  this->ui->label_alerts->setText(warnings);
1482 }
void openDebugLogfile()
Definition: guiutil.cpp:392
QString formatClientStartupTime() const
int getRowByNodeId(NodeId nodeid)
bool isObject() const
Definition: univalue.h:96
void addWallet(WalletModel *const walletModel)
QString formatSubVersion() const
int getNumConnections(NumConnections flags=CONNECTIONS_ALL) const
Return number of connections, default is in- and outbound (total)
Definition: clientmodel.cpp:66
Local Bitcoin RPC console.
Definition: rpcconsole.h:36
RPC timer "driver".
Definition: server.h:98
QString cmdBeforeBrowsing
Definition: rpcconsole.h:163
QFont fixedPitchFont()
Definition: guiutil.cpp:75
CNodeStateStats nodeStateStats
virtual bool getNetworkActive()=0
Get network active.
QList< QModelIndex > getEntryData(QAbstractItemView *view, int column)
Return a field of the currently selected entry as a QString.
Definition: guiutil.cpp:263
std::string addrLocal
Definition: net.h:670
static bool isWalletEnabled()
void on_lineEdit_returnPressed()
RPCExecutor(interfaces::Node &node)
Definition: rpcconsole.cpp:81
QString blocksDir() const
virtual double getVerificationProgress()=0
Get verification progress.
bool m_legacyWhitelisted
Definition: net.h:664
void showPeersTableContextMenu(const QPoint &point)
Show custom context menu on Peers tab.
virtual bool unban(const CSubNet &ip)=0
Unban node.
WalletModel * m_last_wallet_model
Definition: rpcconsole.h:172
uint64_t nRecvBytes
Definition: net.h:661
virtual void rpcUnsetTimerInterface(RPCTimerInterface *iface)=0
Unset RPC timer interface.
NodeId nodeid
Definition: net.h:646
QStringList history
Definition: rpcconsole.h:161
virtual int64_t getTotalBytesRecv()=0
Get total bytes recv.
interfaces::Node & m_node
Definition: rpcconsole.h:158
QThread thread
Definition: rpcconsole.h:171
constexpr bool IsDigit(char c)
Tests if the given character is a decimal digit.
Definition: strencodings.h:74
void setNetworkActive(bool networkActive)
Set network state shown in the UI.
void scrollToEnd()
Scroll console view to end.
QString formatBytes(uint64_t bytes)
Definition: guiutil.cpp:831
QString formatTimeOffset(int64_t nTimeOffset)
Definition: guiutil.cpp:797
void networkActiveChanged(bool networkActive)
virtual UniValue executeRpc(Config &config, const std::string &command, const UniValue &params, const std::string &uri)=0
Execute rpc command.
static QString categoryClass(int category)
Definition: rpcconsole.cpp:851
void clearSelectedNode()
clear the selected node
RPCConsole(interfaces::Node &node, const PlatformStyle *platformStyle, QWidget *parent)
Definition: rpcconsole.cpp:513
const std::string & get_str() const
QIcon SingleColorIcon(const QString &filename) const
Colorize an icon (given filename) with the icon color.
bool isStr() const
Definition: univalue.h:93
QString HtmlEscape(const QString &str, bool fMultiLine)
Definition: guiutil.cpp:239
int nStartingHeight
Definition: net.h:658
void fontSmaller()
Definition: rpcconsole.cpp:871
PeerTableModel * getPeerTableModel()
void numBlocksChanged(int count, const QDateTime &blockDate, double nVerificationProgress, bool header, SynchronizationState sync_state)
void disconnectSelectedNode()
Disconnect a selected node on the Peers tab.
CNodeStats nodeStats
void on_tabWidget_currentChanged(int index)
int64_t GetSystemTimeInSeconds()
Returns the system time (not mockable)
Definition: time.cpp:75
void numConnectionsChanged(int count)
virtual bool ban(const CNetAddr &net_addr, int64_t ban_time_offset)=0
Ban node.
void updateNodeDetail(const CNodeCombinedStats *stats)
show detailed information on ui about selected node
virtual void rpcSetTimerInterfaceIfUnset(RPCTimerInterface *iface)=0
Set RPC timer interface if unset.
QString getStatusBarWarnings() const
Return warnings to be displayed in status bar.
QString tabTitle(TabTypes tab_type) const
void alertsChanged(const QString &warnings)
const UniValue & find_value(const UniValue &obj, const std::string &name)
Definition: univalue.cpp:234
bool LookupSubNet(const std::string &strSubnet, CSubNet &ret)
Parse and resolve a specified subnet string into the appropriate internal representation.
Definition: netbase.cpp:890
UniValue RPCConvertValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert positional arguments to command-specific RPC representation.
Definition: client.cpp:214
void setClientModel(ClientModel *model)
Definition: rpcconsole.cpp:649
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut)
const PlatformStyle *const platformStyle
Definition: rpcconsole.h:165
const char * url
Definition: rpcconsole.cpp:55
void reply(int category, const QString &command)
QMenu * peersTableContextMenu
Definition: rpcconsole.h:167
const char * source
Definition: rpcconsole.cpp:56
void browseHistory(int offset)
Go forward or back in history.
void resizeEvent(QResizeEvent *event) override
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
int64_t nTimeConnected
Definition: net.h:651
void message(int category, const QString &msg)
Append the message to the message widget.
Definition: rpcconsole.h:105
QString formatPingTime(int64_t ping_usec)
Definition: guiutil.cpp:790
Class for handling RPC timers (used for e.g.
Definition: rpcconsole.cpp:96
QString formatDurationStr(int secs)
Definition: guiutil.cpp:751
const int CONSOLE_HISTORY
Definition: rpcconsole.cpp:49
void handleCloseWindowShortcut(QWidget *w)
Definition: guiutil.cpp:387
const struct @10 ICON_MAPPING[]
bool fInbound
Definition: net.h:656
int atoi(const std::string &str)
void setTabFocus(enum TabTypes tabType)
set which tab has the focus (is visible)
BanTableModel * getBanTableModel()
interfaces::Node & node() const
Definition: clientmodel.h:49
int historyPtr
Definition: rpcconsole.h:162
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
void peerLayoutChanged()
Handle updated peer information.
RPCTimerInterface * rpcTimerInterface
Definition: rpcconsole.h:166
virtual bool disconnectByAddress(const CNetAddr &net_addr)=0
Disconnect node by address.
int nVersion
Definition: net.h:654
void updateNetworkState()
Update UI with latest network info from model.
Definition: rpcconsole.cpp:988
std::string addrName
Definition: net.h:653
int64_t NodeId
Definition: net.h:99
const CNodeCombinedStats * getNodeStats(int idx)
int get_int() const
QString getWalletName() const
void on_openDebugLogfileButton_clicked()
open the debug.log from the current datadir
const char * Name() override
Implementation name.
Definition: rpcconsole.cpp:114
QtRPCTimerBase(std::function< void()> &_func, int64_t millis)
Definition: rpcconsole.cpp:99
Model for Bitcoin network client.
Definition: clientmodel.h:34
void unbanSelectedNode()
Unban a selected node on the Bans tab.
ClientModel * clientModel
Definition: rpcconsole.h:160
QMenu * banTableContextMenu
Definition: rpcconsole.h:168
void setTrafficGraphRange(int mins)
QKeySequence tabShortcut(TabTypes tab_type) const
void clear(bool clearHistory=true)
Definition: rpcconsole.cpp:905
void showOrHideBanTableIfRequired()
Hides ban table if no bans are present.
void fontBigger()
Definition: rpcconsole.cpp:867
void updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
update traffic statistics
bool IsValid() const
Definition: netaddress.cpp:930
int64_t m_ping_wait_usec
Definition: net.h:666
virtual int64_t getLastBlockTime()=0
Get last block time.
QList< NodeId > cachedNodeids
Definition: rpcconsole.h:164
void setMempoolSize(long numberOfTxs, size_t dynUsage)
Set size (number of transactions and memory usage) of the mempool in the UI.
void setFontSize(int newSize)
Definition: rpcconsole.cpp:875
std::function< void()> func
Definition: rpcconsole.cpp:108
void setNumConnections(int count)
Set number of connections shown in the UI.
void startExecutor()
QImage SingleColorImage(const QString &filename) const
Colorize an image (given filename) with the icon color.
const CChainParams & Params()
Return the currently selected parameters.
ServiceFlags nServices
Definition: net.h:647
static bool RPCParseCommandLine(interfaces::Node *node, std::string &strResult, const std::string &strCommand, bool fExecute, std::string *const pstrFilteredOut=nullptr, const WalletModel *wallet_model=nullptr)
Split shell command line into a list of arguments and optionally execute the command(s).
Definition: rpcconsole.cpp:149
interfaces::Node & m_node
Definition: rpcconsole.cpp:90
void peerLayoutAboutToChange()
Handle selection caching before update.
int64_t nLastSend
Definition: net.h:649
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:47
virtual std::vector< std::string > listRpcCommands()=0
List rpc commands.
QString formatServicesStr(quint64 mask)
Definition: guiutil.cpp:774
void on_sldGraphRange_valueChanged(int value)
change the time range of the network traffic graph
void banSelectedNode(int bantime)
Ban a selected node on the Peers tab.
Ui::RPCConsole *const ui
Definition: rpcconsole.h:159
void updateAlerts(const QString &warnings)
uint64_t nSendBytes
Definition: net.h:659
int64_t m_min_ping_usec
Definition: net.h:667
Opaque base class for timers returned by NewTimerFunc.
Definition: server.h:90
void removeWallet(WalletModel *const walletModel)
std::string cleanSubVer
Definition: net.h:655
int64_t m_ping_usec
Definition: net.h:665
const int INITIAL_TRAFFIC_GRAPH_MINS
Definition: rpcconsole.cpp:50
static int count
Definition: tests.c:35
const char fontSizeSettingsKey[]
Definition: rpcconsole.cpp:52
void peerSelected(const QItemSelection &selected, const QItemSelection &deselected)
Handle selection of peer in peers list.
int consoleFontSize
Definition: rpcconsole.h:169
RPCTimerBase * NewTimer(std::function< void()> &func, int64_t millis) override
Factory function for timers.
Definition: rpcconsole.cpp:115
QString getDisplayName() const
void request(const QString &command, const WalletModel *wallet_model)
Definition: rpcconsole.cpp:446
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes)
uint32_t m_mapped_as
Definition: net.h:675
const QSize FONT_RANGE(4, 40)
static bool RPCExecuteCommandLine(interfaces::Node &node, std::string &strResult, const std::string &strCommand, std::string *const pstrFilteredOut=nullptr, const WalletModel *wallet_model=nullptr)
Definition: rpcconsole.h:50
QString dataDir() const
void clear()
Definition: univalue.cpp:15
virtual int getNumBlocks()=0
Get num blocks.
int64_t nLastRecv
Definition: net.h:650
virtual bool disconnectById(NodeId id)=0
Disconnect node by id.
void showEvent(QShowEvent *event) override
void cmdRequest(const QString &command, const WalletModel *wallet_model)
QCompleter * autoCompleter
Definition: rpcconsole.h:170
virtual int64_t getTotalBytesSent()=0
Get total bytes sent.
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:45
bool isArray() const
Definition: univalue.h:95
CAddress addr
Definition: net.h:672
bool getImagesOnButtons() const
Definition: platformstyle.h:20
void setNumBlocks(int count, const QDateTime &blockDate, double nVerificationProgress, bool headers)
Set number of blocks and last block date shown in the UI.
void showBanTableContextMenu(const QPoint &point)
Show custom context menu on Bans tab.
void keyPressEvent(QKeyEvent *) override
Definition: rpcconsole.cpp:964
void hideEvent(QHideEvent *event) override
virtual bool eventFilter(QObject *obj, QEvent *event) override
Definition: rpcconsole.cpp:594
QString formatFullVersion() const
int64_t nTimeOffset
Definition: net.h:652