From 99d4821769cb952a3954dfe702e9f48776dd4b95 Mon Sep 17 00:00:00 2001 From: Lukas Korba Date: Tue, 6 Feb 2024 10:10:02 +0100 Subject: [PATCH] [#1368] Handle any lightwalletd error with retry logic - The retry logic was implemented for blockStream errors only but this PR generalize it for any lightwalletd error --- .../Block/CompactBlockProcessor.swift | 30 ++++++++++++------- .../Constants/ZcashSDK.swift | 7 ++--- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Sources/ZcashLightClientKit/Block/CompactBlockProcessor.swift b/Sources/ZcashLightClientKit/Block/CompactBlockProcessor.swift index 39ce519c..72a0f729 100644 --- a/Sources/ZcashLightClientKit/Block/CompactBlockProcessor.swift +++ b/Sources/ZcashLightClientKit/Block/CompactBlockProcessor.swift @@ -40,7 +40,7 @@ actor CompactBlockProcessor { private let fileManager: ZcashFileManager private var retryAttempts: Int = 0 - private var blockStreamRetryAttempts: Int = 0 + private var serviceFailureRetryAttempts: Int = 0 private var backoffTimer: Timer? private var consecutiveChainValidationErrors: Int = 0 @@ -264,7 +264,7 @@ extension CompactBlockProcessor { func start(retry: Bool = false) async { if retry { self.retryAttempts = 0 - self.blockStreamRetryAttempts = 0 + self.serviceFailureRetryAttempts = 0 self.backoffTimer?.invalidate() self.backoffTimer = nil } @@ -291,7 +291,7 @@ extension CompactBlockProcessor { self.backoffTimer = nil await stopAllActions() retryAttempts = 0 - blockStreamRetryAttempts = 0 + serviceFailureRetryAttempts = 0 } func latestHeight() async throws -> BlockHeight { @@ -579,13 +579,23 @@ extension CompactBlockProcessor { await stopAllActions() logger.error("Sync failed with error: \(error)") - // catching the block stream error - if case ZcashError.serviceBlockStreamFailed = error, self.blockStreamRetryAttempts < ZcashSDK.blockStreamRetries { - // This may be false positive communication error that is usually resolved by retry. - // We will try to reset the sync and continue but this will we done at most `ZcashSDK.blockStreamRetries` times. - logger.error("ZcashError.serviceBlockStreamFailed, retry is available, starting the sync all over again.") + // catching the service errors + let serviceError: Bool + switch error { + case ZcashError.serviceGetInfoFailed, ZcashError.serviceLatestBlockFailed, + ZcashError.serviceLatestBlockHeightFailed, ZcashError.serviceBlockRangeFailed, + ZcashError.serviceSubmitFailed, ZcashError.serviceFetchTransactionFailed, + ZcashError.serviceFetchUTXOsFailed, ZcashError.serviceBlockStreamFailed, + ZcashError.serviceSubtreeRootsStreamFailed: serviceError = true + default: serviceError = false + } - self.blockStreamRetryAttempts += 1 + if serviceError && self.serviceFailureRetryAttempts < ZcashSDK.serviceFailureRetries { + // This may be false positive communication error that is usually resolved by retry. + // We will try to reset the sync and continue but this will we done at most `ZcashSDK.serviceFailureRetries` times. + logger.error("ServiceError: \(error), retry is available, starting the sync all over again.") + + self.serviceFailureRetryAttempts += 1 // Start sync all over again await resetContext() @@ -694,7 +704,7 @@ extension CompactBlockProcessor { latestBlockHeightWhenSyncing > 0 && latestBlockHeightWhenSyncing < latestBlockHeight retryAttempts = 0 - blockStreamRetryAttempts = 0 + serviceFailureRetryAttempts = 0 consecutiveChainValidationErrors = 0 let lastScannedHeight = await latestBlocksDataProvider.maxScannedHeight diff --git a/Sources/ZcashLightClientKit/Constants/ZcashSDK.swift b/Sources/ZcashLightClientKit/Constants/ZcashSDK.swift index ff89768a..22770e88 100644 --- a/Sources/ZcashLightClientKit/Constants/ZcashSDK.swift +++ b/Sources/ZcashLightClientKit/Constants/ZcashSDK.swift @@ -105,10 +105,9 @@ public enum ZcashSDK { // TODO: [#1304] smart retry logic, https://github.com/zcash/ZcashLightClientKit/issues/1304 public static let defaultRetries = Int.max - /// The communication errors are represented as serviceBlockStreamFailed : LightWalletServiceError, unavailable 14 - /// These cases are usually false positive and another try will continue the work, in case the service is trully down we - /// cap the amount of retries by this value. - public static let blockStreamRetries = 3 + /// The communication errors are usually false positive and another try will continue the work, + /// in case the service is trully down we cap the amount of retries by this value. + public static let serviceFailureRetries = 3 /// The default maximum amount of time to wait during retry backoff intervals. Failed loops will never wait longer than /// this before retrying.