Adoption of sync & recovery progresses

Sync and recovery progresses

- FFI bumped to preview 0.15.0
- SDK has been refactored to incorporate recoveryProgress alongside scanProgress

Non-optional syncProgress

0 Denominator fix

OfflineTests fixed

Sync progress merged

- the progress is merged now but boolean value whether funds are spendable or not has been added extra
This commit is contained in:
Lukas Korba 2025-04-09 09:27:06 +02:00
parent 04ca05428f
commit 1a2db6b167
17 changed files with 128 additions and 89 deletions

View File

@ -176,8 +176,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/Electric-Coin-Company/zcash-light-client-ffi", "location" : "https://github.com/Electric-Coin-Company/zcash-light-client-ffi",
"state" : { "state" : {
"revision" : "78cc7388a2ba5530888a99e584823a7399631d48", "branch" : "preview/release/0.15.0",
"version" : "0.14.2" "revision" : "c336dfc88b81aa3c857bc35e2d7d5452ae816d6e"
} }
} }
], ],

View File

@ -21,14 +21,18 @@ enum DemoAppConfig {
static let host = ZcashSDK.isMainnet ? "zec.rocks" : "lightwalletd.testnet.electriccoin.co" static let host = ZcashSDK.isMainnet ? "zec.rocks" : "lightwalletd.testnet.electriccoin.co"
static let port: Int = 443 static let port: Int = 443
static let defaultBirthdayHeight: BlockHeight = ZcashSDK.isMainnet ? 935000 : 1386000 static let defaultBirthdayHeight: BlockHeight = 2832500//ZcashSDK.isMainnet ? 935000 : 1386000
// static let defaultSeed = try! Mnemonic.deterministicSeedBytes(from: """ // static let defaultSeed = try! Mnemonic.deterministicSeedBytes(from: """
// wish puppy smile loan doll curve hole maze file ginger hair nose key relax knife witness cannon grab despair throw review deal slush frame // wish puppy smile loan doll curve hole maze file ginger hair nose key relax knife witness cannon grab despair throw review deal slush frame
// """)
// static let defaultSeed = try! Mnemonic.deterministicSeedBytes(from: """
// live combine flight accident slow soda mind bright absent bid hen shy decade biology amazing mix enlist ensure biology rhythm snap duty soap armor
// """) // """)
static let defaultSeed = try! Mnemonic.deterministicSeedBytes(from: """ static let defaultSeed = try! Mnemonic.deterministicSeedBytes(from: """
live combine flight accident slow soda mind bright absent bid hen shy decade biology amazing mix enlist ensure biology rhythm snap duty soap armor wreck craft number between hard warfare wisdom leave radar host local crane float play logic whale clap parade dynamic cotton attitude people guard together
""") """)
static let otherSynchronizers: [SynchronizerInitData] = [ static let otherSynchronizers: [SynchronizerInitData] = [

View File

@ -319,8 +319,8 @@ extension SendViewController: UITextViewDelegate {
extension SDKSynchronizer { extension SDKSynchronizer {
static func textFor(state: SyncStatus) -> String { static func textFor(state: SyncStatus) -> String {
switch state { switch state {
case .syncing(let progress): case let .syncing(syncProgress, areFundsSpendable):
return "Syncing \(progress * 100.0)%" return "Syncing \(syncProgress * 100.0)% spendable: \(areFundsSpendable)"
case .upToDate: case .upToDate:
return "Up to Date 😎" return "Up to Date 😎"

View File

@ -172,8 +172,8 @@ extension SyncBlocksListViewController: UITableViewDataSource {
extension SyncStatus { extension SyncStatus {
var text: String { var text: String {
switch self { switch self {
case let .syncing(progress): case let .syncing(syncProgress, areFundsSpendable):
return "Syncing 🤖 \(floor(progress * 1000) / 10)%" return "Syncing 🤖 \(floor(syncProgress * 1000) / 10)% spendable: \(areFundsSpendable)"
case .upToDate: case .upToDate:
return "Up to Date 😎" return "Up to Date 😎"
case .unprepared: case .unprepared:

View File

@ -68,11 +68,13 @@ class SyncBlocksViewController: UIViewController {
case .unprepared: case .unprepared:
break break
case let .syncing(progress): case let .syncing(syncProgress, areFundsSpendable):
enhancingStarted = false enhancingStarted = false
progressBar.progress = progress print("__LD syncProgress \(syncProgress) areFundsSpendable \(areFundsSpendable)")
progressLabel.text = "\(floor(progress * 1000) / 10)%"
progressBar.progress = syncProgress
progressLabel.text = "\(floor(syncProgress * 1000) / 10)% spendable: \(areFundsSpendable)"
let progressText = """ let progressText = """
latest block height \(state.latestBlockHeight) latest block height \(state.latestBlockHeight)
""" """
@ -87,19 +89,9 @@ class SyncBlocksViewController: UIViewController {
} }
@IBAction func startStop() { @IBAction func startStop() {
var components = DateComponents() Task { @MainActor in
components.year = 2019 await doStartStop()
components.month = 11
components.day = 1
let calendar = Calendar.current
if let date = calendar.date(from: components) {
synchronizer.estimateBirthdayHeight(for: date)
} }
// Task { @MainActor in
// await doStartStop()
// }
} }
func doStartStop() async { func doStartStop() async {

View File

@ -16,7 +16,8 @@ let package = Package(
dependencies: [ dependencies: [
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.24.2"), .package(url: "https://github.com/grpc/grpc-swift.git", from: "1.24.2"),
.package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.15.3"), .package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.15.3"),
.package(url: "https://github.com/Electric-Coin-Company/zcash-light-client-ffi", exact: "0.14.2") // .package(url: "https://github.com/Electric-Coin-Company/zcash-light-client-ffi", exact: "0.14.2")
.package(url: "https://github.com/Electric-Coin-Company/zcash-light-client-ffi", branch: "preview/release/0.15.0")
], ],
targets: [ targets: [
.target( .target(

View File

@ -73,13 +73,35 @@ extension ScanAction: Action {
// Proper solution is handled in // Proper solution is handled in
// TODO: [#1353] Advanced progress reporting, https://github.com/Electric-Coin-Company/zcash-swift-wallet-sdk/issues/1353 // TODO: [#1353] Advanced progress reporting, https://github.com/Electric-Coin-Company/zcash-swift-wallet-sdk/issues/1353
if progressReportReducer == 0 { if progressReportReducer == 0 {
let walletSummary = try? await rustBackend.getWalletSummary()
let recoveryProgress = walletSummary?.recoveryProgress
// report scan progress only if it's available // report scan progress only if it's available
if let scanProgress = try? await rustBackend.getWalletSummary()?.scanProgress { if let scanProgress = walletSummary?.scanProgress {
logger.debug("progress ratio: \(scanProgress.numerator)/\(scanProgress.denominator)") let composedNumerator: Float = Float(scanProgress.numerator) + Float(recoveryProgress?.numerator ?? 0)
let progress = try scanProgress.progress() let composedDenominator: Float = Float(scanProgress.denominator) + Float(recoveryProgress?.denominator ?? 0)
logger.debug("progress ratio: \(composedNumerator)/\(composedDenominator)")
let progress: Float
if composedDenominator == 0 {
progress = 1.0
} else {
progress = composedNumerator / composedDenominator
}
// this shouldn't happen but if it does, we need to get notified by clients and work on a fix
if progress > 1.0 {
throw ZcashError.rustScanProgressOutOfRange("\(progress)")
}
let scanProgress: Float = (try? scanProgress.progress()) ?? 0.0
let areFundsSpendable = scanProgress == 1.0
logger.debug("progress float: \(progress)") logger.debug("progress float: \(progress)")
await didUpdate(.syncProgress(progress)) await didUpdate(.syncProgress(progress, areFundsSpendable))
} }
progressReportReducer = Constants.reportDelay progressReportReducer = Constants.reportDelay
} else { } else {
progressReportReducer -= 1 progressReportReducer -= 1

View File

@ -483,10 +483,10 @@ extension CompactBlockProcessor {
case handledReorg(_ reorgHeight: BlockHeight, _ rewindHeight: BlockHeight) case handledReorg(_ reorgHeight: BlockHeight, _ rewindHeight: BlockHeight)
/// Event sent when progress of some specific action happened. /// Event sent when progress of some specific action happened.
case syncProgress(Float) case syncProgress(Float, Bool)
/// Event sent when progress of the sync process changes. /// Event sent when progress of the sync process changes.
case progressUpdated(Float) case progressUpdated(Float, Bool)
/// Event sent when the CompactBlockProcessor fetched utxos from lightwalletd attempted to store them. /// Event sent when the CompactBlockProcessor fetched utxos from lightwalletd attempted to store them.
case storedUTXOs((inserted: [UnspentTransactionOutputEntity], skipped: [UnspentTransactionOutputEntity])) case storedUTXOs((inserted: [UnspentTransactionOutputEntity], skipped: [UnspentTransactionOutputEntity]))
@ -569,7 +569,9 @@ extension CompactBlockProcessor {
await self?.send(event: event) await self?.send(event: event)
if let progressChanged = await self?.compactBlockProgress.hasProgressUpdated(event), progressChanged { if let progressChanged = await self?.compactBlockProgress.hasProgressUpdated(event), progressChanged {
if let progress = await self?.compactBlockProgress.progress { if let progress = await self?.compactBlockProgress.progress {
await self?.send(event: .progressUpdated(progress)) await self?.send(
event: .progressUpdated(progress, self?.compactBlockProgress.areFundsSpendable ?? false)
)
} }
} }
} }
@ -713,7 +715,7 @@ extension CompactBlockProcessor {
let lastScannedHeight = await latestBlocksDataProvider.maxScannedHeight let lastScannedHeight = await latestBlocksDataProvider.maxScannedHeight
// Some actions may not run. For example there are no transactions to enhance and therefore there is no enhance progress. And in // Some actions may not run. For example there are no transactions to enhance and therefore there is no enhance progress. And in
// cases like this computation of final progress won't work properly. So let's fake 100% progress at the end of the sync process. // cases like this computation of final progress won't work properly. So let's fake 100% progress at the end of the sync process.
await send(event: .progressUpdated(1)) await send(event: .progressUpdated(1, false))
await send(event: .finished(lastScannedHeight)) await send(event: .finished(lastScannedHeight))
await context.update(state: .finished) await context.update(state: .finished)

View File

@ -11,14 +11,16 @@ final actor CompactBlockProgress {
static let zero = CompactBlockProgress() static let zero = CompactBlockProgress()
var progress: Float = 0.0 var progress: Float = 0.0
var areFundsSpendable: Bool = false
func hasProgressUpdated(_ event: CompactBlockProcessor.Event) -> Bool { func hasProgressUpdated(_ event: CompactBlockProcessor.Event) -> Bool {
guard case .syncProgress(let update) = event else { guard case let .syncProgress(progress, areFundsSpendable) = event else {
return false return false
} }
progress = update self.progress = progress
self.areFundsSpendable = areFundsSpendable
return true return true
} }
} }

View File

@ -33,8 +33,7 @@ struct ScanProgress: Equatable {
func progress() throws -> Float { func progress() throws -> Float {
guard denominator != 0 else { guard denominator != 0 else {
// this shouldn't happen but if it does, we need to get notified by clients and work on a fix return 1.0
throw ZcashError.rustScanProgressOutOfRange("\(numerator)/\(denominator)")
} }
let value = Float(numerator) / Float(denominator) let value = Float(numerator) / Float(denominator)
@ -52,6 +51,7 @@ struct WalletSummary: Equatable {
let accountBalances: [AccountUUID: AccountBalance] let accountBalances: [AccountUUID: AccountBalance]
let chainTipHeight: BlockHeight let chainTipHeight: BlockHeight
let fullyScannedHeight: BlockHeight let fullyScannedHeight: BlockHeight
let recoveryProgress: ScanProgress?
let scanProgress: ScanProgress? let scanProgress: ScanProgress?
let nextSaplingSubtreeIndex: UInt32 let nextSaplingSubtreeIndex: UInt32
let nextOrchardSubtreeIndex: UInt32 let nextOrchardSubtreeIndex: UInt32

View File

@ -909,6 +909,7 @@ struct ZcashRustBackend: ZcashRustBackendWelding {
accountBalances: accountBalances, accountBalances: accountBalances,
chainTipHeight: BlockHeight(summaryPtr.pointee.chain_tip_height), chainTipHeight: BlockHeight(summaryPtr.pointee.chain_tip_height),
fullyScannedHeight: BlockHeight(summaryPtr.pointee.fully_scanned_height), fullyScannedHeight: BlockHeight(summaryPtr.pointee.fully_scanned_height),
recoveryProgress: summaryPtr.pointee.recovery_progress?.pointee.toScanProgress(),
scanProgress: summaryPtr.pointee.scan_progress?.pointee.toScanProgress(), scanProgress: summaryPtr.pointee.scan_progress?.pointee.toScanProgress(),
nextSaplingSubtreeIndex: UInt32(summaryPtr.pointee.next_sapling_subtree_index), nextSaplingSubtreeIndex: UInt32(summaryPtr.pointee.next_sapling_subtree_index),
nextOrchardSubtreeIndex: UInt32(summaryPtr.pointee.next_orchard_subtree_index) nextOrchardSubtreeIndex: UInt32(summaryPtr.pointee.next_orchard_subtree_index)

View File

@ -436,7 +436,8 @@ public enum SyncStatus: Equatable {
public static func == (lhs: SyncStatus, rhs: SyncStatus) -> Bool { public static func == (lhs: SyncStatus, rhs: SyncStatus) -> Bool {
switch (lhs, rhs) { switch (lhs, rhs) {
case (.unprepared, .unprepared): return true case (.unprepared, .unprepared): return true
case let (.syncing(lhsProgress), .syncing(rhsProgress)): return lhsProgress == rhsProgress case let (.syncing(lhsSyncProgress, lhsRecoveryPrgoress), .syncing(rhsSyncProgress, rhsRecoveryPrgoress)):
return lhsSyncProgress == rhsSyncProgress && lhsRecoveryPrgoress == rhsRecoveryPrgoress
case (.upToDate, .upToDate): return true case (.upToDate, .upToDate): return true
case (.error, .error): return true case (.error, .error): return true
default: return false default: return false
@ -448,7 +449,7 @@ public enum SyncStatus: Equatable {
/// taking other maintenance steps that need to occur after an upgrade. /// taking other maintenance steps that need to occur after an upgrade.
case unprepared case unprepared
case syncing(_ progress: Float) case syncing(_ syncProgress: Float, _ areFundsSpendable: Bool)
/// Indicates that this Synchronizer is fully up to date and ready for all wallet functions. /// Indicates that this Synchronizer is fully up to date and ready for all wallet functions.
/// When set, a UI element may want to turn green. /// When set, a UI element may want to turn green.
@ -501,7 +502,7 @@ enum InternalSyncStatus: Equatable {
case unprepared case unprepared
/// Indicates that this Synchronizer is actively processing new blocks (consists of fetch, scan and enhance operations) /// Indicates that this Synchronizer is actively processing new blocks (consists of fetch, scan and enhance operations)
case syncing(Float) case syncing(Float, Bool)
/// Indicates that this Synchronizer is fully up to date and ready for all wallet functions. /// Indicates that this Synchronizer is fully up to date and ready for all wallet functions.
/// When set, a UI element may want to turn green. /// When set, a UI element may want to turn green.
@ -597,7 +598,8 @@ extension InternalSyncStatus {
public static func == (lhs: InternalSyncStatus, rhs: InternalSyncStatus) -> Bool { public static func == (lhs: InternalSyncStatus, rhs: InternalSyncStatus) -> Bool {
switch (lhs, rhs) { switch (lhs, rhs) {
case (.unprepared, .unprepared): return true case (.unprepared, .unprepared): return true
case let (.syncing(lhsProgress), .syncing(rhsProgress)): return lhsProgress == rhsProgress case let (.syncing(lhsSyncProgress, lhsRecoveryPrgoress), .syncing(rhsSyncProgress, rhsRecoveryPrgoress)):
return lhsSyncProgress == rhsSyncProgress && lhsRecoveryPrgoress == rhsRecoveryPrgoress
case (.synced, .synced): return true case (.synced, .synced): return true
case (.stopped, .stopped): return true case (.stopped, .stopped): return true
case (.disconnected, .disconnected): return true case (.disconnected, .disconnected): return true
@ -608,8 +610,8 @@ extension InternalSyncStatus {
} }
extension InternalSyncStatus { extension InternalSyncStatus {
init(_ blockProcessorProgress: Float) { init(_ syncProgress: Float, _ areFundsSpendable: Bool) {
self = .syncing(blockProcessorProgress) self = .syncing(syncProgress, areFundsSpendable)
} }
} }
@ -618,8 +620,8 @@ extension InternalSyncStatus {
switch self { switch self {
case .unprepared: case .unprepared:
return .unprepared return .unprepared
case .syncing(let progress): case let .syncing(syncProgress, areFundsSpendable):
return .syncing(progress) return .syncing(syncProgress, areFundsSpendable)
case .synced: case .synced:
return .upToDate return .upToDate
case .stopped: case .stopped:

View File

@ -173,8 +173,34 @@ public class SDKSynchronizer: Synchronizer {
await blockProcessor.start(retry: retry) await blockProcessor.start(retry: retry)
case .stopped, .synced, .disconnected, .error: case .stopped, .synced, .disconnected, .error:
let syncProgress = (try? await initializer.rustBackend.getWalletSummary()?.scanProgress?.progress()) ?? 0 let walletSummary = try? await initializer.rustBackend.getWalletSummary()
await updateStatus(.syncing(syncProgress)) let recoveryProgress = walletSummary?.recoveryProgress
var syncProgress: Float = 0.0
var areFundsSpendable = false
if let scanProgress = walletSummary?.scanProgress {
let composedNumerator: Float = Float(scanProgress.numerator) + Float(recoveryProgress?.numerator ?? 0)
let composedDenominator: Float = Float(scanProgress.denominator) + Float(recoveryProgress?.denominator ?? 0)
let progress: Float
if composedDenominator == 0 {
progress = 1.0
} else {
progress = composedNumerator / composedDenominator
}
// this shouldn't happen but if it does, we need to get notified by clients and work on a fix
if progress > 1.0 {
throw ZcashError.rustScanProgressOutOfRange("\(progress)")
}
let scanProgress: Float = (try? scanProgress.progress()) ?? 0.0
areFundsSpendable = scanProgress == 1.0
syncProgress = progress
}
await updateStatus(.syncing(syncProgress, areFundsSpendable))
await blockProcessor.start(retry: retry) await blockProcessor.start(retry: retry)
} }
} }
@ -240,8 +266,8 @@ public class SDKSynchronizer: Synchronizer {
// log reorg information // log reorg information
self?.logger.info("handling reorg at: \(reorgHeight) with rewind height: \(rewindHeight)") self?.logger.info("handling reorg at: \(reorgHeight) with rewind height: \(rewindHeight)")
case let .progressUpdated(progress): case let .progressUpdated(syncProgress, areFundsSpendable):
await self?.progressUpdated(progress: progress) await self?.progressUpdated(syncProgress, areFundsSpendable)
case .syncProgress: case .syncProgress:
break break
@ -281,8 +307,8 @@ public class SDKSynchronizer: Synchronizer {
} }
} }
private func progressUpdated(progress: Float) async { private func progressUpdated(_ syncProgress: Float, _ areFundsSpendable: Bool) async {
let newStatus = InternalSyncStatus(progress) let newStatus = InternalSyncStatus(syncProgress, areFundsSpendable)
await updateStatus(newStatus) await updateStatus(newStatus)
} }

View File

@ -197,19 +197,19 @@ class SynchronizerDarksideTests: ZcashTestCase {
SynchronizerState( SynchronizerState(
syncSessionID: uuids[0], syncSessionID: uuids[0],
accountsBalances: [:], accountsBalances: [:],
internalSyncStatus: .syncing(0), internalSyncStatus: .syncing(0, false),
latestBlockHeight: 0 latestBlockHeight: 0
), ),
SynchronizerState( SynchronizerState(
syncSessionID: uuids[0], syncSessionID: uuids[0],
accountsBalances: [:], accountsBalances: [:],
internalSyncStatus: .syncing(0.9), internalSyncStatus: .syncing(0.9, false),
latestBlockHeight: 663189 latestBlockHeight: 663189
), ),
SynchronizerState( SynchronizerState(
syncSessionID: uuids[0], syncSessionID: uuids[0],
accountsBalances: [:], accountsBalances: [:],
internalSyncStatus: .syncing(1.0), internalSyncStatus: .syncing(1.0, false),
latestBlockHeight: 663189 latestBlockHeight: 663189
), ),
SynchronizerState( SynchronizerState(
@ -269,19 +269,19 @@ class SynchronizerDarksideTests: ZcashTestCase {
SynchronizerState( SynchronizerState(
syncSessionID: uuids[0], syncSessionID: uuids[0],
accountsBalances: [:], accountsBalances: [:],
internalSyncStatus: .syncing(0), internalSyncStatus: .syncing(0, false),
latestBlockHeight: 0 latestBlockHeight: 0
), ),
SynchronizerState( SynchronizerState(
syncSessionID: uuids[0], syncSessionID: uuids[0],
accountsBalances: [:], accountsBalances: [:],
internalSyncStatus: .syncing(0.9), internalSyncStatus: .syncing(0.9, false),
latestBlockHeight: 663189 latestBlockHeight: 663189
), ),
SynchronizerState( SynchronizerState(
syncSessionID: uuids[0], syncSessionID: uuids[0],
accountsBalances: [:], accountsBalances: [:],
internalSyncStatus: .syncing(1.0), internalSyncStatus: .syncing(1.0, false),
latestBlockHeight: 663189 latestBlockHeight: 663189
), ),
SynchronizerState( SynchronizerState(
@ -320,19 +320,19 @@ class SynchronizerDarksideTests: ZcashTestCase {
SynchronizerState( SynchronizerState(
syncSessionID: uuids[1], syncSessionID: uuids[1],
accountsBalances: [:], accountsBalances: [:],
internalSyncStatus: .syncing(0), internalSyncStatus: .syncing(0, false),
latestBlockHeight: 663189 latestBlockHeight: 663189
), ),
SynchronizerState( SynchronizerState(
syncSessionID: uuids[1], syncSessionID: uuids[1],
accountsBalances: [:], accountsBalances: [:],
internalSyncStatus: .syncing(0.9), internalSyncStatus: .syncing(0.9, false),
latestBlockHeight: 663200 latestBlockHeight: 663200
), ),
SynchronizerState( SynchronizerState(
syncSessionID: uuids[1], syncSessionID: uuids[1],
accountsBalances: [:], accountsBalances: [:],
internalSyncStatus: .syncing(1.0), internalSyncStatus: .syncing(1.0, false),
latestBlockHeight: 663200 latestBlockHeight: 663200
), ),
SynchronizerState( SynchronizerState(

View File

@ -333,7 +333,7 @@ class SynchronizerOfflineTests: ZcashTestCase {
} }
func testIsNewSessionOnUnpreparedToValidTransition() { func testIsNewSessionOnUnpreparedToValidTransition() {
XCTAssertTrue(SessionTicker.live.isNewSyncSession(.unprepared, .syncing(0))) XCTAssertTrue(SessionTicker.live.isNewSyncSession(.unprepared, .syncing(0, false)))
} }
func testIsNotNewSessionOnUnpreparedToStateThatWontSync() { func testIsNotNewSessionOnUnpreparedToStateThatWontSync() {
@ -348,12 +348,8 @@ class SynchronizerOfflineTests: ZcashTestCase {
func testIsNotNewSyncSessionOnSameSession() { func testIsNotNewSyncSessionOnSameSession() {
XCTAssertFalse( XCTAssertFalse(
SessionTicker.live.isNewSyncSession( SessionTicker.live.isNewSyncSession(
.syncing( .syncing(0.5, false),
0.5 .syncing(0.6, false)
),
.syncing(
0.6
)
) )
) )
} }
@ -362,9 +358,7 @@ class SynchronizerOfflineTests: ZcashTestCase {
XCTAssertTrue( XCTAssertTrue(
SessionTicker.live.isNewSyncSession( SessionTicker.live.isNewSyncSession(
.synced, .synced,
.syncing( .syncing(0.6, false)
0.6
)
) )
) )
} }
@ -373,9 +367,7 @@ class SynchronizerOfflineTests: ZcashTestCase {
XCTAssertTrue( XCTAssertTrue(
SessionTicker.live.isNewSyncSession( SessionTicker.live.isNewSyncSession(
.disconnected, .disconnected,
.syncing( .syncing(0.6, false)
0.6
)
) )
) )
} }
@ -384,16 +376,14 @@ class SynchronizerOfflineTests: ZcashTestCase {
XCTAssertTrue( XCTAssertTrue(
SessionTicker.live.isNewSyncSession( SessionTicker.live.isNewSyncSession(
.stopped, .stopped,
.syncing( .syncing(0.6, false)
0.6
)
) )
) )
} }
func testInternalSyncStatusesDontDifferWhenOuterStatusIsTheSame() { func testInternalSyncStatusesDontDifferWhenOuterStatusIsTheSame() {
XCTAssertFalse(InternalSyncStatus.disconnected.isDifferent(from: .disconnected)) XCTAssertFalse(InternalSyncStatus.disconnected.isDifferent(from: .disconnected))
XCTAssertFalse(InternalSyncStatus.syncing(0).isDifferent(from: .syncing(0))) XCTAssertFalse(InternalSyncStatus.syncing(0, false).isDifferent(from: .syncing(0, false)))
XCTAssertFalse(InternalSyncStatus.stopped.isDifferent(from: .stopped)) XCTAssertFalse(InternalSyncStatus.stopped.isDifferent(from: .stopped))
XCTAssertFalse(InternalSyncStatus.synced.isDifferent(from: .synced)) XCTAssertFalse(InternalSyncStatus.synced.isDifferent(from: .synced))
XCTAssertFalse(InternalSyncStatus.unprepared.isDifferent(from: .unprepared)) XCTAssertFalse(InternalSyncStatus.unprepared.isDifferent(from: .unprepared))
@ -402,10 +392,10 @@ class SynchronizerOfflineTests: ZcashTestCase {
func testInternalSyncStatusMap_SyncingLowerBound() { func testInternalSyncStatusMap_SyncingLowerBound() {
let synchronizerState = synchronizerState( let synchronizerState = synchronizerState(
for: for:
InternalSyncStatus.syncing(0) InternalSyncStatus.syncing(0, false)
) )
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(0.0, data) { if case let .syncing(data, false) = synchronizerState.syncStatus, data != nextafter(0.0, data) {
XCTFail("Syncing is expected to be 0% (0.0) but received \(data).") XCTFail("Syncing is expected to be 0% (0.0) but received \(data).")
} }
} }
@ -413,10 +403,10 @@ class SynchronizerOfflineTests: ZcashTestCase {
func testInternalSyncStatusMap_SyncingInTheMiddle() { func testInternalSyncStatusMap_SyncingInTheMiddle() {
let synchronizerState = synchronizerState( let synchronizerState = synchronizerState(
for: for:
InternalSyncStatus.syncing(0.45) InternalSyncStatus.syncing(0.45, false)
) )
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(0.45, data) { if case let .syncing(data, false) = synchronizerState.syncStatus, data != nextafter(0.45, data) {
XCTFail("Syncing is expected to be 45% (0.45) but received \(data).") XCTFail("Syncing is expected to be 45% (0.45) but received \(data).")
} }
} }
@ -424,18 +414,18 @@ class SynchronizerOfflineTests: ZcashTestCase {
func testInternalSyncStatusMap_SyncingUpperBound() { func testInternalSyncStatusMap_SyncingUpperBound() {
let synchronizerState = synchronizerState( let synchronizerState = synchronizerState(
for: for:
InternalSyncStatus.syncing(0.9) InternalSyncStatus.syncing(0.9, false)
) )
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(0.9, data) { if case let .syncing(data, false) = synchronizerState.syncStatus, data != nextafter(0.9, data) {
XCTFail("Syncing is expected to be 90% (0.9) but received \(data).") XCTFail("Syncing is expected to be 90% (0.9) but received \(data).")
} }
} }
func testInternalSyncStatusMap_FetchingUpperBound() { func testInternalSyncStatusMap_FetchingUpperBound() {
let synchronizerState = synchronizerState(for: InternalSyncStatus.syncing(1)) let synchronizerState = synchronizerState(for: InternalSyncStatus.syncing(1, false))
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(1.0, data) { if case let .syncing(data, false) = synchronizerState.syncStatus, data != nextafter(1.0, data) {
XCTFail("Syncing is expected to be 100% (1.0) but received \(data).") XCTFail("Syncing is expected to be 100% (1.0) but received \(data).")
} }
} }

View File

@ -135,9 +135,6 @@ class ZcashRustBackendTests: XCTestCase {
} }
func testScanProgressThrowsOnWrongValues() { func testScanProgressThrowsOnWrongValues() {
// Assert that throws on Zero denominator
XCTAssertThrowsError(try ScanProgress(numerator: 0, denominator: 0).progress())
// Assert that throws on numerator > denominator // Assert that throws on numerator > denominator
XCTAssertThrowsError(try ScanProgress(numerator: 23, denominator: 2).progress()) XCTAssertThrowsError(try ScanProgress(numerator: 23, denominator: 2).progress())

View File

@ -146,7 +146,7 @@ extension SynchronizerState {
SynchronizerState( SynchronizerState(
syncSessionID: .nullID, syncSessionID: .nullID,
accountsBalances: [:], accountsBalances: [:],
internalSyncStatus: .syncing(0), internalSyncStatus: .syncing(0, false),
latestBlockHeight: 222222 latestBlockHeight: 222222
) )
} }