[#811] Eliminate suspending function for sending/shielding

This commit is contained in:
Carter Jernigan 2022-12-07 08:36:08 -05:00 committed by Carter Jernigan
parent d4e75e6a5f
commit d9a0e98dc0
3 changed files with 41 additions and 21 deletions

View File

@ -46,6 +46,7 @@ Change Log
- `Synchronizer.shieldFunds` now takes a `UnifiedSpendingKey` instead of separately
encoded Sapling and transparent keys.
- `Synchronizer` methods that previously took an `Int` for account index now take an `Account` object
- `Synchronizer.sendToAddress()` and `Synchronizer.shieldFunds()` return flows that can now be collected multiple times. Prior versions of the SDK had a bug that could submit transactions multiple times if the flow was collected more than once.
### Removed
- `cash.z.ecc.android.sdk`:

View File

@ -71,13 +71,16 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@ -627,41 +630,57 @@ class SdkSynchronizer internal constructor(
override suspend fun getTransparentAddress(account: Account): String =
processor.getTransparentAddress(account)
override suspend fun sendToAddress(
override fun sendToAddress(
usk: UnifiedSpendingKey,
amount: Zatoshi,
toAddress: String,
memo: String
): Flow<PendingTransaction> {
// Emit the placeholder transaction, then switch to monitoring the database
val placeHolderTx = txManager.initSpend(amount, TransactionRecipient.Address(toAddress), memo, usk.account)
// Using a job to ensure that even if the flow is collected multiple times, the transaction is only submitted
// once
val deferred = coroutineScope.async {
// Emit the placeholder transaction, then switch to monitoring the database
val placeHolderTx = txManager.initSpend(amount, TransactionRecipient.Address(toAddress), memo, usk.account)
txManager.encode(usk, placeHolderTx).let { encodedTx ->
txManager.submit(encodedTx)
txManager.encode(usk, placeHolderTx).let { encodedTx ->
txManager.submit(encodedTx)
}
placeHolderTx.id
}
return txManager.monitorById(placeHolderTx.id)
return flow<PendingTransaction> {
val placeHolderTxId = deferred.await()
emitAll(txManager.monitorById(placeHolderTxId))
}
}
override suspend fun shieldFunds(
override fun shieldFunds(
usk: UnifiedSpendingKey,
memo: String
): Flow<PendingTransaction> {
twig("Initializing shielding transaction")
val tAddr = processor.getTransparentAddress(usk.account)
val tBalance = processor.getUtxoCacheBalance(tAddr)
val deferred = coroutineScope.async {
val tAddr = processor.getTransparentAddress(usk.account)
val tBalance = processor.getUtxoCacheBalance(tAddr)
// Emit the placeholder transaction, then switch to monitoring the database
val placeHolderTx = txManager.initSpend(
tBalance.available,
TransactionRecipient.Account(usk.account),
memo,
usk.account
)
val encodedTx = txManager.encode("", usk, placeHolderTx)
txManager.submit(encodedTx)
// Emit the placeholder transaction, then switch to monitoring the database
val placeHolderTx = txManager.initSpend(
tBalance.available,
TransactionRecipient.Account(usk.account),
memo,
usk.account
)
val encodedTx = txManager.encode("", usk, placeHolderTx)
txManager.submit(encodedTx)
return txManager.monitorById(placeHolderTx.id)
placeHolderTx.id
}
return flow<PendingTransaction> {
val placeHolderTxId = deferred.await()
emitAll(txManager.monitorById(placeHolderTxId))
}
}
override suspend fun refreshUtxos(tAddr: String, since: BlockHeight): Int? {

View File

@ -239,14 +239,14 @@ interface Synchronizer {
* 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(
fun sendToAddress(
usk: UnifiedSpendingKey,
amount: Zatoshi,
toAddress: String,
memo: String = ""
): Flow<PendingTransaction>
suspend fun shieldFunds(
fun shieldFunds(
usk: UnifiedSpendingKey,
memo: String = ZcashSdk.DEFAULT_SHIELD_FUNDS_MEMO_PREFIX
): Flow<PendingTransaction>