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