Skip to content
New issue

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

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable Automatic Wallet Backup #306

Merged
merged 14 commits into from
Apr 13, 2015
Merged
94 changes: 78 additions & 16 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ using namespace boost;
#ifdef ENABLE_WALLET
std::string strWalletFile;
CWallet* pwalletMain;
int nWalletBackups = 10;
#endif

#ifdef WIN32
Expand Down Expand Up @@ -273,21 +274,22 @@ std::string HelpMessage(HelpMessageMode hmm)

#ifdef ENABLE_WALLET
strUsage += "\n" + _("Wallet options:") + "\n";
strUsage += " -disablewallet " + _("Do not load the wallet and disable wallet RPC calls") + "\n";
strUsage += " -keepass " + _("Use KeePass 2 integration using KeePassHttp plugin (default: 0)") + "\n";
strUsage += " -keepassport=<port> " + _("Connect to KeePassHttp on port <port> (default: 19455)") + "\n";
strUsage += " -keepasskey=<key> " + _("KeePassHttp key for AES encrypted communication with KeePass") + "\n";
strUsage += " -keepassid=<name> " + _("KeePassHttp id for the established association") + "\n";
strUsage += " -keepassname=<name> " + _("Name to construct url for KeePass entry that stores the wallet passphrase") + "\n";
strUsage += " -keypool=<n> " + _("Set key pool size to <n> (default: 1000)") + "\n";
strUsage += " -paytxfee=<amt> " + _("Fee per kB to add to transactions you send") + "\n";
strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + " " + _("on startup") + "\n";
strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup") + "\n";
strUsage += " -spendzeroconfchange " + _("Spend unconfirmed change when sending transactions (default: 1)") + "\n";
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + " " + _("on startup") + "\n";
strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + " " + _("(default: wallet.dat)") + "\n";
strUsage += " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n";
strUsage += " -zapwallettxes " + _("Clear list of wallet transactions (diagnostic tool; implies -rescan)") + "\n";
strUsage += " -createwalletbackups=<n> " + _("Number of automatic wallet backups (default: 10)") + "\n";
strUsage += " -disablewallet " + _("Do not load the wallet and disable wallet RPC calls") + "\n";
strUsage += " -keepass " + _("Use KeePass 2 integration using KeePassHttp plugin (default: 0)") + "\n";
strUsage += " -keepassport=<port> " + _("Connect to KeePassHttp on port <port> (default: 19455)") + "\n";
strUsage += " -keepasskey=<key> " + _("KeePassHttp key for AES encrypted communication with KeePass") + "\n";
strUsage += " -keepassid=<name> " + _("KeePassHttp id for the established association") + "\n";
strUsage += " -keepassname=<name> " + _("Name to construct url for KeePass entry that stores the wallet passphrase") + "\n";
strUsage += " -keypool=<n> " + _("Set key pool size to <n> (default: 1000)") + "\n";
strUsage += " -paytxfee=<amt> " + _("Fee per kB to add to transactions you send") + "\n";
strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + " " + _("on startup") + "\n";
strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup") + "\n";
strUsage += " -spendzeroconfchange " + _("Spend unconfirmed change when sending transactions (default: 1)") + "\n";
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + " " + _("on startup") + "\n";
strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + " " + _("(default: wallet.dat)") + "\n";
strUsage += " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n";
strUsage += " -zapwallettxes " + _("Clear list of wallet transactions (diagnostic tool; implies -rescan)") + "\n";
#endif

strUsage += "\n" + _("Debugging/Testing options:") + "\n";
Expand Down Expand Up @@ -711,9 +713,69 @@ bool AppInit2(boost::thread_group& threadGroup)

int64_t nStart;

// ********************************************************* Step 5: verify wallet database integrity
// ********************************************************* Step 5: Backup wallet and verify wallet database integrity
#ifdef ENABLE_WALLET
if (!fDisableWallet) {

filesystem::path backupDir = GetDataDir() / "backups";
if (!filesystem::exists(backupDir))
{
// Always create backup folder to not confuse the operating system's file browser
filesystem::create_directories(backupDir);
}
nWalletBackups = GetArg("-createwalletbackups", 10);
nWalletBackups = std::max(0, std::min(10, nWalletBackups));
if(nWalletBackups > 0)
{
if (filesystem::exists(backupDir))
{
// Create backup of the wallet
std::string dateTimeStr = DateTimeStrFormat(".%Y-%m-%d-%H.%M", GetTime());
std::string backupPathStr = backupDir.string();
backupPathStr += "/" + strWalletFile;
std::string sourcePathStr = GetDataDir().string();
sourcePathStr += "/" + strWalletFile;
boost::filesystem::path sourceFile = sourcePathStr;
boost::filesystem::path backupFile = backupPathStr + dateTimeStr;
sourceFile.make_preferred();
backupFile.make_preferred();
try {
boost::filesystem::copy_file(sourceFile, backupFile);
LogPrintf("Creating backup of %s -> %s\n", sourceFile, backupFile);
} catch(boost::filesystem::filesystem_error &error) {
LogPrintf("Failed to create backup %s\n", error.what());
}
// Keep only the last 10 backups, including the new one of course
typedef std::multimap<std::time_t, boost::filesystem::path> folder_set_t;
folder_set_t folder_set;
boost::filesystem::directory_iterator end_iter;
boost::filesystem::path backupFolder = backupDir.string();
backupFolder.make_preferred();
// Build map of backup files sorted by last write time
for (boost::filesystem::directory_iterator dir_iter(backupFolder); dir_iter != end_iter; ++dir_iter)
{
if ( boost::filesystem::is_regular_file(dir_iter->status()))
folder_set.insert(folder_set_t::value_type(boost::filesystem::last_write_time(dir_iter->path()), *dir_iter));
}
// Loop backward through backup files and keep the 10 newest ones
int counter = 0;
BOOST_REVERSE_FOREACH(PAIRTYPE(const std::time_t, boost::filesystem::path) file, folder_set)
{
counter++;
if (counter > nWalletBackups)
{
// More than nWalletBackups backups: delete oldest one(s)
try {
boost::filesystem::remove(file.second);
LogPrintf("Old backup deleted: %s\n", file.second);
} catch(boost::filesystem::filesystem_error &error) {
LogPrintf("Failed to delete backup %s\n", error.what());
}
}
}
}
}

LogPrintf("Using wallet %s\n", strWalletFile);
uiInterface.InitMessage(_("Verifying wallet..."));

Expand Down
Empty file modified src/init.h
100644 → 100755
Empty file.
3 changes: 2 additions & 1 deletion src/qt/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ RES_ICONS = \
res/icons/drkblue_editpaste.png \
res/icons/drkblue_address-book.png \
res/icons/drkblue_editcopy.png \
res/icons/drkblue_remove.png
res/icons/drkblue_remove.png \
res/icons/browse.png


BITCOIN_QT_CPP = \
Expand Down
5 changes: 5 additions & 0 deletions src/qt/bitcoingui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(showConsole()));
connect(openNetworkAction, SIGNAL(triggered()), rpcConsole, SLOT(showNetwork()));
connect(openConfEditorAction, SIGNAL(triggered()), rpcConsole, SLOT(showConfEditor()));
connect(showBackupsAction, SIGNAL(triggered()), rpcConsole, SLOT(showBackups()));


// prevents an oben debug window from becoming stuck/unusable on client shutdown
Expand Down Expand Up @@ -330,6 +331,8 @@ void BitcoinGUI::createActions(bool fIsTestnet)
openNetworkAction->setStatusTip(tr("Show network monitor"));
openConfEditorAction = new QAction(QIcon(":/icons/edit"), tr("Open &Configuration File"), this);
openConfEditorAction->setStatusTip(tr("Open configuration file"));
showBackupsAction = new QAction(QIcon(":/icons/browse"), tr("Show Automatic &Backups"), this);
showBackupsAction->setStatusTip(tr("Show automatically created wallet backups"));

usedSendingAddressesAction = new QAction(QIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
Expand Down Expand Up @@ -408,6 +411,7 @@ void BitcoinGUI::createMenuBar()
tools->addAction(openRPCConsoleAction);
tools->addAction(openNetworkAction);
tools->addAction(openConfEditorAction);
tools->addAction(showBackupsAction);
}

QMenu *help = appMenuBar->addMenu(tr("&Help"));
Expand Down Expand Up @@ -570,6 +574,7 @@ void BitcoinGUI::createTrayIconMenu()
trayIconMenu->addAction(openRPCConsoleAction);
trayIconMenu->addAction(openNetworkAction);
trayIconMenu->addAction(openConfEditorAction);
trayIconMenu->addAction(showBackupsAction);
#ifndef Q_OS_MAC // This is built-in on Mac
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
Expand Down
1 change: 1 addition & 0 deletions src/qt/bitcoingui.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class BitcoinGUI : public QMainWindow
QAction *openRPCConsoleAction;
QAction *openNetworkAction;
QAction *openConfEditorAction;
QAction *showBackupsAction;
QAction *openAction;
QAction *showHelpMessageAction;

Expand Down
1 change: 1 addition & 0 deletions src/qt/dash.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
<file alias="drkblue_address-book">res/icons/drkblue_address-book.png</file>
<file alias="drkblue_editcopy">res/icons/drkblue_editcopy.png</file>
<file alias="drkblue_remove">res/icons/drkblue_remove.png</file>
<file alias="browse">res/icons/browse.png</file>
</qresource>
<qresource prefix="/css">
<file alias="drkblue">res/css/drkblue.css</file>
Expand Down
9 changes: 9 additions & 0 deletions src/qt/guiutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,15 @@ void openConfigfile()
QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig)));
}

void showBackups()
{
boost::filesystem::path pathBackups = GetDataDir() / "backups";

/* Open folder with default browser */
if (boost::filesystem::exists(pathBackups))
QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathBackups)));
}

ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent) :
QObject(parent), size_threshold(size_threshold)
{
Expand Down
3 changes: 3 additions & 0 deletions src/qt/guiutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ namespace GUIUtil

// Open dash.conf
void openConfigfile();

// Browse backup folder
void showBackups();

/** Qt event filter that intercepts ToolTipChange events, and replaces the tooltip with a rich text
representation if needed. This assures that Qt can word-wrap long tooltip messages.
Expand Down
Binary file added src/qt/res/icons/browse.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/qt/rpcconsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,3 +524,8 @@ void RPCConsole::showConfEditor()
{
GUIUtil::openConfigfile();
}

void RPCConsole::showBackups()
{
GUIUtil::showBackups();
}
2 changes: 2 additions & 0 deletions src/qt/rpcconsole.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public slots:
void showNetwork();
/** Open external (default) editor with dash.conf */
void showConfEditor();
/** Show folder with wallet backups in default browser */
void showBackups();

signals:
// For RPC command executor
Expand Down