[#1042] Implement ComputeSyncRangesAction

Closes #1042
This commit is contained in:
Michal Fousek 2023-05-11 13:28:43 +02:00
parent 8cfd25f9ec
commit c9632c4513
2 changed files with 73 additions and 5 deletions

View File

@ -10,15 +10,16 @@ import Foundation
actor ActionContext {
var state: CBPState
var syncRanges: SyncRanges
var totalProgressRange: CompactBlockRange = 0...0
init(state: CBPState) {
self.state = state
syncRanges = SyncRanges.empty
}
func update(state: CBPState) async {
self.state = state
}
func update(state: CBPState) async { self.state = state }
func update(syncRanges: SyncRanges) async { self.syncRanges = syncRanges }
func update(totalProgressRange: CompactBlockRange) async { self.totalProgressRange = totalProgressRange }
}
enum CBPState: CaseIterable {

View File

@ -8,7 +8,34 @@
import Foundation
class ComputeSyncRangesAction {
init(container: DIContainer) { }
let config: CompactBlockProcessorNG.Configuration
let downloaderService: BlockDownloaderService
let internalSyncProgress: InternalSyncProgress
let latestBlocksDataProvider: LatestBlocksDataProvider
let logger: Logger
init(container: DIContainer, config: CompactBlockProcessorNG.Configuration) {
self.config = config
downloaderService = container.resolve(BlockDownloaderService.self)
internalSyncProgress = container.resolve(InternalSyncProgress.self)
latestBlocksDataProvider = container.resolve(LatestBlocksDataProvider.self)
logger = container.resolve(Logger.self)
}
/// It may happen that sync process start with syncing blocks that were downloaded but not synced in previous run of the sync process. This
/// methods analyses what must be done and computes range that should be used to compute reported progress.
private func computeTotalProgressRange(from syncRanges: SyncRanges) -> CompactBlockRange {
guard syncRanges.downloadedButUnscannedRange != nil || syncRanges.downloadAndScanRange != nil else {
// In this case we are sure that no downloading or scanning happens so this returned range won't be even used. And it's easier to return
// this "fake" range than to handle nil.
return 0...0
}
// Thanks to guard above we can be sure that one of these two ranges is not nil.
let lowerBound = syncRanges.downloadedButUnscannedRange?.lowerBound ?? syncRanges.downloadAndScanRange?.lowerBound ?? 0
let upperBound = syncRanges.downloadAndScanRange?.upperBound ?? syncRanges.downloadedButUnscannedRange?.upperBound ?? 0
return lowerBound...upperBound
}
}
extension ComputeSyncRangesAction: Action {
@ -16,7 +43,47 @@ extension ComputeSyncRangesAction: Action {
// call internalSyncProgress and compute sync ranges and store them in context
// if there is nothing sync just switch to finished state
await context.update(state: .checksBeforeSync)
let latestDownloadHeight = try await downloaderService.lastDownloadedBlockHeight()
await internalSyncProgress.migrateIfNeeded(latestDownloadedBlockHeightFromCacheDB: latestDownloadHeight)
await latestBlocksDataProvider.updateScannedData()
await latestBlocksDataProvider.updateBlockData()
let nextState = await internalSyncProgress.computeNextState(
latestBlockHeight: latestBlocksDataProvider.latestBlockHeight,
latestScannedHeight: latestBlocksDataProvider.latestScannedHeight,
walletBirthday: config.walletBirthday
)
switch nextState {
case .finishProcessing:
await context.update(state: .finished)
case .processNewBlocks(let ranges):
let totalProgressRange = computeTotalProgressRange(from: ranges)
await context.update(totalProgressRange: totalProgressRange)
await context.update(syncRanges: ranges)
await context.update(state: .checksBeforeSync)
logger.debug("""
Syncing with ranges:
downloaded but not scanned: \
\(ranges.downloadedButUnscannedRange?.lowerBound ?? -1)...\(ranges.downloadedButUnscannedRange?.upperBound ?? -1)
download and scan: \(ranges.downloadAndScanRange?.lowerBound ?? -1)...\(ranges.downloadAndScanRange?.upperBound ?? -1)
enhance range: \(ranges.enhanceRange?.lowerBound ?? -1)...\(ranges.enhanceRange?.upperBound ?? -1)
fetchUTXO range: \(ranges.fetchUTXORange?.lowerBound ?? -1)...\(ranges.fetchUTXORange?.upperBound ?? -1)
total progress range: \(totalProgressRange.lowerBound)...\(totalProgressRange.upperBound)
""")
case let .wait(latestHeight, latestDownloadHeight):
// Lightwalletd might be syncing
logger.info(
"Lightwalletd might be syncing: latest downloaded block height is: \(latestDownloadHeight) " +
"while latest blockheight is reported at: \(latestHeight)"
)
await context.update(state: .finished)
}
return context
}