]>
Commit | Line | Data |
---|---|---|
0a61b0df | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
88216419 | 2 | // Copyright (c) 2009-2012 The Bitcoin developers |
0a61b0df | 3 | // Distributed under the MIT/X11 software license, see the accompanying |
3a25a2b9 | 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
0a61b0df | 5 | |
1512d5ce | 6 | #include "db.h" |
ed6d0b5f PW |
7 | #include "util.h" |
8 | #include "main.h" | |
4efbda3f | 9 | #include <boost/version.hpp> |
926e14b3 | 10 | #include <boost/filesystem.hpp> |
31f29312 | 11 | #include <boost/filesystem/fstream.hpp> |
0a61b0df | 12 | |
ed6d0b5f PW |
13 | #ifndef WIN32 |
14 | #include "sys/stat.h" | |
15 | #endif | |
16 | ||
223b6f1b WL |
17 | using namespace std; |
18 | using namespace boost; | |
19 | ||
0a61b0df | 20 | |
21 | unsigned int nWalletDBUpdated; | |
0a61b0df | 22 | |
23 | ||
24 | ||
25 | // | |
26 | // CDB | |
27 | // | |
28 | ||
cd9696fc | 29 | CDBEnv bitdb; |
0a61b0df | 30 | |
cd9696fc | 31 | void CDBEnv::EnvShutdown() |
d764d916 GA |
32 | { |
33 | if (!fDbEnvInit) | |
34 | return; | |
35 | ||
36 | fDbEnvInit = false; | |
8d5f461c GA |
37 | int ret = dbenv.close(0); |
38 | if (ret != 0) | |
39 | printf("EnvShutdown exception: %s (%d)\n", DbEnv::strerror(ret), ret); | |
148e107d LD |
40 | if (!fMockDb) |
41 | DbEnv(0).remove(GetDataDir().string().c_str(), 0); | |
d764d916 GA |
42 | } |
43 | ||
8d5f461c | 44 | CDBEnv::CDBEnv() : dbenv(DB_CXX_NO_EXCEPTIONS) |
0a61b0df | 45 | { |
0a61b0df | 46 | } |
0a61b0df | 47 | |
cd9696fc JG |
48 | CDBEnv::~CDBEnv() |
49 | { | |
50 | EnvShutdown(); | |
51 | } | |
52 | ||
53 | void CDBEnv::Close() | |
54 | { | |
55 | EnvShutdown(); | |
56 | } | |
0a61b0df | 57 | |
c74bae0f | 58 | bool CDBEnv::Open(const boost::filesystem::path& path) |
cd9696fc JG |
59 | { |
60 | if (fDbEnvInit) | |
61 | return true; | |
62 | ||
63 | if (fShutdown) | |
64 | return false; | |
65 | ||
c74bae0f | 66 | filesystem::path pathLogDir = path / "database"; |
cd9696fc | 67 | filesystem::create_directory(pathLogDir); |
c74bae0f | 68 | filesystem::path pathErrorFile = path / "db.log"; |
cd9696fc JG |
69 | printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str()); |
70 | ||
0134a1c0 JG |
71 | unsigned int nEnvFlags = 0; |
72 | if (GetBoolArg("-privdb", true)) | |
73 | nEnvFlags |= DB_PRIVATE; | |
74 | ||
c74bae0f | 75 | unsigned int nDbCache = GetArg("-dbcache", 25); |
cd9696fc JG |
76 | dbenv.set_lg_dir(pathLogDir.string().c_str()); |
77 | dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1); | |
78 | dbenv.set_lg_bsize(1048576); | |
79 | dbenv.set_lg_max(10485760); | |
ae8bfd12 PW |
80 | dbenv.set_lk_max_locks(40000); |
81 | dbenv.set_lk_max_objects(40000); | |
cd9696fc JG |
82 | dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug |
83 | dbenv.set_flags(DB_AUTO_COMMIT, 1); | |
84 | dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); | |
85 | dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); | |
c74bae0f | 86 | int ret = dbenv.open(path.string().c_str(), |
cd9696fc JG |
87 | DB_CREATE | |
88 | DB_INIT_LOCK | | |
89 | DB_INIT_LOG | | |
90 | DB_INIT_MPOOL | | |
91 | DB_INIT_TXN | | |
92 | DB_THREAD | | |
0134a1c0 JG |
93 | DB_RECOVER | |
94 | nEnvFlags, | |
cd9696fc | 95 | S_IRUSR | S_IWUSR); |
8d5f461c GA |
96 | if (ret != 0) |
97 | return error("CDB() : error %s (%d) opening database environment", DbEnv::strerror(ret), ret); | |
cd9696fc JG |
98 | |
99 | fDbEnvInit = true; | |
148e107d | 100 | fMockDb = false; |
cd9696fc JG |
101 | return true; |
102 | } | |
103 | ||
148e107d LD |
104 | void CDBEnv::MakeMock() |
105 | { | |
106 | if (fDbEnvInit) | |
107 | throw runtime_error("CDBEnv::MakeMock(): already initialized"); | |
108 | ||
109 | if (fShutdown) | |
110 | throw runtime_error("CDBEnv::MakeMock(): during shutdown"); | |
111 | ||
112 | printf("CDBEnv::MakeMock()\n"); | |
113 | ||
114 | dbenv.set_cachesize(1, 0, 1); | |
115 | dbenv.set_lg_bsize(10485760*4); | |
116 | dbenv.set_lg_max(10485760); | |
117 | dbenv.set_lk_max_locks(10000); | |
118 | dbenv.set_lk_max_objects(10000); | |
119 | dbenv.set_flags(DB_AUTO_COMMIT, 1); | |
120 | dbenv.log_set_config(DB_LOG_IN_MEMORY, 1); | |
121 | int ret = dbenv.open(NULL, | |
122 | DB_CREATE | | |
123 | DB_INIT_LOCK | | |
124 | DB_INIT_LOG | | |
125 | DB_INIT_MPOOL | | |
126 | DB_INIT_TXN | | |
127 | DB_THREAD | | |
128 | DB_PRIVATE, | |
129 | S_IRUSR | S_IWUSR); | |
130 | if (ret > 0) | |
131 | throw runtime_error(strprintf("CDBEnv::MakeMock(): error %d opening database environment", ret)); | |
132 | ||
133 | fDbEnvInit = true; | |
134 | fMockDb = true; | |
135 | } | |
136 | ||
eed1785f GA |
137 | CDBEnv::VerifyResult CDBEnv::Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile)) |
138 | { | |
139 | LOCK(cs_db); | |
140 | assert(mapFileUseCount.count(strFile) == 0); | |
141 | ||
142 | Db db(&dbenv, 0); | |
143 | int result = db.verify(strFile.c_str(), NULL, NULL, 0); | |
144 | if (result == 0) | |
145 | return VERIFY_OK; | |
146 | else if (recoverFunc == NULL) | |
147 | return RECOVER_FAIL; | |
148 | ||
149 | // Try to recover: | |
150 | bool fRecovered = (*recoverFunc)(*this, strFile); | |
151 | return (fRecovered ? RECOVER_OK : RECOVER_FAIL); | |
152 | } | |
153 | ||
154 | bool CDBEnv::Salvage(std::string strFile, bool fAggressive, | |
155 | std::vector<CDBEnv::KeyValPair >& vResult) | |
156 | { | |
157 | LOCK(cs_db); | |
158 | assert(mapFileUseCount.count(strFile) == 0); | |
159 | ||
160 | u_int32_t flags = DB_SALVAGE; | |
161 | if (fAggressive) flags |= DB_AGGRESSIVE; | |
162 | ||
163 | stringstream strDump; | |
164 | ||
165 | Db db(&dbenv, 0); | |
166 | int result = db.verify(strFile.c_str(), NULL, &strDump, flags); | |
167 | if (result != 0) | |
168 | { | |
169 | printf("ERROR: db salvage failed\n"); | |
170 | return false; | |
171 | } | |
172 | ||
173 | // Format of bdb dump is ascii lines: | |
174 | // header lines... | |
175 | // HEADER=END | |
176 | // hexadecimal key | |
177 | // hexadecimal value | |
178 | // ... repeated | |
179 | // DATA=END | |
180 | ||
181 | string strLine; | |
182 | while (!strDump.eof() && strLine != "HEADER=END") | |
183 | getline(strDump, strLine); // Skip past header | |
184 | ||
185 | std::string keyHex, valueHex; | |
186 | while (!strDump.eof() && keyHex != "DATA=END") | |
187 | { | |
188 | getline(strDump, keyHex); | |
189 | if (keyHex != "DATA_END") | |
190 | { | |
191 | getline(strDump, valueHex); | |
192 | vResult.push_back(make_pair(ParseHex(keyHex),ParseHex(valueHex))); | |
193 | } | |
194 | } | |
195 | ||
196 | return (result == 0); | |
197 | } | |
198 | ||
199 | ||
cd9696fc JG |
200 | void CDBEnv::CheckpointLSN(std::string strFile) |
201 | { | |
202 | dbenv.txn_checkpoint(0, 0, 0); | |
148e107d LD |
203 | if (fMockDb) |
204 | return; | |
cd9696fc JG |
205 | dbenv.lsn_reset(strFile.c_str(), 0); |
206 | } | |
0a61b0df | 207 | |
208 | ||
94e34fa0 JG |
209 | CDB::CDB(const char *pszFile, const char* pszMode) : |
210 | pdb(NULL), activeTxn(NULL) | |
0a61b0df | 211 | { |
212 | int ret; | |
213 | if (pszFile == NULL) | |
214 | return; | |
215 | ||
216 | fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); | |
217 | bool fCreate = strchr(pszMode, 'c'); | |
218 | unsigned int nFlags = DB_THREAD; | |
219 | if (fCreate) | |
220 | nFlags |= DB_CREATE; | |
221 | ||
0a61b0df | 222 | { |
cd9696fc JG |
223 | LOCK(bitdb.cs_db); |
224 | if (!bitdb.Open(GetDataDir())) | |
225 | throw runtime_error("env open failed"); | |
0a61b0df | 226 | |
227 | strFile = pszFile; | |
ffe8b77a JG |
228 | ++bitdb.mapFileUseCount[strFile]; |
229 | pdb = bitdb.mapDb[strFile]; | |
0a61b0df | 230 | if (pdb == NULL) |
231 | { | |
cd9696fc | 232 | pdb = new Db(&bitdb.dbenv, 0); |
0a61b0df | 233 | |
148e107d LD |
234 | bool fMockDb = bitdb.IsMock(); |
235 | if (fMockDb) | |
236 | { | |
237 | DbMpoolFile*mpf = pdb->get_mpf(); | |
238 | ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); | |
239 | if (ret != 0) | |
240 | throw runtime_error(strprintf("CDB() : failed to configure for no temp file backing for database %s", pszFile)); | |
241 | } | |
242 | ||
0a61b0df | 243 | ret = pdb->open(NULL, // Txn pointer |
148e107d | 244 | fMockDb ? NULL : pszFile, // Filename |
450cbb09 | 245 | fMockDb ? pszFile : "main", // Logical db name |
0a61b0df | 246 | DB_BTREE, // Database type |
247 | nFlags, // Flags | |
248 | 0); | |
249 | ||
8d5f461c | 250 | if (ret != 0) |
0a61b0df | 251 | { |
252 | delete pdb; | |
253 | pdb = NULL; | |
028ec224 | 254 | --bitdb.mapFileUseCount[strFile]; |
0a61b0df | 255 | strFile = ""; |
d743f035 | 256 | throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret)); |
0a61b0df | 257 | } |
258 | ||
259 | if (fCreate && !Exists(string("version"))) | |
260 | { | |
261 | bool fTmp = fReadOnly; | |
262 | fReadOnly = false; | |
f8ded588 | 263 | WriteVersion(CLIENT_VERSION); |
0a61b0df | 264 | fReadOnly = fTmp; |
265 | } | |
266 | ||
ffe8b77a | 267 | bitdb.mapDb[strFile] = pdb; |
0a61b0df | 268 | } |
269 | } | |
270 | } | |
271 | ||
ae8bfd12 | 272 | void CDB::Flush() |
0a61b0df | 273 | { |
8b1202c5 | 274 | if (activeTxn) |
ae8bfd12 | 275 | return; |
0a61b0df | 276 | |
277 | // Flush database activity from memory pool to disk log | |
278 | unsigned int nMinutes = 0; | |
f03304a9 | 279 | if (fReadOnly) |
280 | nMinutes = 1; | |
25c5eca8 | 281 | |
cd9696fc | 282 | bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0); |
ae8bfd12 PW |
283 | } |
284 | ||
285 | void CDB::Close() | |
286 | { | |
287 | if (!pdb) | |
288 | return; | |
289 | if (activeTxn) | |
290 | activeTxn->abort(); | |
291 | activeTxn = NULL; | |
292 | pdb = NULL; | |
293 | ||
294 | Flush(); | |
0a61b0df | 295 | |
f8dcd5ca | 296 | { |
cd9696fc | 297 | LOCK(bitdb.cs_db); |
ffe8b77a | 298 | --bitdb.mapFileUseCount[strFile]; |
f8dcd5ca | 299 | } |
0a61b0df | 300 | } |
301 | ||
ffe8b77a | 302 | void CDBEnv::CloseDb(const string& strFile) |
0a61b0df | 303 | { |
0a61b0df | 304 | { |
f8dcd5ca | 305 | LOCK(cs_db); |
0a61b0df | 306 | if (mapDb[strFile] != NULL) |
307 | { | |
308 | // Close the database handle | |
309 | Db* pdb = mapDb[strFile]; | |
310 | pdb->close(0); | |
311 | delete pdb; | |
312 | mapDb[strFile] = NULL; | |
313 | } | |
314 | } | |
315 | } | |
316 | ||
eed1785f GA |
317 | bool CDBEnv::RemoveDb(const string& strFile) |
318 | { | |
319 | this->CloseDb(strFile); | |
320 | ||
321 | LOCK(cs_db); | |
322 | int rc = dbenv.dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT); | |
323 | return (rc == 0); | |
324 | } | |
325 | ||
d764d916 | 326 | bool CDB::Rewrite(const string& strFile, const char* pszSkip) |
9e9869d0 PW |
327 | { |
328 | while (!fShutdown) | |
329 | { | |
9e9869d0 | 330 | { |
cd9696fc | 331 | LOCK(bitdb.cs_db); |
ffe8b77a | 332 | if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) |
9e9869d0 PW |
333 | { |
334 | // Flush log data to the dat file | |
ffe8b77a | 335 | bitdb.CloseDb(strFile); |
cd9696fc | 336 | bitdb.CheckpointLSN(strFile); |
ffe8b77a | 337 | bitdb.mapFileUseCount.erase(strFile); |
9e9869d0 PW |
338 | |
339 | bool fSuccess = true; | |
d764d916 GA |
340 | printf("Rewriting %s...\n", strFile.c_str()); |
341 | string strFileRes = strFile + ".rewrite"; | |
f53c5ede PW |
342 | { // surround usage of db with extra {} |
343 | CDB db(strFile.c_str(), "r"); | |
cd9696fc | 344 | Db* pdbCopy = new Db(&bitdb.dbenv, 0); |
ea0796bd | 345 | |
f53c5ede PW |
346 | int ret = pdbCopy->open(NULL, // Txn pointer |
347 | strFileRes.c_str(), // Filename | |
348 | "main", // Logical db name | |
349 | DB_BTREE, // Database type | |
350 | DB_CREATE, // Flags | |
351 | 0); | |
352 | if (ret > 0) | |
9e9869d0 | 353 | { |
f53c5ede PW |
354 | printf("Cannot create database file %s\n", strFileRes.c_str()); |
355 | fSuccess = false; | |
356 | } | |
ea0796bd | 357 | |
f53c5ede PW |
358 | Dbc* pcursor = db.GetCursor(); |
359 | if (pcursor) | |
360 | while (fSuccess) | |
d764d916 | 361 | { |
6b6aaa16 PW |
362 | CDataStream ssKey(SER_DISK, CLIENT_VERSION); |
363 | CDataStream ssValue(SER_DISK, CLIENT_VERSION); | |
f53c5ede PW |
364 | int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT); |
365 | if (ret == DB_NOTFOUND) | |
366 | { | |
367 | pcursor->close(); | |
368 | break; | |
369 | } | |
370 | else if (ret != 0) | |
371 | { | |
372 | pcursor->close(); | |
373 | fSuccess = false; | |
374 | break; | |
375 | } | |
376 | if (pszSkip && | |
377 | strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0) | |
378 | continue; | |
379 | if (strncmp(&ssKey[0], "\x07version", 8) == 0) | |
380 | { | |
381 | // Update version: | |
382 | ssValue.clear(); | |
f8ded588 | 383 | ssValue << CLIENT_VERSION; |
f53c5ede PW |
384 | } |
385 | Dbt datKey(&ssKey[0], ssKey.size()); | |
386 | Dbt datValue(&ssValue[0], ssValue.size()); | |
387 | int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE); | |
388 | if (ret2 > 0) | |
389 | fSuccess = false; | |
d764d916 | 390 | } |
f53c5ede PW |
391 | if (fSuccess) |
392 | { | |
393 | db.Close(); | |
ffe8b77a | 394 | bitdb.CloseDb(strFile); |
f53c5ede | 395 | if (pdbCopy->close(0)) |
9e9869d0 | 396 | fSuccess = false; |
f53c5ede | 397 | delete pdbCopy; |
9e9869d0 | 398 | } |
9e9869d0 PW |
399 | } |
400 | if (fSuccess) | |
401 | { | |
cd9696fc | 402 | Db dbA(&bitdb.dbenv, 0); |
9e9869d0 PW |
403 | if (dbA.remove(strFile.c_str(), NULL, 0)) |
404 | fSuccess = false; | |
cd9696fc | 405 | Db dbB(&bitdb.dbenv, 0); |
9e9869d0 PW |
406 | if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) |
407 | fSuccess = false; | |
408 | } | |
409 | if (!fSuccess) | |
d764d916 | 410 | printf("Rewriting of %s FAILED!\n", strFileRes.c_str()); |
9e9869d0 PW |
411 | return fSuccess; |
412 | } | |
413 | } | |
414 | Sleep(100); | |
415 | } | |
416 | return false; | |
417 | } | |
418 | ||
419 | ||
cd9696fc | 420 | void CDBEnv::Flush(bool fShutdown) |
0a61b0df | 421 | { |
53d0e6dd | 422 | int64 nStart = GetTimeMillis(); |
0a61b0df | 423 | // Flush log data to the actual data file |
424 | // on all files that are not in use | |
cd9696fc | 425 | printf("Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started"); |
0a61b0df | 426 | if (!fDbEnvInit) |
427 | return; | |
0a61b0df | 428 | { |
f8dcd5ca | 429 | LOCK(cs_db); |
0a61b0df | 430 | map<string, int>::iterator mi = mapFileUseCount.begin(); |
431 | while (mi != mapFileUseCount.end()) | |
432 | { | |
433 | string strFile = (*mi).first; | |
434 | int nRefCount = (*mi).second; | |
435 | printf("%s refcount=%d\n", strFile.c_str(), nRefCount); | |
436 | if (nRefCount == 0) | |
437 | { | |
438 | // Move log data to the dat file | |
439 | CloseDb(strFile); | |
83743ed6 | 440 | printf("%s checkpoint\n", strFile.c_str()); |
0a61b0df | 441 | dbenv.txn_checkpoint(0, 0, 0); |
92467073 PW |
442 | printf("%s detach\n", strFile.c_str()); |
443 | if (!fMockDb) | |
444 | dbenv.lsn_reset(strFile.c_str(), 0); | |
83743ed6 | 445 | printf("%s closed\n", strFile.c_str()); |
0a61b0df | 446 | mapFileUseCount.erase(mi++); |
447 | } | |
448 | else | |
449 | mi++; | |
450 | } | |
53d0e6dd | 451 | printf("DBFlush(%s)%s ended %15"PRI64d"ms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started", GetTimeMillis() - nStart); |
0a61b0df | 452 | if (fShutdown) |
453 | { | |
454 | char** listp; | |
455 | if (mapFileUseCount.empty()) | |
d764d916 | 456 | { |
0a61b0df | 457 | dbenv.log_archive(&listp, DB_ARCH_REMOVE); |
cd9696fc | 458 | Close(); |
d764d916 | 459 | } |
0a61b0df | 460 | } |
461 | } | |
462 | } | |
463 | ||
464 | ||
465 | ||
466 | ||
467 | ||
468 | ||
9ac282ca JG |
469 | |
470 | ||
471 | ||
0a61b0df | 472 | |
473 | ||
474 | // | |
475 | // CAddrDB | |
476 | // | |
477 | ||
928d3a01 JG |
478 | |
479 | CAddrDB::CAddrDB() | |
5fee401f | 480 | { |
928d3a01 | 481 | pathAddr = GetDataDir() / "peers.dat"; |
5fee401f PW |
482 | } |
483 | ||
928d3a01 | 484 | bool CAddrDB::Write(const CAddrMan& addr) |
0a61b0df | 485 | { |
928d3a01 JG |
486 | // Generate random temporary filename |
487 | unsigned short randv = 0; | |
488 | RAND_bytes((unsigned char *)&randv, sizeof(randv)); | |
489 | std::string tmpfn = strprintf("peers.dat.%04x", randv); | |
490 | ||
491 | // serialize addresses, checksum data up to that point, then append csum | |
492 | CDataStream ssPeers(SER_DISK, CLIENT_VERSION); | |
493 | ssPeers << FLATDATA(pchMessageStart); | |
494 | ssPeers << addr; | |
495 | uint256 hash = Hash(ssPeers.begin(), ssPeers.end()); | |
496 | ssPeers << hash; | |
497 | ||
498 | // open temp output file, and associate with CAutoFile | |
499 | boost::filesystem::path pathTmp = GetDataDir() / tmpfn; | |
500 | FILE *file = fopen(pathTmp.string().c_str(), "wb"); | |
501 | CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION); | |
502 | if (!fileout) | |
503 | return error("CAddrman::Write() : open failed"); | |
504 | ||
505 | // Write and commit header, data | |
506 | try { | |
507 | fileout << ssPeers; | |
5fee401f | 508 | } |
928d3a01 JG |
509 | catch (std::exception &e) { |
510 | return error("CAddrman::Write() : I/O error"); | |
511 | } | |
512 | FileCommit(fileout); | |
513 | fileout.fclose(); | |
5fee401f | 514 | |
928d3a01 JG |
515 | // replace existing peers.dat, if any, with new peers.dat.XXXX |
516 | if (!RenameOver(pathTmp, pathAddr)) | |
517 | return error("CAddrman::Write() : Rename-into-place failed"); | |
5fee401f | 518 | |
928d3a01 JG |
519 | return true; |
520 | } | |
0a61b0df | 521 | |
928d3a01 JG |
522 | bool CAddrDB::Read(CAddrMan& addr) |
523 | { | |
524 | // open input file, and associate with CAutoFile | |
525 | FILE *file = fopen(pathAddr.string().c_str(), "rb"); | |
526 | CAutoFile filein = CAutoFile(file, SER_DISK, CLIENT_VERSION); | |
527 | if (!filein) | |
528 | return error("CAddrman::Read() : open failed"); | |
529 | ||
530 | // use file size to size memory buffer | |
531 | int fileSize = GetFilesize(filein); | |
532 | int dataSize = fileSize - sizeof(uint256); | |
533 | vector<unsigned char> vchData; | |
534 | vchData.resize(dataSize); | |
535 | uint256 hashIn; | |
536 | ||
537 | // read data and checksum from file | |
538 | try { | |
539 | filein.read((char *)&vchData[0], dataSize); | |
540 | filein >> hashIn; | |
5fee401f | 541 | } |
928d3a01 JG |
542 | catch (std::exception &e) { |
543 | return error("CAddrman::Read() 2 : I/O error or stream data corrupted"); | |
544 | } | |
545 | filein.fclose(); | |
0a61b0df | 546 | |
928d3a01 | 547 | CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION); |
53cb1a49 | 548 | |
928d3a01 JG |
549 | // verify stored checksum matches input data |
550 | uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end()); | |
551 | if (hashIn != hashTmp) | |
552 | return error("CAddrman::Read() : checksum mismatch; data corrupted"); | |
0a61b0df | 553 | |
928d3a01 JG |
554 | unsigned char pchMsgTmp[4]; |
555 | try { | |
bd2e1405 | 556 | // de-serialize file header (pchMessageStart magic number) and |
928d3a01 | 557 | ssPeers >> FLATDATA(pchMsgTmp); |
bd2e1405 JG |
558 | |
559 | // verify the network matches ours | |
560 | if (memcmp(pchMsgTmp, pchMessageStart, sizeof(pchMsgTmp))) | |
561 | return error("CAddrman::Read() : invalid network magic number"); | |
562 | ||
563 | // de-serialize address data into one CAddrMan object | |
928d3a01 JG |
564 | ssPeers >> addr; |
565 | } | |
566 | catch (std::exception &e) { | |
567 | return error("CAddrman::Read() : I/O error or stream data corrupted"); | |
568 | } | |
0a61b0df | 569 | |
928d3a01 JG |
570 | return true; |
571 | } | |
0a61b0df | 572 |