mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 12:29:51 +00:00
Implement background sync for xmr using flutter_daemon (#2094)
* Implement background sync for xmr using flutter_daemon * - initialize app config in background thread - initializeAppConfigs without loading the wallet. * - properly do awaited calls in methodChannel - prevent locking main thread during background sync * add back background sync debug page fix issues caused by xmr wallet being view only (and read only) * changes from review improve starting of bgsync task * update stopBackgroundSync, await listener functions, ensure that listener always start (call _start in constructor) * DO-NOT-MERGE: extre verbose monero logs * stop background service when app is being opened * improve monitoring of background sync * update flutter_daemon to ensure network constraint prevent throwing errors on isBackgroundSyncEnabled check network before syncing * Update lib/main.dart * revert Update main.dart [skip ci] * continously run network check * disable charging requirement, fix status reporting of background sync in UI * Refactor background sync logic, and add UI notifications for battery optimization. Updated flutter_daemon version modified build.gradle for signing config to allow testing in both release and debug modes. * verbose monero only when requested in code. Do not start background sync when battery optimization is on * fix background sync mode not properly reflecting state changes * drop unnecessary dependency --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
parent
d44621e6c7
commit
686580ff78
60 changed files with 853 additions and 352 deletions
|
@ -37,7 +37,8 @@ List<monero.SubaddressAccountRow> getAllAccount() {
|
|||
int size = monero.SubaddressAccount_getAll_size(subaddressAccount!);
|
||||
if (size == 0) {
|
||||
monero.Wallet_addSubaddressAccount(wptr!);
|
||||
return getAllAccount();
|
||||
monero.Wallet_status(wptr!);
|
||||
return [];
|
||||
}
|
||||
return List.generate(size, (index) {
|
||||
return monero.SubaddressAccount_getAll_byIndex(subaddressAccount!, index: index);
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
import 'dart:ffi';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:cw_core/root_dir.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_monero/api/account_list.dart';
|
||||
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
|
||||
|
@ -108,9 +109,13 @@ Map<int, Map<int, Map<int, String>>> addressCache = {};
|
|||
|
||||
String getAddress({int accountIndex = 0, int addressIndex = 0}) {
|
||||
// printV("getaddress: ${accountIndex}/${addressIndex}: ${monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)}: ${monero.Wallet_address(wptr!, accountIndex: accountIndex, addressIndex: addressIndex)}");
|
||||
while (monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)-1 < addressIndex) {
|
||||
printV("adding subaddress");
|
||||
monero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex);
|
||||
// this could be a while loop, but I'm in favor of making it if to not cause freezes
|
||||
if (monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)-1 < addressIndex) {
|
||||
if (monero.Wallet_numSubaddressAccounts(wptr!) < accountIndex) {
|
||||
monero.Wallet_addSubaddressAccount(wptr!);
|
||||
} else {
|
||||
monero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex);
|
||||
}
|
||||
}
|
||||
addressCache[wptr!.address] ??= {};
|
||||
addressCache[wptr!.address]![accountIndex] ??= {};
|
||||
|
@ -149,6 +154,7 @@ Future<bool> setupNodeSync(
|
|||
}
|
||||
''');
|
||||
final addr = wptr!.address;
|
||||
printV("init: start");
|
||||
await Isolate.run(() {
|
||||
monero.Wallet_init(Pointer.fromAddress(addr),
|
||||
daemonAddress: address,
|
||||
|
@ -157,6 +163,7 @@ Future<bool> setupNodeSync(
|
|||
daemonUsername: login ?? '',
|
||||
daemonPassword: password ?? '');
|
||||
});
|
||||
printV("init: end");
|
||||
|
||||
final status = monero.Wallet_status(wptr!);
|
||||
|
||||
|
@ -168,7 +175,7 @@ Future<bool> setupNodeSync(
|
|||
}
|
||||
}
|
||||
|
||||
if (kDebugMode && debugMonero) {
|
||||
if (true) {
|
||||
monero.Wallet_init3(
|
||||
wptr!, argv0: '',
|
||||
defaultLogBaseName: 'moneroc',
|
||||
|
@ -243,7 +250,9 @@ class SyncListener {
|
|||
SyncListener(this.onNewBlock, this.onNewTransaction)
|
||||
: _cachedBlockchainHeight = 0,
|
||||
_lastKnownBlockHeight = 0,
|
||||
_initialSyncHeight = 0;
|
||||
_initialSyncHeight = 0 {
|
||||
_start();
|
||||
}
|
||||
|
||||
void Function(int, int, double) onNewBlock;
|
||||
void Function() onNewTransaction;
|
||||
|
@ -261,7 +270,7 @@ class SyncListener {
|
|||
return _cachedBlockchainHeight;
|
||||
}
|
||||
|
||||
void start() {
|
||||
void _start() {
|
||||
_cachedBlockchainHeight = 0;
|
||||
_lastKnownBlockHeight = 0;
|
||||
_initialSyncHeight = 0;
|
||||
|
@ -282,7 +291,7 @@ class SyncListener {
|
|||
}
|
||||
|
||||
final bchHeight = await getNodeHeightOrUpdate(syncHeight);
|
||||
|
||||
// printV("syncHeight: $syncHeight, _lastKnownBlockHeight: $_lastKnownBlockHeight, bchHeight: $bchHeight");
|
||||
if (_lastKnownBlockHeight == syncHeight) {
|
||||
return;
|
||||
}
|
||||
|
@ -379,4 +388,4 @@ String signMessage(String message, {String address = ""}) {
|
|||
|
||||
bool verifyMessage(String message, String address, String signature) {
|
||||
return monero.Wallet_verifySignedMessage(wptr!, message: message, address: address, signature: signature);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import 'package:cw_monero/api/exceptions/wallet_restore_from_seed_exception.dart
|
|||
import 'package:cw_monero/api/transaction_history.dart';
|
||||
import 'package:cw_monero/api/wallet.dart';
|
||||
import 'package:cw_monero/ledger.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
|
||||
class MoneroCException implements Exception {
|
||||
|
@ -50,7 +51,13 @@ final monero.WalletManager wmPtr = Pointer.fromAddress((() {
|
|||
// codebase, so it will be easier to debug what happens. At least easier
|
||||
// than plugging gdb in. Especially on windows/android.
|
||||
monero.printStarts = false;
|
||||
if (kDebugMode && debugMonero) {
|
||||
monero.WalletManagerFactory_setLogLevel(4);
|
||||
}
|
||||
_wmPtr ??= monero.WalletManagerFactory_getWalletManager();
|
||||
if (kDebugMode && debugMonero) {
|
||||
monero.WalletManagerFactory_setLogLevel(4);
|
||||
}
|
||||
printV("ptr: $_wmPtr");
|
||||
} catch (e) {
|
||||
printV(e);
|
||||
|
@ -77,10 +84,17 @@ void createWalletSync(
|
|||
final newWptr = monero.WalletManager_createWallet(wmPtr,
|
||||
path: path, password: password, language: language, networkType: 0);
|
||||
|
||||
final status = monero.Wallet_status(newWptr);
|
||||
int status = monero.Wallet_status(newWptr);
|
||||
if (status != 0) {
|
||||
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
|
||||
}
|
||||
|
||||
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
|
||||
status = monero.Wallet_status(newWptr);
|
||||
if (status != 0) {
|
||||
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
|
||||
}
|
||||
|
||||
wptr = newWptr;
|
||||
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase);
|
||||
monero.Wallet_store(wptr!, path: path);
|
||||
|
@ -166,12 +180,19 @@ void restoreWalletFromKeysSync(
|
|||
nettype: 0,
|
||||
);
|
||||
|
||||
final status = monero.Wallet_status(newWptr);
|
||||
int status = monero.Wallet_status(newWptr);
|
||||
if (status != 0) {
|
||||
throw WalletRestoreFromKeysException(
|
||||
message: monero.Wallet_errorString(newWptr));
|
||||
}
|
||||
|
||||
|
||||
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
|
||||
status = monero.Wallet_status(newWptr);
|
||||
if (status != 0) {
|
||||
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
|
||||
}
|
||||
|
||||
// CW-712 - Try to restore deterministic wallet first, if the view key doesn't
|
||||
// match the view key provided
|
||||
if (spendKey != "") {
|
||||
|
@ -190,11 +211,17 @@ void restoreWalletFromKeysSync(
|
|||
spendKeyString: spendKey,
|
||||
nettype: 0,
|
||||
);
|
||||
final status = monero.Wallet_status(newWptr);
|
||||
int status = monero.Wallet_status(newWptr);
|
||||
if (status != 0) {
|
||||
throw WalletRestoreFromKeysException(
|
||||
message: monero.Wallet_errorString(newWptr));
|
||||
}
|
||||
|
||||
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
|
||||
status = monero.Wallet_status(newWptr);
|
||||
if (status != 0) {
|
||||
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,7 +254,7 @@ void restoreWalletFromPolyseedWithOffset(
|
|||
kdfRounds: 1,
|
||||
);
|
||||
|
||||
final status = monero.Wallet_status(newWptr);
|
||||
int status = monero.Wallet_status(newWptr);
|
||||
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(newWptr);
|
||||
|
@ -240,6 +267,12 @@ void restoreWalletFromPolyseedWithOffset(
|
|||
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
|
||||
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: seedOffset);
|
||||
monero.Wallet_store(wptr!);
|
||||
|
||||
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
|
||||
status = monero.Wallet_status(newWptr);
|
||||
if (status != 0) {
|
||||
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
|
||||
}
|
||||
storeSync();
|
||||
|
||||
openedWalletsByPath[path] = wptr!;
|
||||
|
@ -277,7 +310,7 @@ void restoreWalletFromSpendKeySync(
|
|||
restoreHeight: restoreHeight,
|
||||
);
|
||||
|
||||
final status = monero.Wallet_status(newWptr);
|
||||
int status = monero.Wallet_status(newWptr);
|
||||
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(newWptr);
|
||||
|
@ -290,6 +323,12 @@ void restoreWalletFromSpendKeySync(
|
|||
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
|
||||
|
||||
storeSync();
|
||||
|
||||
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
|
||||
status = monero.Wallet_status(newWptr);
|
||||
if (status != 0) {
|
||||
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
|
||||
}
|
||||
|
||||
openedWalletsByPath[path] = wptr!;
|
||||
_lastOpenedWallet = path;
|
||||
|
@ -321,6 +360,14 @@ Future<void> restoreWalletFromHardwareWallet(
|
|||
final error = monero.Wallet_errorString(newWptr);
|
||||
throw WalletRestoreFromSeedException(message: error);
|
||||
}
|
||||
|
||||
// TODO: Check with upstream if we can use background sync here
|
||||
// monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
|
||||
// status = monero.Wallet_status(newWptr);
|
||||
// if (status != 0) {
|
||||
// throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
|
||||
// }
|
||||
|
||||
wptr = newWptr;
|
||||
_lastOpenedWallet = path;
|
||||
openedWalletsByPath[path] = wptr!;
|
||||
|
@ -384,7 +431,14 @@ Future<void> loadWallet(
|
|||
|
||||
final newWptr = Pointer<Void>.fromAddress(newWptrAddr);
|
||||
|
||||
final status = monero.Wallet_status(newWptr);
|
||||
int status = monero.Wallet_status(newWptr);
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(newWptr);
|
||||
printV("loadWallet:"+err);
|
||||
throw WalletOpeningException(message: err);
|
||||
}
|
||||
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
|
||||
status = monero.Wallet_status(newWptr);
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(newWptr);
|
||||
printV("loadWallet:"+err);
|
||||
|
|
|
@ -218,7 +218,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
// FIXME: hardcoded value
|
||||
socksProxyAddress: node.socksProxyAddress);
|
||||
|
||||
monero_wallet.setTrustedDaemon(node.trusted);
|
||||
await monero_wallet.setTrustedDaemon(node.trusted);
|
||||
syncStatus = ConnectedSyncStatus();
|
||||
} catch (e) {
|
||||
syncStatus = FailedSyncStatus();
|
||||
|
@ -226,6 +226,57 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> startBackgroundSync() async {
|
||||
if (isBackgroundSyncRunning) {
|
||||
printV("Background sync already running");
|
||||
return;
|
||||
}
|
||||
isBackgroundSyncRunning = true;
|
||||
int status = monero.Wallet_status(wptr!);
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(wptr!);
|
||||
throw Exception("unable to setup background sync: $err");
|
||||
}
|
||||
await save();
|
||||
|
||||
monero.Wallet_startBackgroundSync(wptr!);
|
||||
status = monero.Wallet_status(wptr!);
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(wptr!);
|
||||
throw Exception("unable to start background sync: $err");
|
||||
}
|
||||
await save();
|
||||
await init();
|
||||
await startSync();
|
||||
}
|
||||
|
||||
bool isBackgroundSyncRunning = false;
|
||||
|
||||
@action
|
||||
@override
|
||||
Future<void> stopSync() async {
|
||||
if (isBackgroundSyncRunning) {
|
||||
printV("Stopping background sync");
|
||||
await save();
|
||||
monero.Wallet_stopBackgroundSync(wptr!, '');
|
||||
await save();
|
||||
isBackgroundSyncRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
@override
|
||||
Future<void> stopBackgroundSync(String password) async {
|
||||
if (isBackgroundSyncRunning) {
|
||||
printV("Stopping background sync");
|
||||
await save();
|
||||
monero.Wallet_stopBackgroundSync(wptr!, password);
|
||||
await save();
|
||||
isBackgroundSyncRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> startSync() async {
|
||||
try {
|
||||
|
@ -250,7 +301,6 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
syncStatus = AttemptingSyncStatus();
|
||||
monero_wallet.startRefresh();
|
||||
_setListeners();
|
||||
_listener?.start();
|
||||
} catch (e) {
|
||||
syncStatus = FailedSyncStatus();
|
||||
printV(e);
|
||||
|
@ -782,6 +832,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
}
|
||||
|
||||
void _onNewBlock(int height, int blocksLeft, double ptc) async {
|
||||
printV("onNewBlock: $height, $blocksLeft, $ptc");
|
||||
try {
|
||||
if (walletInfo.isRecovery) {
|
||||
await _askForUpdateTransactionHistory();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue