diff options
| author | Bitflash-sh <btf01@proton.me> | 2026-07-24 11:18:11 -0300 |
|---|---|---|
| committer | Bitflash-sh <btf01@proton.me> | 2026-07-24 11:18:11 -0300 |
| commit | 51d617e70f90a972185917ea0096c1ecef2bfa8b (patch) | |
| tree | 9fbbcd867de9de9d0776afdd02f594ba312c46eb /src/db.cpp | |
Bitflash: fair-launch release
Satoshi's bitcoin-0.1.0 reborn with RandomX CPU proof of work, anonymous .btf
addressing over Nostr with CGNAT rendezvous, automatic peer discovery, a
headless Linux node, and Windows GUI wallet. Fair launch, no premine, 21M cap.
Diffstat (limited to 'src/db.cpp')
| -rw-r--r-- | src/db.cpp | 604 |
1 files changed, 604 insertions, 0 deletions
diff --git a/src/db.cpp b/src/db.cpp new file mode 100644 index 0000000..0df68fc --- /dev/null +++ b/src/db.cpp | |||
| @@ -0,0 +1,604 @@ | |||
| 1 | // Copyright (c) 2009 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 | |||
| 5 | #include "headers.h" | ||
| 6 | |||
| 7 | |||
| 8 | |||
| 9 | |||
| 10 | |||
| 11 | |||
| 12 | // | ||
| 13 | // CDB | ||
| 14 | // | ||
| 15 | |||
| 16 | static CCriticalSection cs_db; | ||
| 17 | static bool fDbEnvInit = false; | ||
| 18 | DbEnv dbenv(0u); | ||
| 19 | static map<string, int> mapFileUseCount; | ||
| 20 | |||
| 21 | class CDBInit | ||
| 22 | { | ||
| 23 | public: | ||
| 24 | CDBInit() | ||
| 25 | { | ||
| 26 | } | ||
| 27 | ~CDBInit() | ||
| 28 | { | ||
| 29 | if (fDbEnvInit) | ||
| 30 | { | ||
| 31 | dbenv.close(0); | ||
| 32 | fDbEnvInit = false; | ||
| 33 | } | ||
| 34 | } | ||
| 35 | } | ||
| 36 | instance_of_cdbinit; | ||
| 37 | |||
| 38 | |||
| 39 | CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) | ||
| 40 | { | ||
| 41 | int ret; | ||
| 42 | if (pszFile == NULL) | ||
| 43 | return; | ||
| 44 | |||
| 45 | bool fCreate = strchr(pszMode, 'c'); | ||
| 46 | bool fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); | ||
| 47 | unsigned int nFlags = DB_THREAD; | ||
| 48 | if (fCreate) | ||
| 49 | nFlags |= DB_CREATE; | ||
| 50 | else if (fReadOnly) | ||
| 51 | nFlags |= DB_RDONLY; | ||
| 52 | if (!fReadOnly || fTxn) | ||
| 53 | nFlags |= DB_AUTO_COMMIT; | ||
| 54 | |||
| 55 | CRITICAL_BLOCK(cs_db) | ||
| 56 | { | ||
| 57 | if (!fDbEnvInit) | ||
| 58 | { | ||
| 59 | string strAppDir = GetAppDir(); | ||
| 60 | string strLogDir = strAppDir + "/database"; | ||
| 61 | _mkdir(strLogDir.c_str()); | ||
| 62 | printf("dbenv.open strAppDir=%s\n", strAppDir.c_str()); | ||
| 63 | |||
| 64 | dbenv.set_lg_dir(strLogDir.c_str()); | ||
| 65 | dbenv.set_lg_max(10000000); | ||
| 66 | dbenv.set_lk_max_locks(10000); | ||
| 67 | dbenv.set_lk_max_objects(10000); | ||
| 68 | dbenv.set_errfile(fopen("db.log", "a")); /// debug | ||
| 69 | ///dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); /// causes corruption | ||
| 70 | ret = dbenv.open(strAppDir.c_str(), | ||
| 71 | DB_CREATE | | ||
| 72 | DB_INIT_LOCK | | ||
| 73 | DB_INIT_LOG | | ||
| 74 | DB_INIT_MPOOL | | ||
| 75 | DB_INIT_TXN | | ||
| 76 | DB_THREAD | | ||
| 77 | DB_PRIVATE | | ||
| 78 | DB_RECOVER, | ||
| 79 | 0); | ||
| 80 | if (ret > 0) | ||
| 81 | throw runtime_error(strprintf("CDB() : error %d opening database environment\n", ret)); | ||
| 82 | fDbEnvInit = true; | ||
| 83 | } | ||
| 84 | |||
| 85 | strFile = pszFile; | ||
| 86 | ++mapFileUseCount[strFile]; | ||
| 87 | } | ||
| 88 | |||
| 89 | pdb = new Db(&dbenv, 0); | ||
| 90 | |||
| 91 | ret = pdb->open(NULL, // Txn pointer | ||
| 92 | pszFile, // Filename | ||
| 93 | "main", // Logical db name | ||
| 94 | DB_BTREE, // Database type | ||
| 95 | nFlags, // Flags | ||
| 96 | 0); | ||
| 97 | |||
| 98 | if (ret > 0) | ||
| 99 | { | ||
| 100 | delete pdb; | ||
| 101 | pdb = NULL; | ||
| 102 | CRITICAL_BLOCK(cs_db) | ||
| 103 | --mapFileUseCount[strFile]; | ||
| 104 | strFile = ""; | ||
| 105 | throw runtime_error(strprintf("CDB() : can't open database file %s, error %d\n", pszFile, ret)); | ||
| 106 | } | ||
| 107 | |||
| 108 | if (fCreate && !Exists(string("version"))) | ||
| 109 | WriteVersion(VERSION); | ||
| 110 | |||
| 111 | RandAddSeed(); | ||
| 112 | } | ||
| 113 | |||
| 114 | void CDB::Close() | ||
| 115 | { | ||
| 116 | if (!pdb) | ||
| 117 | return; | ||
| 118 | if (!vTxn.empty()) | ||
| 119 | vTxn.front()->abort(); | ||
| 120 | vTxn.clear(); | ||
| 121 | pdb->close(0); | ||
| 122 | delete pdb; | ||
| 123 | pdb = NULL; | ||
| 124 | dbenv.txn_checkpoint(0, 0, 0); | ||
| 125 | |||
| 126 | CRITICAL_BLOCK(cs_db) | ||
| 127 | --mapFileUseCount[strFile]; | ||
| 128 | |||
| 129 | RandAddSeed(); | ||
| 130 | } | ||
| 131 | |||
| 132 | void DBFlush(bool fShutdown) | ||
| 133 | { | ||
| 134 | // Flush log data to the actual data file | ||
| 135 | // on all files that are not in use | ||
| 136 | printf("DBFlush(%s)\n", fShutdown ? "true" : "false"); | ||
| 137 | CRITICAL_BLOCK(cs_db) | ||
| 138 | { | ||
| 139 | dbenv.txn_checkpoint(0, 0, 0); | ||
| 140 | map<string, int>::iterator mi = mapFileUseCount.begin(); | ||
| 141 | while (mi != mapFileUseCount.end()) | ||
| 142 | { | ||
| 143 | string strFile = (*mi).first; | ||
| 144 | int nRefCount = (*mi).second; | ||
| 145 | if (nRefCount == 0) | ||
| 146 | { | ||
| 147 | dbenv.lsn_reset(strFile.c_str(), 0); | ||
| 148 | mapFileUseCount.erase(mi++); | ||
| 149 | } | ||
| 150 | else | ||
| 151 | mi++; | ||
| 152 | } | ||
| 153 | if (fShutdown) | ||
| 154 | { | ||
| 155 | char** listp; | ||
| 156 | if (mapFileUseCount.empty()) | ||
| 157 | dbenv.log_archive(&listp, DB_ARCH_REMOVE); | ||
| 158 | dbenv.close(0); | ||
| 159 | fDbEnvInit = false; | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | |||
| 165 | |||
| 166 | |||
| 167 | |||
| 168 | |||
| 169 | // | ||
| 170 | // CTxDB | ||
| 171 | // | ||
| 172 | |||
| 173 | bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex) | ||
| 174 | { | ||
| 175 | assert(!fClient); | ||
| 176 | txindex.SetNull(); | ||
| 177 | return Read(make_pair(string("tx"), hash), txindex); | ||
| 178 | } | ||
| 179 | |||
| 180 | bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex) | ||
| 181 | { | ||
| 182 | assert(!fClient); | ||
| 183 | return Write(make_pair(string("tx"), hash), txindex); | ||
| 184 | } | ||
| 185 | |||
| 186 | bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight) | ||
| 187 | { | ||
| 188 | assert(!fClient); | ||
| 189 | |||
| 190 | // Add to tx index | ||
| 191 | uint256 hash = tx.GetHash(); | ||
| 192 | CTxIndex txindex(pos, tx.vout.size()); | ||
| 193 | return Write(make_pair(string("tx"), hash), txindex); | ||
| 194 | } | ||
| 195 | |||
| 196 | bool CTxDB::EraseTxIndex(const CTransaction& tx) | ||
| 197 | { | ||
| 198 | assert(!fClient); | ||
| 199 | uint256 hash = tx.GetHash(); | ||
| 200 | |||
| 201 | return Erase(make_pair(string("tx"), hash)); | ||
| 202 | } | ||
| 203 | |||
| 204 | bool CTxDB::ContainsTx(uint256 hash) | ||
| 205 | { | ||
| 206 | assert(!fClient); | ||
| 207 | return Exists(make_pair(string("tx"), hash)); | ||
| 208 | } | ||
| 209 | |||
| 210 | bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>& vtx) | ||
| 211 | { | ||
| 212 | assert(!fClient); | ||
| 213 | vtx.clear(); | ||
| 214 | |||
| 215 | // Get cursor | ||
| 216 | Dbc* pcursor = GetCursor(); | ||
| 217 | if (!pcursor) | ||
| 218 | return false; | ||
| 219 | |||
| 220 | unsigned int fFlags = DB_SET_RANGE; | ||
| 221 | loop | ||
| 222 | { | ||
| 223 | // Read next record | ||
| 224 | CDataStream ssKey; | ||
| 225 | if (fFlags == DB_SET_RANGE) | ||
| 226 | ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0); | ||
| 227 | CDataStream ssValue; | ||
| 228 | int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); | ||
| 229 | fFlags = DB_NEXT; | ||
| 230 | if (ret == DB_NOTFOUND) | ||
| 231 | break; | ||
| 232 | else if (ret != 0) | ||
| 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 | |||
| 243 | // Read transaction | ||
| 244 | if (strType != "owner" || hashItem != hash160) | ||
| 245 | break; | ||
| 246 | if (nItemHeight >= nMinHeight) | ||
| 247 | { | ||
| 248 | vtx.resize(vtx.size()+1); | ||
| 249 | if (!vtx.back().ReadFromDisk(pos)) | ||
| 250 | return false; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | return true; | ||
| 254 | } | ||
| 255 | |||
| 256 | bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex) | ||
| 257 | { | ||
| 258 | assert(!fClient); | ||
| 259 | tx.SetNull(); | ||
| 260 | if (!ReadTxIndex(hash, txindex)) | ||
| 261 | return false; | ||
| 262 | return (tx.ReadFromDisk(txindex.pos)); | ||
| 263 | } | ||
| 264 | |||
| 265 | bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx) | ||
| 266 | { | ||
| 267 | CTxIndex txindex; | ||
| 268 | return ReadDiskTx(hash, tx, txindex); | ||
| 269 | } | ||
| 270 | |||
| 271 | bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex) | ||
| 272 | { | ||
| 273 | return ReadDiskTx(outpoint.hash, tx, txindex); | ||
| 274 | } | ||
| 275 | |||
| 276 | bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx) | ||
| 277 | { | ||
| 278 | CTxIndex txindex; | ||
| 279 | return ReadDiskTx(outpoint.hash, tx, txindex); | ||
| 280 | } | ||
| 281 | |||
| 282 | bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) | ||
| 283 | { | ||
| 284 | return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex); | ||
| 285 | } | ||
| 286 | |||
| 287 | bool CTxDB::EraseBlockIndex(uint256 hash) | ||
| 288 | { | ||
| 289 | return Erase(make_pair(string("blockindex"), hash)); | ||
| 290 | } | ||
| 291 | |||
| 292 | bool CTxDB::ReadHashBestChain(uint256& hashBestChain) | ||
| 293 | { | ||
| 294 | return Read(string("hashBestChain"), hashBestChain); | ||
| 295 | } | ||
| 296 | |||
| 297 | bool CTxDB::WriteHashBestChain(uint256 hashBestChain) | ||
| 298 | { | ||
| 299 | return Write(string("hashBestChain"), hashBestChain); | ||
| 300 | } | ||
| 301 | |||
| 302 | CBlockIndex* InsertBlockIndex(uint256 hash) | ||
| 303 | { | ||
| 304 | if (hash == 0) | ||
| 305 | return NULL; | ||
| 306 | |||
| 307 | // Return existing | ||
| 308 | map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash); | ||
| 309 | if (mi != mapBlockIndex.end()) | ||
| 310 | return (*mi).second; | ||
| 311 | |||
| 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 | |||
| 319 | return pindexNew; | ||
| 320 | } | ||
| 321 | |||
| 322 | bool CTxDB::LoadBlockIndex() | ||
| 323 | { | ||
| 324 | // Get cursor | ||
| 325 | Dbc* pcursor = GetCursor(); | ||
| 326 | if (!pcursor) | ||
| 327 | return false; | ||
| 328 | |||
| 329 | unsigned int fFlags = DB_SET_RANGE; | ||
| 330 | loop | ||
| 331 | { | ||
| 332 | // Read next record | ||
| 333 | CDataStream ssKey; | ||
| 334 | if (fFlags == DB_SET_RANGE) | ||
| 335 | ssKey << make_pair(string("blockindex"), uint256(0)); | ||
| 336 | CDataStream ssValue; | ||
| 337 | int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); | ||
| 338 | fFlags = DB_NEXT; | ||
| 339 | if (ret == DB_NOTFOUND) | ||
| 340 | break; | ||
| 341 | else if (ret != 0) | ||
| 342 | return false; | ||
| 343 | |||
| 344 | // Unserialize | ||
| 345 | string strType; | ||
| 346 | ssKey >> strType; | ||
| 347 | if (strType == "blockindex") | ||
| 348 | { | ||
| 349 | CDiskBlockIndex diskindex; | ||
| 350 | ssValue >> diskindex; | ||
| 351 | |||
| 352 | // Construct block index object | ||
| 353 | CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); | ||
| 354 | pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); | ||
| 355 | pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); | ||
| 356 | pindexNew->nFile = diskindex.nFile; | ||
| 357 | pindexNew->nBlockPos = diskindex.nBlockPos; | ||
| 358 | pindexNew->nHeight = diskindex.nHeight; | ||
| 359 | pindexNew->nVersion = diskindex.nVersion; | ||
| 360 | pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; | ||
| 361 | pindexNew->nTime = diskindex.nTime; | ||
| 362 | pindexNew->nBits = diskindex.nBits; | ||
| 363 | pindexNew->nNonce = diskindex.nNonce; | ||
| 364 | |||
| 365 | // Watch for genesis block and best block | ||
| 366 | if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock) | ||
| 367 | pindexGenesisBlock = pindexNew; | ||
| 368 | } | ||
| 369 | else | ||
| 370 | { | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | if (!ReadHashBestChain(hashBestChain)) | ||
| 376 | { | ||
| 377 | if (pindexGenesisBlock == NULL) | ||
| 378 | return true; | ||
| 379 | return error("CTxDB::LoadBlockIndex() : hashBestChain not found\n"); | ||
| 380 | } | ||
| 381 | |||
| 382 | if (!mapBlockIndex.count(hashBestChain)) | ||
| 383 | return error("CTxDB::LoadBlockIndex() : blockindex for hashBestChain not found\n"); | ||
| 384 | pindexBest = mapBlockIndex[hashBestChain]; | ||
| 385 | nBestHeight = pindexBest->nHeight; | ||
| 386 | printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,14).c_str(), nBestHeight); | ||
| 387 | |||
| 388 | return true; | ||
| 389 | } | ||
| 390 | |||
| 391 | |||
| 392 | |||
| 393 | |||
| 394 | |||
| 395 | // | ||
| 396 | // CAddrDB | ||
| 397 | // | ||
| 398 | |||
| 399 | bool CAddrDB::WriteAddress(const CAddress& addr) | ||
| 400 | { | ||
| 401 | return Write(make_pair(string("addr"), addr.GetKey()), addr); | ||
| 402 | } | ||
| 403 | |||
| 404 | bool CAddrDB::LoadAddresses() | ||
| 405 | { | ||
| 406 | CRITICAL_BLOCK(cs_mapAddresses) | ||
| 407 | { | ||
| 408 | // Load user provided addresses | ||
| 409 | CAutoFile filein = fopen("addr.txt", "rt"); | ||
| 410 | if (filein) | ||
| 411 | { | ||
| 412 | try | ||
| 413 | { | ||
| 414 | char psz[1000]; | ||
| 415 | while (fgets(psz, sizeof(psz), filein)) | ||
| 416 | { | ||
| 417 | CAddress addr(psz, NODE_NETWORK); | ||
| 418 | if (addr.ip != 0) | ||
| 419 | AddAddress(*this, addr); | ||
| 420 | } | ||
| 421 | } | ||
| 422 | catch (...) { } | ||
| 423 | } | ||
| 424 | |||
| 425 | // Get cursor | ||
| 426 | Dbc* pcursor = GetCursor(); | ||
| 427 | if (!pcursor) | ||
| 428 | return false; | ||
| 429 | |||
| 430 | loop | ||
| 431 | { | ||
| 432 | // Read next record | ||
| 433 | CDataStream ssKey; | ||
| 434 | CDataStream ssValue; | ||
| 435 | int ret = ReadAtCursor(pcursor, ssKey, ssValue); | ||
| 436 | if (ret == DB_NOTFOUND) | ||
| 437 | break; | ||
| 438 | else if (ret != 0) | ||
| 439 | return false; | ||
| 440 | |||
| 441 | // Unserialize | ||
| 442 | string strType; | ||
| 443 | ssKey >> strType; | ||
| 444 | if (strType == "addr") | ||
| 445 | { | ||
| 446 | CAddress addr; | ||
| 447 | ssValue >> addr; | ||
| 448 | mapAddresses.insert(make_pair(addr.GetKey(), addr)); | ||
| 449 | } | ||
| 450 | } | ||
| 451 | |||
| 452 | //// debug print | ||
| 453 | printf("mapAddresses:\n"); | ||
| 454 | foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses) | ||
| 455 | item.second.print(); | ||
| 456 | printf("-----\n"); | ||
| 457 | } | ||
| 458 | |||
| 459 | return true; | ||
| 460 | } | ||
| 461 | |||
| 462 | bool LoadAddresses() | ||
| 463 | { | ||
| 464 | return CAddrDB("cr+").LoadAddresses(); | ||
| 465 | } | ||
| 466 | |||
| 467 | |||
| 468 | |||
| 469 | |||
| 470 | // | ||
| 471 | // CReviewDB | ||
| 472 | // | ||
| 473 | |||
| 474 | bool CReviewDB::ReadReviews(uint256 hash, vector<CReview>& vReviews) | ||
| 475 | { | ||
| 476 | vReviews.size(); // msvc workaround, just need to do anything with vReviews | ||
| 477 | return Read(make_pair(string("reviews"), hash), vReviews); | ||
| 478 | } | ||
| 479 | |||
| 480 | bool CReviewDB::WriteReviews(uint256 hash, const vector<CReview>& vReviews) | ||
| 481 | { | ||
| 482 | return Write(make_pair(string("reviews"), hash), vReviews); | ||
| 483 | } | ||
| 484 | |||
| 485 | |||
| 486 | |||
| 487 | |||
| 488 | |||
| 489 | |||
| 490 | |||
| 491 | // | ||
| 492 | // CWalletDB | ||
| 493 | // | ||
| 494 | |||
| 495 | bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet) | ||
| 496 | { | ||
| 497 | vchDefaultKeyRet.clear(); | ||
| 498 | |||
| 499 | //// todo: shouldn't we catch exceptions and try to recover and continue? | ||
| 500 | CRITICAL_BLOCK(cs_mapKeys) | ||
| 501 | CRITICAL_BLOCK(cs_mapWallet) | ||
| 502 | { | ||
| 503 | // Get cursor | ||
| 504 | Dbc* pcursor = GetCursor(); | ||
| 505 | if (!pcursor) | ||
| 506 | return false; | ||
| 507 | |||
| 508 | loop | ||
| 509 | { | ||
| 510 | // Read next record | ||
| 511 | CDataStream ssKey; | ||
| 512 | CDataStream ssValue; | ||
| 513 | int ret = ReadAtCursor(pcursor, ssKey, ssValue); | ||
| 514 | if (ret == DB_NOTFOUND) | ||
| 515 | break; | ||
| 516 | else if (ret != 0) | ||
| 517 | return false; | ||
| 518 | |||
| 519 | // Unserialize | ||
| 520 | // Taking advantage of the fact that pair serialization | ||
| 521 | // is just the two items serialized one after the other | ||
| 522 | string strType; | ||
| 523 | ssKey >> strType; | ||
| 524 | if (strType == "name") | ||
| 525 | { | ||
| 526 | string strAddress; | ||
| 527 | ssKey >> strAddress; | ||
| 528 | ssValue >> mapAddressBook[strAddress]; | ||
| 529 | } | ||
| 530 | else if (strType == "tx") | ||
| 531 | { | ||
| 532 | uint256 hash; | ||
| 533 | ssKey >> hash; | ||
| 534 | CWalletTx& wtx = mapWallet[hash]; | ||
| 535 | ssValue >> wtx; | ||
| 536 | |||
| 537 | if (wtx.GetHash() != hash) | ||
| 538 | printf("Error in wallet.dat, hash mismatch\n"); | ||
| 539 | |||
| 540 | //// debug print | ||
| 541 | //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str()); | ||
| 542 | //printf(" %12I64d %s %s %s\n", | ||
| 543 | // wtx.vout[0].nValue, | ||
| 544 | // DateTimeStr(wtx.nTime).c_str(), | ||
| 545 | // wtx.hashBlock.ToString().substr(0,14).c_str(), | ||
| 546 | // wtx.mapValue["message"].c_str()); | ||
| 547 | } | ||
| 548 | else if (strType == "key") | ||
| 549 | { | ||
| 550 | vector<unsigned char> vchPubKey; | ||
| 551 | ssKey >> vchPubKey; | ||
| 552 | CPrivKey vchPrivKey; | ||
| 553 | ssValue >> vchPrivKey; | ||
| 554 | |||
| 555 | mapKeys[vchPubKey] = vchPrivKey; | ||
| 556 | mapPubKeys[Hash160(vchPubKey)] = vchPubKey; | ||
| 557 | } | ||
| 558 | else if (strType == "defaultkey") | ||
| 559 | { | ||
| 560 | ssValue >> vchDefaultKeyRet; | ||
| 561 | } | ||
| 562 | else if (strType == "setting") /// or settings or option or options or config? | ||
| 563 | { | ||
| 564 | string strKey; | ||
| 565 | ssKey >> strKey; | ||
| 566 | if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins; | ||
| 567 | if (strKey == "nTransactionFee") ssValue >> nTransactionFee; | ||
| 568 | if (strKey == "addrIncoming") ssValue >> addrIncoming; | ||
| 569 | } | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 573 | printf("fGenerateBitcoins = %d\n", fGenerateBitcoins); | ||
| 574 | printf("nTransactionFee = %I64d\n", nTransactionFee); | ||
| 575 | printf("addrIncoming = %s\n", addrIncoming.ToString().c_str()); | ||
| 576 | |||
| 577 | return true; | ||
| 578 | } | ||
| 579 | |||
| 580 | bool LoadWallet() | ||
| 581 | { | ||
| 582 | vector<unsigned char> vchDefaultKey; | ||
| 583 | if (!CWalletDB("cr").LoadWallet(vchDefaultKey)) | ||
| 584 | return false; | ||
| 585 | |||
| 586 | if (mapKeys.count(vchDefaultKey)) | ||
| 587 | { | ||
| 588 | // Set keyUser | ||
| 589 | keyUser.SetPubKey(vchDefaultKey); | ||
| 590 | keyUser.SetPrivKey(mapKeys[vchDefaultKey]); | ||
| 591 | } | ||
| 592 | else | ||
| 593 | { | ||
| 594 | // Create new keyUser and set as default key | ||
| 595 | keyUser.MakeNewKey(); | ||
| 596 | if (!AddKey(keyUser)) | ||
| 597 | return false; | ||
| 598 | if (!SetAddressBookName(PubKeyToAddress(keyUser.GetPubKey()), "Your Address")) | ||
| 599 | return false; | ||
| 600 | CWalletDB().WriteDefaultKey(keyUser.GetPubKey()); | ||
| 601 | } | ||
| 602 | |||
| 603 | return true; | ||
| 604 | } | ||