From 5cf5c71b9073db0f125b3d016ad59c30e0d19944 Mon Sep 17 00:00:00 2001 From: Oscar Mira Date: Wed, 26 Apr 2023 23:50:20 +0200 Subject: [PATCH] demo: autosave wallet state --- .../molly/monero/demo/data/MoneroSdkClient.kt | 16 ++++-- .../monero/demo/data/WalletRepository.kt | 5 +- .../molly/monero/demo/service/SyncService.kt | 50 +++++++++++-------- .../main/aidl/im/molly/monero/IWallet.aidl | 2 +- lib/android/src/main/cpp/wallet.cc | 36 ++++++------- lib/android/src/main/cpp/wallet.h | 4 +- vendor/monero | 2 +- 7 files changed, 68 insertions(+), 47 deletions(-) diff --git a/demo/android/src/main/kotlin/im/molly/monero/demo/data/MoneroSdkClient.kt b/demo/android/src/main/kotlin/im/molly/monero/demo/data/MoneroSdkClient.kt index c41d3cb..5c77d80 100644 --- a/demo/android/src/main/kotlin/im/molly/monero/demo/data/MoneroSdkClient.kt +++ b/demo/android/src/main/kotlin/im/molly/monero/demo/data/MoneroSdkClient.kt @@ -20,13 +20,23 @@ class MoneroSdkClient( val provider = providerDeferred.await() return withContext(ioDispatcher) { val wallet = provider.createNewWallet(moneroNetwork) - walletDataFileStorage.tryWriteData(wallet.publicAddress, false) { output -> - provider.saveWallet(wallet, output) - } + saveToFile(wallet, provider, false) wallet } } + suspend fun saveWallet(wallet: MoneroWallet) { + withContext(ioDispatcher) { + saveToFile(wallet, providerDeferred.await(), true) + } + } + + private fun saveToFile(wallet: MoneroWallet, provider: WalletProvider, canOverwrite: Boolean) { + walletDataFileStorage.tryWriteData(wallet.publicAddress, canOverwrite) { output -> + provider.saveWallet(wallet, output) + } + } + suspend fun openWallet( publicAddress: String, remoteNodes: Flow>, diff --git a/demo/android/src/main/kotlin/im/molly/monero/demo/data/WalletRepository.kt b/demo/android/src/main/kotlin/im/molly/monero/demo/data/WalletRepository.kt index 521b37b..218db63 100644 --- a/demo/android/src/main/kotlin/im/molly/monero/demo/data/WalletRepository.kt +++ b/demo/android/src/main/kotlin/im/molly/monero/demo/data/WalletRepository.kt @@ -58,7 +58,7 @@ class WalletRepository( moneroNetwork: MoneroNetwork, name: String, remoteNodeIds: List, - ): Pair { + ): Pair { val wallet = moneroSdkClient.createWallet(moneroNetwork) val walletId = walletDataSource.createWalletConfig( publicAddress = wallet.publicAddress, @@ -68,6 +68,9 @@ class WalletRepository( return walletId to wallet } + suspend fun saveWallet(wallet: MoneroWallet) = + moneroSdkClient.saveWallet(wallet) + suspend fun updateWalletConfig(walletConfig: WalletConfig) = walletDataSource.updateWalletConfig(walletConfig) } diff --git a/demo/android/src/main/kotlin/im/molly/monero/demo/service/SyncService.kt b/demo/android/src/main/kotlin/im/molly/monero/demo/service/SyncService.kt index 60c519a..5021ba1 100644 --- a/demo/android/src/main/kotlin/im/molly/monero/demo/service/SyncService.kt +++ b/demo/android/src/main/kotlin/im/molly/monero/demo/service/SyncService.kt @@ -9,16 +9,39 @@ import androidx.lifecycle.LifecycleService import androidx.lifecycle.lifecycleScope import im.molly.monero.demo.AppModule import im.molly.monero.demo.data.WalletRepository -import kotlinx.coroutines.delay -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch +import kotlinx.coroutines.* import kotlin.time.Duration.Companion.seconds const val TAG = "SyncService" class SyncService( private val walletRepository: WalletRepository = AppModule.walletRepository, + private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO, ) : LifecycleService() { + + private suspend fun doSync() = coroutineScope { + val syncedWalletIds = mutableSetOf() + + walletRepository.getWalletIdList().collect { + val idSet = it.toSet() + val toSync = idSet subtract syncedWalletIds + toSync.forEach { walletId -> + val wallet = walletRepository.getWallet(walletId) + launch { + while (isActive) { + val result = wallet.awaitRefresh() + if (result.isError()) { + break + } + walletRepository.saveWallet(wallet) + delay(10.seconds) + } + } + } + syncedWalletIds.addAll(toSync) + } + } + private val binder: IBinder = LocalBinder() inner class LocalBinder : Binder() { @@ -41,25 +64,8 @@ class SyncService( Log.d(TAG, "onCreate") super.onCreate() - lifecycleScope.launch { - val syncedWalletIds = mutableSetOf() - walletRepository.getWalletIdList().collect { - val idSet = it.toSet() - val toSync = idSet subtract syncedWalletIds - toSync.forEach { walletId -> - val wallet = walletRepository.getWallet(walletId) - lifecycleScope.launch { - while (isActive) { - val result = wallet.awaitRefresh() - if (result.isError()) { - break - } - delay(10.seconds) - } - } - } - syncedWalletIds.addAll(toSync) - } + lifecycleScope.launch(ioDispatcher) { + doSync() } } diff --git a/lib/android/src/main/aidl/im/molly/monero/IWallet.aidl b/lib/android/src/main/aidl/im/molly/monero/IWallet.aidl index befc527..aa21cae 100644 --- a/lib/android/src/main/aidl/im/molly/monero/IWallet.aidl +++ b/lib/android/src/main/aidl/im/molly/monero/IWallet.aidl @@ -7,7 +7,7 @@ interface IWallet { String getPrimaryAccountAddress(); void addBalanceListener(in IBalanceListener listener); void removeBalanceListener(in IBalanceListener listener); - void save(in ParcelFileDescriptor destination); + oneway void save(in ParcelFileDescriptor destination); oneway void resumeRefresh(boolean skipCoinbaseOutputs, in IRefreshCallback callback); void cancelRefresh(); void setRefreshSince(long heightOrTimestamp); diff --git a/lib/android/src/main/cpp/wallet.cc b/lib/android/src/main/cpp/wallet.cc index 84732db..ce79222 100644 --- a/lib/android/src/main/cpp/wallet.cc +++ b/lib/android/src/main/cpp/wallet.cc @@ -88,6 +88,7 @@ bool Wallet::parseFrom(std::istream& input) { return false; if (!serialization::serialize(ar, m_wallet)) return false; + m_blockchain_height = m_wallet.get_blockchain_current_height(); m_wallet.get_transfers(m_tx_outs); m_account_ready = true; return true; @@ -130,31 +131,30 @@ void Wallet::handleBalanceChanged(uint64_t at_block_height) { m_wallet.get_transfers(m_tx_outs); m_tx_outs_mutex.unlock(); m_blockchain_height = at_block_height; - JNIEnv* env = getJniEnv(); - m_callback.callVoidMethod(env, WalletNative_onRefresh, at_block_height, true); + callOnRefresh(true); } -void Wallet::handleNewBlock(uint64_t height, bool debounce) { +void Wallet::handleNewBlock(uint64_t height) { m_blockchain_height = height; - bool notify = false; - if (debounce) { - // Notify the blockchain height once every 200 ms if the height is a multiple of 100. - if (height % 100 == 0) { - static std::chrono::steady_clock::time_point last_time; - auto now = std::chrono::steady_clock::now(); - if (now - last_time >= 200.ms) { - last_time = now; - notify = true; - } + // Notify the blockchain height once every 200 ms if the height is a multiple of 100. + bool debounce = true; + if (height % 100 == 0) { + static std::chrono::steady_clock::time_point last_time; + auto now = std::chrono::steady_clock::now(); + if (now - last_time >= 200.ms) { + last_time = now; + debounce = false; } - } else { - notify = true; } - if (notify) { - m_callback.callVoidMethod(getJniEnv(), WalletNative_onRefresh, height, false); + if (!debounce) { + callOnRefresh(false); } } +void Wallet::callOnRefresh(bool balance_changed) { + m_callback.callVoidMethod(getJniEnv(), WalletNative_onRefresh, m_blockchain_height, balance_changed); +} + Wallet::Status Wallet::nonReentrantRefresh(bool skip_coinbase) { LOG_FATAL_IF(m_refresh_running.exchange(true), "Refresh should not be called concurrently"); @@ -187,7 +187,7 @@ Wallet::Status Wallet::nonReentrantRefresh(bool skip_coinbase) { } m_refresh_running.store(false); // Always notify the last block height. - handleNewBlock(m_blockchain_height, false); + callOnRefresh(false); return ret; } diff --git a/lib/android/src/main/cpp/wallet.h b/lib/android/src/main/cpp/wallet.h index 6ff91f0..b3eee7e 100644 --- a/lib/android/src/main/cpp/wallet.h +++ b/lib/android/src/main/cpp/wallet.h @@ -75,7 +75,9 @@ class Wallet : tools::i_wallet2_callback { auto suspendRefreshAndRunLocked(T block) -> decltype(block()); void handleBalanceChanged(uint64_t at_block_height); - void handleNewBlock(uint64_t height, bool debounce = true); + void handleNewBlock(uint64_t height); + + void callOnRefresh(bool balance_changed); // Implementation of i_wallet2_callback follows. private: diff --git a/vendor/monero b/vendor/monero index 1bfa33a..4ba282d 160000 --- a/vendor/monero +++ b/vendor/monero @@ -1 +1 @@ -Subproject commit 1bfa33ad2b4b2b4bd752a6dda74102defabba063 +Subproject commit 4ba282d12182bc3c907e3e77ef1091e2e806f086