5#include <bitcoin-build-config.h>
8#include <qt/forms/ui_debugwindow.h>
10#include <chainparams.h>
31#include <QAbstractButton>
32#include <QAbstractItemModel>
36#include <QKeySequence>
37#include <QLatin1String>
46#include <QStyledItemDelegate>
64 {
"cmd-request",
":/icons/tx_input"},
65 {
"cmd-reply",
":/icons/tx_output"},
66 {
"cmd-error",
":/icons/tx_output"},
67 {
"misc",
":/icons/tx_inout"},
76 <<
"createwalletdescriptor"
78 <<
"signmessagewithprivkey"
79 <<
"signrawtransactionwithkey"
81 <<
"walletpassphrasechange"
109 : QStyledItemDelegate(parent) {}
119#include <qt/rpcconsole.moc>
143 std::vector< std::vector<std::string> > stack;
144 stack.emplace_back();
172 stack.emplace_back();
220 throw std::runtime_error(
"Invalid result query");
227 throw std::runtime_error(
"Invalid result query");
271 case '(':
case ')':
case '\n':
273 throw std::runtime_error(
"Invalid Syntax");
276 if (
ch ==
'(' && stack.size() && stack.back().size() > 0)
281 stack.emplace_back();
286 throw std::runtime_error(
"Invalid Syntax");
292 if ((
ch ==
')' ||
ch ==
'\n') && stack.size() > 0)
297 UniValue params =
RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
298 std::string method = stack.back()[0];
300 if (!wallet_name.isEmpty()) {
312 case ' ':
case ',':
case '\t':
314 throw std::runtime_error(
"Invalid Syntax");
391 "This console accepts RPC commands using the standard syntax.\n"
392 " example: getblockhash 0\n\n"
394 "This console can also accept RPC commands using the parenthesized syntax.\n"
395 " example: getblockhash(0)\n\n"
397 "Commands may be nested when specified with the parenthesized syntax.\n"
398 " example: getblock(getblockhash(0) 1)\n\n"
400 "A space or a comma can be used to delimit arguments for either syntax.\n"
401 " example: getblockhash 0\n"
402 " getblockhash,0\n\n"
404 "Named results can be queried with a non-quoted key string in brackets using the parenthesized syntax.\n"
405 " example: getblock(getblockhash(0) 1)[tx]\n\n"
407 "Results without keys can be queried with an integer in brackets using the parenthesized syntax.\n"
408 " example: getblock(getblockhash(0),1)[tx][0]\n\n")));
422 int code =
objError.find_value(
"code").getInt<
int>();
423 std::string message =
objError.find_value(
"message").get_str();
426 catch (
const std::runtime_error&)
431 catch (
const std::exception&
e)
452 ui->splitter->restoreState(
settings.value(
"RPCConsoleWindowPeersTabSplitterSizes").toByteArray());
457 ui->splitter->restoreState(
settings.value(
"RPCConsoleWidgetPeersTabSplitterSizes").toByteArray());
466 tr(
"Inbound: initiated by peer"),
470 tr(
"Outbound Full Relay: default"),
473 tr(
"Outbound Block Relay: does not relay transactions or addresses"),
478 tr(
"Outbound Manual: added using RPC %1 or %2/%3 configuration options")
484 tr(
"Outbound Feeler: short-lived, for testing addresses"),
487 tr(
"Outbound Address Fetch: short-lived, for soliciting addresses"),
490 tr(
"Private broadcast: short-lived, for broadcasting privacy-sensitive transactions")};
495 tr(
"detecting: peer could be v1 or v2"),
497 tr(
"v1: unencrypted, plaintext transport protocol"),
499 tr(
"v2: BIP324 encrypted transport protocol")};
503 +
ts.
to +
"\" – " +
tr(
"we selected the peer for high bandwidth relay") +
"</li><li>\""
504 +
ts.
from +
"\" – " +
tr(
"the peer selected us for high bandwidth relay") +
"</li><li>\""
505 +
ts.
no +
"\" – " +
tr(
"no high bandwidth relay selected") +
"</li></ul>"};
506 ui->peerHighBandwidthLabel->setToolTip(
ui->peerHighBandwidthLabel->toolTip().arg(
hb_list));
509 ui->openDebugLogfileButton->setToolTip(
ui->openDebugLogfileButton->toolTip().arg(
CLIENT_NAME));
518 ui->fontBiggerButton->setShortcut(
tr(
"Ctrl++"));
524 ui->fontSmallerButton->setShortcut(
tr(
"Ctrl+-"));
531 ui->lineEdit->installEventFilter(
this);
532 ui->lineEdit->setMaxLength(16 * 1024 * 1024);
533 ui->messagesWidget->installEventFilter(
this);
536 connect(
ui->clearButton, &QAbstractButton::clicked, [
this] { clear(); });
542 ui->WalletSelector->setVisible(
false);
543 ui->WalletSelectorLabel->setVisible(
false);
563 settings.setValue(
"RPCConsoleWindowPeersTabSplitterSizes",
ui->splitter->saveState());
568 settings.setValue(
"RPCConsoleWidgetPeersTabSplitterSizes",
ui->splitter->saveState());
579 if(event->type() == QEvent::KeyPress)
583 Qt::KeyboardModifiers
mod =
keyevt->modifiers();
589 case Qt::Key_PageDown:
590 if (
obj ==
ui->lineEdit) {
591 QApplication::sendEvent(
ui->messagesWidget,
keyevt);
599 QApplication::sendEvent(
ui->lineEdit,
keyevt);
607 if(
obj ==
ui->messagesWidget && (
608 (!
mod && !
keyevt->text().isEmpty() && key != Qt::Key_Tab) ||
609 ((
mod & Qt::ControlModifier) && key == Qt::Key_V) ||
610 ((
mod & Qt::ShiftModifier) && key == Qt::Key_Insert)))
612 ui->lineEdit->setFocus();
613 QApplication::sendEvent(
ui->lineEdit,
keyevt);
618 return QWidget::eventFilter(
obj, event);
635 ui->trafficGraph->setClientModel(model);
655 ui->peerWidget->verticalHeader()->hide();
656 ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
657 ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
658 ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
665 ui->peerWidget->horizontalHeader()->setSectionResizeMode(
PeerTableModel::Age, QHeaderView::ResizeToContents);
666 ui->peerWidget->horizontalHeader()->setStretchLastSection(
true);
685 connect(model->
getPeerTableModel(), &QAbstractItemModel::dataChanged, [
this] { updateDetailWidget(); });
689 ui->banlistWidget->verticalHeader()->hide();
690 ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
691 ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection);
692 ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu);
699 ui->banlistWidget->horizontalHeader()->setStretchLastSection(
true);
725 ui->networkName->setText(QString::fromStdString(
Params().GetChainTypeString()));
739 autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
742 ui->lineEdit->setEnabled(
true);
756void RPCConsole::addWallet(
WalletModel *
const walletModel)
759 ui->WalletSelector->addItem(walletModel->
getDisplayName(), QVariant::fromValue(walletModel));
760 if (
ui->WalletSelector->count() == 2) {
762 ui->WalletSelector->setCurrentIndex(1);
764 if (
ui->WalletSelector->count() > 2) {
765 ui->WalletSelector->setVisible(
true);
766 ui->WalletSelectorLabel->setVisible(
true);
770void RPCConsole::removeWallet(
WalletModel *
const walletModel)
772 ui->WalletSelector->removeItem(
ui->WalletSelector->findData(QVariant::fromValue(walletModel)));
773 if (
ui->WalletSelector->count() == 2) {
774 ui->WalletSelector->setVisible(
false);
775 ui->WalletSelectorLabel->setVisible(
false);
782 ui->WalletSelector->setCurrentIndex(
ui->WalletSelector->findData(data));
793 default:
return "misc";
816 QString str =
ui->messagesWidget->toHtml();
826 float oldPosFactor = 1.0 /
ui->messagesWidget->verticalScrollBar()->maximum() *
ui->messagesWidget->verticalScrollBar()->value();
828 ui->messagesWidget->setHtml(str);
829 ui->messagesWidget->verticalScrollBar()->setValue(
oldPosFactor *
ui->messagesWidget->verticalScrollBar()->maximum());
834 ui->messagesWidget->clear();
836 ui->lineEdit->setFocus();
842 ui->messagesWidget->document()->addResource(
843 QTextDocument::ImageResource,
854 ui->messagesWidget->document()->setDefaultStyleSheet(
857 "td.time { color: #808080; font-size: %2; padding-top: 3px; } "
858 "td.message { font-family: %1; font-size: %2; white-space:pre-wrap; } "
859 "td.cmd-request { color: #006060; } "
860 "td.cmd-error { color: red; } "
861 ".secwarning { color: red; }"
862 "b { color: #006060; } "
870 tr(
"Welcome to the %1 RPC console.\n"
871 "Use up and down arrows to navigate history, and %2 to clear screen.\n"
872 "Use %3 and %4 to increase or decrease the font size.\n"
873 "Type %5 for an overview of available commands.\n"
874 "For more information on using this console, type %6.\n"
876 "%7WARNING: Scammers have been active, telling users to type"
877 " commands here, stealing their wallet contents. Do not use this console"
878 " without fully understanding the ramifications of a command.%8")
880 "<b>" +
ui->clearButton->shortcut().toString(QKeySequence::NativeText) +
"</b>",
881 "<b>" +
ui->fontBiggerButton->shortcut().toString(QKeySequence::NativeText) +
"</b>",
882 "<b>" +
ui->fontSmallerButton->shortcut().toString(QKeySequence::NativeText) +
"</b>",
884 "<b>help-console</b>",
885 "<span class=\"secwarning\">",
900 if (
e->type() == QEvent::PaletteChange) {
907 ui->messagesWidget->document()->addResource(
908 QTextDocument::ImageResource,
914 QWidget::changeEvent(
e);
919 QTime time = QTime::currentTime();
922 out +=
"<table><tr><td class=\"time\" width=\"65\">" +
timeString +
"</td>";
923 out +=
"<td class=\"icon\" width=\"32\"><img src=\"" +
categoryClass(category) +
"\"></td>";
924 out +=
"<td class=\"message " +
categoryClass(category) +
"\" valign=\"middle\">";
929 out +=
"</td></tr></table>";
930 ui->messagesWidget->append(out);
948 for (
const auto& [addr, info] :
hosts) {
950 if (!addr.IsI2P())
local_addresses +=
":" + QString::number(info.nPort);
975 ui->numberOfBlocks->setText(QString::number(
count));
985 QObject::tr(
"%1 kB").arg(
dynUsage / 1000.0, 0,
'f', 2) :
986 QObject::tr(
"%1 MB").arg(
dynUsage / 1000000.0, 0,
'f', 2);
1005 throw std::runtime_error(
"Invalid command line");
1007 }
catch (
const std::exception&
e) {
1008 QMessageBox::critical(
this,
"Error",
QString(
"Error: ") + QString::fromStdString(
e.what()));
1023 ui->lineEdit->clear();
1083 ui->lineEdit->setText(
cmd);
1094 ui->messagesWidget->undo();
1101 connect(&
thread, &QThread::finished,
m_executor, &RPCExecutor::deleteLater);
1113 if (
ui->tabWidget->widget(index) ==
ui->tab_console) {
1114 ui->lineEdit->setFocus();
1138 ui->trafficGraph->setGraphRange(std::chrono::minutes{
mins});
1152 ui->peersTabRightPanel->hide();
1153 ui->peerHeading->setText(
tr(
"Select a peer to view detailed information."));
1159 peerAddrDetails +=
tr(
"(peer: %1)").arg(QString::number(stats->nodeStats.nodeid));
1160 if (!stats->nodeStats.addrLocal.empty())
1161 peerAddrDetails +=
"<br />" +
tr(
"via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
1178 ui->peerVersion->setText(stats->nodeStats.nVersion ? QString::number(stats->nodeStats.nVersion) :
ts.
na);
1179 ui->peerSubversion->setText(!stats->nodeStats.cleanSubVer.empty() ? QString::fromStdString(stats->nodeStats.cleanSubVer) :
ts.
na);
1181 ui->peerTransportType->setText(QString::fromStdString(
TransportTypeAsString(stats->nodeStats.m_transport_type)));
1183 ui->peerSessionIdLabel->setVisible(
true);
1184 ui->peerSessionId->setVisible(
true);
1185 ui->peerSessionId->setText(QString::fromStdString(stats->nodeStats.m_session_id));
1187 ui->peerSessionIdLabel->setVisible(
false);
1188 ui->peerSessionId->setVisible(
false);
1192 ui->peerPermissions->setText(
ts.
na);
1200 ui->peerMappedAS->setText(stats->nodeStats.m_mapped_as != 0 ? QString::number(stats->nodeStats.m_mapped_as) :
ts.
na);
1204 if (stats->fNodeStateStatsAvailable) {
1208 if (stats->nodeStateStats.nSyncHeight > -1) {
1209 ui->peerSyncHeight->setText(
QString(
"%1").arg(stats->nodeStateStats.nSyncHeight));
1214 if (stats->nodeStateStats.nCommonHeight > -1) {
1215 ui->peerCommonHeight->setText(
QString(
"%1").arg(stats->nodeStateStats.nCommonHeight));
1220 ui->peerAddrRelayEnabled->setText(stats->nodeStateStats.m_addr_relay_enabled ?
ts.
yes :
ts.
no);
1221 ui->peerAddrProcessed->setText(QString::number(stats->nodeStateStats.m_addr_processed));
1222 ui->peerAddrRateLimited->setText(QString::number(stats->nodeStateStats.m_addr_rate_limited));
1223 ui->peerRelayTxes->setText(stats->nodeStateStats.m_relay_txs ?
ts.
yes :
ts.
no);
1227 ui->peersTabRightPanel->show();
1232 QWidget::resizeEvent(event);
1237 QWidget::showEvent(event);
1253 QWidget::hideEvent(event);
1265 if (index.isValid())
1272 if (index.isValid())
1280 for(
int i = 0; i <
nodes.count(); i++)
1326 ui->peerWidget->selectionModel()->clearSelection();
1343 ui->tabWidget->setCurrentIndex(
int(
tabType));
1348 return ui->tabWidget->tabText(
int(
tab_type));
1365 this->
ui->label_alerts->setVisible(!warnings.isEmpty());
1366 this->
ui->label_alerts->setText(warnings);
const CChainParams & Params()
Return the currently selected parameters.
Qt model providing information about banned peers, similar to the "getpeerinfo" RPC call.
bool unban(const QModelIndex &index)
ChainType GetChainType() const
Return the chain type.
Model for Bitcoin network client.
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut)
QString blocksDir() const
QString getStatusBarWarnings() const
Return warnings to be displayed in status bar.
std::map< CNetAddr, LocalServiceInfo > getNetLocalAddresses() const
PeerTableModel * getPeerTableModel()
PeerTableSortProxy * peerTableSortProxy()
void numConnectionsChanged(int count)
QString formatClientStartupTime() const
int getNumConnections(unsigned int flags=CONNECTIONS_ALL) const
Return number of connections, default is in- and outbound (total)
BanTableModel * getBanTableModel()
void numBlocksChanged(int count, const QDateTime &blockDate, double nVerificationProgress, SyncType header, SynchronizationState sync_state)
void alertsChanged(const QString &warnings)
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes, size_t mempoolMaxSizeInBytes)
QString formatFullVersion() const
QString formatSubVersion() const
void networkActiveChanged(bool networkActive)
interfaces::Node & node() const
static std::vector< std::string > ToStrings(NetPermissionFlags flags)
QString displayText(const QVariant &value, const QLocale &locale) const override
PeerIdViewDelegate(QObject *parent=nullptr)
Local Bitcoin RPC console.
static bool RPCExecuteCommandLine(interfaces::Node &node, std::string &strResult, const std::string &strCommand, std::string *const pstrFilteredOut=nullptr, const QString &wallet_name={})
QMenu * peersTableContextMenu
RPCConsole(interfaces::Node &node, const PlatformStyle *platformStyle, QWidget *parent)
struct RPCConsole::TranslatedStrings ts
void browseHistory(int offset)
Go forward or back in history.
QByteArray m_banlist_widget_header_state
QString TimeDurationField(std::chrono::seconds time_now, std::chrono::seconds time_at_event) const
Helper for the output of a time duration field.
void on_lineEdit_returnPressed()
void message(int category, const QString &msg)
Append the message to the message widget.
void setFontSize(int newSize)
void updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
update traffic statistics
void setTrafficGraphRange(int mins)
const PlatformStyle *const platformStyle
void setMempoolSize(long numberOfTxs, size_t dynUsage, size_t maxUsage)
Set size (number of transactions and memory usage) of the mempool in the UI.
void updateDetailWidget()
show detailed information on ui about selected node
void showEvent(QShowEvent *event) override
void resizeEvent(QResizeEvent *event) override
QString tabTitle(TabTypes tab_type) const
void updateNetworkState()
Update UI with latest network info from model.
void clear(bool keep_prompt=false)
void disconnectSelectedNode()
Disconnect a selected node on the Peers tab.
@ SUBVERSION_COLUMN_WIDTH
QCompleter * autoCompleter
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
interfaces::Node & m_node
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
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
void banSelectedNode(int bantime)
Ban a selected node on the Peers tab.
void scrollToEnd()
Scroll console view to end.
void keyPressEvent(QKeyEvent *) override
void on_tabWidget_currentChanged(int index)
void setNetworkActive(bool networkActive)
Set network state shown in the UI.
QString cmdBeforeBrowsing
virtual bool eventFilter(QObject *obj, QEvent *event) override
void on_openDebugLogfileButton_clicked()
open the debug.log from the current datadir
void showBanTableContextMenu(const QPoint &point)
Show custom context menu on Bans tab.
void setClientModel(ClientModel *model=nullptr, int bestblock_height=0, int64_t bestblock_date=0, double verification_progress=0.0)
void setTabFocus(enum TabTypes tabType)
set which tab has the focus (is visible)
QByteArray m_peer_widget_header_state
void changeEvent(QEvent *e) override
WalletModel * m_last_wallet_model
void showOrHideBanTableIfRequired()
Hides ban table if no bans are present.
QMenu * banTableContextMenu
static bool RPCParseCommandLine(interfaces::Node *node, std::string &strResult, const std::string &strCommand, bool fExecute, std::string *pstrFilteredOut=nullptr, const QString &wallet_name={})
Split shell command line into a list of arguments and optionally execute the command(s).
void reply(int category, const QString &command)
RPCExecutor(interfaces::Node &node)
interfaces::Node & m_node
void request(const QString &command, const QString &wallet_name)
void push_back(UniValue val)
Interface to Bitcoin wallet from Qt view code.
QString getDisplayName() const
static bool isWalletEnabled()
QString getWalletName() const
Top-level interface for a bitcoin node (bitcoind process).
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 bool getNetworkActive()=0
Get network active.
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 command lines arguments to params object when -named is disabled.
std::string TransportTypeAsString(TransportProtocolType transport_type)
Convert TransportProtocolType enum to a string value.
QString NetworkToQString(Network net)
Convert enum Network to QString.
QString HtmlEscape(const QString &str, bool fMultiLine)
QList< QModelIndex > getEntryData(const QAbstractItemView *view, int column)
Return a field of the currently selected entry as a QString.
QFont fixedPitchFont(bool use_embedded_font)
QString formatBytes(uint64_t bytes)
QString formatDurationStr(std::chrono::seconds dur)
Convert seconds into a QString with days, hours, mins, secs.
void AddButtonShortcut(QAbstractButton *button, const QKeySequence &shortcut)
Connects an additional shortcut to a QAbstractButton.
void handleCloseWindowShortcut(QWidget *w)
void copyEntryData(const QAbstractItemView *view, int column, int role)
Copy a field of the currently selected entry of a view to the clipboard.
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.
QString ConnectionTypeToQString(ConnectionType conn_type, bool prepend_direction)
Convert enum ConnectionType to QString.
QString formatServicesStr(quint64 mask)
Format CNodeStats.nServices bitmask into a user-readable string.
QString formatTimeOffset(int64_t time_offset)
Format a CNodeStateStats.time_offset into a user-readable string.
bool IsEscapeOrBack(int key)
void ThreadRename(const std::string &)
Rename a thread both in terms of an internal (in-memory) name as well as its system thread name.
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
const std::vector< std::string > CONNECTION_TYPE_DOC
const std::vector< std::string > TRANSPORT_TYPE_DOC
const int INITIAL_TRAFFIC_GRAPH_MINS
const struct @8 ICON_MAPPING[]
const QSize FONT_RANGE(4, 40)
const int CONSOLE_HISTORY
static QString categoryClass(int category)
const char fontSizeSettingsKey[]
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.