[wallet] loadwallet RPC - load wallet at runtime #10740

pull jnewbery wants to merge 7 commits into bitcoin:master from jnewbery:load_unload_wallet changing 6 files +178 −57
  1. jnewbery commented at 2:24 pm on July 4, 2017: member

    Adds a loadwallet RPCs. This allows wallets to be loaded dynamically during runtime without having to stop-start the node with new -wallet params.

    Includes functional tests and release notes.

    Limitations:

    • currently this functionality is only available through the RPC interface.
    • wallets loaded in this way will not be displayed in the GUI.
  2. fanquake added the label Wallet on Jul 5, 2017
  3. jnewbery force-pushed on Jul 5, 2017
  4. in src/init.cpp:248 in 72c37457cd outdated
    244@@ -252,10 +245,7 @@ void Shutdown()
    245 #endif
    246     UnregisterAllValidationInterfaces();
    247 #ifdef ENABLE_WALLET
    248-    for (CWalletRef pwallet : vpwallets) {
    249-        delete pwallet;
    250-    }
    251-    vpwallets.clear();
    252+    DeleteWallets();
    


    jonasschnelli commented at 4:22 pm on July 5, 2017:
    It’d probably call this deallocWallets()

    jnewbery commented at 10:18 am on July 7, 2017:
    Yes, DeleteWallets() is a bad name. DeallocWallets() is good, or perhaps DetachWallets()
  5. in src/wallet/db.cpp:325 in 72c37457cd outdated
    226@@ -227,40 +227,12 @@ bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*reco
    227 
    228 bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr)
    229 {
    230-    LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
    


    jonasschnelli commented at 4:24 pm on July 5, 2017:
    What’s the reasons for keeping this function (that now always returns true)?

    jnewbery commented at 10:23 am on July 7, 2017:
    You’re right. This (and CWalletDB::VerifyEnvironment()) are now entirely vestigial and are not called. Both can be removed.
  6. in src/wallet/wallet.cpp:42 in 72c37457cd outdated
    34@@ -35,6 +35,8 @@
    35 #include <boost/algorithm/string/replace.hpp>
    36 #include <boost/thread.hpp>
    37 
    38+/** Protects the vpwallets vector */
    39+CCriticalSection cs_wallets;
    40 std::vector<CWalletRef> vpwallets;
    


    jonasschnelli commented at 4:26 pm on July 5, 2017:
    I guess this belongs to walletinit.h now?

    jnewbery commented at 10:28 am on July 7, 2017:
    Why? vpwallets is accessed by functions in several of the wallet source files.

    jonasschnelli commented at 6:58 pm on July 9, 2017:

    I had the idea that walletinit.h/.c is kind of the multiwallet interface (wallet manager). The functions we have there (DeleteWallets(), VerifyWallets(), ShutdownWallets();, etc.) sounded for me after vpwallets belongs there…

    IMO, the multiwallet map should ideally not sit within the objects (CWallet) implementation.


    TheBlueMatt commented at 10:15 pm on December 3, 2017:
    Tend to agree with @jonasschnelli here, though I agree the barrier isn’t exactly clear (yet). Ideally we’d move more towards clarifying the interface here - making CWallet less and less aware of all the things around it (including other wallets). @sipa thoughts here?
  7. jnewbery commented at 10:30 am on July 7, 2017: member
    This overlaps significantly with #10762. Not sure how I should ask for review. Perhaps find out which one people think is the priority? Or I could split the walletinit.cpp commits into their own PR.
  8. in src/wallet/rpcwallet.cpp:2997 in 72c37457cd outdated
    2467+    }
    2468+
    2469+    return obj;
    2470+}
    2471+
    2472+UniValue loadwallet(const JSONRPCRequest& request)
    


    jnewbery commented at 10:33 am on July 7, 2017:
    On further thought, I think I prefer the names attachwallet and detachwallet. That gives a bit more distinction from the dump/import RPCs and makes a stronger implication that the new .dat file is being loaded and attached as a separate wallet.
  9. promag commented at 10:43 am on July 7, 2017: member
    @jnewbery IMO this one should rebase on the other.
  10. jnewbery commented at 10:46 am on July 7, 2017: member

    IMO this one should rebase on the other.

    Makes logical sense. Downside is that the other is a more significant change, so may take longer to get merged.

  11. promag commented at 10:54 am on July 7, 2017: member
    If this really depends on that work then there’s no other way than waiting. The other downside is that the other commits will show up here too.
  12. jnewbery commented at 3:09 pm on July 7, 2017: member

    I’ve changed the PR sequence, so this will now depend on #10767. If I get positive concept feedbac on #10767 I’ll rebase this on top of it.

    For now, I’m still just looking for concept feedback.

  13. jnewbery force-pushed on Aug 28, 2017
  14. jnewbery commented at 9:21 pm on August 28, 2017: member
    Rebased on #10767 . Reviewers, please review #10767 first.
  15. jnewbery force-pushed on Aug 30, 2017
  16. MarcoFalke referenced this in commit 791a0e6dda on Sep 7, 2017
  17. jnewbery force-pushed on Sep 11, 2017
  18. jnewbery commented at 4:31 pm on September 11, 2017: member
    Rebased now that #10767 is merged. Still a work in progress. PR text updated.
  19. jnewbery force-pushed on Sep 15, 2017
  20. jnewbery force-pushed on Sep 15, 2017
  21. jnewbery force-pushed on Sep 15, 2017
  22. jnewbery renamed this:
    [WIP] [wallet] dynamic loading/unloading of wallets
    [wallet] dynamic loading/unloading of wallets
    on Sep 15, 2017
  23. jnewbery force-pushed on Sep 20, 2017
  24. jnewbery commented at 2:16 pm on September 20, 2017: member
    Bad automatic merge of the testcase. Re-merged manually.
  25. jnewbery commented at 4:51 pm on September 20, 2017: member

    Manual rebase fixed the test bug. Travis now passes.

    This is ready for initial review.

  26. in src/qt/bitcoin.cpp:490 in 6c5b84119d outdated
    494-
    495-            connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)),
    496-                             paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray)));
    497+            // TODO: Expose secondary wallets
    498+            LOCK(cs_wallets);
    499+            if (!vpwallets.empty())
    


    promag commented at 9:07 am on September 21, 2017:
    {.
  27. in src/qt/bitcoin.cpp:497 in 6c5b84119d outdated
    501+                walletModel = new WalletModel(platformStyle, vpwallets[0], optionsModel);
    502+
    503+                window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel);
    504+                window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET);
    505+
    506+                connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)),
    


    promag commented at 9:08 am on September 21, 2017:
    Missing spaces after ,?
  28. in src/wallet/init.cpp:198 in 6c5b84119d outdated
    192-    for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
    193-        if (boost::filesystem::path(walletFile).filename() != walletFile) {
    194-            return InitError(strprintf(_("Error loading wallet %s. -wallet parameter must only specify a filename (not a path)."), walletFile));
    195-        }
    196+    // -salvagewallet can only be used when loading a single wallet
    197+    bool salvage_wallet = gArgs.GetBoolArg("-salvagewallet", false) && wallet_files.size() <= 1;
    


    promag commented at 9:39 am on September 21, 2017:
    Throw an error if -salvagewallet and there are multiple wallets?

    jnewbery commented at 1:44 pm on September 21, 2017:
    Sounds like a sensible change in behaviour. I think it’s beyond the scope of this PR.

    ryanofsky commented at 6:05 pm on December 20, 2017:

    #10740 (review)

    In commit “Allow single wallet to be verified”

    It looks like WalletParameterInteraction is already throwing an error in this case. I think it would be better to drop the comment and wallet_files check here. If you’d prefer to keep the check, I think the comment should be something clearer like “// parameter interaction code should have thrown an error if -salvagewallet was enabled with more than wallet file, so the wallet_files size check here should have no effect.”


    jnewbery commented at 6:11 pm on April 24, 2018:
    Updated comment as suggested by @ryanofsky .

    jimpo commented at 9:37 pm on May 9, 2018:
    Appears this comment update was lost somewhere?
  29. in src/wallet/rpcwallet.cpp:40 in 6c5b84119d outdated
    36@@ -37,6 +37,7 @@ static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
    37 
    38 CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
    39 {
    40+    AssertLockHeld(cs_wallets);
    


    promag commented at 9:45 am on September 21, 2017:
    Why not just LOCK(cs_wallets) too?

    jnewbery commented at 1:44 pm on September 21, 2017:
    Because I’d prefer to avoid recursive locking if possible.

    promag commented at 9:30 pm on September 21, 2017:
    Just curious, why?

    TheBlueMatt commented at 10:13 pm on December 3, 2017:
    Yes, definitely. cs_wallets is locked before cs_main in global lock order, so putting it too many places is just asking for trouble, IMO.
  30. promag commented at 9:51 am on September 21, 2017: member

    Quick review. All touched code could be updated as per dev notes.

    Most importantly, With the LOCK(cs_wallets) it will be impossible to have concurrent RPC to different wallets, not to mention to the same wallet. Is this expected behavior? - I’m assuming there is a thread pool for RPC.

  31. jnewbery commented at 1:43 pm on September 21, 2017: member

    Thanks for the review @promag!

    Regarding the locking: Yes, I’ve implemented this as a mutex for now, which as you point out would limit wallet RPCs to be single-threaded. I’d like to update this to be something a bit better before v0.16. Suggestions are either a shared mutex or (suggested by @theuni) a version of the decay pointers in #10738. The problem with using a shared mutex is that C++ doesn’t have a standard library shared mutex until C++14 (std::shared_timed_mutex) so I’d either have to use boost::shared_mutex or roll my own.

    (apologies - I thought I’d already written a note in this PR explaining this, but I must have failed to hit send!)

    For now, I think review of this PR with the mutex is helpful, and I’ll change it around to use a shared_mutex later.

  32. laanwj added this to the "Blockers" column in a project

  33. luke-jr commented at 8:03 pm on September 21, 2017: member
    This seems to ignore the whole issue of long-term wallet references, and probably locks cs_wallets too long.
  34. laanwj added this to the milestone 0.16.0 on Sep 28, 2017
  35. laanwj commented at 6:44 am on September 28, 2017: member
    Adding 0.16.0 milestone, I think this should be merged after 0.15.1 to prevent extra rebasing in the wallet code when porting back to 0.15.1.
  36. in src/wallet/rpcwallet.cpp:2725 in e188d00ece outdated
    2720+        if (!EnsureWalletIsAvailable(*wallet_iter, request.fHelp)) {
    2721+            throw JSONRPCError(RPC_WALLET_ERROR, "Error accessing wallets");
    2722+        }
    2723+
    2724+        if ((*wallet_iter)->GetName() == walletName) {
    2725+
    


    kallewoof commented at 3:45 am on October 4, 2017:
    Unneeded newline.
  37. in src/wallet/rpcwallet.cpp:2718 in e188d00ece outdated
    2713+
    2714+    std::string walletName = request.params[0].get_str();
    2715+
    2716+    bool unloaded = false;
    2717+
    2718+    for (std::vector<CWalletRef>::iterator wallet_iter = vpwallets.begin(); wallet_iter != vpwallets.end(); wallet_iter++) {
    


    kallewoof commented at 3:46 am on October 4, 2017:
    Any reason for not just doing for (auto wallet : vpwallets) { here?
  38. in src/wallet/rpcwallet.cpp:2663 in 6c5b84119d outdated
    2657@@ -2658,35 +2658,53 @@ UniValue listwallets(const JSONRPCRequest& request)
    2658 
    2659 UniValue openwallet(const JSONRPCRequest& request)
    2660 {
    2661-    if (request.fHelp || request.params.size() != 1)
    2662+    if (request.fHelp || request.params.size() > 2)
    2663         throw std::runtime_error(
    2664-            "openwallet \"filename\"\n"
    2665+            "openwallet \"filename\" (\"passphrase\")\n"
    


    kallewoof commented at 3:59 am on October 4, 2017:
    Ugh, passwords on prompts leaves the password as plaintext in shell history etc. Can’t really be fixed for HTTP-RPC I guess, but CLI could probably take a bool to mean “prompt me for password”.
  39. in src/wallet/rpcwallet.cpp:2668 in 6c5b84119d outdated
    2665+            "openwallet \"filename\" (\"passphrase\")\n"
    2666             "\nOpens a wallet from a wallet.dat file.\n"
    2667+            "\nUse the passphrase argument to unlock an encrypted wallet while opening.\n"
    2668             "\nArguments:\n"
    2669             "1. \"filename\"    (string, required) The wallet.dat file\n"
    2670+            "2. \"passphrase\"    (string, optional) The wallet.dat file\n"
    


    kallewoof commented at 4:00 am on October 4, 2017:
    Description is wrong.
  40. kallewoof commented at 4:03 am on October 4, 2017: member
    utACK 6c5b84119d1ffa547bf094b28ca602bdaf07c21a
  41. promag commented at 2:31 pm on October 11, 2017: member

    Needs rebase.

    The openwallet should rescan?

  42. fanquake added this to the "In progress" column in a project

  43. Sjors commented at 3:56 pm on November 20, 2017: member

    Concept ACK.

    I was able to use openwallet and closewallet.

    I wonder how this interacts with #11383. E.g. I’m guessing the UI wouldn’t pick up on this (not a big issue). I can try once both are rebased.

    It would be nice if bitcoin-cli -rpcwallet=X would open X if it’s not open yet, maybe close it when done (future PR).

    Should there be a separate RPC for creating a new wallet or should that be done using openwallet? (my initial thoughts are that there should be a separate RPC)

    I would prefer it if openwallet fails for wallets that don’t exist, rather than creating a new wallet. I understand it makes sense for bitcoind -wallet to create a new one, because that’s what a new user would expect, but I don’t think that’s needed for openwallet.

  44. promag commented at 4:29 pm on November 20, 2017: member
    @Sjors this PR must be rebased with #11383 (probably when that gets merged).
  45. in src/wallet/init.cpp:200 in 2e774d8912 outdated
    223-            CWallet dummyWallet;
    224-            std::string backup_filename;
    225-            if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet, CWalletDB::RecoverKeysOnlyFilter, backup_filename)) {
    226-                return false;
    227-            }
    228+            return InitError(strprintf(_("Error loading wallet %s. Duplicate wallet filename specified."), walletFile));
    


    TheBlueMatt commented at 4:01 pm on December 5, 2017:
    This is redundant now, no?
  46. in src/wallet/wallet.h:1084 in 2e774d8912 outdated
    1079@@ -1080,6 +1080,9 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
    1080     /** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
    1081     bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
    1082 
    1083+    //! Verify wallet naming and perform salvage on the wallet if required
    1084+    static bool VerifyWallet(std::string walletFile, bool salvage_wallet);
    


    TheBlueMatt commented at 4:08 pm on December 5, 2017:
    nit: I’d rather not make this a static CWallet member. wallet.cpp is already plenty big and the stuff that it does seems more external db-related stuff and less wallet-related stuff. Ideally it’d be nice to more clearly separate the DB stuff from the wallet logic itself by pulling things like the DB-related stuff out of CreateWalletFromFile.

    promag commented at 4:04 pm on May 7, 2018:
    @TheBlueMatt btw my suggestion is to move (some) static code to a WalletManager (#13034).

    jnewbery commented at 9:14 pm on May 7, 2018:

    I agree with @promag that a WalletManager class is a good place for this in the long run.

    Since this is a nit only, can we save it for a future PR.

  47. in src/qt/test/wallettests.cpp:187 in 1eddc3afc0 outdated
    183@@ -184,7 +184,8 @@ void TestSendCoins()
    184     BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, false /* cancel */);
    185     BumpFee(transactionView, txid2, true /* expect disabled */, "already bumped" /* expected error */, false /* cancel */);
    186 
    187-    bitdb.Flush(true);
    188+    bitdb.Flush("wallet_test.dat");
    


    ryanofsky commented at 6:17 pm on December 20, 2017:

    In commit “call CDBEnv.shutdown() from FlushWallets”

    Maybe could use dbw->GetName() instead of repeating wallet_test.dat here

  48. in src/wallet/db.cpp:673 in 1eddc3afc0 outdated
    580+    LogPrint(BCLog::DB, "CDBEnv::Flush: Flush%s\n", fDbEnvInit ? "" : " database not started");
    581     if (!fDbEnvInit)
    582         return;
    583     {
    584         LOCK(cs_db);
    585         std::map<std::string, int>::iterator mi = mapFileUseCount.begin();
    


    ryanofsky commented at 6:22 pm on December 20, 2017:

    In commit “call CDBEnv.shutdown() from FlushWallets”

    Could change this line to: mi = mapFileUseCount.find(strFile), and change the while to an if on the line below to skip unnecessary loop.

  49. in src/wallet/init.cpp:240 in 1eddc3afc0 outdated
    239 
    240 void StopWallets() {
    241-    for (CWalletRef pwallet : vpwallets) {
    242-        pwallet->Flush(true);
    243-    }
    244+    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) return;
    


    ryanofsky commented at 6:23 pm on December 20, 2017:

    In commit “call CDBEnv.shutdown() from FlushWallets”

    Is this line doing anything? Should add comment explaining

  50. in src/wallet/db.cpp:565 in 3919301a5d outdated
    559@@ -560,6 +560,16 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip)
    560     }
    561 }
    562 
    563+void CDBEnv::Shutdown()
    564+{
    565+    char** listp;
    


    ryanofsky commented at 6:28 pm on December 20, 2017:

    In commit “add CDBEnv::Shutdown() function”

    I think this method should start with if (!fDbEnvInit) return; similar to the Flush method so shutdown code can be simple for callers (no need for -disablewallet check).


    ryanofsky commented at 6:31 pm on December 20, 2017:

    In commit “add CDBEnv::Shutdown() function”

    Maybe AssertLockHeld(cs_db)

  51. in src/wallet/wallet.cpp:3763 in b3f0973d92 outdated
    3760+bool CWallet::VerifyWallet(std::string walletFile, bool salvage_wallet, std::string& strError)
    3761 {
    3762     if (boost::filesystem::path(walletFile).filename() != walletFile) {
    3763-        return InitError(strprintf(_("Error loading wallet %s. wallet parameter must only specify a filename (not a path)."), walletFile));
    3764+        strError = strprintf(_("Error loading wallet %s. wallet parameter must only specify a filename (not a path)."), walletFile);
    3765+        return InitError(strError);
    


    ryanofsky commented at 6:39 pm on December 20, 2017:
    It might be better to drop thee InitError calls here and let callers VerifyWallet callers invoke it. Otherwise calls to open wallets via RPC could trigger GUI message boxes and maybe hang.
  52. ryanofsky commented at 7:49 pm on December 20, 2017: member

    Maybe mark work in progress due to unresolved locking issues.

    It’s not clear to me that exclusively locking cs_wallets is really that much worse than current behavior, since most current RPCs seem to acquire locks for a long time and effectively be single threaded. But it would be good to avoid this.

    It might be straightforward to fix by making vpwallets hold shared pointers, and by releasing the cs_wallets lock except when accessing vpwallets. I don’t think there is any need for strong_ptrs because there should be no reason to care what threads wallets are closed on.

    Using a shared lock as a substitute for shared pointers seems a little kludgy to me since it would just be speeding up overbroad cs_wallets locks instead of removing them, and would it would still block operations on unrelated wallets when any wallet was being opened or closed.

    Verify and Flush refactoring commits in this PR seem like they might be useful changes on their own, and could maybe be pulled out into separate PRs to simplify this one.

  53. jnewbery renamed this:
    [wallet] dynamic loading/unloading of wallets
    [WIP] [wallet] dynamic loading/unloading of wallets
    on Dec 20, 2017
  54. wtogami commented at 9:03 am on December 30, 2017: contributor

    Needs rebase

    Should there be a separate RPC for creating a new wallet or should that be done using openwallet? (my initial thoughts are that there should be a separate RPC)

    I suggest there should be a new RPC command to create new wallets. Aside from least surprise, there is more than one type of wallet that the user could want created.

  55. jonasschnelli commented at 7:22 am on January 4, 2018: contributor
    Needs rebase and issues (@ryanofsky) addressed.
  56. laanwj removed this from the milestone 0.16.0 on Jan 11, 2018
  57. laanwj added this to the milestone 0.17.0 on Jan 11, 2018
  58. laanwj removed this from the "Blockers" column in a project

  59. achow101 commented at 4:13 am on February 14, 2018: member
    Closing the wallet that is in use by qt (the one at vpwallets[0] will result in a crash. So additional handling for Qt stuff is needed.
  60. jnewbery commented at 8:15 pm on April 10, 2018: member

    I plan to pick this up again in the next few days. it requires:

  61. Sjors commented at 10:40 am on April 11, 2018: member

    considering how this interacts with multiwallet in the GUI

    A good enough first step would be if the dropdowns update when wallets are loaded / unloaded through the console. Adding UI to load and unload wallets can be a followup PR.

  62. jnewbery commented at 9:28 pm on April 12, 2018: member

    This was discussed in the IRC meeting today: https://botbot.me/freenode/bitcoin-core-dev/2018-04-12/?msg=98919702&page=5

     015:26 < wumpus> #topic dynamic wallet load/unload (promag)
     115:26 < Randolf> Ack.
     215:26 < promag> not sure what you guys think
     315:26 < instagibbs_> what's the controversy in this topic :)
     415:27 < jonasschnelli> [#10740](/bitcoin-bitcoin/10740/)
     515:27 < sipa> it should happen, duh
     615:27 < gribble> [#10740](/bitcoin-bitcoin/10740/) | [WIP] [wallet] dynamic loading/unloading of wallets by jnewbery · Pull Request [#10740](/bitcoin-bitcoin/10740/) · bitcoin/bitcoin · GitHub
     715:27 < wumpus> seems like something we want to have at some point...
     815:27 < promag> but I think luke agrees that wallet management should be with shared pointers
     915:27 < sipa> how and when is another :)
    1015:27 < luke-jr> indeed, using names just asks for chaos with runtime-changing wallets
    1115:28 < promag> please read [#11402](/bitcoin-bitcoin/11402/) for some reasons to switch
    1215:28 < gribble> [#11402](/bitcoin-bitcoin/11402/) | Use shared pointer for wallet instances by promag · Pull Request [#11402](/bitcoin-bitcoin/11402/) · bitcoin/bitcoin · GitHub
    1315:28 < jonasschnelli> IMO 10740 can't create wallets, IMO first step would be to add a createwallet RPC call
    1415:29 < jonasschnelli> the whole creation/configuration setup if flawed since multiwallet
    1515:29 < jonasschnelli> stuff like -keypool should be per wallet
    1615:29 < jnewbery> jonasschnelli: you think createwallet should go in *before* load/unload?
    1715:29 < jonasschnelli> and persisted in the wallet file (as configuration section)
    1815:29 < jonasschnelli> jnewbery: not sure,.. just thinking
    1915:30 < jnewbery> seems reasonable to me
    2015:30 < jonasschnelli> createwallet could also *not* load the wallet in the first step (not ideal, but maybe reduces complexity)
    2115:30 < sipa> that seems strange... you could create a new wallet at run time but not use it?
    2215:30 < jonasschnelli> sipa: createwallet could also directly load/use the wallet
    2315:30 < jnewbery> I think createwallet would also load the new wallet, no?
    2415:30 < promag> create implies loading
    2515:30 < luke-jr> sipa: iow, 0 to 1 only.
    2615:31 < sipa> jonasschnelli: well then you need to have loading functionality first!
    2715:31 < sipa> and if you have it, why not expose it
    2815:31 < jonasschnelli> sipa: yes. That's a point.
    2915:31 < jnewbery> createwallet could also be done by bitcoin-wallet-tool
    3015:32 < jnewbery> (#8745)
    3115:32 < gribble> [#8745](/bitcoin-bitcoin/8745/) | [PoC] Add wallet inspection and modification tool "bitcoin-wallet-tool" by jonasschnelli · Pull Request [#8745](/bitcoin-bitcoin/8745/) · bitcoin/bitcoin · GitHub
    3215:32 < jonasschnelli> Yes. Would be possible...
    3315:32 < jonasschnelli> I just think the create-during-startup approach is not good
    3415:33 < promag> also related [#10973](/bitcoin-bitcoin/10973/)
    3515:33 < jnewbery> jonasschnelli: I agree
    3615:33 < gribble> [#10973](/bitcoin-bitcoin/10973/) | Refactor: separate wallet from node by ryanofsky · Pull Request [#10973](/bitcoin-bitcoin/10973/) · bitcoin/bitcoin · GitHub
    3715:33 < sipa> jonasschnelli: agree
    3815:33 < jonasschnelli> And as a first step I though createwallet would make sense.. but not loading it seems after a strange use-case
    3915:33 < luke-jr> load -> create -> unload
    4015:33 < jonasschnelli> but a nice first code/impl. step
    4115:33 < luke-jr> unload is the complex part tbh
    4215:33 < jnewbery> luke-jr: agree
    4315:34 < jonasschnelli> Agree with luke-jr. Maybe split unload away from the existing PR jnewbery ?
    4415:34 < jnewbery> yes
    4515:34 < jnewbery> I intend to pick up 10740 again soon, rebase and rework it
    4615:34 < promag> consider the use case: 1) rpc rescan wallet 2) in parallel unload wallet - should 2) wait for 1) ?
    4715:34 < luke-jr> probably
    4815:35 < jonasschnelli> Great. Dynamic loading/creating is a nice feature that we probably want for 0.17!
    4915:35 < promag> luke-jr: and if the unload is from the UI?
    5015:35 < jnewbery> promag: do you consider 11402 a prereq for load/unload? What about just load?
    5115:36 < jonasschnelli> the wallet-tool is IMO orthogonal to wallet creation
    5215:36 < jonasschnelli> *via RPC
    5315:36 < luke-jr> promag: probably the same
    5415:36 < promag> jnewbery: IMHO for both
    5515:36 < jonasschnelli> RPC seems to be a must, wallet-tool can be a better place to create some sorts of wallets (or inspect it), .. like encrypted wallets
    5615:36 < luke-jr> promag: at least initially
    5715:37 < jnewbery> promag: want to rebase and put on high priority for review then, if you consider it a blocker?
    5815:37 < promag> luke-jr: my point is that it should not block, you request the unload and go on, when the wallet is not used anymore it gets unloaded
    5915:38 < jonasschnelli> [#11402](/bitcoin-bitcoin/11402/)
    6015:38 < gribble> [#11402](/bitcoin-bitcoin/11402/) | Use shared pointer for wallet instances by promag · Pull Request [#11402](/bitcoin-bitcoin/11402/) · bitcoin/bitcoin · GitHub
    6115:38 < luke-jr> promag: you mean leave the wallet loaded, but invisible? that seems worst outcome IMO
    6215:38 < luke-jr> user may unload and just shut off the PC
    6315:38 < wumpus> the unload should probably be in two stages: after requesting it, RPC and the GUI lose access to it. Then it waits for current operations tofinish. Then the thing really gets delted.
    6415:38 < luke-jr> yes
    6515:38 < promag> luke-jr: then the application will wait for wallets to unload
    6615:38 < jnewbery> I don't think we need to worry about unload at this stage. First step is add load functionality, then createwallet functionality
    6715:38 < luke-jr> and make it visible to the user in the meantime
    6815:39 < luke-jr> jnewbery: +1
    6915:39 < promag> wumpus: right, hence shared pointers
    

    I should reduce the scope of this PR to just a loadwallet RPC. A createwallet RPC should come next, followed by unloadwallet. (unloadwallet is where most of the difficulties are).

  63. jnewbery renamed this:
    [WIP] [wallet] dynamic loading/unloading of wallets
    [WIP] [wallet] `loadwallet` RPC - load wallet at runtime
    on Apr 18, 2018
  64. jnewbery commented at 9:03 pm on April 18, 2018: member

    Updated PR text since this PR is now only for loading wallets (not creating or unloading).

    Original text also had the following motivation:

    Main motivation for this was the fact that several wallet parameters are actions for individual wallet load/creation, rather than properties of the wallet component. Examples are -salvagewallet, -rescan, -usehd and -upgradewallet. Continuing with that config/loading model is difficult in a multi-wallet world - how can users run those actions on individual wallets when loading multiple wallets? This PR offers a solution: individual wallets can be loaded at run-time, and RPC parameters can be passed in to carry out the various wallet-loading actions. Note that none of those load actions are yet implemented in this PR, but can easily be added.

  65. jnewbery force-pushed on Apr 18, 2018
  66. jnewbery commented at 9:06 pm on April 18, 2018: member

    Overhauled this PR to just contain the loadwallet functionality.

    It is built on @promag’s PR #13017. Please review that first.

    This also needs the cs_wallets locking functionality from #11402 to be thread-safe.

    I’ll rebase once those PRs are merged. I’ve pushed the branch now in case anyone wants to do early review.

  67. promag commented at 9:11 pm on April 18, 2018: member
    @jnewbery Nice. BTW I was thinking creating a different PR to just make #13017 thread safe.
  68. jnewbery commented at 9:13 pm on April 18, 2018: member

    I was thinking creating a different PR to just make #13017 thread safe.

    Great. I’ll keep an eye out and rebase on top of that when it’s ready.

  69. in src/wallet/rpcwallet.cpp:2910 in d667f8b82e outdated
    2905+    if (!wallet) {
    2906+        throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed.");
    2907+    }
    2908+    AddWallet(wallet);
    2909+
    2910+    wallet->ReacceptWalletTransactions();
    


    promag commented at 0:12 am on April 19, 2018:
    Should call CWallet::postInitProcess instead? Otherwise MaybeCompactWalletDB is not called if the daemon is launched without wallets.
  70. jnewbery renamed this:
    [WIP] [wallet] `loadwallet` RPC - load wallet at runtime
    [wallet] `loadwallet` RPC - load wallet at runtime
    on Apr 19, 2018
  71. jnewbery force-pushed on Apr 19, 2018
  72. jnewbery commented at 9:54 pm on April 19, 2018: member

    Thanks for the review @promag - I’ve done as you suggested and called CWallet::postInitProcess(). Because rpc doesn’t have the CScheduler reference when loading the wallet, I had to change the WalletInit::Start() function to always schedule background wallet flushes, even when started with no wallets (ie -nowallet). Note that when started with -disablewallet, the entire wallet module is disabled and it’s not possible to load wallets later.

    I’ve also rebased on [#13028 rebased on master].

    Removed the [WIP] tag since I think this implementation is now complete and ready for review.

  73. in src/wallet/wallet.h:748 in 1faccae15d outdated
    744@@ -747,6 +745,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
    745     const CBlockIndex* m_last_block_processed = nullptr;
    746 
    747 public:
    748+    static std::atomic<bool> fFlushScheduled;
    


    promag commented at 0:56 am on April 20, 2018:
    Remove.

    jnewbery commented at 3:22 pm on April 20, 2018:
    done
  74. in src/wallet/init.cpp:242 in 1faccae15d outdated
    324@@ -324,7 +325,12 @@ bool WalletInit::Open() const
    325 void WalletInit::Start(CScheduler& scheduler) const
    326 {
    327     for (CWallet* pwallet : GetWallets()) {
    328-        pwallet->postInitProcess(scheduler);
    329+        pwallet->postInitProcess();
    


    promag commented at 0:58 am on April 20, 2018:

    Move CWallet::postInitProcess() content here:

    0for (CWallet* pwallet : GetWallets()) {
    1    // Add wallet transactions that aren't already in a block to mempool
    2    // Do this here as mempool requires genesis block to be loaded
    3    pwallet->ReacceptWalletTransactions();
    4}
    5..
    
  75. in src/wallet/init.cpp:332 in 1faccae15d outdated
    324@@ -324,7 +325,12 @@ bool WalletInit::Open() const
    325 void WalletInit::Start(CScheduler& scheduler) const
    326 {
    327     for (CWallet* pwallet : GetWallets()) {
    328-        pwallet->postInitProcess(scheduler);
    329+        pwallet->postInitProcess();
    330+    }
    331+
    332+    // Run a thread to flush wallet periodically
    333+    if (!CWallet::fFlushScheduled.exchange(true)) {
    


    promag commented at 1:03 am on April 20, 2018:
    WalletInitInterface::Start() is called only once, remove this check (and fFlushScheduled)?

    jnewbery commented at 3:22 pm on April 20, 2018:
    Yes - much better. Thanks!
  76. in src/wallet/wallet.h:1131 in 1faccae15d outdated
    1101@@ -1103,7 +1102,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
    1102      * Wallet post-init setup
    1103      * Gives the wallet a chance to register repetitive tasks and complete post-init tasks
    1104      */
    1105-    void postInitProcess(CScheduler& scheduler);
    1106+    void postInitProcess();
    


    promag commented at 1:05 am on April 20, 2018:
    Post-init doesn’t matter now that wallets are dynamically loaded. Remove?

    jnewbery commented at 3:24 pm on April 20, 2018:

    I’m going to leave this function here for now. It seems reasonable to have a postInitProcess() step for loading wallets, even if it is only doing one thing.

    This makes the diff smaller, and we can always remove postInitProcess() later if it really is unnecessary.

  77. promag commented at 1:09 am on April 20, 2018: member

    I had to change the WalletInit::Start() function to always schedule background wallet flushes

    Much better out of CWallet IMO.

  78. jonasschnelli commented at 11:51 am on April 23, 2018: contributor
    Needs rebase again.
  79. jnewbery force-pushed on Apr 23, 2018
  80. jnewbery commented at 4:44 pm on April 23, 2018: member
    Rebased on #13028
  81. in src/wallet/wallet.cpp:3972 in 422e3f9e24 outdated
    3968@@ -3968,6 +3969,64 @@ std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
    3969     return values;
    3970 }
    3971 
    3972+bool CWallet::Verify(std::string wallet_file, bool salvage_wallet)
    


    promag commented at 2:04 pm on April 24, 2018:
    Lock cs_wallets?

    promag commented at 2:04 pm on April 24, 2018:
    nit, const std::string& wallet_file.

    jnewbery commented at 6:25 pm on April 24, 2018:

    Lock cs_wallets?

    Done. How does this interact with your WalletManager work? Was the idea that cs_wallets was only held by WalletManager?


    jnewbery commented at 6:25 pm on April 24, 2018:

    nit, const std::string& wallet_file.

    Thanks - fixed


    promag commented at 7:07 pm on April 24, 2018:
    I was thinking moving CWallet::Verify to WalletManager or calling part of it from WalletManager. Let’s worry about that later.
  82. in src/wallet/rpcwallet.cpp:3035 in a5af75ca68 outdated
    2907+    }
    2908+    AddWallet(wallet);
    2909+
    2910+    wallet->postInitProcess();
    2911+
    2912+    UniValue obj(UniValue::VSTR);
    


    promag commented at 2:06 pm on April 24, 2018:

    Not object :trollface:

    Anyway, could return object instead?

    0{
    1    "name": ...
    2}
    

    jnewbery commented at 6:41 pm on April 24, 2018:
    yep - changed to return an object

    promag commented at 10:21 pm on May 3, 2018:
    Ops, this is not done.
  83. in src/wallet/rpcwallet.cpp:3039 in a5af75ca68 outdated
    2911+
    2912+    UniValue obj(UniValue::VSTR);
    2913+    obj = wallet_file;
    2914+
    2915+    return obj;
    2916+
    


    promag commented at 2:07 pm on April 24, 2018:
    nit, empty line.

    jnewbery commented at 6:41 pm on April 24, 2018:
    removed

    promag commented at 10:22 pm on May 3, 2018:
    Not removed.
  84. in test/functional/wallet_multiwallet.py:203 in db5d3f9c99 outdated
    159+
    160+        # Fail to load if wallet doesn't exist
    161+        assert_raises_rpc_error(-18, 'Wallet wallets not found.', self.nodes[0].loadwallet, 'wallets')
    162+
    163+        # Fail to load duplicate wallets
    164+        assert_raises_rpc_error(-4, 'Wallet file verification failed: Error loading wallet w1. Duplicate -wallet filename specified.', self.nodes[0].loadwallet, 'w1')
    


    promag commented at 2:15 pm on April 24, 2018:
    Use wallet_names[0] instead of 'w1'?

    jnewbery commented at 6:41 pm on April 24, 2018:
    yes, better. Changed
  85. promag commented at 2:17 pm on April 24, 2018: member
    Some comments after testing.
  86. jnewbery force-pushed on Apr 24, 2018
  87. jnewbery force-pushed on Apr 24, 2018
  88. jnewbery commented at 6:42 pm on April 24, 2018: member
    Rebased on master and addressed @promag’s comments.
  89. in test/functional/wallet_multiwallet.py:195 in 0569d2cd13 outdated
    169@@ -170,5 +170,24 @@ def run_test(self):
    170         assert_equal(w1.getwalletinfo()['paytxfee'], 0)
    171         assert_equal(w2.getwalletinfo()['paytxfee'], 4.0)
    172 
    173+        # dynamic wallet loading
    174+        self.restart_node(0, ['-nowallet'])
    175+        for wallet_name in wallet_names:
    176+            self.nodes[0].loadwallet(wallet_name)
    


    conscott commented at 11:31 am on April 25, 2018:

    If I add a line here to inspect the wallet after the load:

    0self.nodes[0].getwalletinfo()
    

    OR

    0self.nodes[0].getbalance()
    

    I get the json exception throw here after the second load operation. Is this expected behavior?


    jnewbery commented at 8:43 pm on April 25, 2018:
    Yes - if there are multiple wallets loaded, you need to send the RPC request to the correct wallet endpoint. Look at TestNode’s get_wallet_rpc() method.

    conscott commented at 6:18 am on April 27, 2018:

    Got it, thank you.

    As a nit, It might be useful just to verify you can call getbalance on the loaded wallet, just to show loaded wallets have expected behavior.


    jnewbery commented at 1:38 pm on April 27, 2018:
    Yes, good idea. I’ll update the test
  90. conscott commented at 6:20 am on April 27, 2018: contributor
    Test ACK 0569d2cd1324304ba2d78d1299454126c9d82b51 - just left a small test nit
  91. promag commented at 9:10 am on April 27, 2018: member
    @conscott thanks for the review, mind review #13028 too (this is rebased on that one)?
  92. laanwj referenced this in commit 783bb6455e on Apr 30, 2018
  93. jnewbery force-pushed on Apr 30, 2018
  94. jnewbery commented at 3:59 pm on April 30, 2018: member
    Updated test following @conscott’s suggestion and rebased on master to get #13028
  95. in doc/release-notes-pr10740.md:4 in 5423e5899a outdated
    0@@ -0,0 +1,6 @@
    1+Dynamic loading of wallets
    2+--------------------------
    3+
    4+Previously, wallets could only be loaded at startup, by specifying `-wallet` parameters on the command line or in the bitcoin.conf file. It is now possible to load wallets dynamically at runtime by calling the `loadwallet` RPC. The wallet file/directory must be located in the `walletdir` directory in order to be loaded.
    


    promag commented at 11:28 pm on April 30, 2018:

    The wallet file/directory must be located in the walletdir directory in order to be loaded.

    It works with external wallets (absolute path not related to -walletdir).


    jnewbery commented at 10:16 pm on May 2, 2018:
    Thanks promag. Release notes update. Please let me know what you think.
  96. promag commented at 3:07 pm on May 2, 2018: member

    Consider:

    0mkdir /tmp/ws
    1bitcoind -regtest -walletdir=/tmp/ws -wallet=w1 -wallet=w2
    2bitcoin-cli -regtest listwallets
    3[
    4  "w1",
    5  "w2"
    6]
    

    Then:

    0bitcoind -regtest -walletdir=/tmp/ws -wallet=w1
    1bitcoin-cli -regtest loadwallet /tmp/ws/w2
    2bitcoin-cli -regtest listwallets
    3[
    4  "w1",
    5  "/tmp/ws/w2"
    6]
    

    Also

    0bitcoind -regtest -walletdir=/tmp/ws -wallet=w1 -wallet=/tmp/ws/w2
    1bitcoin-cli -regtest listwallets
    2[
    3  "w1",
    4  "/tmp/ws/w2"
    5]
    

    Is this fine or should the outputs be the same? Should it be possible to specify an absolute path if it’s in the walletdir?

  97. jnewbery commented at 10:12 pm on May 2, 2018: member

    Is this fine or should the outputs be the same? Should it be possible to specify an absolute path if it’s in the walletdir?

    I think that question is orthogonal to this PR. As you’ve noted, this is pre-existing behaviour and is exhibited when specifying wallet names on the command line or .conf file. This behaviour was specified in the PR that introduced external wallet files (here: #11687 (review)).

    Can we save discussion on whether that’s the best behaviour for outside this PR?

  98. jnewbery force-pushed on May 2, 2018
  99. promag commented at 10:21 pm on May 2, 2018: member

    Release notes LGTM.

    Tested ACK a395059 (previously tested 2d67656).

    Can we save discussion on whether that’s the best behaviour for outside this PR?

    Absolutely!

  100. conscott commented at 9:11 am on May 3, 2018: contributor
    Tested Re-ACK a395059d4f576cc1b3b61ef78f2e01dec7758d3f
  101. jnewbery commented at 3:09 pm on May 3, 2018: member

    @promag , @conscott - thanks for the review!

    This could really do with some review from people with longer term wallet experience - nagging @TheBlueMatt @jonasschnelli @luke-jr @laanwj :slightly_smiling_face:

  102. laanwj added this to the "Blockers" column in a project

  103. jonasschnelli commented at 7:14 pm on May 3, 2018: contributor
    utACK a395059d4f576cc1b3b61ef78f2e01dec7758d3f
  104. in src/wallet/rpcwallet.cpp:3042 in a395059d4f outdated
    3037+
    3038+    return obj;
    3039+
    3040+}
    3041+
    3042+
    


    promag commented at 10:22 pm on May 3, 2018:
    Remove 2nd empty line.
  105. promag commented at 10:23 pm on May 3, 2018: member
    @jnewbery please check these missing changes.
  106. jnewbery force-pushed on May 4, 2018
  107. jnewbery commented at 2:35 pm on May 4, 2018: member

    Oops. Thanks @promag . I accidentally dropped those changes in one of my force-pushes. They should be fixed now.

    Thanks for keeping me honest!

  108. jnewbery force-pushed on May 4, 2018
  109. jnewbery force-pushed on May 4, 2018
  110. jnewbery commented at 9:51 pm on May 4, 2018: member
    rebased
  111. in src/wallet/rpcwallet.cpp:3035 in 122d0f0157 outdated
    3030+    AddWallet(wallet);
    3031+
    3032+    wallet->postInitProcess();
    3033+
    3034+    UniValue obj(UniValue::VOBJ);
    3035+    obj.pushKV("name", wallet_file);
    


    promag commented at 12:58 pm on May 7, 2018:
    nit, wallet->GetName() instead.

    jnewbery commented at 1:48 pm on May 7, 2018:
    Yes, good idea. Updated.
  112. promag commented at 1:01 pm on May 7, 2018: member
    Tested ACK 3d3e785.
  113. jnewbery force-pushed on May 7, 2018
  114. in src/wallet/rpcwallet.cpp:3024 in 56c8bd4e61 outdated
    3017+    if (fs::symlink_status(wallet_path).type() == fs::file_not_found) {
    3018+        throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + wallet_file + " not found.");
    3019+    }
    3020+
    3021+    std::string dummy_warning;
    3022+    if (!CWallet::Verify(wallet_file, false, error, dummy_warning)) {
    


    TheBlueMatt commented at 3:42 pm on May 7, 2018:
    This needs some kind of lock to avoid double-loading a wallet in two rpc threads at once.

    promag commented at 4:08 pm on May 7, 2018:
    Hmm @jnewbery this is missing #10740 (review).

    jnewbery commented at 9:14 pm on May 7, 2018:
    Re-added. Thanks @promag
  115. in src/wallet/rpcwallet.cpp:3002 in 56c8bd4e61 outdated
    2993@@ -2994,6 +2994,49 @@ static UniValue listwallets(const JSONRPCRequest& request)
    2994     return obj;
    2995 }
    2996 
    2997+UniValue loadwallet(const JSONRPCRequest& request)
    2998+{
    2999+    if (request.fHelp || request.params.size() != 1)
    3000+        throw std::runtime_error(
    3001+            "loadwallet \"filename\"\n"
    3002+            "\nLoads a wallet from a wallet file or directory.\n"
    


    TheBlueMatt commented at 3:45 pm on May 7, 2018:
    Maybe some help messages noting that certain config options still apply here - eg if you started with something like zapwallettxes, upgradewallet, rescan, etc it will take the same action for newly-loaded wallets here.

    jnewbery commented at 9:21 pm on May 7, 2018:
    Done
  116. TheBlueMatt commented at 3:47 pm on May 7, 2018: member
    Should probably fix the various memory leaks in CreateWalletFromFile first - we didnt really use to care cause it would just persist through operation, now we do.
  117. promag commented at 3:59 pm on May 7, 2018: member

    Should probably fix the various memory leaks in CreateWalletFromFile first - we didnt really use to care cause it would just persist through operation, now we do. @TheBlueMatt #13063 fixes that.

  118. TheBlueMatt commented at 4:04 pm on May 7, 2018: member

    #13063 seems overkill for this issue, we could just use a unique_ptr within CreateWalletFromFile.

    On May 7, 2018 3:59:40 PM UTC, “João Barbosa” notifications@github.com wrote:

    Should probably fix the various memory leaks in CreateWalletFromFile first - we didnt really use to care cause it would just persist through operation, now we do.

    @TheBlueMatt #13063 fixes that.

    – You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub: https://github.com/bitcoin/bitcoin/pull/10740#issuecomment-387113002

  119. promag commented at 4:16 pm on May 7, 2018: member
    @TheBlueMatt Then you mean #12647. Either way it’s something that can be fixed in another PR.
  120. TheBlueMatt commented at 4:43 pm on May 7, 2018: member
    @promag it can be fixed in another PR, but that would have to be merged before this one. Its really no big deal on master, but with an RPC that allows you to create arbitrary memory leaks, that’s not great…
  121. jnewbery commented at 9:15 pm on May 7, 2018: member

    Should probably fix the various memory leaks in CreateWalletFromFile first - we didnt really use to care cause it would just persist through operation, now we do.

    I’ve added the minimal fix from here: #12647 (review) to address the memory lead. @promag - that conflicts with your shared pointer PR, but it should be trivial for you to rebase that.

  122. jnewbery force-pushed on May 7, 2018
  123. in src/wallet/rpcwallet.cpp:3030 in fc45f748ca outdated
    3025+        throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error);
    3026+    }
    3027+
    3028+    CWallet * const wallet = CWallet::CreateWalletFromFile(wallet_file, fs::absolute(wallet_file, GetWalletDir()));
    3029+    if (!wallet) {
    3030+        throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed.");
    


    laanwj commented at 2:10 pm on May 9, 2018:
    “creation failed” is a confusing error message to give to the user here, “Wallet loading failed” would be more straightforward

    jnewbery commented at 2:45 pm on May 9, 2018:
    Agree. Changed
  124. in src/wallet/wallet.cpp:4007 in fc45f748ca outdated
    3963+    fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir());
    3964+    fs::file_type path_type = fs::symlink_status(wallet_path).type();
    3965+    if (!(path_type == fs::file_not_found || path_type == fs::directory_file ||
    3966+          (path_type == fs::symlink_file && fs::is_directory(wallet_path)) ||
    3967+          (path_type == fs::regular_file && fs::path(wallet_file).filename() == wallet_file))) {
    3968+        error_string = strprintf(
    


    laanwj commented at 2:12 pm on May 9, 2018:
    As these errors are reported over RPC, we should stop translating them; RPC errors should not depend on the locale.

    jnewbery commented at 2:52 pm on May 9, 2018:
    Yes - removed translation.
  125. in src/wallet/wallet.cpp:4026 in fc45f748ca outdated
    4022@@ -3973,7 +4023,8 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
    4023 
    4024     int64_t nStart = GetTimeMillis();
    4025     bool fFirstRun = true;
    4026-    CWallet *walletInstance = new CWallet(name, WalletDatabase::Create(path));
    4027+    auto wallet_deleter = MakeUnique<CWallet>(name, WalletDatabase::Create(path));
    


    laanwj commented at 2:14 pm on May 9, 2018:
    The name wallet_deleter scares me.

    jnewbery commented at 2:55 pm on May 9, 2018:
    is temp_wallet (with a comment above) less scary?

    laanwj commented at 5:31 pm on May 9, 2018:
    Yes, certainly. What I’d prefer, ideally, is to just call this wallet_instance and use this smart pointer everywhere instead of CWallet* walletInstance = temp_wallet.get(). But this is fine, it’s no longer scary.

    jnewbery commented at 7:16 pm on May 9, 2018:
    ok, I’ll change it if I need to update the branch for another reason.
  126. laanwj commented at 2:15 pm on May 9, 2018: member
    Looks overall good to me. Some small comments.
  127. jnewbery force-pushed on May 9, 2018
  128. laanwj commented at 5:32 pm on May 9, 2018: member
    utACK 5ef858bfed2438746db0ba096ff3c98755603cb8
  129. in src/wallet/wallet.cpp:4016 in dffe989059 outdated
    3971+              "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)"),
    3972+            wallet_file, GetWalletDir()));
    3973+    }
    3974+
    3975+    // Make sure that the wallet path doesn't clash with an existing wallet path
    3976+    std::set<fs::path> wallet_paths;
    


    jimpo commented at 9:07 pm on May 9, 2018:

    commit: [wallet] Add CWallet::Verify function

    Using a set here is unnecessary, can just do a direct equality check.


    jnewbery commented at 2:15 pm on May 15, 2018:
    Yes, much better idea.
  130. in src/wallet/rpcwallet.cpp:3023 in b2f8378e2a outdated
    3018+    fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir());
    3019+    if (fs::symlink_status(wallet_path).type() == fs::file_not_found) {
    3020+        throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + wallet_file + " not found.");
    3021+    }
    3022+
    3023+    std::string dummy_warning;
    


    jimpo commented at 9:20 pm on May 9, 2018:

    commit: [wallet] [rpc] Add loadwallet RPC

    Feels like this warning should get logged or maybe even returned in a “warning” field in the JSON response.


    jnewbery commented at 4:56 pm on May 15, 2018:
    ok, added to the JSON response.
  131. in src/wallet/wallet.cpp:4147 in f8c81def4f outdated
    4143@@ -4141,7 +4144,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
    4144     }
    4145 
    4146     walletInstance->m_last_block_processed = chainActive.Tip();
    4147-    RegisterValidationInterface(walletInstance);
    4148+    RegisterValidationInterface(temp_wallet.release());
    


    jimpo commented at 9:35 pm on May 9, 2018:

    commit: [wallet] Fix potential memory leak in CreateWalletFromFile

    This isn’t a complete fix because there are still early returns with errors in the rescan logic below. I believe it is safe to move the RegisterValidationInterface call to the bottom of the function as I argued in #12647 because cs_main gets locked on line 4135.


    ryanofsky commented at 5:43 pm on May 15, 2018:

    This isn’t a complete fix because there are still early returns with errors in the rescan logic below. I believe it is safe to move the RegisterValidationInterface call to the bottom of the function as I argued in #12647 because cs_main gets locked on line 4135.

    jimpo’s right, f8c81def4f5f88074348890a613c1006824b1b5d [wallet] Fix potential memory leak in CreateWalletFromFile isn’t currently a complete fix for all memory leaks. Also, his suggestion to move RegisterValidationInterface and fix more leaks should be ok because of the cs_main lock. If you want to make that change, I would just add a comment above the RegisterValidationInterface call that says, “it is safe to register for notifications after rescanning (no notifications will be missed) because cs_main is held during the entire scan.” Only downside to this change is that if in the future we do optimize the rescan to not hold cs_main the entire time, it could introduce a bug where notifications are missed after the rescan completes.

    Other options:

    • Just drop this commit and deal with memory leaks in a separate PR.
    • Just add a comment above the temp_wallet.release() call in this commit noting that walletInstance will be leaked if there is an error and the code below returns nullptr.
    • Get rid of temp_wallet, and make walletInstance a unique ptr. Return walletInstance.release() on the last line of this function. Add UnregisterValidationInterface(walletInstance.get()) calls below where nullptr is returned.

    jnewbery commented at 5:45 pm on May 15, 2018:
    Done (and added comment)
  132. laanwj commented at 5:37 am on May 14, 2018: member
    This seems very near ready for merge except for @jimpo’s nits.
  133. [wallet] Fix potential memory leak in CreateWalletFromFile
    Fix proposed by ryanofsky in
    https://github.com/bitcoin/bitcoin/pull/12647#discussion_r174875670
    59b87a27ef
  134. [wallet] setup wallet background flushing in WalletInit directly
    WalletInit::Start calls postInitProcess() for each wallet. Previously
    each call to postInitProcess() would attempt to schedule wallet
    background flushing.
    
    Just start wallet background flushing once from WalletInit::Start().
    470316c3bf
  135. jnewbery force-pushed on May 15, 2018
  136. jnewbery commented at 5:46 pm on May 15, 2018: member
    Rebased and addressed @jimpo’s comments
  137. in src/wallet/wallet.cpp:4022 in 155f47dad2 outdated
    4017+        if (fs::absolute(wallet->GetName(), GetWalletDir()) == wallet_path) {
    4018+            return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file));
    4019+        }
    4020+    }
    4021+
    4022+    if (!wallet_paths.insert(wallet_path).second) {
    


    jimpo commented at 7:40 pm on May 15, 2018:

    [wallet] Add CWallet::Verify function

    Can drop this and the declaration of wallet_paths above.


    promag commented at 12:04 pm on May 16, 2018:
    True, no longer necessary.

    jnewbery commented at 4:07 pm on May 16, 2018:
    Thanks @jimpo. Fixed
  138. jimpo commented at 7:40 pm on May 15, 2018: contributor
    Sorry, one more thing then I’ll ACK.
  139. [wallet] Add CWallet::Verify function
    This allows a single wallet to be verified. Prior to this commit, all
    wallets were verified together by the WalletInit::Verify() function at
    start-up.
    
    Individual wallet verification will be done when loading wallets
    dynamically at runtime.
    e0e90db07b
  140. [wallet] Pass error message back from CWallet::Verify()
    Pass an error message back from CWallet::Verify(), and call
    InitError/InitWarning from WalletInit::Verify().
    
    This means that we can call CWallet::Verify() independently from
    WalletInit and not have InitErrors printed to stdout. It also means that
    the error can be reported to the user if dynamic wallet load fails.
    876eb64680
  141. [wallet] [rpc] Add loadwallet RPC
    The new `loadwallet` RPC method allows an existing wallet to be loaded
    dynamically at runtime.
    
    `unloadwallet` and `createwallet` are not implemented. Notably,
    `loadwallet` can only be used to load existing wallets, not to create a
    new wallet.
    5d152601e9
  142. [wallet] [tests] Test loadwallet
    Add testcases to wallet_multiwallet.py to test the new `loadwallet` RPC
    method.
    a46aeb6901
  143. [docs] Add release notes for `loadwallet` RPC. cd53981b3d
  144. jnewbery force-pushed on May 16, 2018
  145. jimpo commented at 6:36 pm on May 16, 2018: contributor
    ACK cd53981
  146. laanwj merged this on May 16, 2018
  147. laanwj closed this on May 16, 2018

  148. laanwj referenced this in commit 4cfe17c338 on May 16, 2018
  149. jnewbery deleted the branch on May 16, 2018
  150. laanwj removed this from the "Blockers" column in a project

  151. fanquake moved this from the "In progress" to the "Done" column in a project

  152. PastaPastaPasta referenced this in commit 358c4db77a on Dec 22, 2019
  153. PastaPastaPasta referenced this in commit 6c4c334350 on Jan 2, 2020
  154. PastaPastaPasta referenced this in commit 54e52012c2 on Jan 4, 2020
  155. PastaPastaPasta referenced this in commit 02e1fecfbd on Jan 4, 2020
  156. PastaPastaPasta referenced this in commit 6ef89566e0 on Jan 10, 2020
  157. PastaPastaPasta referenced this in commit 25d98e2bdd on Jan 10, 2020
  158. PastaPastaPasta referenced this in commit 99ccb6ebdd on Jan 10, 2020
  159. PastaPastaPasta referenced this in commit f6f455db81 on Jan 12, 2020
  160. PastaPastaPasta referenced this in commit a3386a3fda on Apr 14, 2020
  161. PastaPastaPasta referenced this in commit 96dc3027bf on Apr 14, 2020
  162. PastaPastaPasta referenced this in commit 3333dee99c on Apr 14, 2020
  163. PastaPastaPasta referenced this in commit 10182d0444 on Apr 14, 2020
  164. PastaPastaPasta referenced this in commit e4b122fbf7 on Apr 14, 2020
  165. PastaPastaPasta referenced this in commit 44159fe3cf on Apr 15, 2020
  166. PastaPastaPasta referenced this in commit a5c5c591d2 on Apr 15, 2020
  167. PastaPastaPasta referenced this in commit 5d02fa540e on Apr 15, 2020
  168. PastaPastaPasta referenced this in commit bdf4fb3cfc on Apr 15, 2020
  169. PastaPastaPasta referenced this in commit d9706ddeb5 on Apr 15, 2020
  170. PastaPastaPasta referenced this in commit ee0f3f2592 on Apr 15, 2020
  171. PastaPastaPasta referenced this in commit 93248e49d4 on Apr 15, 2020
  172. PastaPastaPasta referenced this in commit 494bb74077 on Apr 15, 2020
  173. PastaPastaPasta referenced this in commit 95af923340 on Apr 15, 2020
  174. PastaPastaPasta referenced this in commit 41c3831fb9 on Apr 15, 2020
  175. PastaPastaPasta referenced this in commit 918f0978cb on Apr 15, 2020
  176. PastaPastaPasta referenced this in commit c0c46932d5 on Apr 15, 2020
  177. PastaPastaPasta referenced this in commit a7f55b3442 on Apr 15, 2020
  178. PastaPastaPasta referenced this in commit a762ac80f5 on Apr 15, 2020
  179. PastaPastaPasta referenced this in commit 37954f4062 on Apr 15, 2020
  180. PastaPastaPasta referenced this in commit 79e49511b1 on Apr 15, 2020
  181. PastaPastaPasta referenced this in commit 91cd6c3510 on Apr 15, 2020
  182. PastaPastaPasta referenced this in commit af06fb5cd6 on Apr 16, 2020
  183. PastaPastaPasta referenced this in commit 63d6252ca7 on Apr 16, 2020
  184. PastaPastaPasta referenced this in commit 5f7934ed52 on Apr 16, 2020
  185. PastaPastaPasta referenced this in commit 1217f87cb7 on Apr 16, 2020
  186. PastaPastaPasta referenced this in commit 7657f30980 on Apr 16, 2020
  187. PastaPastaPasta referenced this in commit 0a31408dec on Apr 16, 2020
  188. PastaPastaPasta referenced this in commit 2d8a3d1295 on Apr 26, 2020
  189. PastaPastaPasta referenced this in commit ab7fecc81e on Apr 26, 2020
  190. PastaPastaPasta referenced this in commit b512b8922d on Apr 26, 2020
  191. PastaPastaPasta referenced this in commit 35fa9feec2 on May 10, 2020
  192. PastaPastaPasta referenced this in commit fcde41dda2 on May 10, 2020
  193. PastaPastaPasta referenced this in commit 41460518df on May 10, 2020
  194. PastaPastaPasta referenced this in commit 84af55906c on May 10, 2020
  195. PastaPastaPasta referenced this in commit 3d73de3381 on May 10, 2020
  196. PastaPastaPasta referenced this in commit 53670a2b9f on May 10, 2020
  197. PastaPastaPasta referenced this in commit 8ebbdfe805 on May 10, 2020
  198. ckti referenced this in commit 1bc9245138 on Mar 28, 2021
  199. ckti referenced this in commit ea688a5fbd on Mar 28, 2021
  200. ckti referenced this in commit 40977a0c5e on Mar 28, 2021
  201. gades referenced this in commit 4d034dc8cd on Jun 30, 2021
  202. MarcoFalke locked this on Sep 8, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-07-03 10:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me