From 9485fb489209fe12460f74e5796a3f7785163c53 Mon Sep 17 00:00:00 2001 From: Brandon Odiwuor Date: Tue, 14 Nov 2023 14:22:17 +0300 Subject: [PATCH] Gui: getrawtransaction Implementation Add getrawtransaction RPC to GUI on Help > Verify external txid --- src/qt/bitcoingui.cpp | 12 ++ src/qt/bitcoingui.h | 3 + src/qt/forms/helpmessagedialog.ui | 103 +++++++++++++++++ src/qt/utilitydialog.cpp | 182 ++++++++++++++++++++++-------- src/qt/utilitydialog.h | 13 ++- 5 files changed, 264 insertions(+), 49 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 185e1cf1de7..3b6f1699b92 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -368,12 +368,17 @@ void BitcoinGUI::createActions() m_mask_values_action->setStatusTip(tr("Mask the values in the Overview tab")); m_mask_values_action->setCheckable(true); + getRawTransactionAction = new QAction(tr("Verify external txid"), this); + getRawTransactionAction->setMenuRole(QAction::NoRole); + getRawTransactionAction->setStatusTip(tr("getrawtransaction RPC")); + connect(quitAction, &QAction::triggered, this, &BitcoinGUI::quitRequested); connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked); connect(aboutQtAction, &QAction::triggered, qApp, QApplication::aboutQt); connect(optionsAction, &QAction::triggered, this, &BitcoinGUI::optionsClicked); connect(showHelpMessageAction, &QAction::triggered, this, &BitcoinGUI::showHelpMessageClicked); connect(openRPCConsoleAction, &QAction::triggered, this, &BitcoinGUI::showDebugWindow); + connect(getRawTransactionAction, &QAction::triggered, this, &BitcoinGUI::getRawTransactionClicked); // prevents an open debug window from becoming stuck/unusable on client shutdown connect(quitAction, &QAction::triggered, rpcConsole, &QWidget::hide); @@ -560,6 +565,7 @@ void BitcoinGUI::createMenuBar() help->addSeparator(); help->addAction(aboutAction); help->addAction(aboutQtAction); + help->addAction(getRawTransactionAction); } void BitcoinGUI::createToolBars() @@ -932,6 +938,12 @@ void BitcoinGUI::showHelpMessageClicked() GUIUtil::bringToFront(helpMessageDialog); } +void BitcoinGUI::getRawTransactionClicked() +{ + auto dlg = new HelpMessageDialog(this, HelpMessageDialog::GetRawTransactionMode, &m_node); + GUIUtil::ShowModalDialogAsynchronously(dlg); +} + #ifdef ENABLE_WALLET void BitcoinGUI::openClicked() { diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 6fdc4c60d8b..cf004732938 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -145,6 +145,7 @@ class BitcoinGUI : public QMainWindow QAction* m_load_psbt_action = nullptr; QAction* m_load_psbt_clipboard_action = nullptr; QAction* aboutAction = nullptr; + QAction* getRawTransactionAction = nullptr; QAction* receiveCoinsAction = nullptr; QAction* optionsAction = nullptr; QAction* encryptWalletAction = nullptr; @@ -308,6 +309,8 @@ public Q_SLOTS: void showDebugWindowActivateConsole(); /** Show help message dialog */ void showHelpMessageClicked(); + /** show getrawtransaction dialog*/ + void getRawTransactionClicked(); /** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */ void showNormalIfMinimized() { showNormalIfMinimized(false); } diff --git a/src/qt/forms/helpmessagedialog.ui b/src/qt/forms/helpmessagedialog.ui index b7f941f70b4..33f6b4c3222 100644 --- a/src/qt/forms/helpmessagedialog.ui +++ b/src/qt/forms/helpmessagedialog.ui @@ -76,6 +76,60 @@ + + + + 12 + + + + + transaction id: + + + + + + + The transaction id + + + Enter a transaction id... + + + + + + + verbose + + + verbose + + + false + + + + + + + blockhash (optional): + + + + + + + The block in which to look for the transaction + + + Enter Blockhash... + + + + + @@ -135,6 +189,16 @@ + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + @@ -152,6 +216,13 @@ + + + QValidatedLineEdit + QLineEdit +
qt/qvalidatedlineedit.h
+
+
okButton @@ -185,5 +256,37 @@ + + submitButton + accepted() + HelpMessageDialog + onSubmitForm() + + + 395 + 343 + + + 389 + 199 + + + + + submitButton + rejected() + HelpMessageDialog + reject() + + + 395 + 343 + + + 389 + 199 + + + diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 9e592556301..89a81a97517 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include @@ -27,12 +29,14 @@ #include #include #include +#include /** "Help message" or "About" dialog box */ -HelpMessageDialog::HelpMessageDialog(QWidget *parent, Mode _mode) : +HelpMessageDialog::HelpMessageDialog(QWidget *parent, Mode _mode, interfaces::Node* _node) : QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::HelpMessageDialog), - mode(_mode) + mode(_mode), + node(_node) { ui->setupUi(this); @@ -40,7 +44,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, Mode _mode) : switch(mode) { - case AboutMode: + case AboutMode: { setWindowTitle(tr("About %1").arg(PACKAGE_NAME)); @@ -59,56 +63,83 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, Mode _mode) : ui->aboutMessage->setText(version + "

" + licenseInfoHTML); ui->aboutMessage->setWordWrap(true); ui->helpMessage->setVisible(false); + ui->labelTxId->setVisible(false); + ui->txidEdit->setVisible(false); + ui->labelBlockHash->setVisible(false); + ui->blockHashEdit->setVisible(false); + ui->submitButton->setVisible(false); + ui->verboseCheckbox->setVisible(false); break; } - case CommandLineOptionsMode: - setWindowTitle(tr("Command-line options")); - QString header = "Usage: bitcoin-qt [command-line options] \n"; - QTextCursor cursor(ui->helpMessage->document()); - cursor.insertText(version); - cursor.insertBlock(); - cursor.insertText(header); - cursor.insertBlock(); - - std::string strUsage = gArgs.GetHelpMessage(); - QString coreOptions = QString::fromStdString(strUsage); - text = version + "\n\n" + header + "\n" + coreOptions; - - QTextTableFormat tf; - tf.setBorderStyle(QTextFrameFormat::BorderStyle_None); - tf.setCellPadding(2); - QVector widths; - widths << QTextLength(QTextLength::PercentageLength, 35); - widths << QTextLength(QTextLength::PercentageLength, 65); - tf.setColumnWidthConstraints(widths); - - QTextCharFormat bold; - bold.setFontWeight(QFont::Bold); - - for (const QString &line : coreOptions.split("\n")) { - if (line.startsWith(" -")) - { - cursor.currentTable()->appendRows(1); - cursor.movePosition(QTextCursor::PreviousCell); - cursor.movePosition(QTextCursor::NextRow); - cursor.insertText(line.trimmed()); - cursor.movePosition(QTextCursor::NextCell); - } else if (line.startsWith(" ")) { - cursor.insertText(line.trimmed()+' '); - } else if (line.size() > 0) { - //Title of a group - if (cursor.currentTable()) + case CommandLineOptionsMode: + { + setWindowTitle(tr("Command-line options")); + QString header = "Usage: bitcoin-qt [command-line options] \n"; + QTextCursor cursor(ui->helpMessage->document()); + cursor.insertText(version); + cursor.insertBlock(); + cursor.insertText(header); + cursor.insertBlock(); + + std::string strUsage = gArgs.GetHelpMessage(); + QString coreOptions = QString::fromStdString(strUsage); + text = version + "\n\n" + header + "\n" + coreOptions; + + QTextTableFormat tf; + tf.setBorderStyle(QTextFrameFormat::BorderStyle_None); + tf.setCellPadding(2); + QVector widths; + widths << QTextLength(QTextLength::PercentageLength, 35); + widths << QTextLength(QTextLength::PercentageLength, 65); + tf.setColumnWidthConstraints(widths); + + QTextCharFormat bold; + bold.setFontWeight(QFont::Bold); + + for (const QString &line : coreOptions.split("\n")) { + if (line.startsWith(" -")) + { cursor.currentTable()->appendRows(1); - cursor.movePosition(QTextCursor::Down); - cursor.insertText(line.trimmed(), bold); - cursor.insertTable(1, 2, tf); + cursor.movePosition(QTextCursor::PreviousCell); + cursor.movePosition(QTextCursor::NextRow); + cursor.insertText(line.trimmed()); + cursor.movePosition(QTextCursor::NextCell); + } else if (line.startsWith(" ")) { + cursor.insertText(line.trimmed()+' '); + } else if (line.size() > 0) { + //Title of a group + if (cursor.currentTable()) + cursor.currentTable()->appendRows(1); + cursor.movePosition(QTextCursor::Down); + cursor.insertText(line.trimmed(), bold); + cursor.insertTable(1, 2, tf); + } } + + ui->helpMessage->moveCursor(QTextCursor::Start); + ui->scrollArea->setVisible(false); + ui->aboutLogo->setVisible(false); + ui->labelTxId->setVisible(false); + ui->txidEdit->setVisible(false); + ui->labelBlockHash->setVisible(false); + ui->blockHashEdit->setVisible(false); + ui->submitButton->setVisible(false); + ui->verboseCheckbox->setVisible(false); + break; } + case GetRawTransactionMode: + setWindowTitle(tr("getrawtransaction")); + ui->submitButton->button(QDialogButtonBox::Ok)->setText(tr("Submit")); + ui->submitButton->button(QDialogButtonBox::Ok)->setEnabled(false); + ui->scrollArea->setVisible(false); + ui->aboutLogo->setVisible(false); + ui->okButton->setVisible(false); + ui->formLayout->setSpacing(6); - ui->helpMessage->moveCursor(QTextCursor::Start); - ui->scrollArea->setVisible(false); - ui->aboutLogo->setVisible(false); - break; + connect(ui->txidEdit, &QLineEdit::textEdited, [this](const QString& text) { + ui->submitButton->button(QDialogButtonBox::Ok)->setEnabled(!text.isEmpty()); + }); + break; } GUIUtil::handleCloseWindowShortcut(this); @@ -136,6 +167,63 @@ void HelpMessageDialog::showOrPrint() #endif } +QString HelpMessageDialog::txid() const +{ + return ui->txidEdit->text(); +} + +bool HelpMessageDialog::isVerboseChecked() const +{ + return ui->verboseCheckbox->isChecked(); +} + +QString HelpMessageDialog::blockhash() const +{ + return ui->blockHashEdit->text(); +} + +void HelpMessageDialog::onSubmitForm() +{ + std::string transaction_id = txid().toUtf8().constData(); + bool verbose = isVerboseChecked(); + std::string block_hash = blockhash().toUtf8().constData(); + std::string result; + + getrawtransactionRPC(transaction_id, verbose, block_hash, result); + + QTextDocument *document = ui->helpMessage->document(); + document->clear(); + QTextCursor cursor(document); + cursor.movePosition(QTextCursor::Start); + cursor.insertText(QString::fromStdString(result)); +} + +void HelpMessageDialog::getrawtransactionRPC(std::string txid, bool verbose, std::string blockhash, std::string& result) +{ + std::string command {"getrawtransaction"}; + std::vector args {txid}; + args.emplace_back(verbose ? "true" : "false"); + if (!blockhash.empty()) { + args.emplace_back(blockhash); + } + UniValue params {RPCConvertValues(command, args)}; + UniValue lastResult; + + try { + assert(node); + lastResult = node->executeRpc(command, params, ""); + + if (lastResult.isStr()) + result = lastResult.get_str(); + else + result = lastResult.write(2); + } catch (std::exception& e) { + result = "Error: " + std::string(e.what()); + } catch (...) { + result = "No such mempool transaction. Use -txindex or provide a block hash to enable blockchain transaction queries. Use gettransaction for wallet transactions"; + } +} + void HelpMessageDialog::on_okButton_accepted() { close(); diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h index 44397538eea..c5f53a1dc2d 100644 --- a/src/qt/utilitydialog.h +++ b/src/qt/utilitydialog.h @@ -7,6 +7,7 @@ #include #include +#include QT_BEGIN_NAMESPACE class QMainWindow; @@ -24,22 +25,30 @@ class HelpMessageDialog : public QDialog public: enum Mode { AboutMode, - CommandLineOptionsMode + CommandLineOptionsMode, + GetRawTransactionMode }; - explicit HelpMessageDialog(QWidget *parent, Mode _mode); + explicit HelpMessageDialog(QWidget *parent, Mode _mode, interfaces::Node* _node = NULL); ~HelpMessageDialog(); void printToConsole(); void showOrPrint(); + QString txid() const; + bool isVerboseChecked() const; + QString blockhash() const; + void getrawtransactionRPC(std::string txid, bool verbose, std::string blockhash, std::string& result); + private: Ui::HelpMessageDialog *ui; QString text; Mode mode; + interfaces::Node* node; private Q_SLOTS: void on_okButton_accepted(); + void onSubmitForm(); };