aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSjors Provoost <sjors@sprovoost.nl>2022-02-21 13:32:21 +0100
committerHennadii Stepanov <32963518+hebasto@users.noreply.github.com>2022-03-17 07:28:50 +0100
commit642f2726deaa1dad21912d4319fac0deb6dbb564 (patch)
tree794ace9bfee49d620e8753b2215582083a91790c
parent940694664de2a10b9d6d81ddff9be05495e6a3da (diff)
downloadbitcoin-642f2726deaa1dad21912d4319fac0deb6dbb564.tar.xz
gui: restore Send for external signer
Before this change the send confirmation dialog would keep the Send option disabled. The Create Unsigned choice would actually send. This is potentially confusing. With this change the Create Unsigned button will not attempt to sign and always produce a PSBT. The Send button will attempt to sign, and only return a PSBT if more signatures are needed. When using an external signer, the Create Unsigned option only appears when PSBT controls are enabled in the wallet settings. This commit maintains the pre-existing behavior of filling the PSBT (without signing) even when not using an external signer. Closes #551 Co-authored-by: Jon Atack <jon@atack.com> Github-Pull: bitcoin-core/gui#555 Rebased-From: 2efdfb88aab6496dcf2b98e0de30635bc6bade85
-rw-r--r--src/qt/sendcoinsdialog.cpp64
-rw-r--r--src/qt/sendcoinsdialog.h2
2 files changed, 40 insertions, 26 deletions
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index b73032cb37..c924789796 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -485,7 +485,9 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
assert(m_current_transaction);
const QString confirmation = tr("Confirm send coins");
- auto confirmationDialog = new SendConfirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, !model->wallet().privateKeysDisabled(), model->getOptionsModel()->getEnablePSBTControls(), this);
+ const bool enable_send{!model->wallet().privateKeysDisabled() || model->wallet().hasExternalSigner()};
+ const bool always_show_unsigned{model->getOptionsModel()->getEnablePSBTControls()};
+ auto confirmationDialog = new SendConfirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, enable_send, always_show_unsigned, this);
confirmationDialog->setAttribute(Qt::WA_DeleteOnClose);
// TODO: Replace QDialog::exec() with safer QDialog::show().
const auto retval = static_cast<QMessageBox::StandardButton>(confirmationDialog->exec());
@@ -498,23 +500,50 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
bool send_failure = false;
if (retval == QMessageBox::Save) {
+ // "Create Unsigned" clicked
CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx())};
PartiallySignedTransaction psbtx(mtx);
bool complete = false;
- // Always fill without signing first. This prevents an external signer
- // from being called prematurely and is not expensive.
- TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, nullptr, psbtx, complete);
+ // Fill without signing
+ TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete);
assert(!complete);
assert(err == TransactionError::OK);
+
+ // Copy PSBT to clipboard and offer to save
+ presentPSBT(psbtx);
+ } else {
+ // "Send" clicked
+ assert(!model->wallet().privateKeysDisabled() || model->wallet().hasExternalSigner());
+ bool broadcast = true;
if (model->wallet().hasExternalSigner()) {
+ CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx())};
+ PartiallySignedTransaction psbtx(mtx);
+ bool complete = false;
+ // Always fill without signing first. This prevents an external signer
+ // from being called prematurely and is not expensive.
+ TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete);
+ assert(!complete);
+ assert(err == TransactionError::OK);
send_failure = !signWithExternalSigner(psbtx, mtx, complete);
+ // Don't broadcast when user rejects it on the device or there's a failure:
+ broadcast = complete && !send_failure;
+ if (!send_failure) {
+ // A transaction signed with an external signer is not always complete,
+ // e.g. in a multisig wallet.
+ if (complete) {
+ // Prepare transaction for broadcast transaction if complete
+ const CTransactionRef tx = MakeTransactionRef(mtx);
+ m_current_transaction->setWtx(tx);
+ } else {
+ presentPSBT(psbtx);
+ }
+ }
}
- // Broadcast transaction if complete (even with an external signer this
- // is not always the case, e.g. in a multisig wallet).
- if (complete) {
- const CTransactionRef tx = MakeTransactionRef(mtx);
- m_current_transaction->setWtx(tx);
+ // Broadcast the transaction, unless an external signer was used and it
+ // failed, or more signatures are needed.
+ if (broadcast) {
+ // now send the prepared transaction
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction);
// process sendStatus and on error generate message shown to user
processSendCoinsReturn(sendStatus);
@@ -524,23 +553,6 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
} else {
send_failure = true;
}
- return;
- }
-
- // Copy PSBT to clipboard and offer to save
- assert(!complete);
- presentPSBT(psbtx);
- } else {
- assert(!model->wallet().privateKeysDisabled());
- // now send the prepared transaction
- WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction);
- // process sendStatus and on error generate message shown to user
- processSendCoinsReturn(sendStatus);
-
- if (sendStatus.status == WalletModel::OK) {
- Q_EMIT coinsSent(m_current_transaction->getWtx()->GetHash());
- } else {
- send_failure = true;
}
}
if (!send_failure) {
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 87f3fbc14c..400503d0c0 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -128,6 +128,8 @@ class SendConfirmationDialog : public QMessageBox
public:
SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, bool enable_send = true, bool always_show_unsigned = true, QWidget* parent = nullptr);
+ /* Returns QMessageBox::Cancel, QMessageBox::Yes when "Send" is
+ clicked and QMessageBox::Save when "Create Unsigned" is clicked. */
int exec() override;
private Q_SLOTS: