Skip to content

Commit 58adbcf

Browse files
committed
qt: Defer transaction signing until user clicks Send
Fixes #30070 When creating an unsigned PSBT from the GUI, the transaction was already signed during preparation, causing legacy inputs to have non-empty scriptSig fields. The PSBT parser then rejects them. This defers signing until the user clicks "Send" instead of signing during preparation. Fee calculation still works since transactions can be created without signing. Follows the approach suggested by @achow101 in the issue comments.
1 parent 0690514 commit 58adbcf

3 files changed

Lines changed: 26 additions & 4 deletions

File tree

src/qt/sendcoinsdialog.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,16 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa
281281
}
282282

283283
// prepare transaction for getting txFee earlier
284+
// Create unsigned transaction to support creating unsigned PSBTs.
285+
// Signing is deferred until the user clicks "Send".
284286
m_current_transaction = std::make_unique<WalletModelTransaction>(recipients);
285287
WalletModel::SendCoinsReturn prepareStatus;
286288

287289
updateCoinControlState();
288290

289291
CCoinControl coin_control = *m_coin_control;
290292
coin_control.m_allow_other_inputs = !coin_control.HasSelected(); // future, could introduce a checkbox to customize this value.
291-
prepareStatus = model->prepareTransaction(*m_current_transaction, coin_control);
293+
prepareStatus = model->prepareTransaction(*m_current_transaction, coin_control, /*sign=*/false);
292294

293295
// process prepareStatus and on error generate message shown to user
294296
processSendCoinsReturn(prepareStatus,
@@ -540,6 +542,24 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
540542
presentPSBT(psbtx);
541543
}
542544
}
545+
} else {
546+
// Sign the transaction now that the user has confirmed they want to send.
547+
CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx())};
548+
PartiallySignedTransaction psbtx(mtx);
549+
bool complete = false;
550+
// Fill and sign the PSBT
551+
const auto err{model->wallet().fillPSBT(std::nullopt, /*sign=*/true, /*bip32derivs=*/false, /*n_signed=*/nullptr, psbtx, complete)};
552+
if (err || !complete) {
553+
Q_EMIT message(tr("Send Coins"), tr("Failed to sign transaction."),
554+
CClientUIInterface::MSG_ERROR);
555+
send_failure = true;
556+
broadcast = false;
557+
} else {
558+
// Extract the signed transaction
559+
CHECK_NONFATAL(FinalizeAndExtractPSBT(psbtx, mtx));
560+
const CTransactionRef tx = MakeTransactionRef(mtx);
561+
m_current_transaction->setWtx(tx);
562+
}
543563
}
544564

545565
// Broadcast the transaction, unless an external signer was used and it

src/qt/walletmodel.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ bool WalletModel::validateAddress(const QString& address) const
147147
return IsValidDestinationString(address.toStdString());
148148
}
149149

150-
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
150+
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl, bool sign)
151151
{
152152
CAmount total = 0;
153153
bool fSubtractFeeFromAmount = false;
@@ -203,7 +203,9 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
203203
int nChangePosRet = -1;
204204

205205
auto& newTx = transaction.getWtx();
206-
const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), nChangePosRet, nFeeRequired);
206+
// Only sign if explicitly requested via the sign parameter.
207+
const bool should_sign = sign && !wallet().privateKeysDisabled();
208+
const auto& res = m_wallet->createTransaction(vecSend, coinControl, should_sign, nChangePosRet, nFeeRequired);
207209
newTx = res ? *res : nullptr;
208210
transaction.setTransactionFee(nFeeRequired);
209211
if (fSubtractFeeFromAmount && newTx)

src/qt/walletmodel.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class WalletModel : public QObject
9696
};
9797

9898
// prepare transaction for getting txfee before sending coins
99-
SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const wallet::CCoinControl& coinControl);
99+
SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const wallet::CCoinControl& coinControl, bool sign = false);
100100

101101
// Send coins to a list of recipients
102102
void sendCoins(WalletModelTransaction& transaction);

0 commit comments

Comments
 (0)