Page MenuHomePhabricator

D8596.id26174.diff
No OneTemporary

D8596.id26174.diff

diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -20,6 +20,7 @@
load.cpp
rpcdump.cpp
rpcwallet.cpp
+ salvage.cpp
scriptpubkeyman.cpp
wallet.cpp
walletdb.cpp
diff --git a/src/wallet/db.h b/src/wallet/db.h
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -411,10 +411,4 @@
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);
-
#endif // BITCOIN_WALLET_DB_H
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -338,145 +338,6 @@
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<uint8_t>, std::vector<uint8_t>> 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) {
- // Skip past header
- getline(strDump, strLine);
- }
-
- 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 = std::make_unique<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/salvage.h b/src/wallet/salvage.h
new file mode 100644
--- /dev/null
+++ b/src/wallet/salvage.h
@@ -0,0 +1,23 @@
+// 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/salvage.cpp b/src/wallet/salvage.cpp
new file mode 100644
--- /dev/null
+++ b/src/wallet/salvage.cpp
@@ -0,0 +1,170 @@
+// 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<uint8_t>, std::vector<uint8_t>> 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 = std::make_unique<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/walletdb.h b/src/wallet/walletdb.h
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -55,6 +55,38 @@
NEED_REWRITE
};
+namespace DBKeys {
+extern const std::string ACENTRY;
+extern const std::string ACTIVEEXTERNALSPK;
+extern const std::string ACTIVEINTERNALSPK;
+extern const std::string BESTBLOCK;
+extern const std::string BESTBLOCK_NOMERKLE;
+extern const std::string CRYPTED_KEY;
+extern const std::string CSCRIPT;
+extern const std::string DEFAULTKEY;
+extern const std::string DESTDATA;
+extern const std::string FLAGS;
+extern const std::string HDCHAIN;
+extern const std::string KEY;
+extern const std::string KEYMETA;
+extern const std::string MASTER_KEY;
+extern const std::string MINVERSION;
+extern const std::string NAME;
+extern const std::string OLD_KEY;
+extern const std::string ORDERPOSNEXT;
+extern const std::string POOL;
+extern const std::string PURPOSE;
+extern const std::string SETTINGS;
+extern const std::string TX;
+extern const std::string VERSION;
+extern const std::string WALLETDESCRIPTOR;
+extern const std::string WALLETDESCRIPTORCACHE;
+extern const std::string WALLETDESCRIPTORCKEY;
+extern const std::string WALLETDESCRIPTORKEY;
+extern const std::string WATCHMETA;
+extern const std::string WATCHS;
+} // namespace DBKeys
+
/* simple HD chain data model */
class CHDChain {
public:
@@ -279,9 +311,4 @@
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/walletdb.cpp b/src/wallet/walletdb.cpp
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -965,28 +965,6 @@
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/wallettool.cpp b/src/wallet/wallettool.cpp
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -6,6 +6,7 @@
#include <fs.h>
#include <util/system.h>
#include <util/translation.h>
+#include <wallet/salvage.h>
#include <wallet/wallet.h>
#include <wallet/walletutil.h>

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 26, 11:50 (2 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5573455
Default Alt Text
D8596.id26174.diff (16 KB)

Event Timeline