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"},
77 <<
"createwalletdescriptor"
79 <<
"signmessagewithprivkey"
80 <<
"signrawtransactionwithkey"
82 <<
"walletpassphrasechange"
110 : QStyledItemDelegate(parent) {}
120#include <qt/rpcconsole.moc>
144 std::vector< std::vector<std::string> > stack;
145 stack.emplace_back();
174 stack.emplace_back();
222 throw std::runtime_error(
"Invalid result query");
229 throw std::runtime_error(
"Invalid result query");
273 case '(':
case ')':
case '\n':
275 throw std::runtime_error(
"Invalid Syntax");
278 if (
ch ==
'(' && stack.size() && stack.back().size() > 0)
283 stack.emplace_back();
288 throw std::runtime_error(
"Invalid Syntax");
294 if ((
ch ==
')' ||
ch ==
'\n') && stack.size() > 0 && stack.back().size() > 0)
299 UniValue params =
RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
300 std::string method = stack.back()[0];
302 if (!wallet_name.isEmpty()) {
315 case ' ':
case ',':
case '\t':
317 throw std::runtime_error(
"Invalid Syntax");
397 "This console accepts RPC commands using the standard syntax.\n"
398 " example: getblockhash 0\n\n"
400 "This console can also accept RPC commands using the parenthesized syntax.\n"
401 " example: getblockhash(0)\n\n"
403 "Commands may be nested when specified with the parenthesized syntax.\n"
404 " example: getblock(getblockhash(0) 1)\n\n"
406 "A space or a comma can be used to delimit arguments for either syntax.\n"
407 " example: getblockhash 0\n"
408 " getblockhash,0\n\n"
410 "Named results can be queried with a non-quoted key string in brackets using the parenthesized syntax.\n"
411 " example: getblock(getblockhash(0) 1)[tx]\n\n"
413 "Results without keys can be queried with an integer in brackets using the parenthesized syntax.\n"
414 " example: getblock(getblockhash(0),1)[tx][0]\n\n")));
428 int code =
objError.find_value(
"code").getInt<
int>();
429 std::string message =
objError.find_value(
"message").get_str();
432 catch (
const std::runtime_error&)
437 catch (
const std::exception&
e)
458 ui->splitter->restoreState(
settings.value(
"RPCConsoleWindowPeersTabSplitterSizes").toByteArray());
463 ui->splitter->restoreState(
settings.value(
"RPCConsoleWidgetPeersTabSplitterSizes").toByteArray());
472 tr(
"Inbound: initiated by peer"),
476 tr(
"Outbound Full Relay: default"),
479 tr(
"Outbound Block Relay: does not relay transactions or addresses"),
484 tr(
"Outbound Manual: added using RPC %1 or %2/%3 configuration options")
490 tr(
"Outbound Feeler: short-lived, for testing addresses"),
493 tr(
"Outbound Address Fetch: short-lived, for soliciting addresses"),
496 tr(
"Private broadcast: short-lived, for broadcasting privacy-sensitive transactions")};
501 tr(
"detecting: peer could be v1 or v2"),
503 tr(
"v1: unencrypted, plaintext transport protocol"),
505 tr(
"v2: BIP324 encrypted transport protocol")};
509 +
ts.
to +
"\" – " +
tr(
"we selected the peer for high bandwidth relay") +
"</li><li>\""
510 +
ts.
from +
"\" – " +
tr(
"the peer selected us for high bandwidth relay") +
"</li><li>\""
511 +
ts.
no +
"\" – " +
tr(
"no high bandwidth relay selected") +
"</li></ul>"};
512 ui->peerHighBandwidthLabel->setToolTip(
ui->peerHighBandwidthLabel->toolTip().arg(
hb_list));
515 ui->openDebugLogfileButton->setToolTip(
ui->openDebugLogfileButton->toolTip().arg(
CLIENT_NAME));
524 ui->fontBiggerButton->setShortcut(
tr(
"Ctrl++"));
530 ui->fontSmallerButton->setShortcut(
tr(
"Ctrl+-"));
537 ui->lineEdit->installEventFilter(
this);
538 ui->lineEdit->setMaxLength(16
_MiB);
539 ui->messagesWidget->installEventFilter(
this);
542 connect(
ui->clearButton, &QAbstractButton::clicked, [
this] { clear(); });
548 ui->WalletSelector->setVisible(
false);
549 ui->WalletSelectorLabel->setVisible(
false);
569 settings.setValue(
"RPCConsoleWindowPeersTabSplitterSizes",
ui->splitter->saveState());
574 settings.setValue(
"RPCConsoleWidgetPeersTabSplitterSizes",
ui->splitter->saveState());
585 if(event->type() == QEvent::KeyPress)
589 Qt::KeyboardModifiers
mod =
keyevt->modifiers();
595 case Qt::Key_PageDown:
596 if (
obj ==
ui->lineEdit) {
597 QApplication::sendEvent(
ui->messagesWidget,
keyevt);
605 QApplication::sendEvent(
ui->lineEdit,
keyevt);
613 if(
obj ==
ui->messagesWidget && (
614 (!
mod && !
keyevt->text().isEmpty() && key != Qt::Key_Tab) ||
615 ((
mod & Qt::ControlModifier) && key == Qt::Key_V) ||
616 ((
mod & Qt::ShiftModifier) && key == Qt::Key_Insert)))
618 ui->lineEdit->setFocus();
619 QApplication::sendEvent(
ui->lineEdit,
keyevt);
624 return QWidget::eventFilter(
obj, event);
641 ui->trafficGraph->setClientModel(model);
661 ui->peerWidget->verticalHeader()->hide();
662 ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
663 ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
664 ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
671 ui->peerWidget->horizontalHeader()->setSectionResizeMode(
PeerTableModel::Age, QHeaderView::ResizeToContents);
672 ui->peerWidget->horizontalHeader()->setStretchLastSection(
true);
691 connect(model->
getPeerTableModel(), &QAbstractItemModel::dataChanged, [
this] { updateDetailWidget(); });
695 ui->banlistWidget->verticalHeader()->hide();
696 ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
697 ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection);
698 ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu);
705 ui->banlistWidget->horizontalHeader()->setStretchLastSection(
true);
731 ui->networkName->setText(QString::fromStdString(
Params().GetChainTypeString()));
745 autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
748 ui->lineEdit->setEnabled(
true);
762void RPCConsole::addWallet(
WalletModel *
const walletModel)
765 ui->WalletSelector->addItem(walletModel->
getDisplayName(), QVariant::fromValue(walletModel));
766 if (
ui->WalletSelector->count() == 2) {
768 ui->WalletSelector->setCurrentIndex(1);
770 if (
ui->WalletSelector->count() > 2) {
771 ui->WalletSelector->setVisible(
true);
772 ui->WalletSelectorLabel->setVisible(
true);
776void RPCConsole::removeWallet(
WalletModel *
const walletModel)
778 ui->WalletSelector->removeItem(
ui->WalletSelector->findData(QVariant::fromValue(walletModel)));
779 if (
ui->WalletSelector->count() == 2) {
780 ui->WalletSelector->setVisible(
false);
781 ui->WalletSelectorLabel->setVisible(
false);
788 ui->WalletSelector->setCurrentIndex(
ui->WalletSelector->findData(
data));
799 default:
return "misc";
822 QString str =
ui->messagesWidget->toHtml();
832 float oldPosFactor = 1.0 /
ui->messagesWidget->verticalScrollBar()->maximum() *
ui->messagesWidget->verticalScrollBar()->value();
834 ui->messagesWidget->setHtml(str);
835 ui->messagesWidget->verticalScrollBar()->setValue(
oldPosFactor *
ui->messagesWidget->verticalScrollBar()->maximum());
840 ui->messagesWidget->clear();
842 ui->lineEdit->setFocus();
848 ui->messagesWidget->document()->addResource(
849 QTextDocument::ImageResource,
860 ui->messagesWidget->document()->setDefaultStyleSheet(
863 "td.time { color: #808080; font-size: %2; padding-top: 3px; } "
864 "td.message { font-family: %1; font-size: %2; white-space:pre-wrap; } "
865 "td.cmd-request { color: #006060; } "
866 "td.cmd-error { color: red; } "
867 ".secwarning { color: red; }"
868 "b { color: #006060; } "
876 tr(
"Welcome to the %1 RPC console.\n"
877 "Use up and down arrows to navigate history, and %2 to clear screen.\n"
878 "Use %3 and %4 to increase or decrease the font size.\n"
879 "Type %5 for an overview of available commands.\n"
880 "For more information on using this console, type %6.\n"
882 "%7WARNING: Scammers have been active, telling users to type"
883 " commands here, stealing their wallet contents. Do not use this console"
884 " without fully understanding the ramifications of a command.%8")
886 "<b>" +
ui->clearButton->shortcut().toString(QKeySequence::NativeText) +
"</b>",
887 "<b>" +
ui->fontBiggerButton->shortcut().toString(QKeySequence::NativeText) +
"</b>",
888 "<b>" +
ui->fontSmallerButton->shortcut().toString(QKeySequence::NativeText) +
"</b>",
890 "<b>help-console</b>",
891 "<span class=\"secwarning\">",
906 if (
e->type() == QEvent::PaletteChange) {
913 ui->messagesWidget->document()->addResource(
914 QTextDocument::ImageResource,
920 QWidget::changeEvent(
e);
925 QTime time = QTime::currentTime();
928 out +=
"<table><tr><td class=\"time\" width=\"65\">" +
timeString +
"</td>";
929 out +=
"<td class=\"icon\" width=\"32\"><img src=\"" +
categoryClass(category) +
"\"></td>";
930 out +=
"<td class=\"message " +
categoryClass(category) +
"\" valign=\"middle\">";
935 out +=
"</td></tr></table>";
936 ui->messagesWidget->append(out);
954 for (
const auto& [addr, info] :
hosts) {
956 if (!addr.IsI2P())
local_addresses +=
":" + QString::number(info.nPort);
981 ui->numberOfBlocks->setText(QString::number(
count));
991 QObject::tr(
"%1 kB").arg(
dynUsage / 1000.0, 0,
'f', 2) :
992 QObject::tr(
"%1 MB").arg(
dynUsage / 1000000.0, 0,
'f', 2);
1002 if (
cmd.isEmpty()) {
1011 throw std::runtime_error(
"Invalid command line");
1013 }
catch (
const std::exception&
e) {
1014 QMessageBox::critical(
this,
"Error",
QString(
"Error: ") + QString::fromStdString(
e.what()));
1029 ui->lineEdit->clear();
1089 ui->lineEdit->setText(
cmd);
1100 ui->messagesWidget->undo();
1107 connect(&
thread, &QThread::finished,
m_executor, &RPCExecutor::deleteLater);
1119 if (
ui->tabWidget->widget(index) ==
ui->tab_console) {
1120 ui->lineEdit->setFocus();
1144 ui->trafficGraph->setGraphRange(std::chrono::minutes{
mins});
1158 ui->peersTabRightPanel->hide();
1159 ui->peerHeading->setText(
tr(
"Select a peer to view detailed information."));
1165 peerAddrDetails +=
tr(
"(peer: %1)").arg(QString::number(stats->nodeStats.nodeid));
1166 if (!stats->nodeStats.addrLocal.empty())
1167 peerAddrDetails +=
"<br />" +
tr(
"via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
1185 ui->peerVersion->setText(stats->nodeStats.nVersion ? QString::number(stats->nodeStats.nVersion) :
ts.
na);
1186 ui->peerSubversion->setText(!stats->nodeStats.cleanSubVer.empty() ? QString::fromStdString(stats->nodeStats.cleanSubVer) :
ts.
na);
1188 ui->peerTransportType->setText(QString::fromStdString(
TransportTypeAsString(stats->nodeStats.m_transport_type)));
1190 ui->peerSessionIdLabel->setVisible(
true);
1191 ui->peerSessionId->setVisible(
true);
1192 ui->peerSessionId->setText(QString::fromStdString(stats->nodeStats.m_session_id));
1194 ui->peerSessionIdLabel->setVisible(
false);
1195 ui->peerSessionId->setVisible(
false);
1199 ui->peerPermissions->setText(
ts.
na);
1207 ui->peerMappedAS->setText(stats->nodeStats.m_mapped_as != 0 ? QString::number(stats->nodeStats.m_mapped_as) :
ts.
na);
1211 if (stats->fNodeStateStatsAvailable) {
1215 if (stats->nodeStateStats.nSyncHeight > -1) {
1216 ui->peerSyncHeight->setText(
QString(
"%1").arg(stats->nodeStateStats.nSyncHeight));
1221 if (stats->nodeStateStats.nCommonHeight > -1) {
1222 ui->peerCommonHeight->setText(
QString(
"%1").arg(stats->nodeStateStats.nCommonHeight));
1227 ui->peerAddrRelayEnabled->setText(stats->nodeStateStats.m_addr_relay_enabled ?
ts.
yes :
ts.
no);
1228 ui->peerAddrProcessed->setText(QString::number(stats->nodeStateStats.m_addr_processed));
1229 ui->peerAddrRateLimited->setText(QString::number(stats->nodeStateStats.m_addr_rate_limited));
1230 ui->peerRelayTxes->setText(stats->nodeStateStats.m_relay_txs ?
ts.
yes :
ts.
no);
1234 ui->peersTabRightPanel->show();
1239 QWidget::resizeEvent(event);
1244 QWidget::showEvent(event);
1260 QWidget::hideEvent(event);
1272 if (index.isValid())
1279 if (index.isValid())
1287 for(
int i = 0; i <
nodes.count(); i++)
1333 ui->peerWidget->selectionModel()->clearSelection();
1350 ui->tabWidget->setCurrentIndex(
int(
tabType));
1355 return ui->tabWidget->tabText(
int(
tab_type));
1372 this->
ui->label_alerts->setVisible(!warnings.isEmpty());
1373 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.
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[]
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.