You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

db.cpp 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026
  1. // Copyright (c) 2009-2010 Satoshi Nakamoto
  2. // Distributed under the MIT/X11 software license, see the accompanying
  3. // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  4. #include "headers.h"
  5. using namespace std;
  6. using namespace boost;
  7. void ThreadFlushWalletDB(void* parg);
  8. unsigned int nWalletDBUpdated;
  9. uint64 nAccountingEntryNumber = 0;
  10. //
  11. // CDB
  12. //
  13. static CCriticalSection cs_db;
  14. static bool fDbEnvInit = false;
  15. DbEnv dbenv(0);
  16. static map<string, int> mapFileUseCount;
  17. static map<string, Db*> mapDb;
  18. class CDBInit
  19. {
  20. public:
  21. CDBInit()
  22. {
  23. }
  24. ~CDBInit()
  25. {
  26. if (fDbEnvInit)
  27. {
  28. dbenv.close(0);
  29. fDbEnvInit = false;
  30. }
  31. }
  32. }
  33. instance_of_cdbinit;
  34. CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL)
  35. {
  36. int ret;
  37. if (pszFile == NULL)
  38. return;
  39. fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
  40. bool fCreate = strchr(pszMode, 'c');
  41. unsigned int nFlags = DB_THREAD;
  42. if (fCreate)
  43. nFlags |= DB_CREATE;
  44. CRITICAL_BLOCK(cs_db)
  45. {
  46. if (!fDbEnvInit)
  47. {
  48. if (fShutdown)
  49. return;
  50. string strDataDir = GetDataDir();
  51. string strLogDir = strDataDir + "/database";
  52. filesystem::create_directory(strLogDir.c_str());
  53. string strErrorFile = strDataDir + "/db.log";
  54. printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str());
  55. dbenv.set_lg_dir(strLogDir.c_str());
  56. dbenv.set_lg_max(10000000);
  57. dbenv.set_lk_max_locks(10000);
  58. dbenv.set_lk_max_objects(10000);
  59. dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug
  60. dbenv.set_flags(DB_AUTO_COMMIT, 1);
  61. ret = dbenv.open(strDataDir.c_str(),
  62. DB_CREATE |
  63. DB_INIT_LOCK |
  64. DB_INIT_LOG |
  65. DB_INIT_MPOOL |
  66. DB_INIT_TXN |
  67. DB_THREAD |
  68. DB_RECOVER,
  69. S_IRUSR | S_IWUSR);
  70. if (ret > 0)
  71. throw runtime_error(strprintf("CDB() : error %d opening database environment", ret));
  72. fDbEnvInit = true;
  73. }
  74. strFile = pszFile;
  75. ++mapFileUseCount[strFile];
  76. pdb = mapDb[strFile];
  77. if (pdb == NULL)
  78. {
  79. pdb = new Db(&dbenv, 0);
  80. ret = pdb->open(NULL, // Txn pointer
  81. pszFile, // Filename
  82. "main", // Logical db name
  83. DB_BTREE, // Database type
  84. nFlags, // Flags
  85. 0);
  86. if (ret > 0)
  87. {
  88. delete pdb;
  89. pdb = NULL;
  90. CRITICAL_BLOCK(cs_db)
  91. --mapFileUseCount[strFile];
  92. strFile = "";
  93. throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret));
  94. }
  95. if (fCreate && !Exists(string("version")))
  96. {
  97. bool fTmp = fReadOnly;
  98. fReadOnly = false;
  99. WriteVersion(VERSION);
  100. fReadOnly = fTmp;
  101. }
  102. mapDb[strFile] = pdb;
  103. }
  104. }
  105. }
  106. void CDB::Close()
  107. {
  108. if (!pdb)
  109. return;
  110. if (!vTxn.empty())
  111. vTxn.front()->abort();
  112. vTxn.clear();
  113. pdb = NULL;
  114. // Flush database activity from memory pool to disk log
  115. unsigned int nMinutes = 0;
  116. if (fReadOnly)
  117. nMinutes = 1;
  118. if (strFile == "addr.dat")
  119. nMinutes = 2;
  120. if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 500 != 0)
  121. nMinutes = 1;
  122. dbenv.txn_checkpoint(0, nMinutes, 0);
  123. CRITICAL_BLOCK(cs_db)
  124. --mapFileUseCount[strFile];
  125. }
  126. void CloseDb(const string& strFile)
  127. {
  128. CRITICAL_BLOCK(cs_db)
  129. {
  130. if (mapDb[strFile] != NULL)
  131. {
  132. // Close the database handle
  133. Db* pdb = mapDb[strFile];
  134. pdb->close(0);
  135. delete pdb;
  136. mapDb[strFile] = NULL;
  137. }
  138. }
  139. }
  140. void DBFlush(bool fShutdown)
  141. {
  142. // Flush log data to the actual data file
  143. // on all files that are not in use
  144. printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started");
  145. if (!fDbEnvInit)
  146. return;
  147. CRITICAL_BLOCK(cs_db)
  148. {
  149. map<string, int>::iterator mi = mapFileUseCount.begin();
  150. while (mi != mapFileUseCount.end())
  151. {
  152. string strFile = (*mi).first;
  153. int nRefCount = (*mi).second;
  154. printf("%s refcount=%d\n", strFile.c_str(), nRefCount);
  155. if (nRefCount == 0)
  156. {
  157. // Move log data to the dat file
  158. CloseDb(strFile);
  159. dbenv.txn_checkpoint(0, 0, 0);
  160. printf("%s flush\n", strFile.c_str());
  161. dbenv.lsn_reset(strFile.c_str(), 0);
  162. mapFileUseCount.erase(mi++);
  163. }
  164. else
  165. mi++;
  166. }
  167. if (fShutdown)
  168. {
  169. char** listp;
  170. if (mapFileUseCount.empty())
  171. dbenv.log_archive(&listp, DB_ARCH_REMOVE);
  172. dbenv.close(0);
  173. fDbEnvInit = false;
  174. }
  175. }
  176. }
  177. //
  178. // CTxDB
  179. //
  180. bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
  181. {
  182. assert(!fClient);
  183. txindex.SetNull();
  184. return Read(make_pair(string("tx"), hash), txindex);
  185. }
  186. bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
  187. {
  188. assert(!fClient);
  189. return Write(make_pair(string("tx"), hash), txindex);
  190. }
  191. bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
  192. {
  193. assert(!fClient);
  194. // Add to tx index
  195. uint256 hash = tx.GetHash();
  196. CTxIndex txindex(pos, tx.vout.size());
  197. return Write(make_pair(string("tx"), hash), txindex);
  198. }
  199. bool CTxDB::EraseTxIndex(const CTransaction& tx)
  200. {
  201. assert(!fClient);
  202. uint256 hash = tx.GetHash();
  203. return Erase(make_pair(string("tx"), hash));
  204. }
  205. bool CTxDB::ContainsTx(uint256 hash)
  206. {
  207. assert(!fClient);
  208. return Exists(make_pair(string("tx"), hash));
  209. }
  210. bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>& vtx)
  211. {
  212. assert(!fClient);
  213. vtx.clear();
  214. // Get cursor
  215. Dbc* pcursor = GetCursor();
  216. if (!pcursor)
  217. return false;
  218. unsigned int fFlags = DB_SET_RANGE;
  219. loop
  220. {
  221. // Read next record
  222. CDataStream ssKey;
  223. if (fFlags == DB_SET_RANGE)
  224. ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0);
  225. CDataStream ssValue;
  226. int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
  227. fFlags = DB_NEXT;
  228. if (ret == DB_NOTFOUND)
  229. break;
  230. else if (ret != 0)
  231. {
  232. pcursor->close();
  233. return false;
  234. }
  235. // Unserialize
  236. string strType;
  237. uint160 hashItem;
  238. CDiskTxPos pos;
  239. ssKey >> strType >> hashItem >> pos;
  240. int nItemHeight;
  241. ssValue >> nItemHeight;
  242. // Read transaction
  243. if (strType != "owner" || hashItem != hash160)
  244. break;
  245. if (nItemHeight >= nMinHeight)
  246. {
  247. vtx.resize(vtx.size()+1);
  248. if (!vtx.back().ReadFromDisk(pos))
  249. {
  250. pcursor->close();
  251. return false;
  252. }
  253. }
  254. }
  255. pcursor->close();
  256. return true;
  257. }
  258. bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
  259. {
  260. assert(!fClient);
  261. tx.SetNull();
  262. if (!ReadTxIndex(hash, txindex))
  263. return false;
  264. return (tx.ReadFromDisk(txindex.pos));
  265. }
  266. bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx)
  267. {
  268. CTxIndex txindex;
  269. return ReadDiskTx(hash, tx, txindex);
  270. }
  271. bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex)
  272. {
  273. return ReadDiskTx(outpoint.hash, tx, txindex);
  274. }
  275. bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx)
  276. {
  277. CTxIndex txindex;
  278. return ReadDiskTx(outpoint.hash, tx, txindex);
  279. }
  280. bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
  281. {
  282. return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
  283. }
  284. bool CTxDB::EraseBlockIndex(uint256 hash)
  285. {
  286. return Erase(make_pair(string("blockindex"), hash));
  287. }
  288. bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
  289. {
  290. return Read(string("hashBestChain"), hashBestChain);
  291. }
  292. bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
  293. {
  294. return Write(string("hashBestChain"), hashBestChain);
  295. }
  296. bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
  297. {
  298. return Read(string("bnBestInvalidWork"), bnBestInvalidWork);
  299. }
  300. bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
  301. {
  302. return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
  303. }
  304. CBlockIndex* InsertBlockIndex(uint256 hash)
  305. {
  306. if (hash == 0)
  307. return NULL;
  308. // Return existing
  309. map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
  310. if (mi != mapBlockIndex.end())
  311. return (*mi).second;
  312. // Create new
  313. CBlockIndex* pindexNew = new CBlockIndex();
  314. if (!pindexNew)
  315. throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
  316. mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
  317. pindexNew->phashBlock = &((*mi).first);
  318. return pindexNew;
  319. }
  320. bool CTxDB::LoadBlockIndex()
  321. {
  322. // Get database cursor
  323. Dbc* pcursor = GetCursor();
  324. if (!pcursor)
  325. return false;
  326. // Load mapBlockIndex
  327. unsigned int fFlags = DB_SET_RANGE;
  328. loop
  329. {
  330. // Read next record
  331. CDataStream ssKey;
  332. if (fFlags == DB_SET_RANGE)
  333. ssKey << make_pair(string("blockindex"), uint256(0));
  334. CDataStream ssValue;
  335. int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
  336. fFlags = DB_NEXT;
  337. if (ret == DB_NOTFOUND)
  338. break;
  339. else if (ret != 0)
  340. return false;
  341. // Unserialize
  342. string strType;
  343. ssKey >> strType;
  344. if (strType == "blockindex")
  345. {
  346. CDiskBlockIndex diskindex;
  347. ssValue >> diskindex;
  348. // Construct block index object
  349. CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
  350. pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
  351. pindexNew->pnext = InsertBlockIndex(diskindex.hashNext);
  352. pindexNew->nFile = diskindex.nFile;
  353. pindexNew->nBlockPos = diskindex.nBlockPos;
  354. pindexNew->nHeight = diskindex.nHeight;
  355. pindexNew->nVersion = diskindex.nVersion;
  356. pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
  357. pindexNew->nTime = diskindex.nTime;
  358. pindexNew->nBits = diskindex.nBits;
  359. pindexNew->nNonce = diskindex.nNonce;
  360. // Watch for genesis block
  361. if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
  362. pindexGenesisBlock = pindexNew;
  363. if (!pindexNew->CheckIndex())
  364. return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
  365. }
  366. else
  367. {
  368. break;
  369. }
  370. }
  371. pcursor->close();
  372. // Calculate bnChainWork
  373. vector<pair<int, CBlockIndex*> > vSortedByHeight;
  374. vSortedByHeight.reserve(mapBlockIndex.size());
  375. BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
  376. {
  377. CBlockIndex* pindex = item.second;
  378. vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
  379. }
  380. sort(vSortedByHeight.begin(), vSortedByHeight.end());
  381. BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
  382. {
  383. CBlockIndex* pindex = item.second;
  384. pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();
  385. }
  386. // Load hashBestChain pointer to end of best chain
  387. if (!ReadHashBestChain(hashBestChain))
  388. {
  389. if (pindexGenesisBlock == NULL)
  390. return true;
  391. return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
  392. }
  393. if (!mapBlockIndex.count(hashBestChain))
  394. return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
  395. pindexBest = mapBlockIndex[hashBestChain];
  396. nBestHeight = pindexBest->nHeight;
  397. bnBestChainWork = pindexBest->bnChainWork;
  398. printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight);
  399. // Load bnBestInvalidWork, OK if it doesn't exist
  400. ReadBestInvalidWork(bnBestInvalidWork);
  401. // Verify blocks in the best chain
  402. CBlockIndex* pindexFork = NULL;
  403. for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
  404. {
  405. if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks"))
  406. break;
  407. CBlock block;
  408. if (!block.ReadFromDisk(pindex))
  409. return error("LoadBlockIndex() : block.ReadFromDisk failed");
  410. if (!block.CheckBlock())
  411. {
  412. printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
  413. pindexFork = pindex->pprev;
  414. }
  415. }
  416. if (pindexFork)
  417. {
  418. // Reorg back to the fork
  419. printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
  420. CBlock block;
  421. if (!block.ReadFromDisk(pindexFork))
  422. return error("LoadBlockIndex() : block.ReadFromDisk failed");
  423. CTxDB txdb;
  424. block.SetBestChain(txdb, pindexFork);
  425. }
  426. return true;
  427. }
  428. //
  429. // CAddrDB
  430. //
  431. bool CAddrDB::WriteAddress(const CAddress& addr)
  432. {
  433. return Write(make_pair(string("addr"), addr.GetKey()), addr);
  434. }
  435. bool CAddrDB::EraseAddress(const CAddress& addr)
  436. {
  437. return Erase(make_pair(string("addr"), addr.GetKey()));
  438. }
  439. bool CAddrDB::LoadAddresses()
  440. {
  441. CRITICAL_BLOCK(cs_mapAddresses)
  442. {
  443. // Load user provided addresses
  444. CAutoFile filein = fopen((GetDataDir() + "/addr.txt").c_str(), "rt");
  445. if (filein)
  446. {
  447. try
  448. {
  449. char psz[1000];
  450. while (fgets(psz, sizeof(psz), filein))
  451. {
  452. CAddress addr(psz, NODE_NETWORK);
  453. addr.nTime = 0; // so it won't relay unless successfully connected
  454. if (addr.IsValid())
  455. AddAddress(addr);
  456. }
  457. }
  458. catch (...) { }
  459. }
  460. // Get cursor
  461. Dbc* pcursor = GetCursor();
  462. if (!pcursor)
  463. return false;
  464. loop
  465. {
  466. // Read next record
  467. CDataStream ssKey;
  468. CDataStream ssValue;
  469. int ret = ReadAtCursor(pcursor, ssKey, ssValue);
  470. if (ret == DB_NOTFOUND)
  471. break;
  472. else if (ret != 0)
  473. return false;
  474. // Unserialize
  475. string strType;
  476. ssKey >> strType;
  477. if (strType == "addr")
  478. {
  479. CAddress addr;
  480. ssValue >> addr;
  481. mapAddresses.insert(make_pair(addr.GetKey(), addr));
  482. }
  483. }
  484. pcursor->close();
  485. printf("Loaded %d addresses\n", mapAddresses.size());
  486. }
  487. return true;
  488. }
  489. bool LoadAddresses()
  490. {
  491. return CAddrDB("cr+").LoadAddresses();
  492. }
  493. //
  494. // CWalletDB
  495. //
  496. static set<int64> setKeyPool;
  497. static CCriticalSection cs_setKeyPool;
  498. bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
  499. {
  500. account.SetNull();
  501. return Read(make_pair(string("acc"), strAccount), account);
  502. }
  503. bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
  504. {
  505. return Write(make_pair(string("acc"), strAccount), account);
  506. }
  507. bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
  508. {
  509. return Write(make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry);
  510. }
  511. int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
  512. {
  513. list<CAccountingEntry> entries;
  514. ListAccountCreditDebit(strAccount, entries);
  515. int64 nCreditDebit = 0;
  516. BOOST_FOREACH (const CAccountingEntry& entry, entries)
  517. nCreditDebit += entry.nCreditDebit;
  518. return nCreditDebit;
  519. }
  520. void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
  521. {
  522. int64 nCreditDebit = 0;
  523. bool fAllAccounts = (strAccount == "*");
  524. Dbc* pcursor = GetCursor();
  525. if (!pcursor)
  526. throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
  527. unsigned int fFlags = DB_SET_RANGE;
  528. loop
  529. {
  530. // Read next record
  531. CDataStream ssKey;
  532. if (fFlags == DB_SET_RANGE)
  533. ssKey << make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0));
  534. CDataStream ssValue;
  535. int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
  536. fFlags = DB_NEXT;
  537. if (ret == DB_NOTFOUND)
  538. break;
  539. else if (ret != 0)
  540. {
  541. pcursor->close();
  542. throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB");
  543. }
  544. // Unserialize
  545. string strType;
  546. ssKey >> strType;
  547. if (strType != "acentry")
  548. break;
  549. CAccountingEntry acentry;
  550. ssKey >> acentry.strAccount;
  551. if (!fAllAccounts && acentry.strAccount != strAccount)
  552. break;
  553. ssValue >> acentry;
  554. entries.push_back(acentry);
  555. }
  556. pcursor->close();
  557. }
  558. bool CWalletDB::LoadWallet()
  559. {
  560. vchDefaultKey.clear();
  561. int nFileVersion = 0;
  562. vector<uint256> vWalletUpgrade;
  563. // Modify defaults
  564. #ifndef __WXMSW__
  565. // Tray icon sometimes disappears on 9.10 karmic koala 64-bit, leaving no way to access the program
  566. fMinimizeToTray = false;
  567. fMinimizeOnClose = false;
  568. #endif
  569. //// todo: shouldn't we catch exceptions and try to recover and continue?
  570. CRITICAL_BLOCK(cs_mapWallet)
  571. CRITICAL_BLOCK(cs_mapKeys)
  572. {
  573. // Get cursor
  574. Dbc* pcursor = GetCursor();
  575. if (!pcursor)
  576. return false;
  577. loop
  578. {
  579. // Read next record
  580. CDataStream ssKey;
  581. CDataStream ssValue;
  582. int ret = ReadAtCursor(pcursor, ssKey, ssValue);
  583. if (ret == DB_NOTFOUND)
  584. break;
  585. else if (ret != 0)
  586. return false;
  587. // Unserialize
  588. // Taking advantage of the fact that pair serialization
  589. // is just the two items serialized one after the other
  590. string strType;
  591. ssKey >> strType;
  592. if (strType == "name")
  593. {
  594. string strAddress;
  595. ssKey >> strAddress;
  596. ssValue >> mapAddressBook[strAddress];
  597. }
  598. else if (strType == "tx")
  599. {
  600. uint256 hash;
  601. ssKey >> hash;
  602. CWalletTx& wtx = mapWallet[hash];
  603. ssValue >> wtx;
  604. if (wtx.GetHash() != hash)
  605. printf("Error in wallet.dat, hash mismatch\n");
  606. // Undo serialize changes in 31600
  607. if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
  608. {
  609. if (!ssValue.empty())
  610. {
  611. char fTmp;
  612. char fUnused;
  613. ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
  614. printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str());
  615. wtx.fTimeReceivedIsTxTime = fTmp;
  616. }
  617. else
  618. {
  619. printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str());
  620. wtx.fTimeReceivedIsTxTime = 0;
  621. }
  622. vWalletUpgrade.push_back(hash);
  623. }
  624. //// debug print
  625. //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str());
  626. //printf(" %12I64d %s %s %s\n",
  627. // wtx.vout[0].nValue,
  628. // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
  629. // wtx.hashBlock.ToString().substr(0,20).c_str(),
  630. // wtx.mapValue["message"].c_str());
  631. }
  632. else if (strType == "acentry")
  633. {
  634. string strAccount;
  635. ssKey >> strAccount;
  636. uint64 nNumber;
  637. ssKey >> nNumber;
  638. if (nNumber > nAccountingEntryNumber)
  639. nAccountingEntryNumber = nNumber;
  640. }
  641. else if (strType == "key" || strType == "wkey")
  642. {
  643. vector<unsigned char> vchPubKey;
  644. ssKey >> vchPubKey;
  645. CWalletKey wkey;
  646. if (strType == "key")
  647. ssValue >> wkey.vchPrivKey;
  648. else
  649. ssValue >> wkey;
  650. mapKeys[vchPubKey] = wkey.vchPrivKey;
  651. mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
  652. }
  653. else if (strType == "defaultkey")
  654. {
  655. ssValue >> vchDefaultKey;
  656. }
  657. else if (strType == "pool")
  658. {
  659. int64 nIndex;
  660. ssKey >> nIndex;
  661. setKeyPool.insert(nIndex);
  662. }
  663. else if (strType == "version")
  664. {
  665. ssValue >> nFileVersion;
  666. if (nFileVersion == 10300)
  667. nFileVersion = 300;
  668. }
  669. else if (strType == "setting")
  670. {
  671. string strKey;
  672. ssKey >> strKey;
  673. // Options
  674. #ifndef GUI
  675. if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins;
  676. #endif
  677. if (strKey == "nTransactionFee") ssValue >> nTransactionFee;
  678. if (strKey == "addrIncoming") ssValue >> addrIncoming;
  679. if (strKey == "fLimitProcessors") ssValue >> fLimitProcessors;
  680. if (strKey == "nLimitProcessors") ssValue >> nLimitProcessors;
  681. if (strKey == "fMinimizeToTray") ssValue >> fMinimizeToTray;
  682. if (strKey == "fMinimizeOnClose") ssValue >> fMinimizeOnClose;
  683. if (strKey == "fUseProxy") ssValue >> fUseProxy;
  684. if (strKey == "addrProxy") ssValue >> addrProxy;
  685. if (fHaveUPnP && strKey == "fUseUPnP") ssValue >> fUseUPnP;
  686. }
  687. }
  688. pcursor->close();
  689. }
  690. BOOST_FOREACH(uint256 hash, vWalletUpgrade)
  691. WriteTx(hash, mapWallet[hash]);
  692. printf("nFileVersion = %d\n", nFileVersion);
  693. printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
  694. printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
  695. printf("addrIncoming = %s\n", addrIncoming.ToString().c_str());
  696. printf("fMinimizeToTray = %d\n", fMinimizeToTray);
  697. printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
  698. printf("fUseProxy = %d\n", fUseProxy);
  699. printf("addrProxy = %s\n", addrProxy.ToString().c_str());
  700. if (fHaveUPnP)
  701. printf("fUseUPnP = %d\n", fUseUPnP);
  702. // Upgrade
  703. if (nFileVersion < VERSION)
  704. {
  705. // Get rid of old debug.log file in current directory
  706. if (nFileVersion <= 105 && !pszSetDataDir[0])
  707. unlink("debug.log");
  708. WriteVersion(VERSION);
  709. }
  710. return true;
  711. }
  712. bool LoadWallet(bool& fFirstRunRet)
  713. {
  714. fFirstRunRet = false;
  715. if (!CWalletDB("cr+").LoadWallet())
  716. return false;
  717. fFirstRunRet = vchDefaultKey.empty();
  718. if (mapKeys.count(vchDefaultKey))
  719. {
  720. // Set keyUser
  721. keyUser.SetPubKey(vchDefaultKey);
  722. keyUser.SetPrivKey(mapKeys[vchDefaultKey]);
  723. }
  724. else
  725. {
  726. // Create new keyUser and set as default key
  727. RandAddSeedPerfmon();
  728. keyUser.MakeNewKey();
  729. if (!AddKey(keyUser))
  730. return false;
  731. if (!SetAddressBookName(PubKeyToAddress(keyUser.GetPubKey()), ""))
  732. return false;
  733. CWalletDB().WriteDefaultKey(keyUser.GetPubKey());
  734. }
  735. CreateThread(ThreadFlushWalletDB, NULL);
  736. return true;
  737. }
  738. void ThreadFlushWalletDB(void* parg)
  739. {
  740. static bool fOneThread;
  741. if (fOneThread)
  742. return;
  743. fOneThread = true;
  744. if (mapArgs.count("-noflushwallet"))
  745. return;
  746. unsigned int nLastSeen = nWalletDBUpdated;
  747. unsigned int nLastFlushed = nWalletDBUpdated;
  748. int64 nLastWalletUpdate = GetTime();
  749. while (!fShutdown)
  750. {
  751. Sleep(500);
  752. if (nLastSeen != nWalletDBUpdated)
  753. {
  754. nLastSeen = nWalletDBUpdated;
  755. nLastWalletUpdate = GetTime();
  756. }
  757. if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
  758. {
  759. TRY_CRITICAL_BLOCK(cs_db)
  760. {
  761. // Don't do this if any databases are in use
  762. int nRefCount = 0;
  763. map<string, int>::iterator mi = mapFileUseCount.begin();
  764. while (mi != mapFileUseCount.end())
  765. {
  766. nRefCount += (*mi).second;
  767. mi++;
  768. }
  769. if (nRefCount == 0 && !fShutdown)
  770. {
  771. string strFile = "wallet.dat";
  772. map<string, int>::iterator mi = mapFileUseCount.find(strFile);
  773. if (mi != mapFileUseCount.end())
  774. {
  775. printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
  776. printf("Flushing wallet.dat\n");
  777. nLastFlushed = nWalletDBUpdated;
  778. int64 nStart = GetTimeMillis();
  779. // Flush wallet.dat so it's self contained
  780. CloseDb(strFile);
  781. dbenv.txn_checkpoint(0, 0, 0);
  782. dbenv.lsn_reset(strFile.c_str(), 0);
  783. mapFileUseCount.erase(mi++);
  784. printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
  785. }
  786. }
  787. }
  788. }
  789. }
  790. }
  791. void BackupWallet(const string& strDest)
  792. {
  793. while (!fShutdown)
  794. {
  795. CRITICAL_BLOCK(cs_db)
  796. {
  797. const string strFile = "wallet.dat";
  798. if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0)
  799. {
  800. // Flush log data to the dat file
  801. CloseDb(strFile);
  802. dbenv.txn_checkpoint(0, 0, 0);
  803. dbenv.lsn_reset(strFile.c_str(), 0);
  804. mapFileUseCount.erase(strFile);
  805. // Copy wallet.dat
  806. filesystem::path pathSrc(GetDataDir() + "/" + strFile);
  807. filesystem::path pathDest(strDest);
  808. if (filesystem::is_directory(pathDest))
  809. pathDest = pathDest / strFile;
  810. #if BOOST_VERSION >= 104000
  811. filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
  812. #else
  813. filesystem::copy_file(pathSrc, pathDest);
  814. #endif
  815. printf("copied wallet.dat to %s\n", pathDest.string().c_str());
  816. return;
  817. }
  818. }
  819. Sleep(100);
  820. }
  821. }
  822. void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
  823. {
  824. nIndex = -1;
  825. keypool.vchPubKey.clear();
  826. CRITICAL_BLOCK(cs_main)
  827. CRITICAL_BLOCK(cs_mapWallet)
  828. CRITICAL_BLOCK(cs_setKeyPool)
  829. {
  830. // Top up key pool
  831. int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
  832. while (setKeyPool.size() < nTargetSize+1)
  833. {
  834. int64 nEnd = 1;
  835. if (!setKeyPool.empty())
  836. nEnd = *(--setKeyPool.end()) + 1;
  837. if (!Write(make_pair(string("pool"), nEnd), CKeyPool(GenerateNewKey())))
  838. throw runtime_error("ReserveKeyFromKeyPool() : writing generated key failed");
  839. setKeyPool.insert(nEnd);
  840. printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
  841. }
  842. // Get the oldest key
  843. assert(!setKeyPool.empty());
  844. nIndex = *(setKeyPool.begin());
  845. setKeyPool.erase(setKeyPool.begin());
  846. if (!Read(make_pair(string("pool"), nIndex), keypool))
  847. throw runtime_error("ReserveKeyFromKeyPool() : read failed");
  848. if (!mapKeys.count(keypool.vchPubKey))
  849. throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
  850. assert(!keypool.vchPubKey.empty());
  851. printf("keypool reserve %"PRI64d"\n", nIndex);
  852. }
  853. }
  854. void CWalletDB::KeepKey(int64 nIndex)
  855. {
  856. // Remove from key pool
  857. CRITICAL_BLOCK(cs_main)
  858. CRITICAL_BLOCK(cs_mapWallet)
  859. {
  860. Erase(make_pair(string("pool"), nIndex));
  861. }
  862. printf("keypool keep %"PRI64d"\n", nIndex);
  863. }
  864. void CWalletDB::ReturnKey(int64 nIndex)
  865. {
  866. // Return to key pool
  867. CRITICAL_BLOCK(cs_setKeyPool)
  868. setKeyPool.insert(nIndex);
  869. printf("keypool return %"PRI64d"\n", nIndex);
  870. }
  871. vector<unsigned char> GetKeyFromKeyPool()
  872. {
  873. CWalletDB walletdb;
  874. int64 nIndex = 0;
  875. CKeyPool keypool;
  876. walletdb.ReserveKeyFromKeyPool(nIndex, keypool);
  877. walletdb.KeepKey(nIndex);
  878. return keypool.vchPubKey;
  879. }
  880. int64 GetOldestKeyPoolTime()
  881. {
  882. CWalletDB walletdb;
  883. int64 nIndex = 0;
  884. CKeyPool keypool;
  885. walletdb.ReserveKeyFromKeyPool(nIndex, keypool);
  886. walletdb.ReturnKey(nIndex);
  887. return keypool.nTime;
  888. }