Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Added CWalletManager class to support loading of multiple wallets. #2407

Closed
wants to merge 2 commits into from

6 participants

@CodeShark

This pull request is a minimal step in the direction of merging #2124.

The idea is to merge things incrementally rather than all at once.

@BitcoinPullTester

Automatic sanity-testing: FAILED BUILD/TEST, see http://jenkins.bluematt.me/pull-tester/74c341604961ea9611a6c024c0bdecb573f2361a for binaries and test log.

This could happen for one of several reasons:
1. It chanages paths in makefile.linux-mingw or otherwise changes build scripts in a way that made them incompatible with the automated testing scripts
2. It adds/modifies tests which test network rules (thanks for doing that), which conflicts with a patch applied at test time
3. It does not build on either Linux i386 or Win32 (via MinGW cross compile)
4. The test suite fails on either Linux i386 or Win32
5. The block test-cases failed (lookup the first bNN identifier which failed in https://github.com/TheBlueMatt/test-scripts/blob/master/FullBlockTestGenerator.java)

If you believe this to be in error, please ping BlueMatt on freenode or TheBlueMatt here.

@BitcoinPullTester

Automatic sanity-testing: PASSED, see http://jenkins.bluematt.me/pull-tester/f48ace32517880418420f45e51b9a97caaa33ce8 for binaries and test log.
This is an automated test script which runs test cases on each commit every time is updated.
It, however, dies sometimes and fails to test properly, if you are waiting on a test, please check timestamps and if the test.log is moving at http://jenkins.bluematt.me/pull-tester/current/
and contact BlueMatt on freenode if something looks broken.

src/walletmanager.cpp
((66 lines not shown))
+ uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING);
+ return true;
+}
+
+// TODO: Remove dependencies for I/O on printf to debug.log, InitError, and InitWarning
+// TODO: Fix error handling.
+bool CWalletManager::LoadWallet(const string& strName, ostringstream& strErrors)
+{
+ // Check that the wallet name is valid
+ if (!CWalletManager::IsValidName(strName))
+ {
+ strErrors << _("Wallet name may only contain letters, numbers, and underscores.");
+ return false;
+ }
+
+ ENTER_CRITICAL_SECTION(cs_WalletManager);
@sipa Owner
sipa added a note

I think you can better abstract the part between the ENTER_CRITICAL_SECTION and the LEAVE_CRITICAL_SECTION into a separate function that has a LOCK(cs_WalletManager) at the start. This also means you don't need to explicitly leave the section prematurely in case of errors.

Yes, I realized this after I manually parsed the macros in sync.h. But this code is just copy/pasted from the original multiwallet pull request. I'll change it. Thanks for pointing it out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@CodeShark

This pull request has been refactored and reworked a little to improve error messaging.

@sipa
Owner

If you add a dependency on a boost library, please add it to the gitian descriptors too (though it seems overkill to me ofr this purpose).

@sipa sipa commented on the diff
src/walletmanager.cpp
((9 lines not shown))
+
+////////////////////////////////////////////////////////////
+//
+// TODO: Move GetFilesAtPath to utils.h/utils.cpp
+//
+namespace file_option_flags
+{
+ const unsigned int REGULAR_FILES = 0x01;
+ const unsigned int DIRECTORIES = 0x02;
+};
+
+vector<string> GetFilesAtPath(const boost::filesystem::path& _path, unsigned int flags)
+{
+ vector<string> vstrFiles;
+ if (!boost::filesystem::exists(_path))
+ throw runtime_error("Path does not exist.");
@sipa Owner
sipa added a note

A runtime error for this sounds very severe.

It's not that severe if we allow wallets to be stored at arbitrary locations on the file system as in multiwallet-qt. It would be quite severe if _path happened to be the datadir :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@sipa sipa commented on the diff
src/walletmanager.cpp
((31 lines not shown))
+ vstrFiles.push_back(_path.filename());
+#endif
+ return vstrFiles;
+ }
+ if (boost::filesystem::is_directory(_path))
+ {
+ vector<boost::filesystem::path> vPaths;
+ copy(boost::filesystem::directory_iterator(_path), boost::filesystem::directory_iterator(), back_inserter(vPaths));
+ BOOST_FOREACH(const boost::filesystem::path& pFile, vPaths)
+ {
+ if (((flags & file_option_flags::REGULAR_FILES) && boost::filesystem::is_regular_file(pFile)) ||
+ ((flags & file_option_flags::DIRECTORIES) && boost::filesystem::is_directory(pFile)))
+#if defined (BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION == 3
+ vstrFiles.push_back(pFile.filename().string());
+#else
+ vstrFiles.push_back(pFile.filename());
@sipa Owner
sipa added a note

Indentation problem.

Also, should probably be BOOST_FILESYSTEM_VERSION >= 3. I hope they don't decide to break this again in version 4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@sipa sipa commented on the diff
src/walletmanager.h
((6 lines not shown))
+
+#include "wallet.h"
+
+#include <stdexcept>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/regex.hpp>
+#include <boost/thread.hpp>
+
+/** A CWalletManager handles loading, unloading, allocation, deallocation, and synchronization of wallet objects.
+ */
+typedef std::map<std::string, boost::shared_ptr<CWallet> > wallet_map;
+class CWalletManager
+{
+protected:
+ static const boost::regex WALLET_NAME_REGEX;
@sipa Owner
sipa added a note

Do these need to be exposed?

No, they don't. I'll move them into cpp file when I get a chance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@BitcoinPullTester

Automatic sanity-testing: PASSED, see http://jenkins.bluematt.me/pull-tester/19f569cdd364592d91453fd246b11e44cef3940e for binaries and test log.
This test script verifies pulls every time they are updated. It, however, dies sometimes and fails to test properly. If you are waiting on a test, please check timestamps to verify that the test.log is moving at http://jenkins.bluematt.me/pull-tester/current/
Contact BlueMatt on freenode if something looks broken.

@kyledrake

Not sure if this is the appropriate place for this comment, but one feature request I wanted to recommend was to allow for the dynamic creation of wallets via RPC. That way you could add new ones without having to restart the daemon. I think people writing wallet interfaces might find that handy.

@kyledrake

Also, this is great work, happy that you're tackling this hard problem. Thanks!

@CodeShark

@Kyle r.e. dynamic creation of wallets via RPC: that was one of the main objectives of #2124
I think I've found a better approach to wallet management which I've been pursuing separate from these pull requests. I'll publish something on it soon.

@gavinandresen

Needs rebase and response to code review comments.

@laanwj
Owner

Like #2124, this pull request has fallen behind. Needs a lot of rebasing work. Please open a new pull or let me know in case anyone wants to pick this up.

@laanwj laanwj closed this
@laanwj laanwj referenced this pull request
Closed

Multiple wallet #4093

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 7, 2013
  1. @CodeShark
Commits on Jul 9, 2013
  1. @CodeShark

    Added gitian descriptor.

    CodeShark authored
This page is out of date. Refresh to see the latest.
View
3  bitcoin-qt.pro
@@ -245,6 +245,7 @@ SOURCES += src/qt/bitcoin.cpp \
src/addrman.cpp \
src/db.cpp \
src/walletdb.cpp \
+ src/walletmanager.cpp \
src/qt/clientmodel.cpp \
src/qt/guiutil.cpp \
src/qt/transactionrecord.cpp \
@@ -416,7 +417,7 @@ LIBS += $$join(BOOST_LIB_PATH,,-L,) $$join(BDB_LIB_PATH,,-L,) $$join(OPENSSL_LIB
LIBS += -lssl -lcrypto -ldb_cxx$$BDB_LIB_SUFFIX
# -lgdi32 has to happen after -lcrypto (see #681)
win32:LIBS += -lws2_32 -lshlwapi -lmswsock -lole32 -loleaut32 -luuid -lgdi32
-LIBS += -lboost_system$$BOOST_LIB_SUFFIX -lboost_filesystem$$BOOST_LIB_SUFFIX -lboost_program_options$$BOOST_LIB_SUFFIX -lboost_thread$$BOOST_THREAD_LIB_SUFFIX
+LIBS += -lboost_system$$BOOST_LIB_SUFFIX -lboost_filesystem$$BOOST_LIB_SUFFIX -lboost_program_options$$BOOST_LIB_SUFFIX -lboost_thread$$BOOST_THREAD_LIB_SUFFIX -lboost_regex$$BOOST_LIB_SUFFIX
win32:LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX
macx:LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX
View
1  contrib/gitian-descriptors/gitian.yml
@@ -13,6 +13,7 @@ packages:
- "libboost-filesystem-dev"
- "libboost-program-options-dev"
- "libboost-thread-dev"
+- "libboost-regex-dev"
- "libssl-dev"
- "git-core"
- "unzip"
View
99 src/init.cpp
@@ -9,6 +9,7 @@
#include "chainparams.h"
#include "txdb.h"
#include "walletdb.h"
+#include "walletmanager.h"
#include "bitcoinrpc.h"
#include "net.h"
#include "util.h"
@@ -29,6 +30,9 @@
using namespace std;
using namespace boost;
+CWalletManager g_walletManager;
+
+// TODO: eliminate pwalletMain and request wallet objects from g_walletManager throughout instead.
CWallet* pwalletMain;
CClientUIInterface uiInterface;
@@ -119,8 +123,6 @@ void Shutdown()
}
bitdb.Flush(true);
boost::filesystem::remove(GetPidFile());
- UnregisterAllWallets();
- delete pwalletMain;
}
//
@@ -832,93 +834,24 @@ bool AppInit2(boost::thread_group& threadGroup)
return false;
}
- // ********************************************************* Step 8: load wallet
+ // ********************************************************* Step 8: load default wallet
- uiInterface.InitMessage(_("Loading wallet..."));
+ uiInterface.InitMessage(_("Loading default wallet..."));
- nStart = GetTimeMillis();
- bool fFirstRun = true;
- pwalletMain = new CWallet("wallet.dat");
- DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
- if (nLoadWalletRet != DB_LOAD_OK)
+ try
{
- if (nLoadWalletRet == DB_CORRUPT)
- strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n";
- else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
- {
- string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data"
- " or address book entries might be missing or incorrect."));
- InitWarning(msg);
- }
- else if (nLoadWalletRet == DB_TOO_NEW)
- strErrors << _("Error loading wallet.dat: Wallet requires newer version of Bitcoin") << "\n";
- else if (nLoadWalletRet == DB_NEED_REWRITE)
- {
- strErrors << _("Wallet needed to be rewritten: restart Bitcoin to complete") << "\n";
- printf("%s", strErrors.str().c_str());
- return InitError(strErrors.str());
- }
- else
- strErrors << _("Error loading wallet.dat") << "\n";
- }
+ g_walletManager.LoadDefaultWallet();
- if (GetBoolArg("-upgradewallet", fFirstRun))
- {
- int nMaxVersion = GetArg("-upgradewallet", 0);
- if (nMaxVersion == 0) // the -upgradewallet without argument case
- {
- printf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
- nMaxVersion = CLIENT_VERSION;
- pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
- }
- else
- printf("Allowing wallet upgrade up to %i\n", nMaxVersion);
- if (nMaxVersion < pwalletMain->GetVersion())
- strErrors << _("Cannot downgrade wallet") << "\n";
- pwalletMain->SetMaxVersion(nMaxVersion);
+ // pwalletMain needs to be eliminated throughout the application.
+ // Wallet objects should always be requested from g_walletManager instead.
+ pwalletMain = g_walletManager.GetDefaultWallet().get();
}
-
- if (fFirstRun)
+ catch (const std::exception& e)
{
- // Create new keyUser and set as default key
- RandAddSeedPerfmon();
-
- CPubKey newDefaultKey;
- if (pwalletMain->GetKeyFromPool(newDefaultKey, false)) {
- pwalletMain->SetDefaultKey(newDefaultKey);
- if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), ""))
- strErrors << _("Cannot write default address") << "\n";
- }
-
- pwalletMain->SetBestChain(CBlockLocator(pindexBest));
- }
-
- printf("%s", strErrors.str().c_str());
- printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
-
- RegisterWallet(pwalletMain);
-
- CBlockIndex *pindexRescan = pindexBest;
- if (GetBoolArg("-rescan", false))
- pindexRescan = pindexGenesisBlock;
- else
- {
- CWalletDB walletdb("wallet.dat");
- CBlockLocator locator;
- if (walletdb.ReadBestBlock(locator))
- pindexRescan = locator.GetBlockIndex();
- else
- pindexRescan = pindexGenesisBlock;
- }
- if (pindexBest && pindexBest != pindexRescan)
- {
- uiInterface.InitMessage(_("Rescanning..."));
- printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
- nStart = GetTimeMillis();
- pwalletMain->ScanForWalletTransactions(pindexRescan, true);
- printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
- pwalletMain->SetBestChain(CBlockLocator(pindexBest));
- nWalletDBUpdated++;
+ ostringstream err;
+ err << _("Failed to load default wallet. Error: ") << e.what() << _(" Exiting...");
+ printf("%s\n", err.str().c_str());
+ return false;
}
// ********************************************************* Step 9: import blocks
View
2  src/makefile.linux-mingw
@@ -29,6 +29,7 @@ LIBS= \
-l boost_filesystem-mt-s \
-l boost_program_options-mt-s \
-l boost_thread_win32-mt-s \
+ -l boost_regex-mt-s \
-l boost_chrono-mt-s \
-l db_cxx \
-l ssl \
@@ -89,6 +90,7 @@ OBJS= \
obj/util.o \
obj/wallet.o \
obj/walletdb.o \
+ obj/walletmanager.o \
obj/noui.o \
obj/hash.o \
obj/bloom.o \
View
2  src/makefile.mingw
@@ -38,6 +38,7 @@ LIBS= \
-l boost_filesystem$(BOOST_SUFFIX) \
-l boost_program_options$(BOOST_SUFFIX) \
-l boost_thread$(BOOST_SUFFIX) \
+ -l boost_regex$(BOOST_SUFFIX) \
-l boost_chrono$(BOOST_SUFFIX) \
-l db_cxx \
-l ssl \
@@ -97,6 +98,7 @@ OBJS= \
obj/util.o \
obj/wallet.o \
obj/walletdb.o \
+ obj/walletmanager.o \
obj/hash.o \
obj/bloom.o \
obj/noui.o \
View
3  src/makefile.osx
@@ -36,6 +36,7 @@ LIBS += \
$(DEPSDIR)/lib/libboost_filesystem-mt.a \
$(DEPSDIR)/lib/libboost_program_options-mt.a \
$(DEPSDIR)/lib/libboost_thread-mt.a \
+ $(DEPSDIR)/lib/libboost_regex-mt.a \
$(DEPSDIR)/lib/libboost_chrono-mt.a \
$(DEPSDIR)/lib/libssl.a \
$(DEPSDIR)/lib/libcrypto.a \
@@ -49,6 +50,7 @@ LIBS += \
-lboost_filesystem-mt \
-lboost_program_options-mt \
-lboost_thread-mt \
+ -lboost_regex-mt \
-lboost_chrono-mt \
-lssl \
-lcrypto \
@@ -100,6 +102,7 @@ OBJS= \
obj/util.o \
obj/wallet.o \
obj/walletdb.o \
+ obj/walletmanager.o \
obj/hash.o \
obj/bloom.o \
obj/noui.o \
View
2  src/makefile.unix
@@ -38,6 +38,7 @@ LIBS += \
-l boost_filesystem$(BOOST_LIB_SUFFIX) \
-l boost_program_options$(BOOST_LIB_SUFFIX) \
-l boost_thread$(BOOST_LIB_SUFFIX) \
+ -l boost_regex$(BOOST_LIB_SUFFIX) \
-l db_cxx$(BDB_LIB_SUFFIX) \
-l ssl \
-l crypto
@@ -139,6 +140,7 @@ OBJS= \
obj/util.o \
obj/wallet.o \
obj/walletdb.o \
+ obj/walletmanager.o \
obj/hash.o \
obj/bloom.o \
obj/noui.o \
View
308 src/walletmanager.cpp
@@ -0,0 +1,308 @@
+// Copyright (c) 2012-2013 Eric Lombrozo, The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "walletmanager.h"
+#include "walletdb.h"
+
+using namespace std;
+
+////////////////////////////////////////////////////////////
+//
+// TODO: Move GetFilesAtPath to utils.h/utils.cpp
+//
+namespace file_option_flags
+{
+ const unsigned int REGULAR_FILES = 0x01;
+ const unsigned int DIRECTORIES = 0x02;
+};
+
+vector<string> GetFilesAtPath(const boost::filesystem::path& _path, unsigned int flags)
+{
+ vector<string> vstrFiles;
+ if (!boost::filesystem::exists(_path))
+ throw runtime_error("Path does not exist.");
@sipa Owner
sipa added a note

A runtime error for this sounds very severe.

It's not that severe if we allow wallets to be stored at arbitrary locations on the file system as in multiwallet-qt. It would be quite severe if _path happened to be the datadir :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ if ((flags & file_option_flags::REGULAR_FILES) && boost::filesystem::is_regular_file(_path))
+ {
+#if defined (BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION == 3
+ vstrFiles.push_back(_path.filename().string());
+#else
+ vstrFiles.push_back(_path.filename());
+#endif
+ return vstrFiles;
+ }
+ if (boost::filesystem::is_directory(_path))
+ {
+ vector<boost::filesystem::path> vPaths;
+ copy(boost::filesystem::directory_iterator(_path), boost::filesystem::directory_iterator(), back_inserter(vPaths));
+ BOOST_FOREACH(const boost::filesystem::path& pFile, vPaths)
+ {
+ if (((flags & file_option_flags::REGULAR_FILES) && boost::filesystem::is_regular_file(pFile)) ||
+ ((flags & file_option_flags::DIRECTORIES) && boost::filesystem::is_directory(pFile)))
+#if defined (BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION == 3
+ vstrFiles.push_back(pFile.filename().string());
+#else
+ vstrFiles.push_back(pFile.filename());
@sipa Owner
sipa added a note

Indentation problem.

Also, should probably be BOOST_FILESYSTEM_VERSION >= 3. I hope they don't decide to break this again in version 4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+#endif
+ }
+ return vstrFiles;
+ }
+ throw runtime_error("Path exists but is neither a regular file nor a directory.");
+}
+//
+////////////////////////////////////////////////////////////
+
+
+// TODO: Remove these functions
+bool static InitError(const std::string &str)
+{
+ uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR);
+ return false;
+}
+
+bool static InitWarning(const std::string &str)
+{
+ uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING);
+ return true;
+}
+
+// TODO: Remove dependencies for I/O on printf to debug.log, InitError, and InitWarning
+// TODO: Improve error messages and error handling.
+void CWalletManager::LoadWallet(const string& strName)
+{
+ ostringstream err;
+ string strFile = "wallet";
+ CWallet* pWallet = NULL;
+ int64 nStart = GetTimeMillis();
+
+ // Check that the wallet name is valid. A wallet name can only contain alphanumerics and underscores.
+ if (!CWalletManager::IsValidName(strName))
+ {
+ err << _("Invalid wallet name \"") << strName << _("\".");
+ throw runtime_error(err.str());
+ }
+
+ {
+ LOCK(cs_WalletManager);
+
+ // Check that wallet is not already loaded
+ if (wallets.count(strName) > 0)
+ {
+ err << _("A wallet with the name ") << strName << _(" is already loaded.");
+ throw runtime_error(err.str());
+ }
+
+ // Wallet file name for wallet foo will be wallet-foo.dat
+ // The empty string is reserved for the default wallet whose file is wallet.dat
+ if (strName.size() > 0)
+ {
+ strFile += "-" + strName;
+ }
+ strFile += ".dat";
+
+ printf("Loading wallet %s from %s...\n", strName.c_str(), strFile.c_str());
+ bool fFirstRun = true;
+ DBErrors nLoadWalletRet;
+
+ try
+ {
+ pWallet = new CWallet(strFile);
+ nLoadWalletRet = pWallet->LoadWallet(fFirstRun);
+ }
+ catch (const exception& e)
+ {
+ err << _("Critical error loading wallet ") << strName << _(" from ") << strFile << ": " << e.what();
+ throw runtime_error(err.str());
+ }
+ catch (...)
+ {
+ err << _("Critical error loading wallet ") << strName <<_(" from ") << strFile;
+ throw runtime_error(err.str());
+ }
+
+ if (nLoadWalletRet != DB_LOAD_OK)
+ {
+ if (nLoadWalletRet == DB_CORRUPT)
+ {
+ delete pWallet;
+ err << _("Error loading ") << strFile << _(": Wallet corrupted.");
+ throw runtime_error(err.str());
+ }
+ else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
+ {
+ err << _("Warning: error reading ") << strFile
+ << _(": All keys read correctly, but transaction data or address book entries might be missing or incorrect.");
+ printf("%s\n", err.str().c_str());
+ InitWarning(err.str());
+ err.str("");
+ }
+ else if (nLoadWalletRet == DB_TOO_NEW)
+ {
+ err << _("Error loading ") << strFile << _(": Wallet requires newer version of Bitcoin.");
+ throw runtime_error(err.str());
+ }
+ else if (nLoadWalletRet == DB_NEED_REWRITE)
+ {
+ err << _("Wallet needed to be rewritten: restart Bitcoin to complete.");
+ InitError(err.str());
+ throw runtime_error(err.str());
+ }
+ else
+ {
+ err << _("Error loading ") << strFile << _(": Unknown database error.");
+ throw runtime_error(err.str());
+ }
+ }
+
+ if (GetBoolArg("-upgradewallet", fFirstRun))
+ {
+ int nMaxVersion = GetArg("-upgradewallet", 0);
+ if (nMaxVersion == 0) // the -upgradewallet without argument case
+ {
+ printf("Performing wallet upgrade to %i for wallet %s.\n", FEATURE_LATEST, strName.c_str());
+ nMaxVersion = CLIENT_VERSION;
+ pWallet->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
+ }
+ else
+ {
+ printf("Allowing wallet upgrade up to %i for wallet %s.\n", nMaxVersion, strName.c_str());
+ }
+ if (nMaxVersion < pWallet->GetVersion())
+ {
+ err << _("Cannot downgrade wallet ") << strName << _(".");
+ printf("%s\n", err.str().c_str());
+ err.str("");
+ }
+ pWallet->SetMaxVersion(nMaxVersion);
+ }
+
+ if (fFirstRun)
+ {
+ // Create new keyUser and set as default key
+ RandAddSeedPerfmon();
+
+ CPubKey newDefaultKey;
+ if (!pWallet->GetKeyFromPool(newDefaultKey, false))
+ {
+ err << _("Cannot initialize keypool for wallet ") << strName << _(".");
+ printf("%s\n", err.str().c_str());
+ err.str("");
+ }
+ pWallet->SetDefaultKey(newDefaultKey);
+ if (!pWallet->SetAddressBookName(pWallet->vchDefaultKey.GetID(), ""))
+ {
+ err << _("Cannot write default address.");
+ printf("%s\n", err.str().c_str());
+ err.str("");
+ }
+ }
+
+ printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+
+ boost::shared_ptr<CWallet> spWallet(pWallet);
+ this->wallets[strName] = spWallet;
+ RegisterWallet(pWallet);
+ }
+
+ CBlockIndex *pindexRescan = pindexBest;
+ if (GetBoolArg("-rescan", false))
+ {
+ pindexRescan = pindexGenesisBlock;
+ }
+ else
+ {
+ CWalletDB walletdb(strFile);
+ CBlockLocator locator;
+ if (walletdb.ReadBestBlock(locator))
+ {
+ pindexRescan = locator.GetBlockIndex();
+ }
+ else
+ {
+ pindexRescan = pindexGenesisBlock;
+ }
+ }
+ if (pindexBest && pindexBest != pindexRescan)
+ {
+ uiInterface.InitMessage(_("Rescanning..."));
+ printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
+ nStart = GetTimeMillis();
+ pWallet->ScanForWalletTransactions(pindexRescan, true);
+ printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+ pWallet->SetBestChain(CBlockLocator(pindexBest));
+ nWalletDBUpdated++;
+ }
+}
+
+bool CWalletManager::UnloadWallet(const std::string& strName)
+{
+ {
+ LOCK(cs_WalletManager);
+ if (!wallets.count(strName)) return false;
+ boost::shared_ptr<CWallet> spWallet(wallets[strName]);
+ printf("Unloading wallet %s\n", strName.c_str());
+ {
+ LOCK(spWallet->cs_wallet);
+ UnregisterWallet(spWallet.get());
+ wallets.erase(strName);
+ }
+ }
+ return true;
+}
+
+void CWalletManager::UnloadAllWallets()
+{
+ {
+ LOCK(cs_WalletManager);
+ vector<string> vstrNames;
+ vector<boost::shared_ptr<CWallet> > vpWallets;
+ BOOST_FOREACH(const wallet_map::value_type& item, wallets)
+ {
+ vstrNames.push_back(item.first);
+ vpWallets.push_back(item.second);
+ }
+
+ for (unsigned int i = 0; i < vstrNames.size(); i++)
+ {
+ printf("Unloading wallet %s\n", vstrNames[i].c_str());
+ {
+ LOCK(vpWallets[i]->cs_wallet);
+ UnregisterWallet(vpWallets[i].get());
+ wallets.erase(vstrNames[i]);
+ }
+ }
+ }
+}
+
+boost::shared_ptr<CWallet> CWalletManager::GetWallet(const string& strName)
+{
+ {
+ LOCK(cs_WalletManager);
+ if (!wallets.count(strName)) {
+ throw runtime_error("CWalletManager::GetWallet() - Wallet not loaded.");
+ }
+ return wallets[strName];
+ }
+}
+
+const boost::regex CWalletManager::WALLET_NAME_REGEX("[a-zA-Z0-9_]*");
+const boost::regex CWalletManager::WALLET_FILE_REGEX("wallet-([a-zA-Z0-9_]+)\\.dat");
+
+bool CWalletManager::IsValidName(const string& strName)
+{
+ return boost::regex_match(strName, CWalletManager::WALLET_NAME_REGEX);
+}
+
+vector<string> CWalletManager::GetWalletsAtPath(const boost::filesystem::path& pathWallets)
+{
+ vector<string> vstrFiles = GetFilesAtPath(pathWallets, file_option_flags::REGULAR_FILES);
+ vector<string> vstrNames;
+ boost::cmatch match;
+ BOOST_FOREACH(const string& strFile, vstrFiles)
+ {
+ if (boost::regex_match(strFile.c_str(), match, CWalletManager::WALLET_FILE_REGEX))
+ vstrNames.push_back(string(match[1].first, match[1].second));
+ }
+ return vstrNames;
+}
View
49 src/walletmanager.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2012-2013 Eric Lombrozo, The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_WALLETMANAGER_H
+#define BITCOIN_WALLETMANAGER_H
+
+#include "wallet.h"
+
+#include <stdexcept>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/regex.hpp>
+#include <boost/thread.hpp>
+
+/** A CWalletManager handles loading, unloading, allocation, deallocation, and synchronization of wallet objects.
+ */
+typedef std::map<std::string, boost::shared_ptr<CWallet> > wallet_map;
+class CWalletManager
+{
+protected:
+ static const boost::regex WALLET_NAME_REGEX;
@sipa Owner
sipa added a note

Do these need to be exposed?

No, they don't. I'll move them into cpp file when I get a chance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ static const boost::regex WALLET_FILE_REGEX;
+
+ mutable CCriticalSection cs_WalletManager;
+ wallet_map wallets;
+
+public:
+ ~CWalletManager() { UnloadAllWallets(); }
+
+ // Default wallet has empty string for name.
+ void LoadWallet(const std::string& strName);
+ void LoadDefaultWallet() { LoadWallet(""); }
+
+ bool UnloadWallet(const std::string& strName);
+ void UnloadAllWallets();
+
+ // GetWallet and GetDefaultWallet throw exception if the wallet is not found.
+ boost::shared_ptr<CWallet> GetWallet(const std::string& strName);
+ boost::shared_ptr<CWallet> GetDefaultWallet() { return GetWallet(""); }
+
+ int GetWalletCount() { return wallets.size(); }
+ wallet_map GetWalletMap() { return wallets; }
+ bool HaveWallet(const std::string& strName) { return (wallets.count(strName) > 0); }
+
+ static bool IsValidName(const std::string& strName);
+ static std::vector<std::string> GetWalletsAtPath(const boost::filesystem::path& pathWallets);
+};
+
+#endif // BITCOIN_WALLETMANAGER_H
Something went wrong with that request. Please try again.