ZcashLightClientKit/Tests/NetworkTests/CompactBlockReorgTests.swift

168 lines
7.8 KiB
Swift
Raw Normal View History

//
// CompactBlockReorgTests.swift
// ZcashLightClientKit-Unit-Tests
//
// Created by Francisco Gindre on 11/13/19.
//
// Copyright © 2019 Electric Coin Company. All rights reserved.
import XCTest
2022-02-28 09:03:20 -08:00
@testable import TestUtils
@testable import ZcashLightClientKit
2021-09-23 06:26:41 -07:00
// swiftlint:disable implicitly_unwrapped_optional force_try
class CompactBlockReorgTests: XCTestCase {
2021-09-23 06:26:41 -07:00
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!
var reorgNotificationExpectation: XCTestExpectation!
2021-07-28 09:59:10 -07:00
let network = ZcashNetworkBuilder.network(for: .testnet)
2021-09-15 05:21:29 -07:00
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
2021-07-28 15:25:47 -07:00
override func setUpWithError() throws {
2021-09-23 06:26:41 -07:00
try super.setUpWithError()
2021-07-28 15:25:47 -07:00
logger = SampleLogger(logLevel: .debug)
2021-09-23 06:26:41 -07:00
let service = MockLightWalletService(
latestBlockHeight: mockLatestHeight,
service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)
)
2021-07-28 15:25:47 -07:00
let branchID = try ZcashRustBackend.consensusBranchIdFor(height: Int32(mockLatestHeight), networkType: network.networkType)
2021-09-23 06:26:41 -07:00
service.mockLightDInfo = LightdInfo.with { info in
2021-07-28 15:25:47 -07:00
info.blockHeight = UInt64(mockLatestHeight)
info.branch = "asdf"
info.buildDate = "today"
info.buildUser = "testUser"
info.chainName = "test"
info.consensusBranchID = branchID.toString()
info.estimatedHeight = UInt64(mockLatestHeight)
2021-09-15 05:21:29 -07:00
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
2021-09-23 06:26:41 -07:00
}
2021-07-28 15:25:47 -07:00
2022-10-31 05:57:10 -07:00
guard case .success = try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, seed: nil, networkType: .testnet) else {
XCTFail("initDataDb failed. Expected Success but got .seedRequired")
return
}
2021-07-28 15:25:47 -07:00
let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString))
try! storage.createTable()
let mockBackend = MockRustBackend.self
mockBackend.mockValidateCombinedChainFailAfterAttempts = 3
mockBackend.mockValidateCombinedChainKeepFailing = false
2021-09-15 05:21:29 -07:00
mockBackend.mockValidateCombinedChainFailureHeight = self.network.constants.saplingActivationHeight + 320
2021-09-23 06:26:41 -07:00
processor = CompactBlockProcessor(
service: service,
storage: storage,
backend: mockBackend,
config: processorConfig
)
2021-09-23 06:26:41 -07:00
downloadStartedExpect = XCTestExpectation(description: "\(self.description) downloadStartedExpect")
stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation")
updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation")
startedValidatingNotificationExpectation = XCTestExpectation(
description: "\(self.description) startedValidatingNotificationExpectation"
)
startedScanningNotificationExpectation = XCTestExpectation(
description: "\(self.description) startedScanningNotificationExpectation"
)
idleNotificationExpectation = XCTestExpectation(description: "\(self.description) idleNotificationExpectation")
reorgNotificationExpectation = XCTestExpectation(description: "\(self.description) reorgNotificationExpectation")
2021-09-23 06:26:41 -07:00
NotificationCenter.default.addObserver(
self,
selector: #selector(processorHandledReorg(_:)),
name: Notification.Name.blockProcessorHandledReOrg,
object: processor
)
NotificationCenter.default.addObserver(
self,
selector: #selector(processorFailed(_:)),
name: Notification.Name.blockProcessorFailed,
object: processor
)
}
override func tearDown() {
2021-09-23 06:26:41 -07:00
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()
reorgNotificationExpectation.unsubscribeFromNotifications()
NotificationCenter.default.removeObserver(self)
}
@objc func processorHandledReorg(_ notification: Notification) {
2021-09-23 06:26:41 -07:00
XCTAssertNotNil(notification.userInfo)
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
XCTAssertTrue( reorg == 0 || reorg > self.network.constants.saplingActivationHeight)
XCTAssertTrue( rewind == 0 || rewind > self.network.constants.saplingActivationHeight)
XCTAssertTrue( rewind <= reorg )
reorgNotificationExpectation.fulfill()
} else {
XCTFail("CompactBlockProcessor reorg notification is malformed")
}
}
@objc func processorFailed(_ notification: Notification) {
2021-09-23 06:26:41 -07:00
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)
2021-07-28 15:25:47 -07:00
idleNotificationExpectation.subscribe(to: Notification.Name.blockProcessorFinished, object: processor)
reorgNotificationExpectation.subscribe(to: Notification.Name.blockProcessorHandledReOrg, object: processor)
2022-10-31 05:57:10 -07:00
await processor.start()
}
func testNotifiesReorg() async {
await startProcessing()
2021-09-23 06:26:41 -07:00
wait(
for: [
downloadStartedExpect,
startedValidatingNotificationExpectation,
startedScanningNotificationExpectation,
reorgNotificationExpectation,
idleNotificationExpectation
],
timeout: 300,
enforceOrder: true
)
}
private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int {
2021-09-23 06:26:41 -07:00
(abs(currentHeight - targetHeight) / batchSize)
}
}