walletdb.h raw

   1  // Copyright (c) 2009-2010 Satoshi Nakamoto
   2  // Copyright (c) 2009-2022 The Limenka 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 LIMENKA_WALLET_WALLETDB_H
   7  #define LIMENKA_WALLET_WALLETDB_H
   8  
   9  #include <script/sign.h>
  10  #include <wallet/db.h>
  11  #include <wallet/ct.h>
  12  #include <wallet/walletutil.h>
  13  #include <key.h>
  14  
  15  #include <stdint.h>
  16  #include <string>
  17  #include <vector>
  18  
  19  class CScript;
  20  class uint160;
  21  class uint256;
  22  struct CBlockLocator;
  23  
  24  namespace wallet {
  25  class CKeyPool;
  26  class CMasterKey;
  27  class CWallet;
  28  class CWalletTx;
  29  struct WalletContext;
  30  
  31  /**
  32   * Overview of wallet database classes:
  33   *
  34   * - WalletBatch is an abstract modifier object for the wallet database, and encapsulates a database
  35   *   batch update as well as methods to act on the database. It should be agnostic to the database implementation.
  36   *
  37   * The following classes are implementation specific:
  38   * - BerkeleyEnvironment is an environment in which the database exists.
  39   * - BerkeleyDatabase represents a wallet database.
  40   * - BerkeleyBatch is a low-level database batch update.
  41   */
  42  
  43  static const bool DEFAULT_FLUSHWALLET = true;
  44  
  45  /** Error statuses for the wallet database.
  46   * Values are in order of severity. When multiple errors occur, the most severe (highest value) will be returned.
  47   */
  48  enum class DBErrors : int
  49  {
  50      LOAD_OK = 0,
  51      NEED_RESCAN = 1,
  52      NEED_REWRITE = 2,
  53      EXTERNAL_SIGNER_SUPPORT_REQUIRED = 3,
  54      NONCRITICAL_ERROR = 4,
  55      TOO_NEW = 5,
  56      UNKNOWN_DESCRIPTOR = 6,
  57      LOAD_FAIL = 7,
  58      UNEXPECTED_LEGACY_ENTRY = 8,
  59      CORRUPT = 9,
  60  };
  61  
  62  namespace DBKeys {
  63  extern const std::string ACENTRY;
  64  extern const std::string ACTIVEEXTERNALSPK;
  65  extern const std::string ACTIVEINTERNALSPK;
  66  extern const std::string BESTBLOCK;
  67  extern const std::string BESTBLOCK_NOMERKLE;
  68  extern const std::string CRYPTED_KEY;
  69  extern const std::string CSCRIPT;
  70  extern const std::string DEFAULTKEY;
  71  extern const std::string DESTDATA;
  72  extern const std::string FLAGS;
  73  extern const std::string HDCHAIN;
  74  extern const std::string KEY;
  75  extern const std::string KEYMETA;
  76  extern const std::string LOCKED_UTXO;
  77  extern const std::string MASTER_KEY;
  78  extern const std::string MINVERSION;
  79  extern const std::string NAME;
  80  extern const std::string OLD_KEY;
  81  extern const std::string ORDERPOSNEXT;
  82  extern const std::string POOL;
  83  extern const std::string PURPOSE;
  84  extern const std::string SETTINGS;
  85  extern const std::string TX;
  86  extern const std::string VERSION;
  87  extern const std::string WALLETDESCRIPTOR;
  88  extern const std::string WALLETDESCRIPTORCKEY;
  89  extern const std::string WALLETDESCRIPTORKEY;
  90  extern const std::string WATCHMETA;
  91  extern const std::string WATCHS;
  92  
  93  // Keys in this set pertain only to the legacy wallet (LegacyScriptPubKeyMan) and are removed during migration from legacy to descriptors.
  94  extern const std::unordered_set<std::string> LEGACY_TYPES;
  95  } // namespace DBKeys
  96  
  97  /* simple HD chain data model */
  98  class CHDChain
  99  {
 100  public:
 101      uint32_t nExternalChainCounter;
 102      uint32_t nInternalChainCounter;
 103      CKeyID seed_id; //!< seed hash160
 104      int64_t m_next_external_index{0}; // Next index in the keypool to be used. Memory only.
 105      int64_t m_next_internal_index{0}; // Next index in the keypool to be used. Memory only.
 106  
 107      static const int VERSION_HD_BASE        = 1;
 108      static const int VERSION_HD_CHAIN_SPLIT = 2;
 109      static const int CURRENT_VERSION        = VERSION_HD_CHAIN_SPLIT;
 110      int nVersion;
 111  
 112      CHDChain() { SetNull(); }
 113  
 114      SERIALIZE_METHODS(CHDChain, obj)
 115      {
 116          READWRITE(obj.nVersion, obj.nExternalChainCounter, obj.seed_id);
 117          if (obj.nVersion >= VERSION_HD_CHAIN_SPLIT) {
 118              READWRITE(obj.nInternalChainCounter);
 119          }
 120      }
 121  
 122      void SetNull()
 123      {
 124          nVersion = CHDChain::CURRENT_VERSION;
 125          nExternalChainCounter = 0;
 126          nInternalChainCounter = 0;
 127          seed_id.SetNull();
 128      }
 129  
 130      bool operator==(const CHDChain& chain) const
 131      {
 132          return seed_id == chain.seed_id;
 133      }
 134  };
 135  
 136  class CKeyMetadata
 137  {
 138  public:
 139      static const int VERSION_BASIC=1;
 140      static const int VERSION_WITH_FLAGS = 2;  // not supported, but preserved
 141      static const int VERSION_WITH_HDDATA=10;
 142      static const int VERSION_WITH_KEY_ORIGIN = 12;
 143      static const int CURRENT_VERSION=VERSION_WITH_KEY_ORIGIN;
 144      int nVersion;
 145      int64_t nCreateTime; // 0 means unknown
 146      std::string hdKeypath; //optional HD/bip32 keypath. Still used to determine whether a key is a seed. Also kept for backwards compatibility
 147      CKeyID hd_seed_id; //id of the HD seed used to derive this key
 148      uint8_t unsupported_key_flags;
 149      KeyOriginInfo key_origin; // Key origin info with path and fingerprint
 150      bool has_key_origin = false; //!< Whether the key_origin is useful
 151  
 152      CKeyMetadata()
 153      {
 154          SetNull();
 155      }
 156      explicit CKeyMetadata(int64_t nCreateTime_)
 157      {
 158          SetNull();
 159          nCreateTime = nCreateTime_;
 160      }
 161  
 162      SERIALIZE_METHODS(CKeyMetadata, obj)
 163      {
 164          READWRITE(obj.nVersion, obj.nCreateTime);
 165          if (obj.nVersion >= VERSION_WITH_HDDATA) {
 166              READWRITE(obj.hdKeypath, obj.hd_seed_id);
 167          } else if (obj.nVersion >= VERSION_WITH_FLAGS) {
 168              READWRITE(obj.unsupported_key_flags);
 169          }
 170          if (obj.nVersion >= VERSION_WITH_KEY_ORIGIN)
 171          {
 172              READWRITE(obj.key_origin);
 173              READWRITE(obj.has_key_origin);
 174          }
 175      }
 176  
 177      void SetNull()
 178      {
 179          nVersion = CKeyMetadata::CURRENT_VERSION;
 180          nCreateTime = 0;
 181          hdKeypath.clear();
 182          hd_seed_id.SetNull();
 183          key_origin.clear();
 184          has_key_origin = false;
 185      }
 186  };
 187  
 188  struct DbTxnListener
 189  {
 190      std::function<void()> on_commit, on_abort;
 191  };
 192  
 193  /** Access to the wallet database.
 194   * Opens the database and provides read and write access to it. Each read and write is its own transaction.
 195   * Multiple operation transactions can be started using TxnBegin() and committed using TxnCommit()
 196   * Otherwise the transaction will be committed when the object goes out of scope.
 197   * Optionally (on by default) it will flush to disk on close.
 198   * Every 1000 writes will automatically trigger a flush to disk.
 199   */
 200  class WalletBatch
 201  {
 202  private:
 203      template <typename K, typename T>
 204      bool WriteIC(const K& key, const T& value, bool fOverwrite = true)
 205      {
 206          if (!m_batch->Write(key, value, fOverwrite)) {
 207              return false;
 208          }
 209          m_database.IncrementUpdateCounter();
 210          if (m_database.nUpdateCounter % 1000 == 0) {
 211              m_batch->Flush();
 212          }
 213          return true;
 214      }
 215  
 216      template <typename K>
 217      bool EraseIC(const K& key)
 218      {
 219          if (!m_batch->Erase(key)) {
 220              return false;
 221          }
 222          m_database.IncrementUpdateCounter();
 223          if (m_database.nUpdateCounter % 1000 == 0) {
 224              m_batch->Flush();
 225          }
 226          return true;
 227      }
 228  
 229  public:
 230      explicit WalletBatch(WalletDatabase &database, bool _fFlushOnClose = true) :
 231          m_batch(database.MakeBatch(_fFlushOnClose)),
 232          m_database(database)
 233      {
 234      }
 235      WalletBatch(const WalletBatch&) = delete;
 236      WalletBatch& operator=(const WalletBatch&) = delete;
 237  
 238      bool WriteName(const std::string& strAddress, const std::string& strName);
 239      bool EraseName(const std::string& strAddress);
 240  
 241      bool WritePurpose(const std::string& strAddress, const std::string& purpose);
 242      bool ErasePurpose(const std::string& strAddress);
 243  
 244      bool WriteTx(const CWalletTx& wtx);
 245      bool EraseTx(uint256 hash);
 246  
 247      bool WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite);
 248      bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta);
 249      bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, const CKeyMetadata &keyMeta);
 250      bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey);
 251      bool EraseMasterKey(unsigned int id);
 252  
 253      bool WriteCScript(const uint160& hash, const CScript& redeemScript);
 254  
 255      bool WriteWatchOnly(const CScript &script, const CKeyMetadata &keymeta);
 256      // Stealth CT keypair record (dedicated type; not legacy KEY records).
 257      // The private keys are stored plaintext when the wallet is unencrypted
 258      // and encrypted with the wallet encryption key otherwise.
 259      bool WriteStealthKeys(const CPubKey& view_pub, const CPubKey& spend_pub,
 260                            const CPrivKey& view_priv, const CPrivKey& spend_priv);
 261      bool ReadStealthKeys(CPubKey& view_pub, CPubKey& spend_pub,
 262                           CPrivKey& view_priv, CPrivKey& spend_priv);
 263      // Confidential transaction receipts, keyed by txid (P2BPCT).
 264      bool WriteCTReceipts(const uint256& txid, const std::vector<CTReceipt>& receipts);
 265      bool ReadCTReceipts(const uint256& txid, std::vector<CTReceipt>& receipts);
 266      bool EraseCTReceipts(const uint256& txid);
 267      bool ListCTReceipts(std::map<uint256, std::vector<CTReceipt>>& out);
 268      bool EraseWatchOnly(const CScript &script);
 269  
 270      bool WriteBestBlock(const CBlockLocator& locator);
 271      bool ReadBestBlock(CBlockLocator& locator);
 272  
 273      // Returns true if wallet stores encryption keys
 274      bool IsEncrypted();
 275  
 276      bool WriteOrderPosNext(int64_t nOrderPosNext);
 277  
 278      bool ReadPool(int64_t nPool, CKeyPool& keypool);
 279      bool WritePool(int64_t nPool, const CKeyPool& keypool);
 280      bool ErasePool(int64_t nPool);
 281  
 282      bool WriteMinVersion(int nVersion);
 283  
 284      bool WriteDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const CPrivKey& privkey);
 285      bool WriteCryptedDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const std::vector<unsigned char>& secret);
 286      bool WriteDescriptor(const uint256& desc_id, const WalletDescriptor& descriptor);
 287      bool WriteDescriptorDerivedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index, uint32_t der_index);
 288      bool WriteDescriptorParentCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index);
 289      bool WriteDescriptorLastHardenedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index);
 290      bool WriteDescriptorCacheItems(const uint256& desc_id, const DescriptorCache& cache);
 291  
 292      bool WriteLockedUTXO(const COutPoint& output);
 293      bool EraseLockedUTXO(const COutPoint& output);
 294  
 295      bool WriteAddressPreviouslySpent(const CTxDestination& dest, bool previously_spent);
 296      bool WriteAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& receive_request);
 297      bool EraseAddressReceiveRequest(const CTxDestination& dest, const std::string& id);
 298      bool EraseAddressData(const CTxDestination& dest);
 299  
 300      bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256& id, bool internal);
 301      bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal);
 302  
 303      DBErrors LoadWallet(CWallet* pwallet);
 304  
 305      //! write the hdchain model (external chain child index counter)
 306      bool WriteHDChain(const CHDChain& chain);
 307  
 308      //! Delete records of the given types
 309      bool EraseRecords(const std::unordered_set<std::string>& types);
 310  
 311      bool WriteWalletFlags(const uint64_t flags);
 312      //! Begin a new transaction
 313      bool TxnBegin();
 314      //! Commit current transaction
 315      bool TxnCommit();
 316      //! Abort current transaction
 317      bool TxnAbort();
 318      bool HasActiveTxn() { return m_batch->HasActiveTxn(); }
 319  
 320      //! Registers db txn callback functions
 321      void RegisterTxnListener(const DbTxnListener& l);
 322  
 323  private:
 324      std::unique_ptr<DatabaseBatch> m_batch;
 325      WalletDatabase& m_database;
 326  
 327      // External functions listening to the current db txn outcome.
 328      // Listeners are cleared at the end of the transaction.
 329      std::vector<DbTxnListener> m_txn_listeners;
 330  };
 331  
 332  /**
 333   * Executes the provided function 'func' within a database transaction context.
 334   *
 335   * This function ensures that all db modifications performed within 'func()' are
 336   * atomically committed to the db at the end of the process. And, in case of a
 337   * failure during execution, all performed changes are rolled back.
 338   *
 339   * @param database The db connection instance to perform the transaction on.
 340   * @param process_desc A description of the process being executed, used for logging purposes in the event of a failure.
 341   * @param func The function to be executed within the db txn context. It returns a boolean indicating whether to commit or roll back the txn.
 342   * @return true if the db txn executed successfully, false otherwise.
 343   */
 344  bool RunWithinTxn(WalletDatabase& database, std::string_view process_desc, const std::function<bool(WalletBatch&)>& func);
 345  
 346  //! Compacts BDB state so that wallet.dat is self-contained (if there are changes)
 347  void MaybeCompactWalletDB(WalletContext& context);
 348  
 349  bool LoadKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr);
 350  bool LoadCryptedKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr);
 351  bool LoadEncryptionKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr);
 352  bool LoadHDChain(CWallet* pwallet, DataStream& ssValue, std::string& strErr);
 353  } // namespace wallet
 354  
 355  #endif // LIMENKA_WALLET_WALLETDB_H
 356