#pragma once #include #include #include #include struct sqlite3; namespace dragonx { namespace ui { struct ExplorerBlockSummary { int height = 0; std::string hash; int tx_count = 0; int size = 0; std::int64_t time = 0; double difficulty = 0.0; }; class ExplorerBlockCache { public: struct SavedTipValidation { bool needed = false; int height = 0; std::string expectedHash; }; ExplorerBlockCache(); ExplorerBlockCache(std::string databasePath, std::string legacyJsonPath); ~ExplorerBlockCache(); ExplorerBlockCache(const ExplorerBlockCache&) = delete; ExplorerBlockCache& operator=(const ExplorerBlockCache&) = delete; static std::string defaultDatabasePath(); static std::string defaultLegacyJsonPath(); bool ensureOpen(); bool isOpen() const { return db_ != nullptr; } const std::string& databasePath() const { return database_path_; } std::map loadRange(int minHeight, int maxHeight); // Fuzzy search over cached blocks: matches when the query is a substring of the height (as text) // or the block hash (case-insensitive). Returns newest-first, capped at `limit`. std::vector searchBlocks(const std::string& query, int limit); bool storeBlock(const ExplorerBlockSummary& block); int cachedBlockCount(); void clearBlocks(); SavedTipValidation prepareValidation(int currentHeight, const std::string& currentBestHash); void applySavedTipValidation(const SavedTipValidation& validation, const std::string& actualHash, int currentHeight, const std::string& currentBestHash); void updateTip(int height, const std::string& hash); private: bool exec(const char* sql); std::string getMetaValue(const std::string& key); int getMetaInt(const std::string& key, int fallback); void setMetaValue(const std::string& key, const std::string& value); bool createSchema(); void migrateLegacyJsonIfNeeded(); void close(); sqlite3* db_ = nullptr; std::string database_path_; std::string legacy_json_path_; }; } // namespace ui } // namespace dragonx