/ src / index / db_key.h
db_key.h
  1  // Copyright (c) 2025-present The Bitcoin Core developers
  2  // Distributed under the MIT software license, see the accompanying
  3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4  
  5  #ifndef BITCOIN_INDEX_DB_KEY_H
  6  #define BITCOIN_INDEX_DB_KEY_H
  7  
  8  #include <dbwrapper.h>
  9  #include <interfaces/types.h>
 10  #include <logging.h>
 11  #include <serialize.h>
 12  #include <uint256.h>
 13  
 14  #include <cstdint>
 15  #include <ios>
 16  #include <string>
 17  #include <utility>
 18  
 19  namespace index_util {
 20  /*
 21   * This file includes the logic for the db keys used by blockfilterindex and coinstatsindex.
 22   * Index data is usually indexed by height, but in case of a reorg, entries of blocks no
 23   * longer in the main chain will be copied to a hash index by which they can still be queried.
 24   * Keys for the height index have the type [DB_BLOCK_HEIGHT, uint32 (BE)]. The height is represented
 25   * as big-endian so that sequential reads of filters by height are fast.
 26   * Keys for the hash index have the type [DB_BLOCK_HASH, uint256].
 27   */
 28  
 29  static constexpr uint8_t DB_BLOCK_HASH{'s'};
 30  static constexpr uint8_t DB_BLOCK_HEIGHT{'t'};
 31  
 32  struct DBHeightKey {
 33      int height;
 34  
 35      explicit DBHeightKey(int height_in) : height(height_in) {}
 36  
 37      template<typename Stream>
 38      void Serialize(Stream& s) const
 39      {
 40          ser_writedata8(s, DB_BLOCK_HEIGHT);
 41          ser_writedata32be(s, height);
 42      }
 43  
 44      template<typename Stream>
 45      void Unserialize(Stream& s)
 46      {
 47          const uint8_t prefix{ser_readdata8(s)};
 48          if (prefix != DB_BLOCK_HEIGHT) {
 49              throw std::ios_base::failure("Invalid format for index DB height key");
 50          }
 51          height = ser_readdata32be(s);
 52      }
 53  };
 54  
 55  struct DBHashKey {
 56      uint256 hash;
 57  
 58      explicit DBHashKey(const uint256& hash_in) : hash(hash_in) {}
 59  
 60      SERIALIZE_METHODS(DBHashKey, obj) {
 61          uint8_t prefix{DB_BLOCK_HASH};
 62          READWRITE(prefix);
 63          if (prefix != DB_BLOCK_HASH) {
 64              throw std::ios_base::failure("Invalid format for index DB hash key");
 65          }
 66  
 67          READWRITE(obj.hash);
 68      }
 69  };
 70  
 71  template <typename DBVal>
 72  [[nodiscard]] static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
 73                                                       const std::string& index_name, int height)
 74  {
 75      DBHeightKey key(height);
 76      db_it.Seek(key);
 77  
 78      if (!db_it.GetKey(key) || key.height != height) {
 79          LogError("unexpected key in %s: expected (%c, %d)",
 80                    index_name, DB_BLOCK_HEIGHT, height);
 81          return false;
 82      }
 83  
 84      std::pair<uint256, DBVal> value;
 85      if (!db_it.GetValue(value)) {
 86          LogError("unable to read value in %s at key (%c, %d)",
 87                   index_name, DB_BLOCK_HEIGHT, height);
 88          return false;
 89      }
 90  
 91      batch.Write(DBHashKey(value.first), value.second);
 92      return true;
 93  }
 94  
 95  template <typename DBVal>
 96  static bool LookUpOne(const CDBWrapper& db, const interfaces::BlockRef& block, DBVal& result)
 97  {
 98      // First check if the result is stored under the height index and the value
 99      // there matches the block hash. This should be the case if the block is on
100      // the active chain.
101      std::pair<uint256, DBVal> read_out;
102      if (!db.Read(DBHeightKey(block.height), read_out)) {
103          return false;
104      }
105      if (read_out.first == block.hash) {
106          result = std::move(read_out.second);
107          return true;
108      }
109  
110      // If value at the height index corresponds to an different block, the
111      // result will be stored in the hash index.
112      return db.Read(DBHashKey(block.hash), result);
113  }
114  } // namespace index_util
115  
116  #endif // BITCOIN_INDEX_DB_KEY_H