aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/wallet/db.cpp128
-rw-r--r--src/wallet/db.h2
-rw-r--r--src/wallet/salvage.cpp160
-rw-r--r--src/wallet/salvage.h17
-rw-r--r--src/wallet/walletdb.cpp22
-rw-r--r--src/wallet/walletdb.h3
-rw-r--r--src/wallet/wallettool.cpp1
8 files changed, 180 insertions, 155 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 13812de0e7..0f562433de 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -243,6 +243,7 @@ BITCOIN_CORE_H = \
wallet/ismine.h \
wallet/load.h \
wallet/rpcwallet.h \
+ wallet/salvage.h \
wallet/scriptpubkeyman.h \
wallet/wallet.h \
wallet/walletdb.h \
@@ -351,6 +352,7 @@ libbitcoin_wallet_a_SOURCES = \
wallet/load.cpp \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
+ wallet/salvage.cpp \
wallet/scriptpubkeyman.cpp \
wallet/wallet.cpp \
wallet/walletdb.cpp \
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index cff83e3d01..4ed28b0623 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -317,134 +317,6 @@ BerkeleyBatch::SafeDbt::operator Dbt*()
return &m_dbt;
}
-/* End of headers, beginning of key/value data */
-static const char *HEADER_END = "HEADER=END";
-/* End of key/value data */
-static const char *DATA_END = "DATA=END";
-typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
-
-bool RecoverDatabaseFile(const fs::path& file_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& newFilename)
-{
- std::string filename;
- std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, filename);
-
- // Recovery procedure:
- // move wallet file to walletfilename.timestamp.bak
- // Call Salvage with fAggressive=true to
- // get as much data as possible.
- // Rewrite salvaged data to fresh wallet file
- // Set -rescan so any missing transactions will be
- // found.
- int64_t now = GetTime();
- newFilename = strprintf("%s.%d.bak", filename, now);
-
- int result = env->dbenv->dbrename(nullptr, filename.c_str(), nullptr,
- newFilename.c_str(), DB_AUTO_COMMIT);
- if (result == 0)
- LogPrintf("Renamed %s to %s\n", filename, newFilename);
- else
- {
- LogPrintf("Failed to rename %s to %s\n", filename, newFilename);
- return false;
- }
-
- /**
- * Salvage data from a file. The DB_AGGRESSIVE flag is being used (see berkeley DB->verify() method documentation).
- * key/value pairs are appended to salvagedData which are then written out to a new wallet file.
- * NOTE: reads the entire database into memory, so cannot be used
- * for huge databases.
- */
- std::vector<KeyValPair> salvagedData;
-
- std::stringstream strDump;
-
- Db db(env->dbenv.get(), 0);
- result = db.verify(newFilename.c_str(), nullptr, &strDump, DB_SALVAGE | DB_AGGRESSIVE);
- if (result == DB_VERIFY_BAD) {
- LogPrintf("Salvage: Database salvage found errors, all data may not be recoverable.\n");
- }
- if (result != 0 && result != DB_VERIFY_BAD) {
- LogPrintf("Salvage: Database salvage failed with result %d.\n", result);
- return false;
- }
-
- // Format of bdb dump is ascii lines:
- // header lines...
- // HEADER=END
- // hexadecimal key
- // hexadecimal value
- // ... repeated
- // DATA=END
-
- std::string strLine;
- while (!strDump.eof() && strLine != HEADER_END)
- getline(strDump, strLine); // Skip past header
-
- std::string keyHex, valueHex;
- while (!strDump.eof() && keyHex != DATA_END) {
- getline(strDump, keyHex);
- if (keyHex != DATA_END) {
- if (strDump.eof())
- break;
- getline(strDump, valueHex);
- if (valueHex == DATA_END) {
- LogPrintf("Salvage: WARNING: Number of keys in data does not match number of values.\n");
- break;
- }
- salvagedData.push_back(make_pair(ParseHex(keyHex), ParseHex(valueHex)));
- }
- }
-
- bool fSuccess;
- if (keyHex != DATA_END) {
- LogPrintf("Salvage: WARNING: Unexpected end of file while reading salvage output.\n");
- fSuccess = false;
- } else {
- fSuccess = (result == 0);
- }
-
- if (salvagedData.empty())
- {
- LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename);
- return false;
- }
- LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
-
- std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(env->dbenv.get(), 0);
- int ret = pdbCopy->open(nullptr, // Txn pointer
- filename.c_str(), // Filename
- "main", // Logical db name
- DB_BTREE, // Database type
- DB_CREATE, // Flags
- 0);
- if (ret > 0) {
- LogPrintf("Cannot create database file %s\n", filename);
- pdbCopy->close(0);
- return false;
- }
-
- DbTxn* ptxn = env->TxnBegin();
- for (KeyValPair& row : salvagedData)
- {
- if (recoverKVcallback)
- {
- CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
- CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
- if (!(*recoverKVcallback)(callbackDataIn, ssKey, ssValue))
- continue;
- }
- Dbt datKey(&row.first[0], row.first.size());
- Dbt datValue(&row.second[0], row.second.size());
- int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
- if (ret2 > 0)
- fSuccess = false;
- }
- ptxn->commit(0);
- pdbCopy->close(0);
-
- return fSuccess;
-}
-
bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, bilingual_str& errorStr)
{
std::string walletFile;
diff --git a/src/wallet/db.h b/src/wallet/db.h
index c802470045..54ce144ffc 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -389,8 +389,6 @@ public:
bool static Rewrite(BerkeleyDatabase& database, const char* pszSkip = nullptr);
};
-bool RecoverDatabaseFile(const fs::path& file_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
-
std::string BerkeleyDatabaseVersion();
#endif // BITCOIN_WALLET_DB_H
diff --git a/src/wallet/salvage.cpp b/src/wallet/salvage.cpp
new file mode 100644
index 0000000000..99d6238490
--- /dev/null
+++ b/src/wallet/salvage.cpp
@@ -0,0 +1,160 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <fs.h>
+#include <streams.h>
+#include <wallet/salvage.h>
+#include <wallet/wallet.h>
+#include <wallet/walletdb.h>
+
+/* End of headers, beginning of key/value data */
+static const char *HEADER_END = "HEADER=END";
+/* End of key/value data */
+static const char *DATA_END = "DATA=END";
+typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
+
+bool RecoverDatabaseFile(const fs::path& file_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& newFilename)
+{
+ std::string filename;
+ std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, filename);
+
+ // Recovery procedure:
+ // move wallet file to walletfilename.timestamp.bak
+ // Call Salvage with fAggressive=true to
+ // get as much data as possible.
+ // Rewrite salvaged data to fresh wallet file
+ // Set -rescan so any missing transactions will be
+ // found.
+ int64_t now = GetTime();
+ newFilename = strprintf("%s.%d.bak", filename, now);
+
+ int result = env->dbenv->dbrename(nullptr, filename.c_str(), nullptr,
+ newFilename.c_str(), DB_AUTO_COMMIT);
+ if (result == 0)
+ LogPrintf("Renamed %s to %s\n", filename, newFilename);
+ else
+ {
+ LogPrintf("Failed to rename %s to %s\n", filename, newFilename);
+ return false;
+ }
+
+ /**
+ * Salvage data from a file. The DB_AGGRESSIVE flag is being used (see berkeley DB->verify() method documentation).
+ * key/value pairs are appended to salvagedData which are then written out to a new wallet file.
+ * NOTE: reads the entire database into memory, so cannot be used
+ * for huge databases.
+ */
+ std::vector<KeyValPair> salvagedData;
+
+ std::stringstream strDump;
+
+ Db db(env->dbenv.get(), 0);
+ result = db.verify(newFilename.c_str(), nullptr, &strDump, DB_SALVAGE | DB_AGGRESSIVE);
+ if (result == DB_VERIFY_BAD) {
+ LogPrintf("Salvage: Database salvage found errors, all data may not be recoverable.\n");
+ }
+ if (result != 0 && result != DB_VERIFY_BAD) {
+ LogPrintf("Salvage: Database salvage failed with result %d.\n", result);
+ return false;
+ }
+
+ // Format of bdb dump is ascii lines:
+ // header lines...
+ // HEADER=END
+ // hexadecimal key
+ // hexadecimal value
+ // ... repeated
+ // DATA=END
+
+ std::string strLine;
+ while (!strDump.eof() && strLine != HEADER_END)
+ getline(strDump, strLine); // Skip past header
+
+ std::string keyHex, valueHex;
+ while (!strDump.eof() && keyHex != DATA_END) {
+ getline(strDump, keyHex);
+ if (keyHex != DATA_END) {
+ if (strDump.eof())
+ break;
+ getline(strDump, valueHex);
+ if (valueHex == DATA_END) {
+ LogPrintf("Salvage: WARNING: Number of keys in data does not match number of values.\n");
+ break;
+ }
+ salvagedData.push_back(make_pair(ParseHex(keyHex), ParseHex(valueHex)));
+ }
+ }
+
+ bool fSuccess;
+ if (keyHex != DATA_END) {
+ LogPrintf("Salvage: WARNING: Unexpected end of file while reading salvage output.\n");
+ fSuccess = false;
+ } else {
+ fSuccess = (result == 0);
+ }
+
+ if (salvagedData.empty())
+ {
+ LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename);
+ return false;
+ }
+ LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
+
+ std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(env->dbenv.get(), 0);
+ int ret = pdbCopy->open(nullptr, // Txn pointer
+ filename.c_str(), // Filename
+ "main", // Logical db name
+ DB_BTREE, // Database type
+ DB_CREATE, // Flags
+ 0);
+ if (ret > 0) {
+ LogPrintf("Cannot create database file %s\n", filename);
+ pdbCopy->close(0);
+ return false;
+ }
+
+ DbTxn* ptxn = env->TxnBegin();
+ for (KeyValPair& row : salvagedData)
+ {
+ if (recoverKVcallback)
+ {
+ CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
+ CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
+ if (!(*recoverKVcallback)(callbackDataIn, ssKey, ssValue))
+ continue;
+ }
+ Dbt datKey(&row.first[0], row.first.size());
+ Dbt datValue(&row.second[0], row.second.size());
+ int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
+ if (ret2 > 0)
+ fSuccess = false;
+ }
+ ptxn->commit(0);
+ pdbCopy->close(0);
+
+ return fSuccess;
+}
+
+bool RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue)
+{
+ CWallet *dummyWallet = reinterpret_cast<CWallet*>(callbackData);
+ std::string strType, strErr;
+ bool fReadOK;
+ {
+ // Required in LoadKeyMetadata():
+ LOCK(dummyWallet->cs_wallet);
+ fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue, strType, strErr);
+ }
+ if (!WalletBatch::IsKeyType(strType) && strType != DBKeys::HDCHAIN) {
+ return false;
+ }
+ if (!fReadOK)
+ {
+ LogPrintf("WARNING: WalletBatch::Recover skipping %s: %s\n", strType, strErr);
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/wallet/salvage.h b/src/wallet/salvage.h
new file mode 100644
index 0000000000..e501c54456
--- /dev/null
+++ b/src/wallet/salvage.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_WALLET_SALVAGE_H
+#define BITCOIN_WALLET_SALVAGE_H
+
+#include <fs.h>
+#include <streams.h>
+
+bool RecoverDatabaseFile(const fs::path& file_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
+
+/* Recover filter (used as callback), will only let keys (cryptographical keys) as KV/key-type pass through */
+bool RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue);
+
+#endif // BITCOIN_WALLET_SALVAGE_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 2a3daf59b4..32fc002660 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -885,28 +885,6 @@ void MaybeCompactWalletDB()
fOneThread = false;
}
-bool RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue)
-{
- CWallet *dummyWallet = reinterpret_cast<CWallet*>(callbackData);
- std::string strType, strErr;
- bool fReadOK;
- {
- // Required in LoadKeyMetadata():
- LOCK(dummyWallet->cs_wallet);
- fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue, strType, strErr);
- }
- if (!WalletBatch::IsKeyType(strType) && strType != DBKeys::HDCHAIN) {
- return false;
- }
- if (!fReadOK)
- {
- LogPrintf("WARNING: WalletBatch::Recover skipping %s: %s\n", strType, strErr);
- return false;
- }
-
- return true;
-}
-
bool WalletBatch::VerifyEnvironment(const fs::path& wallet_path, bilingual_str& errorStr)
{
return BerkeleyBatch::VerifyEnvironment(wallet_path, errorStr);
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 389b96189f..bcd1f9303d 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -291,7 +291,4 @@ void MaybeCompactWalletDB();
//! Unserialize a given Key-Value pair and load it into the wallet
bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr);
-/* Recover filter (used as callback), will only let keys (cryptographical keys) as KV/key-type pass through */
-bool RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue);
-
#endif // BITCOIN_WALLET_WALLETDB_H
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index 2b46eef0e0..ab5cf0061c 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -5,6 +5,7 @@
#include <fs.h>
#include <util/system.h>
#include <util/translation.h>
+#include <wallet/salvage.h>
#include <wallet/wallet.h>
#include <wallet/walletutil.h>