2021-03-26 15:56:51 -07:00
|
|
|
//
|
|
|
|
// XCTRewindRescanTests.swift
|
|
|
|
// ZcashLightClientKit-Unit-Tests
|
|
|
|
//
|
|
|
|
// Created by Francisco Gindre on 3/25/21.
|
|
|
|
//
|
|
|
|
|
2023-03-02 04:19:25 -08:00
|
|
|
import Combine
|
2021-03-26 15:56:51 -07:00
|
|
|
import XCTest
|
2022-02-28 09:03:20 -08:00
|
|
|
@testable import TestUtils
|
2021-03-26 15:56:51 -07:00
|
|
|
@testable import ZcashLightClientKit
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2023-01-18 08:09:04 -08:00
|
|
|
// FIXME: [#586] disabled until this is resolved https://github.com/zcash/ZcashLightClientKit/issues/586
|
2023-05-01 07:28:59 -07:00
|
|
|
class RewindRescanTests: ZcashTestCase {
|
2021-03-26 15:56:51 -07:00
|
|
|
let sendAmount: Int64 = 1000
|
|
|
|
let defaultLatestHeight: BlockHeight = 663175
|
2021-09-23 06:26:41 -07:00
|
|
|
let branchID = "2bb40e60"
|
|
|
|
let chainName = "main"
|
|
|
|
|
2023-03-02 04:19:25 -08:00
|
|
|
var cancellables: [AnyCancellable] = []
|
2021-09-23 06:26:41 -07:00
|
|
|
var birthday: BlockHeight = 663150
|
2021-03-26 15:56:51 -07:00
|
|
|
var coordinator: TestCoordinator!
|
|
|
|
var syncedExpectation = XCTestExpectation(description: "synced")
|
|
|
|
var sentTransactionExpectation = XCTestExpectation(description: "sent")
|
|
|
|
var expectedReorgHeight: BlockHeight = 665188
|
|
|
|
var expectedRewindHeight: BlockHeight = 665188
|
2021-09-23 06:26:41 -07:00
|
|
|
var reorgExpectation = XCTestExpectation(description: "reorg")
|
2021-07-28 15:25:47 -07:00
|
|
|
var network = ZcashNetworkBuilder.network(for: .mainnet)
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2023-03-30 10:01:47 -07:00
|
|
|
override func setUp() async throws {
|
|
|
|
try await super.setUp()
|
2022-10-31 16:17:05 -07:00
|
|
|
|
2023-05-01 07:28:59 -07:00
|
|
|
self.coordinator = try await TestCoordinator(
|
|
|
|
container: mockContainer,
|
|
|
|
walletBirthday: birthday,
|
|
|
|
network: network
|
|
|
|
)
|
2023-05-05 08:04:13 -07:00
|
|
|
try await coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main")
|
2021-03-26 15:56:51 -07:00
|
|
|
}
|
2023-03-30 10:01:47 -07:00
|
|
|
|
|
|
|
override func tearDown() async throws {
|
|
|
|
try await super.tearDown()
|
|
|
|
let coordinator = self.coordinator!
|
|
|
|
self.coordinator = nil
|
|
|
|
cancellables = []
|
|
|
|
|
|
|
|
try await coordinator.stop()
|
2023-02-02 08:58:12 -08:00
|
|
|
try? FileManager.default.removeItem(at: coordinator.databases.fsCacheDbRoot)
|
2021-03-26 15:56:51 -07:00
|
|
|
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
|
|
|
|
}
|
|
|
|
|
|
|
|
func handleError(_ error: Error?) {
|
|
|
|
guard let testError = error else {
|
|
|
|
XCTFail("failed with nil error")
|
|
|
|
return
|
|
|
|
}
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2021-03-26 15:56:51 -07:00
|
|
|
XCTFail("Failed with error: \(testError)")
|
|
|
|
}
|
|
|
|
|
2022-10-27 03:51:38 -07:00
|
|
|
func testBirthdayRescan() async throws {
|
2021-03-26 15:56:51 -07:00
|
|
|
// 1 sync and get spendable funds
|
2021-05-18 14:22:29 -07:00
|
|
|
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
|
|
|
try coordinator.applyStaged(blockheight: defaultLatestHeight + 50)
|
2023-03-30 03:49:28 -07:00
|
|
|
let initialVerifiedBalance: Zatoshi = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
|
|
|
let initialTotalBalance: Zatoshi = try await coordinator.synchronizer.getShieldedBalance()
|
2021-03-26 15:56:51 -07:00
|
|
|
sleep(1)
|
|
|
|
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
2022-11-29 14:59:16 -08:00
|
|
|
|
2023-03-16 02:11:18 -07:00
|
|
|
do {
|
|
|
|
try await coordinator.sync(
|
|
|
|
completion: { _ in
|
|
|
|
firstSyncExpectation.fulfill()
|
|
|
|
},
|
|
|
|
error: self.handleError
|
|
|
|
)
|
|
|
|
} catch {
|
|
|
|
handleError(error)
|
2022-11-29 14:59:16 -08:00
|
|
|
}
|
2023-03-16 02:11:18 -07:00
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [firstSyncExpectation], timeout: 12)
|
2023-03-30 03:49:28 -07:00
|
|
|
let verifiedBalance: Zatoshi = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
|
|
|
let totalBalance: Zatoshi = try await coordinator.synchronizer.getShieldedBalance()
|
2021-03-26 15:56:51 -07:00
|
|
|
// 2 check that there are no unconfirmed funds
|
2021-07-28 09:59:10 -07:00
|
|
|
XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: defaultLatestHeight))
|
2021-03-26 15:56:51 -07:00
|
|
|
XCTAssertEqual(verifiedBalance, totalBalance)
|
2023-03-02 04:19:25 -08:00
|
|
|
|
|
|
|
let rewindExpectation = XCTestExpectation(description: "RewindExpectation")
|
|
|
|
|
|
|
|
try await withCheckedThrowingContinuation { continuation in
|
|
|
|
// rewind to birthday
|
|
|
|
coordinator.synchronizer.rewind(.birthday)
|
|
|
|
.sink(
|
|
|
|
receiveCompletion: { result in
|
|
|
|
rewindExpectation.fulfill()
|
|
|
|
switch result {
|
|
|
|
case .finished:
|
|
|
|
continuation.resume()
|
|
|
|
|
|
|
|
case let .failure(error):
|
|
|
|
XCTFail("Rewind failed with error: \(error)")
|
|
|
|
continuation.resume(with: .failure(error))
|
|
|
|
}
|
|
|
|
},
|
|
|
|
receiveValue: { _ in }
|
|
|
|
)
|
|
|
|
.store(in: &cancellables)
|
|
|
|
}
|
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [rewindExpectation], timeout: 2)
|
2023-03-02 04:19:25 -08:00
|
|
|
|
2021-03-26 15:56:51 -07:00
|
|
|
// assert that after the new height is
|
2023-03-27 07:12:06 -07:00
|
|
|
let lastScannedHeight = try await coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight()
|
|
|
|
XCTAssertEqual(lastScannedHeight, self.birthday)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
|
|
|
// check that the balance is cleared
|
2023-03-30 03:49:28 -07:00
|
|
|
var expectedVerifiedBalance = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
|
|
|
var expectedBalance = try await coordinator.synchronizer.getShieldedBalance()
|
|
|
|
XCTAssertEqual(initialVerifiedBalance, expectedVerifiedBalance)
|
|
|
|
XCTAssertEqual(initialTotalBalance, expectedBalance)
|
2021-03-26 15:56:51 -07:00
|
|
|
let secondScanExpectation = XCTestExpectation(description: "rescan")
|
|
|
|
|
2023-03-16 02:11:18 -07:00
|
|
|
do {
|
|
|
|
try await coordinator.sync(
|
|
|
|
completion: { _ in
|
|
|
|
secondScanExpectation.fulfill()
|
|
|
|
},
|
|
|
|
error: self.handleError
|
|
|
|
)
|
|
|
|
} catch {
|
|
|
|
handleError(error)
|
2022-11-29 14:59:16 -08:00
|
|
|
}
|
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [secondScanExpectation], timeout: 12)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
|
|
|
// verify that the balance still adds up
|
2023-03-30 03:49:28 -07:00
|
|
|
expectedVerifiedBalance = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
|
|
|
expectedBalance = try await coordinator.synchronizer.getShieldedBalance()
|
|
|
|
XCTAssertEqual(verifiedBalance, expectedVerifiedBalance)
|
|
|
|
XCTAssertEqual(totalBalance, expectedBalance)
|
2021-03-26 15:56:51 -07:00
|
|
|
}
|
2023-02-14 02:30:08 -08:00
|
|
|
|
|
|
|
// FIXME [#789]: Fix test
|
2023-02-27 05:39:07 -08:00
|
|
|
func testRescanToHeight() async throws {
|
2021-03-26 15:56:51 -07:00
|
|
|
// 1 sync and get spendable funds
|
2021-09-23 06:26:41 -07:00
|
|
|
try FakeChainBuilder.buildChainWithTxsFarFromEachOther(
|
|
|
|
darksideWallet: coordinator.service,
|
|
|
|
branchID: branchID,
|
|
|
|
chainName: chainName,
|
|
|
|
length: 10000
|
|
|
|
)
|
2021-04-19 10:16:24 -07:00
|
|
|
let newChaintTip = defaultLatestHeight + 10000
|
|
|
|
try coordinator.applyStaged(blockheight: newChaintTip)
|
|
|
|
sleep(3)
|
2023-03-30 03:49:28 -07:00
|
|
|
let initialVerifiedBalance: Zatoshi = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
2021-03-26 15:56:51 -07:00
|
|
|
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
|
|
|
|
2023-03-16 02:11:18 -07:00
|
|
|
do {
|
|
|
|
try await coordinator.sync(
|
|
|
|
completion: { _ in
|
2022-09-13 03:19:56 -07:00
|
|
|
firstSyncExpectation.fulfill()
|
2023-03-16 02:11:18 -07:00
|
|
|
},
|
|
|
|
error: self.handleError
|
|
|
|
)
|
|
|
|
} catch {
|
|
|
|
handleError(error)
|
2022-09-13 03:19:56 -07:00
|
|
|
}
|
2023-03-16 02:11:18 -07:00
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [firstSyncExpectation], timeout: 20)
|
2023-03-30 03:49:28 -07:00
|
|
|
let verifiedBalance: Zatoshi = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
|
|
|
let totalBalance: Zatoshi = try await coordinator.synchronizer.getShieldedBalance()
|
2021-03-26 15:56:51 -07:00
|
|
|
// 2 check that there are no unconfirmed funds
|
2021-07-28 09:59:10 -07:00
|
|
|
XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: defaultLatestHeight))
|
2021-03-26 15:56:51 -07:00
|
|
|
XCTAssertEqual(verifiedBalance, totalBalance)
|
|
|
|
|
|
|
|
// rewind to birthday
|
2021-04-19 10:16:24 -07:00
|
|
|
let targetHeight: BlockHeight = newChaintTip - 8000
|
2023-03-31 10:10:35 -07:00
|
|
|
|
|
|
|
do {
|
|
|
|
_ = try await coordinator.synchronizer.initializer.rustBackend.getNearestRewindHeight(height: Int32(targetHeight))
|
|
|
|
} catch {
|
|
|
|
XCTFail("get nearest height failed error: \(error)")
|
|
|
|
return
|
|
|
|
}
|
2023-03-02 04:19:25 -08:00
|
|
|
|
|
|
|
let rewindExpectation = XCTestExpectation(description: "RewindExpectation")
|
|
|
|
|
|
|
|
try await withCheckedThrowingContinuation { continuation in
|
|
|
|
coordinator.synchronizer.rewind(.height(blockheight: targetHeight))
|
|
|
|
.sink(
|
|
|
|
receiveCompletion: { result in
|
|
|
|
rewindExpectation.fulfill()
|
|
|
|
switch result {
|
|
|
|
case .finished:
|
|
|
|
continuation.resume()
|
|
|
|
|
|
|
|
case let .failure(error):
|
|
|
|
XCTFail("Rewind failed with error: \(error)")
|
|
|
|
continuation.resume(with: .failure(error))
|
|
|
|
}
|
|
|
|
},
|
|
|
|
receiveValue: { _ in }
|
|
|
|
)
|
|
|
|
.store(in: &cancellables)
|
|
|
|
}
|
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [rewindExpectation], timeout: 2)
|
2023-03-02 04:19:25 -08:00
|
|
|
|
2021-03-26 15:56:51 -07:00
|
|
|
// check that the balance is cleared
|
2023-03-30 03:49:28 -07:00
|
|
|
var expectedVerifiedBalance = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
|
|
|
XCTAssertEqual(initialVerifiedBalance, expectedVerifiedBalance)
|
2021-04-19 10:16:24 -07:00
|
|
|
|
2021-03-26 15:56:51 -07:00
|
|
|
let secondScanExpectation = XCTestExpectation(description: "rescan")
|
|
|
|
|
2023-03-16 02:11:18 -07:00
|
|
|
do {
|
|
|
|
try await coordinator.sync(
|
|
|
|
completion: { _ in
|
2022-09-13 03:19:56 -07:00
|
|
|
secondScanExpectation.fulfill()
|
2023-03-16 02:11:18 -07:00
|
|
|
},
|
|
|
|
error: self.handleError
|
|
|
|
)
|
|
|
|
} catch {
|
|
|
|
handleError(error)
|
2022-09-13 03:19:56 -07:00
|
|
|
}
|
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [secondScanExpectation], timeout: 20)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
|
|
|
// verify that the balance still adds up
|
2023-03-30 03:49:28 -07:00
|
|
|
expectedVerifiedBalance = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
|
|
|
let expectedBalance = try await coordinator.synchronizer.getShieldedBalance()
|
|
|
|
XCTAssertEqual(verifiedBalance, expectedVerifiedBalance)
|
|
|
|
XCTAssertEqual(totalBalance, expectedBalance)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
2021-04-19 10:16:24 -07:00
|
|
|
// try to spend the funds
|
|
|
|
let sendExpectation = XCTestExpectation(description: "after rewind expectation")
|
2022-09-13 03:19:56 -07:00
|
|
|
do {
|
|
|
|
let pendingTx = try await coordinator.synchronizer.sendToAddress(
|
|
|
|
spendingKey: coordinator.spendingKey,
|
|
|
|
zatoshi: Zatoshi(1000),
|
2023-02-13 01:34:41 -08:00
|
|
|
toAddress: try! Recipient(Environment.testRecipientAddress, network: .mainnet),
|
2022-10-02 19:11:17 -07:00
|
|
|
memo: .empty
|
|
|
|
)
|
2022-09-13 03:19:56 -07:00
|
|
|
XCTAssertEqual(Zatoshi(1000), pendingTx.value)
|
2023-02-27 05:39:07 -08:00
|
|
|
sendExpectation.fulfill()
|
2022-09-13 03:19:56 -07:00
|
|
|
} catch {
|
|
|
|
XCTFail("sending fail: \(error)")
|
2021-04-19 10:16:24 -07:00
|
|
|
}
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [sendExpectation], timeout: 15)
|
2021-03-26 15:56:51 -07:00
|
|
|
}
|
2023-05-11 04:13:20 -07:00
|
|
|
|
2023-03-27 07:12:06 -07:00
|
|
|
func testRescanToTransaction() async throws {
|
2021-03-26 15:56:51 -07:00
|
|
|
// 1 sync and get spendable funds
|
2021-05-18 14:22:29 -07:00
|
|
|
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
|
|
|
try coordinator.applyStaged(blockheight: defaultLatestHeight + 50)
|
|
|
|
|
|
|
|
sleep(1)
|
|
|
|
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
|
|
|
|
2023-03-16 02:11:18 -07:00
|
|
|
try await coordinator.sync(
|
2023-02-27 05:36:32 -08:00
|
|
|
completion: { _ in
|
|
|
|
firstSyncExpectation.fulfill()
|
|
|
|
},
|
|
|
|
error: handleError
|
|
|
|
)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [firstSyncExpectation], timeout: 12)
|
2023-03-30 03:49:28 -07:00
|
|
|
let verifiedBalance: Zatoshi = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
|
|
|
let totalBalance: Zatoshi = try await coordinator.synchronizer.getShieldedBalance()
|
2021-03-26 15:56:51 -07:00
|
|
|
// 2 check that there are no unconfirmed funds
|
2021-07-28 09:59:10 -07:00
|
|
|
XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: defaultLatestHeight))
|
2021-03-26 15:56:51 -07:00
|
|
|
XCTAssertEqual(verifiedBalance, totalBalance)
|
|
|
|
|
|
|
|
// rewind to transaction
|
2023-05-05 10:30:47 -07:00
|
|
|
guard let transaction = try await coordinator.synchronizer.allTransactions().first else {
|
2021-03-26 15:56:51 -07:00
|
|
|
XCTFail("failed to get a transaction to rewind to")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-02 04:19:25 -08:00
|
|
|
let rewindExpectation = XCTestExpectation(description: "RewindExpectation")
|
|
|
|
|
|
|
|
try await withCheckedThrowingContinuation { continuation in
|
|
|
|
coordinator.synchronizer.rewind(.transaction(transaction))
|
|
|
|
.sink(
|
|
|
|
receiveCompletion: { result in
|
|
|
|
rewindExpectation.fulfill()
|
|
|
|
switch result {
|
|
|
|
case .finished:
|
|
|
|
continuation.resume()
|
|
|
|
|
|
|
|
case let .failure(error):
|
|
|
|
XCTFail("Rewind failed with error: \(error)")
|
|
|
|
continuation.resume(with: .failure(error))
|
|
|
|
}
|
|
|
|
},
|
|
|
|
receiveValue: { _ in }
|
|
|
|
)
|
|
|
|
.store(in: &cancellables)
|
|
|
|
}
|
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [rewindExpectation], timeout: 2)
|
2023-03-02 04:19:25 -08:00
|
|
|
|
2023-02-27 05:36:32 -08:00
|
|
|
// assert that after the new height is lower or same as transaction, rewind doesn't have to be make exactly to transaction height, it can
|
|
|
|
// be done to nearest height provided by rust
|
2023-03-27 07:12:06 -07:00
|
|
|
let lastScannedHeight = try await coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight()
|
|
|
|
XCTAssertLessThanOrEqual(lastScannedHeight, transaction.anchor(network: network) ?? -1)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
|
|
|
let secondScanExpectation = XCTestExpectation(description: "rescan")
|
|
|
|
|
2023-03-16 02:11:18 -07:00
|
|
|
try await coordinator.sync(
|
2023-02-27 05:36:32 -08:00
|
|
|
completion: { _ in
|
|
|
|
secondScanExpectation.fulfill()
|
|
|
|
},
|
|
|
|
error: handleError
|
|
|
|
)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [secondScanExpectation], timeout: 12)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
|
|
|
// verify that the balance still adds up
|
2023-03-30 03:49:28 -07:00
|
|
|
let expectedVerifiedBalance = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
|
|
|
let expectedBalance = try await coordinator.synchronizer.getShieldedBalance()
|
|
|
|
XCTAssertEqual(verifiedBalance, expectedVerifiedBalance)
|
|
|
|
XCTAssertEqual(totalBalance, expectedBalance)
|
2021-03-26 15:56:51 -07:00
|
|
|
}
|
2023-02-14 02:30:08 -08:00
|
|
|
|
|
|
|
// FIXME [#791]: Fix test
|
2023-05-11 04:13:20 -07:00
|
|
|
func testRewindAfterSendingTransaction() async throws {
|
2021-03-26 15:56:51 -07:00
|
|
|
let notificationHandler = SDKSynchonizerListener()
|
|
|
|
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
|
|
|
|
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
|
|
|
|
|
|
|
|
// 0 subscribe to updated transactions events
|
|
|
|
notificationHandler.subscribeToSynchronizer(coordinator.synchronizer)
|
|
|
|
// 1 sync and get spendable funds
|
2021-05-18 14:22:29 -07:00
|
|
|
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
|
|
|
try coordinator.applyStaged(blockheight: defaultLatestHeight + 10)
|
|
|
|
|
|
|
|
sleep(1)
|
|
|
|
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
|
|
|
|
2023-03-16 02:11:18 -07:00
|
|
|
do {
|
|
|
|
try await coordinator.sync(
|
|
|
|
completion: { _ in
|
2022-09-13 03:19:56 -07:00
|
|
|
firstSyncExpectation.fulfill()
|
2023-03-16 02:11:18 -07:00
|
|
|
},
|
|
|
|
error: self.handleError
|
|
|
|
)
|
|
|
|
} catch {
|
|
|
|
handleError(error)
|
2022-09-13 03:19:56 -07:00
|
|
|
}
|
2023-03-16 02:11:18 -07:00
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [firstSyncExpectation], timeout: 12)
|
2021-03-26 15:56:51 -07:00
|
|
|
// 2 check that there are no unconfirmed funds
|
|
|
|
|
2023-03-30 03:49:28 -07:00
|
|
|
let verifiedBalance: Zatoshi = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
|
|
|
let totalBalance: Zatoshi = try await coordinator.synchronizer.getShieldedBalance()
|
2021-07-28 09:59:10 -07:00
|
|
|
XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: defaultLatestHeight))
|
2021-03-26 15:56:51 -07:00
|
|
|
XCTAssertEqual(verifiedBalance, totalBalance)
|
|
|
|
|
2023-05-11 04:13:20 -07:00
|
|
|
let maxBalance = verifiedBalance - Zatoshi(1000)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
|
|
|
// 3 create a transaction for the max amount possible
|
|
|
|
// 4 send the transaction
|
2023-03-10 03:58:28 -08:00
|
|
|
let spendingKey = coordinator.spendingKey
|
2023-05-05 10:30:47 -07:00
|
|
|
var pendingTx: ZcashTransaction.Overview?
|
2022-09-13 03:19:56 -07:00
|
|
|
do {
|
|
|
|
let transaction = try await coordinator.synchronizer.sendToAddress(
|
|
|
|
spendingKey: spendingKey,
|
|
|
|
zatoshi: maxBalance,
|
2023-02-13 01:34:41 -08:00
|
|
|
toAddress: try! Recipient(Environment.testRecipientAddress, network: .mainnet),
|
2022-10-02 19:11:17 -07:00
|
|
|
memo: try Memo(string: "test send \(self.description) \(Date().description)")
|
|
|
|
)
|
2022-09-13 03:19:56 -07:00
|
|
|
pendingTx = transaction
|
2021-03-26 15:56:51 -07:00
|
|
|
self.sentTransactionExpectation.fulfill()
|
2022-09-13 03:19:56 -07:00
|
|
|
} catch {
|
|
|
|
XCTFail("sendToAddress failed: \(error)")
|
2021-03-26 15:56:51 -07:00
|
|
|
}
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [sentTransactionExpectation], timeout: 20)
|
2023-03-14 05:11:17 -07:00
|
|
|
guard let pendingTx else {
|
2021-03-26 15:56:51 -07:00
|
|
|
XCTFail("transaction creation failed")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
notificationHandler.synchronizerMinedTransaction = { transaction in
|
2023-05-05 10:30:47 -07:00
|
|
|
XCTAssertNotNil(transaction.rawID)
|
|
|
|
XCTAssertNotNil(pendingTx.rawID)
|
|
|
|
XCTAssertEqual(transaction.rawID, pendingTx.rawID)
|
2021-03-26 15:56:51 -07:00
|
|
|
transactionMinedExpectation.fulfill()
|
|
|
|
}
|
|
|
|
|
|
|
|
// 5 apply to height
|
|
|
|
// 6 mine the block
|
|
|
|
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
|
|
|
|
XCTFail("no incoming transaction after")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-27 04:40:32 -07:00
|
|
|
let latestHeight = try await coordinator.latestHeight()
|
2021-03-26 15:56:51 -07:00
|
|
|
let sentTxHeight = latestHeight + 1
|
|
|
|
|
|
|
|
notificationHandler.transactionsFound = { txs in
|
2023-05-05 10:30:47 -07:00
|
|
|
let foundTx = txs.first(where: { $0.rawID == pendingTx.rawID })
|
2021-03-26 15:56:51 -07:00
|
|
|
XCTAssertNotNil(foundTx)
|
|
|
|
XCTAssertEqual(foundTx?.minedHeight, sentTxHeight)
|
|
|
|
|
|
|
|
foundTransactionsExpectation.fulfill()
|
|
|
|
}
|
|
|
|
try coordinator.stageBlockCreate(height: sentTxHeight, count: 100)
|
|
|
|
sleep(1)
|
|
|
|
try coordinator.stageTransaction(rawTx, at: sentTxHeight)
|
|
|
|
try coordinator.applyStaged(blockheight: sentTxHeight)
|
|
|
|
sleep(2)
|
|
|
|
|
|
|
|
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
|
|
|
|
2023-03-16 02:11:18 -07:00
|
|
|
do {
|
|
|
|
try await coordinator.sync(
|
|
|
|
completion: { synchronizer in
|
2023-05-05 10:30:47 -07:00
|
|
|
let pendingTransaction = try await synchronizer.allPendingTransactions()
|
|
|
|
.first(where: { $0.rawID == pendingTx.rawID })
|
2023-03-16 02:11:18 -07:00
|
|
|
XCTAssertNotNil(pendingTransaction, "pending transaction should have been mined by now")
|
2023-05-05 10:30:47 -07:00
|
|
|
XCTAssertNotNil(pendingTransaction?.minedHeight)
|
2023-03-16 02:11:18 -07:00
|
|
|
XCTAssertEqual(pendingTransaction?.minedHeight, sentTxHeight)
|
|
|
|
mineExpectation.fulfill()
|
|
|
|
}, error: self.handleError
|
|
|
|
)
|
|
|
|
} catch {
|
|
|
|
handleError(error)
|
2022-09-13 03:19:56 -07:00
|
|
|
}
|
2023-03-16 02:11:18 -07:00
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
|
|
|
// 7 advance to confirmation
|
2023-05-05 10:30:47 -07:00
|
|
|
let advanceToConfirmationHeight = sentTxHeight + 10
|
|
|
|
|
|
|
|
try coordinator.applyStaged(blockheight: advanceToConfirmationHeight)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
|
|
|
sleep(2)
|
2023-03-02 04:19:25 -08:00
|
|
|
|
|
|
|
let rewindExpectation = XCTestExpectation(description: "RewindExpectation")
|
|
|
|
|
2023-05-05 10:30:47 -07:00
|
|
|
let rewindHeight = sentTxHeight - 5
|
2023-03-02 04:19:25 -08:00
|
|
|
try await withCheckedThrowingContinuation { continuation in
|
|
|
|
// rewind 5 blocks prior to sending
|
2023-05-05 10:30:47 -07:00
|
|
|
coordinator.synchronizer.rewind(.height(blockheight: rewindHeight))
|
2023-03-02 04:19:25 -08:00
|
|
|
.sink(
|
|
|
|
receiveCompletion: { result in
|
|
|
|
rewindExpectation.fulfill()
|
|
|
|
switch result {
|
|
|
|
case .finished:
|
|
|
|
continuation.resume()
|
|
|
|
|
|
|
|
case let .failure(error):
|
|
|
|
XCTFail("Rewind failed with error: \(error)")
|
|
|
|
continuation.resume(with: .failure(error))
|
|
|
|
}
|
|
|
|
},
|
|
|
|
receiveValue: { _ in }
|
|
|
|
)
|
|
|
|
.store(in: &cancellables)
|
|
|
|
}
|
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [rewindExpectation], timeout: 2)
|
2023-03-02 04:19:25 -08:00
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
guard
|
2023-03-31 01:49:06 -07:00
|
|
|
let pendingEntity = try await coordinator.synchronizer.allPendingTransactions()
|
2023-05-05 10:30:47 -07:00
|
|
|
.first(where: { $0.rawID == pendingTx.rawID })
|
2021-09-23 06:26:41 -07:00
|
|
|
else {
|
2021-03-26 15:56:51 -07:00
|
|
|
XCTFail("sent pending transaction not found after rewind")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-05 10:30:47 -07:00
|
|
|
XCTAssertNil(pendingEntity.minedHeight)
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2021-03-26 15:56:51 -07:00
|
|
|
let confirmExpectation = XCTestExpectation(description: "confirm expectation")
|
|
|
|
notificationHandler.transactionsFound = { txs in
|
|
|
|
XCTAssertEqual(txs.count, 1)
|
2021-09-23 06:26:41 -07:00
|
|
|
guard let transaction = txs.first else {
|
2021-03-26 15:56:51 -07:00
|
|
|
XCTFail("should have found sent transaction but didn't")
|
|
|
|
return
|
|
|
|
}
|
2023-05-05 10:30:47 -07:00
|
|
|
XCTAssertEqual(transaction.rawID, pendingTx.rawID, "should have mined sent transaction but didn't")
|
2021-03-26 15:56:51 -07:00
|
|
|
}
|
2021-09-23 06:26:41 -07:00
|
|
|
|
|
|
|
notificationHandler.synchronizerMinedTransaction = { transaction in
|
2023-05-11 04:13:20 -07:00
|
|
|
XCTAssertEqual(transaction.rawID, pendingTx.rawID)
|
2021-03-26 15:56:51 -07:00
|
|
|
}
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2023-03-16 02:11:18 -07:00
|
|
|
do {
|
|
|
|
try await coordinator.sync(
|
|
|
|
completion: { _ in
|
2022-09-13 03:19:56 -07:00
|
|
|
confirmExpectation.fulfill()
|
2023-03-16 02:11:18 -07:00
|
|
|
},
|
|
|
|
error: self.handleError
|
|
|
|
)
|
|
|
|
} catch {
|
|
|
|
handleError(error)
|
2022-09-13 03:19:56 -07:00
|
|
|
}
|
2023-03-16 02:11:18 -07:00
|
|
|
|
2023-04-03 06:30:08 -07:00
|
|
|
await fulfillment(of: [confirmExpectation], timeout: 10)
|
2021-03-26 15:56:51 -07:00
|
|
|
|
2023-03-31 01:49:06 -07:00
|
|
|
let confirmedPending = try await coordinator.synchronizer.allPendingTransactions()
|
2023-05-05 10:30:47 -07:00
|
|
|
.first(where: { $0.rawID == pendingTx.rawID })
|
2021-03-26 15:56:51 -07:00
|
|
|
|
|
|
|
XCTAssertNil(confirmedPending, "pending, now confirmed transaction found")
|
2023-03-30 03:49:28 -07:00
|
|
|
|
|
|
|
let expectedVerifiedbalance = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
|
|
|
let expectedBalance = try await coordinator.synchronizer.getShieldedBalance()
|
|
|
|
XCTAssertEqual(expectedBalance, .zero)
|
|
|
|
XCTAssertEqual(expectedVerifiedbalance, .zero)
|
2021-03-26 15:56:51 -07:00
|
|
|
}
|
|
|
|
}
|