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