stack_wallet/lib/db/sqlite/firo_cache.dart

181 lines
5.1 KiB
Dart
Raw Normal View History

2024-05-29 19:29:45 +00:00
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
2024-05-29 19:29:45 +00:00
import 'package:flutter/foundation.dart';
import 'package:flutter_libsparkmobile/flutter_libsparkmobile.dart';
import 'package:mutex/mutex.dart';
2024-05-29 19:29:45 +00:00
import 'package:sqlite3/sqlite3.dart';
import 'package:uuid/uuid.dart';
2024-05-29 19:29:45 +00:00
import '../../electrumx_rpc/electrumx_client.dart';
import '../../utilities/extensions/extensions.dart';
2024-05-29 19:29:45 +00:00
import '../../utilities/logger.dart';
import '../../utilities/stack_file_system.dart';
import '../../wallets/crypto_currency/crypto_currency.dart';
2024-05-29 19:29:45 +00:00
part 'firo_cache_coordinator.dart';
part 'firo_cache_reader.dart';
part 'firo_cache_worker.dart';
part 'firo_cache_writer.dart';
2024-05-29 19:29:45 +00:00
/// Temporary debugging log function for this file
void _debugLog(Object? object) {
if (kDebugMode) {
Logging.instance.log(
object,
2024-05-30 21:17:50 +00:00
level: LogLevel.Debug,
2024-05-29 19:29:45 +00:00
);
}
}
abstract class _FiroCache {
static const int _setCacheVersion = 1;
static const int _tagsCacheVersion = 2;
static final networks = [
CryptoCurrencyNetwork.main,
CryptoCurrencyNetwork.test,
];
static String sparkSetCacheFileName(CryptoCurrencyNetwork network) =>
network == CryptoCurrencyNetwork.main
? "spark_set_v$_setCacheVersion.sqlite3"
: "spark_set_v${_setCacheVersion}_${network.name}.sqlite3";
static String sparkUsedTagsCacheFileName(CryptoCurrencyNetwork network) =>
network == CryptoCurrencyNetwork.main
? "spark_tags_v$_tagsCacheVersion.sqlite3"
: "spark_tags_v${_tagsCacheVersion}_${network.name}.sqlite3";
static final Map<CryptoCurrencyNetwork, Database> _setCacheDB = {};
static final Map<CryptoCurrencyNetwork, Database> _usedTagsCacheDB = {};
static Database setCacheDB(CryptoCurrencyNetwork network) {
if (_setCacheDB[network] == null) {
throw Exception(
"FiroCache.init() must be called before accessing FiroCache.db!",
);
}
return _setCacheDB[network]!;
}
2024-05-29 19:29:45 +00:00
static Database usedTagsCacheDB(CryptoCurrencyNetwork network) {
if (_usedTagsCacheDB[network] == null) {
2024-05-29 19:29:45 +00:00
throw Exception(
"FiroCache.init() must be called before accessing FiroCache.db!",
);
}
return _usedTagsCacheDB[network]!;
2024-05-29 19:29:45 +00:00
}
static Future<void>? _initFuture;
static Future<void> init() => _initFuture ??= _init();
static Future<void> _init() async {
final sqliteDir =
await StackFileSystem.applicationFiroCacheSQLiteDirectory();
2024-05-29 19:29:45 +00:00
for (final network in networks) {
final sparkSetCacheFile =
File("${sqliteDir.path}/${sparkSetCacheFileName(network)}");
2024-05-29 19:29:45 +00:00
final sparkUsedTagsCacheFile =
File("${sqliteDir.path}/${sparkUsedTagsCacheFileName(network)}");
2024-05-29 19:29:45 +00:00
if (!(await sparkSetCacheFile.exists())) {
await _createSparkSetCacheDb(sparkSetCacheFile.path);
}
if (!(await sparkUsedTagsCacheFile.exists())) {
await _createSparkUsedTagsCacheDb(sparkUsedTagsCacheFile.path);
}
_setCacheDB[network] = sqlite3.open(
sparkSetCacheFile.path,
mode: OpenMode.readWrite,
);
_usedTagsCacheDB[network] = sqlite3.open(
sparkUsedTagsCacheFile.path,
mode: OpenMode.readWrite,
);
}
2024-05-29 19:29:45 +00:00
}
static Future<void> _deleteAllCache(CryptoCurrencyNetwork network) async {
final start = DateTime.now();
setCacheDB(network).execute(
"""
DELETE FROM SparkSet;
DELETE FROM SparkCoin;
DELETE FROM SparkSetCoins;
VACUUM;
""",
);
usedTagsCacheDB(network).execute(
"""
DELETE FROM SparkUsedCoinTags;
VACUUM;
""",
);
_debugLog(
"_deleteAllCache() "
"duration = ${DateTime.now().difference(start)}",
);
}
static Future<void> _createSparkSetCacheDb(String file) async {
2024-05-29 19:29:45 +00:00
final db = sqlite3.open(
file,
mode: OpenMode.readWriteCreate,
);
db.execute(
"""
CREATE TABLE SparkSet (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
blockHash TEXT NOT NULL,
setHash TEXT NOT NULL,
groupId INTEGER NOT NULL,
timestampUTC INTEGER NOT NULL,
UNIQUE (blockHash, setHash, groupId)
2024-05-29 19:29:45 +00:00
);
2024-05-29 19:29:45 +00:00
CREATE TABLE SparkCoin (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
serialized TEXT NOT NULL,
txHash TEXT NOT NULL,
context TEXT NOT NULL,
UNIQUE(serialized, txHash, context)
);
2024-05-29 19:29:45 +00:00
CREATE TABLE SparkSetCoins (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
setId INTEGER NOT NULL,
coinId INTEGER NOT NULL,
FOREIGN KEY (setId) REFERENCES SparkSet(id),
FOREIGN KEY (coinId) REFERENCES SparkCoin(id)
2024-05-29 19:29:45 +00:00
);
""",
);
db.dispose();
}
static Future<void> _createSparkUsedTagsCacheDb(String file) async {
final db = sqlite3.open(
file,
mode: OpenMode.readWriteCreate,
);
db.execute(
"""
CREATE TABLE SparkUsedCoinTags (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
tag TEXT NOT NULL UNIQUE,
txid TEXT NOT NULL
);
2024-05-29 19:29:45 +00:00
""",
);
db.dispose();
2024-05-29 19:29:45 +00:00
}
}