diff --git a/Sources/ZcashLightClientKit/Block/Actions/Action.swift b/Sources/ZcashLightClientKit/Block/Actions/Action.swift index 93b2c286..3ab0d7ee 100644 --- a/Sources/ZcashLightClientKit/Block/Actions/Action.swift +++ b/Sources/ZcashLightClientKit/Block/Actions/Action.swift @@ -18,6 +18,8 @@ actor ActionContext { var totalProgressRange: CompactBlockRange = 0...0 /// Amount of blocks that have been processed so far var processedHeight: BlockHeight = 0 + /// Update chain tip must be called repeatadly, this value stores the previous update and help to decide when to call it again + var lastChainTipUpdateTime: TimeInterval = 0.0 var lastScannedHeight: BlockHeight? var lastDownloadedHeight: BlockHeight? var lastEnhancedHeight: BlockHeight? @@ -38,6 +40,7 @@ actor ActionContext { self.totalProgressRange = totalProgressRange } func update(processedHeight: BlockHeight) async { self.processedHeight = processedHeight } + func update(lastChainTipUpdateTime: TimeInterval) async { self.lastChainTipUpdateTime = lastChainTipUpdateTime } func update(lastScannedHeight: BlockHeight) async { self.lastScannedHeight = lastScannedHeight } func update(lastDownloadedHeight: BlockHeight) async { self.lastDownloadedHeight = lastDownloadedHeight } func update(lastEnhancedHeight: BlockHeight?) async { self.lastEnhancedHeight = lastEnhancedHeight } diff --git a/Sources/ZcashLightClientKit/Block/Actions/EnhanceAction.swift b/Sources/ZcashLightClientKit/Block/Actions/EnhanceAction.swift index 0b8d5069..d6d6460d 100644 --- a/Sources/ZcashLightClientKit/Block/Actions/EnhanceAction.swift +++ b/Sources/ZcashLightClientKit/Block/Actions/EnhanceAction.swift @@ -30,7 +30,7 @@ final class EnhanceAction { if lastScannedHeight >= latestBlockHeight { await context.update(state: .clearCache) } else { - await context.update(state: .download) + await context.update(state: .updateChainTip) } return context diff --git a/Sources/ZcashLightClientKit/Block/Actions/ProcessSuggestedScanRangesAction.swift b/Sources/ZcashLightClientKit/Block/Actions/ProcessSuggestedScanRangesAction.swift index f210110a..1c9f95ee 100644 --- a/Sources/ZcashLightClientKit/Block/Actions/ProcessSuggestedScanRangesAction.swift +++ b/Sources/ZcashLightClientKit/Block/Actions/ProcessSuggestedScanRangesAction.swift @@ -25,7 +25,7 @@ extension ProcessSuggestedScanRangesAction: Action { func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext { logger.info("Getting the suggested scan ranges from the wallet database.") let scanRanges = try await rustBackend.suggestScanRanges() - + if let firstRange = scanRanges.first { let lowerBound = firstRange.range.lowerBound - 1 let upperBound = firstRange.range.upperBound - 1 @@ -42,7 +42,7 @@ extension ProcessSuggestedScanRangesAction: Action { latestScannedHeight [DB]: \(lowerBound) firstUnenhancedHeight [DB]: \(lowerBound + 1) """) - + await context.update(lastScannedHeight: lowerBound) await context.update(lastDownloadedHeight: lowerBound) await context.update(syncControlData: syncControlData) @@ -61,7 +61,7 @@ extension ProcessSuggestedScanRangesAction: Action { logger.info("Setting the total range for Spend before Sync to \(minHeight...maxHeight).") await context.update(totalProgressRange: minHeight...maxHeight) } - + // If there is a range of blocks that needs to be verified, it will always // be returned as the first element of the vector of suggested ranges. if firstRange.priority == .verify { diff --git a/Sources/ZcashLightClientKit/Block/Actions/UpdateChainTipAction.swift b/Sources/ZcashLightClientKit/Block/Actions/UpdateChainTipAction.swift index 635279ab..2560d357 100644 --- a/Sources/ZcashLightClientKit/Block/Actions/UpdateChainTipAction.swift +++ b/Sources/ZcashLightClientKit/Block/Actions/UpdateChainTipAction.swift @@ -17,19 +17,31 @@ final class UpdateChainTipAction { rustBackend = container.resolve(ZcashRustBackendWelding.self) logger = container.resolve(Logger.self) } + + func updateChainTip(_ context: ActionContext, time: TimeInterval) async throws { + let latestBlockHeight = try await service.latestBlockHeight() + + logger.info("Latest block height is \(latestBlockHeight)") + try await rustBackend.updateChainTip(height: Int32(latestBlockHeight)) + await context.update(lastChainTipUpdateTime: time) + } } extension UpdateChainTipAction: Action { var removeBlocksCacheWhenFailed: Bool { false } func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext { - let latestBlockHeight = try await service.latestBlockHeight() - - logger.info("Latest block height is \(latestBlockHeight)") - try await rustBackend.updateChainTip(height: Int32(latestBlockHeight)) - - await context.update(state: .processSuggestedScanRanges) + let lastChainTipUpdateTime = await context.lastChainTipUpdateTime + let now = Date().timeIntervalSince1970 + // Update chain tip can be called from different contexts + if await context.prevState == .updateSubtreeRoots || now - lastChainTipUpdateTime > 600 { + try await updateChainTip(context, time: now) + await context.update(state: .processSuggestedScanRanges) + } else if await context.prevState == .enhance { + await context.update(state: .download) + } + return context } diff --git a/Tests/OfflineTests/CompactBlockProcessorActions/EnhanceActionTests.swift b/Tests/OfflineTests/CompactBlockProcessorActions/EnhanceActionTests.swift index 190405b2..2463b6a5 100644 --- a/Tests/OfflineTests/CompactBlockProcessorActions/EnhanceActionTests.swift +++ b/Tests/OfflineTests/CompactBlockProcessorActions/EnhanceActionTests.swift @@ -50,7 +50,7 @@ final class EnhanceActionTests: ZcashTestCase { ) } - func testEnhanceAction_decideWhatToDoNext_DownloadExpected() async throws { + func testEnhanceAction_decideWhatToDoNext_UpdateChainTipExpected() async throws { let enhanceAction = setupAction() underlyingDownloadRange = CompactBlockRange(uncheckedBounds: (1000, 2000)) underlyingScanRange = CompactBlockRange(uncheckedBounds: (1000, 2000)) @@ -60,8 +60,8 @@ final class EnhanceActionTests: ZcashTestCase { let nextState = await nextContext.state XCTAssertTrue( - nextState == .download, - "testEnhanceAction_decideWhatToDoNext_DownloadExpected is expected to be .download but received \(nextState)" + nextState == .updateChainTip, + "testEnhanceAction_decideWhatToDoNext_DownloadExpected is expected to be .updateChainTip but received \(nextState)" ) }