wallet: rebase CWalletDB onto CWalletBatchTyped (SQLite default)

Move CWalletDB off the Berkeley CDB base class and onto the typed batch
seam introduced by walletdb-batch.h / walletdb-{factory,sqlite}.{h,cpp}.

Build seam
----------
* CWalletDB now derives from CWalletBatchTyped. The typed Read/Write/
  Erase/Exists templates come from the seam; their bodies (WriteTx,
  WriteKey, WriteMasterKey, ReadPool, WriteSetting, ...) are unchanged
  because only the base class swapped — the call signatures resolve to
  the same templates.
* CWalletBatchTyped takes ownership of the WalletDatabase so the
  underlying connection outlives any batch issued by it (SQLiteBatch
  holds a reference, not a value). The two-phase Open() pattern lets
  CWalletDB hand the freshly opened database to the base class after
  MakeWalletDatabase() returns.
* MakeWalletDatabase (walletdb-factory.cpp) routes -walletdb=sqlite to
  SQLiteDatabase, returning nullptr with a clear error for the
  unfinished Berkeley branch. The CWalletDB constructor surfaces that
  error string on failure.

Cursor sites (the only Berkeley-specific call sites)
---------------------------------------------------
Three sites used GetCursor()/ReadAtCursor() directly:
  * LoadWallet       — full scan, now uses StartCursor()/NextRecord()
  * ListAccountCreditDebit — used DB_SET_RANGE + DB_NEXT loop; replaced
    with full keyspace scan + filter-in-loop (SQLite cursor does not
    support keyed range seeks). Behaviour matches Berkeley: terminates
    when strType changes or, in single-account mode, when
    acentry.strAccount differs.
  * ZapWalletTx — moved to BerkeleyZapWalletTx (see below) because it
    operates on raw Berkeley Db/Dbc/Dbt now that CWalletDB is on the
    seam.

The 3 unused public methods on the old CWalletDB (GetAtCursor /
GetTxnCursor / GetAtActiveTxn) had no callers outside walletdb.{h,cpp}
(verified by grep) and were removed.

Berkeley-only escape hatches
----------------------------
Recover(CDBEnv&,...) and ZapWalletTx(...) became BerkeleyRecoverWallet
and BerkeleyZapWalletTx in a new walletdb-recover.{h,cpp} pair. They
operate directly on DbEnv/Db/Dbc/Dbt because CDB's members are
protected (free functions cannot use the wrapper). The recovery logic
duplicates a BDB-only ReadKeyValue variant locally to avoid pulling
the typed batch seam into a Berkeley-only file.

Init.cpp uses these via:
  * -salvagewallet   -> BerkeleyRecoverWallet(bitdb, ..., fOnlyKeys=true)
  * -zapwallettxes   -> BerkeleyZapWalletTx(...)
  * bitdb.Verify     -> BerkeleyRecoverWallet as the recover callback

Wallet migration hook
---------------------
After the Berkeley verify/salvage/zap steps and before CWalletDB is
opened for the live wallet, init.cpp now calls:

    if (ResolveWalletDbKind() == SQLite &&
        !IsSQLiteFile(walletPath))
        MaybeMigrateBerkeleyWalletToSQLite(walletPath, err)

The migration code (walletmigrate.{h,cpp}) is unchanged — it opens a
private Berkeley environment over the wallet directory, copies every
record verbatim (raw key/value bytes) into a fresh SQLite file,
verifies the row count, then atomically renames the BDB original to
"<name>.bdb.bak" and the SQLite file into place. On any failure the
BDB original is left exactly as it was. Errors surface through
InitError so the daemon refuses to start with a corrupt wallet rather
than silently falling back to Berkeley.

No working Berkeley fallback
----------------------------
MakeWalletDatabase returns nullptr for the Berkeley branch, so
-walletdb=bdb no longer opens a working wallet through the seam. This
is intentional for this release — the migration hook handles existing
BDB wallets at first startup, after which the on-disk file is SQLite
and the BDB code path becomes pure recovery glue.

Header fallout
--------------
walletdb.h no longer pulls in db.h (which would drag <db_cxx.h> into
every TU that includes the wallet API). Forward decls added for
CWalletTx, CBlockLocator, CWallet, CPubKey, CScript, CMasterKey,
uint160, uint256. nWalletDBUpdated is now extern-declared in
walletdb.h and defined in db.cpp (was previously declared in db.h).

Validation
----------
Build: GREEN with USE_TOR_EMBEDDED=ON USE_I2P_EMBEDDED=ON. 6 binaries:
trianglesd, triangles-cli, test_triangles, test_chaindb_runtime,
test_chaindb_equivalence, test_snapshotnet.

Tests: 107/107 + 10/10 + 5/5 = byte-identical to the 5d9da84
baseline. wallet_tests and accounting_tests inside test_triangles now
exercise the SQLite path for the first time — their pass is the
de-facto wallet-migration validation at the test-suite level.
This commit is contained in:
Triangles Dev
2026-06-30 01:01:16 -07:00
parent 3473e80876
commit 3566eed9e1
7 changed files with 697 additions and 465 deletions
+1
View File
@@ -113,6 +113,7 @@ list(APPEND CORE_SOURCES txdb-rocksdb.cpp)
list(APPEND CORE_SOURCES
walletdb-factory.cpp
walletdb-sqlite.cpp
walletdb-recover.cpp
walletmigrate.cpp
)
+24 -4
View File
@@ -4,6 +4,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "txdb.h"
#include "walletdb.h"
#include "walletdb-recover.h" // BerkeleyRecoverWallet / BerkeleyZapWalletTx
#include "walletmigrate.h" // MaybeMigrateBerkeleyWalletToSQLite / IsSQLiteFile
#include "trianglesrpc.h"
#include "net.h"
#include "netbase.h"
@@ -43,6 +45,8 @@ static bool InitWarning(const std::string& str);
#ifndef WIN32
#include <signal.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#endif
@@ -977,21 +981,37 @@ bool AppInit2()
if (GetBoolArg("-salvagewallet"))
{
// Recover readable keypairs:
if (!CWalletDB::Recover(bitdb, strWalletFileName, true))
// Recover readable keypairs (Berkeley path; only relevant for legacy
// wallet.dat files that haven't been migrated to SQLite yet):
if (!BerkeleyRecoverWallet(bitdb, strWalletFileName, true))
return false;
}
if (GetBoolArg("-zapwallettxes") && fs::exists(GetDataDir() / strWalletFileName))
{
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
if (!CWalletDB::ZapWalletTx(strWalletFileName))
if (!BerkeleyZapWalletTx(strWalletFileName))
return InitError(_("Error: could not zap wallet transactions"));
}
// ── Wallet backend migration ──────────────────────────────────────────────
// The daemon now defaults to SQLite (-walletdb=sqlite). If the wallet file
// on disk is still a Berkeley DB, convert it non-destructively to a SQLite
// wallet here, before the CWalletDB handle is opened downstream. The
// Berkeley original is preserved as "<name>.bdb.bak" alongside.
if (ResolveWalletDbKind() == WalletDbKind::SQLite &&
fs::exists(GetDataDir() / strWalletFileName) &&
!IsSQLiteFile(GetDataDir() / strWalletFileName))
{
uiInterface.InitMessage(_("Migrating wallet from Berkeley DB to SQLite..."));
std::string migErr;
if (!MaybeMigrateBerkeleyWalletToSQLite(GetDataDir() / strWalletFileName, migErr))
return InitError(_("Wallet migration failed: ") + migErr);
}
if (fs::exists(GetDataDir() / strWalletFileName))
{
CDBEnv::VerifyResult r = bitdb.Verify(strWalletFileName, CWalletDB::Recover);
CDBEnv::VerifyResult r = bitdb.Verify(strWalletFileName, BerkeleyRecoverWallet);
if (r == CDBEnv::RECOVER_OK)
{
string msg = strprintf(_("Warning: wallet.dat corrupt, data salvaged!"
+26 -4
View File
@@ -30,12 +30,33 @@
class CWalletBatchTyped
{
public:
explicit CWalletBatchTyped(std::unique_ptr<WalletBatch> batch)
: m_batch(std::move(batch)) {}
// Default-constructed handle is unusable until Open() runs. Subclasses
// (CWalletDB) call Open() once they have opened a WalletDatabase.
CWalletBatchTyped() = default;
virtual ~CWalletBatchTyped() { Close(); }
void Close() { m_batch.reset(); }
// Open a fresh batch against the given database. Closes any previously
// open batch+database. Returns false (and leaves the handle null) if the
// database fails to produce a batch.
bool Open(std::unique_ptr<WalletDatabase> db)
{
Close();
if (!db)
return false;
m_database = std::move(db);
m_batch = m_database->MakeBatch(/*flush_on_close=*/true);
if (!m_batch) {
m_database.reset();
return false;
}
return true;
}
void Close()
{
m_batch.reset();
m_database.reset();
}
bool IsNull() const { return m_batch == nullptr; }
// ── Transactions ─────────────────────────────────────────────────────────
@@ -44,6 +65,7 @@ public:
bool TxnAbort() { return m_batch && m_batch->TxnAbort(); }
protected:
std::unique_ptr<WalletDatabase> m_database;
std::unique_ptr<WalletBatch> m_batch;
// ── Typed accessors (serialize key/value, dispatch to the raw batch) ──────
+325
View File
@@ -0,0 +1,325 @@
// Copyright (c) 2026 The Triangles developers.
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// Berkeley-only wallet recovery helpers. See walletdb-recover.h.
#include "walletdb-recover.h"
#include "wallet.h"
#include <db_cxx.h>
#include <boost/version.hpp>
#include <cstdio>
#include <filesystem>
#include <list>
#include <map>
#include <utility>
#include <vector>
namespace fs = std::filesystem;
class CWalletScanState_BdbOnly {
public:
unsigned int nKeys;
unsigned int nCKeys;
unsigned int nKeyMeta;
bool fIsEncrypted;
bool fAnyUnordered;
int nFileVersion;
std::vector<uint256> vWalletUpgrade;
CWalletScanState_BdbOnly() {
nKeys = nCKeys = nKeyMeta = 0;
fIsEncrypted = false;
fAnyUnordered = false;
nFileVersion = 0;
}
};
static bool IsKeyType_BdbOnly(const std::string& strType)
{
return (strType == "key" || strType == "wkey" ||
strType == "mkey" || strType == "ckey" ||
strType == "hdmnemonic" || strType == "hdcmnemonic");
}
// Same logic as walletdb.cpp::ReadKeyValue, but the only places it is called
// here are Recover() (which scans records) and the resulting scan state. The
// same logic — duplicated locally to avoid dragging in the typed batch seam
// for a Berkeley-only escape hatch.
static bool ReadKeyValue_BdbOnly(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CWalletScanState_BdbOnly& wss,
std::string& strType, std::string& strErr)
{
try {
ssKey >> strType;
if (strType == "name") {
std::string strAddress;
ssKey >> strAddress;
ssValue >> pwallet->mapAddressBook[CTrianglesAddress(strAddress).Get()];
} else if (strType == "tx") {
uint256 hash;
ssKey >> hash;
CWalletTx& wtx = pwallet->mapWallet[hash];
ssValue >> wtx;
if (wtx.CheckTransaction() && (wtx.GetHash() == hash))
wtx.BindWallet(pwallet);
else {
pwallet->mapWallet.erase(hash);
return false;
}
if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703) {
wss.vWalletUpgrade.push_back(hash);
}
} else if (strType == "acentry") {
std::string strAccount;
ssKey >> strAccount;
uint64_t nNumber;
ssKey >> nNumber;
// Note: we intentionally do NOT bump nAccountingEntryNumber here.
// That counter is file-static in walletdb.cpp; the recovery path
// does not need the high-water mark because the salvaged records
// are not re-ordered or re-emitted as new entries.
(void)nNumber;
} else if (strType == "key" || strType == "wkey") {
std::vector<unsigned char> vchPubKey;
ssKey >> vchPubKey;
CKey key;
if (strType == "key") {
wss.nKeys++;
CPrivKey pkey;
ssValue >> pkey;
key.SetPubKey(vchPubKey);
if (!key.SetPrivKey(pkey))
{ strErr = "Recover: CPrivKey corrupt"; return false; }
if (key.GetPubKey() != vchPubKey)
{ strErr = "Recover: CPrivKey pubkey inconsistency"; return false; }
if (!key.IsValid())
{ strErr = "Recover: invalid CPrivKey"; return false; }
} else {
CWalletKey wkey;
ssValue >> wkey;
key.SetPubKey(vchPubKey);
if (!key.SetPrivKey(wkey.vchPrivKey))
{ strErr = "Recover: CPrivKey corrupt"; return false; }
if (key.GetPubKey() != vchPubKey)
{ strErr = "Recover: CWalletKey pubkey inconsistency"; return false; }
if (!key.IsValid())
{ strErr = "Recover: invalid CWalletKey"; return false; }
}
if (!pwallet->LoadKey(key))
{ strErr = "Recover: LoadKey failed"; return false; }
} else if (strType == "mkey") {
unsigned int nID;
ssKey >> nID;
CMasterKey kMasterKey;
ssValue >> kMasterKey;
if (pwallet->mapMasterKeys.count(nID) != 0) {
strErr = strprintf("Recover: duplicate CMasterKey id %u", nID);
return false;
}
pwallet->mapMasterKeys[nID] = kMasterKey;
if (pwallet->nMasterKeyMaxID < nID)
pwallet->nMasterKeyMaxID = nID;
} else if (strType == "ckey") {
wss.nCKeys++;
std::vector<unsigned char> vchPubKey;
ssKey >> vchPubKey;
std::vector<unsigned char> vchPrivKey;
ssValue >> vchPrivKey;
if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
{ strErr = "Recover: LoadCryptedKey failed"; return false; }
wss.fIsEncrypted = true;
} else if (strType == "keymeta") {
CPubKey vchPubKey;
ssKey >> vchPubKey;
CKeyMetadata keyMeta;
ssValue >> keyMeta;
wss.nKeyMeta++;
pwallet->LoadKeyMetadata(vchPubKey, keyMeta);
if (!pwallet->nTimeFirstKey ||
(keyMeta.nCreateTime < pwallet->nTimeFirstKey))
pwallet->nTimeFirstKey = keyMeta.nCreateTime;
} else if (strType == "defaultkey") {
ssValue >> pwallet->vchDefaultKey;
} else if (strType == "pool") {
int64_t nIndex;
ssKey >> nIndex;
CKeyPool keypool;
ssValue >> keypool;
pwallet->setKeyPool.insert(nIndex);
CKeyID keyid = keypool.vchPubKey.GetID();
if (pwallet->mapKeyMetadata.count(keyid) == 0)
pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
} else if (strType == "hdmnemonic") {
std::string m;
ssValue >> m;
pwallet->LoadHDMnemonic(m);
} else if (strType == "hdcmnemonic") {
std::pair<uint256, std::vector<unsigned char>> cm;
ssValue >> cm;
pwallet->LoadCryptedHDMnemonic(cm.first, cm.second);
} else if (strType == "hdchain") {
int64_t n;
ssValue >> n;
pwallet->nHDChainIndex = n;
} else if (strType == "version") {
ssValue >> wss.nFileVersion;
if (wss.nFileVersion == 10300)
wss.nFileVersion = 300;
} else if (strType == "cscript") {
uint160 hash;
ssKey >> hash;
CScript script;
ssValue >> script;
if (!pwallet->LoadCScript(script))
{ strErr = "Recover: LoadCScript failed"; return false; }
} else if (strType == "orderposnext") {
ssValue >> pwallet->nOrderPosNext;
}
} catch (...) {
return false;
}
return true;
}
bool BerkeleyRecoverWallet(CDBEnv& dbenv, std::string filename, bool fOnlyKeys)
{
int64_t now = GetTime();
std::string newFilename = strprintf("wallet.%"PRId64".bak", now);
int result = dbenv.dbenv.dbrename(NULL, filename.c_str(), NULL,
newFilename.c_str(), DB_AUTO_COMMIT);
if (result == 0)
printf("Renamed %s to %s\n", filename.c_str(), newFilename.c_str());
else {
printf("Failed to rename %s to %s\n", filename.c_str(), newFilename.c_str());
return false;
}
std::vector<CDBEnv::KeyValPair> salvagedData;
bool allOK = dbenv.Salvage(newFilename, true, salvagedData);
if (salvagedData.empty()) {
printf("Salvage(aggressive) found no records in %s.\n", newFilename.c_str());
return false;
}
printf("Salvage(aggressive) found %"PRIszu" records\n", salvagedData.size());
bool fSuccess = allOK;
Db* pdbCopy = new Db(&dbenv.dbenv, 0);
int ret = pdbCopy->open(NULL, filename.c_str(), "main", DB_BTREE, DB_CREATE, 0);
if (ret > 0) {
printf("Cannot create database file %s\n", filename.c_str());
return false;
}
CWallet dummyWallet;
CWalletScanState_BdbOnly wss;
DbTxn* ptxn = dbenv.TxnBegin();
for (CDBEnv::KeyValPair& row : salvagedData) {
if (fOnlyKeys) {
CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
std::string strType, strErr;
bool fReadOK = ReadKeyValue_BdbOnly(&dummyWallet, ssKey, ssValue,
wss, strType, strErr);
if (!IsKeyType_BdbOnly(strType))
continue;
if (!fReadOK) {
printf("WARNING: BerkeleyRecoverWallet skipping %s: %s\n",
strType.c_str(), strErr.c_str());
continue;
}
}
Dbt datKey(&row.first[0], row.first.size());
Dbt datValue(&row.second[0], row.second.size());
int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
if (ret2 > 0)
fSuccess = false;
}
ptxn->commit(0);
pdbCopy->close(0);
delete pdbCopy;
return fSuccess;
}
bool BerkeleyZapWalletTx(const std::string& strWalletFile)
{
printf("BerkeleyZapWalletTx: erasing transaction records from %s\n",
strWalletFile.c_str());
// Walk the Berkeley file directly. The CDB wrapper hides its members, but
// the underlying Db* / Dbc* API is the same thing the wrapper does.
DbEnv env(0u);
env.set_error_stream(&std::cerr);
u_int32_t envFlags = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE;
if (env.open(GetDataDir().string().c_str(), envFlags, 0) != 0) {
printf("BerkeleyZapWalletTx: cannot open Berkeley environment\n");
return false;
}
bool ok = false;
{
Db db(&env, 0);
if (db.open(nullptr, strWalletFile.c_str(), "main", DB_BTREE, DB_RDONLY, 0) != 0) {
printf("BerkeleyZapWalletTx: failed to open wallet database\n");
env.close(0);
return false;
}
Dbc* pcursor = nullptr;
if (db.cursor(nullptr, &pcursor, 0) != 0) {
printf("BerkeleyZapWalletTx: failed to get cursor\n");
db.close(0);
env.close(0);
return false;
}
std::vector<uint256> vTxHash;
Dbt datKey, datValue;
while (pcursor->get(&datKey, &datValue, DB_NEXT) == 0) {
try {
CDataStream ssKey(static_cast<const char*>(datKey.get_data()),
static_cast<const char*>(datKey.get_data()) + datKey.get_size(),
SER_DISK, CLIENT_VERSION);
std::string strType;
ssKey >> strType;
if (strType == "tx") {
uint256 hash;
ssKey >> hash;
vTxHash.push_back(hash);
}
} catch (...) {
// Skip records we cannot decode — salvage logic is best-effort.
}
}
pcursor->close();
db.close(0);
// Second pass: re-open the file in r/w mode and erase the collected tx
// records. Two separate connections keep the read pass free of the
// BDB cursor lifetime rules.
if (db.open(nullptr, strWalletFile.c_str(), "main", DB_BTREE, DB_CREATE, 0) != 0) {
printf("BerkeleyZapWalletTx: failed to reopen wallet for erase\n");
env.close(0);
return false;
}
int nErased = 0;
for (const uint256& hash : vTxHash) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey << std::make_pair(std::string("tx"), hash);
Dbt datKey2(&ssKey[0], ssKey.size());
int rc = db.del(nullptr, &datKey2, 0);
if (rc == 0 || rc == DB_NOTFOUND)
++nErased;
}
db.close(0);
printf("BerkeleyZapWalletTx: erased %d of %d transaction records\n",
nErased, (int)vTxHash.size());
ok = true;
}
env.close(0);
return ok;
}
+41
View File
@@ -0,0 +1,41 @@
// Copyright (c) 2026 The Triangles developers.
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// Berkeley-only wallet recovery helpers — moved out of CWalletDB so the
// mainline wallet code path (SQLite via the typed batch seam) does not have
// to include <db_cxx.h>.
//
// These functions operate directly on bitdb / CDB and are used only:
// * during startup, before the wallet migration hook (on a possible BDB
// wallet.dat), and
// * on the .bdb.bak copy that migration leaves behind, for diagnostic /
// manual recovery if migration ever needs investigation.
//
// They are intentionally NOT methods of CWalletDB — that class is on the
// SQLite seam now and has no Berkeley state.
#ifndef TRIANGLES_WALLETDB_RECOVER_H
#define TRIANGLES_WALLETDB_RECOVER_H
#include "db.h"
#include <string>
// Aggressive salvage of a Berkeley wallet.dat file. Moves the file aside to
// wallet.<timestamp>.bak, then walks the salvaged records and re-writes them
// into a fresh Berkeley database at the original path.
//
// If fOnlyKeys is true, only key-type records are kept (used for recovery
// when transaction history is corrupt). Returns true on success.
bool BerkeleyRecoverWallet(CDBEnv& dbenv, std::string filename, bool fOnlyKeys);
inline bool BerkeleyRecoverWallet(CDBEnv& dbenv, std::string filename)
{
return BerkeleyRecoverWallet(dbenv, filename, false);
}
// Strip every "tx" record from a Berkeley wallet.dat, leaving keys and other
// metadata intact. A rescan rebuilds the transaction list from the chain.
// Used for `-zapwallettxes` on legacy (pre-migration) wallets.
bool BerkeleyZapWalletTx(const std::string& strWalletFile);
#endif // TRIANGLES_WALLETDB_RECOVER_H
+241 -426
View File
File diff suppressed because it is too large Load Diff
+39 -31
View File
@@ -5,12 +5,26 @@
#ifndef TRIANGLES_WALLETDB_H
#define TRIANGLES_WALLETDB_H
#include "db.h"
#include "walletdb-batch.h" // CWalletBatchTyped (the typed batch seam)
#include "base58.h"
class CKeyPool;
class CAccount;
class CAccountingEntry;
class CBlockLocator; // forward decl — pulled in via db.h→main.h before
class CPubKey;
class CScript;
class CMasterKey;
class uint160;
class uint256;
class CWallet; // pulled in via db.h→main.h→wallet.h before
class CWalletTx; // forward decl — walletdb.h used to pull this in
// transitively via db.h; the seam removes that.
// Wallet-update counter used by the periodic flush thread (db.cpp defines it).
// Touched on every wallet write; needed regardless of backend so the daemon's
// auto-flush logic can detect changes to the wallet file.
extern unsigned int nWalletDBUpdated;
/** Error statuses for the wallet database */
enum DBErrors
@@ -57,39 +71,20 @@ public:
/** Access to the wallet database (wallet.dat) */
class CWalletDB : public CDB
class CWalletDB : public CWalletBatchTyped
{
public:
CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode)
{
}
/**
* Open (or create) the wallet database via the configured backend
* (-walletdb, default SQLite). The legacy pszMode argument is accepted
* for source compatibility but currently ignored — SQLite is always
* opened read/write with create-if-missing.
*/
CWalletDB(std::string strFilename, const char* pszMode="r+");
private:
CWalletDB(const CWalletDB&);
void operator=(const CWalletDB&);
public:
Dbc* GetAtCursor()
{
return GetCursor();
}
Dbc* GetTxnCursor()
{
if (!pdb)
return NULL;
DbTxn* ptxnid = activeTxn; // call TxnBegin first
Dbc* pcursor = NULL;
int ret = pdb->cursor(ptxnid, &pcursor, 0);
if (ret != 0)
return NULL;
return pcursor;
}
DbTxn* GetAtActiveTxn()
{
return activeTxn;
}
bool WriteName(const std::string& strAddress, const std::string& strName);
@@ -225,6 +220,18 @@ public:
return Write(std::string("minversion"), nVersion);
}
// Mirrors the legacy CDB::WriteVersion / ReadVersion; explicitly retained
// because LoadWallet() upgrades the on-disk version to CLIENT_VERSION.
bool WriteVersion(int nVersion)
{
return Write(std::string("version"), nVersion);
}
bool ReadVersion(int& nVersion)
{
nVersion = 0;
return Read(std::string("version"), nVersion);
}
bool ReadAccount(const std::string& strAccount, CAccount& account);
bool WriteAccount(const std::string& strAccount, const CAccount& account);
private:
@@ -236,9 +243,10 @@ public:
DBErrors ReorderTransactions(CWallet*);
DBErrors LoadWallet(CWallet* pwallet);
static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys);
static bool Recover(CDBEnv& dbenv, std::string filename);
static bool ZapWalletTx(const std::string& strWalletFile);
// NOTE: Recover() / ZapWalletTx() are Berkeley-only escape hatches. They
// live in walletdb-recover.{h,cpp} (which still depends on db.h / db_cxx.h).
// After wallet migration to SQLite those helpers are invoked on the
// .bdb.bak copy at startup, never on the live wallet.
};
#endif // TRIANGLES_WALLETDB_H