From 8d054215421a9c20ca1fcdd7979564b01a95a6e2 Mon Sep 17 00:00:00 2001 From: julian Date: Sun, 10 Sep 2023 08:25:28 -0600 Subject: [PATCH 1/5] clean up cancel transaction in epiccash wallet --- .../coins/epiccash/epiccash_wallet.dart | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index ba5a7b3f7..08758b03f 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -421,34 +421,28 @@ class EpicCashWallet extends CoinServiceAPI late SecureStorageInterface _secureStore; + /// returns an empty String on success, error message on failure Future cancelPendingTransactionAndPost(String txSlateId) async { - String? result; try { - result = await cancelPendingTransaction(txSlateId); + final String wallet = (await _secureStore.read( + key: '${_walletId}_wallet', + ))!; + + final result = await m.protect(() async { + return await compute( + _cancelTransactionWrapper, + Tuple2( + wallet, + txSlateId, + ), + ); + }); Logging.instance.log("result?: $result", level: LogLevel.Info); + return result; } catch (e, s) { Logging.instance.log("$e, $s", level: LogLevel.Error); + return e.toString(); } - return result!; - } - -// - /// returns an empty String on success, error message on failure - Future cancelPendingTransaction(String txSlateId) async { - final String wallet = - (await _secureStore.read(key: '${_walletId}_wallet'))!; - - String? result; - await m.protect(() async { - result = await compute( - _cancelTransactionWrapper, - Tuple2( - wallet, - txSlateId, - ), - ); - }); - return result!; } @override From a5a8bb8ab5bdbff98e64e22cc123715f8411f592 Mon Sep 17 00:00:00 2001 From: julian Date: Sun, 10 Sep 2023 10:44:33 -0600 Subject: [PATCH 2/5] apply scans error propagation fix --- .../coins/epiccash/epiccash_wallet.dart | 181 ++++++++++-------- 1 file changed, 100 insertions(+), 81 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 08758b03f..44865e195 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -437,7 +437,10 @@ class EpicCashWallet extends CoinServiceAPI ), ); }); - Logging.instance.log("result?: $result", level: LogLevel.Info); + Logging.instance.log( + "cancel $txSlateId result: $result", + level: LogLevel.Info, + ); return result; } catch (e, s) { Logging.instance.log("$e, $s", level: LogLevel.Error); @@ -661,25 +664,8 @@ class EpicCashWallet extends CoinServiceAPI await epicUpdateLastScannedBlock(await getRestoreHeight()); - if (!await startScans()) { - refreshMutex = false; - GlobalEventBus.instance.fire( - NodeConnectionStatusChangedEvent( - NodeConnectionStatus.disconnected, - walletId, - coin, - ), - ); - GlobalEventBus.instance.fire( - WalletSyncStatusChangedEvent( - WalletSyncStatus.unableToSync, - walletId, - coin, - ), - ); - return; - } - await refresh(); + await _startScans(); + GlobalEventBus.instance.fire( WalletSyncStatusChangedEvent( WalletSyncStatus.synced, @@ -688,12 +674,23 @@ class EpicCashWallet extends CoinServiceAPI ), ); } catch (e, s) { + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.unableToSync, + walletId, + coin, + ), + ); + + Logging.instance.log( + "Exception rethrown from fullRescan(): $e\n$s", + level: LogLevel.Error, + printFullLength: true, + ); + rethrow; + } finally { refreshMutex = false; - Logging.instance - .log("$e, $s", level: LogLevel.Error, printFullLength: true); } - refreshMutex = false; - return; } @override @@ -1159,58 +1156,97 @@ class EpicCashWallet extends CoinServiceAPI // TODO: refresh anything that needs to be refreshed/updated due to epicbox info changed } - Future startScans() async { + Future _startScans() async { try { + //First stop the current listener if (ListenerManager.pointer != null) { + Logging.instance + .log("LISTENER HANDLER IS NOT NULL ....", level: LogLevel.Info); + Logging.instance + .log("STOPPING ANY WALLET LISTENER ....", level: LogLevel.Info); epicboxListenerStop(ListenerManager.pointer!); } - final wallet = await _secureStore.read(key: '${_walletId}_wallet'); - var restoreHeight = epicGetRestoreHeight(); - var chainHeight = await this.chainHeight; - if (epicGetLastScannedBlock() == null) { - await epicUpdateLastScannedBlock(await getRestoreHeight()); - } - int lastScannedBlock = epicGetLastScannedBlock()!; - const MAX_PER_LOOP = 10000; - await getSyncPercent; - for (; lastScannedBlock < chainHeight;) { - chainHeight = await this.chainHeight; - lastScannedBlock = epicGetLastScannedBlock()!; - Logging.instance.log( - "chainHeight: $chainHeight, restoreHeight: $restoreHeight, lastScannedBlock: $lastScannedBlock", - level: LogLevel.Info); - int? nextScannedBlock; - await m.protect(() async { - ReceivePort receivePort = await getIsolate({ - "function": "scanOutPuts", - "wallet": wallet!, - "startHeight": lastScannedBlock, - "numberOfBlocks": MAX_PER_LOOP, - }, name: walletName); + // max number of blocks to scan per loop iteration + const scanChunkSize = 10000; - var message = await receivePort.first; - if (message is String) { - Logging.instance - .log("this is a string $message", level: LogLevel.Error); - stop(receivePort); - throw Exception("scanOutPuts isolate failed"); + // force firing of scan progress event + await getSyncPercent; + + // fetch current chain height and last scanned block (should be the + // restore height if full rescan or a wallet restore) + int chainHeight = await this.chainHeight; + int lastScannedBlock = + epicGetLastScannedBlock() ?? await getRestoreHeight(); + + // loop while scanning in chain in chunks (of blocks?) + while (lastScannedBlock < chainHeight) { + Logging.instance.log( + "chainHeight: $chainHeight, lastScannedBlock: $lastScannedBlock", + level: LogLevel.Info, + ); + + final int nextScannedBlock = await m.protect(() async { + ReceivePort? receivePort; + try { + receivePort = await getIsolate({ + "function": "scanOutPuts", + "wallet": wallet!, + "startHeight": lastScannedBlock, + "numberOfBlocks": scanChunkSize, + }, name: walletName); + + // get response + final message = await receivePort.first; + + // check for error message + if (message is String) { + throw Exception("scanOutPuts isolate failed: $message"); + } + + // attempt to grab next scanned block number + final nextScanned = int.tryParse(message['outputs'] as String); + if (nextScanned == null) { + throw Exception( + "scanOutPuts failed to parse next scanned block number from: $message", + ); + } + + return nextScanned; + } catch (_) { + rethrow; + } finally { + if (receivePort != null) { + // kill isolate + stop(receivePort); + } } - nextScannedBlock = int.parse(message['outputs'] as String); - stop(receivePort); - Logging.instance - .log('Closing scanOutPuts!\n $message', level: LogLevel.Info); }); - await epicUpdateLastScannedBlock(nextScannedBlock!); + + // update local cache + await epicUpdateLastScannedBlock(nextScannedBlock); + + // force firing of scan progress event await getSyncPercent; + + // update while loop condition variables + chainHeight = await this.chainHeight; + lastScannedBlock = nextScannedBlock; } - Logging.instance.log("successfully at the tip", level: LogLevel.Info); + + Logging.instance.log( + "_startScans successfully at the tip", + level: LogLevel.Info, + ); + //Once scanner completes restart listener await listenToEpicbox(); - return true; } catch (e, s) { - Logging.instance.log("$e, $s", level: LogLevel.Warning); - return false; + Logging.instance.log( + "_startScans failed: $e\n$s", + level: LogLevel.Error, + ); + rethrow; } } @@ -1490,24 +1526,7 @@ class EpicCashWallet extends CoinServiceAPI final int curAdd = await setCurrentIndex(); await _getReceivingAddressForIndex(curAdd); - if (!await startScans()) { - refreshMutex = false; - GlobalEventBus.instance.fire( - NodeConnectionStatusChangedEvent( - NodeConnectionStatus.disconnected, - walletId, - coin, - ), - ); - GlobalEventBus.instance.fire( - WalletSyncStatusChangedEvent( - WalletSyncStatus.unableToSync, - walletId, - coin, - ), - ); - return; - } + await _startScans(); unawaited(startSync()); From f3f63289ef79eaa102c5d62c3c50cf64ee3f3829 Mon Sep 17 00:00:00 2001 From: julian Date: Sun, 10 Sep 2023 10:55:06 -0600 Subject: [PATCH 3/5] clean up epic wallet file --- .../coins/epiccash/epiccash_wallet.dart | 83 +------------------ 1 file changed, 1 insertion(+), 82 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 44865e195..2dacb1639 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -1700,26 +1700,13 @@ class EpicCashWallet extends CoinServiceAPI final List> txnsData = []; - // int latestTxnBlockHeight = - // DB.instance.get(boxName: walletId, key: "storedTxnDataHeight") - // as int? ?? - // 0; final slatesToCommits = await getSlatesToCommits(); for (var tx in jsonTransactions) { Logging.instance.log("tx: $tx", level: LogLevel.Info); // // TODO: does "confirmed" mean finalized? If so please remove this todo final isConfirmed = tx["confirmed"] as bool; - // // TODO: since we are now caching tx history in hive are we losing anything by skipping here? - // // TODO: we can skip this filtering if it causes issues as the cache is later merged with updated data anyways - // // this would just make processing and updating cache more efficient - // if (txHeight > 0 && - // txHeight < latestTxnBlockHeight - MINIMUM_CONFIRMATIONS && - // isConfirmed) { - // continue; - // } - // Logging.instance.log("Transactions listed below"); - // Logging.instance.log(jsonTransactions); + int amt = 0; if (tx["tx_type"] == "TxReceived" || tx["tx_type"] == "TxReceivedCancelled") { @@ -1820,24 +1807,7 @@ class EpicCashWallet extends CoinServiceAPI } } - // - // midSortedTx["inputSize"] = tx["num_inputs"]; - // midSortedTx["outputSize"] = tx["num_outputs"]; - // midSortedTx["aliens"] = []; - // midSortedTx["inputs"] = []; - // midSortedTx["outputs"] = []; - - // key id not used afaik? - // midSortedTx["key_id"] = tx["parent_key_id"]; - - // if (txHeight >= latestTxnBlockHeight) { - // latestTxnBlockHeight = txHeight; - // } - txnsData.add(Tuple2(txn, transactionAddress)); - // cachedMap?.remove(tx["id"].toString()); - // cachedMap?.remove(commitId); - // Logging.instance.log("cmap: $cachedMap", level: LogLevel.Info); } await db.addNewTransactionData(txnsData, walletId); @@ -1852,57 +1822,6 @@ class EpicCashWallet extends CoinServiceAPI ), ); } - - // midSortedArray - // .sort((a, b) => (b["timestamp"] as int) - (a["timestamp"] as int)); - // - // final Map result = {"dateTimeChunks": []}; - // final dateArray = []; - // - // for (int i = 0; i < midSortedArray.length; i++) { - // final txObject = midSortedArray[i]; - // final date = extractDateFromTimestamp(txObject["timestamp"] as int); - // - // final txTimeArray = [txObject["timestamp"], date]; - // - // if (dateArray.contains(txTimeArray[1])) { - // result["dateTimeChunks"].forEach((dynamic chunk) { - // if (extractDateFromTimestamp(chunk["timestamp"] as int) == - // txTimeArray[1]) { - // if (chunk["transactions"] == null) { - // chunk["transactions"] = >[]; - // } - // chunk["transactions"].add(txObject); - // } - // }); - // } else { - // dateArray.add(txTimeArray[1]); - // - // final chunk = { - // "timestamp": txTimeArray[0], - // "transactions": [txObject], - // };sendAll - // - // // result["dateTimeChunks"]. - // result["dateTimeChunks"].add(chunk); - // } - // } - // final transactionsMap = - // TransactionData.fromJson(result).getAllTransactions(); - // if (cachedMap != null) { - // transactionsMap.addAll(cachedMap); - // } - // - // final txModel = TransactionData.fromMap(transactionsMap); - // - // await DB.instance.put( - // boxName: walletId, - // key: 'storedTxnDataHeight', - // value: latestTxnBlockHeight); - // await DB.instance.put( - // boxName: walletId, key: 'latest_tx_model', value: txModel); - // - // return txModel; } @override From 8b4f25e0f3a424b3f65602934b8bc286b25d34b8 Mon Sep 17 00:00:00 2001 From: julian Date: Sun, 10 Sep 2023 14:57:07 -0600 Subject: [PATCH 4/5] hide epic rescan for now --- .../wallet_network_settings_view.dart | 181 ++++++++++-------- 1 file changed, 101 insertions(+), 80 deletions(-) diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart index b447a53ee..8f9fc9eec 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart @@ -340,92 +340,98 @@ class _WalletNetworkSettingsViewState style: STextStyles.navBarTitle(context), ), actions: [ - Padding( - padding: const EdgeInsets.only( - top: 10, - bottom: 10, - right: 10, - ), - child: AspectRatio( - aspectRatio: 1, - child: AppBarIconButton( - key: const Key( - "walletNetworkSettingsAddNewNodeViewButton"), - size: 36, - shadows: const [], - color: Theme.of(context) - .extension()! - .background, - icon: SvgPicture.asset( - Assets.svg.verticalEllipsis, + if (ref + .read(walletsChangeNotifierProvider) + .getManager(widget.walletId) + .coin != + Coin.epicCash) + Padding( + padding: const EdgeInsets.only( + top: 10, + bottom: 10, + right: 10, + ), + child: AspectRatio( + aspectRatio: 1, + child: AppBarIconButton( + key: const Key( + "walletNetworkSettingsAddNewNodeViewButton"), + size: 36, + shadows: const [], color: Theme.of(context) .extension()! - .accentColorDark, - width: 20, - height: 20, - ), - onPressed: () { - showDialog( - barrierColor: Colors.transparent, - barrierDismissible: true, - context: context, - builder: (_) { - return Stack( - children: [ - Positioned( - top: 9, - right: 10, - child: Container( - decoration: BoxDecoration( - color: Theme.of(context) - .extension()! - .popupBG, - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius), - // boxShadow: [CFColors.standardBoxShadow], - boxShadow: const [], - ), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - GestureDetector( - onTap: () { - Navigator.of(context).pop(); - showDialog( - context: context, - useSafeArea: false, - barrierDismissible: true, - builder: (context) { - return ConfirmFullRescanDialog( - onConfirm: _attemptRescan, - ); - }, - ); - }, - child: RoundedWhiteContainer( - child: Material( - color: Colors.transparent, - child: Text( - "Rescan blockchain", - style: - STextStyles.baseXS(context), + .background, + icon: SvgPicture.asset( + Assets.svg.verticalEllipsis, + color: Theme.of(context) + .extension()! + .accentColorDark, + width: 20, + height: 20, + ), + onPressed: () { + showDialog( + barrierColor: Colors.transparent, + barrierDismissible: true, + context: context, + builder: (_) { + return Stack( + children: [ + Positioned( + top: 9, + right: 10, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context) + .extension()! + .popupBG, + borderRadius: BorderRadius.circular( + Constants + .size.circularBorderRadius), + // boxShadow: [CFColors.standardBoxShadow], + boxShadow: const [], + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + GestureDetector( + onTap: () { + Navigator.of(context).pop(); + showDialog( + context: context, + useSafeArea: false, + barrierDismissible: true, + builder: (context) { + return ConfirmFullRescanDialog( + onConfirm: _attemptRescan, + ); + }, + ); + }, + child: RoundedWhiteContainer( + child: Material( + color: Colors.transparent, + child: Text( + "Rescan blockchain", + style: STextStyles.baseXS( + context), + ), ), ), ), - ), - ], + ], + ), ), ), - ), - ], - ); - }, - ); - }, + ], + ); + }, + ); + }, + ), ), ), - ), ], ), body: Padding( @@ -786,11 +792,21 @@ class _WalletNetworkSettingsViewState .select((value) => value.getManager(widget.walletId).coin)), popBackToRoute: WalletNetworkSettingsView.routeName, ), - if (isDesktop) + if (isDesktop && + ref + .read(walletsChangeNotifierProvider) + .getManager(widget.walletId) + .coin != + Coin.epicCash) const SizedBox( height: 32, ), - if (isDesktop) + if (isDesktop && + ref + .read(walletsChangeNotifierProvider) + .getManager(widget.walletId) + .coin != + Coin.epicCash) Padding( padding: const EdgeInsets.only( bottom: 12, @@ -806,7 +822,12 @@ class _WalletNetworkSettingsViewState ], ), ), - if (isDesktop) + if (isDesktop && + ref + .read(walletsChangeNotifierProvider) + .getManager(widget.walletId) + .coin != + Coin.epicCash) RoundedWhiteContainer( borderColor: isDesktop ? Theme.of(context).extension()!.background From 6f06bb834f5d63295f3056618b055636e96a4ff0 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 11 Sep 2023 12:48:32 -0600 Subject: [PATCH 5/5] only show epic cancel button if no confirmations --- .../transaction_views/transaction_details_view.dart | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/pages/wallet_view/transaction_views/transaction_details_view.dart b/lib/pages/wallet_view/transaction_views/transaction_details_view.dart index 88d0d8b1a..54b528245 100644 --- a/lib/pages/wallet_view/transaction_views/transaction_details_view.dart +++ b/lib/pages/wallet_view/transaction_views/transaction_details_view.dart @@ -1577,11 +1577,7 @@ class _TransactionDetailsViewState ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, floatingActionButton: (coin == Coin.epicCash && - _transaction.isConfirmed( - currentHeight, - coin.requiredConfirmations, - ) == - false && + _transaction.getConfirmations(currentHeight) < 1 && _transaction.isCancelled == false) ? ConditionalParent( condition: isDesktop,