2019-10-18 11:45:19 -07:00
|
|
|
//
|
|
|
|
// TestDbBuilder.swift
|
|
|
|
// ZcashLightClientKitTests
|
|
|
|
//
|
|
|
|
// Created by Francisco Gindre on 10/14/19.
|
|
|
|
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import SQLite
|
|
|
|
@testable import ZcashLightClientKit
|
|
|
|
|
2019-11-26 14:32:20 -08:00
|
|
|
struct TestDbHandle {
|
|
|
|
var originalDb: URL
|
|
|
|
var readWriteDb: URL
|
|
|
|
|
|
|
|
init(originalDb: URL) {
|
|
|
|
self.originalDb = originalDb
|
2021-09-23 06:26:41 -07:00
|
|
|
// avoid files clashing because crashing tests failed to remove previous ones by incrementally changing the filename
|
|
|
|
self.readWriteDb = FileManager.default.temporaryDirectory
|
|
|
|
.appendingPathComponent(
|
|
|
|
self.originalDb.lastPathComponent.appending("_\(Date().timeIntervalSince1970)")
|
|
|
|
)
|
2019-11-26 14:32:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func setUp() throws {
|
|
|
|
try FileManager.default.copyItem(at: originalDb, to: readWriteDb)
|
|
|
|
}
|
|
|
|
|
|
|
|
func dispose() {
|
|
|
|
try? FileManager.default.removeItem(at: readWriteDb)
|
|
|
|
}
|
|
|
|
|
|
|
|
func connectionProvider(readwrite: Bool = true) -> ConnectionProvider {
|
|
|
|
SimpleConnectionProvider(path: self.readWriteDb.absoluteString, readonly: !readwrite)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
// This requires reference semantics, an enum cannot be used
|
2023-02-13 03:53:47 -08:00
|
|
|
enum TestDbBuilder {
|
2019-10-18 11:45:19 -07:00
|
|
|
enum TestBuilderError: Error {
|
|
|
|
case generalError
|
|
|
|
}
|
|
|
|
|
2019-11-26 14:32:20 -08:00
|
|
|
static func prePopulatedDataDbURL() -> URL? {
|
2022-02-28 09:03:20 -08:00
|
|
|
Bundle.module.url(forResource: "test_data", withExtension: "db")
|
2019-11-26 14:32:20 -08:00
|
|
|
}
|
2022-04-26 13:45:38 -07:00
|
|
|
|
|
|
|
static func prePopulatedMainnetDataDbURL() -> URL? {
|
2022-10-21 09:54:53 -07:00
|
|
|
Bundle.module.url(forResource: "darkside_data", withExtension: "db")
|
2022-04-26 13:45:38 -07:00
|
|
|
}
|
|
|
|
|
2023-02-02 08:58:12 -08:00
|
|
|
static func prePopulatedDarksideCacheDb() -> URL? {
|
|
|
|
Bundle.module.url(forResource: "darkside_caches", withExtension: "db")
|
|
|
|
}
|
|
|
|
|
2023-03-31 10:10:35 -07:00
|
|
|
static func prepopulatedDataDbProvider(rustBackend: ZcashRustBackendWelding) async throws -> ConnectionProvider? {
|
2022-04-26 13:45:38 -07:00
|
|
|
guard let url = prePopulatedMainnetDataDbURL() else { return nil }
|
2022-10-21 09:54:53 -07:00
|
|
|
|
2019-11-18 11:49:36 -08:00
|
|
|
let provider = SimpleConnectionProvider(path: url.absoluteString, readonly: true)
|
2022-10-21 09:54:53 -07:00
|
|
|
|
2023-03-31 10:10:35 -07:00
|
|
|
let initResult = try await rustBackend.initDataDb(seed: Environment.seedBytes)
|
2022-10-21 09:54:53 -07:00
|
|
|
|
2023-01-18 08:09:04 -08:00
|
|
|
switch initResult {
|
|
|
|
case .success: return provider
|
|
|
|
case .seedRequired:
|
2023-05-05 10:30:47 -07:00
|
|
|
throw ZcashError.compactBlockProcessorDataDbInitFailed("Seed value required to initialize the wallet database")
|
2022-10-20 13:22:24 -07:00
|
|
|
}
|
2019-11-18 11:49:36 -08:00
|
|
|
}
|
|
|
|
|
2023-03-31 10:10:35 -07:00
|
|
|
static func transactionRepository(rustBackend: ZcashRustBackendWelding) async throws -> TransactionRepository? {
|
|
|
|
guard let provider = try await prepopulatedDataDbProvider(rustBackend: rustBackend) else { return nil }
|
2019-11-18 11:49:36 -08:00
|
|
|
|
|
|
|
return TransactionSQLDAO(dbProvider: provider)
|
|
|
|
}
|
2023-04-18 05:10:56 -07:00
|
|
|
|
|
|
|
static func transactionRepository(rustBackend: ZcashRustBackendWelding, withTrace closure: @escaping ((String) -> Void)) async throws -> TransactionRepository? {
|
|
|
|
guard let provider = try await prepopulatedDataDbProvider(rustBackend: rustBackend) else { return nil }
|
|
|
|
|
|
|
|
return TransactionSQLDAO(dbProvider: provider, traceClosure: closure)
|
|
|
|
}
|
2019-10-18 13:09:13 -07:00
|
|
|
|
2022-10-03 16:05:11 -07:00
|
|
|
static func seed(db: CompactBlockRepository, with blockRange: CompactBlockRange) async throws {
|
2019-10-18 11:45:19 -07:00
|
|
|
guard let blocks = StubBlockCreator.createBlockRange(blockRange) else {
|
|
|
|
throw TestBuilderError.generalError
|
|
|
|
}
|
|
|
|
|
2022-10-03 16:05:11 -07:00
|
|
|
try await db.write(blocks: blocks)
|
2019-10-18 11:45:19 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-04 02:03:52 -07:00
|
|
|
class InMemoryDbProvider: ConnectionProvider {
|
2019-10-30 13:18:57 -07:00
|
|
|
var readonly: Bool
|
2022-11-04 02:03:52 -07:00
|
|
|
var conn: Connection?
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2019-11-04 15:18:07 -08:00
|
|
|
init(readonly: Bool = false) throws {
|
2019-10-30 13:18:57 -07:00
|
|
|
self.readonly = readonly
|
|
|
|
}
|
|
|
|
|
|
|
|
func connection() throws -> Connection {
|
2022-11-04 02:03:52 -07:00
|
|
|
guard let conn else {
|
|
|
|
let newConnection = try Connection(.inMemory, readonly: readonly)
|
|
|
|
self.conn = newConnection
|
|
|
|
return newConnection
|
|
|
|
}
|
|
|
|
return conn
|
|
|
|
}
|
|
|
|
|
|
|
|
func close() {
|
|
|
|
self.conn = nil
|
2019-10-30 13:18:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-23 06:26:41 -07:00
|
|
|
enum StubBlockCreator {
|
2023-02-02 08:58:12 -08:00
|
|
|
static func createRandomBlockMeta() -> ZcashCompactBlock.Meta {
|
|
|
|
ZcashCompactBlock.Meta(
|
|
|
|
hash: randomData(ofLength: 32)!,
|
|
|
|
time: UInt32(Date().timeIntervalSince1970),
|
|
|
|
saplingOutputs: UInt32.random(in: 0 ... 32),
|
|
|
|
orchardOutputs: UInt32.random(in: 0 ... 32)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-10-18 11:45:19 -07:00
|
|
|
static func createRandomDataBlock(with height: BlockHeight) -> ZcashCompactBlock? {
|
|
|
|
guard let data = randomData(ofLength: 100) else {
|
2020-03-09 13:25:27 -07:00
|
|
|
LoggerProxy.debug("error creating stub block")
|
2019-10-18 11:45:19 -07:00
|
|
|
return nil
|
|
|
|
}
|
2023-02-02 08:58:12 -08:00
|
|
|
return ZcashCompactBlock(height: height, data: data, meta: createRandomBlockMeta())
|
2019-10-18 11:45:19 -07:00
|
|
|
}
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2019-10-18 11:45:19 -07:00
|
|
|
static func createBlockRange(_ range: CompactBlockRange) -> [ZcashCompactBlock]? {
|
2021-09-23 06:26:41 -07:00
|
|
|
var blocks: [ZcashCompactBlock] = []
|
2019-10-18 11:45:19 -07:00
|
|
|
for height in range {
|
|
|
|
guard let block = createRandomDataBlock(with: height) else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
blocks.append(block)
|
|
|
|
}
|
|
|
|
|
|
|
|
return blocks
|
|
|
|
}
|
|
|
|
|
|
|
|
static func randomData(ofLength length: Int) -> Data? {
|
|
|
|
var bytes = [UInt8](repeating: 0, count: length)
|
|
|
|
let status = SecRandomCopyBytes(kSecRandomDefault, length, &bytes)
|
|
|
|
if status == errSecSuccess {
|
|
|
|
return Data(bytes: &bytes, count: bytes.count)
|
|
|
|
}
|
2020-03-09 13:25:27 -07:00
|
|
|
LoggerProxy.debug("Status \(status)")
|
2021-09-23 06:26:41 -07:00
|
|
|
|
2019-10-18 11:45:19 -07:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|