Skip to content

Commit a99ed89

Browse files
committed
psbt: sign without finalizing
We don't always want to finalize after signing, so make it possible to do that.
1 parent 6a5381a commit a99ed89

File tree

11 files changed

+32
-20
lines changed

11 files changed

+32
-20
lines changed

src/psbt.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction&
247247
return txdata;
248248
}
249249

250-
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata)
250+
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata, bool finalize)
251251
{
252252
PSBTInput& input = psbt.inputs.at(index);
253253
const CMutableTransaction& tx = *psbt.tx;
@@ -295,6 +295,10 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
295295
}
296296
// Verify that a witness signature was produced in case one was required.
297297
if (require_witness_sig && !sigdata.witness) return false;
298+
299+
// If we are not finalizing, set sigdata.complete to false to not set the scriptWitness
300+
if (!finalize && sigdata.complete) sigdata.complete = false;
301+
298302
input.FromSignatureData(sigdata);
299303

300304
// If we have a witness signature, put a witness UTXO.
@@ -324,7 +328,7 @@ bool FinalizePSBT(PartiallySignedTransaction& psbtx)
324328
bool complete = true;
325329
const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
326330
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
327-
complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL);
331+
complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL, nullptr, true);
328332
}
329333

330334
return complete;

src/psbt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ bool PSBTInputSigned(const PSBTInput& input);
578578
* txdata should be the output of PrecomputePSBTData (which can be shared across
579579
* multiple SignPSBTInput calls). If it is nullptr, a dummy signature will be created.
580580
**/
581-
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr);
581+
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool finalize = true);
582582

583583
/** Counts the unsigned inputs of a PSBT. */
584584
size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt);

src/rpc/client.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
115115
{ "walletcreatefundedpsbt", 4, "bip32derivs" },
116116
{ "walletprocesspsbt", 1, "sign" },
117117
{ "walletprocesspsbt", 3, "bip32derivs" },
118+
{ "walletprocesspsbt", 4, "finalize" },
118119
{ "createpsbt", 0, "inputs" },
119120
{ "createpsbt", 1, "outputs" },
120121
{ "createpsbt", 2, "locktime" },

src/wallet/external_signer_scriptpubkeyman.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ bool ExternalSignerScriptPubKeyMan::DisplayAddress(const CScript scriptPubKey, c
6060
}
6161

6262
// If sign is true, transaction must previously have been filled
63-
TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed) const
63+
TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const
6464
{
6565
if (!sign) {
66-
return DescriptorScriptPubKeyMan::FillPSBT(psbt, txdata, sighash_type, false, bip32derivs, n_signed);
66+
return DescriptorScriptPubKeyMan::FillPSBT(psbt, txdata, sighash_type, false, bip32derivs, n_signed, finalize);
6767
}
6868

6969
// Already complete if every input is now signed
@@ -79,6 +79,6 @@ TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransact
7979
tfm::format(std::cerr, "Failed to sign: %s\n", strFailReason);
8080
return TransactionError::EXTERNAL_SIGNER_FAILED;
8181
}
82-
FinalizePSBT(psbt); // This won't work in a multisig setup
82+
if (finalize) FinalizePSBT(psbt); // This won't work in a multisig setup
8383
return TransactionError::OK;
8484
}

src/wallet/external_signer_scriptpubkeyman.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ class ExternalSignerScriptPubKeyMan : public DescriptorScriptPubKeyMan
2828

2929
bool DisplayAddress(const CScript scriptPubKey, const ExternalSigner &signer) const;
3030

31-
TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override;
31+
TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override;
3232
};
3333
#endif // BITCOIN_WALLET_EXTERNAL_SIGNER_SCRIPTPUBKEYMAN_H

src/wallet/rpcwallet.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4429,6 +4429,7 @@ static RPCHelpMan walletprocesspsbt()
44294429
" \"NONE|ANYONECANPAY\"\n"
44304430
" \"SINGLE|ANYONECANPAY\""},
44314431
{"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"},
4432+
{"finalize", RPCArg::Type::BOOL, RPCArg::Default{true}, "Also finalize inputs if possible"},
44324433
},
44334434
RPCResult{
44344435
RPCResult::Type::OBJ, "", "",
@@ -4450,7 +4451,7 @@ static RPCHelpMan walletprocesspsbt()
44504451
// the user could have gotten from another RPC command prior to now
44514452
wallet.BlockUntilSyncedToCurrentChain();
44524453

4453-
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR});
4454+
RPCTypeCheck(request.params, {UniValue::VSTR});
44544455

44554456
// Unserialize the transaction
44564457
PartiallySignedTransaction psbtx;
@@ -4465,11 +4466,12 @@ static RPCHelpMan walletprocesspsbt()
44654466
// Fill transaction with our data and also sign
44664467
bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();
44674468
bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool();
4469+
bool finalize = request.params[4].isNull() ? true : request.params[4].get_bool();
44684470
bool complete = true;
44694471

44704472
if (sign) EnsureWalletIsUnlocked(*pwallet);
44714473

4472-
const TransactionError err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs)};
4474+
const TransactionError err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs, nullptr, finalize)};
44734475
if (err != TransactionError::OK) {
44744476
throw JSONRPCTransactionError(err);
44754477
}

src/wallet/scriptpubkeyman.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ SigningResult LegacyScriptPubKeyMan::SignMessage(const std::string& message, con
610610
return SigningResult::SIGNING_FAILED;
611611
}
612612

613-
TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed) const
613+
TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const
614614
{
615615
if (n_signed) {
616616
*n_signed = 0;
@@ -639,7 +639,7 @@ TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psb
639639
}
640640
SignatureData sigdata;
641641
input.FillSignatureData(sigdata);
642-
SignPSBTInput(HidingSigningProvider(this, !sign, !bip32derivs), psbtx, i, &txdata, sighash_type);
642+
SignPSBTInput(HidingSigningProvider(this, !sign, !bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
643643

644644
bool signed_one = PSBTInputSigned(input);
645645
if (n_signed && (signed_one || !sign)) {
@@ -2078,7 +2078,7 @@ SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message,
20782078
return SigningResult::OK;
20792079
}
20802080

2081-
TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed) const
2081+
TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const
20822082
{
20832083
if (n_signed) {
20842084
*n_signed = 0;
@@ -2128,7 +2128,7 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
21282128
}
21292129
}
21302130

2131-
SignPSBTInput(HidingSigningProvider(keys.get(), !sign, !bip32derivs), psbtx, i, &txdata, sighash_type);
2131+
SignPSBTInput(HidingSigningProvider(keys.get(), !sign, !bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
21322132

21332133
bool signed_one = PSBTInputSigned(input);
21342134
if (n_signed && (signed_one || !sign)) {

src/wallet/scriptpubkeyman.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ class ScriptPubKeyMan
223223
/** Sign a message with the given script */
224224
virtual SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const { return SigningResult::SIGNING_FAILED; };
225225
/** Adds script and derivation path information to a PSBT, and optionally signs it. */
226-
virtual TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const { return TransactionError::INVALID_PSBT; }
226+
virtual TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const { return TransactionError::INVALID_PSBT; }
227227

228228
virtual uint256 GetID() const { return uint256(); }
229229

@@ -387,7 +387,7 @@ class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProv
387387

388388
bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override;
389389
SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override;
390-
TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override;
390+
TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override;
391391

392392
uint256 GetID() const override;
393393

@@ -592,7 +592,7 @@ class DescriptorScriptPubKeyMan : public ScriptPubKeyMan
592592

593593
bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override;
594594
SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override;
595-
TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override;
595+
TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override;
596596

597597
uint256 GetID() const override;
598598

src/wallet/wallet.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1850,7 +1850,7 @@ bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint,
18501850
return false;
18511851
}
18521852

1853-
TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, size_t * n_signed) const
1853+
TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, size_t * n_signed, bool finalize) const
18541854
{
18551855
if (n_signed) {
18561856
*n_signed = 0;
@@ -1882,7 +1882,7 @@ TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& comp
18821882
// Fill in information from ScriptPubKeyMans
18831883
for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {
18841884
int n_signed_this_spkm = 0;
1885-
TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm);
1885+
TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm, finalize);
18861886
if (res != TransactionError::OK) {
18871887
return res;
18881888
}

src/wallet/wallet.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,14 +553,17 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
553553
* @param[in] sighash_type the sighash type to use when signing (if PSBT does not specify)
554554
* @param[in] sign whether to sign or not
555555
* @param[in] bip32derivs whether to fill in bip32 derivation information if available
556+
* @param[out] n_signed the number of inputs signed by this wallet
557+
* @param[in] finalize whether to create the final scriptSig or scriptWitness if possible
556558
* return error
557559
*/
558560
TransactionError FillPSBT(PartiallySignedTransaction& psbtx,
559561
bool& complete,
560562
int sighash_type = 1 /* SIGHASH_ALL */,
561563
bool sign = true,
562564
bool bip32derivs = true,
563-
size_t* n_signed = nullptr) const;
565+
size_t* n_signed = nullptr,
566+
bool finalize = true) const;
564567

565568
/**
566569
* Submit the transaction to the node's mempool and then relay to peers.

0 commit comments

Comments
 (0)