Merge branch 'master' into merge_master_to_zip_316
This commit is contained in:
commit
a81a77f494
|
@ -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)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue