Merge pull request #536 from LukasKorba/486_sendToAddress_async_await

[#486] sendToAddress async/await
This commit is contained in:
Francisco Gindre 2022-09-23 12:08:31 -07:00 committed by GitHub
commit 28985a4e38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1046 additions and 882 deletions

View File

@ -79,25 +79,21 @@ class SaplingParametersViewController: UIViewController {
@IBAction func download(_ sender: Any) { @IBAction func download(_ sender: Any) {
let outputParameter = try! outputParamsURLHelper() let outputParameter = try! outputParamsURLHelper()
let spendParameter = try! spendParamsURLHelper() let spendParameter = try! spendParamsURLHelper()
SaplingParameterDownloader.downloadParamsIfnotPresent(
spendURL: spendParameter, Task { @MainActor in
outputURL: outputParameter, do {
result: { result in let urls = try await SaplingParameterDownloader.downloadParamsIfnotPresent(
DispatchQueue.main.async { [weak self] in spendURL: spendParameter,
guard let self = self else { return } outputURL: outputParameter
switch result { )
case .success(let urls): spendPath.text = urls.spend.path
self.spendPath.text = urls.spend.path outputPath.text = urls.output.path
self.outputPath.text = urls.output.path updateColor()
self.updateColor() updateButtons()
self.updateButtons() } catch {
showError(error)
case .failure(let error):
self.showError(error)
}
}
} }
) }
} }
func fileExists(_ path: String) -> Bool { func fileExists(_ path: String) -> Bool {

View File

@ -214,26 +214,20 @@ class SendViewController: UIViewController {
KRProgressHUD.show() KRProgressHUD.show()
synchronizer.sendToAddress( Task { @MainActor in
spendingKey: address, do {
zatoshi: zec, let pendingTransaction = try await synchronizer.sendToAddress(
toAddress: recipient, spendingKey: address,
memo: !self.memoField.text.isEmpty ? self.memoField.text : nil, zatoshi: zec,
from: 0 toAddress: recipient,
) { [weak self] result in memo: !self.memoField.text.isEmpty ? self.memoField.text : nil,
DispatchQueue.main.async { from: 0
)
KRProgressHUD.dismiss() KRProgressHUD.dismiss()
}
switch result {
case .success(let pendingTransaction):
loggerProxy.info("transaction created: \(pendingTransaction)") loggerProxy.info("transaction created: \(pendingTransaction)")
} catch {
case .failure(let error): fail(error)
DispatchQueue.main.async { loggerProxy.error("SEND FAILED: \(error)")
self?.fail(error)
loggerProxy.error("SEND FAILED: \(error)")
}
} }
} }
} }

View File

@ -320,48 +320,35 @@ public class Initializer {
FileManager.default.isReadableFile(atPath: self.outputParamsURL.path) FileManager.default.isReadableFile(atPath: self.outputParamsURL.path)
} }
func downloadParametersIfNeeded(result: @escaping (Result<Bool, Error>) -> Void) { @discardableResult
func downloadParametersIfNeeded() async throws -> Bool {
let spendParameterPresent = isSpendParameterPresent() let spendParameterPresent = isSpendParameterPresent()
let outputParameterPresent = isOutputParameterPresent() let outputParameterPresent = isOutputParameterPresent()
if spendParameterPresent && outputParameterPresent { if spendParameterPresent && outputParameterPresent {
result(.success(true)) return true
return
} }
let outputURL = self.outputParamsURL let outputURL = self.outputParamsURL
let spendURL = self.spendParamsURL let spendURL = self.spendParamsURL
if !outputParameterPresent { do {
SaplingParameterDownloader.downloadOutputParameter(outputURL) { outputResult in if !outputParameterPresent && !spendParameterPresent {
switch outputResult { async let outputURLRequest = SaplingParameterDownloader.downloadOutputParameter(outputURL)
case .failure(let error): async let spendURLRequest = SaplingParameterDownloader.downloadSpendParameter(spendURL)
result(.failure(error)) _ = try await [outputURLRequest, spendURLRequest]
case .success: return false
guard !spendParameterPresent else { } else if !outputParameterPresent {
result(.success(false)) try await SaplingParameterDownloader.downloadOutputParameter(outputURL)
return return false
} } else if !spendParameterPresent {
SaplingParameterDownloader.downloadSpendParameter(spendURL) { spendResult in try await SaplingParameterDownloader.downloadSpendParameter(spendURL)
switch spendResult { return false
case .failure(let error):
result(.failure(error))
case .success:
result(.success(false))
}
}
}
}
} else if !spendParameterPresent {
SaplingParameterDownloader.downloadSpendParameter(spendURL) { spendResult in
switch spendResult {
case .failure(let error):
result(.failure(error))
case .success:
result(.success(false))
}
} }
} catch {
throw error
} }
return true
} }
} }

View File

@ -107,40 +107,20 @@ public protocol Synchronizer {
/// - Parameter accountIndex: the optional accountId whose address is of interest. By default, the first account is used. /// - Parameter accountIndex: the optional accountId whose address is of interest. By default, the first account is used.
/// - Returns the address or nil if account index is incorrect /// - Returns the address or nil if account index is incorrect
func getTransparentAddress(accountIndex: Int) -> TransparentAddress? func getTransparentAddress(accountIndex: Int) -> TransparentAddress?
/// Sends zatoshi.
/// - Parameter spendingKey: the key that allows spends to occur.
/// - Parameter zatoshi: the amount of zatoshi to send.
/// - Parameter toAddress: the recipient's address.
/// - Parameter memo: the optional memo to include as part of the transaction.
/// - Parameter accountIndex: the optional account id to use. By default, the first account is used.
@available(*, deprecated, message: "This function will be removed soon, use the one reveiving a `Zatoshi` value instead")
// swiftlint:disable:next function_parameter_count
func sendToAddress(
spendingKey: String,
zatoshi: Int64,
toAddress: String,
memo: String?,
from accountIndex: Int,
resultBlock: @escaping (_ result: Result<PendingTransactionEntity, Error>) -> Void
)
/// Sends zatoshi. /// Sends zatoshi.
/// - Parameter spendingKey: the key that allows spends to occur. /// - Parameter spendingKey: the key that allows spends to occur.
/// - Parameter zatoshi: the amount to send in Zatoshi. /// - Parameter zatoshi: the amount to send in Zatoshi.
/// - Parameter toAddress: the recipient's address. /// - Parameter toAddress: the recipient's address.
/// - Parameter memo: the optional memo to include as part of the transaction. /// - Parameter memo: the optional memo to include as part of the transaction.
/// - Parameter accountIndex: the optional account id to use. By default, the first account is used. /// - Parameter accountIndex: the optional account id to use. By default, the first account is used.
// swiftlint:disable:next function_parameter_count
func sendToAddress( func sendToAddress(
spendingKey: String, spendingKey: String,
zatoshi: Zatoshi, zatoshi: Zatoshi,
toAddress: String, toAddress: String,
memo: String?, memo: String?,
from accountIndex: Int, from accountIndex: Int
resultBlock: @escaping (_ result: Result<PendingTransactionEntity, Error>) -> Void ) async throws -> PendingTransactionEntity
)
/// Shields zatoshi. /// Shields zatoshi.
/// - Parameter spendingKey: the key that allows spends to occur. /// - Parameter spendingKey: the key that allows spends to occur.

View File

@ -455,52 +455,27 @@ public class SDKSynchronizer: Synchronizer {
} }
// MARK: Synchronizer methods // MARK: Synchronizer methods
@available(*, deprecated, message: "This function will be removed soon, use the one reveiving a `Zatoshi` value instead")
public func sendToAddress(
spendingKey: String,
zatoshi: Int64,
toAddress: String,
memo: String?,
from accountIndex: Int,
resultBlock: @escaping (Result<PendingTransactionEntity, Error>) -> Void
) {
sendToAddress(
spendingKey: spendingKey,
zatoshi: Zatoshi(zatoshi),
toAddress: toAddress,
memo: memo,
from: accountIndex,
resultBlock: resultBlock
)
}
// swiftlint:disable:next function_parameter_count
public func sendToAddress( public func sendToAddress(
spendingKey: String, spendingKey: String,
zatoshi: Zatoshi, zatoshi: Zatoshi,
toAddress: String, toAddress: String,
memo: String?, memo: String?,
from accountIndex: Int, from accountIndex: Int
resultBlock: @escaping (Result<PendingTransactionEntity, Error>) -> Void ) async throws -> PendingTransactionEntity {
) { do {
initializer.downloadParametersIfNeeded { downloadResult in try await initializer.downloadParametersIfNeeded()
DispatchQueue.main.async { [weak self] in } catch {
switch downloadResult { throw SynchronizerError.parameterMissing(underlyingError: error)
case .success:
self?.createToAddress(
spendingKey: spendingKey,
zatoshi: zatoshi,
toAddress: toAddress,
memo: memo,
from: accountIndex,
resultBlock: resultBlock
)
case .failure(let error):
resultBlock(.failure(SynchronizerError.parameterMissing(underlyingError: error)))
}
}
} }
return try await createToAddress(
spendingKey: spendingKey,
zatoshi: zatoshi,
toAddress: toAddress,
memo: memo,
from: accountIndex
)
} }
public func shieldFunds( public func shieldFunds(
@ -536,16 +511,14 @@ public class SDKSynchronizer: Synchronizer {
throw error throw error
} }
} }
// swiftlint:disable:next function_parameter_count
func createToAddress( func createToAddress(
spendingKey: String, spendingKey: String,
zatoshi: Zatoshi, zatoshi: Zatoshi,
toAddress: String, toAddress: String,
memo: String?, memo: String?,
from accountIndex: Int, from accountIndex: Int
resultBlock: @escaping (Result<PendingTransactionEntity, Error>) -> Void ) async throws -> PendingTransactionEntity {
) {
do { do {
let spend = try transactionManager.initSpend( let spend = try transactionManager.initSpend(
zatoshi: zatoshi, zatoshi: zatoshi,
@ -554,21 +527,14 @@ public class SDKSynchronizer: Synchronizer {
from: accountIndex from: accountIndex
) )
// TODO: Task will be removed when this method is changed to async, issue 487, https://github.com/zcash/ZcashLightClientKit/issues/487 let transaction = try await transactionManager.encode(
Task { spendingKey: spendingKey,
do { pendingTransaction: spend
let transaction = try await transactionManager.encode( )
spendingKey: spendingKey, let submittedTx = try await transactionManager.submit(pendingTransaction: transaction)
pendingTransaction: spend return submittedTx
)
let submittedTx = try await transactionManager.submit(pendingTransaction: transaction)
resultBlock(.success(submittedTx))
} catch {
resultBlock(.failure(error))
}
}
} catch { } catch {
resultBlock(.failure(error)) throw error
} }
} }

View File

@ -15,33 +15,46 @@ public enum SaplingParameterDownloader {
case failed(error: Error) case failed(error: Error)
} }
/** /// Download a Spend parameter from default host and stores it at given URL
Download a Spend parameter from default host and stores it at given URL /// - Parameters:
- Parameters: /// - at: The destination URL for the download
- at: The destination URL for the download @discardableResult
- result: block to handle the download success or error public static func downloadSpendParameter(_ at: URL) async throws -> URL {
*/
public static func downloadSpendParameter(_ at: URL, result: @escaping (Result<URL, Error>) -> Void) {
guard let url = URL(string: spendParamsURLString) else { guard let url = URL(string: spendParamsURLString) else {
result(.failure(Errors.invalidURL(url: spendParamsURLString))) throw Errors.invalidURL(url: spendParamsURLString)
return
} }
downloadFileWithRequest(URLRequest(url: url), at: at, result: result) return try await withCheckedThrowingContinuation { continuation in
downloadFileWithRequest(URLRequest(url: url), at: at) { result in
switch result {
case .success(let outputResultURL):
continuation.resume(returning: outputResultURL)
case .failure(let outputResultError):
continuation.resume(throwing: outputResultError)
}
}
}
} }
/**
Download an Output parameter from default host and stores it at given URL /// Download an Output parameter from default host and stores it at given URL
- Parameters: /// - Parameters:
- at: The destination URL for the download /// - at: The destination URL for the download
- result: block to handle the download success or error @discardableResult
*/ public static func downloadOutputParameter(_ at: URL) async throws -> URL {
public static func downloadOutputParameter(_ at: URL, result: @escaping (Result<URL, Error>) -> Void) {
guard let url = URL(string: outputParamsURLString) else { guard let url = URL(string: outputParamsURLString) else {
result(.failure(Errors.invalidURL(url: outputParamsURLString))) throw Errors.invalidURL(url: outputParamsURLString)
return
} }
downloadFileWithRequest(URLRequest(url: url), at: at, result: result) return try await withCheckedThrowingContinuation { continuation in
downloadFileWithRequest(URLRequest(url: url), at: at) { result in
switch result {
case .success(let outputResultURL):
continuation.resume(returning: outputResultURL)
case .failure(let outputResultError):
continuation.resume(throwing: outputResultError)
}
}
}
} }
private static func downloadFileWithRequest(_ request: URLRequest, at destination: URL, result: @escaping (Result<URL, Error>) -> Void) { private static func downloadFileWithRequest(_ request: URLRequest, at destination: URL, result: @escaping (Result<URL, Error>) -> Void) {
@ -61,52 +74,39 @@ public enum SaplingParameterDownloader {
task.resume() task.resume()
} }
/**
Downloads the parameters if not present and provides the resulting URLs for both parameters /// Downloads the parameters if not present and provides the resulting URLs for both parameters
- Parameters: /// - Parameters:
- spendURL: URL to check whether the parameter is already downloaded /// - spendURL: URL to check whether the parameter is already downloaded
- outputURL: URL to check whether the parameter is already downloaded /// - outputURL: URL to check whether the parameter is already downloaded
- result: block to handle success or error
*/
public static func downloadParamsIfnotPresent( public static func downloadParamsIfnotPresent(
spendURL: URL, spendURL: URL,
outputURL: URL, outputURL: URL
result: @escaping (Result<(spend: URL, output: URL), Error>) -> Void ) async throws -> (spend: URL, output: URL) {
) { do {
ensureSpendParameter(at: spendURL) { spendResult in async let spendResultURL = ensureSpendParameter(at: spendURL)
switch spendResult { async let outputResultURL = ensureOutputParameter(at: outputURL)
case .success(let spendResultURL):
ensureOutputParameter(at: outputURL) { outputResult in let results = try await [spendResultURL, outputResultURL]
switch outputResult { return (spend: results[0], output: results[1])
case .success(let outputResultURL): } catch {
result(.success((spendResultURL, outputResultURL))) throw Errors.failed(error: error)
case .failure(let outputResultError):
result(.failure(Errors.failed(error: outputResultError)))
}
}
case .failure(let spendResultError):
result(.failure(Errors.failed(error: spendResultError)))
}
} }
} }
static func ensureSpendParameter(at url: URL, result: @escaping (Result<URL, Error>) -> Void) { static func ensureSpendParameter(at url: URL) async throws -> URL {
if isFilePresent(url: url) { if isFilePresent(url: url) {
DispatchQueue.global().async { return url
result(.success(url))
}
} else { } else {
downloadSpendParameter(url, result: result) return try await downloadSpendParameter(url)
} }
} }
static func ensureOutputParameter(at url: URL, result: @escaping (Result<URL, Error>) -> Void) { static func ensureOutputParameter(at url: URL) async throws -> URL {
if isFilePresent(url: url) { if isFilePresent(url: url) {
DispatchQueue.global().async { return url
result(.success(url))
}
} else { } else {
downloadOutputParameter(url, result: result) return try await downloadOutputParameter(url)
} }
} }

View File

@ -10,6 +10,7 @@ import XCTest
@testable import ZcashLightClientKit @testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional force_unwrapping type_body_length // swiftlint:disable implicitly_unwrapped_optional force_unwrapping type_body_length
//@MainActor
class AdvancedReOrgTests: XCTestCase { class AdvancedReOrgTests: XCTestCase {
// TODO: Parameterize this from environment? // TODO: Parameterize this from environment?
// swiftlint:disable:next line_length // swiftlint:disable:next line_length
@ -268,7 +269,7 @@ class AdvancedReOrgTests: XCTestCase {
12. applyStaged(sentTx + 10) 12. applyStaged(sentTx + 10)
13. verify that there's no more pending transaction 13. verify that there's no more pending transaction
*/ */
func testReorgChangesOutboundTxIndex() throws { func testReorgChangesOutboundTxIndex() async throws {
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName) try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName)
let receivedTxHeight: BlockHeight = 663188 let receivedTxHeight: BlockHeight = 663188
var initialTotalBalance = Zatoshi(-1) var initialTotalBalance = Zatoshi(-1)
@ -280,44 +281,51 @@ class AdvancedReOrgTests: XCTestCase {
sleep(2) sleep(2)
let preTxExpectation = XCTestExpectation(description: "pre receive") let preTxExpectation = XCTestExpectation(description: "pre receive")
/* /*
3. sync up to received_Tx_height 3. sync up to received_Tx_height
*/ */
try coordinator.sync(completion: { synchronizer in try await withCheckedThrowingContinuation { continuation in
initialTotalBalance = synchronizer.initializer.getBalance() do {
preTxExpectation.fulfill() try coordinator.sync(completion: { synchronizer in
}, error: self.handleError) initialTotalBalance = synchronizer.initializer.getBalance()
continuation.resume()
preTxExpectation.fulfill()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [preTxExpectation], timeout: 5) wait(for: [preTxExpectation], timeout: 5)
let sendExpectation = XCTestExpectation(description: "sendToAddress") let sendExpectation = XCTestExpectation(description: "sendToAddress")
var pendingEntity: PendingTransactionEntity? var pendingEntity: PendingTransactionEntity?
var error: Error? var testError: Error?
let sendAmount = Zatoshi(10000) let sendAmount = Zatoshi(10000)
/* /*
4. create transaction 4. create transaction
*/ */
coordinator.synchronizer.sendToAddress( do {
spendingKey: coordinator.spendingKeys!.first!, let pendingTx = try await coordinator.synchronizer.sendToAddress(
zatoshi: sendAmount, spendingKey: coordinator.spendingKeys!.first!,
toAddress: testRecipientAddress, zatoshi: sendAmount,
memo: "test transaction", toAddress: testRecipientAddress,
from: 0 memo: "test transaction",
) { result in from: 0
switch result { )
case .success(let pending): pendingEntity = pendingTx
pendingEntity = pending
case .failure(let e):
error = e
}
sendExpectation.fulfill() sendExpectation.fulfill()
} } catch {
wait(for: [sendExpectation], timeout: 12) testError = error
guard let pendingTx = pendingEntity else {
XCTFail("error sending to address. Error: \(String(describing: error))") XCTFail("error sending to address. Error: \(String(describing: error))")
}
wait(for: [sendExpectation], timeout: 2)
guard let pendingTx = pendingEntity else {
XCTFail("error sending to address. Error: \(String(describing: testError))")
return return
} }
@ -349,15 +357,18 @@ class AdvancedReOrgTests: XCTestCase {
*/ */
let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation") let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation")
try coordinator.sync( try await withCheckedThrowingContinuation { continuation in
completion: { synchronizer in do {
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight try coordinator.sync(completion: { synchronizer in
XCTAssertEqual(pMinedHeight, sentTxHeight) let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
XCTAssertEqual(pMinedHeight, sentTxHeight)
sentTxSyncExpectation.fulfill() continuation.resume()
}, sentTxSyncExpectation.fulfill()
error: self.handleError }, error: self.handleError)
) } catch {
continuation.resume(throwing: error)
}
}
wait(for: [sentTxSyncExpectation], timeout: 5) wait(for: [sentTxSyncExpectation], timeout: 5)
@ -375,18 +386,22 @@ class AdvancedReOrgTests: XCTestCase {
sleep(2) sleep(2)
let afterReOrgExpectation = XCTestExpectation(description: "after ReOrg Expectation") let afterReOrgExpectation = XCTestExpectation(description: "after ReOrg Expectation")
try coordinator.sync( try await withCheckedThrowingContinuation { continuation in
completion: { synchronizer in do {
/* try coordinator.sync(completion: { synchronizer in
11. verify that the sent tx is mined and balance is correct /*
*/ 11. verify that the sent tx is mined and balance is correct
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight */
XCTAssertEqual(pMinedHeight, sentTxHeight) let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
XCTAssertEqual(initialTotalBalance - sendAmount - Zatoshi(1000), synchronizer.initializer.getBalance()) // fee change on this branch XCTAssertEqual(pMinedHeight, sentTxHeight)
afterReOrgExpectation.fulfill() XCTAssertEqual(initialTotalBalance - sendAmount - Zatoshi(1000), synchronizer.initializer.getBalance()) // fee change on this branch
}, continuation.resume()
error: self.handleError afterReOrgExpectation.fulfill()
) }, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [afterReOrgExpectation], timeout: 5) wait(for: [afterReOrgExpectation], timeout: 5)
@ -400,10 +415,16 @@ class AdvancedReOrgTests: XCTestCase {
13. verify that there's no more pending transaction 13. verify that there's no more pending transaction
*/ */
let lastSyncExpectation = XCTestExpectation(description: "sync to confirmation") let lastSyncExpectation = XCTestExpectation(description: "sync to confirmation")
try await withCheckedThrowingContinuation { continuation in
try coordinator.sync(completion: { _ in do {
lastSyncExpectation.fulfill() try coordinator.sync(completion: { synchronizer in
}, error: self.handleError) lastSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [lastSyncExpectation], timeout: 5) wait(for: [lastSyncExpectation], timeout: 5)
@ -676,7 +697,7 @@ class AdvancedReOrgTests: XCTestCase {
15. verify that there's no pending transaction and that the tx is displayed on the sentTransactions collection 15. verify that there's no pending transaction and that the tx is displayed on the sentTransactions collection
*/ */
func testReOrgChangesOutboundTxMinedHeight() throws { func testReOrgChangesOutboundTxMinedHeight() async throws {
hookToReOrgNotification() hookToReOrgNotification()
/* /*
@ -691,9 +712,16 @@ class AdvancedReOrgTests: XCTestCase {
/* /*
1a. sync to latest height 1a. sync to latest height
*/ */
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
firstSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
firstSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 5) wait(for: [firstSyncExpectation], timeout: 5)
@ -706,22 +734,18 @@ class AdvancedReOrgTests: XCTestCase {
/* /*
2. send transaction to recipient address 2. send transaction to recipient address
*/ */
coordinator.synchronizer.sendToAddress( do {
spendingKey: self.coordinator.spendingKeys!.first!, let pendingTx = try await coordinator.synchronizer.sendToAddress(
zatoshi: Zatoshi(20000), spendingKey: self.coordinator.spendingKeys!.first!,
toAddress: self.testRecipientAddress, zatoshi: Zatoshi(20000),
memo: "this is a test", toAddress: self.testRecipientAddress,
from: 0, memo: "this is a test",
resultBlock: { result in from: 0)
switch result { pendingEntity = pendingTx
case .failure(let e): sendExpectation.fulfill()
self.handleError(e) } catch {
case .success(let pendingTx): self.handleError(error)
pendingEntity = pendingTx }
}
sendExpectation.fulfill()
}
)
wait(for: [sendExpectation], timeout: 11) wait(for: [sendExpectation], timeout: 11)
@ -761,10 +785,17 @@ class AdvancedReOrgTests: XCTestCase {
*/ */
let secondSyncExpectation = XCTestExpectation(description: "after send expectation") let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
secondSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
secondSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [secondSyncExpectation], timeout: 5) wait(for: [secondSyncExpectation], timeout: 5)
XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count, 1) XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count, 1)
@ -799,10 +830,17 @@ class AdvancedReOrgTests: XCTestCase {
self.expectedReorgHeight = sentTxHeight + 1 self.expectedReorgHeight = sentTxHeight + 1
let afterReorgExpectation = XCTestExpectation(description: "after reorg sync") let afterReorgExpectation = XCTestExpectation(description: "after reorg sync")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
afterReorgExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
afterReorgExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [reorgExpectation, afterReorgExpectation], timeout: 5) wait(for: [reorgExpectation, afterReorgExpectation], timeout: 5)
/* /*
@ -827,10 +865,17 @@ class AdvancedReOrgTests: XCTestCase {
/* /*
11a. sync to latest height 11a. sync to latest height
*/ */
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
yetAnotherExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
yetAnotherExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [yetAnotherExpectation], timeout: 5) wait(for: [yetAnotherExpectation], timeout: 5)
/* /*
@ -857,10 +902,17 @@ class AdvancedReOrgTests: XCTestCase {
/* /*
14. sync to latest height 14. sync to latest height
*/ */
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
thisIsTheLastExpectationIPromess.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
thisIsTheLastExpectationIPromess.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [thisIsTheLastExpectationIPromess], timeout: 5) wait(for: [thisIsTheLastExpectationIPromess], timeout: 5)
/* /*
@ -1034,7 +1086,7 @@ class AdvancedReOrgTests: XCTestCase {
8. sync to latest height 8. sync to latest height
9. verify that there's an expired transaction as a pending transaction 9. verify that there's an expired transaction as a pending transaction
*/ */
func testReOrgRemovesOutboundTxAndIsNeverMined() throws { func testReOrgRemovesOutboundTxAndIsNeverMined() async throws {
hookToReOrgNotification() hookToReOrgNotification()
/* /*
@ -1051,10 +1103,17 @@ class AdvancedReOrgTests: XCTestCase {
/* /*
1a. sync to latest height 1a. sync to latest height
*/ */
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
firstSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
firstSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 5) wait(for: [firstSyncExpectation], timeout: 5)
sleep(1) sleep(1)
@ -1066,22 +1125,18 @@ class AdvancedReOrgTests: XCTestCase {
/* /*
2. send transaction to recipient address 2. send transaction to recipient address
*/ */
coordinator.synchronizer.sendToAddress( do {
spendingKey: self.coordinator.spendingKeys!.first!, let pendingTx = try await coordinator.synchronizer.sendToAddress(
zatoshi: Zatoshi(20000), spendingKey: self.coordinator.spendingKeys!.first!,
toAddress: self.testRecipientAddress, zatoshi: Zatoshi(20000),
memo: "this is a test", toAddress: self.testRecipientAddress,
from: 0, memo: "this is a test",
resultBlock: { result in from: 0)
switch result { pendingEntity = pendingTx
case .failure(let e): sendExpectation.fulfill()
self.handleError(e) } catch {
case .success(let pendingTx): self.handleError(error)
pendingEntity = pendingTx }
}
sendExpectation.fulfill()
}
)
wait(for: [sendExpectation], timeout: 11) wait(for: [sendExpectation], timeout: 11)
@ -1121,10 +1176,17 @@ class AdvancedReOrgTests: XCTestCase {
*/ */
let secondSyncExpectation = XCTestExpectation(description: "after send expectation") let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
secondSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
secondSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [secondSyncExpectation], timeout: 5) wait(for: [secondSyncExpectation], timeout: 5)
let extraBlocks = 25 let extraBlocks = 25
try coordinator.stageBlockCreate(height: sentTxHeight, count: extraBlocks, nonce: 5) try coordinator.stageBlockCreate(height: sentTxHeight, count: extraBlocks, nonce: 5)
@ -1134,10 +1196,17 @@ class AdvancedReOrgTests: XCTestCase {
sleep(2) sleep(2)
let reorgSyncExpectation = XCTestExpectation(description: "reorg sync expectation") let reorgSyncExpectation = XCTestExpectation(description: "reorg sync expectation")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
reorgSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
reorgSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [reorgExpectation, reorgSyncExpectation], timeout: 5) wait(for: [reorgExpectation, reorgSyncExpectation], timeout: 5)
guard let pendingTx = coordinator.synchronizer.pendingTransactions.first else { guard let pendingTx = coordinator.synchronizer.pendingTransactions.first else {
@ -1154,10 +1223,17 @@ class AdvancedReOrgTests: XCTestCase {
let lastSyncExpectation = XCTestExpectation(description: "last sync expectation") let lastSyncExpectation = XCTestExpectation(description: "last sync expectation")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
lastSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
lastSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [lastSyncExpectation], timeout: 5) wait(for: [lastSyncExpectation], timeout: 5)
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), initialTotalBalance) XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), initialTotalBalance)

View File

@ -42,7 +42,7 @@ class BalanceTests: XCTestCase {
/** /**
verify that when sending the maximum amount, the transactions are broadcasted properly verify that when sending the maximum amount, the transactions are broadcasted properly
*/ */
func testMaxAmountSend() throws { func testMaxAmountSend() async throws {
let notificationHandler = SDKSynchonizerListener() let notificationHandler = SDKSynchonizerListener()
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation") let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation") let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
@ -57,9 +57,16 @@ class BalanceTests: XCTestCase {
sleep(1) sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation") let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
firstSyncExpectation.fulfill() do {
}, error: handleError) try coordinator.sync(completion: { synchronizer in
firstSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 12) wait(for: [firstSyncExpectation], timeout: 12)
// 2 check that there are no unconfirmed funds // 2 check that there are no unconfirmed funds
@ -79,22 +86,18 @@ class BalanceTests: XCTestCase {
} }
var pendingTx: PendingTransactionEntity? var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress( do {
spendingKey: spendingKey, let transaction = try await coordinator.synchronizer.sendToAddress(
zatoshi: maxBalance, spendingKey: spendingKey,
toAddress: testRecipientAddress, zatoshi: maxBalance,
memo: "test send \(self.description) \(Date().description)", toAddress: testRecipientAddress,
from: 0, memo: "test send \(self.description) \(Date().description)",
resultBlock: { result in from: 0)
switch result { pendingTx = transaction
case .failure(let error): self.sentTransactionExpectation.fulfill()
XCTFail("sendToAddress failed: \(error)") } catch {
case .success(let transaction): XCTFail("sendToAddress failed: \(error)")
pendingTx = transaction }
}
self.sentTransactionExpectation.fulfill()
}
)
wait(for: [sentTransactionExpectation], timeout: 20) wait(for: [sentTransactionExpectation], timeout: 20)
guard let pendingTx = pendingTx else { guard let pendingTx = pendingTx else {
@ -133,23 +136,29 @@ class BalanceTests: XCTestCase {
sleep(2) // add enhance breakpoint here sleep(2) // add enhance breakpoint here
let mineExpectation = XCTestExpectation(description: "mineTxExpectation") let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
try coordinator.sync( try await withCheckedThrowingContinuation { continuation in
completion: { synchronizer in do {
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) try coordinator.sync(
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now") completion: { synchronizer in
XCTAssertTrue(pendingEntity?.isMined ?? false) let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight) XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
mineExpectation.fulfill() XCTAssertTrue(pendingEntity?.isMined ?? false)
}, XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
error: { error in mineExpectation.fulfill()
guard let error = error else { continuation.resume()
XCTFail("unknown error syncing after sending transaction") }, error: { error in
return guard let error = error else {
} XCTFail("unknown error syncing after sending transaction")
return
XCTFail("Error: \(error)") }
XCTFail("Error: \(error)")
}
)
} catch {
continuation.resume(throwing: error)
} }
) }
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5) wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
@ -166,12 +175,17 @@ class BalanceTests: XCTestCase {
notificationHandler.synchronizerMinedTransaction = { transaction in notificationHandler.synchronizerMinedTransaction = { transaction in
XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)") XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)")
} }
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
confirmExpectation.fulfill() do {
}, error: { e in try coordinator.sync(completion: { synchronizer in
self.handleError(e) confirmExpectation.fulfill()
}) continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [confirmExpectation], timeout: 5) wait(for: [confirmExpectation], timeout: 5)
let confirmedPending = try coordinator.synchronizer.allPendingTransactions() let confirmedPending = try coordinator.synchronizer.allPendingTransactions()
@ -186,7 +200,7 @@ class BalanceTests: XCTestCase {
/** /**
verify that when sending the maximum amount minus one zatoshi, the transactions are broadcasted properly verify that when sending the maximum amount minus one zatoshi, the transactions are broadcasted properly
*/ */
func testMaxAmountMinusOneSend() throws { func testMaxAmountMinusOneSend() async throws {
let notificationHandler = SDKSynchonizerListener() let notificationHandler = SDKSynchonizerListener()
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation") let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation") let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
@ -201,9 +215,16 @@ class BalanceTests: XCTestCase {
sleep(1) sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation") let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
firstSyncExpectation.fulfill() do {
}, error: handleError) try coordinator.sync(completion: { synchronizer in
firstSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 12) wait(for: [firstSyncExpectation], timeout: 12)
// 2 check that there are no unconfirmed funds // 2 check that there are no unconfirmed funds
@ -221,24 +242,20 @@ class BalanceTests: XCTestCase {
XCTFail("failed to create spending keys") XCTFail("failed to create spending keys")
return return
} }
var pendingTx: PendingTransactionEntity? var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress( do {
spendingKey: spendingKey, let transaction = try await coordinator.synchronizer.sendToAddress(
zatoshi: maxBalanceMinusOne, spendingKey: spendingKey,
toAddress: testRecipientAddress, zatoshi: maxBalanceMinusOne,
memo: "test send \(self.description) \(Date().description)", toAddress: testRecipientAddress,
from: 0, memo: "test send \(self.description) \(Date().description)",
resultBlock: { result in from: 0)
switch result { pendingTx = transaction
case .failure(let error): self.sentTransactionExpectation.fulfill()
XCTFail("sendToAddress failed: \(error)") } catch {
case .success(let transaction): XCTFail("sendToAddress failed: \(error)")
pendingTx = transaction }
}
self.sentTransactionExpectation.fulfill()
}
)
wait(for: [sentTransactionExpectation], timeout: 20) wait(for: [sentTransactionExpectation], timeout: 20)
guard let pendingTx = pendingTx else { guard let pendingTx = pendingTx else {
@ -277,20 +294,29 @@ class BalanceTests: XCTestCase {
sleep(2) // add enhance breakpoint here sleep(2) // add enhance breakpoint here
let mineExpectation = XCTestExpectation(description: "mineTxExpectation") let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
try coordinator.sync(completion: { synchronizer in try await withCheckedThrowingContinuation { continuation in
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) do {
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now") try coordinator.sync(
XCTAssertTrue(pendingEntity?.isMined ?? false) completion: { synchronizer in
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight) let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
mineExpectation.fulfill() XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
}, error: { error in XCTAssertTrue(pendingEntity?.isMined ?? false)
guard let e = error else { XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
XCTFail("unknown error syncing after sending transaction") mineExpectation.fulfill()
return continuation.resume()
}, error: { error in
guard let error = error else {
XCTFail("unknown error syncing after sending transaction")
return
}
XCTFail("Error: \(error)")
}
)
} catch {
continuation.resume(throwing: error)
} }
}
XCTFail("Error: \(e)")
})
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5) wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
@ -307,11 +333,16 @@ class BalanceTests: XCTestCase {
notificationHandler.synchronizerMinedTransaction = { transaction in notificationHandler.synchronizerMinedTransaction = { transaction in
XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)") XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)")
} }
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
confirmExpectation.fulfill() do {
}, error: { e in try coordinator.sync(completion: { synchronizer in
self.handleError(e) confirmExpectation.fulfill()
}) continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [confirmExpectation], timeout: 5) wait(for: [confirmExpectation], timeout: 5)
@ -328,7 +359,7 @@ class BalanceTests: XCTestCase {
/** /**
verify that when sending the a no change transaction, the transactions are broadcasted properly verify that when sending the a no change transaction, the transactions are broadcasted properly
*/ */
func testSingleNoteNoChangeTransaction() throws { func testSingleNoteNoChangeTransaction() async throws {
let notificationHandler = SDKSynchonizerListener() let notificationHandler = SDKSynchonizerListener()
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation") let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation") let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
@ -343,10 +374,16 @@ class BalanceTests: XCTestCase {
sleep(1) sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation") let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
firstSyncExpectation.fulfill() do {
}, error: handleError) try coordinator.sync(completion: { synchronizer in
firstSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 12) wait(for: [firstSyncExpectation], timeout: 12)
// 2 check that there are no unconfirmed funds // 2 check that there are no unconfirmed funds
@ -364,22 +401,18 @@ class BalanceTests: XCTestCase {
return return
} }
var pendingTx: PendingTransactionEntity? var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress( do {
spendingKey: spendingKey, let transaction = try await coordinator.synchronizer.sendToAddress(
zatoshi: maxBalanceMinusOne, spendingKey: spendingKey,
toAddress: testRecipientAddress, zatoshi: maxBalanceMinusOne,
memo: "test send \(self.description) \(Date().description)", toAddress: testRecipientAddress,
from: 0, memo: "test send \(self.description) \(Date().description)",
resultBlock: { result in from: 0)
switch result { pendingTx = transaction
case .failure(let error): self.sentTransactionExpectation.fulfill()
XCTFail("sendToAddress failed: \(error)") } catch {
case .success(let transaction): XCTFail("sendToAddress failed: \(error)")
pendingTx = transaction }
}
self.sentTransactionExpectation.fulfill()
}
)
wait(for: [sentTransactionExpectation], timeout: 20) wait(for: [sentTransactionExpectation], timeout: 20)
guard let pendingTx = pendingTx else { guard let pendingTx = pendingTx else {
@ -418,20 +451,29 @@ class BalanceTests: XCTestCase {
sleep(2) // add enhance breakpoint here sleep(2) // add enhance breakpoint here
let mineExpectation = XCTestExpectation(description: "mineTxExpectation") let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
try coordinator.sync(completion: { synchronizer in try await withCheckedThrowingContinuation { continuation in
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) do {
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now") try coordinator.sync(
XCTAssertTrue(pendingEntity?.isMined ?? false) completion: { synchronizer in
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight) let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
mineExpectation.fulfill() XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
}, error: { error in XCTAssertTrue(pendingEntity?.isMined ?? false)
guard let e = error else { XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
XCTFail("unknown error syncing after sending transaction") mineExpectation.fulfill()
return continuation.resume()
}, error: { error in
guard let error = error else {
XCTFail("unknown error syncing after sending transaction")
return
}
XCTFail("Error: \(error)")
}
)
} catch {
continuation.resume(throwing: error)
} }
}
XCTFail("Error: \(e)")
})
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5) wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
@ -448,11 +490,16 @@ class BalanceTests: XCTestCase {
notificationHandler.synchronizerMinedTransaction = { transaction in notificationHandler.synchronizerMinedTransaction = { transaction in
XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)") XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)")
} }
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
confirmExpectation.fulfill() do {
}, error: { e in try coordinator.sync(completion: { synchronizer in
self.handleError(e) confirmExpectation.fulfill()
}) continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [confirmExpectation], timeout: 5) wait(for: [confirmExpectation], timeout: 5)
@ -483,14 +530,21 @@ class BalanceTests: XCTestCase {
Error: previous available funds equals to current funds Error: previous available funds equals to current funds
*/ */
// swiftlint:disable cyclomatic_complexity // swiftlint:disable cyclomatic_complexity
func testVerifyAvailableBalanceDuringSend() throws { func testVerifyAvailableBalanceDuringSend() async throws {
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
try coordinator.applyStaged(blockheight: defaultLatestHeight) try coordinator.applyStaged(blockheight: defaultLatestHeight)
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
self.syncedExpectation.fulfill() do {
}, error: handleError) try coordinator.sync(completion: { synchronizer in
self.syncedExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [syncedExpectation], timeout: 60) wait(for: [syncedExpectation], timeout: 60)
@ -507,27 +561,23 @@ class BalanceTests: XCTestCase {
XCTAssertTrue(presendVerifiedBalance >= network.constants.defaultFee(for: defaultLatestHeight) + sendAmount) XCTAssertTrue(presendVerifiedBalance >= network.constants.defaultFee(for: defaultLatestHeight) + sendAmount)
var pendingTx: PendingTransactionEntity? var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress( do {
spendingKey: spendingKey, let transaction = try await coordinator.synchronizer.sendToAddress(
zatoshi: sendAmount, spendingKey: spendingKey,
toAddress: testRecipientAddress, zatoshi: sendAmount,
memo: "test send \(self.description) \(Date().description)", toAddress: testRecipientAddress,
from: 0, memo: "test send \(self.description) \(Date().description)",
resultBlock: { result in from: 0)
switch result { pendingTx = transaction
case .failure(let error): self.sentTransactionExpectation.fulfill()
/* } catch {
balance should be the same as before sending if transaction failed /*
*/ balance should be the same as before sending if transaction failed
XCTAssertEqual(self.coordinator.synchronizer.initializer.getVerifiedBalance(), presendVerifiedBalance) */
XCTFail("sendToAddress failed: \(error)") XCTAssertEqual(self.coordinator.synchronizer.initializer.getVerifiedBalance(), presendVerifiedBalance)
case .success(let transaction): XCTFail("sendToAddress failed: \(error)")
pendingTx = transaction }
}
self.sentTransactionExpectation.fulfill()
}
)
XCTAssertTrue(coordinator.synchronizer.initializer.getVerifiedBalance() > .zero) XCTAssertTrue(coordinator.synchronizer.initializer.getVerifiedBalance() > .zero)
wait(for: [sentTransactionExpectation], timeout: 12) wait(for: [sentTransactionExpectation], timeout: 12)
@ -548,16 +598,25 @@ class BalanceTests: XCTestCase {
sleep(1) sleep(1)
let mineExpectation = XCTestExpectation(description: "mineTxExpectation") let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
mineExpectation.fulfill() do {
}, error: { error in try coordinator.sync(
guard let e = error else { completion: { synchronizer in
XCTFail("unknown error syncing after sending transaction") mineExpectation.fulfill()
return continuation.resume()
}, error: { error in
guard let error else {
XCTFail("unknown error syncing after sending transaction")
return
}
XCTFail("Error: \(error)")
}
)
} catch {
continuation.resume(throwing: error)
} }
}
XCTFail("Error: \(e)")
})
wait(for: [mineExpectation], timeout: 5) wait(for: [mineExpectation], timeout: 5)
@ -654,15 +713,22 @@ class BalanceTests: XCTestCase {
Error: previous total balance funds equals to current total balance Error: previous total balance funds equals to current total balance
*/ */
func testVerifyTotalBalanceDuringSend() throws { func testVerifyTotalBalanceDuringSend() async throws {
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
try coordinator.applyStaged(blockheight: defaultLatestHeight) try coordinator.applyStaged(blockheight: defaultLatestHeight)
sleep(2) sleep(2)
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
self.syncedExpectation.fulfill() do {
}, error: handleError) try coordinator.sync(completion: { synchronizer in
self.syncedExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [syncedExpectation], timeout: 5) wait(for: [syncedExpectation], timeout: 5)
@ -677,33 +743,28 @@ class BalanceTests: XCTestCase {
XCTAssertTrue(presendBalance >= network.constants.defaultFee(for: defaultLatestHeight) + sendAmount) XCTAssertTrue(presendBalance >= network.constants.defaultFee(for: defaultLatestHeight) + sendAmount)
var pendingTx: PendingTransactionEntity? var pendingTx: PendingTransactionEntity?
var error: Error? var testError: Error?
coordinator.synchronizer.sendToAddress( do {
spendingKey: spendingKey, let transaction = try await coordinator.synchronizer.sendToAddress(
zatoshi: sendAmount, spendingKey: spendingKey,
toAddress: testRecipientAddress, zatoshi: sendAmount,
memo: "test send \(self.description) \(Date().description)", toAddress: testRecipientAddress,
from: 0, memo: "test send \(self.description) \(Date().description)",
resultBlock: { result in from: 0)
switch result { pendingTx = transaction
case .failure(let e): self.sentTransactionExpectation.fulfill()
// balance should be the same as before sending if transaction failed } catch {
error = e // balance should be the same as before sending if transaction failed
XCTFail("sendToAddress failed: \(e)") testError = error
XCTFail("sendToAddress failed: \(error)")
case .success(let transaction): }
pendingTx = transaction
}
self.sentTransactionExpectation.fulfill()
}
)
XCTAssertTrue(coordinator.synchronizer.initializer.getVerifiedBalance() > .zero) XCTAssertTrue(coordinator.synchronizer.initializer.getVerifiedBalance() > .zero)
wait(for: [sentTransactionExpectation], timeout: 12) wait(for: [sentTransactionExpectation], timeout: 12)
if let e = error { if let testError {
XCTAssertEqual(self.coordinator.synchronizer.initializer.getVerifiedBalance(), presendBalance) XCTAssertEqual(self.coordinator.synchronizer.initializer.getVerifiedBalance(), presendBalance)
XCTFail("error: \(e)") XCTFail("error: \(testError)")
return return
} }
guard let transaction = pendingTx else { guard let transaction = pendingTx else {
@ -733,16 +794,25 @@ class BalanceTests: XCTestCase {
sleep(2) sleep(2)
let mineExpectation = XCTestExpectation(description: "mineTxExpectation") let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
mineExpectation.fulfill() do {
}, error: { error in try coordinator.sync(
guard let e = error else { completion: { synchronizer in
XCTFail("unknown error syncing after sending transaction") mineExpectation.fulfill()
return continuation.resume()
}, error: { error in
guard let error else {
XCTFail("unknown error syncing after sending transaction")
return
}
XCTFail("Error: \(error)")
}
)
} catch {
continuation.resume(throwing: error)
} }
}
XCTFail("Error: \(e)")
})
wait(for: [mineExpectation], timeout: 5) wait(for: [mineExpectation], timeout: 5)
@ -802,7 +872,7 @@ class BalanceTests: XCTestCase {
Theres a change note of value (previous note value - sent amount) Theres a change note of value (previous note value - sent amount)
*/ */
func testVerifyChangeTransaction() throws { func testVerifyChangeTransaction() async throws {
try FakeChainBuilder.buildSingleNoteChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) try FakeChainBuilder.buildSingleNoteChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
try coordinator.applyStaged(blockheight: defaultLatestHeight) try coordinator.applyStaged(blockheight: defaultLatestHeight)
@ -814,9 +884,16 @@ class BalanceTests: XCTestCase {
/* /*
sync to current tip sync to current tip
*/ */
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
self.syncedExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
self.syncedExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [syncedExpectation], timeout: 6) wait(for: [syncedExpectation], timeout: 6)
@ -833,26 +910,18 @@ class BalanceTests: XCTestCase {
*/ */
let memo = "shielding is fun!" let memo = "shielding is fun!"
var pendingTx: PendingTransactionEntity? var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress( do {
spendingKey: spendingKeys, let transaction = try await coordinator.synchronizer.sendToAddress(
zatoshi: sendAmount, spendingKey: spendingKeys,
toAddress: testRecipientAddress, zatoshi: sendAmount,
memo: memo, toAddress: testRecipientAddress,
from: 0, memo: memo,
resultBlock: { sendResult in from: 0)
DispatchQueue.main.async { pendingTx = transaction
switch sendResult { sendExpectation.fulfill()
case .failure(let sendError): } catch {
XCTFail("error sending \(sendError)") XCTFail("error sending \(error)")
}
case .success(let transaction):
pendingTx = transaction
}
sendExpectation.fulfill()
}
}
)
wait(for: [createToAddressExpectation], timeout: 30) wait(for: [createToAddressExpectation], timeout: 30)
let syncToMinedheightExpectation = XCTestExpectation(description: "sync to mined height + 1") let syncToMinedheightExpectation = XCTestExpectation(description: "sync to mined height + 1")
@ -875,89 +944,93 @@ class BalanceTests: XCTestCase {
/* /*
Sync to that block Sync to that block
*/ */
try coordinator.sync( try await withCheckedThrowingContinuation { continuation in
completion: { synchronizer in do {
let confirmedTx: ConfirmedTransactionEntity! try coordinator.sync(completion: { synchronizer in
do { let confirmedTx: ConfirmedTransactionEntity!
confirmedTx = try synchronizer.allClearedTransactions().first(where: { confirmed -> Bool in do {
confirmed.transactionEntity.transactionId == pendingTx?.transactionEntity.transactionId confirmedTx = try synchronizer.allClearedTransactions().first(where: { confirmed -> Bool in
}) confirmed.transactionEntity.transactionId == pendingTx?.transactionEntity.transactionId
} catch { })
XCTFail("Error retrieving cleared transactions") } catch {
return XCTFail("Error retrieving cleared transactions")
} return
}
/* /*
Theres a sent transaction matching the amount sent to the given zAddr Theres a sent transaction matching the amount sent to the given zAddr
*/ */
XCTAssertEqual(confirmedTx.value, self.sendAmount) XCTAssertEqual(confirmedTx.value, self.sendAmount)
XCTAssertEqual(confirmedTx.toAddress, self.testRecipientAddress) XCTAssertEqual(confirmedTx.toAddress, self.testRecipientAddress)
XCTAssertEqual(confirmedTx.memo?.asZcashTransactionMemo(), memo) XCTAssertEqual(confirmedTx.memo?.asZcashTransactionMemo(), memo)
guard let transactionId = confirmedTx.rawTransactionId else { guard let transactionId = confirmedTx.rawTransactionId else {
XCTFail("no raw transaction id") XCTFail("no raw transaction id")
return return
} }
/* /*
Find out what note was used Find out what note was used
*/ */
let sentNotesRepo = SentNotesSQLDAO( let sentNotesRepo = SentNotesSQLDAO(
dbProvider: SimpleConnectionProvider( dbProvider: SimpleConnectionProvider(
path: synchronizer.initializer.dataDbURL.absoluteString, path: synchronizer.initializer.dataDbURL.absoluteString,
readonly: true readonly: true
)
) )
)
guard let sentNote = try? sentNotesRepo.sentNote(byRawTransactionId: transactionId) else { guard let sentNote = try? sentNotesRepo.sentNote(byRawTransactionId: transactionId) else {
XCTFail("Could not finde sent note with transaction Id \(transactionId)") XCTFail("Could not finde sent note with transaction Id \(transactionId)")
return return
} }
let receivedNotesRepo = ReceivedNotesSQLDAO( let receivedNotesRepo = ReceivedNotesSQLDAO(
dbProvider: SimpleConnectionProvider( dbProvider: SimpleConnectionProvider(
path: self.coordinator.synchronizer.initializer.dataDbURL.absoluteString, path: self.coordinator.synchronizer.initializer.dataDbURL.absoluteString,
readonly: true readonly: true
)
) )
)
/* /*
get change note get change note
*/ */
guard let receivedNote = try? receivedNotesRepo.receivedNote(byRawTransactionId: transactionId) else { guard let receivedNote = try? receivedNotesRepo.receivedNote(byRawTransactionId: transactionId) else {
XCTFail("Could not find received not with change for transaction Id \(transactionId)") XCTFail("Could not find received not with change for transaction Id \(transactionId)")
return return
} }
/* /*
Theres a change note of value (previous note value - sent amount) Theres a change note of value (previous note value - sent amount)
*/ */
XCTAssertEqual( XCTAssertEqual(
previousVerifiedBalance - self.sendAmount - self.network.constants.defaultFee(for: self.defaultLatestHeight), previousVerifiedBalance - self.sendAmount - self.network.constants.defaultFee(for: self.defaultLatestHeight),
Zatoshi(Int64(receivedNote.value)) Zatoshi(Int64(receivedNote.value))
) )
/* /*
Balance meets verified Balance and total balance criteria Balance meets verified Balance and total balance criteria
*/ */
self.verifiedBalanceValidation( self.verifiedBalanceValidation(
previousBalance: previousVerifiedBalance, previousBalance: previousVerifiedBalance,
spentNoteValue: Zatoshi(Int64(sentNote.value)), spentNoteValue: Zatoshi(Int64(sentNote.value)),
changeValue: Zatoshi(Int64(receivedNote.value)), changeValue: Zatoshi(Int64(receivedNote.value)),
sentAmount: self.sendAmount, sentAmount: self.sendAmount,
currentVerifiedBalance: synchronizer.initializer.getVerifiedBalance() currentVerifiedBalance: synchronizer.initializer.getVerifiedBalance()
) )
self.totalBalanceValidation( self.totalBalanceValidation(
totalBalance: synchronizer.initializer.getBalance(), totalBalance: synchronizer.initializer.getBalance(),
previousTotalbalance: previousTotalBalance, previousTotalbalance: previousTotalBalance,
sentAmount: self.sendAmount sentAmount: self.sendAmount
) )
syncToMinedheightExpectation.fulfill() syncToMinedheightExpectation.fulfill()
}, continuation.resume()
error: self.handleError }, error: self.handleError)
) } catch {
continuation.resume(throwing: error)
}
}
wait(for: [syncToMinedheightExpectation], timeout: 5) wait(for: [syncToMinedheightExpectation], timeout: 5)
} }
@ -985,15 +1058,21 @@ class BalanceTests: XCTestCase {
Verified Balance is equal to verified balance previously shown before sending the expired transaction Verified Balance is equal to verified balance previously shown before sending the expired transaction
*/ */
func testVerifyBalanceAfterExpiredTransaction() throws { func testVerifyBalanceAfterExpiredTransaction() async throws {
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
try coordinator.applyStaged(blockheight: self.defaultLatestHeight) try coordinator.applyStaged(blockheight: self.defaultLatestHeight)
sleep(2) sleep(2)
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
self.syncedExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
self.syncedExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [syncedExpectation], timeout: 5) wait(for: [syncedExpectation], timeout: 5)
guard let spendingKey = coordinator.spendingKeys?.first else { guard let spendingKey = coordinator.spendingKeys?.first else {
@ -1005,24 +1084,20 @@ class BalanceTests: XCTestCase {
let previousTotalBalance: Zatoshi = coordinator.synchronizer.initializer.getBalance() let previousTotalBalance: Zatoshi = coordinator.synchronizer.initializer.getBalance()
let sendExpectation = XCTestExpectation(description: "send expectation") let sendExpectation = XCTestExpectation(description: "send expectation")
var pendingTx: PendingTransactionEntity? var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress( do {
spendingKey: spendingKey, let pending = try await coordinator.synchronizer.sendToAddress(
zatoshi: sendAmount, spendingKey: spendingKey,
toAddress: testRecipientAddress, zatoshi: sendAmount,
memo: "test send \(self.description)", toAddress: testRecipientAddress,
from: 0, memo: "test send \(self.description)",
resultBlock: { result in from: 0)
switch result { pendingTx = pending
case .failure(let error): } catch {
// balance should be the same as before sending if transaction failed // balance should be the same as before sending if transaction failed
XCTAssertEqual(self.coordinator.synchronizer.initializer.getVerifiedBalance(), previousVerifiedBalance) XCTAssertEqual(self.coordinator.synchronizer.initializer.getVerifiedBalance(), previousVerifiedBalance)
XCTAssertEqual(self.coordinator.synchronizer.initializer.getBalance(), previousTotalBalance) XCTAssertEqual(self.coordinator.synchronizer.initializer.getBalance(), previousTotalBalance)
XCTFail("sendToAddress failed: \(error)") XCTFail("sendToAddress failed: \(error)")
case .success(let pending): }
pendingTx = pending
}
}
)
wait(for: [sendExpectation], timeout: 12) wait(for: [sendExpectation], timeout: 12)
@ -1038,10 +1113,16 @@ class BalanceTests: XCTestCase {
try coordinator.applyStaged(blockheight: expiryHeight + 1) try coordinator.applyStaged(blockheight: expiryHeight + 1)
sleep(2) sleep(2)
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
expirationSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
expirationSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [expirationSyncExpectation], timeout: 5) wait(for: [expirationSyncExpectation], timeout: 5)
/* /*

View File

@ -43,7 +43,7 @@ class NetworkUpgradeTests: XCTestCase {
/** /**
Given that a wallet had funds prior to activation it can spend them after activation Given that a wallet had funds prior to activation it can spend them after activation
*/ */
func testSpendPriorFundsAfterActivation() throws { func testSpendPriorFundsAfterActivation() async throws {
try FakeChainBuilder.buildChain( try FakeChainBuilder.buildChain(
darksideWallet: coordinator.service, darksideWallet: coordinator.service,
birthday: birthday, birthday: birthday,
@ -58,10 +58,16 @@ class NetworkUpgradeTests: XCTestCase {
try coordinator.applyStaged(blockheight: activationHeight - ZcashSDK.defaultStaleTolerance) try coordinator.applyStaged(blockheight: activationHeight - ZcashSDK.defaultStaleTolerance)
sleep(5) sleep(5)
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
firstSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
firstSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 120) wait(for: [firstSyncExpectation], timeout: 120)
let verifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance()
guard verifiedBalance > network.constants.defaultFee(for: activationHeight) else { guard verifiedBalance > network.constants.defaultFee(for: activationHeight) else {
@ -79,22 +85,18 @@ class NetworkUpgradeTests: XCTestCase {
/* /*
send transaction to recipient address send transaction to recipient address
*/ */
coordinator.synchronizer.sendToAddress( do {
spendingKey: self.coordinator.spendingKeys!.first!, let pendingTx = try await coordinator.synchronizer.sendToAddress(
zatoshi: spendAmount, spendingKey: self.coordinator.spendingKeys!.first!,
toAddress: self.testRecipientAddress, zatoshi: spendAmount,
memo: "this is a test", toAddress: self.testRecipientAddress,
from: 0, memo: "this is a test",
resultBlock: { result in from: 0)
switch result { pendingEntity = pendingTx
case .failure(let e): sendExpectation.fulfill()
self.handleError(e) } catch {
case .success(let pendingTx): self.handleError(error)
pendingEntity = pendingTx }
}
sendExpectation.fulfill()
}
)
wait(for: [sendExpectation], timeout: 11) wait(for: [sendExpectation], timeout: 11)
@ -123,10 +125,17 @@ class NetworkUpgradeTests: XCTestCase {
sleep(1) sleep(1)
let afterSendExpectation = XCTestExpectation(description: "aftersend") let afterSendExpectation = XCTestExpectation(description: "aftersend")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
afterSendExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
afterSendExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [afterSendExpectation], timeout: 10) wait(for: [afterSendExpectation], timeout: 10)
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), verifiedBalance - spendAmount) XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), verifiedBalance - spendAmount)
@ -135,7 +144,7 @@ class NetworkUpgradeTests: XCTestCase {
/** /**
Given that a wallet receives funds after activation it can spend them when confirmed Given that a wallet receives funds after activation it can spend them when confirmed
*/ */
func testSpendPostActivationFundsAfterConfirmation() throws { func testSpendPostActivationFundsAfterConfirmation() async throws {
try FakeChainBuilder.buildChainPostActivationFunds( try FakeChainBuilder.buildChainPostActivationFunds(
darksideWallet: coordinator.service, darksideWallet: coordinator.service,
birthday: birthday, birthday: birthday,
@ -148,9 +157,16 @@ class NetworkUpgradeTests: XCTestCase {
try coordinator.applyStaged(blockheight: activationHeight + 10) try coordinator.applyStaged(blockheight: activationHeight + 10)
sleep(3) sleep(3)
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
firstSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
firstSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 120) wait(for: [firstSyncExpectation], timeout: 120)
guard try !coordinator.synchronizer.allReceivedTransactions().filter({ $0.minedHeight > activationHeight }).isEmpty else { guard try !coordinator.synchronizer.allReceivedTransactions().filter({ $0.minedHeight > activationHeight }).isEmpty else {
@ -168,22 +184,18 @@ class NetworkUpgradeTests: XCTestCase {
/* /*
send transaction to recipient address send transaction to recipient address
*/ */
coordinator.synchronizer.sendToAddress( do {
spendingKey: self.coordinator.spendingKeys!.first!, let pendingTx = try await coordinator.synchronizer.sendToAddress(
zatoshi: spendAmount, spendingKey: self.coordinator.spendingKeys!.first!,
toAddress: self.testRecipientAddress, zatoshi: spendAmount,
memo: "this is a test", toAddress: self.testRecipientAddress,
from: 0, memo: "this is a test",
resultBlock: { result in from: 0)
switch result { pendingEntity = pendingTx
case .failure(let e): sendExpectation.fulfill()
self.handleError(e) } catch {
case .success(let pendingTx): self.handleError(error)
pendingEntity = pendingTx }
}
sendExpectation.fulfill()
}
)
wait(for: [sendExpectation], timeout: 11) wait(for: [sendExpectation], timeout: 11)
@ -197,9 +209,16 @@ class NetworkUpgradeTests: XCTestCase {
let afterSendExpectation = XCTestExpectation(description: "aftersend") let afterSendExpectation = XCTestExpectation(description: "aftersend")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
afterSendExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
afterSendExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [afterSendExpectation], timeout: 10) wait(for: [afterSendExpectation], timeout: 10)
} }
@ -207,7 +226,7 @@ class NetworkUpgradeTests: XCTestCase {
/** /**
Given that a wallet sends funds some between (activation - expiry_height) and activation, those funds are shown as sent if mined. Given that a wallet sends funds some between (activation - expiry_height) and activation, those funds are shown as sent if mined.
*/ */
func testSpendMinedSpendThatExpiresOnActivation() throws { func testSpendMinedSpendThatExpiresOnActivation() async throws {
try FakeChainBuilder.buildChain( try FakeChainBuilder.buildChain(
darksideWallet: coordinator.service, darksideWallet: coordinator.service,
birthday: birthday, birthday: birthday,
@ -222,9 +241,16 @@ class NetworkUpgradeTests: XCTestCase {
try coordinator.applyStaged(blockheight: activationHeight - 10) try coordinator.applyStaged(blockheight: activationHeight - 10)
sleep(3) sleep(3)
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
firstSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
firstSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 120) wait(for: [firstSyncExpectation], timeout: 120)
let verifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance()
@ -237,22 +263,18 @@ class NetworkUpgradeTests: XCTestCase {
/* /*
send transaction to recipient address send transaction to recipient address
*/ */
coordinator.synchronizer.sendToAddress( do {
spendingKey: self.coordinator.spendingKeys!.first!, let pendingTx = try await coordinator.synchronizer.sendToAddress(
zatoshi: spendAmount, spendingKey: self.coordinator.spendingKeys!.first!,
toAddress: self.testRecipientAddress, zatoshi: spendAmount,
memo: "this is a test", toAddress: self.testRecipientAddress,
from: 0, memo: "this is a test",
resultBlock: { result in from: 0)
switch result { pendingEntity = pendingTx
case .failure(let e): sendExpectation.fulfill()
self.handleError(e) } catch {
case .success(let pendingTx): self.handleError(error)
pendingEntity = pendingTx }
}
sendExpectation.fulfill()
}
)
wait(for: [sendExpectation], timeout: 11) wait(for: [sendExpectation], timeout: 11)
@ -283,9 +305,16 @@ class NetworkUpgradeTests: XCTestCase {
let afterSendExpectation = XCTestExpectation(description: "aftersend") let afterSendExpectation = XCTestExpectation(description: "aftersend")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
afterSendExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
afterSendExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [afterSendExpectation], timeout: 10) wait(for: [afterSendExpectation], timeout: 10)
@ -303,7 +332,7 @@ class NetworkUpgradeTests: XCTestCase {
/** /**
Given that a wallet sends funds somewhere between (activation - expiry_height) and activation, those funds are available if expired after expiration height. Given that a wallet sends funds somewhere between (activation - expiry_height) and activation, those funds are available if expired after expiration height.
*/ */
func testExpiredSpendAfterActivation() throws { func testExpiredSpendAfterActivation() async throws {
try FakeChainBuilder.buildChain( try FakeChainBuilder.buildChain(
darksideWallet: coordinator.service, darksideWallet: coordinator.service,
birthday: birthday, birthday: birthday,
@ -320,9 +349,16 @@ class NetworkUpgradeTests: XCTestCase {
let verifiedBalancePreActivation: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalancePreActivation: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance()
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
firstSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
firstSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 120) wait(for: [firstSyncExpectation], timeout: 120)
let verifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance()
@ -338,22 +374,18 @@ class NetworkUpgradeTests: XCTestCase {
/* /*
send transaction to recipient address send transaction to recipient address
*/ */
coordinator.synchronizer.sendToAddress( do {
spendingKey: self.coordinator.spendingKeys!.first!, let pendingTx = try await coordinator.synchronizer.sendToAddress(
zatoshi: spendAmount, spendingKey: self.coordinator.spendingKeys!.first!,
toAddress: self.testRecipientAddress, zatoshi: spendAmount,
memo: "this is a test", toAddress: self.testRecipientAddress,
from: 0, memo: "this is a test",
resultBlock: { result in from: 0)
switch result { pendingEntity = pendingTx
case .failure(let e): sendExpectation.fulfill()
self.handleError(e) } catch {
case .success(let pendingTx): self.handleError(error)
pendingEntity = pendingTx }
}
sendExpectation.fulfill()
}
)
wait(for: [sendExpectation], timeout: 11) wait(for: [sendExpectation], timeout: 11)
@ -380,9 +412,16 @@ class NetworkUpgradeTests: XCTestCase {
let afterSendExpectation = XCTestExpectation(description: "aftersend") let afterSendExpectation = XCTestExpectation(description: "aftersend")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
afterSendExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
afterSendExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [afterSendExpectation], timeout: 10) wait(for: [afterSendExpectation], timeout: 10)
@ -400,7 +439,7 @@ class NetworkUpgradeTests: XCTestCase {
/** /**
Given that a wallet has notes both received prior and after activation these can be combined to supply a larger amount spend. Given that a wallet has notes both received prior and after activation these can be combined to supply a larger amount spend.
*/ */
func testCombinePreActivationNotesAndPostActivationNotesOnSpend() throws { func testCombinePreActivationNotesAndPostActivationNotesOnSpend() async throws {
try FakeChainBuilder.buildChainMixedFunds( try FakeChainBuilder.buildChainMixedFunds(
darksideWallet: coordinator.service, darksideWallet: coordinator.service,
birthday: birthday, birthday: birthday,
@ -415,9 +454,16 @@ class NetworkUpgradeTests: XCTestCase {
try coordinator.applyStaged(blockheight: activationHeight - 1) try coordinator.applyStaged(blockheight: activationHeight - 1)
sleep(3) sleep(3)
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
firstSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
firstSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 120) wait(for: [firstSyncExpectation], timeout: 120)
@ -427,10 +473,17 @@ class NetworkUpgradeTests: XCTestCase {
sleep(2) sleep(2)
let secondSyncExpectation = XCTestExpectation(description: "second sync") let secondSyncExpectation = XCTestExpectation(description: "second sync")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
secondSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
secondSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [secondSyncExpectation], timeout: 10) wait(for: [secondSyncExpectation], timeout: 10)
guard try !coordinator.synchronizer.allReceivedTransactions().filter({ $0.minedHeight > activationHeight }).isEmpty else { guard try !coordinator.synchronizer.allReceivedTransactions().filter({ $0.minedHeight > activationHeight }).isEmpty else {
XCTFail("this test requires funds received after activation height") XCTFail("this test requires funds received after activation height")
@ -450,22 +503,18 @@ class NetworkUpgradeTests: XCTestCase {
/* /*
send transaction to recipient address send transaction to recipient address
*/ */
coordinator.synchronizer.sendToAddress( do {
spendingKey: self.coordinator.spendingKeys!.first!, let pendingTx = try await coordinator.synchronizer.sendToAddress(
zatoshi: spendAmount, spendingKey: self.coordinator.spendingKeys!.first!,
toAddress: self.testRecipientAddress, zatoshi: spendAmount,
memo: "this is a test", toAddress: self.testRecipientAddress,
from: 0, memo: "this is a test",
resultBlock: { result in from: 0)
switch result { pendingEntity = pendingTx
case .failure(let e): sendExpectation.fulfill()
self.handleError(e) } catch {
case .success(let pendingTx): self.handleError(error)
pendingEntity = pendingTx }
}
sendExpectation.fulfill()
}
)
wait(for: [sendExpectation], timeout: 15) wait(for: [sendExpectation], timeout: 15)

View File

@ -61,7 +61,7 @@ class PendingTransactionUpdatesTest: XCTestCase {
reorgExpectation.fulfill() reorgExpectation.fulfill()
} }
func testPendingTransactionMinedHeightUpdated() throws { func testPendingTransactionMinedHeightUpdated() async throws {
/* /*
1. create fake chain 1. create fake chain
*/ */
@ -78,10 +78,16 @@ class PendingTransactionUpdatesTest: XCTestCase {
1a. sync to latest height 1a. sync to latest height
*/ */
LoggerProxy.info("1a. sync to latest height") LoggerProxy.info("1a. sync to latest height")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
firstSyncExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
firstSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 5) wait(for: [firstSyncExpectation], timeout: 5)
sleep(1) sleep(1)
@ -93,23 +99,19 @@ class PendingTransactionUpdatesTest: XCTestCase {
2. send transaction to recipient address 2. send transaction to recipient address
*/ */
LoggerProxy.info("2. send transaction to recipient address") LoggerProxy.info("2. send transaction to recipient address")
coordinator.synchronizer.sendToAddress( do {
// swiftlint:disable:next force_unwrapping let pendingTx = try await coordinator.synchronizer.sendToAddress(
spendingKey: self.coordinator.spendingKeys!.first!, // swiftlint:disable:next force_unwrapping
zatoshi: Zatoshi(20000), spendingKey: self.coordinator.spendingKeys!.first!,
toAddress: self.testRecipientAddress, zatoshi: Zatoshi(20000),
memo: "this is a test", toAddress: self.testRecipientAddress,
from: 0, memo: "this is a test",
resultBlock: { result in from: 0)
switch result { pendingEntity = pendingTx
case .failure(let e): sendExpectation.fulfill()
self.handleError(e) } catch {
case .success(let pendingTx): self.handleError(error)
pendingEntity = pendingTx }
}
sendExpectation.fulfill()
}
)
wait(for: [sendExpectation], timeout: 11) wait(for: [sendExpectation], timeout: 11)
@ -167,13 +169,17 @@ class PendingTransactionUpdatesTest: XCTestCase {
LoggerProxy.info("6. sync to latest height") LoggerProxy.info("6. sync to latest height")
let secondSyncExpectation = XCTestExpectation(description: "after send expectation") let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
try coordinator.sync( try await withCheckedThrowingContinuation { continuation in
completion: { _ in do {
secondSyncExpectation.fulfill() try coordinator.sync(completion: { synchronizer in
}, secondSyncExpectation.fulfill()
error: self.handleError continuation.resume()
) }, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [secondSyncExpectation], timeout: 5) wait(for: [secondSyncExpectation], timeout: 5)
XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count, 1) XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count, 1)
@ -207,10 +213,17 @@ class PendingTransactionUpdatesTest: XCTestCase {
*/ */
LoggerProxy.info("last sync to latest height: \(lastStageHeight)") LoggerProxy.info("last sync to latest height: \(lastStageHeight)")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
syncToConfirmExpectation.fulfill() do {
}, error: self.handleError) try coordinator.sync(completion: { synchronizer in
syncToConfirmExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [syncToConfirmExpectation], timeout: 6) wait(for: [syncToConfirmExpectation], timeout: 6)
var supposedlyPendingUnexistingTransaction: PendingTransactionEntity? var supposedlyPendingUnexistingTransaction: PendingTransactionEntity?

View File

@ -107,7 +107,7 @@ class RewindRescanTests: XCTestCase {
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance()) XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
} }
func testRescanToHeight() throws { func testRescanToHeight() async throws {
// 1 sync and get spendable funds // 1 sync and get spendable funds
try FakeChainBuilder.buildChainWithTxsFarFromEachOther( try FakeChainBuilder.buildChainWithTxsFarFromEachOther(
darksideWallet: coordinator.service, darksideWallet: coordinator.service,
@ -121,13 +121,16 @@ class RewindRescanTests: XCTestCase {
let initialVerifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance() let initialVerifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance()
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation") let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync( try await withCheckedThrowingContinuation { continuation in
completion: { _ in do {
firstSyncExpectation.fulfill() try coordinator.sync(completion: { synchronizer in
}, firstSyncExpectation.fulfill()
error: handleError continuation.resume()
) }, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 20) wait(for: [firstSyncExpectation], timeout: 20)
let verifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance: Zatoshi = coordinator.synchronizer.initializer.getBalance() let totalBalance: Zatoshi = coordinator.synchronizer.initializer.getBalance()
@ -154,10 +157,17 @@ class RewindRescanTests: XCTestCase {
let secondScanExpectation = XCTestExpectation(description: "rescan") let secondScanExpectation = XCTestExpectation(description: "rescan")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
secondScanExpectation.fulfill() do {
}, error: handleError) try coordinator.sync(completion: { synchronizer in
secondScanExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [secondScanExpectation], timeout: 20) wait(for: [secondScanExpectation], timeout: 20)
// verify that the balance still adds up // verify that the balance still adds up
@ -166,20 +176,16 @@ class RewindRescanTests: XCTestCase {
// try to spend the funds // try to spend the funds
let sendExpectation = XCTestExpectation(description: "after rewind expectation") let sendExpectation = XCTestExpectation(description: "after rewind expectation")
coordinator.synchronizer.sendToAddress( do {
spendingKey: coordinator.spendingKey, let pendingTx = try await coordinator.synchronizer.sendToAddress(
zatoshi: Zatoshi(1000), spendingKey: coordinator.spendingKey,
toAddress: testRecipientAddress, zatoshi: Zatoshi(1000),
memo: nil, toAddress: testRecipientAddress,
from: 0 memo: nil,
) { result in from: 0)
sendExpectation.fulfill() XCTAssertEqual(Zatoshi(1000), pendingTx.value)
switch result { } catch {
case .success(let pendingTx): XCTFail("sending fail: \(error)")
XCTAssertEqual(Zatoshi(1000), pendingTx.value)
case .failure(let error):
XCTFail("sending fail: \(error)")
}
} }
wait(for: [sendExpectation], timeout: 15) wait(for: [sendExpectation], timeout: 15)
} }
@ -231,7 +237,7 @@ class RewindRescanTests: XCTestCase {
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance()) XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
} }
func testRewindAfterSendingTransaction() throws { func testRewindAfterSendingTransaction() async throws {
let notificationHandler = SDKSynchonizerListener() let notificationHandler = SDKSynchonizerListener()
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation") let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation") let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
@ -246,10 +252,16 @@ class RewindRescanTests: XCTestCase {
sleep(1) sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation") let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { _ in try await withCheckedThrowingContinuation { continuation in
firstSyncExpectation.fulfill() do {
}, error: handleError) try coordinator.sync(completion: { synchronizer in
firstSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [firstSyncExpectation], timeout: 12) wait(for: [firstSyncExpectation], timeout: 12)
// 2 check that there are no unconfirmed funds // 2 check that there are no unconfirmed funds
@ -267,20 +279,17 @@ class RewindRescanTests: XCTestCase {
return return
} }
var pendingTx: PendingTransactionEntity? var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress( do {
spendingKey: spendingKey, let transaction = try await coordinator.synchronizer.sendToAddress(
zatoshi: maxBalance, spendingKey: spendingKey,
toAddress: testRecipientAddress, zatoshi: maxBalance,
memo: "test send \(self.description) \(Date().description)", toAddress: testRecipientAddress,
from: 0 memo: "test send \(self.description) \(Date().description)",
) { result in from: 0)
switch result { pendingTx = transaction
case .failure(let error):
XCTFail("sendToAddress failed: \(error)")
case .success(let transaction):
pendingTx = transaction
}
self.sentTransactionExpectation.fulfill() self.sentTransactionExpectation.fulfill()
} catch {
XCTFail("sendToAddress failed: \(error)")
} }
wait(for: [sentTransactionExpectation], timeout: 20) wait(for: [sentTransactionExpectation], timeout: 20)
guard let pendingTx = pendingTx else { guard let pendingTx = pendingTx else {
@ -320,25 +329,30 @@ class RewindRescanTests: XCTestCase {
let mineExpectation = XCTestExpectation(description: "mineTxExpectation") let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
try coordinator.sync( try await withCheckedThrowingContinuation { continuation in
completion: { synchronizer in do {
let pendingTransaction = synchronizer.pendingTransactions try coordinator.sync(
.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) completion: { synchronizer in
XCTAssertNotNil(pendingTransaction, "pending transaction should have been mined by now") let pendingTransaction = synchronizer.pendingTransactions
XCTAssertTrue(pendingTransaction?.isMined ?? false) .first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
XCTAssertEqual(pendingTransaction?.minedHeight, sentTxHeight) XCTAssertNotNil(pendingTransaction, "pending transaction should have been mined by now")
mineExpectation.fulfill() XCTAssertTrue(pendingTransaction?.isMined ?? false)
}, XCTAssertEqual(pendingTransaction?.minedHeight, sentTxHeight)
error: { error in mineExpectation.fulfill()
guard let e = error else { continuation.resume()
XCTFail("unknown error syncing after sending transaction") }, error: { error in
return guard let error else {
} XCTFail("unknown error syncing after sending transaction")
return
XCTFail("Error: \(e)") }
XCTFail("Error: \(error)")
}
)
} catch {
continuation.resume(throwing: error)
} }
) }
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5) wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
// 7 advance to confirmation // 7 advance to confirmation
@ -375,15 +389,16 @@ class RewindRescanTests: XCTestCase {
XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)") XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)")
} }
try coordinator.sync( try await withCheckedThrowingContinuation { continuation in
completion: { _ in do {
confirmExpectation.fulfill() try coordinator.sync(completion: { synchronizer in
}, confirmExpectation.fulfill()
error: { e in continuation.resume()
self.handleError(e) }, error: self.handleError)
} catch {
continuation.resume(throwing: error)
} }
) }
wait(for: [confirmExpectation], timeout: 10) wait(for: [confirmExpectation], timeout: 10)
let confirmedPending = try coordinator.synchronizer.allPendingTransactions() let confirmedPending = try coordinator.synchronizer.allPendingTransactions()

View File

@ -69,7 +69,7 @@ class Z2TReceiveTests: XCTestCase {
self.foundTransactionsExpectation.fulfill() self.foundTransactionsExpectation.fulfill()
} }
func testFoundTransactions() throws { func testFoundTransactions() async throws {
subscribeToFoundTransactions() subscribeToFoundTransactions()
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName) try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName)
let receivedTxHeight: BlockHeight = 663188 let receivedTxHeight: BlockHeight = 663188
@ -85,42 +85,42 @@ class Z2TReceiveTests: XCTestCase {
/* /*
3. sync up to received_Tx_height 3. sync up to received_Tx_height
*/ */
try coordinator.sync( try await withCheckedThrowingContinuation { continuation in
completion: { _ in do {
preTxExpectation.fulfill() try coordinator.sync(completion: { synchronizer in
}, preTxExpectation.fulfill()
error: self.handleError continuation.resume()
) }, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [preTxExpectation, foundTransactionsExpectation], timeout: 5) wait(for: [preTxExpectation, foundTransactionsExpectation], timeout: 5)
let sendExpectation = XCTestExpectation(description: "sendToAddress") let sendExpectation = XCTestExpectation(description: "sendToAddress")
var pendingEntity: PendingTransactionEntity? var pendingEntity: PendingTransactionEntity?
var error: Error? var testError: Error?
let sendAmount = Zatoshi(10000) let sendAmount = Zatoshi(10000)
/* /*
4. create transaction 4. create transaction
*/ */
coordinator.synchronizer.sendToAddress( do {
spendingKey: coordinator.spendingKeys!.first!, let pending = try await coordinator.synchronizer.sendToAddress(
zatoshi: sendAmount, spendingKey: coordinator.spendingKeys!.first!,
toAddress: testRecipientAddress, zatoshi: sendAmount,
memo: "test transaction", toAddress: testRecipientAddress,
from: 0 memo: "test transaction",
) { result in from: 0)
switch result { pendingEntity = pending
case .success(let pending):
pendingEntity = pending
case .failure(let e):
error = e
}
sendExpectation.fulfill() sendExpectation.fulfill()
} catch {
testError = error
} }
wait(for: [sendExpectation], timeout: 12) wait(for: [sendExpectation], timeout: 12)
guard pendingEntity != nil else { guard pendingEntity != nil else {
XCTFail("error sending to address. Error: \(String(describing: error))") XCTFail("error sending to address. Error: \(String(describing: testError))")
return return
} }
@ -154,13 +154,20 @@ class Z2TReceiveTests: XCTestCase {
*/ */
let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation") let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation")
try coordinator.sync(completion: { synchronizer in try await withCheckedThrowingContinuation { continuation in
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight do {
XCTAssertEqual(pMinedHeight, sentTxHeight) try coordinator.sync(completion: { synchronizer in
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
sentTxSyncExpectation.fulfill() XCTAssertEqual(pMinedHeight, sentTxHeight)
}, error: self.handleError)
sentTxSyncExpectation.fulfill()
continuation.resume()
}, error: self.handleError)
} catch {
continuation.resume(throwing: error)
}
}
wait(for: [sentTxSyncExpectation, foundTransactionsExpectation], timeout: 5) wait(for: [sentTxSyncExpectation, foundTransactionsExpectation], timeout: 5)
} }