add missing mutex in monero (#3188)

* add missing mutex in monero * wrap critical block in try-finally * Update lib/view_model/dashboard/dashboard_view_model.dart [skip ci] --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

malik1004x committed Apr 16, 2026 at 12:54 UTC 21847cd95806b5be3d581cadb510aa39dd258f42
5 files changed +43 -38
cw_monero/lib/api/subaddress_list.dart
+26 -18
@@ -65,25 +65,33 @@ int lastWptr = 0;
65 int lastTxCount = 0;
66 List<TinyTransactionDetails> ttDetails = [];
67
68 -List<Subaddress> getAllSubaddresses() {
69 - txhistory = currentWallet!.history();
70 - final txCount = txhistory!.count();
71 - if (lastTxCount != txCount && lastWptr != currentWallet!.ffiAddress()) {
72 - final List<TinyTransactionDetails> newttDetails = [];
73 - lastTxCount = txCount;
74 - lastWptr = currentWallet!.ffiAddress();
75 - for (var i = 0; i < txCount; i++) {
76 - final tx = txhistory!.transaction(i);
77 - if (tx.direction() == TransactionInfo_Direction.Out.index) continue;
78 - final subaddrs = tx.subaddrIndex().split(",");
79 - final account = tx.subaddrAccount();
80 - newttDetails.add(TinyTransactionDetails(
81 - address: List.generate(subaddrs.length, (index) => getAddress(accountIndex: account, addressIndex: int.tryParse(subaddrs[index])??0)),
82 - amount: tx.amount(),
83 - ));
68 +Future<List<Subaddress>> getAllSubaddresses() async {
69 + try {
70 + await txHistoryMutex.acquire();
71 + txhistory = currentWallet!.history();
72 + final txCount = txhistory!.count();
73 + if (lastTxCount != txCount && lastWptr != currentWallet!.ffiAddress()) {
74 + final List<TinyTransactionDetails> newttDetails = [];
75 + lastTxCount = txCount;
76 + lastWptr = currentWallet!.ffiAddress();
77 + for (var i = 0; i < txCount; i++) {
78 + final tx = txhistory!.transaction(i);
79 + if (tx.direction() == TransactionInfo_Direction.Out.index) continue;
80 + final subaddrs = tx.subaddrIndex().split(",");
81 + final account = tx.subaddrAccount();
82 + newttDetails.add(TinyTransactionDetails(
83 + address: List.generate(
84 + subaddrs.length,
85 + (index) => getAddress(
86 + accountIndex: account, addressIndex: int.tryParse(subaddrs[index]) ?? 0)),
87 + amount: tx.amount(),
88 + ));
89 + }
90 + ttDetails.clear();
91 + ttDetails.addAll(newttDetails);
92 }
85 - ttDetails.clear();
86 - ttDetails.addAll(newttDetails);
93 + } finally {
94 + txHistoryMutex.release();
95 }
96 final size = currentWallet!.numSubaddresses(accountIndex: subaddress!.accountIndex);
97 final list = List.generate(size, (index) {
cw_monero/lib/monero_subaddress_list.dart
+10 -13
@@ -2,7 +2,7 @@ import 'package:cw_core/subaddress.dart';
2 import 'package:cw_core/utils/print_verbose.dart';
3 import 'package:cw_monero/api/coins_info.dart';
4 import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
5 -import 'package:cw_monero/api/wallet.dart';
5 +
6 import 'package:flutter/services.dart';
7 import 'package:mobx/mobx.dart';
8
@@ -24,7 +24,7 @@ abstract class MoneroSubaddressListBase with Store {
24 bool _isRefreshing;
25 bool _isUpdating;
26
27 - void update({required int accountIndex}) {
27 + Future<void> update({required int accountIndex}) async {
28 refreshCoins(accountIndex);
29
30 if (_isUpdating) {
@@ -35,7 +35,7 @@ abstract class MoneroSubaddressListBase with Store {
35 _isUpdating = true;
36 refresh(accountIndex: accountIndex);
37 subaddresses.clear();
38 - subaddresses.addAll(getAll());
38 + subaddresses.addAll(await getAll());
39 _isUpdating = false;
40 } catch (e) {
41 _isUpdating = false;
@@ -43,8 +43,8 @@ abstract class MoneroSubaddressListBase with Store {
43 }
44 }
45
46 - List<Subaddress> getAll() {
47 - var subaddresses = subaddress_list.getAllSubaddresses();
46 + Future<List<Subaddress>> getAll() async {
47 + var subaddresses = await subaddress_list.getAllSubaddresses();
48
49 if (subaddresses.length > 2) {
50 final primary = subaddresses.first;
@@ -122,7 +122,7 @@ abstract class MoneroSubaddressListBase with Store {
122
123 Future<List<Subaddress>> _getAllUnusedAddresses(
124 {required int accountIndex, required String label}) async {
125 - final allAddresses = subaddress_list.getAllSubaddresses();
125 + final allAddresses = await subaddress_list.getAllSubaddresses();
126 // first because addresses come in reversed order.
127 if (allAddresses.isEmpty || _usedAddresses.contains(allAddresses.first.address)) {
128 final isAddressUnused = await _newSubaddress(accountIndex: accountIndex, label: label);
@@ -151,12 +151,9 @@ abstract class MoneroSubaddressListBase with Store {
151 Future<bool> _newSubaddress({required int accountIndex, required String label}) async {
152 await subaddress_list.addSubaddress(accountIndex: accountIndex, label: label);
153
154 - return subaddress_list
155 - .getAllSubaddresses()
156 - .where((s) {
157 - final address = s.address;
158 - return !_usedAddresses.contains(address);
159 - })
160 - .isNotEmpty;
154 + return (await subaddress_list.getAllSubaddresses()).where((s) {
155 + final address = s.address;
156 + return !_usedAddresses.contains(address);
157 + }).isNotEmpty;
158 }
159 }
lib/monero/cw_monero.dart
+3 -3
@@ -89,10 +89,10 @@ class CWMoneroSubaddressList extends MoneroSubaddressList {
89 }
90
91 @override
92 - List<Subaddress> getAll(Object wallet) {
92 + Future<List<Subaddress>> getAll(Object wallet) async {
93 final moneroWallet = wallet as MoneroWallet;
94 - return moneroWallet.walletAddresses.subaddressList
95 - .getAll()
94 + return (await moneroWallet.walletAddresses.subaddressList
95 + .getAll())
96 .map((sub) => Subaddress(
97 id: sub.id,
98 label: sub.label,
lib/view_model/dashboard/dashboard_view_model.dart
+3 -3
@@ -770,9 +770,9 @@ abstract class DashboardViewModelBase with Store {
770 "public view key is 0",
771 // if (wallet.seed == null) "wallet seed is null",
772 // if (wallet.seed == "") "wallet seed is empty",
773 - if (monero!.getSubaddressList(wallet).getAll(wallet)[0].address ==
774 - "41d7FXjswpK1111111111111111111111111111111111111111111111111111111111111111111111111111112KhNi4")
775 - "primary address is invalid, you won't be able to receive / spend funds",
773 + // if (monero!.getSubaddressList(wallet).getAll(wallet)[0].address ==
774 + // "41d7FXjswpK1111111111111111111111111111111111111111111111111111111111111111111111111111112KhNi4")
775 + // "primary address is invalid, you won't be able to receive / spend funds",
776 ];
777 return errors;
778 }
tool/configure.dart
+1 -1
@@ -492,7 +492,7 @@ abstract class MoneroSubaddressList {
492 ObservableList<Subaddress> get subaddresses;
493 void update(Object wallet, {required int accountIndex});
494 void refresh(Object wallet, {required int accountIndex});
495 - List<Subaddress> getAll(Object wallet);
495 + Future<List<Subaddress>> getAll(Object wallet);
496 Future<void> addSubaddress(Object wallet, {required int accountIndex, required String label});
497 Future<void> setLabelSubaddress(Object wallet,
498 {required int accountIndex, required int addressIndex, required String label});