From d8f189a7993da34dc662e58c0be39a22a463fb17 Mon Sep 17 00:00:00 2001 From: Michal Fousek Date: Wed, 10 May 2023 14:42:54 +0200 Subject: [PATCH] [#1043] Implement DownloadAction Closes #1043 --- .../Block/Actions/DownloadAction.swift | 41 ++++++++++++------- .../Block/CompactBlockProcessorNG.swift | 24 ++++------- .../Block/Download/BlockDownloader.swift | 1 + .../Constants/ZcashSDK.swift | 4 ++ 4 files changed, 40 insertions(+), 30 deletions(-) diff --git a/Sources/ZcashLightClientKit/Block/Actions/DownloadAction.swift b/Sources/ZcashLightClientKit/Block/Actions/DownloadAction.swift index b6924f88..86f203db 100644 --- a/Sources/ZcashLightClientKit/Block/Actions/DownloadAction.swift +++ b/Sources/ZcashLightClientKit/Block/Actions/DownloadAction.swift @@ -8,28 +8,41 @@ import Foundation class DownloadAction { - init(container: DIContainer) { } + let config: CompactBlockProcessorNG.Configuration + let downloader: BlockDownloader + let transactionRepository: TransactionRepository + init(container: DIContainer, config: CompactBlockProcessorNG.Configuration) { + self.config = config + downloader = container.resolve(BlockDownloader.self) + transactionRepository = container.resolve(TransactionRepository.self) + } + + private func update(context: ActionContext) async -> ActionContext { + await context.update(state: .validate) + return context + } } extension DownloadAction: Action { func run(with context: ActionContext, didUpdate: @escaping (ActionProgress) async -> Void) async throws -> ActionContext { - // Use `BlockDownloader` to set download limit to latestScannedHeight + (2*batchSize) (after parallel is merged). - // And start download. - // Compute batch sync range (range used by one loop in `downloadAndScanBlocks` method) and wait until blocks in this range are downloaded. + guard let downloadRange = await context.syncRanges.downloadAndScanRange else { + return await update(context: context) + } -// do { -// await blockDownloader.setDownloadLimit(processingRange.upperBound + (2 * batchSize)) -// await blockDownloader.startDownload(maxBlockBufferSize: config.downloadBufferSize) -// -// try await blockDownloader.waitUntilRequestedBlocksAreDownloaded(in: processingRange) -// } catch { -// await ifTaskIsNotCanceledClearCompactBlockCache(lastScannedHeight: lastScannedHeight) -// throw error -// } + let lastScannedHeight = try await transactionRepository.lastScannedHeight() + let downloadLimit = lastScannedHeight + (2 * config.batchSize) + let batchRange = lastScannedHeight...lastScannedHeight + config.batchSize + + try await downloader.setSyncRange(downloadRange) + await downloader.setDownloadLimit(downloadLimit) + + try await downloader.waitUntilRequestedBlocksAreDownloaded(in: batchRange) await context.update(state: .validate) return context } - func stop() async { } + func stop() async { + await downloader.stopDownload() + } } diff --git a/Sources/ZcashLightClientKit/Block/CompactBlockProcessorNG.swift b/Sources/ZcashLightClientKit/Block/CompactBlockProcessorNG.swift index 5d5412f8..faf66cd0 100644 --- a/Sources/ZcashLightClientKit/Block/CompactBlockProcessorNG.swift +++ b/Sources/ZcashLightClientKit/Block/CompactBlockProcessorNG.swift @@ -35,8 +35,7 @@ class CompactBlockProcessorNG { let dataDb: URL let spendParamsURL: URL let outputParamsURL: URL - let downloadBatchSize: Int - let scanningBatchSize: Int + let batchSize: Int let retries: Int let maxBackoffInterval: TimeInterval let maxReorgSize = ZcashSDK.maxReorgSize @@ -59,11 +58,10 @@ class CompactBlockProcessorNG { spendParamsURL: URL, outputParamsURL: URL, saplingParamsSourceURL: SaplingParamsSourceURL, - downloadBatchSize: Int = ZcashSDK.DefaultDownloadBatch, + batchSize: Int = ZcashSDK.DefaultSyncBatch, retries: Int = ZcashSDK.defaultRetries, maxBackoffInterval: TimeInterval = ZcashSDK.defaultMaxBackOffInterval, rewindDistance: Int = ZcashSDK.defaultRewindDistance, - scanningBatchSize: Int = ZcashSDK.DefaultScanningBatch, walletBirthdayProvider: @escaping () -> BlockHeight, saplingActivation: BlockHeight, network: ZcashNetwork @@ -75,15 +73,13 @@ class CompactBlockProcessorNG { self.outputParamsURL = outputParamsURL self.saplingParamsSourceURL = saplingParamsSourceURL self.network = network - self.downloadBatchSize = downloadBatchSize + self.batchSize = batchSize self.retries = retries self.maxBackoffInterval = maxBackoffInterval self.rewindDistance = rewindDistance - self.scanningBatchSize = scanningBatchSize self.walletBirthdayProvider = walletBirthdayProvider self.saplingActivation = saplingActivation self.cacheDbURL = cacheDbURL - assert(downloadBatchSize >= scanningBatchSize) } init( @@ -93,11 +89,10 @@ class CompactBlockProcessorNG { spendParamsURL: URL, outputParamsURL: URL, saplingParamsSourceURL: SaplingParamsSourceURL, - downloadBatchSize: Int = ZcashSDK.DefaultDownloadBatch, + batchSize: Int = ZcashSDK.DefaultSyncBatch, retries: Int = ZcashSDK.defaultRetries, maxBackoffInterval: TimeInterval = ZcashSDK.defaultMaxBackOffInterval, rewindDistance: Int = ZcashSDK.defaultRewindDistance, - scanningBatchSize: Int = ZcashSDK.DefaultScanningBatch, walletBirthdayProvider: @escaping () -> BlockHeight, network: ZcashNetwork ) { @@ -111,25 +106,22 @@ class CompactBlockProcessorNG { self.saplingActivation = network.constants.saplingActivationHeight self.network = network self.cacheDbURL = nil - self.downloadBatchSize = downloadBatchSize + self.batchSize = batchSize self.retries = retries self.maxBackoffInterval = maxBackoffInterval self.rewindDistance = rewindDistance - self.scanningBatchSize = scanningBatchSize - - assert(downloadBatchSize >= scanningBatchSize) } } init(container: DIContainer, config: Configuration) { context = ActionContext(state: .validateServer) - actions = Self.makeActions(container: container) + actions = Self.makeActions(container: container, config: config) self.logger = container.resolve(Logger.self) self.config = config } // swiftlint:disable:next cyclomatic_complexity - static func makeActions(container: DIContainer) -> [CBPState: Action] { + static func makeActions(container: DIContainer, config: Configuration) -> [CBPState: Action] { let actionsDefinition = CBPState.allCases.compactMap { state -> (CBPState, Action)? in let action: Action switch state { @@ -142,7 +134,7 @@ class CompactBlockProcessorNG { case .scanDownloaded: action = ScanDownloadedButUnscannedAction(container: container) case .download: - action = DownloadAction(container: container) + action = DownloadAction(container: container, config: config) case .validate: action = ValidateAction(container: container) case .scan: diff --git a/Sources/ZcashLightClientKit/Block/Download/BlockDownloader.swift b/Sources/ZcashLightClientKit/Block/Download/BlockDownloader.swift index 6699373e..9cd9d2e2 100644 --- a/Sources/ZcashLightClientKit/Block/Download/BlockDownloader.swift +++ b/Sources/ZcashLightClientKit/Block/Download/BlockDownloader.swift @@ -224,6 +224,7 @@ extension BlockDownloaderImpl: BlockDownloader { } func setSyncRange(_ range: CompactBlockRange) async throws { + guard range != syncRange else { return } downloadStream = try await compactBlocksDownloadStream(startHeight: range.lowerBound, targetHeight: range.upperBound) syncRange = range } diff --git a/Sources/ZcashLightClientKit/Constants/ZcashSDK.swift b/Sources/ZcashLightClientKit/Constants/ZcashSDK.swift index 0ee0384d..ee63a57f 100644 --- a/Sources/ZcashLightClientKit/Constants/ZcashSDK.swift +++ b/Sources/ZcashLightClientKit/Constants/ZcashSDK.swift @@ -100,6 +100,10 @@ public enum ZcashSDK { /// Default batch size for scanning blocks for the compact block processor public static let DefaultScanningBatch = 100 + /// Default batch size for downloading and scanning blocks for the compact block processor. Be careful with this number. This amount of blocks + /// times three is held in memory at some point of the sync process. + public static let DefaultSyncBatch = 100 + /// Default amount of time, in in seconds, to poll for new blocks. Typically, this should be about half the average /// block time. public static let defaultPollInterval: TimeInterval = 20