void CWalletDB::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) { bool fAllAccounts = (strAccount == "*"); Dbc* pcursor = batch.GetCursor(); if (!pcursor) throw std::runtime_error(std::string(__func__) + ": cannot create DB cursor"); bool setRange = true; while (true) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (setRange) ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? std::string("") : strAccount), uint64_t(0))); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange); setRange = false; if (ret == DB_NOTFOUND) break; else if (ret != 0) { pcursor->close(); throw std::runtime_error(std::string(__func__) + ": error scanning DB"); } // Unserialize std::string strType; ssKey >> strType; if (strType != "acentry") break; CAccountingEntry acentry; ssKey >> acentry.strAccount; if (!fAllAccounts && acentry.strAccount != strAccount) break; ssValue >> acentry; ssKey >> acentry.nEntryNo; entries.push_back(acentry); } pcursor->close(); }
bool CSyncDataDb::LoadCheckPoint(std::map<int, uint256>& values) { bool ret = false; if (m_dbPoint) { leveldb::Iterator *pcursor = m_dbPoint->NewIterator(); CDataStream ssKeySet(SER_DISK, CLIENT_VERSION); ssKeySet << std::make_pair('c', 0); pcursor->Seek(ssKeySet.str()); while (pcursor->Valid()) { try { leveldb::Slice slKey = pcursor->key(); CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION); char chType = 0; int height = 0; ssKey >> chType; if (chType == 'c') { ssKey >> height; leveldb::Slice slValue = pcursor->value(); CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION); CSyncData data; ssValue >> data; CSyncCheckPoint point; point.SetData(data); values.insert(std::make_pair(height, point.m_hashCheckpoint)); pcursor->Next(); } else { break; } } catch (std::exception &e) { return error("%s : Deserialize or I/O error - %s", __PRETTY_FUNCTION__, e.what()); } }
bool BerkeleyBatch::Rewrite(BerkeleyDatabase& database, const char* pszSkip) { if (database.IsDummy()) { return true; } BerkeleyEnvironment *env = database.env; const std::string& strFile = database.strFile; while (true) { { LOCK(cs_db); if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0) { // Flush log data to the dat file env->CloseDb(strFile); env->CheckpointLSN(strFile); env->mapFileUseCount.erase(strFile); bool fSuccess = true; LogPrintf("BerkeleyBatch::Rewrite: Rewriting %s...\n", strFile); std::string strFileRes = strFile + ".rewrite"; { // surround usage of db with extra {} BerkeleyBatch db(database, "r"); std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(env->dbenv.get(), 0); int ret = pdbCopy->open(nullptr, // Txn pointer strFileRes.c_str(), // Filename "main", // Logical db name DB_BTREE, // Database type DB_CREATE, // Flags 0); if (ret > 0) { LogPrintf("BerkeleyBatch::Rewrite: Can't create database file %s\n", strFileRes); fSuccess = false; } Dbc* pcursor = db.GetCursor(); if (pcursor) while (fSuccess) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret1 = db.ReadAtCursor(pcursor, ssKey, ssValue); if (ret1 == DB_NOTFOUND) { pcursor->close(); break; } else if (ret1 != 0) { pcursor->close(); fSuccess = false; break; } if (pszSkip && strncmp(ssKey.data(), pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0) continue; if (strncmp(ssKey.data(), "\x07version", 8) == 0) { // Update version: ssValue.clear(); ssValue << CLIENT_VERSION; } Dbt datKey(ssKey.data(), ssKey.size()); Dbt datValue(ssValue.data(), ssValue.size()); int ret2 = pdbCopy->put(nullptr, &datKey, &datValue, DB_NOOVERWRITE); if (ret2 > 0) fSuccess = false; } if (fSuccess) { db.Close(); env->CloseDb(strFile); if (pdbCopy->close(0)) fSuccess = false; } else { pdbCopy->close(0); } } if (fSuccess) { Db dbA(env->dbenv.get(), 0); if (dbA.remove(strFile.c_str(), nullptr, 0)) fSuccess = false; Db dbB(env->dbenv.get(), 0); if (dbB.rename(strFileRes.c_str(), nullptr, strFile.c_str(), 0)) fSuccess = false; } if (!fSuccess) LogPrintf("BerkeleyBatch::Rewrite: Failed to rewrite database file %s\n", strFileRes); return fSuccess; } } MilliSleep(100); } }
bool BerkeleyBatch::Recover(const fs::path& file_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& newFilename) { std::string filename; 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; } std::vector<BerkeleyEnvironment::KeyValPair> salvagedData; bool fSuccess = env->Salvage(newFilename, true, salvagedData); 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 (BerkeleyEnvironment::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 CDB::Rewrite(const std::string &strFile, const char *pszSkip) { while (true) { { LOCK(bitdb.cs_db); if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) { // Flush log data to the dat file bitdb.CloseDb(strFile); bitdb.CheckpointLSN(strFile); bitdb.mapFileUseCount.erase(strFile); bool fSuccess = true; LogPrintf("CDB::Rewrite: Rewriting %s...\n", strFile); std::string strFileRes = strFile + ".rewrite"; { // surround usage of db with extra {} CDB db(strFile.c_str(), "r"); Db *pdbCopy = new Db(bitdb.dbenv, 0); int ret = pdbCopy->open(NULL, // Txn pointer strFileRes.c_str(), // Filename "main", // Logical db name DB_BTREE, // Database type DB_CREATE, // Flags 0); if (ret > 0) { LogPrintf("CDB::Rewrite: Can't create database file %s\n", strFileRes); pdbCopy->close(0); fSuccess = false; } Dbc *pcursor = db.GetCursor(); if (pcursor) { while (fSuccess) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret1 = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT); if (ret1 == DB_NOTFOUND) { pcursor->close(); break; } else if (ret1 != 0) { pcursor->close(); fSuccess = false; break; } if (pszSkip && strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0) continue; if (strncmp(&ssKey[0], "\x07version", 8) == 0) { // Update version: ssValue.clear(); ssValue << CLIENT_VERSION; } Dbt datKey(&ssKey[0], ssKey.size()); Dbt datValue(&ssValue[0], ssValue.size()); int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE); if (ret2 > 0) fSuccess = false; } } if (fSuccess) { db.Close(); bitdb.CloseDb(strFile); if (pdbCopy->close(0)) { fSuccess = false; } else { pdbCopy->close(0); } delete pdbCopy; } } if (fSuccess) { Db dbA(bitdb.dbenv, 0); if (dbA.remove(strFile.c_str(), NULL, 0)) fSuccess = false; Db dbB(bitdb.dbenv, 0); if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) fSuccess = false; } if (!fSuccess) LogPrintf("CDB::Rewrite: Failed to rewrite database file %s\n", strFileRes); return fSuccess; } } MilliSleep(100); } return false; }
/* * Look at all the records and parse keys for addresses and private keys */ bool WalletUtilityDB::parseKeys(bool dumppriv, std::string masterPass) { DBErrors result = DB_LOAD_OK; std::string strType; bool first = true; try { Dbc* pcursor = GetCursor(); if (!pcursor) { LogPrintf("Error getting wallet database cursor\n"); result = DB_CORRUPT; } if (dumppriv) { while (result == DB_LOAD_OK && true) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int result = ReadAtCursor(pcursor, ssKey, ssValue); if (result == DB_NOTFOUND) { break; } else if (result != 0) { LogPrintf("Error reading next record from wallet database\n"); result = DB_CORRUPT; break; } ssKey >> strType; if (strType == "mkey") { updateMasterKeys(ssKey, ssValue); } } pcursor->close(); pcursor = GetCursor(); } while (result == DB_LOAD_OK && true) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue); if (ret == DB_NOTFOUND) { std::cout << " ]" << std::endl; first = true; break; } else if (ret != DB_LOAD_OK) { LogPrintf("Error reading next record from wallet database\n"); result = DB_CORRUPT; break; } ssKey >> strType; if (strType == "key" || strType == "ckey") { std::string strAddr = getAddress(ssKey); std::string strKey = ""; if (dumppriv && strType == "key") strKey = getKey(ssKey, ssValue); if (dumppriv && strType == "ckey") { if (masterPass == "") { std::cout << "Encrypted wallet, please provide a password. See help below" << std::endl; show_help(); result = DB_LOAD_FAIL; break; } strKey = getCryptedKey(ssKey, ssValue, masterPass); } if (strAddr != "") { if (first) std::cout << "[ "; else std::cout << ", "; } if (dumppriv) { std::cout << "{\"addr\" : \"" + strAddr + "\", " << "\"pkey\" : \"" + strKey + "\"}" << std::flush; } else { std::cout << "\"" + strAddr + "\""; } first = false; } } pcursor->close(); } catch (DbException &e) { std::cout << "DBException caught " << e.get_errno() << std::endl; } catch (std::exception &e) { std::cout << "Exception caught " << std::endl; } if (result == DB_LOAD_OK) return true; else return false; }