From 3b4de2b2d5a9c71b09b4bf6908f01547cc84a183 Mon Sep 17 00:00:00 2001 From: likho <likhojiba@gmail.com> Date: Wed, 4 Oct 2023 09:53:05 +0200 Subject: [PATCH 1/3] Add EpicTransaction DTO for parsing transactions, clean out mutex stuff for calls to the abstract class --- .../blockchain_data/epic_transaction.dart | 80 ++++++------- .../coins/epiccash/epiccash_wallet.dart | 108 ++++++------------ lib/wallets/example/libepiccash.dart | 24 +++- 3 files changed, 90 insertions(+), 122 deletions(-) diff --git a/lib/models/isar/models/blockchain_data/epic_transaction.dart b/lib/models/isar/models/blockchain_data/epic_transaction.dart index 9640ff49f..251c89705 100644 --- a/lib/models/isar/models/blockchain_data/epic_transaction.dart +++ b/lib/models/isar/models/blockchain_data/epic_transaction.dart @@ -1,22 +1,18 @@ -import 'package:isar/isar.dart'; -import 'package:stackwallet/models/isar/models/isar_models.dart'; +/* + * This file is part of Stack Wallet. + * + * Copyright (c) 2023 Cypher Stack + * All Rights Reserved. + * The code is distributed under GPLv3 license, see LICENSE file for details. + * Generated by Cypher Stack on 2023-10-03 + * + */ class EpicTransaction { - - @Index() - late final String walletId; - - @Index() final String parentKeyId; - - @Index(unique: true, composite: [CompositeIndex("walletId")]) - late final int id; - + final int id; final String? txSlateId; - - @enumerated - final TransactionType txType; - + final EpicTransactionType txType; final String creationTs; final String confirmationTs; final bool confirmed; @@ -32,9 +28,6 @@ class EpicTransaction { final int? kernelLookupMinHeight; final String? paymentProof; - @Backlink(to: "transactions") - final address = IsarLink<Address>(); - EpicTransaction({ required this.parentKeyId, required this.id, @@ -56,26 +49,27 @@ class EpicTransaction { this.paymentProof, }); - factory EpicTransaction.fromJson(Map<String, dynamic> json) { + factory EpicTransaction.fromJson(dynamic json) { + // print("THIS JSON IS $json") return EpicTransaction( parentKeyId: json['parent_key_id'] as String, - id: json['id'] as int, - txSlateId: json['tx_slate_id'] as String, - txType: json['tx_type'] as TransactionType, - creationTs: json['creation_ts'] as String, - confirmationTs: json['confirmation_ts'] as String, - confirmed: json['confirmed'] as bool, - numInputs: json['num_inputs'] as int, - numOutputs: json['num_outputs'] as int, - amountCredited: json['amount_credited'] as String, - amountDebited: json['amount_debited'] as String, - fee: json['fee'] as String, - ttlCutoffHeight: json['ttl_cutoff_height'] as String, + id: int.parse(json!['id'].toString()), + txSlateId: json['tx_slate_id'].toString(), + txType: EpicTransactionType.values.byName(json['tx_type'] as String), + creationTs: json['creation_ts'].toString(), + confirmationTs: json['confirmation_ts'].toString(), + confirmed: bool.parse(json['confirmed'].toString()), + numInputs: int.parse(json['num_inputs'].toString()), + numOutputs: int.parse(json['num_outputs'].toString()), + amountCredited: json['amount_credited'].toString(), + amountDebited: json['amount_debited'].toString(), + fee: json['fee'].toString(), + ttlCutoffHeight: json['ttl_cutoff_height'].toString(), messages: json['messages'] != null ? Messages.fromJson(json['messages'] as Map<String, dynamic>) : null, - storedTx: json['stored_tx'] as String, - kernelExcess: json['kernel_excess'] as String, - kernelLookupMinHeight: json['kernel_lookup_min_height'] as int, - paymentProof: json['payment_proof'] as String, + storedTx: json['stored_tx'].toString(), + kernelExcess: json['kernel_excess'].toString(), + kernelLookupMinHeight: json['kernel_lookup_min_height'] == null? null : int.parse(json['kernel_lookup_min_height'].toString()), + paymentProof: json['payment_proof'].toString(), ); } } @@ -107,10 +101,10 @@ class Message { factory Message.fromJson(Map<String, dynamic> json) { return Message( - id: json['id'] as String, - publicKey: json['public_key'] as String, - message: json['message'] as String, - messageSig: json['message_sig'] as String, + id: json['id'].toString(), + publicKey: json['public_key'].toString(), + message: json['message'].toString(), + messageSig: json['message_sig'].toString(), ); } } @@ -118,8 +112,8 @@ class Message { enum EpicTransactionType { //Use Epic transaction type here - outgoing, - incoming, - sentToSelf, // should we keep this? - unknown; + TxReceived, + TxReceivedCancelled, + TxSent, + TxSentCancelled, // should we keep this? } diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 2beba6f78..efb179deb 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -23,6 +23,7 @@ import 'package:stack_wallet_backup/generate_password.dart'; import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/epicbox_config_model.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/epic_transaction.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart'; @@ -108,16 +109,6 @@ Future<void> executeNative(Map<String, dynamic> arguments) async { sendPort.send(result); return; } - } else if (function == "getTransactions") { - final wallet = arguments['wallet'] as String?; - final refreshFromNode = arguments['refreshFromNode'] as int?; - Map<String, dynamic> result = {}; - if (!(wallet == null || refreshFromNode == null)) { - var res = await getTransactions(wallet, refreshFromNode); - result['result'] = res; - sendPort.send(result); - return; - } } else if (function == "startSync") { final wallet = arguments['wallet'] as String?; const int refreshFromNode = 1; @@ -315,12 +306,10 @@ class EpicCashWallet extends CoinServiceAPI key: '${_walletId}_wallet', ))!; - final result = await m.protect(() async { - return await epiccash.LibEpiccash.cancelTransaction( - wallet: wallet, - transactionId: txSlateId, - ); - }); + final result = await epiccash.LibEpiccash.cancelTransaction( + wallet: wallet, + transactionId: txSlateId, + ); Logging.instance.log( "cancel $txSlateId result: $result", level: LogLevel.Info, @@ -1062,14 +1051,11 @@ class EpicCashWallet extends CoinServiceAPI Future<int> get chainHeight async { try { final config = await getRealConfig(); - int? latestHeight; - await m.protect(() async { - latestHeight = - await epiccash.LibEpiccash.getChainHeight(config: config); - }); + int? latestHeight = + await epiccash.LibEpiccash.getChainHeight(config: config); - await updateCachedChainHeight(latestHeight!); - if (latestHeight! > storedChainHeight) { + await updateCachedChainHeight(latestHeight); + if (latestHeight > storedChainHeight) { GlobalEventBus.instance.fire( UpdatedInBackgroundEvent( "Updated current chain height in $walletId $walletName!", @@ -1077,7 +1063,7 @@ class EpicCashWallet extends CoinServiceAPI ), ); } - return latestHeight!; + return latestHeight; } catch (e, s) { Logging.instance.log("Exception caught in chainHeight: $e\n$s", level: LogLevel.Error); @@ -1383,80 +1369,56 @@ class EpicCashWallet extends CoinServiceAPI bool get isConnected => _isConnected; Future<void> _refreshTransactions() async { - // final currentChainHeight = await chainHeight; + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); const refreshFromNode = 1; - dynamic message; - await m.protect(() async { - ReceivePort receivePort = await getIsolate({ - "function": "getTransactions", - "wallet": wallet!, - "refreshFromNode": refreshFromNode, - }, name: walletName); - - message = await receivePort.first; - if (message is String) { - Logging.instance - .log("this is a string $message", level: LogLevel.Error); - stop(receivePort); - throw Exception("getTransactions isolate failed"); - } - stop(receivePort); - Logging.instance - .log('Closing getTransactions!\n $message', level: LogLevel.Info); - }); - // return message; - final String transactions = message['result'] as String; - - print("RETURNED TRANSACTIONS IS $transactions"); - final jsonTransactions = json.decode(transactions) as List; + var transactions = await epiccash.LibEpiccash.getTransactions(wallet: wallet!, refreshFromNode: refreshFromNode); final List<Tuple2<isar_models.Transaction, isar_models.Address?>> txnsData = []; final slatesToCommits = await getSlatesToCommits(); - for (var tx in jsonTransactions) { + for (var tx in transactions) { 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; + final isConfirmed = tx.confirmed; int amt = 0; - if (tx["tx_type"] == "TxReceived" || - tx["tx_type"] == "TxReceivedCancelled") { - amt = int.parse(tx['amount_credited'] as String); + if (tx.txType == EpicTransactionType.TxReceived || + tx.txType == EpicTransactionType.TxReceivedCancelled) { + amt = int.parse(tx.amountCredited); } else { - int debit = int.parse(tx['amount_debited'] as String); - int credit = int.parse(tx['amount_credited'] as String); - int fee = int.parse((tx['fee'] ?? "0") as String); + int debit = int.parse(tx.amountDebited); + int credit = int.parse(tx.amountCredited); + int fee = int.parse((tx.fee ?? "0")); amt = debit - credit - fee; } - DateTime dt = DateTime.parse(tx["creation_ts"] as String); + DateTime dt = DateTime.parse(tx.creationTs); - String? slateId = tx['tx_slate_id'] as String?; + String? slateId = tx.txSlateId; String address = slatesToCommits[slateId] - ?[tx["tx_type"] == "TxReceived" ? "from" : "to"] as String? ?? + ?[tx.txType == EpicTransactionType.TxReceived ? "from" : "to"] as String? ?? ""; String? commitId = slatesToCommits[slateId]?['commitId'] as String?; - tx['numberOfMessages'] = tx['messages']?['messages']?.length; - tx['onChainNote'] = tx['messages']?['messages']?[0]?['message']; + int? numberOfMessages = tx.messages?.messages.length; + String? onChainNote = tx.messages?.messages[0].message; int? height; if (isConfirmed) { - height = tx["kernel_lookup_min_height"] as int? ?? 1; + height = tx.kernelLookupMinHeight ?? 1; } else { height = null; } - final isIncoming = (tx["tx_type"] == "TxReceived" || - tx["tx_type"] == "TxReceivedCancelled"); - + final isIncoming = (tx.txType == EpicTransactionType.TxReceived || + tx.txType == EpicTransactionType.TxReceivedCancelled); final txn = isar_models.Transaction( walletId: walletId, - txid: commitId ?? tx["id"].toString(), + txid: commitId ?? tx.id.toString(), timestamp: (dt.millisecondsSinceEpoch ~/ 1000), type: isIncoming ? isar_models.TransactionType.incoming @@ -1467,19 +1429,17 @@ class EpicCashWallet extends CoinServiceAPI rawValue: BigInt.from(amt), fractionDigits: coin.decimals, ).toJsonString(), - fee: (tx["fee"] == null) ? 0 : int.parse(tx["fee"] as String), + fee: (tx.fee == "null") ? 0 : int.parse(tx.fee!), height: height, - isCancelled: tx["tx_type"] == "TxSentCancelled" || - tx["tx_type"] == "TxReceivedCancelled", + isCancelled: tx.txType == EpicTransactionType.TxSentCancelled || + tx.txType == EpicTransactionType.TxReceivedCancelled, isLelantus: false, slateId: slateId, nonce: null, - otherData: tx['onChainNote'].toString(), + otherData: onChainNote, inputs: [], outputs: [], - numberOfMessages: ((tx["numberOfMessages"] == null) - ? 0 - : tx["numberOfMessages"]) as int, + numberOfMessages: numberOfMessages, ); // txn.address = diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index 074413f63..f6cb1d913 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -4,6 +4,7 @@ import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_libepiccash/epic_cash.dart' as lib_epiccash; import 'package:mutex/mutex.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/epic_transaction.dart'; /// /// Wrapped up calls to flutter_libepiccash. @@ -263,17 +264,30 @@ abstract class LibEpiccash { /// /// /// - static Future<String> getTransaction({ + static Future<List<EpicTransaction>> getTransactions({ required String wallet, required int refreshFromNode, }) async { try { - return await compute(_getTransactionsWrapper, ( - wallet: wallet, - refreshFromNode: refreshFromNode, + var result = await compute(_getTransactionsWrapper, ( + wallet: wallet, + refreshFromNode: refreshFromNode, )); + + if (result.toUpperCase().contains("ERROR")) { + throw Exception("Error getting epic transactions ${result.toString()}"); + } + //Parse the returned data as an EpicTransaction + List<EpicTransaction> finalResult = []; + var jsonResult = json.decode(result) as List; + for (var tx in jsonResult) { + EpicTransaction itemTx = EpicTransaction.fromJson(tx); + finalResult.add(itemTx); + } + + return finalResult; } catch (e) { - throw ("Error getting epic transaction : ${e.toString()}"); + throw ("Error getting epic transactions : ${e.toString()}"); } } From 9746e789a0980e4c63f07392f0329716e75dc8be Mon Sep 17 00:00:00 2001 From: likho <likhojiba@gmail.com> Date: Wed, 4 Oct 2023 09:59:53 +0200 Subject: [PATCH 2/3] add note --- lib/services/coins/epiccash/epiccash_wallet.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 98e8e8986..07cbcb236 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -1507,7 +1507,7 @@ class EpicCashWallet extends CoinServiceAPI } else { int debit = int.parse(tx.amountDebited); int credit = int.parse(tx.amountCredited); - int fee = int.parse((tx.fee ?? "0")); + int fee = int.parse((tx.fee ?? "0")); //TODO -double check this amt = debit - credit - fee; } From c08bdd3c087dc4ac06e4df6306cb0fb537c89c4d Mon Sep 17 00:00:00 2001 From: likho <likhojiba@gmail.com> Date: Wed, 4 Oct 2023 15:31:35 +0200 Subject: [PATCH 3/3] Remove startSync isolate --- .../coins/epiccash/epiccash_wallet.dart | 40 +++---------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 07cbcb236..c162a1420 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -109,20 +109,6 @@ Future<void> executeNative(Map<String, dynamic> arguments) async { sendPort.send(result); return; } - } else if (function == "startSync") { - final wallet = arguments['wallet'] as String?; - const int refreshFromNode = 1; - Map<String, dynamic> result = {}; - if (!(wallet == null)) { - var res = await epiccash.LibEpiccash.getWalletBalances( - wallet: wallet!, - refreshFromNode: refreshFromNode, - minimumConfirmations: 10, - ); - result['result'] = res; - sendPort.send(result); - return; - } } Logging.instance.log( @@ -247,28 +233,14 @@ class EpicCashWallet extends CoinServiceAPI Future<String> startSync() async { Logging.instance.log("request start sync", level: LogLevel.Info); final wallet = await _secureStore.read(key: '${_walletId}_wallet'); - + const int refreshFromNode = 1; if (!syncMutex.isLocked) { - await syncMutex.protect(() async { - Logging.instance.log("sync started", level: LogLevel.Info); - ReceivePort receivePort = await getIsolate({ - "function": "startSync", - "wallet": wallet!, - }, name: walletName); - this.receivePort = receivePort; - var message = await receivePort.first; - if (message is String) { - Logging.instance - .log("this is a string $message", level: LogLevel.Error); - stop(receivePort); - throw Exception("startSync isolate failed"); - } - stop(receivePort); - Logging.instance - .log('Closing startSync!\n $message', level: LogLevel.Info); - Logging.instance.log("sync ended", level: LogLevel.Info); - }); + await epiccash.LibEpiccash.getWalletBalances( + wallet: wallet!, + refreshFromNode: refreshFromNode, + minimumConfirmations: 10, + ); } else { Logging.instance.log("request start sync denied", level: LogLevel.Info); }