upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBitflash <admin@bitflash.network>2026-08-17 11:08:42 -0300
committerBitflash <admin@bitflash.network>2026-08-17 11:08:42 -0300
commit8e91ff3a57a085663312a6e1821ec4cb1c152144 (patch)
treed511b288e1d0f555723114a9502c897b07cb048a /src
parentf7033201689c6eb70f16b242b9f90be548f67aa5 (diff)
parenta72fc5fa0c9811ff5a57af90bf4440023c94ac5a (diff)
Merge pull request 'wallet: add typed SQLite wallet records' (#56) from wallet-storage-backend-stage into main
Diffstat (limited to 'src')
-rw-r--r--src/selftest.cpp51
-rw-r--r--src/wallet_sqlite.cpp43
-rw-r--r--src/wallet_sqlite.h77
3 files changed, 167 insertions, 4 deletions
diff --git a/src/selftest.cpp b/src/selftest.cpp
index 14bf45a..4b1e733 100644
--- a/src/selftest.cpp
+++ b/src/selftest.cpp
@@ -1115,6 +1115,57 @@ static int RunWalletSQLiteSelfTest()
1115 nFail += Check(!ssReadDefault.fail() && vchReadPubKey == vchPubKey, 1115 nFail += Check(!ssReadDefault.fail() && vchReadPubKey == vchPubKey,
1116 "SQLite wallet preserves public key blobs") ? 0 : 1; 1116 "SQLite wallet preserves public key blobs") ? 0 : 1;
1117 } 1117 }
1118
1119 {
1120 CWalletDBSQLite db;
1121 nFail += Check(db.Open(strPath, strError),
1122 "SQLite wallet reopens for typed records") ? 0 : 1;
1123
1124 nFail += Check(db.WriteTypedRecord(make_pair(string("setting"),
1125 string("sqlite-typed")),
1126 (int64)777, strError),
1127 "SQLite wallet writes a typed setting record") ? 0 : 1;
1128
1129 int64 nTypedRead = 0;
1130 nFail += Check(db.ReadTypedRecord(make_pair(string("setting"),
1131 string("sqlite-typed")),
1132 nTypedRead, strError) &&
1133 nTypedRead == 777,
1134 "SQLite wallet reads a typed setting record") ? 0 : 1;
1135
1136 nFail += Check(!db.WriteTypedRecord(make_pair(string("setting"),
1137 string("sqlite-typed")),
1138 (int64)888, strError, false),
1139 "SQLite wallet refuses typed overwrite when asked") ? 0 : 1;
1140
1141 nTypedRead = 0;
1142 nFail += Check(db.ReadTypedRecord(make_pair(string("setting"),
1143 string("sqlite-typed")),
1144 nTypedRead, strError) &&
1145 nTypedRead == 777,
1146 "SQLite wallet preserves the old typed value after overwrite refusal") ? 0 : 1;
1147
1148 nFail += Check(db.EraseTypedRecord(make_pair(string("setting"),
1149 string("sqlite-typed")),
1150 strError),
1151 "SQLite wallet erases a typed record") ? 0 : 1;
1152
1153 nTypedRead = 0;
1154 nFail += Check(!db.ReadTypedRecord(make_pair(string("setting"),
1155 string("sqlite-typed")),
1156 nTypedRead, strError),
1157 "SQLite wallet typed erase removes the record") ? 0 : 1;
1158
1159 nFail += Check(db.WriteTypedRecord(string("defaultkey"), vchPubKey,
1160 strError),
1161 "SQLite wallet writes a typed defaultkey record") ? 0 : 1;
1162
1163 vector<unsigned char> vchTypedPubKey;
1164 nFail += Check(db.ReadTypedRecord(string("defaultkey"), vchTypedPubKey,
1165 strError) &&
1166 vchTypedPubKey == vchPubKey,
1167 "SQLite wallet reads a typed defaultkey record") ? 0 : 1;
1168 }
1118 } 1169 }
1119 catch (const std::exception& e) 1170 catch (const std::exception& e)
1120 { 1171 {
diff --git a/src/wallet_sqlite.cpp b/src/wallet_sqlite.cpp
index ca81573..f4b4b37 100644
--- a/src/wallet_sqlite.cpp
+++ b/src/wallet_sqlite.cpp
@@ -156,7 +156,8 @@ bool CWalletDBSQLite::InitSchema(string& strError)
156 156
157bool CWalletDBSQLite::WriteRecord(const vector<unsigned char>& vchKey, 157bool CWalletDBSQLite::WriteRecord(const vector<unsigned char>& vchKey,
158 const vector<unsigned char>& vchValue, 158 const vector<unsigned char>& vchValue,
159 string& strError) 159 string& strError,
160 bool fOverwrite)
160{ 161{
161 if (!pdb) 162 if (!pdb)
162 { 163 {
@@ -170,8 +171,9 @@ bool CWalletDBSQLite::WriteRecord(const vector<unsigned char>& vchKey,
170 } 171 }
171 172
172 sqlite3_stmt* stmt = NULL; 173 sqlite3_stmt* stmt = NULL;
173 const char* pszSql = 174 const char* pszSql = fOverwrite
174 "INSERT OR REPLACE INTO wallet_records(key, value) VALUES(?, ?);"; 175 ? "INSERT OR REPLACE INTO wallet_records(key, value) VALUES(?, ?);"
176 : "INSERT INTO wallet_records(key, value) VALUES(?, ?);";
175 int ret = sqlite3_prepare_v2(pdb, pszSql, -1, &stmt, NULL); 177 int ret = sqlite3_prepare_v2(pdb, pszSql, -1, &stmt, NULL);
176 if (ret != SQLITE_OK) 178 if (ret != SQLITE_OK)
177 { 179 {
@@ -250,6 +252,41 @@ bool CWalletDBSQLite::ReadRecord(const vector<unsigned char>& vchKey,
250 return false; 252 return false;
251} 253}
252 254
255bool CWalletDBSQLite::EraseRecord(const vector<unsigned char>& vchKey,
256 string& strError)
257{
258 if (!pdb)
259 {
260 strError = "SQLite wallet is not open";
261 return false;
262 }
263 if (vchKey.empty())
264 {
265 strError = "SQLite wallet record key is empty";
266 return false;
267 }
268
269 sqlite3_stmt* stmt = NULL;
270 const char* pszSql = "DELETE FROM wallet_records WHERE key = ?;";
271 int ret = sqlite3_prepare_v2(pdb, pszSql, -1, &stmt, NULL);
272 if (ret != SQLITE_OK)
273 {
274 SetSQLiteError(pdb, "cannot prepare SQLite wallet erase", strError);
275 return false;
276 }
277
278 ret = sqlite3_bind_blob(stmt, 1, &vchKey[0], (int)vchKey.size(),
279 SQLITE_TRANSIENT);
280 if (ret == SQLITE_OK)
281 ret = sqlite3_step(stmt);
282
283 bool fOk = (ret == SQLITE_DONE);
284 if (!fOk)
285 SetSQLiteError(pdb, "cannot erase SQLite wallet record", strError);
286 sqlite3_finalize(stmt);
287 return fOk;
288}
289
253bool CWalletDBSQLite::ScanRecords(CWalletRecordVisitor& visitor, 290bool CWalletDBSQLite::ScanRecords(CWalletRecordVisitor& visitor,
254 string& strError) 291 string& strError)
255{ 292{
diff --git a/src/wallet_sqlite.h b/src/wallet_sqlite.h
index 5e6467b..d27e13a 100644
--- a/src/wallet_sqlite.h
+++ b/src/wallet_sqlite.h
@@ -25,13 +25,88 @@ public:
25 25
26 bool WriteRecord(const vector<unsigned char>& vchKey, 26 bool WriteRecord(const vector<unsigned char>& vchKey,
27 const vector<unsigned char>& vchValue, 27 const vector<unsigned char>& vchValue,
28 string& strError); 28 string& strError,
29 bool fOverwrite=true);
29 bool ReadRecord(const vector<unsigned char>& vchKey, 30 bool ReadRecord(const vector<unsigned char>& vchKey,
30 vector<unsigned char>& vchValueRet, 31 vector<unsigned char>& vchValueRet,
31 string& strError); 32 string& strError);
33 bool EraseRecord(const vector<unsigned char>& vchKey,
34 string& strError);
32 bool ScanRecords(CWalletRecordVisitor& visitor, string& strError); 35 bool ScanRecords(CWalletRecordVisitor& visitor, string& strError);
33 bool CountRecords(int& nRecordsRet, string& strError); 36 bool CountRecords(int& nRecordsRet, string& strError);
34 37
38 template<typename K, typename T>
39 bool WriteTypedRecord(const K& key, const T& value, string& strError,
40 bool fOverwrite=true)
41 {
42 CDataStream ssKey(SER_DISK);
43 ssKey.reserve(1000);
44 ssKey << key;
45
46 CDataStream ssValue(SER_DISK);
47 ssValue.reserve(10000);
48 ssValue << value;
49
50 vector<unsigned char> vchKey(ssKey.begin(), ssKey.end());
51 vector<unsigned char> vchValue(ssValue.begin(), ssValue.end());
52 bool fOk = WriteRecord(vchKey, vchValue, strError, fOverwrite);
53
54 if (!vchKey.empty())
55 memset(&vchKey[0], 0, vchKey.size());
56 if (!vchValue.empty())
57 memset(&vchValue[0], 0, vchValue.size());
58 if (!ssKey.empty())
59 memset(&ssKey[0], 0, ssKey.size());
60 if (!ssValue.empty())
61 memset(&ssValue[0], 0, ssValue.size());
62 return fOk;
63 }
64
65 template<typename K, typename T>
66 bool ReadTypedRecord(const K& key, T& valueRet, string& strError)
67 {
68 CDataStream ssKey(SER_DISK);
69 ssKey.reserve(1000);
70 ssKey << key;
71 vector<unsigned char> vchKey(ssKey.begin(), ssKey.end());
72
73 vector<unsigned char> vchValue;
74 bool fOk = ReadRecord(vchKey, vchValue, strError);
75 if (!vchKey.empty())
76 memset(&vchKey[0], 0, vchKey.size());
77 if (!ssKey.empty())
78 memset(&ssKey[0], 0, ssKey.size());
79 if (!fOk)
80 return false;
81
82 CDataStream ssValue(vchValue, SER_DISK);
83 ssValue >> valueRet;
84 bool fReadOk = !ssValue.fail();
85 if (!vchValue.empty())
86 memset(&vchValue[0], 0, vchValue.size());
87 if (!ssValue.empty())
88 memset(&ssValue[0], 0, ssValue.size());
89 if (!fReadOk)
90 strError = "SQLite wallet record could not be deserialized";
91 return fReadOk;
92 }
93
94 template<typename K>
95 bool EraseTypedRecord(const K& key, string& strError)
96 {
97 CDataStream ssKey(SER_DISK);
98 ssKey.reserve(1000);
99 ssKey << key;
100 vector<unsigned char> vchKey(ssKey.begin(), ssKey.end());
101
102 bool fOk = EraseRecord(vchKey, strError);
103 if (!vchKey.empty())
104 memset(&vchKey[0], 0, vchKey.size());
105 if (!ssKey.empty())
106 memset(&ssKey[0], 0, ssKey.size());
107 return fOk;
108 }
109
35private: 110private:
36 sqlite3* pdb; 111 sqlite3* pdb;
37 112