1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2018 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.
5 
6 #ifndef BITCOIN_WALLET_WALLETDB_H
7 #define BITCOIN_WALLET_WALLETDB_H
8 
9 #include <amount.h>
10 #include <primitives/transaction.h>
11 #include <script/sign.h>
12 #include <wallet/db.h>
13 #include <key.h>
14 
15 #include <list>
16 #include <stdint.h>
17 #include <string>
18 #include <utility>
19 #include <vector>
20 
21 /**
22  * Overview of wallet database classes:
23  *
24  * - WalletBatch is an abstract modifier object for the wallet database, and encapsulates a database
25  *   batch update as well as methods to act on the database. It should be agnostic to the database implementation.
26  *
27  * The following classes are implementation specific:
28  * - BerkeleyEnvironment is an environment in which the database exists.
29  * - BerkeleyDatabase represents a wallet database.
30  * - BerkeleyBatch is a low-level database batch update.
31  */
32 
33 static const bool DEFAULT_FLUSHWALLET = true;
34 
35 struct CBlockLocator;
36 class CKeyPool;
37 class CMasterKey;
38 class CScript;
39 class CWallet;
40 class CWalletTx;
41 class uint160;
42 class uint256;
43 
44 /** Backend-agnostic database type. */
45 using WalletDatabase = BerkeleyDatabase;
46 
47 /** Error statuses for the wallet database */
48 enum class DBErrors
49 {
50     LOAD_OK,
51     CORRUPT,
52     NONCRITICAL_ERROR,
53     TOO_NEW,
54     LOAD_FAIL,
55     NEED_REWRITE
56 };
57 
58 /* simple HD chain data model */
59 class CHDChain
60 {
61 public:
62     uint32_t nExternalChainCounter;
63     uint32_t nInternalChainCounter;
64     CKeyID seed_id; //!< seed hash160
65 
66     static const int VERSION_HD_BASE        = 1;
67     static const int VERSION_HD_CHAIN_SPLIT = 2;
68     static const int CURRENT_VERSION        = VERSION_HD_CHAIN_SPLIT;
69     int nVersion;
70 
CHDChain()71     CHDChain() { SetNull(); }
72     ADD_SERIALIZE_METHODS;
73     template <typename Stream, typename Operation>
SerializationOp(Stream & s,Operation ser_action)74     inline void SerializationOp(Stream& s, Operation ser_action)
75     {
76         READWRITE(this->nVersion);
77         READWRITE(nExternalChainCounter);
78         READWRITE(seed_id);
79         if (this->nVersion >= VERSION_HD_CHAIN_SPLIT)
80             READWRITE(nInternalChainCounter);
81     }
82 
SetNull()83     void SetNull()
84     {
85         nVersion = CHDChain::CURRENT_VERSION;
86         nExternalChainCounter = 0;
87         nInternalChainCounter = 0;
88         seed_id.SetNull();
89     }
90 };
91 
92 class CKeyMetadata
93 {
94 public:
95     static const int VERSION_BASIC=1;
96     static const int VERSION_WITH_HDDATA=10;
97     static const int VERSION_WITH_KEY_ORIGIN = 12;
98     static const int CURRENT_VERSION=VERSION_WITH_KEY_ORIGIN;
99     int nVersion;
100     int64_t nCreateTime; // 0 means unknown
101     std::string hdKeypath; //optional HD/bip32 keypath. Still used to determine whether a key is a seed. Also kept for backwards compatibility
102     CKeyID hd_seed_id; //id of the HD seed used to derive this key
103     KeyOriginInfo key_origin; // Key origin info with path and fingerprint
104     bool has_key_origin = false; //< Whether the key_origin is useful
105 
CKeyMetadata()106     CKeyMetadata()
107     {
108         SetNull();
109     }
CKeyMetadata(int64_t nCreateTime_)110     explicit CKeyMetadata(int64_t nCreateTime_)
111     {
112         SetNull();
113         nCreateTime = nCreateTime_;
114     }
115 
116     ADD_SERIALIZE_METHODS;
117 
118     template <typename Stream, typename Operation>
SerializationOp(Stream & s,Operation ser_action)119     inline void SerializationOp(Stream& s, Operation ser_action) {
120         READWRITE(this->nVersion);
121         READWRITE(nCreateTime);
122         if (this->nVersion >= VERSION_WITH_HDDATA)
123         {
124             READWRITE(hdKeypath);
125             READWRITE(hd_seed_id);
126         }
127         if (this->nVersion >= VERSION_WITH_KEY_ORIGIN)
128         {
129             READWRITE(key_origin);
130             READWRITE(has_key_origin);
131         }
132     }
133 
SetNull()134     void SetNull()
135     {
136         nVersion = CKeyMetadata::CURRENT_VERSION;
137         nCreateTime = 0;
138         hdKeypath.clear();
139         hd_seed_id.SetNull();
140         key_origin.clear();
141         has_key_origin = false;
142     }
143 };
144 
145 /** Access to the wallet database.
146  * This represents a single transaction at the
147  * database. It will be committed when the object goes out of scope.
148  * Optionally (on by default) it will flush to disk as well.
149  */
150 class WalletBatch
151 {
152 private:
153     template <typename K, typename T>
154     bool WriteIC(const K& key, const T& value, bool fOverwrite = true)
155     {
156         if (!m_batch.Write(key, value, fOverwrite)) {
157             return false;
158         }
159         m_database.IncrementUpdateCounter();
160         return true;
161     }
162 
163     template <typename K>
EraseIC(const K & key)164     bool EraseIC(const K& key)
165     {
166         if (!m_batch.Erase(key)) {
167             return false;
168         }
169         m_database.IncrementUpdateCounter();
170         return true;
171     }
172 
173 public:
174     explicit WalletBatch(WalletDatabase& database, const char* pszMode = "r+", bool _fFlushOnClose = true) :
m_batch(database,pszMode,_fFlushOnClose)175         m_batch(database, pszMode, _fFlushOnClose),
176         m_database(database)
177     {
178     }
179     WalletBatch(const WalletBatch&) = delete;
180     WalletBatch& operator=(const WalletBatch&) = delete;
181 
182     bool WriteName(const std::string& strAddress, const std::string& strName);
183     bool EraseName(const std::string& strAddress);
184 
185     bool WritePurpose(const std::string& strAddress, const std::string& purpose);
186     bool ErasePurpose(const std::string& strAddress);
187 
188     bool WriteTx(const CWalletTx& wtx);
189     bool EraseTx(uint256 hash);
190 
191     bool WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite);
192     bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta);
193     bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, const CKeyMetadata &keyMeta);
194     bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey);
195 
196     bool WriteCScript(const uint160& hash, const CScript& redeemScript);
197 
198     bool WriteWatchOnly(const CScript &script, const CKeyMetadata &keymeta);
199     bool EraseWatchOnly(const CScript &script);
200 
201     bool WriteBestBlock(const CBlockLocator& locator);
202     bool ReadBestBlock(CBlockLocator& locator);
203 
204     bool WriteOrderPosNext(int64_t nOrderPosNext);
205 
206     bool ReadPool(int64_t nPool, CKeyPool& keypool);
207     bool WritePool(int64_t nPool, const CKeyPool& keypool);
208     bool ErasePool(int64_t nPool);
209 
210     bool WriteMinVersion(int nVersion);
211 
212     /// Write destination data key,value tuple to database
213     bool WriteDestData(const std::string &address, const std::string &key, const std::string &value);
214     /// Erase destination data tuple from wallet database
215     bool EraseDestData(const std::string &address, const std::string &key);
216 
217     DBErrors LoadWallet(CWallet* pwallet);
218     DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
219     DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
220     DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
221     /* Try to (very carefully!) recover wallet database (with a possible key type filter) */
222     static bool Recover(const fs::path& wallet_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
223     /* Recover convenience-function to bypass the key filter callback, called when verify fails, recovers everything */
224     static bool Recover(const fs::path& wallet_path, std::string& out_backup_filename);
225     /* Recover filter (used as callback), will only let keys (cryptographical keys) as KV/key-type pass through */
226     static bool RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue);
227     /* Function to determine if a certain KV/key-type is a key (cryptographical key) type */
228     static bool IsKeyType(const std::string& strType);
229     /* verifies the database environment */
230     static bool VerifyEnvironment(const fs::path& wallet_path, std::string& errorStr);
231     /* verifies the database file */
232     static bool VerifyDatabaseFile(const fs::path& wallet_path, std::string& warningStr, std::string& errorStr);
233 
234     //! write the hdchain model (external chain child index counter)
235     bool WriteHDChain(const CHDChain& chain);
236 
237     bool WriteWalletFlags(const uint64_t flags);
238     //! Begin a new transaction
239     bool TxnBegin();
240     //! Commit current transaction
241     bool TxnCommit();
242     //! Abort current transaction
243     bool TxnAbort();
244     //! Read wallet version
245     bool ReadVersion(int& nVersion);
246     //! Write wallet version
247     bool WriteVersion(int nVersion);
248 private:
249     BerkeleyBatch m_batch;
250     WalletDatabase& m_database;
251 };
252 
253 //! Compacts BDB state so that wallet.dat is self-contained (if there are changes)
254 void MaybeCompactWalletDB();
255 
256 #endif // BITCOIN_WALLET_WALLETDB_H
257