Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Dynamically Loadable Multiple Wallet Support Complete!!! #2124

Closed
wants to merge 38 commits into
from

Conversation

Projects
None yet
Contributor

CodeShark commented Dec 23, 2012

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

To specify additional wallets at startup, use option -usewallet=foo -usewallet=bar etc...as detailed here: #2124 (comment) and CodeShark/bitcoin@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.
Contributor

CodeShark commented Dec 23, 2012

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

Diapolo commented Dec 23, 2012

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

Contributor

CodeShark commented Dec 23, 2012

Possible, sure. Better, why?

Contributor

CodeShark commented Dec 23, 2012

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
Contributor

rebroad commented Dec 23, 2012

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.

Contributor

CodeShark commented Dec 24, 2012

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 Dec 21, 2012

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)
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.
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.
Removed dependency on wallet encryption state for getting help on RPC…
… methods. Help always returns usage info now.
Contributor

CodeShark commented Dec 24, 2012

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.

Member

gmaxwell commented Dec 24, 2012

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)

Contributor

CodeShark commented Dec 24, 2012

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.

Member

gmaxwell commented Dec 24, 2012

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::

Contributor

CodeShark commented Dec 24, 2012

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.

Contributor

CodeShark commented Dec 24, 2012

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.

Contributor

CodeShark commented Dec 24, 2012

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.

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.

Contributor

CodeShark commented Dec 25, 2012

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.

@sipa sipa commented on an outdated diff Dec 25, 2012

src/bitcoinrpc.cpp
try
{
// Execute
Value result;
{
- if (pcmd->unlocked)
- result = pcmd->actor(params, false);
+ if (pcmd->unlocked) {
+ result = pcmd->actor(pWallet, params, false);
+ }
else {
LOCK2(cs_main, pwalletMain->cs_wallet);
@sipa

sipa Dec 25, 2012

Owner

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

@sipa sipa and 1 other commented on an outdated diff Dec 25, 2012

@@ -25,6 +25,7 @@
using namespace std;
using namespace boost;
+CWalletMap* pWalletMap;
@sipa

sipa Dec 25, 2012

Owner

pWalletMap can be allocated statically, I believe.

@CodeShark

CodeShark Dec 25, 2012

Contributor

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.

@sipa sipa and 1 other commented on an outdated diff Dec 25, 2012

@@ -311,6 +311,21 @@ class CWallet : public CCryptoKeyStore
boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx, ChangeType status)> NotifyTransactionChanged;
};
+/** A CWalletMap associates wallets with names and automatically deallocates them upon destruction.
+ */
+typedef std::map<std::string, CWallet*> wallet_map;
+class CWalletMap
+{
+public:
+ wallet_map wallets;
+
+ ~CWalletMap()
@sipa

sipa Dec 25, 2012

Owner

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

@CodeShark

CodeShark Dec 25, 2012

Contributor

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.

Owner

sipa commented Dec 25, 2012

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.

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.

Contributor

rebroad commented Dec 25, 2012

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.

Contributor

CodeShark commented Dec 25, 2012

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

CodeShark added some commits Dec 26, 2012

Moved wallet detail information out of getinfo and put it in listwall…
…ets. getinfo now just shows how many wallets are loaded.
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.

Is this LOCK really necessary?

CodeShark added some commits Dec 27, 2012

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.
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.
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.
Contributor

CodeShark commented Dec 27, 2012

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.

@CodeShark CodeShark commented on an outdated diff Dec 29, 2012

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

CodeShark Dec 29, 2012

Contributor

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

@CodeShark CodeShark commented on an outdated diff Dec 29, 2012

src/rpcwallet.cpp
+ objWallet.push_back(Pair("keypoololdest", (boost::int64_t)item.second->GetOldestKeyPoolTime()));
+ obj.push_back(Pair(item.first, objWallet));
+ }
+
+ return obj;
+}
+
+Value usewallet(CWallet* pWallet, const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 2)
+ throw runtime_error(
+ "usewallet <walletname> <method> [params]\n"
+ "Selects which wallet to use.");
+
+ string strWalletName = params[0].get_str();
+ wallet_map::iterator it = pWalletMap->wallets.find(strWalletName);
@CodeShark

CodeShark Dec 29, 2012

Contributor

Should use pWalletMap->GetWallet(strWalletMap);

@CodeShark CodeShark and 1 other commented on an outdated diff Dec 29, 2012

src/rpcwallet.cpp
@@ -1572,3 +1538,92 @@ Value listlockunspent(const Array& params, bool fHelp)
return ret;
}
+Value listwallets(CWallet* pWallet, const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 0)
+ throw runtime_error(
+ "listwallets\n"
+ "Returns list of wallets.");
+
+ Object obj;
+ BOOST_FOREACH(const wallet_map::value_type& item, pWalletMap->wallets)
@CodeShark

CodeShark Dec 29, 2012

Contributor

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

@sipa

sipa Jan 6, 2013

Owner

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

@sipa sipa and 1 other commented on an outdated diff Jan 6, 2013

src/bitcoinrpc.cpp
try
{
// Execute
Value result;
{
- if (pcmd->unlocked)
- result = pcmd->actor(params, false);
+ LOCK(pWalletMap->cs_WalletMap);
@sipa

sipa Jan 6, 2013

Owner

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

@CodeShark

CodeShark Jan 7, 2013

Contributor

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

@sipa sipa commented on the diff Jan 6, 2013

src/bitcoinrpc.cpp
@@ -1220,6 +1228,9 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]);
if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]);
if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]);
+ if (strMethod == "loadwallet" && n > 1) ConvertTo<bool>(params[1]);
+ if (strMethod == "loadwallet" && n > 2) ConvertTo<bool>(params[2]);
+ if (strMethod == "loadwallet" && n > 3) ConvertTo<boost::int64_t>(params[3]);
@sipa

sipa Jan 6, 2013

Owner

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

@CodeShark

CodeShark Jan 7, 2013

Contributor

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

Now RPCConvertValues does the magic.

@sipa sipa and 1 other commented on an outdated diff Jan 6, 2013

src/keystore.cpp
return true;
}
+void CCryptoKeyStore::SleepThenLock(int64 nMyWakeTime)
@sipa

sipa Jan 6, 2013

Owner

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

@CodeShark

CodeShark Jan 10, 2013

Contributor

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.

@sipa sipa and 1 other commented on an outdated diff Jan 6, 2013

@@ -944,12 +944,31 @@ bool WildcardMatch(const string& str, const string& mask)
return WildcardMatch(str.c_str(), mask.c_str());
}
-
-
-
-
-
-
+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.");
+
+ if ((flags & file_option_flags::REGULAR_FILES) && boost::filesystem::is_regular_file(_path))
+ {
+ vstrFiles.push_back(_path.filename().string());
@sipa

sipa Jan 6, 2013

Owner

Just use _path.string().

@CodeShark

CodeShark Jan 7, 2013

Contributor

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

@sipa

sipa Jan 7, 2013

Owner

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

@sipa sipa and 1 other commented on an outdated diff Jan 6, 2013

@@ -311,6 +313,31 @@ class CWallet : public CCryptoKeyStore
boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx, ChangeType status)> NotifyTransactionChanged;
};
+/** A CWalletMap associates wallets with names and automatically deallocates them upon destruction.
+ */
+const boost::regex WALLET_NAME_REGEX("[a-zA-Z0-9_]*");
+const boost::regex WALLET_FILE_REGEX("wallet-([a-zA-Z0-9_]+)\\.dat");
+typedef std::map<std::string, CWallet*> wallet_map;
+class CWalletMap
+{
+public:
+ mutable CCriticalSection cs_WalletMap;
@sipa

sipa Jan 6, 2013

Owner

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.

@CodeShark

CodeShark Jan 10, 2013

Contributor

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?

@CodeShark

CodeShark Jan 10, 2013

Contributor

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?

@CodeShark CodeShark commented on the diff Jan 10, 2013

src/makefile.unix
@@ -32,6 +32,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) \
@CodeShark

CodeShark Jan 10, 2013

Contributor

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

@Diapolo

Diapolo Jan 10, 2013

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.

@gavinandresen

gavinandresen Jan 10, 2013

Contributor

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.

@CodeShark

CodeShark Jan 10, 2013

Contributor

@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.

@CodeShark

CodeShark Jan 10, 2013

Contributor

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

Contributor

CodeShark commented Jan 14, 2013

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.

Contributor

gavinandresen commented Jan 14, 2013

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.

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

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 commented Oct 4, 2013

How i can install bitcoind whit Dynamically Loadable Multiple Wallet ?

Contributor

gavinandresen commented Oct 21, 2013

Rebase needed.

Tranz5 commented Nov 13, 2013

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 commented Dec 1, 2013

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!

Is it already implemented?

Owner

laanwj commented Mar 24, 2014

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.

Owner

laanwj commented Apr 3, 2014

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.

@laanwj laanwj closed this Apr 3, 2014

@laanwj laanwj referenced this pull request Apr 25, 2014

Closed

Multiple wallet #4093

6coind commented Dec 19, 2015

Noone can re-base this ? Amazing that this did not become the standard

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