Skip to content

Commit 383d350

Browse files
committed
Merge bitcoin/bitcoin#22513: rpc: Allow walletprocesspsbt to sign without finalizing
a99ed89 psbt: sign without finalizing (Andrew Chow) Pull request description: It can be useful to sign an input with `walletprocesspsbt` but not finalize that input if it is complete. This PR adds another option to `walletprocesspsbt` to be able to do that. We will still finalize by default. This does not materially change the PSBT workflow since `finalizepsbt` needs to be called in order to extract the tx for broadcast. ACKs for top commit: meshcollider: utACK a99ed89 Sjors: utACK a99ed89 Tree-SHA512: c88e5d3222109c5f4e763b1b9d97ce4655f68f2985a4509caab2d4e7f5bac5047328fd69696e82a330f5c5a333e0312568ae293515689b77a4747ca2f17caca6
2 parents 913b714 + a99ed89 commit 383d350

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
@@ -4551,6 +4551,7 @@ static RPCHelpMan walletprocesspsbt()
45514551
" \"NONE|ANYONECANPAY\"\n"
45524552
" \"SINGLE|ANYONECANPAY\""},
45534553
{"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"},
4554+
{"finalize", RPCArg::Type::BOOL, RPCArg::Default{true}, "Also finalize inputs if possible"},
45544555
},
45554556
RPCResult{
45564557
RPCResult::Type::OBJ, "", "",
@@ -4572,7 +4573,7 @@ static RPCHelpMan walletprocesspsbt()
45724573
// the user could have gotten from another RPC command prior to now
45734574
wallet.BlockUntilSyncedToCurrentChain();
45744575

4575-
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR});
4576+
RPCTypeCheck(request.params, {UniValue::VSTR});
45764577

45774578
// Unserialize the transaction
45784579
PartiallySignedTransaction psbtx;
@@ -4587,11 +4588,12 @@ static RPCHelpMan walletprocesspsbt()
45874588
// Fill transaction with our data and also sign
45884589
bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();
45894590
bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool();
4591+
bool finalize = request.params[4].isNull() ? true : request.params[4].get_bool();
45904592
bool complete = true;
45914593

45924594
if (sign) EnsureWalletIsUnlocked(*pwallet);
45934595

4594-
const TransactionError err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs)};
4596+
const TransactionError err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs, nullptr, finalize)};
45954597
if (err != TransactionError::OK) {
45964598
throw JSONRPCTransactionError(err);
45974599
}

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)) {
@@ -2074,7 +2074,7 @@ SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message,
20742074
return SigningResult::OK;
20752075
}
20762076

2077-
TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed) const
2077+
TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const
20782078
{
20792079
if (n_signed) {
20802080
*n_signed = 0;
@@ -2124,7 +2124,7 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
21242124
}
21252125
}
21262126

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

21292129
bool signed_one = PSBTInputSigned(input);
21302130
if (n_signed && (signed_one || !sign)) {

src/wallet/scriptpubkeyman.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ class ScriptPubKeyMan
224224
/** Sign a message with the given script */
225225
virtual SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const { return SigningResult::SIGNING_FAILED; };
226226
/** Adds script and derivation path information to a PSBT, and optionally signs it. */
227-
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; }
227+
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; }
228228

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

@@ -388,7 +388,7 @@ class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProv
388388

389389
bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override;
390390
SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override;
391-
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;
391+
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;
392392

393393
uint256 GetID() const override;
394394

@@ -593,7 +593,7 @@ class DescriptorScriptPubKeyMan : public ScriptPubKeyMan
593593

594594
bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override;
595595
SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override;
596-
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;
596+
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;
597597

598598
uint256 GetID() const override;
599599

src/wallet/wallet.cpp

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

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

src/wallet/wallet.h

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

567570
/**
568571
* Submit the transaction to the node's mempool and then relay to peers.

0 commit comments

Comments
 (0)