2019-10-18 11:45:19 -07:00
|
|
|
//
|
|
|
|
// BlockScanOperationTests.swift
|
|
|
|
// ZcashLightClientKitTests
|
|
|
|
//
|
|
|
|
// Created by Francisco Gindre on 10/17/19.
|
|
|
|
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import XCTest
|
|
|
|
import SQLite
|
2022-02-28 09:03:20 -08:00
|
|
|
@testable import TestUtils
|
2019-10-18 11:45:19 -07:00
|
|
|
@testable import ZcashLightClientKit
|
2021-09-23 06:26:41 -07:00
|
|
|
|
|
|
|
// swiftlint:disable implicitly_unwrapped_optional force_try force_unwrapping print_function_usage
|
2019-10-18 11:45:19 -07:00
|
|
|
class BlockScanOperationTests: XCTestCase {
|
2021-09-23 06:26:41 -07:00
|
|
|
let rustWelding = ZcashRustBackend.self
|
|
|
|
|
2019-10-18 11:45:19 -07:00
|
|
|
var operationQueue = OperationQueue()
|
|
|
|
var cacheDbURL: URL!
|
|
|
|
var dataDbURL: URL!
|
2021-05-28 15:45:18 -07:00
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
var uvk = UVFakeKey(
|
|
|
|
extfvk: "zxviewtestsapling1qw88ayg8qqqqpqyhg7jnh9mlldejfqwu46pm40ruwstd8znq3v3l4hjf33qcu2a5e36katshcfhcxhzgyfugj2lkhmt40j45cv38rv3frnghzkxcx73k7m7afw9j7ujk7nm4dx5mv02r26umxqgar7v3x390w2h3crqqgjsjly7jy4vtwzrmustm5yudpgcydw7x78awca8wqjvkqj8p8e3ykt7lrgd7xf92fsfqjs5vegfsja4ekzpfh5vtccgvs5747xqm6qflmtqpr8s9u", // swiftlint:disable:this line_length
|
|
|
|
extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61"
|
|
|
|
)
|
|
|
|
|
2022-07-12 12:36:12 -07:00
|
|
|
var walletBirthDay = Checkpoint.birthday(
|
2021-09-23 06:26:41 -07:00
|
|
|
with: 1386000,
|
|
|
|
network: ZcashNetworkBuilder.network(for: .testnet)
|
|
|
|
)
|
2021-05-28 15:45:18 -07:00
|
|
|
|
2021-07-28 09:59:10 -07:00
|
|
|
var network = ZcashNetworkBuilder.network(for: .testnet)
|
2019-10-18 11:45:19 -07:00
|
|
|
var blockRepository: BlockRepository!
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2019-10-18 11:45:19 -07:00
|
|
|
override func setUp() {
|
|
|
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
2021-09-23 06:26:41 -07:00
|
|
|
super.setUp()
|
2019-10-18 11:45:19 -07:00
|
|
|
self.cacheDbURL = try! __cacheDbURL()
|
|
|
|
self.dataDbURL = try! __dataDbURL()
|
2021-05-28 15:45:18 -07:00
|
|
|
|
2019-10-30 13:18:57 -07:00
|
|
|
deleteDBs()
|
|
|
|
operationQueue.maxConcurrentOperationCount = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
private func deleteDBs() {
|
|
|
|
try? FileManager.default.removeItem(at: cacheDbURL)
|
|
|
|
try? FileManager.default.removeItem(at: dataDbURL)
|
2019-10-18 11:45:19 -07:00
|
|
|
}
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2019-10-18 11:45:19 -07:00
|
|
|
override func tearDown() {
|
|
|
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
2021-09-23 06:26:41 -07:00
|
|
|
super.tearDown()
|
2019-10-18 11:45:19 -07:00
|
|
|
operationQueue.cancelAllOperations()
|
|
|
|
|
2019-10-30 13:18:57 -07:00
|
|
|
try? FileManager.default.removeItem(at: cacheDbURL)
|
2019-10-18 13:09:13 -07:00
|
|
|
try? FileManager.default.removeItem(at: dataDbURL)
|
2019-10-18 11:45:19 -07:00
|
|
|
}
|
2019-10-30 13:18:57 -07:00
|
|
|
|
2019-10-18 11:45:19 -07:00
|
|
|
func testSingleDownloadAndScanOperation() {
|
2021-05-28 15:45:18 -07:00
|
|
|
logger = SampleLogger(logLevel: .debug)
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2021-07-28 09:59:10 -07:00
|
|
|
XCTAssertNoThrow(try rustWelding.initDataDb(dbData: dataDbURL, networkType: network.networkType))
|
2021-09-23 06:26:41 -07:00
|
|
|
|
|
|
|
let downloadStartedExpect = XCTestExpectation(description: "\(self.description) download started")
|
|
|
|
let downloadExpect = XCTestExpectation(description: "\(self.description) download")
|
|
|
|
let scanStartedExpect = XCTestExpectation(description: "\(self.description) scan started")
|
|
|
|
let scanExpect = XCTestExpectation(description: "\(self.description) scan")
|
|
|
|
let latestScannedBlockExpect = XCTestExpectation(description: "\(self.description) latestScannedHeight")
|
|
|
|
let service = LightWalletGRPCService(
|
|
|
|
endpoint: LightWalletEndpoint(
|
|
|
|
address: "lightwalletd.testnet.electriccoin.co",
|
|
|
|
port: 9067
|
|
|
|
)
|
|
|
|
)
|
2019-10-18 11:45:19 -07:00
|
|
|
let blockCount = 100
|
2021-09-23 06:26:41 -07:00
|
|
|
let range = network.constants.saplingActivationHeight ... network.constants.saplingActivationHeight + blockCount
|
|
|
|
let downloadOperation = CompactBlockDownloadOperation(
|
|
|
|
downloader: CompactBlockDownloader.sqlDownloader(
|
|
|
|
service: service,
|
|
|
|
at: cacheDbURL
|
|
|
|
)!,
|
|
|
|
range: range
|
|
|
|
)
|
|
|
|
let scanOperation = CompactBlockScanningOperation(
|
|
|
|
rustWelding: rustWelding,
|
|
|
|
cacheDb: cacheDbURL,
|
|
|
|
dataDb: dataDbURL,
|
|
|
|
networkType: network.networkType
|
|
|
|
)
|
2019-10-18 11:45:19 -07:00
|
|
|
|
2019-10-30 13:18:57 -07:00
|
|
|
downloadOperation.startedHandler = {
|
|
|
|
downloadStartedExpect.fulfill()
|
|
|
|
}
|
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
downloadOperation.completionHandler = { finished, cancelled in
|
2019-10-18 11:45:19 -07:00
|
|
|
downloadExpect.fulfill()
|
|
|
|
XCTAssertTrue(finished)
|
|
|
|
XCTAssertFalse(cancelled)
|
|
|
|
}
|
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
downloadOperation.errorHandler = { error in
|
2019-10-30 13:18:57 -07:00
|
|
|
XCTFail("Download Operation failed with Error: \(error)")
|
|
|
|
}
|
|
|
|
|
|
|
|
scanOperation.startedHandler = {
|
|
|
|
scanStartedExpect.fulfill()
|
|
|
|
}
|
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
scanOperation.completionHandler = { finished, cancelled in
|
2019-10-18 11:45:19 -07:00
|
|
|
scanExpect.fulfill()
|
|
|
|
XCTAssertFalse(cancelled)
|
|
|
|
XCTAssertTrue(finished)
|
|
|
|
}
|
2019-10-30 13:18:57 -07:00
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
scanOperation.errorHandler = { error in
|
2019-10-30 13:18:57 -07:00
|
|
|
XCTFail("Scan Operation failed with Error: \(error)")
|
|
|
|
}
|
|
|
|
|
2019-10-18 11:45:19 -07:00
|
|
|
scanOperation.addDependency(downloadOperation)
|
2019-10-30 13:18:57 -07:00
|
|
|
var latestScannedheight = BlockHeight.empty()
|
|
|
|
let latestScannedBlockOperation = BlockOperation {
|
2019-12-16 14:25:45 -08:00
|
|
|
let repository = BlockSQLDAO(dbProvider: SimpleConnectionProvider.init(path: self.dataDbURL.absoluteString, readonly: true))
|
|
|
|
latestScannedheight = repository.lastScannedBlockHeight()
|
2019-10-30 13:18:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
latestScannedBlockOperation.completionBlock = {
|
|
|
|
latestScannedBlockExpect.fulfill()
|
2020-02-26 08:54:48 -08:00
|
|
|
XCTAssertEqual(latestScannedheight, range.upperBound)
|
2019-10-30 13:18:57 -07:00
|
|
|
}
|
2019-10-18 11:45:19 -07:00
|
|
|
|
2019-10-30 13:18:57 -07:00
|
|
|
latestScannedBlockOperation.addDependency(scanOperation)
|
2019-10-18 11:45:19 -07:00
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
operationQueue.addOperations(
|
|
|
|
[downloadOperation, scanOperation, latestScannedBlockOperation],
|
|
|
|
waitUntilFinished: false
|
|
|
|
)
|
|
|
|
|
|
|
|
wait(
|
|
|
|
for: [downloadStartedExpect, downloadExpect, scanStartedExpect, scanExpect, latestScannedBlockExpect],
|
|
|
|
timeout: 10,
|
|
|
|
enforceOrder: true
|
|
|
|
)
|
2019-10-18 11:45:19 -07:00
|
|
|
}
|
2021-05-28 15:45:18 -07:00
|
|
|
@objc func observeBenchmark(_ notification: Notification) {
|
|
|
|
guard let report = SDKMetrics.blockReportFromNotification(notification) else {
|
|
|
|
return
|
2019-10-18 11:45:19 -07:00
|
|
|
}
|
2021-05-28 15:45:18 -07:00
|
|
|
|
|
|
|
print("observed benchmark: \(report)")
|
2019-10-18 11:45:19 -07:00
|
|
|
}
|
2021-05-28 15:45:18 -07:00
|
|
|
func testScanValidateDownload() throws {
|
|
|
|
logger = SampleLogger(logLevel: .debug)
|
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
NotificationCenter.default.addObserver(
|
|
|
|
self,
|
|
|
|
selector: #selector(observeBenchmark(_:)),
|
|
|
|
name: SDKMetrics.notificationName,
|
|
|
|
object: nil
|
|
|
|
)
|
2021-05-28 15:45:18 -07:00
|
|
|
|
2021-07-28 09:59:10 -07:00
|
|
|
try self.rustWelding.initDataDb(dbData: dataDbURL, networkType: network.networkType)
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2021-07-28 09:59:10 -07:00
|
|
|
guard try self.rustWelding.initAccountsTable(dbData: self.dataDbURL, uvks: [uvk], networkType: network.networkType) else {
|
2021-05-28 15:45:18 -07:00
|
|
|
XCTFail("failed to init account table")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
try self.rustWelding.initBlocksTable(
|
|
|
|
dbData: dataDbURL,
|
|
|
|
height: Int32(walletBirthDay.height),
|
|
|
|
hash: walletBirthDay.hash,
|
|
|
|
time: walletBirthDay.time,
|
2022-06-28 12:17:10 -07:00
|
|
|
saplingTree: walletBirthDay.saplingTree,
|
2021-09-23 06:26:41 -07:00
|
|
|
networkType: network.networkType
|
|
|
|
)
|
2021-05-28 15:45:18 -07:00
|
|
|
|
2021-07-28 15:25:47 -07:00
|
|
|
let service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)
|
2021-05-28 15:45:18 -07:00
|
|
|
let storage = CompactBlockStorage(url: cacheDbURL, readonly: false)
|
|
|
|
try storage.createTable()
|
|
|
|
|
|
|
|
let downloadExpectation = XCTestExpectation(description: "download expectation")
|
|
|
|
let validateExpectation = XCTestExpectation(description: "validate expectation")
|
|
|
|
let scanExpectation = XCTestExpectation(description: "scan expectation")
|
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
let downloadOperation = CompactBlockStreamDownloadOperation(
|
|
|
|
service: service,
|
|
|
|
storage: storage,
|
2022-07-30 16:01:18 -07:00
|
|
|
blockBufferSize: 10,
|
2021-09-23 06:26:41 -07:00
|
|
|
startHeight: walletBirthDay.height,
|
|
|
|
targetHeight: walletBirthDay.height + 10000,
|
|
|
|
progressDelegate: self
|
|
|
|
)
|
2021-05-28 15:45:18 -07:00
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
downloadOperation.completionHandler = { finished, cancelled in
|
2021-05-28 15:45:18 -07:00
|
|
|
XCTAssert(finished)
|
|
|
|
XCTAssertFalse(cancelled)
|
|
|
|
downloadExpectation.fulfill()
|
|
|
|
}
|
|
|
|
|
|
|
|
downloadOperation.errorHandler = { error in
|
|
|
|
if let lwdError = error as? LightWalletServiceError {
|
|
|
|
switch lwdError {
|
|
|
|
case .timeOut:
|
|
|
|
XCTAssert(true)
|
|
|
|
default:
|
|
|
|
XCTFail("LWD Service error found, but should have been a timeLimit reached Error - \(lwdError)")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
XCTFail("Error should have been a timeLimit reached Error - \(error)")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
let validationOperation = CompactBlockValidationOperation(
|
|
|
|
rustWelding: rustWelding,
|
|
|
|
cacheDb: cacheDbURL,
|
|
|
|
dataDb: dataDbURL,
|
|
|
|
networkType: network.networkType
|
|
|
|
)
|
|
|
|
|
2021-05-28 15:45:18 -07:00
|
|
|
validationOperation.errorHandler = { error in
|
|
|
|
self.operationQueue.cancelAllOperations()
|
|
|
|
XCTFail("failed with error \(error)")
|
|
|
|
}
|
2021-09-23 06:26:41 -07:00
|
|
|
|
|
|
|
validationOperation.completionHandler = { finished, cancelled in
|
2021-05-28 15:45:18 -07:00
|
|
|
XCTAssert(finished)
|
|
|
|
XCTAssertFalse(cancelled)
|
|
|
|
validateExpectation.fulfill()
|
|
|
|
}
|
|
|
|
|
|
|
|
let transactionRepository = TransactionRepositoryBuilder.build(dataDbURL: dataDbURL)
|
2021-09-23 06:26:41 -07:00
|
|
|
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
|
|
|
|
)
|
2021-05-28 15:45:18 -07:00
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
scanningOperation.completionHandler = { finished, cancelled in
|
2021-05-28 15:45:18 -07:00
|
|
|
XCTAssert(finished)
|
|
|
|
XCTAssertFalse(cancelled)
|
|
|
|
scanExpectation.fulfill()
|
|
|
|
}
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2021-05-28 15:45:18 -07:00
|
|
|
operationQueue.addOperations([downloadOperation, validationOperation, scanningOperation], waitUntilFinished: false)
|
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
wait(for: [downloadExpectation, validateExpectation, scanExpectation], timeout: 300, enforceOrder: true)
|
2021-05-28 15:45:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-14 16:37:23 -07:00
|
|
|
extension BlockScanOperationTests: CompactBlockProgressDelegate {
|
|
|
|
func progressUpdated(_ progress: CompactBlockProgress) {
|
2021-05-28 15:45:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct UVFakeKey: UnifiedViewingKey {
|
|
|
|
var extfvk: ExtendedFullViewingKey
|
|
|
|
var extpub: ExtendedPublicKey
|
2019-10-18 11:45:19 -07:00
|
|
|
}
|