[#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 d9f92ec7a9
commit cda3d6f6cc
5 changed files with 28 additions and 13 deletions

View File

@ -18,6 +18,8 @@ actor ActionContext {
var totalProgressRange: CompactBlockRange = 0...0
/// Amount of blocks that have been processed so far
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 lastDownloadedHeight: BlockHeight?
var lastEnhancedHeight: BlockHeight?
@ -38,6 +40,7 @@ actor ActionContext {
self.totalProgressRange = totalProgressRange
}
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(lastDownloadedHeight: BlockHeight) async { self.lastDownloadedHeight = lastDownloadedHeight }
func update(lastEnhancedHeight: BlockHeight?) async { self.lastEnhancedHeight = lastEnhancedHeight }

View File

@ -30,7 +30,7 @@ final class EnhanceAction {
if lastScannedHeight >= latestBlockHeight {
await context.update(state: .clearCache)
} else {
await context.update(state: .download)
await context.update(state: .updateChainTip)
}
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 {
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
@ -42,7 +42,7 @@ extension ProcessSuggestedScanRangesAction: Action {
latestScannedHeight [DB]: \(lowerBound)
firstUnenhancedHeight [DB]: \(lowerBound + 1)
""")
await context.update(lastScannedHeight: lowerBound)
await context.update(lastDownloadedHeight: lowerBound)
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).")
await context.update(totalProgressRange: minHeight...maxHeight)
}
// 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 {

View File

@ -17,19 +17,31 @@ final class UpdateChainTipAction {
rustBackend = container.resolve(ZcashRustBackendWelding.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 {
var removeBlocksCacheWhenFailed: Bool { false }
func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
let latestBlockHeight = try await service.latestBlockHeight()
logger.info("Latest block height is \(latestBlockHeight)")
try await rustBackend.updateChainTip(height: Int32(latestBlockHeight))
await context.update(state: .processSuggestedScanRanges)
let lastChainTipUpdateTime = await context.lastChainTipUpdateTime
let now = Date().timeIntervalSince1970
// 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
}

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()
underlyingDownloadRange = CompactBlockRange(uncheckedBounds: (1000, 2000))
underlyingScanRange = CompactBlockRange(uncheckedBounds: (1000, 2000))
@ -60,8 +60,8 @@ final class EnhanceActionTests: ZcashTestCase {
let nextState = await nextContext.state
XCTAssertTrue(
nextState == .download,
"testEnhanceAction_decideWhatToDoNext_DownloadExpected is expected to be .download but received \(nextState)"
nextState == .updateChainTip,
"testEnhanceAction_decideWhatToDoNext_DownloadExpected is expected to be .updateChainTip but received \(nextState)"
)
}