Merge pull request #1199 from LukasKorba/1181-Correct-computation-of-progress-for-Spend-before-Sync

[#1181] Correct computation of progress for Spend before Sync
This commit is contained in:
Lukas Korba 2023-08-11 09:02:41 +02:00 committed by GitHub
commit dbd5a1ad3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 54 additions and 33 deletions

View File

@ -8,6 +8,13 @@ be able to write to this location after it creates this directory. It is suggest
a subdirectory of the `Documents` directory. If this information is stored in `Documents` then the a subdirectory of the `Documents` directory. If this information is stored in `Documents` then the
system itself won't remove these data. system itself won't remove these data.
### Removed
### [#1181] Correct computation of progress for Spend before Sync
`latestScannedHeight` and `latestScannedTime` have been removed from `SynchronizerState`. With multiple algorithms
of syncing the amount of data provided is reduced so it's consistent. Spend before Sync is done in non-linear order
so both Height and Time don't make sense anymore.
# 0.22.0-beta # 0.22.0-beta
## Checkpoints ## Checkpoints

View File

@ -18,7 +18,7 @@ enum DemoAppConfig {
let seed: [UInt8] let seed: [UInt8]
} }
static let host = ZcashSDK.isMainnet ? "mainnet.lightwalletd.com" : "testnet.lightwalletd.com" static let host = ZcashSDK.isMainnet ? "mainnet.lightwalletd.com" : "lightwalletd.testnet.electriccoin.co"
static let port: Int = 9067 static let port: Int = 9067
// static let defaultBirthdayHeight: BlockHeight = ZcashSDK.isMainnet ? 935000 : 1386000 // static let defaultBirthdayHeight: BlockHeight = ZcashSDK.isMainnet ? 935000 : 1386000

View File

@ -112,7 +112,6 @@ class SyncBlocksListViewController: UIViewController {
outputParamsURL: try! outputParamsURLHelper(), outputParamsURL: try! outputParamsURLHelper(),
saplingParamsSourceURL: SaplingParamsSourceURL.default, saplingParamsSourceURL: SaplingParamsSourceURL.default,
alias: data.alias, alias: data.alias,
syncAlgorithm: .spendBeforeSync,
loggingPolicy: .default(.debug), loggingPolicy: .default(.debug),
enableBackendTracing: true enableBackendTracing: true
) )

View File

@ -84,10 +84,7 @@ class SyncBlocksViewController: UIViewController {
progressBar.progress = progress progressBar.progress = progress
progressLabel.text = "\(floor(progress * 1000) / 10)%" progressLabel.text = "\(floor(progress * 1000) / 10)%"
let syncedDate = dateFormatter.string(from: Date(timeIntervalSince1970: state.latestScannedTime))
let progressText = """ let progressText = """
synced date \(syncedDate)
synced block \(state.latestScannedHeight)
latest block height \(state.latestBlockHeight) latest block height \(state.latestBlockHeight)
""" """
progressDataLabel.text = progressText progressDataLabel.text = progressText

View File

@ -14,7 +14,10 @@ actor ActionContext {
let preferredSyncAlgorithm: SyncAlgorithm let preferredSyncAlgorithm: SyncAlgorithm
var supportedSyncAlgorithm: SyncAlgorithm? var supportedSyncAlgorithm: SyncAlgorithm?
var requestedRewindHeight: BlockHeight? var requestedRewindHeight: BlockHeight?
/// Represents the overall range of blocks that will be synced, `SyncAlgorithm` doesn't matter.
var totalProgressRange: CompactBlockRange = 0...0 var totalProgressRange: CompactBlockRange = 0...0
/// Amount of blocks that have been processed so far
var processedHeight: BlockHeight = 0
var lastScannedHeight: BlockHeight? var lastScannedHeight: BlockHeight?
var lastDownloadedHeight: BlockHeight? var lastDownloadedHeight: BlockHeight?
var lastEnhancedHeight: BlockHeight? var lastEnhancedHeight: BlockHeight?
@ -30,7 +33,11 @@ actor ActionContext {
self.state = state self.state = state
} }
func update(syncControlData: SyncControlData) async { self.syncControlData = syncControlData } func update(syncControlData: SyncControlData) async { self.syncControlData = syncControlData }
func update(totalProgressRange: CompactBlockRange) async { self.totalProgressRange = totalProgressRange } func update(totalProgressRange: CompactBlockRange) async {
self.processedHeight = totalProgressRange.lowerBound
self.totalProgressRange = totalProgressRange
}
func update(processedHeight: BlockHeight) async { self.processedHeight = processedHeight }
func update(lastScannedHeight: BlockHeight) async { self.lastScannedHeight = lastScannedHeight } func update(lastScannedHeight: BlockHeight) async { self.lastScannedHeight = lastScannedHeight }
func update(lastDownloadedHeight: BlockHeight) async { self.lastDownloadedHeight = lastDownloadedHeight } func update(lastDownloadedHeight: BlockHeight) async { self.lastDownloadedHeight = lastDownloadedHeight }
func update(lastEnhancedHeight: BlockHeight?) async { self.lastEnhancedHeight = lastEnhancedHeight } func update(lastEnhancedHeight: BlockHeight?) async { self.lastEnhancedHeight = lastEnhancedHeight }

View File

@ -46,7 +46,21 @@ extension ProcessSuggestedScanRangesAction: Action {
await context.update(lastScannedHeight: lowerBound) await context.update(lastScannedHeight: lowerBound)
await context.update(lastDownloadedHeight: lowerBound) await context.update(lastDownloadedHeight: lowerBound)
await context.update(syncControlData: syncControlData) await context.update(syncControlData: syncControlData)
await context.update(totalProgressRange: lowerBound...upperBound)
// the total progress range is computed only for the first time
// as a sum of all ranges
let totalProgressRange = await context.totalProgressRange
if totalProgressRange.lowerBound == 0 && totalProgressRange.upperBound == 0 {
var minHeight = Int.max
var maxHeight = 0
scanRanges.forEach { range in
if range.range.lowerBound < minHeight { minHeight = range.range.lowerBound }
if range.range.upperBound > maxHeight { maxHeight = range.range.upperBound }
}
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 // 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. // be returned as the first element of the vector of suggested ranges.

View File

@ -51,11 +51,20 @@ extension ScanAction: Action {
let totalProgressRange = await context.totalProgressRange let totalProgressRange = await context.totalProgressRange
do { do {
try await blockScanner.scanBlocks(at: batchRange, totalProgressRange: totalProgressRange) { [weak self] lastScannedHeight in try await blockScanner.scanBlocks(at: batchRange, totalProgressRange: totalProgressRange) { [weak self] lastScannedHeight, increment in
let processedHeight = await context.processedHeight
let incrementedprocessedHeight = processedHeight + BlockHeight(increment)
await context.update(
processedHeight:
incrementedprocessedHeight < totalProgressRange.upperBound
? incrementedprocessedHeight
: totalProgressRange.upperBound
)
let progress = BlockProgress( let progress = BlockProgress(
startHeight: totalProgressRange.lowerBound, startHeight: totalProgressRange.lowerBound,
targetHeight: totalProgressRange.upperBound, targetHeight: totalProgressRange.upperBound,
progressHeight: lastScannedHeight progressHeight: incrementedprocessedHeight
) )
self?.logger.debug("progress: \(progress)") self?.logger.debug("progress: \(progress)")
await didUpdate(.progressPartialUpdate(.syncing(progress))) await didUpdate(.progressPartialUpdate(.syncing(progress)))

View File

@ -521,7 +521,7 @@ extension CompactBlockProcessor {
// Execute action. // Execute action.
context = try await action.run(with: context) { [weak self] event in context = try await action.run(with: context) { [weak self] event in
await self?.send(event: event) await self?.send(event: event)
if let progressChanged = await self?.compactBlockProgress.event(event), progressChanged { if let progressChanged = await self?.compactBlockProgress.hasProgressUpdated(event), progressChanged {
if let progress = await self?.compactBlockProgress.progress { if let progress = await self?.compactBlockProgress.progress {
await self?.send(event: .progressUpdated(progress)) await self?.send(event: .progressUpdated(progress))
} }

View File

@ -17,7 +17,7 @@ protocol BlockScanner {
func scanBlocks( func scanBlocks(
at range: CompactBlockRange, at range: CompactBlockRange,
totalProgressRange: CompactBlockRange, totalProgressRange: CompactBlockRange,
didScan: @escaping (BlockHeight) async -> Void didScan: @escaping (BlockHeight, UInt32) async -> Void
) async throws -> BlockHeight ) async throws -> BlockHeight
} }
@ -35,7 +35,7 @@ extension BlockScannerImpl: BlockScanner {
func scanBlocks( func scanBlocks(
at range: CompactBlockRange, at range: CompactBlockRange,
totalProgressRange: CompactBlockRange, totalProgressRange: CompactBlockRange,
didScan: @escaping (BlockHeight) async -> Void didScan: @escaping (BlockHeight, UInt32) async -> Void
) async throws -> BlockHeight { ) async throws -> BlockHeight {
logger.debug("Going to scan blocks in range: \(range)") logger.debug("Going to scan blocks in range: \(range)")
try Task.checkCancellation() try Task.checkCancellation()
@ -69,7 +69,7 @@ extension BlockScannerImpl: BlockScanner {
scannedNewBlocks = previousScannedHeight != lastScannedHeight scannedNewBlocks = previousScannedHeight != lastScannedHeight
if scannedNewBlocks { if scannedNewBlocks {
await didScan(lastScannedHeight) await didScan(lastScannedHeight, batchSize)
let progress = BlockProgress( let progress = BlockProgress(
startHeight: totalProgressRange.lowerBound, startHeight: totalProgressRange.lowerBound,

View File

@ -19,7 +19,7 @@ final actor CompactBlockProgress {
switch self { switch self {
case .enhance: return 0.08 case .enhance: return 0.08
case .fetch: return 0.02 case .fetch: return 0.02
case .scan: return 0.9 case .scan: return 1.0
} }
} }
} }
@ -35,18 +35,13 @@ final actor CompactBlockProgress {
return overallProgress return overallProgress
} }
func event(_ event: CompactBlockProcessor.Event) -> Bool { func hasProgressUpdated(_ event: CompactBlockProcessor.Event) -> Bool {
guard case .progressPartialUpdate(let update) = event else { guard case .progressPartialUpdate(let update) = event else {
return false return false
} }
switch update { if case let .syncing(progress) = update {
case .syncing(let progress):
actionProgresses[.scan] = progress.progress actionProgresses[.scan] = progress.progress
case .enhance(let progress):
actionProgresses[.enhance] = progress.progress
case .fetch(let progress):
actionProgresses[.fetch] = progress
} }
return true return true

View File

@ -42,13 +42,8 @@ public struct SynchronizerState: Equatable {
/// status of the whole sync process /// status of the whole sync process
var internalSyncStatus: InternalSyncStatus var internalSyncStatus: InternalSyncStatus
public var syncStatus: SyncStatus public var syncStatus: SyncStatus
/// height of the latest scanned block known to this synchronizer.
public var latestScannedHeight: BlockHeight
/// height of the latest block on the blockchain known to this synchronizer. /// height of the latest block on the blockchain known to this synchronizer.
public var latestBlockHeight: BlockHeight public var latestBlockHeight: BlockHeight
/// timestamp of the latest scanned block on the blockchain known to this synchronizer.
/// The anchor point is timeIntervalSince1970
public var latestScannedTime: TimeInterval
/// Represents a synchronizer that has made zero progress hasn't done a sync attempt /// Represents a synchronizer that has made zero progress hasn't done a sync attempt
public static var zero: SynchronizerState { public static var zero: SynchronizerState {
@ -76,9 +71,7 @@ public struct SynchronizerState: Equatable {
self.shieldedBalance = shieldedBalance self.shieldedBalance = shieldedBalance
self.transparentBalance = transparentBalance self.transparentBalance = transparentBalance
self.internalSyncStatus = internalSyncStatus self.internalSyncStatus = internalSyncStatus
self.latestScannedHeight = latestScannedHeight
self.latestBlockHeight = latestBlockHeight self.latestBlockHeight = latestBlockHeight
self.latestScannedTime = latestScannedTime
self.syncStatus = internalSyncStatus.mapToSyncStatus() self.syncStatus = internalSyncStatus.mapToSyncStatus()
} }
} }

View File

@ -369,7 +369,7 @@ public class SDKSynchronizer: Synchronizer {
} }
public func allPendingTransactions() async throws -> [ZcashTransaction.Overview] { public func allPendingTransactions() async throws -> [ZcashTransaction.Overview] {
let latestScannedHeight = self.latestState.latestScannedHeight let latestScannedHeight = try await transactionRepository.lastScannedHeight()
return try await transactionRepository.findPendingTransactions(latestHeight: latestScannedHeight, offset: 0, limit: .max) return try await transactionRepository.findPendingTransactions(latestHeight: latestScannedHeight, offset: 0, limit: .max)
} }

View File

@ -361,11 +361,11 @@ class BlockScannerMock: BlockScanner {
var scanBlocksAtTotalProgressRangeDidScanCalled: Bool { var scanBlocksAtTotalProgressRangeDidScanCalled: Bool {
return scanBlocksAtTotalProgressRangeDidScanCallsCount > 0 return scanBlocksAtTotalProgressRangeDidScanCallsCount > 0
} }
var scanBlocksAtTotalProgressRangeDidScanReceivedArguments: (range: CompactBlockRange, totalProgressRange: CompactBlockRange, didScan: (BlockHeight) async -> Void)? var scanBlocksAtTotalProgressRangeDidScanReceivedArguments: (range: CompactBlockRange, totalProgressRange: CompactBlockRange, didScan: (BlockHeight, UInt32) async -> Void)?
var scanBlocksAtTotalProgressRangeDidScanReturnValue: BlockHeight! var scanBlocksAtTotalProgressRangeDidScanReturnValue: BlockHeight!
var scanBlocksAtTotalProgressRangeDidScanClosure: ((CompactBlockRange, CompactBlockRange, @escaping (BlockHeight) async -> Void) async throws -> BlockHeight)? var scanBlocksAtTotalProgressRangeDidScanClosure: ((CompactBlockRange, CompactBlockRange, @escaping (BlockHeight, UInt32) async -> Void) async throws -> BlockHeight)?
func scanBlocks(at range: CompactBlockRange, totalProgressRange: CompactBlockRange, didScan: @escaping (BlockHeight) async -> Void) async throws -> BlockHeight { func scanBlocks(at range: CompactBlockRange, totalProgressRange: CompactBlockRange, didScan: @escaping (BlockHeight, UInt32) async -> Void) async throws -> BlockHeight {
if let error = scanBlocksAtTotalProgressRangeDidScanThrowableError { if let error = scanBlocksAtTotalProgressRangeDidScanThrowableError {
throw error throw error
} }