2010-08-29 12:58:15 -04:00
|
|
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
2020-04-16 13:14:08 -04:00
|
|
|
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
2014-10-30 21:43:19 -03:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
2012-05-18 10:02:28 -04:00
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2013-04-13 02:13:08 -03:00
|
|
|
|
2015-03-21 14:15:31 -03:00
|
|
|
#ifndef BITCOIN_WALLET_DB_H
|
|
|
|
#define BITCOIN_WALLET_DB_H
|
2011-05-15 03:11:04 -04:00
|
|
|
|
2017-11-09 21:57:53 -03:00
|
|
|
#include <clientversion.h>
|
|
|
|
#include <fs.h>
|
|
|
|
#include <serialize.h>
|
|
|
|
#include <streams.h>
|
2018-10-22 19:51:11 -03:00
|
|
|
#include <util/system.h>
|
2011-05-15 03:11:04 -04:00
|
|
|
|
2017-06-12 14:39:48 -04:00
|
|
|
#include <atomic>
|
2011-05-15 03:11:04 -04:00
|
|
|
#include <map>
|
2018-04-02 15:31:40 -03:00
|
|
|
#include <memory>
|
2011-05-15 03:11:04 -04:00
|
|
|
#include <string>
|
2018-09-25 10:56:16 -03:00
|
|
|
#include <unordered_map>
|
2011-05-15 03:11:04 -04:00
|
|
|
#include <vector>
|
|
|
|
|
2020-03-14 03:51:27 -03:00
|
|
|
#if defined(__GNUC__) && !defined(__clang__)
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
#pragma GCC diagnostic ignored "-Wsuggest-override"
|
|
|
|
#endif
|
2011-05-15 03:11:04 -04:00
|
|
|
#include <db_cxx.h>
|
2020-03-14 03:51:27 -03:00
|
|
|
#if defined(__GNUC__) && !defined(__clang__)
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
#endif
|
2010-08-29 12:58:15 -04:00
|
|
|
|
2019-08-19 18:12:35 -04:00
|
|
|
struct bilingual_str;
|
|
|
|
|
2015-06-27 20:15:11 -03:00
|
|
|
static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
|
2015-06-27 16:21:41 -03:00
|
|
|
static const bool DEFAULT_WALLET_PRIVDB = true;
|
2015-06-27 20:15:11 -03:00
|
|
|
|
2018-09-25 10:56:16 -03:00
|
|
|
struct WalletDatabaseFileId {
|
|
|
|
u_int8_t value[DB_FILE_ID_LEN];
|
|
|
|
bool operator==(const WalletDatabaseFileId& rhs) const;
|
|
|
|
};
|
|
|
|
|
2018-10-24 17:08:54 -03:00
|
|
|
class BerkeleyDatabase;
|
|
|
|
|
2017-12-08 08:39:22 -03:00
|
|
|
class BerkeleyEnvironment
|
2012-05-13 21:37:39 -04:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
bool fDbEnvInit;
|
2012-05-22 15:51:13 -04:00
|
|
|
bool fMockDb;
|
2017-03-01 13:05:50 -03:00
|
|
|
// Don't change into fs::path, as that can result in
|
2015-06-15 02:46:51 -03:00
|
|
|
// shutdown problems/crashes caused by a static initialized internal pointer.
|
|
|
|
std::string strPath;
|
2012-05-13 21:37:39 -04:00
|
|
|
|
|
|
|
public:
|
2017-08-09 10:24:12 -04:00
|
|
|
std::unique_ptr<DbEnv> dbenv;
|
2012-05-18 02:49:50 -04:00
|
|
|
std::map<std::string, int> mapFileUseCount;
|
2018-10-24 17:08:54 -03:00
|
|
|
std::map<std::string, std::reference_wrapper<BerkeleyDatabase>> m_databases;
|
2018-09-25 10:56:16 -03:00
|
|
|
std::unordered_map<std::string, WalletDatabaseFileId> m_fileids;
|
2018-02-20 17:28:42 -03:00
|
|
|
std::condition_variable_any m_db_in_use;
|
2012-05-13 21:37:39 -04:00
|
|
|
|
2017-12-08 08:39:22 -03:00
|
|
|
BerkeleyEnvironment(const fs::path& env_directory);
|
2018-05-18 16:28:50 -04:00
|
|
|
BerkeleyEnvironment();
|
2017-12-08 08:39:22 -03:00
|
|
|
~BerkeleyEnvironment();
|
2015-03-03 12:49:12 -03:00
|
|
|
void Reset();
|
|
|
|
|
2017-03-09 09:34:54 -03:00
|
|
|
bool IsMock() const { return fMockDb; }
|
2017-11-13 23:25:46 -03:00
|
|
|
bool IsInitialized() const { return fDbEnvInit; }
|
2018-11-08 00:41:56 -03:00
|
|
|
bool IsDatabaseLoaded(const std::string& db_filename) const { return m_databases.find(db_filename) != m_databases.end(); }
|
2017-11-13 23:25:46 -03:00
|
|
|
fs::path Directory() const { return strPath; }
|
2012-09-18 15:30:47 -03:00
|
|
|
|
2020-05-08 18:44:21 -04:00
|
|
|
bool Verify(const std::string& strFile);
|
2012-09-18 15:30:47 -03:00
|
|
|
|
2017-11-13 23:25:46 -03:00
|
|
|
bool Open(bool retry);
|
2012-05-13 21:37:39 -04:00
|
|
|
void Close();
|
|
|
|
void Flush(bool fShutdown);
|
2014-09-16 10:16:29 -03:00
|
|
|
void CheckpointLSN(const std::string& strFile);
|
2012-05-14 12:33:34 -04:00
|
|
|
|
2012-05-18 02:49:50 -04:00
|
|
|
void CloseDb(const std::string& strFile);
|
2018-02-20 17:28:42 -03:00
|
|
|
void ReloadDbEnv();
|
2012-05-18 02:49:50 -04:00
|
|
|
|
2014-09-19 14:21:46 -03:00
|
|
|
DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
|
2012-05-14 12:33:34 -04:00
|
|
|
{
|
2017-08-07 01:36:37 -04:00
|
|
|
DbTxn* ptxn = nullptr;
|
|
|
|
int ret = dbenv->txn_begin(nullptr, &ptxn, flags);
|
2012-05-14 12:33:34 -04:00
|
|
|
if (!ptxn || ret != 0)
|
2017-08-07 01:36:37 -04:00
|
|
|
return nullptr;
|
2012-05-14 12:33:34 -04:00
|
|
|
return ptxn;
|
|
|
|
}
|
2012-05-13 21:37:39 -04:00
|
|
|
};
|
|
|
|
|
2018-10-23 02:26:27 -03:00
|
|
|
/** Return whether a wallet database is currently loaded. */
|
|
|
|
bool IsWalletLoaded(const fs::path& wallet_path);
|
|
|
|
|
2019-03-06 18:22:41 -03:00
|
|
|
/** Given a wallet directory path or legacy file path, return path to main data file in the wallet database. */
|
|
|
|
fs::path WalletDataFilePath(const fs::path& wallet_path);
|
2020-06-15 14:14:51 -04:00
|
|
|
void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename);
|
2019-03-06 18:22:41 -03:00
|
|
|
|
2017-12-08 08:39:22 -03:00
|
|
|
/** Get BerkeleyEnvironment and database filename given a wallet path. */
|
2018-05-18 16:28:50 -04:00
|
|
|
std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, std::string& database_filename);
|
2012-05-13 21:37:39 -04:00
|
|
|
|
2017-03-08 07:48:58 -03:00
|
|
|
/** An instance of this class represents one database.
|
|
|
|
* For BerkeleyDB this is just a (env, strFile) tuple.
|
|
|
|
**/
|
2017-12-08 08:39:22 -03:00
|
|
|
class BerkeleyDatabase
|
2017-03-08 07:48:58 -03:00
|
|
|
{
|
2017-12-08 08:39:22 -03:00
|
|
|
friend class BerkeleyBatch;
|
2017-03-08 07:48:58 -03:00
|
|
|
public:
|
2017-03-08 09:08:26 -03:00
|
|
|
/** Create dummy DB handle */
|
2017-12-08 08:39:22 -03:00
|
|
|
BerkeleyDatabase() : nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(nullptr)
|
2017-03-08 09:08:26 -03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Create DB handle to real database */
|
2018-05-18 16:28:50 -04:00
|
|
|
BerkeleyDatabase(std::shared_ptr<BerkeleyEnvironment> env, std::string filename) :
|
|
|
|
nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(std::move(env)), strFile(std::move(filename))
|
2017-03-08 07:48:58 -03:00
|
|
|
{
|
2018-05-18 16:28:50 -04:00
|
|
|
auto inserted = this->env->m_databases.emplace(strFile, std::ref(*this));
|
2018-10-24 17:08:54 -03:00
|
|
|
assert(inserted.second);
|
2017-11-13 23:25:46 -03:00
|
|
|
}
|
|
|
|
|
2018-10-24 17:08:54 -03:00
|
|
|
~BerkeleyDatabase() {
|
|
|
|
if (env) {
|
|
|
|
size_t erased = env->m_databases.erase(strFile);
|
|
|
|
assert(erased == 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-13 23:25:46 -03:00
|
|
|
/** Return object for accessing database at specified path. */
|
2017-12-08 08:39:22 -03:00
|
|
|
static std::unique_ptr<BerkeleyDatabase> Create(const fs::path& path)
|
2017-11-13 23:25:46 -03:00
|
|
|
{
|
2018-05-18 16:28:50 -04:00
|
|
|
std::string filename;
|
|
|
|
return MakeUnique<BerkeleyDatabase>(GetWalletEnv(path, filename), std::move(filename));
|
2017-11-13 23:25:46 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return object for accessing dummy database with no read/write capabilities. */
|
2017-12-08 08:39:22 -03:00
|
|
|
static std::unique_ptr<BerkeleyDatabase> CreateDummy()
|
2017-11-13 23:25:46 -03:00
|
|
|
{
|
2017-12-08 08:39:22 -03:00
|
|
|
return MakeUnique<BerkeleyDatabase>();
|
2017-11-13 23:25:46 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return object for accessing temporary in-memory database. */
|
2017-12-08 08:39:22 -03:00
|
|
|
static std::unique_ptr<BerkeleyDatabase> CreateMock()
|
2017-11-13 23:25:46 -03:00
|
|
|
{
|
2018-05-18 16:28:50 -04:00
|
|
|
return MakeUnique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "");
|
2017-03-08 07:48:58 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero
|
|
|
|
*/
|
|
|
|
bool Rewrite(const char* pszSkip=nullptr);
|
|
|
|
|
|
|
|
/** Back up the entire database to a file.
|
|
|
|
*/
|
2020-03-02 04:39:22 -03:00
|
|
|
bool Backup(const std::string& strDest) const;
|
2017-03-08 07:48:58 -03:00
|
|
|
|
2017-03-08 10:34:47 -03:00
|
|
|
/** Make sure all changes are flushed to disk.
|
|
|
|
*/
|
|
|
|
void Flush(bool shutdown);
|
|
|
|
|
2017-03-09 17:56:58 -03:00
|
|
|
void IncrementUpdateCounter();
|
2016-09-09 05:42:30 -03:00
|
|
|
|
2018-02-20 17:28:42 -03:00
|
|
|
void ReloadDbEnv();
|
|
|
|
|
2016-09-09 05:42:30 -03:00
|
|
|
std::atomic<unsigned int> nUpdateCounter;
|
|
|
|
unsigned int nLastSeen;
|
|
|
|
unsigned int nLastFlushed;
|
|
|
|
int64_t nLastWalletUpdate;
|
2017-03-09 17:56:58 -03:00
|
|
|
|
2018-05-18 16:28:50 -04:00
|
|
|
/**
|
|
|
|
* Pointer to shared database environment.
|
|
|
|
*
|
|
|
|
* Normally there is only one BerkeleyDatabase object per
|
|
|
|
* BerkeleyEnvivonment, but in the special, backwards compatible case where
|
|
|
|
* multiple wallet BDB data files are loaded from the same directory, this
|
|
|
|
* will point to a shared instance that gets freed when the last data file
|
|
|
|
* is closed.
|
|
|
|
*/
|
|
|
|
std::shared_ptr<BerkeleyEnvironment> env;
|
|
|
|
|
2018-10-24 17:08:54 -03:00
|
|
|
/** Database pointer. This is initialized lazily and reset during flushes, so it can be null. */
|
|
|
|
std::unique_ptr<Db> m_db;
|
|
|
|
|
2017-04-20 12:52:47 -03:00
|
|
|
private:
|
|
|
|
std::string strFile;
|
|
|
|
|
2017-03-08 09:08:26 -03:00
|
|
|
/** Return whether this database handle is a dummy for testing.
|
|
|
|
* Only to be used at a low level, application should ideally not care
|
|
|
|
* about this.
|
|
|
|
*/
|
2020-03-02 04:39:52 -03:00
|
|
|
bool IsDummy() const { return env == nullptr; }
|
2017-03-08 07:48:58 -03:00
|
|
|
};
|
|
|
|
|
2012-03-26 11:48:23 -03:00
|
|
|
/** RAII class that provides access to a Berkeley database */
|
2017-12-08 08:39:22 -03:00
|
|
|
class BerkeleyBatch
|
2010-08-29 12:58:15 -04:00
|
|
|
{
|
2018-09-19 03:38:40 -03:00
|
|
|
/** RAII class that automatically cleanses its data on destruction */
|
2018-11-24 23:49:08 -03:00
|
|
|
class SafeDbt final
|
|
|
|
{
|
2018-09-19 03:38:40 -03:00
|
|
|
Dbt m_dbt;
|
|
|
|
|
|
|
|
public:
|
2018-11-24 23:49:08 -03:00
|
|
|
// construct Dbt with internally-managed data
|
|
|
|
SafeDbt();
|
|
|
|
// construct Dbt with provided data
|
|
|
|
SafeDbt(void* data, size_t size);
|
2018-09-19 03:38:40 -03:00
|
|
|
~SafeDbt();
|
|
|
|
|
|
|
|
// delegate to Dbt
|
|
|
|
const void* get_data() const;
|
|
|
|
u_int32_t get_size() const;
|
|
|
|
|
|
|
|
// conversion operator to access the underlying Dbt
|
|
|
|
operator Dbt*();
|
|
|
|
};
|
|
|
|
|
2010-08-29 12:58:15 -04:00
|
|
|
protected:
|
|
|
|
Db* pdb;
|
2011-05-15 03:11:04 -04:00
|
|
|
std::string strFile;
|
2014-09-19 14:21:46 -03:00
|
|
|
DbTxn* activeTxn;
|
2010-08-29 12:58:15 -04:00
|
|
|
bool fReadOnly;
|
2014-08-30 23:55:27 -04:00
|
|
|
bool fFlushOnClose;
|
2017-12-08 08:39:22 -03:00
|
|
|
BerkeleyEnvironment *env;
|
2010-08-29 12:58:15 -04:00
|
|
|
|
2017-03-08 13:20:08 -03:00
|
|
|
public:
|
2017-12-08 08:39:22 -03:00
|
|
|
explicit BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
|
|
|
|
~BerkeleyBatch() { Close(); }
|
2014-09-16 10:16:29 -03:00
|
|
|
|
2017-12-08 08:39:22 -03:00
|
|
|
BerkeleyBatch(const BerkeleyBatch&) = delete;
|
|
|
|
BerkeleyBatch& operator=(const BerkeleyBatch&) = delete;
|
2017-09-16 07:06:05 -03:00
|
|
|
|
2012-07-06 10:33:34 -04:00
|
|
|
void Flush();
|
2010-08-29 12:58:15 -04:00
|
|
|
void Close();
|
2016-08-24 04:57:23 -03:00
|
|
|
|
|
|
|
/* flush the wallet passively (TRY_LOCK)
|
|
|
|
ideal to be called periodically */
|
2017-12-08 08:39:22 -03:00
|
|
|
static bool PeriodicFlush(BerkeleyDatabase& database);
|
2016-08-24 04:57:23 -03:00
|
|
|
/* verifies the database environment */
|
2019-08-19 18:12:35 -04:00
|
|
|
static bool VerifyEnvironment(const fs::path& file_path, bilingual_str& errorStr);
|
2016-08-24 04:57:23 -03:00
|
|
|
/* verifies the database file */
|
2020-05-08 18:44:21 -04:00
|
|
|
static bool VerifyDatabaseFile(const fs::path& file_path, bilingual_str& errorStr);
|
2014-09-16 10:16:29 -03:00
|
|
|
|
2014-09-19 14:21:46 -03:00
|
|
|
template <typename K, typename T>
|
2010-08-29 12:58:15 -04:00
|
|
|
bool Read(const K& key, T& value)
|
|
|
|
{
|
|
|
|
if (!pdb)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Key
|
2012-04-16 09:56:45 -03:00
|
|
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
2010-08-29 12:58:15 -04:00
|
|
|
ssKey.reserve(1000);
|
|
|
|
ssKey << key;
|
2018-09-19 03:38:40 -03:00
|
|
|
SafeDbt datKey(ssKey.data(), ssKey.size());
|
2010-08-29 12:58:15 -04:00
|
|
|
|
|
|
|
// Read
|
2018-11-24 23:49:08 -03:00
|
|
|
SafeDbt datValue;
|
2018-09-19 03:38:40 -03:00
|
|
|
int ret = pdb->get(activeTxn, datKey, datValue, 0);
|
2017-03-23 18:07:51 -03:00
|
|
|
bool success = false;
|
2017-08-07 01:36:37 -04:00
|
|
|
if (datValue.get_data() != nullptr) {
|
2017-03-23 18:07:51 -03:00
|
|
|
// Unserialize value
|
|
|
|
try {
|
|
|
|
CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
|
|
|
|
ssValue >> value;
|
|
|
|
success = true;
|
|
|
|
} catch (const std::exception&) {
|
|
|
|
// In this case success remains 'false'
|
|
|
|
}
|
2012-05-22 15:12:52 -04:00
|
|
|
}
|
2017-03-23 18:07:51 -03:00
|
|
|
return ret == 0 && success;
|
2010-08-29 12:58:15 -04:00
|
|
|
}
|
|
|
|
|
2014-09-19 14:21:46 -03:00
|
|
|
template <typename K, typename T>
|
|
|
|
bool Write(const K& key, const T& value, bool fOverwrite = true)
|
2010-08-29 12:58:15 -04:00
|
|
|
{
|
|
|
|
if (!pdb)
|
2017-03-08 09:08:26 -03:00
|
|
|
return true;
|
2010-08-29 12:58:15 -04:00
|
|
|
if (fReadOnly)
|
2011-06-24 13:56:23 -04:00
|
|
|
assert(!"Write called on database in read-only mode");
|
2010-08-29 12:58:15 -04:00
|
|
|
|
|
|
|
// Key
|
2012-04-16 09:56:45 -03:00
|
|
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
2010-08-29 12:58:15 -04:00
|
|
|
ssKey.reserve(1000);
|
|
|
|
ssKey << key;
|
2018-09-19 03:38:40 -03:00
|
|
|
SafeDbt datKey(ssKey.data(), ssKey.size());
|
2010-08-29 12:58:15 -04:00
|
|
|
|
|
|
|
// Value
|
2012-04-16 09:56:45 -03:00
|
|
|
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
|
2010-08-29 12:58:15 -04:00
|
|
|
ssValue.reserve(10000);
|
|
|
|
ssValue << value;
|
2018-09-19 03:38:40 -03:00
|
|
|
SafeDbt datValue(ssValue.data(), ssValue.size());
|
2010-08-29 12:58:15 -04:00
|
|
|
|
|
|
|
// Write
|
2018-09-19 03:38:40 -03:00
|
|
|
int ret = pdb->put(activeTxn, datKey, datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
|
2010-08-29 12:58:15 -04:00
|
|
|
return (ret == 0);
|
|
|
|
}
|
|
|
|
|
2014-09-19 14:21:46 -03:00
|
|
|
template <typename K>
|
2010-08-29 12:58:15 -04:00
|
|
|
bool Erase(const K& key)
|
|
|
|
{
|
|
|
|
if (!pdb)
|
|
|
|
return false;
|
|
|
|
if (fReadOnly)
|
2011-06-24 13:56:23 -04:00
|
|
|
assert(!"Erase called on database in read-only mode");
|
2010-08-29 12:58:15 -04:00
|
|
|
|
|
|
|
// Key
|
2012-04-16 09:56:45 -03:00
|
|
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
2010-08-29 12:58:15 -04:00
|
|
|
ssKey.reserve(1000);
|
|
|
|
ssKey << key;
|
2018-09-19 03:38:40 -03:00
|
|
|
SafeDbt datKey(ssKey.data(), ssKey.size());
|
2010-08-29 12:58:15 -04:00
|
|
|
|
|
|
|
// Erase
|
2018-09-19 03:38:40 -03:00
|
|
|
int ret = pdb->del(activeTxn, datKey, 0);
|
2010-08-29 12:58:15 -04:00
|
|
|
return (ret == 0 || ret == DB_NOTFOUND);
|
|
|
|
}
|
|
|
|
|
2014-09-19 14:21:46 -03:00
|
|
|
template <typename K>
|
2010-08-29 12:58:15 -04:00
|
|
|
bool Exists(const K& key)
|
|
|
|
{
|
|
|
|
if (!pdb)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Key
|
2012-04-16 09:56:45 -03:00
|
|
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
2010-08-29 12:58:15 -04:00
|
|
|
ssKey.reserve(1000);
|
|
|
|
ssKey << key;
|
2018-09-19 03:38:40 -03:00
|
|
|
SafeDbt datKey(ssKey.data(), ssKey.size());
|
2010-08-29 12:58:15 -04:00
|
|
|
|
|
|
|
// Exists
|
2018-09-19 03:38:40 -03:00
|
|
|
int ret = pdb->exists(activeTxn, datKey, 0);
|
2010-08-29 12:58:15 -04:00
|
|
|
return (ret == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Dbc* GetCursor()
|
|
|
|
{
|
|
|
|
if (!pdb)
|
2017-08-07 01:36:37 -04:00
|
|
|
return nullptr;
|
|
|
|
Dbc* pcursor = nullptr;
|
|
|
|
int ret = pdb->cursor(nullptr, &pcursor, 0);
|
2010-08-29 12:58:15 -04:00
|
|
|
if (ret != 0)
|
2017-08-07 01:36:37 -04:00
|
|
|
return nullptr;
|
2010-08-29 12:58:15 -04:00
|
|
|
return pcursor;
|
|
|
|
}
|
|
|
|
|
2018-09-19 03:36:23 -03:00
|
|
|
int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue)
|
2010-08-29 12:58:15 -04:00
|
|
|
{
|
|
|
|
// Read at cursor
|
2018-11-24 23:49:08 -03:00
|
|
|
SafeDbt datKey;
|
|
|
|
SafeDbt datValue;
|
2018-09-19 03:38:40 -03:00
|
|
|
int ret = pcursor->get(datKey, datValue, DB_NEXT);
|
2010-08-29 12:58:15 -04:00
|
|
|
if (ret != 0)
|
|
|
|
return ret;
|
2017-08-07 01:36:37 -04:00
|
|
|
else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr)
|
2010-08-29 12:58:15 -04:00
|
|
|
return 99999;
|
|
|
|
|
|
|
|
// Convert to streams
|
|
|
|
ssKey.SetType(SER_DISK);
|
|
|
|
ssKey.clear();
|
|
|
|
ssKey.write((char*)datKey.get_data(), datKey.get_size());
|
|
|
|
ssValue.SetType(SER_DISK);
|
|
|
|
ssValue.clear();
|
|
|
|
ssValue.write((char*)datValue.get_data(), datValue.get_size());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TxnBegin()
|
|
|
|
{
|
2012-05-14 12:39:29 -04:00
|
|
|
if (!pdb || activeTxn)
|
2010-08-29 12:58:15 -04:00
|
|
|
return false;
|
2017-11-13 23:25:46 -03:00
|
|
|
DbTxn* ptxn = env->TxnBegin();
|
2012-05-14 12:33:34 -04:00
|
|
|
if (!ptxn)
|
2010-08-29 12:58:15 -04:00
|
|
|
return false;
|
2012-05-14 12:39:29 -04:00
|
|
|
activeTxn = ptxn;
|
2010-08-29 12:58:15 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TxnCommit()
|
|
|
|
{
|
2012-05-14 12:39:29 -04:00
|
|
|
if (!pdb || !activeTxn)
|
2010-08-29 12:58:15 -04:00
|
|
|
return false;
|
2012-05-14 12:39:29 -04:00
|
|
|
int ret = activeTxn->commit(0);
|
2017-08-07 01:36:37 -04:00
|
|
|
activeTxn = nullptr;
|
2010-08-29 12:58:15 -04:00
|
|
|
return (ret == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TxnAbort()
|
|
|
|
{
|
2012-05-14 12:39:29 -04:00
|
|
|
if (!pdb || !activeTxn)
|
2010-08-29 12:58:15 -04:00
|
|
|
return false;
|
2012-05-14 12:39:29 -04:00
|
|
|
int ret = activeTxn->abort();
|
2017-08-07 01:36:37 -04:00
|
|
|
activeTxn = nullptr;
|
2010-08-29 12:58:15 -04:00
|
|
|
return (ret == 0);
|
|
|
|
}
|
|
|
|
|
2017-12-08 08:39:22 -03:00
|
|
|
bool static Rewrite(BerkeleyDatabase& database, const char* pszSkip = nullptr);
|
2010-08-29 12:58:15 -04:00
|
|
|
};
|
|
|
|
|
2020-03-14 03:50:56 -03:00
|
|
|
std::string BerkeleyDatabaseVersion();
|
|
|
|
|
2015-03-21 14:15:31 -03:00
|
|
|
#endif // BITCOIN_WALLET_DB_H
|