diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -191,7 +191,7 @@ virtual TransactionError fillPSBT(SigHashType sighash_type, bool sign, bool bip32derivs, PartiallySignedTransaction &psbtx, - bool &complete) = 0; + bool &complete) const = 0; //! Get balances. virtual WalletBalances getBalances() = 0; diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -313,9 +312,9 @@ TransactionError fillPSBT(SigHashType sighash_type, bool sign, bool bip32derivs, PartiallySignedTransaction &psbtx, - bool &complete) override { - return FillPSBT(m_wallet.get(), psbtx, complete, sighash_type, sign, - bip32derivs); + bool &complete) const override { + return m_wallet->FillPSBT(psbtx, complete, sighash_type, sign, + bip32derivs); } WalletBalances getBalances() override { const auto bal = m_wallet->GetBalance(); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -18,7 +18,6 @@ db.cpp fees.cpp load.cpp - psbtwallet.cpp rpcdump.cpp rpcwallet.cpp scriptpubkeyman.cpp diff --git a/src/wallet/psbtwallet.h b/src/wallet/psbtwallet.h deleted file mode 100644 --- a/src/wallet/psbtwallet.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_WALLET_PSBTWALLET_H -#define BITCOIN_WALLET_PSBTWALLET_H - -#include -#include - -/** - * Fills out a PSBT with information from the wallet. Fills in UTXOs if we have - * them. Tries to sign if sign=true. Sets `complete` if the PSBT is now complete - * (i.e. has all required signatures or signature-parts, and is ready to - * finalize.) Sets `error` and returns false if something goes wrong. - * - * @param[in] pwallet pointer to a wallet - * @param[in] &psbtx reference to PartiallySignedTransaction to fill in - * @param[out] &complete indicates whether the PSBT is now complete - * @param[in] sighash_type the sighash type to use when signing (if PSBT does - * not specify) - * @param[in] sign whether to sign or not - * @param[in] bip32derivs whether to fill in bip32 derivation information if - * available - * @return error - */ -NODISCARD TransactionError -FillPSBT(const CWallet *pwallet, PartiallySignedTransaction &psbtx, - bool &complete, SigHashType sighash_type = SigHashType().withForkId(), - bool sign = true, bool bip32derivs = true); - -#endif // BITCOIN_WALLET_PSBTWALLET_H diff --git a/src/wallet/psbtwallet.cpp b/src/wallet/psbtwallet.cpp deleted file mode 100644 --- a/src/wallet/psbtwallet.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include - -TransactionError FillPSBT(const CWallet *pwallet, - PartiallySignedTransaction &psbtx, bool &complete, - SigHashType sighash_type, bool sign, - bool bip32derivs) { - LOCK(pwallet->cs_wallet); - // Get all of the previous transactions - complete = true; - for (size_t i = 0; i < psbtx.tx->vin.size(); ++i) { - const CTxIn &txin = psbtx.tx->vin[i]; - PSBTInput &input = psbtx.inputs.at(i); - - if (PSBTInputSigned(input)) { - continue; - } - - // Verify input looks sane. - if (!input.IsSane()) { - return TransactionError::INVALID_PSBT; - } - - // If we have no utxo, grab it from the wallet. - if (input.utxo.IsNull()) { - const TxId &txid = txin.prevout.GetTxId(); - const auto it = pwallet->mapWallet.find(txid); - if (it != pwallet->mapWallet.end()) { - const CWalletTx &wtx = it->second; - CTxOut utxo = wtx.tx->vout[txin.prevout.GetN()]; - // Update UTXOs from the wallet. - input.utxo = utxo; - } - } - - // Get the Sighash type - if (sign && input.sighash_type.getRawSigHashType() > 0 && - input.sighash_type != sighash_type) { - return TransactionError::SIGHASH_MISMATCH; - } - - // Get the scriptPubKey to know which SigningProvider to use - CScript script; - if (!input.utxo.IsNull()) { - script = input.utxo.scriptPubKey; - } else { - // There's no UTXO so we can just skip this now - complete = false; - continue; - } - SignatureData sigdata; - input.FillSignatureData(sigdata); - std::unique_ptr provider = - pwallet->GetSigningProvider(script, sigdata); - if (!provider) { - complete = false; - continue; - } - - complete &= SignPSBTInput( - HidingSigningProvider(provider.get(), !sign, !bip32derivs), psbtx, - i, sighash_type); - } - - // Fill in the bip32 keypaths and redeemscripts for the outputs so that - // hardware wallets can identify change - for (size_t i = 0; i < psbtx.tx->vout.size(); ++i) { - const CTxOut &out = psbtx.tx->vout.at(i); - std::unique_ptr provider = - pwallet->GetSigningProvider(out.scriptPubKey); - if (provider) { - UpdatePSBTOutput( - HidingSigningProvider(provider.get(), true, !bip32derivs), - psbtx, i); - } - } - - return TransactionError::OK; -} diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -4575,7 +4574,7 @@ request.params[3].isNull() ? true : request.params[3].get_bool(); bool complete = true; const TransactionError err = - FillPSBT(pwallet, psbtx, complete, nHashType, sign, bip32derivs); + pwallet->FillPSBT(psbtx, complete, nHashType, sign, bip32derivs); if (err != TransactionError::OK) { throw JSONRPCTransactionError(err); } @@ -4751,9 +4750,8 @@ bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool(); bool complete = true; - const TransactionError err = - FillPSBT(pwallet, psbtx, complete, SigHashType().withForkId(), false, - bip32derivs); + const TransactionError err = pwallet->FillPSBT( + psbtx, complete, SigHashType().withForkId(), false, bip32derivs); if (err != TransactionError::OK) { throw JSONRPCTransactionError(err); } diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp --- a/src/wallet/test/psbt_wallet_tests.cpp +++ b/src/wallet/test/psbt_wallet_tests.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -94,7 +93,7 @@ // Fill transaction with our data bool complete = true; BOOST_REQUIRE_EQUAL( - FillPSBT(&m_wallet, psbtx, complete, SigHashType(), false, true), + m_wallet.FillPSBT(psbtx, complete, SigHashType(), false, true), TransactionError::OK); // Get the final tx diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1106,6 +1107,26 @@ SigHashType sighash, std::map &input_errors) const; + /** + * Fills out a PSBT with information from the wallet. Fills in UTXOs if we + * have them. Tries to sign if sign=true. Sets `complete` if the PSBT is now + * complete (i.e. has all required signatures or signature-parts, and is + * ready to finalize.) Sets `error` and returns false if something goes + * wrong. + * + * @param[in] psbtx PartiallySignedTransaction to fill in + * @param[out] complete indicates whether the PSBT is now complete + * @param[in] sighash_type the sighash type to use when signing (if PSBT + * does not specify) + * @param[in] sign whether to sign or not + * @param[in] bip32derivs whether to fill in bip32 derivation information + * if available return error + */ + TransactionError + FillPSBT(PartiallySignedTransaction &psbtx, bool &complete, + SigHashType sighash_type = SigHashType().withForkId(), + bool sign = true, bool bip32derivs = true) const; + /** * Create a new transaction paying the recipients with a set of coins * selected by SelectCoins(); Also create the change output, when needed diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2791,6 +2791,82 @@ return false; } +TransactionError CWallet::FillPSBT(PartiallySignedTransaction &psbtx, + bool &complete, SigHashType sighash_type, + bool sign, bool bip32derivs) const { + LOCK(cs_wallet); + // Get all of the previous transactions + complete = true; + for (size_t i = 0; i < psbtx.tx->vin.size(); ++i) { + const CTxIn &txin = psbtx.tx->vin[i]; + PSBTInput &input = psbtx.inputs.at(i); + + if (PSBTInputSigned(input)) { + continue; + } + + // Verify input looks sane. + if (!input.IsSane()) { + return TransactionError::INVALID_PSBT; + } + + // If we have no utxo, grab it from the wallet. + if (input.utxo.IsNull()) { + const TxId &txid = txin.prevout.GetTxId(); + const auto it = mapWallet.find(txid); + if (it != mapWallet.end()) { + const CWalletTx &wtx = it->second; + CTxOut utxo = wtx.tx->vout[txin.prevout.GetN()]; + // Update UTXOs from the wallet. + input.utxo = utxo; + } + } + + // Get the Sighash type + if (sign && input.sighash_type.getRawSigHashType() > 0 && + input.sighash_type != sighash_type) { + return TransactionError::SIGHASH_MISMATCH; + } + + // Get the scriptPubKey to know which SigningProvider to use + CScript script; + if (!input.utxo.IsNull()) { + script = input.utxo.scriptPubKey; + } else { + // There's no UTXO so we can just skip this now + complete = false; + continue; + } + SignatureData sigdata; + input.FillSignatureData(sigdata); + std::unique_ptr provider = + GetSigningProvider(script, sigdata); + if (!provider) { + complete = false; + continue; + } + + complete &= SignPSBTInput( + HidingSigningProvider(provider.get(), !sign, !bip32derivs), psbtx, + i, sighash_type); + } + + // Fill in the bip32 keypaths and redeemscripts for the outputs so that + // hardware wallets can identify change + for (size_t i = 0; i < psbtx.tx->vout.size(); ++i) { + const CTxOut &out = psbtx.tx->vout.at(i); + std::unique_ptr provider = + GetSigningProvider(out.scriptPubKey); + if (provider) { + UpdatePSBTOutput( + HidingSigningProvider(provider.get(), true, !bip32derivs), + psbtx, i); + } + } + + return TransactionError::OK; +} + bool CWallet::FundTransaction(CMutableTransaction &tx, Amount &nFeeRet, int &nChangePosInOut, bilingual_str &error, bool lockUnspents,