[#1206] Frequent call of update chain tip

- The State Machine has been slightly updated so it measures time when it lastly updated chain tip. If it happened more than 10mins ago, it calls the .updateChainTip action once again before the download-scan-enhance loop continues
- updated unit test

[#1206] Frequent call of update chain tip (#1207)

- whenever updateChainTip is called, it's followed by suggestScanRanges logic
This commit is contained in:
Lukas Korba 2023-08-23 13:25:38 +02:00
parent 62945ec17d
commit c1ff5615dd
5 changed files with 28 additions and 13 deletions

View File

@ -18,6 +18,8 @@ actor ActionContext {
var totalProgressRange: CompactBlockRange = 0...0 var totalProgressRange: CompactBlockRange = 0...0
/// Amount of blocks that have been processed so far /// Amount of blocks that have been processed so far
var processedHeight: BlockHeight = 0 var processedHeight: BlockHeight = 0
/// Update chain tip must be called repeatadly, this value stores the previous update and help to decide when to call it again
var lastChainTipUpdateTime: TimeInterval = 0.0
var lastScannedHeight: BlockHeight? var lastScannedHeight: BlockHeight?
var lastDownloadedHeight: BlockHeight? var lastDownloadedHeight: BlockHeight?
var lastEnhancedHeight: BlockHeight? var lastEnhancedHeight: BlockHeight?
@ -38,6 +40,7 @@ actor ActionContext {
self.totalProgressRange = totalProgressRange self.totalProgressRange = totalProgressRange
} }
func update(processedHeight: BlockHeight) async { self.processedHeight = processedHeight } func update(processedHeight: BlockHeight) async { self.processedHeight = processedHeight }
func update(lastChainTipUpdateTime: TimeInterval) async { self.lastChainTipUpdateTime = lastChainTipUpdateTime }
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

@ -30,7 +30,7 @@ final class EnhanceAction {
if lastScannedHeight >= latestBlockHeight { if lastScannedHeight >= latestBlockHeight {
await context.update(state: .clearCache) await context.update(state: .clearCache)
} else { } else {
await context.update(state: .download) await context.update(state: .updateChainTip)
} }
return context return context

View File

@ -25,7 +25,7 @@ extension ProcessSuggestedScanRangesAction: Action {
func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext { 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.") logger.info("Getting the suggested scan ranges from the wallet database.")
let scanRanges = try await rustBackend.suggestScanRanges() let scanRanges = try await rustBackend.suggestScanRanges()
if let firstRange = scanRanges.first { if let firstRange = scanRanges.first {
let lowerBound = firstRange.range.lowerBound - 1 let lowerBound = firstRange.range.lowerBound - 1
let upperBound = firstRange.range.upperBound - 1 let upperBound = firstRange.range.upperBound - 1
@ -42,7 +42,7 @@ extension ProcessSuggestedScanRangesAction: Action {
latestScannedHeight [DB]: \(lowerBound) latestScannedHeight [DB]: \(lowerBound)
firstUnenhancedHeight [DB]: \(lowerBound + 1) firstUnenhancedHeight [DB]: \(lowerBound + 1)
""") """)
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)
@ -61,7 +61,7 @@ extension ProcessSuggestedScanRangesAction: Action {
logger.info("Setting the total range for Spend before Sync to \(minHeight...maxHeight).") logger.info("Setting the total range for Spend before Sync to \(minHeight...maxHeight).")
await context.update(totalProgressRange: 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.
if firstRange.priority == .verify { if firstRange.priority == .verify {

View File

@ -17,19 +17,31 @@ final class UpdateChainTipAction {
rustBackend = container.resolve(ZcashRustBackendWelding.self) rustBackend = container.resolve(ZcashRustBackendWelding.self)
logger = container.resolve(Logger.self) logger = container.resolve(Logger.self)
} }
func updateChainTip(_ context: ActionContext, time: TimeInterval) async throws {
let latestBlockHeight = try await service.latestBlockHeight()
logger.info("Latest block height is \(latestBlockHeight)")
try await rustBackend.updateChainTip(height: Int32(latestBlockHeight))
await context.update(lastChainTipUpdateTime: time)
}
} }
extension UpdateChainTipAction: Action { extension UpdateChainTipAction: Action {
var removeBlocksCacheWhenFailed: Bool { false } var removeBlocksCacheWhenFailed: Bool { false }
func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext { func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
let latestBlockHeight = try await service.latestBlockHeight() let lastChainTipUpdateTime = await context.lastChainTipUpdateTime
let now = Date().timeIntervalSince1970
logger.info("Latest block height is \(latestBlockHeight)")
try await rustBackend.updateChainTip(height: Int32(latestBlockHeight))
await context.update(state: .processSuggestedScanRanges)
// Update chain tip can be called from different contexts
if await context.prevState == .updateSubtreeRoots || now - lastChainTipUpdateTime > 600 {
try await updateChainTip(context, time: now)
await context.update(state: .processSuggestedScanRanges)
} else if await context.prevState == .enhance {
await context.update(state: .download)
}
return context return context
} }

View File

@ -50,7 +50,7 @@ final class EnhanceActionTests: ZcashTestCase {
) )
} }
func testEnhanceAction_decideWhatToDoNext_DownloadExpected() async throws { func testEnhanceAction_decideWhatToDoNext_UpdateChainTipExpected() async throws {
let enhanceAction = setupAction() let enhanceAction = setupAction()
underlyingDownloadRange = CompactBlockRange(uncheckedBounds: (1000, 2000)) underlyingDownloadRange = CompactBlockRange(uncheckedBounds: (1000, 2000))
underlyingScanRange = CompactBlockRange(uncheckedBounds: (1000, 2000)) underlyingScanRange = CompactBlockRange(uncheckedBounds: (1000, 2000))
@ -60,8 +60,8 @@ final class EnhanceActionTests: ZcashTestCase {
let nextState = await nextContext.state let nextState = await nextContext.state
XCTAssertTrue( XCTAssertTrue(
nextState == .download, nextState == .updateChainTip,
"testEnhanceAction_decideWhatToDoNext_DownloadExpected is expected to be .download but received \(nextState)" "testEnhanceAction_decideWhatToDoNext_DownloadExpected is expected to be .updateChainTip but received \(nextState)"
) )
} }