From 78b1f937ba85046ea9cd63894928ef6111e7749c Mon Sep 17 00:00:00 2001 From: Adam Stener Date: Thu, 23 Sep 2021 08:26:41 -0500 Subject: [PATCH] SwiftLint Enabled on Test Folder --- .swiftlint.yml | 4 +- .../AdvancedReOrgTests.swift | 823 ++++++++-------- ZcashLightClientKitTests/BalanceTests.swift | 891 ++++++++++-------- .../BlockBatchValidationTests.swift | 289 ++++-- .../BlockDownloaderTests.swift | 47 +- .../BlockScanOperationTests.swift | 147 ++- .../BlockStreamingTest.swift | 140 +-- .../CompactBlockProcessorTests.swift | 111 ++- .../CompactBlockReorgTests.swift | 126 ++- .../CompactBlockStorageTests.swift | 12 +- .../DarksideSanityCheckTests.swift | 40 +- .../DownloadOperationTests.swift | 13 +- .../LightWalletServiceTests.swift | 19 +- ZcashLightClientKitTests/MemoTests.swift | 48 +- .../NetworkUpgradeTests.swift | 343 ++++--- .../NotesRepositoryTests.swift | 6 +- ZcashLightClientKitTests/NullBytesTests.swift | 71 +- .../PagedTransactionRepositoryTests.swift | 23 +- .../PendingTransactionRepositoryTests.swift | 88 +- .../PendingTransactionUpdatesTest.swift | 138 +-- .../RawTransactionTests.swift | 20 +- ZcashLightClientKitTests/ReOrgTests.swift | 189 ++-- .../RewindRescanTests.swift | 180 ++-- .../SychronizerDarksideTests.swift | 71 +- .../TestCoordinator.swift | 233 +++-- .../TransactionEnhancementTests.swift | 117 ++- .../TransactionRepositoryTests.swift | 76 +- ZcashLightClientKitTests/TxIdTests.swift | 3 +- ZcashLightClientKitTests/WalletTests.swift | 35 +- .../Z2TReceiveTests.swift | 95 +- .../ZcashLightClientKitTests.swift | 15 +- .../ZcashRustBackendTests.swift | 87 +- .../utils/DarkSideWalletService.swift | 128 +-- .../utils/FakeChainBuilder.swift | 204 ++-- .../utils/FakeService.swift | 37 +- .../utils/FakeStorage.swift | 3 +- .../utils/MockTransactionRepository.swift | 232 +++-- .../utils/SampleLogger.swift | 14 +- ZcashLightClientKitTests/utils/Stubs.swift | 121 ++- .../utils/TestDbBuilder.swift | 25 +- .../utils/Tests+Utils.swift | 50 +- 41 files changed, 3068 insertions(+), 2246 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index bc319f41..43bf4345 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -3,12 +3,14 @@ excluded: - Pods - - ZcashLightClientKitTests - ZcashLightClientKit/Service/ProtoBuf + - ZcashLightClientKitTests/proto + - ZcashLightClientKitTests/Constants.generated.swift included: - Example/ZcashLightClientSample/ZcashLIghtClientSample - ZcashLightClientKit + - ZcashLightClientKitTests disabled_rules: - notification_center_detachment diff --git a/ZcashLightClientKitTests/AdvancedReOrgTests.swift b/ZcashLightClientKitTests/AdvancedReOrgTests.swift index bef525e4..d9c97f07 100644 --- a/ZcashLightClientKitTests/AdvancedReOrgTests.swift +++ b/ZcashLightClientKitTests/AdvancedReOrgTests.swift @@ -7,12 +7,16 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable implicitly_unwrapped_optional force_unwrapping type_body_length class AdvancedReOrgTests: XCTestCase { - - var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment? - - let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment - + // TODO: Parameterize this from environment? + // swiftlint:disable:next line_length + var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" + + // TODO: Parameterize this from environment + let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" + let sendAmount: Int64 = 1000 var birthday: BlockHeight = 663150 let defaultLatestHeight: BlockHeight = 663175 @@ -21,13 +25,13 @@ class AdvancedReOrgTests: XCTestCase { var sentTransactionExpectation = XCTestExpectation(description: "sent") var expectedReorgHeight: BlockHeight = 665188 var expectedRewindHeight: BlockHeight = 665188 - var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg") + var reorgExpectation = XCTestExpectation(description: "reorg") let branchID = "2bb40e60" let chainName = "main" let network = DarksideWalletDNetwork() override func setUpWithError() throws { - + try super.setUpWithError() coordinator = try TestCoordinator( seed: seedPhrase, walletBirthday: birthday, @@ -38,6 +42,7 @@ class AdvancedReOrgTests: XCTestCase { } override func tearDownWithError() throws { + try super.tearDownWithError() NotificationCenter.default.removeObserver(self) try coordinator.stop() try? FileManager.default.removeItem(at: coordinator.databases.cacheDB) @@ -46,60 +51,64 @@ class AdvancedReOrgTests: XCTestCase { } @objc func handleReorg(_ notification: Notification) { - - guard let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight, + guard + let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight, let rewindHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight - else { - XCTFail("empty reorg notification") - return + else { + XCTFail("empty reorg notification") + return } + logger!.debug("--- REORG DETECTED \(reorgHeight)--- RewindHeight: \(rewindHeight)", file: #file, function: #function, line: #line) -// XCTAssertEqual(rewindHeight, expectedRewindHeight) + XCTAssertEqual(reorgHeight, expectedReorgHeight) reorgExpectation.fulfill() } /* - pre-condition: know balances before tx at received_Tx_height arrives - 1. Setup w/ default dataset - 2. applyStaged(received_Tx_height) - 3. sync up to received_Tx_height - 3a. verify that balance is previous balance + tx amount - 4. get that transaction hex encoded data - 5. stage 5 empty blocks w/heights received_Tx_height to received_Tx_height + 3 - 6. stage tx at received_Tx_height + 3 - 6a. applyheight(received_Tx_height + 1) - 7. sync to received_Tx_height + 1 - 8. assert that reorg happened at received_Tx_height - 9. verify that balance equals initial balance - 10. sync up to received_Tx_height + 3 - 11. verify that balance equals initial balance + tx amount - */ + pre-condition: know balances before tx at received_Tx_height arrives + 1. Setup w/ default dataset + 2. applyStaged(received_Tx_height) + 3. sync up to received_Tx_height + 3a. verify that balance is previous balance + tx amount + 4. get that transaction hex encoded data + 5. stage 5 empty blocks w/heights received_Tx_height to received_Tx_height + 3 + 6. stage tx at received_Tx_height + 3 + 6a. applyheight(received_Tx_height + 1) + 7. sync to received_Tx_height + 1 + 8. assert that reorg happened at received_Tx_height + 9. verify that balance equals initial balance + 10. sync up to received_Tx_height + 3 + 11. verify that balance equals initial balance + tx amount + */ func testReOrgChangesInboundTxMinedHeight() throws { hookToReOrgNotification() try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) - var shouldContinue = false + var shouldContinue = false let receivedTxHeight: BlockHeight = 663188 var initialTotalBalance: Int64 = -1 var initialVerifiedBalance: Int64 = -1 self.expectedReorgHeight = receivedTxHeight + 1 /* - precondition:know balances before tx at received_Tx_height arrives - */ + precondition:know balances before tx at received_Tx_height arrives + */ try coordinator.applyStaged(blockheight: receivedTxHeight - 1) sleep(3) let preTxExpectation = XCTestExpectation(description: "pre receive") - var s: SDKSynchronizer? + var synchronizer: SDKSynchronizer? - try coordinator.sync(completion: { (synchronizer) in - s = synchronizer - initialVerifiedBalance = synchronizer.initializer.getVerifiedBalance() - initialTotalBalance = synchronizer.initializer.getBalance() - preTxExpectation.fulfill() - shouldContinue = true - }, error: self.handleError) + try coordinator.sync( + completion: { synchro in + synchronizer = synchro + initialVerifiedBalance = synchro.initializer.getVerifiedBalance() + initialTotalBalance = synchro.initializer.getBalance() + preTxExpectation.fulfill() + shouldContinue = true + }, + error: self.handleError + ) wait(for: [preTxExpectation], timeout: 10) @@ -109,30 +118,28 @@ class AdvancedReOrgTests: XCTestCase { } /* - 2. applyStaged(received_Tx_height) - */ - + 2. applyStaged(received_Tx_height) + */ try coordinator.applyStaged(blockheight: receivedTxHeight) sleep(2) /* - 3. sync up to received_Tx_height - */ - + 3. sync up to received_Tx_height + */ let receivedTxExpectation = XCTestExpectation(description: "received tx") var receivedTxTotalBalance = Int64(-1) var receivedTxVerifiedBalance = Int64(-1) - try coordinator.sync(completion: { (synchronizer) in - s = synchronizer - receivedTxVerifiedBalance = synchronizer.initializer.getVerifiedBalance() - receivedTxTotalBalance = synchronizer.initializer.getBalance() + try coordinator.sync(completion: { synchro in + synchronizer = synchro + receivedTxVerifiedBalance = synchro.initializer.getVerifiedBalance() + receivedTxTotalBalance = synchro.initializer.getBalance() receivedTxExpectation.fulfill() }, error: self.handleError) sleep(2) wait(for: [receivedTxExpectation], timeout: 10) - guard let syncedSynchronizer = s else { + guard let syncedSynchronizer = synchronizer else { XCTFail("nil synchronizer") return } @@ -142,17 +149,15 @@ class AdvancedReOrgTests: XCTestCase { return } - /* - 3a. verify that balance is previous balance + tx amount - */ - + 3a. verify that balance is previous balance + tx amount + */ XCTAssertEqual(receivedTxTotalBalance, initialTotalBalance + Int64(receivedTx.value)) XCTAssertEqual(receivedTxVerifiedBalance, initialVerifiedBalance) + /* - 4. get that transaction hex encoded data - */ - + 4. get that transaction hex encoded data + */ guard let receivedTxData = receivedTx.raw else { XCTFail("received tx has no raw data!") return @@ -164,56 +169,52 @@ class AdvancedReOrgTests: XCTestCase { } /* - 5. stage 5 empty blocks w/heights received_Tx_height to received_Tx_height + 4 - */ - + 5. stage 5 empty blocks w/heights received_Tx_height to received_Tx_height + 4 + */ try coordinator.stageBlockCreate(height: receivedTxHeight, count: 5) /* - 6. stage tx at received_Tx_height + 3 - */ - + 6. stage tx at received_Tx_height + 3 + */ let reorgedTxheight = receivedTxHeight + 2 - try coordinator.stageTransaction(receivedRawTx, at:reorgedTxheight) + try coordinator.stageTransaction(receivedRawTx, at: reorgedTxheight) /* - 6a. applyheight(received_Tx_height + 1) - */ - + 6a. applyheight(received_Tx_height + 1) + */ try coordinator.applyStaged(blockheight: receivedTxHeight + 1) sleep(2) + /* - 7. sync to received_Tx_height + 1 - */ - + 7. sync to received_Tx_height + 1 + */ let reorgSyncexpectation = XCTestExpectation(description: "reorg expectation") var afterReorgTxTotalBalance = Int64(-1) var afterReorgTxVerifiedBalance = Int64(-1) - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { synchronizer in afterReorgTxTotalBalance = synchronizer.initializer.getBalance() afterReorgTxVerifiedBalance = synchronizer.initializer.getVerifiedBalance() reorgSyncexpectation.fulfill() }, error: self.handleError(_:)) /* - 8. assert that reorg happened at received_Tx_height - */ + 8. assert that reorg happened at received_Tx_height + */ sleep(2) wait(for: [reorgExpectation, reorgSyncexpectation], timeout: 5, enforceOrder: false) + /* - 9. verify that balance equals initial balance - */ - + 9. verify that balance equals initial balance + */ XCTAssertEqual(afterReorgTxVerifiedBalance, initialVerifiedBalance) XCTAssertEqual(afterReorgTxTotalBalance, initialTotalBalance) /* - 10. sync up to received_Tx_height + 3 - */ - + 10. sync up to received_Tx_height + 3 + */ let finalsyncExpectation = XCTestExpectation(description: "final sync") var finalReorgTxTotalBalance = Int64(-1) @@ -221,7 +222,7 @@ class AdvancedReOrgTests: XCTestCase { try coordinator.applyStaged(blockheight: reorgedTxheight + 1) sleep(3) - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { synchronizer in finalReorgTxTotalBalance = synchronizer.initializer.getBalance() finalReorgTxVerifiedBalance = synchronizer.initializer.getVerifiedBalance() finalsyncExpectation.fulfill() @@ -241,48 +242,48 @@ class AdvancedReOrgTests: XCTestCase { } /** - An outbound, unconfirmed transaction in a specific block changes height in the event of a reorg + An outbound, unconfirmed transaction in a specific block changes height in the event of a reorg - The wallet handles this change, reflects it appropriately in local storage, and funds remain spendable post confirmation. + The wallet handles this change, reflects it appropriately in local storage, and funds remain spendable post confirmation. - Pre-conditions: - - Wallet has spendable funds + Pre-conditions: + - Wallet has spendable funds - 1. Setup w/ default dataset - 2. applyStaged(received_Tx_height) - 3. sync up to received_Tx_height - 4. create transaction - 5. stage 10 empty blocks - 6. submit tx at sentTxHeight - 6a. getIncomingTx - 6b. stageTransaction(sentTx, sentTxHeight) - 6c. applyheight(sentTxHeight + 1 ) - 7. sync to sentTxHeight + 2 - 8. stage sentTx and otherTx at sentTxheight - 9. applyStaged(sentTx + 2) - 10. sync up to received_Tx_height + 2 - 11. verify that the sent tx is mined and balance is correct - 12. applyStaged(sentTx + 10) - 13. verify that there's no more pending transaction - */ + 1. Setup w/ default dataset + 2. applyStaged(received_Tx_height) + 3. sync up to received_Tx_height + 4. create transaction + 5. stage 10 empty blocks + 6. submit tx at sentTxHeight + 6a. getIncomingTx + 6b. stageTransaction(sentTx, sentTxHeight) + 6c. applyheight(sentTxHeight + 1 ) + 7. sync to sentTxHeight + 2 + 8. stage sentTx and otherTx at sentTxheight + 9. applyStaged(sentTx + 2) + 10. sync up to received_Tx_height + 2 + 11. verify that the sent tx is mined and balance is correct + 12. applyStaged(sentTx + 10) + 13. verify that there's no more pending transaction + */ func testReorgChangesOutboundTxIndex() throws { try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName) let receivedTxHeight: BlockHeight = 663188 var initialTotalBalance: Int64 = -1 /* - 2. applyStaged(received_Tx_height) - */ + 2. applyStaged(received_Tx_height) + */ try coordinator.applyStaged(blockheight: receivedTxHeight) sleep(2) let preTxExpectation = XCTestExpectation(description: "pre receive") /* - 3. sync up to received_Tx_height - */ - try coordinator.sync(completion: { (synchronizer) in + 3. sync up to received_Tx_height + */ + try coordinator.sync(completion: { synchronizer in initialTotalBalance = synchronizer.initializer.getBalance() preTxExpectation.fulfill() }, error: self.handleError) @@ -290,16 +291,23 @@ class AdvancedReOrgTests: XCTestCase { wait(for: [preTxExpectation], timeout: 5) let sendExpectation = XCTestExpectation(description: "sendToAddress") - var p: PendingTransactionEntity? - var error: Error? = nil + var pendingEntity: PendingTransactionEntity? + var error: Error? let sendAmount: Int64 = 10000 + /* - 4. create transaction - */ - coordinator.synchronizer.sendToAddress(spendingKey: coordinator.spendingKeys!.first!, zatoshi: sendAmount, toAddress: testRecipientAddress, memo: "test transaction", from: 0) { (result) in + 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): - p = pending + pendingEntity = pending case .failure(let e): error = e } @@ -307,21 +315,21 @@ class AdvancedReOrgTests: XCTestCase { } wait(for: [sendExpectation], timeout: 12) - guard let pendingTx = p else { + guard let pendingTx = pendingEntity else { XCTFail("error sending to address. Error: \(String(describing: error))") return } /* - 5. stage 10 empty blocks - */ + 5. stage 10 empty blocks + */ try coordinator.stageBlockCreate(height: receivedTxHeight + 1, count: 10) let sentTxHeight = receivedTxHeight + 1 /* - 6. stage sent tx at sentTxHeight - */ + 6. stage sent tx at sentTxHeight + */ guard let sentTx = try coordinator.getIncomingTransactions()?.first else { XCTFail("sent transaction not present on Darksidewalletd") return @@ -329,70 +337,70 @@ class AdvancedReOrgTests: XCTestCase { try coordinator.stageTransaction(sentTx, at: sentTxHeight) /* - 6a. applyheight(sentTxHeight + 1 ) - */ + 6a. applyheight(sentTxHeight + 1 ) + */ try coordinator.applyStaged(blockheight: sentTxHeight + 1) sleep(2) /* - 7. sync to sentTxHeight + 1 - */ - + 7. sync to sentTxHeight + 1 + */ let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation") - try coordinator.sync(completion: { (s) in - - let pMinedHeight = s.pendingTransactions.first?.minedHeight - XCTAssertEqual(pMinedHeight, sentTxHeight) - - sentTxSyncExpectation.fulfill() - }, error: self.handleError) - + try coordinator.sync( + completion: { synchronizer in + let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight + XCTAssertEqual(pMinedHeight, sentTxHeight) + + sentTxSyncExpectation.fulfill() + }, + error: self.handleError + ) wait(for: [sentTxSyncExpectation], timeout: 5) - /* - 8. stage sentTx and otherTx at sentTxheight - */ + 8. stage sentTx and otherTx at sentTxheight + */ try coordinator.stageBlockCreate(height: sentTxHeight, count: 20, nonce: 5) try coordinator.stageTransaction(url: FakeChainBuilder.someOtherTxUrl, at: sentTxHeight) try coordinator.stageTransaction(sentTx, at: sentTxHeight) /* - 9. applyStaged(sentTx + 1) - */ + 9. applyStaged(sentTx + 1) + */ try coordinator.applyStaged(blockheight: sentTxHeight + 1) sleep(2) let afterReOrgExpectation = XCTestExpectation(description: "after ReOrg Expectation") - try coordinator.sync(completion: { (s) in - /* - 11. verify that the sent tx is mined and balance is correct - */ - let pMinedHeight = s.pendingTransactions.first?.minedHeight - XCTAssertEqual(pMinedHeight, sentTxHeight) - XCTAssertEqual(initialTotalBalance - sendAmount - Int64(1000), s.initializer.getBalance()) // fee change on this branch - afterReOrgExpectation.fulfill() - }, error: self.handleError) + 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 - Int64(1000), synchronizer.initializer.getBalance()) // fee change on this branch + afterReOrgExpectation.fulfill() + }, + error: self.handleError + ) wait(for: [afterReOrgExpectation], timeout: 5) - /* - 12. applyStaged(sentTx + 10) - */ - + 12. applyStaged(sentTx + 10) + */ try coordinator.applyStaged(blockheight: sentTxHeight + 12) sleep(2) + /* - 13. verify that there's no more pending transaction - */ + 13. verify that there's no more pending transaction + */ let lastSyncExpectation = XCTestExpectation(description: "sync to confirmation") - try coordinator.sync(completion: { (s) in - + try coordinator.sync(completion: { _ in lastSyncExpectation.fulfill() }, error: self.handleError) @@ -415,7 +423,7 @@ class AdvancedReOrgTests: XCTestCase { var preReorgTotalBalance = Int64(0) var preReorgVerifiedBalance = Int64(0) - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { synchronizer in preReorgTotalBalance = synchronizer.initializer.getBalance() preReorgVerifiedBalance = synchronizer.initializer.getVerifiedBalance() firstSyncExpectation.fulfill() @@ -423,11 +431,9 @@ class AdvancedReOrgTests: XCTestCase { wait(for: [firstSyncExpectation], timeout: 10) - /* - trigger reorg - */ - + trigger reorg + */ try coordinator.resetBlocks(dataset: .predefined(dataset: .txIndexChangeAfter)) try coordinator.applyStaged(blockheight: 663200) @@ -437,17 +443,16 @@ class AdvancedReOrgTests: XCTestCase { var postReorgTotalBalance = Int64(0) var postReorgVerifiedBalance = Int64(0) - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { synchronizer in postReorgTotalBalance = synchronizer.initializer.getBalance() postReorgVerifiedBalance = synchronizer.initializer.getVerifiedBalance() afterReorgSync.fulfill() }, error: self.handleError) - wait(for: [reorgExpectation,afterReorgSync], timeout: 15) + wait(for: [reorgExpectation, afterReorgSync], timeout: 15) XCTAssertEqual(postReorgVerifiedBalance, preReorgVerifiedBalance) XCTAssertEqual(postReorgTotalBalance, preReorgTotalBalance) - } func testReOrgExpiresInboundTransaction() throws { @@ -458,11 +463,10 @@ class AdvancedReOrgTests: XCTestCase { let expectation = XCTestExpectation(description: "sync to \(receivedTxHeight - 1) expectation") var initialBalance: Int64 = -1 var initialVerifiedBalance: Int64 = -1 - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { synchronizer in initialBalance = synchronizer.initializer.getBalance() initialVerifiedBalance = synchronizer.initializer.getVerifiedBalance() expectation.fulfill() - }, error: self.handleError) wait(for: [expectation], timeout: 5) @@ -474,12 +478,14 @@ class AdvancedReOrgTests: XCTestCase { var afterTxBalance: Int64 = -1 var afterTxVerifiedBalance: Int64 = -1 - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { synchronizer in afterTxBalance = synchronizer.initializer.getBalance() afterTxVerifiedBalance = synchronizer.initializer.getVerifiedBalance() - XCTAssertNotNil(synchronizer.receivedTransactions.first { $0.minedHeight == receivedTxHeight }, "Transaction not found at \(receivedTxHeight)") + XCTAssertNotNil( + synchronizer.receivedTransactions.first { $0.minedHeight == receivedTxHeight }, + "Transaction not found at \(receivedTxHeight)" + ) afterTxSyncExpectation.fulfill() - }, error: self.handleError) wait(for: [afterTxSyncExpectation], timeout: 10.0) @@ -497,10 +503,13 @@ class AdvancedReOrgTests: XCTestCase { var afterReOrgBalance: Int64 = -1 var afterReOrgVerifiedBalance: Int64 = -1 - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { synchronizer in afterReOrgBalance = synchronizer.initializer.getBalance() afterReOrgVerifiedBalance = synchronizer.initializer.getVerifiedBalance() - XCTAssertNil(synchronizer.receivedTransactions.first { $0.minedHeight == receivedTxHeight }, "Transaction found at \(receivedTxHeight) after reorg") + XCTAssertNil( + synchronizer.receivedTransactions.first { $0.minedHeight == receivedTxHeight }, + "Transaction found at \(receivedTxHeight) after reorg" + ) afterReorgExpectation.fulfill() }, error: self.handleError) @@ -508,20 +517,19 @@ class AdvancedReOrgTests: XCTestCase { XCTAssertEqual(afterReOrgBalance, initialBalance) XCTAssertEqual(afterReOrgVerifiedBalance, initialVerifiedBalance) - } /** - Steps: - 1. sync up to an incoming transaction (incomingTxHeight + 1) - 1a. save balances - 2. stage 4 blocks from incomingTxHeight - 1 with different nonce - 3. stage otherTx at incomingTxHeight - 4. stage incomingTx at incomingTxHeight - 5. applyHeight(incomingHeight + 3) - 6. sync to latest height - 7. check that balances still match - */ + Steps: + 1. sync up to an incoming transaction (incomingTxHeight + 1) + 1a. save balances + 2. stage 4 blocks from incomingTxHeight - 1 with different nonce + 3. stage otherTx at incomingTxHeight + 4. stage incomingTx at incomingTxHeight + 5. applyHeight(incomingHeight + 3) + 6. sync to latest height + 7. check that balances still match + */ func testReOrgChangesInboundTxIndexInBlock() throws { try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) @@ -530,78 +538,76 @@ class AdvancedReOrgTests: XCTestCase { try coordinator.applyStaged(blockheight: incomingTxHeight + 1) /* - 1. sync up to an incoming transaction (incomingTxHeight + 1) - */ - + 1. sync up to an incoming transaction (incomingTxHeight + 1) + */ let firstSyncExpectation = XCTestExpectation(description: "first sync test expectation") var initialBalance: Int64 = -1 var initialVerifiedBalance: Int64 = -1 - var incomingTx: ConfirmedTransactionEntity? = nil - try coordinator.sync(completion: { (synchronizer) in - + var incomingTx: ConfirmedTransactionEntity? + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: self.handleError) wait(for: [firstSyncExpectation], timeout: 5) /* - 1a. save balances - */ + 1a. save balances + */ initialBalance = coordinator.synchronizer.initializer.getBalance() initialVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() incomingTx = coordinator.synchronizer.receivedTransactions.first(where: { $0.minedHeight == incomingTxHeight }) - guard let tx = incomingTx else { + + guard let transaction = incomingTx else { XCTFail("no tx found") return } - guard let txRawData = tx.raw else { + guard let txRawData = transaction.raw else { XCTFail("transaction has no raw data") return } - let rawTransaction = RawTransaction.with( { tx in - tx.data = txRawData + let rawTransaction = RawTransaction.with({ rawTx in + rawTx.data = txRawData }) /* - 2. stage 4 blocks from incomingTxHeight - 1 with different nonce - */ + 2. stage 4 blocks from incomingTxHeight - 1 with different nonce + */ let blockCount = 4 try coordinator.stageBlockCreate(height: incomingTxHeight - 1, count: blockCount, nonce: Int.random(in: 0 ... Int.max)) /* - 3. stage otherTx at incomingTxHeight - */ - + 3. stage otherTx at incomingTxHeight + */ try coordinator.stageTransaction(url: FakeChainBuilder.someOtherTxUrl, at: incomingTxHeight) /* - 4. stage incomingTx at incomingTxHeight - 5. applyHeight(incomingHeight + 3) - 6. sync to latest height - 7. check that balances still match - */ + 4. stage incomingTx at incomingTxHeight + 5. applyHeight(incomingHeight + 3) + 6. sync to latest height + 7. check that balances still match + */ try coordinator.stageTransaction(rawTransaction, at: incomingTxHeight) /* - 5. applyHeight(incomingHeight + 2) - */ - + 5. applyHeight(incomingHeight + 2) + */ try coordinator.applyStaged(blockheight: incomingTxHeight + 2) let lastSyncExpectation = XCTestExpectation(description: "last sync expectation") + /* - 6. sync to latest height - */ - try coordinator.sync(completion: { (s) in + 6. sync to latest height + */ + try coordinator.sync(completion: { _ in lastSyncExpectation.fulfill() }, error: self.handleError) /* - 7. check that balances still match - */ + 7. check that balances still match + */ XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), initialVerifiedBalance) XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), initialBalance) @@ -617,8 +623,7 @@ class AdvancedReOrgTests: XCTestCase { let firstSyncExpectation = XCTestExpectation(description: "first sync test expectation") var initialBalance: Int64 = -1 var initialVerifiedBalance: Int64 = -1 - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { synchronizer in initialBalance = synchronizer.initializer.getBalance() initialVerifiedBalance = synchronizer.initializer.getVerifiedBalance() firstSyncExpectation.fulfill() @@ -626,13 +631,13 @@ class AdvancedReOrgTests: XCTestCase { wait(for: [firstSyncExpectation], timeout: 5) - try coordinator.resetBlocks(dataset:.predefined(dataset: .txIndexChangeAfter)) + try coordinator.resetBlocks(dataset: .predefined(dataset: .txIndexChangeAfter)) try coordinator.applyStaged(blockheight: finalHeight) let lastSyncExpectation = XCTestExpectation(description: "last sync expectation") - try coordinator.sync(completion: { (s) in + try coordinator.sync(completion: { _ in lastSyncExpectation.fulfill() }, error: self.handleError) @@ -643,36 +648,37 @@ class AdvancedReOrgTests: XCTestCase { } /** - A Re Org occurs and changes the height of an outbound transaction - Pre-condition: Wallet has funds + A Re Org occurs and changes the height of an outbound transaction + Pre-condition: Wallet has funds - Steps: - 1. create fake chain - 1a. sync to latest height - 2. send transaction to recipient address - 3. getIncomingTransaction - 4. stage transaction at sentTxHeight - 5. applyHeight(sentTxHeight) - 6. sync to latest height - 6a. verify that there's a pending transaction with a mined height of sentTxHeight - 7. stage 15 blocks from sentTxHeight - 7. a stage sent tx to sentTxHeight + 2 - 8. applyHeight(sentTxHeight + 1) to cause a 1 block reorg - 9. sync to latest height - 10. verify that there's a pending transaction with -1 mined height - 11. applyHeight(sentTxHeight + 2) - 11a. sync to latest height - 12. verify that there's a pending transaction with a mined height of sentTxHeight + 2 - 13. apply height(sentTxHeight + 15) - 14. sync to latest height - 15. verify that there's no pending transaction and that the tx is displayed on the sentTransactions collection + Steps: + 1. create fake chain + 1a. sync to latest height + 2. send transaction to recipient address + 3. getIncomingTransaction + 4. stage transaction at sentTxHeight + 5. applyHeight(sentTxHeight) + 6. sync to latest height + 6a. verify that there's a pending transaction with a mined height of sentTxHeight + 7. stage 15 blocks from sentTxHeight + 7. a stage sent tx to sentTxHeight + 2 + 8. applyHeight(sentTxHeight + 1) to cause a 1 block reorg + 9. sync to latest height + 10. verify that there's a pending transaction with -1 mined height + 11. applyHeight(sentTxHeight + 2) + 11a. sync to latest height + 12. verify that there's a pending transaction with a mined height of sentTxHeight + 2 + 13. apply height(sentTxHeight + 15) + 14. sync to latest height + 15. verify that there's no pending transaction and that the tx is displayed on the sentTransactions collection - */ + */ func testReOrgChangesOutboundTxMinedHeight() throws { hookToReOrgNotification() + /* - 1. create fake chain - */ + 1. create fake chain + */ try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) try coordinator.applyStaged(blockheight: 663188) @@ -680,9 +686,9 @@ class AdvancedReOrgTests: XCTestCase { let firstSyncExpectation = XCTestExpectation(description: "first sync") /* - 1a. sync to latest height - */ - try coordinator.sync(completion: { (s) in + 1a. sync to latest height + */ + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: self.handleError) @@ -692,31 +698,39 @@ class AdvancedReOrgTests: XCTestCase { let initialTotalBalance = coordinator.synchronizer.initializer.getBalance() let sendExpectation = XCTestExpectation(description: "send expectation") - var p: PendingTransactionEntity? = nil + var pendingEntity: PendingTransactionEntity? /* - 2. send transaction to recipient address - */ - coordinator.synchronizer.sendToAddress(spendingKey: self.coordinator.spendingKeys!.first!, 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): - p = pendingTx + 2. send transaction to recipient address + */ + coordinator.synchronizer.sendToAddress( + spendingKey: self.coordinator.spendingKeys!.first!, + 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() } - sendExpectation.fulfill() - }) + ) wait(for: [sendExpectation], timeout: 11) - guard let _ = p else { + guard pendingEntity != nil else { XCTFail("no pending transaction after sending") try coordinator.stop() return } + /** - 3. getIncomingTransaction - */ + 3. getIncomingTransaction + */ guard let incomingTx = try coordinator.getIncomingTransactions()?.first else { XCTFail("no incoming transaction") try coordinator.stop() @@ -725,27 +739,26 @@ class AdvancedReOrgTests: XCTestCase { let sentTxHeight: BlockHeight = 663189 - /* - 4. stage transaction at sentTxHeight - */ - + 4. stage transaction at sentTxHeight + */ try coordinator.stageBlockCreate(height: sentTxHeight) try coordinator.stageTransaction(incomingTx, at: sentTxHeight) + /* - 5. applyHeight(sentTxHeight) - */ + 5. applyHeight(sentTxHeight) + */ try coordinator.applyStaged(blockheight: sentTxHeight) sleep(2) /* - 6. sync to latest height - */ - let secondSyncExpectation = XCTestExpectation(description: "after send expectation") + 6. sync to latest height + */ + let secondSyncExpectation = XCTestExpectation(description: "after send expectation") - try coordinator.sync(completion: { (s) in + try coordinator.sync(completion: { _ in secondSyncExpectation.fulfill() }, error: self.handleError) @@ -757,42 +770,41 @@ class AdvancedReOrgTests: XCTestCase { } /* - 6a. verify that there's a pending transaction with a mined height of sentTxHeight - */ - + 6a. verify that there's a pending transaction with a mined height of sentTxHeight + */ XCTAssertEqual(afterStagePendingTx.minedHeight, sentTxHeight) /* - 7. stage 20 blocks from sentTxHeight - */ + 7. stage 20 blocks from sentTxHeight + */ try coordinator.stageBlockCreate(height: sentTxHeight, count: 25) /* - 7a. stage sent tx to sentTxHeight + 2 - */ + 7a. stage sent tx to sentTxHeight + 2 + */ try coordinator.stageTransaction(incomingTx, at: sentTxHeight + 2) /* - 8. applyHeight(sentTxHeight + 1) to cause a 1 block reorg - */ + 8. applyHeight(sentTxHeight + 1) to cause a 1 block reorg + */ try coordinator.applyStaged(blockheight: sentTxHeight + 1) sleep(2) /* - 9. sync to latest height - */ + 9. sync to latest height + */ self.expectedReorgHeight = sentTxHeight + 1 let afterReorgExpectation = XCTestExpectation(description: "after reorg sync") - try coordinator.sync(completion: { (s) in + try coordinator.sync(completion: { _ in afterReorgExpectation.fulfill() }, error: self.handleError) - wait(for: [reorgExpectation,afterReorgExpectation], timeout: 5) + wait(for: [reorgExpectation, afterReorgExpectation], timeout: 5) /* - 10. verify that there's a pending transaction with -1 mined height - */ + 10. verify that there's a pending transaction with -1 mined height + */ guard let newPendingTx = coordinator.synchronizer.pendingTransactions.first else { XCTFail("No pending transaction") try coordinator.stop() @@ -802,29 +814,26 @@ class AdvancedReOrgTests: XCTestCase { XCTAssertEqual(newPendingTx.minedHeight, BlockHeight.empty()) /* - 11. applyHeight(sentTxHeight + 2) - */ + 11. applyHeight(sentTxHeight + 2) + */ try coordinator.applyStaged(blockheight: sentTxHeight + 2) sleep(2) - let yetAnotherExpectation = XCTestExpectation(description: "after staging expectation") /* - 11a. sync to latest height - */ - try coordinator.sync(completion: { (s) in + 11a. sync to latest height + */ + try coordinator.sync(completion: { _ in yetAnotherExpectation.fulfill() }, error: self.handleError) wait(for: [yetAnotherExpectation], timeout: 5) - /* - 12. verify that there's a pending transaction with a mined height of sentTxHeight + 2 - */ - - XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count,1) + 12. verify that there's a pending transaction with a mined height of sentTxHeight + 2 + */ + XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count, 1) guard let newlyPendingTx = try coordinator.synchronizer.allPendingTransactions().first else { XCTFail("no pending transaction") try coordinator.stop() @@ -834,54 +843,64 @@ class AdvancedReOrgTests: XCTestCase { XCTAssertEqual(newlyPendingTx.minedHeight, sentTxHeight + 2) /* - 13. apply height(sentTxHeight + 25) - */ - + 13. apply height(sentTxHeight + 25) + */ try coordinator.applyStaged(blockheight: sentTxHeight + 25) sleep(2) let thisIsTheLastExpectationIPromess = XCTestExpectation(description: "last sync") + /* - 14. sync to latest height - */ - - try coordinator.sync(completion: { (s) in + 14. sync to latest height + */ + try coordinator.sync(completion: { _ in thisIsTheLastExpectationIPromess.fulfill() }, error: self.handleError) wait(for: [thisIsTheLastExpectationIPromess], timeout: 5) /* - 15. verify that there's no pending transaction and that the tx is displayed on the sentTransactions collection - */ - + 15. verify that there's no pending transaction and that the tx is displayed on the sentTransactions collection + */ XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count, 0) - XCTAssertNotNil(coordinator.synchronizer.sentTransactions.first(where: { t in - guard let txId = t.rawTransactionId else { return false } - return txId == newlyPendingTx.rawTransactionId - }), "Sent Tx is not on sent transactions") - - XCTAssertEqual(initialTotalBalance - Int64(newlyPendingTx.value) - Int64(1000), coordinator.synchronizer.initializer.getBalance()) - XCTAssertEqual(initialTotalBalance - Int64(newlyPendingTx.value) - Int64(1000), coordinator.synchronizer.initializer.getVerifiedBalance()) - + XCTAssertNotNil( + coordinator.synchronizer.sentTransactions + .first( + where: { transaction in + guard let txId = transaction.rawTransactionId else { return false } + return txId == newlyPendingTx.rawTransactionId + } + ), + "Sent Tx is not on sent transactions" + ) + XCTAssertEqual( + initialTotalBalance - Int64(newlyPendingTx.value) - Int64(1000), + coordinator.synchronizer.initializer.getBalance() + ) + + XCTAssertEqual( + initialTotalBalance - Int64(newlyPendingTx.value) - Int64(1000), + coordinator.synchronizer.initializer.getVerifiedBalance() + ) } + /** - Uses the zcash-hackworks data set. - - A Re Org occurs at 663195, and sweeps an Inbound Tx that appears later on the chain. - Steps: - 1. reset dlwd - 2. load blocks from txHeightReOrgBefore - 3. applyStaged(663195) - 4. sync to latest height - 5. get balances - 6. load blocks from dataset txHeightReOrgBefore - 7. apply stage 663200 - 8. sync to latest height - 9. verify that the balance is equal to the one before the reorg - */ + Uses the zcash-hackworks data set. + + A Re Org occurs at 663195, and sweeps an Inbound Tx that appears later on the chain. + Steps: + 1. reset dlwd + 2. load blocks from txHeightReOrgBefore + 3. applyStaged(663195) + 4. sync to latest height + 5. get balances + 6. load blocks from dataset txHeightReOrgBefore + 7. apply stage 663200 + 8. sync to latest height + 9. verify that the balance is equal to the one before the reorg + */ func testReOrgChangesInboundMinedHeight() throws { try coordinator.reset(saplingActivation: 663150, branchID: branchID, chainName: chainName) sleep(2) @@ -891,8 +910,7 @@ class AdvancedReOrgTests: XCTestCase { sleep(2) let firstSyncExpectation = XCTestExpectation(description: "first sync") - try coordinator.sync(completion: { (s) in - + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: self.handleError) @@ -914,8 +932,7 @@ class AdvancedReOrgTests: XCTestCase { sleep(6) let afterReOrgExpectation = XCTestExpectation(description: "after reorg") - try coordinator.sync(completion: { (s) in - + try coordinator.sync(completion: { _ in afterReOrgExpectation.fulfill() }, error: self.handleError) @@ -928,18 +945,18 @@ class AdvancedReOrgTests: XCTestCase { XCTAssertEqual(initialVerifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance()) XCTAssertEqual(initialBalance, coordinator.synchronizer.initializer.getBalance()) XCTAssert(afterReOrgTxHeight > initialTxHeight) - } + /** - Re Org removes incoming transaction and is never mined - Steps: - 1. sync prior to incomingTxHeight - 1 to get balances there - 2. sync to latest height - 3. cause reorg - 4. sync to latest height - 5. verify that reorg Happened at reorgHeight - 6. verify that balances match initial balances - */ + Re Org removes incoming transaction and is never mined + Steps: + 1. sync prior to incomingTxHeight - 1 to get balances there + 2. sync to latest height + 3. cause reorg + 4. sync to latest height + 5. verify that reorg Happened at reorgHeight + 6. verify that balances match initial balances + */ func testReOrgRemovesIncomingTxForever() throws { hookToReOrgNotification() try coordinator.reset(saplingActivation: 663150, branchID: branchID, chainName: chainName) @@ -956,9 +973,9 @@ class AdvancedReOrgTests: XCTestCase { let firstSyncExpectation = XCTestExpectation(description: "first sync") /** - 1. sync prior to incomingTxHeight - 1 to get balances there - */ - try coordinator.sync(completion: { (s) in + 1. sync prior to incomingTxHeight - 1 to get balances there + */ + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: self.handleError) @@ -972,24 +989,24 @@ class AdvancedReOrgTests: XCTestCase { let secondSyncExpectation = XCTestExpectation(description: "second sync expectation") /** - 2. sync to latest height - */ - try coordinator.sync(completion: { (s) in + 2. sync to latest height + */ + try coordinator.sync(completion: { _ in secondSyncExpectation.fulfill() }, error: self.handleError) wait(for: [secondSyncExpectation], timeout: 10) /** - 3. cause reorg - */ + 3. cause reorg + */ try coordinator.resetBlocks(dataset: .predefined(dataset: .txReOrgRemovesInboundTxAfter)) try coordinator.applyStaged(blockheight: 663200) sleep(2) let afterReorgSyncExpectation = XCTestExpectation(description: "after reorg expectation") - try coordinator.sync(completion: { (s) in + try coordinator.sync(completion: { _ in afterReorgSyncExpectation.fulfill() }, error: self.handleError) @@ -1000,38 +1017,38 @@ class AdvancedReOrgTests: XCTestCase { } /** - Transaction was included in a block, and then is not included in a block after a reorg, and expires. - Steps: - 1. create fake chain - 1a. sync to latest height - 2. send transaction to recipient address - 3. getIncomingTransaction - 4. stage transaction at sentTxHeight - 5. applyHeight(sentTxHeight) - 6. sync to latest height - 6a. verify that there's a pending transaction with a mined height of sentTxHeight - 7. stage 15 blocks from sentTxHeigth to cause a reorg - 8. sync to latest height - 9. verify that there's an expired transaction as a pending transaction - */ + Transaction was included in a block, and then is not included in a block after a reorg, and expires. + Steps: + 1. create fake chain + 1a. sync to latest height + 2. send transaction to recipient address + 3. getIncomingTransaction + 4. stage transaction at sentTxHeight + 5. applyHeight(sentTxHeight) + 6. sync to latest height + 6a. verify that there's a pending transaction with a mined height of sentTxHeight + 7. stage 15 blocks from sentTxHeigth to cause a reorg + 8. sync to latest height + 9. verify that there's an expired transaction as a pending transaction + */ func testReOrgRemovesOutboundTxAndIsNeverMined() throws { hookToReOrgNotification() /* - 1. create fake chain - */ + 1. create fake chain + */ try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) let sentTxHeight: BlockHeight = 663195 try coordinator.applyStaged(blockheight: sentTxHeight - 1) - sleep(2) let firstSyncExpectation = XCTestExpectation(description: "first sync") + /* - 1a. sync to latest height - */ - try coordinator.sync(completion: { (s) in + 1a. sync to latest height + */ + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: self.handleError) @@ -1040,33 +1057,40 @@ class AdvancedReOrgTests: XCTestCase { sleep(1) let initialTotalBalance = coordinator.synchronizer.initializer.getBalance() - let sendExpectation = XCTestExpectation(description: "send expectation") - var p: PendingTransactionEntity? = nil + var pendingEntity: PendingTransactionEntity? /* - 2. send transaction to recipient address - */ - coordinator.synchronizer.sendToAddress(spendingKey: self.coordinator.spendingKeys!.first!, 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): - p = pendingTx + 2. send transaction to recipient address + */ + coordinator.synchronizer.sendToAddress( + spendingKey: self.coordinator.spendingKeys!.first!, + 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() } - sendExpectation.fulfill() - }) + ) wait(for: [sendExpectation], timeout: 11) - guard let _ = p else { + guard pendingEntity != nil else { XCTFail("no pending transaction after sending") try coordinator.stop() return } + /** - 3. getIncomingTransaction - */ + 3. getIncomingTransaction + */ guard let incomingTx = try coordinator.getIncomingTransactions()?.first else { XCTFail("no incoming transaction") try coordinator.stop() @@ -1074,26 +1098,27 @@ class AdvancedReOrgTests: XCTestCase { } self.expectedReorgHeight = sentTxHeight + 1 + /* - 4. stage transaction at sentTxHeight - */ - + 4. stage transaction at sentTxHeight + */ try coordinator.stageBlockCreate(height: sentTxHeight) try coordinator.stageTransaction(incomingTx, at: sentTxHeight) + /* - 5. applyHeight(sentTxHeight) - */ + 5. applyHeight(sentTxHeight) + */ try coordinator.applyStaged(blockheight: sentTxHeight) sleep(2) /* - 6. sync to latest height - */ - let secondSyncExpectation = XCTestExpectation(description: "after send expectation") + 6. sync to latest height + */ + let secondSyncExpectation = XCTestExpectation(description: "after send expectation") - try coordinator.sync(completion: { (s) in + try coordinator.sync(completion: { _ in secondSyncExpectation.fulfill() }, error: self.handleError) @@ -1106,7 +1131,7 @@ class AdvancedReOrgTests: XCTestCase { sleep(2) let reorgSyncExpectation = XCTestExpectation(description: "reorg sync expectation") - try coordinator.sync(completion: { (s) in + try coordinator.sync(completion: { _ in reorgSyncExpectation.fulfill() }, error: self.handleError) @@ -1126,36 +1151,35 @@ class AdvancedReOrgTests: XCTestCase { let lastSyncExpectation = XCTestExpectation(description: "last sync expectation") - try coordinator.sync(completion: { (s) in + try coordinator.sync(completion: { _ in lastSyncExpectation.fulfill() }, error: self.handleError) wait(for: [lastSyncExpectation], timeout: 5) XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), initialTotalBalance) - } func testLongSync() throws { - hookToReOrgNotification() /* - 1. create fake chain - */ + 1. create fake chain + */ let fullSyncLength = 100_000 - try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID , chainName: chainName, length: fullSyncLength) + try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName, length: fullSyncLength) try coordinator.applyStaged(blockheight: birthday + fullSyncLength) sleep(10) let firstSyncExpectation = XCTestExpectation(description: "first sync") + /* - sync to latest height - */ - try coordinator.sync(completion: { (s) in + sync to latest height + */ + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: { error in _ = try? self.coordinator.stop() @@ -1184,5 +1208,4 @@ class AdvancedReOrgTests: XCTestCase { func hookToReOrgNotification() { NotificationCenter.default.addObserver(self, selector: #selector(handleReorg(_:)), name: .blockProcessorHandledReOrg, object: nil) } - } diff --git a/ZcashLightClientKitTests/BalanceTests.swift b/ZcashLightClientKitTests/BalanceTests.swift index fb7ce46a..c965cb2e 100644 --- a/ZcashLightClientKitTests/BalanceTests.swift +++ b/ZcashLightClientKitTests/BalanceTests.swift @@ -7,22 +7,28 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable type_body_length implicitly_unwrapped_optional force_unwrapping file_length class BalanceTests: XCTestCase { - var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment? - - let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment - + // TODO: Parameterize this from environment? + // swiftlint:disable:next line_length + let seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" + + // TODO: Parameterize this from environment + let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" let sendAmount: Int64 = 1000 - var birthday: BlockHeight = 663150 let defaultLatestHeight: BlockHeight = 663188 - var coordinator: TestCoordinator! let branchID = "2bb40e60" let chainName = "main" - var syncedExpectation = XCTestExpectation(description: "synced") - var sentTransactionExpectation = XCTestExpectation(description: "sent") let network: ZcashNetwork = DarksideWalletDNetwork() + + var birthday: BlockHeight = 663150 + var sentTransactionExpectation = XCTestExpectation(description: "sent") + var syncedExpectation = XCTestExpectation(description: "synced") + var coordinator: TestCoordinator! + override func setUpWithError() throws { - + try super.setUpWithError() coordinator = try TestCoordinator( seed: seedPhrase, walletBirthday: birthday, @@ -30,12 +36,11 @@ class BalanceTests: XCTestCase { network: network ) try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main") - } /** - verify that when sending the maximum amount, the transactions are broadcasted properly - */ + verify that when sending the maximum amount, the transactions are broadcasted properly + */ func testMaxAmountSend() throws { let notificationHandler = SDKSynchonizerListener() let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation") @@ -51,7 +56,7 @@ class BalanceTests: XCTestCase { sleep(1) let firstSyncExpectation = XCTestExpectation(description: "first sync expectation") - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: handleError) @@ -71,34 +76,38 @@ class BalanceTests: XCTestCase { XCTFail("failed to create spending keys") 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 + 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() } - self.sentTransactionExpectation.fulfill() - } + ) + wait(for: [sentTransactionExpectation], timeout: 20) guard let pendingTx = pendingTx else { XCTFail("transaction creation failed") return } - notificationHandler.synchronizerMinedTransaction = { tx in - XCTAssertNotNil(tx.rawTransactionId) + notificationHandler.synchronizerMinedTransaction = { transaction in + XCTAssertNotNil(transaction.rawTransactionId) XCTAssertNotNil(pendingTx.rawTransactionId) - XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId) + XCTAssertEqual(transaction.rawTransactionId, pendingTx.rawTransactionId) transactionMinedExpectation.fulfill() } - // 5 apply to height // 6 mine the block guard let rawTx = try coordinator.getIncomingTransactions()?.first else { @@ -110,7 +119,7 @@ class BalanceTests: XCTestCase { let sentTxHeight = latestHeight + 1 notificationHandler.transactionsFound = { txs in - let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId}) + let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) XCTAssertNotNil(foundTx) XCTAssertEqual(foundTx?.minedHeight, sentTxHeight) @@ -123,21 +132,23 @@ class BalanceTests: XCTestCase { sleep(2) // add enhance breakpoint here let mineExpectation = XCTestExpectation(description: "mineTxExpectation") - try coordinator.sync(completion: { (synchronizer) in - let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId}) - XCTAssertNotNil(p, "pending transaction should have been mined by now") - XCTAssertTrue(p?.isMined ?? false) - XCTAssertEqual(p?.minedHeight, sentTxHeight) - mineExpectation.fulfill() - - }, error: { (error) in - guard let e = error else { - XCTFail("unknown error syncing after sending transaction") - return + 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)") } - - XCTFail("Error: \(e)") - }) + ) wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5) @@ -151,10 +162,10 @@ class BalanceTests: XCTestCase { notificationHandler.transactionsFound = { txs in XCTFail("We shouldn't find any transactions at this point but found \(txs)") } - notificationHandler.synchronizerMinedTransaction = { tx in - XCTFail("We shouldn't find any mined transactions at this point but found \(tx)") + notificationHandler.synchronizerMinedTransaction = { transaction in + XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)") } - try coordinator.sync(completion: { synchronizer in + try coordinator.sync(completion: { _ in confirmExpectation.fulfill() }, error: { e in self.handleError(e) @@ -162,7 +173,8 @@ class BalanceTests: XCTestCase { wait(for: [confirmExpectation], timeout: 5) - let confirmedPending = try coordinator.synchronizer.allPendingTransactions().first(where: { $0.rawTransactionId == pendingTx.rawTransactionId}) + let confirmedPending = try coordinator.synchronizer.allPendingTransactions() + .first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) XCTAssertNil(confirmedPending, "pending, now confirmed transaction found") @@ -170,10 +182,9 @@ class BalanceTests: XCTestCase { XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 0) } - /** - verify that when sending the maximum amount minus one zatoshi, the transactions are broadcasted properly - */ + verify that when sending the maximum amount minus one zatoshi, the transactions are broadcasted properly + */ func testMaxAmountMinusOneSend() throws { let notificationHandler = SDKSynchonizerListener() let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation") @@ -189,7 +200,7 @@ class BalanceTests: XCTestCase { sleep(1) let firstSyncExpectation = XCTestExpectation(description: "first sync expectation") - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: handleError) @@ -209,34 +220,38 @@ 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) { result in - switch result { - case .failure(let error): - XCTFail("sendToAddress failed: \(error)") - case .success(let transaction): - pendingTx = transaction + 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() } - self.sentTransactionExpectation.fulfill() - } + ) + wait(for: [sentTransactionExpectation], timeout: 20) guard let pendingTx = pendingTx else { XCTFail("transaction creation failed") return } - notificationHandler.synchronizerMinedTransaction = { tx in - XCTAssertNotNil(tx.rawTransactionId) + notificationHandler.synchronizerMinedTransaction = { transaction in + XCTAssertNotNil(transaction.rawTransactionId) XCTAssertNotNil(pendingTx.rawTransactionId) - XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId) + XCTAssertEqual(transaction.rawTransactionId, pendingTx.rawTransactionId) transactionMinedExpectation.fulfill() } - // 5 apply to height // 6 mine the block guard let rawTx = try coordinator.getIncomingTransactions()?.first else { @@ -248,7 +263,7 @@ class BalanceTests: XCTestCase { let sentTxHeight = latestHeight + 1 notificationHandler.transactionsFound = { txs in - let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId}) + let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) XCTAssertNotNil(foundTx) XCTAssertEqual(foundTx?.minedHeight, sentTxHeight) @@ -261,14 +276,13 @@ class BalanceTests: XCTestCase { sleep(2) // add enhance breakpoint here let mineExpectation = XCTestExpectation(description: "mineTxExpectation") - try coordinator.sync(completion: { (synchronizer) in - let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId}) - XCTAssertNotNil(p, "pending transaction should have been mined by now") - XCTAssertTrue(p?.isMined ?? false) - XCTAssertEqual(p?.minedHeight, sentTxHeight) + 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 + }, error: { error in guard let e = error else { XCTFail("unknown error syncing after sending transaction") return @@ -289,10 +303,10 @@ class BalanceTests: XCTestCase { notificationHandler.transactionsFound = { txs in XCTFail("We shouldn't find any transactions at this point but found \(txs)") } - notificationHandler.synchronizerMinedTransaction = { tx in - XCTFail("We shouldn't find any mined transactions at this point but found \(tx)") + notificationHandler.synchronizerMinedTransaction = { transaction in + XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)") } - try coordinator.sync(completion: { synchronizer in + try coordinator.sync(completion: { _ in confirmExpectation.fulfill() }, error: { e in self.handleError(e) @@ -300,7 +314,9 @@ class BalanceTests: XCTestCase { wait(for: [confirmExpectation], timeout: 5) - let confirmedPending = try coordinator.synchronizer.allPendingTransactions().first(where: { $0.rawTransactionId == pendingTx.rawTransactionId}) + let confirmedPending = try coordinator.synchronizer + .allPendingTransactions() + .first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) XCTAssertNil(confirmedPending, "pending, now confirmed transaction found") @@ -309,8 +325,8 @@ class BalanceTests: XCTestCase { } /** - verify that when sending the a no change transaction, the transactions are broadcasted properly - */ + verify that when sending the a no change transaction, the transactions are broadcasted properly + */ func testSingleNoteNoChangeTransaction() throws { let notificationHandler = SDKSynchonizerListener() let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation") @@ -326,7 +342,7 @@ class BalanceTests: XCTestCase { sleep(1) let firstSyncExpectation = XCTestExpectation(description: "first sync expectation") - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: handleError) @@ -347,33 +363,36 @@ 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) { result in - switch result { - case .failure(let error): - XCTFail("sendToAddress failed: \(error)") - case .success(let transaction): - pendingTx = transaction + 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() } - self.sentTransactionExpectation.fulfill() - } + ) + wait(for: [sentTransactionExpectation], timeout: 20) guard let pendingTx = pendingTx else { XCTFail("transaction creation failed") return } - notificationHandler.synchronizerMinedTransaction = { tx in - XCTAssertNotNil(tx.rawTransactionId) + notificationHandler.synchronizerMinedTransaction = { transaction in + XCTAssertNotNil(transaction.rawTransactionId) XCTAssertNotNil(pendingTx.rawTransactionId) - XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId) + XCTAssertEqual(transaction.rawTransactionId, pendingTx.rawTransactionId) transactionMinedExpectation.fulfill() } - // 5 apply to height // 6 mine the block guard let rawTx = try coordinator.getIncomingTransactions()?.first else { @@ -385,7 +404,7 @@ class BalanceTests: XCTestCase { let sentTxHeight = latestHeight + 1 notificationHandler.transactionsFound = { txs in - let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId}) + let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) XCTAssertNotNil(foundTx) XCTAssertEqual(foundTx?.minedHeight, sentTxHeight) @@ -398,14 +417,13 @@ class BalanceTests: XCTestCase { sleep(2) // add enhance breakpoint here let mineExpectation = XCTestExpectation(description: "mineTxExpectation") - try coordinator.sync(completion: { (synchronizer) in - let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId}) - XCTAssertNotNil(p, "pending transaction should have been mined by now") - XCTAssertTrue(p?.isMined ?? false) - XCTAssertEqual(p?.minedHeight, sentTxHeight) + 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 + }, error: { error in guard let e = error else { XCTFail("unknown error syncing after sending transaction") return @@ -426,10 +444,10 @@ class BalanceTests: XCTestCase { notificationHandler.transactionsFound = { txs in XCTFail("We shouldn't find any transactions at this point but found \(txs)") } - notificationHandler.synchronizerMinedTransaction = { tx in - XCTFail("We shouldn't find any mined transactions at this point but found \(tx)") + notificationHandler.synchronizerMinedTransaction = { transaction in + XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)") } - try coordinator.sync(completion: { synchronizer in + try coordinator.sync(completion: { _ in confirmExpectation.fulfill() }, error: { e in self.handleError(e) @@ -437,39 +455,39 @@ class BalanceTests: XCTestCase { wait(for: [confirmExpectation], timeout: 5) - let confirmedPending = try coordinator.synchronizer.allPendingTransactions().first(where: { $0.rawTransactionId == pendingTx.rawTransactionId}) + let confirmedPending = try coordinator.synchronizer + .allPendingTransactions() + .first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) XCTAssertNil(confirmedPending, "pending, now confirmed transaction found") XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), 100000) XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 100000) } + /** - - Verify available balance is correct in all wallet states during a send - - This can be either a Wallet test or a Synchronizer test. The latter is supposed to be simpler because it involves no UI testing whatsoever. - - Precondition: - Account has spendable funds - Librustzcash is ‘synced’ up to ‘current tip’ - - Action: - Send Amount(*) to zAddr - - Success per state: - Sent: (previous available funds - spent note + change) equals to (previous available funds - sent amount) - Error: previous available funds equals to current funds - - */ + Verify available balance is correct in all wallet states during a send + + This can be either a Wallet test or a Synchronizer test. The latter is supposed to be simpler because it involves no UI testing whatsoever. + + Precondition: + Account has spendable funds + Librustzcash is ‘synced’ up to ‘current tip’ + + Action: + Send Amount(*) to zAddr + + Success per state: + Sent: (previous available funds - spent note + change) equals to (previous available funds - sent amount) + Error: previous available funds equals to current funds + */ + // swiftlint:disable cyclomatic_complexity func testVerifyAvailableBalanceDuringSend() throws { try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) try coordinator.applyStaged(blockheight: defaultLatestHeight) - - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in self.syncedExpectation.fulfill() }, error: handleError) @@ -483,30 +501,32 @@ class BalanceTests: XCTestCase { let presendVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() /* - there's more zatoshi to send than network fee - */ + there's more zatoshi to send than network fee + */ XCTAssertTrue(presendVerifiedBalance >= (Int64(network.constants.defaultFee(for: defaultLatestHeight)) + sendAmount)) var pendingTx: PendingTransactionEntity? - coordinator.synchronizer.sendToAddress(spendingKey: spendingKey, - zatoshi: Int64(sendAmount), - toAddress: testRecipientAddress, - memo: "test send \(self.description) \(Date().description)", - from: 0) { 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): - - pendingTx = transaction - + coordinator.synchronizer.sendToAddress( + spendingKey: spendingKey, + zatoshi: Int64(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): + + pendingTx = transaction + } + self.sentTransactionExpectation.fulfill() } - self.sentTransactionExpectation.fulfill() - } + ) XCTAssertTrue(coordinator.synchronizer.initializer.getVerifiedBalance() > 0) wait(for: [sentTransactionExpectation], timeout: 12) @@ -527,11 +547,9 @@ class BalanceTests: XCTestCase { sleep(1) let mineExpectation = XCTestExpectation(description: "mineTxExpectation") - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in mineExpectation.fulfill() - - }, error: { (error) in + }, error: { error in guard let e = error else { XCTFail("unknown error syncing after sending transaction") return @@ -542,84 +560,106 @@ class BalanceTests: XCTestCase { wait(for: [mineExpectation], timeout: 5) - XCTAssertEqual(presendVerifiedBalance - self.sendAmount - network.constants.defaultFee(for: defaultLatestHeight),coordinator.synchronizer.initializer.getBalance()) - XCTAssertEqual(presendVerifiedBalance - self.sendAmount - network.constants.defaultFee(for: defaultLatestHeight),coordinator.synchronizer.initializer.getVerifiedBalance()) + XCTAssertEqual( + presendVerifiedBalance - self.sendAmount - network.constants.defaultFee(for: defaultLatestHeight), + coordinator.synchronizer.initializer.getBalance() + ) + + XCTAssertEqual( + presendVerifiedBalance - self.sendAmount - network.constants.defaultFee(for: defaultLatestHeight), + coordinator.synchronizer.initializer.getVerifiedBalance() + ) guard let transaction = pendingTx else { XCTFail("pending transaction nil") return } + /* - basic health check - */ + basic health check + */ XCTAssertEqual(Int64(transaction.value), self.sendAmount) /* - build up repos to get data - */ + build up repos to get data + */ guard let txid = transaction.rawTransactionId else { XCTFail("sent transaction has no internal id") return } - let sentNoteDAO = SentNotesSQLDAO(dbProvider: SimpleConnectionProvider(path: self.coordinator.synchronizer.initializer.dataDbURL.absoluteString, readonly: true)) + + let sentNoteDAO = SentNotesSQLDAO( + dbProvider: SimpleConnectionProvider( + path: self.coordinator.synchronizer.initializer.dataDbURL.absoluteString, + readonly: true + ) + ) - let receivedNoteDAO = ReceivedNotesSQLDAO(dbProvider: SimpleConnectionProvider(path: self.coordinator.synchronizer.initializer.dataDbURL.absoluteString, readonly: true)) - var s: SentNoteEntity? + let receivedNoteDAO = ReceivedNotesSQLDAO( + dbProvider: SimpleConnectionProvider( + path: self.coordinator.synchronizer.initializer.dataDbURL.absoluteString, + readonly: true + ) + ) + var sentEntity: SentNoteEntity? do { - s = try sentNoteDAO.sentNote(byRawTransactionId: txid) + sentEntity = try sentNoteDAO.sentNote(byRawTransactionId: txid) } catch { XCTFail("error retrieving sent note: \(error)") } - guard let sentNote = s else { + guard let sentNote = sentEntity else { XCTFail("could not find sent note for this transaction") return } - var r: ReceivedNoteEntity? + + var receivedEntity: ReceivedNoteEntity? do { - r = try receivedNoteDAO.receivedNote(byRawTransactionId: txid) + receivedEntity = try receivedNoteDAO.receivedNote(byRawTransactionId: txid) } catch { XCTFail("error retrieving received note: \(error)") } - guard let receivedNote = r else { + guard let receivedNote = receivedEntity else { XCTFail("could not find sent note for this transaction") return } + // (previous available funds - spent note + change) equals to (previous available funds - sent amount) - self.verifiedBalanceValidation(previousBalance: presendVerifiedBalance, - spentNoteValue: Int64(sentNote.value), - changeValue: Int64(receivedNote.value), - sentAmount: Int64(self.sendAmount), - currentVerifiedBalance: self.coordinator.synchronizer.initializer.getVerifiedBalance()) - + self.verifiedBalanceValidation( + previousBalance: presendVerifiedBalance, + spentNoteValue: Int64(sentNote.value), + changeValue: Int64(receivedNote.value), + sentAmount: Int64(self.sendAmount), + currentVerifiedBalance: self.coordinator.synchronizer.initializer.getVerifiedBalance() + ) } /** - Verify total balance in all wallet states during a send - This can be either a Wallet test or a Synchronizer test. The latter is supposed to be simpler because it involves no UI testing whatsoever. - - Precondition: - Account has spendable funds - Librustzcash is ‘synced’ up to ‘current tip’ - - Action: - Send Amount to zAddr - - Success per state: - Sent: (total balance funds - sentAmount) equals to (previous available funds - sent amount) - Error: previous total balance funds equals to current total balance - - */ + Verify total balance in all wallet states during a send + This can be either a Wallet test or a Synchronizer test. The latter is supposed to be simpler because it involves no UI testing whatsoever. + + Precondition: + Account has spendable funds + Librustzcash is ‘synced’ up to ‘current tip’ + + Action: + Send Amount to zAddr + + Success per state: + Sent: (total balance funds - sentAmount) equals to (previous available funds - sent amount) + Error: previous total balance funds equals to current total balance + + */ func testVerifyTotalBalanceDuringSend() throws { try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) try coordinator.applyStaged(blockheight: defaultLatestHeight) sleep(2) - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { _ in self.syncedExpectation.fulfill() }, error: handleError) @@ -631,28 +671,31 @@ class BalanceTests: XCTestCase { } let presendBalance = coordinator.synchronizer.initializer.getBalance() - XCTAssertTrue(presendBalance >= (Int64(network.constants.defaultFee(for: defaultLatestHeight)) + sendAmount)) // there's more zatoshi to send than network fee - + + // there's more zatoshi to send than network fee + XCTAssertTrue(presendBalance >= (Int64(network.constants.defaultFee(for: defaultLatestHeight)) + sendAmount)) var pendingTx: PendingTransactionEntity? var error: Error? - coordinator.synchronizer.sendToAddress(spendingKey: spendingKey, - zatoshi: Int64(sendAmount), - toAddress: testRecipientAddress, - memo: "test send \(self.description) \(Date().description)", - from: 0) { 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 + coordinator.synchronizer.sendToAddress( + spendingKey: spendingKey, + zatoshi: Int64(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() } - self.sentTransactionExpectation.fulfill() - } + ) XCTAssertTrue(coordinator.synchronizer.initializer.getVerifiedBalance() > 0) wait(for: [sentTransactionExpectation], timeout: 12) @@ -669,7 +712,10 @@ class BalanceTests: XCTestCase { XCTAssertEqual(Int64(transaction.value), self.sendAmount) - XCTAssertEqual(self.coordinator.synchronizer.initializer.getBalance(), presendBalance - Int64(self.sendAmount) - network.constants.defaultFee(for: defaultLatestHeight)) + XCTAssertEqual( + self.coordinator.synchronizer.initializer.getBalance(), + presendBalance - Int64(self.sendAmount) - network.constants.defaultFee(for: defaultLatestHeight) + ) XCTAssertNil(transaction.errorCode) @@ -681,14 +727,14 @@ class BalanceTests: XCTestCase { return } - try coordinator.stageTransaction(rawTx, at: latestHeight + 1) + try coordinator.stageTransaction(rawTx, at: latestHeight + 1) try coordinator.applyStaged(blockheight: latestHeight + 1) sleep(2) let mineExpectation = XCTestExpectation(description: "mineTxExpectation") - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { _ in mineExpectation.fulfill() - }, error: { (error) in + }, error: { error in guard let e = error else { XCTFail("unknown error syncing after sending transaction") return @@ -699,28 +745,31 @@ class BalanceTests: XCTestCase { wait(for: [mineExpectation], timeout: 5) - XCTAssertEqual(presendBalance - self.sendAmount - Int64(network.constants.defaultFee(for: defaultLatestHeight)),coordinator.synchronizer.initializer.getBalance()) + XCTAssertEqual( + presendBalance - self.sendAmount - Int64(network.constants.defaultFee(for: defaultLatestHeight)), + coordinator.synchronizer.initializer.getBalance() + ) } /** - Verify incoming transactions - This can be either a Wallet test or a Synchronizer test. The latter is supposed to be simpler because it involves no UI testing whatsoever. + Verify incoming transactions + This can be either a Wallet test or a Synchronizer test. The latter is supposed to be simpler because it involves no UI testing whatsoever. - Precondition: - Librustzcash is ‘synced’ up to ‘current tip’ - Known list of expected transactions on the block range to sync the wallet up to. - Known expected balance on the block range to sync the wallet up to. - Action: - sync to latest height - Success criteria: - The transaction list matches the expected one - Balance matches expected balance - - */ + Precondition: + Librustzcash is ‘synced’ up to ‘current tip’ + Known list of expected transactions on the block range to sync the wallet up to. + Known expected balance on the block range to sync the wallet up to. + Action: + sync to latest height + Success criteria: + The transaction list matches the expected one + Balance matches expected balance + + */ func testVerifyIncomingTransaction() throws { try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) try coordinator.applyStaged(blockheight: defaultLatestHeight) - try coordinator.sync(completion: { (syncronizer) in + try coordinator.sync(completion: { _ in self.syncedExpectation.fulfill() }, error: self.handleError) @@ -731,27 +780,27 @@ class BalanceTests: XCTestCase { } /** - Verify change transactions - - This can be either a Wallet test or a Synchronizer test. The latter is supposed to be simpler because it involves no UI testing whatsoever. - - Precondition - Librustzcash is ‘synced’ up to ‘current tip’ - Known list of expected transactions on the block range to sync the wallet up to. - Known expected balance on the block range to sync the wallet up to. - There’s a spendable note with value > send amount that generates change - - Action: - Send amount to zAddr - sync to minedHeight + 1 - - Success Criteria: - There’s a sent transaction matching the amount sent to the given zAddr - minedHeight is not -1 - Balance meets verified Balance and total balance criteria - There’s a change note of value (previous note value - sent amount) - - */ + Verify change transactions + + This can be either a Wallet test or a Synchronizer test. The latter is supposed to be simpler because it involves no UI testing whatsoever. + + Precondition + Librustzcash is ‘synced’ up to ‘current tip’ + Known list of expected transactions on the block range to sync the wallet up to. + Known expected balance on the block range to sync the wallet up to. + There’s a spendable note with value > send amount that generates change + + Action: + Send amount to zAddr + sync to minedHeight + 1 + + Success Criteria: + There’s a sent transaction matching the amount sent to the given zAddr + minedHeight is not -1 + Balance meets verified Balance and total balance criteria + There’s a change note of value (previous note value - sent amount) + + */ func testVerifyChangeTransaction() throws { try FakeChainBuilder.buildSingleNoteChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) @@ -759,20 +808,17 @@ class BalanceTests: XCTestCase { let sendExpectation = XCTestExpectation(description: "send expectation") let createToAddressExpectation = XCTestExpectation(description: "create to address") - try coordinator.setLatestHeight(height: defaultLatestHeight) + /* - sync to current tip - */ - - try coordinator.sync(completion: { (synchronizer) in + sync to current tip + */ + try coordinator.sync(completion: { _ in self.syncedExpectation.fulfill() }, error: self.handleError) wait(for: [syncedExpectation], timeout: 6) - - let previousVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() let previousTotalBalance = coordinator.synchronizer.initializer.getBalance() @@ -782,29 +828,37 @@ class BalanceTests: XCTestCase { } /* - Send - */ + Send + */ let memo = "shielding is fun!" var pendingTx: PendingTransactionEntity? - coordinator.synchronizer.sendToAddress(spendingKey: spendingKeys, zatoshi: Int64(sendAmount), toAddress: testRecipientAddress, memo: memo, from: 0) { (sendResult) in - DispatchQueue.main.async { - switch sendResult { - case .failure(let sendError): - XCTFail("error sending \(sendError)") - case .success(let tx): - pendingTx = tx + coordinator.synchronizer.sendToAddress( + spendingKey: spendingKeys, + zatoshi: Int64(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() } - - sendExpectation.fulfill() } - } + ) wait(for: [createToAddressExpectation], timeout: 30) let syncToMinedheightExpectation = XCTestExpectation(description: "sync to mined height + 1") /* - include sent transaction in block - */ + include sent transaction in block + */ guard let rawTx = try coordinator.getIncomingTransactions()?.first else { XCTFail("pending transaction nil after send") return @@ -818,121 +872,129 @@ class BalanceTests: XCTestCase { sleep(2) /* - 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 - } - - /* - There’s a sent transaction matching the amount sent to the given zAddr - */ - - XCTAssertEqual(Int64(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 - } - - /* - 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 - } - - 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 - } - - /* - There’s a change note of value (previous note value - sent amount) - */ - XCTAssertEqual(previousVerifiedBalance - self.sendAmount - self.network.constants.defaultFee(for: self.defaultLatestHeight), Int64(receivedNote.value)) - - - /* - Balance meets verified Balance and total balance criteria - */ - - self.verifiedBalanceValidation( - previousBalance: previousVerifiedBalance, - spentNoteValue: Int64(sentNote.value), - changeValue: Int64(receivedNote.value), - sentAmount: Int64(self.sendAmount), - currentVerifiedBalance: synchronizer.initializer.getVerifiedBalance()) - - - - self.totalBalanceValidation(totalBalance: synchronizer.initializer.getBalance(), - previousTotalbalance: previousTotalBalance, - sentAmount: Int64(self.sendAmount)) - - syncToMinedheightExpectation.fulfill() - }, error: self.handleError) + 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 + } + + /* + There’s a sent transaction matching the amount sent to the given zAddr + */ + XCTAssertEqual(Int64(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 + } + + /* + 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 + } + + 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 + } + + /* + There’s a change note of value (previous note value - sent amount) + */ + XCTAssertEqual( + previousVerifiedBalance - self.sendAmount - self.network.constants.defaultFee(for: self.defaultLatestHeight), + Int64(receivedNote.value) + ) + + /* + Balance meets verified Balance and total balance criteria + */ + self.verifiedBalanceValidation( + previousBalance: previousVerifiedBalance, + spentNoteValue: Int64(sentNote.value), + changeValue: Int64(receivedNote.value), + sentAmount: Int64(self.sendAmount), + currentVerifiedBalance: synchronizer.initializer.getVerifiedBalance() + ) + + self.totalBalanceValidation( + totalBalance: synchronizer.initializer.getBalance(), + previousTotalbalance: previousTotalBalance, + sentAmount: Int64(self.sendAmount) + ) + + syncToMinedheightExpectation.fulfill() + }, + error: self.handleError + ) wait(for: [syncToMinedheightExpectation], timeout: 5) } /** - Verify transactions that expire are reflected accurately in balance - This test requires the transaction to expire. + erify transactions that expire are reflected accurately in balance + This test requires the transaction to expire. + + How can we mock or cause this? Would createToAddress and faking a network submission through lightwalletService and syncing 10 more blocks work? - How can we mock or cause this? Would createToAddress and faking a network submission through lightwalletService and syncing 10 more blocks work? + Precondition: + Account has spendable funds + Librustzcash is ‘synced’ up to ‘current tip’ † + Current tip can be scanned 10 blocks past the generated to be expired transaction + + Action: + Sync to current tip + Create transaction to zAddr + Mock send success + Sync 10 blocks more + + Success Criteria: + There’s a pending transaction that has expired + Total Balance is equal to total balance previously shown before sending the expired transaction + Verified Balance is equal to verified balance previously shown before sending the expired transaction - Precondition: - Account has spendable funds - Librustzcash is ‘synced’ up to ‘current tip’ † - Current tip can be scanned 10 blocks past the generated to be expired transaction - - Action: - Sync to current tip - Create transaction to zAddr - Mock send success - Sync 10 blocks more - - Success Criteria: - There’s a pending transaction that has expired - Total Balance is equal to total balance previously shown before sending the expired transaction - Verified Balance is equal to verified balance previously shown before sending the expired transaction - - */ + */ func testVerifyBalanceAfterExpiredTransaction() throws { - try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) try coordinator.applyStaged(blockheight: self.defaultLatestHeight) sleep(2) - try coordinator.sync(completion: { (syncronizer) in + try coordinator.sync(completion: { _ in self.syncedExpectation.fulfill() }, error: self.handleError) wait(for: [syncedExpectation], timeout: 5) - guard let spendingKey = coordinator.spendingKeys?.first else { XCTFail("no synchronizer or spending keys") return @@ -942,17 +1004,25 @@ class BalanceTests: XCTestCase { let previousTotalBalance = 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) { (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 + 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 + } } - } + ) + wait(for: [sendExpectation], timeout: 12) guard let pendingTransaction = pendingTx, pendingTransaction.expiryHeight > defaultLatestHeight else { @@ -967,23 +1037,27 @@ class BalanceTests: XCTestCase { try coordinator.applyStaged(blockheight: expiryHeight + 1) sleep(2) - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { _ in expirationSyncExpectation.fulfill() }, error: self.handleError) wait(for: [expirationSyncExpectation], timeout: 5) /* - Verified Balance is equal to verified balance previously shown before sending the expired transaction - */ + Verified Balance is equal to verified balance previously shown before sending the expired transaction + */ XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), previousVerifiedBalance) /* - Total Balance is equal to total balance previously shown before sending the expired transaction - */ + Total Balance is equal to total balance previously shown before sending the expired transaction + */ XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), previousTotalBalance) - let pendingRepo = PendingTransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: coordinator.synchronizer.initializer.pendingDbURL.absoluteString)) + let pendingRepo = PendingTransactionSQLDAO( + dbProvider: SimpleConnectionProvider( + path: coordinator.synchronizer.initializer.pendingDbURL.absoluteString + ) + ) guard let expiredPending = try? pendingRepo.find(by: pendingTransaction.id!), let id = expiredPending.id else { @@ -992,15 +1066,14 @@ class BalanceTests: XCTestCase { } /* - there no sent transaction displayed - */ - - XCTAssertNil( try coordinator.synchronizer.allSentTransactions().first(where: { $0.id == id})) - /* - There’s a pending transaction that has expired - */ - XCTAssertEqual(expiredPending.minedHeight, -1) + there no sent transaction displayed + */ + XCTAssertNil( try coordinator.synchronizer.allSentTransactions().first(where: { $0.id == id })) + /* + There’s a pending transaction that has expired + */ + XCTAssertEqual(expiredPending.minedHeight, -1) } func handleError(_ error: Error?) { @@ -1012,28 +1085,30 @@ class BalanceTests: XCTestCase { } /** - check if (previous available funds - spent note + change) equals to (previous available funds - sent amount) - */ - func verifiedBalanceValidation(previousBalance: Int64, - spentNoteValue: Int64, - changeValue: Int64, - sentAmount: Int64, - currentVerifiedBalance: Int64) { - // (previous available funds - spent note + change) equals to (previous available funds - sent amount) + check if (previous available funds - spent note + change) equals to (previous available funds - sent amount) + */ + func verifiedBalanceValidation( + previousBalance: Int64, + spentNoteValue: Int64, + changeValue: Int64, + sentAmount: Int64, + currentVerifiedBalance: Int64 + ) { XCTAssertEqual(previousBalance - spentNoteValue + changeValue, currentVerifiedBalance - sentAmount) } - func totalBalanceValidation(totalBalance: Int64, - previousTotalbalance: Int64, - sentAmount: Int64) { + func totalBalanceValidation( + totalBalance: Int64, + previousTotalbalance: Int64, + sentAmount: Int64 + ) { XCTAssertEqual(totalBalance, previousTotalbalance - sentAmount - Int64(network.constants.defaultFee(for: defaultLatestHeight))) } - } class SDKSynchonizerListener { - var transactionsFound: (([ConfirmedTransactionEntity]) -> ())? - var synchronizerMinedTransaction: ((PendingTransactionEntity) -> ())? + var transactionsFound: (([ConfirmedTransactionEntity]) -> Void)? + var synchronizerMinedTransaction: ((PendingTransactionEntity) -> Void)? func subscribeToSynchronizer(_ synchronizer: SDKSynchronizer) { NotificationCenter.default.addObserver(self, selector: #selector(txFound(_:)), name: .synchronizerFoundTransactions, object: synchronizer) @@ -1057,12 +1132,12 @@ class SDKSynchonizerListener { @objc func txMined(_ notification: Notification) { DispatchQueue.main.async { [weak self] in - guard let tx = notification.userInfo?[SDKSynchronizer.NotificationKeys.minedTransaction] as? PendingTransactionEntity else { + guard let transaction = notification.userInfo?[SDKSynchronizer.NotificationKeys.minedTransaction] as? PendingTransactionEntity else { XCTFail("expected transaction") return } - self?.synchronizerMinedTransaction?(tx) + self?.synchronizerMinedTransaction?(transaction) } } } diff --git a/ZcashLightClientKitTests/BlockBatchValidationTests.swift b/ZcashLightClientKitTests/BlockBatchValidationTests.swift index 7d5b6de8..b811f367 100644 --- a/ZcashLightClientKitTests/BlockBatchValidationTests.swift +++ b/ZcashLightClientKitTests/BlockBatchValidationTests.swift @@ -8,27 +8,45 @@ import XCTest @testable import ZcashLightClientKit +// swiftlint:disable force_try type_body_length class BlockBatchValidationTests: XCTestCase { var queue: OperationQueue = { - let q = OperationQueue() - q.name = "Test Queue" - q.maxConcurrentOperationCount = 1 - return q + let queue = OperationQueue() + queue.name = "Test Queue" + queue.maxConcurrentOperationCount = 1 + return queue }() - override func setUpWithError() throws { + + override func setUp() { // Put setup code here. This method is called before the invocation of each test method in the class. + super.setUp() } - override func tearDownWithError() throws { + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() } func testBranchIdFailure() throws { let network = ZcashNetworkBuilder.network(for: .mainnet) - let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)) + let service = MockLightWalletService( + latestBlockHeight: 1210000, + service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) + ) let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000) let downloader = CompactBlockDownloader(service: service, storage: repository) - let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network) + let config = CompactBlockProcessor.Configuration( + cacheDb: try! __cacheDbURL(), + dataDb: try! __dataDbURL(), + downloadBatchSize: 100, + retries: 5, + maxBackoffInterval: 10, + rewindDistance: 100, + walletBirthday: 1210000, + saplingActivation: network.constants.saplingActivationHeight, + network: network + ) + var info = LightdInfo() info.blockHeight = 130000 info.branch = "d34db33f" @@ -40,13 +58,15 @@ class BlockBatchValidationTests: XCTestCase { let mockRust = MockRustBackend.self mockRust.consensusBranchID = Int32(0xd34d) + let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust) - let expectation = XCTestExpectation(description: "failure expectation") let startedExpectation = XCTestExpectation(description: "start Expectation") + operation.startedHandler = { startedExpectation.fulfill() } + operation.errorHandler = { error in expectation.fulfill() switch error { @@ -58,17 +78,30 @@ class BlockBatchValidationTests: XCTestCase { } queue.addOperations([operation], waitUntilFinished: false) - wait(for: [startedExpectation,expectation], timeout: 1, enforceOrder: true) + wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true) XCTAssertNotNil(operation.error) XCTAssertTrue(operation.isCancelled) } func testBranchNetworkMismatchFailure() throws { let network = ZcashNetworkBuilder.network(for: .mainnet) - let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)) + let service = MockLightWalletService( + latestBlockHeight: 1210000, + service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) + ) let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000) let downloader = CompactBlockDownloader(service: service, storage: repository) - let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network) + let config = CompactBlockProcessor.Configuration( + cacheDb: try! __cacheDbURL(), + dataDb: try! __dataDbURL(), + downloadBatchSize: 100, + retries: 5, + maxBackoffInterval: 10, + rewindDistance: 100, + walletBirthday: 1210000, + saplingActivation: network.constants.saplingActivationHeight, + network: network + ) var info = LightdInfo() info.blockHeight = 130000 info.branch = "d34db33f" @@ -76,17 +109,20 @@ class BlockBatchValidationTests: XCTestCase { info.buildUser = "test user" info.consensusBranchID = "d34db4d" info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight) + service.mockLightDInfo = info let mockRust = MockRustBackend.self mockRust.consensusBranchID = 0xd34db4d + let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust) - let expectation = XCTestExpectation(description: "failure expectation") let startedExpectation = XCTestExpectation(description: "start Expectation") + operation.startedHandler = { startedExpectation.fulfill() } + operation.errorHandler = { error in expectation.fulfill() switch error { @@ -96,20 +132,33 @@ class BlockBatchValidationTests: XCTestCase { XCTFail("Expected CompactBlockProcessorError.networkMismatch but found \(error)") } } + queue.addOperations([operation], waitUntilFinished: false) - wait(for: [startedExpectation,expectation], timeout: 1, enforceOrder: true) + wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true) XCTAssertNotNil(operation.error) XCTAssertTrue(operation.isCancelled) } - func testBranchNetworkTypeWrongFailure() throws { let network = ZcashNetworkBuilder.network(for: .testnet) - let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)) + let service = MockLightWalletService( + latestBlockHeight: 1210000, + service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) + ) let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000) let downloader = CompactBlockDownloader(service: service, storage: repository) - let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network) + let config = CompactBlockProcessor.Configuration( + cacheDb: try! __cacheDbURL(), + dataDb: try! __dataDbURL(), + downloadBatchSize: 100, + retries: 5, + maxBackoffInterval: 10, + rewindDistance: 100, + walletBirthday: 1210000, + saplingActivation: network.constants.saplingActivationHeight, + network: network + ) var info = LightdInfo() info.blockHeight = 130000 info.branch = "d34db33f" @@ -117,17 +166,20 @@ class BlockBatchValidationTests: XCTestCase { info.buildUser = "test user" info.consensusBranchID = "d34db4d" info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight) + service.mockLightDInfo = info let mockRust = MockRustBackend.self mockRust.consensusBranchID = 0xd34db4d + let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust) - let expectation = XCTestExpectation(description: "failure expectation") let startedExpectation = XCTestExpectation(description: "start Expectation") + operation.startedHandler = { startedExpectation.fulfill() } + operation.errorHandler = { error in expectation.fulfill() switch error { @@ -137,19 +189,34 @@ class BlockBatchValidationTests: XCTestCase { XCTFail("Expected CompactBlockProcessorError.generalError but found \(error)") } } + queue.addOperations([operation], waitUntilFinished: false) - wait(for: [startedExpectation,expectation], timeout: 1, enforceOrder: true) + wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true) XCTAssertNotNil(operation.error) XCTAssertTrue(operation.isCancelled) } func testSaplingActivationHeightMismatch() throws { let network = ZcashNetworkBuilder.network(for: .mainnet) - let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)) + let service = MockLightWalletService( + latestBlockHeight: 1210000, + service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) + ) let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000) let downloader = CompactBlockDownloader(service: service, storage: repository) - let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network) + let config = CompactBlockProcessor.Configuration( + cacheDb: try! __cacheDbURL(), + dataDb: try! __dataDbURL(), + downloadBatchSize: 100, + retries: 5, + maxBackoffInterval: 10, + rewindDistance: 100, + walletBirthday: 1210000, + saplingActivation: network.constants.saplingActivationHeight, + network: network + ) + var info = LightdInfo() info.blockHeight = 130000 info.branch = "d34db33f" @@ -157,29 +224,36 @@ class BlockBatchValidationTests: XCTestCase { info.buildUser = "test user" info.consensusBranchID = "d34db4d" info.saplingActivationHeight = UInt64(3434343) + service.mockLightDInfo = info let mockRust = MockRustBackend.self mockRust.consensusBranchID = 0xd34db4d + let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust) - let expectation = XCTestExpectation(description: "failure expectation") let startedExpectation = XCTestExpectation(description: "start Expectation") + operation.startedHandler = { startedExpectation.fulfill() } + operation.errorHandler = { error in expectation.fulfill() switch error { - case CompactBlockProcessorError.saplingActivationMismatch(expected: network.constants.saplingActivationHeight, found: BlockHeight(info.saplingActivationHeight)): + case CompactBlockProcessorError.saplingActivationMismatch( + expected: network.constants.saplingActivationHeight, + found: BlockHeight(info.saplingActivationHeight) + ): break default: XCTFail("Expected CompactBlockProcessorError.saplingActivationMismatch but found \(error)") } } + queue.addOperations([operation], waitUntilFinished: false) - wait(for: [startedExpectation,expectation], timeout: 1, enforceOrder: true) + wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true) XCTAssertNotNil(operation.error) XCTAssertTrue(operation.isCancelled) } @@ -188,12 +262,29 @@ class BlockBatchValidationTests: XCTestCase { let network = ZcashNetworkBuilder.network(for: .mainnet) let expectedLatestHeight = BlockHeight(1210000) - let service = MockLightWalletService(latestBlockHeight: expectedLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)) + let service = MockLightWalletService( + latestBlockHeight: expectedLatestHeight, + service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) + ) let expectedStoreLatestHeight = BlockHeight(1220000) - let expectedResult = FigureNextBatchOperation.NextState.wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight) + let expectedResult = FigureNextBatchOperation.NextState.wait( + latestHeight: expectedLatestHeight, + latestDownloadHeight: expectedLatestHeight + ) let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight) let downloader = CompactBlockDownloader(service: service, storage: repository) - let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network) + let config = CompactBlockProcessor.Configuration( + cacheDb: try! __cacheDbURL(), + dataDb: try! __dataDbURL(), + downloadBatchSize: 100, + retries: 5, + maxBackoffInterval: 10, + rewindDistance: 100, + walletBirthday: 1210000, + saplingActivation: network.constants.saplingActivationHeight, + network: network + ) + var info = LightdInfo() info.blockHeight = UInt64(expectedLatestHeight) info.branch = "d34db33f" @@ -201,56 +292,84 @@ class BlockBatchValidationTests: XCTestCase { info.buildUser = "test user" info.consensusBranchID = "d34db4d" info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight) + service.mockLightDInfo = info let mockRust = MockRustBackend.self mockRust.consensusBranchID = 0xd34db4d + let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust) - let completedExpectation = XCTestExpectation(description: "completed expectation") let startedExpectation = XCTestExpectation(description: "start Expectation") + operation.startedHandler = { startedExpectation.fulfill() } + operation.errorHandler = { error in XCTFail("this shouldn't happen: \(error)") } - operation.completionHandler = { (finished, cancelled) in + + operation.completionHandler = { finished, cancelled in completedExpectation.fulfill() XCTAssertTrue(finished) XCTAssertFalse(cancelled) - } + queue.addOperations([operation], waitUntilFinished: false) - wait(for: [startedExpectation,completedExpectation], timeout: 1, enforceOrder: true) + wait(for: [startedExpectation, completedExpectation], timeout: 1, enforceOrder: true) XCTAssertNil(operation.error) XCTAssertFalse(operation.isCancelled) + guard let result = operation.result else { XCTFail("result should not be nil") return } - XCTAssertTrue({ - switch result { - case .wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight): - return true - default: - return false - } - }(), "Expected \(expectedResult) got: \(result)") + XCTAssertTrue( + { + switch result { + case .wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight): + return true + default: + return false + } + }(), + "Expected \(expectedResult) got: \(result)" + ) } func testResultProcessNew() throws { let network = ZcashNetworkBuilder.network(for: .mainnet) let expectedLatestHeight = BlockHeight(1230000) - let service = MockLightWalletService(latestBlockHeight: expectedLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)) + let service = MockLightWalletService( + latestBlockHeight: expectedLatestHeight, + service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) + ) let expectedStoreLatestHeight = BlockHeight(1220000) let walletBirthday = BlockHeight(1210000) - let expectedResult = FigureNextBatchOperation.NextState.processNewBlocks(range: CompactBlockProcessor.nextBatchBlockRange(latestHeight: expectedLatestHeight, latestDownloadedHeight: expectedStoreLatestHeight, walletBirthday: walletBirthday)) + let expectedResult = FigureNextBatchOperation.NextState.processNewBlocks( + range: CompactBlockProcessor.nextBatchBlockRange( + latestHeight: expectedLatestHeight, + latestDownloadedHeight: expectedStoreLatestHeight, + walletBirthday: walletBirthday + ) + ) let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight) let downloader = CompactBlockDownloader(service: service, storage: repository) - let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: walletBirthday, saplingActivation: network.constants.saplingActivationHeight, network: network) + let config = CompactBlockProcessor.Configuration( + cacheDb: try! __cacheDbURL(), + dataDb: try! __dataDbURL(), + downloadBatchSize: 100, + retries: 5, + maxBackoffInterval: 10, + rewindDistance: 100, + walletBirthday: walletBirthday, + saplingActivation: network.constants.saplingActivationHeight, + network: network + ) + var info = LightdInfo() info.blockHeight = UInt64(expectedLatestHeight) info.branch = "d34db33f" @@ -258,56 +377,78 @@ class BlockBatchValidationTests: XCTestCase { info.buildUser = "test user" info.consensusBranchID = "d34db4d" info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight) + service.mockLightDInfo = info let mockRust = MockRustBackend.self mockRust.consensusBranchID = 0xd34db4d + let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust) - let completedExpectation = XCTestExpectation(description: "completed expectation") let startedExpectation = XCTestExpectation(description: "start Expectation") + operation.startedHandler = { startedExpectation.fulfill() } - operation.errorHandler = { error in + + operation.errorHandler = { _ in XCTFail("this shouldn't happen") } - operation.completionHandler = { (finished, cancelled) in + + operation.completionHandler = { finished, cancelled in completedExpectation.fulfill() XCTAssertTrue(finished) XCTAssertFalse(cancelled) - } + queue.addOperations([operation], waitUntilFinished: false) - wait(for: [startedExpectation,completedExpectation], timeout: 1, enforceOrder: true) + wait(for: [startedExpectation, completedExpectation], timeout: 1, enforceOrder: true) XCTAssertNil(operation.error) XCTAssertFalse(operation.isCancelled) + guard let result = operation.result else { XCTFail("result should not be nil") return } - XCTAssertTrue({ - switch result { - case .processNewBlocks(range: CompactBlockRange(uncheckedBounds: (expectedStoreLatestHeight + 1, expectedLatestHeight))): - return true - default: - return false - } - }(), "Expected \(expectedResult) got: \(result)") + XCTAssertTrue( + { + switch result { + case .processNewBlocks(range: CompactBlockRange(uncheckedBounds: (expectedStoreLatestHeight + 1, expectedLatestHeight))): + return true + default: + return false + } + }(), + "Expected \(expectedResult) got: \(result)" + ) } func testResultProcessorFinished() throws { let network = ZcashNetworkBuilder.network(for: .mainnet) let expectedLatestHeight = BlockHeight(1230000) - let service = MockLightWalletService(latestBlockHeight: expectedLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)) + let service = MockLightWalletService( + latestBlockHeight: expectedLatestHeight, + service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) + ) let expectedStoreLatestHeight = BlockHeight(1230000) let walletBirthday = BlockHeight(1210000) let expectedResult = FigureNextBatchOperation.NextState.finishProcessing(height: expectedStoreLatestHeight) let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight) let downloader = CompactBlockDownloader(service: service, storage: repository) - let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: walletBirthday, saplingActivation: network.constants.saplingActivationHeight, network: network) + let config = CompactBlockProcessor.Configuration( + cacheDb: try! __cacheDbURL(), + dataDb: try! __dataDbURL(), + downloadBatchSize: 100, + retries: 5, + maxBackoffInterval: 10, + rewindDistance: 100, + walletBirthday: walletBirthday, + saplingActivation: network.constants.saplingActivationHeight, + network: network + ) + var info = LightdInfo() info.blockHeight = UInt64(expectedLatestHeight) info.branch = "d34db33f" @@ -315,43 +456,51 @@ class BlockBatchValidationTests: XCTestCase { info.buildUser = "test user" info.consensusBranchID = "d34db4d" info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight) + service.mockLightDInfo = info let mockRust = MockRustBackend.self mockRust.consensusBranchID = 0xd34db4d + let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust) - let completedExpectation = XCTestExpectation(description: "completed expectation") let startedExpectation = XCTestExpectation(description: "start Expectation") + operation.startedHandler = { startedExpectation.fulfill() } - operation.errorHandler = { error in + + operation.errorHandler = { _ in XCTFail("this shouldn't happen") } - operation.completionHandler = { (finished, cancelled) in + + operation.completionHandler = { finished, cancelled in completedExpectation.fulfill() XCTAssertTrue(finished) XCTAssertFalse(cancelled) - } + queue.addOperations([operation], waitUntilFinished: false) - wait(for: [startedExpectation,completedExpectation], timeout: 1, enforceOrder: true) + wait(for: [startedExpectation, completedExpectation], timeout: 1, enforceOrder: true) XCTAssertNil(operation.error) XCTAssertFalse(operation.isCancelled) + guard let result = operation.result else { XCTFail("result should not be nil") return } - XCTAssertTrue({ - switch result { - case .finishProcessing(height: expectedLatestHeight): - return true - default: - return false - } - }(), "Expected \(expectedResult) got: \(result)") + XCTAssertTrue( + { + switch result { + case .finishProcessing(height: expectedLatestHeight): + return true + default: + return false + } + }(), + "Expected \(expectedResult) got: \(result)" + ) } } diff --git a/ZcashLightClientKitTests/BlockDownloaderTests.swift b/ZcashLightClientKitTests/BlockDownloaderTests.swift index ec6f8611..e8c4d812 100644 --- a/ZcashLightClientKitTests/BlockDownloaderTests.swift +++ b/ZcashLightClientKitTests/BlockDownloaderTests.swift @@ -8,17 +8,21 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable implicitly_unwrapped_optional force_cast force_try class BlockDownloaderTests: XCTestCase { - + let branchID = "2bb40e60" + let chainName = "main" + + var darksideWalletService: DarksideWalletService! var downloader: CompactBlockDownloading! var service: LightWalletService! var storage: CompactBlockRepository! var cacheDB = try! __cacheDbURL() var network = DarksideWalletDNetwork() - var darksideWalletService: DarksideWalletService! - let branchID = "2bb40e60" - let chainName = "main" + override func setUpWithError() throws { + try super.setUpWithError() service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) storage = try! TestDbBuilder.diskCompactBlockStorage(at: cacheDB) downloader = CompactBlockDownloader(service: service, storage: storage) @@ -29,7 +33,7 @@ class BlockDownloaderTests: XCTestCase { } override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. + try super.tearDown() service = nil storage = nil downloader = nil @@ -37,24 +41,23 @@ class BlockDownloaderTests: XCTestCase { } func testSmallDownloadAsync() { - let expect = XCTestExpectation(description: self.description) expect.expectedFulfillmentCount = 3 let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99 - let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange)) - downloader.downloadBlockRange(range) { (error) in + let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange)) + downloader.downloadBlockRange(range) { error in expect.fulfill() XCTAssertNil(error) // check what was 'stored' - self.storage.latestHeight { (result) in + self.storage.latestHeight { result in expect.fulfill() XCTAssertTrue(self.validate(result: result, against: upperRange)) - self.downloader.lastDownloadedBlockHeight { (resultHeight) in + self.downloader.lastDownloadedBlockHeight { resultHeight in expect.fulfill() XCTAssertTrue(self.validate(result: resultHeight, against: upperRange)) } @@ -65,11 +68,10 @@ class BlockDownloaderTests: XCTestCase { } func testSmallDownload() { - let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99 - let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange)) + let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange)) var latest: BlockHeight = 0 do { @@ -84,26 +86,31 @@ class BlockDownloaderTests: XCTestCase { var currentLatest: BlockHeight = 0 do { currentLatest = try downloader.lastDownloadedBlockHeight() - } catch { XCTFail("latest block failed") return } - XCTAssertEqual(currentLatest,upperRange ) - + + XCTAssertEqual(currentLatest, upperRange ) } func testFailure() { - let awfulDownloader = CompactBlockDownloader(service: AwfulLightWalletService(latestBlockHeight: self.network.constants.saplingActivationHeight + 1000, service: darksideWalletService), storage: ZcashConsoleFakeStorage()) + let awfulDownloader = CompactBlockDownloader( + service: AwfulLightWalletService( + latestBlockHeight: self.network.constants.saplingActivationHeight + 1000, + service: darksideWalletService + ), + storage: ZcashConsoleFakeStorage() + ) let expect = XCTestExpectation(description: self.description) expect.expectedFulfillmentCount = 1 let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99 - let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange)) + let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange)) - awfulDownloader.downloadBlockRange(range) { (error) in + awfulDownloader.downloadBlockRange(range) { error in expect.fulfill() XCTAssertNotNil(error) } @@ -114,14 +121,12 @@ class BlockDownloaderTests: XCTestCase { /// Helper functions extension BlockDownloaderTests { - func validate(result: Result ,against height: BlockHeight) -> Bool { - + func validate(result: Result, against height: BlockHeight) -> Bool { switch result { case .success(let resultHeight): return resultHeight == height default: return false } - } } diff --git a/ZcashLightClientKitTests/BlockScanOperationTests.swift b/ZcashLightClientKitTests/BlockScanOperationTests.swift index 9854d18b..266d0a2a 100644 --- a/ZcashLightClientKitTests/BlockScanOperationTests.swift +++ b/ZcashLightClientKitTests/BlockScanOperationTests.swift @@ -9,23 +9,31 @@ import XCTest import SQLite @testable import ZcashLightClientKit + +// swiftlint:disable implicitly_unwrapped_optional force_try force_unwrapping print_function_usage class BlockScanOperationTests: XCTestCase { - + let rustWelding = ZcashRustBackend.self + var operationQueue = OperationQueue() var cacheDbURL: URL! var dataDbURL: URL! - let rustWelding = ZcashRustBackend.self - - var uvk = UVFakeKey(extfvk: "zxviewtestsapling1qw88ayg8qqqqpqyhg7jnh9mlldejfqwu46pm40ruwstd8znq3v3l4hjf33qcu2a5e36katshcfhcxhzgyfugj2lkhmt40j45cv38rv3frnghzkxcx73k7m7afw9j7ujk7nm4dx5mv02r26umxqgar7v3x390w2h3crqqgjsjly7jy4vtwzrmustm5yudpgcydw7x78awca8wqjvkqj8p8e3ykt7lrgd7xf92fsfqjs5vegfsja4ekzpfh5vtccgvs5747xqm6qflmtqpr8s9u", - extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61") - - var walletBirthDay = WalletBirthday.birthday(with: 1386000, network: ZcashNetworkBuilder.network(for: .testnet)) + var uvk = UVFakeKey( + extfvk: "zxviewtestsapling1qw88ayg8qqqqpqyhg7jnh9mlldejfqwu46pm40ruwstd8znq3v3l4hjf33qcu2a5e36katshcfhcxhzgyfugj2lkhmt40j45cv38rv3frnghzkxcx73k7m7afw9j7ujk7nm4dx5mv02r26umxqgar7v3x390w2h3crqqgjsjly7jy4vtwzrmustm5yudpgcydw7x78awca8wqjvkqj8p8e3ykt7lrgd7xf92fsfqjs5vegfsja4ekzpfh5vtccgvs5747xqm6qflmtqpr8s9u", // swiftlint:disable:this line_length + extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61" + ) + + var walletBirthDay = WalletBirthday.birthday( + with: 1386000, + network: ZcashNetworkBuilder.network(for: .testnet) + ) var network = ZcashNetworkBuilder.network(for: .testnet) var blockRepository: BlockRepository! + override func setUp() { // Put setup code here. This method is called before the invocation of each test method in the class. + super.setUp() self.cacheDbURL = try! __cacheDbURL() self.dataDbURL = try! __dataDbURL() @@ -37,8 +45,10 @@ class BlockScanOperationTests: XCTestCase { try? FileManager.default.removeItem(at: cacheDbURL) try? FileManager.default.removeItem(at: dataDbURL) } + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() operationQueue.cancelAllOperations() try? FileManager.default.removeItem(at: cacheDbURL) @@ -47,29 +57,47 @@ class BlockScanOperationTests: XCTestCase { func testSingleDownloadAndScanOperation() { logger = SampleLogger(logLevel: .debug) + XCTAssertNoThrow(try rustWelding.initDataDb(dbData: dataDbURL, networkType: network.networkType)) - let downloadStartedExpect = XCTestExpectation(description: self.description + "download started") - let downloadExpect = XCTestExpectation(description: self.description + "download") - let scanStartedExpect = XCTestExpectation(description: self.description + "scan started") - let scanExpect = XCTestExpectation(description: self.description + "scan") - let latestScannedBlockExpect = XCTestExpectation(description: self.description + "latestScannedHeight") - let service = LightWalletGRPCService(endpoint: LightWalletEndpoint(address: "lightwalletd.testnet.electriccoin.co", port: 9067)) + + let downloadStartedExpect = XCTestExpectation(description: "\(self.description) download started") + let downloadExpect = XCTestExpectation(description: "\(self.description) download") + let scanStartedExpect = XCTestExpectation(description: "\(self.description) scan started") + let scanExpect = XCTestExpectation(description: "\(self.description) scan") + let latestScannedBlockExpect = XCTestExpectation(description: "\(self.description) latestScannedHeight") + let service = LightWalletGRPCService( + endpoint: LightWalletEndpoint( + address: "lightwalletd.testnet.electriccoin.co", + port: 9067 + ) + ) let blockCount = 100 - let range = network.constants.saplingActivationHeight ... network.constants.saplingActivationHeight + blockCount - let downloadOperation = CompactBlockDownloadOperation(downloader: CompactBlockDownloader.sqlDownloader(service: service, at: cacheDbURL)!, range: range) - let scanOperation = CompactBlockScanningOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, networkType: network.networkType) + let range = network.constants.saplingActivationHeight ... network.constants.saplingActivationHeight + blockCount + let downloadOperation = CompactBlockDownloadOperation( + downloader: CompactBlockDownloader.sqlDownloader( + service: service, + at: cacheDbURL + )!, + range: range + ) + let scanOperation = CompactBlockScanningOperation( + rustWelding: rustWelding, + cacheDb: cacheDbURL, + dataDb: dataDbURL, + networkType: network.networkType + ) downloadOperation.startedHandler = { downloadStartedExpect.fulfill() } - downloadOperation.completionHandler = { (finished, cancelled) in + downloadOperation.completionHandler = { finished, cancelled in downloadExpect.fulfill() XCTAssertTrue(finished) XCTAssertFalse(cancelled) } - downloadOperation.errorHandler = { (error) in + downloadOperation.errorHandler = { error in XCTFail("Download Operation failed with Error: \(error)") } @@ -77,13 +105,13 @@ class BlockScanOperationTests: XCTestCase { scanStartedExpect.fulfill() } - scanOperation.completionHandler = { (finished, cancelled) in + scanOperation.completionHandler = { finished, cancelled in scanExpect.fulfill() XCTAssertFalse(cancelled) XCTAssertTrue(finished) } - scanOperation.errorHandler = { (error) in + scanOperation.errorHandler = { error in XCTFail("Scan Operation failed with Error: \(error)") } @@ -101,10 +129,16 @@ class BlockScanOperationTests: XCTestCase { latestScannedBlockOperation.addDependency(scanOperation) - operationQueue.addOperations([downloadOperation,scanOperation,latestScannedBlockOperation], waitUntilFinished: false) - - - wait(for: [downloadStartedExpect, downloadExpect, scanStartedExpect, scanExpect,latestScannedBlockExpect], timeout: 10, enforceOrder: true) + operationQueue.addOperations( + [downloadOperation, scanOperation, latestScannedBlockOperation], + waitUntilFinished: false + ) + + wait( + for: [downloadStartedExpect, downloadExpect, scanStartedExpect, scanExpect, latestScannedBlockExpect], + timeout: 10, + enforceOrder: true + ) } @objc func observeBenchmark(_ notification: Notification) { guard let report = SDKMetrics.blockReportFromNotification(notification) else { @@ -112,20 +146,32 @@ class BlockScanOperationTests: XCTestCase { } print("observed benchmark: \(report)") - } func testScanValidateDownload() throws { logger = SampleLogger(logLevel: .debug) - NotificationCenter.default.addObserver(self, selector: #selector(observeBenchmark(_:)), name: SDKMetrics.notificationName, object: nil) + NotificationCenter.default.addObserver( + self, + selector: #selector(observeBenchmark(_:)), + name: SDKMetrics.notificationName, + object: nil + ) try self.rustWelding.initDataDb(dbData: dataDbURL, networkType: network.networkType) + guard try self.rustWelding.initAccountsTable(dbData: self.dataDbURL, uvks: [uvk], networkType: network.networkType) else { XCTFail("failed to init account table") return } - try self.rustWelding.initBlocksTable(dbData: dataDbURL, height: Int32(walletBirthDay.height), hash: walletBirthDay.hash, time: walletBirthDay.time, saplingTree: walletBirthDay.tree, networkType: network.networkType) + try self.rustWelding.initBlocksTable( + dbData: dataDbURL, + height: Int32(walletBirthDay.height), + hash: walletBirthDay.hash, + time: walletBirthDay.time, + saplingTree: walletBirthDay.tree, + networkType: network.networkType + ) let service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet) let storage = CompactBlockStorage(url: cacheDbURL, readonly: false) @@ -135,13 +181,15 @@ class BlockScanOperationTests: XCTestCase { let validateExpectation = XCTestExpectation(description: "validate expectation") let scanExpectation = XCTestExpectation(description: "scan expectation") - let downloadOperation = CompactBlockStreamDownloadOperation(service: service, - storage: storage, - startHeight: walletBirthDay.height, - targetHeight: walletBirthDay.height + 10000, - progressDelegate: self) + let downloadOperation = CompactBlockStreamDownloadOperation( + service: service, + storage: storage, + startHeight: walletBirthDay.height, + targetHeight: walletBirthDay.height + 10000, + progressDelegate: self + ) - downloadOperation.completionHandler = { (finished, cancelled) in + downloadOperation.completionHandler = { finished, cancelled in XCTAssert(finished) XCTAssertFalse(cancelled) downloadExpectation.fulfill() @@ -160,40 +208,55 @@ class BlockScanOperationTests: XCTestCase { } } - - let validationOperation = CompactBlockValidationOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, networkType: network.networkType) + let validationOperation = CompactBlockValidationOperation( + rustWelding: rustWelding, + cacheDb: cacheDbURL, + dataDb: dataDbURL, + networkType: network.networkType + ) + validationOperation.errorHandler = { error in self.operationQueue.cancelAllOperations() XCTFail("failed with error \(error)") - } - validationOperation.completionHandler = { (finished,cancelled) in + + validationOperation.completionHandler = { finished, cancelled in XCTAssert(finished) XCTAssertFalse(cancelled) validateExpectation.fulfill() } let transactionRepository = TransactionRepositoryBuilder.build(dataDbURL: dataDbURL) - let scanningOperation = CompactBlockBatchScanningOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, transactionRepository: transactionRepository, range: CompactBlockRange(uncheckedBounds: (walletBirthDay.height, walletBirthDay.height + 10000)), batchSize: 1000, networkType: network.networkType, progressDelegate: self) + let scanningOperation = CompactBlockBatchScanningOperation( + rustWelding: rustWelding, + cacheDb: cacheDbURL, + dataDb: dataDbURL, + transactionRepository: transactionRepository, + range: CompactBlockRange( + uncheckedBounds: (walletBirthDay.height, walletBirthDay.height + 10000) + ), + batchSize: 1000, + networkType: network.networkType, + progressDelegate: self + ) - scanningOperation.completionHandler = { (finished,cancelled) in + scanningOperation.completionHandler = { finished, cancelled in XCTAssert(finished) XCTAssertFalse(cancelled) scanExpectation.fulfill() } + operationQueue.addOperations([downloadOperation, validationOperation, scanningOperation], waitUntilFinished: false) - wait(for: [downloadExpectation,validateExpectation,scanExpectation], timeout: 300, enforceOrder: true) + wait(for: [downloadExpectation, validateExpectation, scanExpectation], timeout: 300, enforceOrder: true) } } extension BlockScanOperationTests: CompactBlockProgressDelegate { func progressUpdated(_ progress: CompactBlockProgress) { -// print("progressHeight: \(progress.progressHeight) startHeight: \(progress.startHeight), targetHeight: \(progress.targetHeight)") } } - struct UVFakeKey: UnifiedViewingKey { var extfvk: ExtendedFullViewingKey var extpub: ExtendedPublicKey diff --git a/ZcashLightClientKitTests/BlockStreamingTest.swift b/ZcashLightClientKitTests/BlockStreamingTest.swift index 80949a27..adc8f3f4 100644 --- a/ZcashLightClientKitTests/BlockStreamingTest.swift +++ b/ZcashLightClientKitTests/BlockStreamingTest.swift @@ -7,36 +7,40 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable print_function_usage class BlockStreamingTest: XCTestCase { var queue: OperationQueue = { - let q = OperationQueue() - q.maxConcurrentOperationCount = 1 - return q + let queue = OperationQueue() + queue.maxConcurrentOperationCount = 1 + return queue }() + override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. + try super.setUpWithError() logger = SampleLogger(logLevel: .debug) } override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. + try super.tearDownWithError() try? FileManager.default.removeItem(at: __dataDbURL()) } func testStreamOperation() throws { let expectation = XCTestExpectation(description: "blockstream expectation") - let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host, - port: 9067, - secure: true, - singleCallTimeout: 1000, - streamingCallTimeout: 100000) - + let service = LightWalletGRPCService( + host: LightWalletEndpointBuilder.eccTestnet.host, + port: 9067, + secure: true, + singleCallTimeout: 1000, + streamingCallTimeout: 100000 + ) let latestHeight = try service.latestBlockHeight() let startHeight = latestHeight - 100_000 - var blocks = [ZcashCompactBlock]() + var blocks: [ZcashCompactBlock] = [] service.blockStream(startHeight: startHeight, endHeight: latestHeight) { result in expectation.fulfill() switch result { @@ -49,29 +53,34 @@ class BlockStreamingTest: XCTestCase { print("received block \(compactBlock.height)") blocks.append(compactBlock) } progress: { progressReport in - print("progressHeight: \(progressReport.progressHeight) startHeight: \(progressReport.startHeight), targetHeight: \(progressReport.targetHeight)") + print("progressHeight: \(progressReport.progressHeight)") + print("startHeight: \(progressReport.startHeight)") + print("targetHeight: \(progressReport.targetHeight)") } wait(for: [expectation], timeout: 1000) } - func testStreamOperationCancellation() throws { let expectation = XCTestExpectation(description: "blockstream expectation") - let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host, - port: 9067, - secure: true, - singleCallTimeout: 10000, - streamingCallTimeout: 10000) + let service = LightWalletGRPCService( + host: LightWalletEndpointBuilder.eccTestnet.host, + port: 9067, + secure: true, + singleCallTimeout: 10000, + streamingCallTimeout: 10000 + ) let storage = try TestDbBuilder.inMemoryCompactBlockStorage() let startHeight = try service.latestBlockHeight() - 100_000 - let operation = CompactBlockStreamDownloadOperation(service: service, - storage: storage, - startHeight: startHeight, - progressDelegate: self) + let operation = CompactBlockStreamDownloadOperation( + service: service, + storage: storage, + startHeight: startHeight, + progressDelegate: self + ) - operation.completionHandler = { (finished, cancelled) in + operation.completionHandler = { _, cancelled in XCTAssert(cancelled) expectation.fulfill() } @@ -91,20 +100,24 @@ class BlockStreamingTest: XCTestCase { func testStreamOperationTimeout() throws { let expectation = XCTestExpectation(description: "blockstream expectation") let errorExpectation = XCTestExpectation(description: "blockstream error expectation") - let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host, - port: 9067, - secure: true, - singleCallTimeout: 1000, - streamingCallTimeout: 3000) + let service = LightWalletGRPCService( + host: LightWalletEndpointBuilder.eccTestnet.host, + port: 9067, + secure: true, + singleCallTimeout: 1000, + streamingCallTimeout: 3000 + ) let storage = try TestDbBuilder.inMemoryCompactBlockStorage() let startHeight = try service.latestBlockHeight() - 100_000 - let operation = CompactBlockStreamDownloadOperation(service: service, - storage: storage, - startHeight: startHeight, - progressDelegate: self) + let operation = CompactBlockStreamDownloadOperation( + service: service, + storage: storage, + startHeight: startHeight, + progressDelegate: self + ) - operation.completionHandler = { (finished, cancelled) in + operation.completionHandler = { finished, _ in XCTAssert(finished) expectation.fulfill() @@ -136,20 +149,25 @@ class BlockStreamingTest: XCTestCase { func testBatchOperation() throws { let expectation = XCTestExpectation(description: "blockbatch expectation") - let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host, - port: 9067, - secure: true, - singleCallTimeout: 300000, - streamingCallTimeout: 10000) + let service = LightWalletGRPCService( + host: LightWalletEndpointBuilder.eccTestnet.host, + port: 9067, + secure: true, + singleCallTimeout: 300000, + streamingCallTimeout: 10000 + ) let storage = try TestDbBuilder.diskCompactBlockStorage(at: __dataDbURL() ) let targetHeight = try service.latestBlockHeight() - let startHeight = targetHeight - 10_000 - let operation = CompactBlockBatchDownloadOperation(service: service, - storage: storage, - startHeight: startHeight, targetHeight: targetHeight, - progressDelegate: self) + let startHeight = targetHeight - 10_000 + let operation = CompactBlockBatchDownloadOperation( + service: service, + storage: storage, + startHeight: startHeight, + targetHeight: targetHeight, + progressDelegate: self + ) - operation.completionHandler = { (finished, cancelled) in + operation.completionHandler = { _, cancelled in if cancelled { XCTFail("operation cancelled") } @@ -169,20 +187,25 @@ class BlockStreamingTest: XCTestCase { func testBatchOperationCancellation() throws { let expectation = XCTestExpectation(description: "blockbatch expectation") - let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host, - port: 9067, - secure: true, - singleCallTimeout: 300000, - streamingCallTimeout: 10000) + let service = LightWalletGRPCService( + host: LightWalletEndpointBuilder.eccTestnet.host, + port: 9067, + secure: true, + singleCallTimeout: 300000, + streamingCallTimeout: 10000 + ) let storage = try TestDbBuilder.diskCompactBlockStorage(at: __dataDbURL() ) let targetHeight = try service.latestBlockHeight() - let startHeight = targetHeight - 100_000 - let operation = CompactBlockBatchDownloadOperation(service: service, - storage: storage, - startHeight: startHeight, targetHeight: targetHeight, - progressDelegate: self) + let startHeight = targetHeight - 100_000 + let operation = CompactBlockBatchDownloadOperation( + service: service, + storage: storage, + startHeight: startHeight, + targetHeight: targetHeight, + progressDelegate: self + ) - operation.completionHandler = { (finished, cancelled) in + operation.completionHandler = { _, cancelled in XCTAssert(cancelled) expectation.fulfill() } @@ -201,8 +224,9 @@ class BlockStreamingTest: XCTestCase { } extension BlockStreamingTest: CompactBlockProgressDelegate { - func progressUpdated(_ progress: CompactBlockProgress) { - print("progressHeight: \(String(describing: progress.progressHeight)) startHeight: \(progress.progress), targetHeight: \(String(describing: progress.targetHeight))") + print("progressHeight: \(String(describing: progress.progressHeight))") + print("startHeight: \(progress.progress)") + print("targetHeight: \(String(describing: progress.targetHeight))") } } diff --git a/ZcashLightClientKitTests/CompactBlockProcessorTests.swift b/ZcashLightClientKitTests/CompactBlockProcessorTests.swift index 6dec0127..d6c425aa 100644 --- a/ZcashLightClientKitTests/CompactBlockProcessorTests.swift +++ b/ZcashLightClientKitTests/CompactBlockProcessorTests.swift @@ -8,9 +8,13 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable force_try implicitly_unwrapped_optional class CompactBlockProcessorTests: XCTestCase { - - let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight) + let processorConfig = CompactBlockProcessor.Configuration.standard( + for: ZcashNetworkBuilder.network(for: .testnet), + walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + ) var processor: CompactBlockProcessor! var downloadStartedExpect: XCTestExpectation! var updatedNotificationExpectation: XCTestExpectation! @@ -22,10 +26,13 @@ class CompactBlockProcessorTests: XCTestCase { let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000 override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. + try super.setUpWithError() logger = SampleLogger(logLevel: .debug) - let service = MockLightWalletService(latestBlockHeight: mockLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)) + let service = MockLightWalletService( + latestBlockHeight: mockLatestHeight, + service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet) + ) let branchID = try ZcashRustBackend.consensusBranchIdFor(height: Int32(mockLatestHeight), networkType: network.networkType) service.mockLightDInfo = LightdInfo.with({ info in info.blockHeight = UInt64(mockLatestHeight) @@ -41,23 +48,33 @@ class CompactBlockProcessorTests: XCTestCase { let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString)) try! storage.createTable() - - processor = CompactBlockProcessor(service: service, - storage: storage, - backend: ZcashRustBackend.self, - config: processorConfig) + processor = CompactBlockProcessor( + service: service, + storage: storage, + backend: ZcashRustBackend.self, + config: processorConfig + ) try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: .testnet) - downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect") - stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation") - updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation") - startedValidatingNotificationExpectation = XCTestExpectation(description: self.description + " startedValidatingNotificationExpectation") - startedScanningNotificationExpectation = XCTestExpectation(description: self.description + " startedScanningNotificationExpectation") - idleNotificationExpectation = XCTestExpectation(description: self.description + " idleNotificationExpectation") - NotificationCenter.default.addObserver(self, selector: #selector(processorFailed(_:)), name: Notification.Name.blockProcessorFailed, object: processor) + downloadStartedExpect = XCTestExpectation(description: "\(self.description) downloadStartedExpect") + stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation") + updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation") + startedValidatingNotificationExpectation = XCTestExpectation( + description: "\(self.description) startedValidatingNotificationExpectation" + ) + startedScanningNotificationExpectation = XCTestExpectation( + description: "\(self.description) startedScanningNotificationExpectation" + ) + idleNotificationExpectation = XCTestExpectation(description: "\(self.description) idleNotificationExpectation") + NotificationCenter.default.addObserver( + self, + selector: #selector(processorFailed(_:)), + name: Notification.Name.blockProcessorFailed, + object: processor + ) } override func tearDown() { - + super.tearDown() try! FileManager.default.removeItem(at: processorConfig.cacheDb) try? FileManager.default.removeItem(at: processorConfig.dataDb) downloadStartedExpect.unsubscribeFromNotifications() @@ -78,7 +95,7 @@ class CompactBlockProcessorTests: XCTestCase { } } - fileprivate func startProcessing() { + private func startProcessing() { XCTAssertNotNil(processor) // Subscribe to notifications @@ -93,41 +110,51 @@ class CompactBlockProcessorTests: XCTestCase { } func testStartNotifiesSuscriptors() { - startProcessing() - wait(for: [ - downloadStartedExpect, - startedValidatingNotificationExpectation, - startedScanningNotificationExpectation, - idleNotificationExpectation, - ], timeout: 30,enforceOrder: true) + wait( + for: [ + downloadStartedExpect, + startedValidatingNotificationExpectation, + startedScanningNotificationExpectation, + idleNotificationExpectation + ], + timeout: 30, + enforceOrder: true + ) } func testProgressNotifications() { - - let expectedUpdates = expectedBatches(currentHeight: processorConfig.walletBirthday, targetHeight: mockLatestHeight, batchSize: processorConfig.downloadBatchSize) + let expectedUpdates = expectedBatches( + currentHeight: processorConfig.walletBirthday, + targetHeight: mockLatestHeight, + batchSize: processorConfig.downloadBatchSize + ) updatedNotificationExpectation.expectedFulfillmentCount = expectedUpdates startProcessing() wait(for: [updatedNotificationExpectation], timeout: 300) - - } private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int { - (abs(currentHeight-targetHeight)/batchSize) + (abs(currentHeight - targetHeight) / batchSize) } func testNextBatchBlockRange() { - // test first range var latestDownloadedHeight = processorConfig.walletBirthday // this can be either this or Wallet Birthday. var latestBlockchainHeight = BlockHeight(network.constants.saplingActivationHeight + 1000) var expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight, upper:latestBlockchainHeight)) - XCTAssertEqual(expectedBatchRange, CompactBlockProcessor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight, walletBirthday: processorConfig.walletBirthday)) + XCTAssertEqual( + expectedBatchRange, + CompactBlockProcessor.nextBatchBlockRange( + latestHeight: latestBlockchainHeight, + latestDownloadedHeight: latestDownloadedHeight, + walletBirthday: processorConfig.walletBirthday + ) + ) // Test mid-range latestDownloadedHeight = BlockHeight(network.constants.saplingActivationHeight + ZcashSDK.DefaultBatchSize) @@ -135,7 +162,14 @@ class CompactBlockProcessorTests: XCTestCase { expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight)) - XCTAssertEqual(expectedBatchRange, CompactBlockProcessor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight, walletBirthday: processorConfig.walletBirthday)) + XCTAssertEqual( + expectedBatchRange, + CompactBlockProcessor.nextBatchBlockRange( + latestHeight: latestBlockchainHeight, + latestDownloadedHeight: latestDownloadedHeight, + walletBirthday: processorConfig.walletBirthday + ) + ) // Test last batch range @@ -144,7 +178,14 @@ class CompactBlockProcessorTests: XCTestCase { expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight)) - XCTAssertEqual(expectedBatchRange, CompactBlockProcessor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight, walletBirthday: processorConfig.walletBirthday)) + XCTAssertEqual( + expectedBatchRange, + CompactBlockProcessor.nextBatchBlockRange( + latestHeight: latestBlockchainHeight, + latestDownloadedHeight: latestDownloadedHeight, + walletBirthday: processorConfig.walletBirthday + ) + ) } func testDetermineLowerBoundPastBirthday() { @@ -156,7 +197,6 @@ class CompactBlockProcessorTests: XCTestCase { let expected = 781_886 XCTAssertEqual(result, expected) - } func testDetermineLowerBound() { @@ -168,6 +208,5 @@ class CompactBlockProcessorTests: XCTestCase { let expected = 781_896 XCTAssertEqual(result, expected) - } } diff --git a/ZcashLightClientKitTests/CompactBlockReorgTests.swift b/ZcashLightClientKitTests/CompactBlockReorgTests.swift index b541e81c..51b3bb77 100644 --- a/ZcashLightClientKitTests/CompactBlockReorgTests.swift +++ b/ZcashLightClientKitTests/CompactBlockReorgTests.swift @@ -6,12 +6,15 @@ // // Copyright © 2019 Electric Coin Company. All rights reserved. - import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable implicitly_unwrapped_optional force_try class CompactBlockReorgTests: XCTestCase { - - let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight) + let processorConfig = CompactBlockProcessor.Configuration.standard( + for: ZcashNetworkBuilder.network(for: .testnet), + walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + ) var processor: CompactBlockProcessor! var downloadStartedExpect: XCTestExpectation! var updatedNotificationExpectation: XCTestExpectation! @@ -24,13 +27,15 @@ class CompactBlockReorgTests: XCTestCase { let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000 override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - + try super.setUpWithError() logger = SampleLogger(logLevel: .debug) - let service = MockLightWalletService(latestBlockHeight: mockLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)) + let service = MockLightWalletService( + latestBlockHeight: mockLatestHeight, + service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet) + ) let branchID = try ZcashRustBackend.consensusBranchIdFor(height: Int32(mockLatestHeight), networkType: network.networkType) - service.mockLightDInfo = LightdInfo.with({ info in + service.mockLightDInfo = LightdInfo.with { info in info.blockHeight = UInt64(mockLatestHeight) info.branch = "asdf" info.buildDate = "today" @@ -39,7 +44,7 @@ class CompactBlockReorgTests: XCTestCase { info.consensusBranchID = branchID.toString() info.estimatedHeight = UInt64(mockLatestHeight) info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight) - }) + } try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: .testnet) @@ -51,24 +56,42 @@ class CompactBlockReorgTests: XCTestCase { mockBackend.mockValidateCombinedChainKeepFailing = false mockBackend.mockValidateCombinedChainFailureHeight = self.network.constants.saplingActivationHeight + 320 - processor = CompactBlockProcessor(service: service, - storage: storage, - backend: mockBackend, - config: processorConfig) + processor = CompactBlockProcessor( + service: service, + storage: storage, + backend: mockBackend, + config: processorConfig + ) - downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect") - stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation") - updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation") - startedValidatingNotificationExpectation = XCTestExpectation(description: self.description + " startedValidatingNotificationExpectation") - startedScanningNotificationExpectation = XCTestExpectation(description: self.description + " startedScanningNotificationExpectation") - idleNotificationExpectation = XCTestExpectation(description: self.description + " idleNotificationExpectation") - reorgNotificationExpectation = XCTestExpectation(description: self.description + " reorgNotificationExpectation") + downloadStartedExpect = XCTestExpectation(description: "\(self.description) downloadStartedExpect") + stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation") + updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation") + startedValidatingNotificationExpectation = XCTestExpectation( + description: "\(self.description) startedValidatingNotificationExpectation" + ) + startedScanningNotificationExpectation = XCTestExpectation( + description: "\(self.description) startedScanningNotificationExpectation" + ) + idleNotificationExpectation = XCTestExpectation(description: "\(self.description) idleNotificationExpectation") + reorgNotificationExpectation = XCTestExpectation(description: "\(self.description) reorgNotificationExpectation") - NotificationCenter.default.addObserver(self, selector: #selector(processorHandledReorg(_:)), name: Notification.Name.blockProcessorHandledReOrg, object: processor) - NotificationCenter.default.addObserver(self, selector: #selector(processorFailed(_:)), name: Notification.Name.blockProcessorFailed, object: processor) + NotificationCenter.default.addObserver( + self, + selector: #selector(processorHandledReorg(_:)), + name: Notification.Name.blockProcessorHandledReOrg, + object: processor + ) + + NotificationCenter.default.addObserver( + self, + selector: #selector(processorFailed(_:)), + name: Notification.Name.blockProcessorFailed, + object: processor + ) } override func tearDown() { + super.tearDown() try! FileManager.default.removeItem(at: processorConfig.cacheDb) try? FileManager.default.removeItem(at: processorConfig.dataDb) downloadStartedExpect.unsubscribeFromNotifications() @@ -82,31 +105,28 @@ class CompactBlockReorgTests: XCTestCase { } @objc func processorHandledReorg(_ notification: Notification) { - - XCTAssertNotNil(notification.userInfo) - if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight, - let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight { - XCTAssertTrue( reorg == 0 || reorg > self.network.constants.saplingActivationHeight) - XCTAssertTrue( rewind == 0 || rewind > self.network.constants.saplingActivationHeight) - XCTAssertTrue( rewind <= reorg ) - reorgNotificationExpectation.fulfill() - } else { - XCTFail("CompactBlockProcessor reorg notification is malformed") - } + XCTAssertNotNil(notification.userInfo) + if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight, + let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight { + XCTAssertTrue( reorg == 0 || reorg > self.network.constants.saplingActivationHeight) + XCTAssertTrue( rewind == 0 || rewind > self.network.constants.saplingActivationHeight) + XCTAssertTrue( rewind <= reorg ) + reorgNotificationExpectation.fulfill() + } else { + XCTFail("CompactBlockProcessor reorg notification is malformed") + } } @objc func processorFailed(_ notification: Notification) { - - XCTAssertNotNil(notification.userInfo) - if let error = notification.userInfo?["error"] { - XCTFail("CompactBlockProcessor failed with Error: \(error)") - } else { - XCTFail("CompactBlockProcessor failed") - } - + XCTAssertNotNil(notification.userInfo) + if let error = notification.userInfo?["error"] { + XCTFail("CompactBlockProcessor failed with Error: \(error)") + } else { + XCTFail("CompactBlockProcessor failed") + } } - fileprivate func startProcessing() { + private func startProcessing() { XCTAssertNotNil(processor) // Subscribe to notifications @@ -122,20 +142,22 @@ class CompactBlockReorgTests: XCTestCase { } func testNotifiesReorg() { - startProcessing() - - wait(for: [ - downloadStartedExpect, - startedValidatingNotificationExpectation, - startedScanningNotificationExpectation, - reorgNotificationExpectation, - idleNotificationExpectation, - ], timeout: 300,enforceOrder: true) + + wait( + for: [ + downloadStartedExpect, + startedValidatingNotificationExpectation, + startedScanningNotificationExpectation, + reorgNotificationExpectation, + idleNotificationExpectation + ], + timeout: 300, + enforceOrder: true + ) } private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int { - (abs(currentHeight-targetHeight)/batchSize) + (abs(currentHeight - targetHeight) / batchSize) } - } diff --git a/ZcashLightClientKitTests/CompactBlockStorageTests.swift b/ZcashLightClientKitTests/CompactBlockStorageTests.swift index e6fde17e..81a8ccdc 100644 --- a/ZcashLightClientKitTests/CompactBlockStorageTests.swift +++ b/ZcashLightClientKitTests/CompactBlockStorageTests.swift @@ -8,12 +8,13 @@ import Foundation import XCTest + +// swiftlint:disable force_try @testable import ZcashLightClientKit class CompactBlockStorageTests: XCTestCase { - - var compactBlockDao: CompactBlockRepository = try! TestDbBuilder.inMemoryCompactBlockStorage() - let network = ZcashNetworkBuilder.network(for: .testnet) + var compactBlockDao: CompactBlockRepository = try! TestDbBuilder.inMemoryCompactBlockStorage() + func testEmptyStorage() { XCTAssertEqual(try! compactBlockDao.latestHeight(), BlockHeight.empty()) } @@ -34,11 +35,9 @@ class CompactBlockStorageTests: XCTestCase { let latestHeight = try! compactBlockDao.latestHeight() XCTAssertNotEqual(initialHeight, latestHeight) XCTAssertEqual(latestHeight, finalHeight) - } func testStoreOneBlockFromEmpty() { - let initialHeight = try! compactBlockDao.latestHeight() guard initialHeight == BlockHeight.empty() else { XCTFail("database not empty, latest height: \(initialHeight)") @@ -62,7 +61,6 @@ class CompactBlockStorageTests: XCTestCase { } func testRewindTo() { - let startHeight = self.network.constants.saplingActivationHeight let blockCount = Int(1_000) let finalHeight = startHeight + blockCount @@ -79,10 +77,8 @@ class CompactBlockStorageTests: XCTestCase { do { let latestHeight = try compactBlockDao.latestHeight() XCTAssertEqual(latestHeight, rewindHeight - 1) - } catch { XCTFail("Rewind latest block failed with error: \(error)") } - } } diff --git a/ZcashLightClientKitTests/DarksideSanityCheckTests.swift b/ZcashLightClientKitTests/DarksideSanityCheckTests.swift index d1ee8983..b926602b 100644 --- a/ZcashLightClientKitTests/DarksideSanityCheckTests.swift +++ b/ZcashLightClientKitTests/DarksideSanityCheckTests.swift @@ -8,12 +8,15 @@ import Foundation import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable implicitly_unwrapped_optional class DarksideSanityCheckTests: XCTestCase { - - var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment? - - let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment - + // TODO: Parameterize this from environment? + // swiftlint:disable:next line_length + var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" + // TODO: Parameterize this from environment + let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" + let sendAmount: Int64 = 1000 var birthday: BlockHeight = 663150 let defaultLatestHeight: BlockHeight = 663175 @@ -23,12 +26,12 @@ class DarksideSanityCheckTests: XCTestCase { var expectedReorgHeight: BlockHeight = 665188 var expectedRewindHeight: BlockHeight = 665188 var network = DarksideWalletDNetwork() - var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg") + var reorgExpectation = XCTestExpectation(description: "reorg") let branchID = "2bb40e60" let chainName = "main" override func setUpWithError() throws { - + try super.setUpWithError() coordinator = try TestCoordinator( seed: seedPhrase, walletBirthday: birthday, @@ -37,10 +40,10 @@ class DarksideSanityCheckTests: XCTestCase { ) try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName) try coordinator.resetBlocks(dataset: .default) - } override func tearDownWithError() throws { + try super.tearDownWithError() try? FileManager.default.removeItem(at: coordinator.databases.cacheDB) try? FileManager.default.removeItem(at: coordinator.databases.dataDB) try? FileManager.default.removeItem(at: coordinator.databases.pendingDB) @@ -54,17 +57,19 @@ class DarksideSanityCheckTests: XCTestCase { let syncExpectation = XCTestExpectation(description: "sync to \(expectedLastBlock.height)") - try coordinator.sync(completion: { (synchronizer) in - - syncExpectation.fulfill() - }, error: { (error) in - guard let e = error else { - XCTFail("failed with unknown error") + try coordinator.sync( + completion: { _ in + syncExpectation.fulfill() + }, + error: { error in + guard let e = error else { + XCTFail("failed with unknown error") + return + } + XCTFail("failed with error: \(e)") return } - XCTFail("failed with error: \(e)") - return - }) + ) wait(for: [syncExpectation], timeout: 5) @@ -75,6 +80,5 @@ class DarksideSanityCheckTests: XCTestCase { XCTAssertEqual(firstBlock?.hash.toHexStringTxId(), expectedFirstBlock.hash) XCTAssertEqual(lastBlock?.hash.toHexStringTxId(), expectedLastBlock.hash) - } } diff --git a/ZcashLightClientKitTests/DownloadOperationTests.swift b/ZcashLightClientKitTests/DownloadOperationTests.swift index a34857df..41b0ee99 100644 --- a/ZcashLightClientKitTests/DownloadOperationTests.swift +++ b/ZcashLightClientKitTests/DownloadOperationTests.swift @@ -9,12 +9,14 @@ import XCTest import SQLite @testable import ZcashLightClientKit + +// swiftlint:disable force_try class DownloadOperationTests: XCTestCase { - var operationQueue = OperationQueue() var network = ZcashNetworkBuilder.network(for: .testnet) + override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() operationQueue.cancelAllOperations() } @@ -29,13 +31,13 @@ class DownloadOperationTests: XCTestCase { let range = activationHeight ... activationHeight + blockCount let downloadOperation = CompactBlockDownloadOperation(downloader: downloader, range: range) - downloadOperation.completionHandler = { (finished, cancelled) in + downloadOperation.completionHandler = { finished, cancelled in expect.fulfill() XCTAssertTrue(finished) XCTAssertFalse(cancelled) } - downloadOperation.errorHandler = { (error) in + downloadOperation.errorHandler = { error in XCTFail("Donwload Operation failed with error: \(error)") } @@ -43,7 +45,6 @@ class DownloadOperationTests: XCTestCase { wait(for: [expect], timeout: 10) - XCTAssertEqual(try! storage.latestHeight(),range.upperBound) + XCTAssertEqual(try! storage.latestHeight(), range.upperBound) } - } diff --git a/ZcashLightClientKitTests/LightWalletServiceTests.swift b/ZcashLightClientKitTests/LightWalletServiceTests.swift index 5c58e2ce..36e0fe00 100644 --- a/ZcashLightClientKitTests/LightWalletServiceTests.swift +++ b/ZcashLightClientKitTests/LightWalletServiceTests.swift @@ -9,21 +9,21 @@ import XCTest @testable import ZcashLightClientKit import GRPC + +// swiftlint:disable implicitly_unwrapped_optional force_unwrapping class LightWalletServiceTests: XCTestCase { - + let network: ZcashNetwork = ZcashNetworkBuilder.network(for: .testnet) + var service: LightWalletService! var channel: Channel! - let network: ZcashNetwork = ZcashNetworkBuilder.network(for: .testnet) + override func setUp() { // Put setup code here. This method is called before the invocation of each test method in the class. + super.setUp() channel = ChannelProvider().channel() service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet) } - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - /// FIXME: check whether this test is stil valid on in memory lwd implementatiojn // func testFailure() { // @@ -44,7 +44,7 @@ class LightWalletServiceTests: XCTestCase { let upperRange: BlockHeight = network.constants.saplingActivationHeight + count let blockRange = lowerRange ... upperRange - service.blockRange(blockRange) { (result) in + service.blockRange(blockRange) { result in expect.fulfill() switch result { case .failure(let error): @@ -73,9 +73,9 @@ class LightWalletServiceTests: XCTestCase { } } - func testLatestBlock(){ + func testLatestBlock() { let expect = XCTestExpectation(description: self.description) - service.latestBlockHeight { (result) in + service.latestBlockHeight { result in expect.fulfill() switch result { case .failure(let e): @@ -87,5 +87,4 @@ class LightWalletServiceTests: XCTestCase { wait(for: [expect], timeout: 10) } - } diff --git a/ZcashLightClientKitTests/MemoTests.swift b/ZcashLightClientKitTests/MemoTests.swift index 47f60de9..433c9441 100644 --- a/ZcashLightClientKitTests/MemoTests.swift +++ b/ZcashLightClientKitTests/MemoTests.swift @@ -7,32 +7,30 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable force_unwrapping print_function_usage class MemoTests: XCTestCase { - - /** - Non-utf8 memos are properly ignored - */ + Non-utf8 memos are properly ignored + */ func testNonUnicodeMemos() throws { XCTAssertNil(Self.randomMemoData()!.asZcashTransactionMemo()) } /** - Memo length is correct, padding characters are ignored - */ + Memo length is correct, padding characters are ignored + */ func testMemoLength() throws { XCTAssertEqual(validMemoData.count, 512) XCTAssertEqual(validMemoData.asZcashTransactionMemo()!.count, Self.validMemoDataExpectedString.count) } /** - Verify support for common unicode characters - */ + Verify support for common unicode characters + */ func testUnicodeCharacters() throws { - let memo = validMemoData.asZcashTransactionMemo() XCTAssertNotNil(memo) XCTAssertEqual(memo!, Self.validMemoDataExpectedString) - } func testEmojiUnicodeCharacters() throws { @@ -42,32 +40,34 @@ class MemoTests: XCTestCase { } /** - Blank memos are ignored - */ + Blank memos are ignored + */ func testBlankMemos() throws { // This is an example of a functional test case. XCTAssertNil(emptyMemoData.asZcashTransactionMemo()) } /** - test canonical memos - */ + test canonical memos + */ func testCanonicalBlankMemos() throws { XCTAssertNil(Self.canonicalEmptyMemo().asZcashTransactionMemo()) } /** - ******* - * mocked memos - * ****** - */ + ******* + * mocked memos + * ****** + */ /** - Real text: "Here's gift from the Zec Fairy @ ECC!" - */ + Real text: "Here's gift from the Zec Fairy @ ECC!" + */ static let validMemoDataExpectedString = "Here's gift from the Zec Fairy @ ECC!" - static let validMemoDataBase64 = "SGVyZSdzIGdpZnQgZnJvbSB0aGUgWmVjIEZhaXJ5IEAgRUNDIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + static let validMemoDataBase64 = + // swiftlint:disable:next line_length + "SGVyZSdzIGdpZnQgZnJvbSB0aGUgWmVjIEZhaXJ5IEAgRUNDIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" let validMemoData = Data(base64Encoded: validMemoDataBase64)! @@ -75,8 +75,9 @@ class MemoTests: XCTestCase { let totallyRandomDataMemo = randomMemoData()! - - static let emojiDataBase64 = "8J+SlfCfkpXwn5KV8J+mk/CfppPwn6aT8J+bofCfm6Hwn5uhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + static let emojiDataBase64 = + // swiftlint:disable:next line_length + "8J+SlfCfkpXwn5KV8J+mk/CfppPwn6aT8J+bofCfm6Hwn5uhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" static let emojiMemoData = Data(base64Encoded: emojiDataBase64)! @@ -102,4 +103,3 @@ class MemoTests: XCTestCase { } } } - diff --git a/ZcashLightClientKitTests/NetworkUpgradeTests.swift b/ZcashLightClientKitTests/NetworkUpgradeTests.swift index 61fc0469..04be4ded 100644 --- a/ZcashLightClientKitTests/NetworkUpgradeTests.swift +++ b/ZcashLightClientKitTests/NetworkUpgradeTests.swift @@ -7,32 +7,31 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable implicitly_unwrapped_optional type_body_length force_unwrapping class NetworkUpgradeTests: XCTestCase { - let activationHeight: BlockHeight = 1028500 - var spendingKey = "secret-extended-key-test1qv2vf437qqqqpqpfc0arpv55ncq33p2p895hlcx0ra6d0g739v93luqdjpxun3kt050j9qnrqjyp8d7fdxgedfyxpjmuyha2ulxa6hmqvm2gnvuc3tvs3enpxwuz768qfkd286vr3jgyrgr5ddx2ukrdl95ak3tzqylzjeqw3pnmgtmwsvemrj3sk6vqgwxm9khlv46wccn33ayw52prr233ea069c9u8m3839dvw30sdf6k32xddhpte6p6qsuxval6usyh6lr55pgypkgtz" - - let testRecipientAddress = "ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc" //TODO: Parameterize this from environment - + let spendingKey = + // swiftlint:disable:next line_length + "secret-extended-key-test1qv2vf437qqqqpqpfc0arpv55ncq33p2p895hlcx0ra6d0g739v93luqdjpxun3kt050j9qnrqjyp8d7fdxgedfyxpjmuyha2ulxa6hmqvm2gnvuc3tvs3enpxwuz768qfkd286vr3jgyrgr5ddx2ukrdl95ak3tzqylzjeqw3pnmgtmwsvemrj3sk6vqgwxm9khlv46wccn33ayw52prr233ea069c9u8m3839dvw30sdf6k32xddhpte6p6qsuxval6usyh6lr55pgypkgtz" + + // TODO: Parameterize this from environment + let testRecipientAddress = "ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc" let sendAmount: Int64 = 1000 - var birthday: BlockHeight = 1013250 let branchID = "2bb40e60" let chainName = "main" + + var birthday: BlockHeight = 1013250 var coordinator: TestCoordinator! var network = ZcashNetworkBuilder.network(for: .testnet) override func setUpWithError() throws { - -// coordinator = try TestCoordinator( -// spendingKey: spendingKey, -// unifiedViewingKey: <#UnifiedViewingKey#>, -// walletBirthday: birthday, -// channelProvider: ChannelProvider() -// ) + try super.setUpWithError() try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName) } override func tearDownWithError() throws { + try super.tearDownWithError() NotificationCenter.default.removeObserver(self) try coordinator.stop() try? FileManager.default.removeItem(at: coordinator.databases.cacheDB) @@ -40,22 +39,26 @@ class NetworkUpgradeTests: XCTestCase { try? FileManager.default.removeItem(at: coordinator.databases.pendingDB) } - /** - Given that a wallet had funds prior to activation it can spend them after activation - */ + Given that a wallet had funds prior to activation it can spend them after activation + */ func testSpendPriorFundsAfterActivation() throws { - try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, birthday: birthday, networkActivationHeight: activationHeight, branchID: branchID, chainName: chainName, length: 15300) + try FakeChainBuilder.buildChain( + darksideWallet: coordinator.service, + birthday: birthday, + networkActivationHeight: activationHeight, + branchID: branchID, + chainName: chainName, + length: 15300 + ) let firstSyncExpectation = XCTestExpectation(description: "first sync") try coordinator.applyStaged(blockheight: activationHeight - ZcashSDK.defaultStaleTolerance) sleep(5) - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() - }, error: self.handleError) wait(for: [firstSyncExpectation], timeout: 120) @@ -69,31 +72,40 @@ class NetworkUpgradeTests: XCTestCase { sleep(2) let sendExpectation = XCTestExpectation(description: "send expectation") - var p: PendingTransactionEntity? = nil + var pendingEntity: PendingTransactionEntity? let spendAmount: Int64 = 10000 + /* - 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): - p = pendingTx + 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() } - sendExpectation.fulfill() - }) + ) wait(for: [sendExpectation], timeout: 11) - guard let _ = p else { + guard pendingEntity != nil else { XCTFail("no pending transaction after sending") try coordinator.stop() return } + /* - getIncomingTransaction - */ + getIncomingTransaction + */ guard let incomingTx = try coordinator.getIncomingTransactions()?.first else { XCTFail("no incoming transaction") try coordinator.stop() @@ -103,45 +115,44 @@ class NetworkUpgradeTests: XCTestCase { let sentTxHeight: BlockHeight = activationHeight + 2 /* - stage transaction at sentTxHeight - */ - + stage transaction at sentTxHeight + */ try coordinator.stageTransaction(incomingTx, at: sentTxHeight) try coordinator.applyStaged(blockheight: activationHeight + 20) sleep(1) let afterSendExpectation = XCTestExpectation(description: "aftersend") - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in afterSendExpectation.fulfill() - }, error: self.handleError) wait(for: [afterSendExpectation], timeout: 10) XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), verifiedBalance - spendAmount) - } /** - Given that a wallet receives funds after activation it can spend them when confirmed - */ + Given that a wallet receives funds after activation it can spend them when confirmed + */ func testSpendPostActivationFundsAfterConfirmation() throws { - try FakeChainBuilder.buildChainPostActivationFunds(darksideWallet: coordinator.service, birthday: birthday, networkActivationHeight: activationHeight, length: 15300) + try FakeChainBuilder.buildChainPostActivationFunds( + darksideWallet: coordinator.service, + birthday: birthday, + networkActivationHeight: activationHeight, + length: 15300 + ) let firstSyncExpectation = XCTestExpectation(description: "first sync") try coordinator.applyStaged(blockheight: activationHeight + 10) sleep(3) - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() - }, error: self.handleError) wait(for: [firstSyncExpectation], timeout: 120) - guard try coordinator.synchronizer.allReceivedTransactions().filter({$0.minedHeight > activationHeight}).count > 0 else { + guard try !coordinator.synchronizer.allReceivedTransactions().filter({ $0.minedHeight > activationHeight }).isEmpty else { XCTFail("this test requires funds received after activation height") return } @@ -149,26 +160,33 @@ class NetworkUpgradeTests: XCTestCase { try coordinator.applyStaged(blockheight: activationHeight + 20) sleep(2) - let sendExpectation = XCTestExpectation(description: "send expectation") - var p: PendingTransactionEntity? = nil + var pendingEntity: PendingTransactionEntity? let spendAmount: Int64 = 10000 + /* - 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): - p = pendingTx + 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() } - sendExpectation.fulfill() - }) + ) wait(for: [sendExpectation], timeout: 11) - guard let _ = p else { + guard pendingEntity != nil else { XCTFail("no pending transaction after sending") try coordinator.stop() return @@ -178,66 +196,74 @@ class NetworkUpgradeTests: XCTestCase { let afterSendExpectation = XCTestExpectation(description: "aftersend") - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in afterSendExpectation.fulfill() - }, error: self.handleError) wait(for: [afterSendExpectation], timeout: 10) - } - /** - Given that a wallet sends funds some between (activation - expiry_height) and activation, those funds are shown as sent if mined. - */ + /** + Given that a wallet sends funds some between (activation - expiry_height) and activation, those funds are shown as sent if mined. + */ func testSpendMinedSpendThatExpiresOnActivation() throws { - try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, birthday: birthday, networkActivationHeight: activationHeight, branchID: branchID, chainName: chainName, length: 15300) + try FakeChainBuilder.buildChain( + darksideWallet: coordinator.service, + birthday: birthday, + networkActivationHeight: activationHeight, + branchID: branchID, + chainName: chainName, + length: 15300 + ) let firstSyncExpectation = XCTestExpectation(description: "first sync") try coordinator.applyStaged(blockheight: activationHeight - 10) sleep(3) - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() - }, error: self.handleError) wait(for: [firstSyncExpectation], timeout: 120) let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: activationHeight)) - - let sendExpectation = XCTestExpectation(description: "send expectation") - var p: PendingTransactionEntity? = nil + var pendingEntity: PendingTransactionEntity? let spendAmount: Int64 = 10000 + /* - 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): - p = pendingTx + 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() } - sendExpectation.fulfill() - }) + ) wait(for: [sendExpectation], timeout: 11) - guard let pendingTx = p else { + guard let pendingTx = pendingEntity else { XCTFail("no pending transaction after sending") try coordinator.stop() return } /* - getIncomingTransaction - */ + getIncomingTransaction + */ guard let incomingTx = try coordinator.getIncomingTransactions()?.first else { XCTFail("no incoming transaction") try coordinator.stop() @@ -246,12 +272,9 @@ class NetworkUpgradeTests: XCTestCase { let sentTxHeight: BlockHeight = activationHeight - 5 - /* - stage transaction at sentTxHeight - */ - - + stage transaction at sentTxHeight + */ try coordinator.stageTransaction(incomingTx, at: sentTxHeight) try coordinator.applyStaged(blockheight: activationHeight + 5) @@ -259,15 +282,16 @@ class NetworkUpgradeTests: XCTestCase { let afterSendExpectation = XCTestExpectation(description: "aftersend") - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in afterSendExpectation.fulfill() - }, error: self.handleError) wait(for: [afterSendExpectation], timeout: 10) - guard let confirmedTx = try coordinator.synchronizer.allConfirmedTransactions(from: nil, limit: Int.max)?.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) else { + guard + let confirmedTx = try coordinator.synchronizer.allConfirmedTransactions(from: nil, limit: Int.max)? + .first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) + else { XCTFail("the sent transaction is not listed as a confirmed transaction") return } @@ -276,11 +300,17 @@ class NetworkUpgradeTests: XCTestCase { } /** - Given that a wallet sends funds somewhere between (activation - expiry_height) and activation, those funds are available if expired after expiration height. - */ - + Given that a wallet sends funds somewhere between (activation - expiry_height) and activation, those funds are available if expired after expiration height. + */ func testExpiredSpendAfterActivation() throws { - try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, birthday: birthday, networkActivationHeight: activationHeight, branchID: branchID, chainName: chainName, length: 15300) + try FakeChainBuilder.buildChain( + darksideWallet: coordinator.service, + birthday: birthday, + networkActivationHeight: activationHeight, + branchID: branchID, + chainName: chainName, + length: 15300 + ) let firstSyncExpectation = XCTestExpectation(description: "first sync") let offset = 5 @@ -289,10 +319,8 @@ class NetworkUpgradeTests: XCTestCase { let verifiedBalancePreActivation = coordinator.synchronizer.initializer.getVerifiedBalance() - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() - }, error: self.handleError) wait(for: [firstSyncExpectation], timeout: 120) @@ -303,57 +331,64 @@ class NetworkUpgradeTests: XCTestCase { } let sendExpectation = XCTestExpectation(description: "send expectation") - var p: PendingTransactionEntity? = nil + var pendingEntity: PendingTransactionEntity? let spendAmount: Int64 = 10000 + /* - 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): - p = pendingTx + 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() } - sendExpectation.fulfill() - }) + ) wait(for: [sendExpectation], timeout: 11) - guard let pendingTx = p else { + guard let pendingTx = pendingEntity else { XCTFail("no pending transaction after sending") try coordinator.stop() return } /* - getIncomingTransaction - */ - guard let _ = try coordinator.getIncomingTransactions()?.first else { + getIncomingTransaction + */ + guard try coordinator.getIncomingTransactions()?.first != nil else { XCTFail("no incoming transaction") try coordinator.stop() return } /* - don't stage transaction - */ - - + don't stage transaction + */ try coordinator.applyStaged(blockheight: activationHeight + offset) sleep(2) let afterSendExpectation = XCTestExpectation(description: "aftersend") - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in afterSendExpectation.fulfill() - }, error: self.handleError) wait(for: [afterSendExpectation], timeout: 10) - guard try coordinator.synchronizer.allConfirmedTransactions(from: nil, limit: Int.max)?.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) == nil else { + guard + try coordinator.synchronizer.allConfirmedTransactions(from: nil, limit: Int.max)? + .first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) == nil + else { XCTFail("the sent transaction should not be not listed as a confirmed transaction") return } @@ -362,20 +397,25 @@ class NetworkUpgradeTests: XCTestCase { } /** - Given that a wallet has notes both received prior and after activation these can be combined to supply a larger amount spend. - */ + Given that a wallet has notes both received prior and after activation these can be combined to supply a larger amount spend. + */ func testCombinePreActivationNotesAndPostActivationNotesOnSpend() throws { - try FakeChainBuilder.buildChainMixedFunds(darksideWallet: coordinator.service, birthday: birthday, networkActivationHeight: activationHeight, branchID: branchID, chainName: chainName, length: 15300) + try FakeChainBuilder.buildChainMixedFunds( + darksideWallet: coordinator.service, + birthday: birthday, + networkActivationHeight: activationHeight, + branchID: branchID, + chainName: chainName, + length: 15300 + ) let firstSyncExpectation = XCTestExpectation(description: "first sync") try coordinator.applyStaged(blockheight: activationHeight - 1) sleep(3) - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() - }, error: self.handleError) wait(for: [firstSyncExpectation], timeout: 120) @@ -386,14 +426,12 @@ class NetworkUpgradeTests: XCTestCase { sleep(2) let secondSyncExpectation = XCTestExpectation(description: "second sync") - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in secondSyncExpectation.fulfill() - }, error: self.handleError) wait(for: [secondSyncExpectation], timeout: 10) - guard try coordinator.synchronizer.allReceivedTransactions().filter({$0.minedHeight > activationHeight}).count > 0 else { + guard try !coordinator.synchronizer.allReceivedTransactions().filter({ $0.minedHeight > activationHeight }).isEmpty else { XCTFail("this test requires funds received after activation height") return } @@ -401,27 +439,34 @@ class NetworkUpgradeTests: XCTestCase { XCTAssertTrue(preActivationBalance < postActivationBalance, "This test requires that funds post activation are greater that pre activation") let sendExpectation = XCTestExpectation(description: "send expectation") - var p: PendingTransactionEntity? = nil + var pendingEntity: PendingTransactionEntity? // spend all the funds let spendAmount: Int64 = postActivationBalance - Int64(network.constants.defaultFee(for: activationHeight)) /* - 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): - p = pendingTx + 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() } - sendExpectation.fulfill() - }) + ) wait(for: [sendExpectation], timeout: 15) - guard let _ = p else { + guard pendingEntity != nil else { XCTFail("no pending transaction after sending") try coordinator.stop() return diff --git a/ZcashLightClientKitTests/NotesRepositoryTests.swift b/ZcashLightClientKitTests/NotesRepositoryTests.swift index 739e739d..0351a1b0 100644 --- a/ZcashLightClientKitTests/NotesRepositoryTests.swift +++ b/ZcashLightClientKitTests/NotesRepositoryTests.swift @@ -8,16 +8,19 @@ import XCTest @testable import ZcashLightClientKit +// swiftlint:disable implicitly_unwrapped_optional class NotesRepositoryTests: XCTestCase { - var sentNotesRepository: SentNotesRepository! var receivedNotesRepository: ReceivedNoteRepository! + override func setUp() { + super.setUp() sentNotesRepository = TestDbBuilder.sentNotesRepository() receivedNotesRepository = TestDbBuilder.receivedNotesRepository() } override func tearDown() { + super.tearDown() sentNotesRepository = nil receivedNotesRepository = nil } @@ -32,6 +35,5 @@ class NotesRepositoryTests: XCTestCase { var count: Int? XCTAssertNoThrow(try { count = try receivedNotesRepository.count() }()) XCTAssertEqual(count, 27) - } } diff --git a/ZcashLightClientKitTests/NullBytesTests.swift b/ZcashLightClientKitTests/NullBytesTests.swift index ebc653f5..a5e809bc 100644 --- a/ZcashLightClientKitTests/NullBytesTests.swift +++ b/ZcashLightClientKitTests/NullBytesTests.swift @@ -7,19 +7,24 @@ import XCTest @testable import ZcashLightClientKit + class NullBytesTests: XCTestCase { let networkType = NetworkType.mainnet + func testZaddrNullBytes() throws { - let validZaddr = "zs1gqtfu59z20s9t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp" // this is a valid zAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/ - let ZaddrWithNullBytes = "\(validZaddr)\0something else that makes the address invalid" + // this is a valid zAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/ + let validZaddr = "zs1gqtfu59z20s9t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp" + let zAddrWithNullBytes = "\(validZaddr)\0something else that makes the address invalid" - XCTAssertFalse(try ZcashRustBackend.isValidShieldedAddress(ZaddrWithNullBytes, networkType: networkType)) + XCTAssertFalse(try ZcashRustBackend.isValidShieldedAddress(zAddrWithNullBytes, networkType: networkType)) } func testTaddrNullBytes() throws { - let validTAddr = "t1J5pTRzJi7j8Xw9VJTrPxPEkaigr69gKVT" // this is a valid tAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/ - let TaddrWithNullBytes = "\(validTAddr)\0fasdfasdf" - XCTAssertFalse(try ZcashRustBackend.isValidTransparentAddress(TaddrWithNullBytes, networkType: networkType)) + // this is a valid tAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/ + let validTAddr = "t1J5pTRzJi7j8Xw9VJTrPxPEkaigr69gKVT" + let tAddrWithNullBytes = "\(validTAddr)\0fasdfasdf" + + XCTAssertFalse(try ZcashRustBackend.isValidTransparentAddress(tAddrWithNullBytes, networkType: networkType)) } func testInitAccountTableNullBytes() throws { @@ -27,11 +32,24 @@ class NullBytesTests: XCTestCase { let goodHash = "00000000015c597fab53f58b9e1ededbe8bd83ca0203788e2039eceeb0d65ca6" let time: UInt32 = 1582235356 let height: Int32 = 735000 + + // swiftlint:disable:next line_length let wrongTree = "0161f2ff97ff6ac6a90f9bce76c11710460f4944d8695aecc7dc99e34cad0131040011015325b185e23e82562db27817be996ffade9597181244f67efc40561aeb9dde1101daeffadc9e38f755bcb55a847a1278518a0ba4a2ef33b2fe01bbb3eb242ab0070000000000011c51f9077e3f7e28e8e337eaf4bb99b41acbc853a37dcc1e172467a1c919fe4100010bb1f55481b2268ef31997dc0fb6b48a530bc17870220f156d832326c433eb0a010b3768d3bf7868a67823e022f49be67982d0588e7041c498a756024\0750065a4a0001a9e1bf4bccb48b14b544e770f21d48f2d3ad8d6ca54eccc92f60634e3078eb48013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260" + + // swiftlint:disable:next line_length let goodTree = "0161f2ff97ff6ac6a90f9bce76c11710460f4944d8695aecc7dc99e34cad0131040011015325b185e23e82562db27817be996ffade9597181244f67efc40561aeb9dde1101daeffadc9e38f755bcb55a847a1278518a0ba4a2ef33b2fe01bbb3eb242ab0070000000000011c51f9077e3f7e28e8e337eaf4bb99b41acbc853a37dcc1e172467a1c919fe4100010bb1f55481b2268ef31997dc0fb6b48a530bc17870220f156d832326c433eb0a010b3768d3bf7868a67823e022f49be67982d0588e7041c498a756024750065a4a0001a9e1bf4bccb48b14b544e770f21d48f2d3ad8d6ca54eccc92f60634e3078eb48013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260" - XCTAssertThrowsError(try ZcashRustBackend.initBlocksTable(dbData: __dataDbURL(), height: height , hash: wrongHash, time: time, saplingTree: goodTree, networkType: networkType), "InitBlocksTable with Null bytes on hash string should have failed") { (error) in - + XCTAssertThrowsError( + try ZcashRustBackend.initBlocksTable( + dbData: __dataDbURL(), + height: height, + hash: wrongHash, + time: time, + saplingTree: goodTree, + networkType: networkType + ), + "InitBlocksTable with Null bytes on hash string should have failed" + ) { error in guard let rustError = error as? RustWeldingError else { XCTFail("Expected RustWeldingError") return @@ -45,8 +63,17 @@ class NullBytesTests: XCTestCase { } } - XCTAssertThrowsError(try ZcashRustBackend.initBlocksTable(dbData: __dataDbURL(), height: height , hash: goodHash, time: time, saplingTree: wrongTree, networkType: networkType), "InitBlocksTable with Null bytes on saplingTree string should have failed") { (error) in - + XCTAssertThrowsError( + try ZcashRustBackend.initBlocksTable( + dbData: __dataDbURL(), + height: height, + hash: goodHash, + time: time, + saplingTree: wrongTree, + networkType: networkType + ), + "InitBlocksTable with Null bytes on saplingTree string should have failed" + ) { error in guard let rustError = error as? RustWeldingError else { XCTFail("Expected RustWeldingError") return @@ -62,12 +89,16 @@ class NullBytesTests: XCTestCase { } func testderiveExtendedFullViewingKeyWithNullBytes() throws { - let wrongSpendingKeys = "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mq\0uy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv" //this spending key corresponds to the "demo app reference seed" - + // swiftlint:disable:next line_length + let wrongSpendingKeys = "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mq\0uy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv" // this spending key corresponds to the "demo app reference seed" + + // swiftlint:disable:next line_length let goodSpendingKeys = "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv" - XCTAssertThrowsError(try ZcashRustBackend.deriveExtendedFullViewingKey(wrongSpendingKeys, networkType: networkType),"Should have thrown an error but didn't! this is dangerous!") { (error) in - + XCTAssertThrowsError( + try ZcashRustBackend.deriveExtendedFullViewingKey(wrongSpendingKeys, networkType: networkType), + "Should have thrown an error but didn't! this is dangerous!" + ) { error in guard let rustError = error as? RustWeldingError else { XCTFail("Expected RustWeldingError") return @@ -82,15 +113,17 @@ class NullBytesTests: XCTestCase { } XCTAssertNoThrow(try ZcashRustBackend.deriveExtendedFullViewingKey(goodSpendingKeys, networkType: networkType)) - } func testCheckNullBytes() throws { - let validZaddr = "zs1gqtfu59z20s9t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp" // this is a valid zAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/ + // this is a valid zAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/ + let validZaddr = "zs1gqtfu59z20s9t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp" + XCTAssertFalse(validZaddr.containsCStringNullBytesBeforeStringEnding()) - - XCTAssertTrue("zs1gqtfu59z20s\09t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp".containsCStringNullBytesBeforeStringEnding()) - + XCTAssertTrue( + "zs1gqtfu59z20s\09t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp" + .containsCStringNullBytesBeforeStringEnding() + ) XCTAssertTrue("\0".containsCStringNullBytesBeforeStringEnding()) XCTAssertFalse("".containsCStringNullBytesBeforeStringEnding()) } diff --git a/ZcashLightClientKitTests/PagedTransactionRepositoryTests.swift b/ZcashLightClientKitTests/PagedTransactionRepositoryTests.swift index 194a0cbb..971ceddb 100644 --- a/ZcashLightClientKitTests/PagedTransactionRepositoryTests.swift +++ b/ZcashLightClientKitTests/PagedTransactionRepositoryTests.swift @@ -7,13 +7,20 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable implicitly_unwrapped_optional class PagedTransactionRepositoryTests: XCTestCase { - var pagedTransactionRepository: PaginatedTransactionRepository! var transactionRepository: TransactionRepository! override func setUp() { - transactionRepository = MockTransactionRepository(unminedCount: 5, receivedCount: 150, sentCount: 100, network: ZcashNetworkBuilder.network(for: .testnet)) + super.setUp() + transactionRepository = MockTransactionRepository( + unminedCount: 5, + receivedCount: 150, + sentCount: 100, + network: ZcashNetworkBuilder.network(for: .testnet) + ) pagedTransactionRepository = PagedTransactionDAO(repository: transactionRepository) } @@ -21,18 +28,18 @@ class PagedTransactionRepositoryTests: XCTestCase { let pageSize = pagedTransactionRepository.pageSize let pageCount = pagedTransactionRepository.pageCount let totalItems = pagedTransactionRepository.itemCount - for i in 0 ..< pageCount/pageSize { - guard let page = try? pagedTransactionRepository.page(i) else { - XCTFail("page failed to get page \(i)") + + for index in 0 ..< pageCount / pageSize { + guard let page = try? pagedTransactionRepository.page(index) else { + XCTFail("page failed to get page \(index)") return } - if i < pageCount { + if index < pageCount { XCTAssert(page.count == pageSize) } else { // last page has to have the remainding items - XCTAssertEqual(page.count, totalItems - (pageSize * pageCount)) + XCTAssertEqual(page.count, totalItems - (pageSize * pageCount)) } } } - } diff --git a/ZcashLightClientKitTests/PendingTransactionRepositoryTests.swift b/ZcashLightClientKitTests/PendingTransactionRepositoryTests.swift index 2097432f..afee3ed2 100644 --- a/ZcashLightClientKitTests/PendingTransactionRepositoryTests.swift +++ b/ZcashLightClientKitTests/PendingTransactionRepositoryTests.swift @@ -7,22 +7,24 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable force_try force_unwrapping implicitly_unwrapped_optional class PendingTransactionRepositoryTests: XCTestCase { - - var pendingRepository: PendingTransactionRepository! - let dbUrl = try! TestDbBuilder.pendingTransactionsDbURL() - let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6" + + var pendingRepository: PendingTransactionRepository! + override func setUp() { + super.setUp() cleanUpDb() let dao = PendingTransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: try! TestDbBuilder.pendingTransactionsDbURL().absoluteString)) try! dao.createrTableIfNeeded() pendingRepository = dao - } override func tearDown() { + super.tearDown() cleanUpDb() } @@ -31,77 +33,79 @@ class PendingTransactionRepositoryTests: XCTestCase { } func testCreate() { + let transaction = createAndStoreMockedTransaction() - let tx = createAndStoreMockedTransaction() - - guard let id = tx.id, id >= 0 else { + guard let id = transaction.id, id >= 0 else { XCTFail("failed to create mocked transaction that was just inserted") return } var expectedTx: PendingTransactionEntity? - XCTAssertNoThrow(try { expectedTx = try pendingRepository.find(by: id)}()) + XCTAssertNoThrow(try { expectedTx = try pendingRepository.find(by: id) }()) guard let expected = expectedTx else { XCTFail("failed to retrieve mocked transaction by id \(id) that was just inserted") return } - XCTAssertEqual(tx.accountIndex, expected.accountIndex) - XCTAssertEqual(tx.value, expected.value) - XCTAssertEqual(tx.toAddress, expected.toAddress) + XCTAssertEqual(transaction.accountIndex, expected.accountIndex) + XCTAssertEqual(transaction.value, expected.value) + XCTAssertEqual(transaction.toAddress, expected.toAddress) } func testFindById() { - let tx = createAndStoreMockedTransaction() + let transaction = createAndStoreMockedTransaction() var expected: PendingTransactionEntity? - guard let id = tx.id else { + guard let id = transaction.id else { XCTFail("transaction with no id") return } - XCTAssertNoThrow(try { expected = try pendingRepository.find(by: id)}()) - + + XCTAssertNoThrow(try { expected = try pendingRepository.find(by: id) }()) XCTAssertNotNil(expected) } func testCancel() { - let tx = createAndStoreMockedTransaction() - guard let id = tx.id else { - XCTFail("transaction with no id") - return - } + let transaction = createAndStoreMockedTransaction() + + guard let id = transaction.id else { + XCTFail("transaction with no id") + return + } + guard id >= 0 else { XCTFail("failed to create mocked transaction that was just inserted") return } - XCTAssertNoThrow(try pendingRepository.cancel(tx)) + XCTAssertNoThrow(try pendingRepository.cancel(transaction)) } func testDelete() { - let tx = createAndStoreMockedTransaction() - guard let id = tx.id else { - XCTFail("transaction with no id") - return - } + let transaction = createAndStoreMockedTransaction() + + guard let id = transaction.id else { + XCTFail("transaction with no id") + return + } + guard id >= 0 else { XCTFail("failed to create mocked transaction that was just inserted") return } - XCTAssertNoThrow(try pendingRepository.delete(tx)) + XCTAssertNoThrow(try pendingRepository.delete(transaction)) var unexpectedTx: PendingTransactionEntity? XCTAssertNoThrow(try { unexpectedTx = try pendingRepository.find(by: id) }()) - XCTAssertNil(unexpectedTx) } func testGetAll() { - var mockTransactions = [PendingTransactionEntity]() + var mockTransactions: [PendingTransactionEntity] = [] for _ in 1...100 { mockTransactions.append(createAndStoreMockedTransaction()) } @@ -116,20 +120,21 @@ class PendingTransactionRepositoryTests: XCTestCase { } XCTAssertEqual(mockTransactions.count, allTxs.count) - } func testUpdate() { let newAccountIndex = 1 let newValue: Int = 123_456 - let tx = createAndStoreMockedTransaction() - guard let id = tx.id else { - XCTFail("transaction with no id") - return - } + let transaction = createAndStoreMockedTransaction() + + guard let id = transaction.id else { + XCTFail("transaction with no id") + return + } + var stored: PendingTransactionEntity? - XCTAssertNoThrow(try { stored = try pendingRepository.find(by: id)}()) + XCTAssertNoThrow(try { stored = try pendingRepository.find(by: id) }()) guard stored != nil else { XCTFail("failed to store tx") @@ -152,12 +157,12 @@ class PendingTransactionRepositoryTests: XCTestCase { } func createAndStoreMockedTransaction() -> PendingTransactionEntity { - var tx = mockTransaction() + var transaction = mockTransaction() var id: Int? - XCTAssertNoThrow(try { id = try pendingRepository.create(tx) }()) - tx.id = Int(id ?? -1) - return tx + XCTAssertNoThrow(try { id = try pendingRepository.create(transaction) }()) + transaction.id = Int(id ?? -1) + return transaction } func testPerformanceExample() { @@ -170,5 +175,4 @@ class PendingTransactionRepositoryTests: XCTestCase { private func mockTransaction() -> PendingTransactionEntity { PendingTransaction(value: Int.random(in: 1 ... 1_000_000), toAddress: recipientAddress, memo: nil, account: 0) } - } diff --git a/ZcashLightClientKitTests/PendingTransactionUpdatesTest.swift b/ZcashLightClientKitTests/PendingTransactionUpdatesTest.swift index 30f34d31..9c0cf570 100644 --- a/ZcashLightClientKitTests/PendingTransactionUpdatesTest.swift +++ b/ZcashLightClientKitTests/PendingTransactionUpdatesTest.swift @@ -7,10 +7,14 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable implicitly_unwrapped_optional class PendingTransactionUpdatesTest: XCTestCase { - var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment? - - let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment + // TODO: Parameterize this from environment? + // swiftlint:disable:next line_length + var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" + // TODO: Parameterize this from environment + let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" let sendAmount: Int64 = 1000 var birthday: BlockHeight = 663150 @@ -20,12 +24,12 @@ class PendingTransactionUpdatesTest: XCTestCase { var sentTransactionExpectation = XCTestExpectation(description: "sent") var expectedReorgHeight: BlockHeight = 665188 var expectedRewindHeight: BlockHeight = 665188 - var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg") + var reorgExpectation = XCTestExpectation(description: "reorg") let branchID = "2bb40e60" let chainName = "main" let network = DarksideWalletDNetwork() override func setUpWithError() throws { - + try super.setUpWithError() coordinator = try TestCoordinator( seed: seedPhrase, walletBirthday: birthday, @@ -36,6 +40,7 @@ class PendingTransactionUpdatesTest: XCTestCase { } override func tearDownWithError() throws { + try super.tearDownWithError() NotificationCenter.default.removeObserver(self) try coordinator.stop() try? FileManager.default.removeItem(at: coordinator.databases.cacheDB) @@ -44,23 +49,21 @@ class PendingTransactionUpdatesTest: XCTestCase { } @objc func handleReorg(_ notification: Notification) { - - guard let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight - // let rewindHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight - else { - XCTFail("empty reorg notification") - return + guard + let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight + else { + XCTFail("empty reorg notification") + return } - // XCTAssertEqual(rewindHeight, expectedRewindHeight) XCTAssertEqual(reorgHeight, expectedReorgHeight) reorgExpectation.fulfill() } func testPendingTransactionMinedHeightUpdated() throws { /* - 1. create fake chain - */ + 1. create fake chain + */ LoggerProxy.info("1. create fake chain") try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName) @@ -69,13 +72,12 @@ class PendingTransactionUpdatesTest: XCTestCase { sleep(2) let firstSyncExpectation = XCTestExpectation(description: "first sync") + /* - 1a. sync to latest height - */ - + 1a. sync to latest height + */ LoggerProxy.info("1a. sync to latest height") - try coordinator.sync(completion: { (s) in - + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: self.handleError) @@ -84,37 +86,55 @@ class PendingTransactionUpdatesTest: XCTestCase { sleep(1) let sendExpectation = XCTestExpectation(description: "send expectation") - var p: PendingTransactionEntity? = nil + var pendingEntity: PendingTransactionEntity? /* - 2. send transaction to recipient address - */ + 2. send transaction to recipient address + */ LoggerProxy.info("2. send transaction to recipient address") - coordinator.synchronizer.sendToAddress(spendingKey: self.coordinator.spendingKeys!.first!, 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): - p = pendingTx + coordinator.synchronizer.sendToAddress( + // swiftlint:disable:next force_unwrapping + spendingKey: self.coordinator.spendingKeys!.first!, + 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() } - sendExpectation.fulfill() - }) + ) wait(for: [sendExpectation], timeout: 11) - guard let pendingUnconfirmedTx = p else { + guard let pendingUnconfirmedTx = pendingEntity else { XCTFail("no pending transaction after sending") try coordinator.stop() return } - XCTAssertFalse(pendingUnconfirmedTx.isConfirmed(currentHeight: 663188), "pending transaction evaluated as confirmed when it shouldn't") - XCTAssertFalse(pendingUnconfirmedTx.isMined, "pending transaction evaluated as mined when it shouldn't") + XCTAssertFalse( + pendingUnconfirmedTx.isConfirmed(currentHeight: 663188), + "pending transaction evaluated as confirmed when it shouldn't" + ) + XCTAssertFalse( + pendingUnconfirmedTx.isMined, + "pending transaction evaluated as mined when it shouldn't" + ) - XCTAssertTrue(pendingUnconfirmedTx.isPending(currentHeight: 663188), "pending transaction evaluated as not pending when it should be") + XCTAssertTrue( + pendingUnconfirmedTx.isPending(currentHeight: 663188), + "pending transaction evaluated as not pending when it should be" + ) + /** - 3. getIncomingTransaction - */ + 3. getIncomingTransaction + */ LoggerProxy.info("3. getIncomingTransaction") guard let incomingTx = try coordinator.getIncomingTransactions()?.first else { XCTFail("no incoming transaction") @@ -124,31 +144,34 @@ class PendingTransactionUpdatesTest: XCTestCase { let sentTxHeight: BlockHeight = 663189 - /* - 4. stage transaction at sentTxHeight - */ + 4. stage transaction at sentTxHeight + */ LoggerProxy.info("4. stage transaction at \(sentTxHeight)") try coordinator.stageBlockCreate(height: sentTxHeight) try coordinator.stageTransaction(incomingTx, at: sentTxHeight) + /* - 5. applyHeight(sentTxHeight) - */ + 5. applyHeight(sentTxHeight) + */ LoggerProxy.info("5. applyHeight(\(sentTxHeight))") try coordinator.applyStaged(blockheight: sentTxHeight) sleep(2) /* - 6. sync to latest height - */ + 6. sync to latest height + */ LoggerProxy.info("6. sync to latest height") - let secondSyncExpectation = XCTestExpectation(description: "after send expectation") + let secondSyncExpectation = XCTestExpectation(description: "after send expectation") - try coordinator.sync(completion: { (s) in - secondSyncExpectation.fulfill() - }, error: self.handleError) + try coordinator.sync( + completion: { _ in + secondSyncExpectation.fulfill() + }, + error: self.handleError + ) wait(for: [secondSyncExpectation], timeout: 5) @@ -158,16 +181,16 @@ class PendingTransactionUpdatesTest: XCTestCase { } /* - 6a. verify that there's a pending transaction with a mined height of sentTxHeight - */ + 6a. verify that there's a pending transaction with a mined height of sentTxHeight + */ LoggerProxy.info("6a. verify that there's a pending transaction with a mined height of \(sentTxHeight)") XCTAssertEqual(afterStagePendingTx.minedHeight, sentTxHeight) XCTAssertTrue(afterStagePendingTx.isMined, "pending transaction shown as unmined when it has been mined") XCTAssertTrue(afterStagePendingTx.isPending(currentHeight: sentTxHeight)) /* - 7. stage 15 blocks from sentTxHeight - */ + 7. stage 15 blocks from sentTxHeight + */ LoggerProxy.info("7. stage 15 blocks from \(sentTxHeight)") try coordinator.stageBlockCreate(height: sentTxHeight + 1, count: 15) sleep(2) @@ -183,20 +206,18 @@ class PendingTransactionUpdatesTest: XCTestCase { */ LoggerProxy.info("last sync to latest height: \(lastStageHeight)") - try coordinator.sync(completion: { (s) in + try coordinator.sync(completion: { _ in syncToConfirmExpectation.fulfill() }, error: self.handleError) wait(for: [syncToConfirmExpectation], timeout: 6) - var supposedlyPendingUnexistingTransaction: PendingTransactionEntity? = nil + var supposedlyPendingUnexistingTransaction: PendingTransactionEntity? XCTAssertNoThrow(try { supposedlyPendingUnexistingTransaction = try coordinator.synchronizer.allPendingTransactions().first }()) XCTAssertNil(supposedlyPendingUnexistingTransaction) } - - func handleError(_ error: Error?) { _ = try? coordinator.stop() guard let testError = error else { @@ -207,6 +228,11 @@ class PendingTransactionUpdatesTest: XCTestCase { } func hookToReOrgNotification() { - NotificationCenter.default.addObserver(self, selector: #selector(handleReorg(_:)), name: .blockProcessorHandledReOrg, object: nil) + NotificationCenter.default.addObserver( + self, + selector: #selector(handleReorg(_:)), + name: .blockProcessorHandledReOrg, + object: nil + ) } } diff --git a/ZcashLightClientKitTests/RawTransactionTests.swift b/ZcashLightClientKitTests/RawTransactionTests.swift index 7e1a3b66..3b20f52c 100644 --- a/ZcashLightClientKitTests/RawTransactionTests.swift +++ b/ZcashLightClientKitTests/RawTransactionTests.swift @@ -8,29 +8,35 @@ import XCTest @testable import ZcashLightClientKit @testable import SwiftProtobuf + +// swiftlint:disable implicitly_unwrapped_optional class RawTransactionTests: XCTestCase { var rawTx: Data! var transactionRepository: TransactionSQLDAO! + override func setUp() { + super.setUp() rawTx = Data(base64Encoded: txBase64String) } func testDeserialize() { - guard let raw = Data(base64Encoded: txFromAndroidSDK) else { XCTFail("no raw data") return } - let rawTransaction = RawTransaction.with({ (r) in - r.data = raw + let rawTransaction = RawTransaction.with({ rawTr in + rawTr.data = raw }) XCTAssertNotNil(rawTransaction) - } + + let txFromAndroidSDK = + // swiftlint:disable:next line_length + "BAAAgIUgL4kAAAAAAACqoAoAECcAAAAAAAAB25ACAriMhxsTPYM1Lit6Ob0O1PssJwZ8e3/rLA+epll+1eKFT4lvPvDHjzY5udeJfHtvCcbFr+WL6rQGAjdrK7Y6Lu+Ofn1DOSOuVtv6z4FMSBB2EsrYkjsHkYTz93xpwTPnB2J42JrYdrq3qviFGaT3T06/dZGmuIxZVYqKFWaCKjniLNYh5epX3U33l7fjKzLKXiFXcJjAFmElvzbjEcEdMTvcDcno0swmE9XNPZ2iMNyeIX1TqEQJCvnTfK26D+ig768BZqdzYMDXu8sSDa0SdeHwJWmRUPoPUG1AbFQZPmzp3ZYITbpUigsKFJhB+lQ+DP62qKIP/uJq8wLCevMgfcVLFk6rzkgMGkz5/ySm4R5yFcj4GLQ65GcX8EvnMbM0WT4nwpjhttTSb6Fquzxb38VfqGoVBnH5VrRLwBrSsucr7dZtMcLxZCyZ29JPtfVf2o/BrEaigYGF0vLQnkDl4fWTnuafIMFPa4uO7tUtPGU6DwmRXX33Twz7P7ACAh8O6RK6jOJ+2vZWHXx+P0hqIHrYL/5lip60hQ9llRVYCSCiT7tvm57lIfDP5whUda6zwpyp4p7tjE4HvTMlOV0uZIuxN8J14gsrDnDbpn+hR+FCdEXS88of4UIe4oRNxjel70OAmMVCPFd2Y1O47jZo2BjHx4+1e9mou2SyjGSCepsbGizfn+5xz6jH2dYLGbWGlaNQyosCLlY6/UHswRV7y1NZcaFY5zh9ytMsdfYC20I3Zv1MyyDk1Jd6mlscRksP/iAjAUGr/PSCGEvOZ1z1dp2XIBism9NHi6Gy2uCFhOqpxfCM7DaKeqUYhH9R1Gfc5Vpy0LKAFVxOaTSha4odsOlgAE5GffwzPA11g43wR0scKGR0JImRVRfxyYVaKHggRaP/UnEsvXIiE+e3Mx0CA1aKfwbl9n0AlLuUVttAgZxUxnULHtC3jRt0l4gippyxD658jInGnbJfi3dKcI4H6OGeH7wznXpaUP7wfXIUa1kyv8FuZwkktXPLOW+1XKd9hAs+5UDqSajq/TZ0bNaCxOJQruASxqtUq+678hBmAhhqjk7IJ99KSy5y07bRnxVnDfVj5ZpEXBzkK08/G8pBA5qSGXjgEqXKRXFTgXzuW+m7c2jVCxpM5lDy5Adej7H61sz6T0N9OXwN8SjssWtS65unp6pKg1psowwNAAVdv/bvtyQOidwnf20j6LlitvVNNY3vGedRxCaeatvcDYb9cdBqqxzb3ki/Sn7beLOS/LF2YnYtLhdT8qB40dILmyOMeXOA1L2wzeCnbx9fIuCrGZDPjTRfIWWCMZVJ4RuJ5CqKFcYbYN+GrxtKkMmprwbcE8XxW71cUEsE9M5GtM8uDvmpTGFQKQTV2EcYoN0Go47CSPx4kfFSybGWsRir2aX+7i5QHNYvicfoWOXWSY60I7OHIOR8xs2qYBgfbb+7/ml1xxCm7WDdO6NfyJib9d6YpbIanSYh77ytwVlOu4HMhrs9K+NuSQYE7gKiHcoWOJkNYqW4VmLKiuw51kmm3Q0238VTOBOzba1oUz1ukR+9bPXjUhFmoY/Ueen9aZdobcE33YYu8iqua6E1zyknnsL+h/Zc7fT5FBpcQGEfYqsKKZKNsuCA+N6IRyq3OtmRVFhL1wFU1YdVQeKQfd69CTNpPJbnDkNVN7Img/+cEgMj5H5qDD4rE1vsq1cx48RnxV5lMa/T9WHnpcaAZ4/1qkFCKGhw6yRBcoGTWuH0vbS6071/iPJV5AhjlqNJMUw1s7BpojmxPOaWhAV3ztOOi3ZhiyPrtRJnUmfwfjYZO7FQq8eF4MDP7njiICsP74skUJoe0BBAcUgTatSIST2MkYgpa0QJAragwcRg1ZHFmTZYoEWhYp9K8FP8WLl1XrlSetPrEgo2zCrnb6GoOLSjnvF9CIdzXB2lpB8c71azvFAO3Kc58QDsIAFTN5cWMFMZTrmQi/AqsSVwaF92FZeNdAL5lVNfZ2LePrmXGSvGrDFjt3Wql/9KYebrGwBXpHdUOWRIF8FJMplg+jN2lz/0GGp39EkDZBXUlJUsCgnCInDyeKxI0rMJY8w5cVXyN9FW3/v6ns3UtYkFqNv2dcOT7WUBFgI0ZJ+M3i/L88MKga/dtntmZrXOxD6LXQ3hApLcm06t40cOVZdVlQ2doIMNzx1I66lXXjq8ij6L6Z40qwgrsFzX1RYUXooM+1HvmEmaffglOdqHkwtk3hK+4OWNoxdb8QFG5EbGCcahIpvRg0Wj60/zhzv6LfQC6/Yqd65QVjgYorV0Uy8eGGlD/aDDQp7nIu/1+EA5Aav0isl3TPBd/qmjGxdTI6BANQrB8rl58V+0rAY2AdBuXTM0bo8Ak/QcVDMp7arN8cViLCb3rq1Job34GZE8OzyRDuk2E499JqxClQPtPeJa47AKGV4OofPN6qOnbCEB2DlqrW4cPVDE95Ty+I1qUS2eDD0lZS0Ll/czErJ9H4cqFpFKUbXF6yZ+JbcPyMWqgaZHCatmM2rc6yxgWP8R6/KW/xdx++N/SGi3zQW2Zk7om26VZiBaGP36de0hut6VuHS54bobzSjZChwL4tcHcsgGW3cF+iWL3bHJ/Yo2b7r1r/lRboArd6c+8Ap2HFqCJYxPfdnqG5M8WfkbHecWkf4uAqn0aAWoFeBS7w+PGOuBE0RdQTt14UkwUu2OVfcxWyVjfDZ5DggMJ5bwszMzz2FVivIDZ7fUnZ5ftUkuALx4PcN58vJGycgWpBk55ZhIdFKTD7hx/Psv5myn2y7ZJarlMAS6PLGjjd7XKqi/3Q5f0RCR6QSB8ImecdwJfECwN80Dx6sNCy2eZAnx2kjXCYq5lJiGQ4feDvp/GBuf3SnggsFa4YZHThRWQH/83qe8RgTYcSuPc6p2MTfE2RVCHg4Ek8usMLcrORtH6a53/slMp10DW4i9fMF2GZroorM762i6y2OQq7/YzwWzsISBupQANlPGwRwFrqwXY2BSqNPgt1r7p68SFUZ8KtzWov1QWl9cDjFRAeISXo7CcjLyWgDQwBPKo4otCxnJ0tHIQpttJYwPx/39bLbaiou5HXFRYeBE1JxlyRQv1Be5KCGoL0kOdoe4psIKEZ5ijIYhCqoC" - let txFromAndroidSDK = "BAAAgIUgL4kAAAAAAACqoAoAECcAAAAAAAAB25ACAriMhxsTPYM1Lit6Ob0O1PssJwZ8e3/rLA+epll+1eKFT4lvPvDHjzY5udeJfHtvCcbFr+WL6rQGAjdrK7Y6Lu+Ofn1DOSOuVtv6z4FMSBB2EsrYkjsHkYTz93xpwTPnB2J42JrYdrq3qviFGaT3T06/dZGmuIxZVYqKFWaCKjniLNYh5epX3U33l7fjKzLKXiFXcJjAFmElvzbjEcEdMTvcDcno0swmE9XNPZ2iMNyeIX1TqEQJCvnTfK26D+ig768BZqdzYMDXu8sSDa0SdeHwJWmRUPoPUG1AbFQZPmzp3ZYITbpUigsKFJhB+lQ+DP62qKIP/uJq8wLCevMgfcVLFk6rzkgMGkz5/ySm4R5yFcj4GLQ65GcX8EvnMbM0WT4nwpjhttTSb6Fquzxb38VfqGoVBnH5VrRLwBrSsucr7dZtMcLxZCyZ29JPtfVf2o/BrEaigYGF0vLQnkDl4fWTnuafIMFPa4uO7tUtPGU6DwmRXX33Twz7P7ACAh8O6RK6jOJ+2vZWHXx+P0hqIHrYL/5lip60hQ9llRVYCSCiT7tvm57lIfDP5whUda6zwpyp4p7tjE4HvTMlOV0uZIuxN8J14gsrDnDbpn+hR+FCdEXS88of4UIe4oRNxjel70OAmMVCPFd2Y1O47jZo2BjHx4+1e9mou2SyjGSCepsbGizfn+5xz6jH2dYLGbWGlaNQyosCLlY6/UHswRV7y1NZcaFY5zh9ytMsdfYC20I3Zv1MyyDk1Jd6mlscRksP/iAjAUGr/PSCGEvOZ1z1dp2XIBism9NHi6Gy2uCFhOqpxfCM7DaKeqUYhH9R1Gfc5Vpy0LKAFVxOaTSha4odsOlgAE5GffwzPA11g43wR0scKGR0JImRVRfxyYVaKHggRaP/UnEsvXIiE+e3Mx0CA1aKfwbl9n0AlLuUVttAgZxUxnULHtC3jRt0l4gippyxD658jInGnbJfi3dKcI4H6OGeH7wznXpaUP7wfXIUa1kyv8FuZwkktXPLOW+1XKd9hAs+5UDqSajq/TZ0bNaCxOJQruASxqtUq+678hBmAhhqjk7IJ99KSy5y07bRnxVnDfVj5ZpEXBzkK08/G8pBA5qSGXjgEqXKRXFTgXzuW+m7c2jVCxpM5lDy5Adej7H61sz6T0N9OXwN8SjssWtS65unp6pKg1psowwNAAVdv/bvtyQOidwnf20j6LlitvVNNY3vGedRxCaeatvcDYb9cdBqqxzb3ki/Sn7beLOS/LF2YnYtLhdT8qB40dILmyOMeXOA1L2wzeCnbx9fIuCrGZDPjTRfIWWCMZVJ4RuJ5CqKFcYbYN+GrxtKkMmprwbcE8XxW71cUEsE9M5GtM8uDvmpTGFQKQTV2EcYoN0Go47CSPx4kfFSybGWsRir2aX+7i5QHNYvicfoWOXWSY60I7OHIOR8xs2qYBgfbb+7/ml1xxCm7WDdO6NfyJib9d6YpbIanSYh77ytwVlOu4HMhrs9K+NuSQYE7gKiHcoWOJkNYqW4VmLKiuw51kmm3Q0238VTOBOzba1oUz1ukR+9bPXjUhFmoY/Ueen9aZdobcE33YYu8iqua6E1zyknnsL+h/Zc7fT5FBpcQGEfYqsKKZKNsuCA+N6IRyq3OtmRVFhL1wFU1YdVQeKQfd69CTNpPJbnDkNVN7Img/+cEgMj5H5qDD4rE1vsq1cx48RnxV5lMa/T9WHnpcaAZ4/1qkFCKGhw6yRBcoGTWuH0vbS6071/iPJV5AhjlqNJMUw1s7BpojmxPOaWhAV3ztOOi3ZhiyPrtRJnUmfwfjYZO7FQq8eF4MDP7njiICsP74skUJoe0BBAcUgTatSIST2MkYgpa0QJAragwcRg1ZHFmTZYoEWhYp9K8FP8WLl1XrlSetPrEgo2zCrnb6GoOLSjnvF9CIdzXB2lpB8c71azvFAO3Kc58QDsIAFTN5cWMFMZTrmQi/AqsSVwaF92FZeNdAL5lVNfZ2LePrmXGSvGrDFjt3Wql/9KYebrGwBXpHdUOWRIF8FJMplg+jN2lz/0GGp39EkDZBXUlJUsCgnCInDyeKxI0rMJY8w5cVXyN9FW3/v6ns3UtYkFqNv2dcOT7WUBFgI0ZJ+M3i/L88MKga/dtntmZrXOxD6LXQ3hApLcm06t40cOVZdVlQ2doIMNzx1I66lXXjq8ij6L6Z40qwgrsFzX1RYUXooM+1HvmEmaffglOdqHkwtk3hK+4OWNoxdb8QFG5EbGCcahIpvRg0Wj60/zhzv6LfQC6/Yqd65QVjgYorV0Uy8eGGlD/aDDQp7nIu/1+EA5Aav0isl3TPBd/qmjGxdTI6BANQrB8rl58V+0rAY2AdBuXTM0bo8Ak/QcVDMp7arN8cViLCb3rq1Job34GZE8OzyRDuk2E499JqxClQPtPeJa47AKGV4OofPN6qOnbCEB2DlqrW4cPVDE95Ty+I1qUS2eDD0lZS0Ll/czErJ9H4cqFpFKUbXF6yZ+JbcPyMWqgaZHCatmM2rc6yxgWP8R6/KW/xdx++N/SGi3zQW2Zk7om26VZiBaGP36de0hut6VuHS54bobzSjZChwL4tcHcsgGW3cF+iWL3bHJ/Yo2b7r1r/lRboArd6c+8Ap2HFqCJYxPfdnqG5M8WfkbHecWkf4uAqn0aAWoFeBS7w+PGOuBE0RdQTt14UkwUu2OVfcxWyVjfDZ5DggMJ5bwszMzz2FVivIDZ7fUnZ5ftUkuALx4PcN58vJGycgWpBk55ZhIdFKTD7hx/Psv5myn2y7ZJarlMAS6PLGjjd7XKqi/3Q5f0RCR6QSB8ImecdwJfECwN80Dx6sNCy2eZAnx2kjXCYq5lJiGQ4feDvp/GBuf3SnggsFa4YZHThRWQH/83qe8RgTYcSuPc6p2MTfE2RVCHg4Ek8usMLcrORtH6a53/slMp10DW4i9fMF2GZroorM762i6y2OQq7/YzwWzsISBupQANlPGwRwFrqwXY2BSqNPgt1r7p68SFUZ8KtzWov1QWl9cDjFRAeISXo7CcjLyWgDQwBPKo4otCxnJ0tHIQpttJYwPx/39bLbaiou5HXFRYeBE1JxlyRQv1Be5KCGoL0kOdoe4psIKEZ5ijIYhCqoC" - - let txBase64String = "BAAAgIUgL4kAAAAAAACz/goAECcAAAAAAAABXcTpMQ7kFhTifSbypMLlmgvAh/mR9z78+mocYt7rvJvLFjfBGp9aDf/066bWOsKt4N78Kovjr5mPuVNSMUegJuwZuAxnaO+iu+z17zABU4TUdixiCq97W74jgttjhG+Nxe+HeXvlqX7NmDJJmRO0anXaL1pBcPxOcb1pXcfO5VG1SFGLFIhLNyDlCoYa42sPHnQ4WsjMUv7Jh8rIH/tJ/vhHv9mGEg+zfld5KkMQ1JSykSen34KAPjc/em+2KMN6qAKrUWRPYlQvkz/QTxXeXI1OoCLCmqdsbHEG5ffSdmkAJfJpKfRsI04DQdTF03eVxpSVxlmz7gfeEmwVowKGV284KwmGHsnuHawjcBVb2tWIU9tBfQtONE1HgA5B6wt8ynZGSrlit0gFaTxCxzFcRmYgkgLbJeqx1lu+wUBVqAqvbkA4wGTvNX28b3SWmTx40eTu251bzqzy/Ip/7tSgh6QupSzatDF2gHcpb91EY6r3E3Jyhm2zfu38JSHTctMMArFWhOyfzBwrMPFjrLKDc9IiX7zjMBluTTMgQosb81o4ZF+2ZIKbplfugQICjuQjC5UFvihNCNF6+j8ITfwwD105VO52qVFiAdNAvCsymmPGI0Wr2w9PdBweIhUsrDLz11wi1pnydHdRwArU82CCqcVd5rwixomZrjwP8IFL0wd5CKho7QdU4rXF39VN2nffD+hwAPl0X3TCntws3/8Q1066bRTJLhaZcSzaVB0Bq0GKRAMS/WflBIlkd4KG6+/dDw01B0/lobAJIXfa+UrGKbDxXjLQlW8R8Bi9I+Y7S1h8I/gYOQiuuoCpJyV//4sKi1/zI1nnDcTu1q7P1eDYv30Y1g31FK9IWoXIQaZJ8ehKJqSx/FDBvhsEEh2aHvRolFTwHvxiVV3b9L3txePJRTEBq/RDUvW1BjAST/xfd3TTUILEZ962Ix3hu+ZfKWDSFCb/YW1fHlf98O05QunwBwDnaC3qgzNbqDjF9mldOFWZ84XE6IJVCHTN04L4hR8dl4bltpjnVnQmy34bcKLNtsFoRXot9ckOcrbX8Bf9lfneichrYtWZi6bVt6irwFo4+qXwABsUQGA2TMgsKpw9z4KysdSqoMXOEe+k/wPPQIqTPtFp4jrkMIntSokR6hRPZFdJJ23OWHjOoIKxSZUeOgkbKlqSrcQa/IHZQ8cpEof8T1PyNx/VDgEf6oIxnk2+E/iosraQpunYgAtQCm1pC8tF5oI6MshGj2nfonSug9PS2ORf0xk2RJLnSbg3kdQGx85ulMrOojkci80RIeyta3vX527MKDANTsN6W2y8fT9oDVA4l11lm4j31TyK754eTb1VPsy0YOo1L5Vr0LOOZtpF+tCaojz6Kx980jkzlEJOQ+imLERLAckclxFCWYyQ+9UOJnuXS5YCy32cdkzm17e2SwmeYGmNrTGUm6eaT0/ZqqsPAQEo+h/z4Bgt9eUEUvkRaDhz/vZjJkNfHdLA2c3CI5iTA0WUJQa5J4XNbFSQmEl4RYNHLHz0utsHcgFC9czxtDZkLcTUcQ2i/dQv07E84FhrMG5bJ818SaABpMlX99gaMYRpW3SWSuU0++/apORrIOSqonXunqroBtnAzeAIGY30ikpmkuf/BYTxAADZHCLkUBNVFmkASV91In4r6nfDbwMVOXCffBBHf2Cr/9hcd5TNL10MG0qhSsYrpv1FpCxg56hYiglS3BQ1uj63bzf4lmRbAvwXdI99lgoPQqjws3hIDIAImobsRWJoGSjT6Gq2hd40CVmmFjlXxdPpo6+m4L2PFD97LnHjF9X/VA+VWc+ihPCLrzgVl63NJcsEf/0bNt/iNWkIILM38WUSMEWj4CaSp1wI8ank+JfE7elapFRza98CGb52g+gZSkEv/xWRn/SjL3RvqQwSdWh38N/ijzpRfL48MiwYd15U7HZ2pc/0WtYVe7JSH6BHBXExBUzhqnZqRxK+1jZflKsYFbCAaZOjpeLSy5l8AvOjDfGR5+Uk+7dIs97lSGHZd+EQWgV/bmH+NwicyMMImJQ6ZSZgiBWx/JU0kB0Vz3Mm5t8a7aWG3/AhUSwYTwLgzbYG4MyiCfV3UAUB81yMxirGLIOqkb/CguZCrQO9/oMhTA9Ek2GkHtG6qOdDEMXSpN1StPwqgQUaSb3PgW1rlPUC3jLGPYyv2CCF3+5d3Q6RkyZaOq5jIM0uaV7sUCqinnCs78yL8yRkQAEPJTAT8oH9J0YEaempSz1df5LnluJ3r2CsFK/by8745lQlWtm8jdmRBojPG9JDrVTkO2Z/hudc1uQqz9N0X7l3VYlXSpYty4QtQMDTy3LxAzo8Ecot84Wc7kZbtXhqMKwQRGJOUSHNBEZwjAw0SwfyS0ajnCUbhw08U2UguoLzHsW0XVFQ3bc4pUr0X04vFj5/w/hVGflo9uLssHxxmdfH2WgSltEZR3yX0/T5GlDj8qctgryO06ubRYZkola0uEkTmIZWtgL4TmFAKYwPVmBQ7eHl7/nZV5PQY8p68ubQZmQTYlQEOc36+Gj2TDHCLAXF1aGPqVcsyJDHULSSQ3CT17XGJEABI5eHCEzTrsBsVywUNpBcNQItghd18IMCkv9b2gw+N0NKJJjmuyRgIF5NXOXS8XupSuvPT857eIdx7tFmmzPh+5Gu6V/8MqREYWf4281x0ydKl6Eq5oURFVqFGtAQZcizcNoBn4OMVduvBRRyb81cNrNvMcveAQTRCj4eqvP9C7cBfPByELIullTRLXwAOaoYJ0c/rimHMCNDZqwBWVw+HNo0kZmjHjT3PF/CExoLkpS0ThBV97NhiNaRuJ9U4IidKLDwE19q2ptO76WXybzKJegFycWnsUxOkxyst9Nb5ur08Z+4+i07ePNAbj6ACufdZGVmu1Vtd5cPMw9PjJyM7BcxHwF30YxlhV4M0lRkatlGleALP2CXLG994wZ+SCA1n0/09wwD11G1ibX5l4TNdFCDDRdcq7Yyb08J/JBfsAyQNJrrNdWslND8nRMdGraxycrMfkMgq4dIDgCgs++1SPri1JMyv02WeIzCGjnHnhvphMxyFbFJqRzeA1oKF3dE9w95zItNagaY9PKLyx00g1C4ViaYgkagB6gG" + let txBase64String = + // swiftlint:disable:next line_length + "BAAAgIUgL4kAAAAAAACz/goAECcAAAAAAAABXcTpMQ7kFhTifSbypMLlmgvAh/mR9z78+mocYt7rvJvLFjfBGp9aDf/066bWOsKt4N78Kovjr5mPuVNSMUegJuwZuAxnaO+iu+z17zABU4TUdixiCq97W74jgttjhG+Nxe+HeXvlqX7NmDJJmRO0anXaL1pBcPxOcb1pXcfO5VG1SFGLFIhLNyDlCoYa42sPHnQ4WsjMUv7Jh8rIH/tJ/vhHv9mGEg+zfld5KkMQ1JSykSen34KAPjc/em+2KMN6qAKrUWRPYlQvkz/QTxXeXI1OoCLCmqdsbHEG5ffSdmkAJfJpKfRsI04DQdTF03eVxpSVxlmz7gfeEmwVowKGV284KwmGHsnuHawjcBVb2tWIU9tBfQtONE1HgA5B6wt8ynZGSrlit0gFaTxCxzFcRmYgkgLbJeqx1lu+wUBVqAqvbkA4wGTvNX28b3SWmTx40eTu251bzqzy/Ip/7tSgh6QupSzatDF2gHcpb91EY6r3E3Jyhm2zfu38JSHTctMMArFWhOyfzBwrMPFjrLKDc9IiX7zjMBluTTMgQosb81o4ZF+2ZIKbplfugQICjuQjC5UFvihNCNF6+j8ITfwwD105VO52qVFiAdNAvCsymmPGI0Wr2w9PdBweIhUsrDLz11wi1pnydHdRwArU82CCqcVd5rwixomZrjwP8IFL0wd5CKho7QdU4rXF39VN2nffD+hwAPl0X3TCntws3/8Q1066bRTJLhaZcSzaVB0Bq0GKRAMS/WflBIlkd4KG6+/dDw01B0/lobAJIXfa+UrGKbDxXjLQlW8R8Bi9I+Y7S1h8I/gYOQiuuoCpJyV//4sKi1/zI1nnDcTu1q7P1eDYv30Y1g31FK9IWoXIQaZJ8ehKJqSx/FDBvhsEEh2aHvRolFTwHvxiVV3b9L3txePJRTEBq/RDUvW1BjAST/xfd3TTUILEZ962Ix3hu+ZfKWDSFCb/YW1fHlf98O05QunwBwDnaC3qgzNbqDjF9mldOFWZ84XE6IJVCHTN04L4hR8dl4bltpjnVnQmy34bcKLNtsFoRXot9ckOcrbX8Bf9lfneichrYtWZi6bVt6irwFo4+qXwABsUQGA2TMgsKpw9z4KysdSqoMXOEe+k/wPPQIqTPtFp4jrkMIntSokR6hRPZFdJJ23OWHjOoIKxSZUeOgkbKlqSrcQa/IHZQ8cpEof8T1PyNx/VDgEf6oIxnk2+E/iosraQpunYgAtQCm1pC8tF5oI6MshGj2nfonSug9PS2ORf0xk2RJLnSbg3kdQGx85ulMrOojkci80RIeyta3vX527MKDANTsN6W2y8fT9oDVA4l11lm4j31TyK754eTb1VPsy0YOo1L5Vr0LOOZtpF+tCaojz6Kx980jkzlEJOQ+imLERLAckclxFCWYyQ+9UOJnuXS5YCy32cdkzm17e2SwmeYGmNrTGUm6eaT0/ZqqsPAQEo+h/z4Bgt9eUEUvkRaDhz/vZjJkNfHdLA2c3CI5iTA0WUJQa5J4XNbFSQmEl4RYNHLHz0utsHcgFC9czxtDZkLcTUcQ2i/dQv07E84FhrMG5bJ818SaABpMlX99gaMYRpW3SWSuU0++/apORrIOSqonXunqroBtnAzeAIGY30ikpmkuf/BYTxAADZHCLkUBNVFmkASV91In4r6nfDbwMVOXCffBBHf2Cr/9hcd5TNL10MG0qhSsYrpv1FpCxg56hYiglS3BQ1uj63bzf4lmRbAvwXdI99lgoPQqjws3hIDIAImobsRWJoGSjT6Gq2hd40CVmmFjlXxdPpo6+m4L2PFD97LnHjF9X/VA+VWc+ihPCLrzgVl63NJcsEf/0bNt/iNWkIILM38WUSMEWj4CaSp1wI8ank+JfE7elapFRza98CGb52g+gZSkEv/xWRn/SjL3RvqQwSdWh38N/ijzpRfL48MiwYd15U7HZ2pc/0WtYVe7JSH6BHBXExBUzhqnZqRxK+1jZflKsYFbCAaZOjpeLSy5l8AvOjDfGR5+Uk+7dIs97lSGHZd+EQWgV/bmH+NwicyMMImJQ6ZSZgiBWx/JU0kB0Vz3Mm5t8a7aWG3/AhUSwYTwLgzbYG4MyiCfV3UAUB81yMxirGLIOqkb/CguZCrQO9/oMhTA9Ek2GkHtG6qOdDEMXSpN1StPwqgQUaSb3PgW1rlPUC3jLGPYyv2CCF3+5d3Q6RkyZaOq5jIM0uaV7sUCqinnCs78yL8yRkQAEPJTAT8oH9J0YEaempSz1df5LnluJ3r2CsFK/by8745lQlWtm8jdmRBojPG9JDrVTkO2Z/hudc1uQqz9N0X7l3VYlXSpYty4QtQMDTy3LxAzo8Ecot84Wc7kZbtXhqMKwQRGJOUSHNBEZwjAw0SwfyS0ajnCUbhw08U2UguoLzHsW0XVFQ3bc4pUr0X04vFj5/w/hVGflo9uLssHxxmdfH2WgSltEZR3yX0/T5GlDj8qctgryO06ubRYZkola0uEkTmIZWtgL4TmFAKYwPVmBQ7eHl7/nZV5PQY8p68ubQZmQTYlQEOc36+Gj2TDHCLAXF1aGPqVcsyJDHULSSQ3CT17XGJEABI5eHCEzTrsBsVywUNpBcNQItghd18IMCkv9b2gw+N0NKJJjmuyRgIF5NXOXS8XupSuvPT857eIdx7tFmmzPh+5Gu6V/8MqREYWf4281x0ydKl6Eq5oURFVqFGtAQZcizcNoBn4OMVduvBRRyb81cNrNvMcveAQTRCj4eqvP9C7cBfPByELIullTRLXwAOaoYJ0c/rimHMCNDZqwBWVw+HNo0kZmjHjT3PF/CExoLkpS0ThBV97NhiNaRuJ9U4IidKLDwE19q2ptO76WXybzKJegFycWnsUxOkxyst9Nb5ur08Z+4+i07ePNAbj6ACufdZGVmu1Vtd5cPMw9PjJyM7BcxHwF30YxlhV4M0lRkatlGleALP2CXLG994wZ+SCA1n0/09wwD11G1ibX5l4TNdFCDDRdcq7Yyb08J/JBfsAyQNJrrNdWslND8nRMdGraxycrMfkMgq4dIDgCgs++1SPri1JMyv02WeIzCGjnHnhvphMxyFbFJqRzeA1oKF3dE9w95zItNagaY9PKLyx00g1C4ViaYgkagB6gG" } diff --git a/ZcashLightClientKitTests/ReOrgTests.swift b/ZcashLightClientKitTests/ReOrgTests.swift index c9d1f43e..58b5ea15 100644 --- a/ZcashLightClientKitTests/ReOrgTests.swift +++ b/ZcashLightClientKitTests/ReOrgTests.swift @@ -7,61 +7,69 @@ import XCTest @testable import ZcashLightClientKit -/** - basic reorg test. Scan, get a reorg and then reach latest height. - - * connect to dLWD - * request latest height -> receive 663250 - * download and sync blocks from 663150 to 663250 - * trigger reorg by calling API (no need to pass params)** - * request latest height -> receive 663251! - * download that block - * observe that the prev hash of that block does not match the hash that we have for 663250 - * rewind 10 blocks and request blocks 663241 to 663251 - */ -class ReOrgTests: XCTestCase { - var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment? - - let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment +/** +basic reorg test. Scan, get a reorg and then reach latest height. + +* connect to dLWD +* request latest height -> receive 663250 +* download and sync blocks from 663150 to 663250 +* trigger reorg by calling API (no need to pass params)** +* request latest height -> receive 663251! +* download that block +* observe that the prev hash of that block does not match the hash that we have for 663250 +* rewind 10 blocks and request blocks 663241 to 663251 +*/ +// swiftlint:disable implicitly_unwrapped_optional print_function_usage function_parameter_count +class ReOrgTests: XCTestCase { + // TODO: Parameterize this from environment? + // swiftlint:disable:next line_length + let seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" + // TODO: Parameterize this from environment + let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" let sendAmount: Int64 = 1000 - var birthday: BlockHeight = 663150 let defaultLatestHeight: BlockHeight = 663175 + let network = DarksideWalletDNetwork() + let branchID = "2bb40e60" + let chainName = "main" + let mockLatestHeight = BlockHeight(663250) + let targetLatestHeight = BlockHeight(663251) + let walletBirthday = BlockHeight(663150) + + var birthday: BlockHeight = 663150 + var reorgExpectation = XCTestExpectation(description: "reorg") var coordinator: TestCoordinator! var syncedExpectation = XCTestExpectation(description: "synced") var sentTransactionExpectation = XCTestExpectation(description: "sent") var expectedReorgHeight: BlockHeight = 665188 var expectedRewindHeight: BlockHeight = 665188 - let network = DarksideWalletDNetwork() - let branchID = "2bb40e60" - let chainName = "main" - var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg") + override func setUpWithError() throws { - NotificationCenter.default.addObserver(self, selector: #selector(handleReOrgNotification(_:)), name: Notification.Name.blockProcessorHandledReOrg, object: nil) - coordinator = try TestCoordinator( - seed: seedPhrase, - walletBirthday: birthday, - channelProvider: ChannelProvider(), - network: network - ) + try super.setUpWithError() + NotificationCenter.default.addObserver( + self, + selector: #selector(handleReOrgNotification(_:)), + name: Notification.Name.blockProcessorHandledReOrg, + object: nil + ) + coordinator = try TestCoordinator( + seed: seedPhrase, + walletBirthday: birthday, + channelProvider: ChannelProvider(), + network: network + ) try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName) - try coordinator.resetBlocks(dataset: .default) - - } - - override func tearDownWithError() throws { - try? FileManager.default.removeItem(at: coordinator.databases.cacheDB) - try? FileManager.default.removeItem(at: coordinator.databases.dataDB) - try? FileManager.default.removeItem(at: coordinator.databases.pendingDB) - } - let mockLatestHeight = BlockHeight(663250) - let targetLatestHeight = BlockHeight(663251) - let walletBirthday = BlockHeight(663150) - - - + try coordinator.resetBlocks(dataset: .default) + } + + override func tearDownWithError() throws { + try super.tearDownWithError() + try? FileManager.default.removeItem(at: coordinator.databases.cacheDB) + try? FileManager.default.removeItem(at: coordinator.databases.dataDB) + try? FileManager.default.removeItem(at: coordinator.databases.pendingDB) + } + @objc func handleReOrgNotification(_ notification: Notification) { - reorgExpectation.fulfill() guard let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight, let rewindHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight else { @@ -81,12 +89,14 @@ class ReOrgTests: XCTestCase { let reOrgHeight = BlockHeight(663195) let walletBirthday = WalletBirthday.birthday(with: 663150, network: network).height - try basicReOrgTest(baseDataset: .beforeReOrg, - reorgDataset: .afterSmallReorg, - firstLatestHeight: mockLatestHeight, - reorgHeight: reOrgHeight, - walletBirthday: walletBirthday, - targetHeight: targetLatestHeight) + try basicReOrgTest( + baseDataset: .beforeReOrg, + reorgDataset: .afterSmallReorg, + firstLatestHeight: mockLatestHeight, + reorgHeight: reOrgHeight, + walletBirthday: walletBirthday, + targetHeight: targetLatestHeight + ) } func testTenPlusBlockReOrg() throws { @@ -95,26 +105,29 @@ class ReOrgTests: XCTestCase { let reOrgHeight = BlockHeight(663180) let walletBirthday = WalletBirthday.birthday(with: BlockHeight(663150), network: network).height - try basicReOrgTest(baseDataset: .beforeReOrg, - reorgDataset: .afterLargeReorg, - firstLatestHeight: mockLatestHeight, - reorgHeight: reOrgHeight, - walletBirthday: walletBirthday, - targetHeight: targetLatestHeight) + try basicReOrgTest( + baseDataset: .beforeReOrg, + reorgDataset: .afterLargeReorg, + firstLatestHeight: mockLatestHeight, + reorgHeight: reOrgHeight, + walletBirthday: walletBirthday, + targetHeight: targetLatestHeight + ) } - func basicReOrgTest(baseDataset: DarksideDataset, - reorgDataset: DarksideDataset, - firstLatestHeight: BlockHeight, - reorgHeight: BlockHeight, - walletBirthday: BlockHeight, - targetHeight: BlockHeight) throws { - + func basicReOrgTest( + baseDataset: DarksideDataset, + reorgDataset: DarksideDataset, + firstLatestHeight: BlockHeight, + reorgHeight: BlockHeight, + walletBirthday: BlockHeight, + targetHeight: BlockHeight + ) throws { do { try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName) try coordinator.resetBlocks(dataset: .predefined(dataset: .beforeReOrg)) try coordinator.applyStaged(blockheight: firstLatestHeight) - } catch { + } catch { XCTFail("Error: \(error)") return } @@ -122,11 +135,11 @@ class ReOrgTests: XCTestCase { let firstSyncExpectation = XCTestExpectation(description: "firstSyncExpectation") /** - download and sync blocks from walletBirthday to firstLatestHeight - */ + download and sync blocks from walletBirthday to firstLatestHeight + */ var synchronizer: SDKSynchronizer? - try coordinator.sync(completion: { (s) in - synchronizer = s + try coordinator.sync(completion: { synchro in + synchronizer = synchro firstSyncExpectation.fulfill() }, error: self.handleError) @@ -136,51 +149,50 @@ class ReOrgTests: XCTestCase { XCTFail("nil synchronizer") return } + /** - verify that mock height has been reached - */ + verify that mock height has been reached + */ var latestDownloadedHeight = BlockHeight(0) - XCTAssertNoThrow(try {latestDownloadedHeight = try syncedSynchronizer.initializer.downloader.latestBlockHeight()}()) + XCTAssertNoThrow(try { latestDownloadedHeight = try syncedSynchronizer.initializer.downloader.latestBlockHeight() }()) XCTAssertTrue(latestDownloadedHeight > 0) /** - trigger reorg! - */ - + trigger reorg! + */ try coordinator.resetBlocks(dataset: .predefined(dataset: reorgDataset)) try coordinator.applyStaged(blockheight: targetHeight) /** - request latest height -> receive targetHeight! - download that block - observe that the prev hash of that block does not match the hash that we have for firstLatestHeight - rewind 10 blocks and request blocks targetHeight-10 to targetHeight - */ - + request latest height -> receive targetHeight! + download that block + observe that the prev hash of that block does not match the hash that we have for firstLatestHeight + rewind 10 blocks and request blocks targetHeight-10 to targetHeight + */ let secondSyncExpectation = XCTestExpectation(description: "second sync") sleep(2) - try coordinator.sync(completion: { (_) in - secondSyncExpectation.fulfill() - }, error: self.handleError) + try coordinator.sync( + completion: { _ in + secondSyncExpectation.fulfill() + }, + error: self.handleError + ) // now reorg should happen and reorg notifications and idle notification should be triggered - wait(for: [reorgExpectation,secondSyncExpectation], timeout: 5) + wait(for: [reorgExpectation, secondSyncExpectation], timeout: 5) // now everything should be fine. latest block should be targetHeight - XCTAssertNoThrow(try {latestDownloadedHeight = try syncedSynchronizer.initializer.downloader.latestBlockHeight()}()) + XCTAssertNoThrow(try { latestDownloadedHeight = try syncedSynchronizer.initializer.downloader.latestBlockHeight() }()) XCTAssertEqual(latestDownloadedHeight, targetHeight) } @objc func processorHandledReorg(_ notification: Notification) { - XCTAssertNotNil(notification.userInfo) if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight, let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight { - - XCTAssertTrue( rewind <= reorg ) reorgExpectation.fulfill() } else { @@ -195,5 +207,4 @@ class ReOrgTests: XCTestCase { } XCTFail("Failed with error: \(testError)") } - } diff --git a/ZcashLightClientKitTests/RewindRescanTests.swift b/ZcashLightClientKitTests/RewindRescanTests.swift index 658cb9b6..dd8b7151 100644 --- a/ZcashLightClientKitTests/RewindRescanTests.swift +++ b/ZcashLightClientKitTests/RewindRescanTests.swift @@ -7,48 +7,59 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable type_body_length implicitly_unwrapped_optional class RewindRescanTests: XCTestCase { - var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment? - - let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment - + // TODO: Parameterize this from environment? + // swiftlint:disable:next line_length + let seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" + + // TODO: Parameterize this from environment + let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" let sendAmount: Int64 = 1000 - var birthday: BlockHeight = 663150 let defaultLatestHeight: BlockHeight = 663175 + let branchID = "2bb40e60" + let chainName = "main" + + var birthday: BlockHeight = 663150 var coordinator: TestCoordinator! var syncedExpectation = XCTestExpectation(description: "synced") var sentTransactionExpectation = XCTestExpectation(description: "sent") var expectedReorgHeight: BlockHeight = 665188 var expectedRewindHeight: BlockHeight = 665188 - var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg") - let branchID = "2bb40e60" - let chainName = "main" + var reorgExpectation = XCTestExpectation(description: "reorg") var network = ZcashNetworkBuilder.network(for: .mainnet) + override func setUpWithError() throws { - + try super.setUpWithError() + coordinator = try TestCoordinator( seed: seedPhrase, walletBirthday: birthday, channelProvider: ChannelProvider(), network: network ) + try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main") } override func tearDownWithError() throws { + try super.tearDownWithError() + NotificationCenter.default.removeObserver(self) + try coordinator.stop() try? FileManager.default.removeItem(at: coordinator.databases.cacheDB) try? FileManager.default.removeItem(at: coordinator.databases.dataDB) try? FileManager.default.removeItem(at: coordinator.databases.pendingDB) } - func handleError(_ error: Error?) { guard let testError = error else { XCTFail("failed with nil error") return } + XCTFail("Failed with error: \(testError)") } @@ -62,7 +73,7 @@ class RewindRescanTests: XCTestCase { sleep(1) let firstSyncExpectation = XCTestExpectation(description: "first sync expectation") - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: handleError) @@ -77,14 +88,14 @@ class RewindRescanTests: XCTestCase { try coordinator.synchronizer.rewind(.birthday) // assert that after the new height is - XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(),self.birthday) + XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(), self.birthday) // check that the balance is cleared XCTAssertEqual(initialVerifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance()) XCTAssertEqual(initialTotalBalance, coordinator.synchronizer.initializer.getBalance()) let secondScanExpectation = XCTestExpectation(description: "rescan") - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { _ in secondScanExpectation.fulfill() }, error: handleError) @@ -93,24 +104,28 @@ class RewindRescanTests: XCTestCase { // verify that the balance still adds up XCTAssertEqual(verifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance()) XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance()) - } - func testRescanToHeight() throws { // 1 sync and get spendable funds - try FakeChainBuilder.buildChainWithTxsFarFromEachOther(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName, length: 10000) + try FakeChainBuilder.buildChainWithTxsFarFromEachOther( + darksideWallet: coordinator.service, + branchID: branchID, + chainName: chainName, + length: 10000 + ) let newChaintTip = defaultLatestHeight + 10000 try coordinator.applyStaged(blockheight: newChaintTip) sleep(3) let initialVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() -// let initialTotalBalance = coordinator.synchronizer.initializer.getBalance() - let firstSyncExpectation = XCTestExpectation(description: "first sync expectation") - try coordinator.sync(completion: { (synchronizer) in - firstSyncExpectation.fulfill() - }, error: handleError) + try coordinator.sync( + completion: { _ in + firstSyncExpectation.fulfill() + }, + error: handleError + ) wait(for: [firstSyncExpectation], timeout: 20) let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() @@ -121,23 +136,24 @@ class RewindRescanTests: XCTestCase { // rewind to birthday let targetHeight: BlockHeight = newChaintTip - 8000 - let rewindHeight = ZcashRustBackend.getNearestRewindHeight(dbData: coordinator.databases.dataDB, height: Int32(targetHeight), networkType: network.networkType) + let rewindHeight = ZcashRustBackend.getNearestRewindHeight( + dbData: coordinator.databases.dataDB, + height: Int32(targetHeight), + networkType: network.networkType + ) try coordinator.synchronizer.rewind(.height(blockheight: targetHeight)) - guard rewindHeight > 0 else { XCTFail("get nearest height failed error: \(ZcashRustBackend.getLastError() ?? "null")") return } - // assert that after the new height is -// XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(), BlockHeight(rewindHeight)) - + // check that the balance is cleared XCTAssertEqual(initialVerifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance()) let secondScanExpectation = XCTestExpectation(description: "rescan") - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { _ in secondScanExpectation.fulfill() }, error: handleError) @@ -149,7 +165,13 @@ class RewindRescanTests: XCTestCase { // try to spend the funds let sendExpectation = XCTestExpectation(description: "after rewind expectation") - coordinator.synchronizer.sendToAddress(spendingKey: coordinator.spendingKey, zatoshi: 1000, toAddress: testRecipientAddress, memo: nil, from: 0) { result in + coordinator.synchronizer.sendToAddress( + spendingKey: coordinator.spendingKey, + zatoshi: 1000, + toAddress: testRecipientAddress, + memo: nil, + from: 0 + ) { result in sendExpectation.fulfill() switch result { case .success(let pendingTx): @@ -159,9 +181,6 @@ class RewindRescanTests: XCTestCase { } } wait(for: [sendExpectation], timeout: 15) - - - } func testRescanToTransaction() throws { @@ -173,7 +192,7 @@ class RewindRescanTests: XCTestCase { sleep(1) let firstSyncExpectation = XCTestExpectation(description: "first sync expectation") - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: handleError) @@ -191,14 +210,16 @@ class RewindRescanTests: XCTestCase { } try coordinator.synchronizer.rewind(.transaction(transaction.transactionEntity)) - // assert that after the new height is - XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(),transaction.transactionEntity.anchor(network: network)) + XCTAssertEqual( + try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(), + transaction.transactionEntity.anchor(network: network) + ) let secondScanExpectation = XCTestExpectation(description: "rescan") - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { _ in secondScanExpectation.fulfill() }, error: handleError) @@ -207,7 +228,6 @@ class RewindRescanTests: XCTestCase { // verify that the balance still adds up XCTAssertEqual(verifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance()) XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance()) - } func testRewindAfterSendingTransaction() throws { @@ -225,7 +245,7 @@ class RewindRescanTests: XCTestCase { sleep(1) let firstSyncExpectation = XCTestExpectation(description: "first sync expectation") - try coordinator.sync(completion: { (synchronizer) in + try coordinator.sync(completion: { _ in firstSyncExpectation.fulfill() }, error: handleError) @@ -246,11 +266,13 @@ 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 + 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)") @@ -265,14 +287,13 @@ class RewindRescanTests: XCTestCase { return } - notificationHandler.synchronizerMinedTransaction = { tx in - XCTAssertNotNil(tx.rawTransactionId) + notificationHandler.synchronizerMinedTransaction = { transaction in + XCTAssertNotNil(transaction.rawTransactionId) XCTAssertNotNil(pendingTx.rawTransactionId) - XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId) + XCTAssertEqual(transaction.rawTransactionId, pendingTx.rawTransactionId) transactionMinedExpectation.fulfill() } - // 5 apply to height // 6 mine the block guard let rawTx = try coordinator.getIncomingTransactions()?.first else { @@ -284,7 +305,7 @@ class RewindRescanTests: XCTestCase { let sentTxHeight = latestHeight + 1 notificationHandler.transactionsFound = { txs in - let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId}) + let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) XCTAssertNotNil(foundTx) XCTAssertEqual(foundTx?.minedHeight, sentTxHeight) @@ -296,24 +317,26 @@ class RewindRescanTests: XCTestCase { try coordinator.applyStaged(blockheight: sentTxHeight) sleep(2) - let mineExpectation = XCTestExpectation(description: "mineTxExpectation") - try coordinator.sync(completion: { (synchronizer) in - let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId}) - XCTAssertNotNil(p, "pending transaction should have been mined by now") - XCTAssertTrue(p?.isMined ?? false) - XCTAssertEqual(p?.minedHeight, sentTxHeight) - mineExpectation.fulfill() + 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 + } - }, error: { (error) in - guard let e = error else { - XCTFail("unknown error syncing after sending transaction") - return + XCTFail("Error: \(e)") } - - XCTFail("Error: \(e)") - }) + ) wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5) @@ -327,36 +350,45 @@ class RewindRescanTests: XCTestCase { try coordinator.synchronizer.rewind(.height(blockheight: sentTxHeight - 5)) - guard let np = try coordinator.synchronizer.allPendingTransactions().first(where: { $0.rawTransactionId == pendingTx.rawTransactionId}) else { + guard + let pendingEntity = try coordinator.synchronizer.allPendingTransactions() + .first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) + else { XCTFail("sent pending transaction not found after rewind") return } - XCTAssertFalse(np.isMined) + XCTAssertFalse(pendingEntity.isMined) + let confirmExpectation = XCTestExpectation(description: "confirm expectation") notificationHandler.transactionsFound = { txs in XCTAssertEqual(txs.count, 1) - guard let t = txs.first else { + guard let transaction = txs.first else { XCTFail("should have found sent transaction but didn't") return } - XCTAssertEqual(t.rawTransactionId, pendingTx.rawTransactionId,"should have mined sent transaction but didn't") + XCTAssertEqual(transaction.rawTransactionId, pendingTx.rawTransactionId, "should have mined sent transaction but didn't") } - notificationHandler.synchronizerMinedTransaction = { tx in - XCTFail("We shouldn't find any mined transactions at this point but found \(tx)") + + notificationHandler.synchronizerMinedTransaction = { transaction in + XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)") } - try coordinator.sync(completion: { synchronizer in - confirmExpectation.fulfill() - }, error: { e in - self.handleError(e) - }) + + try coordinator.sync( + completion: { _ in + confirmExpectation.fulfill() + }, + error: { e in + self.handleError(e) + } + ) wait(for: [confirmExpectation], timeout: 10) - let confirmedPending = try coordinator.synchronizer.allPendingTransactions().first(where: { $0.rawTransactionId == pendingTx.rawTransactionId}) + let confirmedPending = try coordinator.synchronizer.allPendingTransactions() + .first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) XCTAssertNil(confirmedPending, "pending, now confirmed transaction found") - XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), 0) XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 0) } diff --git a/ZcashLightClientKitTests/SychronizerDarksideTests.swift b/ZcashLightClientKitTests/SychronizerDarksideTests.swift index bcd7e5b4..febf7e63 100644 --- a/ZcashLightClientKitTests/SychronizerDarksideTests.swift +++ b/ZcashLightClientKitTests/SychronizerDarksideTests.swift @@ -7,26 +7,32 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable implicitly_unwrapped_optional class SychronizerDarksideTests: XCTestCase { - var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment? - - let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment - + // TODO: Parameterize this from environment? + // swiftlint:disable:next line_length + let seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" + + // TODO: Parameterize this from environment + let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" let sendAmount: Int64 = 1000 - var birthday: BlockHeight = 663150 let defaultLatestHeight: BlockHeight = 663175 + let branchID = "2bb40e60" + let chainName = "main" + let network = DarksideWalletDNetwork() + + var birthday: BlockHeight = 663150 var coordinator: TestCoordinator! var syncedExpectation = XCTestExpectation(description: "synced") var sentTransactionExpectation = XCTestExpectation(description: "sent") var expectedReorgHeight: BlockHeight = 665188 var expectedRewindHeight: BlockHeight = 665188 - var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg") - let branchID = "2bb40e60" - let chainName = "main" - let network = DarksideWalletDNetwork() - var foundTransactions = [ConfirmedTransactionEntity]() + var reorgExpectation = XCTestExpectation(description: "reorg") + var foundTransactions: [ConfirmedTransactionEntity] = [] + override func setUpWithError() throws { - + try super.setUpWithError() coordinator = try TestCoordinator( seed: seedPhrase, walletBirthday: birthday, @@ -37,6 +43,7 @@ class SychronizerDarksideTests: XCTestCase { } override func tearDownWithError() throws { + try super.tearDownWithError() NotificationCenter.default.removeObserver(self) try coordinator.stop() try? FileManager.default.removeItem(at: coordinator.databases.cacheDB) @@ -45,20 +52,22 @@ class SychronizerDarksideTests: XCTestCase { } func testFoundTransactions() throws { - NotificationCenter.default.addObserver(self, selector: #selector(handleFoundTransactions(_:)), name: Notification.Name.synchronizerFoundTransactions, object: nil) + NotificationCenter.default.addObserver( + self, + selector: #selector(handleFoundTransactions(_:)), + name: Notification.Name.synchronizerFoundTransactions, + object: nil + ) try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName) let receivedTxHeight: BlockHeight = 663188 - try coordinator.applyStaged(blockheight: receivedTxHeight + 1) sleep(2) let preTxExpectation = XCTestExpectation(description: "pre receive") - - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in preTxExpectation.fulfill() }, error: self.handleError) @@ -68,20 +77,22 @@ class SychronizerDarksideTests: XCTestCase { } func testFoundManyTransactions() throws { - NotificationCenter.default.addObserver(self, selector: #selector(handleFoundTransactions(_:)), name: Notification.Name.synchronizerFoundTransactions, object: nil) + NotificationCenter.default.addObserver( + self, + selector: #selector(handleFoundTransactions(_:)), + name: Notification.Name.synchronizerFoundTransactions, + object: nil + ) - try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName,length: 1000) + try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName, length: 1000) let receivedTxHeight: BlockHeight = 663229 - try coordinator.applyStaged(blockheight: receivedTxHeight + 1) sleep(2) let firsTxExpectation = XCTestExpectation(description: "first sync") - - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in firsTxExpectation.fulfill() }, error: self.handleError) @@ -95,36 +106,34 @@ class SychronizerDarksideTests: XCTestCase { sleep(2) let preTxExpectation = XCTestExpectation(description: "intermediate sync") - - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in preTxExpectation.fulfill() }, error: self.handleError) wait(for: [preTxExpectation], timeout: 10) - XCTAssertTrue(self.foundTransactions.count == 0) + XCTAssertTrue(self.foundTransactions.isEmpty) let findManyTxExpectation = XCTestExpectation(description: "final sync") try coordinator.applyStaged(blockheight: 664010) sleep(2) - try coordinator.sync(completion: { (synchronizer) in - + try coordinator.sync(completion: { _ in findManyTxExpectation.fulfill() }, error: self.handleError) wait(for: [findManyTxExpectation], timeout: 10) XCTAssertEqual(self.foundTransactions.count, 2) - } @objc func handleFoundTransactions(_ notification: Notification) { - guard let userInfo = notification.userInfo, - let transactions = userInfo[SDKSynchronizer.NotificationKeys.foundTransactions] as? [ConfirmedTransactionEntity] else { + guard + let userInfo = notification.userInfo, + let transactions = userInfo[SDKSynchronizer.NotificationKeys.foundTransactions] as? [ConfirmedTransactionEntity] + else { return } self.foundTransactions.append(contentsOf: transactions) diff --git a/ZcashLightClientKitTests/TestCoordinator.swift b/ZcashLightClientKitTests/TestCoordinator.swift index 4bd15675..e6aa08dd 100644 --- a/ZcashLightClientKitTests/TestCoordinator.swift +++ b/ZcashLightClientKitTests/TestCoordinator.swift @@ -9,13 +9,13 @@ import Foundation @testable import ZcashLightClientKit /** - This is the TestCoordinator - What does it do? quite a lot. - Is it a nice "SOLID" "Clean Code" piece of source code? - Hell no. It's your testing overlord and you will be grateful it is. - */ +This is the TestCoordinator +What does it do? quite a lot. +Is it a nice "SOLID" "Clean Code" piece of source code? +Hell no. It's your testing overlord and you will be grateful it is. +*/ +// swiftlint:disable force_try function_parameter_count class TestCoordinator { - enum CoordinatorError: Error { case notDarksideWallet case notificationFromUnknownSynchronizer @@ -44,22 +44,43 @@ class TestCoordinator { var spendingKeys: [String]? var databases: TemporaryTestDatabases let network: ZcashNetwork - convenience init(seed: String, - walletBirthday: BlockHeight, - channelProvider: ChannelProvider, - network: ZcashNetwork) throws { + convenience init( + seed: String, + walletBirthday: BlockHeight, + channelProvider: ChannelProvider, + network: ZcashNetwork + ) throws { let derivationTool = DerivationTool(networkType: network.networkType) - guard let spendingKey = try derivationTool.deriveSpendingKeys( - seed: TestSeed().seed(), - numberOfAccounts: 1).first else { + + guard + let spendingKey = try derivationTool + .deriveSpendingKeys( + seed: TestSeed().seed(), + numberOfAccounts: 1 + ) + .first + else { throw CoordinatorError.builderError } - guard let uvk = try derivationTool.deriveUnifiedViewingKeysFromSeed(TestSeed().seed(), numberOfAccounts: 1).first else { + guard + let uvk = try derivationTool + .deriveUnifiedViewingKeysFromSeed( + TestSeed().seed(), + numberOfAccounts: 1 + ) + .first + else { throw CoordinatorError.builderError } - try self.init(spendingKey: spendingKey, unifiedViewingKey: uvk, walletBirthday: walletBirthday, channelProvider: channelProvider, network: network) + try self.init( + spendingKey: spendingKey, + unifiedViewingKey: uvk, + walletBirthday: walletBirthday, + channelProvider: channelProvider, + network: network + ) } required init( @@ -67,35 +88,47 @@ class TestCoordinator { unifiedViewingKey: UnifiedViewingKey, walletBirthday: BlockHeight, channelProvider: ChannelProvider, - network: ZcashNetwork) throws { + network: ZcashNetwork + ) throws { self.spendingKey = spendingKey self.birthday = walletBirthday self.channelProvider = channelProvider self.databases = TemporaryDbBuilder.build() self.network = network - self.service = DarksideWalletService(service: LightWalletGRPCService(host: Constants.address, port: 9067, secure: false, singleCallTimeout: 10000, streamingCallTimeout: 1000000)) + self.service = DarksideWalletService( + service: LightWalletGRPCService( + host: Constants.address, + port: 9067, + secure: false, + singleCallTimeout: 10000, + streamingCallTimeout: 1000000 + ) + ) let storage = CompactBlockStorage(url: databases.cacheDB, readonly: false) try storage.createTable() let buildResult = try TestSynchronizerBuilder.build( - rustBackend: ZcashRustBackend.self, - lowerBoundHeight: self.birthday, - cacheDbURL: databases.cacheDB, - dataDbURL: databases.dataDB, - pendingDbURL: databases.pendingDB, - endpoint: LightWalletEndpointBuilder.default, - service: self.service, - repository: TransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: databases.dataDB.absoluteString)), - accountRepository: AccountRepositoryBuilder.build(dataDbURL: databases.dataDB, - readOnly: true), - storage: storage, - spendParamsURL: try __spendParamsURL(), - outputParamsURL: try __outputParamsURL(), - spendingKey: spendingKey, - unifiedViewingKey: unifiedViewingKey, - walletBirthday: WalletBirthday.birthday(with: birthday, network: network), - network: network, - loggerProxy: SampleLogger(logLevel: .debug)) + rustBackend: ZcashRustBackend.self, + lowerBoundHeight: self.birthday, + cacheDbURL: databases.cacheDB, + dataDbURL: databases.dataDB, + pendingDbURL: databases.pendingDB, + endpoint: LightWalletEndpointBuilder.default, + service: self.service, + repository: TransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: databases.dataDB.absoluteString)), + accountRepository: AccountRepositoryBuilder.build( + dataDbURL: databases.dataDB, + readOnly: true + ), + storage: storage, + spendParamsURL: try __spendParamsURL(), + outputParamsURL: try __outputParamsURL(), + spendingKey: spendingKey, + unifiedViewingKey: unifiedViewingKey, + walletBirthday: WalletBirthday.birthday(with: birthday, network: network), + network: network, + loggerProxy: SampleLogger(logLevel: .debug) + ) self.synchronizer = buildResult.synchronizer self.spendingKeys = buildResult.spendingKeys @@ -114,7 +147,7 @@ class TestCoordinator { try service.useDataset(DarksideDataset.beforeReOrg.rawValue) case .predefined(let dataset): try service.useDataset(dataset.rawValue) - case .url(let urlString,_): + case .url(let urlString, _): try service.useDataset(from: urlString) } } @@ -130,15 +163,12 @@ class TestCoordinator { try synchronizer.start(retry: true) } - /** - Notifications - */ + Notifications + */ func subscribeToNotifications(synchronizer: Synchronizer) { - NotificationCenter.default.addObserver(self, selector: #selector(synchronizerFailed(_:)), name: .synchronizerFailed, object: synchronizer) NotificationCenter.default.addObserver(self, selector: #selector(synchronizerSynced(_:)), name: .synchronizerSynced, object: synchronizer) - } @objc func synchronizerFailed(_ notification: Notification) { @@ -172,13 +202,12 @@ class TestCoordinator { extension TestCoordinator { func resetBlocks(dataset: DarksideData) throws { - switch dataset { case .default: try service.useDataset(DarksideDataset.beforeReOrg.rawValue) case .predefined(let blocks): try service.useDataset(blocks.rawValue) - case .url(let urlString,_): + case .url(let urlString, _): try service.useDataset(urlString) } } @@ -191,8 +220,8 @@ extension TestCoordinator { try service.applyStaged(nextLatestHeight: blockheight) } - func stageTransaction(_ tx: RawTransaction, at height: BlockHeight) throws { - try service.stageTransaction(tx, at: height) + func stageTransaction(_ transaction: RawTransaction, at height: BlockHeight) throws { + try service.stageTransaction(transaction, at: height) } func stageTransaction(url: String, at height: BlockHeight) throws { @@ -206,17 +235,17 @@ extension TestCoordinator { func reset(saplingActivation: BlockHeight, branchID: String, chainName: String) throws { let config = self.synchronizer.blockProcessor.config - self.synchronizer.blockProcessor.config = CompactBlockProcessor.Configuration( - cacheDb: config.cacheDb, - dataDb: config.dataDb, - downloadBatchSize: config.downloadBatchSize, - retries: config.retries, - maxBackoffInterval: config.maxBackoffInterval, - rewindDistance: config.rewindDistance, - walletBirthday: config.walletBirthday, - saplingActivation: config.saplingActivation, - network: config.network) + cacheDb: config.cacheDb, + dataDb: config.dataDb, + downloadBatchSize: config.downloadBatchSize, + retries: config.retries, + maxBackoffInterval: config.maxBackoffInterval, + rewindDistance: config.rewindDistance, + walletBirthday: config.walletBirthday, + saplingActivation: config.saplingActivation, + network: config.network + ) try service.reset(saplingActivation: saplingActivation, branchID: branchID, chainName: chainName) } @@ -226,24 +255,25 @@ extension TestCoordinator { } struct TemporaryTestDatabases { - var cacheDB: URL - var dataDB: URL - var pendingDB: URL + var cacheDB: URL + var dataDB: URL + var pendingDB: URL } -class TemporaryDbBuilder { - +enum TemporaryDbBuilder { static func build() -> TemporaryTestDatabases { let tempUrl = try! __documentsDirectory() let timestamp = String(Int(Date().timeIntervalSince1970)) - return TemporaryTestDatabases(cacheDB: tempUrl.appendingPathComponent("cache_db_\(timestamp).db"), - dataDB: tempUrl.appendingPathComponent("data_db_\(timestamp).db"), - pendingDB: tempUrl.appendingPathComponent("pending_db_\(timestamp).db")) + return TemporaryTestDatabases( + cacheDB: tempUrl.appendingPathComponent("cache_db_\(timestamp).db"), + dataDB: tempUrl.appendingPathComponent("data_db_\(timestamp).db"), + pendingDB: tempUrl.appendingPathComponent("pending_db_\(timestamp).db") + ) } } -class TestSynchronizerBuilder { +enum TestSynchronizerBuilder { static func build( rustBackend: ZcashRustBackendWelding.Type, lowerBoundHeight: BlockHeight, @@ -262,7 +292,7 @@ class TestSynchronizerBuilder { walletBirthday: WalletBirthday, network: ZcashNetwork, loggerProxy: Logger? = nil - ) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) { + ) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) { let initializer = Initializer( rustBackend: rustBackend, lowerBoundHeight: lowerBoundHeight, @@ -281,37 +311,42 @@ class TestSynchronizerBuilder { walletBirthday: walletBirthday.height, loggerProxy: loggerProxy ) + let config = CompactBlockProcessor.Configuration( - cacheDb: initializer.cacheDbURL, - dataDb: initializer.dataDbURL, - downloadBatchSize: 100, - retries: 5, - maxBackoffInterval: ZcashSDK.defaultMaxBackOffInterval, - rewindDistance: ZcashSDK.defaultRewindDistance, - walletBirthday: walletBirthday.height, - saplingActivation: lowerBoundHeight, - network: network) + cacheDb: initializer.cacheDbURL, + dataDb: initializer.dataDbURL, + downloadBatchSize: 100, + retries: 5, + maxBackoffInterval: ZcashSDK.defaultMaxBackOffInterval, + rewindDistance: ZcashSDK.defaultRewindDistance, + walletBirthday: walletBirthday.height, + saplingActivation: lowerBoundHeight, + network: network + ) - let processor = CompactBlockProcessor(service: service, - storage: storage, - backend: rustBackend, - config: config, - repository: repository, - accountRepository: accountRepository) + let processor = CompactBlockProcessor( + service: service, + storage: storage, + backend: rustBackend, + config: config, + repository: repository, + accountRepository: accountRepository + ) - - let synchronizer = try SDKSynchronizer(status: .unprepared, - initializer: initializer, - transactionManager: OutboundTransactionManagerBuilder.build(initializer: initializer), - transactionRepository: repository, - utxoRepository: UTXORepositoryBuilder.build(initializer: initializer), - blockProcessor: processor - ) - + let synchronizer = try SDKSynchronizer( + status: .unprepared, + initializer: initializer, + transactionManager: OutboundTransactionManagerBuilder.build(initializer: initializer), + transactionRepository: repository, + utxoRepository: UTXORepositoryBuilder.build(initializer: initializer), + blockProcessor: processor + ) + try synchronizer.prepare() return ([spendingKey], synchronizer) } + static func build( rustBackend: ZcashRustBackendWelding.Type, lowerBoundHeight: BlockHeight, @@ -330,14 +365,23 @@ class TestSynchronizerBuilder { network: ZcashNetwork, loggerProxy: Logger? = nil ) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) { - guard let spendingKey = try DerivationTool(networkType: network.networkType).deriveSpendingKeys(seed: seedBytes, numberOfAccounts: 1).first else { + guard + let spendingKey = try DerivationTool(networkType: network.networkType) + .deriveSpendingKeys(seed: seedBytes, numberOfAccounts: 1) + .first + else { throw TestCoordinator.CoordinatorError.builderError } - guard let uvk = try DerivationTool(networkType: network.networkType).deriveUnifiedViewingKeysFromSeed(seedBytes, numberOfAccounts: 1).first else { + guard let uvk = try DerivationTool(networkType: network.networkType) + .deriveUnifiedViewingKeysFromSeed(seedBytes, numberOfAccounts: 1) + .first + else { throw TestCoordinator.CoordinatorError.builderError } - return try build(rustBackend: rustBackend, + + return try build( + rustBackend: rustBackend, lowerBoundHeight: lowerBoundHeight, cacheDbURL: cacheDbURL, dataDbURL: dataDbURL, @@ -352,8 +396,7 @@ class TestSynchronizerBuilder { spendingKey: spendingKey, unifiedViewingKey: uvk, walletBirthday: walletBirthday, - network: network) - + network: network + ) } } - diff --git a/ZcashLightClientKitTests/TransactionEnhancementTests.swift b/ZcashLightClientKitTests/TransactionEnhancementTests.swift index f8c0fd83..ef79b36d 100644 --- a/ZcashLightClientKitTests/TransactionEnhancementTests.swift +++ b/ZcashLightClientKitTests/TransactionEnhancementTests.swift @@ -7,7 +7,16 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable implicitly_unwrapped_optional force_try class TransactionEnhancementTests: XCTestCase { + let mockLatestHeight = BlockHeight(663250) + let targetLatestHeight = BlockHeight(663251) + let walletBirthday = BlockHeight(663150) + let network = DarksideWalletDNetwork() + let branchID = "2bb40e60" + let chainName = "main" + var initializer: Initializer! var processorConfig: CompactBlockProcessor.Configuration! var processor: CompactBlockProcessor! @@ -23,26 +32,26 @@ class TransactionEnhancementTests: XCTestCase { var afterReorgIdleNotification: XCTestExpectation! var txFoundNotificationExpectation: XCTestExpectation! var waitExpectation: XCTestExpectation! - let mockLatestHeight = BlockHeight(663250) - let targetLatestHeight = BlockHeight(663251) - let walletBirthday = BlockHeight(663150) - let network = DarksideWalletDNetwork() - let branchID = "2bb40e60" - let chainName = "main" + override func setUpWithError() throws { + try super.setUpWithError() logger = SampleLogger(logLevel: .debug) - downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect") - stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation") - updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation") - startedValidatingNotificationExpectation = XCTestExpectation(description: self.description + " startedValidatingNotificationExpectation") - startedScanningNotificationExpectation = XCTestExpectation(description: self.description + " startedScanningNotificationExpectation") - idleNotificationExpectation = XCTestExpectation(description: self.description + " idleNotificationExpectation") - afterReorgIdleNotification = XCTestExpectation(description: self.description + " afterReorgIdleNotification") - reorgNotificationExpectation = XCTestExpectation(description: self.description + " reorgNotificationExpectation") - txFoundNotificationExpectation = XCTestExpectation(description: self.description + "txFoundNotificationExpectation") + downloadStartedExpect = XCTestExpectation(description: "\(self.description) downloadStartedExpect") + stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation") + updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation") + startedValidatingNotificationExpectation = XCTestExpectation( + description: "\(self.description) startedValidatingNotificationExpectation" + ) + startedScanningNotificationExpectation = XCTestExpectation( + description: "\(self.description) startedScanningNotificationExpectation" + ) + idleNotificationExpectation = XCTestExpectation(description: "\(self.description) idleNotificationExpectation") + afterReorgIdleNotification = XCTestExpectation(description: "\(self.description) afterReorgIdleNotification") + reorgNotificationExpectation = XCTestExpectation(description: "\(self.description) reorgNotificationExpectation") + txFoundNotificationExpectation = XCTestExpectation(description: "\(self.description) txFoundNotificationExpectation") - waitExpectation = XCTestExpectation(description: self.description + "waitExpectation") + waitExpectation = XCTestExpectation(description: "\(self.description) waitExpectation") let birthday = WalletBirthday.birthday(with: walletBirthday, network: network) @@ -50,14 +59,19 @@ class TransactionEnhancementTests: XCTestCase { let rustBackend = ZcashRustBackend.self processorConfig = config - - try? FileManager.default.removeItem(at: processorConfig.cacheDb) try? FileManager.default.removeItem(at: processorConfig.dataDb) - _ = rustBackend.initAccountsTable(dbData: processorConfig.dataDb, seed: TestSeed().seed(), accounts: 1,networkType: network.networkType) + _ = rustBackend.initAccountsTable(dbData: processorConfig.dataDb, seed: TestSeed().seed(), accounts: 1, networkType: network.networkType) _ = try rustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: network.networkType) - _ = try rustBackend.initBlocksTable(dbData: processorConfig.dataDb, height: Int32(birthday.height), hash: birthday.hash, time: birthday.time, saplingTree: birthday.tree, networkType: network.networkType) + _ = try rustBackend.initBlocksTable( + dbData: processorConfig.dataDb, + height: Int32(birthday.height), + hash: birthday.hash, + time: birthday.time, + saplingTree: birthday.tree, + networkType: network.networkType + ) let service = DarksideWalletService() darksideWalletService = service @@ -65,17 +79,23 @@ class TransactionEnhancementTests: XCTestCase { try! storage.createTable() downloader = CompactBlockDownloader(service: service, storage: storage) - processor = CompactBlockProcessor(service: service, - storage: storage, - backend: rustBackend, - config: processorConfig) + processor = CompactBlockProcessor( + service: service, + storage: storage, + backend: rustBackend, + config: processorConfig + ) - - - NotificationCenter.default.addObserver(self, selector: #selector(processorFailed(_:)), name: Notification.Name.blockProcessorFailed, object: processor) + NotificationCenter.default.addObserver( + self, + selector: #selector(processorFailed(_:)), + name: Notification.Name.blockProcessorFailed, + object: processor + ) } override func tearDownWithError() throws { + try super.tearDownWithError() try? FileManager.default.removeItem(at: processorConfig.cacheDb) try? FileManager.default.removeItem(at: processorConfig.dataDb) downloadStartedExpect.unsubscribeFromNotifications() @@ -89,7 +109,7 @@ class TransactionEnhancementTests: XCTestCase { NotificationCenter.default.removeObserver(self) } - fileprivate func startProcessing() throws { + private func startProcessing() throws { XCTAssertNotNil(processor) // Subscribe to notifications @@ -98,13 +118,11 @@ class TransactionEnhancementTests: XCTestCase { updatedNotificationExpectation.subscribe(to: Notification.Name.blockProcessorUpdated, object: processor) startedValidatingNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedValidating, object: processor) startedScanningNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedScanning, object: processor) - try processor.start() } func testBasicEnhacement() throws { - let targetLatestHeight = BlockHeight(663250) let walletBirthday = WalletBirthday.birthday(with: 663151, network: network).height @@ -112,47 +130,48 @@ class TransactionEnhancementTests: XCTestCase { } func basicEnhancementTest(latestHeight: BlockHeight, walletBirthday: BlockHeight) throws { - do { try darksideWalletService.reset(saplingActivation: 663150, branchID: branchID, chainName: chainName) try darksideWalletService.useDataset(DarksideDataset.beforeReOrg.rawValue) try darksideWalletService.applyStaged(nextLatestHeight: 663200) - } catch { + } catch { XCTFail("Error: \(error)") return } sleep(3) + /** - connect to dLWD - request latest height -> receive firstLatestHeight - */ + connect to dLWD + request latest height -> receive firstLatestHeight + */ do { - print("first latest height: \(try darksideWalletService.latestBlockHeight())") + dump("first latest height: \(try darksideWalletService.latestBlockHeight())") } catch { XCTFail("Error: \(error)") return } - /** - download and sync blocks from walletBirthday to firstLatestHeight - */ + download and sync blocks from walletBirthday to firstLatestHeight + */ do { - try startProcessing() - } catch { XCTFail("Error: \(error)") } - - wait(for: [downloadStartedExpect, - startedValidatingNotificationExpectation, - startedScanningNotificationExpectation, - txFoundNotificationExpectation, - idleNotificationExpectation], timeout: 30) - idleNotificationExpectation.unsubscribeFromNotifications() + wait( + for: [ + downloadStartedExpect, + startedValidatingNotificationExpectation, + startedScanningNotificationExpectation, + txFoundNotificationExpectation, + idleNotificationExpectation + ], + timeout: 30 + ) + idleNotificationExpectation.unsubscribeFromNotifications() } @objc func processorFailed(_ notification: Notification) { @@ -163,6 +182,4 @@ class TransactionEnhancementTests: XCTestCase { XCTFail("CompactBlockProcessor failed") } } - } - diff --git a/ZcashLightClientKitTests/TransactionRepositoryTests.swift b/ZcashLightClientKitTests/TransactionRepositoryTests.swift index 22736856..e8897cb2 100644 --- a/ZcashLightClientKitTests/TransactionRepositoryTests.swift +++ b/ZcashLightClientKitTests/TransactionRepositoryTests.swift @@ -7,37 +7,39 @@ import XCTest @testable import ZcashLightClientKit + +// swiftlint:disable implicitly_unwrapped_optional force_unwrapping class TransactionRepositoryTests: XCTestCase { - var transactionRepository: TransactionRepository! override func setUp() { + super.setUp() transactionRepository = TestDbBuilder.transactionRepository() } override func tearDown() { + super.tearDown() transactionRepository = nil } func testCount() { var count: Int? - XCTAssertNoThrow(try { count = try self.transactionRepository.countAll()}()) + XCTAssertNoThrow(try { count = try self.transactionRepository.countAll() }()) XCTAssertNotNil(count) XCTAssertEqual(count, 27) - } func testCountUnmined() { var count: Int? - XCTAssertNoThrow(try { count = try self.transactionRepository.countUnmined()}()) + XCTAssertNoThrow(try { count = try self.transactionRepository.countUnmined() }()) XCTAssertNotNil(count) XCTAssertEqual(count, 0) } func testFindById() { - var tx: TransactionEntity? - XCTAssertNoThrow(try { tx = try self.transactionRepository.findBy(id: 10)}()) - guard let transaction = tx else { + var transaction: TransactionEntity? + XCTAssertNoThrow(try { transaction = try self.transactionRepository.findBy(id: 10) }()) + guard let transaction = transaction else { XCTFail("transaction is nil") return } @@ -45,16 +47,18 @@ class TransactionRepositoryTests: XCTestCase { XCTAssertEqual(transaction.id, 10) XCTAssertEqual(transaction.minedHeight, 652812) XCTAssertEqual(transaction.transactionIndex, 5) - } func testFindByTxId() { - var tx: TransactionEntity? + var transaction: TransactionEntity? let id = Data(fromHexEncodedString: "0BAFC5B83F5B39A5270144ECD98DBC65115055927EDDA8FF20F081FFF13E4780")! - XCTAssertNoThrow(try { tx = try self.transactionRepository.findBy(rawId: id)}()) - guard let transaction = tx else { + XCTAssertNoThrow( + try { transaction = try self.transactionRepository.findBy(rawId: id) }() + ) + + guard let transaction = transaction else { XCTFail("transaction is nil") return } @@ -111,16 +115,17 @@ class TransactionRepositoryTests: XCTestCase { } func testFindAllFrom() throws { - guard let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max), - let allFromNil = try self.transactionRepository.findAll(from: nil, limit: Int.max) + guard + let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max), + let allFromNil = try self.transactionRepository.findAll(from: nil, limit: Int.max) else { return XCTFail("find all failed") } XCTAssertEqual(transactions.count, allFromNil.count) - for t in transactions { - guard allFromNil.first(where: { $0.rawTransactionId == t.rawTransactionId}) != nil else { + for transaction in transactions { + guard allFromNil.first(where: { $0.rawTransactionId == transaction.rawTransactionId }) != nil else { XCTFail("not equal") return } @@ -128,11 +133,11 @@ class TransactionRepositoryTests: XCTestCase { } func testFindAllFromSlice() throws { - let limit = 4 let start = 7 - guard let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max), - let allFromNil = try self.transactionRepository.findAll(from: transactions[start], limit: limit) + guard + let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max), + let allFromNil = try self.transactionRepository.findAll(from: transactions[start], limit: limit) else { return XCTFail("find all failed") } @@ -141,29 +146,28 @@ class TransactionRepositoryTests: XCTestCase { let slice = transactions[start + 1 ... start + limit] XCTAssertEqual(slice.count, allFromNil.count) - for t in slice { - guard allFromNil.first(where: { $0.rawTransactionId == t.rawTransactionId}) != nil else { + for transaction in slice { + guard allFromNil.first(where: { $0.rawTransactionId == transaction.rawTransactionId }) != nil else { XCTFail("not equal") return } } } - func testFindAllFromLastSlice() throws { - let limit = 10 let start = 20 - guard let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max), - let allFromNil = try self.transactionRepository.findAll(from: transactions[start], limit: limit) + guard + let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max), + let allFromNil = try self.transactionRepository.findAll(from: transactions[start], limit: limit) else { return XCTFail("find all failed") } let slice = transactions[start + 1 ..< transactions.count] XCTAssertEqual(slice.count, allFromNil.count) - for t in slice { - guard allFromNil.first(where: { $0.rawTransactionId == t.rawTransactionId}) != nil else { + for transaction in slice { + guard allFromNil.first(where: { $0.rawTransactionId == transaction.rawTransactionId }) != nil else { XCTFail("not equal") return } @@ -172,36 +176,34 @@ class TransactionRepositoryTests: XCTestCase { } extension Data { - init?(fromHexEncodedString string: String) { - // Convert 0 ... 9, a ... f, A ...F to their decimal value, // return nil for all other input characters - func decodeNibble(u: UInt16) -> UInt8? { - switch(u) { + func decodeNibble(bytes: UInt16) -> UInt8? { + switch bytes { case 0x30 ... 0x39: - return UInt8(u - 0x30) + return UInt8(bytes - 0x30) case 0x41 ... 0x46: - return UInt8(u - 0x41 + 10) + return UInt8(bytes - 0x41 + 10) case 0x61 ... 0x66: - return UInt8(u - 0x61 + 10) + return UInt8(bytes - 0x61 + 10) default: return nil } } - self.init(capacity: string.utf16.count/2) + self.init(capacity: string.utf16.count / 2) var even = true var byte: UInt8 = 0 - for c in string.utf16 { - guard let val = decodeNibble(u: c) else { return nil } + for char in string.utf16 { + guard let val = decodeNibble(bytes: char) else { return nil } if even { byte = val << 4 } else { byte += val self.append(byte) } - even = !even + even.toggle() } guard even else { return nil } } diff --git a/ZcashLightClientKitTests/TxIdTests.swift b/ZcashLightClientKitTests/TxIdTests.swift index 814c522b..f28f50a8 100644 --- a/ZcashLightClientKitTests/TxIdTests.swift +++ b/ZcashLightClientKitTests/TxIdTests.swift @@ -7,13 +7,12 @@ import XCTest +// swiftlint:disable force_unwrapping class TxIdTests: XCTestCase { - func testTxIdAsString() { let transactionId = "5cf915c5d01007c39d602e08ab59d98aba366e2fb7ac01f2cdad4bf4f8f300bb" let expectedTxIdString = "bb00f3f8f44badcdf201acb72f6e36ba8ad959ab082e609dc30710d0c515f95c" XCTAssertEqual(Data(fromHexEncodedString: transactionId)!.toHexStringTxId(), expectedTxIdString) } - } diff --git a/ZcashLightClientKitTests/WalletTests.swift b/ZcashLightClientKitTests/WalletTests.swift index 29712a59..6676ded7 100644 --- a/ZcashLightClientKitTests/WalletTests.swift +++ b/ZcashLightClientKitTests/WalletTests.swift @@ -10,41 +10,42 @@ import Foundation import XCTest @testable import ZcashLightClientKit +// swiftlint:disable implicitly_unwrapped_optional force_try force_unwrapping class WalletTests: XCTestCase { - var dbData: URL! = nil var paramDestination: URL! = nil var cacheData: URL! = nil var network = ZcashNetworkBuilder.network(for: .testnet) - var seedData: Data = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")! + var seedData = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")! + override func setUp() { - + super.setUp() dbData = try! __dataDbURL() cacheData = try! __cacheDbURL() paramDestination = try! __documentsDirectory().appendingPathComponent("parameters") } override func tearDown() { + super.tearDown() if FileManager.default.fileExists(atPath: dbData.absoluteString) { - try! FileManager.default.trashItem(at: dbData, resultingItemURL: nil) + try! FileManager.default.trashItem(at: dbData, resultingItemURL: nil) } } func testWalletInitialization() throws { - let derivationTool = DerivationTool(networkType: network.networkType) let uvk = try derivationTool.deriveUnifiedViewingKeysFromSeed(seedData.bytes, numberOfAccounts: 1) - let wallet = Initializer(cacheDbURL: try __cacheDbURL(), - dataDbURL: try __dataDbURL(), - pendingDbURL: try TestDbBuilder.pendingTransactionsDbURL(), - endpoint: LightWalletEndpointBuilder.default, - network: network, - spendParamsURL: try __spendParamsURL(), - outputParamsURL: try __outputParamsURL(), - viewingKeys: uvk, - walletBirthday: 663194) - - + let wallet = Initializer( + cacheDbURL: try __cacheDbURL(), + dataDbURL: try __dataDbURL(), + pendingDbURL: try TestDbBuilder.pendingTransactionsDbURL(), + endpoint: LightWalletEndpointBuilder.default, + network: network, + spendParamsURL: try __spendParamsURL(), + outputParamsURL: try __outputParamsURL(), + viewingKeys: uvk, + walletBirthday: 663194 + ) let synchronizer = try SDKSynchronizer(initializer: wallet) XCTAssertNoThrow(try synchronizer.prepare()) @@ -56,7 +57,7 @@ class WalletTests: XCTestCase { } } -struct WalletBirthdayProvider { +enum WalletBirthdayProvider { static var testBirthday: WalletBirthday { WalletBirthday() } diff --git a/ZcashLightClientKitTests/Z2TReceiveTests.swift b/ZcashLightClientKitTests/Z2TReceiveTests.swift index e427859b..6a8fbdf7 100644 --- a/ZcashLightClientKitTests/Z2TReceiveTests.swift +++ b/ZcashLightClientKitTests/Z2TReceiveTests.swift @@ -7,11 +7,13 @@ import XCTest @testable import ZcashLightClientKit -class Z2TReceiveTests: XCTestCase { - var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment? +// swiftlint:disable force_unwrapping implicitly_unwrapped_optional +class Z2TReceiveTests: XCTestCase { + // swiftlint:disable:next line_length + var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" // TODO: Parameterize this from environment? - let testRecipientAddress = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz" //TODO: Parameterize this from environment + let testRecipientAddress = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz" // TODO: Parameterize this from environment let sendAmount: Int64 = 1000 var birthday: BlockHeight = 663150 @@ -26,18 +28,23 @@ class Z2TReceiveTests: XCTestCase { let network = DarksideWalletDNetwork() override func setUpWithError() throws { - + try super.setUpWithError() + coordinator = try TestCoordinator( seed: seedPhrase, walletBirthday: birthday, channelProvider: ChannelProvider(), network: network ) + try coordinator.reset(saplingActivation: 663150, branchID: self.branchID, chainName: self.chainName) } override func tearDownWithError() throws { + try super.tearDownWithError() + NotificationCenter.default.removeObserver(self) + try coordinator.stop() try? FileManager.default.removeItem(at: coordinator.databases.cacheDB) try? FileManager.default.removeItem(at: coordinator.databases.dataDB) @@ -45,108 +52,116 @@ class Z2TReceiveTests: XCTestCase { } func subscribeToFoundTransactions() { - NotificationCenter.default.addObserver(self, selector: #selector(foundTransactions(_:)), name: .synchronizerFoundTransactions, object: nil) + NotificationCenter.default.addObserver( + self, + selector: #selector(foundTransactions(_:)), + name: .synchronizerFoundTransactions, + object: nil + ) } @objc func foundTransactions(_ notification: Notification) { - guard let transactions = notification.userInfo?[SDKSynchronizer.NotificationKeys.foundTransactions] else { + guard notification.userInfo?[SDKSynchronizer.NotificationKeys.foundTransactions] != nil else { XCTFail("found transactions notification is empty") return } self.foundTransactionsExpectation.fulfill() - } func testFoundTransactions() throws { subscribeToFoundTransactions() try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName) let receivedTxHeight: BlockHeight = 663188 - var initialTotalBalance: Int64 = -1 - + /* - 2. applyStaged(received_Tx_height) - */ + 2. applyStaged(received_Tx_height) + */ try coordinator.applyStaged(blockheight: receivedTxHeight) 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) + 3. sync up to received_Tx_height + */ + try coordinator.sync( + completion: { _ in + preTxExpectation.fulfill() + }, + error: self.handleError + ) wait(for: [preTxExpectation, foundTransactionsExpectation], timeout: 5) let sendExpectation = XCTestExpectation(description: "sendToAddress") - var p: PendingTransactionEntity? - var error: Error? = nil + var pendingEntity: PendingTransactionEntity? + var error: Error? let sendAmount: Int64 = 10000 /* - 4. create transaction - */ - coordinator.synchronizer.sendToAddress(spendingKey: coordinator.spendingKeys!.first!, zatoshi: sendAmount, toAddress: testRecipientAddress, memo: "test transaction", from: 0) { (result) in + 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): - p = pending + pendingEntity = pending case .failure(let e): error = e } sendExpectation.fulfill() } + wait(for: [sendExpectation], timeout: 12) - guard let pendingTx = p else { + guard pendingEntity != nil else { XCTFail("error sending to address. Error: \(String(describing: error))") return } /* - 5. stage 10 empty blocks - */ + 5. stage 10 empty blocks + */ try coordinator.stageBlockCreate(height: receivedTxHeight + 1, count: 10) let sentTxHeight = receivedTxHeight + 1 /* - 6. stage sent tx at sentTxHeight - */ + 6. stage sent tx at sentTxHeight + */ guard let sentTx = try coordinator.getIncomingTransactions()?.first else { XCTFail("sent transaction not present on Darksidewalletd") return } + try coordinator.stageTransaction(sentTx, at: sentTxHeight) /* - 6a. applyheight(sentTxHeight + 1 ) - */ + 6a. applyheight(sentTxHeight + 1 ) + */ try coordinator.applyStaged(blockheight: sentTxHeight + 1) sleep(2) self.foundTransactionsExpectation = XCTestExpectation(description: "inbound expectation") + /* - 7. sync to sentTxHeight + 1 - */ - + 7. sync to sentTxHeight + 1 + */ let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation") - try coordinator.sync(completion: { (s) in - - let pMinedHeight = s.pendingTransactions.first?.minedHeight + try coordinator.sync(completion: { synchronizer in + let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight XCTAssertEqual(pMinedHeight, sentTxHeight) sentTxSyncExpectation.fulfill() }, error: self.handleError) - wait(for: [sentTxSyncExpectation, foundTransactionsExpectation], timeout: 5) - - } - func handleError(_ error: Error?) { _ = try? coordinator.stop() diff --git a/ZcashLightClientKitTests/ZcashLightClientKitTests.swift b/ZcashLightClientKitTests/ZcashLightClientKitTests.swift index f336e310..eee91014 100644 --- a/ZcashLightClientKitTests/ZcashLightClientKitTests.swift +++ b/ZcashLightClientKitTests/ZcashLightClientKitTests.swift @@ -8,14 +8,13 @@ import XCTest import GRPC - @testable import ZcashLightClientKit +// swiftlint:disable implicitly_unwrapped_optional force_try force_unwrapping class ZcashLightClientKitTests: XCTestCase { - var latestBlockHeight: BlockHeight! - var service: LightWalletGRPCService! + override func setUp() { super.setUp() service = LightWalletGRPCService(endpoint: LightWalletEndpoint(address: Constants.address, port: 9067)) @@ -30,17 +29,14 @@ class ZcashLightClientKitTests: XCTestCase { } func testEnvironmentLaunch() { - let address = Constants.address XCTAssertFalse(address.isEmpty, "Your \'\(Environment.lightwalletdKey)\' key is missing from your launch environment variables") } func testService() { - // and that it has a non-zero size XCTAssert(latestBlockHeight > 0) - } func testBlockRangeServiceTilLastest() { @@ -49,11 +45,10 @@ class ZcashLightClientKitTests: XCTestCase { let startHeight = latestBlockHeight - expectedCount let endHeight = latestBlockHeight! - var blocks = [CompactBlock]() + var blocks: [CompactBlock] = [] guard let call = try? service!.blockRange(startHeight: startHeight, endHeight: endHeight, result: { blocks.append($0) count += 1 - }) else { XCTFail("failed to create getBlockRange( \(startHeight) ..<= \(endHeight)") return @@ -61,11 +56,9 @@ class ZcashLightClientKitTests: XCTestCase { _ = try! call.status.wait() XCTAssertEqual(expectedCount + 1, count) - } - } -class Environment { +enum Environment { static let lightwalletdKey = "LIGHTWALLETD_ADDRESS" } diff --git a/ZcashLightClientKitTests/ZcashRustBackendTests.swift b/ZcashLightClientKitTests/ZcashRustBackendTests.swift index 88e4ef6d..4000f3e8 100644 --- a/ZcashLightClientKitTests/ZcashRustBackendTests.swift +++ b/ZcashLightClientKitTests/ZcashRustBackendTests.swift @@ -9,23 +9,27 @@ import XCTest @testable import ZcashLightClientKit +// swiftlint:disable force_unwrapping implicitly_unwrapped_optional force_try class ZcashRustBackendTests: XCTestCase { var dbData: URL! var dataDbHandle = TestDbHandle(originalDb: TestDbBuilder.prePopulatedDataDbURL()!) var cacheDbHandle = TestDbHandle(originalDb: TestDbBuilder.prePopulatedCacheDbURL()!) - let spendingKey = "secret-extended-key-test1qvpevftsqqqqpqy52ut2vv24a2qh7nsukew7qg9pq6djfwyc3xt5vaxuenshp2hhspp9qmqvdh0gs2ljpwxders5jkwgyhgln0drjqaguaenfhehz4esdl4kwlm5t9q0l6wmzcrvcf5ed6dqzvct3e2ge7f6qdvzhp02m7sp5a0qjssrwpdh7u6tq89hl3wchuq8ljq8r8rwd6xdwh3nry9at80z7amnj3s6ah4jevnvfr08gxpws523z95g6dmn4wm6l3658kd4xcq9rc0qn" + let spendingKey = + // swiftlint:disable:next line_length + "secret-extended-key-test1qvpevftsqqqqpqy52ut2vv24a2qh7nsukew7qg9pq6djfwyc3xt5vaxuenshp2hhspp9qmqvdh0gs2ljpwxders5jkwgyhgln0drjqaguaenfhehz4esdl4kwlm5t9q0l6wmzcrvcf5ed6dqzvct3e2ge7f6qdvzhp02m7sp5a0qjssrwpdh7u6tq89hl3wchuq8ljq8r8rwd6xdwh3nry9at80z7amnj3s6ah4jevnvfr08gxpws523z95g6dmn4wm6l3658kd4xcq9rc0qn" let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6" let zpend: Int = 500_000 let networkType = NetworkType.testnet override func setUp() { + super.setUp() dbData = try! __dataDbURL() try? dataDbHandle.setUp() } override func tearDown() { - + super.tearDown() try? FileManager.default.removeItem(at: dbData!) dataDbHandle.dispose() } @@ -35,27 +39,33 @@ class ZcashRustBackendTests: XCTestCase { XCTAssertNoThrow(try ZcashRustBackend.initDataDb(dbData: dbData!, networkType: networkType)) - let _ = ZcashRustBackend.initAccountsTable(dbData: dbData!, seed: Array(seed.utf8), accounts: 1, networkType: networkType) + _ = ZcashRustBackend.initAccountsTable(dbData: dbData!, seed: Array(seed.utf8), accounts: 1, networkType: networkType) XCTAssertNotNil(ZcashRustBackend.getLastError()) - } func testDeriveExtendedSpendingKeys() { let seed = Array("testreferencealicetestreferencealice".utf8) - var spendingKeys: [String]? = nil + var spendingKeys: [String]? XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1, networkType: networkType) }()) XCTAssertNotNil(spendingKeys) XCTAssertFalse(spendingKeys?.first?.isEmpty ?? true) - } func testDeriveExtendedFullViewingKeys() { let seed = Array("testreferencealicetestreferencealice".utf8) - var fullViewingKeys: [String]? = nil - XCTAssertNoThrow(try { fullViewingKeys = try ZcashRustBackend.deriveExtendedFullViewingKeys(seed: seed, accounts: 1, networkType: networkType) }()) + var fullViewingKeys: [String]? + XCTAssertNoThrow( + try { + fullViewingKeys = try ZcashRustBackend.deriveExtendedFullViewingKeys( + seed: seed, + accounts: 1, + networkType: networkType + ) + }() + ) XCTAssertNotNil(fullViewingKeys) XCTAssertFalse(fullViewingKeys?.first?.isEmpty ?? true) @@ -63,10 +73,9 @@ class ZcashRustBackendTests: XCTestCase { func testDeriveExtendedFullViewingKey() { let seed = Array("testreferencealicetestreferencealice".utf8) - var fullViewingKey: String? = nil + var fullViewingKey: String? - - var spendingKeys: [String]? = nil + var spendingKeys: [String]? XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1, networkType: networkType) }()) XCTAssertNotNil(spendingKeys) @@ -100,57 +109,81 @@ class ZcashRustBackendTests: XCTestCase { XCTAssertEqual(addr, Optional("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc")) XCTAssertTrue(ZcashRustBackend.scanBlocks(dbCache: cacheDb, dbData: dbData, networkType: networkType)) - } func testIsValidTransparentAddressFalse() { - var isValid: Bool? = nil + var isValid: Bool? - XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidTransparentAddress("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc", networkType: networkType) }()) + XCTAssertNoThrow( + try { + isValid = try ZcashRustBackend.isValidTransparentAddress( + "ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc", + networkType: networkType + ) + }() + ) if let valid = isValid { XCTAssertFalse(valid) } else { - XCTFail() + XCTFail("Failed as invalid") } - - } func testIsValidTransparentAddressTrue() { - var isValid: Bool? = nil + var isValid: Bool? - XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidTransparentAddress("tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7", networkType: networkType) }()) + XCTAssertNoThrow( + try { + isValid = try ZcashRustBackend.isValidTransparentAddress( + "tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7", + networkType: networkType + ) + }() + ) if let valid = isValid { XCTAssertTrue(valid) } else { - XCTFail() + XCTFail("Failed as invalid") } } func testIsValidShieldedAddressTrue() { - var isValid: Bool? = nil + var isValid: Bool? - XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidShieldedAddress("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc", networkType: networkType) }()) + XCTAssertNoThrow( + try { + isValid = try ZcashRustBackend.isValidShieldedAddress( + "ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc", + networkType: networkType + ) + }() + ) if let valid = isValid { XCTAssertTrue(valid) } else { - XCTFail() + XCTFail("Failed as invalid") } } func testIsValidShieldedAddressFalse() { - var isValid: Bool? = nil + var isValid: Bool? - XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidShieldedAddress("tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7", networkType: networkType) }()) + XCTAssertNoThrow( + try { + isValid = try ZcashRustBackend.isValidShieldedAddress( + "tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7", + networkType: networkType + ) + }() + ) if let valid = isValid { XCTAssertFalse(valid) } else { - XCTFail() + XCTFail("Failed as invalid") } } - } diff --git a/ZcashLightClientKitTests/utils/DarkSideWalletService.swift b/ZcashLightClientKitTests/utils/DarkSideWalletService.swift index 41b9014a..6492d834 100644 --- a/ZcashLightClientKitTests/utils/DarkSideWalletService.swift +++ b/ZcashLightClientKitTests/utils/DarkSideWalletService.swift @@ -11,35 +11,68 @@ import GRPC enum DarksideDataset: String { case afterLargeReorg = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/after-large-large.txt" - case afterSmallReorg = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/after-small-reorg.txt" + case afterSmallReorg = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/after-small-reorg.txt" case beforeReOrg = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/before-reorg.txt" /** - see - https://github.com/zcash-hackworks/darksidewalletd-test-data/tree/master/tx-index-reorg - */ + see + https://github.com/zcash-hackworks/darksidewalletd-test-data/tree/master/tx-index-reorg + */ case txIndexChangeBefore = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/tx-index-reorg/before-reorg.txt" case txIndexChangeAfter = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/tx-index-reorg/after-reorg.txt" /** - See https://github.com/zcash-hackworks/darksidewalletd-test-data/tree/master/tx-height-reorg - */ + See https://github.com/zcash-hackworks/darksidewalletd-test-data/tree/master/tx-height-reorg + */ case txHeightReOrgBefore = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/tx-height-reorg/before-reorg.txt" case txHeightReOrgAfter = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/tx-height-reorg/after-reorg.txt" /* - see: https://github.com/zcash-hackworks/darksidewalletd-test-data/tree/master/tx-remove-reorg - */ + see: https://github.com/zcash-hackworks/darksidewalletd-test-data/tree/master/tx-remove-reorg + */ case txReOrgRemovesInboundTxBefore = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/tx-remove-reorg/before-reorg.txt" case txReOrgRemovesInboundTxAfter = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/tx-remove-reorg/after-reorg.txt" } class DarksideWalletService: LightWalletService { - @discardableResult func blockStream(startHeight: BlockHeight, endHeight: BlockHeight, result: @escaping (Result) -> Void, handler: @escaping (ZcashCompactBlock) -> Void, progress: @escaping (BlockProgressReporting) -> Void) -> CancellableCall { - return service.blockStream(startHeight: startHeight, endHeight: endHeight, result: result, handler: handler, progress: progress) + var channel: Channel + var service: LightWalletGRPCService + var darksideService: DarksideStreamerClient + + init(endpoint: LightWalletEndpoint) { + self.channel = ChannelProvider().channel() + self.service = LightWalletGRPCService(endpoint: endpoint) + self.darksideService = DarksideStreamerClient(channel: channel) + } + + init(service: LightWalletGRPCService) { + self.channel = ChannelProvider().channel() + self.darksideService = DarksideStreamerClient(channel: channel) + self.service = service + } + + convenience init() { + self.init(endpoint: LightWalletEndpointBuilder.default) + } + + @discardableResult + func blockStream( + startHeight: BlockHeight, + endHeight: BlockHeight, + result: @escaping (Result) -> Void, + handler: @escaping (ZcashCompactBlock) -> Void, + progress: @escaping (BlockProgress) -> Void + ) -> CancellableCall { + return service.blockStream( + startHeight: startHeight, + endHeight: endHeight, + result: result, + handler: handler, + progress: progress + ) } func getInfo() throws -> LightWalletdInfo { @@ -51,15 +84,18 @@ class DarksideWalletService: LightWalletService { } func closeConnection() { - } func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] { return [] } - func fetchUTXOs(for tAddress: String, height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) { - DispatchQueue.global().asyncAfter(deadline: .now() + 0.1){ + func fetchUTXOs( + for tAddress: String, + height: BlockHeight, + result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void + ) { + DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) { result(.success([])) } } @@ -68,14 +104,18 @@ class DarksideWalletService: LightWalletService { [] } - func fetchUTXOs(for tAddresses: [String], height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) { - DispatchQueue.global().asyncAfter(deadline: .now() + 0.1){ + func fetchUTXOs( + for tAddresses: [String], + height: BlockHeight, + result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void + ) { + DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) { result(.success([])) } } func fetchUTXOs(for tAddress: String, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) { - DispatchQueue.global().asyncAfter(deadline: .now() + 0.1){ + DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) { result(.success([])) } } @@ -88,28 +128,6 @@ class DarksideWalletService: LightWalletService { service.fetchTransaction(txId: txId, result: result) } - var channel: Channel - init(endpoint: LightWalletEndpoint) { - self.channel = ChannelProvider().channel() - self.service = LightWalletGRPCService(endpoint: endpoint) - self.darksideService = DarksideStreamerClient(channel: channel) - } - - init(service: LightWalletGRPCService) { - self.channel = ChannelProvider().channel() - self.darksideService = DarksideStreamerClient(channel: channel) - self.service = service - } - - - - convenience init() { - self.init(endpoint: LightWalletEndpointBuilder.default) - } - - var service: LightWalletGRPCService - var darksideService: DarksideStreamerClient - func latestBlockHeight(result: @escaping (Result) -> Void) { service.latestBlockHeight(result: result) } @@ -127,8 +145,8 @@ class DarksideWalletService: LightWalletService { } /** - Darskside lightwalletd should do a fake submission, by sending over the tx, retrieving it and including it in a new block - */ + Darskside lightwalletd should do a fake submission, by sending over the tx, retrieving it and including it in a new block + */ func submit(spendTransaction: Data, result: @escaping (Result) -> Void) { service.submit(spendTransaction: spendTransaction, result: result) } @@ -158,11 +176,17 @@ class DarksideWalletService: LightWalletService { } func getIncomingTransactions() throws -> [RawTransaction]? { - var txs = [RawTransaction]() - let response = try darksideService.getIncomingTransactions(Empty(), handler: { txs.append($0) }).status.wait() + var txs: [RawTransaction] = [] + let response = try darksideService.getIncomingTransactions( + Empty(), + handler: { txs.append($0) } + ) + .status + .wait() + switch response.code { - case .success: - return txs.count > 0 ? txs : nil + case .ok: + return !txs.isEmpty ? txs : nil default: throw response } @@ -186,9 +210,11 @@ class DarksideWalletService: LightWalletService { } func stageTransaction(_ rawTransaction: RawTransaction, at height: BlockHeight) throws { - var tx = rawTransaction - tx.height = UInt64(height) - _ = try darksideService.stageTransactionsStream().sendMessage(tx).wait() + var transaction = rawTransaction + transaction.height = UInt64(height) + _ = try darksideService.stageTransactionsStream() + .sendMessage(transaction) + .wait() } func stageTransaction(from url: String, at height: BlockHeight) throws { @@ -197,12 +223,9 @@ class DarksideWalletService: LightWalletService { txUrl.url = url _ = try darksideService.stageTransactions(txUrl, callOptions: nil).response.wait() } - } - -class DarksideWalletDConstants: NetworkConstants { - +enum DarksideWalletDConstants: NetworkConstants { static var saplingActivationHeight: BlockHeight { 663150 } @@ -227,9 +250,8 @@ class DarksideWalletDConstants: NetworkConstants { ZcashSDKMainnetConstants.feeChangeHeight } } + class DarksideWalletDNetwork: ZcashNetwork { var constants: NetworkConstants.Type = DarksideWalletDConstants.self - var networkType = NetworkType.mainnet - } diff --git a/ZcashLightClientKitTests/utils/FakeChainBuilder.swift b/ZcashLightClientKitTests/utils/FakeChainBuilder.swift index e89e4b5b..3cc41901 100644 --- a/ZcashLightClientKitTests/utils/FakeChainBuilder.swift +++ b/ZcashLightClientKitTests/utils/FakeChainBuilder.swift @@ -11,7 +11,9 @@ import Foundation enum FakeChainBuilderError: Error { case fakeHexDataConversionFailed } -class FakeChainBuilder { + +// swiftlint:disable force_unwrapping function_parameter_count +enum FakeChainBuilder { static let someOtherTxUrl = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/transactions/t-shielded-spend.txt" static let txMainnetBlockUrl = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/663150.txt" @@ -29,7 +31,6 @@ class FakeChainBuilder { try darksideWallet.stageBlocksCreate(from: 663151, count: 100) try darksideWallet.stageTransaction(from: txUrls[663174]!, at: 663174) - } static func buildChain(darksideWallet: DarksideWalletService, branchID: String, chainName: String) throws { @@ -41,7 +42,6 @@ class FakeChainBuilder { try darksideWallet.stageTransaction(from: txUrls[663174]!, at: 663174) try darksideWallet.stageTransaction(from: txUrls[663188]!, at: 663188) - } static func buildChainWithTxsFarFromEachOther(darksideWallet: DarksideWalletService, branchID: String, chainName: String, length: Int) throws { @@ -53,10 +53,8 @@ class FakeChainBuilder { try darksideWallet.stageTransaction(from: txUrls[663188]!, at: 663188) try darksideWallet.stageTransaction(from: txUrls[663974]!, at: 663974) - } - static func buildChain(darksideWallet: DarksideWalletService, branchID: String, chainName: String, length: Int) throws { try darksideWallet.reset(saplingActivation: 663150, branchID: branchID, chainName: chainName) try darksideWallet.useDataset(from: txMainnetBlockUrl) @@ -70,34 +68,49 @@ class FakeChainBuilder { try darksideWallet.stageTransaction(from: txUrls[663953]!, at: 663953) try darksideWallet.stageTransaction(from: txUrls[663974]!, at: 663974) - } - static func buildChain(darksideWallet: DarksideWalletService, birthday: BlockHeight, networkActivationHeight: BlockHeight, branchID: String, chainName: String, length: Int) throws { - + static func buildChain( + darksideWallet: DarksideWalletService, + birthday: BlockHeight, + networkActivationHeight: BlockHeight, + branchID: String, + chainName: String, + length: Int + ) throws { try darksideWallet.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName) try darksideWallet.useDataset(testnetCanopyStartBlock) try darksideWallet.stageBlocksCreate(from: birthday + 1, count: length) try darksideWallet.stageTransaction(from: testnetPreCanopyTx, at: networkActivationHeight - ZcashSDK.expiryOffset) - } static func buildChainPostActivationFunds(darksideWallet: DarksideWalletService, birthday: BlockHeight, networkActivationHeight: BlockHeight, length: Int) throws { - - try darksideWallet.reset(saplingActivation: birthday, branchID: "e9ff75a6" , chainName: "testnet") + try darksideWallet.reset(saplingActivation: birthday, branchID: "e9ff75a6", chainName: "testnet") try darksideWallet.useDataset(testnetCanopyStartBlock) try darksideWallet.stageBlocksCreate(from: birthday + 1, count: length) try darksideWallet.stageTransaction(from: testnetPostCanopyTx, at: networkActivationHeight + 1) - } - static func buildChainMixedFunds(darksideWallet: DarksideWalletService, birthday: BlockHeight, networkActivationHeight: BlockHeight, branchID: String, chainName: String, length: Int) throws { - try buildChain(darksideWallet: darksideWallet, birthday: birthday, networkActivationHeight: networkActivationHeight, branchID: branchID, chainName: chainName, length: length) + static func buildChainMixedFunds( + darksideWallet: DarksideWalletService, + birthday: BlockHeight, + networkActivationHeight: BlockHeight, + branchID: String, + chainName: String, + length: Int + ) throws { + try buildChain( + darksideWallet: darksideWallet, + birthday: birthday, + networkActivationHeight: networkActivationHeight, + branchID: branchID, + chainName: chainName, + length: length + ) try darksideWallet.stageTransaction(from: testnetPostCanopyTx, at: networkActivationHeight + ZcashSDK.expiryOffset) - } static func buildTxUrl(for id: String) -> String { @@ -105,86 +118,85 @@ class FakeChainBuilder { } static var txUrls = [ - 663174 : buildTxUrl(for: "8f064d23c66dc36e32445e5f3b50e0f32ac3ddb78cff21fb521eb6c19c07c99a"), - 663188 : buildTxUrl(for: "15a677b6770c5505fb47439361d3d3a7c21238ee1a6874fdedad18ae96850590"), - 663202 : buildTxUrl(for: "d2e7be14bbb308f9d4d68de424d622cbf774226d01cd63cc6f155fafd5cd212c"), - 663218 : buildTxUrl(for: "e6566be3a4f9a80035dab8e1d97e40832a639e3ea938fb7972ea2f8482ff51ce"), - 663229 : buildTxUrl(for: "0821a89be7f2fc1311792c3fa1dd2171a8cdfb2effd98590cbd5ebcdcfcf491f"), - 663849 : buildTxUrl(for: "c9e35e6ff444b071d63bf9bab6480409d6361760445c8a28d24179adb35c2495"), - 663891 : buildTxUrl(for: "72a29d7db511025da969418880b749f7fc0fc910cdb06f52193b5fa5c0401d9d"), - 663922 : buildTxUrl(for: "ff6ea36765dc29793775c7aa71de19fca039c5b5b873a0497866e9c4bc48af01"), - 663938 : buildTxUrl(for: "34e507cab780546f980176f3ff2695cd404917508c7e5ee18cc1d2ff3858cb08"), - 663942 : buildTxUrl(for: "6edf869063eccff3345676b0fed9f1aa6988fb2524e3d9ca7420a13cfadcd76c"), - 663947 : buildTxUrl(for: "de97394ae220c28a33ba78b944e82dabec8cb404a4407650b134b3d5950358c0"), - 663949 : buildTxUrl(for: "4eaa902279f8380914baf5bcc470d8b7c11d84fda809f67f517a7cb48912b87b"), - 663953 : buildTxUrl(for: "e9527891b5d43d1ac72f2c0a3ac18a33dc5a0529aec04fa600616ed35f8123f8"), - 663956 : buildTxUrl(for: "73c5edf8ffba774d99155121ccf07e67fbcf14284458f7e732751fea60d3bcbc"), - 663974 : buildTxUrl(for: "4dcc95dd0a2f1f51bd64bb9f729b423c6de1690664a1b6614c75925e781662f7"), - 664003 : buildTxUrl(for: "d2e859e8ef8ab27355c7a6caf643065d2d7a720e334c4a84943f6d1ae3919b5d"), - 664012 : buildTxUrl(for: "547784f746eef2f164bbb1a56882723dde744157a21e4fdfeadee763f73fee84"), - 664022 : buildTxUrl(for: "981638bb7ac08e31ee6db5c70d98ad6b137a448716b19245f9454b450c07c911"), - 664037 : buildTxUrl(for: "36505ab3c78c62981c8111d143cd57dcfe6cafcb2c3cdc258b023ae5210d53f1"), - 664038 : buildTxUrl(for: "0ffc55af750bb10a9e6a7e425138cc5acb5f7ddca68bf9d0c4606437bd692622"), - 678828 : buildTxUrl(for: "cfd3bce9fdeeae12b99fdb977a997177e183c2312871f0454bdf61640cc03d93"), - 678836 : buildTxUrl(for: "5af3bc9818e5fabcc691f319d7354cc4194f17727f6303d59a94c3e5f0daf560"), - 682588 : buildTxUrl(for: "b1f566dec94048ff81306884b6ed92eb73cdb768b738d9c8cbd94babc1f0a9c9"), - 683689 : buildTxUrl(for: "3b568a1547832ac28bfcaf4c269f85fd68083735790f7949aa3a548ab53acf65"), - 683791 : buildTxUrl(for: "9e2eb538207ab47356a3723fd0e6f44b9349ea944d9c2d7be0d4e3a6a02c2c29"), - 683795 : buildTxUrl(for: "15d2f32494271f0a60f3928e4fc79c2cea337e06fbbbe7f6fb4a0d36002a0d42"), - 683809 : buildTxUrl(for: "76be7c244c37e1710bbb9f162baab265eebc8a379ad1843435ba5e7a2c21a600"), - 684374 : buildTxUrl(for: "3640a35c02cf4d9e0fa178380173b193873d8a0ef4bad57dd43e7d95db450c89"), - 685126 : buildTxUrl(for: "86f3457bdb8793a413c009a8a7e128b5a82723f41ebe557327bbe555fd47fbf3"), - 687746 : buildTxUrl(for: "edb32a55d5fa18fc5c6bf09f5f1de198b219b6780ca71bbc4fd321b655bbfe42"), - 687900 : buildTxUrl(for: "855af341c14b94fec67e5eb56bb801a59551df33e9d955982672f5f62e76f72e"), - 688059 : buildTxUrl(for: "57c226f77ad01ecf833515612e7cba7abe64500fa891144c2c89c59af8c36c22"), - 691540 : buildTxUrl(for: "9a74cd7f170f6c8cef04f3327fdcf63ec69dd1263f80c9bf0b3002c871950ddd"), - 691593 : buildTxUrl(for: "6b64134034ec282092501f85bf8955006894dbcac402fa5e6c85ee867334cd3d"), - 691632 : buildTxUrl(for: "75f2cdd2ff6a94535326abb5d9e663d53cbfa5f31ebb24b4d7e420e9440d41a2"), - 692981 : buildTxUrl(for: "f98f2c75785f110203930c7fd4115019ec70af6470db1be052985b469906fe98"), - 692984 : buildTxUrl(for: "67138ad7e5e97216124c2bbcda8edb7687c2cfbf5d644df2af2a86344437a661"), - 692992 : buildTxUrl(for: "6cf507ab4d3255fa51679c0256a1be1d668786bd3f558000f9e90ec442514212"), - 693248 : buildTxUrl(for: "d1278d74424807b830256ccbd4d7624dc9e68a50760f870a55c8e99715072ef1"), - 693268 : buildTxUrl(for: "e56c84718de5dee049b31c89832f4bf1694268e2664a04df182a8797cb00b52e"), - 693325 : buildTxUrl(for: "5635f48dc99adfebb0be105231b9383bd2d0df64e43a780d11620390640b8d3d"), - 693398 : buildTxUrl(for: "26c41d5dbbaaa3934b37109645b0aece9600248c5f51404d1f4ea7b711ac3312"), - 693460 : buildTxUrl(for: "8d381a3d993c8d424db0907bab3fef6000bc8de9efe7186846d44dd6d6a014b1"), - 693475 : buildTxUrl(for: "900f2a406c1546126e1dba0e4e6ca0e092ebe697a2f7b0abee4e9771e1038f0b"), - 693718 : buildTxUrl(for: "7690c8ec740c1be3c50e2aedae8bf907ac81141ae8b6a134c1811706c73f49a6"), - 693736 : buildTxUrl(for: "34a4d630f120e4c1e7d2b9844c69fd4d3be71532ade1aaf7147566f05162c316"), - 696005 : buildTxUrl(for: "076d30ca62082dda9a760e0d004393cd96830056c6dca643fccdbe500053e355"), - 696012 : buildTxUrl(for: "e2da49325057b2232e85b0228955234f4a3538df2ebf4cd121589bac9771f6f2"), - 696040 : buildTxUrl(for: "4f6ef63bd3be8338c902901daf77ab5aa23dd97c160ee91b00950accf7f0b194"), - 698361 : buildTxUrl(for: "d275a9e96e6c68dfb8fe6ec3fd39737ce5fa880f86552b3ed993048373d6e8ad"), - 710823 : buildTxUrl(for: "bac04ad7734628e70a57408c65403ec845bce575197e7984435976e1ac64ae4f"), - 710896 : buildTxUrl(for: "56c63ef496f633418f0576cc34a0730c74023d78003b95aff731e0448c8b9203"), - 711847 : buildTxUrl(for: "82439eade5d1deba7606f3db53bf33588677b1bd9765a5eb5f4d3f6980ecb3d4"), - 727486 : buildTxUrl(for: "b5877c7f7dd3856bae679f7ccb37ddf3fcd2fafe72a081878ee9069fc25934cd"), - 728159 : buildTxUrl(for: "5d6a0c4879a244d2c0a6e2d26c4d0d26dee5a5c1f3f13f42436253272d4b8a03"), - 736102 : buildTxUrl(for: "be3a3a3fe10b9a1976410e5aaf425b24695dcdd04df926a23d9f3f8ed43178c6"), - 736254 : buildTxUrl(for: "acc0685aee04f7b7c6a12c969c1646038ea4a3b940d00b28d1eaf7643602d49e"), - 736262 : buildTxUrl(for: "fed00ff5cb6ee057d00ec70f1f5f1b189d591903c1e1cbde654ad39c8477808c"), - 736301 : buildTxUrl(for: "f3ef9f3adedf2b66e438c9d7d878ed72886b62b70e68547bb47d5b6033519dcd"), - 736574 : buildTxUrl(for: "34574442629a2378eccd216385d8bc99859e214e79265941319599130de2c69a"), - 739582 : buildTxUrl(for: "71935e29127a7de0b96081f4c8a42a9c11584d83adedfaab414362a6f3d965cf"), - 741148 : buildTxUrl(for: "5eff7f15b39b9ab463767b768e23f90b4a23239ed873fdfbd4afa286027f7b57"), - 741154 : buildTxUrl(for: "b05c3df882ccff4f58acc1e3dbe2520213159d584bac01ff0199c37c25451430"), - 741156 : buildTxUrl(for: "1a3bb3d4fece0fcde1a47ef8271511cefcdb67f2698afc2c63297fbeab2003d8"), - 741158 : buildTxUrl(for: "a979dc83f55d9114dcab2eb5694bbf4fbb84602ceb27af6e287d6af8775d92c7"), - 741162 : buildTxUrl(for: "23278a3c1bf03f20f67299ed0b8dc4d577909d2344f1f02971c8890c6341d79d"), - 741170 : buildTxUrl(for: "db4101f3cccb1671dc1557670fa8b4e64c958008778b8ab1779a4a2969fe1153"), - 741171 : buildTxUrl(for: "74a94aceedb3a22eedb0b5d450487340b3783e1d22ef47af2359c45d0804d9ff"), - 741172 : buildTxUrl(for: "2899ccaea26e4c873a09965e0c268c96a86b1931d896b8622f36422d32c234c2"), - 741174 : buildTxUrl(for: "819009ec1d0cfb50d30c944a41bde545ee631663af39f8a17c31255ada12de13"), - 775018 : buildTxUrl(for: "85b3b64903b1873f5b7578eb2f167752b6a66ba64bb5c4cb8a4d75072219678b"), - 775021 : buildTxUrl(for: "6d69d23c8db7736efdd38090c3cd032f8e68431272964157c52a924315e1a3f5"), - 775267 : buildTxUrl(for: "daf24871749c8360028a19e4d82ddb0d573d7c765a894d601aa241f1e040ac5f"), - 776019 : buildTxUrl(for: "f64378feb08c30b28a90f31e8cd84a932ed064108fb17a3e0aee1585ff994138"), - 776158 : buildTxUrl(for: "9339a0a231f88b3067f3378c7ae70170fdf4246e0e70f442552a6e3961391b56"), - 776233 : buildTxUrl(for: "c9c33e44468c1fa0ee5f9d411b43748f8882915640b3b13c6e48c56e9cdde798"), - 776240 : buildTxUrl(for: "0e1c70fc67d3b9ae29a98996d4363b512d51d7b8422a6fa58f5803bebb247e7a"), - 820691 : buildTxUrl(for: "1948bc40226e53d2652f593ebe4f34c5d81550eeb16fe2ed797b7ef3c1083899"), - 822410 : buildTxUrl(for: "f3f8684be8d77367d099a38f30e3652410cdebe35c006d0599d86d8ec640867f"), - 828933 : buildTxUrl(for: "1fd394257d1c10c8a70fb760cf73f6d0e96e61edcf1ffca6da12d733a59221a4") + 663174: buildTxUrl(for: "8f064d23c66dc36e32445e5f3b50e0f32ac3ddb78cff21fb521eb6c19c07c99a"), + 663188: buildTxUrl(for: "15a677b6770c5505fb47439361d3d3a7c21238ee1a6874fdedad18ae96850590"), + 663202: buildTxUrl(for: "d2e7be14bbb308f9d4d68de424d622cbf774226d01cd63cc6f155fafd5cd212c"), + 663218: buildTxUrl(for: "e6566be3a4f9a80035dab8e1d97e40832a639e3ea938fb7972ea2f8482ff51ce"), + 663229: buildTxUrl(for: "0821a89be7f2fc1311792c3fa1dd2171a8cdfb2effd98590cbd5ebcdcfcf491f"), + 663849: buildTxUrl(for: "c9e35e6ff444b071d63bf9bab6480409d6361760445c8a28d24179adb35c2495"), + 663891: buildTxUrl(for: "72a29d7db511025da969418880b749f7fc0fc910cdb06f52193b5fa5c0401d9d"), + 663922: buildTxUrl(for: "ff6ea36765dc29793775c7aa71de19fca039c5b5b873a0497866e9c4bc48af01"), + 663938: buildTxUrl(for: "34e507cab780546f980176f3ff2695cd404917508c7e5ee18cc1d2ff3858cb08"), + 663942: buildTxUrl(for: "6edf869063eccff3345676b0fed9f1aa6988fb2524e3d9ca7420a13cfadcd76c"), + 663947: buildTxUrl(for: "de97394ae220c28a33ba78b944e82dabec8cb404a4407650b134b3d5950358c0"), + 663949: buildTxUrl(for: "4eaa902279f8380914baf5bcc470d8b7c11d84fda809f67f517a7cb48912b87b"), + 663953: buildTxUrl(for: "e9527891b5d43d1ac72f2c0a3ac18a33dc5a0529aec04fa600616ed35f8123f8"), + 663956: buildTxUrl(for: "73c5edf8ffba774d99155121ccf07e67fbcf14284458f7e732751fea60d3bcbc"), + 663974: buildTxUrl(for: "4dcc95dd0a2f1f51bd64bb9f729b423c6de1690664a1b6614c75925e781662f7"), + 664003: buildTxUrl(for: "d2e859e8ef8ab27355c7a6caf643065d2d7a720e334c4a84943f6d1ae3919b5d"), + 664012: buildTxUrl(for: "547784f746eef2f164bbb1a56882723dde744157a21e4fdfeadee763f73fee84"), + 664022: buildTxUrl(for: "981638bb7ac08e31ee6db5c70d98ad6b137a448716b19245f9454b450c07c911"), + 664037: buildTxUrl(for: "36505ab3c78c62981c8111d143cd57dcfe6cafcb2c3cdc258b023ae5210d53f1"), + 664038: buildTxUrl(for: "0ffc55af750bb10a9e6a7e425138cc5acb5f7ddca68bf9d0c4606437bd692622"), + 678828: buildTxUrl(for: "cfd3bce9fdeeae12b99fdb977a997177e183c2312871f0454bdf61640cc03d93"), + 678836: buildTxUrl(for: "5af3bc9818e5fabcc691f319d7354cc4194f17727f6303d59a94c3e5f0daf560"), + 682588: buildTxUrl(for: "b1f566dec94048ff81306884b6ed92eb73cdb768b738d9c8cbd94babc1f0a9c9"), + 683689: buildTxUrl(for: "3b568a1547832ac28bfcaf4c269f85fd68083735790f7949aa3a548ab53acf65"), + 683791: buildTxUrl(for: "9e2eb538207ab47356a3723fd0e6f44b9349ea944d9c2d7be0d4e3a6a02c2c29"), + 683795: buildTxUrl(for: "15d2f32494271f0a60f3928e4fc79c2cea337e06fbbbe7f6fb4a0d36002a0d42"), + 683809: buildTxUrl(for: "76be7c244c37e1710bbb9f162baab265eebc8a379ad1843435ba5e7a2c21a600"), + 684374: buildTxUrl(for: "3640a35c02cf4d9e0fa178380173b193873d8a0ef4bad57dd43e7d95db450c89"), + 685126: buildTxUrl(for: "86f3457bdb8793a413c009a8a7e128b5a82723f41ebe557327bbe555fd47fbf3"), + 687746: buildTxUrl(for: "edb32a55d5fa18fc5c6bf09f5f1de198b219b6780ca71bbc4fd321b655bbfe42"), + 687900: buildTxUrl(for: "855af341c14b94fec67e5eb56bb801a59551df33e9d955982672f5f62e76f72e"), + 688059: buildTxUrl(for: "57c226f77ad01ecf833515612e7cba7abe64500fa891144c2c89c59af8c36c22"), + 691540: buildTxUrl(for: "9a74cd7f170f6c8cef04f3327fdcf63ec69dd1263f80c9bf0b3002c871950ddd"), + 691593: buildTxUrl(for: "6b64134034ec282092501f85bf8955006894dbcac402fa5e6c85ee867334cd3d"), + 691632: buildTxUrl(for: "75f2cdd2ff6a94535326abb5d9e663d53cbfa5f31ebb24b4d7e420e9440d41a2"), + 692981: buildTxUrl(for: "f98f2c75785f110203930c7fd4115019ec70af6470db1be052985b469906fe98"), + 692984: buildTxUrl(for: "67138ad7e5e97216124c2bbcda8edb7687c2cfbf5d644df2af2a86344437a661"), + 692992: buildTxUrl(for: "6cf507ab4d3255fa51679c0256a1be1d668786bd3f558000f9e90ec442514212"), + 693248: buildTxUrl(for: "d1278d74424807b830256ccbd4d7624dc9e68a50760f870a55c8e99715072ef1"), + 693268: buildTxUrl(for: "e56c84718de5dee049b31c89832f4bf1694268e2664a04df182a8797cb00b52e"), + 693325: buildTxUrl(for: "5635f48dc99adfebb0be105231b9383bd2d0df64e43a780d11620390640b8d3d"), + 693398: buildTxUrl(for: "26c41d5dbbaaa3934b37109645b0aece9600248c5f51404d1f4ea7b711ac3312"), + 693460: buildTxUrl(for: "8d381a3d993c8d424db0907bab3fef6000bc8de9efe7186846d44dd6d6a014b1"), + 693475: buildTxUrl(for: "900f2a406c1546126e1dba0e4e6ca0e092ebe697a2f7b0abee4e9771e1038f0b"), + 693718: buildTxUrl(for: "7690c8ec740c1be3c50e2aedae8bf907ac81141ae8b6a134c1811706c73f49a6"), + 693736: buildTxUrl(for: "34a4d630f120e4c1e7d2b9844c69fd4d3be71532ade1aaf7147566f05162c316"), + 696005: buildTxUrl(for: "076d30ca62082dda9a760e0d004393cd96830056c6dca643fccdbe500053e355"), + 696012: buildTxUrl(for: "e2da49325057b2232e85b0228955234f4a3538df2ebf4cd121589bac9771f6f2"), + 696040: buildTxUrl(for: "4f6ef63bd3be8338c902901daf77ab5aa23dd97c160ee91b00950accf7f0b194"), + 698361: buildTxUrl(for: "d275a9e96e6c68dfb8fe6ec3fd39737ce5fa880f86552b3ed993048373d6e8ad"), + 710823: buildTxUrl(for: "bac04ad7734628e70a57408c65403ec845bce575197e7984435976e1ac64ae4f"), + 710896: buildTxUrl(for: "56c63ef496f633418f0576cc34a0730c74023d78003b95aff731e0448c8b9203"), + 711847: buildTxUrl(for: "82439eade5d1deba7606f3db53bf33588677b1bd9765a5eb5f4d3f6980ecb3d4"), + 727486: buildTxUrl(for: "b5877c7f7dd3856bae679f7ccb37ddf3fcd2fafe72a081878ee9069fc25934cd"), + 728159: buildTxUrl(for: "5d6a0c4879a244d2c0a6e2d26c4d0d26dee5a5c1f3f13f42436253272d4b8a03"), + 736102: buildTxUrl(for: "be3a3a3fe10b9a1976410e5aaf425b24695dcdd04df926a23d9f3f8ed43178c6"), + 736254: buildTxUrl(for: "acc0685aee04f7b7c6a12c969c1646038ea4a3b940d00b28d1eaf7643602d49e"), + 736262: buildTxUrl(for: "fed00ff5cb6ee057d00ec70f1f5f1b189d591903c1e1cbde654ad39c8477808c"), + 736301: buildTxUrl(for: "f3ef9f3adedf2b66e438c9d7d878ed72886b62b70e68547bb47d5b6033519dcd"), + 736574: buildTxUrl(for: "34574442629a2378eccd216385d8bc99859e214e79265941319599130de2c69a"), + 739582: buildTxUrl(for: "71935e29127a7de0b96081f4c8a42a9c11584d83adedfaab414362a6f3d965cf"), + 741148: buildTxUrl(for: "5eff7f15b39b9ab463767b768e23f90b4a23239ed873fdfbd4afa286027f7b57"), + 741154: buildTxUrl(for: "b05c3df882ccff4f58acc1e3dbe2520213159d584bac01ff0199c37c25451430"), + 741156: buildTxUrl(for: "1a3bb3d4fece0fcde1a47ef8271511cefcdb67f2698afc2c63297fbeab2003d8"), + 741158: buildTxUrl(for: "a979dc83f55d9114dcab2eb5694bbf4fbb84602ceb27af6e287d6af8775d92c7"), + 741162: buildTxUrl(for: "23278a3c1bf03f20f67299ed0b8dc4d577909d2344f1f02971c8890c6341d79d"), + 741170: buildTxUrl(for: "db4101f3cccb1671dc1557670fa8b4e64c958008778b8ab1779a4a2969fe1153"), + 741171: buildTxUrl(for: "74a94aceedb3a22eedb0b5d450487340b3783e1d22ef47af2359c45d0804d9ff"), + 741172: buildTxUrl(for: "2899ccaea26e4c873a09965e0c268c96a86b1931d896b8622f36422d32c234c2"), + 741174: buildTxUrl(for: "819009ec1d0cfb50d30c944a41bde545ee631663af39f8a17c31255ada12de13"), + 775018: buildTxUrl(for: "85b3b64903b1873f5b7578eb2f167752b6a66ba64bb5c4cb8a4d75072219678b"), + 775021: buildTxUrl(for: "6d69d23c8db7736efdd38090c3cd032f8e68431272964157c52a924315e1a3f5"), + 775267: buildTxUrl(for: "daf24871749c8360028a19e4d82ddb0d573d7c765a894d601aa241f1e040ac5f"), + 776019: buildTxUrl(for: "f64378feb08c30b28a90f31e8cd84a932ed064108fb17a3e0aee1585ff994138"), + 776158: buildTxUrl(for: "9339a0a231f88b3067f3378c7ae70170fdf4246e0e70f442552a6e3961391b56"), + 776233: buildTxUrl(for: "c9c33e44468c1fa0ee5f9d411b43748f8882915640b3b13c6e48c56e9cdde798"), + 776240: buildTxUrl(for: "0e1c70fc67d3b9ae29a98996d4363b512d51d7b8422a6fa58f5803bebb247e7a"), + 820691: buildTxUrl(for: "1948bc40226e53d2652f593ebe4f34c5d81550eeb16fe2ed797b7ef3c1083899"), + 822410: buildTxUrl(for: "f3f8684be8d77367d099a38f30e3652410cdebe35c006d0599d86d8ec640867f"), + 828933: buildTxUrl(for: "1fd394257d1c10c8a70fb760cf73f6d0e96e61edcf1ffca6da12d733a59221a4") ] - } diff --git a/ZcashLightClientKitTests/utils/FakeService.swift b/ZcashLightClientKitTests/utils/FakeService.swift index 634c95ee..c7042ae2 100644 --- a/ZcashLightClientKitTests/utils/FakeService.swift +++ b/ZcashLightClientKitTests/utils/FakeService.swift @@ -14,15 +14,24 @@ struct LightWalletServiceMockResponse: LightWalletServiceResponse { var errorCode: Int32 var errorMessage: String var unknownFields: UnknownStorage - } + struct MockCancellable: CancellableCall { func cancel() {} } + class MockLightWalletService: LightWalletService { var mockLightDInfo: LightWalletdInfo? var queue = DispatchQueue(label: "mock service queue") - @discardableResult func blockStream(startHeight: BlockHeight, endHeight: BlockHeight, result: @escaping (Result) -> Void, handler: @escaping (ZcashCompactBlock) -> Void, progress: @escaping (BlockProgressReporting) -> Void) -> CancellableCall { + + @discardableResult + func blockStream( + startHeight: BlockHeight, + endHeight: BlockHeight, + result: @escaping (Result) -> Void, + handler: @escaping (ZcashCompactBlock) -> Void, + progress: @escaping (BlockProgress) -> Void + ) -> CancellableCall { return MockCancellable() } @@ -35,7 +44,6 @@ class MockLightWalletService: LightWalletService { func getInfo(result: @escaping (Result) -> Void) { queue.async { [weak self] in - guard let info = self?.mockLightDInfo else { result(.failure(LightWalletServiceError.generalError(message: "Not Implemented"))) return @@ -45,27 +53,34 @@ class MockLightWalletService: LightWalletService { } func closeConnection() { - } func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] { [] } - func fetchUTXOs(for tAddress: String, height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) { - + func fetchUTXOs( + for tAddress: String, + height: BlockHeight, + result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void + ) { } func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] { [] } - func fetchUTXOs(for tAddresses: [String], height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) { - + func fetchUTXOs( + for tAddresses: [String], + height: BlockHeight, + result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void + ) { } - func fetchUTXOs(for tAddress: String, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) { - + func fetchUTXOs( + for tAddress: String, + result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void + ) { } private var service: LightWalletService @@ -110,7 +125,5 @@ class MockLightWalletService: LightWalletService { } func fetchTransaction(txId: Data, result: @escaping (Result) -> Void) { - } - } diff --git a/ZcashLightClientKitTests/utils/FakeStorage.swift b/ZcashLightClientKitTests/utils/FakeStorage.swift index e021bf8d..8ba79084 100644 --- a/ZcashLightClientKitTests/utils/FakeStorage.swift +++ b/ZcashLightClientKitTests/utils/FakeStorage.swift @@ -35,7 +35,7 @@ class ZcashConsoleFakeStorage: CompactBlockRepository { } } - fileprivate func fakeSave(blocks: [ZcashCompactBlock]) { + private func fakeSave(blocks: [ZcashCompactBlock]) { blocks.forEach { LoggerProxy.debug("saving block \($0)") self.latestBlockHeight = $0.height @@ -60,5 +60,4 @@ class ZcashConsoleFakeStorage: CompactBlockRepository { LoggerProxy.debug("rewind to \(height)") self.latestBlockHeight = min(self.latestBlockHeight, height) } - } diff --git a/ZcashLightClientKitTests/utils/MockTransactionRepository.swift b/ZcashLightClientKitTests/utils/MockTransactionRepository.swift index 37cb8b0b..3f3c82bc 100644 --- a/ZcashLightClientKitTests/utils/MockTransactionRepository.swift +++ b/ZcashLightClientKitTests/utils/MockTransactionRepository.swift @@ -6,123 +6,50 @@ // import Foundation - @testable import ZcashLightClientKit -class MockTransactionRepository: TransactionRepository { - func findConfirmedTransactionBy(rawId: Data) throws -> ConfirmedTransactionEntity? { - nil - } - - func blockForHeight(_ height: BlockHeight) throws -> Block? { - nil - } - - func findConfirmedTransactions(in range: BlockRange, offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? { - nil - } - - func findAll(from: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]? { - nil - } - - func findTransactions(in range: BlockRange, limit: Int) throws -> [TransactionEntity]? { - nil +class MockTransactionRepository { + enum Kind { + case sent + case received } - var unminedCount: Int var receivedCount: Int var sentCount: Int - var transactions: [ConfirmedTransactionEntity] = [] var reference: [Kind] = [] var sentTransactions: [ConfirmedTransaction] = [] var receivedTransactions: [ConfirmedTransaction] = [] - + var network: ZcashNetwork + var allCount: Int { receivedCount + sentCount } - - var network: ZcashNetwork - init(unminedCount: Int, - receivedCount: Int, - sentCount: Int, - network: ZcashNetwork) { + + init( + unminedCount: Int, + receivedCount: Int, + sentCount: Int, + network: ZcashNetwork + ) { self.unminedCount = unminedCount self.receivedCount = receivedCount self.sentCount = sentCount self.network = network } - + func generate() { - - var txArray = [ConfirmedTransactionEntity]() + var txArray: [ConfirmedTransactionEntity] = [] reference = referenceArray() - for i in 0 ..< reference.count { - txArray.append(mockTx(index: i, kind: reference[i])) + for index in 0 ..< reference.count { + txArray.append(mockTx(index: index, kind: reference[index])) } transactions = txArray } - func countAll() throws -> Int { - allCount - } - - func countUnmined() throws -> Int { - unminedCount - } - - func findBy(id: Int) throws -> TransactionEntity? { - transactions.first(where: {$0.id == id})?.transactionEntity - } - - func findBy(rawId: Data) throws -> TransactionEntity? { - transactions.first(where: {$0.rawTransactionId == rawId})?.transactionEntity - } - - func findAllSentTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? { - guard let indices = reference.indices(where: { $0 == .sent }) else { return nil } - - let sentTxs = indices.map { (idx) -> ConfirmedTransactionEntity in - transactions[idx] - } - return slice(txs: sentTxs, offset: offset, limit: limit) - } - - - func findAllReceivedTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? { - guard let indices = reference.indices(where: { $0 == .received }) else { return nil } - - let receivedTxs = indices.map { (idx) -> ConfirmedTransactionEntity in - transactions[idx] - } - return slice(txs: receivedTxs, offset: offset, limit: limit) - } - - func findAll(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? { - transactions - } - - func lastScannedHeight() throws -> BlockHeight { - return 700000 - } - - func isInitialized() throws -> Bool { - true - } - - func findEncodedTransactionBy(txId: Int) -> EncodedTransaction? { - nil - } - - enum Kind { - case sent - case received - } - func referenceArray() -> [Kind] { - var template = [Kind]() + var template: [Kind] = [] for _ in 0 ..< sentCount { template.append(.sent) @@ -130,10 +57,10 @@ class MockTransactionRepository: TransactionRepository { for _ in 0 ..< receivedCount { template.append(.received) } + return template.shuffled() } - func mockTx(index: Int, kind: Kind) -> ConfirmedTransactionEntity { switch kind { case .received: @@ -144,17 +71,41 @@ class MockTransactionRepository: TransactionRepository { } func mockSent(_ index: Int) -> ConfirmedTransactionEntity { - ConfirmedTransaction(toAddress: "some_address", expiryHeight: BlockHeight.max, minedHeight: randomBlockHeight(), noteId: index, blockTimeInSeconds: randomTimeInterval(), transactionIndex: index, raw: Data(), id: index, value: Int.random(in: 1 ... ZcashSDK.zatoshiPerZEC), memo: nil, rawTransactionId: Data()) + ConfirmedTransaction( + toAddress: "some_address", + expiryHeight: BlockHeight.max, + minedHeight: randomBlockHeight(), + noteId: index, + blockTimeInSeconds: randomTimeInterval(), + transactionIndex: index, + raw: Data(), + id: index, + value: Int.random(in: 1 ... ZcashSDK.zatoshiPerZEC), + memo: nil, + rawTransactionId: Data() + ) } - func mockReceived(_ index: Int) -> ConfirmedTransactionEntity { - ConfirmedTransaction(toAddress: nil, expiryHeight: BlockHeight.max, minedHeight: randomBlockHeight(), noteId: index, blockTimeInSeconds: randomTimeInterval(), transactionIndex: index, raw: Data(), id: index, value: Int.random(in: 1 ... ZcashSDK.zatoshiPerZEC), memo: nil, rawTransactionId: Data()) + ConfirmedTransaction( + toAddress: nil, + expiryHeight: BlockHeight.max, + minedHeight: randomBlockHeight(), + noteId: index, + blockTimeInSeconds: randomTimeInterval(), + transactionIndex: index, + raw: Data(), + id: index, + value: Int.random(in: 1 ... ZcashSDK.zatoshiPerZEC), + memo: nil, + rawTransactionId: Data() + ) } func randomBlockHeight() -> BlockHeight { BlockHeight.random(in: network.constants.saplingActivationHeight ... 1_000_000) } + func randomTimeInterval() -> TimeInterval { Double.random(in: Date().timeIntervalSince1970 - 1000000.0 ... Date().timeIntervalSince1970) } @@ -168,18 +119,93 @@ class MockTransactionRepository: TransactionRepository { extension MockTransactionRepository.Kind: Equatable {} +// MARK: - TransactionRepository +extension MockTransactionRepository: TransactionRepository { + func countAll() throws -> Int { + allCount + } + + func countUnmined() throws -> Int { + unminedCount + } + + func blockForHeight(_ height: BlockHeight) throws -> Block? { + nil + } + + func findBy(id: Int) throws -> TransactionEntity? { + transactions.first(where: { $0.id == id })?.transactionEntity + } + + func findBy(rawId: Data) throws -> TransactionEntity? { + transactions.first(where: { $0.rawTransactionId == rawId })?.transactionEntity + } + + func findAllSentTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? { + guard let indices = reference.indices(where: { $0 == .sent }) else { return nil } + + let sentTxs = indices.map { idx -> ConfirmedTransactionEntity in + transactions[idx] + } + return slice(txs: sentTxs, offset: offset, limit: limit) + } + + func findAllReceivedTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? { + guard let indices = reference.indices(where: { $0 == .received }) else { return nil } + + let receivedTxs = indices.map { idx -> ConfirmedTransactionEntity in + transactions[idx] + } + + return slice(txs: receivedTxs, offset: offset, limit: limit) + } + + func findAll(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? { + transactions + } + + func findAll(from: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]? { + nil + } + + func lastScannedHeight() throws -> BlockHeight { + return 700000 + } + + func isInitialized() throws -> Bool { + true + } + + func findEncodedTransactionBy(txId: Int) -> EncodedTransaction? { + nil + } + + func findTransactions(in range: BlockRange, limit: Int) throws -> [TransactionEntity]? { + nil + } + + func findConfirmedTransactionBy(rawId: Data) throws -> ConfirmedTransactionEntity? { + nil + } + + func findConfirmedTransactions(in range: BlockRange, offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? { + nil + } +} + extension Array { - func indices(where f: (_ element: Element) -> Bool) -> [Int]? { - guard self.count > 0 else { return nil } - var idx = [Int]() - for i in 0 ..< self.count { - if f(self[i]) { - idx.append(i) + func indices(where function: (_ element: Element) -> Bool) -> [Int]? { + guard !self.isEmpty else { return nil } + + var idx: [Int] = [] + + for index in 0 ..< self.count { + if function(self[index]) { + idx.append(index) } } - guard idx.count > 0 else { return nil } + guard !idx.isEmpty else { return nil } return idx - } } diff --git a/ZcashLightClientKitTests/utils/SampleLogger.swift b/ZcashLightClientKitTests/utils/SampleLogger.swift index 10f58c4f..9cc50417 100644 --- a/ZcashLightClientKitTests/utils/SampleLogger.swift +++ b/ZcashLightClientKitTests/utils/SampleLogger.swift @@ -10,6 +10,7 @@ import Foundation import ZcashLightClientKit import os +// swiftlint:disable force_unwrapping print_function_usage class SampleLogger: ZcashLightClientKit.Logger { enum LogLevel: Int { case debug @@ -46,8 +47,8 @@ class SampleLogger: ZcashLightClientKit.Logger { } func warn(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) { - guard level.rawValue <= LogLevel.warning.rawValue else { return } - log(level: "WARNING ⚠️", message: message, file: file, function: function, line: line) + guard level.rawValue <= LogLevel.warning.rawValue else { return } + log(level: "WARNING ⚠️", message: message, file: file, function: function, line: line) } func event(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) { @@ -66,7 +67,14 @@ class SampleLogger: ZcashLightClientKit.Logger { case .printerLog: print("[\(level)] \(fileName) - \(function) - line: \(line) -> \(message)") default: - os_log("[%{public}@] %{public}@ - %{public}@ - Line: %{public}d -> %{public}@", level, fileName, String(describing: function), line, message) + os_log( + "[%{public}@] %{public}@ - %{public}@ - Line: %{public}d -> %{public}@", + level, + fileName, + String(describing: function), + line, + message + ) } } } diff --git a/ZcashLightClientKitTests/utils/Stubs.swift b/ZcashLightClientKitTests/utils/Stubs.swift index 67782546..70ea9a36 100644 --- a/ZcashLightClientKitTests/utils/Stubs.swift +++ b/ZcashLightClientKitTests/utils/Stubs.swift @@ -11,6 +11,7 @@ import GRPC import SwiftProtobuf @testable import ZcashLightClientKit +// swiftlint:disable function_parameter_count identifier_name class AwfulLightWalletService: MockLightWalletService { override func latestBlockHeight() throws -> BlockHeight { throw LightWalletServiceError.criticalError @@ -24,7 +25,6 @@ class AwfulLightWalletService: MockLightWalletService { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { result(.failure(LightWalletServiceError.invalidBlock)) } - } override func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) { @@ -33,56 +33,54 @@ class AwfulLightWalletService: MockLightWalletService { } } - override func submit(spendTransaction: Data, result: @escaping(Result) -> Void) { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - result(.failure(LightWalletServiceError.invalidBlock)) - } + override func submit(spendTransaction: Data, result: @escaping(Result) -> Void) { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + result(.failure(LightWalletServiceError.invalidBlock)) + } } - /** - Submits a raw transaction over lightwalletd. Blocking - */ - + /** + Submits a raw transaction over lightwalletd. Blocking + */ override func submit(spendTransaction: Data) throws -> LightWalletServiceResponse { throw LightWalletServiceError.invalidBlock } } class SlightlyBadLightWalletService: MockLightWalletService { - - - override func submit(spendTransaction: Data, result: @escaping(Result) -> Void) { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + override func submit(spendTransaction: Data, result: @escaping(Result) -> Void) { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { result(.success(LightWalletServiceMockResponse.error)) - } + } } - - /** - Submits a raw transaction over lightwalletd. Blocking - */ - + + /** + Submits a raw transaction over lightwalletd. Blocking + */ override func submit(spendTransaction: Data) throws -> LightWalletServiceResponse { LightWalletServiceMockResponse.error } } - extension LightWalletServiceMockResponse { static var error: LightWalletServiceMockResponse { - LightWalletServiceMockResponse(errorCode: -100, errorMessage: "Ohhh this is bad dude, really bad, you lost all your internet money", unknownFields: UnknownStorage()) + LightWalletServiceMockResponse( + errorCode: -100, + errorMessage: "Ohhh this is bad, really bad, you lost all your internet money", + unknownFields: UnknownStorage() + ) } + static var success: LightWalletServiceMockResponse { LightWalletServiceMockResponse(errorCode: 0, errorMessage: "", unknownFields: UnknownStorage()) } } class MockRustBackend: ZcashRustBackendWelding { - static func clearUtxos(dbData: URL, address: String, sinceHeight: BlockHeight, networkType: NetworkType) throws -> Int32 { -1 } - static func getNearestRewindHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Int32 { -1 } @@ -103,7 +101,16 @@ class MockRustBackend: ZcashRustBackendWelding { -1 } - static func putUnspentTransparentOutput(dbData: URL, address: String, txid: [UInt8], index: Int, script: [UInt8], value: Int64, height: BlockHeight, networkType: NetworkType) throws -> Bool { + static func putUnspentTransparentOutput( + dbData: URL, + address: String, + txid: [UInt8], + index: Int, + script: [UInt8], + value: Int64, + height: BlockHeight, + networkType: NetworkType + ) throws -> Bool { false } @@ -111,11 +118,31 @@ class MockRustBackend: ZcashRustBackendWelding { throw RustWeldingError.genericError(message: "unimplemented") } - static func createToAddress(dbData: URL, account: Int32, extsk: String, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 { + static func createToAddress( + dbData: URL, + account: Int32, + extsk: String, + to address: String, + value: Int64, + memo: String?, + spendParamsPath: String, + outputParamsPath: String, + networkType: NetworkType + ) -> Int64 { -1 } - static func shieldFunds(dbCache: URL, dbData: URL, account: Int32, tsk: String, extsk: String, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 { + static func shieldFunds( + dbCache: URL, + dbData: URL, + account: Int32, + tsk: String, + extsk: String, + memo: String?, + spendParamsPath: String, + outputParamsPath: String, + networkType: NetworkType + ) -> Int64 { -1 } @@ -171,12 +198,11 @@ class MockRustBackend: ZcashRustBackendWelding { nil } - static func consensusBranchIdFor(height: Int32, networkType: NetworkType) throws -> Int32 { - guard let c = consensusBranchID else { + guard let consensus = consensusBranchID else { return try rustBackend.consensusBranchIdFor(height: height, networkType: networkType) } - return c + return consensus } static var networkType = NetworkType.testnet @@ -225,9 +251,23 @@ class MockRustBackend: ZcashRustBackendWelding { mockAccounts ?? rustBackend.initAccountsTable(dbData: dbData, seed: seed, accounts: accounts, networkType: networkType) } - static func initBlocksTable(dbData: URL, height: Int32, hash: String, time: UInt32, saplingTree: String, networkType: NetworkType) throws { + static func initBlocksTable( + dbData: URL, + height: Int32, + hash: String, + time: UInt32, + saplingTree: String, + networkType: NetworkType + ) throws { if !mockDataDb { - try rustBackend.initBlocksTable(dbData: dbData, height: height, hash: hash, time: time, saplingTree: saplingTree, networkType: networkType) + try rustBackend.initBlocksTable( + dbData: dbData, + height: height, + hash: hash, + time: time, + saplingTree: saplingTree, + networkType: networkType + ) } } @@ -263,7 +303,6 @@ class MockRustBackend: ZcashRustBackendWelding { if attempts > 0 { return validationResult(dbCache: dbCache, dbData: dbData, networkType: networkType) } else { - if attempts == 0 { return Int32(mockValidateCombinedChainFailureHeight) } else if attempts < 0 && mockValidateCombinedChainKeepFailing { @@ -276,7 +315,7 @@ class MockRustBackend: ZcashRustBackendWelding { return rustBackend.validateCombinedChain(dbCache: dbCache, dbData: dbData, networkType: networkType) } - private static func validationResult(dbCache: URL, dbData: URL, networkType: NetworkType) -> Int32{ + private static func validationResult(dbCache: URL, dbData: URL, networkType: NetworkType) -> Int32 { if mockDataDb { return -1 } else { @@ -290,7 +329,6 @@ class MockRustBackend: ZcashRustBackendWelding { static func scanBlocks(dbCache: URL, dbData: URL, limit: UInt32, networkType: NetworkType) -> Bool { if let rate = mockScanblocksSuccessRate { - if shouldSucceed(successRate: rate) { return mockDataDb ? true : rustBackend.scanBlocks(dbCache: dbCache, dbData: dbData, networkType: networkType) } else { @@ -300,8 +338,18 @@ class MockRustBackend: ZcashRustBackendWelding { return rustBackend.scanBlocks(dbCache: dbCache, dbData: dbData, networkType: Self.networkType) } - static func createToAddress(dbData: URL, account: Int32, extsk: String, consensusBranchId: Int32, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 { -// mockCreateToAddress ?? rustBackend.createToAddress(dbData: dbData, account: account, extsk: extsk, consensusBranchId: consensusBranchId, to: to, value: value, memo: memo, spendParamsPath: spendParamsPath, outputParamsPath: outputParamsPath) + static func createToAddress( + dbData: URL, + account: Int32, + extsk: String, + consensusBranchId: Int32, + to address: String, + value: Int64, + memo: String?, + spendParamsPath: String, + outputParamsPath: String, + networkType: NetworkType + ) -> Int64 { -1 } @@ -325,5 +373,4 @@ class MockRustBackend: ZcashRustBackendWelding { static func decryptAndStoreTransaction(dbData: URL, txBytes: [UInt8], minedHeight: Int32, networkType: NetworkType) -> Bool { false } - } diff --git a/ZcashLightClientKitTests/utils/TestDbBuilder.swift b/ZcashLightClientKitTests/utils/TestDbBuilder.swift index 89ab94e7..1855d5cb 100644 --- a/ZcashLightClientKitTests/utils/TestDbBuilder.swift +++ b/ZcashLightClientKitTests/utils/TestDbBuilder.swift @@ -16,7 +16,11 @@ struct TestDbHandle { init(originalDb: URL) { self.originalDb = originalDb - self.readWriteDb = FileManager.default.temporaryDirectory.appendingPathComponent(self.originalDb.lastPathComponent.appending("_\(Date().timeIntervalSince1970)")) // avoid files clashing because crashing tests failed to remove previous ones by incrementally changing the filename + // avoid files clashing because crashing tests failed to remove previous ones by incrementally changing the filename + self.readWriteDb = FileManager.default.temporaryDirectory + .appendingPathComponent( + self.originalDb.lastPathComponent.appending("_\(Date().timeIntervalSince1970)") + ) } func setUp() throws { @@ -32,8 +36,9 @@ struct TestDbHandle { } } +// This requires reference semantics, an enum cannot be used +// swiftlint:disable:next convenience_type class TestDbBuilder { - enum TestBuilderError: Error { case generalError } @@ -41,18 +46,21 @@ class TestDbBuilder { static func inMemoryCompactBlockStorage() throws -> CompactBlockStorage { let compactBlockDao = CompactBlockStorage(connectionProvider: try InMemoryDbProvider()) try compactBlockDao.createTable() + return compactBlockDao } static func diskCompactBlockStorage(at url: URL) throws -> CompactBlockStorage { let compactBlockDao = CompactBlockStorage(connectionProvider: SimpleConnectionProvider(path: url.absoluteString)) try compactBlockDao.createTable() + return compactBlockDao } static func pendingTransactionsDbURL() throws -> URL { try __documentsDirectory().appendingPathComponent("pending.db") } + static func prePopulatedCacheDbURL() -> URL? { Bundle(for: TestDbBuilder.self).url(forResource: "cache", withExtension: "db") } @@ -65,6 +73,7 @@ class TestDbBuilder { let bundle = Bundle(for: TestDbBuilder.self) guard let url = bundle.url(forResource: "ZcashSdk_Data", withExtension: "db") else { return nil } let provider = SimpleConnectionProvider(path: url.absoluteString, readonly: true) + return provider } @@ -85,7 +94,6 @@ class TestDbBuilder { } static func seed(db: CompactBlockRepository, with blockRange: CompactBlockRange) throws { - guard let blocks = StubBlockCreator.createBlockRange(blockRange) else { throw TestBuilderError.generalError } @@ -96,8 +104,8 @@ class TestDbBuilder { struct InMemoryDbProvider: ConnectionProvider { var readonly: Bool - var conn: Connection + init(readonly: Bool = false) throws { self.readonly = readonly self.conn = try Connection(.inMemory, readonly: readonly) @@ -108,7 +116,7 @@ struct InMemoryDbProvider: ConnectionProvider { } } -struct StubBlockCreator { +enum StubBlockCreator { static func createRandomDataBlock(with height: BlockHeight) -> ZcashCompactBlock? { guard let data = randomData(ofLength: 100) else { LoggerProxy.debug("error creating stub block") @@ -116,9 +124,9 @@ struct StubBlockCreator { } return ZcashCompactBlock(height: height, data: data) } + static func createBlockRange(_ range: CompactBlockRange) -> [ZcashCompactBlock]? { - - var blocks = [ZcashCompactBlock]() + var blocks: [ZcashCompactBlock] = [] for height in range { guard let block = createRandomDataBlock(with: height) else { return nil @@ -136,8 +144,7 @@ struct StubBlockCreator { return Data(bytes: &bytes, count: bytes.count) } LoggerProxy.debug("Status \(status)") + return nil - } - } diff --git a/ZcashLightClientKitTests/utils/Tests+Utils.swift b/ZcashLightClientKitTests/utils/Tests+Utils.swift index 818b152e..c43f64de 100644 --- a/ZcashLightClientKitTests/utils/Tests+Utils.swift +++ b/ZcashLightClientKitTests/utils/Tests+Utils.swift @@ -11,7 +11,9 @@ import GRPC import ZcashLightClientKit import XCTest import NIO -class LightWalletEndpointBuilder { + +// swiftlint:disable identifier_name +enum LightWalletEndpointBuilder { static var `default`: LightWalletEndpoint { LightWalletEndpoint(address: Constants.address, port: 9067, secure: false) } @@ -29,23 +31,25 @@ class ChannelProvider { func channel(secure: Bool = false) -> GRPCChannel { let endpoint = LightWalletEndpointBuilder.default - let configuration = ClientConnection.Configuration(target: .hostAndPort(endpoint.host, endpoint.port), eventLoopGroup: MultiThreadedEventLoopGroup(numberOfThreads: 1), tls: secure ? .init() : nil) + let configuration = ClientConnection.Configuration( + target: .hostAndPort(endpoint.host, endpoint.port), + eventLoopGroup: MultiThreadedEventLoopGroup(numberOfThreads: 1), + tls: secure ? .init() : nil + ) + return ClientConnection(configuration: configuration) - } } -struct MockDbInit { - @discardableResult static func emptyFile(at path: String) -> Bool { - +enum MockDbInit { + @discardableResult + static func emptyFile(at path: String) -> Bool { FileManager.default.createFile(atPath: path, contents: Data("".utf8), attributes: nil) - } static func destroy(at path: String) throws { try FileManager.default.removeItem(atPath: path) } - } extension XCTestExpectation { @@ -83,7 +87,6 @@ func __outputParamsURL() throws -> URL { } func copyParametersToDocuments() throws -> (spend: URL, output: URL) { - let spendURL = try __documentsDirectory().appendingPathComponent("sapling-spend.params", isDirectory: false) let outputURL = try __documentsDirectory().appendingPathComponent("sapling-output.params", isDirectory: false) try FileManager.default.copyItem(at: try __spendParamsURL(), to: spendURL) @@ -94,37 +97,42 @@ func copyParametersToDocuments() throws -> (spend: URL, output: URL) { func deleteParametersFromDocuments() throws { let documents = try __documentsDirectory() - deleteParamsFrom(spend: documents.appendingPathComponent("sapling-spend.params"), output: documents.appendingPathComponent("sapling-output.params")) + deleteParamsFrom( + spend: documents.appendingPathComponent("sapling-spend.params"), + output: documents.appendingPathComponent("sapling-output.params") + ) } -func deleteParamsFrom(spend: URL, output: URL) { +func deleteParamsFrom(spend: URL, output: URL) { try? FileManager.default.removeItem(at: spend) try? FileManager.default.removeItem(at: output) } func parametersReady() -> Bool { - - guard let output = try? __outputParamsURL(), - let spend = try? __spendParamsURL(), - FileManager.default.isReadableFile(atPath: output.absoluteString), - FileManager.default.isReadableFile(atPath: spend.absoluteString) else { - return false + guard + let output = try? __outputParamsURL(), + let spend = try? __spendParamsURL(), + FileManager.default.isReadableFile(atPath: output.absoluteString), + FileManager.default.isReadableFile(atPath: spend.absoluteString) + else { + return false } + return true } class StubTest: XCTestCase {} + extension Bundle { static var testBundle: Bundle { Bundle(for: StubTest.self) } } - +// swiftlint:disable force_unwrapping class TestSeed { - /** - test account: "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" - */ + test account: "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" + */ let seedString = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")! func seed() -> [UInt8] {