Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#1180] handle production get subtree roots arg #1197

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
spendParamsURL: try! spendParamsURLHelper(),
outputParamsURL: try! outputParamsURLHelper(),
saplingParamsSourceURL: SaplingParamsSourceURL.default,
syncAlgorithm: .spendBeforeSync,
enableBackendTracing: true
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ enum DemoAppConfig {

static let defaultBirthdayHeight: BlockHeight = ZcashSDK.isMainnet ? 1935000 : 2170000
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] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class SyncBlocksListViewController: UIViewController {
outputParamsURL: try! outputParamsURLHelper(),
saplingParamsSourceURL: SaplingParamsSourceURL.default,
alias: data.alias,
syncAlgorithm: .spendBeforeSync,
loggingPolicy: .default(.debug),
enableBackendTracing: true
)
Expand Down
12 changes: 11 additions & 1 deletion Sources/ZcashLightClientKit/Block/Actions/Action.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,17 @@ actor ActionContext {
var state: CBPState
var prevState: CBPState?
var syncControlData: SyncControlData
let preferredSyncAlgorithm: SyncAlgorithm
var supportedSyncAlgorithm: SyncAlgorithm?
var requestedRewindHeight: BlockHeight?
var totalProgressRange: CompactBlockRange = 0...0
var lastScannedHeight: BlockHeight?
var lastDownloadedHeight: BlockHeight?
var lastEnhancedHeight: BlockHeight?

init(state: CBPState) {
init(state: CBPState, preferredSyncAlgorithm: SyncAlgorithm = .linear) {
self.state = state
self.preferredSyncAlgorithm = preferredSyncAlgorithm
syncControlData = SyncControlData.empty
}

Expand All @@ -26,8 +31,11 @@ actor ActionContext {
}
func update(syncControlData: SyncControlData) async { self.syncControlData = syncControlData }
func update(totalProgressRange: CompactBlockRange) async { self.totalProgressRange = totalProgressRange }
func update(lastScannedHeight: BlockHeight) async { self.lastScannedHeight = lastScannedHeight }
func update(lastDownloadedHeight: BlockHeight) async { self.lastDownloadedHeight = lastDownloadedHeight }
func update(lastEnhancedHeight: BlockHeight?) async { self.lastEnhancedHeight = lastEnhancedHeight }
func update(supportedSyncAlgorithm: SyncAlgorithm) async { self.supportedSyncAlgorithm = supportedSyncAlgorithm }
func update(requestedRewindHeight: BlockHeight) async { self.requestedRewindHeight = requestedRewindHeight }
}

enum CBPState: CaseIterable {
Expand All @@ -36,6 +44,8 @@ enum CBPState: CaseIterable {
case validateServer
case updateSubtreeRoots
case updateChainTip
case processSuggestedScanRanges
case rewind
case computeSyncControlData
case download
case scan
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ extension ClearAlreadyScannedBlocksAction: Action {
var removeBlocksCacheWhenFailed: Bool { false }

func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
let lastScannedHeight = try await transactionRepository.lastScannedHeight()
guard let lastScannedHeight = await context.lastScannedHeight else {
throw ZcashError.compactBlockProcessorLastScannedHeight
}

try await storage.clear(upTo: lastScannedHeight)

await context.update(state: .enhance)
Expand Down
14 changes: 13 additions & 1 deletion Sources/ZcashLightClientKit/Block/Actions/ClearCacheAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,19 @@ extension ClearCacheAction: Action {
if await context.prevState == .idle {
await context.update(state: .migrateLegacyCacheDB)
} else {
await context.update(state: .finished)
if context.preferredSyncAlgorithm == .linear {
await context.update(state: .finished)
} else {
if let supportedSyncAlgorithm = await context.supportedSyncAlgorithm {
if supportedSyncAlgorithm == .linear {
await context.update(state: .finished)
} else {
await context.update(state: .processSuggestedScanRanges)
}
} else {
throw ZcashError.compactBlockProcessorSupportedSyncAlgorithm
}
}
}
return context
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ extension ComputeSyncControlDataAction: Action {
firstUnenhancedHeight: enhanceStart
)

await context.update(lastScannedHeight: latestScannedHeight)
await context.update(lastDownloadedHeight: latestScannedHeight)
await context.update(syncControlData: syncControlData)
await context.update(totalProgressRange: latestScannedHeight...latestBlockHeight)
Expand All @@ -72,7 +73,7 @@ extension ComputeSyncControlDataAction: Action {
if latestBlockHeight < latestScannedHeight || latestBlockHeight == latestScannedHeight {
await context.update(state: .finished)
} else {
await context.update(state: .fetchUTXO)
await context.update(state: .download)
}

return context
Expand Down
10 changes: 5 additions & 5 deletions Sources/ZcashLightClientKit/Block/Actions/DownloadAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,27 @@ extension DownloadAction: Action {
var removeBlocksCacheWhenFailed: Bool { true }

func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
guard let lastScannedHeight = await context.syncControlData.latestScannedHeight else {
guard let lastScannedHeight = await context.lastScannedHeight else {
return await update(context: context)
}

let config = await configProvider.config
let lastScannedHeightDB = try await transactionRepository.lastScannedHeight()
let latestBlockHeight = await context.syncControlData.latestBlockHeight
// This action is executed for each batch (batch size is 100 blocks by default) until all the blocks in whole `downloadRange` are downloaded.
// So the right range for this batch must be computed.
let batchRangeStart = max(lastScannedHeightDB, lastScannedHeight)
let batchRangeStart = lastScannedHeight
let batchRangeEnd = min(latestBlockHeight, batchRangeStart + config.batchSize)

guard batchRangeStart <= batchRangeEnd else {
return await update(context: context)
}

let batchRange = batchRangeStart...batchRangeEnd
let downloadLimit = batchRange.upperBound + (2 * config.batchSize)
let potentialDownloadLimit = batchRange.upperBound + (2 * config.batchSize)
let downloadLimit = await context.syncControlData.latestBlockHeight >= potentialDownloadLimit ? potentialDownloadLimit : batchRangeEnd

logger.debug("Starting download with range: \(batchRange.lowerBound)...\(batchRange.upperBound)")
await downloader.update(latestDownloadedBlockHeight: batchRange.lowerBound)
await downloader.update(latestDownloadedBlockHeight: batchRange.lowerBound, force: true) // SbS
try await downloader.setSyncRange(lastScannedHeight...latestBlockHeight, batchSize: config.batchSize)
await downloader.setDownloadLimit(downloadLimit)
await downloader.startDownload(maxBlockBufferSize: config.downloadBufferSize)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ extension EnhanceAction: Action {
// download and scan.

let config = await configProvider.config
let lastScannedHeight = try await transactionRepository.lastScannedHeight()
guard let lastScannedHeight = await context.lastScannedHeight else {
throw ZcashError.compactBlockProcessorLastScannedHeight
}

guard let firstUnenhancedHeight = await context.syncControlData.firstUnenhancedHeight else {
return await decideWhatToDoNext(context: context, lastScannedHeight: lastScannedHeight)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// ProcessSuggestedScanRangesAction.swift
//
//
// Created by Lukáš Korba on 02.08.2023.
//

import Foundation

final class ProcessSuggestedScanRangesAction {
let rustBackend: ZcashRustBackendWelding
let service: LightWalletService
let logger: Logger

init(container: DIContainer) {
service = container.resolve(LightWalletService.self)
rustBackend = container.resolve(ZcashRustBackendWelding.self)
logger = container.resolve(Logger.self)
}
}

extension ProcessSuggestedScanRangesAction: Action {
var removeBlocksCacheWhenFailed: Bool { false }

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

let syncControlData = SyncControlData(
latestBlockHeight: upperBound,
latestScannedHeight: lowerBound,
firstUnenhancedHeight: lowerBound + 1
)

logger.debug("""
Init numbers:
latestBlockHeight [BC]: \(upperBound)
latestScannedHeight [DB]: \(lowerBound)
firstUnenhancedHeight [DB]: \(lowerBound + 1)
""")

await context.update(lastScannedHeight: lowerBound)
await context.update(lastDownloadedHeight: lowerBound)
await context.update(syncControlData: syncControlData)
await context.update(totalProgressRange: lowerBound...upperBound)

// 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 {
await context.update(requestedRewindHeight: lowerBound + 1)
await context.update(state: .rewind)
} else {
await context.update(state: .download)
}
} else {
await context.update(state: .finished)
}

return context
}

func stop() async { }
}
48 changes: 48 additions & 0 deletions Sources/ZcashLightClientKit/Block/Actions/RewindAction.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// RewindAction.swift
//
//
// Created by Lukáš Korba on 09.08.2023.
//

import Foundation

final class RewindAction {
let downloader: BlockDownloader
let rustBackend: ZcashRustBackendWelding
let downloaderService: BlockDownloaderService
let logger: Logger

init(container: DIContainer) {
downloader = container.resolve(BlockDownloader.self)
rustBackend = container.resolve(ZcashRustBackendWelding.self)
downloaderService = container.resolve(BlockDownloaderService.self)
logger = container.resolve(Logger.self)
}

private func update(context: ActionContext) async -> ActionContext {
await context.update(state: .download)
return context
}
}

extension RewindAction: Action {
var removeBlocksCacheWhenFailed: Bool { false }

func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
guard let rewindHeight = await context.requestedRewindHeight else {
return await update(context: context)
}

logger.debug("Executing rewind.")
await downloader.rewind(latestDownloadedBlockHeight: rewindHeight)
try await rustBackend.rewindToHeight(height: Int32(rewindHeight))

// clear cache
try await downloaderService.rewind(to: rewindHeight)

return await update(context: context)
}

func stop() async { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ extension SaplingParamsAction: Action {
func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
logger.debug("Fetching sapling parameters")
try await saplingParametersHandler.handleIfNeeded()
await context.update(state: .download)

if context.preferredSyncAlgorithm == .spendBeforeSync {
await context.update(state: .updateSubtreeRoots)
} else {
await context.update(state: .computeSyncControlData)
}
return context
}

Expand Down
45 changes: 34 additions & 11 deletions Sources/ZcashLightClientKit/Block/Actions/ScanAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,15 @@ extension ScanAction: Action {
var removeBlocksCacheWhenFailed: Bool { true }

func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
guard let lastScannedHeight = await context.syncControlData.latestScannedHeight else {
guard let lastScannedHeight = await context.lastScannedHeight else {
return await update(context: context)
}

let config = await configProvider.config
let lastScannedHeightDB = try await transactionRepository.lastScannedHeight()
let latestBlockHeight = await context.syncControlData.latestBlockHeight
// This action is executed for each batch (batch size is 100 blocks by default) until all the blocks in whole `scanRange` are scanned.
// So the right range for this batch must be computed.
let batchRangeStart = max(lastScannedHeightDB, lastScannedHeight)
let batchRangeStart = lastScannedHeight
let batchRangeEnd = min(latestBlockHeight, batchRangeStart + config.batchSize)

guard batchRangeStart <= batchRangeEnd else {
Expand All @@ -50,18 +49,42 @@ extension ScanAction: Action {

logger.debug("Starting scan blocks with range: \(batchRange.lowerBound)...\(batchRange.upperBound)")
let totalProgressRange = await context.totalProgressRange
try await blockScanner.scanBlocks(at: batchRange, totalProgressRange: totalProgressRange) { [weak self] lastScannedHeight in
let progress = BlockProgress(
startHeight: totalProgressRange.lowerBound,
targetHeight: totalProgressRange.upperBound,
progressHeight: lastScannedHeight
)
self?.logger.debug("progress: \(progress)")
await didUpdate(.progressPartialUpdate(.syncing(progress)))

do {
try await blockScanner.scanBlocks(at: batchRange, totalProgressRange: totalProgressRange) { [weak self] lastScannedHeight in
let progress = BlockProgress(
startHeight: totalProgressRange.lowerBound,
targetHeight: totalProgressRange.upperBound,
progressHeight: lastScannedHeight
)
self?.logger.debug("progress: \(progress)")
await didUpdate(.progressPartialUpdate(.syncing(progress)))

// ScanAction is controlled locally so it must report back the updated scanned height
await context.update(lastScannedHeight: lastScannedHeight)
}
} catch ZcashError.rustScanBlocks(let errorMsg) {
if isContinuityError(errorMsg) {
await context.update(requestedRewindHeight: batchRange.lowerBound - 10)
await context.update(state: .download)
return context
} else {
throw ZcashError.rustScanBlocks(errorMsg)
}
} catch {
throw error
}

return await update(context: context)
}

func stop() async { }
}

private extension ScanAction {
func isContinuityError(_ errorMsg: String) -> Bool {
errorMsg.contains("The parent hash of proposed block does not correspond to the block hash at height")
|| errorMsg.contains("Block height discontinuity at height")
|| errorMsg.contains("note commitment tree size provided by a compact block did not match the expected size at height")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ extension UpdateChainTipAction: Action {
logger.info("Latest block height is \(latestBlockHeight)")
try await rustBackend.updateChainTip(height: Int32(latestBlockHeight))

// TODO: [#1169] Switching back to linear sync for now before step 5 & 6 are implemented
// https://github.com/zcash/ZcashLightClientKit/issues/1169
await context.update(state: .computeSyncControlData)
await context.update(state: .processSuggestedScanRanges)

return context
}
Expand Down
Loading
Loading