close coin cache hive boxes when not in use

This commit is contained in:
julian 2023-07-03 16:27:36 -06:00
parent 42abebe1d2
commit b7b43e3380
5 changed files with 66 additions and 72 deletions

View file

@ -26,6 +26,7 @@ class DB {
// legacy (required for migrations) // legacy (required for migrations)
@Deprecated("Left over for migration from old versions of Stack Wallet") @Deprecated("Left over for migration from old versions of Stack Wallet")
static const String boxNameAddressBook = "addressBook"; static const String boxNameAddressBook = "addressBook";
static const String boxNameTrades = "exchangeTransactionsBox";
// in use // in use
// TODO: migrate // TODO: migrate
@ -36,7 +37,6 @@ class DB {
static const String boxNameWatchedTransactions = static const String boxNameWatchedTransactions =
"watchedTxNotificationModels"; "watchedTxNotificationModels";
static const String boxNameWatchedTrades = "watchedTradesNotificationModels"; static const String boxNameWatchedTrades = "watchedTradesNotificationModels";
static const String boxNameTrades = "exchangeTransactionsBox";
static const String boxNameTradesV2 = "exchangeTradesBox"; static const String boxNameTradesV2 = "exchangeTradesBox";
static const String boxNameTradeNotes = "tradeNotesBox"; static const String boxNameTradeNotes = "tradeNotesBox";
static const String boxNameTradeLookup = "tradeToTxidLookUpBox"; static const String boxNameTradeLookup = "tradeToTxidLookUpBox";
@ -48,10 +48,12 @@ class DB {
static const String boxNameDBInfo = "dbInfo"; static const String boxNameDBInfo = "dbInfo";
static const String boxNamePrefs = "prefs"; static const String boxNamePrefs = "prefs";
String boxNameTxCache({required Coin coin}) => "${coin.name}_txCache"; String _boxNameTxCache({required Coin coin}) => "${coin.name}_txCache";
String boxNameSetCache({required Coin coin}) =>
// firo only
String _boxNameSetCache({required Coin coin}) =>
"${coin.name}_anonymitySetCache"; "${coin.name}_anonymitySetCache";
String boxNameUsedSerialsCache({required Coin coin}) => String _boxNameUsedSerialsCache({required Coin coin}) =>
"${coin.name}_usedSerialsCache"; "${coin.name}_usedSerialsCache";
Box<NodeModel>? _boxNodeModels; Box<NodeModel>? _boxNodeModels;
@ -146,7 +148,6 @@ class DB {
await Future.wait([ await Future.wait([
Hive.openBox<dynamic>(boxNamePriceCache), Hive.openBox<dynamic>(boxNamePriceCache),
_loadWalletBoxes(), _loadWalletBoxes(),
_loadSharedCoinCacheBoxes(),
]); ]);
} }
@ -178,14 +179,39 @@ class DB {
} }
} }
Future<void> _loadSharedCoinCacheBoxes() async { Future<Box<dynamic>> getTxCacheBox({required Coin coin}) async {
for (final coin in Coin.values) { return _txCacheBoxes[coin] ??=
_txCacheBoxes[coin] = await Hive.openBox<dynamic>(_boxNameTxCache(coin: coin));
await Hive.openBox<dynamic>(boxNameTxCache(coin: coin)); }
_setCacheBoxes[coin] =
await Hive.openBox<dynamic>(boxNameSetCache(coin: coin)); Future<void> closeTxCacheBox({required Coin coin}) async {
_usedSerialsCacheBoxes[coin] = await _txCacheBoxes[coin]?.close();
await Hive.openBox<dynamic>(boxNameUsedSerialsCache(coin: coin)); }
Future<Box<dynamic>> getAnonymitySetCacheBox({required Coin coin}) async {
return _setCacheBoxes[coin] ??=
await Hive.openBox<dynamic>(_boxNameSetCache(coin: coin));
}
Future<void> closeAnonymitySetCacheBox({required Coin coin}) async {
await _setCacheBoxes[coin]?.close();
}
Future<Box<dynamic>> getUsedSerialsCacheBox({required Coin coin}) async {
return _usedSerialsCacheBoxes[coin] ??=
await Hive.openBox<dynamic>(_boxNameUsedSerialsCache(coin: coin));
}
Future<void> closeUsedSerialsCacheBox({required Coin coin}) async {
await _usedSerialsCacheBoxes[coin]?.close();
}
/// Clear all cached transactions for the specified coin
Future<void> clearSharedTransactionCache({required Coin coin}) async {
await deleteAll<dynamic>(boxName: _boxNameTxCache(coin: coin));
if (coin == Coin.firo) {
await deleteAll<dynamic>(boxName: _boxNameSetCache(coin: coin));
await deleteAll<dynamic>(boxName: _boxNameUsedSerialsCache(coin: coin));
} }
} }

View file

@ -38,9 +38,8 @@ class CachedElectrumX {
required Coin coin, required Coin coin,
}) async { }) async {
try { try {
final cachedSet = DB.instance.get<dynamic>( final box = await DB.instance.getAnonymitySetCacheBox(coin: coin);
boxName: DB.instance.boxNameSetCache(coin: coin), final cachedSet = box.get(groupId) as Map?;
key: groupId) as Map?;
Map<String, dynamic> set; Map<String, dynamic> set;
@ -71,7 +70,7 @@ class CachedElectrumX {
: newSet["blockHash"]; : newSet["blockHash"];
for (int i = (newSet["coins"] as List).length - 1; i >= 0; i--) { for (int i = (newSet["coins"] as List).length - 1; i >= 0; i--) {
dynamic newCoin = newSet["coins"][i]; dynamic newCoin = newSet["coins"][i];
List translatedCoin = []; List<dynamic> translatedCoin = [];
translatedCoin.add(!isHexadecimal(newCoin[0] as String) translatedCoin.add(!isHexadecimal(newCoin[0] as String)
? base64ToHex(newCoin[0] as String) ? base64ToHex(newCoin[0] as String)
: newCoin[0]); : newCoin[0]);
@ -91,10 +90,7 @@ class CachedElectrumX {
set["coins"].insert(0, translatedCoin); set["coins"].insert(0, translatedCoin);
} }
// save set to db // save set to db
await DB.instance.put<dynamic>( await box.put(groupId, set);
boxName: DB.instance.boxNameSetCache(coin: coin),
key: groupId,
value: set);
Logging.instance.log( Logging.instance.log(
"Updated current anonymity set for ${coin.name} with group ID $groupId", "Updated current anonymity set for ${coin.name} with group ID $groupId",
level: LogLevel.Info, level: LogLevel.Info,
@ -107,6 +103,8 @@ class CachedElectrumX {
"Failed to process CachedElectrumX.getAnonymitySet(): $e\n$s", "Failed to process CachedElectrumX.getAnonymitySet(): $e\n$s",
level: LogLevel.Error); level: LogLevel.Error);
rethrow; rethrow;
} finally {
await DB.instance.closeAnonymitySetCacheBox(coin: coin);
} }
} }
@ -130,8 +128,9 @@ class CachedElectrumX {
bool verbose = true, bool verbose = true,
}) async { }) async {
try { try {
final cachedTx = DB.instance.get<dynamic>( final box = await DB.instance.getTxCacheBox(coin: coin);
boxName: DB.instance.boxNameTxCache(coin: coin), key: txHash) as Map?;
final cachedTx = box.get(txHash) as Map?;
if (cachedTx == null) { if (cachedTx == null) {
final Map<String, dynamic> result = await electrumXClient final Map<String, dynamic> result = await electrumXClient
.getTransaction(txHash: txHash, verbose: verbose); .getTransaction(txHash: txHash, verbose: verbose);
@ -141,10 +140,7 @@ class CachedElectrumX {
if (result["confirmations"] != null && if (result["confirmations"] != null &&
result["confirmations"] as int > minCacheConfirms) { result["confirmations"] as int > minCacheConfirms) {
await DB.instance.put<dynamic>( await box.put(txHash, result);
boxName: DB.instance.boxNameTxCache(coin: coin),
key: txHash,
value: result);
} }
Logging.instance.log("using fetched result", level: LogLevel.Info); Logging.instance.log("using fetched result", level: LogLevel.Info);
@ -158,6 +154,8 @@ class CachedElectrumX {
"Failed to process CachedElectrumX.getTransaction(): $e\n$s", "Failed to process CachedElectrumX.getTransaction(): $e\n$s",
level: LogLevel.Error); level: LogLevel.Error);
rethrow; rethrow;
} finally {
await DB.instance.closeTxCacheBox(coin: coin);
} }
} }
@ -166,9 +164,9 @@ class CachedElectrumX {
int startNumber = 0, int startNumber = 0,
}) async { }) async {
try { try {
final _list = DB.instance.get<dynamic>( final box = await DB.instance.getUsedSerialsCacheBox(coin: coin);
boxName: DB.instance.boxNameUsedSerialsCache(coin: coin),
key: "serials") as List?; final _list = box.get("serials") as List?;
List<String> cachedSerials = List<String> cachedSerials =
_list == null ? [] : List<String>.from(_list); _list == null ? [] : List<String>.from(_list);
@ -188,10 +186,9 @@ class CachedElectrumX {
} }
cachedSerials.addAll(newSerials); cachedSerials.addAll(newSerials);
await DB.instance.put<dynamic>( await box.put(
boxName: DB.instance.boxNameUsedSerialsCache(coin: coin), "serials",
key: "serials", cachedSerials,
value: cachedSerials,
); );
return cachedSerials; return cachedSerials;
@ -200,16 +197,13 @@ class CachedElectrumX {
"Failed to process CachedElectrumX.getTransaction(): $e\n$s", "Failed to process CachedElectrumX.getTransaction(): $e\n$s",
level: LogLevel.Error); level: LogLevel.Error);
rethrow; rethrow;
} finally {
await DB.instance.closeUsedSerialsCacheBox(coin: coin);
} }
} }
/// Clear all cached transactions for the specified coin /// Clear all cached transactions for the specified coin
Future<void> clearSharedTransactionCache({required Coin coin}) async { Future<void> clearSharedTransactionCache({required Coin coin}) async {
await DB.instance await DB.instance.closeAnonymitySetCacheBox(coin: coin);
.deleteAll<dynamic>(boxName: DB.instance.boxNameTxCache(coin: coin));
await DB.instance
.deleteAll<dynamic>(boxName: DB.instance.boxNameSetCache(coin: coin));
await DB.instance.deleteAll<dynamic>(
boxName: DB.instance.boxNameUsedSerialsCache(coin: coin));
} }
} }

View file

@ -178,10 +178,8 @@ class DbVersionMigrator with WalletDB {
case 3: case 3:
// clear possible broken firo cache // clear possible broken firo cache
await DB.instance.deleteBoxFromDisk( await DB.instance.clearSharedTransactionCache(coin: Coin.firo);
boxName: DB.instance.boxNameSetCache(coin: Coin.firo));
await DB.instance.deleteBoxFromDisk(
boxName: DB.instance.boxNameUsedSerialsCache(coin: Coin.firo));
// update version // update version
await DB.instance.put<dynamic>( await DB.instance.put<dynamic>(

View file

@ -1,9 +1,7 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:hive/hive.dart';
import 'package:hive_test/hive_test.dart'; import 'package:hive_test/hive_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:stackwallet/db/hive/db.dart';
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
import 'package:stackwallet/electrumx_rpc/electrumx.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -17,10 +15,10 @@ void main() {
group("tests using mock hive", () { group("tests using mock hive", () {
setUp(() async { setUp(() async {
await setUpTestHive(); await setUpTestHive();
await Hive.openBox<dynamic>( // await Hive.openBox<dynamic>(
DB.instance.boxNameUsedSerialsCache(coin: Coin.firo)); // DB.instance.boxNameUsedSerialsCache(coin: Coin.firo));
await Hive.openBox<dynamic>(DB.instance.boxNameSetCache(coin: Coin.firo)); // await Hive.openBox<dynamic>(DB.instance.boxNameSetCache(coin: Coin.firo));
await Hive.openBox<dynamic>(DB.instance.boxNameTxCache(coin: Coin.firo)); // await Hive.openBox<dynamic>(DB.instance.boxNameTxCache(coin: Coin.firo));
}); });
group("getAnonymitySet", () { group("getAnonymitySet", () {
// test("empty set cache call", () async { // test("empty set cache call", () async {

View file

@ -1,12 +1,10 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:hive_test/hive_test.dart'; import 'package:hive_test/hive_test.dart';
import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/db/hive/db.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
void main() { void main() {
group("DB box names", () { group("DB box names", () {
test("address book", () => expect(DB.boxNameAddressBook, "addressBook")); test("address book", () => expect(DB.boxNameAddressBook, "addressBook"));
test("debug info", () => expect(DB.boxNameDebugInfo, "debugInfoBox"));
test("nodes", () => expect(DB.boxNameNodeModels, "nodeModels")); test("nodes", () => expect(DB.boxNameNodeModels, "nodeModels"));
test("primary nodes", () => expect(DB.boxNamePrimaryNodes, "primaryNodes")); test("primary nodes", () => expect(DB.boxNamePrimaryNodes, "primaryNodes"));
test("wallets info", () => expect(DB.boxNameAllWalletsData, "wallets")); test("wallets info", () => expect(DB.boxNameAllWalletsData, "wallets"));
@ -33,26 +31,6 @@ void main() {
expect(DB.boxNameWalletsToDeleteOnStart, "walletsToDeleteOnStart")); expect(DB.boxNameWalletsToDeleteOnStart, "walletsToDeleteOnStart"));
test("price cache", test("price cache",
() => expect(DB.boxNamePriceCache, "priceAPIPrice24hCache")); () => expect(DB.boxNamePriceCache, "priceAPIPrice24hCache"));
test("boxNameTxCache", () {
for (final coin in Coin.values) {
expect(DB.instance.boxNameTxCache(coin: coin), "${coin.name}_txCache");
}
});
test("boxNameSetCache", () {
for (final coin in Coin.values) {
expect(DB.instance.boxNameSetCache(coin: coin),
"${coin.name}_anonymitySetCache");
}
});
test("boxNameUsedSerialsCache", () {
for (final coin in Coin.values) {
expect(DB.instance.boxNameUsedSerialsCache(coin: coin),
"${coin.name}_usedSerialsCache");
}
});
}); });
group("tests requiring test hive environment", () { group("tests requiring test hive environment", () {