ZcashLightClientKit/Sources/ZcashLightClientKit/Block/Scan/BlockScanner.swift

95 lines
3.3 KiB
Swift

//
// CompactBlockProcessing.swift
// ZcashLightClientKit
//
// Created by Francisco Gindre on 10/15/19.
// Copyright © 2019 Electric Coin Company. All rights reserved.
//
import Foundation
struct BlockScannerConfig {
let networkType: NetworkType
let scanningBatchSize: Int
}
protocol BlockScanner {
func scanBlocks(at range: CompactBlockRange, totalProgressRange: CompactBlockRange, didScan: @escaping (BlockHeight) async -> Void) async throws
}
struct BlockScannerImpl {
let config: BlockScannerConfig
let rustBackend: ZcashRustBackendWelding
let transactionRepository: TransactionRepository
let metrics: SDKMetrics
let logger: Logger
}
extension BlockScannerImpl: BlockScanner {
func scanBlocks(at range: CompactBlockRange, totalProgressRange: CompactBlockRange, didScan: @escaping (BlockHeight) async -> Void) async throws {
try Task.checkCancellation()
let scanStartHeight = try await transactionRepository.lastScannedHeight()
let targetScanHeight = range.upperBound
var scannedNewBlocks = false
var lastScannedHeight = scanStartHeight
repeat {
try Task.checkCancellation()
let previousScannedHeight = lastScannedHeight
// TODO: [#576] remove this arbitrary batch size https://github.com/zcash/ZcashLightClientKit/issues/576
let batchSize = scanBatchSize(startScanHeight: previousScannedHeight + 1, network: config.networkType)
let scanStartTime = Date()
do {
try await self.rustBackend.scanBlocks(limit: batchSize)
} catch {
logger.debug("block scanning failed with error: \(String(describing: error))")
throw error
}
let scanFinishTime = Date()
lastScannedHeight = try await transactionRepository.lastScannedHeight()
scannedNewBlocks = previousScannedHeight != lastScannedHeight
if scannedNewBlocks {
await didScan(lastScannedHeight)
let progress = BlockProgress(
startHeight: totalProgressRange.lowerBound,
targetHeight: totalProgressRange.upperBound,
progressHeight: lastScannedHeight
)
metrics.pushProgressReport(
progress: progress,
start: scanStartTime,
end: scanFinishTime,
batchSize: Int(batchSize),
operation: .scanBlocks
)
let heightCount = lastScannedHeight - previousScannedHeight
let seconds = scanFinishTime.timeIntervalSinceReferenceDate - scanStartTime.timeIntervalSinceReferenceDate
logger.debug("Scanned \(heightCount) blocks in \(seconds) seconds")
}
await Task.yield()
} while !Task.isCancelled && scannedNewBlocks && lastScannedHeight < targetScanHeight
}
private func scanBatchSize(startScanHeight height: BlockHeight, network: NetworkType) -> UInt32 {
assert(config.scanningBatchSize > 0, "ZcashSDK.DefaultScanningBatch must be larger than 0!")
guard network == .mainnet else { return UInt32(config.scanningBatchSize) }
if height > 1_600_000 {
return 5
}
return UInt32(config.scanningBatchSize)
}
}