New: Begin working on test harness.
For now, just pushing all uncommitted changes to tests. Next sprint we will begin focusing on generating a useful test harness.
This commit is contained in:
parent
05b8d0ddc4
commit
30f7bf0b82
|
@ -0,0 +1,29 @@
|
|||
package cash.z.ecc.android.sdk.integration.darkside.reproduce
|
||||
|
||||
import cash.z.ecc.android.sdk.ext.DarksideTest
|
||||
import org.junit.Before
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Test
|
||||
|
||||
class ReproduceZ2TFailureTest : DarksideTest() {
|
||||
@Before
|
||||
fun setup() {
|
||||
println("dBUG RUNNING")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun once() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun twice() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@BeforeClass
|
||||
fun beforeAll() {
|
||||
println("dBUG BEFOERE IOT ALL")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
package cash.z.ecc.android.sdk.sample
|
||||
|
||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||
import cash.z.ecc.android.sdk.ext.twig
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork.Testnet
|
||||
import cash.z.ecc.android.sdk.util.TestWallet
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
/**
|
||||
* Sample tests are used to demonstrate functionality. This one attempts to setup a scenario where
|
||||
* one wallet shields funds and the other restores from the blockchain. Ultimately, they should have
|
||||
* the same data.
|
||||
*/
|
||||
class TransparentRestoreSample {
|
||||
|
||||
val TX_VALUE = ZcashSdk.MINERS_FEE_ZATOSHI / 2
|
||||
|
||||
// val walletA = SimpleWallet(SEED_PHRASE, "WalletA")
|
||||
|
||||
// the wallet that only restores what everyone else did
|
||||
// val walletB = SimpleWallet(SEED_PHRASE, "WalletB")
|
||||
// // the wallet that sends Z2T transactions
|
||||
//
|
||||
// // sandbox wallet
|
||||
// val walletSandbox = SimpleWallet(SEED_PHRASE, "WalletC")
|
||||
// val walletZ2T = SimpleWallet(SEED_PHRASE, "WalletZ2T")
|
||||
// val externalTransparentAddress =
|
||||
// DerivationTool.deriveTransparentAddress(Mnemonics.MnemonicCode(RANDOM_PHRASE).toSeed(), Testnet)
|
||||
|
||||
// @Test
|
||||
fun sendZ2Texternal() = runBlocking {
|
||||
twig("Syncing WalletExt")
|
||||
val extWallet = TestWallet(TestWallet.Backups.ALICE, alias = "WalletE")
|
||||
extWallet.sync()
|
||||
// extWallet.send(542, walletSandbox.transparentAddress, "External funds memo is lost, though")
|
||||
delay(1000)
|
||||
twig("Done sending funds to external address (Z->T COMPLETE!)")
|
||||
}
|
||||
|
||||
// @Test
|
||||
fun sendZ2T() = runBlocking {
|
||||
// walletSandbox.sync()
|
||||
// walletZ2T.send(543, externalTransparentAddress, "External funds memo is lost, though")
|
||||
delay(1000)
|
||||
twig("Done sending funds to external address (Z->T COMPLETE!)")
|
||||
}
|
||||
|
||||
// @Test
|
||||
fun autoShield() = runBlocking<Unit> {
|
||||
val wallet = TestWallet(TestWallet.Backups.SAMPLE_WALLET, alias = "WalletC")
|
||||
wallet.sync()
|
||||
twig("Done syncing wallet!")
|
||||
val tbalance = wallet.transparentBalance()
|
||||
val address = wallet.transparentAddress
|
||||
|
||||
twig("t-avail: ${tbalance.availableZatoshi} t-total: ${tbalance.totalZatoshi}")
|
||||
Assert.assertTrue("Not enough funds to run sample. Expected some Zatoshi but found ${tbalance.availableZatoshi}. Try adding funds to $address", tbalance.availableZatoshi > 0)
|
||||
|
||||
twig("Shielding available transparent funds!")
|
||||
// wallet.shieldFunds()
|
||||
}
|
||||
|
||||
// @Test
|
||||
fun cli() = runBlocking<Unit> {
|
||||
// val wallet = SimpleWallet(SEED_PHRASE, "WalletCli")
|
||||
// wallet.sync()
|
||||
// wallet.rewindToHeight(1343500).join(45_000)
|
||||
val wallet = TestWallet(TestWallet.Backups.SAMPLE_WALLET, alias = "WalletC")
|
||||
// wallet.sync().rewindToHeight(1339178).join(10000)
|
||||
wallet.sync().rewindToHeight(1339178).send(
|
||||
"ztestsapling17zazsl8rryl8kjaqxnr2r29rw9d9a2mud37ugapm0s8gmyv0ue43h9lqwmhdsp3nu9dazeqfs6l",
|
||||
"is send broken?"
|
||||
).join(5)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun kris() = runBlocking<Unit> {
|
||||
val wallet0 = TestWallet(TestWallet.Backups.SAMPLE_WALLET.seedPhrase, "tmpabc", Testnet, startHeight = 1330190)
|
||||
// val wallet1 = SimpleWallet(WALLET0_PHRASE, "Wallet1")
|
||||
|
||||
wallet0.sync() // .shieldFunds()
|
||||
// .send(amount = 1543L, memo = "")
|
||||
.join()
|
||||
// wallet1.sync().join(5_000L)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sanity check that the wallet has enough funds for the test
|
||||
*/
|
||||
// @Test
|
||||
fun hasFunds() = runBlocking<Unit> {
|
||||
val walletSandbox = TestWallet(TestWallet.Backups.SAMPLE_WALLET.seedPhrase, "WalletC", Testnet, startHeight = 1330190)
|
||||
// val job = walletA.walletScope.launch {
|
||||
// twig("Syncing WalletA")
|
||||
// walletA.sync()
|
||||
// }
|
||||
twig("Syncing WalletSandbox")
|
||||
walletSandbox.sync()
|
||||
// job.join()
|
||||
delay(500)
|
||||
|
||||
twig("Done syncing both wallets!")
|
||||
// val value = walletA.available
|
||||
// val address = walletA.shieldedAddress
|
||||
// Assert.assertTrue("Not enough funds to run sample. Expected at least $TX_VALUE Zatoshi but found $value. Try adding funds to $address", value >= TX_VALUE)
|
||||
|
||||
// send z->t
|
||||
// walletA.send(TX_VALUE, walletA.transparentAddress, "${TransparentRestoreSample::class.java.simpleName} z->t")
|
||||
|
||||
walletSandbox.rewindToHeight(1339178)
|
||||
twig("Done REWINDING!")
|
||||
twig("T-ADDR (for the win!): ${walletSandbox.transparentAddress}")
|
||||
delay(500)
|
||||
// walletB.sync()
|
||||
// rewind database B to height then rescan
|
||||
}
|
||||
|
||||
// // when startHeight is null, it will use the latest checkpoint
|
||||
// class SimpleWallet(
|
||||
// seedPhrase: String,
|
||||
// alias: String = ZcashSdk.DEFAULT_ALIAS,
|
||||
// startHeight: Int? = null
|
||||
// ) {
|
||||
// val walletScope = CoroutineScope(
|
||||
// SupervisorJob() + newFixedThreadPoolContext(3, this.javaClass.simpleName)
|
||||
// )
|
||||
// private val context = InstrumentationRegistry.getInstrumentation().context
|
||||
// private val seed: ByteArray = Mnemonics.MnemonicCode(seedPhrase).toSeed()
|
||||
// private val shieldedSpendingKey = DerivationTool.deriveSpendingKeys(seed, Testnet)[0]
|
||||
// private val transparentSecretKey = DerivationTool.deriveTransparentSecretKey(seed, Testnet)
|
||||
// private val host = "lightwalletd.testnet.electriccoin.co"
|
||||
// private val initializer = Initializer(context) { config ->
|
||||
// config.importWallet(seed, startHeight)
|
||||
// config.setNetwork(Testnet, host)
|
||||
// config.alias = alias
|
||||
// }
|
||||
//
|
||||
// val synchronizer = Synchronizer(initializer)
|
||||
// val available get() = synchronizer.latestBalance.availableZatoshi
|
||||
// val shieldedAddress = DerivationTool.deriveShieldedAddress(seed, Testnet)
|
||||
// val transparentAddress = DerivationTool.deriveTransparentAddress(seed, Testnet)
|
||||
// val birthdayHeight get() = synchronizer.latestBirthdayHeight
|
||||
//
|
||||
// suspend fun transparentBalance(): WalletBalance {
|
||||
// synchronizer.refreshUtxos(transparentAddress, synchronizer.latestBirthdayHeight)
|
||||
// return synchronizer.getTransparentBalance(transparentAddress)
|
||||
// }
|
||||
//
|
||||
// suspend fun sync(): SimpleWallet {
|
||||
// if (!synchronizer.isStarted) {
|
||||
// twig("Starting sync")
|
||||
// synchronizer.start(walletScope)
|
||||
// } else {
|
||||
// twig("Awaiting next SYNCED status")
|
||||
// }
|
||||
//
|
||||
// // block until synced
|
||||
// synchronizer.status.first { it == SYNCED }
|
||||
// twig("Synced!")
|
||||
// return this
|
||||
// }
|
||||
//
|
||||
// suspend fun send(address: String = transparentAddress, memo: String = "", amount: Long = 500L): SimpleWallet {
|
||||
// synchronizer.sendToAddress(shieldedSpendingKey, amount, address, memo)
|
||||
// .takeWhile { it.isPending() }
|
||||
// .collect {
|
||||
// twig("Updated transaction: $it")
|
||||
// }
|
||||
// return this
|
||||
// }
|
||||
//
|
||||
// suspend fun rewindToHeight(height: Int): SimpleWallet {
|
||||
// synchronizer.rewindToHeight(height, false)
|
||||
// return this
|
||||
// }
|
||||
//
|
||||
// suspend fun shieldFunds(): SimpleWallet {
|
||||
// twig("checking $transparentAddress for transactions!")
|
||||
// synchronizer.refreshUtxos(transparentAddress, 935000).let { count ->
|
||||
// twig("FOUND $count new UTXOs")
|
||||
// }
|
||||
//
|
||||
// synchronizer.getTransparentBalance(transparentAddress).let { walletBalance ->
|
||||
// twig("FOUND utxo balance of total: ${walletBalance.totalZatoshi} available: ${walletBalance.availableZatoshi}")
|
||||
//
|
||||
// if (walletBalance.availableZatoshi > 0L) {
|
||||
// synchronizer.shieldFunds(shieldedSpendingKey, transparentSecretKey)
|
||||
// .onCompletion { twig("done shielding funds") }
|
||||
// .catch { twig("Failed with $it") }
|
||||
// .collect()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return this
|
||||
// }
|
||||
//
|
||||
// suspend fun join(timeout: Long? = null): SimpleWallet {
|
||||
// // block until stopped
|
||||
// twig("Staying alive until synchronizer is stopped!")
|
||||
// if (timeout != null) {
|
||||
// twig("Scheduling a stop in ${timeout}ms")
|
||||
// walletScope.launch {
|
||||
// delay(timeout)
|
||||
// synchronizer.stop()
|
||||
// }
|
||||
// }
|
||||
// synchronizer.status.first { it == Synchronizer.Status.STOPPED }
|
||||
// twig("Stopped!")
|
||||
// return this
|
||||
// }
|
||||
//
|
||||
// companion object {
|
||||
// init {
|
||||
// Twig.plant(TroubleshootingTwig())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
|
@ -1,24 +1,17 @@
|
|||
package cash.z.ecc.android.sdk.util
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import cash.z.ecc.android.sdk.Initializer
|
||||
import cash.z.ecc.android.sdk.SdkSynchronizer
|
||||
import cash.z.ecc.android.sdk.Synchronizer
|
||||
import cash.z.ecc.android.sdk.db.entity.isSubmitSuccess
|
||||
import cash.z.ecc.android.sdk.ext.ScopedTest
|
||||
import cash.z.ecc.android.sdk.ext.Twig
|
||||
import cash.z.ecc.android.sdk.ext.seedPhrase
|
||||
import cash.z.ecc.android.sdk.ext.twig
|
||||
import cash.z.ecc.android.sdk.tool.DerivationTool
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
import io.grpc.StatusRuntimeException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
@ -26,11 +19,17 @@ import org.junit.Assert
|
|||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
|
||||
class DarksideTestCoordinator(val host: String = "127.0.0.1", val testName: String = "DarksideTestCoordinator", val network: ZcashNetwork = ZcashNetwork.Mainnet, val port: Int = 9067) {
|
||||
private val birthdayHeight = 663150
|
||||
class DarksideTestCoordinator(val wallet: TestWallet) {
|
||||
constructor(
|
||||
alias: String = "DarksideTestCoordinator",
|
||||
seedPhrase: String = DEFAULT_SEED_PHRASE,
|
||||
startHeight: Int = DEFAULT_START_HEIGHT,
|
||||
host: String = "127.0.0.1",
|
||||
network: ZcashNetwork = ZcashNetwork.Mainnet,
|
||||
port: Int = network.defaultPort,
|
||||
) : this(TestWallet(seedPhrase, alias, network, host, port, startHeight))
|
||||
|
||||
private val targetHeight = 663250
|
||||
private val seedPhrase =
|
||||
"still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
|
||||
private val context = InstrumentationRegistry.getInstrumentation().context
|
||||
|
||||
// dependencies: private
|
||||
|
@ -39,10 +38,10 @@ class DarksideTestCoordinator(val host: String = "127.0.0.1", val testName: Stri
|
|||
// dependencies: public
|
||||
val validator = DarksideTestValidator()
|
||||
val chainMaker = DarksideChainMaker()
|
||||
lateinit var synchronizer: Synchronizer
|
||||
|
||||
val spendingKey: String get() = DerivationTool.deriveSpendingKeys(SimpleMnemonics().toSeed(seedPhrase.toCharArray()), network)[0]
|
||||
|
||||
// wallet delegates
|
||||
val synchronizer get() = wallet.synchronizer
|
||||
val send get() = wallet::send
|
||||
//
|
||||
// High-level APIs
|
||||
//
|
||||
|
@ -77,14 +76,7 @@ class DarksideTestCoordinator(val host: String = "127.0.0.1", val testName: Stri
|
|||
*/
|
||||
fun initiate() {
|
||||
twig("*************** INITIALIZING TEST COORDINATOR (ONLY ONCE) ***********************")
|
||||
val initializer = Initializer(context) { config ->
|
||||
config.setNetwork(network, host, port)
|
||||
config.seedPhrase(seedPhrase, network)
|
||||
config.setBirthdayHeight(birthdayHeight)
|
||||
config.alias = testName
|
||||
}
|
||||
synchronizer = Synchronizer(initializer)
|
||||
val channel = (synchronizer as SdkSynchronizer).channel
|
||||
val channel = synchronizer.channel
|
||||
darkside = DarksideApi(channel)
|
||||
darkside.reset()
|
||||
}
|
||||
|
@ -101,6 +93,7 @@ class DarksideTestCoordinator(val host: String = "127.0.0.1", val testName: Stri
|
|||
synchronizer.start(scope)
|
||||
}
|
||||
|
||||
// redo this as a call to wallet but add delay time to wallet join() function
|
||||
/**
|
||||
* Waits for, at most, the given amount of time for the synchronizer to download and scan blocks
|
||||
* and reach a 'SYNCED' status.
|
||||
|
@ -129,27 +122,19 @@ class DarksideTestCoordinator(val host: String = "127.0.0.1", val testName: Stri
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a transaction and wait until it has been fully created and successfully submitted, which
|
||||
* takes about 10 seconds.
|
||||
*/
|
||||
suspend fun createAndSubmitTx(
|
||||
zatoshi: Long,
|
||||
toAddress: String,
|
||||
memo: String = "",
|
||||
fromAccountIndex: Int = 0
|
||||
) = coroutineScope {
|
||||
Twig.sprout("sending")
|
||||
var job: Job? = null
|
||||
job = synchronizer
|
||||
.sendToAddress(spendingKey, zatoshi, toAddress, memo, fromAccountIndex)
|
||||
.onEach {
|
||||
twig("got an update submitted yet? ${it.isSubmitSuccess()}")
|
||||
if (it.isSubmitSuccess()) job?.cancel()
|
||||
}.launchIn(this)
|
||||
job.join()
|
||||
Twig.clip("sending")
|
||||
}
|
||||
// /**
|
||||
// * Send a transaction and wait until it has been fully created and successfully submitted, which
|
||||
// * takes about 10 seconds.
|
||||
// */
|
||||
// suspend fun createAndSubmitTx(
|
||||
// zatoshi: Long,
|
||||
// toAddress: String,
|
||||
// memo: String = "",
|
||||
// fromAccountIndex: Int = 0
|
||||
// ) = coroutineScope {
|
||||
//
|
||||
// wallet.send(toAddress, memo, zatoshi, fromAccountIndex)
|
||||
// }
|
||||
|
||||
fun stall(delay: Long = 5000L) = runBlocking {
|
||||
twig("*** Stalling for ${delay}ms ***")
|
||||
|
@ -319,5 +304,7 @@ class DarksideTestCoordinator(val host: String = "127.0.0.1", val testName: Stri
|
|||
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 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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,11 +30,12 @@ import java.util.concurrent.TimeoutException
|
|||
* easy to drive and nice to use.
|
||||
*/
|
||||
class TestWallet(
|
||||
seedPhrase: String,
|
||||
alias: String = "TestWallet",
|
||||
network: ZcashNetwork = ZcashNetwork.Testnet,
|
||||
host: String? = null,
|
||||
startHeight: Int? = null
|
||||
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,
|
||||
) {
|
||||
constructor(
|
||||
backup: Backups,
|
||||
|
@ -47,7 +48,6 @@ class TestWallet(
|
|||
alias = alias
|
||||
)
|
||||
|
||||
val hostToUse = host ?: network.defaultHost
|
||||
val walletScope = CoroutineScope(
|
||||
SupervisorJob() + newFixedThreadPoolContext(3, this.javaClass.simpleName)
|
||||
)
|
||||
|
@ -56,7 +56,7 @@ class TestWallet(
|
|||
private val shieldedSpendingKey = DerivationTool.deriveSpendingKeys(seed, network = network)[0]
|
||||
private val transparentSecretKey = DerivationTool.deriveTransparentSecretKey(seed, network = network)
|
||||
val initializer = Initializer(context) { config ->
|
||||
config.importWallet(seed, startHeight, network, hostToUse, alias = alias)
|
||||
config.importWallet(seed, startHeight, network, host, alias = alias)
|
||||
}
|
||||
val synchronizer: SdkSynchronizer = Synchronizer(initializer) as SdkSynchronizer
|
||||
val service = (synchronizer.processor.downloader.lightWalletService as LightWalletGrpcService)
|
||||
|
@ -94,12 +94,14 @@ class TestWallet(
|
|||
return this
|
||||
}
|
||||
|
||||
suspend fun send(address: String = transparentAddress, memo: String = "", amount: Long = 500L): TestWallet {
|
||||
synchronizer.sendToAddress(shieldedSpendingKey, amount, address, memo)
|
||||
suspend fun send(address: String = transparentAddress, memo: String = "", amount: Long = 500L, fromAccountIndex: Int = 0): TestWallet {
|
||||
Twig.sprout("$alias sending")
|
||||
synchronizer.sendToAddress(shieldedSpendingKey, amount, address, memo, fromAccountIndex)
|
||||
.takeWhile { it.isPending() }
|
||||
.collect {
|
||||
twig("Updated transaction: $it")
|
||||
}
|
||||
Twig.clip("$alias sending")
|
||||
return this
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue