diff options
Diffstat (limited to 'src/db.cpp')
| -rw-r--r-- | src/db.cpp | 356 |
1 files changed, 353 insertions, 3 deletions
| @@ -164,6 +164,72 @@ bool WalletSQLiteRuntimeEraseRecord(const vector<unsigned char>& vchKey) | |||
| 164 | return pWalletSQLiteRuntime->EraseRecord(vchKey, strError); | 164 | return pWalletSQLiteRuntime->EraseRecord(vchKey, strError); |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | // Transaction bracket for the SQLite runtime. When the SQLite backend is not | ||
| 168 | // active these are no-ops that succeed, so a caller can wrap a group of related | ||
| 169 | // writes and Berkeley DB keeps its existing per-write behaviour unchanged while | ||
| 170 | // SQLite gets all-or-nothing. | ||
| 171 | bool WalletSQLiteRuntimeBeginTxn() | ||
| 172 | { | ||
| 173 | if (!pWalletSQLiteRuntime) | ||
| 174 | return true; | ||
| 175 | string strError; | ||
| 176 | if (pWalletSQLiteRuntime->BeginTransaction(strError)) | ||
| 177 | return true; | ||
| 178 | printf("WalletSQLiteRuntimeBeginTxn() : %s\n", strError.c_str()); | ||
| 179 | return false; | ||
| 180 | } | ||
| 181 | |||
| 182 | bool WalletSQLiteRuntimeCommitTxn() | ||
| 183 | { | ||
| 184 | if (!pWalletSQLiteRuntime) | ||
| 185 | return true; | ||
| 186 | string strError; | ||
| 187 | if (pWalletSQLiteRuntime->CommitTransaction(strError)) | ||
| 188 | return true; | ||
| 189 | printf("WalletSQLiteRuntimeCommitTxn() : %s\n", strError.c_str()); | ||
| 190 | return false; | ||
| 191 | } | ||
| 192 | |||
| 193 | void WalletSQLiteRuntimeRollbackTxn() | ||
| 194 | { | ||
| 195 | if (!pWalletSQLiteRuntime) | ||
| 196 | return; | ||
| 197 | string strError; | ||
| 198 | pWalletSQLiteRuntime->RollbackTransaction(strError); | ||
| 199 | } | ||
| 200 | |||
| 201 | // Open the SQLite wallet read-only as the active runtime. Used by the one-shot | ||
| 202 | // storage diagnostics, which run before the normal wallet load and must be able | ||
| 203 | // to inspect a wallet that the loader would refuse -- so this opens the file for | ||
| 204 | // scanning without loading or validating its records. | ||
| 205 | bool WalletSQLiteRuntimeOpenReadOnly(const string& strPath, string& strErrorRet) | ||
| 206 | { | ||
| 207 | strErrorRet.clear(); | ||
| 208 | if (!FileExists(strPath.c_str())) | ||
| 209 | { | ||
| 210 | strErrorRet = strprintf("SQLite wallet does not exist: %s", strPath.c_str()); | ||
| 211 | return false; | ||
| 212 | } | ||
| 213 | |||
| 214 | WalletSQLiteRuntimeClose(); | ||
| 215 | std::auto_ptr<CWalletDBSQLite> db(new CWalletDBSQLite()); | ||
| 216 | if (!db->OpenReadOnly(strPath, strErrorRet)) | ||
| 217 | return false; | ||
| 218 | |||
| 219 | pWalletSQLiteRuntime = db.release(); | ||
| 220 | return true; | ||
| 221 | } | ||
| 222 | |||
| 223 | bool WalletSQLiteRuntimeCheckpoint(string& strErrorRet) | ||
| 224 | { | ||
| 225 | if (!pWalletSQLiteRuntime) | ||
| 226 | { | ||
| 227 | strErrorRet = "SQLite wallet backend is not active"; | ||
| 228 | return false; | ||
| 229 | } | ||
| 230 | return pWalletSQLiteRuntime->Checkpoint(strErrorRet); | ||
| 231 | } | ||
| 232 | |||
| 167 | 233 | ||
| 168 | CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) | 234 | CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) |
| 169 | { | 235 | { |
| @@ -1320,6 +1386,16 @@ bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet) | |||
| 1320 | 1386 | ||
| 1321 | bool ScanWalletRecords(CWalletRecordVisitor& visitor, string& strErrorRet) | 1387 | bool ScanWalletRecords(CWalletRecordVisitor& visitor, string& strErrorRet) |
| 1322 | { | 1388 | { |
| 1389 | // Under the SQLite backend there is no Berkeley DB cursor to walk; scan the | ||
| 1390 | // active SQLite store instead. This is the single choke point every "read | ||
| 1391 | // every wallet record" caller goes through (storage audit and check among | ||
| 1392 | // them), so routing it here makes those honour -walletbackend=sqlite. | ||
| 1393 | if (WalletSQLiteRuntimeActive()) | ||
| 1394 | { | ||
| 1395 | strErrorRet.clear(); | ||
| 1396 | return pWalletSQLiteRuntime->ScanRecords(visitor, strErrorRet); | ||
| 1397 | } | ||
| 1398 | |||
| 1323 | class CWalletScanDB : public CWalletDB | 1399 | class CWalletScanDB : public CWalletDB |
| 1324 | { | 1400 | { |
| 1325 | public: | 1401 | public: |
| @@ -1550,11 +1626,81 @@ bool LoadWalletFromSQLiteRuntime(const string& strPath) | |||
| 1550 | // this file was written are not spendable from it. Backing up once is not | 1626 | // this file was written are not spendable from it. Backing up once is not |
| 1551 | // enough, and that is a property of the wallet format rather than of this | 1627 | // enough, and that is a property of the wallet format rather than of this |
| 1552 | // function. | 1628 | // function. |
| 1629 | // Back up the active SQLite wallet. The store is checkpointed so the WAL is | ||
| 1630 | // folded into the main file, then the single self-contained wallet.sqlite is | ||
| 1631 | // copied through a temp file and renamed into place (same temp/old/rename dance | ||
| 1632 | // as the Berkeley DB path, for Windows' non-overwriting rename). No lsn_reset: | ||
| 1633 | // a checkpointed SQLite file needs nothing beside it to open. | ||
| 1634 | static bool BackupWalletSQLite(const string& strDest) | ||
| 1635 | { | ||
| 1636 | string strSrc = GetAppDir() + "/wallet.sqlite"; | ||
| 1637 | if (!FileExists(strSrc.c_str())) | ||
| 1638 | return error("BackupWallet() : %s does not exist\n", strSrc.c_str()); | ||
| 1639 | |||
| 1640 | string strCheckpointError; | ||
| 1641 | if (!WalletSQLiteRuntimeCheckpoint(strCheckpointError)) | ||
| 1642 | return error("BackupWallet() : checkpoint failed: %s\n", strCheckpointError.c_str()); | ||
| 1643 | |||
| 1644 | string strTemp = strprintf("%s.tmp.%lld", strDest.c_str(), GetTime()); | ||
| 1645 | for (int i = 1; FileExists(strTemp.c_str()); i++) | ||
| 1646 | strTemp = strprintf("%s.tmp.%lld.%d", strDest.c_str(), GetTime(), i); | ||
| 1647 | string strOld = strprintf("%s.old.%lld", strDest.c_str(), GetTime()); | ||
| 1648 | for (int i = 1; FileExists(strOld.c_str()); i++) | ||
| 1649 | strOld = strprintf("%s.old.%lld.%d", strDest.c_str(), GetTime(), i); | ||
| 1650 | |||
| 1651 | FILE* pfIn = fopen(strSrc.c_str(), "rb"); | ||
| 1652 | if (!pfIn) | ||
| 1653 | return error("BackupWallet() : cannot read %s\n", strSrc.c_str()); | ||
| 1654 | FILE* pfOut = fopen(strTemp.c_str(), "wb"); | ||
| 1655 | if (!pfOut) | ||
| 1656 | { | ||
| 1657 | fclose(pfIn); | ||
| 1658 | return error("BackupWallet() : cannot write %s\n", strTemp.c_str()); | ||
| 1659 | } | ||
| 1660 | |||
| 1661 | char buf[65536]; | ||
| 1662 | size_t n; | ||
| 1663 | bool fOk = true; | ||
| 1664 | while ((n = fread(buf, 1, sizeof(buf), pfIn)) > 0) | ||
| 1665 | if (fwrite(buf, 1, n, pfOut) != n) { fOk = false; break; } | ||
| 1666 | if (ferror(pfIn)) | ||
| 1667 | fOk = false; | ||
| 1668 | fclose(pfIn); | ||
| 1669 | if (fclose(pfOut) != 0) | ||
| 1670 | fOk = false; | ||
| 1671 | if (!fOk) | ||
| 1672 | { | ||
| 1673 | remove(strTemp.c_str()); // half a wallet is worse than none | ||
| 1674 | return error("BackupWallet() : copy to %s failed\n", strTemp.c_str()); | ||
| 1675 | } | ||
| 1676 | |||
| 1677 | bool fHadOldDest = FileExists(strDest.c_str()); | ||
| 1678 | if (fHadOldDest && rename(strDest.c_str(), strOld.c_str()) != 0) | ||
| 1679 | { | ||
| 1680 | remove(strTemp.c_str()); | ||
| 1681 | return error("BackupWallet() : could not move old %s aside\n", strDest.c_str()); | ||
| 1682 | } | ||
| 1683 | if (rename(strTemp.c_str(), strDest.c_str()) != 0) | ||
| 1684 | { | ||
| 1685 | remove(strTemp.c_str()); | ||
| 1686 | if (fHadOldDest) | ||
| 1687 | rename(strOld.c_str(), strDest.c_str()); | ||
| 1688 | return error("BackupWallet() : could not install %s\n", strDest.c_str()); | ||
| 1689 | } | ||
| 1690 | if (fHadOldDest) | ||
| 1691 | remove(strOld.c_str()); | ||
| 1692 | return true; | ||
| 1693 | } | ||
| 1694 | |||
| 1553 | bool BackupWallet(const string& strDest) | 1695 | bool BackupWallet(const string& strDest) |
| 1554 | { | 1696 | { |
| 1555 | if (strDest.empty()) | 1697 | if (strDest.empty()) |
| 1556 | return error("BackupWallet() : no destination given\n"); | 1698 | return error("BackupWallet() : no destination given\n"); |
| 1557 | 1699 | ||
| 1700 | // Under the SQLite backend the live wallet is wallet.sqlite, not wallet.dat. | ||
| 1701 | if (WalletSQLiteRuntimeActive()) | ||
| 1702 | return BackupWalletSQLite(strDest); | ||
| 1703 | |||
| 1558 | string strSrc = GetAppDir() + "/wallet.dat"; | 1704 | string strSrc = GetAppDir() + "/wallet.dat"; |
| 1559 | if (!FileExists(strSrc.c_str())) | 1705 | if (!FileExists(strSrc.c_str())) |
| 1560 | return error("BackupWallet() : %s does not exist\n", strSrc.c_str()); | 1706 | return error("BackupWallet() : %s does not exist\n", strSrc.c_str()); |
| @@ -1974,9 +2120,9 @@ static bool CopyPublicWalletRecordsTo(CWalletRewriteDB& dbTo, | |||
| 1974 | return ScanWalletRecords(visitor, strErrorRet); | 2120 | return ScanWalletRecords(visitor, strErrorRet); |
| 1975 | } | 2121 | } |
| 1976 | 2122 | ||
| 1977 | static string WalletEncryptBackupPath() | 2123 | static string WalletEncryptBackupPathFor(const char* pszBaseName) |
| 1978 | { | 2124 | { |
| 1979 | string strBase = GetAppDir() + "/wallet.dat.before-encrypt."; | 2125 | string strBase = GetAppDir() + "/" + pszBaseName + ".before-encrypt."; |
| 1980 | string strPath = strBase + i64tostr(GetTime()) + ".bak"; | 2126 | string strPath = strBase + i64tostr(GetTime()) + ".bak"; |
| 1981 | for (int i = 1; FileExists(strPath.c_str()); i++) | 2127 | for (int i = 1; FileExists(strPath.c_str()); i++) |
| 1982 | strPath = strBase + i64tostr(GetTime()) + "." + itostr(i) + ".bak"; | 2128 | strPath = strBase + i64tostr(GetTime()) + "." + itostr(i) + ".bak"; |
| @@ -2006,6 +2152,192 @@ static void SecureClearBytes(vector<unsigned char>& vch) | |||
| 2006 | vch.clear(); | 2152 | vch.clear(); |
| 2007 | } | 2153 | } |
| 2008 | 2154 | ||
| 2155 | // The SQLite counterpart of CWalletPublicRecordCopyVisitor: same skip list, | ||
| 2156 | // same byte-for-byte copy, but the destination is a CWalletDBSQLite record | ||
| 2157 | // store rather than a Berkeley DB file. | ||
| 2158 | class CWalletPublicRecordCopyToSQLiteVisitor : public CWalletRecordVisitor | ||
| 2159 | { | ||
| 2160 | public: | ||
| 2161 | CWalletDBSQLite& dbTo; | ||
| 2162 | int& nCopied; | ||
| 2163 | |||
| 2164 | CWalletPublicRecordCopyToSQLiteVisitor(CWalletDBSQLite& dbToIn, int& nCopiedIn) | ||
| 2165 | : dbTo(dbToIn), nCopied(nCopiedIn) { } | ||
| 2166 | |||
| 2167 | bool VisitWalletRecord(const CDataStream& ssKey, | ||
| 2168 | const CDataStream& ssValue, | ||
| 2169 | string& strErrorRet) | ||
| 2170 | { | ||
| 2171 | string strType; | ||
| 2172 | try | ||
| 2173 | { | ||
| 2174 | CDataStream ssType = ssKey; | ||
| 2175 | ssType >> strType; | ||
| 2176 | } | ||
| 2177 | catch (...) | ||
| 2178 | { | ||
| 2179 | strErrorRet = "SQLite wallet has a record whose key type cannot be read"; | ||
| 2180 | return false; | ||
| 2181 | } | ||
| 2182 | |||
| 2183 | if (IsWalletEncryptionPrivateRecord(strType)) | ||
| 2184 | return true; | ||
| 2185 | |||
| 2186 | vector<unsigned char> vchKey(ssKey.begin(), ssKey.end()); | ||
| 2187 | vector<unsigned char> vchValue(ssValue.begin(), ssValue.end()); | ||
| 2188 | bool fOk = dbTo.WriteRecord(vchKey, vchValue, strErrorRet, true); | ||
| 2189 | if (!vchKey.empty()) | ||
| 2190 | memset(&vchKey[0], 0, vchKey.size()); | ||
| 2191 | if (!vchValue.empty()) | ||
| 2192 | memset(&vchValue[0], 0, vchValue.size()); | ||
| 2193 | if (!fOk) | ||
| 2194 | { | ||
| 2195 | strErrorRet = strprintf("could not copy wallet record '%s': %s", | ||
| 2196 | strType.c_str(), strErrorRet.c_str()); | ||
| 2197 | return false; | ||
| 2198 | } | ||
| 2199 | nCopied++; | ||
| 2200 | return true; | ||
| 2201 | } | ||
| 2202 | }; | ||
| 2203 | |||
| 2204 | // Persist an encrypted wallet under the SQLite backend. Everything the caller | ||
| 2205 | // computed -- the master key, the re-encrypted private keys, the fresh crypted | ||
| 2206 | // key pool, the encrypted HD seed -- lands in a brand new wallet.sqlite built | ||
| 2207 | // in one transaction, which is then swapped in for the plaintext original. | ||
| 2208 | // | ||
| 2209 | // A fresh file rather than an in-place rewrite for two reasons: it keeps the | ||
| 2210 | // whole change atomic (a crash before the rename leaves the old wallet whole), | ||
| 2211 | // and it guarantees no plaintext key survives in a freed page the way an | ||
| 2212 | // in-place DELETE would leave behind until a VACUUM. | ||
| 2213 | static bool EncryptWalletPersistSQLite( | ||
| 2214 | const vector<pair<vector<unsigned char>, vector<unsigned char> > >& vCryptedKeys, | ||
| 2215 | const vector<pair<vector<unsigned char>, vector<unsigned char> > >& vNewPoolKeys, | ||
| 2216 | const vector<pair<int64, vector<unsigned char> > >& vNewPool, | ||
| 2217 | const CWalletMasterKey& kMasterKey, | ||
| 2218 | const vector<unsigned char>& vchCryptedHDMasterNew, | ||
| 2219 | const vector<unsigned char>& vchCryptedHDChainCodeNew, | ||
| 2220 | unsigned int nHDNextNew, | ||
| 2221 | int& nCopiedRet, | ||
| 2222 | string& strBackupRet, | ||
| 2223 | string& strErrorRet) | ||
| 2224 | { | ||
| 2225 | nCopiedRet = 0; | ||
| 2226 | if (!pWalletSQLiteRuntime) | ||
| 2227 | { | ||
| 2228 | strErrorRet = "SQLite wallet backend is not active"; | ||
| 2229 | return false; | ||
| 2230 | } | ||
| 2231 | |||
| 2232 | string strWalletPath = GetAppDir() + "/wallet.sqlite"; | ||
| 2233 | string strTempPath = GetAppDir() + "/" + | ||
| 2234 | strprintf("wallet.sqlite.encrypting.%lld", GetTime()); | ||
| 2235 | remove(strTempPath.c_str()); | ||
| 2236 | remove((strTempPath + "-wal").c_str()); | ||
| 2237 | remove((strTempPath + "-shm").c_str()); | ||
| 2238 | |||
| 2239 | { | ||
| 2240 | CWalletDBSQLite dbTmp; | ||
| 2241 | if (!dbTmp.Open(strTempPath, strErrorRet)) | ||
| 2242 | { | ||
| 2243 | remove(strTempPath.c_str()); | ||
| 2244 | return false; | ||
| 2245 | } | ||
| 2246 | if (!dbTmp.BeginTransaction(strErrorRet)) | ||
| 2247 | { | ||
| 2248 | dbTmp.Close(); | ||
| 2249 | remove(strTempPath.c_str()); | ||
| 2250 | return false; | ||
| 2251 | } | ||
| 2252 | |||
| 2253 | // The public records come from the live SQLite store -- under this | ||
| 2254 | // backend ScanWalletRecords() has no Berkeley DB behind it to read. | ||
| 2255 | CWalletPublicRecordCopyToSQLiteVisitor visitor(dbTmp, nCopiedRet); | ||
| 2256 | bool fOk = pWalletSQLiteRuntime->ScanRecords(visitor, strErrorRet); | ||
| 2257 | |||
| 2258 | // Encrypted metadata, serialized byte-for-byte the way the Berkeley DB | ||
| 2259 | // path (CWalletRewriteDB) writes it, so a wallet encrypted under either | ||
| 2260 | // backend is the same set of records. ckey uses INSERT-only to match | ||
| 2261 | // WriteCryptedKey; the rest overwrite. | ||
| 2262 | fOk = fOk && | ||
| 2263 | dbTmp.WriteTypedRecord(string("walletminversion"), | ||
| 2264 | (int)WALLET_FORMAT_ENCRYPTED, strErrorRet, true) && | ||
| 2265 | dbTmp.WriteTypedRecord(make_pair(string("mkey"), | ||
| 2266 | (unsigned int)(nWalletMasterKeyMaxID + 1)), | ||
| 2267 | kMasterKey, strErrorRet, true); | ||
| 2268 | for (size_t i = 0; fOk && i < vCryptedKeys.size(); i++) | ||
| 2269 | fOk = dbTmp.WriteTypedRecord(make_pair(string("ckey"), vCryptedKeys[i].first), | ||
| 2270 | vCryptedKeys[i].second, strErrorRet, false); | ||
| 2271 | for (size_t i = 0; fOk && i < vNewPoolKeys.size(); i++) | ||
| 2272 | fOk = dbTmp.WriteTypedRecord(make_pair(string("ckey"), vNewPoolKeys[i].first), | ||
| 2273 | vNewPoolKeys[i].second, strErrorRet, false); | ||
| 2274 | if (fOk && !vchCryptedHDMasterNew.empty()) | ||
| 2275 | fOk = dbTmp.WriteTypedRecord(string("cryptedhdmaster"), | ||
| 2276 | vchCryptedHDMasterNew, strErrorRet, true) && | ||
| 2277 | dbTmp.WriteTypedRecord(string("cryptedhdchaincode"), | ||
| 2278 | vchCryptedHDChainCodeNew, strErrorRet, true); | ||
| 2279 | if (fOk) | ||
| 2280 | fOk = dbTmp.WriteTypedRecord(string("hdnext"), nHDNextNew, strErrorRet, true); | ||
| 2281 | for (size_t i = 0; fOk && i < vNewPool.size(); i++) | ||
| 2282 | fOk = dbTmp.WriteTypedRecord(make_pair(string("pool"), vNewPool[i].first), | ||
| 2283 | vNewPool[i].second, strErrorRet, true); | ||
| 2284 | |||
| 2285 | if (!fOk) | ||
| 2286 | { | ||
| 2287 | string strIgnore; | ||
| 2288 | dbTmp.RollbackTransaction(strIgnore); | ||
| 2289 | dbTmp.Close(); | ||
| 2290 | remove(strTempPath.c_str()); | ||
| 2291 | remove((strTempPath + "-wal").c_str()); | ||
| 2292 | remove((strTempPath + "-shm").c_str()); | ||
| 2293 | return false; | ||
| 2294 | } | ||
| 2295 | |||
| 2296 | if (!dbTmp.CommitTransaction(strErrorRet)) | ||
| 2297 | { | ||
| 2298 | dbTmp.Close(); | ||
| 2299 | remove(strTempPath.c_str()); | ||
| 2300 | remove((strTempPath + "-wal").c_str()); | ||
| 2301 | remove((strTempPath + "-shm").c_str()); | ||
| 2302 | return false; | ||
| 2303 | } | ||
| 2304 | string strCheckpointError; | ||
| 2305 | dbTmp.Checkpoint(strCheckpointError); | ||
| 2306 | dbTmp.Close(); | ||
| 2307 | } | ||
| 2308 | |||
| 2309 | // The rebuilt wallet is committed and self-contained. Close the live handle | ||
| 2310 | // so the file can be swapped: Windows will not rename a file that still has | ||
| 2311 | // an open handle, and the node exits right after this. | ||
| 2312 | WalletSQLiteRuntimeClose(); | ||
| 2313 | |||
| 2314 | string strBackupPath = WalletEncryptBackupPathFor("wallet.sqlite"); | ||
| 2315 | if (rename(strWalletPath.c_str(), strBackupPath.c_str()) != 0) | ||
| 2316 | { | ||
| 2317 | strErrorRet = strprintf("could not move the original SQLite wallet to %s", | ||
| 2318 | strBackupPath.c_str()); | ||
| 2319 | remove(strTempPath.c_str()); | ||
| 2320 | return false; | ||
| 2321 | } | ||
| 2322 | // The moved-aside wallet owns any leftover write-ahead log or shared-memory | ||
| 2323 | // sidecar; drop stale ones so they cannot shadow the new wallet. | ||
| 2324 | remove((strWalletPath + "-wal").c_str()); | ||
| 2325 | remove((strWalletPath + "-shm").c_str()); | ||
| 2326 | |||
| 2327 | if (rename(strTempPath.c_str(), strWalletPath.c_str()) != 0) | ||
| 2328 | { | ||
| 2329 | rename(strBackupPath.c_str(), strWalletPath.c_str()); | ||
| 2330 | strErrorRet = "could not install the encrypted SQLite wallet; the original was restored"; | ||
| 2331 | remove(strTempPath.c_str()); | ||
| 2332 | return false; | ||
| 2333 | } | ||
| 2334 | remove((strTempPath + "-wal").c_str()); | ||
| 2335 | remove((strTempPath + "-shm").c_str()); | ||
| 2336 | |||
| 2337 | strBackupRet = strBackupPath; | ||
| 2338 | return true; | ||
| 2339 | } | ||
| 2340 | |||
| 2009 | bool EncryptWallet(const string& strPassphrase, string& strBackupRet, string& strErrorRet) | 2341 | bool EncryptWallet(const string& strPassphrase, string& strBackupRet, string& strErrorRet) |
| 2010 | { | 2342 | { |
| 2011 | strBackupRet.clear(); | 2343 | strBackupRet.clear(); |
| @@ -2144,6 +2476,24 @@ bool EncryptWallet(const string& strPassphrase, string& strBackupRet, string& st | |||
| 2144 | vNewPool.push_back(make_pair((int64)i + 1, vchPubKey)); | 2476 | vNewPool.push_back(make_pair((int64)i + 1, vchPubKey)); |
| 2145 | } | 2477 | } |
| 2146 | 2478 | ||
| 2479 | // Every ciphertext is computed; nothing has touched the store yet. Under | ||
| 2480 | // the SQLite backend, persist by rebuilding wallet.sqlite in one atomic | ||
| 2481 | // transaction and swapping it in. The Berkeley DB path below is unchanged. | ||
| 2482 | if (WalletSQLiteRuntimeActive()) | ||
| 2483 | { | ||
| 2484 | int nCopiedSQLite = 0; | ||
| 2485 | if (!EncryptWalletPersistSQLite(vCryptedKeys, vNewPoolKeys, vNewPool, | ||
| 2486 | kMasterKey, vchCryptedHDMasterNew, | ||
| 2487 | vchCryptedHDChainCodeNew, nHDNextNew, | ||
| 2488 | nCopiedSQLite, strBackupRet, strErrorRet)) | ||
| 2489 | return false; | ||
| 2490 | printf("EncryptWallet() : copied %d public record(s), encrypted %u key(s), " | ||
| 2491 | "rebuilt %d key-pool entry(s) [SQLite]\n", | ||
| 2492 | nCopiedSQLite, (unsigned int)(vCryptedKeys.size() + vNewPoolKeys.size()), | ||
| 2493 | (int)vNewPool.size()); | ||
| 2494 | return true; | ||
| 2495 | } | ||
| 2496 | |||
| 2147 | string strTempFile = strprintf("wallet.encrypting.%lld.dat", GetTime()); | 2497 | string strTempFile = strprintf("wallet.encrypting.%lld.dat", GetTime()); |
| 2148 | string strTempPath = GetAppDir() + "/" + strTempFile; | 2498 | string strTempPath = GetAppDir() + "/" + strTempFile; |
| 2149 | remove(strTempPath.c_str()); | 2499 | remove(strTempPath.c_str()); |
| @@ -2211,7 +2561,7 @@ bool EncryptWallet(const string& strPassphrase, string& strBackupRet, string& st | |||
| 2211 | DBFlush(true); | 2561 | DBFlush(true); |
| 2212 | 2562 | ||
| 2213 | string strWalletPath = GetAppDir() + "/wallet.dat"; | 2563 | string strWalletPath = GetAppDir() + "/wallet.dat"; |
| 2214 | string strBackupPath = WalletEncryptBackupPath(); | 2564 | string strBackupPath = WalletEncryptBackupPathFor("wallet.dat"); |
| 2215 | if (rename(strWalletPath.c_str(), strBackupPath.c_str()) != 0) | 2565 | if (rename(strWalletPath.c_str(), strBackupPath.c_str()) != 0) |
| 2216 | { | 2566 | { |
| 2217 | strErrorRet = strprintf("could not move the original wallet to %s", strBackupPath.c_str()); | 2567 | strErrorRet = strprintf("could not move the original wallet to %s", strBackupPath.c_str()); |