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

557 lines
23 KiB
Kotlin
Raw Normal View History

package cash.z.ecc.android.sdk
import android.content.Context
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
import cash.z.ecc.android.sdk.ext.ZcashSdk
import cash.z.ecc.android.sdk.internal.Derivation
import cash.z.ecc.android.sdk.internal.SaplingParamTool
import cash.z.ecc.android.sdk.internal.db.DatabaseCoordinator
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
import cash.z.ecc.android.sdk.model.TransactionOverview
2022-10-31 12:27:34 -07:00
import cash.z.ecc.android.sdk.model.TransactionRecipient
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.tool.CheckpointTool
import cash.z.ecc.android.sdk.tool.DerivationTool
import cash.z.ecc.android.sdk.type.AddressType
import cash.z.ecc.android.sdk.type.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
import co.electriccoin.lightwallet.client.model.LightWalletEndpoint
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.runBlocking
import java.io.Closeable
[#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")
interface Synchronizer {
2023-05-02 06:59:52 -07:00
// Status
2019-11-01 13:25:28 -07:00
/**
* The network to which this synchronizer is connected and from which it is processing blocks.
*/
val network: ZcashNetwork
/**
2019-11-01 13:25:28 -07:00
* A flow of values representing the [Status] of this Synchronizer. As the status changes, a new
* value will be emitted by this flow.
*/
2019-11-01 13:25:28 -07:00
val status: Flow<Status>
/**
2019-11-01 13:25:28 -07:00
* A flow of progress values, typically corresponding to this Synchronizer downloading blocks.
* Typically, any non-zero value below `PercentDecimal.ONE_HUNDRED_PERCENT` indicates that progress indicators can
* be shown and a value of `PercentDecimal.ONE_HUNDRED_PERCENT` signals that progress is complete and any progress
* indicators can be hidden.
*/
val progress: Flow<PercentDecimal>
/**
* A flow of processor details, updated every time blocks are processed to include the latest
* block height, blocks downloaded and blocks scanned. Similar to the [progress] flow but with a
* lot more detail.
*/
val processorInfo: Flow<CompactBlockProcessor.ProcessorInfo>
/**
* The latest height observed on the network, which does not necessarily correspond to the
* latest downloaded height or scanned height. Although this is present in [processorInfo], it
* is such a frequently used value that it is convenient to have the real-time value by itself.
*/
val networkHeight: StateFlow<BlockHeight?>
/**
* A stream of balance values for the orchard pool. Includes the available and total balance.
*/
val orchardBalances: StateFlow<WalletBalance?>
/**
* A stream of balance values for the sapling pool. Includes the available and total balance.
*/
val saplingBalances: StateFlow<WalletBalance?>
/**
* A stream of balance values for the transparent pool. Includes the available and total balance.
*/
val transparentBalances: StateFlow<WalletBalance?>
2019-11-01 13:25:28 -07:00
2019-07-14 15:13:12 -07:00
/**
2019-11-01 13:25:28 -07:00
* A flow of all the transactions that are on the blockchain.
2019-07-14 15:13:12 -07:00
*/
val transactions: Flow<List<TransactionOverview>>
//
// Latest Properties
//
/**
* An in-memory reference to the latest height seen on the network.
*/
val latestHeight: BlockHeight?
/**
* An in-memory reference to the best known birthday height, which can change if the first
* transaction has not yet occurred.
*/
val latestBirthdayHeight: BlockHeight?
2019-07-14 15:13:12 -07:00
//
// Operations
//
/**
* Adds the next available account-level spend authority, given the current set of
* [ZIP 316](https://zips.z.cash/zip-0316) account identifiers known, to the wallet
* database.
*
* The caller should store the byte encoding of the returned spending key in a secure
* fashion. This encoding **MUST NOT** be exposed to users. It is an internal encoding
* that is inherently unstable, and only intended to be passed between the SDK and the
* storage backend. The caller **MUST NOT** allow this encoding to be exported or
* imported.
*
* If `seed` was imported from a backup and this method is being used to restore a
* previous wallet state, you should use this method to add all of the desired
* accounts before scanning the chain from the seed's birthday height.
*
* By convention, wallets should only allow a new account to be generated after funds
* have been received by the currently-available account (in order to enable
* automated account recovery).
*
* @param seed the wallet's seed phrase.
*
* @return the newly created ZIP 316 account identifier, along with the binary
* encoding of the `UnifiedSpendingKey` for the newly created account.
*/
2022-10-06 10:44:34 -07:00
// This is not yet ready to be a public API
// suspend fun createAccount(seed: ByteArray): UnifiedSpendingKey
/**
* Gets the current unified address for the given account.
*
2019-11-01 13:25:28 -07:00
* @param accountId the optional accountId whose address is of interest. By default, the first
* account is used.
2020-02-27 00:25:07 -08:00
*
* @return the current unified address for the given account.
*/
2022-11-08 11:25:56 -08:00
suspend fun getUnifiedAddress(account: Account = Account.DEFAULT): String
/**
* Gets the legacy Sapling address corresponding to the current unified address for the given account.
*
2022-10-06 10:44:34 -07:00
* @param account the optional accountId whose address is of interest. By default, the first
* account is used.
*
* @return a legacy Sapling address for the given account.
*/
2022-11-08 11:25:56 -08:00
suspend fun getSaplingAddress(account: Account = Account.DEFAULT): String
/**
* Gets the legacy transparent address corresponding to the current unified address for the given account.
*
2022-10-06 10:44:34 -07:00
* @param account the optional accountId whose address is of interest. By default, the first
* account is used.
*
* @return a legacy transparent address for the given account.
*/
2022-11-08 11:25:56 -08:00
suspend fun getTransparentAddress(account: Account = Account.DEFAULT): String
/**
* Sends zatoshi.
*
* @param usk the unified spending key associated with the notes that will be spent.
* @param zatoshi the amount of zatoshi to send.
* @param toAddress the recipient's address.
* @param memo the optional memo to include as part of the transaction.
2020-02-27 00:25:07 -08:00
*
* @return a flow of PendingTransaction objects representing changes to the state of the
* transaction. Any time the state changes a new instance will be emitted by this flow. This is
* useful for updating the UI without needing to poll. Of course, polling is always an option
* for any wallet that wants to ignore this return value.
*/
suspend fun sendToAddress(
usk: UnifiedSpendingKey,
amount: Zatoshi,
2019-07-14 15:13:12 -07:00
toAddress: String,
2022-10-06 10:44:34 -07:00
memo: String = ""
): Long
suspend fun shieldFunds(
usk: UnifiedSpendingKey,
memo: String = ZcashSdk.DEFAULT_SHIELD_FUNDS_MEMO_PREFIX
): Long
/**
* Returns true when the given address is a valid z-addr. Invalid addresses will throw an
2020-02-27 00:25:07 -08:00
* exception. Valid z-addresses have these characteristics: //TODO copy info from related ZIP
*
* @param address the address to validate.
2020-02-27 00:25:07 -08:00
*
* @return true when the given address is a valid z-addr.
*
* @throws RuntimeException when the address is invalid.
*/
suspend fun isValidShieldedAddr(address: String): Boolean
/**
* Returns true when the given address is a valid t-addr. Invalid addresses will throw an
2020-02-27 00:25:07 -08:00
* exception. Valid t-addresses have these characteristics: //TODO copy info from related ZIP
*
* @param address the address to validate.
2020-02-27 00:25:07 -08:00
*
* @return true when the given address is a valid t-addr.
*
* @throws RuntimeException when the address is invalid.
*/
suspend fun isValidTransparentAddr(address: String): Boolean
/**
* Returns true when the given address is a valid ZIP 316 unified address.
*
* This method is intended for type checking (e.g. form validation). Invalid
* addresses will throw an exception.
*
* @param address the address to validate.
*
* @return true when the given address is a valid unified address.
*
* @throws RuntimeException when the address is invalid.
*/
suspend fun isValidUnifiedAddr(address: String): Boolean
/**
* Validate whether the server and this SDK share the same consensus branch. This is
* particularly important to check around network updates so that any wallet that's connected to
* an incompatible server can surface that information effectively. For the SDK, the consensus
* branch is used when creating transactions as each one needs to target a specific branch. This
* function compares the server's branch id to this SDK's and returns information that helps
* determine whether they match.
*
* @return an instance of [ConsensusMatchType] that is essentially a wrapper for both branch ids
* and provides helper functions for communicating detailed errors to the user.
*/
suspend fun validateConsensusBranch(): ConsensusMatchType
/**
2020-02-27 00:25:07 -08:00
* Validates the given address, returning information about why it is invalid. This is a
* convenience method that combines the behavior of [isValidShieldedAddr],
* [isValidTransparentAddr], and [isValidUnifiedAddr] into one call so that the developer
* doesn't have to worry about handling the exceptions that they throw. Rather, exceptions
* are converted to [AddressType.Invalid] which has a `reason` property describing why it is
* invalid.
*
* @param address the address to validate.
2020-02-27 00:25:07 -08:00
*
* @return an instance of [AddressType] providing validation info regarding the given address.
*/
suspend fun validateAddress(address: String): AddressType
2021-07-29 10:24:13 -07:00
/**
* Download all UTXOs for the given account addresses and store any new ones in the database.
2021-07-29 10:24:13 -07:00
*
* @param account The Account, for which all addresses blocks will be downloaded.
* @param since The BlockHeight, from which blocks will be downloaded.
*
* @return the number of utxos that were downloaded and added to the UTXO table.
2021-07-29 10:24:13 -07:00
*/
suspend fun refreshUtxos(
account: Account = Account.DEFAULT,
since: BlockHeight = network.saplingActivationHeight
): Int?
/**
* Returns the balance that the wallet knows about. This should be called after [refreshUtxos].
*/
suspend fun getTransparentBalance(tAddr: String): WalletBalance
suspend fun getNearestRewindHeight(height: BlockHeight): BlockHeight
/**
* Returns the safest height to which we can rewind, given a desire to rewind to the height
* provided. Due to how witness incrementing works, a wallet cannot simply rewind to any
* arbitrary height. This handles all that complexity yet remains flexible in the future as
* improvements are made.
*/
suspend fun rewindToNearestHeight(height: BlockHeight, alsoClearBlockCache: Boolean = false)
suspend fun quickRewind()
2022-10-24 06:09:29 -07:00
/**
* Returns a list of memos for a transaction.
*/
fun getMemos(transactionOverview: TransactionOverview): Flow<String>
2022-10-31 12:27:34 -07:00
/**
* Returns a list of recipients for a transaction.
*/
fun getRecipients(transactionOverview: TransactionOverview): Flow<TransactionRecipient>
2019-07-14 15:13:12 -07:00
//
// Error Handling
//
/**
2019-11-01 13:25:28 -07:00
* Gets or sets a global error handler. This is a useful hook for handling unexpected critical
* errors.
2019-07-14 15:13:12 -07:00
*
2019-11-01 13:25:28 -07:00
* @return true when the error has been handled and the Synchronizer should attempt to continue.
* False when the error is unrecoverable and the Synchronizer should [stop].
2019-07-14 15:13:12 -07:00
*/
var onCriticalErrorHandler: ((Throwable?) -> Boolean)?
/**
2019-11-01 13:25:28 -07:00
* An error handler for exceptions during processing. For instance, a block might be missing or
* a reorg may get mishandled or the database may get corrupted.
2019-07-14 15:13:12 -07:00
*
2019-11-01 13:25:28 -07:00
* @return true when the error has been handled and the processor should attempt to continue.
* False when the error is unrecoverable and the processor should [stop].
2019-07-14 15:13:12 -07:00
*/
var onProcessorErrorHandler: ((Throwable?) -> Boolean)?
/**
2019-11-01 13:25:28 -07:00
* An error handler for exceptions while submitting transactions to lightwalletd. For instance,
* a transaction may get rejected because it would be a double-spend or the user might lose
* their cellphone signal.
2019-07-14 15:13:12 -07:00
*
2019-11-01 13:25:28 -07:00
* @return true when the error has been handled and the sender should attempt to resend. False
* when the error is unrecoverable and the sender should [stop].
2019-07-14 15:13:12 -07:00
*/
var onSubmissionErrorHandler: ((Throwable?) -> Boolean)?
/**
* Callback for setup errors that occur prior to processing compact blocks. Can be used to
* override any errors encountered during setup. When this listener is missing then all setup
* errors will result in the synchronizer not starting. This is particularly useful for wallets
* to receive a callback right before the SDK will reject a lightwalletd server because it
* appears not to match.
*
* @return true when the setup error should be ignored and processing should be allowed to
* start. Otherwise, processing will not begin.
*/
var onSetupErrorHandler: ((Throwable?) -> Boolean)?
/**
* A callback to invoke whenever a chain error is encountered. These occur whenever the
2021-07-29 10:24:13 -07:00
* processor detects a missing or non-chain-sequential block (i.e. a reorg). At a minimum, it is
* best to log these errors because they are the most common source of bugs and unexpected
* behavior in wallets, due to the chain data mutating and wallets becoming out of sync.
*/
var onChainErrorHandler: ((BlockHeight, BlockHeight) -> Any)?
2020-02-27 00:25:07 -08:00
/**
* Represents the status of this Synchronizer, which is useful for communicating to the user.
*/
enum class Status {
/**
* Indicates that [stop] has been called on this Synchronizer and it will no longer be used.
*/
STOPPED,
/**
* Indicates that this Synchronizer is disconnected from its lightwalletd server.
* When set, a UI element may want to turn red.
*/
DISCONNECTED,
/**
* Indicates that the Synchronizer is actively syncing new blocks. It starts with downloading
* new blocks, then validating these blocks and scanning them at the end.
*
* In **Downloading** sub-phase the Synchronizer is actively downloading new blocks from the
* server.
*
* In **Validating** sub-phase the Synchronizer is actively validating new blocks that were downloaded
2020-01-15 04:10:22 -08:00
* from the server. Blocks need to be verified before they are scanned. This confirms that
* each block is chain-sequential, thereby detecting missing blocks and reorgs.
*
* In **Scanning** sub-phase Synchronizer is actively decrypting new blocks that were downloaded
2020-01-15 04:10:22 -08:00
* from the server.
*/
SYNCING,
/**
* Indicates that this Synchronizer is actively enhancing newly scanned blocks with
* additional transaction details, fetched from the server.
*/
ENHANCING,
/**
* Indicates that this Synchronizer is fully up to date and ready for all wallet functions.
2020-01-15 04:10:22 -08:00
* When set, a UI element may want to turn green. In this state, the balance can be trusted.
*/
SYNCED
}
companion object {
/**
* Primary method that SDK clients will use to construct a synchronizer.
*
* @param zcashNetwork the network to use.
* @param alias A string used to segregate multiple wallets in the filesystem. This implies the string
* should not contain characters unsuitable for the platform's filesystem. The default value is
* generally used unless an SDK client needs to support multiple wallets.
* @param lightWalletEndpoint Server endpoint. See [cash.z.ecc.android.sdk.model.defaultForNetwork]. If a
* client wishes to change the server endpoint, the active synchronizer will need to be stopped and a new
* instance created with a new value.
* @param seed the wallet's seed phrase. This is required the first time a new wallet is set up. For
* subsequent calls, seed is only needed if [InitializerException.SeedRequired] is thrown.
* @param birthday Block height representing the "birthday" of the wallet. When creating a new wallet, see
* [BlockHeight.ofLatestCheckpoint]. When restoring an existing wallet, use block height that was first used
* to create the wallet. If that value is unknown, null is acceptable but will result in longer
* sync times. After sync completes, the birthday can be determined from [Synchronizer.latestBirthdayHeight].
* @throws InitializerException.SeedRequired Indicates clients need to call this method again, providing the
* seed bytes.
* @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.
*/
/*
* If customized initialization is required (e.g. for dependency injection or testing), see
* [DefaultSynchronizerFactory].
*/
@Suppress("LongParameterList", "LongMethod")
suspend fun new(
context: Context,
zcashNetwork: ZcashNetwork,
alias: String = ZcashSdk.DEFAULT_ALIAS,
lightWalletEndpoint: LightWalletEndpoint,
seed: ByteArray?,
birthday: BlockHeight?
): CloseableSynchronizer {
val applicationContext = context.applicationContext
validateAlias(alias)
val saplingParamTool = SaplingParamTool.new(applicationContext)
val loadedCheckpoint = CheckpointTool.loadNearest(
applicationContext,
zcashNetwork,
birthday ?: zcashNetwork.saplingActivationHeight
)
val coordinator = DatabaseCoordinator.getInstance(context)
// The pending transaction database no longer exists, so we can delete the file
coordinator.deletePendingTransactionDatabase(zcashNetwork, alias)
val backend = DefaultSynchronizerFactory.defaultBackend(
zcashNetwork,
alias,
saplingParamTool,
coordinator
)
[#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
val blockStore =
DefaultSynchronizerFactory
.defaultCompactBlockRepository(coordinator.fsBlockDbRoot(zcashNetwork, alias), backend)
val viewingKeys = seed?.let {
DerivationTool.getInstance().deriveUnifiedFullViewingKeys(
seed,
zcashNetwork,
Derivation.DEFAULT_NUMBER_OF_ACCOUNTS
).toList()
} ?: emptyList()
val repository = DefaultSynchronizerFactory.defaultDerivedDataRepository(
applicationContext,
backend,
coordinator.dataDbFile(zcashNetwork, alias),
zcashNetwork,
loadedCheckpoint,
seed,
viewingKeys
)
val service = DefaultSynchronizerFactory.defaultService(applicationContext, lightWalletEndpoint)
val encoder = DefaultSynchronizerFactory.defaultEncoder(backend, saplingParamTool, repository)
val downloader = DefaultSynchronizerFactory.defaultDownloader(service, blockStore)
val txManager = DefaultSynchronizerFactory.defaultTxManager(
encoder,
service
)
val processor = DefaultSynchronizerFactory.defaultProcessor(
backend,
downloader,
repository,
birthday
?: zcashNetwork.saplingActivationHeight
)
return SdkSynchronizer.new(
zcashNetwork,
alias,
repository,
txManager,
2022-10-24 06:09:29 -07:00
processor,
backend
)
}
/**
* Effectively the same as [new] although designed to be a blocking call with better
* interoperability with Java clients.
*
* This is a blocking call, so it should not be called from the main thread.
*/
@JvmStatic
@Suppress("LongParameterList")
fun newBlocking(
context: Context,
zcashNetwork: ZcashNetwork,
alias: String = ZcashSdk.DEFAULT_ALIAS,
lightWalletEndpoint: LightWalletEndpoint,
seed: ByteArray?,
birthday: BlockHeight?
): CloseableSynchronizer = runBlocking {
new(context, zcashNetwork, alias, lightWalletEndpoint, seed, birthday)
}
/**
* Delete the databases associated with this wallet. This removes all compact blocks and
* data derived from those blocks. Although most data can be regenerated by setting up a new
* Synchronizer instance with the seed, there are two special cases where data is not retained:
* 1. Outputs created with a `null` OVK
* 2. The UA to which a transaction was sent (recovery from seed will only reveal the receiver, not the full UA)
*
* @param appContext the application context.
* @param network the network associated with the data to be erased.
* @param alias the alias used to create the local data.
*
* @return true when one of the associated files was found. False most likely indicates
* that the wrong alias was provided.
*/
suspend fun erase(
appContext: Context,
network: ZcashNetwork,
alias: String = ZcashSdk.DEFAULT_ALIAS
): Boolean = SdkSynchronizer.erase(appContext, network, alias)
}
}
interface CloseableSynchronizer : Synchronizer, Closeable
/**
* Validate that the alias doesn't contain malicious characters by enforcing simple rules which
* permit the alias to be used as part of a file name for the preferences and databases. This
* enables multiple wallets to exist on one device, which is also helpful for sweeping funds.
*
* @param alias the alias to validate.
*
* @throws IllegalArgumentException whenever the alias is not less than 100 characters or
* contains something other than alphanumeric characters. Underscores and hyphens are allowed.
*/
private fun validateAlias(alias: String) {
require(
alias.length in ZcashSdk.ALIAS_MIN_LENGTH..ZcashSdk.ALIAS_MAX_LENGTH &&
alias.all { it.isLetterOrDigit() || it == '_' || it == '-' }
) {
"ERROR: Invalid alias ($alias). For security, the alias must be shorter than 100 " +
"characters and only contain letters, digits, hyphens, and underscores."
}
2020-03-26 04:00:04 -07:00
}