diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -90,8 +90,10 @@ virtual std::set getLabelAddresses(const std::string &label) = 0; - //! Get key from pool. - virtual bool getKeyFromPool(bool internal, CPubKey &pub_key) = 0; + // Get a new address. + virtual bool getNewDestination(const OutputType type, + const std::string label, + CTxDestination &dest) = 0; //! Get public key. virtual bool getPubKey(const CKeyID &address, CPubKey &pub_key) = 0; diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -148,8 +148,11 @@ getLabelAddresses(const std::string &label) override { return m_wallet->GetLabelAddresses(label); }; - bool getKeyFromPool(bool internal, CPubKey &pub_key) override { - return m_wallet->GetKeyFromPool(pub_key, internal); + bool getNewDestination(const OutputType type, const std::string label, + CTxDestination &dest) override { + LOCK(m_wallet->cs_wallet); + std::string error; + return m_wallet->GetNewDestination(type, label, dest, error); } const CChainParams &getChainParams() override { return m_wallet->chainParams; diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -340,34 +340,31 @@ editStatus = DUPLICATE_ADDRESS; return QString(); } + // Add entry + walletModel->wallet().setAddressBook( + DecodeDestination(strAddress, walletModel->getChainParams()), + strLabel, "send"); } else if (type == Receive) { // Generate a new address to associate with given label - CPubKey newKey; - if (!walletModel->wallet().getKeyFromPool(false /* internal */, - newKey)) { + CTxDestination dest; + if (!walletModel->wallet().getNewDestination(address_type, strLabel, + dest)) { WalletModel::UnlockContext ctx(walletModel->requestUnlock()); if (!ctx.isValid()) { // Unlock wallet failed or was cancelled editStatus = WALLET_UNLOCK_FAILURE; return QString(); } - if (!walletModel->wallet().getKeyFromPool(false /* internal */, - newKey)) { + if (!walletModel->wallet().getNewDestination(address_type, strLabel, + dest)) { editStatus = KEY_GENERATION_FAILURE; return QString(); } } - walletModel->wallet().learnRelatedScripts(newKey, address_type); - strAddress = EncodeCashAddr(GetDestinationForKey(newKey, address_type), - walletModel->getChainParams()); + strAddress = EncodeCashAddr(dest, walletModel->getChainParams()); } else { return QString(); } - - // Add entry - walletModel->wallet().setAddressBook( - DecodeDestination(strAddress, walletModel->getChainParams()), strLabel, - (type == Send ? "send" : "receive")); return QString::fromStdString(strAddress); } diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -732,21 +732,18 @@ payment.add_transactions(transaction.data(), transaction.size()); // Create a new refund address, or re-use: - CPubKey newKey; - if (walletModel->wallet().getKeyFromPool(false /* internal */, newKey)) { + CTxDestination dest; + const OutputType change_type = + walletModel->wallet().getDefaultChangeType() != OutputType::CHANGE_AUTO + ? walletModel->wallet().getDefaultChangeType() + : walletModel->wallet().getDefaultAddressType(); + if (walletModel->wallet().getNewDestination(change_type, "", dest)) { // BIP70 requests encode the scriptPubKey directly, so we are not // restricted to address types supported by the receiver. As a result, // we choose the address format we also use for change. Despite an // actual payment and not change, this is a close match: it's the output // type we use subject to privacy issues, but not restricted by what // other software supports. - const OutputType change_type = - walletModel->wallet().getDefaultChangeType() != - OutputType::CHANGE_AUTO - ? walletModel->wallet().getDefaultChangeType() - : walletModel->wallet().getDefaultAddressType(); - walletModel->wallet().learnRelatedScripts(newKey, change_type); - CTxDestination dest = GetDestinationForKey(newKey, change_type); std::string label = tr("Refund from %1") .arg(recipient.authenticatedMerchant) .toStdString(); diff --git a/src/test/util.cpp b/src/test/util.cpp --- a/src/test/util.cpp +++ b/src/test/util.cpp @@ -22,17 +22,12 @@ #ifdef ENABLE_WALLET std::string getnewaddress(const Config &config, CWallet &w) { constexpr auto output_type = OutputType::LEGACY; - - CPubKey new_key; - if (!w.GetKeyFromPool(new_key)) { + CTxDestination dest; + std::string error; + if (!w.GetNewDestination(output_type, "", dest, error)) { assert(false); } - w.LearnRelatedScripts(new_key, output_type); - const auto dest = GetDestinationForKey(new_key, output_type); - - w.SetAddressBook(dest, /* label */ "", "receive"); - return EncodeDestination(dest, config); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -222,21 +222,11 @@ } } - if (!pwallet->IsLocked()) { - pwallet->TopUpKeyPool(); - } - - // Generate a new key that is added to wallet - CPubKey newKey; - if (!pwallet->GetKeyFromPool(newKey)) { - throw JSONRPCError( - RPC_WALLET_KEYPOOL_RAN_OUT, - "Error: Keypool ran out, please call keypoolrefill first"); + CTxDestination dest; + std::string error; + if (!pwallet->GetNewDestination(output_type, label, dest, error)) { + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error); } - pwallet->LearnRelatedScripts(newKey, output_type); - CTxDestination dest = GetDestinationForKey(newKey, output_type); - - pwallet->SetAddressBook(dest, label, "receive"); return EncodeDestination(dest, config); } diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -504,8 +504,10 @@ wallet->SetMinVersion(FEATURE_LATEST); wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS); BOOST_CHECK(!wallet->TopUpKeyPool(1000)); - CPubKey pubkey; - BOOST_CHECK(!wallet->GetKeyFromPool(pubkey, false)); + CTxDestination dest; + std::string error; + BOOST_CHECK( + !wallet->GetNewDestination(OutputType::LEGACY, "", dest, error)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -946,6 +946,9 @@ */ BlockHash m_last_block_processed GUARDED_BY(cs_wallet); + //! Fetches a key from the keypool + bool GetKeyFromPool(CPubKey &key, bool internal = false); + public: const CChainParams &chainParams; /* @@ -1373,7 +1376,6 @@ bool fRequestedInternal); void KeepKey(int64_t nIndex); void ReturnKey(int64_t nIndex, bool fInternal, const CPubKey &pubkey); - bool GetKeyFromPool(CPubKey &key, bool internal = false); int64_t GetOldestKeyPoolTime(); /** * Marks all keys in the keypool up to and including reserve_key as used. @@ -1391,6 +1393,9 @@ std::set GetLabelAddresses(const std::string &label) const; + bool GetNewDestination(const OutputType type, const std::string label, + CTxDestination &dest, std::string &error); + isminetype IsMine(const CTxIn &txin) const; /** * Returns amount of debit if the input matches the filter, otherwise diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4108,6 +4108,27 @@ return true; } +bool CWallet::GetNewDestination(const OutputType type, const std::string label, + CTxDestination &dest, std::string &error) { + LOCK(cs_wallet); + error.clear(); + if (!IsLocked()) { + TopUpKeyPool(); + } + + // Generate a new key that is added to wallet + CPubKey new_key; + if (!GetKeyFromPool(new_key)) { + error = "Error: Keypool ran out, please call keypoolrefill first"; + return false; + } + LearnRelatedScripts(new_key, type); + dest = GetDestinationForKey(new_key, type); + + SetAddressBook(dest, label, "receive"); + return true; +} + static int64_t GetOldestKeyTimeInPool(const std::set &setKeyPool, WalletBatch &batch) { if (setKeyPool.empty()) {