ZcashLightClientKit/Tests/NetworkTests/CompactBlockProcessorTests....

226 lines
9.7 KiB
Swift

//
// CompactBlockProcessorTests.swift
// ZcashLightClientKitTests
//
// Created by Francisco Gindre on 20/09/2019.
// Copyright © 2019 Electric Coin Company. All rights reserved.
//
import XCTest
@testable import TestUtils
@testable import ZcashLightClientKit
// swiftlint:disable force_try implicitly_unwrapped_optional
class CompactBlockProcessorTests: XCTestCase {
let processorConfig = CompactBlockProcessor.Configuration.standard(
for: ZcashNetworkBuilder.network(for: .testnet),
walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight
)
var processor: CompactBlockProcessor!
var downloadStartedExpect: XCTestExpectation!
var updatedNotificationExpectation: XCTestExpectation!
var stopNotificationExpectation: XCTestExpectation!
var startedScanningNotificationExpectation: XCTestExpectation!
var startedValidatingNotificationExpectation: XCTestExpectation!
var idleNotificationExpectation: XCTestExpectation!
let network = ZcashNetworkBuilder.network(for: .testnet)
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
override func setUpWithError() throws {
try super.setUpWithError()
logger = SampleLogger(logLevel: .debug)
let service = MockLightWalletService(
latestBlockHeight: mockLatestHeight,
service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)
)
let branchID = try ZcashRustBackend.consensusBranchIdFor(height: Int32(mockLatestHeight), networkType: network.networkType)
service.mockLightDInfo = LightdInfo.with({ info in
info.blockHeight = UInt64(mockLatestHeight)
info.branch = "asdf"
info.buildDate = "today"
info.buildUser = "testUser"
info.chainName = "test"
info.consensusBranchID = branchID.toString()
info.estimatedHeight = UInt64(mockLatestHeight)
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
})
let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString))
try! storage.createTable()
processor = CompactBlockProcessor(
service: service,
storage: storage,
backend: ZcashRustBackend.self,
config: processorConfig
)
let dbInit = try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, seed: nil, networkType: .testnet)
guard case .success = dbInit else {
XCTFail("Failed to initDataDb. Expected `.success` got: \(dbInit)")
return
}
downloadStartedExpect = XCTestExpectation(description: "\(self.description) downloadStartedExpect")
stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation")
updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation")
startedValidatingNotificationExpectation = XCTestExpectation(
description: "\(self.description) startedValidatingNotificationExpectation"
)
startedScanningNotificationExpectation = XCTestExpectation(
description: "\(self.description) startedScanningNotificationExpectation"
)
idleNotificationExpectation = XCTestExpectation(description: "\(self.description) idleNotificationExpectation")
NotificationCenter.default.addObserver(
self,
selector: #selector(processorFailed(_:)),
name: Notification.Name.blockProcessorFailed,
object: processor
)
}
override func tearDown() {
super.tearDown()
try! FileManager.default.removeItem(at: processorConfig.cacheDb)
try? FileManager.default.removeItem(at: processorConfig.dataDb)
downloadStartedExpect.unsubscribeFromNotifications()
stopNotificationExpectation.unsubscribeFromNotifications()
updatedNotificationExpectation.unsubscribeFromNotifications()
startedScanningNotificationExpectation.unsubscribeFromNotifications()
startedValidatingNotificationExpectation.unsubscribeFromNotifications()
idleNotificationExpectation.unsubscribeFromNotifications()
NotificationCenter.default.removeObserver(self)
}
@objc func processorFailed(_ notification: Notification) {
XCTAssertNotNil(notification.userInfo)
if let error = notification.userInfo?["error"] {
XCTFail("CompactBlockProcessor failed with Error: \(error)")
} else {
XCTFail("CompactBlockProcessor failed")
}
}
private func startProcessing() async {
XCTAssertNotNil(processor)
// Subscribe to notifications
downloadStartedExpect.subscribe(to: Notification.Name.blockProcessorStartedDownloading, object: processor)
stopNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStopped, object: processor)
updatedNotificationExpectation.subscribe(to: Notification.Name.blockProcessorUpdated, object: processor)
startedValidatingNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedValidating, object: processor)
startedScanningNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedScanning, object: processor)
idleNotificationExpectation.subscribe(to: Notification.Name.blockProcessorIdle, object: processor)
do {
try await processor.start()
} catch {
XCTFail("shouldn't fail")
}
}
// FIXME: disabled see https://github.com/zcash/ZcashLightClientKit/issues/590
func testStartNotifiesSuscriptors() async {
await startProcessing()
wait(
for: [
downloadStartedExpect,
startedValidatingNotificationExpectation,
startedScanningNotificationExpectation,
idleNotificationExpectation
],
timeout: 30,
enforceOrder: false
)
}
// FIXME: disabled see https://github.com/zcash/ZcashLightClientKit/issues/590
func testProgressNotifications() async {
let expectedUpdates = expectedBatches(
currentHeight: processorConfig.walletBirthday,
targetHeight: mockLatestHeight,
batchSize: processorConfig.downloadBatchSize
)
updatedNotificationExpectation.expectedFulfillmentCount = expectedUpdates
await startProcessing()
wait(for: [updatedNotificationExpectation], timeout: 300)
}
private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int {
(abs(currentHeight - targetHeight) / batchSize)
}
func testNextBatchBlockRange() {
// test first range
var latestDownloadedHeight = processorConfig.walletBirthday // this can be either this or Wallet Birthday.
var latestBlockchainHeight = BlockHeight(network.constants.saplingActivationHeight + 1000)
var expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight, upper:latestBlockchainHeight))
XCTAssertEqual(
expectedBatchRange,
CompactBlockProcessor.nextBatchBlockRange(
latestHeight: latestBlockchainHeight,
latestDownloadedHeight: latestDownloadedHeight,
walletBirthday: processorConfig.walletBirthday
)
)
// Test mid-range
latestDownloadedHeight = BlockHeight(network.constants.saplingActivationHeight + ZcashSDK.DefaultDownloadBatch)
latestBlockchainHeight = BlockHeight(network.constants.saplingActivationHeight + 1000)
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
XCTAssertEqual(
expectedBatchRange,
CompactBlockProcessor.nextBatchBlockRange(
latestHeight: latestBlockchainHeight,
latestDownloadedHeight: latestDownloadedHeight,
walletBirthday: processorConfig.walletBirthday
)
)
// Test last batch range
latestDownloadedHeight = BlockHeight(network.constants.saplingActivationHeight + 950)
latestBlockchainHeight = BlockHeight(network.constants.saplingActivationHeight + 1000)
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
XCTAssertEqual(
expectedBatchRange,
CompactBlockProcessor.nextBatchBlockRange(
latestHeight: latestBlockchainHeight,
latestDownloadedHeight: latestDownloadedHeight,
walletBirthday: processorConfig.walletBirthday
)
)
}
func testDetermineLowerBoundPastBirthday() async {
let errorHeight = 781_906
let walletBirthday = 781_900
let result = await processor.determineLowerBound(errorHeight: errorHeight, consecutiveErrors: 1, walletBirthday: walletBirthday)
let expected = 781_886
XCTAssertEqual(result, expected)
}
func testDetermineLowerBound() async {
let errorHeight = 781_906
let walletBirthday = 780_900
let result = await processor.determineLowerBound(errorHeight: errorHeight, consecutiveErrors: 0, walletBirthday: walletBirthday)
let expected = 781_896
XCTAssertEqual(result, expected)
}
}