v1.9.0-beta01 changes

This commit includes HUSH specific changes starting at v.1.9.0-beta01 release here: https://github.com/zcash/zcash-android-wallet-sdk/releases/tag/v1.9.0-beta01
This commit is contained in:
fekt
2022-11-29 20:19:12 -05:00
parent 1b4660b53b
commit 2225f65ee7
115 changed files with 2335 additions and 1766 deletions

View File

@@ -4,6 +4,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import cash.z.ecc.android.sdk.darkside.test.DarksideTestCoordinator
import cash.z.ecc.android.sdk.darkside.test.ScopedTest
import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.ZcashNetwork
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
@@ -18,12 +20,12 @@ class InboundTxTests : ScopedTest() {
@Test
fun testTargetBlock_scanned() {
validator.validateMinHeightScanned(targetTxBlock - 1)
validator.validateMinHeightScanned(BlockHeight.new(ZcashNetwork.Mainnet, targetTxBlock.value - 1))
}
@Test
fun testLatestHeight() {
validator.validateLatestHeight(targetTxBlock - 1)
validator.validateLatestHeight(BlockHeight.new(ZcashNetwork.Mainnet, targetTxBlock.value - 1))
}
@Test
@@ -40,7 +42,7 @@ class InboundTxTests : ScopedTest() {
validator.validateTxCount(2)
}
private fun addTransactions(targetHeight: Int, vararg txs: String) {
private fun addTransactions(targetHeight: BlockHeight, vararg txs: String) {
val overwriteBlockCount = 5
chainMaker
// .stageEmptyBlocks(targetHeight, overwriteBlockCount)
@@ -78,8 +80,8 @@ class InboundTxTests : ScopedTest() {
"https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/transactions/recv/71935e29127a7de0b96081f4c8a42a9c11584d83adedfaab414362a6f3d965cf.txt"
)
private const val firstBlock = 663150
private const val targetTxBlock = 663188
private val firstBlock = BlockHeight.new(ZcashNetwork.Mainnet, 663150L)
private val targetTxBlock = BlockHeight.new(ZcashNetwork.Mainnet, 663188L)
private const val lastBlockHash = "2fc7b4682f5ba6ba6f86e170b40f0aa9302e1d3becb2a6ee0db611ff87835e4a"
private val sithLord = DarksideTestCoordinator()
private val validator = sithLord.validator
@@ -93,7 +95,7 @@ class InboundTxTests : ScopedTest() {
chainMaker
.resetBlocks(blocksUrl, startHeight = firstBlock, tipHeight = targetTxBlock)
.stageEmptyBlocks(firstBlock + 1, 100)
.applyTipHeight(targetTxBlock - 1)
.applyTipHeight(BlockHeight.new(ZcashNetwork.Mainnet, targetTxBlock.value - 1))
sithLord.synchronizer.start(classScope)
sithLord.await()

View File

@@ -3,6 +3,8 @@ package cash.z.ecc.android.sdk.darkside.reorgs
import androidx.test.ext.junit.runners.AndroidJUnit4
import cash.z.ecc.android.sdk.darkside.test.DarksideTestCoordinator
import cash.z.ecc.android.sdk.darkside.test.ScopedTest
import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.ZcashNetwork
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
@@ -11,8 +13,8 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ReorgSetupTest : ScopedTest() {
private val birthdayHeight = 663150
private val targetHeight = 663250
private val birthdayHeight = BlockHeight.new(ZcashNetwork.Mainnet, 663150)
private val targetHeight = BlockHeight.new(ZcashNetwork.Mainnet, 663250)
@Before
fun setup() {

View File

@@ -4,6 +4,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import cash.z.ecc.android.sdk.darkside.test.DarksideTestCoordinator
import cash.z.ecc.android.sdk.darkside.test.ScopedTest
import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.ZcashNetwork
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.BeforeClass
@@ -13,7 +15,10 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ReorgSmallTest : ScopedTest() {
private val targetHeight = 663250
private val targetHeight = BlockHeight.new(
ZcashNetwork.Mainnet,
663250
)
private val hashBeforeReorg = "09ec0d5de30d290bc5a2318fbf6a2427a81c7db4790ce0e341a96aeac77108b9"
private val hashAfterReorg = "tbd"

View File

@@ -1,10 +1,12 @@
package cash.z.ecc.android.sdk.darkside.test
import android.content.Context
import cash.z.ecc.android.sdk.R
import cash.z.ecc.android.sdk.internal.service.LightWalletGrpcService
import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.type.ZcashNetwork
import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.Darkside
import cash.z.ecc.android.sdk.model.LightWalletEndpoint
import cash.z.ecc.android.sdk.model.ZcashNetwork
import cash.z.wallet.sdk.rpc.Darkside
import cash.z.wallet.sdk.rpc.Darkside.DarksideTransactionsURL
import cash.z.wallet.sdk.rpc.DarksideStreamerGrpc
@@ -22,17 +24,11 @@ class DarksideApi(
constructor(
appContext: Context,
host: String,
port: Int = ZcashNetwork.Mainnet.defaultPort,
usePlainText: Boolean = appContext.resources.getBoolean(
R.bool.lightwalletd_allow_very_insecure_connections
)
lightWalletEndpoint: LightWalletEndpoint
) : this(
LightWalletGrpcService.createDefaultChannel(
appContext,
host,
port,
usePlainText
lightWalletEndpoint
)
)
@@ -41,7 +37,7 @@ class DarksideApi(
//
fun reset(
saplingActivationHeight: Int = 419200,
saplingActivationHeight: BlockHeight = ZcashNetwork.Mainnet.saplingActivationHeight,
branchId: String = "e9ff75a6", // Canopy,
chainName: String = "darkside${ZcashNetwork.Mainnet.networkName}"
) = apply {
@@ -49,7 +45,7 @@ class DarksideApi(
Darkside.DarksideMetaState.newBuilder()
.setBranchID(branchId)
.setChainName(chainName)
.setSaplingActivation(saplingActivationHeight)
.setSaplingActivation(saplingActivationHeight.value.toInt())
.build().let { request ->
createStub().reset(request)
}
@@ -60,21 +56,21 @@ class DarksideApi(
createStub().stageBlocks(url.toUrl())
}
fun stageTransactions(url: String, targetHeight: Int) = apply {
fun stageTransactions(url: String, targetHeight: BlockHeight) = apply {
twig("staging transaction at height=$targetHeight from url=$url")
createStub().stageTransactions(
DarksideTransactionsURL.newBuilder().setHeight(targetHeight).setUrl(url).build()
DarksideTransactionsURL.newBuilder().setHeight(targetHeight.value).setUrl(url).build()
)
}
fun stageEmptyBlocks(startHeight: Int, count: Int = 10, nonce: Int = Random.nextInt()) = apply {
fun stageEmptyBlocks(startHeight: BlockHeight, count: Int = 10, nonce: Int = Random.nextInt()) = apply {
twig("staging $count empty blocks starting at $startHeight with nonce $nonce")
createStub().stageBlocksCreate(
Darkside.DarksideEmptyBlocks.newBuilder().setHeight(startHeight).setCount(count).setNonce(nonce).build()
Darkside.DarksideEmptyBlocks.newBuilder().setHeight(startHeight.value).setCount(count).setNonce(nonce).build()
)
}
fun stageTransactions(txs: Iterator<Service.RawTransaction>?, tipHeight: Int) {
fun stageTransactions(txs: Iterator<Service.RawTransaction>?, tipHeight: BlockHeight) {
if (txs == null) {
twig("no transactions to stage")
return
@@ -84,7 +80,7 @@ class DarksideApi(
createStreamingStub().stageTransactionsStream(response).apply {
txs.forEach {
twig("stageTransactions: onNext calling!!!")
onNext(it.newBuilderForType().setData(it.data).setHeight(tipHeight.toLong()).build()) // apply the tipHeight because the passed in txs might not know their destination height (if they were created via SendTransaction)
onNext(it.newBuilderForType().setData(it.data).setHeight(tipHeight.value).build()) // apply the tipHeight because the passed in txs might not know their destination height (if they were created via SendTransaction)
twig("stageTransactions: onNext called")
}
twig("stageTransactions: onCompleted calling!!!")
@@ -94,7 +90,7 @@ class DarksideApi(
response.await()
}
fun applyBlocks(tipHeight: Int) {
fun applyBlocks(tipHeight: BlockHeight) {
twig("applying blocks up to tipHeight=$tipHeight")
createStub().applyStaged(tipHeight.toHeight())
}
@@ -146,7 +142,7 @@ class DarksideApi(
.withDeadlineAfter(singleRequestTimeoutSec, TimeUnit.SECONDS)
private fun String.toUrl() = Darkside.DarksideBlocksURL.newBuilder().setUrl(this).build()
private fun Int.toHeight() = Darkside.DarksideHeight.newBuilder().setHeight(this).build()
private fun BlockHeight.toHeight() = Darkside.DarksideHeight.newBuilder().setHeight(this.value).build()
class EmptyResponse : StreamObserver<Service.Empty> {
var completed = false

View File

@@ -4,7 +4,10 @@ import androidx.test.platform.app.InstrumentationRegistry
import cash.z.ecc.android.sdk.SdkSynchronizer
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.type.ZcashNetwork
import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.Darkside
import cash.z.ecc.android.sdk.model.LightWalletEndpoint
import cash.z.ecc.android.sdk.model.ZcashNetwork
import io.grpc.StatusRuntimeException
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.filter
@@ -14,19 +17,19 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
class DarksideTestCoordinator(val wallet: TestWallet) {
constructor(
alias: String = "DarksideTestCoordinator",
seedPhrase: String = DEFAULT_SEED_PHRASE,
startHeight: Int = DEFAULT_START_HEIGHT,
host: String = COMPUTER_LOCALHOST,
startHeight: BlockHeight = DEFAULT_START_HEIGHT,
network: ZcashNetwork = ZcashNetwork.Mainnet,
port: Int = network.defaultPort
) : this(TestWallet(seedPhrase, alias, network, host, startHeight = startHeight, port = port))
endpoint: LightWalletEndpoint = LightWalletEndpoint.Darkside
) : this(TestWallet(seedPhrase, alias, network, endpoint, startHeight = startHeight))
private val targetHeight = 663250
private val targetHeight = BlockHeight.new(wallet.network, 663250)
private val context = InstrumentationRegistry.getInstrumentation().context
// dependencies: private
@@ -91,20 +94,20 @@ class DarksideTestCoordinator(val wallet: TestWallet) {
* Waits for, at most, the given amount of time for the synchronizer to download and scan blocks
* and reach a 'SYNCED' status.
*/
fun await(timeout: Long = 60_000L, targetHeight: Int = -1) = runBlocking {
fun await(timeout: Long = 60_000L, targetHeight: BlockHeight? = null) = runBlocking {
ScopedTest.timeoutWith(this, timeout) {
twig("*** Waiting up to ${timeout / 1_000}s for sync ***")
synchronizer.status.onEach {
twig("got processor status $it")
if (it == Synchronizer.Status.DISCONNECTED) {
twig("waiting a bit before giving up on connection...")
} else if (targetHeight != -1 && (synchronizer as SdkSynchronizer).processor.getLastScannedHeight() < targetHeight) {
} else if (targetHeight != null && (synchronizer as SdkSynchronizer).processor.getLastScannedHeight() < targetHeight) {
twig("awaiting new blocks from server...")
}
}.map {
// whenever we're waiting for a target height, for simplicity, if we're sleeping,
// and in between polls, then consider it that we're not synced
if (targetHeight != -1 && (synchronizer as SdkSynchronizer).processor.getLastScannedHeight() < targetHeight) {
if (targetHeight != null && (synchronizer as SdkSynchronizer).processor.getLastScannedHeight() < targetHeight) {
twig("switching status to DOWNLOADING because we're still waiting for height $targetHeight")
Synchronizer.Status.DOWNLOADING
} else {
@@ -140,14 +143,14 @@ class DarksideTestCoordinator(val wallet: TestWallet) {
inner class DarksideTestValidator {
fun validateHasBlock(height: Int) {
fun validateHasBlock(height: BlockHeight) {
runBlocking {
assertTrue((synchronizer as SdkSynchronizer).findBlockHashAsHex(height) != null)
assertTrue((synchronizer as SdkSynchronizer).findBlockHash(height)?.size ?: 0 > 0)
}
}
fun validateLatestHeight(height: Int) = runBlocking<Unit> {
fun validateLatestHeight(height: BlockHeight) = runBlocking<Unit> {
val info = synchronizer.processorInfo.first()
val networkBlockHeight = info.networkBlockHeight
assertTrue(
@@ -157,41 +160,44 @@ class DarksideTestCoordinator(val wallet: TestWallet) {
)
}
fun validateMinHeightDownloaded(minHeight: Int) = runBlocking<Unit> {
fun validateMinHeightDownloaded(minHeight: BlockHeight) = runBlocking<Unit> {
val info = synchronizer.processorInfo.first()
val lastDownloadedHeight = info.lastDownloadedHeight
assertNotNull(lastDownloadedHeight)
assertTrue(
"Expected to have at least downloaded $minHeight but the last downloaded block was" +
" $lastDownloadedHeight! Full details: $info",
lastDownloadedHeight >= minHeight
lastDownloadedHeight!! >= minHeight
)
}
fun validateMinHeightScanned(minHeight: Int) = runBlocking<Unit> {
fun validateMinHeightScanned(minHeight: BlockHeight) = runBlocking<Unit> {
val info = synchronizer.processorInfo.first()
val lastScannedHeight = info.lastScannedHeight
assertNotNull(lastScannedHeight)
assertTrue(
"Expected to have at least scanned $minHeight but the last scanned block was" +
" $lastScannedHeight! Full details: $info",
lastScannedHeight >= minHeight
lastScannedHeight!! >= minHeight
)
}
fun validateMaxHeightScanned(maxHeight: Int) = runBlocking<Unit> {
fun validateMaxHeightScanned(maxHeight: BlockHeight) = runBlocking<Unit> {
val lastDownloadedHeight = synchronizer.processorInfo.first().lastScannedHeight
assertNotNull(lastDownloadedHeight)
assertTrue(
"Did not expect to be synced beyond $maxHeight but we are synced to" +
" $lastDownloadedHeight",
lastDownloadedHeight <= maxHeight
lastDownloadedHeight!! <= maxHeight
)
}
fun validateBlockHash(height: Int, expectedHash: String) {
fun validateBlockHash(height: BlockHeight, expectedHash: String) {
val hash = runBlocking { (synchronizer as SdkSynchronizer).findBlockHashAsHex(height) }
assertEquals(expectedHash, hash)
}
fun onReorg(callback: (errorHeight: Int, rewindHeight: Int) -> Unit) {
fun onReorg(callback: (errorHeight: BlockHeight, rewindHeight: BlockHeight) -> Unit) {
synchronizer.onChainErrorHandler = callback
}
@@ -225,7 +231,7 @@ class DarksideTestCoordinator(val wallet: TestWallet) {
//
inner class DarksideChainMaker {
var lastTipHeight = -1
var lastTipHeight: BlockHeight? = null
/**
* Resets the darksidelightwalletd server, stages the blocks represented by the given URL, then
@@ -233,8 +239,8 @@ class DarksideTestCoordinator(val wallet: TestWallet) {
*/
fun resetBlocks(
blocksUrl: String,
startHeight: Int = DEFAULT_START_HEIGHT,
tipHeight: Int = startHeight + 100
startHeight: BlockHeight = DEFAULT_START_HEIGHT,
tipHeight: BlockHeight = startHeight + 100
): DarksideChainMaker = apply {
darkside
.reset(startHeight)
@@ -242,23 +248,23 @@ class DarksideTestCoordinator(val wallet: TestWallet) {
applyTipHeight(tipHeight)
}
fun stageTransaction(url: String, targetHeight: Int): DarksideChainMaker = apply {
fun stageTransaction(url: String, targetHeight: BlockHeight): DarksideChainMaker = apply {
darkside.stageTransactions(url, targetHeight)
}
fun stageTransactions(targetHeight: Int, vararg urls: String): DarksideChainMaker = apply {
fun stageTransactions(targetHeight: BlockHeight, vararg urls: String): DarksideChainMaker = apply {
urls.forEach {
darkside.stageTransactions(it, targetHeight)
}
}
fun stageEmptyBlocks(startHeight: Int, count: Int = 10): DarksideChainMaker = apply {
fun stageEmptyBlocks(startHeight: BlockHeight, count: Int = 10): DarksideChainMaker = apply {
darkside.stageEmptyBlocks(startHeight, count)
}
fun stageEmptyBlock() = stageEmptyBlocks(lastTipHeight + 1, 1)
fun stageEmptyBlock() = stageEmptyBlocks(lastTipHeight!! + 1, 1)
fun applyTipHeight(tipHeight: Int): DarksideChainMaker = apply {
fun applyTipHeight(tipHeight: BlockHeight): DarksideChainMaker = apply {
twig("applying tip height of $tipHeight")
darkside.applyBlocks(tipHeight)
lastTipHeight = tipHeight
@@ -277,14 +283,14 @@ class DarksideTestCoordinator(val wallet: TestWallet) {
}
fun advanceBy(numEmptyBlocks: Int) {
val nextBlock = lastTipHeight + 1
val nextBlock = lastTipHeight!! + 1
twig("adding $numEmptyBlocks empty blocks to the chain starting at $nextBlock")
darkside.stageEmptyBlocks(nextBlock, numEmptyBlocks)
applyTipHeight(nextBlock + numEmptyBlocks)
}
fun applyPendingTransactions(targetHeight: Int = lastTipHeight + 1) {
stageEmptyBlocks(lastTipHeight + 1, targetHeight - lastTipHeight)
fun applyPendingTransactions(targetHeight: BlockHeight = lastTipHeight!! + 1) {
stageEmptyBlocks(lastTipHeight!! + 1, (targetHeight.value - lastTipHeight!!.value).toInt())
darkside.stageTransactions(darkside.getSentTransactions()?.iterator(), targetHeight)
applyTipHeight(targetHeight)
}
@@ -304,7 +310,7 @@ class DarksideTestCoordinator(val wallet: TestWallet) {
"https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/after-small-reorg.txt"
private const val largeReorg =
"https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/after-large-reorg.txt"
private const val DEFAULT_START_HEIGHT = 663150
private val DEFAULT_START_HEIGHT = BlockHeight.new(ZcashNetwork.Mainnet, 663150)
private const val DEFAULT_SEED_PHRASE =
"still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
}

View File

@@ -10,10 +10,13 @@ import cash.z.ecc.android.sdk.db.entity.isPending
import cash.z.ecc.android.sdk.internal.Twig
import cash.z.ecc.android.sdk.internal.service.LightWalletGrpcService
import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.Darkside
import cash.z.ecc.android.sdk.model.LightWalletEndpoint
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.DerivationTool
import cash.z.ecc.android.sdk.type.WalletBalance
import cash.z.ecc.android.sdk.type.ZcashNetwork
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
@@ -35,9 +38,8 @@ class TestWallet(
val seedPhrase: String,
val alias: String = "TestWallet",
val network: ZcashNetwork = ZcashNetwork.Testnet,
val host: String = network.defaultHost,
startHeight: Int? = null,
val port: Int = network.defaultPort
val endpoint: LightWalletEndpoint = LightWalletEndpoint.Darkside,
startHeight: BlockHeight? = null
) {
constructor(
backup: Backups,
@@ -65,7 +67,7 @@ class TestWallet(
runBlocking { DerivationTool.deriveTransparentSecretKey(seed, network = network) }
val initializer = runBlocking {
Initializer.new(context) { config ->
runBlocking { config.importWallet(seed, startHeight, network, host, alias = alias) }
runBlocking { config.importWallet(seed, startHeight, network, endpoint, alias = alias) }
}
}
val synchronizer: SdkSynchronizer = runBlocking { Synchronizer.new(initializer) } as SdkSynchronizer
@@ -78,14 +80,11 @@ class TestWallet(
runBlocking { DerivationTool.deriveTransparentAddress(seed, network = network) }
val birthdayHeight get() = synchronizer.latestBirthdayHeight
val networkName get() = synchronizer.network.networkName
val connectionInfo get() = service.connectionInfo.toString()
/* NOT SUPPORTED IN HUSH LIGHTWALLETD
suspend fun transparentBalance(): WalletBalance {
synchronizer.refreshUtxos(transparentAddress, synchronizer.latestBirthdayHeight)
return synchronizer.getTransparentBalance(transparentAddress)
}
*/
suspend fun sync(timeout: Long = -1): TestWallet {
val killSwitch = walletScope.launch {
@@ -111,7 +110,7 @@ class TestWallet(
suspend fun send(address: String = transparentAddress, memo: String = "", amount: Zatoshi = Zatoshi(500L), fromAccountIndex: Int = 0): TestWallet {
Twig.sprout("$alias sending")
synchronizer.sendToAddress(shieldedSpendingKey, amount, address, memo, fromAccountIndex)
.takeWhile { it.isPending() }
.takeWhile { it.isPending(null) }
.collect {
twig("Updated transaction: $it")
}
@@ -119,15 +118,14 @@ class TestWallet(
return this
}
suspend fun rewindToHeight(height: Int): TestWallet {
suspend fun rewindToHeight(height: BlockHeight): TestWallet {
synchronizer.rewindToNearestHeight(height, false)
return this
}
/* NOT SUPPORTED IN HUSH LIGHTWALLETD
suspend fun shieldFunds(): TestWallet {
twig("checking $transparentAddress for transactions!")
synchronizer.refreshUtxos(transparentAddress, 935000).let { count ->
synchronizer.refreshUtxos(transparentAddress, BlockHeight.new(ZcashNetwork.Mainnet, 935000)).let { count ->
twig("FOUND $count new UTXOs")
}
@@ -144,7 +142,6 @@ class TestWallet(
return this
}
*/
suspend fun join(timeout: Long? = null): TestWallet {
// block until stopped
@@ -167,13 +164,48 @@ class TestWallet(
}
}
enum class Backups(val seedPhrase: String, val testnetBirthday: Int, val mainnetBirthday: Int) {
enum class Backups(val seedPhrase: String, val testnetBirthday: BlockHeight, val mainnetBirthday: BlockHeight) {
// TODO: get the proper birthday values for these wallets
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", 1_355_928, 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", 1_330_190, 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", 1_000_000, 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", 1_330_190, 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", 1_330_190, 1_000_000),
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)
),
;
}
}