Skip to content

Commit cd03849

Browse files
Merge pull request #735 from cypherstack/monero_changes
Possible monero shared history fix
2 parents cb29144 + 0f8e0db commit cd03849

File tree

3 files changed

+213
-109
lines changed

3 files changed

+213
-109
lines changed

lib/wallets/wallet/impl/monero_wallet.dart

Lines changed: 100 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
3737

3838
@override
3939
Address addressFor({required int index, int account = 0}) {
40-
String address = (cwWalletBase as MoneroWalletBase)
40+
String address = (CwBasedInterface.cwWalletBase as MoneroWalletBase)
4141
.getTransactionAddress(account, index);
4242

4343
final newReceivingAddress = Address(
@@ -55,16 +55,19 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
5555

5656
@override
5757
Future<void> exitCwWallet() async {
58-
resetWalletOpenCompleter();
59-
(cwWalletBase as MoneroWalletBase?)?.onNewBlock = null;
60-
(cwWalletBase as MoneroWalletBase?)?.onNewTransaction = null;
61-
(cwWalletBase as MoneroWalletBase?)?.syncStatusChanged = null;
62-
await (cwWalletBase as MoneroWalletBase?)?.save(prioritySave: true);
58+
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)?.onNewBlock = null;
59+
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)?.onNewTransaction =
60+
null;
61+
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)?.syncStatusChanged =
62+
null;
63+
await (CwBasedInterface.cwWalletBase as MoneroWalletBase?)
64+
?.save(prioritySave: true);
6365
}
6466

6567
@override
6668
Future<void> open() async {
67-
resetWalletOpenCompleter();
69+
// await any previous exit
70+
await CwBasedInterface.exitMutex.protect(() async {});
6871

6972
String? password;
7073
try {
@@ -73,30 +76,32 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
7376
throw Exception("Password not found $e, $s");
7477
}
7578

76-
cwWalletBase?.close();
77-
cwWalletBase = (await cwWalletService!.openWallet(walletId, password))
78-
as MoneroWalletBase;
79+
CwBasedInterface.cwWalletBase?.close();
80+
CwBasedInterface.cwWalletBase = (await CwBasedInterface.cwWalletService!
81+
.openWallet(walletId, password)) as MoneroWalletBase;
7982

80-
(cwWalletBase as MoneroWalletBase?)?.onNewBlock = onNewBlock;
81-
(cwWalletBase as MoneroWalletBase?)?.onNewTransaction = onNewTransaction;
82-
(cwWalletBase as MoneroWalletBase?)?.syncStatusChanged = syncStatusChanged;
83+
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)?.onNewBlock =
84+
onNewBlock;
85+
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)?.onNewTransaction =
86+
onNewTransaction;
87+
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)?.syncStatusChanged =
88+
syncStatusChanged;
8389

8490
await updateNode();
8591

86-
await cwWalletBase?.startSync();
92+
await CwBasedInterface.cwWalletBase?.startSync();
8793
unawaited(refresh());
8894
autoSaveTimer?.cancel();
8995
autoSaveTimer = Timer.periodic(
9096
const Duration(seconds: 193),
91-
(_) async => await cwWalletBase?.save(),
97+
(_) async => await CwBasedInterface.cwWalletBase?.save(),
9298
);
93-
94-
walletOpenCompleter?.complete();
9599
}
96100

97101
@override
98102
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
99-
if (cwWalletBase == null || cwWalletBase?.syncStatus is! SyncedSyncStatus) {
103+
if (CwBasedInterface.cwWalletBase == null ||
104+
CwBasedInterface.cwWalletBase?.syncStatus is! SyncedSyncStatus) {
100105
return Amount.zeroWith(
101106
fractionDigits: cryptoCurrency.fractionDigits,
102107
);
@@ -124,7 +129,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
124129

125130
int approximateFee = 0;
126131
await estimateFeeMutex.protect(() async {
127-
approximateFee = cwWalletBase!.calculateEstimatedFee(
132+
approximateFee = CwBasedInterface.cwWalletBase!.calculateEstimatedFee(
128133
priority,
129134
amount.raw.toInt(),
130135
);
@@ -138,15 +143,17 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
138143

139144
@override
140145
Future<bool> pingCheck() async {
141-
return await (cwWalletBase as MoneroWalletBase?)?.isConnected() ?? false;
146+
return await (CwBasedInterface.cwWalletBase as MoneroWalletBase?)
147+
?.isConnected() ??
148+
false;
142149
}
143150

144151
@override
145152
Future<void> updateNode() async {
146153
final node = getCurrentNode();
147154

148155
final host = Uri.parse(node.host).host;
149-
await cwWalletBase?.connectToNode(
156+
await CwBasedInterface.cwWalletBase?.connectToNode(
150157
node: Node(
151158
uri: "$host:${node.port}",
152159
type: WalletType.monero,
@@ -157,16 +164,15 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
157164

158165
@override
159166
Future<void> updateTransactions() async {
160-
try {
161-
await waitForWalletOpen().timeout(const Duration(seconds: 30));
162-
} catch (e, s) {
163-
Logging.instance
164-
.log("Failed to wait for wallet open: $e\n$s", level: LogLevel.Fatal);
165-
}
167+
final base = (CwBasedInterface.cwWalletBase as MoneroWalletBase?);
166168

167-
await (cwWalletBase as MoneroWalletBase?)?.updateTransactions();
168-
final transactions =
169-
(cwWalletBase as MoneroWalletBase?)?.transactionHistory?.transactions;
169+
if (base == null ||
170+
base.walletInfo.name != walletId ||
171+
CwBasedInterface.exitMutex.isLocked) {
172+
return;
173+
}
174+
await base.updateTransactions();
175+
final transactions = base.transactionHistory?.transactions;
170176

171177
// final cachedTransactions =
172178
// DB.instance.get<dynamic>(boxName: walletId, key: 'latest_tx_model')
@@ -210,7 +216,8 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
210216
final addressInfo = tx.value.additionalInfo;
211217

212218
final addressString =
213-
(cwWalletBase as MoneroWalletBase?)?.getTransactionAddress(
219+
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)
220+
?.getTransactionAddress(
214221
addressInfo!['accountIndex'] as int,
215222
addressInfo['addressIndex'] as int,
216223
);
@@ -256,15 +263,42 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
256263
}
257264
}
258265

259-
await mainDB.addNewTransactionData(txnsData, walletId);
266+
await mainDB.isar.writeTxn(() async {
267+
await mainDB.isar.transactions
268+
.where()
269+
.walletIdEqualTo(walletId)
270+
.deleteAll();
271+
for (final data in txnsData) {
272+
final tx = data.item1;
273+
274+
// save transaction
275+
await mainDB.isar.transactions.put(tx);
276+
277+
if (data.item2 != null) {
278+
final address = await mainDB.getAddress(walletId, data.item2!.value);
279+
280+
// check if address exists in db and add if it does not
281+
if (address == null) {
282+
await mainDB.isar.addresses.put(data.item2!);
283+
}
284+
285+
// link and save address
286+
tx.address.value = address ?? data.item2!;
287+
await tx.address.save();
288+
}
289+
}
290+
});
260291
}
261292

262293
@override
263294
Future<void> init({bool? isRestore}) async {
264-
cwWalletService = xmr_dart.monero
295+
await CwBasedInterface.exitMutex.protect(() async {});
296+
297+
CwBasedInterface.cwWalletService = xmr_dart.monero
265298
.createMoneroWalletService(DB.instance.moneroWalletInfoBox);
266299

267-
if (!(await cwWalletService!.isWalletExit(walletId)) && isRestore != true) {
300+
if (!(await CwBasedInterface.cwWalletService!.isWalletExit(walletId)) &&
301+
isRestore != true) {
268302
WalletInfo walletInfo;
269303
WalletCredentials credentials;
270304
try {
@@ -292,7 +326,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
292326

293327
final _walletCreationService = WalletCreationService(
294328
secureStorage: secureStorageInterface,
295-
walletService: cwWalletService,
329+
walletService: CwBasedInterface.cwWalletService,
296330
keyService: cwKeysStorage,
297331
);
298332
_walletCreationService.type = WalletType.monero;
@@ -328,7 +362,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
328362
wallet.close();
329363
} catch (e, s) {
330364
Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
331-
cwWalletBase?.close();
365+
CwBasedInterface.cwWalletBase?.close();
332366
}
333367
await updateNode();
334368
}
@@ -338,14 +372,17 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
338372

339373
@override
340374
Future<void> recover({required bool isRescan}) async {
375+
await CwBasedInterface.exitMutex.protect(() async {});
376+
341377
if (isRescan) {
342378
await refreshMutex.protect(() async {
343379
// clear blockchain info
344380
await mainDB.deleteWalletBlockchainData(walletId);
345381

346-
var restoreHeight = cwWalletBase?.walletInfo.restoreHeight;
382+
var restoreHeight =
383+
CwBasedInterface.cwWalletBase?.walletInfo.restoreHeight;
347384
highestPercentCached = 0;
348-
await cwWalletBase?.rescan(height: restoreHeight ?? 0);
385+
await CwBasedInterface.cwWalletBase?.rescan(height: restoreHeight ?? 0);
349386
});
350387
unawaited(refresh());
351388
return;
@@ -367,7 +404,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
367404
isar: mainDB.isar,
368405
);
369406

370-
cwWalletService = xmr_dart.monero
407+
CwBasedInterface.cwWalletService = xmr_dart.monero
371408
.createMoneroWalletService(DB.instance.moneroWalletInfoBox);
372409
WalletInfo walletInfo;
373410
WalletCredentials credentials;
@@ -397,7 +434,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
397434

398435
final cwWalletCreationService = WalletCreationService(
399436
secureStorage: secureStorageInterface,
400-
walletService: cwWalletService,
437+
walletService: CwBasedInterface.cwWalletService,
401438
keyService: cwKeysStorage,
402439
);
403440
cwWalletCreationService.type = WalletType.monero;
@@ -425,15 +462,15 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
425462
isar: mainDB.isar,
426463
);
427464
}
428-
cwWalletBase?.close();
429-
cwWalletBase = wallet as MoneroWalletBase;
465+
CwBasedInterface.cwWalletBase?.close();
466+
CwBasedInterface.cwWalletBase = wallet as MoneroWalletBase;
430467
} catch (e, s) {
431468
Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
432469
}
433470
await updateNode();
434471

435-
await cwWalletBase?.rescan(height: credentials.height);
436-
cwWalletBase?.close();
472+
await CwBasedInterface.cwWalletBase?.rescan(height: credentials.height);
473+
CwBasedInterface.cwWalletBase?.close();
437474
} catch (e, s) {
438475
Logging.instance.log(
439476
"Exception rethrown from recoverFromMnemonic(): $e\n$s",
@@ -475,7 +512,7 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
475512

476513
List<monero_output.Output> outputs = [];
477514
for (final recipient in txData.recipients!) {
478-
final output = monero_output.Output(cwWalletBase!);
515+
final output = monero_output.Output(CwBasedInterface.cwWalletBase!);
479516
output.address = recipient.address;
480517
output.sendAll = isSendAll;
481518
String amountToSend = recipient.amount.decimal.toString();
@@ -490,7 +527,8 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
490527
);
491528

492529
await prepareSendMutex.protect(() async {
493-
awaitPendingTransaction = cwWalletBase!.createTransaction(tmp);
530+
awaitPendingTransaction =
531+
CwBasedInterface.cwWalletBase!.createTransaction(tmp);
494532
});
495533
} catch (e, s) {
496534
Logging.instance.log("Exception rethrown from prepareSend(): $e\n$s",
@@ -549,9 +587,13 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
549587
@override
550588
Future<Amount> get availableBalance async {
551589
try {
590+
if (CwBasedInterface.exitMutex.isLocked) {
591+
throw Exception("Exit in progress");
592+
}
552593
int runningBalance = 0;
553-
for (final entry
554-
in (cwWalletBase as MoneroWalletBase?)!.balance!.entries) {
594+
for (final entry in (CwBasedInterface.cwWalletBase as MoneroWalletBase?)!
595+
.balance!
596+
.entries) {
555597
runningBalance += entry.value.unlockedBalance;
556598
}
557599
return Amount(
@@ -566,8 +608,13 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
566608
@override
567609
Future<Amount> get totalBalance async {
568610
try {
611+
if (CwBasedInterface.exitMutex.isLocked) {
612+
throw Exception("Exit in progress");
613+
}
569614
final balanceEntries =
570-
(cwWalletBase as MoneroWalletBase?)?.balance?.entries;
615+
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)
616+
?.balance
617+
?.entries;
571618
if (balanceEntries != null) {
572619
int bal = 0;
573620
for (var element in balanceEntries) {
@@ -578,9 +625,10 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
578625
fractionDigits: cryptoCurrency.fractionDigits,
579626
);
580627
} else {
581-
final transactions = (cwWalletBase as MoneroWalletBase?)!
582-
.transactionHistory!
583-
.transactions;
628+
final transactions =
629+
(CwBasedInterface.cwWalletBase as MoneroWalletBase?)!
630+
.transactionHistory!
631+
.transactions;
584632
int transactionBalance = 0;
585633
for (var tx in transactions!.entries) {
586634
if (tx.value.direction == TransactionDirection.incoming) {

0 commit comments

Comments
 (0)