zcash-android-wallet-sdk/sdk-lib/src/androidTest/java/cash/z/ecc/android/sdk/util/TestWallet.kt

192 lines
7.2 KiB
Kotlin
Raw Normal View History

package cash.z.ecc.android.sdk.util
import androidx.test.platform.app.InstrumentationRegistry
import cash.z.ecc.android.bip39.Mnemonics
import cash.z.ecc.android.bip39.toSeed
import cash.z.ecc.android.sdk.SdkSynchronizer
import cash.z.ecc.android.sdk.Synchronizer
2021-10-13 07:20:13 -07:00
import cash.z.ecc.android.sdk.internal.Twig
import cash.z.ecc.android.sdk.internal.deriveUnifiedSpendingKey
import cash.z.ecc.android.sdk.internal.jni.RustDerivationTool
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.Testnet
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
[#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.CoroutineScope
[#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
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.newFixedThreadPoolContext
import kotlinx.coroutines.runBlocking
import java.util.concurrent.TimeoutException
/**
* A simple wallet that connects to testnet for integration testing. The intention is that it is
* easy to drive and nice to use.
*/
[#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
@OptIn(DelicateCoroutinesApi::class)
class TestWallet(
val seedPhrase: String,
val alias: String = "TestWallet",
val network: ZcashNetwork = ZcashNetwork.Testnet,
val endpoint: LightWalletEndpoint = LightWalletEndpoint.Testnet,
startHeight: BlockHeight? = null
) {
constructor(
backup: Backups,
network: ZcashNetwork = ZcashNetwork.Testnet,
alias: String = "TestWallet"
) : this(
backup.seedPhrase,
network = network,
startHeight = if (network == ZcashNetwork.Mainnet) backup.mainnetBirthday else backup.testnetBirthday,
alias = alias
)
val walletScope = CoroutineScope(
SupervisorJob() + newFixedThreadPoolContext(3, this.javaClass.simpleName)
)
// Although runBlocking isn't great, this usage is OK because this is only used within the
// automated tests
private val account = Account.DEFAULT
private val context = InstrumentationRegistry.getInstrumentation().context
private val seed: ByteArray = Mnemonics.MnemonicCode(seedPhrase).toSeed()
2022-10-06 10:44:34 -07:00
private val spendingKey =
runBlocking { RustDerivationTool.new().deriveUnifiedSpendingKey(seed, network = network, account) }
val synchronizer: SdkSynchronizer = Synchronizer.newBlocking(
context,
network,
alias,
lightWalletEndpoint = endpoint,
seed = seed,
startHeight
) as SdkSynchronizer
val available get() = synchronizer.saplingBalances.value?.available
val unifiedAddress =
runBlocking { synchronizer.getUnifiedAddress(account) }
val transparentAddress =
runBlocking { synchronizer.getTransparentAddress(account) }
val birthdayHeight get() = synchronizer.latestBirthdayHeight
val networkName get() = synchronizer.network.networkName
suspend fun transparentBalance(): WalletBalance {
synchronizer.refreshUtxos(account, synchronizer.latestBirthdayHeight)
return synchronizer.getTransparentBalance(transparentAddress)
}
suspend fun sync(timeout: Long = -1): TestWallet {
val killSwitch = walletScope.launch {
if (timeout > 0) {
delay(timeout)
throw TimeoutException("Failed to sync wallet within ${timeout}ms")
}
}
// block until synced
synchronizer.status.first { it == Synchronizer.Status.SYNCED }
killSwitch.cancel()
return this
}
suspend fun send(
address: String = transparentAddress,
memo: String = "",
2022-10-06 10:44:34 -07:00
amount: Zatoshi = Zatoshi(500L)
): TestWallet {
2022-10-06 10:44:34 -07:00
synchronizer.sendToAddress(spendingKey, amount, address, memo)
return this
}
suspend fun rewindToHeight(height: BlockHeight): TestWallet {
2021-04-26 14:37:30 -07:00
synchronizer.rewindToNearestHeight(height, false)
return this
}
suspend fun shieldFunds(): TestWallet {
synchronizer.refreshUtxos(Account.DEFAULT, BlockHeight.new(ZcashNetwork.Mainnet, 935000)).let { count ->
2023-02-06 14:36:28 -08:00
Twig.debug { "FOUND $count new UTXOs" }
}
synchronizer.getTransparentBalance(transparentAddress).let { walletBalance ->
2023-02-06 14:36:28 -08:00
Twig.debug { "FOUND utxo balance of total: ${walletBalance.total} available: ${walletBalance.available}" }
if (walletBalance.available.value > 0L) {
synchronizer.shieldFunds(spendingKey)
}
}
return this
}
suspend fun join(timeout: Long? = null): TestWallet {
// block until stopped
2023-02-06 14:36:28 -08:00
Twig.debug { "Staying alive until synchronizer is stopped!" }
if (timeout != null) {
2023-02-06 14:36:28 -08:00
Twig.debug { "Scheduling a stop in ${timeout}ms" }
walletScope.launch {
delay(timeout)
synchronizer.close()
}
}
synchronizer.status.first { it == Synchronizer.Status.STOPPED }
2023-02-06 14:36:28 -08:00
Twig.debug { "Stopped!" }
return this
}
companion object {
}
enum class Backups(val seedPhrase: String, val testnetBirthday: BlockHeight, val mainnetBirthday: BlockHeight) {
// TODO: [#902] Get the proper birthday values for test wallets
// TODO: [#902] https://github.com/zcash/zcash-android-wallet-sdk/issues/902
DEFAULT(
"column rhythm acoustic gym cost fit keen maze fence seed mail medal shrimp tell relief clip cannon foster soldier shallow refuse lunar parrot banana",
BlockHeight.new(
ZcashNetwork.Testnet,
1_355_928
),
BlockHeight.new(ZcashNetwork.Mainnet, 1_000_000)
),
SAMPLE_WALLET(
"input frown warm senior anxiety abuse yard prefer churn reject people glimpse govern glory crumble swallow verb laptop switch trophy inform friend permit purpose",
BlockHeight.new(
ZcashNetwork.Testnet,
1_330_190
),
BlockHeight.new(ZcashNetwork.Mainnet, 1_000_000)
),
DEV_WALLET(
"still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread",
BlockHeight.new(
ZcashNetwork.Testnet,
1_000_000
),
BlockHeight.new(ZcashNetwork.Mainnet, 991645)
),
ALICE(
"quantum whisper lion route fury lunar pelican image job client hundred sauce chimney barely life cliff spirit admit weekend message recipe trumpet impact kitten",
BlockHeight.new(
ZcashNetwork.Testnet,
1_330_190
),
BlockHeight.new(ZcashNetwork.Mainnet, 1_000_000)
),
BOB(
"canvas wine sugar acquire garment spy tongue odor hole cage year habit bullet make label human unit option top calm neutral try vocal arena",
BlockHeight.new(
ZcashNetwork.Testnet,
1_330_190
),
BlockHeight.new(ZcashNetwork.Mainnet, 1_000_000)
)
}
}