SwiftLint Enabled on Test Folder

This commit is contained in:
Adam Stener 2021-09-23 08:26:41 -05:00
parent db5f02dbf9
commit 78b1f937ba
41 changed files with 3068 additions and 2246 deletions

View File

@ -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

View File

@ -7,11 +7,15 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional force_unwrapping type_body_length
class AdvancedReOrgTests: XCTestCase {
// 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"
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
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
let sendAmount: Int64 = 1000
var birthday: BlockHeight = 663150
@ -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,15 +51,16 @@ 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
}
logger!.debug("--- REORG DETECTED \(reorgHeight)--- RewindHeight: \(rewindHeight)", file: #file, function: #function, line: #line)
// XCTAssertEqual(rewindHeight, expectedRewindHeight)
XCTAssertEqual(reorgHeight, expectedReorgHeight)
reorgExpectation.fulfill()
}
@ -91,15 +97,18 @@ class AdvancedReOrgTests: XCTestCase {
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()
try coordinator.sync(
completion: { synchro in
synchronizer = synchro
initialVerifiedBalance = synchro.initializer.getVerifiedBalance()
initialTotalBalance = synchro.initializer.getBalance()
preTxExpectation.fulfill()
shouldContinue = true
}, error: self.handleError)
},
error: self.handleError
)
wait(for: [preTxExpectation], timeout: 10)
@ -111,28 +120,26 @@ class AdvancedReOrgTests: XCTestCase {
/*
2. applyStaged(received_Tx_height)
*/
try coordinator.applyStaged(blockheight: receivedTxHeight)
sleep(2)
/*
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
*/
XCTAssertEqual(receivedTxTotalBalance, initialTotalBalance + Int64(receivedTx.value))
XCTAssertEqual(receivedTxVerifiedBalance, initialVerifiedBalance)
/*
4. get that transaction hex encoded data
*/
guard let receivedTxData = receivedTx.raw else {
XCTFail("received tx has no raw data!")
return
@ -166,33 +171,30 @@ class AdvancedReOrgTests: XCTestCase {
/*
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
*/
let reorgedTxheight = receivedTxHeight + 2
try coordinator.stageTransaction(receivedRawTx, at: reorgedTxheight)
/*
6a. applyheight(received_Tx_height + 1)
*/
try coordinator.applyStaged(blockheight: receivedTxHeight + 1)
sleep(2)
/*
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()
@ -203,17 +205,16 @@ class AdvancedReOrgTests: XCTestCase {
*/
sleep(2)
wait(for: [reorgExpectation, reorgSyncexpectation], timeout: 5, enforceOrder: false)
/*
9. verify that balance equals initial balance
*/
XCTAssertEqual(afterReorgTxVerifiedBalance, initialVerifiedBalance)
XCTAssertEqual(afterReorgTxTotalBalance, initialTotalBalance)
/*
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()
@ -282,7 +283,7 @@ class AdvancedReOrgTests: XCTestCase {
/*
3. sync up to received_Tx_height
*/
try coordinator.sync(completion: { (synchronizer) in
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
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,7 +315,7 @@ 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
}
@ -338,21 +346,20 @@ class AdvancedReOrgTests: XCTestCase {
/*
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)
},
error: self.handleError
)
wait(for: [sentTxSyncExpectation], timeout: 5)
/*
8. stage sentTx and otherTx at sentTxheight
*/
@ -367,32 +374,33 @@ class AdvancedReOrgTests: XCTestCase {
sleep(2)
let afterReOrgExpectation = XCTestExpectation(description: "after ReOrg Expectation")
try coordinator.sync(completion: { (s) in
try coordinator.sync(
completion: { synchronizer in
/*
11. verify that the sent tx is mined and balance is correct
*/
let pMinedHeight = s.pendingTransactions.first?.minedHeight
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
XCTAssertEqual(pMinedHeight, sentTxHeight)
XCTAssertEqual(initialTotalBalance - sendAmount - Int64(1000), s.initializer.getBalance()) // fee change on this branch
XCTAssertEqual(initialTotalBalance - sendAmount - Int64(1000), synchronizer.initializer.getBalance()) // fee change on this branch
afterReOrgExpectation.fulfill()
}, error: self.handleError)
},
error: self.handleError
)
wait(for: [afterReOrgExpectation], timeout: 5)
/*
12. applyStaged(sentTx + 10)
*/
try coordinator.applyStaged(blockheight: sentTxHeight + 12)
sleep(2)
/*
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
*/
try coordinator.resetBlocks(dataset: .predefined(dataset: .txIndexChangeAfter))
try coordinator.applyStaged(blockheight: 663200)
@ -437,7 +443,7 @@ 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()
@ -447,7 +453,6 @@ class AdvancedReOrgTests: XCTestCase {
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,7 +517,6 @@ class AdvancedReOrgTests: XCTestCase {
XCTAssertEqual(afterReOrgBalance, initialBalance)
XCTAssertEqual(afterReOrgVerifiedBalance, initialVerifiedBalance)
}
/**
@ -532,14 +540,12 @@ class AdvancedReOrgTests: XCTestCase {
/*
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)
@ -551,18 +557,19 @@ class AdvancedReOrgTests: XCTestCase {
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
})
/*
@ -574,7 +581,6 @@ class AdvancedReOrgTests: XCTestCase {
/*
3. stage otherTx at incomingTxHeight
*/
try coordinator.stageTransaction(url: FakeChainBuilder.someOtherTxUrl, at: incomingTxHeight)
/*
@ -588,14 +594,14 @@ class AdvancedReOrgTests: XCTestCase {
/*
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
try coordinator.sync(completion: { _ in
lastSyncExpectation.fulfill()
}, error: self.handleError)
@ -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()
@ -632,7 +637,7 @@ 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)
@ -670,6 +675,7 @@ class AdvancedReOrgTests: XCTestCase {
*/
func testReOrgChangesOutboundTxMinedHeight() throws {
hookToReOrgNotification()
/*
1. create fake chain
*/
@ -682,7 +688,7 @@ class AdvancedReOrgTests: XCTestCase {
/*
1a. sync to latest height
*/
try coordinator.sync(completion: { (s) in
try coordinator.sync(completion: { _ in
firstSyncExpectation.fulfill()
}, error: self.handleError)
@ -692,28 +698,36 @@ 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
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
pendingEntity = pendingTx
}
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
*/
@ -725,14 +739,13 @@ class AdvancedReOrgTests: XCTestCase {
let sentTxHeight: BlockHeight = 663189
/*
4. stage transaction at sentTxHeight
*/
try coordinator.stageBlockCreate(height: sentTxHeight)
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
/*
5. applyHeight(sentTxHeight)
*/
@ -745,7 +758,7 @@ class AdvancedReOrgTests: XCTestCase {
*/
let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
try coordinator.sync(completion: { (s) in
try coordinator.sync(completion: { _ in
secondSyncExpectation.fulfill()
}, error: self.handleError)
@ -759,7 +772,6 @@ class AdvancedReOrgTests: XCTestCase {
/*
6a. verify that there's a pending transaction with a mined height of sentTxHeight
*/
XCTAssertEqual(afterStagePendingTx.minedHeight, sentTxHeight)
/*
@ -784,7 +796,7 @@ class AdvancedReOrgTests: XCTestCase {
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)
@ -807,23 +819,20 @@ class AdvancedReOrgTests: XCTestCase {
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
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)
guard let newlyPendingTx = try coordinator.synchronizer.allPendingTransactions().first else {
XCTFail("no pending transaction")
@ -836,17 +845,16 @@ class AdvancedReOrgTests: XCTestCase {
/*
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
try coordinator.sync(completion: { _ in
thisIsTheLastExpectationIPromess.fulfill()
}, error: self.handleError)
@ -855,18 +863,29 @@ class AdvancedReOrgTests: XCTestCase {
/*
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 }
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())
}
),
"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.
@ -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,8 +945,8 @@ 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:
@ -958,7 +975,7 @@ class AdvancedReOrgTests: XCTestCase {
/**
1. sync prior to incomingTxHeight - 1 to get balances there
*/
try coordinator.sync(completion: { (s) in
try coordinator.sync(completion: { _ in
firstSyncExpectation.fulfill()
}, error: self.handleError)
@ -974,7 +991,7 @@ class AdvancedReOrgTests: XCTestCase {
/**
2. sync to latest height
*/
try coordinator.sync(completion: { (s) in
try coordinator.sync(completion: { _ in
secondSyncExpectation.fulfill()
}, error: self.handleError)
@ -989,7 +1006,7 @@ class AdvancedReOrgTests: XCTestCase {
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)
@ -1024,14 +1041,14 @@ class AdvancedReOrgTests: XCTestCase {
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
try coordinator.sync(completion: { _ in
firstSyncExpectation.fulfill()
}, error: self.handleError)
@ -1040,30 +1057,37 @@ 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
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
pendingEntity = pendingTx
}
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
*/
@ -1074,13 +1098,14 @@ class AdvancedReOrgTests: XCTestCase {
}
self.expectedReorgHeight = sentTxHeight + 1
/*
4. stage transaction at sentTxHeight
*/
try coordinator.stageBlockCreate(height: sentTxHeight)
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
/*
5. applyHeight(sentTxHeight)
*/
@ -1093,7 +1118,7 @@ class AdvancedReOrgTests: XCTestCase {
*/
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,18 +1151,16 @@ 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()
/*
@ -1152,10 +1175,11 @@ class AdvancedReOrgTests: XCTestCase {
sleep(10)
let firstSyncExpectation = XCTestExpectation(description: "first sync")
/*
sync to latest height
*/
try coordinator.sync(completion: { (s) in
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)
}
}

View File

@ -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()
override func setUpWithError() throws {
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,7 +36,6 @@ class BalanceTests: XCTestCase {
network: network
)
try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main")
}
/**
@ -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,12 +76,15 @@ class BalanceTests: XCTestCase {
XCTFail("failed to create spending keys")
return
}
var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
coordinator.synchronizer.sendToAddress(
spendingKey: spendingKey,
zatoshi: maxBalance,
toAddress: testRecipientAddress,
memo: "test send \(self.description) \(Date().description)",
from: 0) { result in
from: 0,
resultBlock: { result in
switch result {
case .failure(let error):
XCTFail("sendToAddress failed: \(error)")
@ -85,20 +93,21 @@ class BalanceTests: XCTestCase {
}
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 {
@ -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)
try coordinator.sync(
completion: { synchronizer in
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
XCTAssertTrue(pendingEntity?.isMined ?? false)
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
mineExpectation.fulfill()
}, error: { (error) in
guard let e = error else {
},
error: { error in
guard let error = error else {
XCTFail("unknown error syncing after sending transaction")
return
}
XCTFail("Error: \(e)")
})
XCTFail("Error: \(error)")
}
)
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,7 +182,6 @@ class BalanceTests: XCTestCase {
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 0)
}
/**
verify that when sending the maximum amount minus one zatoshi, the transactions are broadcasted properly
*/
@ -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,12 +220,15 @@ class BalanceTests: XCTestCase {
XCTFail("failed to create spending keys")
return
}
var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
coordinator.synchronizer.sendToAddress(
spendingKey: spendingKey,
zatoshi: maxBalanceMinusOne,
toAddress: testRecipientAddress,
memo: "test send \(self.description) \(Date().description)",
from: 0) { result in
from: 0,
resultBlock: { result in
switch result {
case .failure(let error):
XCTFail("sendToAddress failed: \(error)")
@ -223,20 +237,21 @@ class BalanceTests: XCTestCase {
}
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 {
@ -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")
@ -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,11 +363,13 @@ class BalanceTests: XCTestCase {
return
}
var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
coordinator.synchronizer.sendToAddress(
spendingKey: spendingKey,
zatoshi: maxBalanceMinusOne,
toAddress: testRecipientAddress,
memo: "test send \(self.description) \(Date().description)",
from: 0) { result in
from: 0,
resultBlock: { result in
switch result {
case .failure(let error):
XCTFail("sendToAddress failed: \(error)")
@ -360,20 +378,21 @@ class BalanceTests: XCTestCase {
}
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 {
@ -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,15 +455,17 @@ 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.
@ -460,16 +480,14 @@ class BalanceTests: XCTestCase {
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)
@ -488,11 +506,13 @@ class BalanceTests: XCTestCase {
XCTAssertTrue(presendVerifiedBalance >= (Int64(network.constants.defaultFee(for: defaultLatestHeight)) + sendAmount))
var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
coordinator.synchronizer.sendToAddress(
spendingKey: spendingKey,
zatoshi: Int64(sendAmount),
toAddress: testRecipientAddress,
memo: "test send \(self.description) \(Date().description)",
from: 0) { result in
from: 0,
resultBlock: { result in
switch result {
case .failure(let error):
/*
@ -503,10 +523,10 @@ class BalanceTests: XCTestCase {
case .success(let transaction):
pendingTx = transaction
}
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,13 +560,21 @@ 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
*/
@ -561,40 +587,54 @@ class BalanceTests: XCTestCase {
XCTFail("sent transaction has no internal id")
return
}
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 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 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,
self.verifiedBalanceValidation(
previousBalance: presendVerifiedBalance,
spentNoteValue: Int64(sentNote.value),
changeValue: Int64(receivedNote.value),
sentAmount: Int64(self.sendAmount),
currentVerifiedBalance: self.coordinator.synchronizer.initializer.getVerifiedBalance())
currentVerifiedBalance: self.coordinator.synchronizer.initializer.getVerifiedBalance()
)
}
/**
@ -619,7 +659,7 @@ class BalanceTests: XCTestCase {
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,
coordinator.synchronizer.sendToAddress(
spendingKey: spendingKey,
zatoshi: Int64(sendAmount),
toAddress: testRecipientAddress,
memo: "test send \(self.description) \(Date().description)",
from: 0) { result in
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):
case .success(let transaction):
pendingTx = transaction
}
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)
@ -686,9 +732,9 @@ class BalanceTests: XCTestCase {
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,7 +745,10 @@ 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()
)
}
/**
@ -720,7 +769,7 @@ class BalanceTests: XCTestCase {
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)
@ -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
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()
@ -786,18 +832,26 @@ class BalanceTests: XCTestCase {
*/
let memo = "shielding is fun!"
var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress(spendingKey: spendingKeys, zatoshi: Int64(sendAmount), toAddress: testRecipientAddress, memo: memo, from: 0) { (sendResult) in
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 tx):
pendingTx = tx
case .success(let transaction):
pendingTx = transaction
}
sendExpectation.fulfill()
}
}
)
wait(for: [createToAddressExpectation], timeout: 30)
let syncToMinedheightExpectation = XCTestExpectation(description: "sync to mined height + 1")
@ -820,15 +874,13 @@ class BalanceTests: XCTestCase {
/*
Sync to that block
*/
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(
completion: { synchronizer in
let confirmedTx: ConfirmedTransactionEntity!
do {
confirmedTx = try synchronizer.allClearedTransactions().first(where: { (confirmed) -> Bool in
confirmedTx = try synchronizer.allClearedTransactions().first(where: { confirmed -> Bool in
confirmed.transactionEntity.transactionId == pendingTx?.transactionEntity.transactionId
})
} catch {
XCTFail("Error retrieving cleared transactions")
return
@ -837,10 +889,8 @@ class BalanceTests: XCTestCase {
/*
Theres 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 {
@ -851,14 +901,24 @@ class BalanceTests: XCTestCase {
/*
Find out what note was used
*/
let sentNotesRepo = SentNotesSQLDAO(dbProvider: SimpleConnectionProvider(path: synchronizer.initializer.dataDbURL.absoluteString, readonly: true))
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))
let receivedNotesRepo = ReceivedNotesSQLDAO(
dbProvider: SimpleConnectionProvider(
path: self.coordinator.synchronizer.initializer.dataDbURL.absoluteString,
readonly: true
)
)
/*
get change note
@ -871,34 +931,38 @@ class BalanceTests: XCTestCase {
/*
Theres a change note of value (previous note value - sent amount)
*/
XCTAssertEqual(previousVerifiedBalance - self.sendAmount - self.network.constants.defaultFee(for: self.defaultLatestHeight), Int64(receivedNote.value))
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())
currentVerifiedBalance: synchronizer.initializer.getVerifiedBalance()
)
self.totalBalanceValidation(totalBalance: synchronizer.initializer.getBalance(),
self.totalBalanceValidation(
totalBalance: synchronizer.initializer.getBalance(),
previousTotalbalance: previousTotalBalance,
sentAmount: Int64(self.sendAmount))
sentAmount: Int64(self.sendAmount)
)
syncToMinedheightExpectation.fulfill()
}, error: self.handleError)
},
error: self.handleError
)
wait(for: [syncToMinedheightExpectation], timeout: 5)
}
/**
Verify transactions that expire are reflected accurately in balance
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?
@ -921,18 +985,16 @@ class BalanceTests: XCTestCase {
*/
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,7 +1004,13 @@ 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
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
@ -953,6 +1021,8 @@ class BalanceTests: XCTestCase {
pendingTx = pending
}
}
)
wait(for: [sendExpectation], timeout: 12)
guard let pendingTransaction = pendingTx, pendingTransaction.expiryHeight > defaultLatestHeight else {
@ -967,7 +1037,7 @@ 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)
@ -983,7 +1053,11 @@ class BalanceTests: XCTestCase {
*/
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 {
@ -994,13 +1068,12 @@ class BalanceTests: XCTestCase {
/*
there no sent transaction displayed
*/
XCTAssertNil( try coordinator.synchronizer.allSentTransactions().first(where: { $0.id == id }))
/*
Theres a pending transaction that has expired
*/
XCTAssertEqual(expiredPending.minedHeight, -1)
}
func handleError(_ error: Error?) {
@ -1014,26 +1087,28 @@ class BalanceTests: XCTestCase {
/**
check if (previous available funds - spent note + change) equals to (previous available funds - sent amount)
*/
func verifiedBalanceValidation(previousBalance: Int64,
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)
currentVerifiedBalance: Int64
) {
XCTAssertEqual(previousBalance - spentNoteValue + changeValue, currentVerifiedBalance - sentAmount)
}
func totalBalanceValidation(totalBalance: Int64,
func totalBalanceValidation(
totalBalance: Int64,
previousTotalbalance: Int64,
sentAmount: 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)
}
}
}

View File

@ -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 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 {
@ -65,10 +85,23 @@ class BlockBatchValidationTests: XCTestCase {
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 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,6 +132,7 @@ class BlockBatchValidationTests: XCTestCase {
XCTFail("Expected CompactBlockProcessorError.networkMismatch but found \(error)")
}
}
queue.addOperations([operation], waitUntilFinished: false)
wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true)
@ -103,13 +140,25 @@ class BlockBatchValidationTests: XCTestCase {
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 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,6 +189,7 @@ class BlockBatchValidationTests: XCTestCase {
XCTFail("Expected CompactBlockProcessorError.generalError but found \(error)")
}
}
queue.addOperations([operation], waitUntilFinished: false)
wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true)
@ -146,10 +199,24 @@ class BlockBatchValidationTests: XCTestCase {
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,26 +224,33 @@ 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 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)
@ -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 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)
XCTAssertNil(operation.error)
XCTAssertFalse(operation.isCancelled)
guard let result = operation.result else {
XCTFail("result should not be nil")
return
}
XCTAssertTrue({
XCTAssertTrue(
{
switch result {
case .wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight):
return true
default:
return false
}
}(), "Expected \(expectedResult) got: \(result)")
}(),
"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 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)
XCTAssertNil(operation.error)
XCTAssertFalse(operation.isCancelled)
guard let result = operation.result else {
XCTFail("result should not be nil")
return
}
XCTAssertTrue({
XCTAssertTrue(
{
switch result {
case .processNewBlocks(range: CompactBlockRange(uncheckedBounds: (expectedStoreLatestHeight + 1, expectedLatestHeight))):
return true
default:
return false
}
}(), "Expected \(expectedResult) got: \(result)")
}(),
"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 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)
XCTAssertNil(operation.error)
XCTAssertFalse(operation.isCancelled)
guard let result = operation.result else {
XCTFail("result should not be nil")
return
}
XCTAssertTrue({
XCTAssertTrue(
{
switch result {
case .finishProcessing(height: expectedLatestHeight):
return true
default:
return false
}
}(), "Expected \(expectedResult) got: \(result)")
}(),
"Expected \(expectedResult) got: \(result)"
)
}
}

View File

@ -8,17 +8,21 @@
import XCTest
@testable import ZcashLightClientKit
class BlockDownloaderTests: XCTestCase {
// 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
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,7 +68,6 @@ class BlockDownloaderTests: XCTestCase {
}
func testSmallDownload() {
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
@ -84,17 +86,22 @@ 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
@ -103,7 +110,7 @@ class BlockDownloaderTests: XCTestCase {
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
awfulDownloader.downloadBlockRange(range) { (error) in
awfulDownloader.downloadBlockRange(range) { error in
expect.fulfill()
XCTAssertNotNil(error)
}
@ -115,13 +122,11 @@ class BlockDownloaderTests: XCTestCase {
extension BlockDownloaderTests {
func validate(result: Result<BlockHeight, Error>, against height: BlockHeight) -> Bool {
switch result {
case .success(let resultHeight):
return resultHeight == height
default:
return false
}
}
}

View File

@ -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 uvk = UVFakeKey(
extfvk: "zxviewtestsapling1qw88ayg8qqqqpqyhg7jnh9mlldejfqwu46pm40ruwstd8znq3v3l4hjf33qcu2a5e36katshcfhcxhzgyfugj2lkhmt40j45cv38rv3frnghzkxcx73k7m7afw9j7ujk7nm4dx5mv02r26umxqgar7v3x390w2h3crqqgjsjly7jy4vtwzrmustm5yudpgcydw7x78awca8wqjvkqj8p8e3ykt7lrgd7xf92fsfqjs5vegfsja4ekzpfh5vtccgvs5747xqm6qflmtqpr8s9u", // swiftlint:disable:this line_length
extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61"
)
var walletBirthDay = WalletBirthday.birthday(with: 1386000, network: ZcashNetworkBuilder.network(for: .testnet))
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 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)
operationQueue.addOperations(
[downloadOperation, scanOperation, latestScannedBlockOperation],
waitUntilFinished: false
)
wait(for: [downloadStartedExpect, downloadExpect, scanStartedExpect, scanExpect,latestScannedBlockExpect], timeout: 10, enforceOrder: true)
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,
let downloadOperation = CompactBlockStreamDownloadOperation(
service: service,
storage: storage,
startHeight: walletBirthDay.height,
targetHeight: walletBirthDay.height + 10000,
progressDelegate: self)
progressDelegate: self
)
downloadOperation.completionHandler = { (finished, cancelled) in
downloadOperation.completionHandler = { finished, cancelled in
XCTAssert(finished)
XCTAssertFalse(cancelled)
downloadExpectation.fulfill()
@ -160,27 +208,44 @@ 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)
@ -189,11 +254,9 @@ class BlockScanOperationTests: XCTestCase {
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

View File

@ -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,
let service = LightWalletGRPCService(
host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 1000,
streamingCallTimeout: 100000)
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,
let service = LightWalletGRPCService(
host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 10000,
streamingCallTimeout: 10000)
streamingCallTimeout: 10000
)
let storage = try TestDbBuilder.inMemoryCompactBlockStorage()
let startHeight = try service.latestBlockHeight() - 100_000
let operation = CompactBlockStreamDownloadOperation(service: service,
let operation = CompactBlockStreamDownloadOperation(
service: service,
storage: storage,
startHeight: startHeight,
progressDelegate: self)
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,
let service = LightWalletGRPCService(
host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 1000,
streamingCallTimeout: 3000)
streamingCallTimeout: 3000
)
let storage = try TestDbBuilder.inMemoryCompactBlockStorage()
let startHeight = try service.latestBlockHeight() - 100_000
let operation = CompactBlockStreamDownloadOperation(service: service,
let operation = CompactBlockStreamDownloadOperation(
service: service,
storage: storage,
startHeight: startHeight,
progressDelegate: self)
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,
let service = LightWalletGRPCService(
host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 300000,
streamingCallTimeout: 10000)
streamingCallTimeout: 10000
)
let storage = try TestDbBuilder.diskCompactBlockStorage(at: __dataDbURL() )
let targetHeight = try service.latestBlockHeight()
let startHeight = targetHeight - 10_000
let operation = CompactBlockBatchDownloadOperation(service: service,
let operation = CompactBlockBatchDownloadOperation(
service: service,
storage: storage,
startHeight: startHeight, targetHeight: targetHeight,
progressDelegate: self)
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,
let service = LightWalletGRPCService(
host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 300000,
streamingCallTimeout: 10000)
streamingCallTimeout: 10000
)
let storage = try TestDbBuilder.diskCompactBlockStorage(at: __dataDbURL() )
let targetHeight = try service.latestBlockHeight()
let startHeight = targetHeight - 100_000
let operation = CompactBlockBatchDownloadOperation(service: service,
let operation = CompactBlockBatchDownloadOperation(
service: service,
storage: storage,
startHeight: startHeight, targetHeight: targetHeight,
progressDelegate: self)
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))")
}
}

View File

@ -8,9 +8,13 @@
import XCTest
@testable import ZcashLightClientKit
class CompactBlockProcessorTests: XCTestCase {
let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight)
// 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
)
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,
processor = CompactBlockProcessor(
service: service,
storage: storage,
backend: ZcashRustBackend.self,
config: processorConfig)
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,26 +110,30 @@ class CompactBlockProcessorTests: XCTestCase {
}
func testStartNotifiesSuscriptors() {
startProcessing()
wait(for: [
wait(
for: [
downloadStartedExpect,
startedValidatingNotificationExpectation,
startedScanningNotificationExpectation,
idleNotificationExpectation,
], timeout: 30,enforceOrder: true)
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 {
@ -120,14 +141,20 @@ class CompactBlockProcessorTests: XCTestCase {
}
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)
}
}

View File

@ -6,12 +6,15 @@
//
// Copyright © 2019 Electric Coin Company. All rights reserved.
import XCTest
@testable import ZcashLightClientKit
class CompactBlockReorgTests: XCTestCase {
let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight)
// 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
)
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,
processor = CompactBlockProcessor(
service: service,
storage: storage,
backend: mockBackend,
config: processorConfig)
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,7 +105,6 @@ 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 {
@ -96,17 +118,15 @@ class CompactBlockReorgTests: XCTestCase {
}
@objc func processorFailed(_ notification: Notification) {
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: [
wait(
for: [
downloadStartedExpect,
startedValidatingNotificationExpectation,
startedScanningNotificationExpectation,
reorgNotificationExpectation,
idleNotificationExpectation,
], timeout: 300,enforceOrder: true)
idleNotificationExpectation
],
timeout: 300,
enforceOrder: true
)
}
private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int {
(abs(currentHeight - targetHeight) / batchSize)
}
}

View File

@ -8,12 +8,13 @@
import Foundation
import XCTest
// swiftlint:disable force_try
@testable import ZcashLightClientKit
class CompactBlockStorageTests: XCTestCase {
let network = ZcashNetworkBuilder.network(for: .testnet)
var compactBlockDao: CompactBlockRepository = try! TestDbBuilder.inMemoryCompactBlockStorage()
let network = ZcashNetworkBuilder.network(for: .testnet)
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)")
}
}
}

View File

@ -8,11 +8,14 @@
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
@ -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
try coordinator.sync(
completion: { _ in
syncExpectation.fulfill()
}, error: { (error) in
},
error: { error in
guard let e = error else {
XCTFail("failed with unknown error")
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)
}
}

View File

@ -9,12 +9,14 @@
import XCTest
import SQLite
@testable import ZcashLightClientKit
class DownloadOperationTests: XCTestCase {
// 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)")
}
@ -45,5 +47,4 @@ class DownloadOperationTests: XCTestCase {
XCTAssertEqual(try! storage.latestHeight(), range.upperBound)
}
}

View File

@ -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):
@ -75,7 +75,7 @@ class LightWalletServiceTests: XCTestCase {
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)
}
}

View File

@ -7,9 +7,9 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable force_unwrapping print_function_usage
class MemoTests: XCTestCase {
/**
Non-utf8 memos are properly ignored
*/
@ -28,11 +28,9 @@ class MemoTests: XCTestCase {
Verify support for common unicode characters
*/
func testUnicodeCharacters() throws {
let memo = validMemoData.asZcashTransactionMemo()
XCTAssertNotNil(memo)
XCTAssertEqual(memo!, Self.validMemoDataExpectedString)
}
func testEmojiUnicodeCharacters() throws {
@ -67,7 +65,9 @@ class MemoTests: XCTestCase {
*/
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 {
}
}
}

View File

@ -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
*/
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,28 +72,37 @@ 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
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
pendingEntity = pendingTx
}
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
*/
@ -105,43 +117,42 @@ class NetworkUpgradeTests: XCTestCase {
/*
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
*/
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
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
pendingEntity = pendingTx
}
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,58 +196,66 @@ 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.
*/
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
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
pendingEntity = pendingTx
}
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
@ -246,12 +272,9 @@ class NetworkUpgradeTests: XCTestCase {
let sentTxHeight: BlockHeight = activationHeight - 5
/*
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
}
@ -278,9 +302,15 @@ class NetworkUpgradeTests: XCTestCase {
/**
Given that a wallet sends funds somewhere between (activation - expiry_height) and activation, those funds are available if expired after expiration height.
*/
func testExpiredSpendAfterActivation() throws {
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,24 +331,32 @@ 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
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
pendingEntity = pendingTx
}
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
@ -329,7 +365,7 @@ class NetworkUpgradeTests: XCTestCase {
/*
getIncomingTransaction
*/
guard let _ = try coordinator.getIncomingTransactions()?.first else {
guard try coordinator.getIncomingTransactions()?.first != nil else {
XCTFail("no incoming transaction")
try coordinator.stop()
return
@ -338,22 +374,21 @@ class NetworkUpgradeTests: XCTestCase {
/*
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
}
@ -365,17 +400,22 @@ class NetworkUpgradeTests: XCTestCase {
Given that a wallet has notes both received prior and after activation these can be combined to supply a larger amount spend.
*/
func testCombinePreActivationNotesAndPostActivationNotesOnSpend() throws {
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,7 +439,7 @@ 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))
@ -409,19 +447,26 @@ class NetworkUpgradeTests: XCTestCase {
/*
send transaction to recipient address
*/
coordinator.synchronizer.sendToAddress(spendingKey: self.coordinator.spendingKeys!.first!, zatoshi: spendAmount, toAddress: self.testRecipientAddress, memo: "this is a test", from: 0, resultBlock: { (result) in
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
pendingEntity = pendingTx
}
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

View File

@ -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)
}
}

View File

@ -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"
XCTAssertFalse(try ZcashRustBackend.isValidShieldedAddress(ZaddrWithNullBytes, networkType: networkType))
func testZaddrNullBytes() throws {
// 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))
}
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 {
// 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())
}

View File

@ -7,13 +7,20 @@
import XCTest
@testable import ZcashLightClientKit
class PagedTransactionRepositoryTests: XCTestCase {
// 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,12 +28,13 @@ 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
@ -34,5 +42,4 @@ class PagedTransactionRepositoryTests: XCTestCase {
}
}
}
}

View File

@ -7,22 +7,24 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable force_try force_unwrapping implicitly_unwrapped_optional
class PendingTransactionRepositoryTests: XCTestCase {
let dbUrl = try! TestDbBuilder.pendingTransactionsDbURL()
let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6"
var pendingRepository: PendingTransactionRepository!
let dbUrl = try! TestDbBuilder.pendingTransactionsDbURL()
let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6"
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,10 +33,9 @@ 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
}
@ -47,61 +48,64 @@ class PendingTransactionRepositoryTests: XCTestCase {
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 {
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 {
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,17 +120,18 @@ 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 {
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) }())
@ -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)
}
}

View File

@ -7,10 +7,14 @@
import XCTest
@testable import ZcashLightClientKit
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
// swiftlint:disable implicitly_unwrapped_optional
class PendingTransactionUpdatesTest: XCTestCase {
// 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,15 +49,13 @@ 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
guard
let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight
else {
XCTFail("empty reorg notification")
return
}
// XCTAssertEqual(rewindHeight, expectedRewindHeight)
XCTAssertEqual(reorgHeight, expectedReorgHeight)
reorgExpectation.fulfill()
}
@ -69,13 +72,12 @@ class PendingTransactionUpdatesTest: XCTestCase {
sleep(2)
let firstSyncExpectation = XCTestExpectation(description: "first sync")
/*
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,34 +86,52 @@ class PendingTransactionUpdatesTest: XCTestCase {
sleep(1)
let sendExpectation = XCTestExpectation(description: "send expectation")
var p: PendingTransactionEntity? = nil
var pendingEntity: PendingTransactionEntity?
/*
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
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):
p = pendingTx
pendingEntity = pendingTx
}
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
*/
@ -124,7 +144,6 @@ class PendingTransactionUpdatesTest: XCTestCase {
let sentTxHeight: BlockHeight = 663189
/*
4. stage transaction at sentTxHeight
*/
@ -132,6 +151,7 @@ class PendingTransactionUpdatesTest: XCTestCase {
try coordinator.stageBlockCreate(height: sentTxHeight)
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
/*
5. applyHeight(sentTxHeight)
*/
@ -146,9 +166,12 @@ class PendingTransactionUpdatesTest: XCTestCase {
LoggerProxy.info("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)
},
error: self.handleError
)
wait(for: [secondSyncExpectation], timeout: 5)
@ -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
)
}
}

View File

@ -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 = "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"
let txFromAndroidSDK =
// swiftlint:disable:next line_length
"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"
let txBase64String = "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"
let txBase64String =
// swiftlint:disable:next line_length
"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"
}

View File

@ -7,6 +7,7 @@
import XCTest
@testable import ZcashLightClientKit
/**
basic reorg test. Scan, get a reorg and then reach latest height.
@ -19,25 +20,38 @@ import XCTest
* 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 {
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 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)
try super.setUpWithError()
NotificationCenter.default.addObserver(
self,
selector: #selector(handleReOrgNotification(_:)),
name: Notification.Name.blockProcessorHandledReOrg,
object: nil
)
coordinator = try TestCoordinator(
seed: seedPhrase,
walletBirthday: birthday,
@ -46,22 +60,16 @@ class ReOrgTests: 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)
}
let mockLatestHeight = BlockHeight(663250)
let targetLatestHeight = BlockHeight(663251)
let walletBirthday = BlockHeight(663150)
@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,
try basicReOrgTest(
baseDataset: .beforeReOrg,
reorgDataset: .afterSmallReorg,
firstLatestHeight: mockLatestHeight,
reorgHeight: reOrgHeight,
walletBirthday: walletBirthday,
targetHeight: targetLatestHeight)
targetHeight: targetLatestHeight
)
}
func testTenPlusBlockReOrg() throws {
@ -95,21 +105,24 @@ class ReOrgTests: XCTestCase {
let reOrgHeight = BlockHeight(663180)
let walletBirthday = WalletBirthday.birthday(with: BlockHeight(663150), network: network).height
try basicReOrgTest(baseDataset: .beforeReOrg,
try basicReOrgTest(
baseDataset: .beforeReOrg,
reorgDataset: .afterLargeReorg,
firstLatestHeight: mockLatestHeight,
reorgHeight: reOrgHeight,
walletBirthday: walletBirthday,
targetHeight: targetLatestHeight)
targetHeight: targetLatestHeight
)
}
func basicReOrgTest(baseDataset: DarksideDataset,
func basicReOrgTest(
baseDataset: DarksideDataset,
reorgDataset: DarksideDataset,
firstLatestHeight: BlockHeight,
reorgHeight: BlockHeight,
walletBirthday: BlockHeight,
targetHeight: BlockHeight) throws {
targetHeight: BlockHeight
) throws {
do {
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
try coordinator.resetBlocks(dataset: .predefined(dataset: .beforeReOrg))
@ -125,8 +138,8 @@ class ReOrgTests: XCTestCase {
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,6 +149,7 @@ class ReOrgTests: XCTestCase {
XCTFail("nil synchronizer")
return
}
/**
verify that mock height has been reached
*/
@ -146,7 +160,6 @@ class ReOrgTests: XCTestCase {
/**
trigger reorg!
*/
try coordinator.resetBlocks(dataset: .predefined(dataset: reorgDataset))
try coordinator.applyStaged(blockheight: targetHeight)
@ -156,13 +169,15 @@ class ReOrgTests: XCTestCase {
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
try coordinator.sync(
completion: { _ in
secondSyncExpectation.fulfill()
}, error: self.handleError)
},
error: self.handleError
)
// now reorg should happen and reorg notifications and idle notification should be triggered
@ -175,12 +190,9 @@ class ReOrgTests: 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( rewind <= reorg )
reorgExpectation.fulfill()
} else {
@ -195,5 +207,4 @@ class ReOrgTests: XCTestCase {
}
XCTFail("Failed with error: \(testError)")
}
}

View File

@ -7,24 +7,31 @@
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,
@ -32,23 +39,27 @@ class RewindRescanTests: XCTestCase {
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)
@ -84,7 +95,7 @@ class RewindRescanTests: XCTestCase {
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
try coordinator.sync(
completion: { _ in
firstSyncExpectation.fulfill()
}, error: handleError)
},
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)
@ -192,13 +211,15 @@ 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,
coordinator.synchronizer.sendToAddress(
spendingKey: spendingKey,
zatoshi: maxBalance,
toAddress: testRecipientAddress,
memo: "test send \(self.description) \(Date().description)",
from: 0) { result in
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 {
@ -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)
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
},
error: { error in
guard let e = error else {
XCTFail("unknown error syncing after sending transaction")
return
}
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
try coordinator.sync(
completion: { _ in
confirmExpectation.fulfill()
}, error: { e in
},
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)
}

View File

@ -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]()
override func setUpWithError() throws {
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)
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)
@ -96,35 +107,33 @@ class SychronizerDarksideTests: XCTestCase {
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)

View File

@ -14,8 +14,8 @@ import Foundation
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,
convenience init(
seed: String,
walletBirthday: BlockHeight,
channelProvider: ChannelProvider,
network: ZcashNetwork) throws {
network: ZcashNetwork
) throws {
let derivationTool = DerivationTool(networkType: network.networkType)
guard let spendingKey = try derivationTool.deriveSpendingKeys(
guard
let spendingKey = try derivationTool
.deriveSpendingKeys(
seed: TestSeed().seed(),
numberOfAccounts: 1).first else {
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,13 +88,22 @@ 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()
@ -86,8 +116,10 @@ class TestCoordinator {
endpoint: LightWalletEndpointBuilder.default,
service: self.service,
repository: TransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: databases.dataDB.absoluteString)),
accountRepository: AccountRepositoryBuilder.build(dataDbURL: databases.dataDB,
readOnly: true),
accountRepository: AccountRepositoryBuilder.build(
dataDbURL: databases.dataDB,
readOnly: true
),
storage: storage,
spendParamsURL: try __spendParamsURL(),
outputParamsURL: try __outputParamsURL(),
@ -95,7 +127,8 @@ class TestCoordinator {
unifiedViewingKey: unifiedViewingKey,
walletBirthday: WalletBirthday.birthday(with: birthday, network: network),
network: network,
loggerProxy: SampleLogger(logLevel: .debug))
loggerProxy: SampleLogger(logLevel: .debug)
)
self.synchronizer = buildResult.synchronizer
self.spendingKeys = buildResult.spendingKeys
@ -130,15 +163,12 @@ class TestCoordinator {
try synchronizer.start(retry: true)
}
/**
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,7 +202,6 @@ class TestCoordinator {
extension TestCoordinator {
func resetBlocks(dataset: DarksideData) throws {
switch dataset {
case .default:
try service.useDataset(DarksideDataset.beforeReOrg.rawValue)
@ -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,7 +235,6 @@ 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,
@ -216,7 +244,8 @@ extension TestCoordinator {
rewindDistance: config.rewindDistance,
walletBirthday: config.walletBirthday,
saplingActivation: config.saplingActivation,
network: config.network)
network: config.network
)
try service.reset(saplingActivation: saplingActivation, branchID: branchID, chainName: chainName)
}
@ -231,19 +260,20 @@ struct TemporaryTestDatabases {
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"),
return TemporaryTestDatabases(
cacheDB: tempUrl.appendingPathComponent("cache_db_\(timestamp).db"),
dataDB: tempUrl.appendingPathComponent("data_db_\(timestamp).db"),
pendingDB: tempUrl.appendingPathComponent("pending_db_\(timestamp).db"))
pendingDB: tempUrl.appendingPathComponent("pending_db_\(timestamp).db")
)
}
}
class TestSynchronizerBuilder {
enum TestSynchronizerBuilder {
static func build(
rustBackend: ZcashRustBackendWelding.Type,
lowerBoundHeight: BlockHeight,
@ -281,6 +311,7 @@ class TestSynchronizerBuilder {
walletBirthday: walletBirthday.height,
loggerProxy: loggerProxy
)
let config = CompactBlockProcessor.Configuration(
cacheDb: initializer.cacheDbURL,
dataDb: initializer.dataDbURL,
@ -290,17 +321,20 @@ class TestSynchronizerBuilder {
rewindDistance: ZcashSDK.defaultRewindDistance,
walletBirthday: walletBirthday.height,
saplingActivation: lowerBoundHeight,
network: network)
network: network
)
let processor = CompactBlockProcessor(service: service,
let processor = CompactBlockProcessor(
service: service,
storage: storage,
backend: rustBackend,
config: config,
repository: repository,
accountRepository: accountRepository)
accountRepository: accountRepository
)
let synchronizer = try SDKSynchronizer(status: .unprepared,
let synchronizer = try SDKSynchronizer(
status: .unprepared,
initializer: initializer,
transactionManager: OutboundTransactionManagerBuilder.build(initializer: initializer),
transactionRepository: repository,
@ -312,6 +346,7 @@ class TestSynchronizerBuilder {
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
)
}
}

View File

@ -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)
_ = 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,
processor = CompactBlockProcessor(
service: service,
storage: storage,
backend: rustBackend,
config: processorConfig)
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
@ -99,12 +119,10 @@ class TransactionEnhancementTests: XCTestCase {
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,7 +130,6 @@ 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)
@ -123,36 +140,38 @@ class TransactionEnhancementTests: XCTestCase {
}
sleep(3)
/**
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
*/
do {
try startProcessing()
} catch {
XCTFail("Error: \(error)")
}
wait(for: [downloadStartedExpect,
wait(
for: [
downloadStartedExpect,
startedValidatingNotificationExpectation,
startedScanningNotificationExpectation,
txFoundNotificationExpectation,
idleNotificationExpectation], timeout: 30)
idleNotificationExpectation
],
timeout: 30
)
idleNotificationExpectation.unsubscribeFromNotifications()
}
@objc func processorFailed(_ notification: Notification) {
@ -163,6 +182,4 @@ class TransactionEnhancementTests: XCTestCase {
XCTFail("CompactBlockProcessor failed")
}
}
}

View File

@ -7,15 +7,18 @@
import XCTest
@testable import ZcashLightClientKit
class TransactionRepositoryTests: XCTestCase {
// 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
}
@ -24,7 +27,6 @@ class TransactionRepositoryTests: XCTestCase {
XCTAssertNoThrow(try { count = try self.transactionRepository.countAll() }())
XCTAssertNotNil(count)
XCTAssertEqual(count, 27)
}
func testCountUnmined() {
@ -35,9 +37,9 @@ class TransactionRepositoryTests: XCTestCase {
}
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,7 +115,8 @@ class TransactionRepositoryTests: XCTestCase {
}
func testFindAllFrom() throws {
guard let transactions = try self.transactionRepository.findAll(offset: 0, 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")
@ -119,8 +124,8 @@ class TransactionRepositoryTests: XCTestCase {
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,10 +133,10 @@ class TransactionRepositoryTests: XCTestCase {
}
func testFindAllFromSlice() throws {
let limit = 4
let start = 7
guard let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max),
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,20 +146,19 @@ 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),
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")
@ -162,8 +166,8 @@ class TransactionRepositoryTests: XCTestCase {
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,19 +176,17 @@ 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
}
@ -193,15 +195,15 @@ extension Data {
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 }
}

View File

@ -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)
}
}

View File

@ -10,31 +10,33 @@ 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==")!
override func setUp() {
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)
}
}
func testWalletInitialization() throws {
let derivationTool = DerivationTool(networkType: network.networkType)
let uvk = try derivationTool.deriveUnifiedViewingKeysFromSeed(seedData.bytes, numberOfAccounts: 1)
let wallet = Initializer(cacheDbURL: try __cacheDbURL(),
let wallet = Initializer(
cacheDbURL: try __cacheDbURL(),
dataDbURL: try __dataDbURL(),
pendingDbURL: try TestDbBuilder.pendingTransactionsDbURL(),
endpoint: LightWalletEndpointBuilder.default,
@ -42,9 +44,8 @@ class WalletTests: XCTestCase {
spendParamsURL: try __spendParamsURL(),
outputParamsURL: try __outputParamsURL(),
viewingKeys: uvk,
walletBirthday: 663194)
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()
}

View File

@ -7,8 +7,10 @@
import XCTest
@testable import ZcashLightClientKit
class Z2TReceiveTests: XCTestCase {
// 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
@ -26,6 +28,7 @@ class Z2TReceiveTests: XCTestCase {
let network = DarksideWalletDNetwork()
override func setUpWithError() throws {
try super.setUpWithError()
coordinator = try TestCoordinator(
seed: seedPhrase,
@ -33,11 +36,15 @@ class Z2TReceiveTests: XCTestCase {
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,23 +52,26 @@ 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)
@ -74,32 +84,41 @@ class Z2TReceiveTests: XCTestCase {
/*
3. sync up to received_Tx_height
*/
try coordinator.sync(completion: { (synchronizer) in
initialTotalBalance = synchronizer.initializer.getBalance()
try coordinator.sync(
completion: { _ in
preTxExpectation.fulfill()
}, error: self.handleError)
},
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
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
}
@ -118,6 +137,7 @@ class Z2TReceiveTests: XCTestCase {
XCTFail("sent transaction not present on Darksidewalletd")
return
}
try coordinator.stageTransaction(sentTx, at: sentTxHeight)
/*
@ -127,27 +147,22 @@ class Z2TReceiveTests: XCTestCase {
sleep(2)
self.foundTransactionsExpectation = XCTestExpectation(description: "inbound expectation")
/*
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()
guard let testError = error else {

View File

@ -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"
}

View File

@ -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")
}
}
}

View File

@ -38,8 +38,41 @@ enum DarksideDataset: String {
}
class DarksideWalletService: LightWalletService {
@discardableResult func blockStream(startHeight: BlockHeight, endHeight: BlockHeight, result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> 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<GRPCResult, LightWalletServiceError>) -> 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,14 +84,17 @@ 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) {
func fetchUTXOs(
for tAddress: String,
height: BlockHeight,
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
) {
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) {
result(.success([]))
}
@ -68,7 +104,11 @@ class DarksideWalletService: LightWalletService {
[]
}
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
) {
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<BlockHeight, LightWalletServiceError>) -> Void) {
service.latestBlockHeight(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
}

View File

@ -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.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 {
@ -186,5 +199,4 @@ class FakeChainBuilder {
822410: buildTxUrl(for: "f3f8684be8d77367d099a38f30e3652410cdebe35c006d0599d86d8ec640867f"),
828933: buildTxUrl(for: "1fd394257d1c10c8a70fb760cf73f6d0e96e61edcf1ffca6da12d733a59221a4")
]
}

View File

@ -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<GRPCResult, LightWalletServiceError>) -> Void, handler: @escaping (ZcashCompactBlock) -> Void, progress: @escaping (BlockProgressReporting) -> Void) -> CancellableCall {
@discardableResult
func blockStream(
startHeight: BlockHeight,
endHeight: BlockHeight,
result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void,
handler: @escaping (ZcashCompactBlock) -> Void,
progress: @escaping (BlockProgress) -> Void
) -> CancellableCall {
return MockCancellable()
}
@ -35,7 +44,6 @@ class MockLightWalletService: LightWalletService {
func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> 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<TransactionEntity, LightWalletServiceError>) -> Void) {
}
}

View File

@ -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)
}
}

View File

@ -6,49 +6,33 @@
//
import Foundation
@testable import ZcashLightClientKit
class MockTransactionRepository: TransactionRepository {
func findConfirmedTransactionBy(rawId: Data) throws -> ConfirmedTransactionEntity? {
nil
class MockTransactionRepository {
enum Kind {
case sent
case received
}
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
}
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,
init(
unminedCount: Int,
receivedCount: Int,
sentCount: Int,
network: ZcashNetwork) {
network: ZcashNetwork
) {
self.unminedCount = unminedCount
self.receivedCount = receivedCount
self.sentCount = sentCount
@ -56,15 +40,87 @@ class MockTransactionRepository: TransactionRepository {
}
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 referenceArray() -> [Kind] {
var template: [Kind] = []
for _ in 0 ..< sentCount {
template.append(.sent)
}
for _ in 0 ..< receivedCount {
template.append(.received)
}
return template.shuffled()
}
func mockTx(index: Int, kind: Kind) -> ConfirmedTransactionEntity {
switch kind {
case .received:
return mockReceived(index)
case .sent:
return mockSent(index)
}
}
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()
)
}
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()
)
}
func randomBlockHeight() -> BlockHeight {
BlockHeight.random(in: network.constants.saplingActivationHeight ... 1_000_000)
}
func randomTimeInterval() -> TimeInterval {
Double.random(in: Date().timeIntervalSince1970 - 1000000.0 ... Date().timeIntervalSince1970)
}
func slice(txs: [ConfirmedTransactionEntity], offset: Int, limit: Int) -> [ConfirmedTransactionEntity] {
guard offset < txs.count else { return [] }
return Array(txs[offset ..< min(offset + limit, txs.count - offset)])
}
}
extension MockTransactionRepository.Kind: Equatable {}
// MARK: - TransactionRepository
extension MockTransactionRepository: TransactionRepository {
func countAll() throws -> Int {
allCount
}
@ -73,6 +129,10 @@ class MockTransactionRepository: TransactionRepository {
unminedCount
}
func blockForHeight(_ height: BlockHeight) throws -> Block? {
nil
}
func findBy(id: Int) throws -> TransactionEntity? {
transactions.first(where: { $0.id == id })?.transactionEntity
}
@ -84,19 +144,19 @@ class MockTransactionRepository: TransactionRepository {
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
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
let receivedTxs = indices.map { idx -> ConfirmedTransactionEntity in
transactions[idx]
}
return slice(txs: receivedTxs, offset: offset, limit: limit)
}
@ -104,6 +164,10 @@ class MockTransactionRepository: TransactionRepository {
transactions
}
func findAll(from: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]? {
nil
}
func lastScannedHeight() throws -> BlockHeight {
return 700000
}
@ -116,70 +180,32 @@ class MockTransactionRepository: TransactionRepository {
nil
}
enum Kind {
case sent
case received
func findTransactions(in range: BlockRange, limit: Int) throws -> [TransactionEntity]? {
nil
}
func referenceArray() -> [Kind] {
var template = [Kind]()
for _ in 0 ..< sentCount {
template.append(.sent)
}
for _ in 0 ..< receivedCount {
template.append(.received)
}
return template.shuffled()
func findConfirmedTransactionBy(rawId: Data) throws -> ConfirmedTransactionEntity? {
nil
}
func mockTx(index: Int, kind: Kind) -> ConfirmedTransactionEntity {
switch kind {
case .received:
return mockReceived(index)
case .sent:
return mockSent(index)
}
}
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())
}
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())
}
func randomBlockHeight() -> BlockHeight {
BlockHeight.random(in: network.constants.saplingActivationHeight ... 1_000_000)
}
func randomTimeInterval() -> TimeInterval {
Double.random(in: Date().timeIntervalSince1970 - 1000000.0 ... Date().timeIntervalSince1970)
}
func slice(txs: [ConfirmedTransactionEntity], offset: Int, limit: Int) -> [ConfirmedTransactionEntity] {
guard offset < txs.count else { return [] }
return Array(txs[offset ..< min(offset + limit, txs.count - offset)])
}
}
extension MockTransactionRepository.Kind: Equatable {}
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 findConfirmedTransactions(in range: BlockRange, offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
nil
}
}
guard idx.count > 0 else { return nil }
extension Array {
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.isEmpty else { return nil }
return idx
}
}

View File

@ -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
@ -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
)
}
}
}

View File

@ -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) {
@ -42,15 +42,12 @@ class AwfulLightWalletService: MockLightWalletService {
/**
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<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
result(.success(LightWalletServiceMockResponse.error))
@ -60,29 +57,30 @@ class SlightlyBadLightWalletService: MockLightWalletService {
/**
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 {
@ -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
}
}

View File

@ -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]()
static func createBlockRange(_ range: CompactBlockRange) -> [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
}
}

View File

@ -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,7 +97,10 @@ 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) {
try? FileManager.default.removeItem(at: spend)
@ -102,26 +108,28 @@ func deleteParamsFrom(spend: URL, output: URL) {
}
func parametersReady() -> Bool {
guard let output = try? __outputParamsURL(),
guard
let output = try? __outputParamsURL(),
let spend = try? __spendParamsURL(),
FileManager.default.isReadableFile(atPath: output.absoluteString),
FileManager.default.isReadableFile(atPath: spend.absoluteString) else {
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"
*/