From d082210c5d080c0a91412b94a109d8e73422eb31 Mon Sep 17 00:00:00 2001 From: Nsable-sh Date: Mon, 17 Aug 2026 11:32:45 -0300 Subject: wallet: route CWalletDB through SQLite runtime --- src/db.cpp | 67 +++++++++++++++++++++++++ src/db.h | 145 ++++++++++++++++++++++++++++++++++++++++++++----------- src/selftest.cpp | 76 +++++++++++++++++++++++++++++ 3 files changed, 259 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/db.cpp b/src/db.cpp index 581e5a7..7cfb7c5 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -56,6 +56,7 @@ string strWalletLoadError; static DbEnv* pdbenv = NULL; static FILE* pdbErrFile = NULL; static map mapFileUseCount; +static CWalletDBSQLite* pWalletSQLiteRuntime = NULL; DbEnv& GetDbEnv() { @@ -95,6 +96,67 @@ public: } instance_of_cdbinit; +bool WalletSQLiteRuntimeActive() +{ + return pWalletSQLiteRuntime != NULL; +} + +bool WalletSQLiteRuntimeOpen(const string& strPath, string& strErrorRet) +{ + strErrorRet.clear(); + if (!FileExists(strPath.c_str())) + { + strErrorRet = strprintf("SQLite wallet does not exist: %s", + strPath.c_str()); + return false; + } + + WalletSQLiteRuntimeClose(); + std::auto_ptr db(new CWalletDBSQLite()); + if (!db->Open(strPath, strErrorRet)) + return false; + + pWalletSQLiteRuntime = db.release(); + return true; +} + +void WalletSQLiteRuntimeClose() +{ + if (pWalletSQLiteRuntime) + { + delete pWalletSQLiteRuntime; + pWalletSQLiteRuntime = NULL; + } +} + +bool WalletSQLiteRuntimeReadRecord(const vector& vchKey, + vector& vchValueRet) +{ + if (!pWalletSQLiteRuntime) + return false; + string strError; + return pWalletSQLiteRuntime->ReadRecord(vchKey, vchValueRet, strError); +} + +bool WalletSQLiteRuntimeWriteRecord(const vector& vchKey, + const vector& vchValue, + bool fOverwrite) +{ + if (!pWalletSQLiteRuntime) + return false; + string strError; + return pWalletSQLiteRuntime->WriteRecord(vchKey, vchValue, strError, + fOverwrite); +} + +bool WalletSQLiteRuntimeEraseRecord(const vector& vchKey) +{ + if (!pWalletSQLiteRuntime) + return false; + string strError; + return pWalletSQLiteRuntime->EraseRecord(vchKey, strError); +} + CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) { @@ -651,6 +713,11 @@ bool CReviewDB::WriteReviews(uint256 hash, const vector& vReviews) // CWalletDB // +CWalletDB::CWalletDB(const char* pszMode, bool fTxn) : + CDB(WalletSQLiteRuntimeActive() ? NULL : "wallet.dat", pszMode, fTxn) +{ +} + class CSQLiteWalletRuntimeLoadVisitor : public CWalletRecordVisitor { public: diff --git a/src/db.h b/src/db.h index 59ff24a..8fa4ea8 100644 --- a/src/db.h +++ b/src/db.h @@ -356,6 +356,16 @@ private: // Legacy IP-based peer address database (CAddrDB / addr.dat) removed -- // peer discovery is entirely Nostr/.btf-based now. +bool WalletSQLiteRuntimeActive(); +bool WalletSQLiteRuntimeOpen(const string& strPath, string& strErrorRet); +void WalletSQLiteRuntimeClose(); +bool WalletSQLiteRuntimeReadRecord(const vector& vchKey, + vector& vchValueRet); +bool WalletSQLiteRuntimeWriteRecord(const vector& vchKey, + const vector& vchValue, + bool fOverwrite); +bool WalletSQLiteRuntimeEraseRecord(const vector& vchKey); + @@ -363,64 +373,141 @@ private: class CWalletDB : public CDB { public: - CWalletDB(const char* pszMode="r+", bool fTxn=false) : CDB("wallet.dat", pszMode, fTxn) { } + CWalletDB(const char* pszMode="r+", bool fTxn=false); private: CWalletDB(const CWalletDB&); void operator=(const CWalletDB&); + + template + bool ReadWalletRecord(const K& key, T& value) + { + if (!WalletSQLiteRuntimeActive()) + return Read(key, value); + + CDataStream ssKey(SER_DISK); + ssKey.reserve(1000); + ssKey << key; + vector vchKey(ssKey.begin(), ssKey.end()); + vector vchValue; + + bool fOk = WalletSQLiteRuntimeReadRecord(vchKey, vchValue); + if (!vchKey.empty()) + memset(&vchKey[0], 0, vchKey.size()); + if (!ssKey.empty()) + memset(&ssKey[0], 0, ssKey.size()); + if (!fOk) + return false; + + CDataStream ssValue(vchValue, SER_DISK); + ssValue >> value; + bool fReadOk = !ssValue.fail(); + if (!vchValue.empty()) + memset(&vchValue[0], 0, vchValue.size()); + if (!ssValue.empty()) + memset(&ssValue[0], 0, ssValue.size()); + return fReadOk; + } + + template + bool WriteWalletRecord(const K& key, const T& value, bool fOverwrite=true) + { + if (!WalletSQLiteRuntimeActive()) + return Write(key, value, fOverwrite); + + CDataStream ssKey(SER_DISK); + ssKey.reserve(1000); + ssKey << key; + CDataStream ssValue(SER_DISK); + ssValue.reserve(10000); + ssValue << value; + + vector vchKey(ssKey.begin(), ssKey.end()); + vector vchValue(ssValue.begin(), ssValue.end()); + bool fOk = WalletSQLiteRuntimeWriteRecord(vchKey, vchValue, fOverwrite); + + if (!vchKey.empty()) + memset(&vchKey[0], 0, vchKey.size()); + if (!vchValue.empty()) + memset(&vchValue[0], 0, vchValue.size()); + if (!ssKey.empty()) + memset(&ssKey[0], 0, ssKey.size()); + if (!ssValue.empty()) + memset(&ssValue[0], 0, ssValue.size()); + return fOk; + } + + template + bool EraseWalletRecord(const K& key) + { + if (!WalletSQLiteRuntimeActive()) + return Erase(key); + + CDataStream ssKey(SER_DISK); + ssKey.reserve(1000); + ssKey << key; + vector vchKey(ssKey.begin(), ssKey.end()); + bool fOk = WalletSQLiteRuntimeEraseRecord(vchKey); + + if (!vchKey.empty()) + memset(&vchKey[0], 0, vchKey.size()); + if (!ssKey.empty()) + memset(&ssKey[0], 0, ssKey.size()); + return fOk; + } public: bool ReadName(const string& strAddress, string& strName) { strName = ""; - return Read(make_pair(string("name"), strAddress), strName); + return ReadWalletRecord(make_pair(string("name"), strAddress), strName); } bool WriteName(const string& strAddress, const string& strName) { mapAddressBook[strAddress] = strName; - return Write(make_pair(string("name"), strAddress), strName); + return WriteWalletRecord(make_pair(string("name"), strAddress), strName); } bool EraseName(const string& strAddress) { mapAddressBook.erase(strAddress); - return Erase(make_pair(string("name"), strAddress)); + return EraseWalletRecord(make_pair(string("name"), strAddress)); } bool ReadTx(uint256 hash, CWalletTx& wtx) { - return Read(make_pair(string("tx"), hash), wtx); + return ReadWalletRecord(make_pair(string("tx"), hash), wtx); } bool WriteTx(uint256 hash, const CWalletTx& wtx) { - return Write(make_pair(string("tx"), hash), wtx); + return WriteWalletRecord(make_pair(string("tx"), hash), wtx); } bool EraseTx(uint256 hash) { - return Erase(make_pair(string("tx"), hash)); + return EraseWalletRecord(make_pair(string("tx"), hash)); } bool ReadKey(const vector& vchPubKey, CPrivKey& vchPrivKey) { vchPrivKey.clear(); - return Read(make_pair(string("key"), vchPubKey), vchPrivKey); + return ReadWalletRecord(make_pair(string("key"), vchPubKey), vchPrivKey); } bool WriteKey(const vector& vchPubKey, const CPrivKey& vchPrivKey) { - return Write(make_pair(string("key"), vchPubKey), vchPrivKey, false); + return WriteWalletRecord(make_pair(string("key"), vchPubKey), vchPrivKey, false); } bool ReadDefaultKey(vector& vchPubKey) { vchPubKey.clear(); - return Read(string("defaultkey"), vchPubKey); + return ReadWalletRecord(string("defaultkey"), vchPubKey); } bool WriteDefaultKey(const vector& vchPubKey) { - return Write(string("defaultkey"), vchPubKey); + return WriteWalletRecord(string("defaultkey"), vchPubKey); } // --- Deterministic (BIP32) seed --------------------------------------- @@ -438,62 +525,62 @@ public: { vchMasterRet.clear(); vchChainCodeRet.clear(); - return Read(string("hdmaster"), vchMasterRet) - && Read(string("hdchaincode"), vchChainCodeRet); + return ReadWalletRecord(string("hdmaster"), vchMasterRet) + && ReadWalletRecord(string("hdchaincode"), vchChainCodeRet); } bool WriteHDMaster(const vector& vchMaster, const vector& vchChainCode) { - return Write(string("hdmaster"), vchMaster) - && Write(string("hdchaincode"), vchChainCode); + return WriteWalletRecord(string("hdmaster"), vchMaster) + && WriteWalletRecord(string("hdchaincode"), vchChainCode); } bool WriteWalletMinVersion(int nVersion) { - return Write(string("walletminversion"), nVersion); + return WriteWalletRecord(string("walletminversion"), nVersion); } bool WriteMasterKey(unsigned int nID, const CWalletMasterKey& kMasterKey) { - return Write(make_pair(string("mkey"), nID), kMasterKey, true); + return WriteWalletRecord(make_pair(string("mkey"), nID), kMasterKey, true); } bool WriteCryptedKey(const vector& vchPubKey, const vector& vchCryptedSecret) { - return Write(make_pair(string("ckey"), vchPubKey), vchCryptedSecret, false); + return WriteWalletRecord(make_pair(string("ckey"), vchPubKey), vchCryptedSecret, false); } bool WriteCryptedHDMaster(const vector& vchCryptedMaster, const vector& vchCryptedChainCode) { - return Write(string("cryptedhdmaster"), vchCryptedMaster) - && Write(string("cryptedhdchaincode"), vchCryptedChainCode); + return WriteWalletRecord(string("cryptedhdmaster"), vchCryptedMaster) + && WriteWalletRecord(string("cryptedhdchaincode"), vchCryptedChainCode); } bool WriteHDNext(unsigned int nNext) { - return Write(string("hdnext"), nNext); + return WriteWalletRecord(string("hdnext"), nNext); } bool WriteHDSchema(int nSchema) { - return Write(string("hdschema"), nSchema); + return WriteWalletRecord(string("hdschema"), nSchema); } bool WriteHDCoinType(unsigned int nCoinType) { - return Write(string("hdcointype"), nCoinType); + return WriteWalletRecord(string("hdcointype"), nCoinType); } bool WriteHDReceiveNext(unsigned int nNext) { - return Write(string("hdreceivenext"), nNext); + return WriteWalletRecord(string("hdreceivenext"), nNext); } bool WriteHDChangeNext(unsigned int nNext) { - return Write(string("hdchangenext"), nNext); + return WriteWalletRecord(string("hdchangenext"), nNext); } // Keys generated ahead of time and not yet handed out. The private key of @@ -501,24 +588,24 @@ public: // record only says that this one is still unspoken for. bool WritePool(int64 nIndex, const vector& vchPubKey) { - return Write(make_pair(string("pool"), nIndex), vchPubKey); + return WriteWalletRecord(make_pair(string("pool"), nIndex), vchPubKey); } bool ErasePool(int64 nIndex) { - return Erase(make_pair(string("pool"), nIndex)); + return EraseWalletRecord(make_pair(string("pool"), nIndex)); } template bool ReadSetting(const string& strKey, T& value) { - return Read(make_pair(string("setting"), strKey), value); + return ReadWalletRecord(make_pair(string("setting"), strKey), value); } template bool WriteSetting(const string& strKey, const T& value) { - return Write(make_pair(string("setting"), strKey), value); + return WriteWalletRecord(make_pair(string("setting"), strKey), value); } bool LoadWallet(vector& vchDefaultKeyRet); diff --git a/src/selftest.cpp b/src/selftest.cpp index a1efaa0..9fa0938 100644 --- a/src/selftest.cpp +++ b/src/selftest.cpp @@ -1051,6 +1051,8 @@ static int RunWalletSQLiteSelfTest() int nFail = 0; string strPath = tmp + "/wallet.sqlite"; string strError; + string strOldRuntimeDataDir; + bool fRestoreRuntimeDataDir = false; try { @@ -1166,14 +1168,88 @@ static int RunWalletSQLiteSelfTest() vchTypedPubKey == vchPubKey, "SQLite wallet reads a typed defaultkey record") ? 0 : 1; } + + { + string strRuntimePath = tmp + "/runtime-wallet.sqlite"; + string strRuntimeDir = tmp + "/runtime-datadir"; + nFail += Check(MakeDirLocal(strRuntimeDir), + "SQLite runtime datadir can be created") ? 0 : 1; + + { + CWalletDBSQLite db; + nFail += Check(db.Open(strRuntimePath, strError), + "SQLite runtime wallet file can be created") ? 0 : 1; + } + + string strOldDataDir = strSetDataDir; + strSetDataDir = strRuntimeDir; + strOldRuntimeDataDir = strOldDataDir; + fRestoreRuntimeDataDir = true; + bool fRuntimeOpened = WalletSQLiteRuntimeOpen(strRuntimePath, strError); + nFail += Check(fRuntimeOpened, + "SQLite runtime wallet can be activated") ? 0 : 1; + + if (fRuntimeOpened) + { + CKey key; + key.MakeNewKey(); + vector vchRuntimePubKey = key.GetPubKey(); + CPrivKey vchRuntimePrivKey = key.GetPrivKey(); + string strRuntimeAddress = PubKeyToAddress(vchRuntimePubKey); + + nFail += Check(CWalletDB().WriteSetting("runtime-sqlite-setting", + (int64)909090) && + CWalletDB().WriteDefaultKey(vchRuntimePubKey) && + CWalletDB().WriteKey(vchRuntimePubKey, + vchRuntimePrivKey) && + CWalletDB().WriteName(strRuntimeAddress, + "SQLite Runtime Address"), + "CWalletDB writes route to active SQLite runtime") ? 0 : 1; + + int64 nRuntimeSetting = 0; + vector vchRuntimeDefaultKey; + CPrivKey vchRuntimeReadPrivKey; + string strRuntimeName; + nFail += Check(CWalletDB("r").ReadSetting("runtime-sqlite-setting", + nRuntimeSetting) && + nRuntimeSetting == 909090 && + CWalletDB("r").ReadDefaultKey(vchRuntimeDefaultKey) && + vchRuntimeDefaultKey == vchRuntimePubKey && + CWalletDB("r").ReadKey(vchRuntimePubKey, + vchRuntimeReadPrivKey) && + vchRuntimeReadPrivKey == vchRuntimePrivKey && + CWalletDB("r").ReadName(strRuntimeAddress, + strRuntimeName) && + strRuntimeName == "SQLite Runtime Address", + "CWalletDB reads route to active SQLite runtime") ? 0 : 1; + + nFail += Check(CWalletDB().EraseName(strRuntimeAddress) && + !CWalletDB("r").ReadName(strRuntimeAddress, + strRuntimeName), + "CWalletDB erases route to active SQLite runtime") ? 0 : 1; + + nFail += Check(!FileExists((strRuntimeDir + "/wallet.dat").c_str()), + "active SQLite runtime does not create wallet.dat") ? 0 : 1; + } + + WalletSQLiteRuntimeClose(); + strSetDataDir = strOldDataDir; + fRestoreRuntimeDataDir = false; + } } catch (const std::exception& e) { + WalletSQLiteRuntimeClose(); + if (fRestoreRuntimeDataDir) + strSetDataDir = strOldRuntimeDataDir; printf(" FAIL exception: %s\n", e.what()); nFail++; } catch (...) { + WalletSQLiteRuntimeClose(); + if (fRestoreRuntimeDataDir) + strSetDataDir = strOldRuntimeDataDir; printf(" FAIL unknown exception\n"); nFail++; } -- cgit v1.2.3