1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 #ifndef BITCOIN_WALLET_DB_H
7 #define BITCOIN_WALLET_DB_H
9 #include "clientversion.h"
10 #include "serialize.h"
19 #include <boost/filesystem/path.hpp>
23 static const unsigned int DEFAULT_WALLET_DBLOGSIZE
= 100;
24 static const bool DEFAULT_WALLET_PRIVDB
= true;
31 // Don't change into boost::filesystem::path, as that can result in
32 // shutdown problems/crashes caused by a static initialized internal pointer.
38 mutable CCriticalSection cs_db
;
40 std::map
<std::string
, int> mapFileUseCount
;
41 std::map
<std::string
, Db
*> mapDb
;
48 bool IsMock() { return fMockDb
; }
51 * Verify that database file strFile is OK. If it is not,
52 * call the callback to try to recover.
53 * This must be called BEFORE strFile is opened.
54 * Returns true if strFile is OK.
56 enum VerifyResult
{ VERIFY_OK
,
59 VerifyResult
Verify(const std::string
& strFile
, bool (*recoverFunc
)(const std::string
& strFile
));
61 * Salvage data from a file that Verify says is bad.
62 * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).
63 * Appends binary key/value pairs to vResult, returns true if successful.
64 * NOTE: reads the entire database into memory, so cannot be used
67 typedef std::pair
<std::vector
<unsigned char>, std::vector
<unsigned char> > KeyValPair
;
68 bool Salvage(const std::string
& strFile
, bool fAggressive
, std::vector
<KeyValPair
>& vResult
);
70 bool Open(const boost::filesystem::path
& path
);
72 void Flush(bool fShutdown
);
73 void CheckpointLSN(const std::string
& strFile
);
75 void CloseDb(const std::string
& strFile
);
76 bool RemoveDb(const std::string
& strFile
);
78 DbTxn
* TxnBegin(int flags
= DB_TXN_WRITE_NOSYNC
)
81 int ret
= dbenv
->txn_begin(NULL
, &ptxn
, flags
);
82 if (!ptxn
|| ret
!= 0)
91 /** RAII class that provides access to a Berkeley database */
101 explicit CDB(const std::string
& strFilename
, const char* pszMode
= "r+", bool fFlushOnCloseIn
=true);
107 static bool Recover(const std::string
& filename
, void *callbackDataIn
, bool (*recoverKVcallback
)(void* callbackData
, CDataStream ssKey
, CDataStream ssValue
));
109 /* flush the wallet passively (TRY_LOCK)
110 ideal to be called periodically */
111 static bool PeriodicFlush(std::string strFile
);
112 /* verifies the database environment */
113 static bool VerifyEnvironment(const std::string
& walletFile
, const boost::filesystem::path
& dataDir
, std::string
& errorStr
);
114 /* verifies the database file */
115 static bool VerifyDatabaseFile(const std::string
& walletFile
, const boost::filesystem::path
& dataDir
, std::string
& warningStr
, std::string
& errorStr
, bool (*recoverFunc
)(const std::string
& strFile
));
119 void operator=(const CDB
&);
122 template <typename K
, typename T
>
123 bool Read(const K
& key
, T
& value
)
129 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
132 Dbt
datKey(ssKey
.data(), ssKey
.size());
136 datValue
.set_flags(DB_DBT_MALLOC
);
137 int ret
= pdb
->get(activeTxn
, &datKey
, &datValue
, 0);
138 memset(datKey
.get_data(), 0, datKey
.get_size());
139 if (datValue
.get_data() == NULL
)
144 CDataStream
ssValue((char*)datValue
.get_data(), (char*)datValue
.get_data() + datValue
.get_size(), SER_DISK
, CLIENT_VERSION
);
146 } catch (const std::exception
&) {
150 // Clear and free memory
151 memset(datValue
.get_data(), 0, datValue
.get_size());
152 free(datValue
.get_data());
156 template <typename K
, typename T
>
157 bool Write(const K
& key
, const T
& value
, bool fOverwrite
= true)
162 assert(!"Write called on database in read-only mode");
165 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
168 Dbt
datKey(ssKey
.data(), ssKey
.size());
171 CDataStream
ssValue(SER_DISK
, CLIENT_VERSION
);
172 ssValue
.reserve(10000);
174 Dbt
datValue(ssValue
.data(), ssValue
.size());
177 int ret
= pdb
->put(activeTxn
, &datKey
, &datValue
, (fOverwrite
? 0 : DB_NOOVERWRITE
));
179 // Clear memory in case it was a private key
180 memset(datKey
.get_data(), 0, datKey
.get_size());
181 memset(datValue
.get_data(), 0, datValue
.get_size());
185 template <typename K
>
186 bool Erase(const K
& key
)
191 assert(!"Erase called on database in read-only mode");
194 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
197 Dbt
datKey(ssKey
.data(), ssKey
.size());
200 int ret
= pdb
->del(activeTxn
, &datKey
, 0);
203 memset(datKey
.get_data(), 0, datKey
.get_size());
204 return (ret
== 0 || ret
== DB_NOTFOUND
);
207 template <typename K
>
208 bool Exists(const K
& key
)
214 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
217 Dbt
datKey(ssKey
.data(), ssKey
.size());
220 int ret
= pdb
->exists(activeTxn
, &datKey
, 0);
223 memset(datKey
.get_data(), 0, datKey
.get_size());
232 int ret
= pdb
->cursor(NULL
, &pcursor
, 0);
238 int ReadAtCursor(Dbc
* pcursor
, CDataStream
& ssKey
, CDataStream
& ssValue
, bool setRange
= false)
242 unsigned int fFlags
= DB_NEXT
;
244 datKey
.set_data(ssKey
.data());
245 datKey
.set_size(ssKey
.size());
246 fFlags
= DB_SET_RANGE
;
249 datKey
.set_flags(DB_DBT_MALLOC
);
250 datValue
.set_flags(DB_DBT_MALLOC
);
251 int ret
= pcursor
->get(&datKey
, &datValue
, fFlags
);
254 else if (datKey
.get_data() == NULL
|| datValue
.get_data() == NULL
)
257 // Convert to streams
258 ssKey
.SetType(SER_DISK
);
260 ssKey
.write((char*)datKey
.get_data(), datKey
.get_size());
261 ssValue
.SetType(SER_DISK
);
263 ssValue
.write((char*)datValue
.get_data(), datValue
.get_size());
265 // Clear and free memory
266 memset(datKey
.get_data(), 0, datKey
.get_size());
267 memset(datValue
.get_data(), 0, datValue
.get_size());
268 free(datKey
.get_data());
269 free(datValue
.get_data());
276 if (!pdb
|| activeTxn
)
278 DbTxn
* ptxn
= bitdb
.TxnBegin();
287 if (!pdb
|| !activeTxn
)
289 int ret
= activeTxn
->commit(0);
296 if (!pdb
|| !activeTxn
)
298 int ret
= activeTxn
->abort();
303 bool ReadVersion(int& nVersion
)
306 return Read(std::string("version"), nVersion
);
309 bool WriteVersion(int nVersion
)
311 return Write(std::string("version"), nVersion
);
314 bool static Rewrite(const std::string
& strFile
, const char* pszSkip
= NULL
);
317 #endif // BITCOIN_WALLET_DB_H