2022-09-01 05:58:41 -07:00
|
|
|
//
|
|
|
|
// BlockScanTests.swift
|
|
|
|
// ZcashLightClientKitTests
|
|
|
|
//
|
|
|
|
// Created by Francisco Gindre on 10/17/19.
|
|
|
|
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
|
|
|
//
|
|
|
|
|
2023-02-07 05:22:28 -08:00
|
|
|
import Combine
|
2022-09-01 05:58:41 -07:00
|
|
|
import XCTest
|
|
|
|
import SQLite
|
|
|
|
@testable import TestUtils
|
|
|
|
@testable import ZcashLightClientKit
|
|
|
|
|
2023-05-01 07:28:59 -07:00
|
|
|
class BlockScanTests: ZcashTestCase {
|
2023-02-07 05:22:28 -08:00
|
|
|
var cancelables: [AnyCancellable] = []
|
|
|
|
|
2022-09-01 05:58:41 -07:00
|
|
|
var dataDbURL: URL!
|
2022-11-28 22:38:28 -08:00
|
|
|
var spendParamsURL: URL!
|
|
|
|
var outputParamsURL: URL!
|
2023-01-18 08:09:04 -08:00
|
|
|
// swiftlint:disable:next line_length
|
2022-09-15 07:04:49 -07:00
|
|
|
var saplingExtendedKey = SaplingExtendedFullViewingKey(validatedEncoding: "zxviewtestsapling1qw88ayg8qqqqpqyhg7jnh9mlldejfqwu46pm40ruwstd8znq3v3l4hjf33qcu2a5e36katshcfhcxhzgyfugj2lkhmt40j45cv38rv3frnghzkxcx73k7m7afw9j7ujk7nm4dx5mv02r26umxqgar7v3x390w2h3crqqgjsjly7jy4vtwzrmustm5yudpgcydw7x78awca8wqjvkqj8p8e3ykt7lrgd7xf92fsfqjs5vegfsja4ekzpfh5vtccgvs5747xqm6qflmtqpr8s9u")
|
2022-09-01 05:58:41 -07:00
|
|
|
|
|
|
|
var walletBirthDay = Checkpoint.birthday(
|
|
|
|
with: 1386000,
|
|
|
|
network: ZcashNetworkBuilder.network(for: .testnet)
|
|
|
|
)
|
2023-03-31 10:10:35 -07:00
|
|
|
|
|
|
|
var rustBackend: ZcashRustBackendWelding!
|
2022-09-01 05:58:41 -07:00
|
|
|
|
|
|
|
var network = ZcashNetworkBuilder.network(for: .testnet)
|
|
|
|
var blockRepository: BlockRepository!
|
2023-03-31 10:10:35 -07:00
|
|
|
var testTempDirectory: URL!
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
let testFileManager = FileManager()
|
|
|
|
|
2023-03-29 11:28:24 -07:00
|
|
|
override func setUp() async throws {
|
|
|
|
try await super.setUp()
|
|
|
|
logger = OSLogger(logLevel: .debug)
|
2023-03-31 10:10:35 -07:00
|
|
|
dataDbURL = try! __dataDbURL()
|
|
|
|
spendParamsURL = try! __spendParamsURL()
|
|
|
|
outputParamsURL = try! __outputParamsURL()
|
|
|
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
2022-11-28 22:38:28 -08:00
|
|
|
|
2023-03-31 10:10:35 -07:00
|
|
|
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
|
|
|
|
|
|
|
|
rustBackend = ZcashRustBackend.makeForTests(
|
|
|
|
dbData: dataDbURL,
|
|
|
|
fsBlockDbRoot: testTempDirectory,
|
|
|
|
networkType: network.networkType
|
|
|
|
)
|
2023-02-02 08:58:12 -08:00
|
|
|
|
2022-09-01 05:58:41 -07:00
|
|
|
deleteDBs()
|
2023-05-01 07:28:59 -07:00
|
|
|
|
|
|
|
Dependencies.setup(
|
|
|
|
in: mockContainer,
|
|
|
|
urls: Initializer.URLs(
|
|
|
|
fsBlockDbRoot: testTempDirectory,
|
|
|
|
dataDbURL: dataDbURL,
|
|
|
|
spendParamsURL: spendParamsURL,
|
|
|
|
outputParamsURL: outputParamsURL
|
|
|
|
),
|
|
|
|
alias: .default,
|
|
|
|
networkType: .testnet,
|
|
|
|
endpoint: LightWalletEndpointBuilder.default,
|
|
|
|
loggingPolicy: .default(.debug)
|
|
|
|
)
|
|
|
|
|
|
|
|
mockContainer.mock(type: LatestBlocksDataProvider.self, isSingleton: true) { _ in LatestBlocksDataProviderMock() }
|
|
|
|
mockContainer.mock(type: ZcashRustBackendWelding.self, isSingleton: true) { _ in self.rustBackend }
|
2022-09-01 05:58:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private func deleteDBs() {
|
|
|
|
try? FileManager.default.removeItem(at: dataDbURL)
|
|
|
|
}
|
|
|
|
|
2023-02-02 08:58:12 -08:00
|
|
|
override func tearDownWithError() throws {
|
2022-09-01 05:58:41 -07:00
|
|
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
2023-02-02 08:58:12 -08:00
|
|
|
try super.tearDownWithError()
|
|
|
|
try? testFileManager.removeItem(at: dataDbURL)
|
|
|
|
try? testFileManager.removeItem(at: spendParamsURL)
|
|
|
|
try? testFileManager.removeItem(at: outputParamsURL)
|
|
|
|
try? testFileManager.removeItem(at: testTempDirectory)
|
2023-02-16 08:14:31 -08:00
|
|
|
cancelables = []
|
|
|
|
blockRepository = nil
|
2023-03-31 10:10:35 -07:00
|
|
|
testTempDirectory = nil
|
2022-09-01 05:58:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func testSingleDownloadAndScan() async throws {
|
2023-03-31 10:10:35 -07:00
|
|
|
_ = try await rustBackend.initDataDb(seed: nil)
|
2022-09-01 05:58:41 -07:00
|
|
|
|
2023-02-03 02:23:35 -08:00
|
|
|
let endpoint = LightWalletEndpoint(address: "lightwalletd.testnet.electriccoin.co", port: 9067)
|
2022-09-01 05:58:41 -07:00
|
|
|
let blockCount = 100
|
|
|
|
let range = network.constants.saplingActivationHeight ... network.constants.saplingActivationHeight + blockCount
|
2023-01-31 02:11:00 -08:00
|
|
|
|
2023-02-02 02:05:57 -08:00
|
|
|
let processorConfig = CompactBlockProcessor.Configuration(
|
2023-03-22 05:47:32 -07:00
|
|
|
alias: .default,
|
2023-03-31 10:10:35 -07:00
|
|
|
fsBlockCacheRoot: testTempDirectory,
|
2023-02-02 02:05:57 -08:00
|
|
|
dataDb: dataDbURL,
|
|
|
|
spendParamsURL: spendParamsURL,
|
|
|
|
outputParamsURL: outputParamsURL,
|
2023-02-16 08:27:49 -08:00
|
|
|
saplingParamsSourceURL: SaplingParamsSourceURL.tests,
|
2023-03-10 03:58:28 -08:00
|
|
|
walletBirthdayProvider: { [weak self] in self?.walletBirthDay.height ?? .zero },
|
2023-02-02 02:05:57 -08:00
|
|
|
network: network
|
2022-09-01 05:58:41 -07:00
|
|
|
)
|
2023-02-02 08:58:12 -08:00
|
|
|
|
2023-05-01 07:28:59 -07:00
|
|
|
mockContainer.mock(type: LightWalletService.self, isSingleton: true) { _ in
|
|
|
|
LightWalletServiceFactory(endpoint: endpoint).make()
|
|
|
|
}
|
|
|
|
try await mockContainer.resolve(CompactBlockRepository.self).create()
|
|
|
|
|
|
|
|
let compactBlockProcessor = CompactBlockProcessor(container: mockContainer, config: processorConfig)
|
2022-09-01 05:58:41 -07:00
|
|
|
|
|
|
|
let repository = BlockSQLDAO(dbProvider: SimpleConnectionProvider.init(path: self.dataDbURL.absoluteString, readonly: true))
|
|
|
|
var latestScannedheight = BlockHeight.empty()
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
try await compactBlockProcessor.blockDownloaderService.downloadBlockRange(range)
|
|
|
|
XCTAssertFalse(Task.isCancelled)
|
2023-02-02 02:05:57 -08:00
|
|
|
try await compactBlockProcessor.blockScanner.scanBlocks(at: range, totalProgressRange: range, didScan: { _ in })
|
|
|
|
|
2023-02-02 08:58:12 -08:00
|
|
|
latestScannedheight = repository.lastScannedBlockHeight()
|
|
|
|
XCTAssertEqual(latestScannedheight, range.upperBound)
|
2023-03-29 11:28:24 -07:00
|
|
|
|
|
|
|
await compactBlockProcessor.stop()
|
2022-09-01 05:58:41 -07:00
|
|
|
}
|
2023-02-07 05:22:28 -08:00
|
|
|
|
2023-03-22 05:47:32 -07:00
|
|
|
func observeBenchmark(_ metrics: SDKMetrics) {
|
|
|
|
let reports = metrics.popAllBlockReports(flush: true)
|
2023-02-07 05:22:28 -08:00
|
|
|
|
2022-12-21 04:30:05 -08:00
|
|
|
reports.forEach {
|
|
|
|
print("observed benchmark: \($0)")
|
|
|
|
}
|
2022-09-01 05:58:41 -07:00
|
|
|
}
|
2023-02-07 05:22:28 -08:00
|
|
|
|
2022-09-01 05:58:41 -07:00
|
|
|
func testScanValidateDownload() async throws {
|
2022-10-02 19:11:17 -07:00
|
|
|
let seed = "testreferencealicetestreferencealice"
|
|
|
|
|
2023-03-22 05:47:32 -07:00
|
|
|
let metrics = SDKMetrics()
|
|
|
|
metrics.enableMetrics()
|
2022-12-21 04:30:05 -08:00
|
|
|
|
2023-03-31 10:10:35 -07:00
|
|
|
guard try await rustBackend.initDataDb(seed: nil) == .success else {
|
2022-09-15 07:04:49 -07:00
|
|
|
XCTFail("Seed should not be required for this test")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-10-02 19:11:17 -07:00
|
|
|
let derivationTool = DerivationTool(networkType: .testnet)
|
2023-04-25 07:16:04 -07:00
|
|
|
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(seed: Array(seed.utf8), accountIndex: 0)
|
|
|
|
let viewingKey = try derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
2022-10-02 19:11:17 -07:00
|
|
|
|
2022-11-01 09:57:42 -07:00
|
|
|
do {
|
2023-03-31 10:10:35 -07:00
|
|
|
try await rustBackend.initAccountsTable(ufvks: [viewingKey])
|
2022-11-01 09:57:42 -07:00
|
|
|
} catch {
|
2023-03-31 10:10:35 -07:00
|
|
|
XCTFail("failed to init account table. error: \(error)")
|
2022-09-01 05:58:41 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-31 10:10:35 -07:00
|
|
|
try await rustBackend.initBlocksTable(
|
2022-09-01 05:58:41 -07:00
|
|
|
height: Int32(walletBirthDay.height),
|
|
|
|
hash: walletBirthDay.hash,
|
|
|
|
time: walletBirthDay.time,
|
2023-03-31 10:10:35 -07:00
|
|
|
saplingTree: walletBirthDay.saplingTree
|
2022-09-01 05:58:41 -07:00
|
|
|
)
|
|
|
|
|
2023-04-24 14:15:20 -07:00
|
|
|
let processorConfig = CompactBlockProcessor.Configuration(
|
2023-03-22 05:47:32 -07:00
|
|
|
alias: .default,
|
2023-03-31 10:10:35 -07:00
|
|
|
fsBlockCacheRoot: testTempDirectory,
|
2022-09-01 05:58:41 -07:00
|
|
|
dataDb: dataDbURL,
|
2022-11-28 22:38:28 -08:00
|
|
|
spendParamsURL: spendParamsURL,
|
|
|
|
outputParamsURL: outputParamsURL,
|
2023-02-16 08:27:49 -08:00
|
|
|
saplingParamsSourceURL: SaplingParamsSourceURL.tests,
|
2023-04-24 14:15:20 -07:00
|
|
|
downloadBatchSize: 1000,
|
|
|
|
scanningBatchSize: 1000,
|
2023-03-10 03:58:28 -08:00
|
|
|
walletBirthdayProvider: { [weak self] in self?.network.constants.saplingActivationHeight ?? .zero },
|
2022-09-01 05:58:41 -07:00
|
|
|
network: network
|
|
|
|
)
|
|
|
|
|
2023-05-01 07:28:59 -07:00
|
|
|
mockContainer.mock(type: LightWalletService.self, isSingleton: true) { _ in
|
|
|
|
LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.eccTestnet).make()
|
|
|
|
}
|
|
|
|
try await mockContainer.resolve(CompactBlockRepository.self).create()
|
|
|
|
|
|
|
|
let compactBlockProcessor = CompactBlockProcessor(container: mockContainer, config: processorConfig)
|
2023-02-07 05:22:28 -08:00
|
|
|
|
2023-03-16 02:11:18 -07:00
|
|
|
let eventClosure: CompactBlockProcessor.EventClosure = { [weak self] event in
|
|
|
|
switch event {
|
2023-03-22 05:47:32 -07:00
|
|
|
case .progressUpdated: self?.observeBenchmark(metrics)
|
2023-03-16 02:11:18 -07:00
|
|
|
default: break
|
2023-02-07 05:22:28 -08:00
|
|
|
}
|
2023-03-16 02:11:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
await compactBlockProcessor.updateEventClosure(identifier: "tests", closure: eventClosure)
|
2023-02-07 05:22:28 -08:00
|
|
|
|
2022-09-01 05:58:41 -07:00
|
|
|
let range = CompactBlockRange(
|
|
|
|
uncheckedBounds: (walletBirthDay.height, walletBirthDay.height + 10000)
|
|
|
|
)
|
|
|
|
|
|
|
|
do {
|
2023-03-29 11:28:24 -07:00
|
|
|
let blockDownloader = await compactBlockProcessor.blockDownloader
|
|
|
|
await blockDownloader.setDownloadLimit(range.upperBound)
|
2023-05-08 02:04:29 -07:00
|
|
|
try await blockDownloader.setSyncRange(range)
|
|
|
|
await blockDownloader.startDownload(maxBlockBufferSize: 10)
|
2023-03-29 11:28:24 -07:00
|
|
|
try await blockDownloader.waitUntilRequestedBlocksAreDownloaded(in: range)
|
2023-05-01 07:28:59 -07:00
|
|
|
|
2022-09-01 05:58:41 -07:00
|
|
|
XCTAssertFalse(Task.isCancelled)
|
|
|
|
|
2023-02-01 03:45:09 -08:00
|
|
|
try await compactBlockProcessor.blockValidator.validate()
|
2022-09-01 05:58:41 -07:00
|
|
|
XCTAssertFalse(Task.isCancelled)
|
|
|
|
|
2023-02-02 02:05:57 -08:00
|
|
|
try await compactBlockProcessor.blockScanner.scanBlocks(at: range, totalProgressRange: range, didScan: { _ in })
|
2022-09-01 05:58:41 -07:00
|
|
|
XCTAssertFalse(Task.isCancelled)
|
|
|
|
} catch {
|
2023-04-24 14:15:20 -07:00
|
|
|
if let lwdError = error as? ZcashError {
|
2022-09-01 05:58:41 -07:00
|
|
|
switch lwdError {
|
2023-04-24 14:15:20 -07:00
|
|
|
case .serviceBlockStreamFailed:
|
2022-09-01 05:58:41 -07:00
|
|
|
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)")
|
|
|
|
}
|
|
|
|
}
|
2023-03-29 11:28:24 -07:00
|
|
|
|
|
|
|
await compactBlockProcessor.stop()
|
2023-03-22 05:47:32 -07:00
|
|
|
metrics.disableMetrics()
|
2022-09-01 05:58:41 -07:00
|
|
|
}
|
|
|
|
}
|