upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/db.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/db.cpp')
-rw-r--r--src/db.cpp112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/db.cpp b/src/db.cpp
index c16edb4..aafc0f9 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -198,6 +198,38 @@ void WalletSQLiteRuntimeRollbackTxn()
198 pWalletSQLiteRuntime->RollbackTransaction(strError); 198 pWalletSQLiteRuntime->RollbackTransaction(strError);
199} 199}
200 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.
205bool 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
223bool 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
201 233
202CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) 234CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL)
203{ 235{
@@ -1354,6 +1386,16 @@ bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet)
1354 1386
1355bool ScanWalletRecords(CWalletRecordVisitor& visitor, string& strErrorRet) 1387bool ScanWalletRecords(CWalletRecordVisitor& visitor, string& strErrorRet)
1356{ 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
1357 class CWalletScanDB : public CWalletDB 1399 class CWalletScanDB : public CWalletDB
1358 { 1400 {
1359 public: 1401 public:
@@ -1584,11 +1626,81 @@ bool LoadWalletFromSQLiteRuntime(const string& strPath)
1584// 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
1585// 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
1586// 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.
1634static 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
1587bool BackupWallet(const string& strDest) 1695bool BackupWallet(const string& strDest)
1588{ 1696{
1589 if (strDest.empty()) 1697 if (strDest.empty())
1590 return error("BackupWallet() : no destination given\n"); 1698 return error("BackupWallet() : no destination given\n");
1591 1699
1700 // Under the SQLite backend the live wallet is wallet.sqlite, not wallet.dat.
1701 if (WalletSQLiteRuntimeActive())
1702 return BackupWalletSQLite(strDest);
1703
1592 string strSrc = GetAppDir() + "/wallet.dat"; 1704 string strSrc = GetAppDir() + "/wallet.dat";
1593 if (!FileExists(strSrc.c_str())) 1705 if (!FileExists(strSrc.c_str()))
1594 return error("BackupWallet() : %s does not exist\n", strSrc.c_str()); 1706 return error("BackupWallet() : %s does not exist\n", strSrc.c_str());