ZcashLightClientKit/Tests/DarksideTests/TransactionEnhancementTests...

253 lines
9.3 KiB
Swift

//
// TransactionEnhancementTests.swift
// ZcashLightClientKit-Unit-Tests
//
// Created by Francisco Gindre on 4/15/20.
//
import Combine
import XCTest
@testable import TestUtils
@testable import ZcashLightClientKit
class TransactionEnhancementTests: ZcashTestCase {
var cancellables: [AnyCancellable] = []
var processorEventHandler: CompactBlockProcessorEventHandler! = CompactBlockProcessorEventHandler()
let mockLatestHeight = BlockHeight(663250)
let targetLatestHeight = BlockHeight(663251)
let walletBirthday = BlockHeight(663150)
let network = DarksideWalletDNetwork()
let branchID = "2bb40e60"
let chainName = "main"
var testTempDirectory: URL!
let testFileManager = FileManager()
var initializer: Initializer!
var processorConfig: CompactBlockProcessor.Configuration!
var processor: CompactBlockProcessor!
var rustBackend: ZcashRustBackendWelding!
var darksideWalletService: DarksideWalletService!
var downloader: BlockDownloaderServiceImpl!
var syncStartedExpect: XCTestExpectation!
var updatedNotificationExpectation: XCTestExpectation!
var stopNotificationExpectation: XCTestExpectation!
var finishedNotificationExpectation: XCTestExpectation!
var reorgNotificationExpectation: XCTestExpectation!
var afterReorgIdleNotification: XCTestExpectation!
var txFoundNotificationExpectation: XCTestExpectation!
var waitExpectation: XCTestExpectation!
override func setUp() async throws {
try await super.setUp()
testTempDirectory = Environment.uniqueTestTempDirectory
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
await InternalSyncProgress(
alias: .default,
storage: UserDefaults.standard,
logger: logger
).rewind(to: 0)
logger = OSLogger(logLevel: .debug)
syncStartedExpect = XCTestExpectation(description: "\(self.description) syncStartedExpect")
stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation")
updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation")
finishedNotificationExpectation = XCTestExpectation(description: "\(self.description) finishedNotificationExpectation")
afterReorgIdleNotification = XCTestExpectation(description: "\(self.description) afterReorgIdleNotification")
reorgNotificationExpectation = XCTestExpectation(description: "\(self.description) reorgNotificationExpectation")
txFoundNotificationExpectation = XCTestExpectation(description: "\(self.description) txFoundNotificationExpectation")
waitExpectation = XCTestExpectation(description: "\(self.description) waitExpectation")
let birthday = Checkpoint.birthday(with: walletBirthday, network: network)
let pathProvider = DefaultResourceProvider(network: network)
processorConfig = CompactBlockProcessor.Configuration(
alias: .default,
fsBlockCacheRoot: testTempDirectory,
dataDb: pathProvider.dataDbURL,
spendParamsURL: pathProvider.spendParamsURL,
outputParamsURL: pathProvider.outputParamsURL,
saplingParamsSourceURL: SaplingParamsSourceURL.tests,
walletBirthdayProvider: { birthday.height },
network: network
)
rustBackend = ZcashRustBackend.makeForTests(
dbData: processorConfig.dataDb,
fsBlockDbRoot: testTempDirectory,
networkType: network.networkType
)
try? FileManager.default.removeItem(at: processorConfig.fsBlockCacheRoot)
try? FileManager.default.removeItem(at: processorConfig.dataDb)
let dbInit = try await rustBackend.initDataDb(seed: nil)
let derivationTool = DerivationTool(networkType: network.networkType)
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(seed: Environment.seedBytes, accountIndex: 0)
let viewingKey = try derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
do {
try await rustBackend.initAccountsTable(ufvks: [viewingKey])
} catch {
XCTFail("Failed to init accounts table error: \(error)")
return
}
guard case .success = dbInit else {
XCTFail("Failed to initDataDb. Expected `.success` got: \(String(describing: dbInit))")
return
}
_ = try await rustBackend.initBlocksTable(
height: Int32(birthday.height),
hash: birthday.hash,
time: birthday.time,
saplingTree: birthday.saplingTree
)
let service = DarksideWalletService()
darksideWalletService = service
let storage = FSCompactBlockRepository(
fsBlockDbRoot: testTempDirectory,
metadataStore: FSMetadataStore.live(
fsBlockDbRoot: testTempDirectory,
rustBackend: rustBackend,
logger: logger
),
blockDescriptor: .live,
contentProvider: DirectoryListingProviders.defaultSorted,
logger: logger
)
try! await storage.create()
let transactionRepository = MockTransactionRepository(
unminedCount: 0,
receivedCount: 0,
sentCount: 0,
scannedHeight: 0,
network: network
)
downloader = BlockDownloaderServiceImpl(service: service, storage: storage)
Dependencies.setup(
in: mockContainer,
urls: Initializer.URLs(
fsBlockDbRoot: testTempDirectory,
dataDbURL: pathProvider.dataDbURL,
spendParamsURL: pathProvider.spendParamsURL,
outputParamsURL: pathProvider.outputParamsURL
),
alias: .default,
networkType: .testnet,
endpoint: LightWalletEndpointBuilder.default,
loggingPolicy: .default(.debug)
)
mockContainer.mock(type: LatestBlocksDataProvider.self, isSingleton: true) { _ in
LatestBlocksDataProviderImpl(service: service, transactionRepository: transactionRepository)
}
mockContainer.mock(type: ZcashRustBackendWelding.self, isSingleton: true) { _ in self.rustBackend }
processor = CompactBlockProcessor(
container: mockContainer,
config: processorConfig
)
let eventClosure: CompactBlockProcessor.EventClosure = { [weak self] event in
switch event {
case .failed: self?.processorFailed(event: event)
default: break
}
}
await self.processor.updateEventClosure(identifier: "tests", closure: eventClosure)
}
override func tearDown() async throws {
try await super.tearDown()
await self.processor.stop()
try? FileManager.default.removeItem(at: processorConfig.fsBlockCacheRoot)
try? FileManager.default.removeItem(at: processorConfig.dataDb)
processorEventHandler = nil
initializer = nil
processorConfig = nil
processor = nil
darksideWalletService = nil
downloader = nil
testTempDirectory = nil
}
private func startProcessing() async throws {
XCTAssertNotNil(processor)
let expectations: [CompactBlockProcessorEventHandler.EventIdentifier: XCTestExpectation] = [
.startedSyncing: syncStartedExpect,
.stopped: stopNotificationExpectation,
.progressUpdated: updatedNotificationExpectation,
.foundTransactions: txFoundNotificationExpectation,
.finished: finishedNotificationExpectation
]
await processorEventHandler.subscribe(to: processor, expectations: expectations)
await processor.start()
}
func testBasicEnhancement() async throws {
let targetLatestHeight = BlockHeight(663200)
do {
try FakeChainBuilder.buildChain(darksideWallet: darksideWalletService, branchID: branchID, chainName: chainName)
try darksideWalletService.applyStaged(nextLatestHeight: targetLatestHeight)
} catch {
XCTFail("Error: \(error)")
return
}
sleep(3)
/**
connect to dLWD
request latest height -> receive firstLatestHeight
*/
do {
dump("first latest height: \(try await darksideWalletService.latestBlockHeight())")
} catch {
XCTFail("Error: \(error)")
return
}
/**
download and sync blocks from walletBirthday to firstLatestHeight
*/
do {
try await startProcessing()
} catch {
XCTFail("Error: \(error)")
}
await fulfillment(
of: [
syncStartedExpect,
txFoundNotificationExpectation,
finishedNotificationExpectation
],
timeout: 30
)
}
func processorFailed(event: CompactBlockProcessor.Event) {
if case let .failed(error) = event {
XCTFail("CompactBlockProcessor failed with Error: \(error)")
} else {
XCTFail("CompactBlockProcessor failed")
}
}
}