Merge #13017: Add wallets management functions

3c058fd wallet: Add HasWallets (João Barbosa)
373aee2 wallet: Add AddWallet, RemoveWallet, GetWallet and GetWallets (João Barbosa)
6efd964 refactor: Drop CWalletRef typedef (João Barbosa)

Pull request description:

  This is a small step towards dynamic wallet load/unload. The wallets *registry* `vpwallets` is used in several places. With these new functions all `vpwallets` usage are removed and `vpwallets` is now a static variable (no external linkage).

  The typedef `CWalletRef` is also removed as it is narrowly used.

Tree-SHA512: 2ea19da2e17b521ad678bfe10f3257e497ccaf7ab9fd0b6647f9d829f1d6131cfa68db8e8492421711c6da399859432b963a568bdd4ca40a77dd95b597839423
This commit is contained in:
Wladimir J. van der Laan 2018-04-23 07:58:41 +02:00
commit 65d7083f15
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D
9 changed files with 80 additions and 41 deletions

View File

@ -236,7 +236,7 @@ class NodeImpl : public Node
{ {
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
std::vector<std::unique_ptr<Wallet>> wallets; std::vector<std::unique_ptr<Wallet>> wallets;
for (CWalletRef wallet : ::vpwallets) { for (CWallet* wallet : GetWallets()) {
wallets.emplace_back(MakeWallet(*wallet)); wallets.emplace_back(MakeWallet(*wallet));
} }
return wallets; return wallets;

View File

@ -180,9 +180,9 @@ void TestGUI()
TransactionView transactionView(platformStyle.get()); TransactionView transactionView(platformStyle.get());
auto node = interfaces::MakeNode(); auto node = interfaces::MakeNode();
OptionsModel optionsModel(*node); OptionsModel optionsModel(*node);
vpwallets.insert(vpwallets.begin(), &wallet); AddWallet(&wallet);
WalletModel walletModel(std::move(node->getWallets()[0]), *node, platformStyle.get(), &optionsModel); WalletModel walletModel(std::move(node->getWallets().back()), *node, platformStyle.get(), &optionsModel);
vpwallets.erase(vpwallets.begin()); RemoveWallet(&wallet);
sendCoinsDialog.setModel(&walletModel); sendCoinsDialog.setModel(&walletModel);
transactionView.setModel(&walletModel); transactionView.setModel(&walletModel);

View File

@ -69,7 +69,7 @@ UniValue validateaddress(const JSONRPCRequest& request)
{ {
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
if (!::vpwallets.empty() && IsDeprecatedRPCEnabled("validateaddress")) { if (HasWallets() && IsDeprecatedRPCEnabled("validateaddress")) {
ret.pushKVs(getaddressinfo(request)); ret.pushKVs(getaddressinfo(request));
} }
#endif #endif

View File

@ -315,7 +315,7 @@ bool WalletInit::Open() const
if (!pwallet) { if (!pwallet) {
return false; return false;
} }
vpwallets.push_back(pwallet); AddWallet(pwallet);
} }
return true; return true;
@ -323,29 +323,29 @@ bool WalletInit::Open() const
void WalletInit::Start(CScheduler& scheduler) const void WalletInit::Start(CScheduler& scheduler) const
{ {
for (CWalletRef pwallet : vpwallets) { for (CWallet* pwallet : GetWallets()) {
pwallet->postInitProcess(scheduler); pwallet->postInitProcess(scheduler);
} }
} }
void WalletInit::Flush() const void WalletInit::Flush() const
{ {
for (CWalletRef pwallet : vpwallets) { for (CWallet* pwallet : GetWallets()) {
pwallet->Flush(false); pwallet->Flush(false);
} }
} }
void WalletInit::Stop() const void WalletInit::Stop() const
{ {
for (CWalletRef pwallet : vpwallets) { for (CWallet* pwallet : GetWallets()) {
pwallet->Flush(true); pwallet->Flush(true);
} }
} }
void WalletInit::Close() const void WalletInit::Close() const
{ {
for (CWalletRef pwallet : vpwallets) { for (CWallet* pwallet : GetWallets()) {
RemoveWallet(pwallet);
delete pwallet; delete pwallet;
} }
vpwallets.clear();
} }

View File

@ -46,14 +46,13 @@ CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) { if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
// wallet endpoint was used // wallet endpoint was used
std::string requestedWallet = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size())); std::string requestedWallet = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
for (CWalletRef pwallet : ::vpwallets) { CWallet* pwallet = GetWallet(requestedWallet);
if (pwallet->GetName() == requestedWallet) { if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
return pwallet; return pwallet;
}
}
throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
} }
return ::vpwallets.size() == 1 || (request.fHelp && ::vpwallets.size() > 0) ? ::vpwallets[0] : nullptr;
std::vector<CWallet*> wallets = GetWallets();
return wallets.size() == 1 || (request.fHelp && wallets.size() > 0) ? wallets[0] : nullptr;
} }
std::string HelpRequiringPassphrase(CWallet * const pwallet) std::string HelpRequiringPassphrase(CWallet * const pwallet)
@ -67,7 +66,7 @@ bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)
{ {
if (pwallet) return true; if (pwallet) return true;
if (avoidException) return false; if (avoidException) return false;
if (::vpwallets.empty()) { if (!HasWallets()) {
// Note: It isn't currently possible to trigger this error because // Note: It isn't currently possible to trigger this error because
// wallet RPC methods aren't registered unless a wallet is loaded. But // wallet RPC methods aren't registered unless a wallet is loaded. But
// this error is being kept as a precaution, because it's possible in // this error is being kept as a precaution, because it's possible in
@ -2862,8 +2861,7 @@ UniValue listwallets(const JSONRPCRequest& request)
UniValue obj(UniValue::VARR); UniValue obj(UniValue::VARR);
for (CWalletRef pwallet : vpwallets) { for (CWallet* pwallet : GetWallets()) {
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue; return NullUniValue;
} }

View File

@ -74,7 +74,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
// after. // after.
{ {
CWallet wallet("dummy", WalletDatabase::CreateDummy()); CWallet wallet("dummy", WalletDatabase::CreateDummy());
vpwallets.insert(vpwallets.begin(), &wallet); AddWallet(&wallet);
UniValue keys; UniValue keys;
keys.setArray(); keys.setArray();
UniValue key; UniValue key;
@ -105,7 +105,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
"downloading and rescanning the relevant blocks (see -reindex and -rescan " "downloading and rescanning the relevant blocks (see -reindex and -rescan "
"options).\"}},{\"success\":true}]", "options).\"}},{\"success\":true}]",
0, oldTip->GetBlockTimeMax(), TIMESTAMP_WINDOW)); 0, oldTip->GetBlockTimeMax(), TIMESTAMP_WINDOW));
vpwallets.erase(vpwallets.begin()); RemoveWallet(&wallet);
} }
} }
@ -140,9 +140,9 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
JSONRPCRequest request; JSONRPCRequest request;
request.params.setArray(); request.params.setArray();
request.params.push_back((pathTemp / "wallet.backup").string()); request.params.push_back((pathTemp / "wallet.backup").string());
vpwallets.insert(vpwallets.begin(), &wallet); AddWallet(&wallet);
::dumpwallet(request); ::dumpwallet(request);
vpwallets.erase(vpwallets.begin()); RemoveWallet(&wallet);
} }
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME // Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
@ -153,9 +153,9 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
JSONRPCRequest request; JSONRPCRequest request;
request.params.setArray(); request.params.setArray();
request.params.push_back((pathTemp / "wallet.backup").string()); request.params.push_back((pathTemp / "wallet.backup").string());
vpwallets.insert(vpwallets.begin(), &wallet); AddWallet(&wallet);
::importwallet(request); ::importwallet(request);
vpwallets.erase(vpwallets.begin()); RemoveWallet(&wallet);
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3U); BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3U);

View File

@ -28,12 +28,50 @@
#include <utilmoneystr.h> #include <utilmoneystr.h>
#include <wallet/fees.h> #include <wallet/fees.h>
#include <algorithm>
#include <assert.h> #include <assert.h>
#include <future> #include <future>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
std::vector<CWalletRef> vpwallets; static std::vector<CWallet*> vpwallets;
bool AddWallet(CWallet* wallet)
{
assert(wallet);
std::vector<CWallet*>::const_iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
if (i != vpwallets.end()) return false;
vpwallets.push_back(wallet);
return true;
}
bool RemoveWallet(CWallet* wallet)
{
assert(wallet);
std::vector<CWallet*>::iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
if (i == vpwallets.end()) return false;
vpwallets.erase(i);
return true;
}
bool HasWallets()
{
return !vpwallets.empty();
}
std::vector<CWallet*> GetWallets()
{
return vpwallets;
}
CWallet* GetWallet(const std::string& name)
{
for (CWallet* wallet : vpwallets) {
if (wallet->GetName() == name) return wallet;
}
return nullptr;
}
/** Transaction fee set by the user */ /** Transaction fee set by the user */
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET; unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;

View File

@ -32,8 +32,11 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
typedef CWallet* CWalletRef; bool AddWallet(CWallet* wallet);
extern std::vector<CWalletRef> vpwallets; bool RemoveWallet(CWallet* wallet);
bool HasWallets();
std::vector<CWallet*> GetWallets();
CWallet* GetWallet(const std::string& name);
/** /**
* Settings * Settings
@ -268,7 +271,7 @@ public:
//Get the marginal bytes of spending the specified output //Get the marginal bytes of spending the specified output
int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet); int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet);
/** /**
* A transaction with a bunch of additional info that only the owner cares about. * A transaction with a bunch of additional info that only the owner cares about.
* It includes any unrecorded transactions needed to link it back to the block chain. * It includes any unrecorded transactions needed to link it back to the block chain.
*/ */
@ -653,7 +656,7 @@ struct CoinEligibilityFilter
}; };
class WalletRescanReserver; //forward declarations for ScanForWalletTransactions/RescanFromTime class WalletRescanReserver; //forward declarations for ScanForWalletTransactions/RescanFromTime
/** /**
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances, * A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions. * and provides the ability to create new transactions.
*/ */
@ -903,7 +906,7 @@ public:
void GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const; void GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const;
unsigned int ComputeTimeSmart(const CWalletTx& wtx) const; unsigned int ComputeTimeSmart(const CWalletTx& wtx) const;
/** /**
* Increment the next transaction order id * Increment the next transaction order id
* @return next transaction order id * @return next transaction order id
*/ */
@ -1032,7 +1035,7 @@ public:
} }
void GetScriptForMining(std::shared_ptr<CReserveScript> &script); void GetScriptForMining(std::shared_ptr<CReserveScript> &script);
unsigned int GetKeyPoolSize() unsigned int GetKeyPoolSize()
{ {
AssertLockHeld(cs_wallet); // set{Ex,In}ternalKeyPool AssertLockHeld(cs_wallet); // set{Ex,In}ternalKeyPool
@ -1057,7 +1060,7 @@ public:
//! Flush wallet (bitdb flush) //! Flush wallet (bitdb flush)
void Flush(bool shutdown=false); void Flush(bool shutdown=false);
/** /**
* Address book entry changed. * Address book entry changed.
* @note called with lock cs_wallet held. * @note called with lock cs_wallet held.
*/ */
@ -1066,7 +1069,7 @@ public:
const std::string &purpose, const std::string &purpose,
ChangeType status)> NotifyAddressBookChanged; ChangeType status)> NotifyAddressBookChanged;
/** /**
* Wallet transaction added, removed or updated. * Wallet transaction added, removed or updated.
* @note called with lock cs_wallet held. * @note called with lock cs_wallet held.
*/ */
@ -1113,7 +1116,7 @@ public:
/* Generates a new HD master key (will not be activated) */ /* Generates a new HD master key (will not be activated) */
CPubKey GenerateNewHDMasterKey(); CPubKey GenerateNewHDMasterKey();
/* Set the current HD master key (will reset the chain child index counters) /* Set the current HD master key (will reset the chain child index counters)
Sets the master key's version based on the current wallet version (so the Sets the master key's version based on the current wallet version (so the
caller must ensure the current wallet version is correct before calling caller must ensure the current wallet version is correct before calling
@ -1184,7 +1187,7 @@ public:
}; };
/** /**
* DEPRECATED Account information. * DEPRECATED Account information.
* Stored in wallet with key "acc"+string account name. * Stored in wallet with key "acc"+string account name.
*/ */
@ -1230,10 +1233,10 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key);
class WalletRescanReserver class WalletRescanReserver
{ {
private: private:
CWalletRef m_wallet; CWallet* m_wallet;
bool m_could_reserve; bool m_could_reserve;
public: public:
explicit WalletRescanReserver(CWalletRef w) : m_wallet(w), m_could_reserve(false) {} explicit WalletRescanReserver(CWallet* w) : m_wallet(w), m_could_reserve(false) {}
bool reserve() bool reserve()
{ {

View File

@ -756,7 +756,7 @@ void MaybeCompactWalletDB()
return; return;
} }
for (CWalletRef pwallet : vpwallets) { for (CWallet* pwallet : GetWallets()) {
WalletDatabase& dbh = pwallet->GetDBHandle(); WalletDatabase& dbh = pwallet->GetDBHandle();
unsigned int nUpdateCounter = dbh.nUpdateCounter; unsigned int nUpdateCounter = dbh.nUpdateCounter;