Skip to content
This repository

Dynamically Loadable Multiple Wallet Support Complete!!! #2124

Closed
wants to merge 38 commits into from

12 participants

Eric Lombrozo P. Kaufmann R E Broadley Gregory Maxwell Mike Gogulski Pieter Wuille Gavin Andresen BitcoinPullTester MrLei Tranz5 bananas2 Wladimir J. van der Laan
Eric Lombrozo

bitcoind now supports loading more than one wallet at once.

A singleton object of type CWalletManager now exists. It handles dynamic loading/unloading and synchronization of wallets and allows different parts of the application to access wallets by name.

A new CWallet* parameter has been added to the RPC functions. Functions which do not use a wallet simply ignore it. In addition, a new field has been added to CRPCCommand that tells us whether or not the function can be called on a wallet.

Wallet-specific information has been removed from RPC method getinfo. Instead, getinfo just reports how many
wallets are currently loaded. Detailed wallet info is now available via the listwallets method.

Four new RPC methods have been added:

  • listwallets
    Returns an array containing wallet information.

  • usewallet <walletname> <method> [params]
    Allows you to apply existing RPC commands to different wallets.
    A default wallet named the empty string is always loaded and is used if calls are made without usewallet.
    Example: bitcoind usewallet foo listreceivedbyaddress 0 true
    (thanks, gmaxwell, for the idea)

  • loadwallet <walletname> [rescan=false] [upgradewallet=false] [maxversion=(latest)]
    Dynamically loads an existing wallet file wallet-<walletname>.dat.
    If no wallet file exists a new wallet is created. The default wallet file is always called wallet.dat.

  • unloadwallet <walletname>

To specify additional wallets at startup, use option -usewallet=foo -usewallet=bar etc...as detailed here: #2124 (comment) and CodeShark@9d201cf

TODO:

  • Clean up I/O in CWalletManager::LoadWallet - debug, error, and UI output functions.
  • Check synchronization code.
  • Test mining functionality. Allow RPC mining on arbitrary wallets.
  • Integrate with Qt.
Eric Lombrozo

It's a work in progress and can certainly be improved. I welcome all comments, suggestions, criticisms, and witty insults.

P. Kaufmann

Would it be better or possible to use references instead of pointers in your code?

Eric Lombrozo

Possible, sure. Better, why?

Eric Lombrozo

The sanity test failed because the test suite uses the old RPC function prototype. I was still able to build and run using

  • make -f makefile.unix bitcoind
R E Broadley

This may be an opportunity to move away from the wallets being called "wallet.dat", which makes it all the more easier for malware to steal the contents.

Eric Lombrozo

You can now specify additional wallets in the config file or via command line arguments:

usewallet=foo

or

bitcoind -usewallet=foo

A default wallet called "" in the RPC and using file "wallet.dat" is always loaded, as to not break compatibility with the master branch. Therefore, additional wallets should neither be called "default" nor "wallet".

The wallet will be stored in a file called wallet-foo.dat. If the wallet doesn't yet exist, it will be created the first time the wallet is loaded.

CodeShark added some commits
Eric Lombrozo CodeShark Added multiple wallet support
=============================

A new global structure called pWalletMap has been added. Upon initialization, multiple wallets can be loaded.

A new CWallet* parameter has been added to the RPC functions. Functions which do not use a wallet simply ignore it. In addition, a new field has been added to CRPCCommand that tells us whether or not the function uses a wallet.

Two new RPC methods have been added:
  1) listwallets - Returns an array containing wallet names.
  2) usewallet - Prefix existing wallet RPC calls with usewallet <walletname> to use a particular wallet. If no wallet is specified, the default wallet is used.
    example: bitcoind usewallet foo listreceivedbyaddress 0 true

TODO:
  1) Get wallet names from bitcoin.conf in init.cpp.
  2) Change help RPC so that the message does not depend on wallet state (i.e. walletpassphrase RPC call)
71c63e3
Eric Lombrozo CodeShark Added CWallet* parameter to RPC test suite and a CWalletMap instance …
…to test_bitcoin.cpp
4a6b0e2
Eric Lombrozo CodeShark Fixed RPC issues detected by test suite. 158ce39
Eric Lombrozo CodeShark Added loading of wallet names and files from -usewallet arguments
=================================================================

You can now specify additional wallets in the config file or via command line arguments:

	usewallet=foo

or

	bitcoind -usewallet=foo

A default wallet called "default" in the RPC and using file "wallet.dat" is always loaded, as to not break compatibility with the master branch. Therefore, additional wallets should neither be called "default" nor "wallet" nor anything else that might conflict with other filenames in the .bitcoin directory.

The wallet will be stored in a file called foo.dat. If the wallet doesn't yet exist, it will be created the first time bitcoind is run.

TODO: Ensure filename collisions cannot occur. Perhaps allow the wallet files to be arbitrarily named rather than tied to their identifier.
1b640c1
Eric Lombrozo CodeShark TxMemPool::accept() calls SyncWithWallets(), so all mempool transacti…
…ons are synched automatically without having to call SyncWithWallets() explicitly. This is important when sending between two wallets in a single bitcoind instance so that the receiving wallet is alerted of the transaction immediately.

Removed calls to SyncWithWallets() in ProcessMessage() since SyncWithWallets() is already called by tx.AcceptToMemoryPool().

SyncWithWallets() is still called explicitly from CBlock::ConnectBlock() since the transaction never goes through the mempool in this case.
1cdf18b
Eric Lombrozo CodeShark Modified getinfo RPC call to return an array of wallets 27fa196
Eric Lombrozo CodeShark Removed dependency on wallet encryption state for getting help on RPC…
… methods. Help always returns usage info now.
93e6b80
Eric Lombrozo CodeShark usewallet now checks whether method is valid. 0f815bf
Eric Lombrozo

The getinfo RPC method now returns an array of wallets each with wallet-specific information. This change is, unfortunately, not backwards compatible. However, it doesn't really seem to make sense to make this call wallet-specific. And returning an array of wallets seems to be a very useful feature.

Gregory Maxwell
Collaborator

An alternative would be to move that data out of getinfo and into a getwallet info. Part of the reason to do that is that the wallet outputs in getinfo can be rather slow already, and doing them for N wallets won't help matters. (Though lets see if anyone else has an opinion, I could be on drugs here)

Eric Lombrozo

I was thinking listwallets should maybe show all this information with a verbose option. Without the verbose option, it would just give a list of the wallet names.

Gregory Maxwell
Collaborator

Hm. From the perspective of the RPC as a CLI the use of verbose flags isn't especially discoverable— for something basic like 'get your balances' that is probably worth exposing at the top level. ::shrugs::

Eric Lombrozo

What about making the full info the default and having an option to shorten it? That way interactive users get relevant information while application developers seeking to improve performance have an option to do so if they don't need all that information. Of course we can just have two distinct RPC methods...but I'd rather avoid having too many RPC calls when the semantics are similar.

Eric Lombrozo

I do think that the wallet information should be completely removed from getinfo, though.

Anyhow, this is the kind of stuff that's really easy to implement and change up front but becomes a serious problem to change once people start using it to build applications. I'd also like to hear several more opinions on this before committing to anything specific.

Eric Lombrozo

Another issue I'm wondering about is programmatic access to the config file. We could just append the new wallets to the end of the file whenever they are created - but it would be nice to be able to have tags for sections. Presumably whenever a user creates a new wallet they want it to be loaded at next startup unless they explicitly remove it from the config file.

Mike Gogulski

Multiple wallet support came into my head as I was doing #2075 but I left it aside in favor of trying to move the code in the direction of further modularization improvements between the RPC interface and the wallet and the wallet database as a prerequisite. I put off coding there since I expected something like this to come along and because commentary on the pull request died away.

I can't review the code in detail now but this capability needs to happen. Passing CWallet * around is an improvement for sure, definitely better than another global. I'm finding it kinda cringeworth-brittle from an OO perspective, though. It would be lovely to see new RPC functions implemented in ways that drag suitable amounts of code that depends strongly on the wallet's internal representation out along with them the appropriate changes to the wallet object.

Have you tried merging my code? I'll have to look at that later. Multiple wallets are useful for any number of reasons. Certainly the Bitcoin-only accountants and would-be tax collectors of the future aren't going to be running n instances of bitcoind on their desktops.

Ultimate I think the wallet should be decoupled from the rest of the satoshi client. Pushing standarized interfaces down to wallet-object level is somewhere on the road to getting there. You seem to be addressing some modularization issues in other areas though, too.

Eric Lombrozo

As for the OO stuff, I would like to abstract things further and define a listener interface, a transaction store interface, and a key store interface. Technically speaking, a signing agent doesn't even need to store complete transactions. Private keys and unspent outpoints are all it needs. Furthermore, a listening agent could send alerts to other components without the need to store any transactions. For instance, it could just provide filtering.

Having said that, in the interest of seeing these pull requests merged with bitcoin/bitcoin master ASAP, I'm willing to do things incrementally and use whatever structures already exist for now. However, I'd be very interested in giving all this some deeper thought and coming up with a serious reorganization for some later version.

As for now, at the very least it is possible to encapsulate the existing CWallet class much better - and I applaud your efforts.

src/bitcoinrpc.cpp
((6 lines not shown))
1068 1072 try
1069 1073 {
1070 1074 // Execute
1071 1075 Value result;
1072 1076 {
1073   - if (pcmd->unlocked)
1074   - result = pcmd->actor(params, false);
  1077 + if (pcmd->unlocked) {
  1078 + result = pcmd->actor(pWallet, params, false);
  1079 + }
1075 1080 else {
1076 1081 LOCK2(cs_main, pwalletMain->cs_wallet);
1
Pieter Wuille Collaborator
sipa added a note

This will need to lock the appropriate wallet (if any), not pwalletMain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/init.cpp
@@ -25,6 +25,7 @@
25 25 using namespace std;
26 26 using namespace boost;
27 27
  28 +CWalletMap* pWalletMap;
2
Pieter Wuille Collaborator
sipa added a note

pWalletMap can be allocated statically, I believe.

A problem is that it is declared in both init.cpp and test_bitcoin.cpp - and these globals must be accessible from rpcwallet.cpp as well, which includes init.h for the externs. I would prefer the wallet RPC calls to be placed in an RPC class which takes a wallet map in its constructor - and then we could remove any dependencies on these externs entirely and restrict the variable scope to init.cpp or the unit test main. But yeah, it could be allocated statically.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/wallet.h
@@ -311,6 +311,21 @@ class CWallet : public CCryptoKeyStore
311 311 boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx, ChangeType status)> NotifyTransactionChanged;
312 312 };
313 313
  314 +/** A CWalletMap associates wallets with names and automatically deallocates them upon destruction.
  315 + */
  316 +typedef std::map<std::string, CWallet*> wallet_map;
  317 +class CWalletMap
  318 +{
  319 +public:
  320 + wallet_map wallets;
  321 +
  322 + ~CWalletMap()
2
Pieter Wuille Collaborator
sipa added a note

You may want to use an auto_ptr to make this cleanup happen automatically.

I was thinking to expand this class to also handle loading of wallets from config parameters.

Perhaps init.cpp could pass io context stuff to the loader method so that the loader method needn't call printf directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Pieter Wuille
Collaborator

In general: I'm very much in favor of having native support for multiple wallets. Wallet stuff hasn't been a priority for some time, but if necessary I'd like to help to get this working.

Regarding the idea of separating wallets for block chain processing: sure, that's definitely where we need to go in the future. Ideally, I think the code evolves to separate wallet and the rest along a clean interface in a first step indeed. In a second step, we can maybe make them separate processes started from the same binary or even just separate binaries with shared codebase. The final aim should be entirely separate things, either communicating via some private "wallet interconnect protocol" (where several wallets on a trusted network connect to a single validation service), or even turning the wallet processes into standalone SPV clients (with their own blockheader-chain), that can either connect directly to the network, or can connect to a server provide block/tx validation service, simply via the P2P protocol.

Mike Gogulski

On the wallet site of things, IMHO, we could think about switching the interface to JSON-RPC for all interaction with the wallet object(s) and database(s), which would eventually enable bitcoin-qt to talk to wallets on report machines over SSL/TLS. That's painful to tackle all at once, though, since there's plenty of code outside the RPC bundle right now that depends on wallet internals and a while lot of methods sticking off of CWallet.

R E Broadley

This pull request is confusing me as it's raised by a different user to the user making the commits.. (or maybe I don't understand github correctly). Also, I'm wondering if such a thing as a "roadmap" exists for bitcoind/bitcoin-qt. I'm thinking that perhaps the project could be split into two binaries, one that deals with the P2P stuff and sending/receiving tx/blocks, and the other that deals with purely wallet stuff. Currently bitcoind is slowly becoming bloated with both, and a focus on making the split possible might be useful.

Eric Lombrozo

Both users are me. I don't use my CodeShark identity for pushes, though. CodeShark is reserved for github.

CodeShark added some commits
Eric Lombrozo CodeShark Moved wallet detail information out of getinfo and put it in listwall…
…ets. getinfo now just shows how many wallets are loaded.
b0cae87
Eric Lombrozo CodeShark Moved code for locking a wallet automatically at a certain time from …
…rpcwallet.cpp into CCryptoKeyStore class.

TODO:
  Encapsulate the thread spawning and make the call nonblocking.
  Give each thread a unique name.
2b31fdf
Eric Lombrozo

Is this LOCK really necessary?

CodeShark added some commits
Eric Lombrozo CodeShark Dynamic loading and unloading of wallets.
New Changes:
  - Moved LoadWallet out of init.cpp and into CWalletMap class.
  - Added new RPC methods: loadwallet and unloadwallet.

TODO:
  - Clean up I/O in CWalletMap::LoadWallet - debug, error, and UI output functions.
  - Make sure wallet loading and unloading are thread-safe.
  - Save wallets to bitcoin.conf automatically.
1b51a7f
Eric Lombrozo CodeShark New naming scheme for wallets. Checks for valid character set. CWalle…
…tMap now handles unregistration of wallets from main.

Added linker option to makefiles for boost_regex.
3fd110a
Eric Lombrozo CodeShark More load options at startup.
If at least one -usewallet parameter is given, it will use those parameters to determine which wallets to load at startup.
If no -usewallet parameters are given, it searches the data directory for files named wallet-<walletname>.dat.

Also added -nousewallet parameters which override either -usewallet or the data directory.
9d201cf
Eric Lombrozo

Dynamic wallet loading is essentially complete. An important issue that needs to be resolved prior to any integration is making sure its use of LOCKs on threads is ok. Error handling on initialization is also not super smooth, but that's more an issue with AppInit2 generally. At this point I mostly just want to polish up what's there, fix any potential bugs or serious issues, leave this branch alone, and go work on other features.

src/bitcoinrpc.cpp
@@ -1065,16 +1069,20 @@ void ThreadRPCServer3(void* parg)
1065 1069 !pcmd->okSafeMode)
1066 1070 throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
1067 1071
  1072 + if (!pWallet) pWallet = pwalletMain;
1

Probably should use pWalletMap->GetDefaultWallet() wherever pwalletMain appears anywhere in the application.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/rpcwallet.cpp
((20 lines not shown))
  1557 + objWallet.push_back(Pair("keypoololdest", (boost::int64_t)item.second->GetOldestKeyPoolTime()));
  1558 + obj.push_back(Pair(item.first, objWallet));
  1559 + }
  1560 +
  1561 + return obj;
  1562 +}
  1563 +
  1564 +Value usewallet(CWallet* pWallet, const Array& params, bool fHelp)
  1565 +{
  1566 + if (fHelp || params.size() < 2)
  1567 + throw runtime_error(
  1568 + "usewallet <walletname> <method> [params]\n"
  1569 + "Selects which wallet to use.");
  1570 +
  1571 + string strWalletName = params[0].get_str();
  1572 + wallet_map::iterator it = pWalletMap->wallets.find(strWalletName);
1

Should use pWalletMap->GetWallet(strWalletMap);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/rpcwallet.cpp
@@ -1572,3 +1538,92 @@ Value listlockunspent(const Array& params, bool fHelp)
1572 1538 return ret;
1573 1539 }
1574 1540
  1541 +Value listwallets(CWallet* pWallet, const Array& params, bool fHelp)
  1542 +{
  1543 + if (fHelp || params.size() > 0)
  1544 + throw runtime_error(
  1545 + "listwallets\n"
  1546 + "Returns list of wallets.");
  1547 +
  1548 + Object obj;
  1549 + BOOST_FOREACH(const wallet_map::value_type& item, pWalletMap->wallets)
2

I would prefer not to have to access pWalletMap->wallets directly...but using BOOST_FOREACH like this is quite convenient.

Pieter Wuille Collaborator
sipa added a note

You can implement an iterator for CWalletMap, if you really want BOOST_FOREACH.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/bitcoinrpc.cpp
((6 lines not shown))
1068 1074 try
1069 1075 {
1070 1076 // Execute
1071 1077 Value result;
1072 1078 {
1073   - if (pcmd->unlocked)
1074   - result = pcmd->actor(params, false);
  1079 + LOCK(pWalletMap->cs_WalletMap);
2
Pieter Wuille Collaborator
sipa added a note

I don't think you want to keep the walletmap locked during the actual RPC execution.

Totally agreed - this was just me being extra cautious until the locking issues can be further looked into.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Pieter Wuille sipa commented on the diff
src/bitcoinrpc.cpp
@@ -1220,6 +1228,9 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
1220 1228 if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]);
1221 1229 if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]);
1222 1230 if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]);
  1231 + if (strMethod == "loadwallet" && n > 1) ConvertTo<bool>(params[1]);
  1232 + if (strMethod == "loadwallet" && n > 2) ConvertTo<bool>(params[2]);
  1233 + if (strMethod == "loadwallet" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2
Pieter Wuille Collaborator
sipa added a note

Doesn't RPCConvertValues need some magic to deal with usewallet?

usewallet used to call RPCConvertValues on the parameters and pass it to CRPCTable::execute.

Now RPCConvertValues does the magic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/keystore.cpp
((6 lines not shown))
87 89 return true;
88 90 }
89 91
  92 +void CCryptoKeyStore::SleepThenLock(int64 nMyWakeTime)
2
Pieter Wuille Collaborator
sipa added a note

What is this? Seems unrelated to the pull request...

The reason this was added was because we need to be able to unlock each wallet individually. The RPC methods shouldn't have to be keeping track of when it's time to lock the wallet again, so the options seem to be to either move the timer to within the CCryptoKeyStore class itself - or to write a helper class that manages this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/util.cpp
@@ -944,12 +944,31 @@ bool WildcardMatch(const string& str, const string& mask)
944 944 return WildcardMatch(str.c_str(), mask.c_str());
945 945 }
946 946
947   -
948   -
949   -
950   -
951   -
952   -
  947 +vector<string> GetFilesAtPath(const boost::filesystem::path& _path, unsigned int flags)
  948 +{
  949 + vector<string> vstrFiles;
  950 + if (!boost::filesystem::exists(_path))
  951 + throw runtime_error("Path does not exist.");
  952 +
  953 + if ((flags & file_option_flags::REGULAR_FILES) && boost::filesystem::is_regular_file(_path))
  954 + {
  955 + vstrFiles.push_back(_path.filename().string());
3
Pieter Wuille Collaborator
sipa added a note

Just use _path.string().

Won't that return the complete path including directories? I just want the filenames.

Pieter Wuille Collaborator
sipa added a note

Oh, yes - you'll need compatibility with boost filesystem v2 though... for now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/wallet.h
@@ -311,6 +313,31 @@ class CWallet : public CCryptoKeyStore
311 313 boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx, ChangeType status)> NotifyTransactionChanged;
312 314 };
313 315
  316 +/** A CWalletMap associates wallets with names and automatically deallocates them upon destruction.
  317 + */
  318 +const boost::regex WALLET_NAME_REGEX("[a-zA-Z0-9_]*");
  319 +const boost::regex WALLET_FILE_REGEX("wallet-([a-zA-Z0-9_]+)\\.dat");
  320 +typedef std::map<std::string, CWallet*> wallet_map;
  321 +class CWalletMap
  322 +{
  323 +public:
  324 + mutable CCriticalSection cs_WalletMap;
3
Pieter Wuille Collaborator
sipa added a note

Is there an actual need for this critsect to be exposed publically? Ideally (and I know a lot of old code offends against this horribly), critical sections are private and only taken by class methods itself.

so the preferred style would be something like a lock method containing LOCK(cs_WalletMap)? I guess that wouldn't work because it would go out of scope when the method returns.

So could you give a quick example of the style?

Actually, the only locking really needed is when unloading wallets. The rest of the wallet locking could be handled by the wallet class itself. So it seems an even better solution is to just lock on the wallet inside the UnloadWallet method. I'm wondering whether we should be locking on the UnregisterWallet method in main...Btw, is the std::map class thread-safe? Are inserts, deletes, and searches atomic?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Eric Lombrozo CodeShark commented on the diff
src/makefile.unix
@@ -32,6 +32,7 @@ LIBS += \
32 32 -l boost_filesystem$(BOOST_LIB_SUFFIX) \
33 33 -l boost_program_options$(BOOST_LIB_SUFFIX) \
34 34 -l boost_thread$(BOOST_LIB_SUFFIX) \
  35 + -l boost_regex$(BOOST_LIB_SUFFIX) \
5

This is what's causing BitcoinPullTester to fail. Could we add this library?

P. Kaufmann
Diapolo added a note

Is Boost Regex a compiled lib or does it consist only of a .hpp file? If you need it for this pull to work you will also need to add it to bitcoin-qt.pro for the Qt client to work.

Gavin Andresen Owner

If I recall correctly, boost::regex can be used either as headers-only OR requires-linking. Downside of headers-only is it increases compile times and uses a lot more memory when compiling.

It seems odd that the build testing machine would have boost built without the regex library, I thought the regexp library was built by default when you built boost.

@Diapolo indeed. I got this branch to build the Qt client on Mac OS 10.8. I'm still having some problems with std::basic_ostream and QtCore/qglobal.h when I use -mmacosx-version-min=10.5. Using -mmacosx-version-min=10.7 seems to make the first problem go away. The second problem is just a warning.

-mmacosx-version-min=10.6 even works. But 10.5, no way.

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

Hmm, still having some issues with the default wallet not unloading at shutdown. Will need to go over the shutdown sequence to make sure all threads relinquish their pointers to it.

Gavin Andresen

Just to set expectations:

This big a change, in this critical a part of the codebase, will need:

  • A comprehensive test plan, that exercises all the things that have changed.
  • Testing by at least two different people who aren't developers, on Windows and either Linux or Mac

See https://github.com/bitcoin/QA for the lastest QA process.

BitcoinPullTester

Automatic sanity-testing: PASSED, see http://jenkins.bluematt.me/pull-tester/1c45edce2fbe76f7e146ee12c1df80c66c5fa8f9 for binaries and test log.

BitcoinPullTester

Automatic sanity-testing: FAILED MERGE, see http://jenkins.bluematt.me/pull-tester/6c7f86ae371f955371fba05c7f747e4659cd39c8 for test log.

This pull does not merge cleanly onto current master
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.

MrLei

How i can install bitcoind whit Dynamically Loadable Multiple Wallet ?

Gavin Andresen

Rebase needed.

Tranz5

This is awesome work. I hope it makes it way to BTC soon. I've been playing with it for a bit now. Here are the issues I am working through.
1) Export doesn't work. ( Tried making BitCoinGui exportAction public and referencing it in WalletView::gotoHistoryPage but that only gives me default wallet) Still working on different methods to fix this.
2) The RPC commands loadwallet and unloadwallet do not reflect in gui. I think the gui needs a connect to rpc commands.
3) When clicking on the transaction on the right side of the gui, the transaction button doesn't get focus.
4) The gui can't create a new wallet. using loadwallet then unloadwallet rcp, then load button in gui works, but..

So far these are the only issues I have found.

Thanks again for the hard work. I'll share what I can when as I work through these changes. I am still new and trying to catchup as quick as possible. Any hints are appreciated it.

Happy Bitcoining!

Tranz5

I also found that sign message didn't work with other wallets.

I have found a solution to all of these.

I can do a pull request to this version, if this actually has a chance to be part of btc. I don't have time to rebase though.

Thanks!

bananas2

Is it already implemented?

Wladimir J. van der Laan
Owner

No, the pull request was not kept up to date. I needs a lot of rebasing to apply to 0.9.x, which Gavin already noted 5 months ago.

Wladimir J. van der Laan
Owner

I'm going to close this. It has diverged too much from the current code base and no one seems to be interested in rebasing it.

In case anyone ever wants to have a shot at implementing multi-wallet I'll refer to to these code changes, as in principle they are good but they just arrived at the wrong time and were not kept in sync long enough to be tested properly and merged.

Wladimir J. van der Laan laanwj closed this
Wladimir J. van der Laan 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

Showing 38 unique commits by 1 author.

Dec 24, 2012
Eric Lombrozo CodeShark Added multiple wallet support
=============================

A new global structure called pWalletMap has been added. Upon initialization, multiple wallets can be loaded.

A new CWallet* parameter has been added to the RPC functions. Functions which do not use a wallet simply ignore it. In addition, a new field has been added to CRPCCommand that tells us whether or not the function uses a wallet.

Two new RPC methods have been added:
  1) listwallets - Returns an array containing wallet names.
  2) usewallet - Prefix existing wallet RPC calls with usewallet <walletname> to use a particular wallet. If no wallet is specified, the default wallet is used.
    example: bitcoind usewallet foo listreceivedbyaddress 0 true

TODO:
  1) Get wallet names from bitcoin.conf in init.cpp.
  2) Change help RPC so that the message does not depend on wallet state (i.e. walletpassphrase RPC call)
71c63e3
Eric Lombrozo CodeShark Added CWallet* parameter to RPC test suite and a CWalletMap instance …
…to test_bitcoin.cpp
4a6b0e2
Eric Lombrozo CodeShark Fixed RPC issues detected by test suite. 158ce39
Eric Lombrozo CodeShark Added loading of wallet names and files from -usewallet arguments
=================================================================

You can now specify additional wallets in the config file or via command line arguments:

	usewallet=foo

or

	bitcoind -usewallet=foo

A default wallet called "default" in the RPC and using file "wallet.dat" is always loaded, as to not break compatibility with the master branch. Therefore, additional wallets should neither be called "default" nor "wallet" nor anything else that might conflict with other filenames in the .bitcoin directory.

The wallet will be stored in a file called foo.dat. If the wallet doesn't yet exist, it will be created the first time bitcoind is run.

TODO: Ensure filename collisions cannot occur. Perhaps allow the wallet files to be arbitrarily named rather than tied to their identifier.
1b640c1
Eric Lombrozo CodeShark TxMemPool::accept() calls SyncWithWallets(), so all mempool transacti…
…ons are synched automatically without having to call SyncWithWallets() explicitly. This is important when sending between two wallets in a single bitcoind instance so that the receiving wallet is alerted of the transaction immediately.

Removed calls to SyncWithWallets() in ProcessMessage() since SyncWithWallets() is already called by tx.AcceptToMemoryPool().

SyncWithWallets() is still called explicitly from CBlock::ConnectBlock() since the transaction never goes through the mempool in this case.
1cdf18b
Eric Lombrozo CodeShark Modified getinfo RPC call to return an array of wallets 27fa196
Eric Lombrozo CodeShark Removed dependency on wallet encryption state for getting help on RPC…
… methods. Help always returns usage info now.
93e6b80
Eric Lombrozo CodeShark usewallet now checks whether method is valid. 0f815bf
Dec 25, 2012
Eric Lombrozo CodeShark Fixed LOCK to lock appropriate wallet. 924f088
Eric Lombrozo CodeShark Fixed wallet load time indicator. fa1c808
Dec 26, 2012
Eric Lombrozo CodeShark Moved wallet detail information out of getinfo and put it in listwall…
…ets. getinfo now just shows how many wallets are loaded.
b0cae87
Eric Lombrozo CodeShark Moved code for locking a wallet automatically at a certain time from …
…rpcwallet.cpp into CCryptoKeyStore class.

TODO:
  Encapsulate the thread spawning and make the call nonblocking.
  Give each thread a unique name.
2b31fdf
Dec 27, 2012
Eric Lombrozo CodeShark Dynamic loading and unloading of wallets.
New Changes:
  - Moved LoadWallet out of init.cpp and into CWalletMap class.
  - Added new RPC methods: loadwallet and unloadwallet.

TODO:
  - Clean up I/O in CWalletMap::LoadWallet - debug, error, and UI output functions.
  - Make sure wallet loading and unloading are thread-safe.
  - Save wallets to bitcoin.conf automatically.
1b51a7f
Eric Lombrozo CodeShark New naming scheme for wallets. Checks for valid character set. CWalle…
…tMap now handles unregistration of wallets from main.

Added linker option to makefiles for boost_regex.
3fd110a
Eric Lombrozo CodeShark More load options at startup.
If at least one -usewallet parameter is given, it will use those parameters to determine which wallets to load at startup.
If no -usewallet parameters are given, it searches the data directory for files named wallet-<walletname>.dat.

Also added -nousewallet parameters which override either -usewallet or the data directory.
9d201cf
Eric Lombrozo CodeShark Thread-safe CWalletMap. 2256d1d
Dec 29, 2012
Eric Lombrozo CodeShark Using GetWallet instead of pWalletMap->wallets.find 3f5d692
Eric Lombrozo CodeShark Using GetWallet instead of pWalletMap->wallets.find 629ca2f
Eric Lombrozo CodeShark Merge branch 'multiwallet' of 108.60.150.142:../gitrepos/bitcoin into…
… multiwallet
55d301c
Jan 07, 2013
Eric Lombrozo CodeShark Moved RPC type conversion for usewallet to RPCConvertValues function. ebf85b1
Eric Lombrozo CodeShark Fixed usewallet params. 74228a2
Jan 10, 2013
Eric Lombrozo CodeShark Added preprocessor directive for boost filesystem v2 vs v3. ec0cc4b
Eric Lombrozo CodeShark Better encapsulation on WalletMap class, moved critical section locks…
… to within the class methods themselves and out of bitcoinrpc.cpp, wallet unload locks on individual wallet rather than all wallets.
7348f78
Eric Lombrozo CodeShark Checking for CDB exceptions upon loading wallet. d21a960
Eric Lombrozo CodeShark Added unload methods for wallet db and call to unload in ~CWallet(). f409a6d
Eric Lombrozo CodeShark Fixed test_bitcoin issue. 6215e53
Eric Lombrozo CodeShark Added locks on setpwalletRegistered functions. d8b0cf1
Eric Lombrozo CodeShark Added ReacceptWalletTransactions() registered wallet function in main…
… rather than iterating through the wallet map in init.
3d15116
Eric Lombrozo CodeShark Added -lboost_regex to bitcoin-qt.pro. aa93b31
Jan 11, 2013
Eric Lombrozo CodeShark Made wallet pointers in CWalletMap boost::shared_ptr<CWallet>. e0f3cbe
Eric Lombrozo CodeShark Removed pwalletMain. Using pWalletMap->GetDefaultWallet() instead. eba5579
Eric Lombrozo CodeShark Renamed CWalletMap CWalletManager and pWalletMap pWalletManager. 6f3e40b
Jan 14, 2013
Eric Lombrozo CodeShark Added Timer 3944f1d
Eric Lombrozo CodeShark Integrated timer with wallet. 64a9b45
Eric Lombrozo CodeShark Added wallet unloading tracers. Let rpcmining methods use nondefault …
…wallet.
a240960
Eric Lombrozo CodeShark Changed the way unlock time displays in listwallets. 41f561c
Eric Lombrozo CodeShark Made wallet unlock timestamp UTC. 5bb560f
Jan 19, 2013
Eric Lombrozo CodeShark Merged multiwallet(5bb560f) with master. 6c7f86a
Something went wrong with that request. Please try again.