2020-08-13 18:08:01 -07:00
|
|
|
package cash.z.ecc.android.sdk.demoapp.demos.listutxos
|
|
|
|
|
2022-07-12 05:40:09 -07:00
|
|
|
import android.content.Context
|
2020-08-13 18:08:01 -07:00
|
|
|
import android.os.Bundle
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
import android.view.View
|
|
|
|
import androidx.lifecycle.lifecycleScope
|
|
|
|
import androidx.recyclerview.widget.LinearLayoutManager
|
|
|
|
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
|
|
|
|
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
|
|
|
|
import cash.z.ecc.android.sdk.db.entity.ConfirmedTransaction
|
|
|
|
import cash.z.ecc.android.sdk.demoapp.BaseDemoFragment
|
|
|
|
import cash.z.ecc.android.sdk.demoapp.databinding.FragmentListUtxosBinding
|
2021-09-04 04:05:41 -07:00
|
|
|
import cash.z.ecc.android.sdk.demoapp.ext.requireApplicationContext
|
|
|
|
import cash.z.ecc.android.sdk.demoapp.util.fromResources
|
2020-08-13 18:08:01 -07:00
|
|
|
import cash.z.ecc.android.sdk.demoapp.util.mainActivity
|
|
|
|
import cash.z.ecc.android.sdk.ext.collectWith
|
2021-10-13 07:20:13 -07:00
|
|
|
import cash.z.ecc.android.sdk.internal.twig
|
2022-07-12 05:40:09 -07:00
|
|
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
2022-08-02 06:29:09 -07:00
|
|
|
import cash.z.ecc.android.sdk.model.LightWalletEndpoint
|
|
|
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
|
|
|
import cash.z.ecc.android.sdk.model.defaultForNetwork
|
2020-09-11 00:16:46 -07:00
|
|
|
import cash.z.ecc.android.sdk.tool.DerivationTool
|
2020-08-13 18:08:01 -07:00
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
import kotlinx.coroutines.delay
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
import kotlinx.coroutines.withContext
|
2022-07-12 05:40:09 -07:00
|
|
|
import kotlin.math.max
|
2020-09-11 01:04:52 -07:00
|
|
|
|
2020-08-13 18:08:01 -07:00
|
|
|
/**
|
2020-09-11 01:04:52 -07:00
|
|
|
* ===============================================================================================
|
|
|
|
* NOTE: this is still a WIP because t-addrs are not officially supported by the SDK yet
|
|
|
|
* ===============================================================================================
|
|
|
|
*
|
|
|
|
*
|
2020-08-13 18:08:01 -07:00
|
|
|
* List all transactions related to the given seed, since the given birthday. This begins by
|
|
|
|
* downloading any missing blocks and then validating and scanning their contents. Once scan is
|
|
|
|
* complete, the transactions are available in the database and can be accessed by any SQL tool.
|
|
|
|
* By default, the SDK uses a PagedTransactionRepository to provide transaction contents from the
|
|
|
|
* database in a paged format that works natively with RecyclerViews.
|
|
|
|
*/
|
2022-08-23 06:49:00 -07:00
|
|
|
@Suppress("TooManyFunctions")
|
2020-08-13 18:08:01 -07:00
|
|
|
class ListUtxosFragment : BaseDemoFragment<FragmentListUtxosBinding>() {
|
2020-09-21 19:43:50 -07:00
|
|
|
private lateinit var seed: ByteArray
|
2020-08-13 18:08:01 -07:00
|
|
|
private lateinit var synchronizer: Synchronizer
|
2022-08-17 06:48:02 -07:00
|
|
|
private lateinit var adapter: UtxoAdapter
|
2020-08-13 18:08:01 -07:00
|
|
|
private val address: String = "t1RwbKka1CnktvAJ1cSqdn7c6PXWG4tZqgd"
|
|
|
|
private var status: Synchronizer.Status? = null
|
|
|
|
|
|
|
|
private val isSynced get() = status == Synchronizer.Status.SYNCED
|
|
|
|
|
|
|
|
override fun inflateBinding(layoutInflater: LayoutInflater): FragmentListUtxosBinding =
|
|
|
|
FragmentListUtxosBinding.inflate(layoutInflater)
|
|
|
|
|
2020-09-21 19:43:50 -07:00
|
|
|
/**
|
|
|
|
* Initialize the required values that would normally live outside the demo but are repeated
|
|
|
|
* here for completeness so that each demo file can serve as a standalone example.
|
|
|
|
*/
|
|
|
|
private fun setup() {
|
|
|
|
// Use a BIP-39 library to convert a seed phrase into a byte array. Most wallets already
|
|
|
|
// have the seed stored
|
|
|
|
seed = Mnemonics.MnemonicCode(sharedViewModel.seedPhrase.value).toSeed()
|
2022-10-06 10:48:21 -07:00
|
|
|
val network = ZcashNetwork.fromResources(requireApplicationContext())
|
|
|
|
synchronizer = Synchronizer.newBlocking(
|
|
|
|
requireApplicationContext(),
|
|
|
|
network,
|
|
|
|
alias = "Demo_Utxos",
|
|
|
|
lightWalletEndpoint = LightWalletEndpoint.defaultForNetwork(network),
|
|
|
|
seed = seed,
|
|
|
|
birthday = null
|
|
|
|
)
|
2020-09-21 19:43:50 -07:00
|
|
|
}
|
|
|
|
|
2021-09-04 04:05:41 -07:00
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
super.onCreate(savedInstanceState)
|
2020-09-21 19:43:50 -07:00
|
|
|
setup()
|
|
|
|
}
|
|
|
|
|
2022-08-17 06:48:02 -07:00
|
|
|
private fun initUi() {
|
2020-08-13 18:08:01 -07:00
|
|
|
binding.inputAddress.setText(address)
|
2022-08-23 06:49:00 -07:00
|
|
|
binding.inputRangeStart.setText(
|
|
|
|
ZcashNetwork.fromResources(requireApplicationContext()).saplingActivationHeight.toString()
|
|
|
|
)
|
2022-07-12 05:40:09 -07:00
|
|
|
binding.inputRangeEnd.setText(getUxtoEndHeight(requireApplicationContext()).value.toString())
|
2020-08-13 18:08:01 -07:00
|
|
|
|
|
|
|
binding.buttonLoad.setOnClickListener {
|
|
|
|
mainActivity()?.hideKeyboard()
|
|
|
|
downloadTransactions()
|
|
|
|
}
|
|
|
|
|
|
|
|
initTransactionUi()
|
|
|
|
}
|
|
|
|
|
2022-08-17 06:48:02 -07:00
|
|
|
private fun downloadTransactions() {
|
2020-08-13 18:08:01 -07:00
|
|
|
binding.textStatus.text = "loading..."
|
|
|
|
binding.textStatus.post {
|
2022-07-12 05:40:09 -07:00
|
|
|
val network = ZcashNetwork.fromResources(requireApplicationContext())
|
2020-08-13 18:08:01 -07:00
|
|
|
binding.textStatus.requestFocus()
|
|
|
|
val addressToUse = binding.inputAddress.text.toString()
|
2022-08-02 06:29:09 -07:00
|
|
|
val startToUse = max(
|
|
|
|
binding.inputRangeStart.text.toString().toLongOrNull()
|
|
|
|
?: network.saplingActivationHeight.value,
|
|
|
|
network.saplingActivationHeight.value
|
|
|
|
)
|
2022-07-12 05:40:09 -07:00
|
|
|
val endToUse = binding.inputRangeEnd.text.toString().toLongOrNull()
|
|
|
|
?: getUxtoEndHeight(requireApplicationContext()).value
|
2020-08-13 18:08:01 -07:00
|
|
|
var allStart = now
|
|
|
|
twig("loading transactions in range $startToUse..$endToUse")
|
2022-08-17 06:48:02 -07:00
|
|
|
val txids = lightWalletService?.getTAddressTransactions(
|
2022-08-02 06:29:09 -07:00
|
|
|
addressToUse,
|
|
|
|
BlockHeight.new(network, startToUse)..BlockHeight.new(network, endToUse)
|
|
|
|
)
|
2020-08-13 18:08:01 -07:00
|
|
|
var delta = now - allStart
|
2020-09-11 00:16:46 -07:00
|
|
|
updateStatus("found ${txids?.size} transactions in ${delta}ms.", false)
|
2020-09-21 19:43:50 -07:00
|
|
|
|
2020-09-11 00:16:46 -07:00
|
|
|
txids?.map {
|
2022-07-12 05:40:09 -07:00
|
|
|
// Disabled during migration to newer SDK version; this appears to have been
|
|
|
|
// leveraging non-public APIs in the SDK so perhaps should be removed
|
|
|
|
// it.data.apply {
|
|
|
|
// try {
|
|
|
|
// runBlocking { initializer.rustBackend.decryptAndStoreTransaction(toByteArray()) }
|
|
|
|
// } catch (t: Throwable) {
|
|
|
|
// twig("failed to decrypt and store transaction due to: $t")
|
|
|
|
// }
|
|
|
|
// }
|
2022-08-17 06:48:02 -07:00
|
|
|
}?.let { _ ->
|
2021-09-04 04:05:41 -07:00
|
|
|
// Disabled during migration to newer SDK version; this appears to have been
|
|
|
|
// leveraging non-public APIs in the SDK so perhaps should be removed
|
2022-08-17 06:48:02 -07:00
|
|
|
// val parseStart = now
|
|
|
|
// val tList = LocalRpcTypes.TransactionDataList.newBuilder().addAllData(txData).build()
|
|
|
|
// val parsedTransactions = initializer.rustBackend.parseTransactionDataList(tList)
|
|
|
|
// delta = now - parseStart
|
|
|
|
// updateStatus("parsed txs in ${delta}ms.")
|
2020-08-13 18:08:01 -07:00
|
|
|
}
|
|
|
|
(synchronizer as SdkSynchronizer).refreshTransactions()
|
|
|
|
delta = now - allStart
|
|
|
|
updateStatus("Total time ${delta}ms.")
|
|
|
|
|
|
|
|
lifecycleScope.launch {
|
|
|
|
withContext(Dispatchers.IO) {
|
|
|
|
finalCount = (synchronizer as SdkSynchronizer).getTransactionCount()
|
|
|
|
withContext(Dispatchers.Main) {
|
2022-08-23 06:49:00 -07:00
|
|
|
@Suppress("MagicNumber")
|
2020-08-13 18:08:01 -07:00
|
|
|
delay(100)
|
|
|
|
updateStatus("Also found ${finalCount - initialCount} shielded txs")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private val now get() = System.currentTimeMillis()
|
|
|
|
|
|
|
|
private fun updateStatus(message: String, append: Boolean = true) {
|
|
|
|
if (append) {
|
|
|
|
binding.textStatus.text = "${binding.textStatus.text} $message"
|
|
|
|
} else {
|
|
|
|
binding.textStatus.text = message
|
|
|
|
}
|
|
|
|
twig(message)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
|
|
super.onViewCreated(view, savedInstanceState)
|
|
|
|
initUi()
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onResume() {
|
|
|
|
super.onResume()
|
|
|
|
resetInBackground()
|
|
|
|
val seed = Mnemonics.MnemonicCode(sharedViewModel.seedPhrase.value).toSeed()
|
2021-10-21 13:05:02 -07:00
|
|
|
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
|
2022-08-02 06:29:09 -07:00
|
|
|
binding.inputAddress.setText(
|
|
|
|
DerivationTool.deriveTransparentAddress(
|
|
|
|
seed,
|
|
|
|
ZcashNetwork.fromResources(requireApplicationContext())
|
|
|
|
)
|
|
|
|
)
|
2021-10-21 13:05:02 -07:00
|
|
|
}
|
2020-08-13 18:08:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var initialCount: Int = 0
|
|
|
|
var finalCount: Int = 0
|
2022-08-23 06:49:00 -07:00
|
|
|
|
|
|
|
@Suppress("TooGenericExceptionCaught")
|
|
|
|
private fun resetInBackground() {
|
2020-08-13 18:08:01 -07:00
|
|
|
try {
|
|
|
|
lifecycleScope.launch {
|
|
|
|
withContext(Dispatchers.IO) {
|
2021-09-04 04:05:41 -07:00
|
|
|
synchronizer.prepare()
|
2020-08-13 18:08:01 -07:00
|
|
|
initialCount = (synchronizer as SdkSynchronizer).getTransactionCount()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
synchronizer.clearedTransactions.collectWith(lifecycleScope, ::onTransactionsUpdated)
|
2022-08-17 06:48:02 -07:00
|
|
|
// synchronizer.receivedTransactions.collectWith(lifecycleScope, ::onTransactionsUpdated)
|
2020-08-13 18:08:01 -07:00
|
|
|
} catch (t: Throwable) {
|
|
|
|
twig("failed to start the synchronizer!!! due to : $t")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fun onResetComplete() {
|
|
|
|
initTransactionUi()
|
|
|
|
startSynchronizer()
|
|
|
|
monitorStatus()
|
|
|
|
}
|
|
|
|
|
|
|
|
fun onClear() {
|
|
|
|
synchronizer.stop()
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun initTransactionUi() {
|
|
|
|
binding.recyclerTransactions.layoutManager =
|
|
|
|
LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
|
|
|
|
adapter = UtxoAdapter()
|
|
|
|
binding.recyclerTransactions.adapter = adapter
|
2022-08-17 06:48:02 -07:00
|
|
|
// lifecycleScope.launch {
|
|
|
|
// address = synchronizer.getAddress()
|
|
|
|
// synchronizer.receivedTransactions.onEach {
|
|
|
|
// onTransactionsUpdated(it)
|
|
|
|
// }.launchIn(this)
|
|
|
|
// }
|
2020-08-13 18:08:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun startSynchronizer() {
|
|
|
|
lifecycleScope.apply {
|
|
|
|
synchronizer.start(this)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun monitorStatus() {
|
|
|
|
synchronizer.status.collectWith(lifecycleScope, ::onStatus)
|
|
|
|
synchronizer.processorInfo.collectWith(lifecycleScope, ::onProcessorInfoUpdated)
|
|
|
|
synchronizer.progress.collectWith(lifecycleScope, ::onProgress)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun onProcessorInfoUpdated(info: CompactBlockProcessor.ProcessorInfo) {
|
|
|
|
if (info.isScanning) binding.textStatus.text = "Scanning blocks...${info.scanProgress}%"
|
|
|
|
}
|
|
|
|
|
2022-08-23 06:49:00 -07:00
|
|
|
@Suppress("MagicNumber")
|
2020-08-13 18:08:01 -07:00
|
|
|
private fun onProgress(i: Int) {
|
|
|
|
if (i < 100) binding.textStatus.text = "Downloading blocks...$i%"
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun onStatus(status: Synchronizer.Status) {
|
|
|
|
this.status = status
|
|
|
|
binding.textStatus.text = "Status: $status"
|
|
|
|
if (isSynced) onSyncComplete()
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun onSyncComplete() {
|
|
|
|
binding.textStatus.visibility = View.INVISIBLE
|
|
|
|
}
|
|
|
|
|
2021-09-04 04:05:41 -07:00
|
|
|
private fun onTransactionsUpdated(transactions: List<ConfirmedTransaction>) {
|
2020-08-13 18:08:01 -07:00
|
|
|
twig("got a new paged list of transactions of size ${transactions.size}")
|
|
|
|
adapter.submitList(transactions)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onActionButtonClicked() {
|
|
|
|
lifecycleScope.launch {
|
|
|
|
withContext(Dispatchers.IO) {
|
|
|
|
twig("current count: ${(synchronizer as SdkSynchronizer).getTransactionCount()}")
|
|
|
|
twig("refreshing transactions")
|
|
|
|
(synchronizer as SdkSynchronizer).refreshTransactions()
|
|
|
|
twig("current count: ${(synchronizer as SdkSynchronizer).getTransactionCount()}")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-12 05:40:09 -07:00
|
|
|
|
|
|
|
@Suppress("MagicNumber")
|
|
|
|
private fun getUxtoEndHeight(context: Context): BlockHeight {
|
|
|
|
return BlockHeight.new(ZcashNetwork.fromResources(context), 968085L)
|
|
|
|
}
|
2020-08-13 18:08:01 -07:00
|
|
|
}
|