[486] sendToAddress async/await
- sendToAddress and SaplingParameterDownloader refactored to async - unit tests WIP [486] sendToAddress async/await - testing code cleanup [#486] sendToAddress async/await - reducing number of Tasks in Sample app [#486] sendToAddress async/await - I finally figure out how to make the dark side tests async, using new sendToAddress APIs and pass, POC done, 18 more tests to refactor [#486] sendToAddress async/await - async sendToAddress unit test refactored except NetworkUpgradeTests [#486] sendToAddress async/await - NetworkUpgradeTests refactored to async API [#486] sendToAddress async/await - cleanup [#486] sendToAddress async/await (#536) - PR comments resolved
This commit is contained in:
parent
90f38973ac
commit
61683a85f3
|
@ -79,25 +79,21 @@ class SaplingParametersViewController: UIViewController {
|
|||
@IBAction func download(_ sender: Any) {
|
||||
let outputParameter = try! outputParamsURLHelper()
|
||||
let spendParameter = try! spendParamsURLHelper()
|
||||
SaplingParameterDownloader.downloadParamsIfnotPresent(
|
||||
spendURL: spendParameter,
|
||||
outputURL: outputParameter,
|
||||
result: { result in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
switch result {
|
||||
case .success(let urls):
|
||||
self.spendPath.text = urls.spend.path
|
||||
self.outputPath.text = urls.output.path
|
||||
self.updateColor()
|
||||
self.updateButtons()
|
||||
|
||||
case .failure(let error):
|
||||
self.showError(error)
|
||||
}
|
||||
}
|
||||
|
||||
Task { @MainActor in
|
||||
do {
|
||||
let urls = try await SaplingParameterDownloader.downloadParamsIfnotPresent(
|
||||
spendURL: spendParameter,
|
||||
outputURL: outputParameter
|
||||
)
|
||||
spendPath.text = urls.spend.path
|
||||
outputPath.text = urls.output.path
|
||||
updateColor()
|
||||
updateButtons()
|
||||
} catch {
|
||||
showError(error)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func fileExists(_ path: String) -> Bool {
|
||||
|
|
|
@ -214,26 +214,20 @@ class SendViewController: UIViewController {
|
|||
|
||||
KRProgressHUD.show()
|
||||
|
||||
synchronizer.sendToAddress(
|
||||
spendingKey: address,
|
||||
zatoshi: zec,
|
||||
toAddress: recipient,
|
||||
memo: !self.memoField.text.isEmpty ? self.memoField.text : nil,
|
||||
from: 0
|
||||
) { [weak self] result in
|
||||
DispatchQueue.main.async {
|
||||
Task { @MainActor in
|
||||
do {
|
||||
let pendingTransaction = try await synchronizer.sendToAddress(
|
||||
spendingKey: address,
|
||||
zatoshi: zec,
|
||||
toAddress: recipient,
|
||||
memo: !self.memoField.text.isEmpty ? self.memoField.text : nil,
|
||||
from: 0
|
||||
)
|
||||
KRProgressHUD.dismiss()
|
||||
}
|
||||
|
||||
switch result {
|
||||
case .success(let pendingTransaction):
|
||||
loggerProxy.info("transaction created: \(pendingTransaction)")
|
||||
|
||||
case .failure(let error):
|
||||
DispatchQueue.main.async {
|
||||
self?.fail(error)
|
||||
loggerProxy.error("SEND FAILED: \(error)")
|
||||
}
|
||||
} catch {
|
||||
fail(error)
|
||||
loggerProxy.error("SEND FAILED: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -320,48 +320,35 @@ public class Initializer {
|
|||
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 outputParameterPresent = isOutputParameterPresent()
|
||||
|
||||
if spendParameterPresent && outputParameterPresent {
|
||||
result(.success(true))
|
||||
return
|
||||
return true
|
||||
}
|
||||
|
||||
let outputURL = self.outputParamsURL
|
||||
let spendURL = self.spendParamsURL
|
||||
|
||||
if !outputParameterPresent {
|
||||
SaplingParameterDownloader.downloadOutputParameter(outputURL) { outputResult in
|
||||
switch outputResult {
|
||||
case .failure(let error):
|
||||
result(.failure(error))
|
||||
case .success:
|
||||
guard !spendParameterPresent else {
|
||||
result(.success(false))
|
||||
return
|
||||
}
|
||||
SaplingParameterDownloader.downloadSpendParameter(spendURL) { spendResult in
|
||||
switch spendResult {
|
||||
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))
|
||||
}
|
||||
do {
|
||||
if !outputParameterPresent && !spendParameterPresent {
|
||||
async let outputURLRequest = SaplingParameterDownloader.downloadOutputParameter(outputURL)
|
||||
async let spendURLRequest = SaplingParameterDownloader.downloadSpendParameter(spendURL)
|
||||
_ = try await [outputURLRequest, spendURLRequest]
|
||||
return false
|
||||
} else if !outputParameterPresent {
|
||||
try await SaplingParameterDownloader.downloadOutputParameter(outputURL)
|
||||
return false
|
||||
} else if !spendParameterPresent {
|
||||
try await SaplingParameterDownloader.downloadSpendParameter(spendURL)
|
||||
return false
|
||||
}
|
||||
} catch {
|
||||
throw error
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -107,40 +107,20 @@ public protocol Synchronizer {
|
|||
/// - 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
|
||||
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.
|
||||
/// - Parameter spendingKey: the key that allows spends to occur.
|
||||
/// - Parameter zatoshi: the amount to send in Zatoshi.
|
||||
/// - 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.
|
||||
// swiftlint:disable:next function_parameter_count
|
||||
func sendToAddress(
|
||||
spendingKey: String,
|
||||
zatoshi: Zatoshi,
|
||||
toAddress: String,
|
||||
memo: String?,
|
||||
from accountIndex: Int,
|
||||
resultBlock: @escaping (_ result: Result<PendingTransactionEntity, Error>) -> Void
|
||||
)
|
||||
from accountIndex: Int
|
||||
) async throws -> PendingTransactionEntity
|
||||
|
||||
/// Sends zatoshi.
|
||||
/// - Parameter spendingKey: the key that allows spends to occur.
|
||||
|
|
|
@ -455,52 +455,27 @@ public class SDKSynchronizer: Synchronizer {
|
|||
}
|
||||
|
||||
// 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(
|
||||
spendingKey: String,
|
||||
zatoshi: Zatoshi,
|
||||
toAddress: String,
|
||||
memo: String?,
|
||||
from accountIndex: Int,
|
||||
resultBlock: @escaping (Result<PendingTransactionEntity, Error>) -> Void
|
||||
) {
|
||||
initializer.downloadParametersIfNeeded { downloadResult in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
switch downloadResult {
|
||||
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)))
|
||||
}
|
||||
}
|
||||
from accountIndex: Int
|
||||
) async throws -> PendingTransactionEntity {
|
||||
do {
|
||||
try await initializer.downloadParametersIfNeeded()
|
||||
} catch {
|
||||
throw SynchronizerError.parameterMissing(underlyingError: error)
|
||||
}
|
||||
|
||||
return try await createToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: zatoshi,
|
||||
toAddress: toAddress,
|
||||
memo: memo,
|
||||
from: accountIndex
|
||||
)
|
||||
}
|
||||
|
||||
public func shieldFunds(
|
||||
|
@ -547,16 +522,14 @@ public class SDKSynchronizer: Synchronizer {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable:next function_parameter_count
|
||||
|
||||
func createToAddress(
|
||||
spendingKey: String,
|
||||
zatoshi: Zatoshi,
|
||||
toAddress: String,
|
||||
memo: String?,
|
||||
from accountIndex: Int,
|
||||
resultBlock: @escaping (Result<PendingTransactionEntity, Error>) -> Void
|
||||
) {
|
||||
from accountIndex: Int
|
||||
) async throws -> PendingTransactionEntity {
|
||||
do {
|
||||
let spend = try transactionManager.initSpend(
|
||||
zatoshi: zatoshi,
|
||||
|
@ -565,21 +538,14 @@ public class SDKSynchronizer: Synchronizer {
|
|||
from: accountIndex
|
||||
)
|
||||
|
||||
// TODO: Task will be removed when this method is changed to async, issue 487, https://github.com/zcash/ZcashLightClientKit/issues/487
|
||||
Task {
|
||||
do {
|
||||
let transaction = try await transactionManager.encode(
|
||||
spendingKey: spendingKey,
|
||||
pendingTransaction: spend
|
||||
)
|
||||
let submittedTx = try await transactionManager.submit(pendingTransaction: transaction)
|
||||
resultBlock(.success(submittedTx))
|
||||
} catch {
|
||||
resultBlock(.failure(error))
|
||||
}
|
||||
}
|
||||
let transaction = try await transactionManager.encode(
|
||||
spendingKey: spendingKey,
|
||||
pendingTransaction: spend
|
||||
)
|
||||
let submittedTx = try await transactionManager.submit(pendingTransaction: transaction)
|
||||
return submittedTx
|
||||
} catch {
|
||||
resultBlock(.failure(error))
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,33 +15,46 @@ public enum SaplingParameterDownloader {
|
|||
case failed(error: Error)
|
||||
}
|
||||
|
||||
/**
|
||||
Download a Spend parameter from default host and stores it at given URL
|
||||
- Parameters:
|
||||
- at: The destination URL for the download
|
||||
- result: block to handle the download success or error
|
||||
*/
|
||||
public static func downloadSpendParameter(_ at: URL, result: @escaping (Result<URL, Error>) -> Void) {
|
||||
/// Download a Spend parameter from default host and stores it at given URL
|
||||
/// - Parameters:
|
||||
/// - at: The destination URL for the download
|
||||
@discardableResult
|
||||
public static func downloadSpendParameter(_ at: URL) async throws -> URL {
|
||||
guard let url = URL(string: spendParamsURLString) else {
|
||||
result(.failure(Errors.invalidURL(url: spendParamsURLString)))
|
||||
return
|
||||
throw Errors.invalidURL(url: spendParamsURLString)
|
||||
}
|
||||
|
||||
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
|
||||
- Parameters:
|
||||
- at: The destination URL for the download
|
||||
- result: block to handle the download success or error
|
||||
*/
|
||||
public static func downloadOutputParameter(_ at: URL, result: @escaping (Result<URL, Error>) -> Void) {
|
||||
|
||||
/// Download an Output parameter from default host and stores it at given URL
|
||||
/// - Parameters:
|
||||
/// - at: The destination URL for the download
|
||||
@discardableResult
|
||||
public static func downloadOutputParameter(_ at: URL) async throws -> URL {
|
||||
guard let url = URL(string: outputParamsURLString) else {
|
||||
result(.failure(Errors.invalidURL(url: outputParamsURLString)))
|
||||
return
|
||||
throw Errors.invalidURL(url: outputParamsURLString)
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -61,52 +74,39 @@ public enum SaplingParameterDownloader {
|
|||
|
||||
task.resume()
|
||||
}
|
||||
/**
|
||||
Downloads the parameters if not present and provides the resulting URLs for both parameters
|
||||
- Parameters:
|
||||
- spendURL: 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
|
||||
*/
|
||||
|
||||
/// Downloads the parameters if not present and provides the resulting URLs for both parameters
|
||||
/// - Parameters:
|
||||
/// - spendURL: URL to check whether the parameter is already downloaded
|
||||
/// - outputURL: URL to check whether the parameter is already downloaded
|
||||
public static func downloadParamsIfnotPresent(
|
||||
spendURL: URL,
|
||||
outputURL: URL,
|
||||
result: @escaping (Result<(spend: URL, output: URL), Error>) -> Void
|
||||
) {
|
||||
ensureSpendParameter(at: spendURL) { spendResult in
|
||||
switch spendResult {
|
||||
case .success(let spendResultURL):
|
||||
ensureOutputParameter(at: outputURL) { outputResult in
|
||||
switch outputResult {
|
||||
case .success(let outputResultURL):
|
||||
result(.success((spendResultURL, outputResultURL)))
|
||||
case .failure(let outputResultError):
|
||||
result(.failure(Errors.failed(error: outputResultError)))
|
||||
}
|
||||
}
|
||||
case .failure(let spendResultError):
|
||||
result(.failure(Errors.failed(error: spendResultError)))
|
||||
}
|
||||
outputURL: URL
|
||||
) async throws -> (spend: URL, output: URL) {
|
||||
do {
|
||||
async let spendResultURL = ensureSpendParameter(at: spendURL)
|
||||
async let outputResultURL = ensureOutputParameter(at: outputURL)
|
||||
|
||||
let results = try await [spendResultURL, outputResultURL]
|
||||
return (spend: results[0], output: results[1])
|
||||
} catch {
|
||||
throw Errors.failed(error: error)
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
DispatchQueue.global().async {
|
||||
result(.success(url))
|
||||
}
|
||||
return url
|
||||
} 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) {
|
||||
DispatchQueue.global().async {
|
||||
result(.success(url))
|
||||
}
|
||||
return url
|
||||
} else {
|
||||
downloadOutputParameter(url, result: result)
|
||||
return try await downloadOutputParameter(url)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import XCTest
|
|||
@testable import ZcashLightClientKit
|
||||
|
||||
// swiftlint:disable implicitly_unwrapped_optional force_unwrapping type_body_length
|
||||
//@MainActor
|
||||
class AdvancedReOrgTests: XCTestCase {
|
||||
// TODO: Parameterize this from environment?
|
||||
// swiftlint:disable:next line_length
|
||||
|
@ -268,7 +269,7 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
12. applyStaged(sentTx + 10)
|
||||
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)
|
||||
let receivedTxHeight: BlockHeight = 663188
|
||||
var initialTotalBalance = Zatoshi(-1)
|
||||
|
@ -280,44 +281,51 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
|
||||
sleep(2)
|
||||
let preTxExpectation = XCTestExpectation(description: "pre receive")
|
||||
|
||||
|
||||
/*
|
||||
3. sync up to received_Tx_height
|
||||
*/
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
initialTotalBalance = synchronizer.initializer.getBalance()
|
||||
preTxExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
initialTotalBalance = synchronizer.initializer.getBalance()
|
||||
continuation.resume()
|
||||
preTxExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [preTxExpectation], timeout: 5)
|
||||
|
||||
let sendExpectation = XCTestExpectation(description: "sendToAddress")
|
||||
var pendingEntity: PendingTransactionEntity?
|
||||
var error: Error?
|
||||
var testError: Error?
|
||||
let sendAmount = Zatoshi(10000)
|
||||
|
||||
/*
|
||||
4. create transaction
|
||||
*/
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: coordinator.spendingKeys!.first!,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test transaction",
|
||||
from: 0
|
||||
) { result in
|
||||
switch result {
|
||||
case .success(let pending):
|
||||
pendingEntity = pending
|
||||
case .failure(let e):
|
||||
error = e
|
||||
}
|
||||
do {
|
||||
let pendingTx = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: coordinator.spendingKeys!.first!,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test transaction",
|
||||
from: 0
|
||||
)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
}
|
||||
wait(for: [sendExpectation], timeout: 12)
|
||||
|
||||
guard let pendingTx = pendingEntity else {
|
||||
} catch {
|
||||
testError = 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
|
||||
}
|
||||
|
||||
|
@ -349,15 +357,18 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
*/
|
||||
let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation")
|
||||
|
||||
try coordinator.sync(
|
||||
completion: { synchronizer in
|
||||
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
|
||||
XCTAssertEqual(pMinedHeight, sentTxHeight)
|
||||
|
||||
sentTxSyncExpectation.fulfill()
|
||||
},
|
||||
error: self.handleError
|
||||
)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
|
||||
XCTAssertEqual(pMinedHeight, sentTxHeight)
|
||||
continuation.resume()
|
||||
sentTxSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [sentTxSyncExpectation], timeout: 5)
|
||||
|
||||
|
@ -375,18 +386,22 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
|
||||
sleep(2)
|
||||
let afterReOrgExpectation = XCTestExpectation(description: "after ReOrg Expectation")
|
||||
try coordinator.sync(
|
||||
completion: { synchronizer in
|
||||
/*
|
||||
11. verify that the sent tx is mined and balance is correct
|
||||
*/
|
||||
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
|
||||
XCTAssertEqual(pMinedHeight, sentTxHeight)
|
||||
XCTAssertEqual(initialTotalBalance - sendAmount - Zatoshi(1000), synchronizer.initializer.getBalance()) // fee change on this branch
|
||||
afterReOrgExpectation.fulfill()
|
||||
},
|
||||
error: self.handleError
|
||||
)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
/*
|
||||
11. verify that the sent tx is mined and balance is correct
|
||||
*/
|
||||
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
|
||||
XCTAssertEqual(pMinedHeight, sentTxHeight)
|
||||
XCTAssertEqual(initialTotalBalance - sendAmount - Zatoshi(1000), synchronizer.initializer.getBalance()) // fee change on this branch
|
||||
continuation.resume()
|
||||
afterReOrgExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [afterReOrgExpectation], timeout: 5)
|
||||
|
||||
|
@ -400,10 +415,16 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
13. verify that there's no more pending transaction
|
||||
*/
|
||||
let lastSyncExpectation = XCTestExpectation(description: "sync to confirmation")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
lastSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
lastSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
func testReOrgChangesOutboundTxMinedHeight() throws {
|
||||
func testReOrgChangesOutboundTxMinedHeight() async throws {
|
||||
hookToReOrgNotification()
|
||||
|
||||
/*
|
||||
|
@ -691,9 +712,16 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
/*
|
||||
1a. sync to latest height
|
||||
*/
|
||||
try coordinator.sync(completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [firstSyncExpectation], timeout: 5)
|
||||
|
||||
|
@ -706,22 +734,18 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
/*
|
||||
2. send transaction to recipient address
|
||||
*/
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: Zatoshi(20000),
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let e):
|
||||
self.handleError(e)
|
||||
case .success(let pendingTx):
|
||||
pendingEntity = pendingTx
|
||||
}
|
||||
sendExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
do {
|
||||
let pendingTx = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: Zatoshi(20000),
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
self.handleError(error)
|
||||
}
|
||||
|
||||
wait(for: [sendExpectation], timeout: 11)
|
||||
|
||||
|
@ -761,10 +785,17 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
*/
|
||||
let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
secondSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
secondSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [secondSyncExpectation], timeout: 5)
|
||||
|
||||
XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count, 1)
|
||||
|
@ -799,10 +830,17 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
self.expectedReorgHeight = sentTxHeight + 1
|
||||
let afterReorgExpectation = XCTestExpectation(description: "after reorg sync")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
afterReorgExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
afterReorgExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [reorgExpectation, afterReorgExpectation], timeout: 5)
|
||||
|
||||
/*
|
||||
|
@ -827,10 +865,17 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
/*
|
||||
11a. sync to latest height
|
||||
*/
|
||||
try coordinator.sync(completion: { _ in
|
||||
yetAnotherExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
yetAnotherExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [yetAnotherExpectation], timeout: 5)
|
||||
|
||||
/*
|
||||
|
@ -857,10 +902,17 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
/*
|
||||
14. sync to latest height
|
||||
*/
|
||||
try coordinator.sync(completion: { _ in
|
||||
thisIsTheLastExpectationIPromess.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
thisIsTheLastExpectationIPromess.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [thisIsTheLastExpectationIPromess], timeout: 5)
|
||||
|
||||
/*
|
||||
|
@ -1034,7 +1086,7 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
8. sync to latest height
|
||||
9. verify that there's an expired transaction as a pending transaction
|
||||
*/
|
||||
func testReOrgRemovesOutboundTxAndIsNeverMined() throws {
|
||||
func testReOrgRemovesOutboundTxAndIsNeverMined() async throws {
|
||||
hookToReOrgNotification()
|
||||
|
||||
/*
|
||||
|
@ -1051,10 +1103,17 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
/*
|
||||
1a. sync to latest height
|
||||
*/
|
||||
try coordinator.sync(completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [firstSyncExpectation], timeout: 5)
|
||||
|
||||
sleep(1)
|
||||
|
@ -1066,22 +1125,18 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
/*
|
||||
2. send transaction to recipient address
|
||||
*/
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: Zatoshi(20000),
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let e):
|
||||
self.handleError(e)
|
||||
case .success(let pendingTx):
|
||||
pendingEntity = pendingTx
|
||||
}
|
||||
sendExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
do {
|
||||
let pendingTx = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: Zatoshi(20000),
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
self.handleError(error)
|
||||
}
|
||||
|
||||
wait(for: [sendExpectation], timeout: 11)
|
||||
|
||||
|
@ -1121,10 +1176,17 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
*/
|
||||
let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
secondSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
secondSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [secondSyncExpectation], timeout: 5)
|
||||
let extraBlocks = 25
|
||||
try coordinator.stageBlockCreate(height: sentTxHeight, count: extraBlocks, nonce: 5)
|
||||
|
@ -1134,10 +1196,17 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
sleep(2)
|
||||
let reorgSyncExpectation = XCTestExpectation(description: "reorg sync expectation")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
reorgSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
reorgSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [reorgExpectation, reorgSyncExpectation], timeout: 5)
|
||||
|
||||
guard let pendingTx = coordinator.synchronizer.pendingTransactions.first else {
|
||||
|
@ -1154,10 +1223,17 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
|
||||
let lastSyncExpectation = XCTestExpectation(description: "last sync expectation")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
lastSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
lastSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [lastSyncExpectation], timeout: 5)
|
||||
|
||||
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), initialTotalBalance)
|
||||
|
|
|
@ -42,7 +42,7 @@ class BalanceTests: XCTestCase {
|
|||
/**
|
||||
verify that when sending the maximum amount, the transactions are broadcasted properly
|
||||
*/
|
||||
func testMaxAmountSend() throws {
|
||||
func testMaxAmountSend() async throws {
|
||||
let notificationHandler = SDKSynchonizerListener()
|
||||
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
|
||||
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
|
||||
|
@ -57,9 +57,16 @@ class BalanceTests: XCTestCase {
|
|||
sleep(1)
|
||||
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [firstSyncExpectation], timeout: 12)
|
||||
// 2 check that there are no unconfirmed funds
|
||||
|
@ -79,22 +86,18 @@ class BalanceTests: XCTestCase {
|
|||
}
|
||||
|
||||
var pendingTx: PendingTransactionEntity?
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: maxBalance,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description) \(Date().description)",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
case .success(let transaction):
|
||||
pendingTx = transaction
|
||||
}
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
do {
|
||||
let transaction = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: maxBalance,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description) \(Date().description)",
|
||||
from: 0)
|
||||
pendingTx = transaction
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
} catch {
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
}
|
||||
|
||||
wait(for: [sentTransactionExpectation], timeout: 20)
|
||||
guard let pendingTx = pendingTx else {
|
||||
|
@ -133,23 +136,29 @@ class BalanceTests: XCTestCase {
|
|||
sleep(2) // add enhance breakpoint here
|
||||
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
||||
|
||||
try coordinator.sync(
|
||||
completion: { synchronizer in
|
||||
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
|
||||
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
|
||||
XCTAssertTrue(pendingEntity?.isMined ?? false)
|
||||
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
|
||||
mineExpectation.fulfill()
|
||||
},
|
||||
error: { error in
|
||||
guard let error = error else {
|
||||
XCTFail("unknown error syncing after sending transaction")
|
||||
return
|
||||
}
|
||||
|
||||
XCTFail("Error: \(error)")
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(
|
||||
completion: { synchronizer in
|
||||
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
|
||||
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
|
||||
XCTAssertTrue(pendingEntity?.isMined ?? false)
|
||||
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
|
||||
mineExpectation.fulfill()
|
||||
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)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
|
||||
|
||||
|
@ -166,12 +175,17 @@ class BalanceTests: XCTestCase {
|
|||
notificationHandler.synchronizerMinedTransaction = { transaction in
|
||||
XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)")
|
||||
}
|
||||
try coordinator.sync(completion: { _ in
|
||||
confirmExpectation.fulfill()
|
||||
}, error: { e in
|
||||
self.handleError(e)
|
||||
})
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
confirmExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [confirmExpectation], timeout: 5)
|
||||
|
||||
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
|
||||
*/
|
||||
func testMaxAmountMinusOneSend() throws {
|
||||
func testMaxAmountMinusOneSend() async throws {
|
||||
let notificationHandler = SDKSynchonizerListener()
|
||||
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
|
||||
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
|
||||
|
@ -201,9 +215,16 @@ class BalanceTests: XCTestCase {
|
|||
sleep(1)
|
||||
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [firstSyncExpectation], timeout: 12)
|
||||
// 2 check that there are no unconfirmed funds
|
||||
|
@ -221,24 +242,20 @@ class BalanceTests: XCTestCase {
|
|||
XCTFail("failed to create spending keys")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
var pendingTx: PendingTransactionEntity?
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: maxBalanceMinusOne,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description) \(Date().description)",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
case .success(let transaction):
|
||||
pendingTx = transaction
|
||||
}
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
do {
|
||||
let transaction = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: maxBalanceMinusOne,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description) \(Date().description)",
|
||||
from: 0)
|
||||
pendingTx = transaction
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
} catch {
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
}
|
||||
|
||||
wait(for: [sentTransactionExpectation], timeout: 20)
|
||||
guard let pendingTx = pendingTx else {
|
||||
|
@ -277,20 +294,29 @@ class BalanceTests: XCTestCase {
|
|||
sleep(2) // add enhance breakpoint here
|
||||
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
||||
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
|
||||
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
|
||||
XCTAssertTrue(pendingEntity?.isMined ?? false)
|
||||
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
|
||||
mineExpectation.fulfill()
|
||||
}, error: { error in
|
||||
guard let e = error else {
|
||||
XCTFail("unknown error syncing after sending transaction")
|
||||
return
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(
|
||||
completion: { synchronizer in
|
||||
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
|
||||
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
|
||||
XCTAssertTrue(pendingEntity?.isMined ?? false)
|
||||
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
|
||||
mineExpectation.fulfill()
|
||||
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)
|
||||
|
||||
|
@ -307,11 +333,16 @@ class BalanceTests: XCTestCase {
|
|||
notificationHandler.synchronizerMinedTransaction = { transaction in
|
||||
XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)")
|
||||
}
|
||||
try coordinator.sync(completion: { _ in
|
||||
confirmExpectation.fulfill()
|
||||
}, error: { e in
|
||||
self.handleError(e)
|
||||
})
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
confirmExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
func testSingleNoteNoChangeTransaction() throws {
|
||||
func testSingleNoteNoChangeTransaction() async throws {
|
||||
let notificationHandler = SDKSynchonizerListener()
|
||||
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
|
||||
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
|
||||
|
@ -343,10 +374,16 @@ class BalanceTests: XCTestCase {
|
|||
sleep(1)
|
||||
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
wait(for: [firstSyncExpectation], timeout: 12)
|
||||
// 2 check that there are no unconfirmed funds
|
||||
|
||||
|
@ -364,22 +401,18 @@ class BalanceTests: XCTestCase {
|
|||
return
|
||||
}
|
||||
var pendingTx: PendingTransactionEntity?
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: maxBalanceMinusOne,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description) \(Date().description)",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
case .success(let transaction):
|
||||
pendingTx = transaction
|
||||
}
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
do {
|
||||
let transaction = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: maxBalanceMinusOne,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description) \(Date().description)",
|
||||
from: 0)
|
||||
pendingTx = transaction
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
} catch {
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
}
|
||||
|
||||
wait(for: [sentTransactionExpectation], timeout: 20)
|
||||
guard let pendingTx = pendingTx else {
|
||||
|
@ -418,20 +451,29 @@ class BalanceTests: XCTestCase {
|
|||
sleep(2) // add enhance breakpoint here
|
||||
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
||||
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
|
||||
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
|
||||
XCTAssertTrue(pendingEntity?.isMined ?? false)
|
||||
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
|
||||
mineExpectation.fulfill()
|
||||
}, error: { error in
|
||||
guard let e = error else {
|
||||
XCTFail("unknown error syncing after sending transaction")
|
||||
return
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(
|
||||
completion: { synchronizer in
|
||||
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
|
||||
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
|
||||
XCTAssertTrue(pendingEntity?.isMined ?? false)
|
||||
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
|
||||
mineExpectation.fulfill()
|
||||
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)
|
||||
|
||||
|
@ -448,11 +490,16 @@ class BalanceTests: XCTestCase {
|
|||
notificationHandler.synchronizerMinedTransaction = { transaction in
|
||||
XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)")
|
||||
}
|
||||
try coordinator.sync(completion: { _ in
|
||||
confirmExpectation.fulfill()
|
||||
}, error: { e in
|
||||
self.handleError(e)
|
||||
})
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
confirmExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [confirmExpectation], timeout: 5)
|
||||
|
||||
|
@ -483,14 +530,21 @@ class BalanceTests: XCTestCase {
|
|||
Error: previous available funds equals to current funds
|
||||
*/
|
||||
// swiftlint:disable cyclomatic_complexity
|
||||
func testVerifyAvailableBalanceDuringSend() throws {
|
||||
func testVerifyAvailableBalanceDuringSend() async throws {
|
||||
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
|
||||
|
||||
try coordinator.applyStaged(blockheight: defaultLatestHeight)
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
self.syncedExpectation.fulfill()
|
||||
}, error: handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
self.syncedExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [syncedExpectation], timeout: 60)
|
||||
|
||||
|
@ -507,27 +561,23 @@ class BalanceTests: XCTestCase {
|
|||
XCTAssertTrue(presendVerifiedBalance >= network.constants.defaultFee(for: defaultLatestHeight) + sendAmount)
|
||||
|
||||
var pendingTx: PendingTransactionEntity?
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description) \(Date().description)",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
/*
|
||||
balance should be the same as before sending if transaction failed
|
||||
*/
|
||||
XCTAssertEqual(self.coordinator.synchronizer.initializer.getVerifiedBalance(), presendVerifiedBalance)
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
case .success(let transaction):
|
||||
do {
|
||||
let transaction = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description) \(Date().description)",
|
||||
from: 0)
|
||||
pendingTx = transaction
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
} catch {
|
||||
/*
|
||||
balance should be the same as before sending if transaction failed
|
||||
*/
|
||||
XCTAssertEqual(self.coordinator.synchronizer.initializer.getVerifiedBalance(), presendVerifiedBalance)
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
|
||||
pendingTx = transaction
|
||||
}
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
XCTAssertTrue(coordinator.synchronizer.initializer.getVerifiedBalance() > .zero)
|
||||
wait(for: [sentTransactionExpectation], timeout: 12)
|
||||
|
@ -548,16 +598,25 @@ class BalanceTests: XCTestCase {
|
|||
sleep(1)
|
||||
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
mineExpectation.fulfill()
|
||||
}, error: { error in
|
||||
guard let e = error else {
|
||||
XCTFail("unknown error syncing after sending transaction")
|
||||
return
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(
|
||||
completion: { synchronizer in
|
||||
mineExpectation.fulfill()
|
||||
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)
|
||||
|
||||
|
@ -654,15 +713,22 @@ class BalanceTests: XCTestCase {
|
|||
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 coordinator.applyStaged(blockheight: defaultLatestHeight)
|
||||
|
||||
sleep(2)
|
||||
try coordinator.sync(completion: { _ in
|
||||
self.syncedExpectation.fulfill()
|
||||
}, error: handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
self.syncedExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [syncedExpectation], timeout: 5)
|
||||
|
||||
|
@ -677,33 +743,28 @@ class BalanceTests: XCTestCase {
|
|||
XCTAssertTrue(presendBalance >= network.constants.defaultFee(for: defaultLatestHeight) + sendAmount)
|
||||
var pendingTx: PendingTransactionEntity?
|
||||
|
||||
var error: Error?
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description) \(Date().description)",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let e):
|
||||
// balance should be the same as before sending if transaction failed
|
||||
error = e
|
||||
XCTFail("sendToAddress failed: \(e)")
|
||||
|
||||
case .success(let transaction):
|
||||
pendingTx = transaction
|
||||
}
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
var testError: Error?
|
||||
do {
|
||||
let transaction = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description) \(Date().description)",
|
||||
from: 0)
|
||||
pendingTx = transaction
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
} catch {
|
||||
// balance should be the same as before sending if transaction failed
|
||||
testError = error
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
}
|
||||
|
||||
XCTAssertTrue(coordinator.synchronizer.initializer.getVerifiedBalance() > .zero)
|
||||
wait(for: [sentTransactionExpectation], timeout: 12)
|
||||
|
||||
if let e = error {
|
||||
if let testError {
|
||||
XCTAssertEqual(self.coordinator.synchronizer.initializer.getVerifiedBalance(), presendBalance)
|
||||
XCTFail("error: \(e)")
|
||||
XCTFail("error: \(testError)")
|
||||
return
|
||||
}
|
||||
guard let transaction = pendingTx else {
|
||||
|
@ -733,16 +794,25 @@ class BalanceTests: XCTestCase {
|
|||
sleep(2)
|
||||
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
mineExpectation.fulfill()
|
||||
}, error: { error in
|
||||
guard let e = error else {
|
||||
XCTFail("unknown error syncing after sending transaction")
|
||||
return
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(
|
||||
completion: { synchronizer in
|
||||
mineExpectation.fulfill()
|
||||
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)
|
||||
|
||||
|
@ -802,7 +872,7 @@ class BalanceTests: XCTestCase {
|
|||
There’s 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 coordinator.applyStaged(blockheight: defaultLatestHeight)
|
||||
|
@ -814,9 +884,16 @@ class BalanceTests: XCTestCase {
|
|||
/*
|
||||
sync to current tip
|
||||
*/
|
||||
try coordinator.sync(completion: { _ in
|
||||
self.syncedExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
self.syncedExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [syncedExpectation], timeout: 6)
|
||||
|
||||
|
@ -833,26 +910,18 @@ class BalanceTests: XCTestCase {
|
|||
*/
|
||||
let memo = "shielding is fun!"
|
||||
var pendingTx: PendingTransactionEntity?
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKeys,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: memo,
|
||||
from: 0,
|
||||
resultBlock: { sendResult in
|
||||
DispatchQueue.main.async {
|
||||
switch sendResult {
|
||||
case .failure(let sendError):
|
||||
XCTFail("error sending \(sendError)")
|
||||
|
||||
case .success(let transaction):
|
||||
pendingTx = transaction
|
||||
}
|
||||
|
||||
sendExpectation.fulfill()
|
||||
}
|
||||
}
|
||||
)
|
||||
do {
|
||||
let transaction = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKeys,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: memo,
|
||||
from: 0)
|
||||
pendingTx = transaction
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
XCTFail("error sending \(error)")
|
||||
}
|
||||
wait(for: [createToAddressExpectation], timeout: 30)
|
||||
|
||||
let syncToMinedheightExpectation = XCTestExpectation(description: "sync to mined height + 1")
|
||||
|
@ -875,89 +944,93 @@ class BalanceTests: XCTestCase {
|
|||
/*
|
||||
Sync to that block
|
||||
*/
|
||||
try coordinator.sync(
|
||||
completion: { synchronizer in
|
||||
let confirmedTx: ConfirmedTransactionEntity!
|
||||
do {
|
||||
confirmedTx = try synchronizer.allClearedTransactions().first(where: { confirmed -> Bool in
|
||||
confirmed.transactionEntity.transactionId == pendingTx?.transactionEntity.transactionId
|
||||
})
|
||||
} catch {
|
||||
XCTFail("Error retrieving cleared transactions")
|
||||
return
|
||||
}
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
let confirmedTx: ConfirmedTransactionEntity!
|
||||
do {
|
||||
confirmedTx = try synchronizer.allClearedTransactions().first(where: { confirmed -> Bool in
|
||||
confirmed.transactionEntity.transactionId == pendingTx?.transactionEntity.transactionId
|
||||
})
|
||||
} catch {
|
||||
XCTFail("Error retrieving cleared transactions")
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
There’s a sent transaction matching the amount sent to the given zAddr
|
||||
*/
|
||||
XCTAssertEqual(confirmedTx.value, self.sendAmount)
|
||||
XCTAssertEqual(confirmedTx.toAddress, self.testRecipientAddress)
|
||||
XCTAssertEqual(confirmedTx.memo?.asZcashTransactionMemo(), memo)
|
||||
/*
|
||||
There’s a sent transaction matching the amount sent to the given zAddr
|
||||
*/
|
||||
XCTAssertEqual(confirmedTx.value, self.sendAmount)
|
||||
XCTAssertEqual(confirmedTx.toAddress, self.testRecipientAddress)
|
||||
XCTAssertEqual(confirmedTx.memo?.asZcashTransactionMemo(), memo)
|
||||
|
||||
guard let transactionId = confirmedTx.rawTransactionId else {
|
||||
XCTFail("no raw transaction id")
|
||||
return
|
||||
}
|
||||
guard let transactionId = confirmedTx.rawTransactionId else {
|
||||
XCTFail("no raw transaction id")
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Find out what note was used
|
||||
*/
|
||||
let sentNotesRepo = SentNotesSQLDAO(
|
||||
dbProvider: SimpleConnectionProvider(
|
||||
path: synchronizer.initializer.dataDbURL.absoluteString,
|
||||
readonly: true
|
||||
/*
|
||||
Find out what note was used
|
||||
*/
|
||||
let sentNotesRepo = SentNotesSQLDAO(
|
||||
dbProvider: SimpleConnectionProvider(
|
||||
path: synchronizer.initializer.dataDbURL.absoluteString,
|
||||
readonly: true
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
guard let sentNote = try? sentNotesRepo.sentNote(byRawTransactionId: transactionId) else {
|
||||
XCTFail("Could not finde sent note with transaction Id \(transactionId)")
|
||||
return
|
||||
}
|
||||
guard let sentNote = try? sentNotesRepo.sentNote(byRawTransactionId: transactionId) else {
|
||||
XCTFail("Could not finde sent note with transaction Id \(transactionId)")
|
||||
return
|
||||
}
|
||||
|
||||
let receivedNotesRepo = ReceivedNotesSQLDAO(
|
||||
dbProvider: SimpleConnectionProvider(
|
||||
path: self.coordinator.synchronizer.initializer.dataDbURL.absoluteString,
|
||||
readonly: true
|
||||
let receivedNotesRepo = ReceivedNotesSQLDAO(
|
||||
dbProvider: SimpleConnectionProvider(
|
||||
path: self.coordinator.synchronizer.initializer.dataDbURL.absoluteString,
|
||||
readonly: true
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
/*
|
||||
get change note
|
||||
*/
|
||||
guard let receivedNote = try? receivedNotesRepo.receivedNote(byRawTransactionId: transactionId) else {
|
||||
XCTFail("Could not find received not with change for transaction Id \(transactionId)")
|
||||
return
|
||||
}
|
||||
/*
|
||||
get change note
|
||||
*/
|
||||
guard let receivedNote = try? receivedNotesRepo.receivedNote(byRawTransactionId: transactionId) else {
|
||||
XCTFail("Could not find received not with change for transaction Id \(transactionId)")
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
There’s a change note of value (previous note value - sent amount)
|
||||
*/
|
||||
XCTAssertEqual(
|
||||
previousVerifiedBalance - self.sendAmount - self.network.constants.defaultFee(for: self.defaultLatestHeight),
|
||||
Zatoshi(Int64(receivedNote.value))
|
||||
)
|
||||
/*
|
||||
There’s a change note of value (previous note value - sent amount)
|
||||
*/
|
||||
XCTAssertEqual(
|
||||
previousVerifiedBalance - self.sendAmount - self.network.constants.defaultFee(for: self.defaultLatestHeight),
|
||||
Zatoshi(Int64(receivedNote.value))
|
||||
)
|
||||
|
||||
/*
|
||||
Balance meets verified Balance and total balance criteria
|
||||
*/
|
||||
self.verifiedBalanceValidation(
|
||||
previousBalance: previousVerifiedBalance,
|
||||
spentNoteValue: Zatoshi(Int64(sentNote.value)),
|
||||
changeValue: Zatoshi(Int64(receivedNote.value)),
|
||||
sentAmount: self.sendAmount,
|
||||
currentVerifiedBalance: synchronizer.initializer.getVerifiedBalance()
|
||||
)
|
||||
/*
|
||||
Balance meets verified Balance and total balance criteria
|
||||
*/
|
||||
self.verifiedBalanceValidation(
|
||||
previousBalance: previousVerifiedBalance,
|
||||
spentNoteValue: Zatoshi(Int64(sentNote.value)),
|
||||
changeValue: Zatoshi(Int64(receivedNote.value)),
|
||||
sentAmount: self.sendAmount,
|
||||
currentVerifiedBalance: synchronizer.initializer.getVerifiedBalance()
|
||||
)
|
||||
|
||||
self.totalBalanceValidation(
|
||||
totalBalance: synchronizer.initializer.getBalance(),
|
||||
previousTotalbalance: previousTotalBalance,
|
||||
sentAmount: self.sendAmount
|
||||
)
|
||||
self.totalBalanceValidation(
|
||||
totalBalance: synchronizer.initializer.getBalance(),
|
||||
previousTotalbalance: previousTotalBalance,
|
||||
sentAmount: self.sendAmount
|
||||
)
|
||||
|
||||
syncToMinedheightExpectation.fulfill()
|
||||
},
|
||||
error: self.handleError
|
||||
)
|
||||
syncToMinedheightExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
func testVerifyBalanceAfterExpiredTransaction() throws {
|
||||
func testVerifyBalanceAfterExpiredTransaction() async throws {
|
||||
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
|
||||
|
||||
try coordinator.applyStaged(blockheight: self.defaultLatestHeight)
|
||||
sleep(2)
|
||||
try coordinator.sync(completion: { _ in
|
||||
self.syncedExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
self.syncedExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
wait(for: [syncedExpectation], timeout: 5)
|
||||
|
||||
guard let spendingKey = coordinator.spendingKeys?.first else {
|
||||
|
@ -1005,24 +1084,20 @@ class BalanceTests: XCTestCase {
|
|||
let previousTotalBalance: Zatoshi = coordinator.synchronizer.initializer.getBalance()
|
||||
let sendExpectation = XCTestExpectation(description: "send expectation")
|
||||
var pendingTx: PendingTransactionEntity?
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description)",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
// balance should be the same as before sending if transaction failed
|
||||
XCTAssertEqual(self.coordinator.synchronizer.initializer.getVerifiedBalance(), previousVerifiedBalance)
|
||||
XCTAssertEqual(self.coordinator.synchronizer.initializer.getBalance(), previousTotalBalance)
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
case .success(let pending):
|
||||
pendingTx = pending
|
||||
}
|
||||
}
|
||||
)
|
||||
do {
|
||||
let pending = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description)",
|
||||
from: 0)
|
||||
pendingTx = pending
|
||||
} catch {
|
||||
// balance should be the same as before sending if transaction failed
|
||||
XCTAssertEqual(self.coordinator.synchronizer.initializer.getVerifiedBalance(), previousVerifiedBalance)
|
||||
XCTAssertEqual(self.coordinator.synchronizer.initializer.getBalance(), previousTotalBalance)
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
}
|
||||
|
||||
wait(for: [sendExpectation], timeout: 12)
|
||||
|
||||
|
@ -1038,10 +1113,16 @@ class BalanceTests: XCTestCase {
|
|||
try coordinator.applyStaged(blockheight: expiryHeight + 1)
|
||||
|
||||
sleep(2)
|
||||
try coordinator.sync(completion: { _ in
|
||||
expirationSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
expirationSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
wait(for: [expirationSyncExpectation], timeout: 5)
|
||||
|
||||
/*
|
||||
|
|
|
@ -43,7 +43,7 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
/**
|
||||
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(
|
||||
darksideWallet: coordinator.service,
|
||||
birthday: birthday,
|
||||
|
@ -58,10 +58,16 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
try coordinator.applyStaged(blockheight: activationHeight - ZcashSDK.defaultStaleTolerance)
|
||||
sleep(5)
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
wait(for: [firstSyncExpectation], timeout: 120)
|
||||
let verifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance()
|
||||
guard verifiedBalance > network.constants.defaultFee(for: activationHeight) else {
|
||||
|
@ -79,22 +85,18 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
/*
|
||||
send transaction to recipient address
|
||||
*/
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let e):
|
||||
self.handleError(e)
|
||||
case .success(let pendingTx):
|
||||
pendingEntity = pendingTx
|
||||
}
|
||||
sendExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
do {
|
||||
let pendingTx = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
self.handleError(error)
|
||||
}
|
||||
|
||||
wait(for: [sendExpectation], timeout: 11)
|
||||
|
||||
|
@ -123,10 +125,17 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
sleep(1)
|
||||
let afterSendExpectation = XCTestExpectation(description: "aftersend")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
afterSendExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
afterSendExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [afterSendExpectation], timeout: 10)
|
||||
|
||||
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
|
||||
*/
|
||||
func testSpendPostActivationFundsAfterConfirmation() throws {
|
||||
func testSpendPostActivationFundsAfterConfirmation() async throws {
|
||||
try FakeChainBuilder.buildChainPostActivationFunds(
|
||||
darksideWallet: coordinator.service,
|
||||
birthday: birthday,
|
||||
|
@ -148,9 +157,16 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
try coordinator.applyStaged(blockheight: activationHeight + 10)
|
||||
sleep(3)
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [firstSyncExpectation], timeout: 120)
|
||||
guard try !coordinator.synchronizer.allReceivedTransactions().filter({ $0.minedHeight > activationHeight }).isEmpty else {
|
||||
|
@ -168,22 +184,18 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
/*
|
||||
send transaction to recipient address
|
||||
*/
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let e):
|
||||
self.handleError(e)
|
||||
case .success(let pendingTx):
|
||||
pendingEntity = pendingTx
|
||||
}
|
||||
sendExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
do {
|
||||
let pendingTx = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
self.handleError(error)
|
||||
}
|
||||
|
||||
wait(for: [sendExpectation], timeout: 11)
|
||||
|
||||
|
@ -197,9 +209,16 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
|
||||
let afterSendExpectation = XCTestExpectation(description: "aftersend")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
afterSendExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
afterSendExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
func testSpendMinedSpendThatExpiresOnActivation() throws {
|
||||
func testSpendMinedSpendThatExpiresOnActivation() async throws {
|
||||
try FakeChainBuilder.buildChain(
|
||||
darksideWallet: coordinator.service,
|
||||
birthday: birthday,
|
||||
|
@ -222,9 +241,16 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
try coordinator.applyStaged(blockheight: activationHeight - 10)
|
||||
sleep(3)
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [firstSyncExpectation], timeout: 120)
|
||||
let verifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance()
|
||||
|
@ -237,22 +263,18 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
/*
|
||||
send transaction to recipient address
|
||||
*/
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let e):
|
||||
self.handleError(e)
|
||||
case .success(let pendingTx):
|
||||
pendingEntity = pendingTx
|
||||
}
|
||||
sendExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
do {
|
||||
let pendingTx = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
self.handleError(error)
|
||||
}
|
||||
|
||||
wait(for: [sendExpectation], timeout: 11)
|
||||
|
||||
|
@ -283,9 +305,16 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
|
||||
let afterSendExpectation = XCTestExpectation(description: "aftersend")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
afterSendExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
afterSendExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
func testExpiredSpendAfterActivation() throws {
|
||||
func testExpiredSpendAfterActivation() async throws {
|
||||
try FakeChainBuilder.buildChain(
|
||||
darksideWallet: coordinator.service,
|
||||
birthday: birthday,
|
||||
|
@ -320,9 +349,16 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
|
||||
let verifiedBalancePreActivation: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance()
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [firstSyncExpectation], timeout: 120)
|
||||
let verifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance()
|
||||
|
@ -338,22 +374,18 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
/*
|
||||
send transaction to recipient address
|
||||
*/
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let e):
|
||||
self.handleError(e)
|
||||
case .success(let pendingTx):
|
||||
pendingEntity = pendingTx
|
||||
}
|
||||
sendExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
do {
|
||||
let pendingTx = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
self.handleError(error)
|
||||
}
|
||||
|
||||
wait(for: [sendExpectation], timeout: 11)
|
||||
|
||||
|
@ -380,9 +412,16 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
|
||||
let afterSendExpectation = XCTestExpectation(description: "aftersend")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
afterSendExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
afterSendExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
func testCombinePreActivationNotesAndPostActivationNotesOnSpend() throws {
|
||||
func testCombinePreActivationNotesAndPostActivationNotesOnSpend() async throws {
|
||||
try FakeChainBuilder.buildChainMixedFunds(
|
||||
darksideWallet: coordinator.service,
|
||||
birthday: birthday,
|
||||
|
@ -415,9 +454,16 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
try coordinator.applyStaged(blockheight: activationHeight - 1)
|
||||
sleep(3)
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [firstSyncExpectation], timeout: 120)
|
||||
|
||||
|
@ -427,10 +473,17 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
sleep(2)
|
||||
|
||||
let secondSyncExpectation = XCTestExpectation(description: "second sync")
|
||||
try coordinator.sync(completion: { _ in
|
||||
secondSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
secondSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [secondSyncExpectation], timeout: 10)
|
||||
guard try !coordinator.synchronizer.allReceivedTransactions().filter({ $0.minedHeight > activationHeight }).isEmpty else {
|
||||
XCTFail("this test requires funds received after activation height")
|
||||
|
@ -450,22 +503,18 @@ class NetworkUpgradeTests: XCTestCase {
|
|||
/*
|
||||
send transaction to recipient address
|
||||
*/
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let e):
|
||||
self.handleError(e)
|
||||
case .success(let pendingTx):
|
||||
pendingEntity = pendingTx
|
||||
}
|
||||
sendExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
do {
|
||||
let pendingTx = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: spendAmount,
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
self.handleError(error)
|
||||
}
|
||||
|
||||
wait(for: [sendExpectation], timeout: 15)
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
|||
reorgExpectation.fulfill()
|
||||
}
|
||||
|
||||
func testPendingTransactionMinedHeightUpdated() throws {
|
||||
func testPendingTransactionMinedHeightUpdated() async throws {
|
||||
/*
|
||||
1. create fake chain
|
||||
*/
|
||||
|
@ -78,10 +78,16 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
|||
1a. sync to latest height
|
||||
*/
|
||||
LoggerProxy.info("1a. sync to latest height")
|
||||
try coordinator.sync(completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
wait(for: [firstSyncExpectation], timeout: 5)
|
||||
|
||||
sleep(1)
|
||||
|
@ -93,23 +99,19 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
|||
2. send transaction to recipient address
|
||||
*/
|
||||
LoggerProxy.info("2. send transaction to recipient address")
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
// swiftlint:disable:next force_unwrapping
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: Zatoshi(20000),
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0,
|
||||
resultBlock: { result in
|
||||
switch result {
|
||||
case .failure(let e):
|
||||
self.handleError(e)
|
||||
case .success(let pendingTx):
|
||||
pendingEntity = pendingTx
|
||||
}
|
||||
sendExpectation.fulfill()
|
||||
}
|
||||
)
|
||||
do {
|
||||
let pendingTx = try await coordinator.synchronizer.sendToAddress(
|
||||
// swiftlint:disable:next force_unwrapping
|
||||
spendingKey: self.coordinator.spendingKeys!.first!,
|
||||
zatoshi: Zatoshi(20000),
|
||||
toAddress: self.testRecipientAddress,
|
||||
memo: "this is a test",
|
||||
from: 0)
|
||||
pendingEntity = pendingTx
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
self.handleError(error)
|
||||
}
|
||||
|
||||
wait(for: [sendExpectation], timeout: 11)
|
||||
|
||||
|
@ -167,13 +169,17 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
|||
LoggerProxy.info("6. sync to latest height")
|
||||
let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
|
||||
|
||||
try coordinator.sync(
|
||||
completion: { _ in
|
||||
secondSyncExpectation.fulfill()
|
||||
},
|
||||
error: self.handleError
|
||||
)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
secondSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [secondSyncExpectation], timeout: 5)
|
||||
|
||||
XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count, 1)
|
||||
|
@ -207,10 +213,17 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
|||
*/
|
||||
LoggerProxy.info("last sync to latest height: \(lastStageHeight)")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
syncToConfirmExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
syncToConfirmExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [syncToConfirmExpectation], timeout: 6)
|
||||
var supposedlyPendingUnexistingTransaction: PendingTransactionEntity?
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ class RewindRescanTests: XCTestCase {
|
|||
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
|
||||
}
|
||||
|
||||
func testRescanToHeight() throws {
|
||||
func testRescanToHeight() async throws {
|
||||
// 1 sync and get spendable funds
|
||||
try FakeChainBuilder.buildChainWithTxsFarFromEachOther(
|
||||
darksideWallet: coordinator.service,
|
||||
|
@ -121,13 +121,16 @@ class RewindRescanTests: XCTestCase {
|
|||
let initialVerifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance()
|
||||
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
||||
|
||||
try coordinator.sync(
|
||||
completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
},
|
||||
error: handleError
|
||||
)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
wait(for: [firstSyncExpectation], timeout: 20)
|
||||
let verifiedBalance: Zatoshi = coordinator.synchronizer.initializer.getVerifiedBalance()
|
||||
let totalBalance: Zatoshi = coordinator.synchronizer.initializer.getBalance()
|
||||
|
@ -154,10 +157,17 @@ class RewindRescanTests: XCTestCase {
|
|||
|
||||
let secondScanExpectation = XCTestExpectation(description: "rescan")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
secondScanExpectation.fulfill()
|
||||
}, error: handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
secondScanExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [secondScanExpectation], timeout: 20)
|
||||
|
||||
// verify that the balance still adds up
|
||||
|
@ -166,20 +176,16 @@ class RewindRescanTests: XCTestCase {
|
|||
|
||||
// try to spend the funds
|
||||
let sendExpectation = XCTestExpectation(description: "after rewind expectation")
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: coordinator.spendingKey,
|
||||
zatoshi: Zatoshi(1000),
|
||||
toAddress: testRecipientAddress,
|
||||
memo: nil,
|
||||
from: 0
|
||||
) { result in
|
||||
sendExpectation.fulfill()
|
||||
switch result {
|
||||
case .success(let pendingTx):
|
||||
XCTAssertEqual(Zatoshi(1000), pendingTx.value)
|
||||
case .failure(let error):
|
||||
XCTFail("sending fail: \(error)")
|
||||
}
|
||||
do {
|
||||
let pendingTx = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: coordinator.spendingKey,
|
||||
zatoshi: Zatoshi(1000),
|
||||
toAddress: testRecipientAddress,
|
||||
memo: nil,
|
||||
from: 0)
|
||||
XCTAssertEqual(Zatoshi(1000), pendingTx.value)
|
||||
} catch {
|
||||
XCTFail("sending fail: \(error)")
|
||||
}
|
||||
wait(for: [sendExpectation], timeout: 15)
|
||||
}
|
||||
|
@ -231,7 +237,7 @@ class RewindRescanTests: XCTestCase {
|
|||
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
|
||||
}
|
||||
|
||||
func testRewindAfterSendingTransaction() throws {
|
||||
func testRewindAfterSendingTransaction() async throws {
|
||||
let notificationHandler = SDKSynchonizerListener()
|
||||
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
|
||||
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
|
||||
|
@ -246,10 +252,16 @@ class RewindRescanTests: XCTestCase {
|
|||
sleep(1)
|
||||
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
||||
|
||||
try coordinator.sync(completion: { _ in
|
||||
firstSyncExpectation.fulfill()
|
||||
}, error: handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
firstSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
wait(for: [firstSyncExpectation], timeout: 12)
|
||||
// 2 check that there are no unconfirmed funds
|
||||
|
||||
|
@ -267,20 +279,17 @@ class RewindRescanTests: XCTestCase {
|
|||
return
|
||||
}
|
||||
var pendingTx: PendingTransactionEntity?
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: maxBalance,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description) \(Date().description)",
|
||||
from: 0
|
||||
) { result in
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
case .success(let transaction):
|
||||
pendingTx = transaction
|
||||
}
|
||||
do {
|
||||
let transaction = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: maxBalance,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test send \(self.description) \(Date().description)",
|
||||
from: 0)
|
||||
pendingTx = transaction
|
||||
self.sentTransactionExpectation.fulfill()
|
||||
} catch {
|
||||
XCTFail("sendToAddress failed: \(error)")
|
||||
}
|
||||
wait(for: [sentTransactionExpectation], timeout: 20)
|
||||
guard let pendingTx = pendingTx else {
|
||||
|
@ -320,25 +329,30 @@ class RewindRescanTests: XCTestCase {
|
|||
|
||||
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
||||
|
||||
try coordinator.sync(
|
||||
completion: { synchronizer in
|
||||
let pendingTransaction = synchronizer.pendingTransactions
|
||||
.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
|
||||
XCTAssertNotNil(pendingTransaction, "pending transaction should have been mined by now")
|
||||
XCTAssertTrue(pendingTransaction?.isMined ?? false)
|
||||
XCTAssertEqual(pendingTransaction?.minedHeight, sentTxHeight)
|
||||
mineExpectation.fulfill()
|
||||
},
|
||||
error: { error in
|
||||
guard let e = error else {
|
||||
XCTFail("unknown error syncing after sending transaction")
|
||||
return
|
||||
}
|
||||
|
||||
XCTFail("Error: \(e)")
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(
|
||||
completion: { synchronizer in
|
||||
let pendingTransaction = synchronizer.pendingTransactions
|
||||
.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
|
||||
XCTAssertNotNil(pendingTransaction, "pending transaction should have been mined by now")
|
||||
XCTAssertTrue(pendingTransaction?.isMined ?? false)
|
||||
XCTAssertEqual(pendingTransaction?.minedHeight, sentTxHeight)
|
||||
mineExpectation.fulfill()
|
||||
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)
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
|
||||
|
||||
// 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)")
|
||||
}
|
||||
|
||||
try coordinator.sync(
|
||||
completion: { _ in
|
||||
confirmExpectation.fulfill()
|
||||
},
|
||||
error: { e in
|
||||
self.handleError(e)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
confirmExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
wait(for: [confirmExpectation], timeout: 10)
|
||||
|
||||
let confirmedPending = try coordinator.synchronizer.allPendingTransactions()
|
||||
|
|
|
@ -69,7 +69,7 @@ class Z2TReceiveTests: XCTestCase {
|
|||
self.foundTransactionsExpectation.fulfill()
|
||||
}
|
||||
|
||||
func testFoundTransactions() throws {
|
||||
func testFoundTransactions() async throws {
|
||||
subscribeToFoundTransactions()
|
||||
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName)
|
||||
let receivedTxHeight: BlockHeight = 663188
|
||||
|
@ -85,42 +85,42 @@ class Z2TReceiveTests: XCTestCase {
|
|||
/*
|
||||
3. sync up to received_Tx_height
|
||||
*/
|
||||
try coordinator.sync(
|
||||
completion: { _ in
|
||||
preTxExpectation.fulfill()
|
||||
},
|
||||
error: self.handleError
|
||||
)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
preTxExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
wait(for: [preTxExpectation, foundTransactionsExpectation], timeout: 5)
|
||||
|
||||
let sendExpectation = XCTestExpectation(description: "sendToAddress")
|
||||
var pendingEntity: PendingTransactionEntity?
|
||||
var error: Error?
|
||||
var testError: Error?
|
||||
let sendAmount = Zatoshi(10000)
|
||||
/*
|
||||
4. create transaction
|
||||
*/
|
||||
coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: coordinator.spendingKeys!.first!,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test transaction",
|
||||
from: 0
|
||||
) { result in
|
||||
switch result {
|
||||
case .success(let pending):
|
||||
pendingEntity = pending
|
||||
case .failure(let e):
|
||||
error = e
|
||||
}
|
||||
do {
|
||||
let pending = try await coordinator.synchronizer.sendToAddress(
|
||||
spendingKey: coordinator.spendingKeys!.first!,
|
||||
zatoshi: sendAmount,
|
||||
toAddress: testRecipientAddress,
|
||||
memo: "test transaction",
|
||||
from: 0)
|
||||
pendingEntity = pending
|
||||
sendExpectation.fulfill()
|
||||
} catch {
|
||||
testError = error
|
||||
}
|
||||
|
||||
wait(for: [sendExpectation], timeout: 12)
|
||||
|
||||
guard pendingEntity != nil else {
|
||||
XCTFail("error sending to address. Error: \(String(describing: error))")
|
||||
XCTFail("error sending to address. Error: \(String(describing: testError))")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -154,13 +154,20 @@ class Z2TReceiveTests: XCTestCase {
|
|||
*/
|
||||
let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation")
|
||||
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
|
||||
XCTAssertEqual(pMinedHeight, sentTxHeight)
|
||||
|
||||
sentTxSyncExpectation.fulfill()
|
||||
}, error: self.handleError)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
do {
|
||||
try coordinator.sync(completion: { synchronizer in
|
||||
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
|
||||
XCTAssertEqual(pMinedHeight, sentTxHeight)
|
||||
|
||||
sentTxSyncExpectation.fulfill()
|
||||
continuation.resume()
|
||||
}, error: self.handleError)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [sentTxSyncExpectation, foundTransactionsExpectation], timeout: 5)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue