2019-11-14 06:38:54 -08:00
|
|
|
//
|
|
|
|
// 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
|
2019-11-14 06:38:54 -08:00
|
|
|
@testable import ZcashLightClientKit
|
2021-09-23 06:26:41 -07:00
|
|
|
|
|
|
|
// swiftlint:disable implicitly_unwrapped_optional force_try
|
2019-11-14 06:38:54 -08:00
|
|
|
class CompactBlockReorgTests: XCTestCase {
|
2023-02-09 04:58:49 -08:00
|
|
|
lazy var processorConfig = {
|
|
|
|
let pathProvider = DefaultResourceProvider(network: network)
|
|
|
|
return CompactBlockProcessor.Configuration(
|
|
|
|
fsBlockCacheRoot: testTempDirectory,
|
|
|
|
dataDb: pathProvider.dataDbURL,
|
|
|
|
spendParamsURL: pathProvider.spendParamsURL,
|
|
|
|
outputParamsURL: pathProvider.outputParamsURL,
|
|
|
|
walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight,
|
|
|
|
network: ZcashNetworkBuilder.network(for: .testnet)
|
|
|
|
)
|
|
|
|
}()
|
|
|
|
|
2023-02-02 08:58:12 -08:00
|
|
|
let testTempDirectory = URL(fileURLWithPath: NSString(
|
|
|
|
string: NSTemporaryDirectory()
|
|
|
|
)
|
|
|
|
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
|
|
|
|
|
|
let testFileManager = FileManager()
|
|
|
|
|
2019-11-14 06:38:54 -08:00
|
|
|
var processor: CompactBlockProcessor!
|
2022-12-01 08:57:13 -08:00
|
|
|
var syncStartedExpect: XCTestExpectation!
|
2019-11-14 06:38:54 -08:00
|
|
|
var updatedNotificationExpectation: XCTestExpectation!
|
|
|
|
var stopNotificationExpectation: 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
|
2019-11-14 06:38:54 -08:00
|
|
|
|
2021-07-28 15:25:47 -07:00
|
|
|
override func setUpWithError() throws {
|
2021-09-23 06:26:41 -07:00
|
|
|
try super.setUpWithError()
|
2023-02-02 08:58:12 -08:00
|
|
|
try self.testFileManager.createDirectory(at: self.testTempDirectory, withIntermediateDirectories: false)
|
2023-01-26 09:14:07 -08:00
|
|
|
logger = OSLogger(logLevel: .debug)
|
|
|
|
|
2023-02-09 04:58:49 -08:00
|
|
|
XCTestCase.wait { await InternalSyncProgress(storage: UserDefaults.standard).rewind(to: 0) }
|
|
|
|
|
2023-02-03 02:23:35 -08:00
|
|
|
let liveService = LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.eccTestnet, connectionStateChange: { _, _ in }).make()
|
2021-09-23 06:26:41 -07:00
|
|
|
let service = MockLightWalletService(
|
|
|
|
latestBlockHeight: mockLatestHeight,
|
2023-02-03 02:23:35 -08:00
|
|
|
service: liveService
|
2021-09-23 06:26:41 -07:00
|
|
|
)
|
2023-02-03 02:23:35 -08:00
|
|
|
|
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
|
|
|
}
|
2023-02-02 08:58:12 -08:00
|
|
|
|
|
|
|
let realRustBackend = ZcashRustBackend.self
|
|
|
|
|
|
|
|
let realCache = FSCompactBlockRepository(
|
2023-02-09 04:58:49 -08:00
|
|
|
fsBlockDbRoot: processorConfig.fsBlockCacheRoot,
|
2023-02-02 08:58:12 -08:00
|
|
|
metadataStore: FSMetadataStore.live(
|
2023-02-09 04:58:49 -08:00
|
|
|
fsBlockDbRoot: processorConfig.fsBlockCacheRoot,
|
2023-02-02 08:58:12 -08:00
|
|
|
rustBackend: realRustBackend
|
|
|
|
),
|
|
|
|
blockDescriptor: .live,
|
|
|
|
contentProvider: DirectoryListingProviders.defaultSorted
|
|
|
|
)
|
|
|
|
|
|
|
|
try realCache.create()
|
|
|
|
|
|
|
|
guard case .success = try realRustBackend.initDataDb(dbData: processorConfig.dataDb, seed: nil, networkType: .testnet) else {
|
2022-10-31 05:57:10 -07:00
|
|
|
XCTFail("initDataDb failed. Expected Success but got .seedRequired")
|
2023-01-18 08:09:04 -08:00
|
|
|
return
|
2022-10-31 05:57:10 -07:00
|
|
|
}
|
2023-02-02 08:58:12 -08:00
|
|
|
|
2019-11-14 06:38:54 -08:00
|
|
|
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
|
2019-11-14 06:38:54 -08:00
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
processor = CompactBlockProcessor(
|
|
|
|
service: service,
|
2023-02-02 08:58:12 -08:00
|
|
|
storage: realCache,
|
2021-09-23 06:26:41 -07:00
|
|
|
backend: mockBackend,
|
|
|
|
config: processorConfig
|
|
|
|
)
|
2019-11-14 06:38:54 -08:00
|
|
|
|
2022-12-01 08:57:13 -08:00
|
|
|
syncStartedExpect = XCTestExpectation(description: "\(self.description) syncStartedExpect")
|
2021-09-23 06:26:41 -07:00
|
|
|
stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation")
|
|
|
|
updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation")
|
|
|
|
idleNotificationExpectation = XCTestExpectation(description: "\(self.description) idleNotificationExpectation")
|
|
|
|
reorgNotificationExpectation = XCTestExpectation(description: "\(self.description) reorgNotificationExpectation")
|
2019-11-14 06:38:54 -08:00
|
|
|
|
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
|
|
|
|
)
|
2019-11-14 06:38:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
override func tearDown() {
|
2021-09-23 06:26:41 -07:00
|
|
|
super.tearDown()
|
2023-02-02 08:58:12 -08:00
|
|
|
try! FileManager.default.removeItem(at: processorConfig.fsBlockCacheRoot)
|
2019-11-14 06:38:54 -08:00
|
|
|
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
2022-12-01 08:57:13 -08:00
|
|
|
syncStartedExpect.unsubscribeFromNotifications()
|
2019-11-14 06:38:54 -08:00
|
|
|
stopNotificationExpectation.unsubscribeFromNotifications()
|
|
|
|
updatedNotificationExpectation.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")
|
|
|
|
}
|
2019-11-14 06:38:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
@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")
|
|
|
|
}
|
2019-11-14 06:38:54 -08:00
|
|
|
}
|
|
|
|
|
2022-10-27 03:51:38 -07:00
|
|
|
private func startProcessing() async {
|
2019-11-14 06:38:54 -08:00
|
|
|
XCTAssertNotNil(processor)
|
|
|
|
|
|
|
|
// Subscribe to notifications
|
2022-12-01 08:57:13 -08:00
|
|
|
syncStartedExpect.subscribe(to: Notification.Name.blockProcessorStartedSyncing, object: processor)
|
2019-11-14 06:38:54 -08:00
|
|
|
stopNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStopped, object: processor)
|
|
|
|
updatedNotificationExpectation.subscribe(to: Notification.Name.blockProcessorUpdated, object: processor)
|
2021-07-28 15:25:47 -07:00
|
|
|
idleNotificationExpectation.subscribe(to: Notification.Name.blockProcessorFinished, object: processor)
|
2019-11-14 06:38:54 -08:00
|
|
|
reorgNotificationExpectation.subscribe(to: Notification.Name.blockProcessorHandledReOrg, object: processor)
|
2022-10-31 05:57:10 -07:00
|
|
|
|
|
|
|
await processor.start()
|
2019-11-14 06:38:54 -08:00
|
|
|
}
|
|
|
|
|
2022-10-27 03:51:38 -07:00
|
|
|
func testNotifiesReorg() async {
|
|
|
|
await startProcessing()
|
2021-09-23 06:26:41 -07:00
|
|
|
|
|
|
|
wait(
|
|
|
|
for: [
|
2022-12-01 08:57:13 -08:00
|
|
|
syncStartedExpect,
|
2021-09-23 06:26:41 -07:00
|
|
|
reorgNotificationExpectation,
|
|
|
|
idleNotificationExpectation
|
|
|
|
],
|
|
|
|
timeout: 300,
|
|
|
|
enforceOrder: true
|
|
|
|
)
|
2019-11-14 06:38:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int {
|
2021-09-23 06:26:41 -07:00
|
|
|
(abs(currentHeight - targetHeight) / batchSize)
|
2019-11-14 06:38:54 -08:00
|
|
|
}
|
|
|
|
}
|