[backups] Automatic backups basics #5266

pull jonasschnelli wants to merge 2 commits into bitcoin:master from jonasschnelli:walletbackup changing 6 files +266 −53
  1. jonasschnelli commented at 8:28 PM on November 12, 2014: contributor
    • allow to do automatic backups when keypool gets refilled
    • by default backups are turned off
    • by default only encrypted wallets are allowed for backup (configurable)

    This could be the basic for later adding backup possibilities for Bitcoin-Qt including visual elements for latest and amount of backups as also validity-check-display of backup files.

  2. sipa commented at 8:41 PM on November 12, 2014: member

    Would it be possible to use the dumpwallet RPC output instead, it's much easier to parse and likely to remain usable in more software longer. On the downside, it's not natively encrypted.

  3. jonasschnelli force-pushed on Nov 12, 2014
  4. jonasschnelli commented at 8:51 PM on November 12, 2014: contributor

    @sipa hmm... it would be more open to other wallets. correct. On the other hand; how easy would it be for endusers to restore a backup? I think there is no easy way to import a RPC dumped wallet. IMO, endusers should just have <n> valid file(s) where they can restore. But a reasonable question is, how users could load a bitcoin-core wallet into other wallet-apps. But this might be out of scope for the backup-process because it affects also the non-backup wallet.dat.

  5. sipa commented at 8:54 PM on November 12, 2014: member

    Yes there is a way to import it, using importwallet.

  6. jonasschnelli commented at 9:01 PM on November 12, 2014: contributor

    @sipa: ah. right. Somebody should update https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_calls_list :) But the enduser then could not just restore the wallet.dat file... or we could detect if the wallet.dat is RPC dumped file and import it straight. I would prefer to have a restore possibility on file level.

  7. sipa commented at 9:04 PM on November 12, 2014: member

    @jonasschnelli the GUI has no way to restore a backup at all - whether it's done using backupwallet or dumpwallet. That definitely needs fixing, but I would really advise against using the BDB-based format for anything but legacy.

  8. jonasschnelli commented at 9:33 PM on November 12, 2014: contributor

    @sipa i just thought through the whole thing again. Your right. Restore per file won't work anyway without rescan everything. I'll change it to use RPC walletdumped format. Enduser with limited IT understanding should import it through the Qt client (where i will focus on as soon as the basic things are sorted out).

  9. jonasschnelli commented at 7:28 AM on November 13, 2014: contributor

    @sipa i only see a huge drawback when using the walletdumps-txt: encryption. Unencrypted wallet dumps is IMO very risky. Of course we could encrypt the dumps before the go to the filesystem. But this lead to the question what passphrase/key we use for encrypting the backups dumps. Maybe adding a "backup-key" to the wallet would be a overhead? Any ideas how we could solve that in a nice way?

  10. jonasschnelli force-pushed on Nov 13, 2014
  11. laanwj commented at 9:52 AM on November 13, 2014: member

    Good point about dumpwallet format not being encrypted. We should definitely support that.

    For example Schildback's Bitcoin Wallet uses a format similar to our dumpwallet format, one line per key, but encrypts the file before writing. This can be decrypted from the command line using openssl enc -d -aes-256-cbc -a -in (see https://github.com/schildbach/bitcoin-wallet/blob/master/wallet/README.recover ), or of course imported back into the application.

    As for the key, would be multiple options there:

    • Encrypt the file with the same key as used for the wallet (easy for the user, but not very secure)
    • Ask the user for a password every time backing up, and add a "password" parameter to the dumpwallet RPC call (easiest to implement, most transparent to the user)
    • As you say, store a "backup key" in the settings
  12. laanwj added this to the milestone 0.11.0 on Nov 13, 2014
  13. jonasschnelli force-pushed on Nov 13, 2014
  14. jonasschnelli force-pushed on Nov 13, 2014
  15. jonasschnelli commented at 3:34 PM on November 13, 2014: contributor

    I think we should encrypt the dumps with a key derived from the same password the wallet is encrypted.

    Additional to that, for experience users, we could allow to set a base64 encoded EC PubKey in the bitcoinconf. The dumps then could be encrypted aes-256-cbc creating a random key with EVP_Seal. The encrypted key length and data will be stored in the dump. With that, experience users could do encrypted backups with keeping their backup key secret.

  16. jonasschnelli force-pushed on Nov 13, 2014
  17. gmaxwell commented at 11:03 PM on November 13, 2014: contributor

    Please don't introduce yet another encryption format in the system if it can all be avoided, analyizing and maintaining two is additional work I'd rather avoid. The simpler thing is to just backup the existing files, then we're sure to get all the data, sure that it's already encrypted and not creating additional exposure, etc.

  18. jonasschnelli commented at 7:53 AM on November 14, 2014: contributor

    @gmaxwell agreed. Than i keep the pull request as it is. For now we backup just the wallet.dat. Dumping is IMO not a backup because it lacks of metadata (dump != backup). A backup should be somehow a 1:1 copy. If a user enables -backupsdumps AND -backupsallowunencrypted he can do unencrypted dumps as backups.

    Before working on encrypted dumps as backup possibilities i would prefer to implement the/a backup mechanism in the GUI.

  19. in src/wallet.cpp:None in 9f39fc0503 outdated
    2301 | +    }
    2302 | +    mapKeyBirth.clear();
    2303 | +    std::sort(vKeyBirth.begin(), vKeyBirth.end());
    2304 | +
    2305 | +    // produce output
    2306 | +    stream << strprintf("# Wallet dump created by Bitcoin %s (%s)\n", CLIENT_BUILD, CLIENT_DATE);
    


    Diapolo commented at 9:03 AM on November 14, 2014:

    By "Bitcoin Core" :)?

  20. in src/walletdb.cpp:None in 9f39fc0503 outdated
      17 | +
      18 |  #include <boost/filesystem.hpp>
      19 |  #include <boost/foreach.hpp>
      20 |  #include <boost/scoped_ptr.hpp>
      21 |  #include <boost/thread.hpp>
      22 | +#include <boost/algorithm/string.hpp>
    


    Diapolo commented at 9:04 AM on November 14, 2014:

    You were missing a few months here, so this will be my only nit for you ;). Can you please try to use alphabetical ordering for such includes (see e.g. most other files). This belongs to the top of the boost includes.

  21. in src/walletdb.cpp:None in 9f39fc0503 outdated
     892 | @@ -889,6 +893,157 @@ bool BackupWallet(const CWallet& wallet, const string& strDest)
     893 |      return false;
     894 |  }
     895 |  
     896 | +std::map<std::time_t, filesystem::path> CWalletDB::GetAvailableBackups()
     897 | +{
     898 | +    filesystem::path backupDir;
     899 | +    std::string strBackupsDir   = GetArg("-backupspath", "");
    


    Diapolo commented at 9:06 AM on November 14, 2014:

    IMHO the default path could be set as the second parameter here and directly converted to a boost::path perhaps? That could remove the if-else below.


    jonasschnelli commented at 1:00 PM on November 14, 2014:

    hmm.. the GetDataDir() (which must be part of the default backup path) returns a boost::filesystem::path instance which is not compatible with GetArg's default argument. Converting the GetDataDir into a std::string first would probably end up in the same "mess". Or do you see a other solution?

  22. in src/walletdb.cpp:None in 9f39fc0503 outdated
     911 | +            return backupFiles;
     912 | +        
     913 | +        filesystem::directory_iterator it(backupDir), eod;
     914 | +        BOOST_FOREACH(filesystem::path const &p, std::make_pair(it, eod))
     915 | +        {
     916 | +            if(is_regular_file(p) && (ends_with(p.string(), BACKUP_BDB_EXTENSION) || ends_with(p.string(), BACKUP_DUMP_EXTENSION)))
    


    Diapolo commented at 9:07 AM on November 14, 2014:

    Nit: Some comments in the code would be nice.

  23. in src/walletdb.cpp:None in 9f39fc0503 outdated
     917 | +                backupFiles.insert(std::pair<std::time_t, filesystem::path>(filesystem::last_write_time( p ), p));
     918 | +        }
     919 | +    }
     920 | +    catch(const filesystem::filesystem_error &e) {
     921 | +        LogPrintf("error retrieving available backups (%s)\n", e.what());
     922 | +        return backupFiles;
    


    Diapolo commented at 9:08 AM on November 14, 2014:

    Is this return needed or will we reach the function end after the catch anyway?


    jonasschnelli commented at 1:07 PM on November 14, 2014:

    I would say it's needed. When calling GetAvailableBackups you then can expect a empty hash-map even when there was a error.

  24. jonasschnelli commented at 1:08 PM on November 14, 2014: contributor

    @Diapolo okay, did overhaul the code, added some comments, etc. You might check it again.

  25. in src/init.cpp:None in 167fc953dd outdated
     372 | +    
     373 | +#ifdef ENABLE_WALLET
     374 | +    strUsage += "\n" + _("Backup options:") + "\n";
     375 | +    strUsage += "  -backups                                 " + strprintf(_("Enable auto creation of UNENCRYPTED backups (dumps) (default: %u)"), DEFAULT_BACKUPS_ENABLED) + "\n";
     376 | +    strUsage += "  -backupsallowunencrypted                 " + strprintf(_("Allow backups of unencrypted wallets (default: %u)"), DEFAULT_ALLOW_UNENCRYPTED_BACKUPS) + "\n";
     377 | +    strUsage += "  -backupspath=<dir>                       " + strprintf(_("Specify absolut path to backups directory (default: %s)"), strprintf("<datadir>/%s", DEFAULT_BACKUPS_DIR)) + "\n";
    


    luke-jr commented at 1:10 PM on November 14, 2014:

    "absolute"

  26. in src/init.cpp:None in 167fc953dd outdated
     367 | @@ -368,7 +368,16 @@ std::string HelpMessage(HelpMessageMode mode)
     368 |      strUsage += "  -rpcsslcertificatechainfile=<file.cert>  " + strprintf(_("Server certificate file (default: %s)"), "server.cert") + "\n";
     369 |      strUsage += "  -rpcsslprivatekeyfile=<file.pem>         " + strprintf(_("Server private key (default: %s)"), "server.pem") + "\n";
     370 |      strUsage += "  -rpcsslciphers=<ciphers>                 " + strprintf(_("Acceptable ciphers (default: %s)"), "TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH") + "\n";
     371 | -
     372 | +    
     373 | +#ifdef ENABLE_WALLET
     374 | +    strUsage += "\n" + _("Backup options:") + "\n";
     375 | +    strUsage += "  -backups                                 " + strprintf(_("Enable auto creation of UNENCRYPTED backups (dumps) (default: %u)"), DEFAULT_BACKUPS_ENABLED) + "\n";
     376 | +    strUsage += "  -backupsallowunencrypted                 " + strprintf(_("Allow backups of unencrypted wallets (default: %u)"), DEFAULT_ALLOW_UNENCRYPTED_BACKUPS) + "\n";
    


    luke-jr commented at 1:10 PM on November 14, 2014:

    So I need to specify two options to enable backups (assuming an unencrypted wallet)? Why?


    jonasschnelli commented at 1:20 PM on November 14, 2014:

    I've started it very restrained. Maybe once the -backup feature could be enabled by default. I think enabling two options for making unencrypted backups is okay because it's somehow bad practice.

  27. jonasschnelli force-pushed on Nov 14, 2014
  28. jonasschnelli commented at 9:05 PM on December 16, 2014: contributor

    Any NACKs ACKs? I would like to extend this to the GUI.

  29. laanwj commented at 10:59 AM on December 17, 2014: member

    @jonasschnelli Concept ACK, haven't looked at the code. I promise I will, but right now I cannot keep up with the number of pulls anymore.

  30. laanwj added the label GUI on Jan 8, 2015
  31. sipa removed the label GUI on Jan 9, 2015
  32. jonasschnelli force-pushed on Mar 5, 2015
  33. jonasschnelli commented at 8:07 AM on March 5, 2015: contributor

    rebased

  34. jonasschnelli force-pushed on Mar 5, 2015
  35. jonasschnelli force-pushed on Mar 5, 2015
  36. [backups] Automatic backups basics
    - allow to do automatic backups (wallet.dat copy or dumps) when keypool gets refilled
    - by default backups are turned off
    - by default only encrypted wallets are allowed for backup
    - user can choose to backup dumps instead of the wallet.dat file
    1023f86626
  37. [backups] some code cleaning and comments c5d5e40c19
  38. jonasschnelli force-pushed on Mar 12, 2015
  39. jonasschnelli commented at 1:11 PM on March 12, 2015: contributor

    rebased.

  40. laanwj added the label Wallet on Mar 27, 2015
  41. jonasschnelli commented at 8:59 AM on April 16, 2015: contributor

    I'm no longer convinced that this PRs solution is going into the right direction. As example: what means a encrypted wallet? Why are metadata like labels and comments (which could harm privacy) not encrypted in a encrypted wallet? How would this perform after there is support for Bip32?

  42. gmaxwell commented at 12:09 PM on April 16, 2015: contributor

    @jonasschnelli Things other than private keys are not encrypted because otherwise the user is forced to enter their key at every startup or use, which is inconvenient and would punish users for using encryption and would leave their key more vulnerable to observation by malware or people around them. The entry of the key also becomes an important consent point: a user of an encrypted wallet can never accidentally send money no matter how stupidly they click or how far they explore.

    Encryption of a wallet is not usually adequate for privacy on your local computer in any case: your logs, browser cache, etc all leak much of the same data... When we talk about backups the situation is somewhat different, and I can agree it may make sense to have all the data encrypted there. If I were to do it again I would have an master key encrypted with the hardened user passphrase used to derive separate keys for encrypting the whole wallet and the private keys. At the first use, I'd cache the whole wallet subkey (but not the private key one) in a separate file. This way backups would preserve privacy, so long as they didn't backup the cache.

    BIP32 is not at all a replacement for backups; at most it protects key material. It does nothing to preserve metadata which can be absolutely critical (keeping in mind that in much of the developed world if your taxes are audited its up to you to prove you were paying what you owed). I somewhat regret inventing the public derivation thats most commonly used now-- it's overused, and in ways that harm security (often by people who do not understand the implications).

  43. laanwj removed this from the milestone 0.11.0 on May 18, 2015
  44. jgarzik commented at 6:36 PM on July 23, 2015: contributor

    Closing for this older PR. It sounds like there is general agreement that something like this is a good direction, but it's doesn't seem to be coalescing into a specific solution that is liked.

    My own criticism: I don't think this low level functionality is needed at all for non-GUI daemon. It can be implemented with a simple, external cron script that applies well to the local site.

    Suggestions:

    • Add such a script to contrib/
    • Directly implement a GUI-specific, user-friendly backup method in the GUI. Don't try to match bitcoind and GUI backup behaviors, as the two sets of users can be quite different. Do what makes sense for the GUI.
  45. jgarzik closed this on Jul 23, 2015

  46. jonasschnelli commented at 6:41 PM on July 23, 2015: contributor

    Agree with @jgarzik in general. What made me stop woking on this: as long as an "encrypted wallet" contains unencrypted sensitive data (like transactions [unencrypted], labels [unencrypted] and wtx comments [unencrypted]) it is to risky to auto-backup a wallet. Users might start to think they can store the backup in a insecure space (like dropbox, etc.) because they are assuming the backup is encrypted (which is a false assumption, only the private keys are encrypted).

  47. 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: 2026-04-21 15:15 UTC

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