SwiftLint Enabled on Test Folder
This commit is contained in:
parent
db5f02dbf9
commit
78b1f937ba
|
@ -3,12 +3,14 @@
|
||||||
|
|
||||||
excluded:
|
excluded:
|
||||||
- Pods
|
- Pods
|
||||||
- ZcashLightClientKitTests
|
|
||||||
- ZcashLightClientKit/Service/ProtoBuf
|
- ZcashLightClientKit/Service/ProtoBuf
|
||||||
|
- ZcashLightClientKitTests/proto
|
||||||
|
- ZcashLightClientKitTests/Constants.generated.swift
|
||||||
|
|
||||||
included:
|
included:
|
||||||
- Example/ZcashLightClientSample/ZcashLIghtClientSample
|
- Example/ZcashLightClientSample/ZcashLIghtClientSample
|
||||||
- ZcashLightClientKit
|
- ZcashLightClientKit
|
||||||
|
- ZcashLightClientKitTests
|
||||||
|
|
||||||
disabled_rules:
|
disabled_rules:
|
||||||
- notification_center_detachment
|
- notification_center_detachment
|
||||||
|
|
|
@ -7,11 +7,15 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional force_unwrapping type_body_length
|
||||||
class AdvancedReOrgTests: XCTestCase {
|
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?
|
// TODO: Parameterize this from environment
|
||||||
|
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
|
||||||
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
|
|
||||||
|
|
||||||
let sendAmount: Int64 = 1000
|
let sendAmount: Int64 = 1000
|
||||||
var birthday: BlockHeight = 663150
|
var birthday: BlockHeight = 663150
|
||||||
|
@ -21,13 +25,13 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
var sentTransactionExpectation = XCTestExpectation(description: "sent")
|
var sentTransactionExpectation = XCTestExpectation(description: "sent")
|
||||||
var expectedReorgHeight: BlockHeight = 665188
|
var expectedReorgHeight: BlockHeight = 665188
|
||||||
var expectedRewindHeight: BlockHeight = 665188
|
var expectedRewindHeight: BlockHeight = 665188
|
||||||
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
|
var reorgExpectation = XCTestExpectation(description: "reorg")
|
||||||
let branchID = "2bb40e60"
|
let branchID = "2bb40e60"
|
||||||
let chainName = "main"
|
let chainName = "main"
|
||||||
let network = DarksideWalletDNetwork()
|
let network = DarksideWalletDNetwork()
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
|
try super.setUpWithError()
|
||||||
coordinator = try TestCoordinator(
|
coordinator = try TestCoordinator(
|
||||||
seed: seedPhrase,
|
seed: seedPhrase,
|
||||||
walletBirthday: birthday,
|
walletBirthday: birthday,
|
||||||
|
@ -38,6 +42,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
|
try super.tearDownWithError()
|
||||||
NotificationCenter.default.removeObserver(self)
|
NotificationCenter.default.removeObserver(self)
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
||||||
|
@ -46,15 +51,16 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func handleReorg(_ notification: Notification) {
|
@objc func handleReorg(_ notification: Notification) {
|
||||||
|
guard
|
||||||
guard let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
||||||
let rewindHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight
|
let rewindHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight
|
||||||
else {
|
else {
|
||||||
XCTFail("empty reorg notification")
|
XCTFail("empty reorg notification")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logger!.debug("--- REORG DETECTED \(reorgHeight)--- RewindHeight: \(rewindHeight)", file: #file, function: #function, line: #line)
|
logger!.debug("--- REORG DETECTED \(reorgHeight)--- RewindHeight: \(rewindHeight)", file: #file, function: #function, line: #line)
|
||||||
// XCTAssertEqual(rewindHeight, expectedRewindHeight)
|
|
||||||
XCTAssertEqual(reorgHeight, expectedReorgHeight)
|
XCTAssertEqual(reorgHeight, expectedReorgHeight)
|
||||||
reorgExpectation.fulfill()
|
reorgExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
@ -91,15 +97,18 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
sleep(3)
|
sleep(3)
|
||||||
let preTxExpectation = XCTestExpectation(description: "pre receive")
|
let preTxExpectation = XCTestExpectation(description: "pre receive")
|
||||||
|
|
||||||
var s: SDKSynchronizer?
|
var synchronizer: SDKSynchronizer?
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(
|
||||||
s = synchronizer
|
completion: { synchro in
|
||||||
initialVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
synchronizer = synchro
|
||||||
initialTotalBalance = synchronizer.initializer.getBalance()
|
initialVerifiedBalance = synchro.initializer.getVerifiedBalance()
|
||||||
|
initialTotalBalance = synchro.initializer.getBalance()
|
||||||
preTxExpectation.fulfill()
|
preTxExpectation.fulfill()
|
||||||
shouldContinue = true
|
shouldContinue = true
|
||||||
}, error: self.handleError)
|
},
|
||||||
|
error: self.handleError
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [preTxExpectation], timeout: 10)
|
wait(for: [preTxExpectation], timeout: 10)
|
||||||
|
|
||||||
|
@ -111,28 +120,26 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
2. applyStaged(received_Tx_height)
|
2. applyStaged(received_Tx_height)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: receivedTxHeight)
|
try coordinator.applyStaged(blockheight: receivedTxHeight)
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
3. sync up to received_Tx_height
|
3. sync up to received_Tx_height
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let receivedTxExpectation = XCTestExpectation(description: "received tx")
|
let receivedTxExpectation = XCTestExpectation(description: "received tx")
|
||||||
var receivedTxTotalBalance = Int64(-1)
|
var receivedTxTotalBalance = Int64(-1)
|
||||||
var receivedTxVerifiedBalance = Int64(-1)
|
var receivedTxVerifiedBalance = Int64(-1)
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { synchro in
|
||||||
s = synchronizer
|
synchronizer = synchro
|
||||||
receivedTxVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
receivedTxVerifiedBalance = synchro.initializer.getVerifiedBalance()
|
||||||
receivedTxTotalBalance = synchronizer.initializer.getBalance()
|
receivedTxTotalBalance = synchro.initializer.getBalance()
|
||||||
receivedTxExpectation.fulfill()
|
receivedTxExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
sleep(2)
|
sleep(2)
|
||||||
wait(for: [receivedTxExpectation], timeout: 10)
|
wait(for: [receivedTxExpectation], timeout: 10)
|
||||||
|
|
||||||
guard let syncedSynchronizer = s else {
|
guard let syncedSynchronizer = synchronizer else {
|
||||||
XCTFail("nil synchronizer")
|
XCTFail("nil synchronizer")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -142,17 +149,15 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
3a. verify that balance is previous balance + tx amount
|
3a. verify that balance is previous balance + tx amount
|
||||||
*/
|
*/
|
||||||
|
|
||||||
XCTAssertEqual(receivedTxTotalBalance, initialTotalBalance + Int64(receivedTx.value))
|
XCTAssertEqual(receivedTxTotalBalance, initialTotalBalance + Int64(receivedTx.value))
|
||||||
XCTAssertEqual(receivedTxVerifiedBalance, initialVerifiedBalance)
|
XCTAssertEqual(receivedTxVerifiedBalance, initialVerifiedBalance)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
4. get that transaction hex encoded data
|
4. get that transaction hex encoded data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
guard let receivedTxData = receivedTx.raw else {
|
guard let receivedTxData = receivedTx.raw else {
|
||||||
XCTFail("received tx has no raw data!")
|
XCTFail("received tx has no raw data!")
|
||||||
return
|
return
|
||||||
|
@ -166,33 +171,30 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
5. stage 5 empty blocks w/heights received_Tx_height to received_Tx_height + 4
|
5. stage 5 empty blocks w/heights received_Tx_height to received_Tx_height + 4
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try coordinator.stageBlockCreate(height: receivedTxHeight, count: 5)
|
try coordinator.stageBlockCreate(height: receivedTxHeight, count: 5)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
6. stage tx at received_Tx_height + 3
|
6. stage tx at received_Tx_height + 3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let reorgedTxheight = receivedTxHeight + 2
|
let reorgedTxheight = receivedTxHeight + 2
|
||||||
try coordinator.stageTransaction(receivedRawTx, at: reorgedTxheight)
|
try coordinator.stageTransaction(receivedRawTx, at: reorgedTxheight)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
6a. applyheight(received_Tx_height + 1)
|
6a. applyheight(received_Tx_height + 1)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: receivedTxHeight + 1)
|
try coordinator.applyStaged(blockheight: receivedTxHeight + 1)
|
||||||
|
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
7. sync to received_Tx_height + 1
|
7. sync to received_Tx_height + 1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let reorgSyncexpectation = XCTestExpectation(description: "reorg expectation")
|
let reorgSyncexpectation = XCTestExpectation(description: "reorg expectation")
|
||||||
|
|
||||||
var afterReorgTxTotalBalance = Int64(-1)
|
var afterReorgTxTotalBalance = Int64(-1)
|
||||||
var afterReorgTxVerifiedBalance = Int64(-1)
|
var afterReorgTxVerifiedBalance = Int64(-1)
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { synchronizer in
|
||||||
afterReorgTxTotalBalance = synchronizer.initializer.getBalance()
|
afterReorgTxTotalBalance = synchronizer.initializer.getBalance()
|
||||||
afterReorgTxVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
afterReorgTxVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
||||||
reorgSyncexpectation.fulfill()
|
reorgSyncexpectation.fulfill()
|
||||||
|
@ -203,17 +205,16 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
*/
|
*/
|
||||||
sleep(2)
|
sleep(2)
|
||||||
wait(for: [reorgExpectation, reorgSyncexpectation], timeout: 5, enforceOrder: false)
|
wait(for: [reorgExpectation, reorgSyncexpectation], timeout: 5, enforceOrder: false)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
9. verify that balance equals initial balance
|
9. verify that balance equals initial balance
|
||||||
*/
|
*/
|
||||||
|
|
||||||
XCTAssertEqual(afterReorgTxVerifiedBalance, initialVerifiedBalance)
|
XCTAssertEqual(afterReorgTxVerifiedBalance, initialVerifiedBalance)
|
||||||
XCTAssertEqual(afterReorgTxTotalBalance, initialTotalBalance)
|
XCTAssertEqual(afterReorgTxTotalBalance, initialTotalBalance)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
10. sync up to received_Tx_height + 3
|
10. sync up to received_Tx_height + 3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let finalsyncExpectation = XCTestExpectation(description: "final sync")
|
let finalsyncExpectation = XCTestExpectation(description: "final sync")
|
||||||
|
|
||||||
var finalReorgTxTotalBalance = Int64(-1)
|
var finalReorgTxTotalBalance = Int64(-1)
|
||||||
|
@ -221,7 +222,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: reorgedTxheight + 1)
|
try coordinator.applyStaged(blockheight: reorgedTxheight + 1)
|
||||||
sleep(3)
|
sleep(3)
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { synchronizer in
|
||||||
finalReorgTxTotalBalance = synchronizer.initializer.getBalance()
|
finalReorgTxTotalBalance = synchronizer.initializer.getBalance()
|
||||||
finalReorgTxVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
finalReorgTxVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
||||||
finalsyncExpectation.fulfill()
|
finalsyncExpectation.fulfill()
|
||||||
|
@ -282,7 +283,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
3. sync up to received_Tx_height
|
3. sync up to received_Tx_height
|
||||||
*/
|
*/
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { synchronizer in
|
||||||
initialTotalBalance = synchronizer.initializer.getBalance()
|
initialTotalBalance = synchronizer.initializer.getBalance()
|
||||||
preTxExpectation.fulfill()
|
preTxExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
@ -290,16 +291,23 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
wait(for: [preTxExpectation], timeout: 5)
|
wait(for: [preTxExpectation], timeout: 5)
|
||||||
|
|
||||||
let sendExpectation = XCTestExpectation(description: "sendToAddress")
|
let sendExpectation = XCTestExpectation(description: "sendToAddress")
|
||||||
var p: PendingTransactionEntity?
|
var pendingEntity: PendingTransactionEntity?
|
||||||
var error: Error? = nil
|
var error: Error?
|
||||||
let sendAmount: Int64 = 10000
|
let sendAmount: Int64 = 10000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
4. create transaction
|
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 {
|
switch result {
|
||||||
case .success(let pending):
|
case .success(let pending):
|
||||||
p = pending
|
pendingEntity = pending
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
error = e
|
error = e
|
||||||
}
|
}
|
||||||
|
@ -307,7 +315,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
}
|
}
|
||||||
wait(for: [sendExpectation], timeout: 12)
|
wait(for: [sendExpectation], timeout: 12)
|
||||||
|
|
||||||
guard let pendingTx = p else {
|
guard let pendingTx = pendingEntity else {
|
||||||
XCTFail("error sending to address. Error: \(String(describing: error))")
|
XCTFail("error sending to address. Error: \(String(describing: error))")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -338,21 +346,20 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
7. sync to sentTxHeight + 1
|
7. sync to sentTxHeight + 1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation")
|
let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(
|
||||||
|
completion: { synchronizer in
|
||||||
let pMinedHeight = s.pendingTransactions.first?.minedHeight
|
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
|
||||||
XCTAssertEqual(pMinedHeight, sentTxHeight)
|
XCTAssertEqual(pMinedHeight, sentTxHeight)
|
||||||
|
|
||||||
sentTxSyncExpectation.fulfill()
|
sentTxSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
},
|
||||||
|
error: self.handleError
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sentTxSyncExpectation], timeout: 5)
|
wait(for: [sentTxSyncExpectation], timeout: 5)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
8. stage sentTx and otherTx at sentTxheight
|
8. stage sentTx and otherTx at sentTxheight
|
||||||
*/
|
*/
|
||||||
|
@ -367,32 +374,33 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
|
|
||||||
sleep(2)
|
sleep(2)
|
||||||
let afterReOrgExpectation = XCTestExpectation(description: "after ReOrg Expectation")
|
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
|
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(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()
|
afterReOrgExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
},
|
||||||
|
error: self.handleError
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [afterReOrgExpectation], timeout: 5)
|
wait(for: [afterReOrgExpectation], timeout: 5)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
12. applyStaged(sentTx + 10)
|
12. applyStaged(sentTx + 10)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: sentTxHeight + 12)
|
try coordinator.applyStaged(blockheight: sentTxHeight + 12)
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
13. verify that there's no more pending transaction
|
13. verify that there's no more pending transaction
|
||||||
*/
|
*/
|
||||||
let lastSyncExpectation = XCTestExpectation(description: "sync to confirmation")
|
let lastSyncExpectation = XCTestExpectation(description: "sync to confirmation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
lastSyncExpectation.fulfill()
|
lastSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -415,7 +423,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
|
|
||||||
var preReorgTotalBalance = Int64(0)
|
var preReorgTotalBalance = Int64(0)
|
||||||
var preReorgVerifiedBalance = Int64(0)
|
var preReorgVerifiedBalance = Int64(0)
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { synchronizer in
|
||||||
preReorgTotalBalance = synchronizer.initializer.getBalance()
|
preReorgTotalBalance = synchronizer.initializer.getBalance()
|
||||||
preReorgVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
preReorgVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
|
@ -423,11 +431,9 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
|
|
||||||
wait(for: [firstSyncExpectation], timeout: 10)
|
wait(for: [firstSyncExpectation], timeout: 10)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
trigger reorg
|
trigger reorg
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try coordinator.resetBlocks(dataset: .predefined(dataset: .txIndexChangeAfter))
|
try coordinator.resetBlocks(dataset: .predefined(dataset: .txIndexChangeAfter))
|
||||||
try coordinator.applyStaged(blockheight: 663200)
|
try coordinator.applyStaged(blockheight: 663200)
|
||||||
|
|
||||||
|
@ -437,7 +443,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
|
|
||||||
var postReorgTotalBalance = Int64(0)
|
var postReorgTotalBalance = Int64(0)
|
||||||
var postReorgVerifiedBalance = Int64(0)
|
var postReorgVerifiedBalance = Int64(0)
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { synchronizer in
|
||||||
postReorgTotalBalance = synchronizer.initializer.getBalance()
|
postReorgTotalBalance = synchronizer.initializer.getBalance()
|
||||||
postReorgVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
postReorgVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
||||||
afterReorgSync.fulfill()
|
afterReorgSync.fulfill()
|
||||||
|
@ -447,7 +453,6 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
|
|
||||||
XCTAssertEqual(postReorgVerifiedBalance, preReorgVerifiedBalance)
|
XCTAssertEqual(postReorgVerifiedBalance, preReorgVerifiedBalance)
|
||||||
XCTAssertEqual(postReorgTotalBalance, preReorgTotalBalance)
|
XCTAssertEqual(postReorgTotalBalance, preReorgTotalBalance)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testReOrgExpiresInboundTransaction() throws {
|
func testReOrgExpiresInboundTransaction() throws {
|
||||||
|
@ -458,11 +463,10 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
let expectation = XCTestExpectation(description: "sync to \(receivedTxHeight - 1) expectation")
|
let expectation = XCTestExpectation(description: "sync to \(receivedTxHeight - 1) expectation")
|
||||||
var initialBalance: Int64 = -1
|
var initialBalance: Int64 = -1
|
||||||
var initialVerifiedBalance: Int64 = -1
|
var initialVerifiedBalance: Int64 = -1
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { synchronizer in
|
||||||
initialBalance = synchronizer.initializer.getBalance()
|
initialBalance = synchronizer.initializer.getBalance()
|
||||||
initialVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
initialVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
|
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [expectation], timeout: 5)
|
wait(for: [expectation], timeout: 5)
|
||||||
|
@ -474,12 +478,14 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
|
|
||||||
var afterTxBalance: Int64 = -1
|
var afterTxBalance: Int64 = -1
|
||||||
var afterTxVerifiedBalance: Int64 = -1
|
var afterTxVerifiedBalance: Int64 = -1
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { synchronizer in
|
||||||
afterTxBalance = synchronizer.initializer.getBalance()
|
afterTxBalance = synchronizer.initializer.getBalance()
|
||||||
afterTxVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
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()
|
afterTxSyncExpectation.fulfill()
|
||||||
|
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [afterTxSyncExpectation], timeout: 10.0)
|
wait(for: [afterTxSyncExpectation], timeout: 10.0)
|
||||||
|
@ -497,10 +503,13 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
|
|
||||||
var afterReOrgBalance: Int64 = -1
|
var afterReOrgBalance: Int64 = -1
|
||||||
var afterReOrgVerifiedBalance: Int64 = -1
|
var afterReOrgVerifiedBalance: Int64 = -1
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { synchronizer in
|
||||||
afterReOrgBalance = synchronizer.initializer.getBalance()
|
afterReOrgBalance = synchronizer.initializer.getBalance()
|
||||||
afterReOrgVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
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()
|
afterReorgExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -508,7 +517,6 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
|
|
||||||
XCTAssertEqual(afterReOrgBalance, initialBalance)
|
XCTAssertEqual(afterReOrgBalance, initialBalance)
|
||||||
XCTAssertEqual(afterReOrgVerifiedBalance, initialVerifiedBalance)
|
XCTAssertEqual(afterReOrgVerifiedBalance, initialVerifiedBalance)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -532,14 +540,12 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
1. sync up to an incoming transaction (incomingTxHeight + 1)
|
1. sync up to an incoming transaction (incomingTxHeight + 1)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync test expectation")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync test expectation")
|
||||||
|
|
||||||
var initialBalance: Int64 = -1
|
var initialBalance: Int64 = -1
|
||||||
var initialVerifiedBalance: Int64 = -1
|
var initialVerifiedBalance: Int64 = -1
|
||||||
var incomingTx: ConfirmedTransactionEntity? = nil
|
var incomingTx: ConfirmedTransactionEntity?
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -551,18 +557,19 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
initialBalance = coordinator.synchronizer.initializer.getBalance()
|
initialBalance = coordinator.synchronizer.initializer.getBalance()
|
||||||
initialVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
|
initialVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
|
||||||
incomingTx = coordinator.synchronizer.receivedTransactions.first(where: { $0.minedHeight == incomingTxHeight })
|
incomingTx = coordinator.synchronizer.receivedTransactions.first(where: { $0.minedHeight == incomingTxHeight })
|
||||||
guard let tx = incomingTx else {
|
|
||||||
|
guard let transaction = incomingTx else {
|
||||||
XCTFail("no tx found")
|
XCTFail("no tx found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let txRawData = tx.raw else {
|
guard let txRawData = transaction.raw else {
|
||||||
XCTFail("transaction has no raw data")
|
XCTFail("transaction has no raw data")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let rawTransaction = RawTransaction.with( { tx in
|
let rawTransaction = RawTransaction.with({ rawTx in
|
||||||
tx.data = txRawData
|
rawTx.data = txRawData
|
||||||
})
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -574,7 +581,6 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
3. stage otherTx at incomingTxHeight
|
3. stage otherTx at incomingTxHeight
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try coordinator.stageTransaction(url: FakeChainBuilder.someOtherTxUrl, at: incomingTxHeight)
|
try coordinator.stageTransaction(url: FakeChainBuilder.someOtherTxUrl, at: incomingTxHeight)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -588,14 +594,14 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
5. applyHeight(incomingHeight + 2)
|
5. applyHeight(incomingHeight + 2)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: incomingTxHeight + 2)
|
try coordinator.applyStaged(blockheight: incomingTxHeight + 2)
|
||||||
|
|
||||||
let lastSyncExpectation = XCTestExpectation(description: "last sync expectation")
|
let lastSyncExpectation = XCTestExpectation(description: "last sync expectation")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
6. sync to latest height
|
6. sync to latest height
|
||||||
*/
|
*/
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
lastSyncExpectation.fulfill()
|
lastSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -617,8 +623,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync test expectation")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync test expectation")
|
||||||
var initialBalance: Int64 = -1
|
var initialBalance: Int64 = -1
|
||||||
var initialVerifiedBalance: Int64 = -1
|
var initialVerifiedBalance: Int64 = -1
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { synchronizer in
|
||||||
|
|
||||||
initialBalance = synchronizer.initializer.getBalance()
|
initialBalance = synchronizer.initializer.getBalance()
|
||||||
initialVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
initialVerifiedBalance = synchronizer.initializer.getVerifiedBalance()
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
|
@ -632,7 +637,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
|
|
||||||
let lastSyncExpectation = XCTestExpectation(description: "last sync expectation")
|
let lastSyncExpectation = XCTestExpectation(description: "last sync expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
lastSyncExpectation.fulfill()
|
lastSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -670,6 +675,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
*/
|
*/
|
||||||
func testReOrgChangesOutboundTxMinedHeight() throws {
|
func testReOrgChangesOutboundTxMinedHeight() throws {
|
||||||
hookToReOrgNotification()
|
hookToReOrgNotification()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
1. create fake chain
|
1. create fake chain
|
||||||
*/
|
*/
|
||||||
|
@ -682,7 +688,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
1a. sync to latest height
|
1a. sync to latest height
|
||||||
*/
|
*/
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -692,28 +698,36 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
let initialTotalBalance = coordinator.synchronizer.initializer.getBalance()
|
let initialTotalBalance = coordinator.synchronizer.initializer.getBalance()
|
||||||
|
|
||||||
let sendExpectation = XCTestExpectation(description: "send expectation")
|
let sendExpectation = XCTestExpectation(description: "send expectation")
|
||||||
var p: PendingTransactionEntity? = nil
|
var pendingEntity: PendingTransactionEntity?
|
||||||
|
|
||||||
/*
|
/*
|
||||||
2. send transaction to recipient address
|
2. send transaction to recipient address
|
||||||
*/
|
*/
|
||||||
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 {
|
switch result {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
self.handleError(e)
|
self.handleError(e)
|
||||||
case .success(let pendingTx):
|
case .success(let pendingTx):
|
||||||
p = pendingTx
|
pendingEntity = pendingTx
|
||||||
}
|
}
|
||||||
sendExpectation.fulfill()
|
sendExpectation.fulfill()
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sendExpectation], timeout: 11)
|
wait(for: [sendExpectation], timeout: 11)
|
||||||
|
|
||||||
guard let _ = p else {
|
guard pendingEntity != nil else {
|
||||||
XCTFail("no pending transaction after sending")
|
XCTFail("no pending transaction after sending")
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
3. getIncomingTransaction
|
3. getIncomingTransaction
|
||||||
*/
|
*/
|
||||||
|
@ -725,14 +739,13 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
|
|
||||||
let sentTxHeight: BlockHeight = 663189
|
let sentTxHeight: BlockHeight = 663189
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
4. stage transaction at sentTxHeight
|
4. stage transaction at sentTxHeight
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try coordinator.stageBlockCreate(height: sentTxHeight)
|
try coordinator.stageBlockCreate(height: sentTxHeight)
|
||||||
|
|
||||||
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
|
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
5. applyHeight(sentTxHeight)
|
5. applyHeight(sentTxHeight)
|
||||||
*/
|
*/
|
||||||
|
@ -745,7 +758,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
*/
|
*/
|
||||||
let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
|
let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
secondSyncExpectation.fulfill()
|
secondSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -759,7 +772,6 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
6a. verify that there's a pending transaction with a mined height of sentTxHeight
|
6a. verify that there's a pending transaction with a mined height of sentTxHeight
|
||||||
*/
|
*/
|
||||||
|
|
||||||
XCTAssertEqual(afterStagePendingTx.minedHeight, sentTxHeight)
|
XCTAssertEqual(afterStagePendingTx.minedHeight, sentTxHeight)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -784,7 +796,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
self.expectedReorgHeight = sentTxHeight + 1
|
self.expectedReorgHeight = sentTxHeight + 1
|
||||||
let afterReorgExpectation = XCTestExpectation(description: "after reorg sync")
|
let afterReorgExpectation = XCTestExpectation(description: "after reorg sync")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
afterReorgExpectation.fulfill()
|
afterReorgExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -807,23 +819,20 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
try coordinator.applyStaged(blockheight: sentTxHeight + 2)
|
try coordinator.applyStaged(blockheight: sentTxHeight + 2)
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
|
|
||||||
let yetAnotherExpectation = XCTestExpectation(description: "after staging expectation")
|
let yetAnotherExpectation = XCTestExpectation(description: "after staging expectation")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
11a. sync to latest height
|
11a. sync to latest height
|
||||||
*/
|
*/
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
yetAnotherExpectation.fulfill()
|
yetAnotherExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [yetAnotherExpectation], timeout: 5)
|
wait(for: [yetAnotherExpectation], timeout: 5)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
12. verify that there's a pending transaction with a mined height of sentTxHeight + 2
|
12. verify that there's a pending transaction with a mined height of sentTxHeight + 2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count, 1)
|
XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count, 1)
|
||||||
guard let newlyPendingTx = try coordinator.synchronizer.allPendingTransactions().first else {
|
guard let newlyPendingTx = try coordinator.synchronizer.allPendingTransactions().first else {
|
||||||
XCTFail("no pending transaction")
|
XCTFail("no pending transaction")
|
||||||
|
@ -836,17 +845,16 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
13. apply height(sentTxHeight + 25)
|
13. apply height(sentTxHeight + 25)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: sentTxHeight + 25)
|
try coordinator.applyStaged(blockheight: sentTxHeight + 25)
|
||||||
|
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
let thisIsTheLastExpectationIPromess = XCTestExpectation(description: "last sync")
|
let thisIsTheLastExpectationIPromess = XCTestExpectation(description: "last sync")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
14. sync to latest height
|
14. sync to latest height
|
||||||
*/
|
*/
|
||||||
|
try coordinator.sync(completion: { _ in
|
||||||
try coordinator.sync(completion: { (s) in
|
|
||||||
thisIsTheLastExpectationIPromess.fulfill()
|
thisIsTheLastExpectationIPromess.fulfill()
|
||||||
}, error: self.handleError)
|
}, 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
|
15. verify that there's no pending transaction and that the tx is displayed on the sentTransactions collection
|
||||||
*/
|
*/
|
||||||
|
|
||||||
XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count, 0)
|
XCTAssertEqual(coordinator.synchronizer.pendingTransactions.count, 0)
|
||||||
XCTAssertNotNil(coordinator.synchronizer.sentTransactions.first(where: { t in
|
XCTAssertNotNil(
|
||||||
guard let txId = t.rawTransactionId else { return false }
|
coordinator.synchronizer.sentTransactions
|
||||||
|
.first(
|
||||||
|
where: { transaction in
|
||||||
|
guard let txId = transaction.rawTransactionId else { return false }
|
||||||
return txId == newlyPendingTx.rawTransactionId
|
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.
|
Uses the zcash-hackworks data set.
|
||||||
|
|
||||||
|
@ -891,8 +910,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
sleep(2)
|
sleep(2)
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -914,8 +932,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
sleep(6)
|
sleep(6)
|
||||||
|
|
||||||
let afterReOrgExpectation = XCTestExpectation(description: "after reorg")
|
let afterReOrgExpectation = XCTestExpectation(description: "after reorg")
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
afterReOrgExpectation.fulfill()
|
afterReOrgExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -928,8 +945,8 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
XCTAssertEqual(initialVerifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
|
XCTAssertEqual(initialVerifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
|
||||||
XCTAssertEqual(initialBalance, coordinator.synchronizer.initializer.getBalance())
|
XCTAssertEqual(initialBalance, coordinator.synchronizer.initializer.getBalance())
|
||||||
XCTAssert(afterReOrgTxHeight > initialTxHeight)
|
XCTAssert(afterReOrgTxHeight > initialTxHeight)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Re Org removes incoming transaction and is never mined
|
Re Org removes incoming transaction and is never mined
|
||||||
Steps:
|
Steps:
|
||||||
|
@ -958,7 +975,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
/**
|
/**
|
||||||
1. sync prior to incomingTxHeight - 1 to get balances there
|
1. sync prior to incomingTxHeight - 1 to get balances there
|
||||||
*/
|
*/
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -974,7 +991,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
/**
|
/**
|
||||||
2. sync to latest height
|
2. sync to latest height
|
||||||
*/
|
*/
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
secondSyncExpectation.fulfill()
|
secondSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -989,7 +1006,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
let afterReorgSyncExpectation = XCTestExpectation(description: "after reorg expectation")
|
let afterReorgSyncExpectation = XCTestExpectation(description: "after reorg expectation")
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
afterReorgSyncExpectation.fulfill()
|
afterReorgSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -1024,14 +1041,14 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
let sentTxHeight: BlockHeight = 663195
|
let sentTxHeight: BlockHeight = 663195
|
||||||
try coordinator.applyStaged(blockheight: sentTxHeight - 1)
|
try coordinator.applyStaged(blockheight: sentTxHeight - 1)
|
||||||
|
|
||||||
|
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
1a. sync to latest height
|
1a. sync to latest height
|
||||||
*/
|
*/
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -1040,30 +1057,37 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
let initialTotalBalance = coordinator.synchronizer.initializer.getBalance()
|
let initialTotalBalance = coordinator.synchronizer.initializer.getBalance()
|
||||||
|
|
||||||
|
|
||||||
let sendExpectation = XCTestExpectation(description: "send expectation")
|
let sendExpectation = XCTestExpectation(description: "send expectation")
|
||||||
var p: PendingTransactionEntity? = nil
|
var pendingEntity: PendingTransactionEntity?
|
||||||
|
|
||||||
/*
|
/*
|
||||||
2. send transaction to recipient address
|
2. send transaction to recipient address
|
||||||
*/
|
*/
|
||||||
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 {
|
switch result {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
self.handleError(e)
|
self.handleError(e)
|
||||||
case .success(let pendingTx):
|
case .success(let pendingTx):
|
||||||
p = pendingTx
|
pendingEntity = pendingTx
|
||||||
}
|
}
|
||||||
sendExpectation.fulfill()
|
sendExpectation.fulfill()
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sendExpectation], timeout: 11)
|
wait(for: [sendExpectation], timeout: 11)
|
||||||
|
|
||||||
guard let _ = p else {
|
guard pendingEntity != nil else {
|
||||||
XCTFail("no pending transaction after sending")
|
XCTFail("no pending transaction after sending")
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
3. getIncomingTransaction
|
3. getIncomingTransaction
|
||||||
*/
|
*/
|
||||||
|
@ -1074,13 +1098,14 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.expectedReorgHeight = sentTxHeight + 1
|
self.expectedReorgHeight = sentTxHeight + 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
4. stage transaction at sentTxHeight
|
4. stage transaction at sentTxHeight
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try coordinator.stageBlockCreate(height: sentTxHeight)
|
try coordinator.stageBlockCreate(height: sentTxHeight)
|
||||||
|
|
||||||
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
|
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
5. applyHeight(sentTxHeight)
|
5. applyHeight(sentTxHeight)
|
||||||
*/
|
*/
|
||||||
|
@ -1093,7 +1118,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
*/
|
*/
|
||||||
let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
|
let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
secondSyncExpectation.fulfill()
|
secondSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -1106,7 +1131,7 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
sleep(2)
|
sleep(2)
|
||||||
let reorgSyncExpectation = XCTestExpectation(description: "reorg sync expectation")
|
let reorgSyncExpectation = XCTestExpectation(description: "reorg sync expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
reorgSyncExpectation.fulfill()
|
reorgSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -1126,18 +1151,16 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
|
|
||||||
let lastSyncExpectation = XCTestExpectation(description: "last sync expectation")
|
let lastSyncExpectation = XCTestExpectation(description: "last sync expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
lastSyncExpectation.fulfill()
|
lastSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [lastSyncExpectation], timeout: 5)
|
wait(for: [lastSyncExpectation], timeout: 5)
|
||||||
|
|
||||||
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), initialTotalBalance)
|
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), initialTotalBalance)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testLongSync() throws {
|
func testLongSync() throws {
|
||||||
|
|
||||||
hookToReOrgNotification()
|
hookToReOrgNotification()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1152,10 +1175,11 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
sleep(10)
|
sleep(10)
|
||||||
|
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
sync to latest height
|
sync to latest height
|
||||||
*/
|
*/
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: { error in
|
}, error: { error in
|
||||||
_ = try? self.coordinator.stop()
|
_ = try? self.coordinator.stop()
|
||||||
|
@ -1184,5 +1208,4 @@ class AdvancedReOrgTests: XCTestCase {
|
||||||
func hookToReOrgNotification() {
|
func hookToReOrgNotification() {
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(handleReorg(_:)), name: .blockProcessorHandledReOrg, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(handleReorg(_:)), name: .blockProcessorHandledReOrg, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,22 +7,28 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable type_body_length implicitly_unwrapped_optional force_unwrapping file_length
|
||||||
class BalanceTests: XCTestCase {
|
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?
|
// TODO: Parameterize this from environment?
|
||||||
|
// swiftlint:disable:next line_length
|
||||||
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
|
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
|
let sendAmount: Int64 = 1000
|
||||||
var birthday: BlockHeight = 663150
|
|
||||||
let defaultLatestHeight: BlockHeight = 663188
|
let defaultLatestHeight: BlockHeight = 663188
|
||||||
var coordinator: TestCoordinator!
|
|
||||||
let branchID = "2bb40e60"
|
let branchID = "2bb40e60"
|
||||||
let chainName = "main"
|
let chainName = "main"
|
||||||
var syncedExpectation = XCTestExpectation(description: "synced")
|
|
||||||
var sentTransactionExpectation = XCTestExpectation(description: "sent")
|
|
||||||
let network: ZcashNetwork = DarksideWalletDNetwork()
|
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(
|
coordinator = try TestCoordinator(
|
||||||
seed: seedPhrase,
|
seed: seedPhrase,
|
||||||
walletBirthday: birthday,
|
walletBirthday: birthday,
|
||||||
|
@ -30,7 +36,6 @@ class BalanceTests: XCTestCase {
|
||||||
network: network
|
network: network
|
||||||
)
|
)
|
||||||
try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main")
|
try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,7 +56,7 @@ class BalanceTests: XCTestCase {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: handleError)
|
}, error: handleError)
|
||||||
|
|
||||||
|
@ -71,12 +76,15 @@ class BalanceTests: XCTestCase {
|
||||||
XCTFail("failed to create spending keys")
|
XCTFail("failed to create spending keys")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var pendingTx: PendingTransactionEntity?
|
var pendingTx: PendingTransactionEntity?
|
||||||
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
|
coordinator.synchronizer.sendToAddress(
|
||||||
|
spendingKey: spendingKey,
|
||||||
zatoshi: maxBalance,
|
zatoshi: maxBalance,
|
||||||
toAddress: testRecipientAddress,
|
toAddress: testRecipientAddress,
|
||||||
memo: "test send \(self.description) \(Date().description)",
|
memo: "test send \(self.description) \(Date().description)",
|
||||||
from: 0) { result in
|
from: 0,
|
||||||
|
resultBlock: { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
XCTFail("sendToAddress failed: \(error)")
|
XCTFail("sendToAddress failed: \(error)")
|
||||||
|
@ -85,20 +93,21 @@ class BalanceTests: XCTestCase {
|
||||||
}
|
}
|
||||||
self.sentTransactionExpectation.fulfill()
|
self.sentTransactionExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sentTransactionExpectation], timeout: 20)
|
wait(for: [sentTransactionExpectation], timeout: 20)
|
||||||
guard let pendingTx = pendingTx else {
|
guard let pendingTx = pendingTx else {
|
||||||
XCTFail("transaction creation failed")
|
XCTFail("transaction creation failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationHandler.synchronizerMinedTransaction = { tx in
|
notificationHandler.synchronizerMinedTransaction = { transaction in
|
||||||
XCTAssertNotNil(tx.rawTransactionId)
|
XCTAssertNotNil(transaction.rawTransactionId)
|
||||||
XCTAssertNotNil(pendingTx.rawTransactionId)
|
XCTAssertNotNil(pendingTx.rawTransactionId)
|
||||||
XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId)
|
XCTAssertEqual(transaction.rawTransactionId, pendingTx.rawTransactionId)
|
||||||
transactionMinedExpectation.fulfill()
|
transactionMinedExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 5 apply to height
|
// 5 apply to height
|
||||||
// 6 mine the block
|
// 6 mine the block
|
||||||
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
|
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
|
||||||
|
@ -123,21 +132,23 @@ class BalanceTests: XCTestCase {
|
||||||
sleep(2) // add enhance breakpoint here
|
sleep(2) // add enhance breakpoint here
|
||||||
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(
|
||||||
let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId})
|
completion: { synchronizer in
|
||||||
XCTAssertNotNil(p, "pending transaction should have been mined by now")
|
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
|
||||||
XCTAssertTrue(p?.isMined ?? false)
|
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
|
||||||
XCTAssertEqual(p?.minedHeight, sentTxHeight)
|
XCTAssertTrue(pendingEntity?.isMined ?? false)
|
||||||
|
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
|
||||||
mineExpectation.fulfill()
|
mineExpectation.fulfill()
|
||||||
|
},
|
||||||
}, error: { (error) in
|
error: { error in
|
||||||
guard let e = error else {
|
guard let error = error else {
|
||||||
XCTFail("unknown error syncing after sending transaction")
|
XCTFail("unknown error syncing after sending transaction")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTFail("Error: \(e)")
|
XCTFail("Error: \(error)")
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
|
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
|
||||||
|
|
||||||
|
@ -151,10 +162,10 @@ class BalanceTests: XCTestCase {
|
||||||
notificationHandler.transactionsFound = { txs in
|
notificationHandler.transactionsFound = { txs in
|
||||||
XCTFail("We shouldn't find any transactions at this point but found \(txs)")
|
XCTFail("We shouldn't find any transactions at this point but found \(txs)")
|
||||||
}
|
}
|
||||||
notificationHandler.synchronizerMinedTransaction = { tx in
|
notificationHandler.synchronizerMinedTransaction = { transaction in
|
||||||
XCTFail("We shouldn't find any mined transactions at this point but found \(tx)")
|
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()
|
confirmExpectation.fulfill()
|
||||||
}, error: { e in
|
}, error: { e in
|
||||||
self.handleError(e)
|
self.handleError(e)
|
||||||
|
@ -162,7 +173,8 @@ class BalanceTests: XCTestCase {
|
||||||
|
|
||||||
wait(for: [confirmExpectation], timeout: 5)
|
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")
|
XCTAssertNil(confirmedPending, "pending, now confirmed transaction found")
|
||||||
|
|
||||||
|
@ -170,7 +182,6 @@ class BalanceTests: XCTestCase {
|
||||||
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 0)
|
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
verify that when sending the maximum amount minus one zatoshi, the transactions are broadcasted properly
|
verify that when sending the maximum amount minus one zatoshi, the transactions are broadcasted properly
|
||||||
*/
|
*/
|
||||||
|
@ -189,7 +200,7 @@ class BalanceTests: XCTestCase {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: handleError)
|
}, error: handleError)
|
||||||
|
|
||||||
|
@ -209,12 +220,15 @@ class BalanceTests: XCTestCase {
|
||||||
XCTFail("failed to create spending keys")
|
XCTFail("failed to create spending keys")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var pendingTx: PendingTransactionEntity?
|
var pendingTx: PendingTransactionEntity?
|
||||||
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
|
coordinator.synchronizer.sendToAddress(
|
||||||
|
spendingKey: spendingKey,
|
||||||
zatoshi: maxBalanceMinusOne,
|
zatoshi: maxBalanceMinusOne,
|
||||||
toAddress: testRecipientAddress,
|
toAddress: testRecipientAddress,
|
||||||
memo: "test send \(self.description) \(Date().description)",
|
memo: "test send \(self.description) \(Date().description)",
|
||||||
from: 0) { result in
|
from: 0,
|
||||||
|
resultBlock: { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
XCTFail("sendToAddress failed: \(error)")
|
XCTFail("sendToAddress failed: \(error)")
|
||||||
|
@ -223,20 +237,21 @@ class BalanceTests: XCTestCase {
|
||||||
}
|
}
|
||||||
self.sentTransactionExpectation.fulfill()
|
self.sentTransactionExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sentTransactionExpectation], timeout: 20)
|
wait(for: [sentTransactionExpectation], timeout: 20)
|
||||||
guard let pendingTx = pendingTx else {
|
guard let pendingTx = pendingTx else {
|
||||||
XCTFail("transaction creation failed")
|
XCTFail("transaction creation failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationHandler.synchronizerMinedTransaction = { tx in
|
notificationHandler.synchronizerMinedTransaction = { transaction in
|
||||||
XCTAssertNotNil(tx.rawTransactionId)
|
XCTAssertNotNil(transaction.rawTransactionId)
|
||||||
XCTAssertNotNil(pendingTx.rawTransactionId)
|
XCTAssertNotNil(pendingTx.rawTransactionId)
|
||||||
XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId)
|
XCTAssertEqual(transaction.rawTransactionId, pendingTx.rawTransactionId)
|
||||||
transactionMinedExpectation.fulfill()
|
transactionMinedExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 5 apply to height
|
// 5 apply to height
|
||||||
// 6 mine the block
|
// 6 mine the block
|
||||||
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
|
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
|
||||||
|
@ -261,14 +276,13 @@ class BalanceTests: XCTestCase {
|
||||||
sleep(2) // add enhance breakpoint here
|
sleep(2) // add enhance breakpoint here
|
||||||
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { synchronizer in
|
||||||
let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId})
|
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
|
||||||
XCTAssertNotNil(p, "pending transaction should have been mined by now")
|
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
|
||||||
XCTAssertTrue(p?.isMined ?? false)
|
XCTAssertTrue(pendingEntity?.isMined ?? false)
|
||||||
XCTAssertEqual(p?.minedHeight, sentTxHeight)
|
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
|
||||||
mineExpectation.fulfill()
|
mineExpectation.fulfill()
|
||||||
|
}, error: { error in
|
||||||
}, error: { (error) in
|
|
||||||
guard let e = error else {
|
guard let e = error else {
|
||||||
XCTFail("unknown error syncing after sending transaction")
|
XCTFail("unknown error syncing after sending transaction")
|
||||||
return
|
return
|
||||||
|
@ -289,10 +303,10 @@ class BalanceTests: XCTestCase {
|
||||||
notificationHandler.transactionsFound = { txs in
|
notificationHandler.transactionsFound = { txs in
|
||||||
XCTFail("We shouldn't find any transactions at this point but found \(txs)")
|
XCTFail("We shouldn't find any transactions at this point but found \(txs)")
|
||||||
}
|
}
|
||||||
notificationHandler.synchronizerMinedTransaction = { tx in
|
notificationHandler.synchronizerMinedTransaction = { transaction in
|
||||||
XCTFail("We shouldn't find any mined transactions at this point but found \(tx)")
|
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()
|
confirmExpectation.fulfill()
|
||||||
}, error: { e in
|
}, error: { e in
|
||||||
self.handleError(e)
|
self.handleError(e)
|
||||||
|
@ -300,7 +314,9 @@ class BalanceTests: XCTestCase {
|
||||||
|
|
||||||
wait(for: [confirmExpectation], timeout: 5)
|
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")
|
XCTAssertNil(confirmedPending, "pending, now confirmed transaction found")
|
||||||
|
|
||||||
|
@ -326,7 +342,7 @@ class BalanceTests: XCTestCase {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: handleError)
|
}, error: handleError)
|
||||||
|
|
||||||
|
@ -347,11 +363,13 @@ class BalanceTests: XCTestCase {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var pendingTx: PendingTransactionEntity?
|
var pendingTx: PendingTransactionEntity?
|
||||||
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
|
coordinator.synchronizer.sendToAddress(
|
||||||
|
spendingKey: spendingKey,
|
||||||
zatoshi: maxBalanceMinusOne,
|
zatoshi: maxBalanceMinusOne,
|
||||||
toAddress: testRecipientAddress,
|
toAddress: testRecipientAddress,
|
||||||
memo: "test send \(self.description) \(Date().description)",
|
memo: "test send \(self.description) \(Date().description)",
|
||||||
from: 0) { result in
|
from: 0,
|
||||||
|
resultBlock: { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
XCTFail("sendToAddress failed: \(error)")
|
XCTFail("sendToAddress failed: \(error)")
|
||||||
|
@ -360,20 +378,21 @@ class BalanceTests: XCTestCase {
|
||||||
}
|
}
|
||||||
self.sentTransactionExpectation.fulfill()
|
self.sentTransactionExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sentTransactionExpectation], timeout: 20)
|
wait(for: [sentTransactionExpectation], timeout: 20)
|
||||||
guard let pendingTx = pendingTx else {
|
guard let pendingTx = pendingTx else {
|
||||||
XCTFail("transaction creation failed")
|
XCTFail("transaction creation failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationHandler.synchronizerMinedTransaction = { tx in
|
notificationHandler.synchronizerMinedTransaction = { transaction in
|
||||||
XCTAssertNotNil(tx.rawTransactionId)
|
XCTAssertNotNil(transaction.rawTransactionId)
|
||||||
XCTAssertNotNil(pendingTx.rawTransactionId)
|
XCTAssertNotNil(pendingTx.rawTransactionId)
|
||||||
XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId)
|
XCTAssertEqual(transaction.rawTransactionId, pendingTx.rawTransactionId)
|
||||||
transactionMinedExpectation.fulfill()
|
transactionMinedExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 5 apply to height
|
// 5 apply to height
|
||||||
// 6 mine the block
|
// 6 mine the block
|
||||||
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
|
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
|
||||||
|
@ -398,14 +417,13 @@ class BalanceTests: XCTestCase {
|
||||||
sleep(2) // add enhance breakpoint here
|
sleep(2) // add enhance breakpoint here
|
||||||
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { synchronizer in
|
||||||
let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId})
|
let pendingEntity = synchronizer.pendingTransactions.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
|
||||||
XCTAssertNotNil(p, "pending transaction should have been mined by now")
|
XCTAssertNotNil(pendingEntity, "pending transaction should have been mined by now")
|
||||||
XCTAssertTrue(p?.isMined ?? false)
|
XCTAssertTrue(pendingEntity?.isMined ?? false)
|
||||||
XCTAssertEqual(p?.minedHeight, sentTxHeight)
|
XCTAssertEqual(pendingEntity?.minedHeight, sentTxHeight)
|
||||||
mineExpectation.fulfill()
|
mineExpectation.fulfill()
|
||||||
|
}, error: { error in
|
||||||
}, error: { (error) in
|
|
||||||
guard let e = error else {
|
guard let e = error else {
|
||||||
XCTFail("unknown error syncing after sending transaction")
|
XCTFail("unknown error syncing after sending transaction")
|
||||||
return
|
return
|
||||||
|
@ -426,10 +444,10 @@ class BalanceTests: XCTestCase {
|
||||||
notificationHandler.transactionsFound = { txs in
|
notificationHandler.transactionsFound = { txs in
|
||||||
XCTFail("We shouldn't find any transactions at this point but found \(txs)")
|
XCTFail("We shouldn't find any transactions at this point but found \(txs)")
|
||||||
}
|
}
|
||||||
notificationHandler.synchronizerMinedTransaction = { tx in
|
notificationHandler.synchronizerMinedTransaction = { transaction in
|
||||||
XCTFail("We shouldn't find any mined transactions at this point but found \(tx)")
|
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()
|
confirmExpectation.fulfill()
|
||||||
}, error: { e in
|
}, error: { e in
|
||||||
self.handleError(e)
|
self.handleError(e)
|
||||||
|
@ -437,15 +455,17 @@ class BalanceTests: XCTestCase {
|
||||||
|
|
||||||
wait(for: [confirmExpectation], timeout: 5)
|
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")
|
XCTAssertNil(confirmedPending, "pending, now confirmed transaction found")
|
||||||
|
|
||||||
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), 100000)
|
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), 100000)
|
||||||
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 100000)
|
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 100000)
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
|
|
||||||
|
/**
|
||||||
Verify available balance is correct in all wallet states during a send
|
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.
|
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:
|
Success per state:
|
||||||
Sent: (previous available funds - spent note + change) equals to (previous available funds - sent amount)
|
Sent: (previous available funds - spent note + change) equals to (previous available funds - sent amount)
|
||||||
Error: previous available funds equals to current funds
|
Error: previous available funds equals to current funds
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
// swiftlint:disable cyclomatic_complexity
|
||||||
func testVerifyAvailableBalanceDuringSend() throws {
|
func testVerifyAvailableBalanceDuringSend() throws {
|
||||||
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
|
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: defaultLatestHeight)
|
try coordinator.applyStaged(blockheight: defaultLatestHeight)
|
||||||
|
|
||||||
|
try coordinator.sync(completion: { _ in
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
|
||||||
|
|
||||||
self.syncedExpectation.fulfill()
|
self.syncedExpectation.fulfill()
|
||||||
}, error: handleError)
|
}, error: handleError)
|
||||||
|
|
||||||
|
@ -488,11 +506,13 @@ class BalanceTests: XCTestCase {
|
||||||
XCTAssertTrue(presendVerifiedBalance >= (Int64(network.constants.defaultFee(for: defaultLatestHeight)) + sendAmount))
|
XCTAssertTrue(presendVerifiedBalance >= (Int64(network.constants.defaultFee(for: defaultLatestHeight)) + sendAmount))
|
||||||
|
|
||||||
var pendingTx: PendingTransactionEntity?
|
var pendingTx: PendingTransactionEntity?
|
||||||
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
|
coordinator.synchronizer.sendToAddress(
|
||||||
|
spendingKey: spendingKey,
|
||||||
zatoshi: Int64(sendAmount),
|
zatoshi: Int64(sendAmount),
|
||||||
toAddress: testRecipientAddress,
|
toAddress: testRecipientAddress,
|
||||||
memo: "test send \(self.description) \(Date().description)",
|
memo: "test send \(self.description) \(Date().description)",
|
||||||
from: 0) { result in
|
from: 0,
|
||||||
|
resultBlock: { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
/*
|
/*
|
||||||
|
@ -503,10 +523,10 @@ class BalanceTests: XCTestCase {
|
||||||
case .success(let transaction):
|
case .success(let transaction):
|
||||||
|
|
||||||
pendingTx = transaction
|
pendingTx = transaction
|
||||||
|
|
||||||
}
|
}
|
||||||
self.sentTransactionExpectation.fulfill()
|
self.sentTransactionExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
XCTAssertTrue(coordinator.synchronizer.initializer.getVerifiedBalance() > 0)
|
XCTAssertTrue(coordinator.synchronizer.initializer.getVerifiedBalance() > 0)
|
||||||
wait(for: [sentTransactionExpectation], timeout: 12)
|
wait(for: [sentTransactionExpectation], timeout: 12)
|
||||||
|
@ -527,11 +547,9 @@ class BalanceTests: XCTestCase {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
mineExpectation.fulfill()
|
mineExpectation.fulfill()
|
||||||
|
}, error: { error in
|
||||||
}, error: { (error) in
|
|
||||||
guard let e = error else {
|
guard let e = error else {
|
||||||
XCTFail("unknown error syncing after sending transaction")
|
XCTFail("unknown error syncing after sending transaction")
|
||||||
return
|
return
|
||||||
|
@ -542,13 +560,21 @@ class BalanceTests: XCTestCase {
|
||||||
|
|
||||||
wait(for: [mineExpectation], timeout: 5)
|
wait(for: [mineExpectation], timeout: 5)
|
||||||
|
|
||||||
XCTAssertEqual(presendVerifiedBalance - self.sendAmount - network.constants.defaultFee(for: defaultLatestHeight),coordinator.synchronizer.initializer.getBalance())
|
XCTAssertEqual(
|
||||||
XCTAssertEqual(presendVerifiedBalance - self.sendAmount - network.constants.defaultFee(for: defaultLatestHeight),coordinator.synchronizer.initializer.getVerifiedBalance())
|
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 {
|
guard let transaction = pendingTx else {
|
||||||
XCTFail("pending transaction nil")
|
XCTFail("pending transaction nil")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
basic health check
|
basic health check
|
||||||
*/
|
*/
|
||||||
|
@ -561,40 +587,54 @@ class BalanceTests: XCTestCase {
|
||||||
XCTFail("sent transaction has no internal id")
|
XCTFail("sent transaction has no internal id")
|
||||||
return
|
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))
|
let sentNoteDAO = SentNotesSQLDAO(
|
||||||
var s: SentNoteEntity?
|
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 {
|
do {
|
||||||
s = try sentNoteDAO.sentNote(byRawTransactionId: txid)
|
sentEntity = try sentNoteDAO.sentNote(byRawTransactionId: txid)
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("error retrieving sent note: \(error)")
|
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")
|
XCTFail("could not find sent note for this transaction")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var r: ReceivedNoteEntity?
|
|
||||||
|
var receivedEntity: ReceivedNoteEntity?
|
||||||
|
|
||||||
do {
|
do {
|
||||||
r = try receivedNoteDAO.receivedNote(byRawTransactionId: txid)
|
receivedEntity = try receivedNoteDAO.receivedNote(byRawTransactionId: txid)
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("error retrieving received note: \(error)")
|
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")
|
XCTFail("could not find sent note for this transaction")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// (previous available funds - spent note + change) equals to (previous available funds - sent amount)
|
// (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),
|
spentNoteValue: Int64(sentNote.value),
|
||||||
changeValue: Int64(receivedNote.value),
|
changeValue: Int64(receivedNote.value),
|
||||||
sentAmount: Int64(self.sendAmount),
|
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)
|
try coordinator.applyStaged(blockheight: defaultLatestHeight)
|
||||||
|
|
||||||
sleep(2)
|
sleep(2)
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
self.syncedExpectation.fulfill()
|
self.syncedExpectation.fulfill()
|
||||||
}, error: handleError)
|
}, error: handleError)
|
||||||
|
|
||||||
|
@ -631,28 +671,31 @@ class BalanceTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
let presendBalance = coordinator.synchronizer.initializer.getBalance()
|
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 pendingTx: PendingTransactionEntity?
|
||||||
|
|
||||||
var error: Error?
|
var error: Error?
|
||||||
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
|
coordinator.synchronizer.sendToAddress(
|
||||||
|
spendingKey: spendingKey,
|
||||||
zatoshi: Int64(sendAmount),
|
zatoshi: Int64(sendAmount),
|
||||||
toAddress: testRecipientAddress,
|
toAddress: testRecipientAddress,
|
||||||
memo: "test send \(self.description) \(Date().description)",
|
memo: "test send \(self.description) \(Date().description)",
|
||||||
from: 0) { result in
|
from: 0,
|
||||||
|
resultBlock: { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
// balance should be the same as before sending if transaction failed
|
// balance should be the same as before sending if transaction failed
|
||||||
|
|
||||||
error = e
|
error = e
|
||||||
XCTFail("sendToAddress failed: \(e)")
|
XCTFail("sendToAddress failed: \(e)")
|
||||||
case .success(let transaction):
|
|
||||||
|
|
||||||
|
case .success(let transaction):
|
||||||
pendingTx = transaction
|
pendingTx = transaction
|
||||||
}
|
}
|
||||||
self.sentTransactionExpectation.fulfill()
|
self.sentTransactionExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
XCTAssertTrue(coordinator.synchronizer.initializer.getVerifiedBalance() > 0)
|
XCTAssertTrue(coordinator.synchronizer.initializer.getVerifiedBalance() > 0)
|
||||||
wait(for: [sentTransactionExpectation], timeout: 12)
|
wait(for: [sentTransactionExpectation], timeout: 12)
|
||||||
|
@ -669,7 +712,10 @@ class BalanceTests: XCTestCase {
|
||||||
|
|
||||||
XCTAssertEqual(Int64(transaction.value), self.sendAmount)
|
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)
|
XCTAssertNil(transaction.errorCode)
|
||||||
|
|
||||||
|
@ -686,9 +732,9 @@ class BalanceTests: XCTestCase {
|
||||||
sleep(2)
|
sleep(2)
|
||||||
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
mineExpectation.fulfill()
|
mineExpectation.fulfill()
|
||||||
}, error: { (error) in
|
}, error: { error in
|
||||||
guard let e = error else {
|
guard let e = error else {
|
||||||
XCTFail("unknown error syncing after sending transaction")
|
XCTFail("unknown error syncing after sending transaction")
|
||||||
return
|
return
|
||||||
|
@ -699,7 +745,10 @@ class BalanceTests: XCTestCase {
|
||||||
|
|
||||||
wait(for: [mineExpectation], timeout: 5)
|
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 {
|
func testVerifyIncomingTransaction() throws {
|
||||||
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
|
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
|
||||||
try coordinator.applyStaged(blockheight: defaultLatestHeight)
|
try coordinator.applyStaged(blockheight: defaultLatestHeight)
|
||||||
try coordinator.sync(completion: { (syncronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
self.syncedExpectation.fulfill()
|
self.syncedExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -759,20 +808,17 @@ class BalanceTests: XCTestCase {
|
||||||
let sendExpectation = XCTestExpectation(description: "send expectation")
|
let sendExpectation = XCTestExpectation(description: "send expectation")
|
||||||
let createToAddressExpectation = XCTestExpectation(description: "create to address")
|
let createToAddressExpectation = XCTestExpectation(description: "create to address")
|
||||||
|
|
||||||
|
|
||||||
try coordinator.setLatestHeight(height: defaultLatestHeight)
|
try coordinator.setLatestHeight(height: defaultLatestHeight)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
sync to current tip
|
sync to current tip
|
||||||
*/
|
*/
|
||||||
|
try coordinator.sync(completion: { _ in
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
|
||||||
self.syncedExpectation.fulfill()
|
self.syncedExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [syncedExpectation], timeout: 6)
|
wait(for: [syncedExpectation], timeout: 6)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let previousVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
|
let previousVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
|
||||||
let previousTotalBalance = coordinator.synchronizer.initializer.getBalance()
|
let previousTotalBalance = coordinator.synchronizer.initializer.getBalance()
|
||||||
|
|
||||||
|
@ -786,18 +832,26 @@ class BalanceTests: XCTestCase {
|
||||||
*/
|
*/
|
||||||
let memo = "shielding is fun!"
|
let memo = "shielding is fun!"
|
||||||
var pendingTx: PendingTransactionEntity?
|
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 {
|
DispatchQueue.main.async {
|
||||||
switch sendResult {
|
switch sendResult {
|
||||||
case .failure(let sendError):
|
case .failure(let sendError):
|
||||||
XCTFail("error sending \(sendError)")
|
XCTFail("error sending \(sendError)")
|
||||||
case .success(let tx):
|
|
||||||
pendingTx = tx
|
case .success(let transaction):
|
||||||
|
pendingTx = transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
sendExpectation.fulfill()
|
sendExpectation.fulfill()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
wait(for: [createToAddressExpectation], timeout: 30)
|
wait(for: [createToAddressExpectation], timeout: 30)
|
||||||
|
|
||||||
let syncToMinedheightExpectation = XCTestExpectation(description: "sync to mined height + 1")
|
let syncToMinedheightExpectation = XCTestExpectation(description: "sync to mined height + 1")
|
||||||
|
@ -820,15 +874,13 @@ class BalanceTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
Sync to that block
|
Sync to that block
|
||||||
*/
|
*/
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(
|
||||||
|
completion: { synchronizer in
|
||||||
let confirmedTx: ConfirmedTransactionEntity!
|
let confirmedTx: ConfirmedTransactionEntity!
|
||||||
do {
|
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
|
confirmed.transactionEntity.transactionId == pendingTx?.transactionEntity.transactionId
|
||||||
})
|
})
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("Error retrieving cleared transactions")
|
XCTFail("Error retrieving cleared transactions")
|
||||||
return
|
return
|
||||||
|
@ -837,10 +889,8 @@ class BalanceTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
There’s a sent transaction matching the amount sent to the given zAddr
|
There’s a sent transaction matching the amount sent to the given zAddr
|
||||||
*/
|
*/
|
||||||
|
|
||||||
XCTAssertEqual(Int64(confirmedTx.value), self.sendAmount)
|
XCTAssertEqual(Int64(confirmedTx.value), self.sendAmount)
|
||||||
XCTAssertEqual(confirmedTx.toAddress, self.testRecipientAddress)
|
XCTAssertEqual(confirmedTx.toAddress, self.testRecipientAddress)
|
||||||
|
|
||||||
XCTAssertEqual(confirmedTx.memo?.asZcashTransactionMemo(), memo)
|
XCTAssertEqual(confirmedTx.memo?.asZcashTransactionMemo(), memo)
|
||||||
|
|
||||||
guard let transactionId = confirmedTx.rawTransactionId else {
|
guard let transactionId = confirmedTx.rawTransactionId else {
|
||||||
|
@ -851,14 +901,24 @@ class BalanceTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
Find out what note was used
|
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 {
|
guard let sentNote = try? sentNotesRepo.sentNote(byRawTransactionId: transactionId) else {
|
||||||
XCTFail("Could not finde sent note with transaction Id \(transactionId)")
|
XCTFail("Could not finde sent note with transaction Id \(transactionId)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let receivedNotesRepo = ReceivedNotesSQLDAO(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
|
get change note
|
||||||
|
@ -871,34 +931,38 @@ class BalanceTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
There’s a change note of value (previous note value - sent amount)
|
There’s a change note of value (previous note value - sent amount)
|
||||||
*/
|
*/
|
||||||
XCTAssertEqual(previousVerifiedBalance - self.sendAmount - self.network.constants.defaultFee(for: self.defaultLatestHeight), Int64(receivedNote.value))
|
XCTAssertEqual(
|
||||||
|
previousVerifiedBalance - self.sendAmount - self.network.constants.defaultFee(for: self.defaultLatestHeight),
|
||||||
|
Int64(receivedNote.value)
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Balance meets verified Balance and total balance criteria
|
Balance meets verified Balance and total balance criteria
|
||||||
*/
|
*/
|
||||||
|
|
||||||
self.verifiedBalanceValidation(
|
self.verifiedBalanceValidation(
|
||||||
previousBalance: previousVerifiedBalance,
|
previousBalance: previousVerifiedBalance,
|
||||||
spentNoteValue: Int64(sentNote.value),
|
spentNoteValue: Int64(sentNote.value),
|
||||||
changeValue: Int64(receivedNote.value),
|
changeValue: Int64(receivedNote.value),
|
||||||
sentAmount: Int64(self.sendAmount),
|
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,
|
previousTotalbalance: previousTotalBalance,
|
||||||
sentAmount: Int64(self.sendAmount))
|
sentAmount: Int64(self.sendAmount)
|
||||||
|
)
|
||||||
|
|
||||||
syncToMinedheightExpectation.fulfill()
|
syncToMinedheightExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
},
|
||||||
|
error: self.handleError
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [syncToMinedheightExpectation], timeout: 5)
|
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.
|
This test requires the transaction to expire.
|
||||||
|
|
||||||
How can we mock or cause this? Would createToAddress and faking a network submission through lightwalletService and syncing 10 more blocks work?
|
How can we mock or cause this? Would createToAddress and faking a network submission through lightwalletService and syncing 10 more blocks work?
|
||||||
|
@ -921,18 +985,16 @@ class BalanceTests: XCTestCase {
|
||||||
|
|
||||||
*/
|
*/
|
||||||
func testVerifyBalanceAfterExpiredTransaction() throws {
|
func testVerifyBalanceAfterExpiredTransaction() throws {
|
||||||
|
|
||||||
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
|
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: self.defaultLatestHeight)
|
try coordinator.applyStaged(blockheight: self.defaultLatestHeight)
|
||||||
sleep(2)
|
sleep(2)
|
||||||
try coordinator.sync(completion: { (syncronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
self.syncedExpectation.fulfill()
|
self.syncedExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [syncedExpectation], timeout: 5)
|
wait(for: [syncedExpectation], timeout: 5)
|
||||||
|
|
||||||
|
|
||||||
guard let spendingKey = coordinator.spendingKeys?.first else {
|
guard let spendingKey = coordinator.spendingKeys?.first else {
|
||||||
XCTFail("no synchronizer or spending keys")
|
XCTFail("no synchronizer or spending keys")
|
||||||
return
|
return
|
||||||
|
@ -942,7 +1004,13 @@ class BalanceTests: XCTestCase {
|
||||||
let previousTotalBalance = coordinator.synchronizer.initializer.getBalance()
|
let previousTotalBalance = coordinator.synchronizer.initializer.getBalance()
|
||||||
let sendExpectation = XCTestExpectation(description: "send expectation")
|
let sendExpectation = XCTestExpectation(description: "send expectation")
|
||||||
var pendingTx: PendingTransactionEntity?
|
var pendingTx: PendingTransactionEntity?
|
||||||
coordinator.synchronizer.sendToAddress(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 {
|
switch result {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
// balance should be the same as before sending if transaction failed
|
// balance should be the same as before sending if transaction failed
|
||||||
|
@ -953,6 +1021,8 @@ class BalanceTests: XCTestCase {
|
||||||
pendingTx = pending
|
pendingTx = pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sendExpectation], timeout: 12)
|
wait(for: [sendExpectation], timeout: 12)
|
||||||
|
|
||||||
guard let pendingTransaction = pendingTx, pendingTransaction.expiryHeight > defaultLatestHeight else {
|
guard let pendingTransaction = pendingTx, pendingTransaction.expiryHeight > defaultLatestHeight else {
|
||||||
|
@ -967,7 +1037,7 @@ class BalanceTests: XCTestCase {
|
||||||
try coordinator.applyStaged(blockheight: expiryHeight + 1)
|
try coordinator.applyStaged(blockheight: expiryHeight + 1)
|
||||||
|
|
||||||
sleep(2)
|
sleep(2)
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
expirationSyncExpectation.fulfill()
|
expirationSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -983,7 +1053,11 @@ class BalanceTests: XCTestCase {
|
||||||
*/
|
*/
|
||||||
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), previousTotalBalance)
|
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!),
|
guard let expiredPending = try? pendingRepo.find(by: pendingTransaction.id!),
|
||||||
let id = expiredPending.id else {
|
let id = expiredPending.id else {
|
||||||
|
@ -994,13 +1068,12 @@ class BalanceTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
there no sent transaction displayed
|
there no sent transaction displayed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
XCTAssertNil( try coordinator.synchronizer.allSentTransactions().first(where: { $0.id == id }))
|
XCTAssertNil( try coordinator.synchronizer.allSentTransactions().first(where: { $0.id == id }))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
There’s a pending transaction that has expired
|
There’s a pending transaction that has expired
|
||||||
*/
|
*/
|
||||||
XCTAssertEqual(expiredPending.minedHeight, -1)
|
XCTAssertEqual(expiredPending.minedHeight, -1)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleError(_ error: Error?) {
|
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)
|
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,
|
spentNoteValue: Int64,
|
||||||
changeValue: Int64,
|
changeValue: Int64,
|
||||||
sentAmount: Int64,
|
sentAmount: Int64,
|
||||||
currentVerifiedBalance: Int64) {
|
currentVerifiedBalance: Int64
|
||||||
// (previous available funds - spent note + change) equals to (previous available funds - sent amount)
|
) {
|
||||||
XCTAssertEqual(previousBalance - spentNoteValue + changeValue, currentVerifiedBalance - sentAmount)
|
XCTAssertEqual(previousBalance - spentNoteValue + changeValue, currentVerifiedBalance - sentAmount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func totalBalanceValidation(totalBalance: Int64,
|
func totalBalanceValidation(
|
||||||
|
totalBalance: Int64,
|
||||||
previousTotalbalance: Int64,
|
previousTotalbalance: Int64,
|
||||||
sentAmount: Int64) {
|
sentAmount: Int64
|
||||||
|
) {
|
||||||
XCTAssertEqual(totalBalance, previousTotalbalance - sentAmount - Int64(network.constants.defaultFee(for: defaultLatestHeight)))
|
XCTAssertEqual(totalBalance, previousTotalbalance - sentAmount - Int64(network.constants.defaultFee(for: defaultLatestHeight)))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SDKSynchonizerListener {
|
class SDKSynchonizerListener {
|
||||||
var transactionsFound: (([ConfirmedTransactionEntity]) -> ())?
|
var transactionsFound: (([ConfirmedTransactionEntity]) -> Void)?
|
||||||
var synchronizerMinedTransaction: ((PendingTransactionEntity) -> ())?
|
var synchronizerMinedTransaction: ((PendingTransactionEntity) -> Void)?
|
||||||
|
|
||||||
func subscribeToSynchronizer(_ synchronizer: SDKSynchronizer) {
|
func subscribeToSynchronizer(_ synchronizer: SDKSynchronizer) {
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(txFound(_:)), name: .synchronizerFoundTransactions, object: synchronizer)
|
NotificationCenter.default.addObserver(self, selector: #selector(txFound(_:)), name: .synchronizerFoundTransactions, object: synchronizer)
|
||||||
|
@ -1057,12 +1132,12 @@ class SDKSynchonizerListener {
|
||||||
|
|
||||||
@objc func txMined(_ notification: Notification) {
|
@objc func txMined(_ notification: Notification) {
|
||||||
DispatchQueue.main.async { [weak self] in
|
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")
|
XCTFail("expected transaction")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self?.synchronizerMinedTransaction?(tx)
|
self?.synchronizerMinedTransaction?(transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,27 +8,45 @@
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable force_try type_body_length
|
||||||
class BlockBatchValidationTests: XCTestCase {
|
class BlockBatchValidationTests: XCTestCase {
|
||||||
var queue: OperationQueue = {
|
var queue: OperationQueue = {
|
||||||
let q = OperationQueue()
|
let queue = OperationQueue()
|
||||||
q.name = "Test Queue"
|
queue.name = "Test Queue"
|
||||||
q.maxConcurrentOperationCount = 1
|
queue.maxConcurrentOperationCount = 1
|
||||||
return q
|
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.
|
// 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.
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||||
|
super.tearDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBranchIdFailure() throws {
|
func testBranchIdFailure() throws {
|
||||||
let network = ZcashNetworkBuilder.network(for: .mainnet)
|
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 repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = 130000
|
info.blockHeight = 130000
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
|
@ -40,13 +58,15 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockRust = MockRustBackend.self
|
||||||
mockRust.consensusBranchID = Int32(0xd34d)
|
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 expectation = XCTestExpectation(description: "failure expectation")
|
||||||
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
||||||
|
|
||||||
operation.startedHandler = {
|
operation.startedHandler = {
|
||||||
startedExpectation.fulfill()
|
startedExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
operation.errorHandler = { error in
|
operation.errorHandler = { error in
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
switch error {
|
switch error {
|
||||||
|
@ -65,10 +85,23 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
|
|
||||||
func testBranchNetworkMismatchFailure() throws {
|
func testBranchNetworkMismatchFailure() throws {
|
||||||
let network = ZcashNetworkBuilder.network(for: .mainnet)
|
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 repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = 130000
|
info.blockHeight = 130000
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
|
@ -76,17 +109,20 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
info.buildUser = "test user"
|
info.buildUser = "test user"
|
||||||
info.consensusBranchID = "d34db4d"
|
info.consensusBranchID = "d34db4d"
|
||||||
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
|
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockRust = MockRustBackend.self
|
||||||
mockRust.consensusBranchID = 0xd34db4d
|
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 expectation = XCTestExpectation(description: "failure expectation")
|
||||||
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
||||||
|
|
||||||
operation.startedHandler = {
|
operation.startedHandler = {
|
||||||
startedExpectation.fulfill()
|
startedExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
operation.errorHandler = { error in
|
operation.errorHandler = { error in
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
switch error {
|
switch error {
|
||||||
|
@ -96,6 +132,7 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
XCTFail("Expected CompactBlockProcessorError.networkMismatch but found \(error)")
|
XCTFail("Expected CompactBlockProcessorError.networkMismatch but found \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.addOperations([operation], waitUntilFinished: false)
|
queue.addOperations([operation], waitUntilFinished: false)
|
||||||
|
|
||||||
wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true)
|
wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true)
|
||||||
|
@ -103,13 +140,25 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
XCTAssertTrue(operation.isCancelled)
|
XCTAssertTrue(operation.isCancelled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func testBranchNetworkTypeWrongFailure() throws {
|
func testBranchNetworkTypeWrongFailure() throws {
|
||||||
let network = ZcashNetworkBuilder.network(for: .testnet)
|
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 repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = 130000
|
info.blockHeight = 130000
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
|
@ -117,17 +166,20 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
info.buildUser = "test user"
|
info.buildUser = "test user"
|
||||||
info.consensusBranchID = "d34db4d"
|
info.consensusBranchID = "d34db4d"
|
||||||
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
|
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockRust = MockRustBackend.self
|
||||||
mockRust.consensusBranchID = 0xd34db4d
|
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 expectation = XCTestExpectation(description: "failure expectation")
|
||||||
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
||||||
|
|
||||||
operation.startedHandler = {
|
operation.startedHandler = {
|
||||||
startedExpectation.fulfill()
|
startedExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
operation.errorHandler = { error in
|
operation.errorHandler = { error in
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
switch error {
|
switch error {
|
||||||
|
@ -137,6 +189,7 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
XCTFail("Expected CompactBlockProcessorError.generalError but found \(error)")
|
XCTFail("Expected CompactBlockProcessorError.generalError but found \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.addOperations([operation], waitUntilFinished: false)
|
queue.addOperations([operation], waitUntilFinished: false)
|
||||||
|
|
||||||
wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true)
|
wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true)
|
||||||
|
@ -146,10 +199,24 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
|
|
||||||
func testSaplingActivationHeightMismatch() throws {
|
func testSaplingActivationHeightMismatch() throws {
|
||||||
let network = ZcashNetworkBuilder.network(for: .mainnet)
|
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 repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = 130000
|
info.blockHeight = 130000
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
|
@ -157,26 +224,33 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
info.buildUser = "test user"
|
info.buildUser = "test user"
|
||||||
info.consensusBranchID = "d34db4d"
|
info.consensusBranchID = "d34db4d"
|
||||||
info.saplingActivationHeight = UInt64(3434343)
|
info.saplingActivationHeight = UInt64(3434343)
|
||||||
|
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockRust = MockRustBackend.self
|
||||||
mockRust.consensusBranchID = 0xd34db4d
|
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 expectation = XCTestExpectation(description: "failure expectation")
|
||||||
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
||||||
|
|
||||||
operation.startedHandler = {
|
operation.startedHandler = {
|
||||||
startedExpectation.fulfill()
|
startedExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
operation.errorHandler = { error in
|
operation.errorHandler = { error in
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
switch error {
|
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
|
break
|
||||||
default:
|
default:
|
||||||
XCTFail("Expected CompactBlockProcessorError.saplingActivationMismatch but found \(error)")
|
XCTFail("Expected CompactBlockProcessorError.saplingActivationMismatch but found \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.addOperations([operation], waitUntilFinished: false)
|
queue.addOperations([operation], waitUntilFinished: false)
|
||||||
|
|
||||||
wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true)
|
wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true)
|
||||||
|
@ -188,12 +262,29 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
let network = ZcashNetworkBuilder.network(for: .mainnet)
|
let network = ZcashNetworkBuilder.network(for: .mainnet)
|
||||||
|
|
||||||
let expectedLatestHeight = BlockHeight(1210000)
|
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 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 repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = UInt64(expectedLatestHeight)
|
info.blockHeight = UInt64(expectedLatestHeight)
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
|
@ -201,56 +292,84 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
info.buildUser = "test user"
|
info.buildUser = "test user"
|
||||||
info.consensusBranchID = "d34db4d"
|
info.consensusBranchID = "d34db4d"
|
||||||
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
|
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockRust = MockRustBackend.self
|
||||||
mockRust.consensusBranchID = 0xd34db4d
|
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 completedExpectation = XCTestExpectation(description: "completed expectation")
|
||||||
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
||||||
|
|
||||||
operation.startedHandler = {
|
operation.startedHandler = {
|
||||||
startedExpectation.fulfill()
|
startedExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
operation.errorHandler = { error in
|
operation.errorHandler = { error in
|
||||||
XCTFail("this shouldn't happen: \(error)")
|
XCTFail("this shouldn't happen: \(error)")
|
||||||
}
|
}
|
||||||
operation.completionHandler = { (finished, cancelled) in
|
|
||||||
|
operation.completionHandler = { finished, cancelled in
|
||||||
completedExpectation.fulfill()
|
completedExpectation.fulfill()
|
||||||
XCTAssertTrue(finished)
|
XCTAssertTrue(finished)
|
||||||
XCTAssertFalse(cancelled)
|
XCTAssertFalse(cancelled)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.addOperations([operation], waitUntilFinished: false)
|
queue.addOperations([operation], waitUntilFinished: false)
|
||||||
|
|
||||||
wait(for: [startedExpectation, completedExpectation], timeout: 1, enforceOrder: true)
|
wait(for: [startedExpectation, completedExpectation], timeout: 1, enforceOrder: true)
|
||||||
XCTAssertNil(operation.error)
|
XCTAssertNil(operation.error)
|
||||||
XCTAssertFalse(operation.isCancelled)
|
XCTAssertFalse(operation.isCancelled)
|
||||||
|
|
||||||
guard let result = operation.result else {
|
guard let result = operation.result else {
|
||||||
XCTFail("result should not be nil")
|
XCTFail("result should not be nil")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertTrue({
|
XCTAssertTrue(
|
||||||
|
{
|
||||||
switch result {
|
switch result {
|
||||||
case .wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight):
|
case .wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight):
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}(), "Expected \(expectedResult) got: \(result)")
|
}(),
|
||||||
|
"Expected \(expectedResult) got: \(result)"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testResultProcessNew() throws {
|
func testResultProcessNew() throws {
|
||||||
let network = ZcashNetworkBuilder.network(for: .mainnet)
|
let network = ZcashNetworkBuilder.network(for: .mainnet)
|
||||||
let expectedLatestHeight = BlockHeight(1230000)
|
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 expectedStoreLatestHeight = BlockHeight(1220000)
|
||||||
let walletBirthday = BlockHeight(1210000)
|
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 repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = UInt64(expectedLatestHeight)
|
info.blockHeight = UInt64(expectedLatestHeight)
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
|
@ -258,56 +377,78 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
info.buildUser = "test user"
|
info.buildUser = "test user"
|
||||||
info.consensusBranchID = "d34db4d"
|
info.consensusBranchID = "d34db4d"
|
||||||
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
|
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockRust = MockRustBackend.self
|
||||||
mockRust.consensusBranchID = 0xd34db4d
|
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 completedExpectation = XCTestExpectation(description: "completed expectation")
|
||||||
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
||||||
|
|
||||||
operation.startedHandler = {
|
operation.startedHandler = {
|
||||||
startedExpectation.fulfill()
|
startedExpectation.fulfill()
|
||||||
}
|
}
|
||||||
operation.errorHandler = { error in
|
|
||||||
|
operation.errorHandler = { _ in
|
||||||
XCTFail("this shouldn't happen")
|
XCTFail("this shouldn't happen")
|
||||||
}
|
}
|
||||||
operation.completionHandler = { (finished, cancelled) in
|
|
||||||
|
operation.completionHandler = { finished, cancelled in
|
||||||
completedExpectation.fulfill()
|
completedExpectation.fulfill()
|
||||||
XCTAssertTrue(finished)
|
XCTAssertTrue(finished)
|
||||||
XCTAssertFalse(cancelled)
|
XCTAssertFalse(cancelled)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.addOperations([operation], waitUntilFinished: false)
|
queue.addOperations([operation], waitUntilFinished: false)
|
||||||
|
|
||||||
wait(for: [startedExpectation, completedExpectation], timeout: 1, enforceOrder: true)
|
wait(for: [startedExpectation, completedExpectation], timeout: 1, enforceOrder: true)
|
||||||
XCTAssertNil(operation.error)
|
XCTAssertNil(operation.error)
|
||||||
XCTAssertFalse(operation.isCancelled)
|
XCTAssertFalse(operation.isCancelled)
|
||||||
|
|
||||||
guard let result = operation.result else {
|
guard let result = operation.result else {
|
||||||
XCTFail("result should not be nil")
|
XCTFail("result should not be nil")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertTrue({
|
XCTAssertTrue(
|
||||||
|
{
|
||||||
switch result {
|
switch result {
|
||||||
case .processNewBlocks(range: CompactBlockRange(uncheckedBounds: (expectedStoreLatestHeight + 1, expectedLatestHeight))):
|
case .processNewBlocks(range: CompactBlockRange(uncheckedBounds: (expectedStoreLatestHeight + 1, expectedLatestHeight))):
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}(), "Expected \(expectedResult) got: \(result)")
|
}(),
|
||||||
|
"Expected \(expectedResult) got: \(result)"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testResultProcessorFinished() throws {
|
func testResultProcessorFinished() throws {
|
||||||
let network = ZcashNetworkBuilder.network(for: .mainnet)
|
let network = ZcashNetworkBuilder.network(for: .mainnet)
|
||||||
let expectedLatestHeight = BlockHeight(1230000)
|
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 expectedStoreLatestHeight = BlockHeight(1230000)
|
||||||
let walletBirthday = BlockHeight(1210000)
|
let walletBirthday = BlockHeight(1210000)
|
||||||
let expectedResult = FigureNextBatchOperation.NextState.finishProcessing(height: expectedStoreLatestHeight)
|
let expectedResult = FigureNextBatchOperation.NextState.finishProcessing(height: expectedStoreLatestHeight)
|
||||||
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
|
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = UInt64(expectedLatestHeight)
|
info.blockHeight = UInt64(expectedLatestHeight)
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
|
@ -315,43 +456,51 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
info.buildUser = "test user"
|
info.buildUser = "test user"
|
||||||
info.consensusBranchID = "d34db4d"
|
info.consensusBranchID = "d34db4d"
|
||||||
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
|
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockRust = MockRustBackend.self
|
||||||
mockRust.consensusBranchID = 0xd34db4d
|
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 completedExpectation = XCTestExpectation(description: "completed expectation")
|
||||||
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
let startedExpectation = XCTestExpectation(description: "start Expectation")
|
||||||
|
|
||||||
operation.startedHandler = {
|
operation.startedHandler = {
|
||||||
startedExpectation.fulfill()
|
startedExpectation.fulfill()
|
||||||
}
|
}
|
||||||
operation.errorHandler = { error in
|
|
||||||
|
operation.errorHandler = { _ in
|
||||||
XCTFail("this shouldn't happen")
|
XCTFail("this shouldn't happen")
|
||||||
}
|
}
|
||||||
operation.completionHandler = { (finished, cancelled) in
|
|
||||||
|
operation.completionHandler = { finished, cancelled in
|
||||||
completedExpectation.fulfill()
|
completedExpectation.fulfill()
|
||||||
XCTAssertTrue(finished)
|
XCTAssertTrue(finished)
|
||||||
XCTAssertFalse(cancelled)
|
XCTAssertFalse(cancelled)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.addOperations([operation], waitUntilFinished: false)
|
queue.addOperations([operation], waitUntilFinished: false)
|
||||||
|
|
||||||
wait(for: [startedExpectation, completedExpectation], timeout: 1, enforceOrder: true)
|
wait(for: [startedExpectation, completedExpectation], timeout: 1, enforceOrder: true)
|
||||||
XCTAssertNil(operation.error)
|
XCTAssertNil(operation.error)
|
||||||
XCTAssertFalse(operation.isCancelled)
|
XCTAssertFalse(operation.isCancelled)
|
||||||
|
|
||||||
guard let result = operation.result else {
|
guard let result = operation.result else {
|
||||||
XCTFail("result should not be nil")
|
XCTFail("result should not be nil")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertTrue({
|
XCTAssertTrue(
|
||||||
|
{
|
||||||
switch result {
|
switch result {
|
||||||
case .finishProcessing(height: expectedLatestHeight):
|
case .finishProcessing(height: expectedLatestHeight):
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}(), "Expected \(expectedResult) got: \(result)")
|
}(),
|
||||||
|
"Expected \(expectedResult) got: \(result)"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,21 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@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 downloader: CompactBlockDownloading!
|
||||||
var service: LightWalletService!
|
var service: LightWalletService!
|
||||||
var storage: CompactBlockRepository!
|
var storage: CompactBlockRepository!
|
||||||
var cacheDB = try! __cacheDbURL()
|
var cacheDB = try! __cacheDbURL()
|
||||||
var network = DarksideWalletDNetwork()
|
var network = DarksideWalletDNetwork()
|
||||||
var darksideWalletService: DarksideWalletService!
|
|
||||||
let branchID = "2bb40e60"
|
|
||||||
let chainName = "main"
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
|
try super.setUpWithError()
|
||||||
service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)
|
service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)
|
||||||
storage = try! TestDbBuilder.diskCompactBlockStorage(at: cacheDB)
|
storage = try! TestDbBuilder.diskCompactBlockStorage(at: cacheDB)
|
||||||
downloader = CompactBlockDownloader(service: service, storage: storage)
|
downloader = CompactBlockDownloader(service: service, storage: storage)
|
||||||
|
@ -29,7 +33,7 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
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
|
service = nil
|
||||||
storage = nil
|
storage = nil
|
||||||
downloader = nil
|
downloader = nil
|
||||||
|
@ -37,24 +41,23 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSmallDownloadAsync() {
|
func testSmallDownloadAsync() {
|
||||||
|
|
||||||
let expect = XCTestExpectation(description: self.description)
|
let expect = XCTestExpectation(description: self.description)
|
||||||
expect.expectedFulfillmentCount = 3
|
expect.expectedFulfillmentCount = 3
|
||||||
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
||||||
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
||||||
|
|
||||||
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
||||||
downloader.downloadBlockRange(range) { (error) in
|
downloader.downloadBlockRange(range) { error in
|
||||||
expect.fulfill()
|
expect.fulfill()
|
||||||
XCTAssertNil(error)
|
XCTAssertNil(error)
|
||||||
|
|
||||||
// check what was 'stored'
|
// check what was 'stored'
|
||||||
self.storage.latestHeight { (result) in
|
self.storage.latestHeight { result in
|
||||||
expect.fulfill()
|
expect.fulfill()
|
||||||
|
|
||||||
XCTAssertTrue(self.validate(result: result, against: upperRange))
|
XCTAssertTrue(self.validate(result: result, against: upperRange))
|
||||||
|
|
||||||
self.downloader.lastDownloadedBlockHeight { (resultHeight) in
|
self.downloader.lastDownloadedBlockHeight { resultHeight in
|
||||||
expect.fulfill()
|
expect.fulfill()
|
||||||
XCTAssertTrue(self.validate(result: resultHeight, against: upperRange))
|
XCTAssertTrue(self.validate(result: resultHeight, against: upperRange))
|
||||||
}
|
}
|
||||||
|
@ -65,7 +68,6 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSmallDownload() {
|
func testSmallDownload() {
|
||||||
|
|
||||||
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
||||||
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
||||||
|
|
||||||
|
@ -84,17 +86,22 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
var currentLatest: BlockHeight = 0
|
var currentLatest: BlockHeight = 0
|
||||||
do {
|
do {
|
||||||
currentLatest = try downloader.lastDownloadedBlockHeight()
|
currentLatest = try downloader.lastDownloadedBlockHeight()
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("latest block failed")
|
XCTFail("latest block failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
XCTAssertEqual(currentLatest,upperRange )
|
|
||||||
|
|
||||||
|
XCTAssertEqual(currentLatest, upperRange )
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFailure() {
|
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)
|
let expect = XCTestExpectation(description: self.description)
|
||||||
expect.expectedFulfillmentCount = 1
|
expect.expectedFulfillmentCount = 1
|
||||||
|
@ -103,7 +110,7 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
|
|
||||||
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
||||||
|
|
||||||
awfulDownloader.downloadBlockRange(range) { (error) in
|
awfulDownloader.downloadBlockRange(range) { error in
|
||||||
expect.fulfill()
|
expect.fulfill()
|
||||||
XCTAssertNotNil(error)
|
XCTAssertNotNil(error)
|
||||||
}
|
}
|
||||||
|
@ -115,13 +122,11 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
|
|
||||||
extension BlockDownloaderTests {
|
extension BlockDownloaderTests {
|
||||||
func validate(result: Result<BlockHeight, Error>, against height: BlockHeight) -> Bool {
|
func validate(result: Result<BlockHeight, Error>, against height: BlockHeight) -> Bool {
|
||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let resultHeight):
|
case .success(let resultHeight):
|
||||||
return resultHeight == height
|
return resultHeight == height
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,23 +9,31 @@
|
||||||
import XCTest
|
import XCTest
|
||||||
import SQLite
|
import SQLite
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional force_try force_unwrapping print_function_usage
|
||||||
class BlockScanOperationTests: XCTestCase {
|
class BlockScanOperationTests: XCTestCase {
|
||||||
|
let rustWelding = ZcashRustBackend.self
|
||||||
|
|
||||||
var operationQueue = OperationQueue()
|
var operationQueue = OperationQueue()
|
||||||
var cacheDbURL: URL!
|
var cacheDbURL: URL!
|
||||||
var dataDbURL: URL!
|
var dataDbURL: URL!
|
||||||
let rustWelding = ZcashRustBackend.self
|
|
||||||
|
|
||||||
var uvk = UVFakeKey(extfvk: "zxviewtestsapling1qw88ayg8qqqqpqyhg7jnh9mlldejfqwu46pm40ruwstd8znq3v3l4hjf33qcu2a5e36katshcfhcxhzgyfugj2lkhmt40j45cv38rv3frnghzkxcx73k7m7afw9j7ujk7nm4dx5mv02r26umxqgar7v3x390w2h3crqqgjsjly7jy4vtwzrmustm5yudpgcydw7x78awca8wqjvkqj8p8e3ykt7lrgd7xf92fsfqjs5vegfsja4ekzpfh5vtccgvs5747xqm6qflmtqpr8s9u",
|
var uvk = UVFakeKey(
|
||||||
extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61")
|
extfvk: "zxviewtestsapling1qw88ayg8qqqqpqyhg7jnh9mlldejfqwu46pm40ruwstd8znq3v3l4hjf33qcu2a5e36katshcfhcxhzgyfugj2lkhmt40j45cv38rv3frnghzkxcx73k7m7afw9j7ujk7nm4dx5mv02r26umxqgar7v3x390w2h3crqqgjsjly7jy4vtwzrmustm5yudpgcydw7x78awca8wqjvkqj8p8e3ykt7lrgd7xf92fsfqjs5vegfsja4ekzpfh5vtccgvs5747xqm6qflmtqpr8s9u", // swiftlint:disable:this line_length
|
||||||
|
extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61"
|
||||||
|
)
|
||||||
|
|
||||||
|
var walletBirthDay = WalletBirthday.birthday(
|
||||||
var walletBirthDay = WalletBirthday.birthday(with: 1386000, network: ZcashNetworkBuilder.network(for: .testnet))
|
with: 1386000,
|
||||||
|
network: ZcashNetworkBuilder.network(for: .testnet)
|
||||||
|
)
|
||||||
|
|
||||||
var network = ZcashNetworkBuilder.network(for: .testnet)
|
var network = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
var blockRepository: BlockRepository!
|
var blockRepository: BlockRepository!
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// 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.cacheDbURL = try! __cacheDbURL()
|
||||||
self.dataDbURL = try! __dataDbURL()
|
self.dataDbURL = try! __dataDbURL()
|
||||||
|
|
||||||
|
@ -37,8 +45,10 @@ class BlockScanOperationTests: XCTestCase {
|
||||||
try? FileManager.default.removeItem(at: cacheDbURL)
|
try? FileManager.default.removeItem(at: cacheDbURL)
|
||||||
try? FileManager.default.removeItem(at: dataDbURL)
|
try? FileManager.default.removeItem(at: dataDbURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||||
|
super.tearDown()
|
||||||
operationQueue.cancelAllOperations()
|
operationQueue.cancelAllOperations()
|
||||||
|
|
||||||
try? FileManager.default.removeItem(at: cacheDbURL)
|
try? FileManager.default.removeItem(at: cacheDbURL)
|
||||||
|
@ -47,29 +57,47 @@ class BlockScanOperationTests: XCTestCase {
|
||||||
|
|
||||||
func testSingleDownloadAndScanOperation() {
|
func testSingleDownloadAndScanOperation() {
|
||||||
logger = SampleLogger(logLevel: .debug)
|
logger = SampleLogger(logLevel: .debug)
|
||||||
|
|
||||||
XCTAssertNoThrow(try rustWelding.initDataDb(dbData: dataDbURL, networkType: network.networkType))
|
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 downloadStartedExpect = XCTestExpectation(description: "\(self.description) download started")
|
||||||
let scanStartedExpect = XCTestExpectation(description: self.description + "scan started")
|
let downloadExpect = XCTestExpectation(description: "\(self.description) download")
|
||||||
let scanExpect = XCTestExpectation(description: self.description + "scan")
|
let scanStartedExpect = XCTestExpectation(description: "\(self.description) scan started")
|
||||||
let latestScannedBlockExpect = XCTestExpectation(description: self.description + "latestScannedHeight")
|
let scanExpect = XCTestExpectation(description: "\(self.description) scan")
|
||||||
let service = LightWalletGRPCService(endpoint: LightWalletEndpoint(address: "lightwalletd.testnet.electriccoin.co", port: 9067))
|
let latestScannedBlockExpect = XCTestExpectation(description: "\(self.description) latestScannedHeight")
|
||||||
|
let service = LightWalletGRPCService(
|
||||||
|
endpoint: LightWalletEndpoint(
|
||||||
|
address: "lightwalletd.testnet.electriccoin.co",
|
||||||
|
port: 9067
|
||||||
|
)
|
||||||
|
)
|
||||||
let blockCount = 100
|
let blockCount = 100
|
||||||
let range = network.constants.saplingActivationHeight ... network.constants.saplingActivationHeight + blockCount
|
let range = network.constants.saplingActivationHeight ... network.constants.saplingActivationHeight + blockCount
|
||||||
let downloadOperation = CompactBlockDownloadOperation(downloader: CompactBlockDownloader.sqlDownloader(service: service, at: cacheDbURL)!, range: range)
|
let downloadOperation = CompactBlockDownloadOperation(
|
||||||
let scanOperation = CompactBlockScanningOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, networkType: network.networkType)
|
downloader: CompactBlockDownloader.sqlDownloader(
|
||||||
|
service: service,
|
||||||
|
at: cacheDbURL
|
||||||
|
)!,
|
||||||
|
range: range
|
||||||
|
)
|
||||||
|
let scanOperation = CompactBlockScanningOperation(
|
||||||
|
rustWelding: rustWelding,
|
||||||
|
cacheDb: cacheDbURL,
|
||||||
|
dataDb: dataDbURL,
|
||||||
|
networkType: network.networkType
|
||||||
|
)
|
||||||
|
|
||||||
downloadOperation.startedHandler = {
|
downloadOperation.startedHandler = {
|
||||||
downloadStartedExpect.fulfill()
|
downloadStartedExpect.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadOperation.completionHandler = { (finished, cancelled) in
|
downloadOperation.completionHandler = { finished, cancelled in
|
||||||
downloadExpect.fulfill()
|
downloadExpect.fulfill()
|
||||||
XCTAssertTrue(finished)
|
XCTAssertTrue(finished)
|
||||||
XCTAssertFalse(cancelled)
|
XCTAssertFalse(cancelled)
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadOperation.errorHandler = { (error) in
|
downloadOperation.errorHandler = { error in
|
||||||
XCTFail("Download Operation failed with Error: \(error)")
|
XCTFail("Download Operation failed with Error: \(error)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,13 +105,13 @@ class BlockScanOperationTests: XCTestCase {
|
||||||
scanStartedExpect.fulfill()
|
scanStartedExpect.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
scanOperation.completionHandler = { (finished, cancelled) in
|
scanOperation.completionHandler = { finished, cancelled in
|
||||||
scanExpect.fulfill()
|
scanExpect.fulfill()
|
||||||
XCTAssertFalse(cancelled)
|
XCTAssertFalse(cancelled)
|
||||||
XCTAssertTrue(finished)
|
XCTAssertTrue(finished)
|
||||||
}
|
}
|
||||||
|
|
||||||
scanOperation.errorHandler = { (error) in
|
scanOperation.errorHandler = { error in
|
||||||
XCTFail("Scan Operation failed with Error: \(error)")
|
XCTFail("Scan Operation failed with Error: \(error)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,10 +129,16 @@ class BlockScanOperationTests: XCTestCase {
|
||||||
|
|
||||||
latestScannedBlockOperation.addDependency(scanOperation)
|
latestScannedBlockOperation.addDependency(scanOperation)
|
||||||
|
|
||||||
operationQueue.addOperations([downloadOperation,scanOperation,latestScannedBlockOperation], waitUntilFinished: false)
|
operationQueue.addOperations(
|
||||||
|
[downloadOperation, scanOperation, latestScannedBlockOperation],
|
||||||
|
waitUntilFinished: false
|
||||||
|
)
|
||||||
|
|
||||||
|
wait(
|
||||||
wait(for: [downloadStartedExpect, downloadExpect, scanStartedExpect, scanExpect,latestScannedBlockExpect], timeout: 10, enforceOrder: true)
|
for: [downloadStartedExpect, downloadExpect, scanStartedExpect, scanExpect, latestScannedBlockExpect],
|
||||||
|
timeout: 10,
|
||||||
|
enforceOrder: true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@objc func observeBenchmark(_ notification: Notification) {
|
@objc func observeBenchmark(_ notification: Notification) {
|
||||||
guard let report = SDKMetrics.blockReportFromNotification(notification) else {
|
guard let report = SDKMetrics.blockReportFromNotification(notification) else {
|
||||||
|
@ -112,20 +146,32 @@ class BlockScanOperationTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
print("observed benchmark: \(report)")
|
print("observed benchmark: \(report)")
|
||||||
|
|
||||||
}
|
}
|
||||||
func testScanValidateDownload() throws {
|
func testScanValidateDownload() throws {
|
||||||
logger = SampleLogger(logLevel: .debug)
|
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)
|
try self.rustWelding.initDataDb(dbData: dataDbURL, networkType: network.networkType)
|
||||||
|
|
||||||
guard try self.rustWelding.initAccountsTable(dbData: self.dataDbURL, uvks: [uvk], networkType: network.networkType) else {
|
guard try self.rustWelding.initAccountsTable(dbData: self.dataDbURL, uvks: [uvk], networkType: network.networkType) else {
|
||||||
XCTFail("failed to init account table")
|
XCTFail("failed to init account table")
|
||||||
return
|
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 service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)
|
||||||
let storage = CompactBlockStorage(url: cacheDbURL, readonly: false)
|
let storage = CompactBlockStorage(url: cacheDbURL, readonly: false)
|
||||||
|
@ -135,13 +181,15 @@ class BlockScanOperationTests: XCTestCase {
|
||||||
let validateExpectation = XCTestExpectation(description: "validate expectation")
|
let validateExpectation = XCTestExpectation(description: "validate expectation")
|
||||||
let scanExpectation = XCTestExpectation(description: "scan expectation")
|
let scanExpectation = XCTestExpectation(description: "scan expectation")
|
||||||
|
|
||||||
let downloadOperation = CompactBlockStreamDownloadOperation(service: service,
|
let downloadOperation = CompactBlockStreamDownloadOperation(
|
||||||
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
startHeight: walletBirthDay.height,
|
startHeight: walletBirthDay.height,
|
||||||
targetHeight: walletBirthDay.height + 10000,
|
targetHeight: walletBirthDay.height + 10000,
|
||||||
progressDelegate: self)
|
progressDelegate: self
|
||||||
|
)
|
||||||
|
|
||||||
downloadOperation.completionHandler = { (finished, cancelled) in
|
downloadOperation.completionHandler = { finished, cancelled in
|
||||||
XCTAssert(finished)
|
XCTAssert(finished)
|
||||||
XCTAssertFalse(cancelled)
|
XCTAssertFalse(cancelled)
|
||||||
downloadExpectation.fulfill()
|
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
|
validationOperation.errorHandler = { error in
|
||||||
self.operationQueue.cancelAllOperations()
|
self.operationQueue.cancelAllOperations()
|
||||||
XCTFail("failed with error \(error)")
|
XCTFail("failed with error \(error)")
|
||||||
|
|
||||||
}
|
}
|
||||||
validationOperation.completionHandler = { (finished,cancelled) in
|
|
||||||
|
validationOperation.completionHandler = { finished, cancelled in
|
||||||
XCTAssert(finished)
|
XCTAssert(finished)
|
||||||
XCTAssertFalse(cancelled)
|
XCTAssertFalse(cancelled)
|
||||||
validateExpectation.fulfill()
|
validateExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
let transactionRepository = TransactionRepositoryBuilder.build(dataDbURL: dataDbURL)
|
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)
|
XCTAssert(finished)
|
||||||
XCTAssertFalse(cancelled)
|
XCTAssertFalse(cancelled)
|
||||||
scanExpectation.fulfill()
|
scanExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
operationQueue.addOperations([downloadOperation, validationOperation, scanningOperation], waitUntilFinished: false)
|
operationQueue.addOperations([downloadOperation, validationOperation, scanningOperation], waitUntilFinished: false)
|
||||||
|
|
||||||
wait(for: [downloadExpectation, validateExpectation, scanExpectation], timeout: 300, enforceOrder: true)
|
wait(for: [downloadExpectation, validateExpectation, scanExpectation], timeout: 300, enforceOrder: true)
|
||||||
|
@ -189,11 +254,9 @@ class BlockScanOperationTests: XCTestCase {
|
||||||
|
|
||||||
extension BlockScanOperationTests: CompactBlockProgressDelegate {
|
extension BlockScanOperationTests: CompactBlockProgressDelegate {
|
||||||
func progressUpdated(_ progress: CompactBlockProgress) {
|
func progressUpdated(_ progress: CompactBlockProgress) {
|
||||||
// print("progressHeight: \(progress.progressHeight) startHeight: \(progress.startHeight), targetHeight: \(progress.targetHeight)")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct UVFakeKey: UnifiedViewingKey {
|
struct UVFakeKey: UnifiedViewingKey {
|
||||||
var extfvk: ExtendedFullViewingKey
|
var extfvk: ExtendedFullViewingKey
|
||||||
var extpub: ExtendedPublicKey
|
var extpub: ExtendedPublicKey
|
||||||
|
|
|
@ -7,36 +7,40 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable print_function_usage
|
||||||
class BlockStreamingTest: XCTestCase {
|
class BlockStreamingTest: XCTestCase {
|
||||||
var queue: OperationQueue = {
|
var queue: OperationQueue = {
|
||||||
let q = OperationQueue()
|
let queue = OperationQueue()
|
||||||
q.maxConcurrentOperationCount = 1
|
queue.maxConcurrentOperationCount = 1
|
||||||
return q
|
return queue
|
||||||
}()
|
}()
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
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)
|
logger = SampleLogger(logLevel: .debug)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
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())
|
try? FileManager.default.removeItem(at: __dataDbURL())
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStreamOperation() throws {
|
func testStreamOperation() throws {
|
||||||
let expectation = XCTestExpectation(description: "blockstream expectation")
|
let expectation = XCTestExpectation(description: "blockstream expectation")
|
||||||
|
|
||||||
let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
|
let service = LightWalletGRPCService(
|
||||||
|
host: LightWalletEndpointBuilder.eccTestnet.host,
|
||||||
port: 9067,
|
port: 9067,
|
||||||
secure: true,
|
secure: true,
|
||||||
singleCallTimeout: 1000,
|
singleCallTimeout: 1000,
|
||||||
streamingCallTimeout: 100000)
|
streamingCallTimeout: 100000
|
||||||
|
)
|
||||||
|
|
||||||
let latestHeight = try service.latestBlockHeight()
|
let latestHeight = try service.latestBlockHeight()
|
||||||
|
|
||||||
let startHeight = latestHeight - 100_000
|
let startHeight = latestHeight - 100_000
|
||||||
var blocks = [ZcashCompactBlock]()
|
var blocks: [ZcashCompactBlock] = []
|
||||||
service.blockStream(startHeight: startHeight, endHeight: latestHeight) { result in
|
service.blockStream(startHeight: startHeight, endHeight: latestHeight) { result in
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -49,29 +53,34 @@ class BlockStreamingTest: XCTestCase {
|
||||||
print("received block \(compactBlock.height)")
|
print("received block \(compactBlock.height)")
|
||||||
blocks.append(compactBlock)
|
blocks.append(compactBlock)
|
||||||
} progress: { progressReport in
|
} 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)
|
wait(for: [expectation], timeout: 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func testStreamOperationCancellation() throws {
|
func testStreamOperationCancellation() throws {
|
||||||
let expectation = XCTestExpectation(description: "blockstream expectation")
|
let expectation = XCTestExpectation(description: "blockstream expectation")
|
||||||
|
|
||||||
let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
|
let service = LightWalletGRPCService(
|
||||||
|
host: LightWalletEndpointBuilder.eccTestnet.host,
|
||||||
port: 9067,
|
port: 9067,
|
||||||
secure: true,
|
secure: true,
|
||||||
singleCallTimeout: 10000,
|
singleCallTimeout: 10000,
|
||||||
streamingCallTimeout: 10000)
|
streamingCallTimeout: 10000
|
||||||
|
)
|
||||||
let storage = try TestDbBuilder.inMemoryCompactBlockStorage()
|
let storage = try TestDbBuilder.inMemoryCompactBlockStorage()
|
||||||
|
|
||||||
let startHeight = try service.latestBlockHeight() - 100_000
|
let startHeight = try service.latestBlockHeight() - 100_000
|
||||||
let operation = CompactBlockStreamDownloadOperation(service: service,
|
let operation = CompactBlockStreamDownloadOperation(
|
||||||
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
startHeight: startHeight,
|
startHeight: startHeight,
|
||||||
progressDelegate: self)
|
progressDelegate: self
|
||||||
|
)
|
||||||
|
|
||||||
operation.completionHandler = { (finished, cancelled) in
|
operation.completionHandler = { _, cancelled in
|
||||||
XCTAssert(cancelled)
|
XCTAssert(cancelled)
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
}
|
}
|
||||||
|
@ -91,20 +100,24 @@ class BlockStreamingTest: XCTestCase {
|
||||||
func testStreamOperationTimeout() throws {
|
func testStreamOperationTimeout() throws {
|
||||||
let expectation = XCTestExpectation(description: "blockstream expectation")
|
let expectation = XCTestExpectation(description: "blockstream expectation")
|
||||||
let errorExpectation = XCTestExpectation(description: "blockstream error expectation")
|
let errorExpectation = XCTestExpectation(description: "blockstream error expectation")
|
||||||
let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
|
let service = LightWalletGRPCService(
|
||||||
|
host: LightWalletEndpointBuilder.eccTestnet.host,
|
||||||
port: 9067,
|
port: 9067,
|
||||||
secure: true,
|
secure: true,
|
||||||
singleCallTimeout: 1000,
|
singleCallTimeout: 1000,
|
||||||
streamingCallTimeout: 3000)
|
streamingCallTimeout: 3000
|
||||||
|
)
|
||||||
let storage = try TestDbBuilder.inMemoryCompactBlockStorage()
|
let storage = try TestDbBuilder.inMemoryCompactBlockStorage()
|
||||||
|
|
||||||
let startHeight = try service.latestBlockHeight() - 100_000
|
let startHeight = try service.latestBlockHeight() - 100_000
|
||||||
let operation = CompactBlockStreamDownloadOperation(service: service,
|
let operation = CompactBlockStreamDownloadOperation(
|
||||||
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
startHeight: startHeight,
|
startHeight: startHeight,
|
||||||
progressDelegate: self)
|
progressDelegate: self
|
||||||
|
)
|
||||||
|
|
||||||
operation.completionHandler = { (finished, cancelled) in
|
operation.completionHandler = { finished, _ in
|
||||||
XCTAssert(finished)
|
XCTAssert(finished)
|
||||||
|
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
|
@ -136,20 +149,25 @@ class BlockStreamingTest: XCTestCase {
|
||||||
func testBatchOperation() throws {
|
func testBatchOperation() throws {
|
||||||
let expectation = XCTestExpectation(description: "blockbatch expectation")
|
let expectation = XCTestExpectation(description: "blockbatch expectation")
|
||||||
|
|
||||||
let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
|
let service = LightWalletGRPCService(
|
||||||
|
host: LightWalletEndpointBuilder.eccTestnet.host,
|
||||||
port: 9067,
|
port: 9067,
|
||||||
secure: true,
|
secure: true,
|
||||||
singleCallTimeout: 300000,
|
singleCallTimeout: 300000,
|
||||||
streamingCallTimeout: 10000)
|
streamingCallTimeout: 10000
|
||||||
|
)
|
||||||
let storage = try TestDbBuilder.diskCompactBlockStorage(at: __dataDbURL() )
|
let storage = try TestDbBuilder.diskCompactBlockStorage(at: __dataDbURL() )
|
||||||
let targetHeight = try service.latestBlockHeight()
|
let targetHeight = try service.latestBlockHeight()
|
||||||
let startHeight = targetHeight - 10_000
|
let startHeight = targetHeight - 10_000
|
||||||
let operation = CompactBlockBatchDownloadOperation(service: service,
|
let operation = CompactBlockBatchDownloadOperation(
|
||||||
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
startHeight: startHeight, targetHeight: targetHeight,
|
startHeight: startHeight,
|
||||||
progressDelegate: self)
|
targetHeight: targetHeight,
|
||||||
|
progressDelegate: self
|
||||||
|
)
|
||||||
|
|
||||||
operation.completionHandler = { (finished, cancelled) in
|
operation.completionHandler = { _, cancelled in
|
||||||
if cancelled {
|
if cancelled {
|
||||||
XCTFail("operation cancelled")
|
XCTFail("operation cancelled")
|
||||||
}
|
}
|
||||||
|
@ -169,20 +187,25 @@ class BlockStreamingTest: XCTestCase {
|
||||||
func testBatchOperationCancellation() throws {
|
func testBatchOperationCancellation() throws {
|
||||||
let expectation = XCTestExpectation(description: "blockbatch expectation")
|
let expectation = XCTestExpectation(description: "blockbatch expectation")
|
||||||
|
|
||||||
let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
|
let service = LightWalletGRPCService(
|
||||||
|
host: LightWalletEndpointBuilder.eccTestnet.host,
|
||||||
port: 9067,
|
port: 9067,
|
||||||
secure: true,
|
secure: true,
|
||||||
singleCallTimeout: 300000,
|
singleCallTimeout: 300000,
|
||||||
streamingCallTimeout: 10000)
|
streamingCallTimeout: 10000
|
||||||
|
)
|
||||||
let storage = try TestDbBuilder.diskCompactBlockStorage(at: __dataDbURL() )
|
let storage = try TestDbBuilder.diskCompactBlockStorage(at: __dataDbURL() )
|
||||||
let targetHeight = try service.latestBlockHeight()
|
let targetHeight = try service.latestBlockHeight()
|
||||||
let startHeight = targetHeight - 100_000
|
let startHeight = targetHeight - 100_000
|
||||||
let operation = CompactBlockBatchDownloadOperation(service: service,
|
let operation = CompactBlockBatchDownloadOperation(
|
||||||
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
startHeight: startHeight, targetHeight: targetHeight,
|
startHeight: startHeight,
|
||||||
progressDelegate: self)
|
targetHeight: targetHeight,
|
||||||
|
progressDelegate: self
|
||||||
|
)
|
||||||
|
|
||||||
operation.completionHandler = { (finished, cancelled) in
|
operation.completionHandler = { _, cancelled in
|
||||||
XCTAssert(cancelled)
|
XCTAssert(cancelled)
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
}
|
}
|
||||||
|
@ -201,8 +224,9 @@ class BlockStreamingTest: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension BlockStreamingTest: CompactBlockProgressDelegate {
|
extension BlockStreamingTest: CompactBlockProgressDelegate {
|
||||||
|
|
||||||
func progressUpdated(_ progress: CompactBlockProgress) {
|
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))")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,13 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@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 processor: CompactBlockProcessor!
|
||||||
var downloadStartedExpect: XCTestExpectation!
|
var downloadStartedExpect: XCTestExpectation!
|
||||||
var updatedNotificationExpectation: XCTestExpectation!
|
var updatedNotificationExpectation: XCTestExpectation!
|
||||||
|
@ -22,10 +26,13 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
|
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
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)
|
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)
|
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.blockHeight = UInt64(mockLatestHeight)
|
||||||
|
@ -41,23 +48,33 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString))
|
let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString))
|
||||||
try! storage.createTable()
|
try! storage.createTable()
|
||||||
|
|
||||||
|
processor = CompactBlockProcessor(
|
||||||
processor = CompactBlockProcessor(service: service,
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: ZcashRustBackend.self,
|
backend: ZcashRustBackend.self,
|
||||||
config: processorConfig)
|
config: processorConfig
|
||||||
|
)
|
||||||
try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: .testnet)
|
try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: .testnet)
|
||||||
downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect")
|
downloadStartedExpect = XCTestExpectation(description: "\(self.description) downloadStartedExpect")
|
||||||
stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation")
|
stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation")
|
||||||
updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation")
|
updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation")
|
||||||
startedValidatingNotificationExpectation = XCTestExpectation(description: self.description + " startedValidatingNotificationExpectation")
|
startedValidatingNotificationExpectation = XCTestExpectation(
|
||||||
startedScanningNotificationExpectation = XCTestExpectation(description: self.description + " startedScanningNotificationExpectation")
|
description: "\(self.description) startedValidatingNotificationExpectation"
|
||||||
idleNotificationExpectation = XCTestExpectation(description: self.description + " idleNotificationExpectation")
|
)
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(processorFailed(_:)), name: Notification.Name.blockProcessorFailed, object: processor)
|
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() {
|
override func tearDown() {
|
||||||
|
super.tearDown()
|
||||||
try! FileManager.default.removeItem(at: processorConfig.cacheDb)
|
try! FileManager.default.removeItem(at: processorConfig.cacheDb)
|
||||||
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
||||||
downloadStartedExpect.unsubscribeFromNotifications()
|
downloadStartedExpect.unsubscribeFromNotifications()
|
||||||
|
@ -78,7 +95,7 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func startProcessing() {
|
private func startProcessing() {
|
||||||
XCTAssertNotNil(processor)
|
XCTAssertNotNil(processor)
|
||||||
|
|
||||||
// Subscribe to notifications
|
// Subscribe to notifications
|
||||||
|
@ -93,26 +110,30 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStartNotifiesSuscriptors() {
|
func testStartNotifiesSuscriptors() {
|
||||||
|
|
||||||
startProcessing()
|
startProcessing()
|
||||||
|
|
||||||
wait(for: [
|
wait(
|
||||||
|
for: [
|
||||||
downloadStartedExpect,
|
downloadStartedExpect,
|
||||||
startedValidatingNotificationExpectation,
|
startedValidatingNotificationExpectation,
|
||||||
startedScanningNotificationExpectation,
|
startedScanningNotificationExpectation,
|
||||||
idleNotificationExpectation,
|
idleNotificationExpectation
|
||||||
], timeout: 30,enforceOrder: true)
|
],
|
||||||
|
timeout: 30,
|
||||||
|
enforceOrder: true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testProgressNotifications() {
|
func testProgressNotifications() {
|
||||||
|
let expectedUpdates = expectedBatches(
|
||||||
let expectedUpdates = expectedBatches(currentHeight: processorConfig.walletBirthday, targetHeight: mockLatestHeight, batchSize: processorConfig.downloadBatchSize)
|
currentHeight: processorConfig.walletBirthday,
|
||||||
|
targetHeight: mockLatestHeight,
|
||||||
|
batchSize: processorConfig.downloadBatchSize
|
||||||
|
)
|
||||||
updatedNotificationExpectation.expectedFulfillmentCount = expectedUpdates
|
updatedNotificationExpectation.expectedFulfillmentCount = expectedUpdates
|
||||||
|
|
||||||
startProcessing()
|
startProcessing()
|
||||||
wait(for: [updatedNotificationExpectation], timeout: 300)
|
wait(for: [updatedNotificationExpectation], timeout: 300)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int {
|
private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int {
|
||||||
|
@ -120,14 +141,20 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNextBatchBlockRange() {
|
func testNextBatchBlockRange() {
|
||||||
|
|
||||||
// test first range
|
// test first range
|
||||||
var latestDownloadedHeight = processorConfig.walletBirthday // this can be either this or Wallet Birthday.
|
var latestDownloadedHeight = processorConfig.walletBirthday // this can be either this or Wallet Birthday.
|
||||||
var latestBlockchainHeight = BlockHeight(network.constants.saplingActivationHeight + 1000)
|
var latestBlockchainHeight = BlockHeight(network.constants.saplingActivationHeight + 1000)
|
||||||
|
|
||||||
var expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight, upper:latestBlockchainHeight))
|
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
|
// Test mid-range
|
||||||
latestDownloadedHeight = BlockHeight(network.constants.saplingActivationHeight + ZcashSDK.DefaultBatchSize)
|
latestDownloadedHeight = BlockHeight(network.constants.saplingActivationHeight + ZcashSDK.DefaultBatchSize)
|
||||||
|
@ -135,7 +162,14 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
|
|
||||||
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
|
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
|
// Test last batch range
|
||||||
|
|
||||||
|
@ -144,7 +178,14 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
|
|
||||||
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
|
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() {
|
func testDetermineLowerBoundPastBirthday() {
|
||||||
|
@ -156,7 +197,6 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
let expected = 781_886
|
let expected = 781_886
|
||||||
|
|
||||||
XCTAssertEqual(result, expected)
|
XCTAssertEqual(result, expected)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDetermineLowerBound() {
|
func testDetermineLowerBound() {
|
||||||
|
@ -168,6 +208,5 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
let expected = 781_896
|
let expected = 781_896
|
||||||
|
|
||||||
XCTAssertEqual(result, expected)
|
XCTAssertEqual(result, expected)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,15 @@
|
||||||
//
|
//
|
||||||
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
||||||
|
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@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 processor: CompactBlockProcessor!
|
||||||
var downloadStartedExpect: XCTestExpectation!
|
var downloadStartedExpect: XCTestExpectation!
|
||||||
var updatedNotificationExpectation: XCTestExpectation!
|
var updatedNotificationExpectation: XCTestExpectation!
|
||||||
|
@ -24,13 +27,15 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
|
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
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)
|
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)
|
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.blockHeight = UInt64(mockLatestHeight)
|
||||||
info.branch = "asdf"
|
info.branch = "asdf"
|
||||||
info.buildDate = "today"
|
info.buildDate = "today"
|
||||||
|
@ -39,7 +44,7 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
info.consensusBranchID = branchID.toString()
|
info.consensusBranchID = branchID.toString()
|
||||||
info.estimatedHeight = UInt64(mockLatestHeight)
|
info.estimatedHeight = UInt64(mockLatestHeight)
|
||||||
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
})
|
}
|
||||||
|
|
||||||
try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: .testnet)
|
try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: .testnet)
|
||||||
|
|
||||||
|
@ -51,24 +56,42 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
mockBackend.mockValidateCombinedChainKeepFailing = false
|
mockBackend.mockValidateCombinedChainKeepFailing = false
|
||||||
mockBackend.mockValidateCombinedChainFailureHeight = self.network.constants.saplingActivationHeight + 320
|
mockBackend.mockValidateCombinedChainFailureHeight = self.network.constants.saplingActivationHeight + 320
|
||||||
|
|
||||||
processor = CompactBlockProcessor(service: service,
|
processor = CompactBlockProcessor(
|
||||||
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: mockBackend,
|
backend: mockBackend,
|
||||||
config: processorConfig)
|
config: processorConfig
|
||||||
|
)
|
||||||
|
|
||||||
downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect")
|
downloadStartedExpect = XCTestExpectation(description: "\(self.description) downloadStartedExpect")
|
||||||
stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation")
|
stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation")
|
||||||
updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation")
|
updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation")
|
||||||
startedValidatingNotificationExpectation = XCTestExpectation(description: self.description + " startedValidatingNotificationExpectation")
|
startedValidatingNotificationExpectation = XCTestExpectation(
|
||||||
startedScanningNotificationExpectation = XCTestExpectation(description: self.description + " startedScanningNotificationExpectation")
|
description: "\(self.description) startedValidatingNotificationExpectation"
|
||||||
idleNotificationExpectation = XCTestExpectation(description: self.description + " idleNotificationExpectation")
|
)
|
||||||
reorgNotificationExpectation = XCTestExpectation(description: self.description + " reorgNotificationExpectation")
|
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(
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(processorFailed(_:)), name: Notification.Name.blockProcessorFailed, object: processor)
|
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() {
|
override func tearDown() {
|
||||||
|
super.tearDown()
|
||||||
try! FileManager.default.removeItem(at: processorConfig.cacheDb)
|
try! FileManager.default.removeItem(at: processorConfig.cacheDb)
|
||||||
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
||||||
downloadStartedExpect.unsubscribeFromNotifications()
|
downloadStartedExpect.unsubscribeFromNotifications()
|
||||||
|
@ -82,7 +105,6 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func processorHandledReorg(_ notification: Notification) {
|
@objc func processorHandledReorg(_ notification: Notification) {
|
||||||
|
|
||||||
XCTAssertNotNil(notification.userInfo)
|
XCTAssertNotNil(notification.userInfo)
|
||||||
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
||||||
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
|
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
|
||||||
|
@ -96,17 +118,15 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func processorFailed(_ notification: Notification) {
|
@objc func processorFailed(_ notification: Notification) {
|
||||||
|
|
||||||
XCTAssertNotNil(notification.userInfo)
|
XCTAssertNotNil(notification.userInfo)
|
||||||
if let error = notification.userInfo?["error"] {
|
if let error = notification.userInfo?["error"] {
|
||||||
XCTFail("CompactBlockProcessor failed with Error: \(error)")
|
XCTFail("CompactBlockProcessor failed with Error: \(error)")
|
||||||
} else {
|
} else {
|
||||||
XCTFail("CompactBlockProcessor failed")
|
XCTFail("CompactBlockProcessor failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func startProcessing() {
|
private func startProcessing() {
|
||||||
XCTAssertNotNil(processor)
|
XCTAssertNotNil(processor)
|
||||||
|
|
||||||
// Subscribe to notifications
|
// Subscribe to notifications
|
||||||
|
@ -122,20 +142,22 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNotifiesReorg() {
|
func testNotifiesReorg() {
|
||||||
|
|
||||||
startProcessing()
|
startProcessing()
|
||||||
|
|
||||||
wait(for: [
|
wait(
|
||||||
|
for: [
|
||||||
downloadStartedExpect,
|
downloadStartedExpect,
|
||||||
startedValidatingNotificationExpectation,
|
startedValidatingNotificationExpectation,
|
||||||
startedScanningNotificationExpectation,
|
startedScanningNotificationExpectation,
|
||||||
reorgNotificationExpectation,
|
reorgNotificationExpectation,
|
||||||
idleNotificationExpectation,
|
idleNotificationExpectation
|
||||||
], timeout: 300,enforceOrder: true)
|
],
|
||||||
|
timeout: 300,
|
||||||
|
enforceOrder: true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int {
|
private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int {
|
||||||
(abs(currentHeight - targetHeight) / batchSize)
|
(abs(currentHeight - targetHeight) / batchSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,13 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
|
// swiftlint:disable force_try
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
class CompactBlockStorageTests: XCTestCase {
|
class CompactBlockStorageTests: XCTestCase {
|
||||||
|
let network = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
var compactBlockDao: CompactBlockRepository = try! TestDbBuilder.inMemoryCompactBlockStorage()
|
var compactBlockDao: CompactBlockRepository = try! TestDbBuilder.inMemoryCompactBlockStorage()
|
||||||
|
|
||||||
let network = ZcashNetworkBuilder.network(for: .testnet)
|
|
||||||
func testEmptyStorage() {
|
func testEmptyStorage() {
|
||||||
XCTAssertEqual(try! compactBlockDao.latestHeight(), BlockHeight.empty())
|
XCTAssertEqual(try! compactBlockDao.latestHeight(), BlockHeight.empty())
|
||||||
}
|
}
|
||||||
|
@ -34,11 +35,9 @@ class CompactBlockStorageTests: XCTestCase {
|
||||||
let latestHeight = try! compactBlockDao.latestHeight()
|
let latestHeight = try! compactBlockDao.latestHeight()
|
||||||
XCTAssertNotEqual(initialHeight, latestHeight)
|
XCTAssertNotEqual(initialHeight, latestHeight)
|
||||||
XCTAssertEqual(latestHeight, finalHeight)
|
XCTAssertEqual(latestHeight, finalHeight)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStoreOneBlockFromEmpty() {
|
func testStoreOneBlockFromEmpty() {
|
||||||
|
|
||||||
let initialHeight = try! compactBlockDao.latestHeight()
|
let initialHeight = try! compactBlockDao.latestHeight()
|
||||||
guard initialHeight == BlockHeight.empty() else {
|
guard initialHeight == BlockHeight.empty() else {
|
||||||
XCTFail("database not empty, latest height: \(initialHeight)")
|
XCTFail("database not empty, latest height: \(initialHeight)")
|
||||||
|
@ -62,7 +61,6 @@ class CompactBlockStorageTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRewindTo() {
|
func testRewindTo() {
|
||||||
|
|
||||||
let startHeight = self.network.constants.saplingActivationHeight
|
let startHeight = self.network.constants.saplingActivationHeight
|
||||||
let blockCount = Int(1_000)
|
let blockCount = Int(1_000)
|
||||||
let finalHeight = startHeight + blockCount
|
let finalHeight = startHeight + blockCount
|
||||||
|
@ -79,10 +77,8 @@ class CompactBlockStorageTests: XCTestCase {
|
||||||
do {
|
do {
|
||||||
let latestHeight = try compactBlockDao.latestHeight()
|
let latestHeight = try compactBlockDao.latestHeight()
|
||||||
XCTAssertEqual(latestHeight, rewindHeight - 1)
|
XCTAssertEqual(latestHeight, rewindHeight - 1)
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("Rewind latest block failed with error: \(error)")
|
XCTFail("Rewind latest block failed with error: \(error)")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,14 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional
|
||||||
class DarksideSanityCheckTests: XCTestCase {
|
class DarksideSanityCheckTests: XCTestCase {
|
||||||
|
// TODO: Parameterize this from environment?
|
||||||
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
|
// swiftlint:disable: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"
|
||||||
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
|
// TODO: Parameterize this from environment
|
||||||
|
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
|
||||||
|
|
||||||
let sendAmount: Int64 = 1000
|
let sendAmount: Int64 = 1000
|
||||||
var birthday: BlockHeight = 663150
|
var birthday: BlockHeight = 663150
|
||||||
|
@ -23,12 +26,12 @@ class DarksideSanityCheckTests: XCTestCase {
|
||||||
var expectedReorgHeight: BlockHeight = 665188
|
var expectedReorgHeight: BlockHeight = 665188
|
||||||
var expectedRewindHeight: BlockHeight = 665188
|
var expectedRewindHeight: BlockHeight = 665188
|
||||||
var network = DarksideWalletDNetwork()
|
var network = DarksideWalletDNetwork()
|
||||||
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
|
var reorgExpectation = XCTestExpectation(description: "reorg")
|
||||||
let branchID = "2bb40e60"
|
let branchID = "2bb40e60"
|
||||||
let chainName = "main"
|
let chainName = "main"
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
|
try super.setUpWithError()
|
||||||
coordinator = try TestCoordinator(
|
coordinator = try TestCoordinator(
|
||||||
seed: seedPhrase,
|
seed: seedPhrase,
|
||||||
walletBirthday: birthday,
|
walletBirthday: birthday,
|
||||||
|
@ -37,10 +40,10 @@ class DarksideSanityCheckTests: XCTestCase {
|
||||||
)
|
)
|
||||||
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
|
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
|
||||||
try coordinator.resetBlocks(dataset: .default)
|
try coordinator.resetBlocks(dataset: .default)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
|
try super.tearDownWithError()
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
|
||||||
|
@ -54,17 +57,19 @@ class DarksideSanityCheckTests: XCTestCase {
|
||||||
|
|
||||||
let syncExpectation = XCTestExpectation(description: "sync to \(expectedLastBlock.height)")
|
let syncExpectation = XCTestExpectation(description: "sync to \(expectedLastBlock.height)")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(
|
||||||
|
completion: { _ in
|
||||||
syncExpectation.fulfill()
|
syncExpectation.fulfill()
|
||||||
}, error: { (error) in
|
},
|
||||||
|
error: { error in
|
||||||
guard let e = error else {
|
guard let e = error else {
|
||||||
XCTFail("failed with unknown error")
|
XCTFail("failed with unknown error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
XCTFail("failed with error: \(e)")
|
XCTFail("failed with error: \(e)")
|
||||||
return
|
return
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [syncExpectation], timeout: 5)
|
wait(for: [syncExpectation], timeout: 5)
|
||||||
|
|
||||||
|
@ -75,6 +80,5 @@ class DarksideSanityCheckTests: XCTestCase {
|
||||||
|
|
||||||
XCTAssertEqual(firstBlock?.hash.toHexStringTxId(), expectedFirstBlock.hash)
|
XCTAssertEqual(firstBlock?.hash.toHexStringTxId(), expectedFirstBlock.hash)
|
||||||
XCTAssertEqual(lastBlock?.hash.toHexStringTxId(), expectedLastBlock.hash)
|
XCTAssertEqual(lastBlock?.hash.toHexStringTxId(), expectedLastBlock.hash)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,14 @@
|
||||||
import XCTest
|
import XCTest
|
||||||
import SQLite
|
import SQLite
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
class DownloadOperationTests: XCTestCase {
|
|
||||||
|
|
||||||
|
// swiftlint:disable force_try
|
||||||
|
class DownloadOperationTests: XCTestCase {
|
||||||
var operationQueue = OperationQueue()
|
var operationQueue = OperationQueue()
|
||||||
var network = ZcashNetworkBuilder.network(for: .testnet)
|
var network = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
|
|
||||||
override func tearDown() {
|
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()
|
operationQueue.cancelAllOperations()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,13 +31,13 @@ class DownloadOperationTests: XCTestCase {
|
||||||
let range = activationHeight ... activationHeight + blockCount
|
let range = activationHeight ... activationHeight + blockCount
|
||||||
let downloadOperation = CompactBlockDownloadOperation(downloader: downloader, range: range)
|
let downloadOperation = CompactBlockDownloadOperation(downloader: downloader, range: range)
|
||||||
|
|
||||||
downloadOperation.completionHandler = { (finished, cancelled) in
|
downloadOperation.completionHandler = { finished, cancelled in
|
||||||
expect.fulfill()
|
expect.fulfill()
|
||||||
XCTAssertTrue(finished)
|
XCTAssertTrue(finished)
|
||||||
XCTAssertFalse(cancelled)
|
XCTAssertFalse(cancelled)
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadOperation.errorHandler = { (error) in
|
downloadOperation.errorHandler = { error in
|
||||||
XCTFail("Donwload Operation failed with error: \(error)")
|
XCTFail("Donwload Operation failed with error: \(error)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,5 +47,4 @@ class DownloadOperationTests: XCTestCase {
|
||||||
|
|
||||||
XCTAssertEqual(try! storage.latestHeight(), range.upperBound)
|
XCTAssertEqual(try! storage.latestHeight(), range.upperBound)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,21 +9,21 @@
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
import GRPC
|
import GRPC
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional force_unwrapping
|
||||||
class LightWalletServiceTests: XCTestCase {
|
class LightWalletServiceTests: XCTestCase {
|
||||||
|
let network: ZcashNetwork = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
|
|
||||||
var service: LightWalletService!
|
var service: LightWalletService!
|
||||||
var channel: Channel!
|
var channel: Channel!
|
||||||
let network: ZcashNetwork = ZcashNetworkBuilder.network(for: .testnet)
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
|
super.setUp()
|
||||||
channel = ChannelProvider().channel()
|
channel = ChannelProvider().channel()
|
||||||
service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)
|
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
|
/// FIXME: check whether this test is stil valid on in memory lwd implementatiojn
|
||||||
// func testFailure() {
|
// func testFailure() {
|
||||||
//
|
//
|
||||||
|
@ -44,7 +44,7 @@ class LightWalletServiceTests: XCTestCase {
|
||||||
let upperRange: BlockHeight = network.constants.saplingActivationHeight + count
|
let upperRange: BlockHeight = network.constants.saplingActivationHeight + count
|
||||||
let blockRange = lowerRange ... upperRange
|
let blockRange = lowerRange ... upperRange
|
||||||
|
|
||||||
service.blockRange(blockRange) { (result) in
|
service.blockRange(blockRange) { result in
|
||||||
expect.fulfill()
|
expect.fulfill()
|
||||||
switch result {
|
switch result {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
|
@ -75,7 +75,7 @@ class LightWalletServiceTests: XCTestCase {
|
||||||
|
|
||||||
func testLatestBlock() {
|
func testLatestBlock() {
|
||||||
let expect = XCTestExpectation(description: self.description)
|
let expect = XCTestExpectation(description: self.description)
|
||||||
service.latestBlockHeight { (result) in
|
service.latestBlockHeight { result in
|
||||||
expect.fulfill()
|
expect.fulfill()
|
||||||
switch result {
|
switch result {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
|
@ -87,5 +87,4 @@ class LightWalletServiceTests: XCTestCase {
|
||||||
|
|
||||||
wait(for: [expect], timeout: 10)
|
wait(for: [expect], timeout: 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable force_unwrapping print_function_usage
|
||||||
class MemoTests: XCTestCase {
|
class MemoTests: XCTestCase {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Non-utf8 memos are properly ignored
|
Non-utf8 memos are properly ignored
|
||||||
*/
|
*/
|
||||||
|
@ -28,11 +28,9 @@ class MemoTests: XCTestCase {
|
||||||
Verify support for common unicode characters
|
Verify support for common unicode characters
|
||||||
*/
|
*/
|
||||||
func testUnicodeCharacters() throws {
|
func testUnicodeCharacters() throws {
|
||||||
|
|
||||||
let memo = validMemoData.asZcashTransactionMemo()
|
let memo = validMemoData.asZcashTransactionMemo()
|
||||||
XCTAssertNotNil(memo)
|
XCTAssertNotNil(memo)
|
||||||
XCTAssertEqual(memo!, Self.validMemoDataExpectedString)
|
XCTAssertEqual(memo!, Self.validMemoDataExpectedString)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testEmojiUnicodeCharacters() throws {
|
func testEmojiUnicodeCharacters() throws {
|
||||||
|
@ -67,7 +65,9 @@ class MemoTests: XCTestCase {
|
||||||
*/
|
*/
|
||||||
static let validMemoDataExpectedString = "Here's gift from the Zec Fairy @ ECC!"
|
static let validMemoDataExpectedString = "Here's gift from the Zec Fairy @ ECC!"
|
||||||
|
|
||||||
static let validMemoDataBase64 = "SGVyZSdzIGdpZnQgZnJvbSB0aGUgWmVjIEZhaXJ5IEAgRUNDIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
|
static let validMemoDataBase64 =
|
||||||
|
// swiftlint:disable:next line_length
|
||||||
|
"SGVyZSdzIGdpZnQgZnJvbSB0aGUgWmVjIEZhaXJ5IEAgRUNDIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
|
||||||
|
|
||||||
let validMemoData = Data(base64Encoded: validMemoDataBase64)!
|
let validMemoData = Data(base64Encoded: validMemoDataBase64)!
|
||||||
|
|
||||||
|
@ -75,8 +75,9 @@ class MemoTests: XCTestCase {
|
||||||
|
|
||||||
let totallyRandomDataMemo = randomMemoData()!
|
let totallyRandomDataMemo = randomMemoData()!
|
||||||
|
|
||||||
|
static let emojiDataBase64 =
|
||||||
static let emojiDataBase64 = "8J+SlfCfkpXwn5KV8J+mk/CfppPwn6aT8J+bofCfm6Hwn5uhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
|
// swiftlint:disable:next line_length
|
||||||
|
"8J+SlfCfkpXwn5KV8J+mk/CfppPwn6aT8J+bofCfm6Hwn5uhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
|
||||||
|
|
||||||
static let emojiMemoData = Data(base64Encoded: emojiDataBase64)!
|
static let emojiMemoData = Data(base64Encoded: emojiDataBase64)!
|
||||||
|
|
||||||
|
@ -102,4 +103,3 @@ class MemoTests: XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,32 +7,31 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional type_body_length force_unwrapping
|
||||||
class NetworkUpgradeTests: XCTestCase {
|
class NetworkUpgradeTests: XCTestCase {
|
||||||
|
|
||||||
let activationHeight: BlockHeight = 1028500
|
let activationHeight: BlockHeight = 1028500
|
||||||
var spendingKey = "secret-extended-key-test1qv2vf437qqqqpqpfc0arpv55ncq33p2p895hlcx0ra6d0g739v93luqdjpxun3kt050j9qnrqjyp8d7fdxgedfyxpjmuyha2ulxa6hmqvm2gnvuc3tvs3enpxwuz768qfkd286vr3jgyrgr5ddx2ukrdl95ak3tzqylzjeqw3pnmgtmwsvemrj3sk6vqgwxm9khlv46wccn33ayw52prr233ea069c9u8m3839dvw30sdf6k32xddhpte6p6qsuxval6usyh6lr55pgypkgtz"
|
let spendingKey =
|
||||||
|
// swiftlint:disable:next line_length
|
||||||
let testRecipientAddress = "ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc" //TODO: Parameterize this from environment
|
"secret-extended-key-test1qv2vf437qqqqpqpfc0arpv55ncq33p2p895hlcx0ra6d0g739v93luqdjpxun3kt050j9qnrqjyp8d7fdxgedfyxpjmuyha2ulxa6hmqvm2gnvuc3tvs3enpxwuz768qfkd286vr3jgyrgr5ddx2ukrdl95ak3tzqylzjeqw3pnmgtmwsvemrj3sk6vqgwxm9khlv46wccn33ayw52prr233ea069c9u8m3839dvw30sdf6k32xddhpte6p6qsuxval6usyh6lr55pgypkgtz"
|
||||||
|
|
||||||
|
// TODO: Parameterize this from environment
|
||||||
|
let testRecipientAddress = "ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc"
|
||||||
let sendAmount: Int64 = 1000
|
let sendAmount: Int64 = 1000
|
||||||
var birthday: BlockHeight = 1013250
|
|
||||||
let branchID = "2bb40e60"
|
let branchID = "2bb40e60"
|
||||||
let chainName = "main"
|
let chainName = "main"
|
||||||
|
|
||||||
|
var birthday: BlockHeight = 1013250
|
||||||
var coordinator: TestCoordinator!
|
var coordinator: TestCoordinator!
|
||||||
var network = ZcashNetworkBuilder.network(for: .testnet)
|
var network = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
|
try super.setUpWithError()
|
||||||
// coordinator = try TestCoordinator(
|
|
||||||
// spendingKey: spendingKey,
|
|
||||||
// unifiedViewingKey: <#UnifiedViewingKey#>,
|
|
||||||
// walletBirthday: birthday,
|
|
||||||
// channelProvider: ChannelProvider()
|
|
||||||
// )
|
|
||||||
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
|
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
|
try super.tearDownWithError()
|
||||||
NotificationCenter.default.removeObserver(self)
|
NotificationCenter.default.removeObserver(self)
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
||||||
|
@ -40,22 +39,26 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Given that a wallet had funds prior to activation it can spend them after activation
|
Given that a wallet had funds prior to activation it can spend them after activation
|
||||||
*/
|
*/
|
||||||
func testSpendPriorFundsAfterActivation() throws {
|
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")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: activationHeight - ZcashSDK.defaultStaleTolerance)
|
try coordinator.applyStaged(blockheight: activationHeight - ZcashSDK.defaultStaleTolerance)
|
||||||
sleep(5)
|
sleep(5)
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
|
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [firstSyncExpectation], timeout: 120)
|
wait(for: [firstSyncExpectation], timeout: 120)
|
||||||
|
@ -69,28 +72,37 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
let sendExpectation = XCTestExpectation(description: "send expectation")
|
let sendExpectation = XCTestExpectation(description: "send expectation")
|
||||||
var p: PendingTransactionEntity? = nil
|
var pendingEntity: PendingTransactionEntity?
|
||||||
let spendAmount: Int64 = 10000
|
let spendAmount: Int64 = 10000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
send transaction to recipient address
|
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 {
|
switch result {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
self.handleError(e)
|
self.handleError(e)
|
||||||
case .success(let pendingTx):
|
case .success(let pendingTx):
|
||||||
p = pendingTx
|
pendingEntity = pendingTx
|
||||||
}
|
}
|
||||||
sendExpectation.fulfill()
|
sendExpectation.fulfill()
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sendExpectation], timeout: 11)
|
wait(for: [sendExpectation], timeout: 11)
|
||||||
|
|
||||||
guard let _ = p else {
|
guard pendingEntity != nil else {
|
||||||
XCTFail("no pending transaction after sending")
|
XCTFail("no pending transaction after sending")
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
getIncomingTransaction
|
getIncomingTransaction
|
||||||
*/
|
*/
|
||||||
|
@ -105,43 +117,42 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
stage transaction at sentTxHeight
|
stage transaction at sentTxHeight
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
|
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
|
||||||
try coordinator.applyStaged(blockheight: activationHeight + 20)
|
try coordinator.applyStaged(blockheight: activationHeight + 20)
|
||||||
sleep(1)
|
sleep(1)
|
||||||
let afterSendExpectation = XCTestExpectation(description: "aftersend")
|
let afterSendExpectation = XCTestExpectation(description: "aftersend")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
afterSendExpectation.fulfill()
|
afterSendExpectation.fulfill()
|
||||||
|
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [afterSendExpectation], timeout: 10)
|
wait(for: [afterSendExpectation], timeout: 10)
|
||||||
|
|
||||||
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), verifiedBalance - spendAmount)
|
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), verifiedBalance - spendAmount)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Given that a wallet receives funds after activation it can spend them when confirmed
|
Given that a wallet receives funds after activation it can spend them when confirmed
|
||||||
*/
|
*/
|
||||||
func testSpendPostActivationFundsAfterConfirmation() throws {
|
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")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: activationHeight + 10)
|
try coordinator.applyStaged(blockheight: activationHeight + 10)
|
||||||
sleep(3)
|
sleep(3)
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
|
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [firstSyncExpectation], timeout: 120)
|
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")
|
XCTFail("this test requires funds received after activation height")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -149,26 +160,33 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
try coordinator.applyStaged(blockheight: activationHeight + 20)
|
try coordinator.applyStaged(blockheight: activationHeight + 20)
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
|
|
||||||
let sendExpectation = XCTestExpectation(description: "send expectation")
|
let sendExpectation = XCTestExpectation(description: "send expectation")
|
||||||
var p: PendingTransactionEntity? = nil
|
var pendingEntity: PendingTransactionEntity?
|
||||||
let spendAmount: Int64 = 10000
|
let spendAmount: Int64 = 10000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
send transaction to recipient address
|
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 {
|
switch result {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
self.handleError(e)
|
self.handleError(e)
|
||||||
case .success(let pendingTx):
|
case .success(let pendingTx):
|
||||||
p = pendingTx
|
pendingEntity = pendingTx
|
||||||
}
|
}
|
||||||
sendExpectation.fulfill()
|
sendExpectation.fulfill()
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sendExpectation], timeout: 11)
|
wait(for: [sendExpectation], timeout: 11)
|
||||||
|
|
||||||
guard let _ = p else {
|
guard pendingEntity != nil else {
|
||||||
XCTFail("no pending transaction after sending")
|
XCTFail("no pending transaction after sending")
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
return
|
return
|
||||||
|
@ -178,58 +196,66 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
|
|
||||||
let afterSendExpectation = XCTestExpectation(description: "aftersend")
|
let afterSendExpectation = XCTestExpectation(description: "aftersend")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
afterSendExpectation.fulfill()
|
afterSendExpectation.fulfill()
|
||||||
|
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [afterSendExpectation], timeout: 10)
|
wait(for: [afterSendExpectation], timeout: 10)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Given that a wallet sends funds some between (activation - expiry_height) and activation, those funds are shown as sent if mined.
|
Given that a wallet sends funds some between (activation - expiry_height) and activation, those funds are shown as sent if mined.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
func testSpendMinedSpendThatExpiresOnActivation() throws {
|
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")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: activationHeight - 10)
|
try coordinator.applyStaged(blockheight: activationHeight - 10)
|
||||||
sleep(3)
|
sleep(3)
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
|
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [firstSyncExpectation], timeout: 120)
|
wait(for: [firstSyncExpectation], timeout: 120)
|
||||||
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
|
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
|
||||||
XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: activationHeight))
|
XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: activationHeight))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let sendExpectation = XCTestExpectation(description: "send expectation")
|
let sendExpectation = XCTestExpectation(description: "send expectation")
|
||||||
var p: PendingTransactionEntity? = nil
|
var pendingEntity: PendingTransactionEntity?
|
||||||
let spendAmount: Int64 = 10000
|
let spendAmount: Int64 = 10000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
send transaction to recipient address
|
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 {
|
switch result {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
self.handleError(e)
|
self.handleError(e)
|
||||||
case .success(let pendingTx):
|
case .success(let pendingTx):
|
||||||
p = pendingTx
|
pendingEntity = pendingTx
|
||||||
}
|
}
|
||||||
sendExpectation.fulfill()
|
sendExpectation.fulfill()
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sendExpectation], timeout: 11)
|
wait(for: [sendExpectation], timeout: 11)
|
||||||
|
|
||||||
guard let pendingTx = p else {
|
guard let pendingTx = pendingEntity else {
|
||||||
XCTFail("no pending transaction after sending")
|
XCTFail("no pending transaction after sending")
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
return
|
return
|
||||||
|
@ -246,12 +272,9 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
|
|
||||||
let sentTxHeight: BlockHeight = activationHeight - 5
|
let sentTxHeight: BlockHeight = activationHeight - 5
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
stage transaction at sentTxHeight
|
stage transaction at sentTxHeight
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
|
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: activationHeight + 5)
|
try coordinator.applyStaged(blockheight: activationHeight + 5)
|
||||||
|
@ -259,15 +282,16 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
|
|
||||||
let afterSendExpectation = XCTestExpectation(description: "aftersend")
|
let afterSendExpectation = XCTestExpectation(description: "aftersend")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
afterSendExpectation.fulfill()
|
afterSendExpectation.fulfill()
|
||||||
|
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [afterSendExpectation], timeout: 10)
|
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")
|
XCTFail("the sent transaction is not listed as a confirmed transaction")
|
||||||
return
|
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.
|
Given that a wallet sends funds somewhere between (activation - expiry_height) and activation, those funds are available if expired after expiration height.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func testExpiredSpendAfterActivation() throws {
|
func testExpiredSpendAfterActivation() 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 firstSyncExpectation = XCTestExpectation(description: "first sync")
|
||||||
let offset = 5
|
let offset = 5
|
||||||
|
@ -289,10 +319,8 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
|
|
||||||
let verifiedBalancePreActivation = coordinator.synchronizer.initializer.getVerifiedBalance()
|
let verifiedBalancePreActivation = coordinator.synchronizer.initializer.getVerifiedBalance()
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
|
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [firstSyncExpectation], timeout: 120)
|
wait(for: [firstSyncExpectation], timeout: 120)
|
||||||
|
@ -303,24 +331,32 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
let sendExpectation = XCTestExpectation(description: "send expectation")
|
let sendExpectation = XCTestExpectation(description: "send expectation")
|
||||||
var p: PendingTransactionEntity? = nil
|
var pendingEntity: PendingTransactionEntity?
|
||||||
let spendAmount: Int64 = 10000
|
let spendAmount: Int64 = 10000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
send transaction to recipient address
|
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 {
|
switch result {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
self.handleError(e)
|
self.handleError(e)
|
||||||
case .success(let pendingTx):
|
case .success(let pendingTx):
|
||||||
p = pendingTx
|
pendingEntity = pendingTx
|
||||||
}
|
}
|
||||||
sendExpectation.fulfill()
|
sendExpectation.fulfill()
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sendExpectation], timeout: 11)
|
wait(for: [sendExpectation], timeout: 11)
|
||||||
|
|
||||||
guard let pendingTx = p else {
|
guard let pendingTx = pendingEntity else {
|
||||||
XCTFail("no pending transaction after sending")
|
XCTFail("no pending transaction after sending")
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
return
|
return
|
||||||
|
@ -329,7 +365,7 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
getIncomingTransaction
|
getIncomingTransaction
|
||||||
*/
|
*/
|
||||||
guard let _ = try coordinator.getIncomingTransactions()?.first else {
|
guard try coordinator.getIncomingTransactions()?.first != nil else {
|
||||||
XCTFail("no incoming transaction")
|
XCTFail("no incoming transaction")
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
return
|
return
|
||||||
|
@ -338,22 +374,21 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
don't stage transaction
|
don't stage transaction
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: activationHeight + offset)
|
try coordinator.applyStaged(blockheight: activationHeight + offset)
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
let afterSendExpectation = XCTestExpectation(description: "aftersend")
|
let afterSendExpectation = XCTestExpectation(description: "aftersend")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
afterSendExpectation.fulfill()
|
afterSendExpectation.fulfill()
|
||||||
|
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [afterSendExpectation], timeout: 10)
|
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")
|
XCTFail("the sent transaction should not be not listed as a confirmed transaction")
|
||||||
return
|
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.
|
Given that a wallet has notes both received prior and after activation these can be combined to supply a larger amount spend.
|
||||||
*/
|
*/
|
||||||
func testCombinePreActivationNotesAndPostActivationNotesOnSpend() throws {
|
func testCombinePreActivationNotesAndPostActivationNotesOnSpend() 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")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: activationHeight - 1)
|
try coordinator.applyStaged(blockheight: activationHeight - 1)
|
||||||
sleep(3)
|
sleep(3)
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
|
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [firstSyncExpectation], timeout: 120)
|
wait(for: [firstSyncExpectation], timeout: 120)
|
||||||
|
@ -386,14 +426,12 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
let secondSyncExpectation = XCTestExpectation(description: "second sync")
|
let secondSyncExpectation = XCTestExpectation(description: "second sync")
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
secondSyncExpectation.fulfill()
|
secondSyncExpectation.fulfill()
|
||||||
|
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [secondSyncExpectation], timeout: 10)
|
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")
|
XCTFail("this test requires funds received after activation height")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -401,7 +439,7 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
|
|
||||||
XCTAssertTrue(preActivationBalance < postActivationBalance, "This test requires that funds post activation are greater that pre activation")
|
XCTAssertTrue(preActivationBalance < postActivationBalance, "This test requires that funds post activation are greater that pre activation")
|
||||||
let sendExpectation = XCTestExpectation(description: "send expectation")
|
let sendExpectation = XCTestExpectation(description: "send expectation")
|
||||||
var p: PendingTransactionEntity? = nil
|
var pendingEntity: PendingTransactionEntity?
|
||||||
|
|
||||||
// spend all the funds
|
// spend all the funds
|
||||||
let spendAmount: Int64 = postActivationBalance - Int64(network.constants.defaultFee(for: activationHeight))
|
let spendAmount: Int64 = postActivationBalance - Int64(network.constants.defaultFee(for: activationHeight))
|
||||||
|
@ -409,19 +447,26 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
send transaction to recipient address
|
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 {
|
switch result {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
self.handleError(e)
|
self.handleError(e)
|
||||||
case .success(let pendingTx):
|
case .success(let pendingTx):
|
||||||
p = pendingTx
|
pendingEntity = pendingTx
|
||||||
}
|
}
|
||||||
sendExpectation.fulfill()
|
sendExpectation.fulfill()
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sendExpectation], timeout: 15)
|
wait(for: [sendExpectation], timeout: 15)
|
||||||
|
|
||||||
guard let _ = p else {
|
guard pendingEntity != nil else {
|
||||||
XCTFail("no pending transaction after sending")
|
XCTFail("no pending transaction after sending")
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
return
|
return
|
||||||
|
|
|
@ -8,16 +8,19 @@
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional
|
||||||
class NotesRepositoryTests: XCTestCase {
|
class NotesRepositoryTests: XCTestCase {
|
||||||
|
|
||||||
var sentNotesRepository: SentNotesRepository!
|
var sentNotesRepository: SentNotesRepository!
|
||||||
var receivedNotesRepository: ReceivedNoteRepository!
|
var receivedNotesRepository: ReceivedNoteRepository!
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
sentNotesRepository = TestDbBuilder.sentNotesRepository()
|
sentNotesRepository = TestDbBuilder.sentNotesRepository()
|
||||||
receivedNotesRepository = TestDbBuilder.receivedNotesRepository()
|
receivedNotesRepository = TestDbBuilder.receivedNotesRepository()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
|
super.tearDown()
|
||||||
sentNotesRepository = nil
|
sentNotesRepository = nil
|
||||||
receivedNotesRepository = nil
|
receivedNotesRepository = nil
|
||||||
}
|
}
|
||||||
|
@ -32,6 +35,5 @@ class NotesRepositoryTests: XCTestCase {
|
||||||
var count: Int?
|
var count: Int?
|
||||||
XCTAssertNoThrow(try { count = try receivedNotesRepository.count() }())
|
XCTAssertNoThrow(try { count = try receivedNotesRepository.count() }())
|
||||||
XCTAssertEqual(count, 27)
|
XCTAssertEqual(count, 27)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,19 +7,24 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class NullBytesTests: XCTestCase {
|
class NullBytesTests: XCTestCase {
|
||||||
let networkType = NetworkType.mainnet
|
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 {
|
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/
|
// 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"
|
let validTAddr = "t1J5pTRzJi7j8Xw9VJTrPxPEkaigr69gKVT"
|
||||||
XCTAssertFalse(try ZcashRustBackend.isValidTransparentAddress(TaddrWithNullBytes, networkType: networkType))
|
let tAddrWithNullBytes = "\(validTAddr)\0fasdfasdf"
|
||||||
|
|
||||||
|
XCTAssertFalse(try ZcashRustBackend.isValidTransparentAddress(tAddrWithNullBytes, networkType: networkType))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInitAccountTableNullBytes() throws {
|
func testInitAccountTableNullBytes() throws {
|
||||||
|
@ -27,11 +32,24 @@ class NullBytesTests: XCTestCase {
|
||||||
let goodHash = "00000000015c597fab53f58b9e1ededbe8bd83ca0203788e2039eceeb0d65ca6"
|
let goodHash = "00000000015c597fab53f58b9e1ededbe8bd83ca0203788e2039eceeb0d65ca6"
|
||||||
let time: UInt32 = 1582235356
|
let time: UInt32 = 1582235356
|
||||||
let height: Int32 = 735000
|
let height: Int32 = 735000
|
||||||
|
|
||||||
|
// swiftlint:disable:next line_length
|
||||||
let wrongTree = "0161f2ff97ff6ac6a90f9bce76c11710460f4944d8695aecc7dc99e34cad0131040011015325b185e23e82562db27817be996ffade9597181244f67efc40561aeb9dde1101daeffadc9e38f755bcb55a847a1278518a0ba4a2ef33b2fe01bbb3eb242ab0070000000000011c51f9077e3f7e28e8e337eaf4bb99b41acbc853a37dcc1e172467a1c919fe4100010bb1f55481b2268ef31997dc0fb6b48a530bc17870220f156d832326c433eb0a010b3768d3bf7868a67823e022f49be67982d0588e7041c498a756024\0750065a4a0001a9e1bf4bccb48b14b544e770f21d48f2d3ad8d6ca54eccc92f60634e3078eb48013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
|
let wrongTree = "0161f2ff97ff6ac6a90f9bce76c11710460f4944d8695aecc7dc99e34cad0131040011015325b185e23e82562db27817be996ffade9597181244f67efc40561aeb9dde1101daeffadc9e38f755bcb55a847a1278518a0ba4a2ef33b2fe01bbb3eb242ab0070000000000011c51f9077e3f7e28e8e337eaf4bb99b41acbc853a37dcc1e172467a1c919fe4100010bb1f55481b2268ef31997dc0fb6b48a530bc17870220f156d832326c433eb0a010b3768d3bf7868a67823e022f49be67982d0588e7041c498a756024\0750065a4a0001a9e1bf4bccb48b14b544e770f21d48f2d3ad8d6ca54eccc92f60634e3078eb48013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
|
||||||
|
|
||||||
|
// swiftlint:disable:next line_length
|
||||||
let goodTree = "0161f2ff97ff6ac6a90f9bce76c11710460f4944d8695aecc7dc99e34cad0131040011015325b185e23e82562db27817be996ffade9597181244f67efc40561aeb9dde1101daeffadc9e38f755bcb55a847a1278518a0ba4a2ef33b2fe01bbb3eb242ab0070000000000011c51f9077e3f7e28e8e337eaf4bb99b41acbc853a37dcc1e172467a1c919fe4100010bb1f55481b2268ef31997dc0fb6b48a530bc17870220f156d832326c433eb0a010b3768d3bf7868a67823e022f49be67982d0588e7041c498a756024750065a4a0001a9e1bf4bccb48b14b544e770f21d48f2d3ad8d6ca54eccc92f60634e3078eb48013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
|
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 {
|
guard let rustError = error as? RustWeldingError else {
|
||||||
XCTFail("Expected RustWeldingError")
|
XCTFail("Expected RustWeldingError")
|
||||||
return
|
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 {
|
guard let rustError = error as? RustWeldingError else {
|
||||||
XCTFail("Expected RustWeldingError")
|
XCTFail("Expected RustWeldingError")
|
||||||
return
|
return
|
||||||
|
@ -62,12 +89,16 @@ class NullBytesTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testderiveExtendedFullViewingKeyWithNullBytes() throws {
|
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"
|
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"
|
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 {
|
guard let rustError = error as? RustWeldingError else {
|
||||||
XCTFail("Expected RustWeldingError")
|
XCTFail("Expected RustWeldingError")
|
||||||
return
|
return
|
||||||
|
@ -82,15 +113,17 @@ class NullBytesTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertNoThrow(try ZcashRustBackend.deriveExtendedFullViewingKey(goodSpendingKeys, networkType: networkType))
|
XCTAssertNoThrow(try ZcashRustBackend.deriveExtendedFullViewingKey(goodSpendingKeys, networkType: networkType))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCheckNullBytes() throws {
|
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())
|
XCTAssertFalse(validZaddr.containsCStringNullBytesBeforeStringEnding())
|
||||||
|
XCTAssertTrue(
|
||||||
XCTAssertTrue("zs1gqtfu59z20s\09t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp".containsCStringNullBytesBeforeStringEnding())
|
"zs1gqtfu59z20s\09t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp"
|
||||||
|
.containsCStringNullBytesBeforeStringEnding()
|
||||||
|
)
|
||||||
XCTAssertTrue("\0".containsCStringNullBytesBeforeStringEnding())
|
XCTAssertTrue("\0".containsCStringNullBytesBeforeStringEnding())
|
||||||
XCTAssertFalse("".containsCStringNullBytesBeforeStringEnding())
|
XCTAssertFalse("".containsCStringNullBytesBeforeStringEnding())
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,20 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
class PagedTransactionRepositoryTests: XCTestCase {
|
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional
|
||||||
|
class PagedTransactionRepositoryTests: XCTestCase {
|
||||||
var pagedTransactionRepository: PaginatedTransactionRepository!
|
var pagedTransactionRepository: PaginatedTransactionRepository!
|
||||||
var transactionRepository: TransactionRepository!
|
var transactionRepository: TransactionRepository!
|
||||||
|
|
||||||
override func setUp() {
|
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)
|
pagedTransactionRepository = PagedTransactionDAO(repository: transactionRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,12 +28,13 @@ class PagedTransactionRepositoryTests: XCTestCase {
|
||||||
let pageSize = pagedTransactionRepository.pageSize
|
let pageSize = pagedTransactionRepository.pageSize
|
||||||
let pageCount = pagedTransactionRepository.pageCount
|
let pageCount = pagedTransactionRepository.pageCount
|
||||||
let totalItems = pagedTransactionRepository.itemCount
|
let totalItems = pagedTransactionRepository.itemCount
|
||||||
for i in 0 ..< pageCount/pageSize {
|
|
||||||
guard let page = try? pagedTransactionRepository.page(i) else {
|
for index in 0 ..< pageCount / pageSize {
|
||||||
XCTFail("page failed to get page \(i)")
|
guard let page = try? pagedTransactionRepository.page(index) else {
|
||||||
|
XCTFail("page failed to get page \(index)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if i < pageCount {
|
if index < pageCount {
|
||||||
XCTAssert(page.count == pageSize)
|
XCTAssert(page.count == pageSize)
|
||||||
} else {
|
} else {
|
||||||
// last page has to have the remainding items
|
// last page has to have the remainding items
|
||||||
|
@ -34,5 +42,4 @@ class PagedTransactionRepositoryTests: XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,22 +7,24 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable force_try force_unwrapping implicitly_unwrapped_optional
|
||||||
class PendingTransactionRepositoryTests: XCTestCase {
|
class PendingTransactionRepositoryTests: XCTestCase {
|
||||||
|
let dbUrl = try! TestDbBuilder.pendingTransactionsDbURL()
|
||||||
|
let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6"
|
||||||
|
|
||||||
var pendingRepository: PendingTransactionRepository!
|
var pendingRepository: PendingTransactionRepository!
|
||||||
|
|
||||||
let dbUrl = try! TestDbBuilder.pendingTransactionsDbURL()
|
|
||||||
|
|
||||||
let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6"
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
cleanUpDb()
|
cleanUpDb()
|
||||||
let dao = PendingTransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: try! TestDbBuilder.pendingTransactionsDbURL().absoluteString))
|
let dao = PendingTransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: try! TestDbBuilder.pendingTransactionsDbURL().absoluteString))
|
||||||
try! dao.createrTableIfNeeded()
|
try! dao.createrTableIfNeeded()
|
||||||
pendingRepository = dao
|
pendingRepository = dao
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
|
super.tearDown()
|
||||||
cleanUpDb()
|
cleanUpDb()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,10 +33,9 @@ class PendingTransactionRepositoryTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCreate() {
|
func testCreate() {
|
||||||
|
let transaction = createAndStoreMockedTransaction()
|
||||||
|
|
||||||
let tx = createAndStoreMockedTransaction()
|
guard let id = transaction.id, id >= 0 else {
|
||||||
|
|
||||||
guard let id = tx.id, id >= 0 else {
|
|
||||||
XCTFail("failed to create mocked transaction that was just inserted")
|
XCTFail("failed to create mocked transaction that was just inserted")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -47,61 +48,64 @@ class PendingTransactionRepositoryTests: XCTestCase {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertEqual(tx.accountIndex, expected.accountIndex)
|
XCTAssertEqual(transaction.accountIndex, expected.accountIndex)
|
||||||
XCTAssertEqual(tx.value, expected.value)
|
XCTAssertEqual(transaction.value, expected.value)
|
||||||
XCTAssertEqual(tx.toAddress, expected.toAddress)
|
XCTAssertEqual(transaction.toAddress, expected.toAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFindById() {
|
func testFindById() {
|
||||||
let tx = createAndStoreMockedTransaction()
|
let transaction = createAndStoreMockedTransaction()
|
||||||
|
|
||||||
var expected: PendingTransactionEntity?
|
var expected: PendingTransactionEntity?
|
||||||
|
|
||||||
guard let id = tx.id else {
|
guard let id = transaction.id else {
|
||||||
XCTFail("transaction with no id")
|
XCTFail("transaction with no id")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
XCTAssertNoThrow(try { expected = try pendingRepository.find(by: id)}())
|
|
||||||
|
|
||||||
|
XCTAssertNoThrow(try { expected = try pendingRepository.find(by: id) }())
|
||||||
XCTAssertNotNil(expected)
|
XCTAssertNotNil(expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCancel() {
|
func testCancel() {
|
||||||
let tx = createAndStoreMockedTransaction()
|
let transaction = createAndStoreMockedTransaction()
|
||||||
guard let id = tx.id else {
|
|
||||||
|
guard let id = transaction.id else {
|
||||||
XCTFail("transaction with no id")
|
XCTFail("transaction with no id")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard id >= 0 else {
|
guard id >= 0 else {
|
||||||
XCTFail("failed to create mocked transaction that was just inserted")
|
XCTFail("failed to create mocked transaction that was just inserted")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertNoThrow(try pendingRepository.cancel(tx))
|
XCTAssertNoThrow(try pendingRepository.cancel(transaction))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDelete() {
|
func testDelete() {
|
||||||
let tx = createAndStoreMockedTransaction()
|
let transaction = createAndStoreMockedTransaction()
|
||||||
guard let id = tx.id else {
|
|
||||||
|
guard let id = transaction.id else {
|
||||||
XCTFail("transaction with no id")
|
XCTFail("transaction with no id")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard id >= 0 else {
|
guard id >= 0 else {
|
||||||
XCTFail("failed to create mocked transaction that was just inserted")
|
XCTFail("failed to create mocked transaction that was just inserted")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertNoThrow(try pendingRepository.delete(tx))
|
XCTAssertNoThrow(try pendingRepository.delete(transaction))
|
||||||
|
|
||||||
var unexpectedTx: PendingTransactionEntity?
|
var unexpectedTx: PendingTransactionEntity?
|
||||||
|
|
||||||
XCTAssertNoThrow(try { unexpectedTx = try pendingRepository.find(by: id) }())
|
XCTAssertNoThrow(try { unexpectedTx = try pendingRepository.find(by: id) }())
|
||||||
|
|
||||||
XCTAssertNil(unexpectedTx)
|
XCTAssertNil(unexpectedTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetAll() {
|
func testGetAll() {
|
||||||
var mockTransactions = [PendingTransactionEntity]()
|
var mockTransactions: [PendingTransactionEntity] = []
|
||||||
for _ in 1...100 {
|
for _ in 1...100 {
|
||||||
mockTransactions.append(createAndStoreMockedTransaction())
|
mockTransactions.append(createAndStoreMockedTransaction())
|
||||||
}
|
}
|
||||||
|
@ -116,17 +120,18 @@ class PendingTransactionRepositoryTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertEqual(mockTransactions.count, allTxs.count)
|
XCTAssertEqual(mockTransactions.count, allTxs.count)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testUpdate() {
|
func testUpdate() {
|
||||||
let newAccountIndex = 1
|
let newAccountIndex = 1
|
||||||
let newValue: Int = 123_456
|
let newValue: Int = 123_456
|
||||||
let tx = createAndStoreMockedTransaction()
|
let transaction = createAndStoreMockedTransaction()
|
||||||
guard let id = tx.id else {
|
|
||||||
|
guard let id = transaction.id else {
|
||||||
XCTFail("transaction with no id")
|
XCTFail("transaction with no id")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var stored: PendingTransactionEntity?
|
var stored: PendingTransactionEntity?
|
||||||
|
|
||||||
XCTAssertNoThrow(try { stored = try pendingRepository.find(by: id) }())
|
XCTAssertNoThrow(try { stored = try pendingRepository.find(by: id) }())
|
||||||
|
@ -152,12 +157,12 @@ class PendingTransactionRepositoryTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func createAndStoreMockedTransaction() -> PendingTransactionEntity {
|
func createAndStoreMockedTransaction() -> PendingTransactionEntity {
|
||||||
var tx = mockTransaction()
|
var transaction = mockTransaction()
|
||||||
var id: Int?
|
var id: Int?
|
||||||
|
|
||||||
XCTAssertNoThrow(try { id = try pendingRepository.create(tx) }())
|
XCTAssertNoThrow(try { id = try pendingRepository.create(transaction) }())
|
||||||
tx.id = Int(id ?? -1)
|
transaction.id = Int(id ?? -1)
|
||||||
return tx
|
return transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPerformanceExample() {
|
func testPerformanceExample() {
|
||||||
|
@ -170,5 +175,4 @@ class PendingTransactionRepositoryTests: XCTestCase {
|
||||||
private func mockTransaction() -> PendingTransactionEntity {
|
private func mockTransaction() -> PendingTransactionEntity {
|
||||||
PendingTransaction(value: Int.random(in: 1 ... 1_000_000), toAddress: recipientAddress, memo: nil, account: 0)
|
PendingTransaction(value: Int.random(in: 1 ... 1_000_000), toAddress: recipientAddress, memo: nil, account: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,14 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@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
|
let sendAmount: Int64 = 1000
|
||||||
var birthday: BlockHeight = 663150
|
var birthday: BlockHeight = 663150
|
||||||
|
@ -20,12 +24,12 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
||||||
var sentTransactionExpectation = XCTestExpectation(description: "sent")
|
var sentTransactionExpectation = XCTestExpectation(description: "sent")
|
||||||
var expectedReorgHeight: BlockHeight = 665188
|
var expectedReorgHeight: BlockHeight = 665188
|
||||||
var expectedRewindHeight: BlockHeight = 665188
|
var expectedRewindHeight: BlockHeight = 665188
|
||||||
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
|
var reorgExpectation = XCTestExpectation(description: "reorg")
|
||||||
let branchID = "2bb40e60"
|
let branchID = "2bb40e60"
|
||||||
let chainName = "main"
|
let chainName = "main"
|
||||||
let network = DarksideWalletDNetwork()
|
let network = DarksideWalletDNetwork()
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
|
try super.setUpWithError()
|
||||||
coordinator = try TestCoordinator(
|
coordinator = try TestCoordinator(
|
||||||
seed: seedPhrase,
|
seed: seedPhrase,
|
||||||
walletBirthday: birthday,
|
walletBirthday: birthday,
|
||||||
|
@ -36,6 +40,7 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
|
try super.tearDownWithError()
|
||||||
NotificationCenter.default.removeObserver(self)
|
NotificationCenter.default.removeObserver(self)
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
||||||
|
@ -44,15 +49,13 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func handleReorg(_ notification: Notification) {
|
@objc func handleReorg(_ notification: Notification) {
|
||||||
|
guard
|
||||||
guard let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight
|
let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight
|
||||||
// let rewindHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight
|
|
||||||
else {
|
else {
|
||||||
XCTFail("empty reorg notification")
|
XCTFail("empty reorg notification")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// XCTAssertEqual(rewindHeight, expectedRewindHeight)
|
|
||||||
XCTAssertEqual(reorgHeight, expectedReorgHeight)
|
XCTAssertEqual(reorgHeight, expectedReorgHeight)
|
||||||
reorgExpectation.fulfill()
|
reorgExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
@ -69,13 +72,12 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
1a. sync to latest height
|
1a. sync to latest height
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LoggerProxy.info("1a. sync to latest height")
|
LoggerProxy.info("1a. sync to latest height")
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -84,34 +86,52 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
|
|
||||||
let sendExpectation = XCTestExpectation(description: "send expectation")
|
let sendExpectation = XCTestExpectation(description: "send expectation")
|
||||||
var p: PendingTransactionEntity? = nil
|
var pendingEntity: PendingTransactionEntity?
|
||||||
|
|
||||||
/*
|
/*
|
||||||
2. send transaction to recipient address
|
2. send transaction to recipient address
|
||||||
*/
|
*/
|
||||||
LoggerProxy.info("2. send transaction to recipient address")
|
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 {
|
switch result {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
self.handleError(e)
|
self.handleError(e)
|
||||||
case .success(let pendingTx):
|
case .success(let pendingTx):
|
||||||
p = pendingTx
|
pendingEntity = pendingTx
|
||||||
}
|
}
|
||||||
sendExpectation.fulfill()
|
sendExpectation.fulfill()
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [sendExpectation], timeout: 11)
|
wait(for: [sendExpectation], timeout: 11)
|
||||||
|
|
||||||
guard let pendingUnconfirmedTx = p else {
|
guard let pendingUnconfirmedTx = pendingEntity else {
|
||||||
XCTFail("no pending transaction after sending")
|
XCTFail("no pending transaction after sending")
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertFalse(pendingUnconfirmedTx.isConfirmed(currentHeight: 663188), "pending transaction evaluated as confirmed when it shouldn't")
|
XCTAssertFalse(
|
||||||
XCTAssertFalse(pendingUnconfirmedTx.isMined, "pending transaction evaluated as mined when it shouldn't")
|
pendingUnconfirmedTx.isConfirmed(currentHeight: 663188),
|
||||||
|
"pending transaction evaluated as confirmed when it shouldn't"
|
||||||
|
)
|
||||||
|
XCTAssertFalse(
|
||||||
|
pendingUnconfirmedTx.isMined,
|
||||||
|
"pending transaction evaluated as mined when it shouldn't"
|
||||||
|
)
|
||||||
|
|
||||||
|
XCTAssertTrue(
|
||||||
|
pendingUnconfirmedTx.isPending(currentHeight: 663188),
|
||||||
|
"pending transaction evaluated as not pending when it should be"
|
||||||
|
)
|
||||||
|
|
||||||
XCTAssertTrue(pendingUnconfirmedTx.isPending(currentHeight: 663188), "pending transaction evaluated as not pending when it should be")
|
|
||||||
/**
|
/**
|
||||||
3. getIncomingTransaction
|
3. getIncomingTransaction
|
||||||
*/
|
*/
|
||||||
|
@ -124,7 +144,6 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
||||||
|
|
||||||
let sentTxHeight: BlockHeight = 663189
|
let sentTxHeight: BlockHeight = 663189
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
4. stage transaction at sentTxHeight
|
4. stage transaction at sentTxHeight
|
||||||
*/
|
*/
|
||||||
|
@ -132,6 +151,7 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
||||||
try coordinator.stageBlockCreate(height: sentTxHeight)
|
try coordinator.stageBlockCreate(height: sentTxHeight)
|
||||||
|
|
||||||
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
|
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
5. applyHeight(sentTxHeight)
|
5. applyHeight(sentTxHeight)
|
||||||
*/
|
*/
|
||||||
|
@ -146,9 +166,12 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
||||||
LoggerProxy.info("6. sync to latest height")
|
LoggerProxy.info("6. sync to latest height")
|
||||||
let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
|
let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(
|
||||||
|
completion: { _ in
|
||||||
secondSyncExpectation.fulfill()
|
secondSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
},
|
||||||
|
error: self.handleError
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [secondSyncExpectation], timeout: 5)
|
wait(for: [secondSyncExpectation], timeout: 5)
|
||||||
|
|
||||||
|
@ -183,20 +206,18 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
||||||
*/
|
*/
|
||||||
LoggerProxy.info("last sync to latest height: \(lastStageHeight)")
|
LoggerProxy.info("last sync to latest height: \(lastStageHeight)")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { _ in
|
||||||
syncToConfirmExpectation.fulfill()
|
syncToConfirmExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [syncToConfirmExpectation], timeout: 6)
|
wait(for: [syncToConfirmExpectation], timeout: 6)
|
||||||
var supposedlyPendingUnexistingTransaction: PendingTransactionEntity? = nil
|
var supposedlyPendingUnexistingTransaction: PendingTransactionEntity?
|
||||||
|
|
||||||
XCTAssertNoThrow(try { supposedlyPendingUnexistingTransaction = try coordinator.synchronizer.allPendingTransactions().first }())
|
XCTAssertNoThrow(try { supposedlyPendingUnexistingTransaction = try coordinator.synchronizer.allPendingTransactions().first }())
|
||||||
|
|
||||||
XCTAssertNil(supposedlyPendingUnexistingTransaction)
|
XCTAssertNil(supposedlyPendingUnexistingTransaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func handleError(_ error: Error?) {
|
func handleError(_ error: Error?) {
|
||||||
_ = try? coordinator.stop()
|
_ = try? coordinator.stop()
|
||||||
guard let testError = error else {
|
guard let testError = error else {
|
||||||
|
@ -207,6 +228,11 @@ class PendingTransactionUpdatesTest: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func hookToReOrgNotification() {
|
func hookToReOrgNotification() {
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(handleReorg(_:)), name: .blockProcessorHandledReOrg, object: nil)
|
NotificationCenter.default.addObserver(
|
||||||
|
self,
|
||||||
|
selector: #selector(handleReorg(_:)),
|
||||||
|
name: .blockProcessorHandledReOrg,
|
||||||
|
object: nil
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,29 +8,35 @@
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
@testable import SwiftProtobuf
|
@testable import SwiftProtobuf
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional
|
||||||
class RawTransactionTests: XCTestCase {
|
class RawTransactionTests: XCTestCase {
|
||||||
var rawTx: Data!
|
var rawTx: Data!
|
||||||
var transactionRepository: TransactionSQLDAO!
|
var transactionRepository: TransactionSQLDAO!
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
rawTx = Data(base64Encoded: txBase64String)
|
rawTx = Data(base64Encoded: txBase64String)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeserialize() {
|
func testDeserialize() {
|
||||||
|
|
||||||
guard let raw = Data(base64Encoded: txFromAndroidSDK) else {
|
guard let raw = Data(base64Encoded: txFromAndroidSDK) else {
|
||||||
XCTFail("no raw data")
|
XCTFail("no raw data")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let rawTransaction = RawTransaction.with({ (r) in
|
let rawTransaction = RawTransaction.with({ rawTr in
|
||||||
r.data = raw
|
rawTr.data = raw
|
||||||
})
|
})
|
||||||
|
|
||||||
XCTAssertNotNil(rawTransaction)
|
XCTAssertNotNil(rawTransaction)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let txFromAndroidSDK = "BAAAgIUgL4kAAAAAAACqoAoAECcAAAAAAAAB25ACAriMhxsTPYM1Lit6Ob0O1PssJwZ8e3/rLA+epll+1eKFT4lvPvDHjzY5udeJfHtvCcbFr+WL6rQGAjdrK7Y6Lu+Ofn1DOSOuVtv6z4FMSBB2EsrYkjsHkYTz93xpwTPnB2J42JrYdrq3qviFGaT3T06/dZGmuIxZVYqKFWaCKjniLNYh5epX3U33l7fjKzLKXiFXcJjAFmElvzbjEcEdMTvcDcno0swmE9XNPZ2iMNyeIX1TqEQJCvnTfK26D+ig768BZqdzYMDXu8sSDa0SdeHwJWmRUPoPUG1AbFQZPmzp3ZYITbpUigsKFJhB+lQ+DP62qKIP/uJq8wLCevMgfcVLFk6rzkgMGkz5/ySm4R5yFcj4GLQ65GcX8EvnMbM0WT4nwpjhttTSb6Fquzxb38VfqGoVBnH5VrRLwBrSsucr7dZtMcLxZCyZ29JPtfVf2o/BrEaigYGF0vLQnkDl4fWTnuafIMFPa4uO7tUtPGU6DwmRXX33Twz7P7ACAh8O6RK6jOJ+2vZWHXx+P0hqIHrYL/5lip60hQ9llRVYCSCiT7tvm57lIfDP5whUda6zwpyp4p7tjE4HvTMlOV0uZIuxN8J14gsrDnDbpn+hR+FCdEXS88of4UIe4oRNxjel70OAmMVCPFd2Y1O47jZo2BjHx4+1e9mou2SyjGSCepsbGizfn+5xz6jH2dYLGbWGlaNQyosCLlY6/UHswRV7y1NZcaFY5zh9ytMsdfYC20I3Zv1MyyDk1Jd6mlscRksP/iAjAUGr/PSCGEvOZ1z1dp2XIBism9NHi6Gy2uCFhOqpxfCM7DaKeqUYhH9R1Gfc5Vpy0LKAFVxOaTSha4odsOlgAE5GffwzPA11g43wR0scKGR0JImRVRfxyYVaKHggRaP/UnEsvXIiE+e3Mx0CA1aKfwbl9n0AlLuUVttAgZxUxnULHtC3jRt0l4gippyxD658jInGnbJfi3dKcI4H6OGeH7wznXpaUP7wfXIUa1kyv8FuZwkktXPLOW+1XKd9hAs+5UDqSajq/TZ0bNaCxOJQruASxqtUq+678hBmAhhqjk7IJ99KSy5y07bRnxVnDfVj5ZpEXBzkK08/G8pBA5qSGXjgEqXKRXFTgXzuW+m7c2jVCxpM5lDy5Adej7H61sz6T0N9OXwN8SjssWtS65unp6pKg1psowwNAAVdv/bvtyQOidwnf20j6LlitvVNNY3vGedRxCaeatvcDYb9cdBqqxzb3ki/Sn7beLOS/LF2YnYtLhdT8qB40dILmyOMeXOA1L2wzeCnbx9fIuCrGZDPjTRfIWWCMZVJ4RuJ5CqKFcYbYN+GrxtKkMmprwbcE8XxW71cUEsE9M5GtM8uDvmpTGFQKQTV2EcYoN0Go47CSPx4kfFSybGWsRir2aX+7i5QHNYvicfoWOXWSY60I7OHIOR8xs2qYBgfbb+7/ml1xxCm7WDdO6NfyJib9d6YpbIanSYh77ytwVlOu4HMhrs9K+NuSQYE7gKiHcoWOJkNYqW4VmLKiuw51kmm3Q0238VTOBOzba1oUz1ukR+9bPXjUhFmoY/Ueen9aZdobcE33YYu8iqua6E1zyknnsL+h/Zc7fT5FBpcQGEfYqsKKZKNsuCA+N6IRyq3OtmRVFhL1wFU1YdVQeKQfd69CTNpPJbnDkNVN7Img/+cEgMj5H5qDD4rE1vsq1cx48RnxV5lMa/T9WHnpcaAZ4/1qkFCKGhw6yRBcoGTWuH0vbS6071/iPJV5AhjlqNJMUw1s7BpojmxPOaWhAV3ztOOi3ZhiyPrtRJnUmfwfjYZO7FQq8eF4MDP7njiICsP74skUJoe0BBAcUgTatSIST2MkYgpa0QJAragwcRg1ZHFmTZYoEWhYp9K8FP8WLl1XrlSetPrEgo2zCrnb6GoOLSjnvF9CIdzXB2lpB8c71azvFAO3Kc58QDsIAFTN5cWMFMZTrmQi/AqsSVwaF92FZeNdAL5lVNfZ2LePrmXGSvGrDFjt3Wql/9KYebrGwBXpHdUOWRIF8FJMplg+jN2lz/0GGp39EkDZBXUlJUsCgnCInDyeKxI0rMJY8w5cVXyN9FW3/v6ns3UtYkFqNv2dcOT7WUBFgI0ZJ+M3i/L88MKga/dtntmZrXOxD6LXQ3hApLcm06t40cOVZdVlQ2doIMNzx1I66lXXjq8ij6L6Z40qwgrsFzX1RYUXooM+1HvmEmaffglOdqHkwtk3hK+4OWNoxdb8QFG5EbGCcahIpvRg0Wj60/zhzv6LfQC6/Yqd65QVjgYorV0Uy8eGGlD/aDDQp7nIu/1+EA5Aav0isl3TPBd/qmjGxdTI6BANQrB8rl58V+0rAY2AdBuXTM0bo8Ak/QcVDMp7arN8cViLCb3rq1Job34GZE8OzyRDuk2E499JqxClQPtPeJa47AKGV4OofPN6qOnbCEB2DlqrW4cPVDE95Ty+I1qUS2eDD0lZS0Ll/czErJ9H4cqFpFKUbXF6yZ+JbcPyMWqgaZHCatmM2rc6yxgWP8R6/KW/xdx++N/SGi3zQW2Zk7om26VZiBaGP36de0hut6VuHS54bobzSjZChwL4tcHcsgGW3cF+iWL3bHJ/Yo2b7r1r/lRboArd6c+8Ap2HFqCJYxPfdnqG5M8WfkbHecWkf4uAqn0aAWoFeBS7w+PGOuBE0RdQTt14UkwUu2OVfcxWyVjfDZ5DggMJ5bwszMzz2FVivIDZ7fUnZ5ftUkuALx4PcN58vJGycgWpBk55ZhIdFKTD7hx/Psv5myn2y7ZJarlMAS6PLGjjd7XKqi/3Q5f0RCR6QSB8ImecdwJfECwN80Dx6sNCy2eZAnx2kjXCYq5lJiGQ4feDvp/GBuf3SnggsFa4YZHThRWQH/83qe8RgTYcSuPc6p2MTfE2RVCHg4Ek8usMLcrORtH6a53/slMp10DW4i9fMF2GZroorM762i6y2OQq7/YzwWzsISBupQANlPGwRwFrqwXY2BSqNPgt1r7p68SFUZ8KtzWov1QWl9cDjFRAeISXo7CcjLyWgDQwBPKo4otCxnJ0tHIQpttJYwPx/39bLbaiou5HXFRYeBE1JxlyRQv1Be5KCGoL0kOdoe4psIKEZ5ijIYhCqoC"
|
let txFromAndroidSDK =
|
||||||
|
// swiftlint:disable:next line_length
|
||||||
|
"BAAAgIUgL4kAAAAAAACqoAoAECcAAAAAAAAB25ACAriMhxsTPYM1Lit6Ob0O1PssJwZ8e3/rLA+epll+1eKFT4lvPvDHjzY5udeJfHtvCcbFr+WL6rQGAjdrK7Y6Lu+Ofn1DOSOuVtv6z4FMSBB2EsrYkjsHkYTz93xpwTPnB2J42JrYdrq3qviFGaT3T06/dZGmuIxZVYqKFWaCKjniLNYh5epX3U33l7fjKzLKXiFXcJjAFmElvzbjEcEdMTvcDcno0swmE9XNPZ2iMNyeIX1TqEQJCvnTfK26D+ig768BZqdzYMDXu8sSDa0SdeHwJWmRUPoPUG1AbFQZPmzp3ZYITbpUigsKFJhB+lQ+DP62qKIP/uJq8wLCevMgfcVLFk6rzkgMGkz5/ySm4R5yFcj4GLQ65GcX8EvnMbM0WT4nwpjhttTSb6Fquzxb38VfqGoVBnH5VrRLwBrSsucr7dZtMcLxZCyZ29JPtfVf2o/BrEaigYGF0vLQnkDl4fWTnuafIMFPa4uO7tUtPGU6DwmRXX33Twz7P7ACAh8O6RK6jOJ+2vZWHXx+P0hqIHrYL/5lip60hQ9llRVYCSCiT7tvm57lIfDP5whUda6zwpyp4p7tjE4HvTMlOV0uZIuxN8J14gsrDnDbpn+hR+FCdEXS88of4UIe4oRNxjel70OAmMVCPFd2Y1O47jZo2BjHx4+1e9mou2SyjGSCepsbGizfn+5xz6jH2dYLGbWGlaNQyosCLlY6/UHswRV7y1NZcaFY5zh9ytMsdfYC20I3Zv1MyyDk1Jd6mlscRksP/iAjAUGr/PSCGEvOZ1z1dp2XIBism9NHi6Gy2uCFhOqpxfCM7DaKeqUYhH9R1Gfc5Vpy0LKAFVxOaTSha4odsOlgAE5GffwzPA11g43wR0scKGR0JImRVRfxyYVaKHggRaP/UnEsvXIiE+e3Mx0CA1aKfwbl9n0AlLuUVttAgZxUxnULHtC3jRt0l4gippyxD658jInGnbJfi3dKcI4H6OGeH7wznXpaUP7wfXIUa1kyv8FuZwkktXPLOW+1XKd9hAs+5UDqSajq/TZ0bNaCxOJQruASxqtUq+678hBmAhhqjk7IJ99KSy5y07bRnxVnDfVj5ZpEXBzkK08/G8pBA5qSGXjgEqXKRXFTgXzuW+m7c2jVCxpM5lDy5Adej7H61sz6T0N9OXwN8SjssWtS65unp6pKg1psowwNAAVdv/bvtyQOidwnf20j6LlitvVNNY3vGedRxCaeatvcDYb9cdBqqxzb3ki/Sn7beLOS/LF2YnYtLhdT8qB40dILmyOMeXOA1L2wzeCnbx9fIuCrGZDPjTRfIWWCMZVJ4RuJ5CqKFcYbYN+GrxtKkMmprwbcE8XxW71cUEsE9M5GtM8uDvmpTGFQKQTV2EcYoN0Go47CSPx4kfFSybGWsRir2aX+7i5QHNYvicfoWOXWSY60I7OHIOR8xs2qYBgfbb+7/ml1xxCm7WDdO6NfyJib9d6YpbIanSYh77ytwVlOu4HMhrs9K+NuSQYE7gKiHcoWOJkNYqW4VmLKiuw51kmm3Q0238VTOBOzba1oUz1ukR+9bPXjUhFmoY/Ueen9aZdobcE33YYu8iqua6E1zyknnsL+h/Zc7fT5FBpcQGEfYqsKKZKNsuCA+N6IRyq3OtmRVFhL1wFU1YdVQeKQfd69CTNpPJbnDkNVN7Img/+cEgMj5H5qDD4rE1vsq1cx48RnxV5lMa/T9WHnpcaAZ4/1qkFCKGhw6yRBcoGTWuH0vbS6071/iPJV5AhjlqNJMUw1s7BpojmxPOaWhAV3ztOOi3ZhiyPrtRJnUmfwfjYZO7FQq8eF4MDP7njiICsP74skUJoe0BBAcUgTatSIST2MkYgpa0QJAragwcRg1ZHFmTZYoEWhYp9K8FP8WLl1XrlSetPrEgo2zCrnb6GoOLSjnvF9CIdzXB2lpB8c71azvFAO3Kc58QDsIAFTN5cWMFMZTrmQi/AqsSVwaF92FZeNdAL5lVNfZ2LePrmXGSvGrDFjt3Wql/9KYebrGwBXpHdUOWRIF8FJMplg+jN2lz/0GGp39EkDZBXUlJUsCgnCInDyeKxI0rMJY8w5cVXyN9FW3/v6ns3UtYkFqNv2dcOT7WUBFgI0ZJ+M3i/L88MKga/dtntmZrXOxD6LXQ3hApLcm06t40cOVZdVlQ2doIMNzx1I66lXXjq8ij6L6Z40qwgrsFzX1RYUXooM+1HvmEmaffglOdqHkwtk3hK+4OWNoxdb8QFG5EbGCcahIpvRg0Wj60/zhzv6LfQC6/Yqd65QVjgYorV0Uy8eGGlD/aDDQp7nIu/1+EA5Aav0isl3TPBd/qmjGxdTI6BANQrB8rl58V+0rAY2AdBuXTM0bo8Ak/QcVDMp7arN8cViLCb3rq1Job34GZE8OzyRDuk2E499JqxClQPtPeJa47AKGV4OofPN6qOnbCEB2DlqrW4cPVDE95Ty+I1qUS2eDD0lZS0Ll/czErJ9H4cqFpFKUbXF6yZ+JbcPyMWqgaZHCatmM2rc6yxgWP8R6/KW/xdx++N/SGi3zQW2Zk7om26VZiBaGP36de0hut6VuHS54bobzSjZChwL4tcHcsgGW3cF+iWL3bHJ/Yo2b7r1r/lRboArd6c+8Ap2HFqCJYxPfdnqG5M8WfkbHecWkf4uAqn0aAWoFeBS7w+PGOuBE0RdQTt14UkwUu2OVfcxWyVjfDZ5DggMJ5bwszMzz2FVivIDZ7fUnZ5ftUkuALx4PcN58vJGycgWpBk55ZhIdFKTD7hx/Psv5myn2y7ZJarlMAS6PLGjjd7XKqi/3Q5f0RCR6QSB8ImecdwJfECwN80Dx6sNCy2eZAnx2kjXCYq5lJiGQ4feDvp/GBuf3SnggsFa4YZHThRWQH/83qe8RgTYcSuPc6p2MTfE2RVCHg4Ek8usMLcrORtH6a53/slMp10DW4i9fMF2GZroorM762i6y2OQq7/YzwWzsISBupQANlPGwRwFrqwXY2BSqNPgt1r7p68SFUZ8KtzWov1QWl9cDjFRAeISXo7CcjLyWgDQwBPKo4otCxnJ0tHIQpttJYwPx/39bLbaiou5HXFRYeBE1JxlyRQv1Be5KCGoL0kOdoe4psIKEZ5ijIYhCqoC"
|
||||||
|
|
||||||
let txBase64String = "BAAAgIUgL4kAAAAAAACz/goAECcAAAAAAAABXcTpMQ7kFhTifSbypMLlmgvAh/mR9z78+mocYt7rvJvLFjfBGp9aDf/066bWOsKt4N78Kovjr5mPuVNSMUegJuwZuAxnaO+iu+z17zABU4TUdixiCq97W74jgttjhG+Nxe+HeXvlqX7NmDJJmRO0anXaL1pBcPxOcb1pXcfO5VG1SFGLFIhLNyDlCoYa42sPHnQ4WsjMUv7Jh8rIH/tJ/vhHv9mGEg+zfld5KkMQ1JSykSen34KAPjc/em+2KMN6qAKrUWRPYlQvkz/QTxXeXI1OoCLCmqdsbHEG5ffSdmkAJfJpKfRsI04DQdTF03eVxpSVxlmz7gfeEmwVowKGV284KwmGHsnuHawjcBVb2tWIU9tBfQtONE1HgA5B6wt8ynZGSrlit0gFaTxCxzFcRmYgkgLbJeqx1lu+wUBVqAqvbkA4wGTvNX28b3SWmTx40eTu251bzqzy/Ip/7tSgh6QupSzatDF2gHcpb91EY6r3E3Jyhm2zfu38JSHTctMMArFWhOyfzBwrMPFjrLKDc9IiX7zjMBluTTMgQosb81o4ZF+2ZIKbplfugQICjuQjC5UFvihNCNF6+j8ITfwwD105VO52qVFiAdNAvCsymmPGI0Wr2w9PdBweIhUsrDLz11wi1pnydHdRwArU82CCqcVd5rwixomZrjwP8IFL0wd5CKho7QdU4rXF39VN2nffD+hwAPl0X3TCntws3/8Q1066bRTJLhaZcSzaVB0Bq0GKRAMS/WflBIlkd4KG6+/dDw01B0/lobAJIXfa+UrGKbDxXjLQlW8R8Bi9I+Y7S1h8I/gYOQiuuoCpJyV//4sKi1/zI1nnDcTu1q7P1eDYv30Y1g31FK9IWoXIQaZJ8ehKJqSx/FDBvhsEEh2aHvRolFTwHvxiVV3b9L3txePJRTEBq/RDUvW1BjAST/xfd3TTUILEZ962Ix3hu+ZfKWDSFCb/YW1fHlf98O05QunwBwDnaC3qgzNbqDjF9mldOFWZ84XE6IJVCHTN04L4hR8dl4bltpjnVnQmy34bcKLNtsFoRXot9ckOcrbX8Bf9lfneichrYtWZi6bVt6irwFo4+qXwABsUQGA2TMgsKpw9z4KysdSqoMXOEe+k/wPPQIqTPtFp4jrkMIntSokR6hRPZFdJJ23OWHjOoIKxSZUeOgkbKlqSrcQa/IHZQ8cpEof8T1PyNx/VDgEf6oIxnk2+E/iosraQpunYgAtQCm1pC8tF5oI6MshGj2nfonSug9PS2ORf0xk2RJLnSbg3kdQGx85ulMrOojkci80RIeyta3vX527MKDANTsN6W2y8fT9oDVA4l11lm4j31TyK754eTb1VPsy0YOo1L5Vr0LOOZtpF+tCaojz6Kx980jkzlEJOQ+imLERLAckclxFCWYyQ+9UOJnuXS5YCy32cdkzm17e2SwmeYGmNrTGUm6eaT0/ZqqsPAQEo+h/z4Bgt9eUEUvkRaDhz/vZjJkNfHdLA2c3CI5iTA0WUJQa5J4XNbFSQmEl4RYNHLHz0utsHcgFC9czxtDZkLcTUcQ2i/dQv07E84FhrMG5bJ818SaABpMlX99gaMYRpW3SWSuU0++/apORrIOSqonXunqroBtnAzeAIGY30ikpmkuf/BYTxAADZHCLkUBNVFmkASV91In4r6nfDbwMVOXCffBBHf2Cr/9hcd5TNL10MG0qhSsYrpv1FpCxg56hYiglS3BQ1uj63bzf4lmRbAvwXdI99lgoPQqjws3hIDIAImobsRWJoGSjT6Gq2hd40CVmmFjlXxdPpo6+m4L2PFD97LnHjF9X/VA+VWc+ihPCLrzgVl63NJcsEf/0bNt/iNWkIILM38WUSMEWj4CaSp1wI8ank+JfE7elapFRza98CGb52g+gZSkEv/xWRn/SjL3RvqQwSdWh38N/ijzpRfL48MiwYd15U7HZ2pc/0WtYVe7JSH6BHBXExBUzhqnZqRxK+1jZflKsYFbCAaZOjpeLSy5l8AvOjDfGR5+Uk+7dIs97lSGHZd+EQWgV/bmH+NwicyMMImJQ6ZSZgiBWx/JU0kB0Vz3Mm5t8a7aWG3/AhUSwYTwLgzbYG4MyiCfV3UAUB81yMxirGLIOqkb/CguZCrQO9/oMhTA9Ek2GkHtG6qOdDEMXSpN1StPwqgQUaSb3PgW1rlPUC3jLGPYyv2CCF3+5d3Q6RkyZaOq5jIM0uaV7sUCqinnCs78yL8yRkQAEPJTAT8oH9J0YEaempSz1df5LnluJ3r2CsFK/by8745lQlWtm8jdmRBojPG9JDrVTkO2Z/hudc1uQqz9N0X7l3VYlXSpYty4QtQMDTy3LxAzo8Ecot84Wc7kZbtXhqMKwQRGJOUSHNBEZwjAw0SwfyS0ajnCUbhw08U2UguoLzHsW0XVFQ3bc4pUr0X04vFj5/w/hVGflo9uLssHxxmdfH2WgSltEZR3yX0/T5GlDj8qctgryO06ubRYZkola0uEkTmIZWtgL4TmFAKYwPVmBQ7eHl7/nZV5PQY8p68ubQZmQTYlQEOc36+Gj2TDHCLAXF1aGPqVcsyJDHULSSQ3CT17XGJEABI5eHCEzTrsBsVywUNpBcNQItghd18IMCkv9b2gw+N0NKJJjmuyRgIF5NXOXS8XupSuvPT857eIdx7tFmmzPh+5Gu6V/8MqREYWf4281x0ydKl6Eq5oURFVqFGtAQZcizcNoBn4OMVduvBRRyb81cNrNvMcveAQTRCj4eqvP9C7cBfPByELIullTRLXwAOaoYJ0c/rimHMCNDZqwBWVw+HNo0kZmjHjT3PF/CExoLkpS0ThBV97NhiNaRuJ9U4IidKLDwE19q2ptO76WXybzKJegFycWnsUxOkxyst9Nb5ur08Z+4+i07ePNAbj6ACufdZGVmu1Vtd5cPMw9PjJyM7BcxHwF30YxlhV4M0lRkatlGleALP2CXLG994wZ+SCA1n0/09wwD11G1ibX5l4TNdFCDDRdcq7Yyb08J/JBfsAyQNJrrNdWslND8nRMdGraxycrMfkMgq4dIDgCgs++1SPri1JMyv02WeIzCGjnHnhvphMxyFbFJqRzeA1oKF3dE9w95zItNagaY9PKLyx00g1C4ViaYgkagB6gG"
|
let txBase64String =
|
||||||
|
// swiftlint:disable:next line_length
|
||||||
|
"BAAAgIUgL4kAAAAAAACz/goAECcAAAAAAAABXcTpMQ7kFhTifSbypMLlmgvAh/mR9z78+mocYt7rvJvLFjfBGp9aDf/066bWOsKt4N78Kovjr5mPuVNSMUegJuwZuAxnaO+iu+z17zABU4TUdixiCq97W74jgttjhG+Nxe+HeXvlqX7NmDJJmRO0anXaL1pBcPxOcb1pXcfO5VG1SFGLFIhLNyDlCoYa42sPHnQ4WsjMUv7Jh8rIH/tJ/vhHv9mGEg+zfld5KkMQ1JSykSen34KAPjc/em+2KMN6qAKrUWRPYlQvkz/QTxXeXI1OoCLCmqdsbHEG5ffSdmkAJfJpKfRsI04DQdTF03eVxpSVxlmz7gfeEmwVowKGV284KwmGHsnuHawjcBVb2tWIU9tBfQtONE1HgA5B6wt8ynZGSrlit0gFaTxCxzFcRmYgkgLbJeqx1lu+wUBVqAqvbkA4wGTvNX28b3SWmTx40eTu251bzqzy/Ip/7tSgh6QupSzatDF2gHcpb91EY6r3E3Jyhm2zfu38JSHTctMMArFWhOyfzBwrMPFjrLKDc9IiX7zjMBluTTMgQosb81o4ZF+2ZIKbplfugQICjuQjC5UFvihNCNF6+j8ITfwwD105VO52qVFiAdNAvCsymmPGI0Wr2w9PdBweIhUsrDLz11wi1pnydHdRwArU82CCqcVd5rwixomZrjwP8IFL0wd5CKho7QdU4rXF39VN2nffD+hwAPl0X3TCntws3/8Q1066bRTJLhaZcSzaVB0Bq0GKRAMS/WflBIlkd4KG6+/dDw01B0/lobAJIXfa+UrGKbDxXjLQlW8R8Bi9I+Y7S1h8I/gYOQiuuoCpJyV//4sKi1/zI1nnDcTu1q7P1eDYv30Y1g31FK9IWoXIQaZJ8ehKJqSx/FDBvhsEEh2aHvRolFTwHvxiVV3b9L3txePJRTEBq/RDUvW1BjAST/xfd3TTUILEZ962Ix3hu+ZfKWDSFCb/YW1fHlf98O05QunwBwDnaC3qgzNbqDjF9mldOFWZ84XE6IJVCHTN04L4hR8dl4bltpjnVnQmy34bcKLNtsFoRXot9ckOcrbX8Bf9lfneichrYtWZi6bVt6irwFo4+qXwABsUQGA2TMgsKpw9z4KysdSqoMXOEe+k/wPPQIqTPtFp4jrkMIntSokR6hRPZFdJJ23OWHjOoIKxSZUeOgkbKlqSrcQa/IHZQ8cpEof8T1PyNx/VDgEf6oIxnk2+E/iosraQpunYgAtQCm1pC8tF5oI6MshGj2nfonSug9PS2ORf0xk2RJLnSbg3kdQGx85ulMrOojkci80RIeyta3vX527MKDANTsN6W2y8fT9oDVA4l11lm4j31TyK754eTb1VPsy0YOo1L5Vr0LOOZtpF+tCaojz6Kx980jkzlEJOQ+imLERLAckclxFCWYyQ+9UOJnuXS5YCy32cdkzm17e2SwmeYGmNrTGUm6eaT0/ZqqsPAQEo+h/z4Bgt9eUEUvkRaDhz/vZjJkNfHdLA2c3CI5iTA0WUJQa5J4XNbFSQmEl4RYNHLHz0utsHcgFC9czxtDZkLcTUcQ2i/dQv07E84FhrMG5bJ818SaABpMlX99gaMYRpW3SWSuU0++/apORrIOSqonXunqroBtnAzeAIGY30ikpmkuf/BYTxAADZHCLkUBNVFmkASV91In4r6nfDbwMVOXCffBBHf2Cr/9hcd5TNL10MG0qhSsYrpv1FpCxg56hYiglS3BQ1uj63bzf4lmRbAvwXdI99lgoPQqjws3hIDIAImobsRWJoGSjT6Gq2hd40CVmmFjlXxdPpo6+m4L2PFD97LnHjF9X/VA+VWc+ihPCLrzgVl63NJcsEf/0bNt/iNWkIILM38WUSMEWj4CaSp1wI8ank+JfE7elapFRza98CGb52g+gZSkEv/xWRn/SjL3RvqQwSdWh38N/ijzpRfL48MiwYd15U7HZ2pc/0WtYVe7JSH6BHBXExBUzhqnZqRxK+1jZflKsYFbCAaZOjpeLSy5l8AvOjDfGR5+Uk+7dIs97lSGHZd+EQWgV/bmH+NwicyMMImJQ6ZSZgiBWx/JU0kB0Vz3Mm5t8a7aWG3/AhUSwYTwLgzbYG4MyiCfV3UAUB81yMxirGLIOqkb/CguZCrQO9/oMhTA9Ek2GkHtG6qOdDEMXSpN1StPwqgQUaSb3PgW1rlPUC3jLGPYyv2CCF3+5d3Q6RkyZaOq5jIM0uaV7sUCqinnCs78yL8yRkQAEPJTAT8oH9J0YEaempSz1df5LnluJ3r2CsFK/by8745lQlWtm8jdmRBojPG9JDrVTkO2Z/hudc1uQqz9N0X7l3VYlXSpYty4QtQMDTy3LxAzo8Ecot84Wc7kZbtXhqMKwQRGJOUSHNBEZwjAw0SwfyS0ajnCUbhw08U2UguoLzHsW0XVFQ3bc4pUr0X04vFj5/w/hVGflo9uLssHxxmdfH2WgSltEZR3yX0/T5GlDj8qctgryO06ubRYZkola0uEkTmIZWtgL4TmFAKYwPVmBQ7eHl7/nZV5PQY8p68ubQZmQTYlQEOc36+Gj2TDHCLAXF1aGPqVcsyJDHULSSQ3CT17XGJEABI5eHCEzTrsBsVywUNpBcNQItghd18IMCkv9b2gw+N0NKJJjmuyRgIF5NXOXS8XupSuvPT857eIdx7tFmmzPh+5Gu6V/8MqREYWf4281x0ydKl6Eq5oURFVqFGtAQZcizcNoBn4OMVduvBRRyb81cNrNvMcveAQTRCj4eqvP9C7cBfPByELIullTRLXwAOaoYJ0c/rimHMCNDZqwBWVw+HNo0kZmjHjT3PF/CExoLkpS0ThBV97NhiNaRuJ9U4IidKLDwE19q2ptO76WXybzKJegFycWnsUxOkxyst9Nb5ur08Z+4+i07ePNAbj6ACufdZGVmu1Vtd5cPMw9PjJyM7BcxHwF30YxlhV4M0lRkatlGleALP2CXLG994wZ+SCA1n0/09wwD11G1ibX5l4TNdFCDDRdcq7Yyb08J/JBfsAyQNJrrNdWslND8nRMdGraxycrMfkMgq4dIDgCgs++1SPri1JMyv02WeIzCGjnHnhvphMxyFbFJqRzeA1oKF3dE9w95zItNagaY9PKLyx00g1C4ViaYgkagB6gG"
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
basic reorg test. Scan, get a reorg and then reach latest height.
|
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
|
* 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
|
* rewind 10 blocks and request blocks 663241 to 663251
|
||||||
*/
|
*/
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional print_function_usage function_parameter_count
|
||||||
class ReOrgTests: XCTestCase {
|
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?
|
// TODO: Parameterize this from environment?
|
||||||
|
// swiftlint:disable:next line_length
|
||||||
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
|
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
|
let sendAmount: Int64 = 1000
|
||||||
var birthday: BlockHeight = 663150
|
|
||||||
let defaultLatestHeight: BlockHeight = 663175
|
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 coordinator: TestCoordinator!
|
||||||
var syncedExpectation = XCTestExpectation(description: "synced")
|
var syncedExpectation = XCTestExpectation(description: "synced")
|
||||||
var sentTransactionExpectation = XCTestExpectation(description: "sent")
|
var sentTransactionExpectation = XCTestExpectation(description: "sent")
|
||||||
var expectedReorgHeight: BlockHeight = 665188
|
var expectedReorgHeight: BlockHeight = 665188
|
||||||
var expectedRewindHeight: 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 {
|
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(
|
coordinator = try TestCoordinator(
|
||||||
seed: seedPhrase,
|
seed: seedPhrase,
|
||||||
walletBirthday: birthday,
|
walletBirthday: birthday,
|
||||||
|
@ -46,22 +60,16 @@ class ReOrgTests: XCTestCase {
|
||||||
)
|
)
|
||||||
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
|
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
|
||||||
try coordinator.resetBlocks(dataset: .default)
|
try coordinator.resetBlocks(dataset: .default)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
|
try super.tearDownWithError()
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
|
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) {
|
@objc func handleReOrgNotification(_ notification: Notification) {
|
||||||
|
|
||||||
reorgExpectation.fulfill()
|
reorgExpectation.fulfill()
|
||||||
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 {
|
let rewindHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight else {
|
||||||
|
@ -81,12 +89,14 @@ class ReOrgTests: XCTestCase {
|
||||||
let reOrgHeight = BlockHeight(663195)
|
let reOrgHeight = BlockHeight(663195)
|
||||||
let walletBirthday = WalletBirthday.birthday(with: 663150, network: network).height
|
let walletBirthday = WalletBirthday.birthday(with: 663150, network: network).height
|
||||||
|
|
||||||
try basicReOrgTest(baseDataset: .beforeReOrg,
|
try basicReOrgTest(
|
||||||
|
baseDataset: .beforeReOrg,
|
||||||
reorgDataset: .afterSmallReorg,
|
reorgDataset: .afterSmallReorg,
|
||||||
firstLatestHeight: mockLatestHeight,
|
firstLatestHeight: mockLatestHeight,
|
||||||
reorgHeight: reOrgHeight,
|
reorgHeight: reOrgHeight,
|
||||||
walletBirthday: walletBirthday,
|
walletBirthday: walletBirthday,
|
||||||
targetHeight: targetLatestHeight)
|
targetHeight: targetLatestHeight
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testTenPlusBlockReOrg() throws {
|
func testTenPlusBlockReOrg() throws {
|
||||||
|
@ -95,21 +105,24 @@ class ReOrgTests: XCTestCase {
|
||||||
let reOrgHeight = BlockHeight(663180)
|
let reOrgHeight = BlockHeight(663180)
|
||||||
let walletBirthday = WalletBirthday.birthday(with: BlockHeight(663150), network: network).height
|
let walletBirthday = WalletBirthday.birthday(with: BlockHeight(663150), network: network).height
|
||||||
|
|
||||||
try basicReOrgTest(baseDataset: .beforeReOrg,
|
try basicReOrgTest(
|
||||||
|
baseDataset: .beforeReOrg,
|
||||||
reorgDataset: .afterLargeReorg,
|
reorgDataset: .afterLargeReorg,
|
||||||
firstLatestHeight: mockLatestHeight,
|
firstLatestHeight: mockLatestHeight,
|
||||||
reorgHeight: reOrgHeight,
|
reorgHeight: reOrgHeight,
|
||||||
walletBirthday: walletBirthday,
|
walletBirthday: walletBirthday,
|
||||||
targetHeight: targetLatestHeight)
|
targetHeight: targetLatestHeight
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func basicReOrgTest(baseDataset: DarksideDataset,
|
func basicReOrgTest(
|
||||||
|
baseDataset: DarksideDataset,
|
||||||
reorgDataset: DarksideDataset,
|
reorgDataset: DarksideDataset,
|
||||||
firstLatestHeight: BlockHeight,
|
firstLatestHeight: BlockHeight,
|
||||||
reorgHeight: BlockHeight,
|
reorgHeight: BlockHeight,
|
||||||
walletBirthday: BlockHeight,
|
walletBirthday: BlockHeight,
|
||||||
targetHeight: BlockHeight) throws {
|
targetHeight: BlockHeight
|
||||||
|
) throws {
|
||||||
do {
|
do {
|
||||||
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
|
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
|
||||||
try coordinator.resetBlocks(dataset: .predefined(dataset: .beforeReOrg))
|
try coordinator.resetBlocks(dataset: .predefined(dataset: .beforeReOrg))
|
||||||
|
@ -125,8 +138,8 @@ class ReOrgTests: XCTestCase {
|
||||||
download and sync blocks from walletBirthday to firstLatestHeight
|
download and sync blocks from walletBirthday to firstLatestHeight
|
||||||
*/
|
*/
|
||||||
var synchronizer: SDKSynchronizer?
|
var synchronizer: SDKSynchronizer?
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { synchro in
|
||||||
synchronizer = s
|
synchronizer = synchro
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -136,6 +149,7 @@ class ReOrgTests: XCTestCase {
|
||||||
XCTFail("nil synchronizer")
|
XCTFail("nil synchronizer")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
verify that mock height has been reached
|
verify that mock height has been reached
|
||||||
*/
|
*/
|
||||||
|
@ -146,7 +160,6 @@ class ReOrgTests: XCTestCase {
|
||||||
/**
|
/**
|
||||||
trigger reorg!
|
trigger reorg!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try coordinator.resetBlocks(dataset: .predefined(dataset: reorgDataset))
|
try coordinator.resetBlocks(dataset: .predefined(dataset: reorgDataset))
|
||||||
try coordinator.applyStaged(blockheight: targetHeight)
|
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
|
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
|
rewind 10 blocks and request blocks targetHeight-10 to targetHeight
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let secondSyncExpectation = XCTestExpectation(description: "second sync")
|
let secondSyncExpectation = XCTestExpectation(description: "second sync")
|
||||||
|
|
||||||
sleep(2)
|
sleep(2)
|
||||||
try coordinator.sync(completion: { (_) in
|
try coordinator.sync(
|
||||||
|
completion: { _ in
|
||||||
secondSyncExpectation.fulfill()
|
secondSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
},
|
||||||
|
error: self.handleError
|
||||||
|
)
|
||||||
|
|
||||||
// now reorg should happen and reorg notifications and idle notification should be triggered
|
// 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) {
|
@objc func processorHandledReorg(_ notification: Notification) {
|
||||||
|
|
||||||
XCTAssertNotNil(notification.userInfo)
|
XCTAssertNotNil(notification.userInfo)
|
||||||
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
||||||
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
|
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
|
||||||
|
|
||||||
|
|
||||||
XCTAssertTrue( rewind <= reorg )
|
XCTAssertTrue( rewind <= reorg )
|
||||||
reorgExpectation.fulfill()
|
reorgExpectation.fulfill()
|
||||||
} else {
|
} else {
|
||||||
|
@ -195,5 +207,4 @@ class ReOrgTests: XCTestCase {
|
||||||
}
|
}
|
||||||
XCTFail("Failed with error: \(testError)")
|
XCTFail("Failed with error: \(testError)")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,24 +7,31 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable type_body_length implicitly_unwrapped_optional
|
||||||
class RewindRescanTests: XCTestCase {
|
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?
|
// TODO: Parameterize this from environment?
|
||||||
|
// swiftlint:disable:next line_length
|
||||||
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
|
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
|
let sendAmount: Int64 = 1000
|
||||||
var birthday: BlockHeight = 663150
|
|
||||||
let defaultLatestHeight: BlockHeight = 663175
|
let defaultLatestHeight: BlockHeight = 663175
|
||||||
|
let branchID = "2bb40e60"
|
||||||
|
let chainName = "main"
|
||||||
|
|
||||||
|
var birthday: BlockHeight = 663150
|
||||||
var coordinator: TestCoordinator!
|
var coordinator: TestCoordinator!
|
||||||
var syncedExpectation = XCTestExpectation(description: "synced")
|
var syncedExpectation = XCTestExpectation(description: "synced")
|
||||||
var sentTransactionExpectation = XCTestExpectation(description: "sent")
|
var sentTransactionExpectation = XCTestExpectation(description: "sent")
|
||||||
var expectedReorgHeight: BlockHeight = 665188
|
var expectedReorgHeight: BlockHeight = 665188
|
||||||
var expectedRewindHeight: BlockHeight = 665188
|
var expectedRewindHeight: BlockHeight = 665188
|
||||||
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
|
var reorgExpectation = XCTestExpectation(description: "reorg")
|
||||||
let branchID = "2bb40e60"
|
|
||||||
let chainName = "main"
|
|
||||||
var network = ZcashNetworkBuilder.network(for: .mainnet)
|
var network = ZcashNetworkBuilder.network(for: .mainnet)
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
|
try super.setUpWithError()
|
||||||
|
|
||||||
coordinator = try TestCoordinator(
|
coordinator = try TestCoordinator(
|
||||||
seed: seedPhrase,
|
seed: seedPhrase,
|
||||||
|
@ -32,23 +39,27 @@ class RewindRescanTests: XCTestCase {
|
||||||
channelProvider: ChannelProvider(),
|
channelProvider: ChannelProvider(),
|
||||||
network: network
|
network: network
|
||||||
)
|
)
|
||||||
|
|
||||||
try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main")
|
try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main")
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
|
try super.tearDownWithError()
|
||||||
|
|
||||||
NotificationCenter.default.removeObserver(self)
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func handleError(_ error: Error?) {
|
func handleError(_ error: Error?) {
|
||||||
guard let testError = error else {
|
guard let testError = error else {
|
||||||
XCTFail("failed with nil error")
|
XCTFail("failed with nil error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTFail("Failed with error: \(testError)")
|
XCTFail("Failed with error: \(testError)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +73,7 @@ class RewindRescanTests: XCTestCase {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: handleError)
|
}, error: handleError)
|
||||||
|
|
||||||
|
@ -84,7 +95,7 @@ class RewindRescanTests: XCTestCase {
|
||||||
XCTAssertEqual(initialTotalBalance, coordinator.synchronizer.initializer.getBalance())
|
XCTAssertEqual(initialTotalBalance, coordinator.synchronizer.initializer.getBalance())
|
||||||
let secondScanExpectation = XCTestExpectation(description: "rescan")
|
let secondScanExpectation = XCTestExpectation(description: "rescan")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
secondScanExpectation.fulfill()
|
secondScanExpectation.fulfill()
|
||||||
}, error: handleError)
|
}, error: handleError)
|
||||||
|
|
||||||
|
@ -93,24 +104,28 @@ class RewindRescanTests: XCTestCase {
|
||||||
// verify that the balance still adds up
|
// verify that the balance still adds up
|
||||||
XCTAssertEqual(verifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
|
XCTAssertEqual(verifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
|
||||||
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
|
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func testRescanToHeight() throws {
|
func testRescanToHeight() throws {
|
||||||
// 1 sync and get spendable funds
|
// 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
|
let newChaintTip = defaultLatestHeight + 10000
|
||||||
try coordinator.applyStaged(blockheight: newChaintTip)
|
try coordinator.applyStaged(blockheight: newChaintTip)
|
||||||
sleep(3)
|
sleep(3)
|
||||||
let initialVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
|
let initialVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
|
||||||
// let initialTotalBalance = coordinator.synchronizer.initializer.getBalance()
|
|
||||||
|
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(
|
||||||
|
completion: { _ in
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: handleError)
|
},
|
||||||
|
error: handleError
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [firstSyncExpectation], timeout: 20)
|
wait(for: [firstSyncExpectation], timeout: 20)
|
||||||
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
|
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
|
||||||
|
@ -121,23 +136,24 @@ class RewindRescanTests: XCTestCase {
|
||||||
|
|
||||||
// rewind to birthday
|
// rewind to birthday
|
||||||
let targetHeight: BlockHeight = newChaintTip - 8000
|
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))
|
try coordinator.synchronizer.rewind(.height(blockheight: targetHeight))
|
||||||
|
|
||||||
|
|
||||||
guard rewindHeight > 0 else {
|
guard rewindHeight > 0 else {
|
||||||
XCTFail("get nearest height failed error: \(ZcashRustBackend.getLastError() ?? "null")")
|
XCTFail("get nearest height failed error: \(ZcashRustBackend.getLastError() ?? "null")")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// assert that after the new height is
|
|
||||||
// XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(), BlockHeight(rewindHeight))
|
|
||||||
|
|
||||||
// check that the balance is cleared
|
// check that the balance is cleared
|
||||||
XCTAssertEqual(initialVerifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
|
XCTAssertEqual(initialVerifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
|
||||||
|
|
||||||
let secondScanExpectation = XCTestExpectation(description: "rescan")
|
let secondScanExpectation = XCTestExpectation(description: "rescan")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
secondScanExpectation.fulfill()
|
secondScanExpectation.fulfill()
|
||||||
}, error: handleError)
|
}, error: handleError)
|
||||||
|
|
||||||
|
@ -149,7 +165,13 @@ class RewindRescanTests: XCTestCase {
|
||||||
|
|
||||||
// try to spend the funds
|
// try to spend the funds
|
||||||
let sendExpectation = XCTestExpectation(description: "after rewind expectation")
|
let sendExpectation = XCTestExpectation(description: "after rewind expectation")
|
||||||
coordinator.synchronizer.sendToAddress(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()
|
sendExpectation.fulfill()
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let pendingTx):
|
case .success(let pendingTx):
|
||||||
|
@ -159,9 +181,6 @@ class RewindRescanTests: XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wait(for: [sendExpectation], timeout: 15)
|
wait(for: [sendExpectation], timeout: 15)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRescanToTransaction() throws {
|
func testRescanToTransaction() throws {
|
||||||
|
@ -173,7 +192,7 @@ class RewindRescanTests: XCTestCase {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: handleError)
|
}, error: handleError)
|
||||||
|
|
||||||
|
@ -192,13 +211,15 @@ class RewindRescanTests: XCTestCase {
|
||||||
|
|
||||||
try coordinator.synchronizer.rewind(.transaction(transaction.transactionEntity))
|
try coordinator.synchronizer.rewind(.transaction(transaction.transactionEntity))
|
||||||
|
|
||||||
|
|
||||||
// assert that after the new height is
|
// 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")
|
let secondScanExpectation = XCTestExpectation(description: "rescan")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
secondScanExpectation.fulfill()
|
secondScanExpectation.fulfill()
|
||||||
}, error: handleError)
|
}, error: handleError)
|
||||||
|
|
||||||
|
@ -207,7 +228,6 @@ class RewindRescanTests: XCTestCase {
|
||||||
// verify that the balance still adds up
|
// verify that the balance still adds up
|
||||||
XCTAssertEqual(verifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
|
XCTAssertEqual(verifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
|
||||||
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
|
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRewindAfterSendingTransaction() throws {
|
func testRewindAfterSendingTransaction() throws {
|
||||||
|
@ -225,7 +245,7 @@ class RewindRescanTests: XCTestCase {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
firstSyncExpectation.fulfill()
|
firstSyncExpectation.fulfill()
|
||||||
}, error: handleError)
|
}, error: handleError)
|
||||||
|
|
||||||
|
@ -246,11 +266,13 @@ class RewindRescanTests: XCTestCase {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var pendingTx: PendingTransactionEntity?
|
var pendingTx: PendingTransactionEntity?
|
||||||
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
|
coordinator.synchronizer.sendToAddress(
|
||||||
|
spendingKey: spendingKey,
|
||||||
zatoshi: maxBalance,
|
zatoshi: maxBalance,
|
||||||
toAddress: testRecipientAddress,
|
toAddress: testRecipientAddress,
|
||||||
memo: "test send \(self.description) \(Date().description)",
|
memo: "test send \(self.description) \(Date().description)",
|
||||||
from: 0) { result in
|
from: 0
|
||||||
|
) { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
XCTFail("sendToAddress failed: \(error)")
|
XCTFail("sendToAddress failed: \(error)")
|
||||||
|
@ -265,14 +287,13 @@ class RewindRescanTests: XCTestCase {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationHandler.synchronizerMinedTransaction = { tx in
|
notificationHandler.synchronizerMinedTransaction = { transaction in
|
||||||
XCTAssertNotNil(tx.rawTransactionId)
|
XCTAssertNotNil(transaction.rawTransactionId)
|
||||||
XCTAssertNotNil(pendingTx.rawTransactionId)
|
XCTAssertNotNil(pendingTx.rawTransactionId)
|
||||||
XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId)
|
XCTAssertEqual(transaction.rawTransactionId, pendingTx.rawTransactionId)
|
||||||
transactionMinedExpectation.fulfill()
|
transactionMinedExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 5 apply to height
|
// 5 apply to height
|
||||||
// 6 mine the block
|
// 6 mine the block
|
||||||
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
|
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
|
||||||
|
@ -296,24 +317,26 @@ class RewindRescanTests: XCTestCase {
|
||||||
try coordinator.applyStaged(blockheight: sentTxHeight)
|
try coordinator.applyStaged(blockheight: sentTxHeight)
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
|
|
||||||
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(
|
||||||
let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId})
|
completion: { synchronizer in
|
||||||
XCTAssertNotNil(p, "pending transaction should have been mined by now")
|
let pendingTransaction = synchronizer.pendingTransactions
|
||||||
XCTAssertTrue(p?.isMined ?? false)
|
.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
|
||||||
XCTAssertEqual(p?.minedHeight, sentTxHeight)
|
XCTAssertNotNil(pendingTransaction, "pending transaction should have been mined by now")
|
||||||
|
XCTAssertTrue(pendingTransaction?.isMined ?? false)
|
||||||
|
XCTAssertEqual(pendingTransaction?.minedHeight, sentTxHeight)
|
||||||
mineExpectation.fulfill()
|
mineExpectation.fulfill()
|
||||||
|
},
|
||||||
}, error: { (error) in
|
error: { error in
|
||||||
guard let e = error else {
|
guard let e = error else {
|
||||||
XCTFail("unknown error syncing after sending transaction")
|
XCTFail("unknown error syncing after sending transaction")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTFail("Error: \(e)")
|
XCTFail("Error: \(e)")
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
|
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
|
||||||
|
|
||||||
|
@ -327,36 +350,45 @@ class RewindRescanTests: XCTestCase {
|
||||||
|
|
||||||
try coordinator.synchronizer.rewind(.height(blockheight: sentTxHeight - 5))
|
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")
|
XCTFail("sent pending transaction not found after rewind")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertFalse(np.isMined)
|
XCTAssertFalse(pendingEntity.isMined)
|
||||||
|
|
||||||
let confirmExpectation = XCTestExpectation(description: "confirm expectation")
|
let confirmExpectation = XCTestExpectation(description: "confirm expectation")
|
||||||
notificationHandler.transactionsFound = { txs in
|
notificationHandler.transactionsFound = { txs in
|
||||||
XCTAssertEqual(txs.count, 1)
|
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")
|
XCTFail("should have found sent transaction but didn't")
|
||||||
return
|
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()
|
confirmExpectation.fulfill()
|
||||||
}, error: { e in
|
},
|
||||||
|
error: { e in
|
||||||
self.handleError(e)
|
self.handleError(e)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [confirmExpectation], timeout: 10)
|
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")
|
XCTAssertNil(confirmedPending, "pending, now confirmed transaction found")
|
||||||
|
|
||||||
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), 0)
|
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), 0)
|
||||||
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 0)
|
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,26 +7,32 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional
|
||||||
class SychronizerDarksideTests: XCTestCase {
|
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?
|
// TODO: Parameterize this from environment?
|
||||||
|
// swiftlint:disable:next line_length
|
||||||
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
|
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
|
let sendAmount: Int64 = 1000
|
||||||
var birthday: BlockHeight = 663150
|
|
||||||
let defaultLatestHeight: BlockHeight = 663175
|
let defaultLatestHeight: BlockHeight = 663175
|
||||||
|
let branchID = "2bb40e60"
|
||||||
|
let chainName = "main"
|
||||||
|
let network = DarksideWalletDNetwork()
|
||||||
|
|
||||||
|
var birthday: BlockHeight = 663150
|
||||||
var coordinator: TestCoordinator!
|
var coordinator: TestCoordinator!
|
||||||
var syncedExpectation = XCTestExpectation(description: "synced")
|
var syncedExpectation = XCTestExpectation(description: "synced")
|
||||||
var sentTransactionExpectation = XCTestExpectation(description: "sent")
|
var sentTransactionExpectation = XCTestExpectation(description: "sent")
|
||||||
var expectedReorgHeight: BlockHeight = 665188
|
var expectedReorgHeight: BlockHeight = 665188
|
||||||
var expectedRewindHeight: BlockHeight = 665188
|
var expectedRewindHeight: BlockHeight = 665188
|
||||||
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
|
var reorgExpectation = XCTestExpectation(description: "reorg")
|
||||||
let branchID = "2bb40e60"
|
var foundTransactions: [ConfirmedTransactionEntity] = []
|
||||||
let chainName = "main"
|
|
||||||
let network = DarksideWalletDNetwork()
|
|
||||||
var foundTransactions = [ConfirmedTransactionEntity]()
|
|
||||||
override func setUpWithError() throws {
|
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
try super.setUpWithError()
|
||||||
coordinator = try TestCoordinator(
|
coordinator = try TestCoordinator(
|
||||||
seed: seedPhrase,
|
seed: seedPhrase,
|
||||||
walletBirthday: birthday,
|
walletBirthday: birthday,
|
||||||
|
@ -37,6 +43,7 @@ class SychronizerDarksideTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
|
try super.tearDownWithError()
|
||||||
NotificationCenter.default.removeObserver(self)
|
NotificationCenter.default.removeObserver(self)
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
||||||
|
@ -45,20 +52,22 @@ class SychronizerDarksideTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFoundTransactions() throws {
|
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)
|
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName)
|
||||||
let receivedTxHeight: BlockHeight = 663188
|
let receivedTxHeight: BlockHeight = 663188
|
||||||
|
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: receivedTxHeight + 1)
|
try coordinator.applyStaged(blockheight: receivedTxHeight + 1)
|
||||||
|
|
||||||
sleep(2)
|
sleep(2)
|
||||||
let preTxExpectation = XCTestExpectation(description: "pre receive")
|
let preTxExpectation = XCTestExpectation(description: "pre receive")
|
||||||
|
|
||||||
|
try coordinator.sync(completion: { _ in
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
|
||||||
|
|
||||||
preTxExpectation.fulfill()
|
preTxExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -68,20 +77,22 @@ class SychronizerDarksideTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFoundManyTransactions() throws {
|
func testFoundManyTransactions() throws {
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(handleFoundTransactions(_:)), name: Notification.Name.synchronizerFoundTransactions, object: nil)
|
NotificationCenter.default.addObserver(
|
||||||
|
self,
|
||||||
|
selector: #selector(handleFoundTransactions(_:)),
|
||||||
|
name: Notification.Name.synchronizerFoundTransactions,
|
||||||
|
object: nil
|
||||||
|
)
|
||||||
|
|
||||||
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName, length: 1000)
|
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName, length: 1000)
|
||||||
let receivedTxHeight: BlockHeight = 663229
|
let receivedTxHeight: BlockHeight = 663229
|
||||||
|
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: receivedTxHeight + 1)
|
try coordinator.applyStaged(blockheight: receivedTxHeight + 1)
|
||||||
|
|
||||||
sleep(2)
|
sleep(2)
|
||||||
let firsTxExpectation = XCTestExpectation(description: "first sync")
|
let firsTxExpectation = XCTestExpectation(description: "first sync")
|
||||||
|
|
||||||
|
try coordinator.sync(completion: { _ in
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
|
||||||
|
|
||||||
firsTxExpectation.fulfill()
|
firsTxExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
@ -96,35 +107,33 @@ class SychronizerDarksideTests: XCTestCase {
|
||||||
|
|
||||||
let preTxExpectation = XCTestExpectation(description: "intermediate sync")
|
let preTxExpectation = XCTestExpectation(description: "intermediate sync")
|
||||||
|
|
||||||
|
try coordinator.sync(completion: { _ in
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
|
||||||
|
|
||||||
preTxExpectation.fulfill()
|
preTxExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [preTxExpectation], timeout: 10)
|
wait(for: [preTxExpectation], timeout: 10)
|
||||||
|
|
||||||
XCTAssertTrue(self.foundTransactions.count == 0)
|
XCTAssertTrue(self.foundTransactions.isEmpty)
|
||||||
|
|
||||||
let findManyTxExpectation = XCTestExpectation(description: "final sync")
|
let findManyTxExpectation = XCTestExpectation(description: "final sync")
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: 664010)
|
try coordinator.applyStaged(blockheight: 664010)
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { _ in
|
||||||
|
|
||||||
findManyTxExpectation.fulfill()
|
findManyTxExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
wait(for: [findManyTxExpectation], timeout: 10)
|
wait(for: [findManyTxExpectation], timeout: 10)
|
||||||
|
|
||||||
XCTAssertEqual(self.foundTransactions.count, 2)
|
XCTAssertEqual(self.foundTransactions.count, 2)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func handleFoundTransactions(_ notification: Notification) {
|
@objc func handleFoundTransactions(_ notification: Notification) {
|
||||||
guard let userInfo = notification.userInfo,
|
guard
|
||||||
let transactions = userInfo[SDKSynchronizer.NotificationKeys.foundTransactions] as? [ConfirmedTransactionEntity] else {
|
let userInfo = notification.userInfo,
|
||||||
|
let transactions = userInfo[SDKSynchronizer.NotificationKeys.foundTransactions] as? [ConfirmedTransactionEntity]
|
||||||
|
else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.foundTransactions.append(contentsOf: transactions)
|
self.foundTransactions.append(contentsOf: transactions)
|
||||||
|
|
|
@ -14,8 +14,8 @@ import Foundation
|
||||||
Is it a nice "SOLID" "Clean Code" piece of source code?
|
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.
|
Hell no. It's your testing overlord and you will be grateful it is.
|
||||||
*/
|
*/
|
||||||
|
// swiftlint:disable force_try function_parameter_count
|
||||||
class TestCoordinator {
|
class TestCoordinator {
|
||||||
|
|
||||||
enum CoordinatorError: Error {
|
enum CoordinatorError: Error {
|
||||||
case notDarksideWallet
|
case notDarksideWallet
|
||||||
case notificationFromUnknownSynchronizer
|
case notificationFromUnknownSynchronizer
|
||||||
|
@ -44,22 +44,43 @@ class TestCoordinator {
|
||||||
var spendingKeys: [String]?
|
var spendingKeys: [String]?
|
||||||
var databases: TemporaryTestDatabases
|
var databases: TemporaryTestDatabases
|
||||||
let network: ZcashNetwork
|
let network: ZcashNetwork
|
||||||
convenience init(seed: String,
|
convenience init(
|
||||||
|
seed: String,
|
||||||
walletBirthday: BlockHeight,
|
walletBirthday: BlockHeight,
|
||||||
channelProvider: ChannelProvider,
|
channelProvider: ChannelProvider,
|
||||||
network: ZcashNetwork) throws {
|
network: ZcashNetwork
|
||||||
|
) throws {
|
||||||
let derivationTool = DerivationTool(networkType: network.networkType)
|
let derivationTool = DerivationTool(networkType: network.networkType)
|
||||||
guard let spendingKey = try derivationTool.deriveSpendingKeys(
|
|
||||||
|
guard
|
||||||
|
let spendingKey = try derivationTool
|
||||||
|
.deriveSpendingKeys(
|
||||||
seed: TestSeed().seed(),
|
seed: TestSeed().seed(),
|
||||||
numberOfAccounts: 1).first else {
|
numberOfAccounts: 1
|
||||||
|
)
|
||||||
|
.first
|
||||||
|
else {
|
||||||
throw CoordinatorError.builderError
|
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
|
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(
|
required init(
|
||||||
|
@ -67,13 +88,22 @@ class TestCoordinator {
|
||||||
unifiedViewingKey: UnifiedViewingKey,
|
unifiedViewingKey: UnifiedViewingKey,
|
||||||
walletBirthday: BlockHeight,
|
walletBirthday: BlockHeight,
|
||||||
channelProvider: ChannelProvider,
|
channelProvider: ChannelProvider,
|
||||||
network: ZcashNetwork) throws {
|
network: ZcashNetwork
|
||||||
|
) throws {
|
||||||
self.spendingKey = spendingKey
|
self.spendingKey = spendingKey
|
||||||
self.birthday = walletBirthday
|
self.birthday = walletBirthday
|
||||||
self.channelProvider = channelProvider
|
self.channelProvider = channelProvider
|
||||||
self.databases = TemporaryDbBuilder.build()
|
self.databases = TemporaryDbBuilder.build()
|
||||||
self.network = network
|
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)
|
let storage = CompactBlockStorage(url: databases.cacheDB, readonly: false)
|
||||||
try storage.createTable()
|
try storage.createTable()
|
||||||
|
|
||||||
|
@ -86,8 +116,10 @@ class TestCoordinator {
|
||||||
endpoint: LightWalletEndpointBuilder.default,
|
endpoint: LightWalletEndpointBuilder.default,
|
||||||
service: self.service,
|
service: self.service,
|
||||||
repository: TransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: databases.dataDB.absoluteString)),
|
repository: TransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: databases.dataDB.absoluteString)),
|
||||||
accountRepository: AccountRepositoryBuilder.build(dataDbURL: databases.dataDB,
|
accountRepository: AccountRepositoryBuilder.build(
|
||||||
readOnly: true),
|
dataDbURL: databases.dataDB,
|
||||||
|
readOnly: true
|
||||||
|
),
|
||||||
storage: storage,
|
storage: storage,
|
||||||
spendParamsURL: try __spendParamsURL(),
|
spendParamsURL: try __spendParamsURL(),
|
||||||
outputParamsURL: try __outputParamsURL(),
|
outputParamsURL: try __outputParamsURL(),
|
||||||
|
@ -95,7 +127,8 @@ class TestCoordinator {
|
||||||
unifiedViewingKey: unifiedViewingKey,
|
unifiedViewingKey: unifiedViewingKey,
|
||||||
walletBirthday: WalletBirthday.birthday(with: birthday, network: network),
|
walletBirthday: WalletBirthday.birthday(with: birthday, network: network),
|
||||||
network: network,
|
network: network,
|
||||||
loggerProxy: SampleLogger(logLevel: .debug))
|
loggerProxy: SampleLogger(logLevel: .debug)
|
||||||
|
)
|
||||||
|
|
||||||
self.synchronizer = buildResult.synchronizer
|
self.synchronizer = buildResult.synchronizer
|
||||||
self.spendingKeys = buildResult.spendingKeys
|
self.spendingKeys = buildResult.spendingKeys
|
||||||
|
@ -130,15 +163,12 @@ class TestCoordinator {
|
||||||
try synchronizer.start(retry: true)
|
try synchronizer.start(retry: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Notifications
|
Notifications
|
||||||
*/
|
*/
|
||||||
func subscribeToNotifications(synchronizer: Synchronizer) {
|
func subscribeToNotifications(synchronizer: Synchronizer) {
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(synchronizerFailed(_:)), name: .synchronizerFailed, object: synchronizer)
|
NotificationCenter.default.addObserver(self, selector: #selector(synchronizerFailed(_:)), name: .synchronizerFailed, object: synchronizer)
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(synchronizerSynced(_:)), name: .synchronizerSynced, object: synchronizer)
|
NotificationCenter.default.addObserver(self, selector: #selector(synchronizerSynced(_:)), name: .synchronizerSynced, object: synchronizer)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func synchronizerFailed(_ notification: Notification) {
|
@objc func synchronizerFailed(_ notification: Notification) {
|
||||||
|
@ -172,7 +202,6 @@ class TestCoordinator {
|
||||||
|
|
||||||
extension TestCoordinator {
|
extension TestCoordinator {
|
||||||
func resetBlocks(dataset: DarksideData) throws {
|
func resetBlocks(dataset: DarksideData) throws {
|
||||||
|
|
||||||
switch dataset {
|
switch dataset {
|
||||||
case .default:
|
case .default:
|
||||||
try service.useDataset(DarksideDataset.beforeReOrg.rawValue)
|
try service.useDataset(DarksideDataset.beforeReOrg.rawValue)
|
||||||
|
@ -191,8 +220,8 @@ extension TestCoordinator {
|
||||||
try service.applyStaged(nextLatestHeight: blockheight)
|
try service.applyStaged(nextLatestHeight: blockheight)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stageTransaction(_ tx: RawTransaction, at height: BlockHeight) throws {
|
func stageTransaction(_ transaction: RawTransaction, at height: BlockHeight) throws {
|
||||||
try service.stageTransaction(tx, at: height)
|
try service.stageTransaction(transaction, at: height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stageTransaction(url: String, at height: BlockHeight) throws {
|
func stageTransaction(url: String, at height: BlockHeight) throws {
|
||||||
|
@ -206,7 +235,6 @@ extension TestCoordinator {
|
||||||
func reset(saplingActivation: BlockHeight, branchID: String, chainName: String) throws {
|
func reset(saplingActivation: BlockHeight, branchID: String, chainName: String) throws {
|
||||||
let config = self.synchronizer.blockProcessor.config
|
let config = self.synchronizer.blockProcessor.config
|
||||||
|
|
||||||
|
|
||||||
self.synchronizer.blockProcessor.config = CompactBlockProcessor.Configuration(
|
self.synchronizer.blockProcessor.config = CompactBlockProcessor.Configuration(
|
||||||
cacheDb: config.cacheDb,
|
cacheDb: config.cacheDb,
|
||||||
dataDb: config.dataDb,
|
dataDb: config.dataDb,
|
||||||
|
@ -216,7 +244,8 @@ extension TestCoordinator {
|
||||||
rewindDistance: config.rewindDistance,
|
rewindDistance: config.rewindDistance,
|
||||||
walletBirthday: config.walletBirthday,
|
walletBirthday: config.walletBirthday,
|
||||||
saplingActivation: config.saplingActivation,
|
saplingActivation: config.saplingActivation,
|
||||||
network: config.network)
|
network: config.network
|
||||||
|
)
|
||||||
try service.reset(saplingActivation: saplingActivation, branchID: branchID, chainName: chainName)
|
try service.reset(saplingActivation: saplingActivation, branchID: branchID, chainName: chainName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,19 +260,20 @@ struct TemporaryTestDatabases {
|
||||||
var pendingDB: URL
|
var pendingDB: URL
|
||||||
}
|
}
|
||||||
|
|
||||||
class TemporaryDbBuilder {
|
enum TemporaryDbBuilder {
|
||||||
|
|
||||||
static func build() -> TemporaryTestDatabases {
|
static func build() -> TemporaryTestDatabases {
|
||||||
let tempUrl = try! __documentsDirectory()
|
let tempUrl = try! __documentsDirectory()
|
||||||
let timestamp = String(Int(Date().timeIntervalSince1970))
|
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"),
|
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(
|
static func build(
|
||||||
rustBackend: ZcashRustBackendWelding.Type,
|
rustBackend: ZcashRustBackendWelding.Type,
|
||||||
lowerBoundHeight: BlockHeight,
|
lowerBoundHeight: BlockHeight,
|
||||||
|
@ -281,6 +311,7 @@ class TestSynchronizerBuilder {
|
||||||
walletBirthday: walletBirthday.height,
|
walletBirthday: walletBirthday.height,
|
||||||
loggerProxy: loggerProxy
|
loggerProxy: loggerProxy
|
||||||
)
|
)
|
||||||
|
|
||||||
let config = CompactBlockProcessor.Configuration(
|
let config = CompactBlockProcessor.Configuration(
|
||||||
cacheDb: initializer.cacheDbURL,
|
cacheDb: initializer.cacheDbURL,
|
||||||
dataDb: initializer.dataDbURL,
|
dataDb: initializer.dataDbURL,
|
||||||
|
@ -290,17 +321,20 @@ class TestSynchronizerBuilder {
|
||||||
rewindDistance: ZcashSDK.defaultRewindDistance,
|
rewindDistance: ZcashSDK.defaultRewindDistance,
|
||||||
walletBirthday: walletBirthday.height,
|
walletBirthday: walletBirthday.height,
|
||||||
saplingActivation: lowerBoundHeight,
|
saplingActivation: lowerBoundHeight,
|
||||||
network: network)
|
network: network
|
||||||
|
)
|
||||||
|
|
||||||
let processor = CompactBlockProcessor(service: service,
|
let processor = CompactBlockProcessor(
|
||||||
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: rustBackend,
|
backend: rustBackend,
|
||||||
config: config,
|
config: config,
|
||||||
repository: repository,
|
repository: repository,
|
||||||
accountRepository: accountRepository)
|
accountRepository: accountRepository
|
||||||
|
)
|
||||||
|
|
||||||
|
let synchronizer = try SDKSynchronizer(
|
||||||
let synchronizer = try SDKSynchronizer(status: .unprepared,
|
status: .unprepared,
|
||||||
initializer: initializer,
|
initializer: initializer,
|
||||||
transactionManager: OutboundTransactionManagerBuilder.build(initializer: initializer),
|
transactionManager: OutboundTransactionManagerBuilder.build(initializer: initializer),
|
||||||
transactionRepository: repository,
|
transactionRepository: repository,
|
||||||
|
@ -312,6 +346,7 @@ class TestSynchronizerBuilder {
|
||||||
|
|
||||||
return ([spendingKey], synchronizer)
|
return ([spendingKey], synchronizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func build(
|
static func build(
|
||||||
rustBackend: ZcashRustBackendWelding.Type,
|
rustBackend: ZcashRustBackendWelding.Type,
|
||||||
lowerBoundHeight: BlockHeight,
|
lowerBoundHeight: BlockHeight,
|
||||||
|
@ -330,14 +365,23 @@ class TestSynchronizerBuilder {
|
||||||
network: ZcashNetwork,
|
network: ZcashNetwork,
|
||||||
loggerProxy: Logger? = nil
|
loggerProxy: Logger? = nil
|
||||||
) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) {
|
) 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
|
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
|
throw TestCoordinator.CoordinatorError.builderError
|
||||||
}
|
}
|
||||||
return try build(rustBackend: rustBackend,
|
|
||||||
|
return try build(
|
||||||
|
rustBackend: rustBackend,
|
||||||
lowerBoundHeight: lowerBoundHeight,
|
lowerBoundHeight: lowerBoundHeight,
|
||||||
cacheDbURL: cacheDbURL,
|
cacheDbURL: cacheDbURL,
|
||||||
dataDbURL: dataDbURL,
|
dataDbURL: dataDbURL,
|
||||||
|
@ -352,8 +396,7 @@ class TestSynchronizerBuilder {
|
||||||
spendingKey: spendingKey,
|
spendingKey: spendingKey,
|
||||||
unifiedViewingKey: uvk,
|
unifiedViewingKey: uvk,
|
||||||
walletBirthday: walletBirthday,
|
walletBirthday: walletBirthday,
|
||||||
network: network)
|
network: network
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,16 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional force_try
|
||||||
class TransactionEnhancementTests: XCTestCase {
|
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 initializer: Initializer!
|
||||||
var processorConfig: CompactBlockProcessor.Configuration!
|
var processorConfig: CompactBlockProcessor.Configuration!
|
||||||
var processor: CompactBlockProcessor!
|
var processor: CompactBlockProcessor!
|
||||||
|
@ -23,26 +32,26 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
var afterReorgIdleNotification: XCTestExpectation!
|
var afterReorgIdleNotification: XCTestExpectation!
|
||||||
var txFoundNotificationExpectation: XCTestExpectation!
|
var txFoundNotificationExpectation: XCTestExpectation!
|
||||||
var waitExpectation: 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 {
|
override func setUpWithError() throws {
|
||||||
|
try super.setUpWithError()
|
||||||
logger = SampleLogger(logLevel: .debug)
|
logger = SampleLogger(logLevel: .debug)
|
||||||
|
|
||||||
downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect")
|
downloadStartedExpect = XCTestExpectation(description: "\(self.description) downloadStartedExpect")
|
||||||
stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation")
|
stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation")
|
||||||
updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation")
|
updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation")
|
||||||
startedValidatingNotificationExpectation = XCTestExpectation(description: self.description + " startedValidatingNotificationExpectation")
|
startedValidatingNotificationExpectation = XCTestExpectation(
|
||||||
startedScanningNotificationExpectation = XCTestExpectation(description: self.description + " startedScanningNotificationExpectation")
|
description: "\(self.description) startedValidatingNotificationExpectation"
|
||||||
idleNotificationExpectation = XCTestExpectation(description: self.description + " idleNotificationExpectation")
|
)
|
||||||
afterReorgIdleNotification = XCTestExpectation(description: self.description + " afterReorgIdleNotification")
|
startedScanningNotificationExpectation = XCTestExpectation(
|
||||||
reorgNotificationExpectation = XCTestExpectation(description: self.description + " reorgNotificationExpectation")
|
description: "\(self.description) startedScanningNotificationExpectation"
|
||||||
txFoundNotificationExpectation = XCTestExpectation(description: self.description + "txFoundNotificationExpectation")
|
)
|
||||||
|
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)
|
let birthday = WalletBirthday.birthday(with: walletBirthday, network: network)
|
||||||
|
|
||||||
|
@ -50,14 +59,19 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
let rustBackend = ZcashRustBackend.self
|
let rustBackend = ZcashRustBackend.self
|
||||||
processorConfig = config
|
processorConfig = config
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try? FileManager.default.removeItem(at: processorConfig.cacheDb)
|
try? FileManager.default.removeItem(at: processorConfig.cacheDb)
|
||||||
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
||||||
|
|
||||||
_ = rustBackend.initAccountsTable(dbData: processorConfig.dataDb, seed: TestSeed().seed(), accounts: 1, networkType: network.networkType)
|
_ = rustBackend.initAccountsTable(dbData: processorConfig.dataDb, seed: TestSeed().seed(), accounts: 1, networkType: network.networkType)
|
||||||
_ = try rustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: network.networkType)
|
_ = try rustBackend.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()
|
let service = DarksideWalletService()
|
||||||
darksideWalletService = service
|
darksideWalletService = service
|
||||||
|
@ -65,17 +79,23 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
try! storage.createTable()
|
try! storage.createTable()
|
||||||
|
|
||||||
downloader = CompactBlockDownloader(service: service, storage: storage)
|
downloader = CompactBlockDownloader(service: service, storage: storage)
|
||||||
processor = CompactBlockProcessor(service: service,
|
processor = CompactBlockProcessor(
|
||||||
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: rustBackend,
|
backend: rustBackend,
|
||||||
config: processorConfig)
|
config: processorConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(
|
||||||
|
self,
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(processorFailed(_:)), name: Notification.Name.blockProcessorFailed, object: processor)
|
selector: #selector(processorFailed(_:)),
|
||||||
|
name: Notification.Name.blockProcessorFailed,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
|
try super.tearDownWithError()
|
||||||
try? FileManager.default.removeItem(at: processorConfig.cacheDb)
|
try? FileManager.default.removeItem(at: processorConfig.cacheDb)
|
||||||
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
||||||
downloadStartedExpect.unsubscribeFromNotifications()
|
downloadStartedExpect.unsubscribeFromNotifications()
|
||||||
|
@ -89,7 +109,7 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
NotificationCenter.default.removeObserver(self)
|
NotificationCenter.default.removeObserver(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func startProcessing() throws {
|
private func startProcessing() throws {
|
||||||
XCTAssertNotNil(processor)
|
XCTAssertNotNil(processor)
|
||||||
|
|
||||||
// Subscribe to notifications
|
// Subscribe to notifications
|
||||||
|
@ -99,12 +119,10 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
startedValidatingNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedValidating, object: processor)
|
startedValidatingNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedValidating, object: processor)
|
||||||
startedScanningNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedScanning, object: processor)
|
startedScanningNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedScanning, object: processor)
|
||||||
|
|
||||||
|
|
||||||
try processor.start()
|
try processor.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBasicEnhacement() throws {
|
func testBasicEnhacement() throws {
|
||||||
|
|
||||||
let targetLatestHeight = BlockHeight(663250)
|
let targetLatestHeight = BlockHeight(663250)
|
||||||
let walletBirthday = WalletBirthday.birthday(with: 663151, network: network).height
|
let walletBirthday = WalletBirthday.birthday(with: 663151, network: network).height
|
||||||
|
|
||||||
|
@ -112,7 +130,6 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func basicEnhancementTest(latestHeight: BlockHeight, walletBirthday: BlockHeight) throws {
|
func basicEnhancementTest(latestHeight: BlockHeight, walletBirthday: BlockHeight) throws {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try darksideWalletService.reset(saplingActivation: 663150, branchID: branchID, chainName: chainName)
|
try darksideWalletService.reset(saplingActivation: 663150, branchID: branchID, chainName: chainName)
|
||||||
try darksideWalletService.useDataset(DarksideDataset.beforeReOrg.rawValue)
|
try darksideWalletService.useDataset(DarksideDataset.beforeReOrg.rawValue)
|
||||||
|
@ -123,36 +140,38 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep(3)
|
sleep(3)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
connect to dLWD
|
connect to dLWD
|
||||||
request latest height -> receive firstLatestHeight
|
request latest height -> receive firstLatestHeight
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
print("first latest height: \(try darksideWalletService.latestBlockHeight())")
|
dump("first latest height: \(try darksideWalletService.latestBlockHeight())")
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("Error: \(error)")
|
XCTFail("Error: \(error)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
download and sync blocks from walletBirthday to firstLatestHeight
|
download and sync blocks from walletBirthday to firstLatestHeight
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
|
|
||||||
try startProcessing()
|
try startProcessing()
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("Error: \(error)")
|
XCTFail("Error: \(error)")
|
||||||
}
|
}
|
||||||
|
|
||||||
wait(for: [downloadStartedExpect,
|
wait(
|
||||||
|
for: [
|
||||||
|
downloadStartedExpect,
|
||||||
startedValidatingNotificationExpectation,
|
startedValidatingNotificationExpectation,
|
||||||
startedScanningNotificationExpectation,
|
startedScanningNotificationExpectation,
|
||||||
txFoundNotificationExpectation,
|
txFoundNotificationExpectation,
|
||||||
idleNotificationExpectation], timeout: 30)
|
idleNotificationExpectation
|
||||||
|
],
|
||||||
|
timeout: 30
|
||||||
|
)
|
||||||
idleNotificationExpectation.unsubscribeFromNotifications()
|
idleNotificationExpectation.unsubscribeFromNotifications()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func processorFailed(_ notification: Notification) {
|
@objc func processorFailed(_ notification: Notification) {
|
||||||
|
@ -163,6 +182,4 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
XCTFail("CompactBlockProcessor failed")
|
XCTFail("CompactBlockProcessor failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,15 +7,18 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
class TransactionRepositoryTests: XCTestCase {
|
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional force_unwrapping
|
||||||
|
class TransactionRepositoryTests: XCTestCase {
|
||||||
var transactionRepository: TransactionRepository!
|
var transactionRepository: TransactionRepository!
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
transactionRepository = TestDbBuilder.transactionRepository()
|
transactionRepository = TestDbBuilder.transactionRepository()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
|
super.tearDown()
|
||||||
transactionRepository = nil
|
transactionRepository = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +27,6 @@ class TransactionRepositoryTests: XCTestCase {
|
||||||
XCTAssertNoThrow(try { count = try self.transactionRepository.countAll() }())
|
XCTAssertNoThrow(try { count = try self.transactionRepository.countAll() }())
|
||||||
XCTAssertNotNil(count)
|
XCTAssertNotNil(count)
|
||||||
XCTAssertEqual(count, 27)
|
XCTAssertEqual(count, 27)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCountUnmined() {
|
func testCountUnmined() {
|
||||||
|
@ -35,9 +37,9 @@ class TransactionRepositoryTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFindById() {
|
func testFindById() {
|
||||||
var tx: TransactionEntity?
|
var transaction: TransactionEntity?
|
||||||
XCTAssertNoThrow(try { tx = try self.transactionRepository.findBy(id: 10)}())
|
XCTAssertNoThrow(try { transaction = try self.transactionRepository.findBy(id: 10) }())
|
||||||
guard let transaction = tx else {
|
guard let transaction = transaction else {
|
||||||
XCTFail("transaction is nil")
|
XCTFail("transaction is nil")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -45,16 +47,18 @@ class TransactionRepositoryTests: XCTestCase {
|
||||||
XCTAssertEqual(transaction.id, 10)
|
XCTAssertEqual(transaction.id, 10)
|
||||||
XCTAssertEqual(transaction.minedHeight, 652812)
|
XCTAssertEqual(transaction.minedHeight, 652812)
|
||||||
XCTAssertEqual(transaction.transactionIndex, 5)
|
XCTAssertEqual(transaction.transactionIndex, 5)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFindByTxId() {
|
func testFindByTxId() {
|
||||||
var tx: TransactionEntity?
|
var transaction: TransactionEntity?
|
||||||
|
|
||||||
let id = Data(fromHexEncodedString: "0BAFC5B83F5B39A5270144ECD98DBC65115055927EDDA8FF20F081FFF13E4780")!
|
let id = Data(fromHexEncodedString: "0BAFC5B83F5B39A5270144ECD98DBC65115055927EDDA8FF20F081FFF13E4780")!
|
||||||
|
|
||||||
XCTAssertNoThrow(try { tx = try self.transactionRepository.findBy(rawId: id)}())
|
XCTAssertNoThrow(
|
||||||
guard let transaction = tx else {
|
try { transaction = try self.transactionRepository.findBy(rawId: id) }()
|
||||||
|
)
|
||||||
|
|
||||||
|
guard let transaction = transaction else {
|
||||||
XCTFail("transaction is nil")
|
XCTFail("transaction is nil")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -111,7 +115,8 @@ class TransactionRepositoryTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFindAllFrom() throws {
|
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)
|
let allFromNil = try self.transactionRepository.findAll(from: nil, limit: Int.max)
|
||||||
else {
|
else {
|
||||||
return XCTFail("find all failed")
|
return XCTFail("find all failed")
|
||||||
|
@ -119,8 +124,8 @@ class TransactionRepositoryTests: XCTestCase {
|
||||||
|
|
||||||
XCTAssertEqual(transactions.count, allFromNil.count)
|
XCTAssertEqual(transactions.count, allFromNil.count)
|
||||||
|
|
||||||
for t in transactions {
|
for transaction in transactions {
|
||||||
guard allFromNil.first(where: { $0.rawTransactionId == t.rawTransactionId}) != nil else {
|
guard allFromNil.first(where: { $0.rawTransactionId == transaction.rawTransactionId }) != nil else {
|
||||||
XCTFail("not equal")
|
XCTFail("not equal")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -128,10 +133,10 @@ class TransactionRepositoryTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFindAllFromSlice() throws {
|
func testFindAllFromSlice() throws {
|
||||||
|
|
||||||
let limit = 4
|
let limit = 4
|
||||||
let start = 7
|
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)
|
let allFromNil = try self.transactionRepository.findAll(from: transactions[start], limit: limit)
|
||||||
else {
|
else {
|
||||||
return XCTFail("find all failed")
|
return XCTFail("find all failed")
|
||||||
|
@ -141,20 +146,19 @@ class TransactionRepositoryTests: XCTestCase {
|
||||||
|
|
||||||
let slice = transactions[start + 1 ... start + limit]
|
let slice = transactions[start + 1 ... start + limit]
|
||||||
XCTAssertEqual(slice.count, allFromNil.count)
|
XCTAssertEqual(slice.count, allFromNil.count)
|
||||||
for t in slice {
|
for transaction in slice {
|
||||||
guard allFromNil.first(where: { $0.rawTransactionId == t.rawTransactionId}) != nil else {
|
guard allFromNil.first(where: { $0.rawTransactionId == transaction.rawTransactionId }) != nil else {
|
||||||
XCTFail("not equal")
|
XCTFail("not equal")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func testFindAllFromLastSlice() throws {
|
func testFindAllFromLastSlice() throws {
|
||||||
|
|
||||||
let limit = 10
|
let limit = 10
|
||||||
let start = 20
|
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)
|
let allFromNil = try self.transactionRepository.findAll(from: transactions[start], limit: limit)
|
||||||
else {
|
else {
|
||||||
return XCTFail("find all failed")
|
return XCTFail("find all failed")
|
||||||
|
@ -162,8 +166,8 @@ class TransactionRepositoryTests: XCTestCase {
|
||||||
|
|
||||||
let slice = transactions[start + 1 ..< transactions.count]
|
let slice = transactions[start + 1 ..< transactions.count]
|
||||||
XCTAssertEqual(slice.count, allFromNil.count)
|
XCTAssertEqual(slice.count, allFromNil.count)
|
||||||
for t in slice {
|
for transaction in slice {
|
||||||
guard allFromNil.first(where: { $0.rawTransactionId == t.rawTransactionId}) != nil else {
|
guard allFromNil.first(where: { $0.rawTransactionId == transaction.rawTransactionId }) != nil else {
|
||||||
XCTFail("not equal")
|
XCTFail("not equal")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -172,19 +176,17 @@ class TransactionRepositoryTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Data {
|
extension Data {
|
||||||
|
|
||||||
init?(fromHexEncodedString string: String) {
|
init?(fromHexEncodedString string: String) {
|
||||||
|
|
||||||
// Convert 0 ... 9, a ... f, A ...F to their decimal value,
|
// Convert 0 ... 9, a ... f, A ...F to their decimal value,
|
||||||
// return nil for all other input characters
|
// return nil for all other input characters
|
||||||
func decodeNibble(u: UInt16) -> UInt8? {
|
func decodeNibble(bytes: UInt16) -> UInt8? {
|
||||||
switch(u) {
|
switch bytes {
|
||||||
case 0x30 ... 0x39:
|
case 0x30 ... 0x39:
|
||||||
return UInt8(u - 0x30)
|
return UInt8(bytes - 0x30)
|
||||||
case 0x41 ... 0x46:
|
case 0x41 ... 0x46:
|
||||||
return UInt8(u - 0x41 + 10)
|
return UInt8(bytes - 0x41 + 10)
|
||||||
case 0x61 ... 0x66:
|
case 0x61 ... 0x66:
|
||||||
return UInt8(u - 0x61 + 10)
|
return UInt8(bytes - 0x61 + 10)
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -193,15 +195,15 @@ extension Data {
|
||||||
self.init(capacity: string.utf16.count / 2)
|
self.init(capacity: string.utf16.count / 2)
|
||||||
var even = true
|
var even = true
|
||||||
var byte: UInt8 = 0
|
var byte: UInt8 = 0
|
||||||
for c in string.utf16 {
|
for char in string.utf16 {
|
||||||
guard let val = decodeNibble(u: c) else { return nil }
|
guard let val = decodeNibble(bytes: char) else { return nil }
|
||||||
if even {
|
if even {
|
||||||
byte = val << 4
|
byte = val << 4
|
||||||
} else {
|
} else {
|
||||||
byte += val
|
byte += val
|
||||||
self.append(byte)
|
self.append(byte)
|
||||||
}
|
}
|
||||||
even = !even
|
even.toggle()
|
||||||
}
|
}
|
||||||
guard even else { return nil }
|
guard even else { return nil }
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,12 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
|
// swiftlint:disable force_unwrapping
|
||||||
class TxIdTests: XCTestCase {
|
class TxIdTests: XCTestCase {
|
||||||
|
|
||||||
func testTxIdAsString() {
|
func testTxIdAsString() {
|
||||||
let transactionId = "5cf915c5d01007c39d602e08ab59d98aba366e2fb7ac01f2cdad4bf4f8f300bb"
|
let transactionId = "5cf915c5d01007c39d602e08ab59d98aba366e2fb7ac01f2cdad4bf4f8f300bb"
|
||||||
let expectedTxIdString = "bb00f3f8f44badcdf201acb72f6e36ba8ad959ab082e609dc30710d0c515f95c"
|
let expectedTxIdString = "bb00f3f8f44badcdf201acb72f6e36ba8ad959ab082e609dc30710d0c515f95c"
|
||||||
|
|
||||||
XCTAssertEqual(Data(fromHexEncodedString: transactionId)!.toHexStringTxId(), expectedTxIdString)
|
XCTAssertEqual(Data(fromHexEncodedString: transactionId)!.toHexStringTxId(), expectedTxIdString)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,31 +10,33 @@ import Foundation
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional force_try force_unwrapping
|
||||||
class WalletTests: XCTestCase {
|
class WalletTests: XCTestCase {
|
||||||
|
|
||||||
var dbData: URL! = nil
|
var dbData: URL! = nil
|
||||||
var paramDestination: URL! = nil
|
var paramDestination: URL! = nil
|
||||||
var cacheData: URL! = nil
|
var cacheData: URL! = nil
|
||||||
var network = ZcashNetworkBuilder.network(for: .testnet)
|
var network = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
var seedData: Data = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
|
var seedData = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
|
||||||
override func setUp() {
|
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
dbData = try! __dataDbURL()
|
dbData = try! __dataDbURL()
|
||||||
cacheData = try! __cacheDbURL()
|
cacheData = try! __cacheDbURL()
|
||||||
paramDestination = try! __documentsDirectory().appendingPathComponent("parameters")
|
paramDestination = try! __documentsDirectory().appendingPathComponent("parameters")
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
|
super.tearDown()
|
||||||
if FileManager.default.fileExists(atPath: dbData.absoluteString) {
|
if FileManager.default.fileExists(atPath: dbData.absoluteString) {
|
||||||
try! FileManager.default.trashItem(at: dbData, resultingItemURL: nil)
|
try! FileManager.default.trashItem(at: dbData, resultingItemURL: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testWalletInitialization() throws {
|
func testWalletInitialization() throws {
|
||||||
|
|
||||||
let derivationTool = DerivationTool(networkType: network.networkType)
|
let derivationTool = DerivationTool(networkType: network.networkType)
|
||||||
let uvk = try derivationTool.deriveUnifiedViewingKeysFromSeed(seedData.bytes, numberOfAccounts: 1)
|
let uvk = try derivationTool.deriveUnifiedViewingKeysFromSeed(seedData.bytes, numberOfAccounts: 1)
|
||||||
let wallet = Initializer(cacheDbURL: try __cacheDbURL(),
|
let wallet = Initializer(
|
||||||
|
cacheDbURL: try __cacheDbURL(),
|
||||||
dataDbURL: try __dataDbURL(),
|
dataDbURL: try __dataDbURL(),
|
||||||
pendingDbURL: try TestDbBuilder.pendingTransactionsDbURL(),
|
pendingDbURL: try TestDbBuilder.pendingTransactionsDbURL(),
|
||||||
endpoint: LightWalletEndpointBuilder.default,
|
endpoint: LightWalletEndpointBuilder.default,
|
||||||
|
@ -42,9 +44,8 @@ class WalletTests: XCTestCase {
|
||||||
spendParamsURL: try __spendParamsURL(),
|
spendParamsURL: try __spendParamsURL(),
|
||||||
outputParamsURL: try __outputParamsURL(),
|
outputParamsURL: try __outputParamsURL(),
|
||||||
viewingKeys: uvk,
|
viewingKeys: uvk,
|
||||||
walletBirthday: 663194)
|
walletBirthday: 663194
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
let synchronizer = try SDKSynchronizer(initializer: wallet)
|
let synchronizer = try SDKSynchronizer(initializer: wallet)
|
||||||
XCTAssertNoThrow(try synchronizer.prepare())
|
XCTAssertNoThrow(try synchronizer.prepare())
|
||||||
|
@ -56,7 +57,7 @@ class WalletTests: XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WalletBirthdayProvider {
|
enum WalletBirthdayProvider {
|
||||||
static var testBirthday: WalletBirthday {
|
static var testBirthday: WalletBirthday {
|
||||||
WalletBirthday()
|
WalletBirthday()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,10 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@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?
|
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" // TODO: Parameterize this from environment?
|
||||||
|
|
||||||
let testRecipientAddress = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz" // TODO: Parameterize this from environment
|
let testRecipientAddress = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz" // TODO: Parameterize this from environment
|
||||||
|
@ -26,6 +28,7 @@ class Z2TReceiveTests: XCTestCase {
|
||||||
let network = DarksideWalletDNetwork()
|
let network = DarksideWalletDNetwork()
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
|
try super.setUpWithError()
|
||||||
|
|
||||||
coordinator = try TestCoordinator(
|
coordinator = try TestCoordinator(
|
||||||
seed: seedPhrase,
|
seed: seedPhrase,
|
||||||
|
@ -33,11 +36,15 @@ class Z2TReceiveTests: XCTestCase {
|
||||||
channelProvider: ChannelProvider(),
|
channelProvider: ChannelProvider(),
|
||||||
network: network
|
network: network
|
||||||
)
|
)
|
||||||
|
|
||||||
try coordinator.reset(saplingActivation: 663150, branchID: self.branchID, chainName: self.chainName)
|
try coordinator.reset(saplingActivation: 663150, branchID: self.branchID, chainName: self.chainName)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
|
try super.tearDownWithError()
|
||||||
|
|
||||||
NotificationCenter.default.removeObserver(self)
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
|
||||||
try coordinator.stop()
|
try coordinator.stop()
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
|
||||||
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
|
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
|
||||||
|
@ -45,23 +52,26 @@ class Z2TReceiveTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func subscribeToFoundTransactions() {
|
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) {
|
@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")
|
XCTFail("found transactions notification is empty")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.foundTransactionsExpectation.fulfill()
|
self.foundTransactionsExpectation.fulfill()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFoundTransactions() throws {
|
func testFoundTransactions() throws {
|
||||||
subscribeToFoundTransactions()
|
subscribeToFoundTransactions()
|
||||||
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName)
|
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName)
|
||||||
let receivedTxHeight: BlockHeight = 663188
|
let receivedTxHeight: BlockHeight = 663188
|
||||||
var initialTotalBalance: Int64 = -1
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
2. applyStaged(received_Tx_height)
|
2. applyStaged(received_Tx_height)
|
||||||
|
@ -74,32 +84,41 @@ class Z2TReceiveTests: XCTestCase {
|
||||||
/*
|
/*
|
||||||
3. sync up to received_Tx_height
|
3. sync up to received_Tx_height
|
||||||
*/
|
*/
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(
|
||||||
initialTotalBalance = synchronizer.initializer.getBalance()
|
completion: { _ in
|
||||||
preTxExpectation.fulfill()
|
preTxExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
},
|
||||||
|
error: self.handleError
|
||||||
|
)
|
||||||
|
|
||||||
wait(for: [preTxExpectation, foundTransactionsExpectation], timeout: 5)
|
wait(for: [preTxExpectation, foundTransactionsExpectation], timeout: 5)
|
||||||
|
|
||||||
let sendExpectation = XCTestExpectation(description: "sendToAddress")
|
let sendExpectation = XCTestExpectation(description: "sendToAddress")
|
||||||
var p: PendingTransactionEntity?
|
var pendingEntity: PendingTransactionEntity?
|
||||||
var error: Error? = nil
|
var error: Error?
|
||||||
let sendAmount: Int64 = 10000
|
let sendAmount: Int64 = 10000
|
||||||
/*
|
/*
|
||||||
4. create transaction
|
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 {
|
switch result {
|
||||||
case .success(let pending):
|
case .success(let pending):
|
||||||
p = pending
|
pendingEntity = pending
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
error = e
|
error = e
|
||||||
}
|
}
|
||||||
sendExpectation.fulfill()
|
sendExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
wait(for: [sendExpectation], timeout: 12)
|
wait(for: [sendExpectation], timeout: 12)
|
||||||
|
|
||||||
guard let pendingTx = p else {
|
guard pendingEntity != nil else {
|
||||||
XCTFail("error sending to address. Error: \(String(describing: error))")
|
XCTFail("error sending to address. Error: \(String(describing: error))")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -118,6 +137,7 @@ class Z2TReceiveTests: XCTestCase {
|
||||||
XCTFail("sent transaction not present on Darksidewalletd")
|
XCTFail("sent transaction not present on Darksidewalletd")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try coordinator.stageTransaction(sentTx, at: sentTxHeight)
|
try coordinator.stageTransaction(sentTx, at: sentTxHeight)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -127,27 +147,22 @@ class Z2TReceiveTests: XCTestCase {
|
||||||
|
|
||||||
sleep(2)
|
sleep(2)
|
||||||
self.foundTransactionsExpectation = XCTestExpectation(description: "inbound expectation")
|
self.foundTransactionsExpectation = XCTestExpectation(description: "inbound expectation")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
7. sync to sentTxHeight + 1
|
7. sync to sentTxHeight + 1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation")
|
let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation")
|
||||||
|
|
||||||
try coordinator.sync(completion: { (s) in
|
try coordinator.sync(completion: { synchronizer in
|
||||||
|
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
|
||||||
let pMinedHeight = s.pendingTransactions.first?.minedHeight
|
|
||||||
XCTAssertEqual(pMinedHeight, sentTxHeight)
|
XCTAssertEqual(pMinedHeight, sentTxHeight)
|
||||||
|
|
||||||
sentTxSyncExpectation.fulfill()
|
sentTxSyncExpectation.fulfill()
|
||||||
}, error: self.handleError)
|
}, error: self.handleError)
|
||||||
|
|
||||||
|
|
||||||
wait(for: [sentTxSyncExpectation, foundTransactionsExpectation], timeout: 5)
|
wait(for: [sentTxSyncExpectation, foundTransactionsExpectation], timeout: 5)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func handleError(_ error: Error?) {
|
func handleError(_ error: Error?) {
|
||||||
_ = try? coordinator.stop()
|
_ = try? coordinator.stop()
|
||||||
guard let testError = error else {
|
guard let testError = error else {
|
||||||
|
|
|
@ -8,14 +8,13 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
import GRPC
|
import GRPC
|
||||||
|
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable implicitly_unwrapped_optional force_try force_unwrapping
|
||||||
class ZcashLightClientKitTests: XCTestCase {
|
class ZcashLightClientKitTests: XCTestCase {
|
||||||
|
|
||||||
var latestBlockHeight: BlockHeight!
|
var latestBlockHeight: BlockHeight!
|
||||||
|
|
||||||
var service: LightWalletGRPCService!
|
var service: LightWalletGRPCService!
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
service = LightWalletGRPCService(endpoint: LightWalletEndpoint(address: Constants.address, port: 9067))
|
service = LightWalletGRPCService(endpoint: LightWalletEndpoint(address: Constants.address, port: 9067))
|
||||||
|
@ -30,17 +29,14 @@ class ZcashLightClientKitTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testEnvironmentLaunch() {
|
func testEnvironmentLaunch() {
|
||||||
|
|
||||||
let address = Constants.address
|
let address = Constants.address
|
||||||
|
|
||||||
XCTAssertFalse(address.isEmpty, "Your \'\(Environment.lightwalletdKey)\' key is missing from your launch environment variables")
|
XCTAssertFalse(address.isEmpty, "Your \'\(Environment.lightwalletdKey)\' key is missing from your launch environment variables")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testService() {
|
func testService() {
|
||||||
|
|
||||||
// and that it has a non-zero size
|
// and that it has a non-zero size
|
||||||
XCTAssert(latestBlockHeight > 0)
|
XCTAssert(latestBlockHeight > 0)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBlockRangeServiceTilLastest() {
|
func testBlockRangeServiceTilLastest() {
|
||||||
|
@ -49,11 +45,10 @@ class ZcashLightClientKitTests: XCTestCase {
|
||||||
|
|
||||||
let startHeight = latestBlockHeight - expectedCount
|
let startHeight = latestBlockHeight - expectedCount
|
||||||
let endHeight = latestBlockHeight!
|
let endHeight = latestBlockHeight!
|
||||||
var blocks = [CompactBlock]()
|
var blocks: [CompactBlock] = []
|
||||||
guard let call = try? service!.blockRange(startHeight: startHeight, endHeight: endHeight, result: {
|
guard let call = try? service!.blockRange(startHeight: startHeight, endHeight: endHeight, result: {
|
||||||
blocks.append($0)
|
blocks.append($0)
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
}) else {
|
}) else {
|
||||||
XCTFail("failed to create getBlockRange( \(startHeight) ..<= \(endHeight)")
|
XCTFail("failed to create getBlockRange( \(startHeight) ..<= \(endHeight)")
|
||||||
return
|
return
|
||||||
|
@ -61,11 +56,9 @@ class ZcashLightClientKitTests: XCTestCase {
|
||||||
|
|
||||||
_ = try! call.status.wait()
|
_ = try! call.status.wait()
|
||||||
XCTAssertEqual(expectedCount + 1, count)
|
XCTAssertEqual(expectedCount + 1, count)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
enum Environment {
|
||||||
|
|
||||||
class Environment {
|
|
||||||
static let lightwalletdKey = "LIGHTWALLETD_ADDRESS"
|
static let lightwalletdKey = "LIGHTWALLETD_ADDRESS"
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,23 +9,27 @@
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable force_unwrapping implicitly_unwrapped_optional force_try
|
||||||
class ZcashRustBackendTests: XCTestCase {
|
class ZcashRustBackendTests: XCTestCase {
|
||||||
var dbData: URL!
|
var dbData: URL!
|
||||||
var dataDbHandle = TestDbHandle(originalDb: TestDbBuilder.prePopulatedDataDbURL()!)
|
var dataDbHandle = TestDbHandle(originalDb: TestDbBuilder.prePopulatedDataDbURL()!)
|
||||||
var cacheDbHandle = TestDbHandle(originalDb: TestDbBuilder.prePopulatedCacheDbURL()!)
|
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 recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6"
|
||||||
let zpend: Int = 500_000
|
let zpend: Int = 500_000
|
||||||
|
|
||||||
let networkType = NetworkType.testnet
|
let networkType = NetworkType.testnet
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
dbData = try! __dataDbURL()
|
dbData = try! __dataDbURL()
|
||||||
try? dataDbHandle.setUp()
|
try? dataDbHandle.setUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
|
super.tearDown()
|
||||||
try? FileManager.default.removeItem(at: dbData!)
|
try? FileManager.default.removeItem(at: dbData!)
|
||||||
dataDbHandle.dispose()
|
dataDbHandle.dispose()
|
||||||
}
|
}
|
||||||
|
@ -35,27 +39,33 @@ class ZcashRustBackendTests: XCTestCase {
|
||||||
|
|
||||||
XCTAssertNoThrow(try ZcashRustBackend.initDataDb(dbData: dbData!, networkType: networkType))
|
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())
|
XCTAssertNotNil(ZcashRustBackend.getLastError())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeriveExtendedSpendingKeys() {
|
func testDeriveExtendedSpendingKeys() {
|
||||||
let seed = Array("testreferencealicetestreferencealice".utf8)
|
let seed = Array("testreferencealicetestreferencealice".utf8)
|
||||||
|
|
||||||
var spendingKeys: [String]? = nil
|
var spendingKeys: [String]?
|
||||||
XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1, networkType: networkType) }())
|
XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1, networkType: networkType) }())
|
||||||
|
|
||||||
XCTAssertNotNil(spendingKeys)
|
XCTAssertNotNil(spendingKeys)
|
||||||
XCTAssertFalse(spendingKeys?.first?.isEmpty ?? true)
|
XCTAssertFalse(spendingKeys?.first?.isEmpty ?? true)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeriveExtendedFullViewingKeys() {
|
func testDeriveExtendedFullViewingKeys() {
|
||||||
let seed = Array("testreferencealicetestreferencealice".utf8)
|
let seed = Array("testreferencealicetestreferencealice".utf8)
|
||||||
|
|
||||||
var fullViewingKeys: [String]? = nil
|
var fullViewingKeys: [String]?
|
||||||
XCTAssertNoThrow(try { fullViewingKeys = try ZcashRustBackend.deriveExtendedFullViewingKeys(seed: seed, accounts: 1, networkType: networkType) }())
|
XCTAssertNoThrow(
|
||||||
|
try {
|
||||||
|
fullViewingKeys = try ZcashRustBackend.deriveExtendedFullViewingKeys(
|
||||||
|
seed: seed,
|
||||||
|
accounts: 1,
|
||||||
|
networkType: networkType
|
||||||
|
)
|
||||||
|
}()
|
||||||
|
)
|
||||||
|
|
||||||
XCTAssertNotNil(fullViewingKeys)
|
XCTAssertNotNil(fullViewingKeys)
|
||||||
XCTAssertFalse(fullViewingKeys?.first?.isEmpty ?? true)
|
XCTAssertFalse(fullViewingKeys?.first?.isEmpty ?? true)
|
||||||
|
@ -63,10 +73,9 @@ class ZcashRustBackendTests: XCTestCase {
|
||||||
|
|
||||||
func testDeriveExtendedFullViewingKey() {
|
func testDeriveExtendedFullViewingKey() {
|
||||||
let seed = Array("testreferencealicetestreferencealice".utf8)
|
let seed = Array("testreferencealicetestreferencealice".utf8)
|
||||||
var fullViewingKey: String? = nil
|
var fullViewingKey: String?
|
||||||
|
|
||||||
|
var spendingKeys: [String]?
|
||||||
var spendingKeys: [String]? = nil
|
|
||||||
XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1, networkType: networkType) }())
|
XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1, networkType: networkType) }())
|
||||||
|
|
||||||
XCTAssertNotNil(spendingKeys)
|
XCTAssertNotNil(spendingKeys)
|
||||||
|
@ -100,57 +109,81 @@ class ZcashRustBackendTests: XCTestCase {
|
||||||
XCTAssertEqual(addr, Optional("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc"))
|
XCTAssertEqual(addr, Optional("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc"))
|
||||||
|
|
||||||
XCTAssertTrue(ZcashRustBackend.scanBlocks(dbCache: cacheDb, dbData: dbData, networkType: networkType))
|
XCTAssertTrue(ZcashRustBackend.scanBlocks(dbCache: cacheDb, dbData: dbData, networkType: networkType))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIsValidTransparentAddressFalse() {
|
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 {
|
if let valid = isValid {
|
||||||
XCTAssertFalse(valid)
|
XCTAssertFalse(valid)
|
||||||
} else {
|
} else {
|
||||||
XCTFail()
|
XCTFail("Failed as invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIsValidTransparentAddressTrue() {
|
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 {
|
if let valid = isValid {
|
||||||
XCTAssertTrue(valid)
|
XCTAssertTrue(valid)
|
||||||
} else {
|
} else {
|
||||||
XCTFail()
|
XCTFail("Failed as invalid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIsValidShieldedAddressTrue() {
|
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 {
|
if let valid = isValid {
|
||||||
XCTAssertTrue(valid)
|
XCTAssertTrue(valid)
|
||||||
} else {
|
} else {
|
||||||
XCTFail()
|
XCTFail("Failed as invalid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIsValidShieldedAddressFalse() {
|
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 {
|
if let valid = isValid {
|
||||||
XCTAssertFalse(valid)
|
XCTAssertFalse(valid)
|
||||||
} else {
|
} else {
|
||||||
XCTFail()
|
XCTFail("Failed as invalid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,41 @@ enum DarksideDataset: String {
|
||||||
}
|
}
|
||||||
|
|
||||||
class DarksideWalletService: LightWalletService {
|
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 {
|
var channel: Channel
|
||||||
return service.blockStream(startHeight: startHeight, endHeight: endHeight, result: result, handler: handler, progress: progress)
|
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 {
|
func getInfo() throws -> LightWalletdInfo {
|
||||||
|
@ -51,14 +84,17 @@ class DarksideWalletService: LightWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
func closeConnection() {
|
func closeConnection() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||||
return []
|
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) {
|
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) {
|
||||||
result(.success([]))
|
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) {
|
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) {
|
||||||
result(.success([]))
|
result(.success([]))
|
||||||
}
|
}
|
||||||
|
@ -88,28 +128,6 @@ class DarksideWalletService: LightWalletService {
|
||||||
service.fetchTransaction(txId: txId, result: result)
|
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) {
|
func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
|
||||||
service.latestBlockHeight(result: result)
|
service.latestBlockHeight(result: result)
|
||||||
}
|
}
|
||||||
|
@ -158,11 +176,17 @@ class DarksideWalletService: LightWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIncomingTransactions() throws -> [RawTransaction]? {
|
func getIncomingTransactions() throws -> [RawTransaction]? {
|
||||||
var txs = [RawTransaction]()
|
var txs: [RawTransaction] = []
|
||||||
let response = try darksideService.getIncomingTransactions(Empty(), handler: { txs.append($0) }).status.wait()
|
let response = try darksideService.getIncomingTransactions(
|
||||||
|
Empty(),
|
||||||
|
handler: { txs.append($0) }
|
||||||
|
)
|
||||||
|
.status
|
||||||
|
.wait()
|
||||||
|
|
||||||
switch response.code {
|
switch response.code {
|
||||||
case .success:
|
case .ok:
|
||||||
return txs.count > 0 ? txs : nil
|
return !txs.isEmpty ? txs : nil
|
||||||
default:
|
default:
|
||||||
throw response
|
throw response
|
||||||
}
|
}
|
||||||
|
@ -186,9 +210,11 @@ class DarksideWalletService: LightWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
func stageTransaction(_ rawTransaction: RawTransaction, at height: BlockHeight) throws {
|
func stageTransaction(_ rawTransaction: RawTransaction, at height: BlockHeight) throws {
|
||||||
var tx = rawTransaction
|
var transaction = rawTransaction
|
||||||
tx.height = UInt64(height)
|
transaction.height = UInt64(height)
|
||||||
_ = try darksideService.stageTransactionsStream().sendMessage(tx).wait()
|
_ = try darksideService.stageTransactionsStream()
|
||||||
|
.sendMessage(transaction)
|
||||||
|
.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func stageTransaction(from url: String, at height: BlockHeight) throws {
|
func stageTransaction(from url: String, at height: BlockHeight) throws {
|
||||||
|
@ -197,12 +223,9 @@ class DarksideWalletService: LightWalletService {
|
||||||
txUrl.url = url
|
txUrl.url = url
|
||||||
_ = try darksideService.stageTransactions(txUrl, callOptions: nil).response.wait()
|
_ = try darksideService.stageTransactions(txUrl, callOptions: nil).response.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum DarksideWalletDConstants: NetworkConstants {
|
||||||
class DarksideWalletDConstants: NetworkConstants {
|
|
||||||
|
|
||||||
static var saplingActivationHeight: BlockHeight {
|
static var saplingActivationHeight: BlockHeight {
|
||||||
663150
|
663150
|
||||||
}
|
}
|
||||||
|
@ -227,9 +250,8 @@ class DarksideWalletDConstants: NetworkConstants {
|
||||||
ZcashSDKMainnetConstants.feeChangeHeight
|
ZcashSDKMainnetConstants.feeChangeHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DarksideWalletDNetwork: ZcashNetwork {
|
class DarksideWalletDNetwork: ZcashNetwork {
|
||||||
var constants: NetworkConstants.Type = DarksideWalletDConstants.self
|
var constants: NetworkConstants.Type = DarksideWalletDConstants.self
|
||||||
|
|
||||||
var networkType = NetworkType.mainnet
|
var networkType = NetworkType.mainnet
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@ import Foundation
|
||||||
enum FakeChainBuilderError: Error {
|
enum FakeChainBuilderError: Error {
|
||||||
case fakeHexDataConversionFailed
|
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 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"
|
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.stageBlocksCreate(from: 663151, count: 100)
|
||||||
|
|
||||||
try darksideWallet.stageTransaction(from: txUrls[663174]!, at: 663174)
|
try darksideWallet.stageTransaction(from: txUrls[663174]!, at: 663174)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func buildChain(darksideWallet: DarksideWalletService, branchID: String, chainName: String) throws {
|
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[663174]!, at: 663174)
|
||||||
|
|
||||||
try darksideWallet.stageTransaction(from: txUrls[663188]!, at: 663188)
|
try darksideWallet.stageTransaction(from: txUrls[663188]!, at: 663188)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func buildChainWithTxsFarFromEachOther(darksideWallet: DarksideWalletService, branchID: String, chainName: String, length: Int) throws {
|
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[663188]!, at: 663188)
|
||||||
|
|
||||||
try darksideWallet.stageTransaction(from: txUrls[663974]!, at: 663974)
|
try darksideWallet.stageTransaction(from: txUrls[663974]!, at: 663974)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static func buildChain(darksideWallet: DarksideWalletService, branchID: String, chainName: String, length: Int) throws {
|
static func buildChain(darksideWallet: DarksideWalletService, branchID: String, chainName: String, length: Int) throws {
|
||||||
try darksideWallet.reset(saplingActivation: 663150, branchID: branchID, chainName: chainName)
|
try darksideWallet.reset(saplingActivation: 663150, branchID: branchID, chainName: chainName)
|
||||||
try darksideWallet.useDataset(from: txMainnetBlockUrl)
|
try darksideWallet.useDataset(from: txMainnetBlockUrl)
|
||||||
|
@ -70,34 +68,49 @@ class FakeChainBuilder {
|
||||||
|
|
||||||
try darksideWallet.stageTransaction(from: txUrls[663953]!, at: 663953)
|
try darksideWallet.stageTransaction(from: txUrls[663953]!, at: 663953)
|
||||||
try darksideWallet.stageTransaction(from: txUrls[663974]!, at: 663974)
|
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.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
|
||||||
|
|
||||||
try darksideWallet.useDataset(testnetCanopyStartBlock)
|
try darksideWallet.useDataset(testnetCanopyStartBlock)
|
||||||
try darksideWallet.stageBlocksCreate(from: birthday + 1, count: length)
|
try darksideWallet.stageBlocksCreate(from: birthday + 1, count: length)
|
||||||
try darksideWallet.stageTransaction(from: testnetPreCanopyTx, at: networkActivationHeight - ZcashSDK.expiryOffset)
|
try darksideWallet.stageTransaction(from: testnetPreCanopyTx, at: networkActivationHeight - ZcashSDK.expiryOffset)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func buildChainPostActivationFunds(darksideWallet: DarksideWalletService, birthday: BlockHeight, networkActivationHeight: BlockHeight, length: Int) throws {
|
static func buildChainPostActivationFunds(darksideWallet: DarksideWalletService, birthday: BlockHeight, networkActivationHeight: BlockHeight, length: Int) throws {
|
||||||
|
|
||||||
try darksideWallet.reset(saplingActivation: birthday, branchID: "e9ff75a6", chainName: "testnet")
|
try darksideWallet.reset(saplingActivation: birthday, branchID: "e9ff75a6", chainName: "testnet")
|
||||||
|
|
||||||
try darksideWallet.useDataset(testnetCanopyStartBlock)
|
try darksideWallet.useDataset(testnetCanopyStartBlock)
|
||||||
try darksideWallet.stageBlocksCreate(from: birthday + 1, count: length)
|
try darksideWallet.stageBlocksCreate(from: birthday + 1, count: length)
|
||||||
try darksideWallet.stageTransaction(from: testnetPostCanopyTx, at: networkActivationHeight + 1)
|
try darksideWallet.stageTransaction(from: testnetPostCanopyTx, at: networkActivationHeight + 1)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func buildChainMixedFunds(darksideWallet: DarksideWalletService, birthday: BlockHeight, networkActivationHeight: BlockHeight, branchID: String, chainName: String, length: Int) throws {
|
static func buildChainMixedFunds(
|
||||||
try buildChain(darksideWallet: darksideWallet, birthday: birthday, networkActivationHeight: networkActivationHeight, branchID: branchID, chainName: chainName, length: length)
|
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)
|
try darksideWallet.stageTransaction(from: testnetPostCanopyTx, at: networkActivationHeight + ZcashSDK.expiryOffset)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func buildTxUrl(for id: String) -> String {
|
static func buildTxUrl(for id: String) -> String {
|
||||||
|
@ -186,5 +199,4 @@ class FakeChainBuilder {
|
||||||
822410: buildTxUrl(for: "f3f8684be8d77367d099a38f30e3652410cdebe35c006d0599d86d8ec640867f"),
|
822410: buildTxUrl(for: "f3f8684be8d77367d099a38f30e3652410cdebe35c006d0599d86d8ec640867f"),
|
||||||
828933: buildTxUrl(for: "1fd394257d1c10c8a70fb760cf73f6d0e96e61edcf1ffca6da12d733a59221a4")
|
828933: buildTxUrl(for: "1fd394257d1c10c8a70fb760cf73f6d0e96e61edcf1ffca6da12d733a59221a4")
|
||||||
]
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,15 +14,24 @@ struct LightWalletServiceMockResponse: LightWalletServiceResponse {
|
||||||
var errorCode: Int32
|
var errorCode: Int32
|
||||||
var errorMessage: String
|
var errorMessage: String
|
||||||
var unknownFields: UnknownStorage
|
var unknownFields: UnknownStorage
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MockCancellable: CancellableCall {
|
struct MockCancellable: CancellableCall {
|
||||||
func cancel() {}
|
func cancel() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockLightWalletService: LightWalletService {
|
class MockLightWalletService: LightWalletService {
|
||||||
var mockLightDInfo: LightWalletdInfo?
|
var mockLightDInfo: LightWalletdInfo?
|
||||||
var queue = DispatchQueue(label: "mock service queue")
|
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()
|
return MockCancellable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +44,6 @@ class MockLightWalletService: LightWalletService {
|
||||||
|
|
||||||
func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void) {
|
func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void) {
|
||||||
queue.async { [weak self] in
|
queue.async { [weak self] in
|
||||||
|
|
||||||
guard let info = self?.mockLightDInfo else {
|
guard let info = self?.mockLightDInfo else {
|
||||||
result(.failure(LightWalletServiceError.generalError(message: "Not Implemented")))
|
result(.failure(LightWalletServiceError.generalError(message: "Not Implemented")))
|
||||||
return
|
return
|
||||||
|
@ -45,27 +53,34 @@ class MockLightWalletService: LightWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
func closeConnection() {
|
func closeConnection() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
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) 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
|
private var service: LightWalletService
|
||||||
|
@ -110,7 +125,5 @@ class MockLightWalletService: LightWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ class ZcashConsoleFakeStorage: CompactBlockRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func fakeSave(blocks: [ZcashCompactBlock]) {
|
private func fakeSave(blocks: [ZcashCompactBlock]) {
|
||||||
blocks.forEach {
|
blocks.forEach {
|
||||||
LoggerProxy.debug("saving block \($0)")
|
LoggerProxy.debug("saving block \($0)")
|
||||||
self.latestBlockHeight = $0.height
|
self.latestBlockHeight = $0.height
|
||||||
|
@ -60,5 +60,4 @@ class ZcashConsoleFakeStorage: CompactBlockRepository {
|
||||||
LoggerProxy.debug("rewind to \(height)")
|
LoggerProxy.debug("rewind to \(height)")
|
||||||
self.latestBlockHeight = min(self.latestBlockHeight, height)
|
self.latestBlockHeight = min(self.latestBlockHeight, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,49 +6,33 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class MockTransactionRepository: TransactionRepository {
|
class MockTransactionRepository {
|
||||||
func findConfirmedTransactionBy(rawId: Data) throws -> ConfirmedTransactionEntity? {
|
enum Kind {
|
||||||
nil
|
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 unminedCount: Int
|
||||||
var receivedCount: Int
|
var receivedCount: Int
|
||||||
var sentCount: Int
|
var sentCount: Int
|
||||||
|
|
||||||
var transactions: [ConfirmedTransactionEntity] = []
|
var transactions: [ConfirmedTransactionEntity] = []
|
||||||
var reference: [Kind] = []
|
var reference: [Kind] = []
|
||||||
var sentTransactions: [ConfirmedTransaction] = []
|
var sentTransactions: [ConfirmedTransaction] = []
|
||||||
var receivedTransactions: [ConfirmedTransaction] = []
|
var receivedTransactions: [ConfirmedTransaction] = []
|
||||||
|
var network: ZcashNetwork
|
||||||
|
|
||||||
var allCount: Int {
|
var allCount: Int {
|
||||||
receivedCount + sentCount
|
receivedCount + sentCount
|
||||||
}
|
}
|
||||||
|
|
||||||
var network: ZcashNetwork
|
init(
|
||||||
init(unminedCount: Int,
|
unminedCount: Int,
|
||||||
receivedCount: Int,
|
receivedCount: Int,
|
||||||
sentCount: Int,
|
sentCount: Int,
|
||||||
network: ZcashNetwork) {
|
network: ZcashNetwork
|
||||||
|
) {
|
||||||
self.unminedCount = unminedCount
|
self.unminedCount = unminedCount
|
||||||
self.receivedCount = receivedCount
|
self.receivedCount = receivedCount
|
||||||
self.sentCount = sentCount
|
self.sentCount = sentCount
|
||||||
|
@ -56,15 +40,87 @@ class MockTransactionRepository: TransactionRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
func generate() {
|
func generate() {
|
||||||
|
var txArray: [ConfirmedTransactionEntity] = []
|
||||||
var txArray = [ConfirmedTransactionEntity]()
|
|
||||||
reference = referenceArray()
|
reference = referenceArray()
|
||||||
for i in 0 ..< reference.count {
|
for index in 0 ..< reference.count {
|
||||||
txArray.append(mockTx(index: i, kind: reference[i]))
|
txArray.append(mockTx(index: index, kind: reference[index]))
|
||||||
}
|
}
|
||||||
transactions = txArray
|
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 {
|
func countAll() throws -> Int {
|
||||||
allCount
|
allCount
|
||||||
}
|
}
|
||||||
|
@ -73,6 +129,10 @@ class MockTransactionRepository: TransactionRepository {
|
||||||
unminedCount
|
unminedCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func blockForHeight(_ height: BlockHeight) throws -> Block? {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
func findBy(id: Int) throws -> TransactionEntity? {
|
func findBy(id: Int) throws -> TransactionEntity? {
|
||||||
transactions.first(where: { $0.id == id })?.transactionEntity
|
transactions.first(where: { $0.id == id })?.transactionEntity
|
||||||
}
|
}
|
||||||
|
@ -84,19 +144,19 @@ class MockTransactionRepository: TransactionRepository {
|
||||||
func findAllSentTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
|
func findAllSentTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
|
||||||
guard let indices = reference.indices(where: { $0 == .sent }) else { return nil }
|
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]
|
transactions[idx]
|
||||||
}
|
}
|
||||||
return slice(txs: sentTxs, offset: offset, limit: limit)
|
return slice(txs: sentTxs, offset: offset, limit: limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func findAllReceivedTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
|
func findAllReceivedTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
|
||||||
guard let indices = reference.indices(where: { $0 == .received }) else { return nil }
|
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]
|
transactions[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
return slice(txs: receivedTxs, offset: offset, limit: limit)
|
return slice(txs: receivedTxs, offset: offset, limit: limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +164,10 @@ class MockTransactionRepository: TransactionRepository {
|
||||||
transactions
|
transactions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findAll(from: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]? {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
func lastScannedHeight() throws -> BlockHeight {
|
func lastScannedHeight() throws -> BlockHeight {
|
||||||
return 700000
|
return 700000
|
||||||
}
|
}
|
||||||
|
@ -116,70 +180,32 @@ class MockTransactionRepository: TransactionRepository {
|
||||||
nil
|
nil
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Kind {
|
func findTransactions(in range: BlockRange, limit: Int) throws -> [TransactionEntity]? {
|
||||||
case sent
|
nil
|
||||||
case received
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func referenceArray() -> [Kind] {
|
func findConfirmedTransactionBy(rawId: Data) throws -> ConfirmedTransactionEntity? {
|
||||||
var template = [Kind]()
|
nil
|
||||||
|
|
||||||
for _ in 0 ..< sentCount {
|
|
||||||
template.append(.sent)
|
|
||||||
}
|
|
||||||
for _ in 0 ..< receivedCount {
|
|
||||||
template.append(.received)
|
|
||||||
}
|
|
||||||
return template.shuffled()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findConfirmedTransactions(in range: BlockRange, offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
|
||||||
func mockTx(index: Int, kind: Kind) -> ConfirmedTransactionEntity {
|
nil
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
return idx
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import Foundation
|
||||||
import ZcashLightClientKit
|
import ZcashLightClientKit
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
// swiftlint:disable force_unwrapping print_function_usage
|
||||||
class SampleLogger: ZcashLightClientKit.Logger {
|
class SampleLogger: ZcashLightClientKit.Logger {
|
||||||
enum LogLevel: Int {
|
enum LogLevel: Int {
|
||||||
case debug
|
case debug
|
||||||
|
@ -66,7 +67,14 @@ class SampleLogger: ZcashLightClientKit.Logger {
|
||||||
case .printerLog:
|
case .printerLog:
|
||||||
print("[\(level)] \(fileName) - \(function) - line: \(line) -> \(message)")
|
print("[\(level)] \(fileName) - \(function) - line: \(line) -> \(message)")
|
||||||
default:
|
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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import GRPC
|
||||||
import SwiftProtobuf
|
import SwiftProtobuf
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
// swiftlint:disable function_parameter_count identifier_name
|
||||||
class AwfulLightWalletService: MockLightWalletService {
|
class AwfulLightWalletService: MockLightWalletService {
|
||||||
override func latestBlockHeight() throws -> BlockHeight {
|
override func latestBlockHeight() throws -> BlockHeight {
|
||||||
throw LightWalletServiceError.criticalError
|
throw LightWalletServiceError.criticalError
|
||||||
|
@ -24,7 +25,6 @@ class AwfulLightWalletService: MockLightWalletService {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
result(.failure(LightWalletServiceError.invalidBlock))
|
result(.failure(LightWalletServiceError.invalidBlock))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
|
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
|
Submits a raw transaction over lightwalletd. Blocking
|
||||||
*/
|
*/
|
||||||
|
|
||||||
override func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
override func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
||||||
throw LightWalletServiceError.invalidBlock
|
throw LightWalletServiceError.invalidBlock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SlightlyBadLightWalletService: MockLightWalletService {
|
class SlightlyBadLightWalletService: MockLightWalletService {
|
||||||
|
|
||||||
|
|
||||||
override func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
override func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
result(.success(LightWalletServiceMockResponse.error))
|
result(.success(LightWalletServiceMockResponse.error))
|
||||||
|
@ -60,29 +57,30 @@ class SlightlyBadLightWalletService: MockLightWalletService {
|
||||||
/**
|
/**
|
||||||
Submits a raw transaction over lightwalletd. Blocking
|
Submits a raw transaction over lightwalletd. Blocking
|
||||||
*/
|
*/
|
||||||
|
|
||||||
override func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
override func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
||||||
LightWalletServiceMockResponse.error
|
LightWalletServiceMockResponse.error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extension LightWalletServiceMockResponse {
|
extension LightWalletServiceMockResponse {
|
||||||
static var error: 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 {
|
static var success: LightWalletServiceMockResponse {
|
||||||
LightWalletServiceMockResponse(errorCode: 0, errorMessage: "", unknownFields: UnknownStorage())
|
LightWalletServiceMockResponse(errorCode: 0, errorMessage: "", unknownFields: UnknownStorage())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockRustBackend: ZcashRustBackendWelding {
|
class MockRustBackend: ZcashRustBackendWelding {
|
||||||
|
|
||||||
static func clearUtxos(dbData: URL, address: String, sinceHeight: BlockHeight, networkType: NetworkType) throws -> Int32 {
|
static func clearUtxos(dbData: URL, address: String, sinceHeight: BlockHeight, networkType: NetworkType) throws -> Int32 {
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static func getNearestRewindHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Int32 {
|
static func getNearestRewindHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Int32 {
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
|
@ -103,7 +101,16 @@ class MockRustBackend: ZcashRustBackendWelding {
|
||||||
-1
|
-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
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,11 +118,31 @@ class MockRustBackend: ZcashRustBackendWelding {
|
||||||
throw RustWeldingError.genericError(message: "unimplemented")
|
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
|
-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
|
-1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,12 +198,11 @@ class MockRustBackend: ZcashRustBackendWelding {
|
||||||
nil
|
nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static func consensusBranchIdFor(height: Int32, networkType: NetworkType) throws -> Int32 {
|
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 try rustBackend.consensusBranchIdFor(height: height, networkType: networkType)
|
||||||
}
|
}
|
||||||
return c
|
return consensus
|
||||||
}
|
}
|
||||||
|
|
||||||
static var networkType = NetworkType.testnet
|
static var networkType = NetworkType.testnet
|
||||||
|
@ -225,9 +251,23 @@ class MockRustBackend: ZcashRustBackendWelding {
|
||||||
mockAccounts ?? rustBackend.initAccountsTable(dbData: dbData, seed: seed, accounts: accounts, networkType: networkType)
|
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 {
|
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 {
|
if attempts > 0 {
|
||||||
return validationResult(dbCache: dbCache, dbData: dbData, networkType: networkType)
|
return validationResult(dbCache: dbCache, dbData: dbData, networkType: networkType)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if attempts == 0 {
|
if attempts == 0 {
|
||||||
return Int32(mockValidateCombinedChainFailureHeight)
|
return Int32(mockValidateCombinedChainFailureHeight)
|
||||||
} else if attempts < 0 && mockValidateCombinedChainKeepFailing {
|
} else if attempts < 0 && mockValidateCombinedChainKeepFailing {
|
||||||
|
@ -290,7 +329,6 @@ class MockRustBackend: ZcashRustBackendWelding {
|
||||||
|
|
||||||
static func scanBlocks(dbCache: URL, dbData: URL, limit: UInt32, networkType: NetworkType) -> Bool {
|
static func scanBlocks(dbCache: URL, dbData: URL, limit: UInt32, networkType: NetworkType) -> Bool {
|
||||||
if let rate = mockScanblocksSuccessRate {
|
if let rate = mockScanblocksSuccessRate {
|
||||||
|
|
||||||
if shouldSucceed(successRate: rate) {
|
if shouldSucceed(successRate: rate) {
|
||||||
return mockDataDb ? true : rustBackend.scanBlocks(dbCache: dbCache, dbData: dbData, networkType: networkType)
|
return mockDataDb ? true : rustBackend.scanBlocks(dbCache: dbCache, dbData: dbData, networkType: networkType)
|
||||||
} else {
|
} else {
|
||||||
|
@ -300,8 +338,18 @@ class MockRustBackend: ZcashRustBackendWelding {
|
||||||
return rustBackend.scanBlocks(dbCache: dbCache, dbData: dbData, networkType: Self.networkType)
|
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 {
|
static func createToAddress(
|
||||||
// mockCreateToAddress ?? rustBackend.createToAddress(dbData: dbData, account: account, extsk: extsk, consensusBranchId: consensusBranchId, to: to, value: value, memo: memo, spendParamsPath: spendParamsPath, outputParamsPath: outputParamsPath)
|
dbData: URL,
|
||||||
|
account: Int32,
|
||||||
|
extsk: String,
|
||||||
|
consensusBranchId: Int32,
|
||||||
|
to address: String,
|
||||||
|
value: Int64,
|
||||||
|
memo: String?,
|
||||||
|
spendParamsPath: String,
|
||||||
|
outputParamsPath: String,
|
||||||
|
networkType: NetworkType
|
||||||
|
) -> Int64 {
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,5 +373,4 @@ class MockRustBackend: ZcashRustBackendWelding {
|
||||||
static func decryptAndStoreTransaction(dbData: URL, txBytes: [UInt8], minedHeight: Int32, networkType: NetworkType) -> Bool {
|
static func decryptAndStoreTransaction(dbData: URL, txBytes: [UInt8], minedHeight: Int32, networkType: NetworkType) -> Bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,11 @@ struct TestDbHandle {
|
||||||
|
|
||||||
init(originalDb: URL) {
|
init(originalDb: URL) {
|
||||||
self.originalDb = originalDb
|
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 {
|
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 {
|
class TestDbBuilder {
|
||||||
|
|
||||||
enum TestBuilderError: Error {
|
enum TestBuilderError: Error {
|
||||||
case generalError
|
case generalError
|
||||||
}
|
}
|
||||||
|
@ -41,18 +46,21 @@ class TestDbBuilder {
|
||||||
static func inMemoryCompactBlockStorage() throws -> CompactBlockStorage {
|
static func inMemoryCompactBlockStorage() throws -> CompactBlockStorage {
|
||||||
let compactBlockDao = CompactBlockStorage(connectionProvider: try InMemoryDbProvider())
|
let compactBlockDao = CompactBlockStorage(connectionProvider: try InMemoryDbProvider())
|
||||||
try compactBlockDao.createTable()
|
try compactBlockDao.createTable()
|
||||||
|
|
||||||
return compactBlockDao
|
return compactBlockDao
|
||||||
}
|
}
|
||||||
|
|
||||||
static func diskCompactBlockStorage(at url: URL) throws -> CompactBlockStorage {
|
static func diskCompactBlockStorage(at url: URL) throws -> CompactBlockStorage {
|
||||||
let compactBlockDao = CompactBlockStorage(connectionProvider: SimpleConnectionProvider(path: url.absoluteString))
|
let compactBlockDao = CompactBlockStorage(connectionProvider: SimpleConnectionProvider(path: url.absoluteString))
|
||||||
try compactBlockDao.createTable()
|
try compactBlockDao.createTable()
|
||||||
|
|
||||||
return compactBlockDao
|
return compactBlockDao
|
||||||
}
|
}
|
||||||
|
|
||||||
static func pendingTransactionsDbURL() throws -> URL {
|
static func pendingTransactionsDbURL() throws -> URL {
|
||||||
try __documentsDirectory().appendingPathComponent("pending.db")
|
try __documentsDirectory().appendingPathComponent("pending.db")
|
||||||
}
|
}
|
||||||
|
|
||||||
static func prePopulatedCacheDbURL() -> URL? {
|
static func prePopulatedCacheDbURL() -> URL? {
|
||||||
Bundle(for: TestDbBuilder.self).url(forResource: "cache", withExtension: "db")
|
Bundle(for: TestDbBuilder.self).url(forResource: "cache", withExtension: "db")
|
||||||
}
|
}
|
||||||
|
@ -65,6 +73,7 @@ class TestDbBuilder {
|
||||||
let bundle = Bundle(for: TestDbBuilder.self)
|
let bundle = Bundle(for: TestDbBuilder.self)
|
||||||
guard let url = bundle.url(forResource: "ZcashSdk_Data", withExtension: "db") else { return nil }
|
guard let url = bundle.url(forResource: "ZcashSdk_Data", withExtension: "db") else { return nil }
|
||||||
let provider = SimpleConnectionProvider(path: url.absoluteString, readonly: true)
|
let provider = SimpleConnectionProvider(path: url.absoluteString, readonly: true)
|
||||||
|
|
||||||
return provider
|
return provider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +94,6 @@ class TestDbBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
static func seed(db: CompactBlockRepository, with blockRange: CompactBlockRange) throws {
|
static func seed(db: CompactBlockRepository, with blockRange: CompactBlockRange) throws {
|
||||||
|
|
||||||
guard let blocks = StubBlockCreator.createBlockRange(blockRange) else {
|
guard let blocks = StubBlockCreator.createBlockRange(blockRange) else {
|
||||||
throw TestBuilderError.generalError
|
throw TestBuilderError.generalError
|
||||||
}
|
}
|
||||||
|
@ -96,8 +104,8 @@ class TestDbBuilder {
|
||||||
|
|
||||||
struct InMemoryDbProvider: ConnectionProvider {
|
struct InMemoryDbProvider: ConnectionProvider {
|
||||||
var readonly: Bool
|
var readonly: Bool
|
||||||
|
|
||||||
var conn: Connection
|
var conn: Connection
|
||||||
|
|
||||||
init(readonly: Bool = false) throws {
|
init(readonly: Bool = false) throws {
|
||||||
self.readonly = readonly
|
self.readonly = readonly
|
||||||
self.conn = try Connection(.inMemory, 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? {
|
static func createRandomDataBlock(with height: BlockHeight) -> ZcashCompactBlock? {
|
||||||
guard let data = randomData(ofLength: 100) else {
|
guard let data = randomData(ofLength: 100) else {
|
||||||
LoggerProxy.debug("error creating stub block")
|
LoggerProxy.debug("error creating stub block")
|
||||||
|
@ -116,9 +124,9 @@ struct StubBlockCreator {
|
||||||
}
|
}
|
||||||
return ZcashCompactBlock(height: height, data: data)
|
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 {
|
for height in range {
|
||||||
guard let block = createRandomDataBlock(with: height) else {
|
guard let block = createRandomDataBlock(with: height) else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -136,8 +144,7 @@ struct StubBlockCreator {
|
||||||
return Data(bytes: &bytes, count: bytes.count)
|
return Data(bytes: &bytes, count: bytes.count)
|
||||||
}
|
}
|
||||||
LoggerProxy.debug("Status \(status)")
|
LoggerProxy.debug("Status \(status)")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@ import GRPC
|
||||||
import ZcashLightClientKit
|
import ZcashLightClientKit
|
||||||
import XCTest
|
import XCTest
|
||||||
import NIO
|
import NIO
|
||||||
class LightWalletEndpointBuilder {
|
|
||||||
|
// swiftlint:disable identifier_name
|
||||||
|
enum LightWalletEndpointBuilder {
|
||||||
static var `default`: LightWalletEndpoint {
|
static var `default`: LightWalletEndpoint {
|
||||||
LightWalletEndpoint(address: Constants.address, port: 9067, secure: false)
|
LightWalletEndpoint(address: Constants.address, port: 9067, secure: false)
|
||||||
}
|
}
|
||||||
|
@ -29,23 +31,25 @@ class ChannelProvider {
|
||||||
func channel(secure: Bool = false) -> GRPCChannel {
|
func channel(secure: Bool = false) -> GRPCChannel {
|
||||||
let endpoint = LightWalletEndpointBuilder.default
|
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)
|
return ClientConnection(configuration: configuration)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MockDbInit {
|
enum MockDbInit {
|
||||||
@discardableResult static func emptyFile(at path: String) -> Bool {
|
@discardableResult
|
||||||
|
static func emptyFile(at path: String) -> Bool {
|
||||||
FileManager.default.createFile(atPath: path, contents: Data("".utf8), attributes: nil)
|
FileManager.default.createFile(atPath: path, contents: Data("".utf8), attributes: nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func destroy(at path: String) throws {
|
static func destroy(at path: String) throws {
|
||||||
try FileManager.default.removeItem(atPath: path)
|
try FileManager.default.removeItem(atPath: path)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension XCTestExpectation {
|
extension XCTestExpectation {
|
||||||
|
@ -83,7 +87,6 @@ func __outputParamsURL() throws -> URL {
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyParametersToDocuments() throws -> (spend: URL, output: URL) {
|
func copyParametersToDocuments() throws -> (spend: URL, output: URL) {
|
||||||
|
|
||||||
let spendURL = try __documentsDirectory().appendingPathComponent("sapling-spend.params", isDirectory: false)
|
let spendURL = try __documentsDirectory().appendingPathComponent("sapling-spend.params", isDirectory: false)
|
||||||
let outputURL = try __documentsDirectory().appendingPathComponent("sapling-output.params", isDirectory: false)
|
let outputURL = try __documentsDirectory().appendingPathComponent("sapling-output.params", isDirectory: false)
|
||||||
try FileManager.default.copyItem(at: try __spendParamsURL(), to: spendURL)
|
try FileManager.default.copyItem(at: try __spendParamsURL(), to: spendURL)
|
||||||
|
@ -94,7 +97,10 @@ func copyParametersToDocuments() throws -> (spend: URL, output: URL) {
|
||||||
|
|
||||||
func deleteParametersFromDocuments() throws {
|
func deleteParametersFromDocuments() throws {
|
||||||
let documents = try __documentsDirectory()
|
let documents = try __documentsDirectory()
|
||||||
deleteParamsFrom(spend: documents.appendingPathComponent("sapling-spend.params"), output: documents.appendingPathComponent("sapling-output.params"))
|
deleteParamsFrom(
|
||||||
|
spend: documents.appendingPathComponent("sapling-spend.params"),
|
||||||
|
output: documents.appendingPathComponent("sapling-output.params")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
func deleteParamsFrom(spend: URL, output: URL) {
|
func deleteParamsFrom(spend: URL, output: URL) {
|
||||||
try? FileManager.default.removeItem(at: spend)
|
try? FileManager.default.removeItem(at: spend)
|
||||||
|
@ -102,26 +108,28 @@ func deleteParamsFrom(spend: URL, output: URL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parametersReady() -> Bool {
|
func parametersReady() -> Bool {
|
||||||
|
guard
|
||||||
guard let output = try? __outputParamsURL(),
|
let output = try? __outputParamsURL(),
|
||||||
let spend = try? __spendParamsURL(),
|
let spend = try? __spendParamsURL(),
|
||||||
FileManager.default.isReadableFile(atPath: output.absoluteString),
|
FileManager.default.isReadableFile(atPath: output.absoluteString),
|
||||||
FileManager.default.isReadableFile(atPath: spend.absoluteString) else {
|
FileManager.default.isReadableFile(atPath: spend.absoluteString)
|
||||||
|
else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
class StubTest: XCTestCase {}
|
class StubTest: XCTestCase {}
|
||||||
|
|
||||||
extension Bundle {
|
extension Bundle {
|
||||||
static var testBundle: Bundle {
|
static var testBundle: Bundle {
|
||||||
Bundle(for: StubTest.self)
|
Bundle(for: StubTest.self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// swiftlint:disable force_unwrapping
|
||||||
class TestSeed {
|
class TestSeed {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
test account: "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
|
test account: "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue