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