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
@ -30,7 +30,7 @@ enum DemoAppConfig {
static let defaultSeed = try! Mnemonic.deterministicSeedBytes(from: """ static let defaultSeed = try! Mnemonic.deterministicSeedBytes(from: """
kitchen renew wide common vague fold vacuum tilt amazing pear square gossip jewel month tree shock scan alpha just spot fluid toilet view dinner kitchen renew wide common vague fold vacuum tilt amazing pear square gossip jewel month tree shock scan alpha just spot fluid toilet view dinner
""") """)
static let otherSynchronizers: [SynchronizerInitData] = [ static let otherSynchronizers: [SynchronizerInitData] = [
SynchronizerInitData( SynchronizerInitData(
alias: .custom("alt-sync-1"), alias: .custom("alt-sync-1"),

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
} }