zcash-android-wallet-sdk/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt

713 lines
28 KiB
Kotlin
Raw Normal View History

package cash.z.ecc.android.sdk
import android.content.Context
import cash.z.ecc.android.sdk.Synchronizer.Status.DISCONNECTED
import cash.z.ecc.android.sdk.Synchronizer.Status.ENHANCING
import cash.z.ecc.android.sdk.Synchronizer.Status.STOPPED
import cash.z.ecc.android.sdk.Synchronizer.Status.SYNCED
import cash.z.ecc.android.sdk.Synchronizer.Status.SYNCING
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Disconnected
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Enhancing
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Initialized
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Stopped
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Synced
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Syncing
import cash.z.ecc.android.sdk.exception.TransactionEncoderException
import cash.z.ecc.android.sdk.exception.TransactionSubmitException
import cash.z.ecc.android.sdk.ext.ConsensusBranchId
import cash.z.ecc.android.sdk.ext.ZcashSdk
import cash.z.ecc.android.sdk.internal.Backend
import cash.z.ecc.android.sdk.internal.SaplingParamTool
2023-02-06 14:36:28 -08:00
import cash.z.ecc.android.sdk.internal.Twig
2021-11-18 04:10:30 -08:00
import cash.z.ecc.android.sdk.internal.block.CompactBlockDownloader
import cash.z.ecc.android.sdk.internal.db.DatabaseCoordinator
import cash.z.ecc.android.sdk.internal.db.derived.DbDerivedDataRepository
import cash.z.ecc.android.sdk.internal.db.derived.DerivedDataDb
import cash.z.ecc.android.sdk.internal.ext.isNullOrEmpty
import cash.z.ecc.android.sdk.internal.ext.toHexReversed
import cash.z.ecc.android.sdk.internal.ext.tryNull
import cash.z.ecc.android.sdk.internal.jni.RustBackend
import cash.z.ecc.android.sdk.internal.model.Checkpoint
import cash.z.ecc.android.sdk.internal.repository.CompactBlockRepository
import cash.z.ecc.android.sdk.internal.repository.DerivedDataRepository
[#765] Store blocks on disk instead of in SQLite * Switch to FsBlockDb for caching CompactBlocks * Add RustBackend.getLatestHeight() method * Raise MSRV to 1.60 * Migrate to latest Rust crate API * Add RustBackend.findBlockMetadata() method * Add RustBackend.rewindBlockMetadataToHeight() method * [#765] implementation of FileCompactBlockRepository * writing block metadata to database * split write function into smaller easier to test blocks * testing for FileCompactBlockRepository * fixed rewinding * fixed tests * fixed FileCompactBlockRepositoryTest and SynchronizerFactoryTest * code review fixes * updated proto files * override all functions in FakeRustBackend * code review fixes * Fix function body formatting * Improve clear function clarity * Use length of string const * Delete single file instead of directory * Improve function clarity * Refactor outputs counting - Found a typo in intermediary model class JniBlockMeta parameter change of which does not impact encoding from rust to kotlin according to rust layer implementation. * Check blocks mkdir result * Remove unnecessary detekt warning suppression * Refactor buffer size check * Improve visibility annotations * Make file finalise obvious and self documenting * Remove prevHash logging * Move instantiation to the object itself * Enrich fixture with default values * Extend eror message * Rename benchmark blocks range fixture * Fix rebase changes * Improve FileCompactBlockRepositoryTest - "De-integrated" the test suite - it now works with fixture blocks - Created needed fixtures for a clear mocked blocks providing - Enhanced getting of FileCompactBlockRepository in FileCompactBlockRepositoryTest to clarify that it works with mock components * Fix ktlintFormat findings * Bump actions/cache from 3.2.4 to 3.2.5 in /.github/actions/setup (#927) Bumps [actions/cache](https://github.com/actions/cache) from 3.2.4 to 3.2.5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/627f0f41f6904a5b1efbaed9f96d9eb58e92e920...6998d139ddd3e68c71e9e398d8e40b71a2f39812) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Fix incorrect dir checking * More robust min/max checking * Rewinding to more robust middle value * Strengthen blocks counts after rewind * Add check of temp finalized file * Refactor DatabaseCoordinatorTest * Rename cache files root directory - To have the same unified variable name across our repositories - fsBlockDbRoot * Refactor FileCompactBlockRepositoryTest - To have these tests more clear - Fixed FakeRustBackend instantiation bug * Revert back JniBlockMeta param name * Delete legacy Cache db files - Deleted from both the older and the newer legacy locations - All related db files deleted - rollback files included - The deletion is run once we try to access the new store blocks on disk root directory - The deletion check does not throw any exception in case of failure, we just log it in console and try it on the next time - Related new test added too * Test refactoring - Made few changes to improve clarity of provided tests and fixtures - Prepared few new "failure path" tests - Enhanced existing tests * Manual test case * Simplify error printing - As we had some commented out code there * Reset manual tests steps numbering * [#924] Remove alias from WalletCoordinator Also make Compose UI the default. The old UI is deprecated but is still used by the benchmarking tests * Bump benchmark version * Protect JniBlockMetadata agains minification * Enable debuggable while benchmarking * Enhance benchmark screen waiting * Fix cache db files deletion - With this construct we delete all blocks blob metadata files, as well as their sqlite file * Add new benchmark results * Remove benchmark operations receiver fix - As it's not needed after the latest profiler dependency update * Bump gradle/wrapper-validation-action from 1.0.5 to 1.0.6 (#928) Bumps [gradle/wrapper-validation-action](https://github.com/gradle/wrapper-validation-action) from 1.0.5 to 1.0.6. - [Release notes](https://github.com/gradle/wrapper-validation-action/releases) - [Commits](https://github.com/gradle/wrapper-validation-action/compare/55e685c48d84285a5b0418cd094606e199cca3b6...8d49e559aae34d3e0eb16cde532684bc9702762b) --- updated-dependencies: - dependency-name: gradle/wrapper-validation-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump actions/cache from 3.2.5 to 3.2.6 in /.github/actions/setup (#929) Bumps [actions/cache](https://github.com/actions/cache) from 3.2.5 to 3.2.6. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/6998d139ddd3e68c71e9e398d8e40b71a2f39812...69d9d449aced6a2ede0bc19182fadc3a0a42d2b0) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update DatabaseCoordinator.kt Move if/else out from log message body * Update Switch cache to store blocks on disk.md Reset documentation bullets numbering * Hide internal constants from public package * Update manual test user with new UI requirement * Comment out cargo.toml test values * Inline fixture blocks metadata with its creation * Switch to FsBlockDb for caching CompactBlocks * Add RustBackend.getLatestHeight() method * Raise MSRV to 1.60 * Migrate to latest Rust crate API * Add RustBackend.findBlockMetadata() method * Add RustBackend.rewindBlockMetadataToHeight() method * Update cargo.lock * Switch to FsBlockDb for caching CompactBlocks * Migrate to latest Rust crate API * [#765] implementation of FileCompactBlockRepository * writing block metadata to database * split write function into smaller easier to test blocks * testing for FileCompactBlockRepository * fixed rewinding * fixed tests * fixed FileCompactBlockRepositoryTest and SynchronizerFactoryTest * code review fixes * updated proto files * override all functions in FakeRustBackend * code review fixes * Fix function body formatting * Improve clear function clarity * Use length of string const * Delete single file instead of directory * Improve function clarity * Refactor outputs counting - Found a typo in intermediary model class JniBlockMeta parameter change of which does not impact encoding from rust to kotlin according to rust layer implementation. * Check blocks mkdir result * Remove unnecessary detekt warning suppression * Refactor buffer size check * Improve visibility annotations * Make file finalise obvious and self documenting * Remove prevHash logging * Move instantiation to the object itself * Enrich fixture with default values * Extend eror message * Rename benchmark blocks range fixture * Fix rebase changes * Improve FileCompactBlockRepositoryTest - "De-integrated" the test suite - it now works with fixture blocks - Created needed fixtures for a clear mocked blocks providing - Enhanced getting of FileCompactBlockRepository in FileCompactBlockRepositoryTest to clarify that it works with mock components * Fix ktlintFormat findings * Fix incorrect dir checking * More robust min/max checking * Rewinding to more robust middle value * Strengthen blocks counts after rewind * Add check of temp finalized file * Refactor DatabaseCoordinatorTest * Rename cache files root directory - To have the same unified variable name across our repositories - fsBlockDbRoot * Refactor FileCompactBlockRepositoryTest - To have these tests more clear - Fixed FakeRustBackend instantiation bug * Revert back JniBlockMeta param name * Delete legacy Cache db files - Deleted from both the older and the newer legacy locations - All related db files deleted - rollback files included - The deletion is run once we try to access the new store blocks on disk root directory - The deletion check does not throw any exception in case of failure, we just log it in console and try it on the next time - Related new test added too * Test refactoring - Made few changes to improve clarity of provided tests and fixtures - Prepared few new "failure path" tests - Enhanced existing tests * Manual test case * Simplify error printing - As we had some commented out code there * Reset manual tests steps numbering * Bump benchmark version * Protect JniBlockMetadata agains minification * Enable debuggable while benchmarking * Enhance benchmark screen waiting * Fix cache db files deletion - With this construct we delete all blocks blob metadata files, as well as their sqlite file * Add new benchmark results * Remove benchmark operations receiver fix - As it's not needed after the latest profiler dependency update * Update DatabaseCoordinator.kt Move if/else out from log message body * Update Switch cache to store blocks on disk.md Reset documentation bullets numbering * Hide internal constants from public package * Update manual test user with new UI requirement * Comment out cargo.toml test values * Inline fixture blocks metadata with its creation * Update cargo.lock * Update Cargo.lock * Check and document JniBlockMeta params ranges * Add assert for gradle property * Use UInt internally uint * Change array API to list * Fix for using correct SDK Synchronizer alias - Only the older Demo-app UI was impacted. - Thus also our benchmarking was impacted. * Apply documentation suggestions from code review Co-authored-by: Kris Nuttycombe <kris@electriccoin.co> * Final manual test instructions update * Fixture block hash deterministically generated from block height --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Jack Grigg <jack@electriccoin.co> Co-authored-by: Jack Grigg <jack@z.cash> Co-authored-by: Honza <rychnovsky.honza@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Carter Jernigan <git@carterjernigan.com> Co-authored-by: Kris Nuttycombe <kris@electriccoin.co>
2023-03-08 07:04:04 -08:00
import cash.z.ecc.android.sdk.internal.storage.block.FileCompactBlockRepository
import cash.z.ecc.android.sdk.internal.transaction.OutboundTransactionManager
import cash.z.ecc.android.sdk.internal.transaction.OutboundTransactionManagerImpl
import cash.z.ecc.android.sdk.internal.transaction.TransactionEncoder
import cash.z.ecc.android.sdk.internal.transaction.TransactionEncoderImpl
2022-10-06 10:44:34 -07:00
import cash.z.ecc.android.sdk.model.Account
import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.PercentDecimal
2022-10-24 06:09:29 -07:00
import cash.z.ecc.android.sdk.model.TransactionOverview
import cash.z.ecc.android.sdk.model.TransactionRecipient
import cash.z.ecc.android.sdk.model.UnifiedFullViewingKey
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
2022-07-07 05:52:07 -07:00
import cash.z.ecc.android.sdk.model.WalletBalance
import cash.z.ecc.android.sdk.model.Zatoshi
import cash.z.ecc.android.sdk.model.ZcashNetwork
import cash.z.ecc.android.sdk.type.AddressType
import cash.z.ecc.android.sdk.type.AddressType.Shielded
import cash.z.ecc.android.sdk.type.AddressType.Transparent
import cash.z.ecc.android.sdk.type.AddressType.Unified
import cash.z.ecc.android.sdk.type.ConsensusMatchType
import co.electriccoin.lightwallet.client.LightWalletClient
[#615] Refactor lightwalletd client * [#615] Refactor lightwalletd client This moves the lightwalletd client code to a separate Gradle module, but does not yet do much clean up the public API (e.g. hiding generated GRPC objects). That will be a followon change via #673 I’ve prototyped a safer version of the API that would be implemented for #673 for two specific calls: obtaining the current block height and obtaining the light wallet info. These were the easiest endpoints to update and they provide a useful exploration for the future changes needed. * Fix benchmarking for networking module - Moved to fixture and build type check components to the new networking module, so it's accessible from all needed parts of the projects - Changed fixture return type to fit to all needed usages * Align with previous review comment * Fix wrong merge * Add basic sanity test - To satisfy tests requirements on emulators.wtf service * Remove grpc dependency from sdk-lib module * Repackage cash.z.wallet.sdk.rpc to cash.z.wallet.sdk.internal.rpc * Fix BuildConfig path * Update demo-app paths to rpc * Fix broken grpc services locations - Our aim here is to change only the local services location (package name), the server location can't be changed due to backward compatibility. * Enhance GRPC Response model * Adopt enhanced GRPC response model - Adopted in a few endpoints * Enhance Connection failure type * Add simple fixture test * Refactor fetchTransaction() to work with Response - Refactored this server call to adopt our new Response mechanism - GrpsStatusResolver.resolveFailureFromStatus() now accepts Throwable input - Added Response.Failure.toThrowable() to satisfy subsequent server calls results processing - A few other minor refactoring changes * Remove commented out log * Unify return type of collection returning methods - Switched fetchUtxos() to return Sequence instead of List - Added a check on empty tAddress input * fetchUtxos returns flow - Switched fetchUtxos() to return Flow of Service.GetAddressUtxosReply - Internally it calls getAddressUtxosStream() instead of getAddressUtxos() from GRPC layer * Update unsafe suffix documentation * Address several minor change requests * Remove code parameter - Removed from the locally triggered failures with default codes. * Rename local variable * Switch from empty response to exception - Our server calls now rather throw IllegalArgumentException than return an empty response - Removed commented out log message - Updated javadocs * Update proto files - Plus related api changes adoption * Unify new clients instances name * AGP 7.4.0 changes - packagingOptions -> androidComponents in sdk-lib and lightwallet-client-lib modules * SDK version bump * Response resolver tests * Release build upload timeout increase * Release build upload timeout increase fix * Revert timeout - As Github has some infrastructure troubles and we need to wait * Add migrations documentation * Sort packaging filters * Remove private field from public documentation * Hide private variables * Remove package from Android Manifest * Throw exception instead of custom error - This step unify our approach to validation on client side across all server calls * Replace setAddresses index const with number * Fix indentation in proto file --------- Co-authored-by: Honza <rychnovsky.honza@gmail.com>
2023-02-01 02:14:55 -08:00
import co.electriccoin.lightwallet.client.model.LightWalletEndpoint
import co.electriccoin.lightwallet.client.new
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
2022-10-24 06:09:29 -07:00
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
2022-10-24 06:09:29 -07:00
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import java.io.File
import java.util.concurrent.ConcurrentHashMap
import kotlin.coroutines.CoroutineContext
/**
2019-11-01 13:25:28 -07:00
* A Synchronizer that attempts to remain operational, despite any number of errors that can occur.
* It acts as the glue that ties all the pieces of the SDK together. Each component of the SDK is
* designed for the potential of stand-alone usage but coordinating all the interactions is non-
* trivial. So the Synchronizer facilitates this, acting as reference that demonstrates how all the
* pieces can be tied together. Its goal is to allow a developer to focus on their app rather than
* the nuances of how Zcash works.
*
* @property synchronizerKey Identifies the synchronizer's on-disk state
* @property storage exposes flows of wallet transaction information.
* @property txManager manages and tracks outbound transactions.
2020-02-27 00:25:07 -08:00
* @property processor saves the downloaded compact blocks to the cache and then scans those blocks for
* data related to this wallet.
*/
[#366] Fix Detekt warnings * Disable baseline file. Too many functions. * CurrencyFormatter.kt suppress too many functions * PersistentTransactionManager.kt suppress too many functions * OutboundTransactionManager suppress too many functions * Suppress long parameter list * Too many functions * Add log to avoid empty block warning * Fix several magic number warnings * Solve max line length warnings * Solve max line length warnings * Suppress too long method warnings * Suppress too complex method warnings * Suppress large class warning * Fixed empty catch block * Changed directory path to the file * Fix too generic and swallowed exception * Fix print stack trace warning * Suppressed single top level file name declaration * Change parameters name * Suppress Spread operator warning * Remove unused private code * Add Locale to suppress default locale used warning * Solve several forbidden TODOs warnings * Fixed another max line length warning * Simplify return statement * Suppress class to object change * Make DemoConstants variables const * Use error() instead of throwing an IllegalStateException * Solve too complex condition * Suppress intentionally generic and swallowed exception * Suppress TooGenericExceptionCaught * Solve or suppress several TooGenericExceptionCaught * Fix swallowed exception * Suppress warning TooGenericExceptionCaught of PersistentTransactionManager * Suppress warning TooGenericExceptionCaught of WalletTransactionEncoder * Suppress TooGenericExceptionCaught of SdkSynchronizer * Suppress TooGenericExceptionCaught in SaplingParamTool * Suppress TooGenericExceptionCaught in CompactBlockDownloader * Suppress TooGenericExceptionCaught in CheckpointTool * Fix TooGenericExceptionCaught in WalletService * Suppress TooGenericExceptionCaught in DerivedDataDb * Suppress TooGenericExceptionCaught in CompactBlockProcessor * Apply ktlint format after all the previous changes * Remove detekt baseline file * Set Android studio right margin * Address comments from review * Suppress failing tests on CI
2022-08-23 06:49:00 -07:00
@Suppress("TooManyFunctions")
class SdkSynchronizer private constructor(
private val synchronizerKey: SynchronizerKey,
private val storage: DerivedDataRepository,
private val txManager: OutboundTransactionManager,
2022-10-24 06:09:29 -07:00
val processor: CompactBlockProcessor,
private val backend: Backend
) : CloseableSynchronizer {
companion object {
private sealed class InstanceState {
object Active : InstanceState()
data class ShuttingDown(val job: Job) : InstanceState()
}
private val instances: MutableMap<SynchronizerKey, InstanceState> =
ConcurrentHashMap<SynchronizerKey, InstanceState>()
/**
* @throws IllegalStateException If multiple instances of synchronizer with the same network+alias are
* active at the same time. Call `close` to finish one synchronizer before starting another one with the same
* network+alias.
*/
@Suppress("LongParameterList")
internal suspend fun new(
zcashNetwork: ZcashNetwork,
alias: String,
repository: DerivedDataRepository,
txManager: OutboundTransactionManager,
processor: CompactBlockProcessor,
backend: Backend
): CloseableSynchronizer {
val synchronizerKey = SynchronizerKey(zcashNetwork, alias)
waitForShutdown(synchronizerKey)
checkForExistingSynchronizers(synchronizerKey)
return SdkSynchronizer(
synchronizerKey,
repository,
txManager,
processor,
backend
).apply {
instances[synchronizerKey] = InstanceState.Active
start()
}
}
private suspend fun waitForShutdown(synchronizerKey: SynchronizerKey) {
instances[synchronizerKey]?.let {
if (it is InstanceState.ShuttingDown) {
2023-02-06 14:36:28 -08:00
Twig.debug { "Waiting for prior synchronizer instance to shut down" } // $NON-NLS-1$
it.job.join()
}
}
}
private fun checkForExistingSynchronizers(synchronizerKey: SynchronizerKey) {
check(!instances.containsKey(synchronizerKey)) {
"Another synchronizer with $synchronizerKey is currently active" // $NON-NLS-1$
}
}
internal suspend fun erase(
appContext: Context,
network: ZcashNetwork,
alias: String
): Boolean {
val key = SynchronizerKey(network, alias)
waitForShutdown(key)
checkForExistingSynchronizers(key)
return DatabaseCoordinator.getInstance(appContext).deleteDatabases(network, alias)
}
}
// pools
private val _orchardBalances = MutableStateFlow<WalletBalance?>(null)
private val _saplingBalances = MutableStateFlow<WalletBalance?>(null)
private val _transparentBalances = MutableStateFlow<WalletBalance?>(null)
private val _status = MutableStateFlow<Synchronizer.Status>(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 transactions
get() = combine(processor.networkHeight, storage.allTransactions) { networkHeight, allTransactions ->
val latestBlockHeight = networkHeight ?: storage.lastScannedHeight()
allTransactions.map { TransactionOverview.new(it, latestBlockHeight) }
}
override val network: ZcashNetwork get() = processor.network
/**
* Indicates the status of this Synchronizer. This implementation basically simplifies the
* status of the processor to focus only on the high level states that matter most. Whenever the
* processor is finished scanning, the synchronizer updates transaction and balance info and
* then emits a [SYNCED] status.
*/
override val status = _status.asStateFlow()
2019-07-12 01:47:17 -07:00
/**
* Indicates the download progress of the Synchronizer. When progress reaches `PercentDecimal.ONE_HUNDRED_PERCENT`,
* that signals that the Synchronizer is in sync with the network. Balances should be considered
* inaccurate and outbound transactions should be prevented until this sync is complete. It is
* a simplified version of [processorInfo].
*/
override val progress: Flow<PercentDecimal> = processor.progress
/**
* Indicates the latest information about the blocks that have been processed by the SDK. This
* is very helpful for conveying detailed progress and status to the user.
*/
override val processorInfo: Flow<CompactBlockProcessor.ProcessorInfo> = processor.processorInfo
2019-07-12 01:47:17 -07:00
/**
* The latest height seen on the network while processing blocks. This may differ from the
* latest height scanned and is useful for determining block confirmations and expiration.
*/
override val networkHeight: StateFlow<BlockHeight?> = processor.networkHeight
2019-07-12 01:47:17 -07:00
//
2019-07-14 15:13:12 -07:00
// Error Handling
2019-07-12 01:47:17 -07:00
//
/**
2019-11-01 13:25:28 -07:00
* A callback to invoke whenever an uncaught error is encountered. By definition, the return
* value of the function is ignored because this error is unrecoverable. The only reason the
* function has a return value is so that all error handlers work with the same signature which
* allows one function to handle all errors in simple apps. This callback is not called on the
* main thread so any UI work would need to switch context to the main thread.
2019-07-14 15:13:12 -07:00
*/
override var onCriticalErrorHandler: ((Throwable?) -> Boolean)? = null
/**
2019-11-01 13:25:28 -07:00
* A callback to invoke whenever a processor error is encountered. Returning true signals that
* the error was handled and a retry attempt should be made, if possible. This callback is not
* called on the main thread so any UI work would need to switch context to the main thread.
*/
2019-07-14 15:13:12 -07:00
override var onProcessorErrorHandler: ((Throwable?) -> Boolean)? = null
/**
2019-11-01 13:25:28 -07:00
* A callback to invoke whenever a server error is encountered while submitting a transaction to
* lightwalletd. Returning true signals that the error was handled and a retry attempt should be
* made, if possible. This callback is not called on the main thread so any UI work would need
* to switch context to the main thread.
*/
2019-07-14 15:13:12 -07:00
override var onSubmissionErrorHandler: ((Throwable?) -> Boolean)? = null
2019-07-12 01:47:17 -07:00
/**
* A callback to invoke whenever a processor is not setup correctly. Returning true signals that
* the invalid setup should be ignored. If no handler is set, then any setup error will result
* in a critical error. This callback is not called on the main thread so any UI work would need
* to switch context to the main thread.
*/
override var onSetupErrorHandler: ((Throwable?) -> Boolean)? = null
/**
* A callback to invoke whenever a chain error is encountered. These occur whenever the
* processor detects a missing or non-chain-sequential block (i.e. a reorg).
*/
override var onChainErrorHandler: ((errorHeight: BlockHeight, rewindHeight: BlockHeight) -> Any)? = null
2019-11-01 13:25:28 -07:00
//
// Public API
//
/**
* Convenience function for the latest height. Specifically, this value represents the last
* height that the synchronizer has observed from the lightwalletd server. Instead of using
* this, a wallet will more likely want to consume the flow of processor info using
* [processorInfo].
*/
override val latestHeight
get() = processor.processorInfo.value.networkBlockHeight
override val latestBirthdayHeight
get() = processor.birthdayHeight
internal fun start() {
coroutineScope.onReady()
}
override fun close() {
// Note that stopping will continue asynchronously. Race conditions with starting a new synchronizer are
// avoided with a delay during startup.
2019-07-12 01:47:17 -07:00
val shutdownJob = coroutineScope.launch {
2023-02-06 14:36:28 -08:00
Twig.debug { "Stopping synchronizer $synchronizerKey" }
processor.stop()
storage.close()
}
instances[synchronizerKey] = InstanceState.ShuttingDown(shutdownJob)
shutdownJob.invokeOnCompletion {
coroutineScope.cancel()
_status.value = STOPPED
2023-02-06 14:36:28 -08:00
Twig.debug { "Synchronizer $synchronizerKey stopped" }
instances.remove(synchronizerKey)
}
}
override suspend fun getNearestRewindHeight(height: BlockHeight): BlockHeight =
processor.getNearestRewindHeight(height)
override suspend fun rewindToNearestHeight(height: BlockHeight, alsoClearBlockCache: Boolean) {
processor.rewindToNearestHeight(height, alsoClearBlockCache)
}
override suspend fun quickRewind() {
processor.quickRewind()
}
2022-10-24 06:09:29 -07:00
override fun getMemos(transactionOverview: TransactionOverview): Flow<String> {
return storage.getNoteIds(transactionOverview.id).map {
when (transactionOverview.isSentTransaction) {
true -> {
backend.getSentMemoAsUtf8(it)
}
false -> {
backend.getReceivedMemoAsUtf8(it)
}
2022-10-24 06:09:29 -07:00
}
}.filterNotNull()
2022-10-24 06:09:29 -07:00
}
2022-10-31 12:27:34 -07:00
override fun getRecipients(transactionOverview: TransactionOverview): Flow<TransactionRecipient> {
require(transactionOverview.isSentTransaction) { "Recipients can only be queried for sent transactions" }
return storage.getRecipients(transactionOverview.id)
}
//
// Storage APIs
//
[#366] Fix Detekt warnings * Disable baseline file. Too many functions. * CurrencyFormatter.kt suppress too many functions * PersistentTransactionManager.kt suppress too many functions * OutboundTransactionManager suppress too many functions * Suppress long parameter list * Too many functions * Add log to avoid empty block warning * Fix several magic number warnings * Solve max line length warnings * Solve max line length warnings * Suppress too long method warnings * Suppress too complex method warnings * Suppress large class warning * Fixed empty catch block * Changed directory path to the file * Fix too generic and swallowed exception * Fix print stack trace warning * Suppressed single top level file name declaration * Change parameters name * Suppress Spread operator warning * Remove unused private code * Add Locale to suppress default locale used warning * Solve several forbidden TODOs warnings * Fixed another max line length warning * Simplify return statement * Suppress class to object change * Make DemoConstants variables const * Use error() instead of throwing an IllegalStateException * Solve too complex condition * Suppress intentionally generic and swallowed exception * Suppress TooGenericExceptionCaught * Solve or suppress several TooGenericExceptionCaught * Fix swallowed exception * Suppress warning TooGenericExceptionCaught of PersistentTransactionManager * Suppress warning TooGenericExceptionCaught of WalletTransactionEncoder * Suppress TooGenericExceptionCaught of SdkSynchronizer * Suppress TooGenericExceptionCaught in SaplingParamTool * Suppress TooGenericExceptionCaught in CompactBlockDownloader * Suppress TooGenericExceptionCaught in CheckpointTool * Fix TooGenericExceptionCaught in WalletService * Suppress TooGenericExceptionCaught in DerivedDataDb * Suppress TooGenericExceptionCaught in CompactBlockProcessor * Apply ktlint format after all the previous changes * Remove detekt baseline file * Set Android studio right margin * Address comments from review * Suppress failing tests on CI
2022-08-23 06:49:00 -07:00
// TODO [#682]: turn this section into the data access API. For now, just aggregate all the things that we want
// to do with the underlying data
// TODO [#682]: https://github.com/zcash/zcash-android-wallet-sdk/issues/682
suspend fun findBlockHash(height: BlockHeight): ByteArray? {
return storage.findBlockHash(height)
}
suspend fun findBlockHashAsHex(height: BlockHeight): String? {
return findBlockHash(height)?.toHexReversed()
}
suspend fun getTransactionCount(): Int {
return storage.getTransactionCount().toInt()
}
2020-08-13 17:37:09 -07:00
fun refreshTransactions() {
storage.invalidate()
}
//
2019-11-01 13:25:28 -07:00
// Private API
//
2020-02-27 00:25:07 -08:00
/**
* Calculate the latest balance, based on the blocks that have been scanned and transmit this
* information into the flow of [balances].
*/
suspend fun refreshAllBalances() {
refreshSaplingBalance()
refreshTransparentBalance()
[#366] Fix Detekt warnings * Disable baseline file. Too many functions. * CurrencyFormatter.kt suppress too many functions * PersistentTransactionManager.kt suppress too many functions * OutboundTransactionManager suppress too many functions * Suppress long parameter list * Too many functions * Add log to avoid empty block warning * Fix several magic number warnings * Solve max line length warnings * Solve max line length warnings * Suppress too long method warnings * Suppress too complex method warnings * Suppress large class warning * Fixed empty catch block * Changed directory path to the file * Fix too generic and swallowed exception * Fix print stack trace warning * Suppressed single top level file name declaration * Change parameters name * Suppress Spread operator warning * Remove unused private code * Add Locale to suppress default locale used warning * Solve several forbidden TODOs warnings * Fixed another max line length warning * Simplify return statement * Suppress class to object change * Make DemoConstants variables const * Use error() instead of throwing an IllegalStateException * Solve too complex condition * Suppress intentionally generic and swallowed exception * Suppress TooGenericExceptionCaught * Solve or suppress several TooGenericExceptionCaught * Fix swallowed exception * Suppress warning TooGenericExceptionCaught of PersistentTransactionManager * Suppress warning TooGenericExceptionCaught of WalletTransactionEncoder * Suppress TooGenericExceptionCaught of SdkSynchronizer * Suppress TooGenericExceptionCaught in SaplingParamTool * Suppress TooGenericExceptionCaught in CompactBlockDownloader * Suppress TooGenericExceptionCaught in CheckpointTool * Fix TooGenericExceptionCaught in WalletService * Suppress TooGenericExceptionCaught in DerivedDataDb * Suppress TooGenericExceptionCaught in CompactBlockProcessor * Apply ktlint format after all the previous changes * Remove detekt baseline file * Set Android studio right margin * Address comments from review * Suppress failing tests on CI
2022-08-23 06:49:00 -07:00
// TODO [#682]: refresh orchard balance
// TODO [#682]: https://github.com/zcash/zcash-android-wallet-sdk/issues/682
2023-02-06 14:36:28 -08:00
Twig.warn { "Warning: Orchard balance does not yet refresh. Only some of the plumbing is in place." }
}
suspend fun refreshSaplingBalance() {
2023-02-06 14:36:28 -08:00
Twig.debug { "refreshing sapling balance" }
2022-10-06 10:44:34 -07:00
_saplingBalances.value = processor.getBalanceInfo(Account.DEFAULT)
}
suspend fun refreshTransparentBalance() {
2023-02-06 14:36:28 -08:00
Twig.debug { "refreshing transparent balance" }
2022-11-08 11:25:56 -08:00
_transparentBalances.value = processor.getUtxoCacheBalance(getTransparentAddress())
}
suspend fun isValidAddress(address: String): Boolean {
[#366] Fix Detekt warnings * Disable baseline file. Too many functions. * CurrencyFormatter.kt suppress too many functions * PersistentTransactionManager.kt suppress too many functions * OutboundTransactionManager suppress too many functions * Suppress long parameter list * Too many functions * Add log to avoid empty block warning * Fix several magic number warnings * Solve max line length warnings * Solve max line length warnings * Suppress too long method warnings * Suppress too complex method warnings * Suppress large class warning * Fixed empty catch block * Changed directory path to the file * Fix too generic and swallowed exception * Fix print stack trace warning * Suppressed single top level file name declaration * Change parameters name * Suppress Spread operator warning * Remove unused private code * Add Locale to suppress default locale used warning * Solve several forbidden TODOs warnings * Fixed another max line length warning * Simplify return statement * Suppress class to object change * Make DemoConstants variables const * Use error() instead of throwing an IllegalStateException * Solve too complex condition * Suppress intentionally generic and swallowed exception * Suppress TooGenericExceptionCaught * Solve or suppress several TooGenericExceptionCaught * Fix swallowed exception * Suppress warning TooGenericExceptionCaught of PersistentTransactionManager * Suppress warning TooGenericExceptionCaught of WalletTransactionEncoder * Suppress TooGenericExceptionCaught of SdkSynchronizer * Suppress TooGenericExceptionCaught in SaplingParamTool * Suppress TooGenericExceptionCaught in CompactBlockDownloader * Suppress TooGenericExceptionCaught in CheckpointTool * Fix TooGenericExceptionCaught in WalletService * Suppress TooGenericExceptionCaught in DerivedDataDb * Suppress TooGenericExceptionCaught in CompactBlockProcessor * Apply ktlint format after all the previous changes * Remove detekt baseline file * Set Android studio right margin * Address comments from review * Suppress failing tests on CI
2022-08-23 06:49:00 -07:00
return !validateAddress(address).isNotValid
}
private fun CoroutineScope.onReady() {
2023-02-06 14:36:28 -08:00
Twig.debug { "Starting synchronizer…" }
// Triggering UTXOs fetch and transparent balance update at the beginning of the block sync right after the app
// start, as it makes the transparent transactions appearance faster
launch(CoroutineExceptionHandler(::onCriticalError)) {
refreshUtxos()
refreshTransparentBalance()
refreshTransactions()
}
launch(CoroutineExceptionHandler(::onCriticalError)) {
var lastScanTime = 0L
processor.onProcessorErrorListener = ::onProcessorError
processor.onSetupErrorListener = ::onSetupError
processor.onChainErrorListener = ::onChainError
processor.state.onEach {
when (it) {
is Synced -> {
val now = System.currentTimeMillis()
// do a bit of housekeeping and then report synced status
onScanComplete(it.syncedRange, now - lastScanTime)
lastScanTime = now
SYNCED
}
is Stopped -> STOPPED
is Disconnected -> DISCONNECTED
is Syncing, Initialized -> SYNCING
is Enhancing -> ENHANCING
}.let { synchronizerStatus ->
// ignore enhancing status for now
// TODO [#682]: clean this up and handle enhancing gracefully
// TODO [#682]: https://github.com/zcash/zcash-android-wallet-sdk/issues/682
if (synchronizerStatus != ENHANCING) _status.value = synchronizerStatus
}
}.launchIn(this)
processor.start()
Twig.debug { "Completed starting synchronizer" }
}
}
[#367] Fix Kotlin compiler warnings * Fix missing room schema export directory * Fix returned unused fields from cursor * Fix missing db column index * Improved TODO. Added suppress warning * Changed parameters name to correspond to their supertype * Changed type to Kotlin variant * Use priority parameter * Unified parameter names * Suppress unchecked type warning * Removed inline function * Suppress obsolete coroutine warnings * Improve previous commit * Fix unnecessary safe call warning * Remove unused parameter * Unreachable code * toLowerCase where possible * Changed parameter name * Suppress several "unused" warnings * Fixed fromHtml() deprecation * Suppress intentionally unused parameter warning * Remove redundant initializer * Remove inline function * Suppress intentionally used deprecated code * Unreachable code * Suppress obsolete coroutine warnings * Suppress intentionally unused parameter * Remove unused expression * Supertype parameter name * Warnings of GetBlockRangeFragment.kt * Deprecated onActivityCreated * Suppress obsolete coroutine/flow warnings * Unnecessary null check * Suppress intentionally unused parameter * Suppress intentionally unused parameters * Deprecated onActivityCreated * Predetermined type * ListUtxosFragment clean code * Suppress intentionally unused parameter * Lint checks warnings fix * Add data db migration * Enable treating Kotlin compiler warnings as errors * Solve several darkside-test-lib tests warnings * Solve several demo-app tests warnings * Solve several sdk-lib tests warnings * Ktlint check result fix * Remove parentheses now that Synchronizer is not cast * Remove wildcard imports for java.util * Revert "Add data db migration" * Revert "Fix missing db column index" * Suppress missing indexes on data db entities Co-authored-by: Carter Jernigan <git@carterjernigan.com>
2022-08-17 06:48:02 -07:00
@Suppress("UNUSED_PARAMETER")
private fun onCriticalError(unused: CoroutineContext?, error: Throwable) {
2023-02-06 14:36:28 -08:00
Twig.error(error) { "Critical error occurred" }
if (onCriticalErrorHandler == null) {
2023-02-06 14:36:28 -08:00
Twig.debug {
"WARNING: a critical error occurred but no callback is registered to be notified " +
"of critical errors! THIS IS PROBABLY A MISTAKE. To respond to these " +
"errors (perhaps to update the UI or alert the user) set " +
"synchronizer.onCriticalErrorHandler to a non-null value."
2023-02-06 14:36:28 -08:00
}
2023-02-06 14:36:28 -08:00
onCriticalErrorHandler?.invoke(error)
}
}
2019-07-14 15:13:12 -07:00
private fun onProcessorError(error: Throwable): Boolean {
2023-02-06 14:36:28 -08:00
Twig.debug { "ERROR while processing data: $error" }
if (onProcessorErrorHandler == null) {
2023-02-06 14:36:28 -08:00
Twig.debug {
2019-10-23 22:21:52 -07:00
"WARNING: falling back to the default behavior for processor errors. To add" +
" custom behavior, set synchronizer.onProcessorErrorHandler to" +
" a non-null value"
2023-02-06 14:36:28 -08:00
}
return true
}
2019-07-14 15:13:12 -07:00
return onProcessorErrorHandler?.invoke(error)?.also {
2023-02-06 14:36:28 -08:00
Twig.debug {
2019-10-23 22:21:52 -07:00
"processor error handler signaled that we should " +
"${if (it) "try again" else "abort"}!"
2023-02-06 14:36:28 -08:00
}
2019-07-14 15:13:12 -07:00
} == true
}
private fun onSetupError(error: Throwable): Boolean {
if (onSetupErrorHandler == null) {
2023-02-06 14:36:28 -08:00
Twig.debug {
"WARNING: falling back to the default behavior for setup errors. To add custom" +
" behavior, set synchronizer.onSetupErrorHandler to a non-null value"
2023-02-06 14:36:28 -08:00
}
return false
}
return onSetupErrorHandler?.invoke(error) == true
}
private fun onChainError(errorHeight: BlockHeight, rewindHeight: BlockHeight) {
2023-02-06 14:36:28 -08:00
Twig.debug { "Chain error detected at height: $errorHeight. Rewinding to: $rewindHeight" }
if (onChainErrorHandler == null) {
2023-02-06 14:36:28 -08:00
Twig.debug {
"WARNING: a chain error occurred but no callback is registered to be notified of " +
"chain errors. To respond to these errors (perhaps to update the UI or alert the" +
" user) set synchronizer.onChainErrorHandler to a non-null value"
2023-02-06 14:36:28 -08:00
}
}
onChainErrorHandler?.invoke(errorHeight, rewindHeight)
}
/**
* @param elapsedMillis the amount of time that passed since the last scan
*/
private suspend fun onScanComplete(scannedRange: ClosedRange<BlockHeight>?, elapsedMillis: Long) {
// We don't need to update anything if there have been no blocks
// refresh anyway if:
// - if it's the first time we finished scanning
// - if we check for blocks 5 times and find nothing was mined
[#366] Fix Detekt warnings * Disable baseline file. Too many functions. * CurrencyFormatter.kt suppress too many functions * PersistentTransactionManager.kt suppress too many functions * OutboundTransactionManager suppress too many functions * Suppress long parameter list * Too many functions * Add log to avoid empty block warning * Fix several magic number warnings * Solve max line length warnings * Solve max line length warnings * Suppress too long method warnings * Suppress too complex method warnings * Suppress large class warning * Fixed empty catch block * Changed directory path to the file * Fix too generic and swallowed exception * Fix print stack trace warning * Suppressed single top level file name declaration * Change parameters name * Suppress Spread operator warning * Remove unused private code * Add Locale to suppress default locale used warning * Solve several forbidden TODOs warnings * Fixed another max line length warning * Simplify return statement * Suppress class to object change * Make DemoConstants variables const * Use error() instead of throwing an IllegalStateException * Solve too complex condition * Suppress intentionally generic and swallowed exception * Suppress TooGenericExceptionCaught * Solve or suppress several TooGenericExceptionCaught * Fix swallowed exception * Suppress warning TooGenericExceptionCaught of PersistentTransactionManager * Suppress warning TooGenericExceptionCaught of WalletTransactionEncoder * Suppress TooGenericExceptionCaught of SdkSynchronizer * Suppress TooGenericExceptionCaught in SaplingParamTool * Suppress TooGenericExceptionCaught in CompactBlockDownloader * Suppress TooGenericExceptionCaught in CheckpointTool * Fix TooGenericExceptionCaught in WalletService * Suppress TooGenericExceptionCaught in DerivedDataDb * Suppress TooGenericExceptionCaught in CompactBlockProcessor * Apply ktlint format after all the previous changes * Remove detekt baseline file * Set Android studio right margin * Address comments from review * Suppress failing tests on CI
2022-08-23 06:49:00 -07:00
@Suppress("MagicNumber")
val shouldRefresh = !scannedRange.isNullOrEmpty() || elapsedMillis > (ZcashSdk.POLL_INTERVAL * 5)
val reason = if (scannedRange.isNullOrEmpty()) "it's been a while" else "new blocks were scanned"
if (shouldRefresh) {
2023-02-06 14:36:28 -08:00
Twig.debug { "Triggering utxo refresh since $reason!" }
refreshUtxos()
Twig.debug { "Triggering balance refresh since $reason!" }
refreshAllBalances()
Twig.debug { "Triggering transaction refresh since $reason!" }
refreshTransactions()
}
}
//
// Account management
//
// Not ready to be a public API; internal for testing only
internal suspend fun createAccount(seed: ByteArray): UnifiedSpendingKey =
CompactBlockProcessor.createAccount(backend, seed)
/**
* Returns the current Unified Address for this account.
*/
2022-11-08 11:25:56 -08:00
override suspend fun getUnifiedAddress(account: Account): String =
CompactBlockProcessor.getCurrentAddress(backend, account)
/**
* Returns the legacy Sapling address corresponding to the current Unified Address for this account.
*/
2022-11-08 11:25:56 -08:00
override suspend fun getSaplingAddress(account: Account): String =
CompactBlockProcessor.getLegacySaplingAddress(backend, account)
/**
* Returns the legacy transparent address corresponding to the current Unified Address for this account.
*/
2022-11-08 11:25:56 -08:00
override suspend fun getTransparentAddress(account: Account): String =
CompactBlockProcessor.getTransparentAddress(backend, account)
@Throws(TransactionEncoderException::class, TransactionSubmitException::class)
override suspend fun sendToAddress(
usk: UnifiedSpendingKey,
amount: Zatoshi,
toAddress: String,
2022-10-06 10:44:34 -07:00
memo: String
): Long {
val encodedTx = txManager.encode(
usk,
amount,
TransactionRecipient.Address(toAddress),
memo,
usk.account
)
if (txManager.submit(encodedTx)) {
return storage.findMatchingTransactionId(encodedTx.txId.byteArray)!!
} else {
throw TransactionSubmitException()
}
}
@Throws(TransactionEncoderException::class, TransactionSubmitException::class)
override suspend fun shieldFunds(
usk: UnifiedSpendingKey,
memo: String
): Long {
2023-02-06 14:36:28 -08:00
Twig.debug { "Initializing shielding transaction" }
val tAddr = CompactBlockProcessor.getTransparentAddress(backend, usk.account)
val tBalance = processor.getUtxoCacheBalance(tAddr)
val encodedTx = txManager.encode(
usk,
tBalance.available,
TransactionRecipient.Account(usk.account),
memo,
usk.account
)
if (txManager.submit(encodedTx)) {
return storage.findMatchingTransactionId(encodedTx.txId.byteArray)!!
} else {
throw TransactionSubmitException()
}
}
override suspend fun refreshUtxos(account: Account, since: BlockHeight): Int {
return processor.refreshUtxos(account, since)
}
override suspend fun getTransparentBalance(tAddr: String): WalletBalance {
return processor.getUtxoCacheBalance(tAddr)
}
override suspend fun isValidShieldedAddr(address: String) =
txManager.isValidShieldedAddress(address)
override suspend fun isValidTransparentAddr(address: String) =
txManager.isValidTransparentAddress(address)
override suspend fun isValidUnifiedAddr(address: String) =
txManager.isValidUnifiedAddress(address)
override suspend fun validateAddress(address: String): AddressType {
[#366] Fix Detekt warnings * Disable baseline file. Too many functions. * CurrencyFormatter.kt suppress too many functions * PersistentTransactionManager.kt suppress too many functions * OutboundTransactionManager suppress too many functions * Suppress long parameter list * Too many functions * Add log to avoid empty block warning * Fix several magic number warnings * Solve max line length warnings * Solve max line length warnings * Suppress too long method warnings * Suppress too complex method warnings * Suppress large class warning * Fixed empty catch block * Changed directory path to the file * Fix too generic and swallowed exception * Fix print stack trace warning * Suppressed single top level file name declaration * Change parameters name * Suppress Spread operator warning * Remove unused private code * Add Locale to suppress default locale used warning * Solve several forbidden TODOs warnings * Fixed another max line length warning * Simplify return statement * Suppress class to object change * Make DemoConstants variables const * Use error() instead of throwing an IllegalStateException * Solve too complex condition * Suppress intentionally generic and swallowed exception * Suppress TooGenericExceptionCaught * Solve or suppress several TooGenericExceptionCaught * Fix swallowed exception * Suppress warning TooGenericExceptionCaught of PersistentTransactionManager * Suppress warning TooGenericExceptionCaught of WalletTransactionEncoder * Suppress TooGenericExceptionCaught of SdkSynchronizer * Suppress TooGenericExceptionCaught in SaplingParamTool * Suppress TooGenericExceptionCaught in CompactBlockDownloader * Suppress TooGenericExceptionCaught in CheckpointTool * Fix TooGenericExceptionCaught in WalletService * Suppress TooGenericExceptionCaught in DerivedDataDb * Suppress TooGenericExceptionCaught in CompactBlockProcessor * Apply ktlint format after all the previous changes * Remove detekt baseline file * Set Android studio right margin * Address comments from review * Suppress failing tests on CI
2022-08-23 06:49:00 -07:00
@Suppress("TooGenericExceptionCaught")
return try {
if (isValidShieldedAddr(address)) {
Shielded
} else if (isValidTransparentAddr(address)) {
Transparent
} else if (isValidUnifiedAddr(address)) {
Unified
} else {
AddressType.Invalid("Not a Zcash address")
}
} catch (@Suppress("TooGenericExceptionCaught") error: Throwable) {
AddressType.Invalid(error.message ?: "Invalid")
}
}
2019-11-01 13:25:28 -07:00
override suspend fun validateConsensusBranch(): ConsensusMatchType {
[#615] Refactor lightwalletd client * [#615] Refactor lightwalletd client This moves the lightwalletd client code to a separate Gradle module, but does not yet do much clean up the public API (e.g. hiding generated GRPC objects). That will be a followon change via #673 I’ve prototyped a safer version of the API that would be implemented for #673 for two specific calls: obtaining the current block height and obtaining the light wallet info. These were the easiest endpoints to update and they provide a useful exploration for the future changes needed. * Fix benchmarking for networking module - Moved to fixture and build type check components to the new networking module, so it's accessible from all needed parts of the projects - Changed fixture return type to fit to all needed usages * Align with previous review comment * Fix wrong merge * Add basic sanity test - To satisfy tests requirements on emulators.wtf service * Remove grpc dependency from sdk-lib module * Repackage cash.z.wallet.sdk.rpc to cash.z.wallet.sdk.internal.rpc * Fix BuildConfig path * Update demo-app paths to rpc * Fix broken grpc services locations - Our aim here is to change only the local services location (package name), the server location can't be changed due to backward compatibility. * Enhance GRPC Response model * Adopt enhanced GRPC response model - Adopted in a few endpoints * Enhance Connection failure type * Add simple fixture test * Refactor fetchTransaction() to work with Response - Refactored this server call to adopt our new Response mechanism - GrpsStatusResolver.resolveFailureFromStatus() now accepts Throwable input - Added Response.Failure.toThrowable() to satisfy subsequent server calls results processing - A few other minor refactoring changes * Remove commented out log * Unify return type of collection returning methods - Switched fetchUtxos() to return Sequence instead of List - Added a check on empty tAddress input * fetchUtxos returns flow - Switched fetchUtxos() to return Flow of Service.GetAddressUtxosReply - Internally it calls getAddressUtxosStream() instead of getAddressUtxos() from GRPC layer * Update unsafe suffix documentation * Address several minor change requests * Remove code parameter - Removed from the locally triggered failures with default codes. * Rename local variable * Switch from empty response to exception - Our server calls now rather throw IllegalArgumentException than return an empty response - Removed commented out log message - Updated javadocs * Update proto files - Plus related api changes adoption * Unify new clients instances name * AGP 7.4.0 changes - packagingOptions -> androidComponents in sdk-lib and lightwallet-client-lib modules * SDK version bump * Response resolver tests * Release build upload timeout increase * Release build upload timeout increase fix * Revert timeout - As Github has some infrastructure troubles and we need to wait * Add migrations documentation * Sort packaging filters * Remove private field from public documentation * Hide private variables * Remove package from Android Manifest * Throw exception instead of custom error - This step unify our approach to validation on client side across all server calls * Replace setAddresses index const with number * Fix indentation in proto file --------- Co-authored-by: Honza <rychnovsky.honza@gmail.com>
2023-02-01 02:14:55 -08:00
val serverBranchId = tryNull { processor.downloader.getServerInfo()?.consensusBranchId }
val sdkBranchId = tryNull {
(txManager as OutboundTransactionManagerImpl).encoder.getConsensusBranchId()
}
return ConsensusMatchType(
sdkBranchId?.let { ConsensusBranchId.fromId(it) },
serverBranchId?.let { ConsensusBranchId.fromHex(it) }
)
}
}
/**
* Provides a way of constructing a synchronizer where dependencies are injected in.
*
* See the helper methods for generating default values.
*/
internal object DefaultSynchronizerFactory {
internal suspend fun defaultBackend(
network: ZcashNetwork,
alias: String,
saplingParamTool: SaplingParamTool,
coordinator: DatabaseCoordinator
): Backend {
return RustBackend.new(
[#765] Store blocks on disk instead of in SQLite * Switch to FsBlockDb for caching CompactBlocks * Add RustBackend.getLatestHeight() method * Raise MSRV to 1.60 * Migrate to latest Rust crate API * Add RustBackend.findBlockMetadata() method * Add RustBackend.rewindBlockMetadataToHeight() method * [#765] implementation of FileCompactBlockRepository * writing block metadata to database * split write function into smaller easier to test blocks * testing for FileCompactBlockRepository * fixed rewinding * fixed tests * fixed FileCompactBlockRepositoryTest and SynchronizerFactoryTest * code review fixes * updated proto files * override all functions in FakeRustBackend * code review fixes * Fix function body formatting * Improve clear function clarity * Use length of string const * Delete single file instead of directory * Improve function clarity * Refactor outputs counting - Found a typo in intermediary model class JniBlockMeta parameter change of which does not impact encoding from rust to kotlin according to rust layer implementation. * Check blocks mkdir result * Remove unnecessary detekt warning suppression * Refactor buffer size check * Improve visibility annotations * Make file finalise obvious and self documenting * Remove prevHash logging * Move instantiation to the object itself * Enrich fixture with default values * Extend eror message * Rename benchmark blocks range fixture * Fix rebase changes * Improve FileCompactBlockRepositoryTest - "De-integrated" the test suite - it now works with fixture blocks - Created needed fixtures for a clear mocked blocks providing - Enhanced getting of FileCompactBlockRepository in FileCompactBlockRepositoryTest to clarify that it works with mock components * Fix ktlintFormat findings * Bump actions/cache from 3.2.4 to 3.2.5 in /.github/actions/setup (#927) Bumps [actions/cache](https://github.com/actions/cache) from 3.2.4 to 3.2.5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/627f0f41f6904a5b1efbaed9f96d9eb58e92e920...6998d139ddd3e68c71e9e398d8e40b71a2f39812) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Fix incorrect dir checking * More robust min/max checking * Rewinding to more robust middle value * Strengthen blocks counts after rewind * Add check of temp finalized file * Refactor DatabaseCoordinatorTest * Rename cache files root directory - To have the same unified variable name across our repositories - fsBlockDbRoot * Refactor FileCompactBlockRepositoryTest - To have these tests more clear - Fixed FakeRustBackend instantiation bug * Revert back JniBlockMeta param name * Delete legacy Cache db files - Deleted from both the older and the newer legacy locations - All related db files deleted - rollback files included - The deletion is run once we try to access the new store blocks on disk root directory - The deletion check does not throw any exception in case of failure, we just log it in console and try it on the next time - Related new test added too * Test refactoring - Made few changes to improve clarity of provided tests and fixtures - Prepared few new "failure path" tests - Enhanced existing tests * Manual test case * Simplify error printing - As we had some commented out code there * Reset manual tests steps numbering * [#924] Remove alias from WalletCoordinator Also make Compose UI the default. The old UI is deprecated but is still used by the benchmarking tests * Bump benchmark version * Protect JniBlockMetadata agains minification * Enable debuggable while benchmarking * Enhance benchmark screen waiting * Fix cache db files deletion - With this construct we delete all blocks blob metadata files, as well as their sqlite file * Add new benchmark results * Remove benchmark operations receiver fix - As it's not needed after the latest profiler dependency update * Bump gradle/wrapper-validation-action from 1.0.5 to 1.0.6 (#928) Bumps [gradle/wrapper-validation-action](https://github.com/gradle/wrapper-validation-action) from 1.0.5 to 1.0.6. - [Release notes](https://github.com/gradle/wrapper-validation-action/releases) - [Commits](https://github.com/gradle/wrapper-validation-action/compare/55e685c48d84285a5b0418cd094606e199cca3b6...8d49e559aae34d3e0eb16cde532684bc9702762b) --- updated-dependencies: - dependency-name: gradle/wrapper-validation-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump actions/cache from 3.2.5 to 3.2.6 in /.github/actions/setup (#929) Bumps [actions/cache](https://github.com/actions/cache) from 3.2.5 to 3.2.6. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/6998d139ddd3e68c71e9e398d8e40b71a2f39812...69d9d449aced6a2ede0bc19182fadc3a0a42d2b0) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update DatabaseCoordinator.kt Move if/else out from log message body * Update Switch cache to store blocks on disk.md Reset documentation bullets numbering * Hide internal constants from public package * Update manual test user with new UI requirement * Comment out cargo.toml test values * Inline fixture blocks metadata with its creation * Switch to FsBlockDb for caching CompactBlocks * Add RustBackend.getLatestHeight() method * Raise MSRV to 1.60 * Migrate to latest Rust crate API * Add RustBackend.findBlockMetadata() method * Add RustBackend.rewindBlockMetadataToHeight() method * Update cargo.lock * Switch to FsBlockDb for caching CompactBlocks * Migrate to latest Rust crate API * [#765] implementation of FileCompactBlockRepository * writing block metadata to database * split write function into smaller easier to test blocks * testing for FileCompactBlockRepository * fixed rewinding * fixed tests * fixed FileCompactBlockRepositoryTest and SynchronizerFactoryTest * code review fixes * updated proto files * override all functions in FakeRustBackend * code review fixes * Fix function body formatting * Improve clear function clarity * Use length of string const * Delete single file instead of directory * Improve function clarity * Refactor outputs counting - Found a typo in intermediary model class JniBlockMeta parameter change of which does not impact encoding from rust to kotlin according to rust layer implementation. * Check blocks mkdir result * Remove unnecessary detekt warning suppression * Refactor buffer size check * Improve visibility annotations * Make file finalise obvious and self documenting * Remove prevHash logging * Move instantiation to the object itself * Enrich fixture with default values * Extend eror message * Rename benchmark blocks range fixture * Fix rebase changes * Improve FileCompactBlockRepositoryTest - "De-integrated" the test suite - it now works with fixture blocks - Created needed fixtures for a clear mocked blocks providing - Enhanced getting of FileCompactBlockRepository in FileCompactBlockRepositoryTest to clarify that it works with mock components * Fix ktlintFormat findings * Fix incorrect dir checking * More robust min/max checking * Rewinding to more robust middle value * Strengthen blocks counts after rewind * Add check of temp finalized file * Refactor DatabaseCoordinatorTest * Rename cache files root directory - To have the same unified variable name across our repositories - fsBlockDbRoot * Refactor FileCompactBlockRepositoryTest - To have these tests more clear - Fixed FakeRustBackend instantiation bug * Revert back JniBlockMeta param name * Delete legacy Cache db files - Deleted from both the older and the newer legacy locations - All related db files deleted - rollback files included - The deletion is run once we try to access the new store blocks on disk root directory - The deletion check does not throw any exception in case of failure, we just log it in console and try it on the next time - Related new test added too * Test refactoring - Made few changes to improve clarity of provided tests and fixtures - Prepared few new "failure path" tests - Enhanced existing tests * Manual test case * Simplify error printing - As we had some commented out code there * Reset manual tests steps numbering * Bump benchmark version * Protect JniBlockMetadata agains minification * Enable debuggable while benchmarking * Enhance benchmark screen waiting * Fix cache db files deletion - With this construct we delete all blocks blob metadata files, as well as their sqlite file * Add new benchmark results * Remove benchmark operations receiver fix - As it's not needed after the latest profiler dependency update * Update DatabaseCoordinator.kt Move if/else out from log message body * Update Switch cache to store blocks on disk.md Reset documentation bullets numbering * Hide internal constants from public package * Update manual test user with new UI requirement * Comment out cargo.toml test values * Inline fixture blocks metadata with its creation * Update cargo.lock * Update Cargo.lock * Check and document JniBlockMeta params ranges * Add assert for gradle property * Use UInt internally uint * Change array API to list * Fix for using correct SDK Synchronizer alias - Only the older Demo-app UI was impacted. - Thus also our benchmarking was impacted. * Apply documentation suggestions from code review Co-authored-by: Kris Nuttycombe <kris@electriccoin.co> * Final manual test instructions update * Fixture block hash deterministically generated from block height --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Jack Grigg <jack@electriccoin.co> Co-authored-by: Jack Grigg <jack@z.cash> Co-authored-by: Honza <rychnovsky.honza@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Carter Jernigan <git@carterjernigan.com> Co-authored-by: Kris Nuttycombe <kris@electriccoin.co>
2023-03-08 07:04:04 -08:00
coordinator.fsBlockDbRoot(network, alias),
coordinator.dataDbFile(network, alias),
saplingOutputFile = saplingParamTool.outputParamsFile,
saplingSpendFile = saplingParamTool.spendParamsFile,
zcashNetworkId = network.id
)
}
@Suppress("LongParameterList")
internal suspend fun defaultDerivedDataRepository(
context: Context,
rustBackend: Backend,
databaseFile: File,
zcashNetwork: ZcashNetwork,
checkpoint: Checkpoint,
seed: ByteArray?,
viewingKeys: List<UnifiedFullViewingKey>
): DerivedDataRepository =
2023-02-06 14:36:28 -08:00
DbDerivedDataRepository(
DerivedDataDb.new(
context,
rustBackend,
databaseFile,
2023-02-06 14:36:28 -08:00
zcashNetwork,
checkpoint,
seed,
viewingKeys
)
)
internal suspend fun defaultCompactBlockRepository(blockCacheRoot: File, backend: Backend): CompactBlockRepository =
FileCompactBlockRepository.new(
blockCacheRoot,
backend
)
fun defaultService(context: Context, lightWalletEndpoint: LightWalletEndpoint): LightWalletClient =
LightWalletClient.new(context, lightWalletEndpoint)
internal fun defaultEncoder(
backend: Backend,
saplingParamTool: SaplingParamTool,
repository: DerivedDataRepository
): TransactionEncoder = TransactionEncoderImpl(backend, saplingParamTool, repository)
fun defaultDownloader(
service: LightWalletClient,
blockStore: CompactBlockRepository
): CompactBlockDownloader = CompactBlockDownloader(service, blockStore)
internal fun defaultTxManager(
encoder: TransactionEncoder,
service: LightWalletClient
): OutboundTransactionManager {
return OutboundTransactionManagerImpl.new(
encoder,
service
)
}
internal fun defaultProcessor(
backend: Backend,
downloader: CompactBlockDownloader,
repository: DerivedDataRepository,
birthdayHeight: BlockHeight
): CompactBlockProcessor = CompactBlockProcessor(
downloader,
repository,
backend,
birthdayHeight
)
2021-03-10 19:04:39 -08:00
}
internal data class SynchronizerKey(val zcashNetwork: ZcashNetwork, val alias: String)