5#include <bitcoin-build-config.h>
8#include <qt/forms/ui_debugwindow.h>
10#include <chainparams.h>
32#include <QAbstractButton>
33#include <QAbstractItemModel>
37#include <QKeySequence>
38#include <QLatin1String>
47#include <QStyledItemDelegate>
65 {
"cmd-request",
":/icons/tx_input"},
66 {
"cmd-reply",
":/icons/tx_output"},
67 {
"cmd-error",
":/icons/tx_output"},
68 {
"misc",
":/icons/tx_inout"},
78 <<
"createwalletdescriptor"
80 <<
"signmessagewithprivkey"
81 <<
"signrawtransactionwithkey"
83 <<
"walletpassphrasechange"
111 : QStyledItemDelegate(parent) {}
121#include <qt/rpcconsole.moc>
145 std::vector< std::vector<std::string> > stack;
146 stack.emplace_back();
175 stack.emplace_back();
223 throw std::runtime_error(
"Invalid result query");
230 throw std::runtime_error(
"Invalid result query");
274 case '(':
case ')':
case '\n':
276 throw std::runtime_error(
"Invalid Syntax");
279 if (
ch ==
'(' && stack.size() && stack.back().size() > 0)
284 stack.emplace_back();
289 throw std::runtime_error(
"Invalid Syntax");
295 if ((
ch ==
')' ||
ch ==
'\n') && stack.size() > 0 && stack.back().size() > 0)
300 UniValue params =
RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
301 std::string method = stack.back()[0];
303 if (!wallet_name.isEmpty()) {
316 case ' ':
case ',':
case '\t':
318 throw std::runtime_error(
"Invalid Syntax");
398 "This console accepts RPC commands using the standard syntax.\n"
399 " example: getblockhash 0\n\n"
401 "This console can also accept RPC commands using the parenthesized syntax.\n"
402 " example: getblockhash(0)\n\n"
404 "Commands may be nested when specified with the parenthesized syntax.\n"
405 " example: getblock(getblockhash(0) 1)\n\n"
407 "A space or a comma can be used to delimit arguments for either syntax.\n"
408 " example: getblockhash 0\n"
409 " getblockhash,0\n\n"
411 "Named results can be queried with a non-quoted key string in brackets using the parenthesized syntax.\n"
412 " example: getblock(getblockhash(0) 1)[tx]\n\n"
414 "Results without keys can be queried with an integer in brackets using the parenthesized syntax.\n"
415 " example: getblock(getblockhash(0),1)[tx][0]\n\n")));
429 int code =
objError.find_value(
"code").getInt<
int>();
430 std::string message =
objError.find_value(
"message").get_str();
433 catch (
const std::runtime_error&)
438 catch (
const std::exception&
e)
459 ui->splitter->restoreState(
settings.value(
"RPCConsoleWindowPeersTabSplitterSizes").toByteArray());
464 ui->splitter->restoreState(
settings.value(
"RPCConsoleWidgetPeersTabSplitterSizes").toByteArray());
473 tr(
"Inbound: initiated by peer"),
477 tr(
"Outbound Full Relay: default"),
480 tr(
"Outbound Block Relay: does not relay transactions or addresses"),
485 tr(
"Outbound Manual: added using RPC %1 or %2/%3 configuration options")
491 tr(
"Outbound Feeler: short-lived, for testing addresses"),
494 tr(
"Outbound Address Fetch: short-lived, for soliciting addresses"),
497 tr(
"Private broadcast: short-lived, for broadcasting privacy-sensitive transactions")};
502 tr(
"detecting: peer could be v1 or v2"),
504 tr(
"v1: unencrypted, plaintext transport protocol"),
506 tr(
"v2: BIP324 encrypted transport protocol")};
510 +
ts.
to +
"\" – " +
tr(
"we selected the peer for high bandwidth relay") +
"</li><li>\""
511 +
ts.
from +
"\" – " +
tr(
"the peer selected us for high bandwidth relay") +
"</li><li>\""
512 +
ts.
no +
"\" – " +
tr(
"no high bandwidth relay selected") +
"</li></ul>"};
513 ui->peerHighBandwidthLabel->setToolTip(
ui->peerHighBandwidthLabel->toolTip().arg(
hb_list));
516 ui->openDebugLogfileButton->setToolTip(
ui->openDebugLogfileButton->toolTip().arg(
CLIENT_NAME));
525 ui->fontBiggerButton->setShortcut(
tr(
"Ctrl++"));
531 ui->fontSmallerButton->setShortcut(
tr(
"Ctrl+-"));
538 ui->lineEdit->installEventFilter(
this);
539 ui->lineEdit->setMaxLength(16
_MiB);
540 ui->messagesWidget->installEventFilter(
this);
543 connect(
ui->clearButton, &QAbstractButton::clicked, [
this] { clear(); });
549 ui->WalletSelector->setVisible(
false);
550 ui->WalletSelectorLabel->setVisible(
false);
570 settings.setValue(
"RPCConsoleWindowPeersTabSplitterSizes",
ui->splitter->saveState());
575 settings.setValue(
"RPCConsoleWidgetPeersTabSplitterSizes",
ui->splitter->saveState());
586 if(event->type() == QEvent::KeyPress)
590 Qt::KeyboardModifiers
mod =
keyevt->modifiers();
596 case Qt::Key_PageDown:
597 if (
obj ==
ui->lineEdit) {
598 QApplication::sendEvent(
ui->messagesWidget,
keyevt);
606 QApplication::sendEvent(
ui->lineEdit,
keyevt);
614 if(
obj ==
ui->messagesWidget && (
615 (!
mod && !
keyevt->text().isEmpty() && key != Qt::Key_Tab) ||
616 ((
mod & Qt::ControlModifier) && key == Qt::Key_V) ||
617 ((
mod & Qt::ShiftModifier) && key == Qt::Key_Insert)))
619 ui->lineEdit->setFocus();
620 QApplication::sendEvent(
ui->lineEdit,
keyevt);
625 return QWidget::eventFilter(
obj, event);
642 ui->trafficGraph->setClientModel(model);
662 ui->peerWidget->verticalHeader()->hide();
663 ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
664 ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
665 ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
672 ui->peerWidget->horizontalHeader()->setSectionResizeMode(
PeerTableModel::Age, QHeaderView::ResizeToContents);
673 ui->peerWidget->horizontalHeader()->setStretchLastSection(
true);
692 connect(model->
getPeerTableModel(), &QAbstractItemModel::dataChanged, [
this] { updateDetailWidget(); });
696 ui->banlistWidget->verticalHeader()->hide();
697 ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
698 ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection);
699 ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu);
706 ui->banlistWidget->horizontalHeader()->setStretchLastSection(
true);
732 ui->networkName->setText(QString::fromStdString(
Params().GetChainTypeString()));
746 autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
749 ui->lineEdit->setEnabled(
true);
763void RPCConsole::addWallet(
WalletModel *
const walletModel)
766 ui->WalletSelector->addItem(walletModel->
getDisplayName(), QVariant::fromValue(walletModel));
767 if (
ui->WalletSelector->count() == 2) {
769 ui->WalletSelector->setCurrentIndex(1);
771 if (
ui->WalletSelector->count() > 2) {
772 ui->WalletSelector->setVisible(
true);
773 ui->WalletSelectorLabel->setVisible(
true);
777void RPCConsole::removeWallet(
WalletModel *
const walletModel)
779 ui->WalletSelector->removeItem(
ui->WalletSelector->findData(QVariant::fromValue(walletModel)));
780 if (
ui->WalletSelector->count() == 2) {
781 ui->WalletSelector->setVisible(
false);
782 ui->WalletSelectorLabel->setVisible(
false);
789 ui->WalletSelector->setCurrentIndex(
ui->WalletSelector->findData(
data));
800 default:
return "misc";
823 QString str =
ui->messagesWidget->toHtml();
833 float oldPosFactor = 1.0 /
ui->messagesWidget->verticalScrollBar()->maximum() *
ui->messagesWidget->verticalScrollBar()->value();
835 ui->messagesWidget->setHtml(str);
836 ui->messagesWidget->verticalScrollBar()->setValue(
oldPosFactor *
ui->messagesWidget->verticalScrollBar()->maximum());
841 ui->messagesWidget->clear();
843 ui->lineEdit->setFocus();
849 ui->messagesWidget->document()->addResource(
850 QTextDocument::ImageResource,
861 ui->messagesWidget->document()->setDefaultStyleSheet(
864 "td.time { color: #808080; font-size: %2; padding-top: 3px; } "
865 "td.message { font-family: %1; font-size: %2; white-space:pre-wrap; } "
866 "td.cmd-request { color: #006060; } "
867 "td.cmd-error { color: red; } "
868 ".secwarning { color: red; }"
869 "b { color: #006060; } "
877 tr(
"Welcome to the %1 RPC console.\n"
878 "Use up and down arrows to navigate history, and %2 to clear screen.\n"
879 "Use %3 and %4 to increase or decrease the font size.\n"
880 "Type %5 for an overview of available commands.\n"
881 "For more information on using this console, type %6.\n"
883 "%7WARNING: Scammers have been active, telling users to type"
884 " commands here, stealing their wallet contents. Do not use this console"
885 " without fully understanding the ramifications of a command.%8")
887 "<b>" +
ui->clearButton->shortcut().toString(QKeySequence::NativeText) +
"</b>",
888 "<b>" +
ui->fontBiggerButton->shortcut().toString(QKeySequence::NativeText) +
"</b>",
889 "<b>" +
ui->fontSmallerButton->shortcut().toString(QKeySequence::NativeText) +
"</b>",
891 "<b>help-console</b>",
892 "<span class=\"secwarning\">",
907 if (
e->type() == QEvent::PaletteChange) {
914 ui->messagesWidget->document()->addResource(
915 QTextDocument::ImageResource,
921 QWidget::changeEvent(
e);
926 QTime time = QTime::currentTime();
929 out +=
"<table><tr><td class=\"time\" width=\"65\">" +
timeString +
"</td>";
930 out +=
"<td class=\"icon\" width=\"32\"><img src=\"" +
categoryClass(category) +
"\"></td>";
931 out +=
"<td class=\"message " +
categoryClass(category) +
"\" valign=\"middle\">";
936 out +=
"</td></tr></table>";
937 ui->messagesWidget->append(out);
955 for (
const auto& [addr, info] :
hosts) {
957 if (!addr.IsI2P())
local_addresses +=
":" + QString::number(info.nPort);
982 ui->numberOfBlocks->setText(QString::number(
count));
992 QObject::tr(
"%1 kB").arg(
dynUsage / 1000.0, 0,
'f', 2) :
993 QObject::tr(
"%1 MB").arg(
dynUsage / 1000000.0, 0,
'f', 2);
1003 if (
cmd.isEmpty()) {
1012 throw std::runtime_error(
"Invalid command line");
1014 }
catch (
const std::exception&
e) {
1015 QMessageBox::critical(
this,
"Error",
QString(
"Error: ") + QString::fromStdString(
e.what()));
1030 ui->lineEdit->clear();
1090 ui->lineEdit->setText(
cmd);
1101 ui->messagesWidget->undo();
1108 connect(&
thread, &QThread::finished,
m_executor, &RPCExecutor::deleteLater);
1120 if (
ui->tabWidget->widget(index) ==
ui->tab_console) {
1121 ui->lineEdit->setFocus();
1145 ui->trafficGraph->setGraphRange(std::chrono::minutes{
mins});
1159 ui->peersTabRightPanel->hide();
1160 ui->peerHeading->setText(
tr(
"Select a peer to view detailed information."));
1166 peerAddrDetails +=
tr(
"(peer: %1)").arg(QString::number(stats->nodeStats.nodeid));
1167 if (!stats->nodeStats.addrLocal.empty())
1168 peerAddrDetails +=
"<br />" +
tr(
"via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
1186 ui->peerVersion->setText(stats->nodeStats.nVersion ? QString::number(stats->nodeStats.nVersion) :
ts.
na);
1187 ui->peerSubversion->setText(!stats->nodeStats.cleanSubVer.empty() ? QString::fromStdString(stats->nodeStats.cleanSubVer) :
ts.
na);
1189 ui->peerTransportType->setText(QString::fromStdString(
TransportTypeAsString(stats->nodeStats.m_transport_type)));
1191 ui->peerSessionIdLabel->setVisible(
true);
1192 ui->peerSessionId->setVisible(
true);
1193 ui->peerSessionId->setText(QString::fromStdString(stats->nodeStats.m_session_id));
1195 ui->peerSessionIdLabel->setVisible(
false);
1196 ui->peerSessionId->setVisible(
false);
1200 ui->peerPermissions->setText(
ts.
na);
1208 ui->peerMappedAS->setText(stats->nodeStats.m_mapped_as != 0 ? QString::number(stats->nodeStats.m_mapped_as) :
ts.
na);
1212 if (stats->fNodeStateStatsAvailable) {
1216 if (stats->nodeStateStats.nSyncHeight > -1) {
1217 ui->peerSyncHeight->setText(
QString(
"%1").arg(stats->nodeStateStats.nSyncHeight));
1222 if (stats->nodeStateStats.nCommonHeight > -1) {
1223 ui->peerCommonHeight->setText(
QString(
"%1").arg(stats->nodeStateStats.nCommonHeight));
1228 ui->peerAddrRelayEnabled->setText(stats->nodeStateStats.m_addr_relay_enabled ?
ts.
yes :
ts.
no);
1229 ui->peerAddrProcessed->setText(QString::number(stats->nodeStateStats.m_addr_processed));
1230 ui->peerAddrRateLimited->setText(QString::number(stats->nodeStateStats.m_addr_rate_limited));
1231 ui->peerRelayTxes->setText(stats->nodeStateStats.m_relay_txs ?
ts.
yes :
ts.
no);
1235 ui->peersTabRightPanel->show();
1240 QWidget::resizeEvent(event);
1245 QWidget::showEvent(event);
1261 QWidget::hideEvent(event);
1273 if (index.isValid())
1280 if (index.isValid())
1288 for(
int i = 0; i <
nodes.count(); i++)
1334 ui->peerWidget->selectionModel()->clearSelection();
1351 ui->tabWidget->setCurrentIndex(
int(
tabType));
1356 return ui->tabWidget->tabText(
int(
tab_type));
1373 this->
ui->label_alerts->setVisible(!warnings.isEmpty());
1374 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
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.
QString TimeDurationField(NodeClock::time_point now, NodeClock::time_point event) const
Format the duration between now and event as a string.
@ 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.
static const PrecomputedData data
Precomputed COutPoint and CCoins values.
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 formatPingTime(NodeClock::duration ping_time)
Format a CNodeStats.m_last_ping_time/m_min_ping_time/m_ping_wait into a user-readable string if it ex...
QString formatBytes(uint64_t bytes)
void AddButtonShortcut(QAbstractButton *button, const QKeySequence &shortcut)
Connects an additional shortcut to a QAbstractButton.
void handleCloseWindowShortcut(QWidget *w)
QString formatDurationStr(std::chrono::nanoseconds dur)
Convert a duration into a QString with days, hours, mins, secs. This ignores sub-seconds.
void copyEntryData(const QAbstractItemView *view, int column, int role)
Copy a field of the currently selected entry of a view to the clipboard.
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.
int64_t NodeId
Identifier of a peer connection.
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[]
Utilities for converting data from/to strings.
static time_point now() noexcept
Return current system time or mocked time, if set.
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.