mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-09-13 18:13:42 +02:00
Merge bitcoin-core/gui#399: Fix "Load PSBT" functionality when no wallet loaded
0237d95323
qt: Add Load PSBT functionaliy with nowallet (Prateek Sancheti) Pull request description: This PR provides a fix to the issue mentioned in #232. Currently, the **_Load PSBT_** functionality works well in case a wallet is loaded but does nothing when a wallet isn't loaded. If a function cannot work without a wallet being loaded, it is disabled by default (It is unclickable as shown in the image). For e.g. One cannot `Close Wallet` or `Backup Wallet` or `Sign Messages` without a wallet being loaded. And hence they are disabled. But if you notice, `Load PSBT` options are not disabled by default even when a wallet isn't loaded. >  As mentioned by hebasto in the issue description : ``` <hebasto> achow101: does "File" -> "Load PSBT from {file|clipboard}" make any sense when no wallet is loaded? <achow101> hebasto: yes, for finalize and sending ``` This means **_Load PSBT_** should be working just as similar whether wallets are being loaded or not. After making the required changes to the code, The **_Load PSBT_** works as expected even with no wallet loaded and the PSBT is finalized. | Master | PR | |-------------|---------------| |  |  | Close #232 ACKs for top commit: achow101: re-ACK0237d95323
hebasto: ACK0237d95323
, tested on Linux Mint 20.2 (Qt 5.12.8). Tree-SHA512: 8d928c5bfd3c2b286ddcacd0b367c872de8bc3d3d9d82280faeadc60d738b86af328c060b5763ade364c9b386b23f95580c2eb1147b16373fbb713170c100350
This commit is contained in:
@@ -110,6 +110,9 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
|
|||||||
connect(activity, &CreateWalletActivity::finished, activity, &QObject::deleteLater);
|
connect(activity, &CreateWalletActivity::finished, activity, &QObject::deleteLater);
|
||||||
activity->create();
|
activity->create();
|
||||||
});
|
});
|
||||||
|
connect(walletFrame, &WalletFrame::message, [this](const QString& title, const QString& message, unsigned int style) {
|
||||||
|
this->message(title, message, style);
|
||||||
|
});
|
||||||
setCentralWidget(walletFrame);
|
setCentralWidget(walletFrame);
|
||||||
} else
|
} else
|
||||||
#endif // ENABLE_WALLET
|
#endif // ENABLE_WALLET
|
||||||
|
@@ -47,18 +47,22 @@ void PSBTOperationsDialog::openWithPSBT(PartiallySignedTransaction psbtx)
|
|||||||
{
|
{
|
||||||
m_transaction_data = psbtx;
|
m_transaction_data = psbtx;
|
||||||
|
|
||||||
bool complete;
|
bool complete = FinalizePSBT(psbtx); // Make sure all existing signatures are fully combined before checking for completeness.
|
||||||
size_t n_could_sign;
|
if (m_wallet_model) {
|
||||||
FinalizePSBT(psbtx); // Make sure all existing signatures are fully combined before checking for completeness.
|
size_t n_could_sign;
|
||||||
TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, &n_could_sign, m_transaction_data, complete);
|
TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, &n_could_sign, m_transaction_data, complete);
|
||||||
if (err != TransactionError::OK) {
|
if (err != TransactionError::OK) {
|
||||||
showStatus(tr("Failed to load transaction: %1")
|
showStatus(tr("Failed to load transaction: %1")
|
||||||
.arg(QString::fromStdString(TransactionErrorString(err).translated)), StatusLevel::ERR);
|
.arg(QString::fromStdString(TransactionErrorString(err).translated)),
|
||||||
return;
|
StatusLevel::ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_ui->signTransactionButton->setEnabled(!complete && !m_wallet_model->wallet().privateKeysDisabled() && n_could_sign > 0);
|
||||||
|
} else {
|
||||||
|
m_ui->signTransactionButton->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ui->broadcastTransactionButton->setEnabled(complete);
|
m_ui->broadcastTransactionButton->setEnabled(complete);
|
||||||
m_ui->signTransactionButton->setEnabled(!complete && !m_wallet_model->wallet().privateKeysDisabled() && n_could_sign > 0);
|
|
||||||
|
|
||||||
updateTransactionDisplay();
|
updateTransactionDisplay();
|
||||||
}
|
}
|
||||||
@@ -133,7 +137,7 @@ void PSBTOperationsDialog::saveTransaction() {
|
|||||||
}
|
}
|
||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
ExtractDestination(out.scriptPubKey, address);
|
ExtractDestination(out.scriptPubKey, address);
|
||||||
QString amount = BitcoinUnits::format(m_wallet_model->getOptionsModel()->getDisplayUnit(), out.nValue);
|
QString amount = BitcoinUnits::format(m_client_model->getOptionsModel()->getDisplayUnit(), out.nValue);
|
||||||
QString address_str = QString::fromStdString(EncodeDestination(address));
|
QString address_str = QString::fromStdString(EncodeDestination(address));
|
||||||
filename_suggestion.append(address_str + "-" + amount);
|
filename_suggestion.append(address_str + "-" + amount);
|
||||||
first = false;
|
first = false;
|
||||||
@@ -224,6 +228,10 @@ void PSBTOperationsDialog::showStatus(const QString &msg, StatusLevel level) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t PSBTOperationsDialog::couldSignInputs(const PartiallySignedTransaction &psbtx) {
|
size_t PSBTOperationsDialog::couldSignInputs(const PartiallySignedTransaction &psbtx) {
|
||||||
|
if (!m_wallet_model) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t n_signed;
|
size_t n_signed;
|
||||||
bool complete;
|
bool complete;
|
||||||
TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, false /* bip32derivs */, &n_signed, m_transaction_data, complete);
|
TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, false /* bip32derivs */, &n_signed, m_transaction_data, complete);
|
||||||
@@ -246,7 +254,10 @@ void PSBTOperationsDialog::showTransactionStatus(const PartiallySignedTransactio
|
|||||||
case PSBTRole::SIGNER: {
|
case PSBTRole::SIGNER: {
|
||||||
QString need_sig_text = tr("Transaction still needs signature(s).");
|
QString need_sig_text = tr("Transaction still needs signature(s).");
|
||||||
StatusLevel level = StatusLevel::INFO;
|
StatusLevel level = StatusLevel::INFO;
|
||||||
if (m_wallet_model->wallet().privateKeysDisabled()) {
|
if (!m_wallet_model) {
|
||||||
|
need_sig_text += " " + tr("(But no wallet is loaded.)");
|
||||||
|
level = StatusLevel::WARN;
|
||||||
|
} else if (m_wallet_model->wallet().privateKeysDisabled()) {
|
||||||
need_sig_text += " " + tr("(But this wallet cannot sign transactions.)");
|
need_sig_text += " " + tr("(But this wallet cannot sign transactions.)");
|
||||||
level = StatusLevel::WARN;
|
level = StatusLevel::WARN;
|
||||||
} else if (n_could_sign < 1) {
|
} else if (n_could_sign < 1) {
|
||||||
|
@@ -4,12 +4,18 @@
|
|||||||
|
|
||||||
#include <qt/walletframe.h>
|
#include <qt/walletframe.h>
|
||||||
|
|
||||||
|
#include <node/ui_interface.h>
|
||||||
|
#include <psbt.h>
|
||||||
|
#include <qt/guiutil.h>
|
||||||
#include <qt/overviewpage.h>
|
#include <qt/overviewpage.h>
|
||||||
|
#include <qt/psbtoperationsdialog.h>
|
||||||
#include <qt/walletmodel.h>
|
#include <qt/walletmodel.h>
|
||||||
#include <qt/walletview.h>
|
#include <qt/walletview.h>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QClipboard>
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
@@ -184,10 +190,40 @@ void WalletFrame::gotoVerifyMessageTab(QString addr)
|
|||||||
|
|
||||||
void WalletFrame::gotoLoadPSBT(bool from_clipboard)
|
void WalletFrame::gotoLoadPSBT(bool from_clipboard)
|
||||||
{
|
{
|
||||||
WalletView *walletView = currentWalletView();
|
std::string data;
|
||||||
if (walletView) {
|
|
||||||
walletView->gotoLoadPSBT(from_clipboard);
|
if (from_clipboard) {
|
||||||
|
std::string raw = QApplication::clipboard()->text().toStdString();
|
||||||
|
bool invalid;
|
||||||
|
data = DecodeBase64(raw, &invalid);
|
||||||
|
if (invalid) {
|
||||||
|
Q_EMIT message(tr("Error"), tr("Unable to decode PSBT from clipboard (invalid base64)"), CClientUIInterface::MSG_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QString filename = GUIUtil::getOpenFileName(this,
|
||||||
|
tr("Load Transaction Data"), QString(),
|
||||||
|
tr("Partially Signed Transaction (*.psbt)"), nullptr);
|
||||||
|
if (filename.isEmpty()) return;
|
||||||
|
if (GetFileSize(filename.toLocal8Bit().data(), MAX_FILE_SIZE_PSBT) == MAX_FILE_SIZE_PSBT) {
|
||||||
|
Q_EMIT message(tr("Error"), tr("PSBT file must be smaller than 100 MiB"), CClientUIInterface::MSG_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::ifstream in(filename.toLocal8Bit().data(), std::ios::binary);
|
||||||
|
data = std::string(std::istreambuf_iterator<char>{in}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string error;
|
||||||
|
PartiallySignedTransaction psbtx;
|
||||||
|
if (!DecodeRawPSBT(psbtx, data, error)) {
|
||||||
|
Q_EMIT message(tr("Error"), tr("Unable to decode PSBT") + "\n" + QString::fromStdString(error), CClientUIInterface::MSG_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PSBTOperationsDialog* dlg = new PSBTOperationsDialog(this, currentWalletModel(), clientModel);
|
||||||
|
dlg->openWithPSBT(psbtx);
|
||||||
|
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
dlg->exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletFrame::encryptWallet()
|
void WalletFrame::encryptWallet()
|
||||||
|
@@ -48,6 +48,7 @@ public:
|
|||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void createWalletButtonClicked();
|
void createWalletButtonClicked();
|
||||||
|
void message(const QString& title, const QString& message, unsigned int style);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStackedWidget *walletStack;
|
QStackedWidget *walletStack;
|
||||||
|
@@ -8,7 +8,6 @@
|
|||||||
#include <qt/askpassphrasedialog.h>
|
#include <qt/askpassphrasedialog.h>
|
||||||
#include <qt/clientmodel.h>
|
#include <qt/clientmodel.h>
|
||||||
#include <qt/guiutil.h>
|
#include <qt/guiutil.h>
|
||||||
#include <qt/psbtoperationsdialog.h>
|
|
||||||
#include <qt/optionsmodel.h>
|
#include <qt/optionsmodel.h>
|
||||||
#include <qt/overviewpage.h>
|
#include <qt/overviewpage.h>
|
||||||
#include <qt/platformstyle.h>
|
#include <qt/platformstyle.h>
|
||||||
@@ -21,13 +20,10 @@
|
|||||||
|
|
||||||
#include <interfaces/node.h>
|
#include <interfaces/node.h>
|
||||||
#include <node/ui_interface.h>
|
#include <node/ui_interface.h>
|
||||||
#include <psbt.h>
|
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
#include <QApplication>
|
|
||||||
#include <QClipboard>
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QProgressDialog>
|
#include <QProgressDialog>
|
||||||
@@ -205,44 +201,6 @@ void WalletView::gotoVerifyMessageTab(QString addr)
|
|||||||
signVerifyMessageDialog->setAddress_VM(addr);
|
signVerifyMessageDialog->setAddress_VM(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletView::gotoLoadPSBT(bool from_clipboard)
|
|
||||||
{
|
|
||||||
std::string data;
|
|
||||||
|
|
||||||
if (from_clipboard) {
|
|
||||||
std::string raw = QApplication::clipboard()->text().toStdString();
|
|
||||||
bool invalid;
|
|
||||||
data = DecodeBase64(raw, &invalid);
|
|
||||||
if (invalid) {
|
|
||||||
Q_EMIT message(tr("Error"), tr("Unable to decode PSBT from clipboard (invalid base64)"), CClientUIInterface::MSG_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
QString filename = GUIUtil::getOpenFileName(this,
|
|
||||||
tr("Load Transaction Data"), QString(),
|
|
||||||
tr("Partially Signed Transaction (*.psbt)"), nullptr);
|
|
||||||
if (filename.isEmpty()) return;
|
|
||||||
if (GetFileSize(filename.toLocal8Bit().data(), MAX_FILE_SIZE_PSBT) == MAX_FILE_SIZE_PSBT) {
|
|
||||||
Q_EMIT message(tr("Error"), tr("PSBT file must be smaller than 100 MiB"), CClientUIInterface::MSG_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::ifstream in(filename.toLocal8Bit().data(), std::ios::binary);
|
|
||||||
data = std::string(std::istreambuf_iterator<char>{in}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string error;
|
|
||||||
PartiallySignedTransaction psbtx;
|
|
||||||
if (!DecodeRawPSBT(psbtx, data, error)) {
|
|
||||||
Q_EMIT message(tr("Error"), tr("Unable to decode PSBT") + "\n" + QString::fromStdString(error), CClientUIInterface::MSG_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PSBTOperationsDialog* dlg = new PSBTOperationsDialog(this, walletModel, clientModel);
|
|
||||||
dlg->openWithPSBT(psbtx);
|
|
||||||
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
|
||||||
dlg->exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletView::handlePaymentRequest(const SendCoinsRecipient& recipient)
|
bool WalletView::handlePaymentRequest(const SendCoinsRecipient& recipient)
|
||||||
{
|
{
|
||||||
return sendCoinsPage->handlePaymentRequest(recipient);
|
return sendCoinsPage->handlePaymentRequest(recipient);
|
||||||
|
@@ -83,8 +83,6 @@ public Q_SLOTS:
|
|||||||
void gotoSignMessageTab(QString addr = "");
|
void gotoSignMessageTab(QString addr = "");
|
||||||
/** Show Sign/Verify Message dialog and switch to verify message tab */
|
/** Show Sign/Verify Message dialog and switch to verify message tab */
|
||||||
void gotoVerifyMessageTab(QString addr = "");
|
void gotoVerifyMessageTab(QString addr = "");
|
||||||
/** Load Partially Signed Bitcoin Transaction */
|
|
||||||
void gotoLoadPSBT(bool from_clipboard = false);
|
|
||||||
|
|
||||||
/** Show incoming transaction notification for new transactions.
|
/** Show incoming transaction notification for new transactions.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user