From 6b8d95906a3ff1147b7b3a05308b180b7edab451 Mon Sep 17 00:00:00 2001 From: Lukas Korba Date: Mon, 18 Sep 2023 11:01:58 +0200 Subject: [PATCH] [#1273] SynchronizerState not always up to date - latestBlockHeight (chain tip) reported in the SynchronizerState to the clients is now updated every 10mins at most, typically with every sync run (10-30s) - fully and max scanned heights update fixed - new mocks provided and tests fixed --- .../Block/Actions/ScanAction.swift | 5 ++++- .../Block/Actions/UpdateChainTipAction.swift | 3 +++ .../Providers/LatestBlocksDataProvider.swift | 12 +++++++++--- .../ScanActionTests.swift | 14 ++++++++------ .../UpdateChainTipActionTests.swift | 14 ++++++++++---- .../GeneratedMocks/AutoMockable.generated.swift | 15 +++++++++++++++ 6 files changed, 49 insertions(+), 14 deletions(-) diff --git a/Sources/ZcashLightClientKit/Block/Actions/ScanAction.swift b/Sources/ZcashLightClientKit/Block/Actions/ScanAction.swift index 81f27f2d..88067ead 100644 --- a/Sources/ZcashLightClientKit/Block/Actions/ScanAction.swift +++ b/Sources/ZcashLightClientKit/Block/Actions/ScanAction.swift @@ -11,12 +11,14 @@ final class ScanAction { let configProvider: CompactBlockProcessor.ConfigProvider let blockScanner: BlockScanner let rustBackend: ZcashRustBackendWelding + let latestBlocksDataProvider: LatestBlocksDataProvider let logger: Logger init(container: DIContainer, configProvider: CompactBlockProcessor.ConfigProvider) { self.configProvider = configProvider blockScanner = container.resolve(BlockScanner.self) rustBackend = container.resolve(ZcashRustBackendWelding.self) + latestBlocksDataProvider = container.resolve(LatestBlocksDataProvider.self) logger = container.resolve(Logger.self) } @@ -54,7 +56,8 @@ extension ScanAction: Action { let processedHeight = await context.processedHeight let incrementedprocessedHeight = processedHeight + BlockHeight(increment) await context.update(processedHeight: incrementedprocessedHeight) - + await self?.latestBlocksDataProvider.updateScannedData() + // report scan progress only if it's available if let scanProgress = try? await self?.rustBackend.getScanProgress() { let progress = try scanProgress.progress() diff --git a/Sources/ZcashLightClientKit/Block/Actions/UpdateChainTipAction.swift b/Sources/ZcashLightClientKit/Block/Actions/UpdateChainTipAction.swift index 47026f95..4b8eb12f 100644 --- a/Sources/ZcashLightClientKit/Block/Actions/UpdateChainTipAction.swift +++ b/Sources/ZcashLightClientKit/Block/Actions/UpdateChainTipAction.swift @@ -11,12 +11,14 @@ final class UpdateChainTipAction { let rustBackend: ZcashRustBackendWelding let downloader: BlockDownloader let service: LightWalletService + let latestBlocksDataProvider: LatestBlocksDataProvider let logger: Logger init(container: DIContainer) { service = container.resolve(LightWalletService.self) downloader = container.resolve(BlockDownloader.self) rustBackend = container.resolve(ZcashRustBackendWelding.self) + latestBlocksDataProvider = container.resolve(LatestBlocksDataProvider.self) logger = container.resolve(Logger.self) } @@ -26,6 +28,7 @@ final class UpdateChainTipAction { logger.info("Latest block height is \(latestBlockHeight)") try await rustBackend.updateChainTip(height: Int32(latestBlockHeight)) await context.update(lastChainTipUpdateTime: time) + await latestBlocksDataProvider.update(latestBlockHeight) } } diff --git a/Sources/ZcashLightClientKit/Providers/LatestBlocksDataProvider.swift b/Sources/ZcashLightClientKit/Providers/LatestBlocksDataProvider.swift index e831b935..d526bf61 100644 --- a/Sources/ZcashLightClientKit/Providers/LatestBlocksDataProvider.swift +++ b/Sources/ZcashLightClientKit/Providers/LatestBlocksDataProvider.swift @@ -16,6 +16,7 @@ protocol LatestBlocksDataProvider { func updateScannedData() async func updateBlockData() async func updateWalletBirthday(_ walletBirthday: BlockHeight) async + func update(_ latestBlockHeight: BlockHeight) async } actor LatestBlocksDataProviderImpl: LatestBlocksDataProvider { @@ -41,13 +42,18 @@ actor LatestBlocksDataProviderImpl: LatestBlocksDataProvider { } func updateBlockData() async { - if let newLatestBlockHeight = try? await service.latestBlockHeight(), - latestBlockHeight < newLatestBlockHeight { - latestBlockHeight = newLatestBlockHeight + if let newLatestBlockHeight = try? await service.latestBlockHeight() { + await update(newLatestBlockHeight) } } func updateWalletBirthday(_ walletBirthday: BlockHeight) async { self.walletBirthday = walletBirthday } + + func update(_ newLatestBlockHeight: BlockHeight) async { + if latestBlockHeight < newLatestBlockHeight { + latestBlockHeight = newLatestBlockHeight + } + } } diff --git a/Tests/OfflineTests/CompactBlockProcessorActions/ScanActionTests.swift b/Tests/OfflineTests/CompactBlockProcessorActions/ScanActionTests.swift index 785c255d..e176231c 100644 --- a/Tests/OfflineTests/CompactBlockProcessorActions/ScanActionTests.swift +++ b/Tests/OfflineTests/CompactBlockProcessorActions/ScanActionTests.swift @@ -13,7 +13,7 @@ final class ScanActionTests: ZcashTestCase { func testScanAction_NextAction() async throws { let blockScannerMock = BlockScannerMock() let loggerMock = LoggerMock() - + loggerMock.debugFileFunctionLineClosure = { _, _, _, _ in } let scanAction = setupAction(blockScannerMock, loggerMock) @@ -46,7 +46,7 @@ final class ScanActionTests: ZcashTestCase { func testScanAction_EarlyOutForNoDownloadAndScanRangeSet() async throws { let blockScannerMock = BlockScannerMock() let loggerMock = LoggerMock() - + let scanAction = setupAction(blockScannerMock, loggerMock) let syncContext = ActionContextMock.default() @@ -83,7 +83,7 @@ final class ScanActionTests: ZcashTestCase { func testScanAction_EndRangeProperlySetLowerThanBatchSize() async throws { let blockScannerMock = BlockScannerMock() let loggerMock = LoggerMock() - + loggerMock.debugFileFunctionLineClosure = { _, _, _, _ in } let scanAction = setupAction(blockScannerMock, loggerMock) @@ -107,7 +107,7 @@ final class ScanActionTests: ZcashTestCase { func testScanAction_EndRangeProperlySetBatchSize() async throws { let blockScannerMock = BlockScannerMock() let loggerMock = LoggerMock() - + loggerMock.debugFileFunctionLineClosure = { _, _, _, _ in } let scanAction = setupAction(blockScannerMock, loggerMock) @@ -130,7 +130,8 @@ final class ScanActionTests: ZcashTestCase { private func setupAction( _ blockScannerMock: BlockScannerMock, - _ loggerMock: LoggerMock + _ loggerMock: LoggerMock, + _ latestBlocksDataProvider: LatestBlocksDataProvider = LatestBlocksDataProviderMock() ) -> ScanAction { let rustBackendMock = ZcashRustBackendWeldingMock( consensusBranchIdForHeightClosure: { height in @@ -142,7 +143,8 @@ final class ScanActionTests: ZcashTestCase { mockContainer.mock(type: ZcashRustBackendWelding.self, isSingleton: true) { _ in rustBackendMock } mockContainer.mock(type: BlockScanner.self, isSingleton: true) { _ in blockScannerMock } mockContainer.mock(type: Logger.self, isSingleton: true) { _ in loggerMock } - + mockContainer.mock(type: LatestBlocksDataProvider.self, isSingleton: true) { _ in latestBlocksDataProvider } + let config: CompactBlockProcessor.Configuration = .standard( for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: 0 ) diff --git a/Tests/OfflineTests/CompactBlockProcessorActions/UpdateChainTipActionTests.swift b/Tests/OfflineTests/CompactBlockProcessorActions/UpdateChainTipActionTests.swift index 3df86d93..d8034924 100644 --- a/Tests/OfflineTests/CompactBlockProcessorActions/UpdateChainTipActionTests.swift +++ b/Tests/OfflineTests/CompactBlockProcessorActions/UpdateChainTipActionTests.swift @@ -27,11 +27,13 @@ final class UpdateChainTipActionTests: ZcashTestCase { func testUpdateChainTipAction_UpdateChainTipTimeTriggered() async throws { let loggerMock = LoggerMock() let blockDownloaderMock = BlockDownloaderMock() + let latestBlocksDataProvider = LatestBlocksDataProviderMock() loggerMock.infoFileFunctionLineClosure = { _, _, _, _ in } blockDownloaderMock.stopDownloadClosure = { } - - let updateChainTipAction = await setupAction(loggerMock, blockDownloaderMock) + latestBlocksDataProvider.updateClosure = { _ in } + + let updateChainTipAction = await setupAction(loggerMock, blockDownloaderMock, latestBlocksDataProvider) do { let context = ActionContextMock.default() @@ -53,11 +55,13 @@ final class UpdateChainTipActionTests: ZcashTestCase { func testUpdateChainTipAction_UpdateChainTipPrevActionTriggered() async throws { let loggerMock = LoggerMock() let blockDownloaderMock = BlockDownloaderMock() + let latestBlocksDataProvider = LatestBlocksDataProviderMock() loggerMock.infoFileFunctionLineClosure = { _, _, _, _ in } blockDownloaderMock.stopDownloadClosure = { } + latestBlocksDataProvider.updateClosure = { _ in } - let updateChainTipAction = await setupAction(loggerMock, blockDownloaderMock) + let updateChainTipAction = await setupAction(loggerMock, blockDownloaderMock, latestBlocksDataProvider) do { let context = ActionContextMock.default() @@ -104,7 +108,8 @@ final class UpdateChainTipActionTests: ZcashTestCase { private func setupAction( _ loggerMock: LoggerMock = LoggerMock(), - _ blockDownloaderMock: BlockDownloaderMock = BlockDownloaderMock() + _ blockDownloaderMock: BlockDownloaderMock = BlockDownloaderMock(), + _ latestBlocksDataProvider: LatestBlocksDataProvider = LatestBlocksDataProviderMock() ) async -> UpdateChainTipAction { let config: CompactBlockProcessor.Configuration = .standard( for: ZcashNetworkBuilder.network(for: underlyingNetworkType), walletBirthday: 0 @@ -133,6 +138,7 @@ final class UpdateChainTipActionTests: ZcashTestCase { mockContainer.mock(type: LightWalletService.self, isSingleton: true) { _ in serviceMock } mockContainer.mock(type: Logger.self, isSingleton: true) { _ in loggerMock } mockContainer.mock(type: BlockDownloader.self, isSingleton: true) { _ in blockDownloaderMock } + mockContainer.mock(type: LatestBlocksDataProvider.self, isSingleton: true) { _ in latestBlocksDataProvider } return UpdateChainTipAction(container: mockContainer) } diff --git a/Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift b/Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift index c1b6d79f..f201b6ec 100644 --- a/Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift +++ b/Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift @@ -712,6 +712,21 @@ class LatestBlocksDataProviderMock: LatestBlocksDataProvider { await updateWalletBirthdayClosure!(walletBirthday) } + // MARK: - update + + var updateCallsCount = 0 + var updateCalled: Bool { + return updateCallsCount > 0 + } + var updateReceivedLatestBlockHeight: BlockHeight? + var updateClosure: ((BlockHeight) async -> Void)? + + func update(_ latestBlockHeight: BlockHeight) async { + updateCallsCount += 1 + updateReceivedLatestBlockHeight = latestBlockHeight + await updateClosure!(latestBlockHeight) + } + } class LightWalletServiceMock: LightWalletService {