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