diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index df1ced48a7142..c585ec7bd1d79 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -176,7 +176,7 @@ class Wallet CMutableTransaction& mtx) = 0; //! Sign bump transaction. - virtual bool signBumpTransaction(CMutableTransaction& mtx) = 0; + virtual bool signBumpTransaction(CMutableTransaction& mtx, const uint32_t psbt_version) = 0; //! Commit bump transaction. virtual bool commitBumpTransaction(const uint256& txid, diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 1010159209a5e..5d4ed99df2583 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -556,7 +556,7 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) assert(!m_wallet->privateKeysDisabled() || wallet().hasExternalSigner()); // sign bumped transaction - if (!m_wallet->signBumpTransaction(mtx)) { + if (!m_wallet->signBumpTransaction(mtx, /*psbt_version=*/0)) { QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Can't sign transaction.")); return false; } diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index b82d6ef4b327d..afca9ed5d39e2 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -275,12 +275,14 @@ static const CRPCConvertParam vRPCConvertParams[] = { "bumpfee", 1, "replaceable"}, { "bumpfee", 1, "outputs"}, { "bumpfee", 1, "original_change_index"}, + { "bumpfee", 1, "psbt_version"}, { "psbtbumpfee", 1, "options" }, { "psbtbumpfee", 1, "conf_target"}, { "psbtbumpfee", 1, "fee_rate"}, { "psbtbumpfee", 1, "replaceable"}, { "psbtbumpfee", 1, "outputs"}, { "psbtbumpfee", 1, "original_change_index"}, + { "psbtbumpfee", 1, "psbt_version"}, { "logging", 0, "include" }, { "logging", 1, "exclude" }, { "disconnectnode", 1, "nodeid" }, diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp index 3184d0f3b0d8a..845c2623be9e4 100644 --- a/src/wallet/feebumper.cpp +++ b/src/wallet/feebumper.cpp @@ -333,12 +333,12 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo return Result::OK; } -bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx) { +bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx, const uint32_t psbt_version) { LOCK(wallet.cs_wallet); if (wallet.IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) { // Make a blank psbt - PartiallySignedTransaction psbtx(mtx); + PartiallySignedTransaction psbtx(mtx, psbt_version); // First fill transaction with our data without signing, // so external signers are not asked to sign more than once. diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h index d3d43861efcb6..07b20da6c8348 100644 --- a/src/wallet/feebumper.h +++ b/src/wallet/feebumper.h @@ -60,7 +60,7 @@ Result CreateRateBumpTransaction(CWallet& wallet, //! Sign the new transaction, //! @return false if the tx couldn't be found or if it was //! impossible to create the signature(s) -bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx); +bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx, const uint32_t psbt_version); //! Commit the bumpfee transaction. //! @return success in case of CWallet::CommitTransaction was successful, diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 5f29f3e59704e..94c69a3f99067 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -319,9 +319,9 @@ class WalletImpl : public Wallet std::vector outputs; // just an empty list of new recipients for now return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx, /* require_mine= */ true, outputs) == feebumper::Result::OK; } - bool signBumpTransaction(CMutableTransaction& mtx) override + bool signBumpTransaction(CMutableTransaction& mtx, const uint32_t psbt_version) override { - return feebumper::SignTransaction(*m_wallet.get(), mtx); + return feebumper::SignTransaction(*m_wallet.get(), mtx, psbt_version); } bool commitBumpTransaction(const uint256& txid, CMutableTransaction&& mtx, diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index fb4a93d9606a5..1793cdf197e84 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -1032,6 +1032,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name) "The remainder after paying the recipients and fees will be sent to the output script of the " "original change output. The change output’s amount can increase if bumping the transaction " "adds new inputs, otherwise it will decrease. Cannot be used in combination with the 'outputs' option."}, + {"psbt_version", RPCArg::Type::NUM, RPCArg::Default(2), "The PSBT version number to use."}, }, RPCArgOptions{.oneline_description="options"}}, }, @@ -1071,6 +1072,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name) std::vector outputs; std::optional original_change_index; + uint32_t psbt_version = 2; if (!request.params[1].isNull()) { UniValue options = request.params[1]; @@ -1083,6 +1085,8 @@ static RPCHelpMan bumpfee_helper(std::string method_name) {"estimate_mode", UniValueType(UniValue::VSTR)}, {"outputs", UniValueType()}, // will be checked by AddOutputs() {"original_change_index", UniValueType(UniValue::VNUM)}, + {"psbt_version", UniValueType(UniValue::VNUM)}, + }, true, true); @@ -1110,6 +1114,13 @@ static RPCHelpMan bumpfee_helper(std::string method_name) if (options.exists("original_change_index")) { original_change_index = options["original_change_index"].getInt(); } + + if (!options["psbt_version"].isNull()) { + psbt_version = options["psbt_version"].getInt(); + } + if (psbt_version != 2 && psbt_version != 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "The PSBT version can only be 2 or 0"); + } } // Make sure the results are valid at least up to the most recent block @@ -1153,7 +1164,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name) // For bumpfee, return the new transaction id. // For psbtbumpfee, return the base64-encoded unsigned PSBT of the new transaction. if (!want_psbt) { - if (!feebumper::SignTransaction(*pwallet, mtx)) { + if (!feebumper::SignTransaction(*pwallet, mtx, psbt_version)) { if (pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) { throw JSONRPCError(RPC_WALLET_ERROR, "Transaction incomplete. Try psbtbumpfee instead."); } @@ -1167,7 +1178,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name) result.pushKV("txid", txid.GetHex()); } else { - PartiallySignedTransaction psbtx(mtx, /*version=*/2); + PartiallySignedTransaction psbtx(mtx, psbt_version); bool complete = false; const auto err{pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/false, /*bip32derivs=*/true)}; CHECK_NONFATAL(!err);