Skip to content

Commit

Permalink
Remove unused TransactionEncoder functions (#1660)
Browse files Browse the repository at this point in the history
  • Loading branch information
HonzaR authored Dec 13, 2024
1 parent 2cb7315 commit abb2c9c
Show file tree
Hide file tree
Showing 6 changed files with 9 additions and 238 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ class SdkSynchronizer private constructor(
}
}

override suspend fun importAccountByUfvk(setup: AccountImportSetup,): Account {
override suspend fun importAccountByUfvk(setup: AccountImportSetup): Account {
val chainTip: BlockHeight? =
when (val response = processor.downloader.getLatestBlockHeight()) {
is Response.Success -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ interface Synchronizer {
*
* @throws [InitializeException.ImportAccountException] in case of the operation failure
*/
suspend fun importAccountByUfvk(setup: AccountImportSetup,): Account
suspend fun importAccountByUfvk(setup: AccountImportSetup): Account

/**
* Adds the next available account-level spend authority, given the current set of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package cash.z.ecc.android.sdk.internal.transaction
import cash.z.ecc.android.sdk.internal.model.EncodedTransaction
import cash.z.ecc.android.sdk.model.Account
import cash.z.ecc.android.sdk.model.Proposal
import cash.z.ecc.android.sdk.model.TransactionRecipient
import cash.z.ecc.android.sdk.model.TransactionSubmitResult
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
import cash.z.ecc.android.sdk.model.Zatoshi
Expand All @@ -15,26 +14,6 @@ import cash.z.ecc.android.sdk.model.Zatoshi
*/
@Suppress("TooManyFunctions")
internal interface OutboundTransactionManager {
/**
* Encode the pending transaction using the given spending key. This is a local operation that
* produces a raw transaction to submit to lightwalletd.
*
* @param usk the unified spending key to use for constructing the transaction.
* @param amount the amount to send.
* @param recipient the recipient of the transaction.
* @param memo the memo to include in the transaction.
* @param account the account to use for the transaction.
*
* @return The encoded transaction, which can be submitted to lightwalletd.
*/
suspend fun encode(
usk: UnifiedSpendingKey,
amount: Zatoshi,
recipient: TransactionRecipient,
memo: String,
account: Account
): EncodedTransaction

/**
* Creates a proposal for transferring funds from a ZIP-321 compliant payment URI
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import cash.z.ecc.android.sdk.internal.ext.toHexReversed
import cash.z.ecc.android.sdk.internal.model.EncodedTransaction
import cash.z.ecc.android.sdk.model.Account
import cash.z.ecc.android.sdk.model.Proposal
import cash.z.ecc.android.sdk.model.TransactionRecipient
import cash.z.ecc.android.sdk.model.TransactionSubmitResult
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
import cash.z.ecc.android.sdk.model.Zatoshi
Expand All @@ -17,40 +16,6 @@ internal class OutboundTransactionManagerImpl(
internal val encoder: TransactionEncoder,
private val service: LightWalletClient
) : OutboundTransactionManager {
override suspend fun encode(
usk: UnifiedSpendingKey,
amount: Zatoshi,
recipient: TransactionRecipient,
memo: String,
account: Account
): EncodedTransaction {
val memoBytes =
if (memo.isBlank()) {
null
} else {
memo.toByteArray()
}
return when (recipient) {
is TransactionRecipient.RecipientAccount -> {
encoder.createShieldingTransaction(
usk = usk,
account = account,
recipient = recipient,
memo = memoBytes
)
}
is TransactionRecipient.RecipientAddress -> {
encoder.createTransaction(
usk = usk,
account = account,
amount = amount,
recipient = recipient,
memo = memoBytes
)
}
}
}

/**
* Creates a proposal for transferring funds from a ZIP-321 compliant payment URI
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,10 @@ import cash.z.ecc.android.sdk.internal.model.EncodedTransaction
import cash.z.ecc.android.sdk.model.Account
import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.Proposal
import cash.z.ecc.android.sdk.model.TransactionRecipient
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
import cash.z.ecc.android.sdk.model.Zatoshi

@Suppress("TooManyFunctions")
internal interface TransactionEncoder {
/**
* Creates a transaction, throwing an exception whenever things are missing. When the provided
* wallet implementation doesn't throw an exception, we wrap the issue into a descriptive
* exception ourselves (rather than using double-bangs for things).
*
* @param usk the unified spending key associated with the notes that will be spent.
* @param amount the amount of zatoshi to send.
* @param toAddress the recipient's address.
* @param memo the optional memo to include as part of the transaction.
*
* @return the successfully encoded transaction or an exception
*/
suspend fun createTransaction(
usk: UnifiedSpendingKey,
account: Account,
amount: Zatoshi,
recipient: TransactionRecipient,
memo: ByteArray? = byteArrayOf()
): EncodedTransaction

/**
* Creates a transaction that shields any transparent funds sent to the given usk's account.
*
* @param usk the unified spending key associated with the transparent funds that will be shielded.
* @param memo the optional memo to include as part of the transaction.
*/
suspend fun createShieldingTransaction(
usk: UnifiedSpendingKey,
account: Account,
recipient: TransactionRecipient,
memo: ByteArray? = byteArrayOf()
): EncodedTransaction

/**
* Creates a proposal for transferring from a valid ZIP-321 Payment URI string
*
Expand Down Expand Up @@ -127,8 +92,7 @@ internal interface TransactionEncoder {
): List<EncodedTransaction>

/**
* Utility function to help with validation. This is not called during [createTransaction]
* because this class asserts that all validation is done externally by the UI, for now.
* Utility function to help with validation.
*
* @param address the address to validate
*
Expand All @@ -137,8 +101,7 @@ internal interface TransactionEncoder {
suspend fun isValidShieldedAddress(address: String): Boolean

/**
* Utility function to help with validation. This is not called during [createTransaction]
* because this class asserts that all validation is done externally by the UI, for now.
* Utility function to help with validation.
*
* @param address the address to validate
*
Expand All @@ -147,8 +110,7 @@ internal interface TransactionEncoder {
suspend fun isValidTransparentAddress(address: String): Boolean

/**
* Utility function to help with validation. This is not called during [createTransaction]
* because this class asserts that all validation is done externally by the UI, for now.
* Utility function to help with validation.
*
* @param address the address to validate
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package cash.z.ecc.android.sdk.internal.transaction

import cash.z.ecc.android.sdk.exception.SdkException
import cash.z.ecc.android.sdk.exception.TransactionEncoderException
import cash.z.ecc.android.sdk.ext.masked
import cash.z.ecc.android.sdk.internal.SaplingParamTool
Expand All @@ -10,80 +9,24 @@ import cash.z.ecc.android.sdk.internal.model.EncodedTransaction
import cash.z.ecc.android.sdk.internal.repository.DerivedDataRepository
import cash.z.ecc.android.sdk.model.Account
import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.FirstClassByteArray
import cash.z.ecc.android.sdk.model.Proposal
import cash.z.ecc.android.sdk.model.TransactionRecipient
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
import cash.z.ecc.android.sdk.model.Zatoshi

/**
* Class responsible for encoding a transaction in a consistent way. This bridges the gap by
* behaving like a stateless API so that callers can request [createTransaction] and receive a
* behaving like a stateless API so that callers can request create a transaction and receive a
* result, even though there are intermediate database interactions.
*
* @property backend the instance of RustBackendWelding to use for creating and validating.
* @property repository the repository that stores information about the transactions being created
* such as the raw bytes and raw txId.
*/
@Suppress("TooManyFunctions")
internal class TransactionEncoderImpl(
private val backend: TypesafeBackend,
private val saplingParamTool: SaplingParamTool,
private val repository: DerivedDataRepository
) : TransactionEncoder {
/**
* Creates a transaction, throwing an exception whenever things are missing. When the provided
* wallet implementation doesn't throw an exception, we wrap the issue into a descriptive
* exception ourselves (rather than using double-bangs for things).
*
* @param usk the unified spending key associated with the notes that will be spent.
* @param amount the amount of zatoshi to send.
* @param recipient the recipient's address.
* @param memo the optional memo to include as part of the transaction.
*
* @return the successfully encoded transaction or an exception
*
* @throws TransactionEncoderException.TransactionNotFoundException in case the encoded transaction not found
*/
override suspend fun createTransaction(
usk: UnifiedSpendingKey,
account: Account,
amount: Zatoshi,
recipient: TransactionRecipient,
memo: ByteArray?
): EncodedTransaction {
require(recipient is TransactionRecipient.RecipientAddress)

val transactionId =
createSpend(
account = account,
amount = amount,
memo = memo,
toAddress = recipient.addressValue,
usk = usk,
)
return repository.findEncodedTransactionByTxId(transactionId)
?: throw TransactionEncoderException.TransactionNotFoundException(transactionId)
}

override suspend fun createShieldingTransaction(
usk: UnifiedSpendingKey,
account: Account,
recipient: TransactionRecipient,
memo: ByteArray?
): EncodedTransaction {
require(recipient is TransactionRecipient.RecipientAccount)

val transactionId =
createShieldingSpend(
account = account,
memo = memo,
usk = usk,
)
return repository.findEncodedTransactionByTxId(transactionId)
?: throw TransactionEncoderException.TransactionNotFoundException(transactionId)
}

/**
* Creates a proposal for transferring from a valid ZIP-321 Payment URI string
*
Expand Down Expand Up @@ -201,8 +144,7 @@ internal class TransactionEncoderImpl(
}

/**
* Utility function to help with validation. This is not called during [createTransaction]
* because this class asserts that all validation is done externally by the UI, for now.
* Utility function to help with validation.
*
* @param address the address to validate
*
Expand All @@ -211,8 +153,7 @@ internal class TransactionEncoderImpl(
override suspend fun isValidShieldedAddress(address: String): Boolean = backend.isValidSaplingAddr(address)

/**
* Utility function to help with validation. This is not called during [createTransaction]
* because this class asserts that all validation is done externally by the UI, for now.
* Utility function to help with validation.
*
* @param address the address to validate
*
Expand All @@ -221,8 +162,7 @@ internal class TransactionEncoderImpl(
override suspend fun isValidTransparentAddress(address: String): Boolean = backend.isValidTransparentAddr(address)

/**
* Utility function to help with validation. This is not called during [createTransaction]
* because this class asserts that all validation is done externally by the UI, for now.
* Utility function to help with validation.
*
* @param address the address to validate
*
Expand Down Expand Up @@ -255,79 +195,4 @@ internal class TransactionEncoderImpl(
}
return backend.getBranchIdForHeight(height)
}

/**
* Does the proofs and processing required to create a transaction to spend funds and inserts
* the result in the database. On average, this call takes over 10 seconds.
*
* @param usk the unified spending key associated with the notes that will be spent.
* @param amount the amount of zatoshi to send.
* @param toAddress the recipient's address.
* @param memo the optional memo to include as part of the transaction.
*
* @return the row id in the transactions table that contains the spend transaction or -1 if it
* failed.
*/
private suspend fun createSpend(
account: Account,
amount: Zatoshi,
memo: ByteArray? = null,
toAddress: String,
usk: UnifiedSpendingKey,
): FirstClassByteArray {
Twig.debug {
"creating transaction to spend $amount zatoshi to" +
" ${toAddress.masked()} with memo: ${memo?.decodeToString()}"
}

return runCatching {
saplingParamTool.ensureParams(saplingParamTool.properties.paramsDirectory)
Twig.debug { "params exist! attempting to send..." }
val proposal =
backend.proposeTransfer(
account,
toAddress,
amount.value,
memo
)
val transactionIds = backend.createProposedTransactions(proposal, usk)
assert(transactionIds.size == 1)
transactionIds[0]
}.onFailure {
Twig.error(it) { "Caught exception while creating transaction." }
}.onSuccess { result ->
Twig.debug { "result of sendToAddress: $result" }
}.getOrThrow()
}

private suspend fun createShieldingSpend(
account: Account,
memo: ByteArray? = null,
usk: UnifiedSpendingKey,
): FirstClassByteArray {
return runCatching {
saplingParamTool.ensureParams(saplingParamTool.properties.paramsDirectory)
Twig.debug { "params exist! attempting to shield..." }
val proposal =
backend.proposeShielding(account, SHIELDING_THRESHOLD, memo)
?: throw SdkException(
"Insufficient balance (have 0, need $SHIELDING_THRESHOLD including fee)",
null
)
val transactionIds = backend.createProposedTransactions(proposal, usk)
assert(transactionIds.size == 1)
transactionIds[0]
}.onFailure {
// TODO [#680]: if this error matches: Insufficient balance (have 0, need 1000 including fee)
// then consider custom error that says no UTXOs existed to shield
// TODO [#680]: https://github.com/zcash/zcash-android-wallet-sdk/issues/680
Twig.error(it) { "Shield failed" }
}.onSuccess { result ->
Twig.debug { "result of shieldToAddress: $result" }
}.getOrThrow()
}

companion object {
private const val SHIELDING_THRESHOLD = 100000L
}
}

0 comments on commit abb2c9c

Please sign in to comment.