Bitcoin ABC 0.30.12
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 if (!clientModel) {
995 return;
996 }
997
998 QString connections =
999 QString::number(clientModel->getNumConnections()) + " (";
1000 connections += tr("In:") + " " +
1001 QString::number(clientModel->getNumConnections(
1003 " / ";
1004 connections += tr("Out:") + " " +
1005 QString::number(clientModel->getNumConnections(
1007 ")";
1008
1009 if (!clientModel->node().getNetworkActive()) {
1010 connections += " (" + tr("Network activity disabled") + ")";
1011 }
1012
1013 ui->numberOfConnections->setText(connections);
1014}
1015
1017 if (!clientModel) {
1018 return;
1019 }
1020
1022}
1023
1024void RPCConsole::setNetworkActive(bool networkActive) {
1026}
1027
1028void RPCConsole::setNumBlocks(int count, const QDateTime &blockDate,
1029 double nVerificationProgress, SyncType synctype) {
1030 if (synctype == SyncType::BLOCK_SYNC) {
1031 ui->numberOfBlocks->setText(QString::number(count));
1032 ui->lastBlockTime->setText(blockDate.toString());
1033 }
1034}
1035
1036void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage) {
1037 ui->mempoolNumberTxs->setText(QString::number(numberOfTxs));
1038
1039 if (dynUsage < 1000000) {
1040 ui->mempoolSize->setText(QString::number(dynUsage / 1000.0, 'f', 2) +
1041 " KB");
1042 } else {
1043 ui->mempoolSize->setText(QString::number(dynUsage / 1000000.0, 'f', 2) +
1044 " MB");
1045 }
1046}
1047
1049 QString cmd = ui->lineEdit->text();
1050
1051 if (!cmd.isEmpty()) {
1052 std::string strFilteredCmd;
1053 try {
1054 std::string dummy;
1055 if (!RPCParseCommandLine(nullptr, dummy, cmd.toStdString(), false,
1056 &strFilteredCmd)) {
1057 // Failed to parse command, so we cannot even filter it for the
1058 // history
1059 throw std::runtime_error("Invalid command line");
1060 }
1061 } catch (const std::exception &e) {
1062 QMessageBox::critical(this, "Error",
1063 QString("Error: ") +
1064 QString::fromStdString(e.what()));
1065 return;
1066 }
1067
1068 ui->lineEdit->clear();
1069
1070 cmdBeforeBrowsing = QString();
1071
1072#ifdef ENABLE_WALLET
1073 WalletModel *wallet_model =
1074 ui->WalletSelector->currentData().value<WalletModel *>();
1075
1076 if (m_last_wallet_model != wallet_model) {
1077 if (wallet_model) {
1078 message(CMD_REQUEST, tr("Executing command using \"%1\" wallet")
1079 .arg(wallet_model->getWalletName()));
1080 } else {
1082 tr("Executing command without any wallet"));
1083 }
1084 m_last_wallet_model = wallet_model;
1085 }
1086#endif
1087
1088 message(CMD_REQUEST, QString::fromStdString(strFilteredCmd));
1089 Q_EMIT cmdRequest(cmd, m_last_wallet_model);
1090
1091 cmd = QString::fromStdString(strFilteredCmd);
1092
1093 // Remove command, if already in history
1094 history.removeOne(cmd);
1095 // Append command to history
1096 history.append(cmd);
1097 // Enforce maximum history size
1098 while (history.size() > CONSOLE_HISTORY) {
1099 history.removeFirst();
1100 }
1101 // Set pointer to end of history
1102 historyPtr = history.size();
1103
1104 // Scroll console view to end
1105 scrollToEnd();
1106 }
1107}
1108
1110 // store current text when start browsing through the history
1111 if (historyPtr == history.size()) {
1112 cmdBeforeBrowsing = ui->lineEdit->text();
1113 }
1114
1115 historyPtr += offset;
1116 if (historyPtr < 0) {
1117 historyPtr = 0;
1118 }
1119 if (historyPtr > history.size()) {
1120 historyPtr = history.size();
1121 }
1122 QString cmd;
1123 if (historyPtr < history.size()) {
1124 cmd = history.at(historyPtr);
1125 } else if (!cmdBeforeBrowsing.isNull()) {
1126 cmd = cmdBeforeBrowsing;
1127 }
1128 ui->lineEdit->setText(cmd);
1129}
1130
1132 RPCExecutor *executor = new RPCExecutor(m_node);
1133 executor->moveToThread(&thread);
1134
1135 // Replies from executor object must go to this object
1136 connect(executor, &RPCExecutor::reply, this,
1137 static_cast<void (RPCConsole::*)(int, const QString &)>(
1139
1140 // Requests from this object must go to executor
1141 connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request);
1142
1143 // Make sure executor object is deleted in its own thread
1144 connect(&thread, &QThread::finished, executor, &RPCExecutor::deleteLater);
1145
1146 // Default implementation of QThread::run() simply spins up an event loop in
1147 // the thread, which is what we want.
1148 thread.start();
1149 QTimer::singleShot(0, executor,
1150 []() { util::ThreadRename("qt-rpcconsole"); });
1151}
1152
1154 if (ui->tabWidget->widget(index) == ui->tab_console) {
1155 ui->lineEdit->setFocus();
1156 }
1157}
1158
1161}
1162
1164 QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar();
1165 scrollbar->setValue(scrollbar->maximum());
1166}
1167
1169 const int multiplier = 5; // each position on the slider represents 5 min
1170 int mins = value * multiplier;
1172}
1173
1175 ui->trafficGraph->setGraphRangeMins(mins);
1176 ui->lblGraphRange->setText(
1177 GUIUtil::formatDurationStr(std::chrono::minutes{mins}));
1178}
1179
1180void RPCConsole::updateTrafficStats(quint64 totalBytesIn,
1181 quint64 totalBytesOut) {
1182 ui->lblBytesIn->setText(GUIUtil::formatBytes(totalBytesIn));
1183 ui->lblBytesOut->setText(GUIUtil::formatBytes(totalBytesOut));
1184}
1185
1187 QModelIndexList selected =
1188 ui->peerWidget->selectionModel()->selectedIndexes();
1189 cachedNodeids.clear();
1190 for (int i = 0; i < selected.size(); i++) {
1191 const CNodeCombinedStats *stats =
1193 selected.at(i).row());
1194 cachedNodeids.append(stats->nodeStats.nodeid);
1195 }
1196}
1197
1200 return;
1201 }
1202
1203 bool fUnselect = false;
1204 bool fReselect = false;
1205
1206 // no node selected yet
1207 if (cachedNodeids.empty()) {
1208 return;
1209 }
1210
1211 // find the currently selected row
1212 int selectedRow = -1;
1213 QModelIndexList selectedModelIndex =
1214 ui->peerWidget->selectionModel()->selectedIndexes();
1215 if (!selectedModelIndex.isEmpty()) {
1216 selectedRow = selectedModelIndex.first().row();
1217 }
1218
1219 // check if our detail node has a row in the table (it may not necessarily
1220 // be at selectedRow since its position can change after a layout change)
1221 int detailNodeRow =
1223
1224 if (detailNodeRow < 0) {
1225 // detail node disappeared from table (node disconnected)
1226 fUnselect = true;
1227 } else {
1228 if (detailNodeRow != selectedRow) {
1229 // detail node moved position
1230 fUnselect = true;
1231 fReselect = true;
1232 }
1233 }
1234
1235 if (fUnselect && selectedRow >= 0) {
1237 }
1238
1239 if (fReselect) {
1240 for (int i = 0; i < cachedNodeids.size(); i++) {
1241 ui->peerWidget->selectRow(
1243 cachedNodeids.at(i)));
1244 }
1245 }
1246
1248}
1249
1251 QModelIndexList selected_rows;
1252 auto selection_model = ui->peerWidget->selectionModel();
1253 if (selection_model) {
1254 selected_rows = selection_model->selectedRows();
1255 }
1257 selected_rows.size() != 1) {
1258 ui->detailWidget->hide();
1259 ui->peerHeading->setText(
1260 tr("Select a peer to view detailed information."));
1261 return;
1262 }
1263 const CNodeCombinedStats *stats =
1265 selected_rows.first().row());
1266 // update the detail ui with latest node information
1267 QString peerAddrDetails(
1268 QString::fromStdString(stats->nodeStats.m_addr_name) + " ");
1269 peerAddrDetails +=
1270 tr("(peer id: %1)").arg(QString::number(stats->nodeStats.nodeid));
1271 if (!stats->nodeStats.addrLocal.empty()) {
1272 peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(
1273 stats->nodeStats.addrLocal));
1274 }
1275 ui->peerHeading->setText(peerAddrDetails);
1276 QString bip152_hb_settings;
1278 bip152_hb_settings += "To";
1279 }
1281 bip152_hb_settings += (bip152_hb_settings == "" ? "From" : "/From");
1282 }
1283 if (bip152_hb_settings == "") {
1284 bip152_hb_settings = "No";
1285 }
1286 ui->peerHighBandwidth->setText(bip152_hb_settings);
1287 const auto time_now{GetTime<std::chrono::seconds>()};
1288 ui->peerConnTime->setText(
1290 ui->peerLastBlock->setText(
1292 ui->peerLastTx->setText(
1293 TimeDurationField(time_now, stats->nodeStats.m_last_tx_time));
1294 ui->peerLastSend->setText(
1295 TimeDurationField(time_now, stats->nodeStats.m_last_send));
1296 ui->peerLastRecv->setText(
1297 TimeDurationField(time_now, stats->nodeStats.m_last_recv));
1298 ui->peerBytesSent->setText(
1300 ui->peerBytesRecv->setText(
1302 ui->peerPingTime->setText(
1304 ui->peerMinPing->setText(
1306 ui->timeoffset->setText(
1308 ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion));
1309 ui->peerSubversion->setText(
1310 QString::fromStdString(stats->nodeStats.cleanSubVer));
1311 ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound")
1312 : tr("Outbound"));
1313 ui->peerNetwork->setText(
1316 ui->peerPermissions->setText(tr("N/A"));
1317 } else {
1318 QStringList permissions;
1319 for (const auto &permission :
1321 permissions.append(QString::fromStdString(permission));
1322 }
1323 ui->peerPermissions->setText(permissions.join(" & "));
1324 }
1325 ui->peerMappedAS->setText(
1326 stats->nodeStats.m_mapped_as != 0
1327 ? QString::number(stats->nodeStats.m_mapped_as)
1328 : tr("N/A"));
1329
1330 // This check fails for example if the lock was busy and
1331 // nodeStateStats couldn't be fetched.
1332 if (stats->fNodeStateStatsAvailable) {
1333 ui->peerServices->setText(
1335 // Sync height is init to -1
1336 if (stats->nodeStateStats.nSyncHeight > -1) {
1337 ui->peerSyncHeight->setText(
1338 QString("%1").arg(stats->nodeStateStats.nSyncHeight));
1339 } else {
1340 ui->peerSyncHeight->setText(tr("Unknown"));
1341 }
1342
1343 // Common height is init to -1
1344 if (stats->nodeStateStats.nCommonHeight > -1) {
1345 ui->peerCommonHeight->setText(
1346 QString("%1").arg(stats->nodeStateStats.nCommonHeight));
1347 } else {
1348 ui->peerCommonHeight->setText(tr("Unknown"));
1349 }
1350
1351 ui->peerHeight->setText(
1352 QString::number(stats->nodeStateStats.m_starting_height));
1353 ui->peerPingWait->setText(
1355 ui->peerRelayTxes->setText(stats->nodeStateStats.m_relay_txs ? "Yes"
1356 : "No");
1357 }
1358
1359 ui->detailWidget->show();
1360}
1361
1362void RPCConsole::resizeEvent(QResizeEvent *event) {
1363 QWidget::resizeEvent(event);
1364}
1365
1366void RPCConsole::showEvent(QShowEvent *event) {
1367 QWidget::showEvent(event);
1368
1370 return;
1371 }
1372
1373 // start PeerTableModel auto refresh
1375}
1376
1377void RPCConsole::hideEvent(QHideEvent *event) {
1378 QWidget::hideEvent(event);
1379
1381 return;
1382 }
1383
1384 // stop PeerTableModel auto refresh
1386}
1387
1388void RPCConsole::showPeersTableContextMenu(const QPoint &point) {
1389 QModelIndex index = ui->peerWidget->indexAt(point);
1390 if (index.isValid()) {
1391 peersTableContextMenu->exec(QCursor::pos());
1392 }
1393}
1394
1395void RPCConsole::showBanTableContextMenu(const QPoint &point) {
1396 QModelIndex index = ui->banlistWidget->indexAt(point);
1397 if (index.isValid()) {
1398 banTableContextMenu->exec(QCursor::pos());
1399 }
1400}
1401
1403 // Get selected peer addresses
1404 QList<QModelIndex> nodes =
1406 for (int i = 0; i < nodes.count(); i++) {
1407 // Get currently selected peer address
1408 NodeId id = nodes.at(i).data().toLongLong();
1409 // Find the node, disconnect it and clear the selected node
1410 if (m_node.disconnectById(id)) {
1412 }
1413 }
1414}
1415
1417 if (!clientModel) {
1418 return;
1419 }
1420
1421 // Get selected peer addresses
1422 QList<QModelIndex> nodes =
1424 for (int i = 0; i < nodes.count(); i++) {
1425 // Get currently selected peer address
1426 NodeId id = nodes.at(i).data().toLongLong();
1427
1428 // Get currently selected peer address
1429 int detailNodeRow =
1431 if (detailNodeRow < 0) {
1432 return;
1433 }
1434
1435 // Find possible nodes, ban it and clear the selected node
1436 const CNodeCombinedStats *stats =
1437 clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
1438 if (stats) {
1439 m_node.ban(stats->nodeStats.addr, bantime);
1441 }
1442 }
1445}
1446
1448 if (!clientModel) {
1449 return;
1450 }
1451
1452 // Get selected ban addresses
1453 QList<QModelIndex> nodes =
1455 for (int i = 0; i < nodes.count(); i++) {
1456 // Get currently selected ban address
1457 QString strNode = nodes.at(i).data().toString();
1458 CSubNet possibleSubnet;
1459
1460 LookupSubNet(strNode.toStdString(), possibleSubnet);
1461 if (possibleSubnet.IsValid() && m_node.unban(possibleSubnet)) {
1463 }
1464 }
1465}
1466
1468 ui->peerWidget->selectionModel()->clearSelection();
1469 cachedNodeids.clear();
1471}
1472
1474 if (!clientModel) {
1475 return;
1476 }
1477
1478 bool visible = clientModel->getBanTableModel()->shouldShow();
1479 ui->banlistWidget->setVisible(visible);
1480 ui->banHeading->setVisible(visible);
1481}
1482
1484 ui->tabWidget->setCurrentIndex(int(tabType));
1485}
1486
1487QString RPCConsole::tabTitle(TabTypes tab_type) const {
1488 return ui->tabWidget->tabText(int(tab_type));
1489}
1490
1491QKeySequence RPCConsole::tabShortcut(TabTypes tab_type) const {
1492 switch (tab_type) {
1493 case TabTypes::INFO:
1494 return QKeySequence(Qt::CTRL + Qt::Key_I);
1495 case TabTypes::CONSOLE:
1496 return QKeySequence(Qt::CTRL + Qt::Key_T);
1497 case TabTypes::GRAPH:
1498 return QKeySequence(Qt::CTRL + Qt::Key_N);
1499 case TabTypes::PEERS:
1500 return QKeySequence(Qt::CTRL + Qt::Key_P);
1501 } // no default case, so the compiler can warn about missing cases
1502
1503 assert(false);
1504}
1505
1506void RPCConsole::updateAlerts(const QString &warnings) {
1507 this->ui->label_alerts->setVisible(!warnings.isEmpty());
1508 this->ui->label_alerts->setText(warnings);
1509}
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:73
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:60
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:274
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:788
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())