upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/db.h
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-09-05 22:46:52 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-09-05 22:46:52 +0000
commitceae3d076b5ad11ee84729ae43f14e9312896646 (patch)
tree7e9132aa871fdc01cb95268d2f5ea3bb11853ddf /src/db.h
parentbe63e83d79e7e00e6b8ca889a70e6a19886aa1d8 (diff)
parent66e0b9158d050c46b1ff2509faeee3f4573cac1c (diff)
Bring main onto the line this project actually ships
main had drifted to a history with no ancestor in common with the tree we build and deploy. It sat at be63e83 (2026-08-09) with 28 commits; the shipped line, deploy/soak-2026-08-21, had 383. The two shared nothing -- git merge-base returns no result at all -- so anyone cloning this repository landed on a default branch that was neither current nor related to the running node. The 28 commits on main were audited before this merge: every one is already present in the tree by content, including the two that are hardest to see because they were rewritten afterwards -- the payout reorg-safety work (PayoutBlockStillOnChain, since evolved to re-check on every retry rather than once at maturity) and the nostr relay certificate verification (SSL_set1_host, now with a Windows root-store path). Nothing on main is lost by this merge. Recorded as a merge rather than a force-push: main only ever moves forward, its old history stays reachable as the first parent, and this is revertible. The tree is taken wholesale from the merged branch, so main's content is now exactly what was built and tested. What this brings onto main: - compactblock: BIP152-style compact block relay ported from upstream 1.2.23, primitives and unit test only, with the RAND_bytes failure path closed and the reconstruction allocation bounded. - upstream/main 17741d9: isolated testnet parameters and genesis, optional 2 MB large pages for RandomX. Mainnet genesis verified byte-identical through upstream's BuildGenesisBlock() refactor. - deploy: every image built on bookworm so binaries run on Debian 12, and the container build now honours the RandomX and libsecp256k1 pins it had been silently ignoring since before 1.2.15. Gates at this tree: 15/15 selftests, compactblock's 17 checks, consensus constants unchanged against e4f898c apart from the pre-existing MAX_BLOCK_SIZE_GEN, mainnet genesis intact, money-log check ok.
Diffstat (limited to 'src/db.h')
-rw-r--r--src/db.h183
1 files changed, 152 insertions, 31 deletions
diff --git a/src/db.h b/src/db.h
index 37a252f..859e3fb 100644
--- a/src/db.h
+++ b/src/db.h
@@ -46,7 +46,7 @@ public:
46}; 46};
47 47
48 48
49extern DbEnv dbenv; 49extern DbEnv& GetDbEnv();
50extern void DBFlush(bool fShutdown); 50extern void DBFlush(bool fShutdown);
51// Close the environment and delete its logs. Only the encryption command calls 51// Close the environment and delete its logs. Only the encryption command calls
52// this: the logs hold the plaintext records the old wallet wrote. 52// this: the logs hold the plaintext records the old wallet wrote.
@@ -235,7 +235,7 @@ public:
235 if (!pdb) 235 if (!pdb)
236 return false; 236 return false;
237 DbTxn* ptxn = NULL; 237 DbTxn* ptxn = NULL;
238 int ret = dbenv.txn_begin(GetTxn(), &ptxn, 0); 238 int ret = GetDbEnv().txn_begin(GetTxn(), &ptxn, 0);
239 if (!ptxn || ret != 0) 239 if (!ptxn || ret != 0)
240 return false; 240 return false;
241 vTxn.push_back(ptxn); 241 vTxn.push_back(ptxn);
@@ -333,6 +333,24 @@ private:
333// Legacy IP-based peer address database (CAddrDB / addr.dat) removed -- 333// Legacy IP-based peer address database (CAddrDB / addr.dat) removed --
334// peer discovery is entirely Nostr/.btf-based now. 334// peer discovery is entirely Nostr/.btf-based now.
335 335
336bool WalletSQLiteRuntimeActive();
337bool WalletSQLiteRuntimeOpen(const string& strPath, string& strErrorRet, bool fMustExist=true);
338void WalletSQLiteRuntimeClose();
339bool WalletSQLiteRuntimeReadRecord(const vector<unsigned char>& vchKey,
340 vector<unsigned char>& vchValueRet);
341bool WalletSQLiteRuntimeWriteRecord(const vector<unsigned char>& vchKey,
342 const vector<unsigned char>& vchValue,
343 bool fOverwrite);
344bool WalletSQLiteRuntimeEraseRecord(const vector<unsigned char>& vchKey);
345bool WalletSQLiteRuntimeBeginTxn();
346bool WalletSQLiteRuntimeCommitTxn();
347void WalletSQLiteRuntimeRollbackTxn();
348bool WalletSQLiteRuntimeOpenReadOnly(const string& strPath, string& strErrorRet);
349bool WalletSQLiteRuntimeCheckpoint(string& strErrorRet);
350string ReadWalletBackendMarker();
351bool WriteWalletBackendMarker(const string& strBackend);
352bool CreateNewSQLiteWallet(const string& strPath);
353
336 354
337 355
338 356
@@ -340,64 +358,141 @@ private:
340class CWalletDB : public CDB 358class CWalletDB : public CDB
341{ 359{
342public: 360public:
343 CWalletDB(const char* pszMode="r+", bool fTxn=false) : CDB("wallet.dat", pszMode, fTxn) { } 361 CWalletDB(const char* pszMode="r+", bool fTxn=false);
344private: 362private:
345 CWalletDB(const CWalletDB&); 363 CWalletDB(const CWalletDB&);
346 void operator=(const CWalletDB&); 364 void operator=(const CWalletDB&);
365
366 template<typename K, typename T>
367 bool ReadWalletRecord(const K& key, T& value)
368 {
369 if (!WalletSQLiteRuntimeActive())
370 return Read(key, value);
371
372 CDataStream ssKey(SER_DISK);
373 ssKey.reserve(1000);
374 ssKey << key;
375 vector<unsigned char> vchKey(ssKey.begin(), ssKey.end());
376 vector<unsigned char> vchValue;
377
378 bool fOk = WalletSQLiteRuntimeReadRecord(vchKey, vchValue);
379 if (!vchKey.empty())
380 memset(&vchKey[0], 0, vchKey.size());
381 if (!ssKey.empty())
382 memset(&ssKey[0], 0, ssKey.size());
383 if (!fOk)
384 return false;
385
386 CDataStream ssValue(vchValue, SER_DISK);
387 ssValue >> value;
388 bool fReadOk = !ssValue.fail();
389 if (!vchValue.empty())
390 memset(&vchValue[0], 0, vchValue.size());
391 if (!ssValue.empty())
392 memset(&ssValue[0], 0, ssValue.size());
393 return fReadOk;
394 }
395
396 template<typename K, typename T>
397 bool WriteWalletRecord(const K& key, const T& value, bool fOverwrite=true)
398 {
399 if (!WalletSQLiteRuntimeActive())
400 return Write(key, value, fOverwrite);
401
402 CDataStream ssKey(SER_DISK);
403 ssKey.reserve(1000);
404 ssKey << key;
405 CDataStream ssValue(SER_DISK);
406 ssValue.reserve(10000);
407 ssValue << value;
408
409 vector<unsigned char> vchKey(ssKey.begin(), ssKey.end());
410 vector<unsigned char> vchValue(ssValue.begin(), ssValue.end());
411 bool fOk = WalletSQLiteRuntimeWriteRecord(vchKey, vchValue, fOverwrite);
412
413 if (!vchKey.empty())
414 memset(&vchKey[0], 0, vchKey.size());
415 if (!vchValue.empty())
416 memset(&vchValue[0], 0, vchValue.size());
417 if (!ssKey.empty())
418 memset(&ssKey[0], 0, ssKey.size());
419 if (!ssValue.empty())
420 memset(&ssValue[0], 0, ssValue.size());
421 return fOk;
422 }
423
424 template<typename K>
425 bool EraseWalletRecord(const K& key)
426 {
427 if (!WalletSQLiteRuntimeActive())
428 return Erase(key);
429
430 CDataStream ssKey(SER_DISK);
431 ssKey.reserve(1000);
432 ssKey << key;
433 vector<unsigned char> vchKey(ssKey.begin(), ssKey.end());
434 bool fOk = WalletSQLiteRuntimeEraseRecord(vchKey);
435
436 if (!vchKey.empty())
437 memset(&vchKey[0], 0, vchKey.size());
438 if (!ssKey.empty())
439 memset(&ssKey[0], 0, ssKey.size());
440 return fOk;
441 }
347public: 442public:
348 bool ReadName(const string& strAddress, string& strName) 443 bool ReadName(const string& strAddress, string& strName)
349 { 444 {
350 strName = ""; 445 strName = "";
351 return Read(make_pair(string("name"), strAddress), strName); 446 return ReadWalletRecord(make_pair(string("name"), strAddress), strName);
352 } 447 }
353 448
354 bool WriteName(const string& strAddress, const string& strName) 449 bool WriteName(const string& strAddress, const string& strName)
355 { 450 {
356 mapAddressBook[strAddress] = strName; 451 mapAddressBook[strAddress] = strName;
357 return Write(make_pair(string("name"), strAddress), strName); 452 return WriteWalletRecord(make_pair(string("name"), strAddress), strName);
358 } 453 }
359 454
360 bool EraseName(const string& strAddress) 455 bool EraseName(const string& strAddress)
361 { 456 {
362 mapAddressBook.erase(strAddress); 457 mapAddressBook.erase(strAddress);
363 return Erase(make_pair(string("name"), strAddress)); 458 return EraseWalletRecord(make_pair(string("name"), strAddress));
364 } 459 }
365 460
366 bool ReadTx(uint256 hash, CWalletTx& wtx) 461 bool ReadTx(uint256 hash, CWalletTx& wtx)
367 { 462 {
368 return Read(make_pair(string("tx"), hash), wtx); 463 return ReadWalletRecord(make_pair(string("tx"), hash), wtx);
369 } 464 }
370 465
371 bool WriteTx(uint256 hash, const CWalletTx& wtx) 466 bool WriteTx(uint256 hash, const CWalletTx& wtx)
372 { 467 {
373 return Write(make_pair(string("tx"), hash), wtx); 468 return WriteWalletRecord(make_pair(string("tx"), hash), wtx);
374 } 469 }
375 470
376 bool EraseTx(uint256 hash) 471 bool EraseTx(uint256 hash)
377 { 472 {
378 return Erase(make_pair(string("tx"), hash)); 473 return EraseWalletRecord(make_pair(string("tx"), hash));
379 } 474 }
380 475
381 bool ReadKey(const vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey) 476 bool ReadKey(const vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
382 { 477 {
383 vchPrivKey.clear(); 478 vchPrivKey.clear();
384 return Read(make_pair(string("key"), vchPubKey), vchPrivKey); 479 return ReadWalletRecord(make_pair(string("key"), vchPubKey), vchPrivKey);
385 } 480 }
386 481
387 bool WriteKey(const vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey) 482 bool WriteKey(const vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
388 { 483 {
389 return Write(make_pair(string("key"), vchPubKey), vchPrivKey, false); 484 return WriteWalletRecord(make_pair(string("key"), vchPubKey), vchPrivKey, false);
390 } 485 }
391 486
392 bool ReadDefaultKey(vector<unsigned char>& vchPubKey) 487 bool ReadDefaultKey(vector<unsigned char>& vchPubKey)
393 { 488 {
394 vchPubKey.clear(); 489 vchPubKey.clear();
395 return Read(string("defaultkey"), vchPubKey); 490 return ReadWalletRecord(string("defaultkey"), vchPubKey);
396 } 491 }
397 492
398 bool WriteDefaultKey(const vector<unsigned char>& vchPubKey) 493 bool WriteDefaultKey(const vector<unsigned char>& vchPubKey)
399 { 494 {
400 return Write(string("defaultkey"), vchPubKey); 495 return WriteWalletRecord(string("defaultkey"), vchPubKey);
401 } 496 }
402 497
403 // --- Deterministic (BIP32) seed --------------------------------------- 498 // --- Deterministic (BIP32) seed ---------------------------------------
@@ -415,62 +510,75 @@ public:
415 { 510 {
416 vchMasterRet.clear(); 511 vchMasterRet.clear();
417 vchChainCodeRet.clear(); 512 vchChainCodeRet.clear();
418 return Read(string("hdmaster"), vchMasterRet) 513 return ReadWalletRecord(string("hdmaster"), vchMasterRet)
419 && Read(string("hdchaincode"), vchChainCodeRet); 514 && ReadWalletRecord(string("hdchaincode"), vchChainCodeRet);
420 } 515 }
421 516
422 bool WriteHDMaster(const vector<unsigned char>& vchMaster, const vector<unsigned char>& vchChainCode) 517 bool WriteHDMaster(const vector<unsigned char>& vchMaster, const vector<unsigned char>& vchChainCode)
423 { 518 {
424 return Write(string("hdmaster"), vchMaster) 519 // hdmaster and hdchaincode are halves of one seed: a wallet with one but
425 && Write(string("hdchaincode"), vchChainCode); 520 // not the other is an incomplete HD wallet (-walletstoragecheck flags
521 // exactly that). Under the SQLite runtime write them in one transaction
522 // so a failure or crash between the two cannot leave that half-state.
523 // Berkeley DB keeps its existing per-write behaviour -- the bracket is a
524 // no-op there.
525 if (!WalletSQLiteRuntimeBeginTxn())
526 return false;
527 if (!WriteWalletRecord(string("hdmaster"), vchMaster) ||
528 !WriteWalletRecord(string("hdchaincode"), vchChainCode))
529 {
530 WalletSQLiteRuntimeRollbackTxn();
531 return false;
532 }
533 return WalletSQLiteRuntimeCommitTxn();
426 } 534 }
427 535
428 bool WriteWalletMinVersion(int nVersion) 536 bool WriteWalletMinVersion(int nVersion)
429 { 537 {
430 return Write(string("walletminversion"), nVersion); 538 return WriteWalletRecord(string("walletminversion"), nVersion);
431 } 539 }
432 540
433 bool WriteMasterKey(unsigned int nID, const CWalletMasterKey& kMasterKey) 541 bool WriteMasterKey(unsigned int nID, const CWalletMasterKey& kMasterKey)
434 { 542 {
435 return Write(make_pair(string("mkey"), nID), kMasterKey, true); 543 return WriteWalletRecord(make_pair(string("mkey"), nID), kMasterKey, true);
436 } 544 }
437 545
438 bool WriteCryptedKey(const vector<unsigned char>& vchPubKey, 546 bool WriteCryptedKey(const vector<unsigned char>& vchPubKey,
439 const vector<unsigned char>& vchCryptedSecret) 547 const vector<unsigned char>& vchCryptedSecret)
440 { 548 {
441 return Write(make_pair(string("ckey"), vchPubKey), vchCryptedSecret, false); 549 return WriteWalletRecord(make_pair(string("ckey"), vchPubKey), vchCryptedSecret, false);
442 } 550 }
443 551
444 bool WriteCryptedHDMaster(const vector<unsigned char>& vchCryptedMaster, 552 bool WriteCryptedHDMaster(const vector<unsigned char>& vchCryptedMaster,
445 const vector<unsigned char>& vchCryptedChainCode) 553 const vector<unsigned char>& vchCryptedChainCode)
446 { 554 {
447 return Write(string("cryptedhdmaster"), vchCryptedMaster) 555 return WriteWalletRecord(string("cryptedhdmaster"), vchCryptedMaster)
448 && Write(string("cryptedhdchaincode"), vchCryptedChainCode); 556 && WriteWalletRecord(string("cryptedhdchaincode"), vchCryptedChainCode);
449 } 557 }
450 558
451 bool WriteHDNext(unsigned int nNext) 559 bool WriteHDNext(unsigned int nNext)
452 { 560 {
453 return Write(string("hdnext"), nNext); 561 return WriteWalletRecord(string("hdnext"), nNext);
454 } 562 }
455 563
456 bool WriteHDSchema(int nSchema) 564 bool WriteHDSchema(int nSchema)
457 { 565 {
458 return Write(string("hdschema"), nSchema); 566 return WriteWalletRecord(string("hdschema"), nSchema);
459 } 567 }
460 568
461 bool WriteHDCoinType(unsigned int nCoinType) 569 bool WriteHDCoinType(unsigned int nCoinType)
462 { 570 {
463 return Write(string("hdcointype"), nCoinType); 571 return WriteWalletRecord(string("hdcointype"), nCoinType);
464 } 572 }
465 573
466 bool WriteHDReceiveNext(unsigned int nNext) 574 bool WriteHDReceiveNext(unsigned int nNext)
467 { 575 {
468 return Write(string("hdreceivenext"), nNext); 576 return WriteWalletRecord(string("hdreceivenext"), nNext);
469 } 577 }
470 578
471 bool WriteHDChangeNext(unsigned int nNext) 579 bool WriteHDChangeNext(unsigned int nNext)
472 { 580 {
473 return Write(string("hdchangenext"), nNext); 581 return WriteWalletRecord(string("hdchangenext"), nNext);
474 } 582 }
475 583
476 // Keys generated ahead of time and not yet handed out. The private key of 584 // Keys generated ahead of time and not yet handed out. The private key of
@@ -478,30 +586,43 @@ public:
478 // record only says that this one is still unspoken for. 586 // record only says that this one is still unspoken for.
479 bool WritePool(int64 nIndex, const vector<unsigned char>& vchPubKey) 587 bool WritePool(int64 nIndex, const vector<unsigned char>& vchPubKey)
480 { 588 {
481 return Write(make_pair(string("pool"), nIndex), vchPubKey); 589 return WriteWalletRecord(make_pair(string("pool"), nIndex), vchPubKey);
482 } 590 }
483 591
484 bool ErasePool(int64 nIndex) 592 bool ErasePool(int64 nIndex)
485 { 593 {
486 return Erase(make_pair(string("pool"), nIndex)); 594 return EraseWalletRecord(make_pair(string("pool"), nIndex));
487 } 595 }
488 596
489 template<typename T> 597 template<typename T>
490 bool ReadSetting(const string& strKey, T& value) 598 bool ReadSetting(const string& strKey, T& value)
491 { 599 {
492 return Read(make_pair(string("setting"), strKey), value); 600 return ReadWalletRecord(make_pair(string("setting"), strKey), value);
493 } 601 }
494 602
495 template<typename T> 603 template<typename T>
496 bool WriteSetting(const string& strKey, const T& value) 604 bool WriteSetting(const string& strKey, const T& value)
497 { 605 {
498 return Write(make_pair(string("setting"), strKey), value); 606 return WriteWalletRecord(make_pair(string("setting"), strKey), value);
499 } 607 }
500 608
501 bool LoadWallet(vector<unsigned char>& vchDefaultKeyRet); 609 bool LoadWallet(vector<unsigned char>& vchDefaultKeyRet);
502}; 610};
503 611
612class CWalletRecordVisitor
613{
614public:
615 virtual ~CWalletRecordVisitor() { }
616 virtual bool VisitWalletRecord(const CDataStream& ssKey,
617 const CDataStream& ssValue,
618 string& strErrorRet) = 0;
619};
620
621bool ScanWalletRecords(CWalletRecordVisitor& visitor, string& strErrorRet);
622
504bool LoadWallet(); 623bool LoadWallet();
624bool LoadWalletFromSQLite(const string& strPath);
625bool LoadWalletFromSQLiteRuntime(const string& strPath);
505 626
506// Writes a wallet.dat that opens on its own, anywhere -- see the definition in 627// Writes a wallet.dat that opens on its own, anywhere -- see the definition in
507// db.cpp for why a plain file copy does not. Still a point-in-time snapshot: 628// db.cpp for why a plain file copy does not. Still a point-in-time snapshot: