1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2020 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 <script/sign.h>
11 #include <wallet/db.h>
12 #include <wallet/walletutil.h>
13 #include <key.h>
14 
15 #include <stdint.h>
16 #include <string>
17 #include <vector>
18 
19 /**
20  * Overview of wallet database classes:
21  *
22  * - WalletBatch is an abstract modifier object for the wallet database, and encapsulates a database
23  *   batch update as well as methods to act on the database. It should be agnostic to the database implementation.
24  *
25  * The following classes are implementation specific:
26  * - BerkeleyEnvironment is an environment in which the database exists.
27  * - BerkeleyDatabase represents a wallet database.
28  * - BerkeleyBatch is a low-level database batch update.
29  */
30 
31 static const bool DEFAULT_FLUSHWALLET = true;
32 
33 struct CBlockLocator;
34 class CKeyPool;
35 class CMasterKey;
36 class CScript;
37 class CWallet;
38 class CWalletTx;
39 class uint160;
40 class uint256;
41 
42 /** Error statuses for the wallet database */
43 enum class DBErrors
44 {
45     LOAD_OK,
46     CORRUPT,
47     NONCRITICAL_ERROR,
48     TOO_NEW,
49     LOAD_FAIL,
50     NEED_REWRITE
51 };
52 
53 namespace DBKeys {
54 extern const std::string ACENTRY;
55 extern const std::string ACTIVEEXTERNALSPK;
56 extern const std::string ACTIVEINTERNALSPK;
57 extern const std::string BESTBLOCK;
58 extern const std::string BESTBLOCK_NOMERKLE;
59 extern const std::string CRYPTED_KEY;
60 extern const std::string CSCRIPT;
61 extern const std::string DEFAULTKEY;
62 extern const std::string DESTDATA;
63 extern const std::string FLAGS;
64 extern const std::string HDCHAIN;
65 extern const std::string KEY;
66 extern const std::string KEYMETA;
67 extern const std::string MASTER_KEY;
68 extern const std::string MINVERSION;
69 extern const std::string NAME;
70 extern const std::string OLD_KEY;
71 extern const std::string ORDERPOSNEXT;
72 extern const std::string POOL;
73 extern const std::string PURPOSE;
74 extern const std::string SETTINGS;
75 extern const std::string TX;
76 extern const std::string VERSION;
77 extern const std::string WALLETDESCRIPTOR;
78 extern const std::string WALLETDESCRIPTORCKEY;
79 extern const std::string WALLETDESCRIPTORKEY;
80 extern const std::string WATCHMETA;
81 extern const std::string WATCHS;
82 } // namespace DBKeys
83 
84 /* simple HD chain data model */
85 class CHDChain
86 {
87 public:
88     uint32_t nExternalChainCounter;
89     uint32_t nInternalChainCounter;
90     CKeyID seed_id; //!< seed hash160
91 
92     static const int VERSION_HD_BASE        = 1;
93     static const int VERSION_HD_CHAIN_SPLIT = 2;
94     static const int CURRENT_VERSION        = VERSION_HD_CHAIN_SPLIT;
95     int nVersion;
96 
CHDChain()97     CHDChain() { SetNull(); }
98 
SERIALIZE_METHODS(CHDChain,obj)99     SERIALIZE_METHODS(CHDChain, obj)
100     {
101         READWRITE(obj.nVersion, obj.nExternalChainCounter, obj.seed_id);
102         if (obj.nVersion >= VERSION_HD_CHAIN_SPLIT) {
103             READWRITE(obj.nInternalChainCounter);
104         }
105     }
106 
SetNull()107     void SetNull()
108     {
109         nVersion = CHDChain::CURRENT_VERSION;
110         nExternalChainCounter = 0;
111         nInternalChainCounter = 0;
112         seed_id.SetNull();
113     }
114 
115     bool operator==(const CHDChain& chain) const
116     {
117         return seed_id == chain.seed_id;
118     }
119 };
120 
121 class CKeyMetadata
122 {
123 public:
124     static const int VERSION_BASIC=1;
125     static const int VERSION_WITH_HDDATA=10;
126     static const int VERSION_WITH_KEY_ORIGIN = 12;
127     static const int CURRENT_VERSION=VERSION_WITH_KEY_ORIGIN;
128     int nVersion;
129     int64_t nCreateTime; // 0 means unknown
130     std::string hdKeypath; //optional HD/bip32 keypath. Still used to determine whether a key is a seed. Also kept for backwards compatibility
131     CKeyID hd_seed_id; //id of the HD seed used to derive this key
132     KeyOriginInfo key_origin; // Key origin info with path and fingerprint
133     bool has_key_origin = false; //!< Whether the key_origin is useful
134 
CKeyMetadata()135     CKeyMetadata()
136     {
137         SetNull();
138     }
CKeyMetadata(int64_t nCreateTime_)139     explicit CKeyMetadata(int64_t nCreateTime_)
140     {
141         SetNull();
142         nCreateTime = nCreateTime_;
143     }
144 
SERIALIZE_METHODS(CKeyMetadata,obj)145     SERIALIZE_METHODS(CKeyMetadata, obj)
146     {
147         READWRITE(obj.nVersion, obj.nCreateTime);
148         if (obj.nVersion >= VERSION_WITH_HDDATA) {
149             READWRITE(obj.hdKeypath, obj.hd_seed_id);
150         }
151         if (obj.nVersion >= VERSION_WITH_KEY_ORIGIN)
152         {
153             READWRITE(obj.key_origin);
154             READWRITE(obj.has_key_origin);
155         }
156     }
157 
SetNull()158     void SetNull()
159     {
160         nVersion = CKeyMetadata::CURRENT_VERSION;
161         nCreateTime = 0;
162         hdKeypath.clear();
163         hd_seed_id.SetNull();
164         key_origin.clear();
165         has_key_origin = false;
166     }
167 };
168 
169 /** Access to the wallet database.
170  * Opens the database and provides read and write access to it. Each read and write is its own transaction.
171  * Multiple operation transactions can be started using TxnBegin() and committed using TxnCommit()
172  * Otherwise the transaction will be committed when the object goes out of scope.
173  * Optionally (on by default) it will flush to disk on close.
174  * Every 1000 writes will automatically trigger a flush to disk.
175  */
176 class WalletBatch
177 {
178 private:
179     template <typename K, typename T>
180     bool WriteIC(const K& key, const T& value, bool fOverwrite = true)
181     {
182         if (!m_batch->Write(key, value, fOverwrite)) {
183             return false;
184         }
185         m_database.IncrementUpdateCounter();
186         if (m_database.nUpdateCounter % 1000 == 0) {
187             m_batch->Flush();
188         }
189         return true;
190     }
191 
192     template <typename K>
EraseIC(const K & key)193     bool EraseIC(const K& key)
194     {
195         if (!m_batch->Erase(key)) {
196             return false;
197         }
198         m_database.IncrementUpdateCounter();
199         if (m_database.nUpdateCounter % 1000 == 0) {
200             m_batch->Flush();
201         }
202         return true;
203     }
204 
205 public:
206     explicit WalletBatch(WalletDatabase &database, bool _fFlushOnClose = true) :
207         m_batch(database.MakeBatch(_fFlushOnClose)),
208         m_database(database)
209     {
210     }
211     WalletBatch(const WalletBatch&) = delete;
212     WalletBatch& operator=(const WalletBatch&) = delete;
213 
214     bool WriteName(const std::string& strAddress, const std::string& strName);
215     bool EraseName(const std::string& strAddress);
216 
217     bool WritePurpose(const std::string& strAddress, const std::string& purpose);
218     bool ErasePurpose(const std::string& strAddress);
219 
220     bool WriteTx(const CWalletTx& wtx);
221     bool EraseTx(uint256 hash);
222 
223     bool WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite);
224     bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta);
225     bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, const CKeyMetadata &keyMeta);
226     bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey);
227 
228     bool WriteCScript(const uint160& hash, const CScript& redeemScript);
229 
230     bool WriteWatchOnly(const CScript &script, const CKeyMetadata &keymeta);
231     bool EraseWatchOnly(const CScript &script);
232 
233     bool WriteBestBlock(const CBlockLocator& locator);
234     bool ReadBestBlock(CBlockLocator& locator);
235 
236     bool WriteOrderPosNext(int64_t nOrderPosNext);
237 
238     bool ReadPool(int64_t nPool, CKeyPool& keypool);
239     bool WritePool(int64_t nPool, const CKeyPool& keypool);
240     bool ErasePool(int64_t nPool);
241 
242     bool WriteMinVersion(int nVersion);
243 
244     bool WriteDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const CPrivKey& privkey);
245     bool WriteCryptedDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const std::vector<unsigned char>& secret);
246     bool WriteDescriptor(const uint256& desc_id, const WalletDescriptor& descriptor);
247     bool WriteDescriptorDerivedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index, uint32_t der_index);
248     bool WriteDescriptorParentCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index);
249     bool WriteDescriptorLastHardenedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index);
250     bool WriteDescriptorCacheItems(const uint256& desc_id, const DescriptorCache& cache);
251 
252     /// Write destination data key,value tuple to database
253     bool WriteDestData(const std::string &address, const std::string &key, const std::string &value);
254     /// Erase destination data tuple from wallet database
255     bool EraseDestData(const std::string &address, const std::string &key);
256 
257     bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256& id, bool internal);
258     bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal);
259 
260     DBErrors LoadWallet(CWallet* pwallet);
261     DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx);
262     DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
263     /* Function to determine if a certain KV/key-type is a key (cryptographical key) type */
264     static bool IsKeyType(const std::string& strType);
265 
266     //! write the hdchain model (external chain child index counter)
267     bool WriteHDChain(const CHDChain& chain);
268 
269     bool WriteWalletFlags(const uint64_t flags);
270     //! Begin a new transaction
271     bool TxnBegin();
272     //! Commit current transaction
273     bool TxnCommit();
274     //! Abort current transaction
275     bool TxnAbort();
276 private:
277     std::unique_ptr<DatabaseBatch> m_batch;
278     WalletDatabase& m_database;
279 };
280 
281 //! Compacts BDB state so that wallet.dat is self-contained (if there are changes)
282 void MaybeCompactWalletDB();
283 
284 //! Callback for filtering key types to deserialize in ReadKeyValue
285 using KeyFilterFn = std::function<bool(const std::string&)>;
286 
287 //! Unserialize a given Key-Value pair and load it into the wallet
288 bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr);
289 
290 /** Return object for accessing dummy database with no read/write capabilities. */
291 std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase();
292 
293 /** Return object for accessing temporary in-memory database. */
294 std::unique_ptr<WalletDatabase> CreateMockWalletDatabase();
295 
296 #endif // BITCOIN_WALLET_WALLETDB_H
297