From 3be694c920e721445600b1d82ce27a2a2534291e Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Fri, 29 Jul 2022 10:33:23 -0300 Subject: [PATCH] [#444] Syncing Restarts to zero when the wallet is wiped and synced from zero in one go. (#445) This commit changes the way walletBirthday is stored in the synchronizer and intinitializer. Wallets syncing from creation/restore would have a problem where the birthday stored in the Blocks Table would be the one corresponding to the chekpoint found a the time of syncing, but the compact block downloader would start downloading blocks from the height provided by the user when the wallet was restored. This would cause a `validationFailed` error at the height checkpoint.height + 1 and restart downloading from checkpoint.height and then resume correctly. Darksidewalletd test setUp was changed re be able to reproduce the error since injection guaranteed correctness and it was not possible to reproduce the error with it since the wallet birthday height provided matched exactly with the checkpoint on disk and that's the only case that avoided this error. Closes #444 --- Sources/ZcashLightClientKit/Initializer.swift | 7 ++- .../Synchronizer/SDKSynchronizer.swift | 1 - Tests/DarksideTests/AdvancedReOrgTests.swift | 2 +- Tests/TestUtils/TestCoordinator.swift | 48 +++---------------- 4 files changed, 13 insertions(+), 45 deletions(-) diff --git a/Sources/ZcashLightClientKit/Initializer.swift b/Sources/ZcashLightClientKit/Initializer.swift index 8e04a21a..fe0c7851 100644 --- a/Sources/ZcashLightClientKit/Initializer.swift +++ b/Sources/ZcashLightClientKit/Initializer.swift @@ -78,6 +78,8 @@ public class Initializer { private(set) var downloader: CompactBlockDownloader private(set) var network: ZcashNetwork private(set) public var viewingKeys: [UnifiedViewingKey] + /// The effective birthday of the wallet based on the height provided when initializing + /// and the checkpoints available on this SDK private(set) public var walletBirthday: BlockHeight /** @@ -200,9 +202,9 @@ public class Initializer { } catch { throw InitializerError.dataDbInitFailed } - + + let checkpoint = Checkpoint.birthday(with: self.walletBirthday, network: network) do { - let checkpoint = Checkpoint.birthday(with: self.walletBirthday, network: network) try rustBackend.initBlocksTable( dbData: dataDbURL, height: Int32(checkpoint.height), @@ -216,6 +218,7 @@ public class Initializer { } catch { throw InitializerError.dataDbInitFailed } + self.walletBirthday = checkpoint.height let lastDownloaded = (try? downloader.storage.latestHeight()) ?? walletBirthday // resume from last downloaded block diff --git a/Sources/ZcashLightClientKit/Synchronizer/SDKSynchronizer.swift b/Sources/ZcashLightClientKit/Synchronizer/SDKSynchronizer.swift index e59164ba..27c7ee7c 100644 --- a/Sources/ZcashLightClientKit/Synchronizer/SDKSynchronizer.swift +++ b/Sources/ZcashLightClientKit/Synchronizer/SDKSynchronizer.swift @@ -158,7 +158,6 @@ public class SDKSynchronizer: Synchronizer { self.status = .disconnected } - /// Starts the synchronizer /// - Throws: CompactBlockProcessorError when failures occur public func start(retry: Bool = false) throws { diff --git a/Tests/DarksideTests/AdvancedReOrgTests.swift b/Tests/DarksideTests/AdvancedReOrgTests.swift index dc116cb5..2c42354d 100644 --- a/Tests/DarksideTests/AdvancedReOrgTests.swift +++ b/Tests/DarksideTests/AdvancedReOrgTests.swift @@ -35,7 +35,7 @@ class AdvancedReOrgTests: XCTestCase { try super.setUpWithError() coordinator = try TestCoordinator( seed: seedPhrase, - walletBirthday: birthday, + walletBirthday: birthday + 50, //don't use an exact birthday, users never do. channelProvider: ChannelProvider(), network: network ) diff --git a/Tests/TestUtils/TestCoordinator.swift b/Tests/TestUtils/TestCoordinator.swift index 512c3a75..0d79cb9c 100644 --- a/Tests/TestUtils/TestCoordinator.swift +++ b/Tests/TestUtils/TestCoordinator.swift @@ -125,7 +125,7 @@ class TestCoordinator { outputParamsURL: try __outputParamsURL(), spendingKey: spendingKey, unifiedViewingKey: unifiedViewingKey, - walletBirthday: Checkpoint.birthday(with: birthday, network: network), + walletBirthday: walletBirthday, network: network, loggerProxy: SampleLogger(logLevel: .debug) ) @@ -289,59 +289,25 @@ enum TestSynchronizerBuilder { outputParamsURL: URL, spendingKey: String, unifiedViewingKey: UnifiedViewingKey, - walletBirthday: Checkpoint, + walletBirthday: BlockHeight, network: ZcashNetwork, loggerProxy: Logger? = nil ) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) { let initializer = Initializer( - rustBackend: rustBackend, - lowerBoundHeight: lowerBoundHeight, - network: network, cacheDbURL: cacheDbURL, dataDbURL: dataDbURL, pendingDbURL: pendingDbURL, endpoint: endpoint, - service: service, - repository: repository, - accountRepository: accountRepository, - storage: CompactBlockStorage(url: cacheDbURL, readonly: false), + network: network, spendParamsURL: spendParamsURL, outputParamsURL: outputParamsURL, viewingKeys: [unifiedViewingKey], - walletBirthday: walletBirthday.height, + walletBirthday: walletBirthday, + alias: "", loggerProxy: loggerProxy ) - let config = CompactBlockProcessor.Configuration( - cacheDb: initializer.cacheDbURL, - dataDb: initializer.dataDbURL, - downloadBatchSize: 100, - retries: 5, - maxBackoffInterval: ZcashSDK.defaultMaxBackOffInterval, - rewindDistance: ZcashSDK.defaultRewindDistance, - walletBirthday: walletBirthday.height, - saplingActivation: lowerBoundHeight, - network: network - ) - - let processor = CompactBlockProcessor( - service: service, - storage: storage, - backend: rustBackend, - config: config, - repository: repository, - accountRepository: accountRepository - ) - - let synchronizer = try SDKSynchronizer( - status: .unprepared, - initializer: initializer, - transactionManager: OutboundTransactionManagerBuilder.build(initializer: initializer), - transactionRepository: repository, - utxoRepository: UTXORepositoryBuilder.build(initializer: initializer), - blockProcessor: processor - ) - + let synchronizer = try SDKSynchronizer(initializer: initializer) try synchronizer.prepare() return ([spendingKey], synchronizer) @@ -361,7 +327,7 @@ enum TestSynchronizerBuilder { spendParamsURL: URL, outputParamsURL: URL, seedBytes: [UInt8], - walletBirthday: Checkpoint, + walletBirthday: BlockHeight, network: ZcashNetwork, loggerProxy: Logger? = nil ) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) {