From 1e56d2eef4581497777389a3ded8984086af5fd9 Mon Sep 17 00:00:00 2001 From: Honza Date: Tue, 5 Sep 2023 14:24:11 +0200 Subject: [PATCH] [#1109] Regular balance flows emission --- .../cash/z/ecc/android/sdk/SdkSynchronizer.kt | 42 +++++++------- .../block/processor/CompactBlockProcessor.kt | 58 +++++++++++++++---- 2 files changed, 70 insertions(+), 30 deletions(-) diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt index 7c593504f..77f1f5947 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt @@ -176,18 +176,14 @@ class SdkSynchronizer private constructor( } } - // pools - private val _orchardBalances = MutableStateFlow(null) - private val _saplingBalances = MutableStateFlow(null) - private val _transparentBalances = MutableStateFlow(null) - private val _status = MutableStateFlow(DISCONNECTED) var coroutineScope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) - override val orchardBalances = _orchardBalances.asStateFlow() - override val saplingBalances = _saplingBalances.asStateFlow() - override val transparentBalances = _transparentBalances.asStateFlow() + override val orchardBalances = processor.orchardBalances.asStateFlow() + override val saplingBalances = processor.saplingBalances.asStateFlow() + override val transparentBalances = processor.transparentBalances.asStateFlow() + override val transactions get() = combine(processor.networkHeight, storage.allTransactions) { networkHeight, allTransactions -> val latestBlockHeight = networkHeight ?: storage.lastScannedHeight() @@ -362,36 +358,42 @@ class SdkSynchronizer private constructor( storage.invalidate() } - // - // Private API - // - /** - * Calculate the latest balance, based on the blocks that have been scanned and transmit this - * information into the flow of [balances]. + * Calculate the latest balance based on the blocks that have been scanned and transmit this information into the + * [transparentBalances] and [saplingBalances] flow. The [orchardBalances] flow is still not filled with proper data + * because of the current limited Orchard support. */ suspend fun refreshAllBalances() { - refreshSaplingBalance() - refreshTransparentBalance() + processor.checkAllBalances() // TODO [#682]: refresh orchard balance // TODO [#682]: https://github.com/zcash/zcash-android-wallet-sdk/issues/682 Twig.warn { "Warning: Orchard balance does not yet refresh. Only some of the plumbing is in place." } } + /** + * Calculate the latest Sapling balance based on the blocks that have been scanned and transmit this information + * into the [saplingBalances] flow. + */ suspend fun refreshSaplingBalance() { - Twig.debug { "refreshing sapling balance" } - _saplingBalances.value = processor.getBalanceInfo(Account.DEFAULT) + processor.checkSaplingBalance() } + /** + * Calculate the latest Transparent balance based on the blocks that have been scanned and transmit this information + * into the [saplingBalances] flow. + */ suspend fun refreshTransparentBalance() { - Twig.debug { "refreshing transparent balance" } - _transparentBalances.value = processor.getUtxoCacheBalance(getTransparentAddress(Account.DEFAULT)) + processor.checkTransparentBalance() } suspend fun isValidAddress(address: String): Boolean { return !validateAddress(address).isNotValid } + // + // Private API + // + private fun CoroutineScope.onReady() { Twig.debug { "Starting synchronizer…" } diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/CompactBlockProcessor.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/CompactBlockProcessor.kt index 449600320..02fef6118 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/CompactBlockProcessor.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/CompactBlockProcessor.kt @@ -149,6 +149,12 @@ class CompactBlockProcessor internal constructor( private val _progress = MutableStateFlow(PercentDecimal.ZERO_PERCENT) private val _processorInfo = MutableStateFlow(ProcessorInfo(null, null, null)) private val _networkHeight = MutableStateFlow(null) + + // pools + internal val saplingBalances = MutableStateFlow(null) + internal val orchardBalances = MutableStateFlow(null) + internal val transparentBalances = MutableStateFlow(null) + private val processingMutex = Mutex() /** @@ -470,6 +476,7 @@ class CompactBlockProcessor internal constructor( lastBatchOrder = min(rangeSyncProgress.overallOrder, allBatchCountLocal) setProgress(PercentDecimal(lastBatchOrder / allBatchCountLocal.toFloat())) + checkAllBalances() when (rangeSyncProgress.resultState) { SyncingResult.UpdateBirthday -> { @@ -478,7 +485,7 @@ class CompactBlockProcessor internal constructor( SyncingResult.EnhanceSuccess -> { Twig.info { "Triggering transaction refresh now" } // Invalidate transaction data - refreshTransactions(transactionStorage = repository) + checkTransactions(transactionStorage = repository) } is SyncingResult.Failure -> { syncingResult = rangeSyncProgress.resultState @@ -552,6 +559,7 @@ class CompactBlockProcessor internal constructor( lastBatchOrder = min(rangeSyncProgress.overallOrder, allBatchCountLocal) setProgress(PercentDecimal(lastBatchOrder / allBatchCountLocal.toFloat())) + checkAllBalances() when (rangeSyncProgress.resultState) { SyncingResult.UpdateBirthday -> { @@ -561,7 +569,7 @@ class CompactBlockProcessor internal constructor( SyncingResult.EnhanceSuccess -> { Twig.info { "Triggering transaction refresh now" } // Invalidate transaction data and return the common batch syncing success result to the caller - refreshTransactions(transactionStorage = repository) + checkTransactions(transactionStorage = repository) SyncingResult.AllSuccess } is SyncingResult.Failure -> { @@ -609,13 +617,6 @@ class CompactBlockProcessor internal constructor( return BlockProcessingResult.Success } - /** - * This invalidates transaction storage to trigger data refreshing for its subscribers. - */ - private fun refreshTransactions(transactionStorage: DerivedDataRepository) { - transactionStorage.invalidate() - } - @Suppress("ReturnCount") internal suspend fun runSbSSyncingPreparation( backend: TypesafeBackend, @@ -714,6 +715,7 @@ class CompactBlockProcessor internal constructor( lastBatchOrder = 0 ).collect { rangeSyncProgress -> setProgress(PercentDecimal(rangeSyncProgress.overallOrder / allBatchCount.toFloat())) + checkAllBalances() when (rangeSyncProgress.resultState) { SyncingResult.UpdateBirthday -> { @@ -722,7 +724,7 @@ class CompactBlockProcessor internal constructor( SyncingResult.EnhanceSuccess -> { Twig.info { "Triggering transaction refresh now" } // Invalidate transaction data - refreshTransactions(transactionStorage = repository) + checkTransactions(transactionStorage = repository) } is SyncingResult.Failure -> { syncingResult = rangeSyncProgress.resultState @@ -747,6 +749,42 @@ class CompactBlockProcessor internal constructor( return BlockProcessingResult.Success } + /** + * This invalidates transaction storage to trigger data refreshing for its subscribers. + */ + private fun checkTransactions(transactionStorage: DerivedDataRepository) { + transactionStorage.invalidate() + } + + /** + * Calculate the latest balances, based on the blocks that have been scanned and transmit this + * information into the related internal flows. Note that the Orchard balance is not supported. + */ + internal suspend fun checkAllBalances() { + checkSaplingBalance() + checkTransparentBalance() + // TODO [#682]: refresh orchard balance + // TODO [#682]: https://github.com/zcash/zcash-android-wallet-sdk/issues/682 + } + + /** + * Calculate the latest Sapling balance, based on the blocks that have been scanned and transmit this + * information into the internal [saplingBalances] flow. + */ + internal suspend fun checkSaplingBalance() { + Twig.debug { "Checking Sapling balance" } + saplingBalances.value = getBalanceInfo(Account.DEFAULT) + } + + /** + * Calculate the latest Transparent balance, based on the blocks that have been scanned and transmit this + * information into the internal [transparentBalances] flow. + */ + internal suspend fun checkTransparentBalance() { + Twig.debug { "Checking Transparent balance" } + transparentBalances.value = getUtxoCacheBalance(getTransparentAddress(backend, Account.DEFAULT)) + } + sealed class BlockProcessingResult { object NoBlocksToProcess : BlockProcessingResult() object Success : BlockProcessingResult()