import 'package:hive/hive.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart'; import 'package:stackwallet/hive/db.dart'; import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'; import 'package:stackwallet/models/exchange/response_objects/trade.dart'; import 'package:stackwallet/models/lelantus_coin.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/services/wallets_service.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; class DbVersionMigrator { Future migrate( int fromVersion, { required SecureStorageInterface secureStore, }) async { Logging.instance.log( "Running migrate fromVersion $fromVersion", level: LogLevel.Warning, ); switch (fromVersion) { case 0: await Hive.openBox(DB.boxNameAllWalletsData); await Hive.openBox(DB.boxNamePrefs); final walletsService = WalletsService(secureStorageInterface: secureStore); final nodeService = NodeService(secureStorageInterface: secureStore); final prefs = Prefs.instance; final walletInfoList = await walletsService.walletNames; await prefs.init(); ElectrumX? client; int? latestSetId; // only instantiate client if there are firo wallets if (walletInfoList.values.any((element) => element.coin == Coin.firo)) { await Hive.openBox(DB.boxNameNodeModels); await Hive.openBox(DB.boxNamePrimaryNodes); final node = nodeService.getPrimaryNodeFor(coin: Coin.firo) ?? DefaultNodes.firo; List failovers = nodeService .failoverNodesFor(coin: Coin.firo) .map( (e) => ElectrumXNode( address: e.host, port: e.port, name: e.name, id: e.id, useSSL: e.useSSL, ), ) .toList(); client = ElectrumX.from( node: ElectrumXNode( address: node.host, port: node.port, name: node.name, id: node.id, useSSL: node.useSSL), prefs: prefs, failovers: failovers, ); try { latestSetId = await client.getLatestCoinId(); } catch (e) { // default to 2 for now latestSetId = 2; Logging.instance.log( "Failed to fetch latest coin id during firo db migrate: $e \nUsing a default value of 2", level: LogLevel.Warning); } } for (final walletInfo in walletInfoList.values) { // migrate each firo wallet's lelantus coins if (walletInfo.coin == Coin.firo) { await Hive.openBox(walletInfo.walletId); final _lelantusCoins = DB.instance.get( boxName: walletInfo.walletId, key: '_lelantus_coins') as List?; final List> lelantusCoins = []; for (var lCoin in _lelantusCoins ?? []) { lelantusCoins .add({lCoin.keys.first: lCoin.values.first as LelantusCoin}); } List> coins = []; for (final element in lelantusCoins) { LelantusCoin coin = element.values.first; int anonSetId = coin.anonymitySetId; if (coin.anonymitySetId == 1 && (coin.publicCoin == '' || coin.publicCoin == "jmintData.publicCoin")) { anonSetId = latestSetId!; } coins.add({ element.keys.first: LelantusCoin(coin.index, coin.value, coin.publicCoin, coin.txId, anonSetId, coin.isUsed) }); } Logger.print("newcoins $coins", normalLength: false); await DB.instance.put( boxName: walletInfo.walletId, key: '_lelantus_coins', value: coins); } } // update version await DB.instance.put( boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 1); // try to continue migrating return await migrate(1, secureStore: secureStore); case 1: await Hive.openBox(DB.boxNameTrades); await Hive.openBox(DB.boxNameTradesV2); final trades = DB.instance.values(boxName: DB.boxNameTrades); for (final old in trades) { if (old.statusObject != null) { final trade = Trade.fromExchangeTransaction(old, false); await DB.instance.put( boxName: DB.boxNameTradesV2, key: trade.uuid, value: trade, ); } } // update version await DB.instance.put( boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 2); // try to continue migrating return await migrate(2, secureStore: secureStore); case 2: await Hive.openBox(DB.boxNamePrefs); final prefs = Prefs.instance; await prefs.init(); if (!(await prefs.isExternalCallsSet())) { prefs.externalCalls = true; } // update version await DB.instance.put( boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 3); return await migrate(3, secureStore: secureStore); case 3: // clear possible broken firo cache await DB.instance.deleteBoxFromDisk( boxName: DB.instance.boxNameSetCache(coin: Coin.firo)); await DB.instance.deleteBoxFromDisk( boxName: DB.instance.boxNameUsedSerialsCache(coin: Coin.firo)); // update version await DB.instance.put( boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 4); // try to continue migrating return await migrate(4, secureStore: secureStore); default: // finally return return; } } }