Merge branch 'master' into merge_master_to_zip_316

This commit is contained in:
Francisco Gindre 2022-09-12 14:00:40 -03:00
commit a81a77f494
3 changed files with 110 additions and 165 deletions

View File

@ -515,26 +515,17 @@ public class SDKSynchronizer: Synchronizer {
let shieldingSpend = try transactionManager.initSpend(zatoshi: tBalance.verified, toAddress: uAddr.stringEncoded, memo: try memo.asMemoBytes(), from: accountIndex) let shieldingSpend = try transactionManager.initSpend(zatoshi: tBalance.verified, toAddress: uAddr.stringEncoded, memo: try memo.asMemoBytes(), from: accountIndex)
transactionManager.encodeShieldingTransaction( // TODO: Task will be removed when this method is changed to async, issue 487, https://github.com/zcash/ZcashLightClientKit/issues/487
xprv: transparentAccountPrivateKey, Task {
pendingTransaction: shieldingSpend do {
) { [weak self] result in let transaction = try await transactionManager.encodeShieldingTransaction(
guard let self = self else { return } xprv: transparentAccountPrivateKey,
pendingTransaction: shieldingSpend
)
switch result { let submittedTx = try await transactionManager.submit(pendingTransaction: transaction)
case .success(let transaction): resultBlock(.success(submittedTx))
self.transactionManager.submit(pendingTransaction: transaction) { submitResult in } catch {
switch submitResult {
case .success(let submittedTx):
resultBlock(.success(submittedTx))
case .failure(let submissionError):
DispatchQueue.main.async {
resultBlock(.failure(submissionError))
}
}
}
case .failure(let error):
resultBlock(.failure(SynchronizerError.uncategorized(underlyingError: error))) resultBlock(.failure(SynchronizerError.uncategorized(underlyingError: error)))
} }
} }
@ -560,22 +551,15 @@ public class SDKSynchronizer: Synchronizer {
from: accountIndex from: accountIndex
) )
transactionManager.encode(spendingKey: spendingKey, pendingTransaction: spend) { [weak self] result in // TODO: Task will be removed when this method is changed to async, issue 487, https://github.com/zcash/ZcashLightClientKit/issues/487
guard let self = self else { return } Task {
switch result { do {
case .success(let transaction): let transaction = try await transactionManager.encode(
self.transactionManager.submit(pendingTransaction: transaction) { submitResult in pendingTransaction: spend
switch submitResult { )
case .success(let submittedTx): let submittedTx = try await transactionManager.submit(pendingTransaction: transaction)
resultBlock(.success(submittedTx)) resultBlock(.success(submittedTx))
case .failure(let submissionError): } catch {
DispatchQueue.main.async {
resultBlock(.failure(submissionError))
}
}
}
case .failure(let error):
resultBlock(.failure(SynchronizerError.uncategorized(underlyingError: error))) resultBlock(.failure(SynchronizerError.uncategorized(underlyingError: error)))
} }
} }

View File

@ -67,142 +67,106 @@ class PersistentTransactionManager: OutboundTransactionManager {
func encodeShieldingTransaction( func encodeShieldingTransaction(
xprv: TransparentAccountPrivKey, xprv: TransparentAccountPrivKey,
pendingTransaction: PendingTransactionEntity, pendingTransaction: PendingTransactionEntity
result: @escaping (Result<PendingTransactionEntity, Error>) -> Void ) async throws -> PendingTransactionEntity {
) { do {
queue.async { [weak self] in let encodedTransaction = try self.encoder.createShieldingTransaction(
guard let self = self else { return } tAccountPrivateKey: xprv,
memoBytes: try pendingTransaction.memo.intoMemoBytes(),
do { from: pendingTransaction.accountIndex
let encodedTransaction = try self.encoder.createShieldingTransaction( )
tAccountPrivateKey: xprv, let transaction = try self.encoder.expandEncodedTransaction(encodedTransaction)
memoBytes: try pendingTransaction.memo.intoMemoBytes(),
from: pendingTransaction.accountIndex var pending = pendingTransaction
) pending.encodeAttempts += 1
let transaction = try self.encoder.expandEncodedTransaction(encodedTransaction) pending.raw = encodedTransaction.raw
pending.rawTransactionId = encodedTransaction.transactionId
var pending = pendingTransaction pending.expiryHeight = transaction.expiryHeight ?? BlockHeight.empty()
pending.encodeAttempts += 1 pending.minedHeight = transaction.minedHeight ?? BlockHeight.empty()
pending.raw = encodedTransaction.raw
pending.rawTransactionId = encodedTransaction.transactionId try self.repository.update(pending)
pending.expiryHeight = transaction.expiryHeight ?? BlockHeight.empty()
pending.minedHeight = transaction.minedHeight ?? BlockHeight.empty() return pending
} catch StorageError.updateFailed {
try self.repository.update(pending) result(.failure(TransactionManagerError.updateFailed(pendingTransaction)))
} catch MemoBytes.Errors.invalidUTF8 {
result(.success(pending)) result(.failure(TransactionManagerError.shieldingEncodingFailed(pendingTransaction, reason: "Memo contains invalid UTF-8 bytes")))
} catch StorageError.updateFailed { } catch MemoBytes.Errors.tooLong(let length) {
DispatchQueue.main.async { result(.failure(TransactionManagerError.shieldingEncodingFailed(pendingTransaction, reason: "Memo is too long. expected 512 bytes, received \(length)")))
result(.failure(TransactionManagerError.updateFailed(pendingTransaction))) } catch {
} result(.failure(error))
} catch MemoBytes.Errors.invalidUTF8 {
DispatchQueue.main.async {
result(.failure(TransactionManagerError.shieldingEncodingFailed(pendingTransaction, reason: "Memo contains invalid UTF-8 bytes")))
}
} catch MemoBytes.Errors.tooLong(let length) {
DispatchQueue.main.async {
result(.failure(TransactionManagerError.shieldingEncodingFailed(pendingTransaction, reason: "Memo is too long. expected 512 bytes, received \(length)")))
}
} catch {
DispatchQueue.main.async {
result(.failure(error))
}
}
} }
} }
func encode( func encode(
spendingKey: SaplingExtendedSpendingKey, spendingKey: String,
pendingTransaction: PendingTransactionEntity, pendingTransaction: PendingTransactionEntity
result: @escaping (Result<PendingTransactionEntity, Error>) -> Void ) async throws -> PendingTransactionEntity {
) { do {
queue.async { [weak self] in let encodedTransaction = try self.encoder.createTransaction(
guard let self = self else { return } spendingKey: spendingKey,
zatoshi: pendingTransaction.intValue,
to: pendingTransaction.toAddress,
memo: pendingTransaction.memo?.asZcashTransactionMemo(),
from: pendingTransaction.accountIndex
)
let transaction = try self.encoder.expandEncodedTransaction(encodedTransaction)
var pending = pendingTransaction
pending.encodeAttempts += 1
pending.raw = encodedTransaction.raw
pending.rawTransactionId = encodedTransaction.transactionId
pending.expiryHeight = transaction.expiryHeight ?? BlockHeight.empty()
pending.minedHeight = transaction.minedHeight ?? BlockHeight.empty()
try self.repository.update(pending)
return pending
} catch StorageError.updateFailed {
throw TransactionManagerError.updateFailed(pendingTransaction)
} catch {
do { do {
try self.updateOnFailure(transaction: pendingTransaction, error: error)
let encodedTransaction = try self.encoder.createTransaction(
spendingKey: spendingKey,
zatoshi: pendingTransaction.value,
to: pendingTransaction.toAddress,
memoBytes: try pendingTransaction.memo.intoMemoBytes(),
from: pendingTransaction.accountIndex
)
let transaction = try self.encoder.expandEncodedTransaction(encodedTransaction)
var pending = pendingTransaction
pending.encodeAttempts += 1
pending.raw = encodedTransaction.raw
pending.rawTransactionId = encodedTransaction.transactionId
pending.expiryHeight = transaction.expiryHeight ?? BlockHeight.empty()
pending.minedHeight = transaction.minedHeight ?? BlockHeight.empty()
try self.repository.update(pending)
result(.success(pending))
} catch StorageError.updateFailed {
DispatchQueue.main.async {
result(.failure(TransactionManagerError.updateFailed(pendingTransaction)))
}
} catch { } catch {
do { throw TransactionManagerError.updateFailed(pendingTransaction)
try self.updateOnFailure(transaction: pendingTransaction, error: error)
} catch {
DispatchQueue.main.async {
result(.failure(TransactionManagerError.updateFailed(pendingTransaction)))
}
}
DispatchQueue.main.async {
result(.failure(error))
}
} }
throw error
} }
} }
func submit( func submit(
pendingTransaction: PendingTransactionEntity, pendingTransaction: PendingTransactionEntity
result: @escaping (Result<PendingTransactionEntity, Error>) -> Void ) async throws -> PendingTransactionEntity {
) {
guard let txId = pendingTransaction.id else { guard let txId = pendingTransaction.id else {
result(.failure(TransactionManagerError.notPending(pendingTransaction)))// this transaction is not stored throw TransactionManagerError.notPending(pendingTransaction) // this transaction is not stored
return
} }
queue.async { [weak self] in do {
guard let self = self else { return } guard let storedTx = try self.repository.find(by: txId) else {
throw TransactionManagerError.notPending(pendingTransaction)
do {
guard let storedTx = try self.repository.find(by: txId) else {
result(.failure(TransactionManagerError.notPending(pendingTransaction)))
return
}
guard !storedTx.isCancelled else {
LoggerProxy.debug("ignoring cancelled transaction \(storedTx)")
result(.failure(TransactionManagerError.cancelled(storedTx)))
return
}
guard let raw = storedTx.raw else {
LoggerProxy.debug("INCONSISTENCY: attempt to send pending transaction \(txId) that has not raw data")
result(.failure(TransactionManagerError.internalInconsistency(storedTx)))
return
}
let response = try self.service.submit(spendTransaction: raw)
let transaction = try self.update(transaction: storedTx, on: response)
guard response.errorCode >= 0 else {
result(.failure(TransactionManagerError.submitFailed(transaction, errorCode: Int(response.errorCode))))
return
}
result(.success(transaction))
} catch {
try? self.updateOnFailure(transaction: pendingTransaction, error: error)
result(.failure(error))
} }
guard !storedTx.isCancelled else {
LoggerProxy.debug("ignoring cancelled transaction \(storedTx)")
throw TransactionManagerError.cancelled(storedTx)
}
guard let raw = storedTx.raw else {
LoggerProxy.debug("INCONSISTENCY: attempt to send pending transaction \(txId) that has not raw data")
throw TransactionManagerError.internalInconsistency(storedTx)
}
let response = try self.service.submit(spendTransaction: raw)
let transaction = try self.update(transaction: storedTx, on: response)
guard response.errorCode >= 0 else {
throw TransactionManagerError.submitFailed(transaction, errorCode: Int(response.errorCode))
}
return transaction
} catch {
try? self.updateOnFailure(transaction: pendingTransaction, error: error)
throw error
} }
} }

View File

@ -23,20 +23,17 @@ protocol OutboundTransactionManager {
func encodeShieldingTransaction( func encodeShieldingTransaction(
xprv: TransparentAccountPrivKey, xprv: TransparentAccountPrivKey,
pendingTransaction: PendingTransactionEntity, pendingTransaction: PendingTransactionEntity
result: @escaping (Result<PendingTransactionEntity, Error>) -> Void ) async throws -> PendingTransactionEntity
)
func encode( func encode(
spendingKey: SaplingExtendedSpendingKey, spendingKey: SaplingExtendedSpendingKey,
pendingTransaction: PendingTransactionEntity, pendingTransaction: PendingTransactionEntity
result: @escaping (Result<PendingTransactionEntity, Error> ) async throws -> PendingTransactionEntity
) -> Void)
func submit( func submit(
pendingTransaction: PendingTransactionEntity, pendingTransaction: PendingTransactionEntity
result: @escaping (Result<PendingTransactionEntity, Error>) -> Void ) async throws -> PendingTransactionEntity
)
func applyMinedHeight( func applyMinedHeight(
pendingTransaction: PendingTransactionEntity, pendingTransaction: PendingTransactionEntity,