[#843] Simplify Synchronizer Status
- SyncStatus refactored to InternalSyncStatus, so the SDK works internally with the SyncStatus as previously - new SyncStatus is a computed property that maps InternalSyncStatus to simplified SyncStatus [#843] Simplify Synchronizer Status (#1010) - simplification of SyncStatus done - % computation moved to the mapping function so the rest of the SDK works just like before - fixed unit tests - new unit tests checking the boundaries of the new progress [#843] Simplify Synchronizer Status (#1010) - removed commented code [#843] Simplify Synchronizer Status (#1010) - package.resolved [#843] Simplify Synchronizer Status (#1010) - fixed dark side tests [#843] Simplify Synchronizer Status (#1010) - package.resolved
This commit is contained in:
parent
336c5a7c38
commit
44e17ca042
|
@ -123,7 +123,7 @@ class SendViewController: UIViewController {
|
|||
|
||||
func isFormValid() async -> Bool {
|
||||
switch synchronizer.latestState.syncStatus {
|
||||
case .synced:
|
||||
case .upToDate:
|
||||
let isBalanceValid = await self.isBalanceValid()
|
||||
let isAmountValid = await self.isAmountValid()
|
||||
return isBalanceValid && isAmountValid && isRecipientValid()
|
||||
|
@ -301,26 +301,17 @@ extension SDKSynchronizer {
|
|||
static func textFor(state: SyncStatus) -> String {
|
||||
switch state {
|
||||
case .syncing(let progress):
|
||||
return "Syncing \(progress.progressHeight)/\(progress.targetHeight)"
|
||||
return "Syncing \(progress)"
|
||||
|
||||
case .enhancing(let enhanceProgress):
|
||||
return "Enhancing tx \(enhanceProgress.enhancedTransactions) of \(enhanceProgress.totalTransactions)"
|
||||
|
||||
case .fetching:
|
||||
return "fetching UTXOs"
|
||||
|
||||
case .disconnected:
|
||||
return "disconnected 💔"
|
||||
|
||||
case .stopped:
|
||||
return "Stopped 🚫"
|
||||
|
||||
case .synced:
|
||||
return "Synced 😎"
|
||||
case .upToDate:
|
||||
return "Up to Date 😎"
|
||||
|
||||
case .unprepared:
|
||||
return "Unprepared 😅"
|
||||
|
||||
case .error(ZcashError.synchronizerDisconnected):
|
||||
return "disconnected 💔"
|
||||
|
||||
case .error(let error):
|
||||
return "Error: \(error)"
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ class SyncBlocksListViewController: UIViewController {
|
|||
loggerProxy.debug("Processing synchronizer with alias \(synchronizer.alias.description) \(index)")
|
||||
|
||||
switch syncStatus {
|
||||
case .stopped, .unprepared, .synced, .disconnected, .error:
|
||||
case .unprepared, .upToDate, .error(ZcashError.synchronizerDisconnected), .error:
|
||||
do {
|
||||
if syncStatus == .unprepared {
|
||||
let derivationTool = DerivationTool(networkType: kZcashNetwork.networkType)
|
||||
|
@ -82,7 +82,7 @@ class SyncBlocksListViewController: UIViewController {
|
|||
} catch {
|
||||
loggerProxy.error("Can't start synchronizer: \(error)")
|
||||
}
|
||||
case .syncing, .enhancing, .fetching:
|
||||
case .syncing:
|
||||
synchronizer.stop()
|
||||
}
|
||||
}
|
||||
|
@ -147,9 +147,9 @@ extension SyncBlocksListViewController: UITableViewDataSource {
|
|||
|
||||
let image: UIImage?
|
||||
switch synchronizerStatus {
|
||||
case .unprepared, .synced, .stopped, .disconnected, .error:
|
||||
case .unprepared, .upToDate, .error(ZcashError.synchronizerDisconnected), .error:
|
||||
image = UIImage(systemName: "play.circle")
|
||||
case .syncing, .enhancing, .fetching:
|
||||
case .syncing:
|
||||
image = UIImage(systemName: "stop.circle")
|
||||
}
|
||||
|
||||
|
@ -173,21 +173,15 @@ extension SyncStatus {
|
|||
var text: String {
|
||||
switch self {
|
||||
case let .syncing(progress):
|
||||
return "Syncing 🤖 \(floor(progress.progress * 1000) / 10)%"
|
||||
case let .error(error):
|
||||
return "error 💔 \(error)"
|
||||
case .stopped:
|
||||
return "Stopped 🚫"
|
||||
case .synced:
|
||||
return "Synced 😎"
|
||||
case let .enhancing(progress):
|
||||
return "Enhancing 🤖 \(floor(progress.progress * 1000) / 10)%"
|
||||
case .fetching:
|
||||
return "Fetching UTXOs"
|
||||
return "Syncing 🤖 \(floor(progress * 1000) / 10)%"
|
||||
case .upToDate:
|
||||
return "Up to Date 😎"
|
||||
case .unprepared:
|
||||
return "Unprepared"
|
||||
case .disconnected:
|
||||
case .error(ZcashError.synchronizerDisconnected):
|
||||
return "Disconnected"
|
||||
case let .error(error):
|
||||
return "error 💔 \(error.localizedDescription)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,8 +82,8 @@ class SyncBlocksViewController: UIViewController {
|
|||
case let .syncing(progress):
|
||||
enhancingStarted = false
|
||||
|
||||
progressBar.progress = progress.progress
|
||||
progressLabel.text = "\(floor(progress.progress * 1000) / 10)%"
|
||||
progressBar.progress = progress
|
||||
progressLabel.text = "\(floor(progress * 1000) / 10)%"
|
||||
let syncedDate = dateFormatter.string(from: Date(timeIntervalSince1970: state.latestScannedTime))
|
||||
let progressText = """
|
||||
synced date \(syncedDate)
|
||||
|
@ -97,27 +97,11 @@ class SyncBlocksViewController: UIViewController {
|
|||
metricLabel.text = currentMetricName + report.debugDescription
|
||||
}
|
||||
|
||||
case .enhancing:
|
||||
guard !enhancingStarted else { return }
|
||||
enhancingStarted = true
|
||||
|
||||
accumulateMetrics()
|
||||
summaryLabel.text = "scan: \(accumulatedMetrics.debugDescription)"
|
||||
accumulatedMetrics = .initial
|
||||
currentMetric = .enhancement
|
||||
|
||||
case .fetching:
|
||||
break
|
||||
|
||||
case .synced:
|
||||
case .upToDate:
|
||||
accumulateMetrics()
|
||||
summaryLabel.text = "enhancement: \(accumulatedMetrics.debugDescription)"
|
||||
overallSummary()
|
||||
|
||||
case .stopped:
|
||||
break
|
||||
case .disconnected:
|
||||
break
|
||||
case .error:
|
||||
break
|
||||
}
|
||||
|
@ -163,7 +147,7 @@ class SyncBlocksViewController: UIViewController {
|
|||
func doStartStop() async {
|
||||
let syncStatus = synchronizer.latestState.syncStatus
|
||||
switch syncStatus {
|
||||
case .stopped, .unprepared, .error:
|
||||
case .unprepared, .error:
|
||||
do {
|
||||
if syncStatus == .unprepared {
|
||||
// swiftlint:disable:next force_try
|
||||
|
@ -212,7 +196,7 @@ class SyncBlocksViewController: UIViewController {
|
|||
|
||||
statusLabel.text = textFor(state: syncStatus)
|
||||
startPause.setTitle(buttonText(for: syncStatus), for: .normal)
|
||||
if case SyncStatus.synced = syncStatus {
|
||||
if case SyncStatus.upToDate = syncStatus {
|
||||
startPause.isEnabled = false
|
||||
} else {
|
||||
startPause.isEnabled = true
|
||||
|
@ -223,16 +207,12 @@ class SyncBlocksViewController: UIViewController {
|
|||
switch state {
|
||||
case .syncing:
|
||||
return "Pause"
|
||||
case .stopped, .unprepared:
|
||||
case .unprepared:
|
||||
return "Start"
|
||||
case .error, .disconnected:
|
||||
return "Retry"
|
||||
case .synced:
|
||||
case .upToDate:
|
||||
return "Chill!"
|
||||
case .enhancing:
|
||||
return "Enhance"
|
||||
case .fetching:
|
||||
return "fetch"
|
||||
case .error:
|
||||
return "Retry"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,20 +220,14 @@ class SyncBlocksViewController: UIViewController {
|
|||
switch state {
|
||||
case .syncing:
|
||||
return "Syncing 🤖"
|
||||
case .error:
|
||||
return "error 💔"
|
||||
case .stopped:
|
||||
return "Stopped 🚫"
|
||||
case .synced:
|
||||
return "Synced 😎"
|
||||
case .enhancing:
|
||||
return "Enhancing 🤖"
|
||||
case .fetching:
|
||||
return "Fetching UTXOs"
|
||||
case .upToDate:
|
||||
return "Up to Date 😎"
|
||||
case .unprepared:
|
||||
return "Unprepared"
|
||||
case .disconnected:
|
||||
case .error(ZcashError.synchronizerDisconnected):
|
||||
return "Disconnected"
|
||||
case .error:
|
||||
return "error 💔"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,19 +15,19 @@ public typealias RefreshedUTXOs = (inserted: [UnspentTransactionOutputEntity], s
|
|||
public enum CompactBlockProgress {
|
||||
case syncing(_ progress: BlockProgress)
|
||||
case enhance(_ progress: EnhancementProgress)
|
||||
case fetch
|
||||
|
||||
case fetch(_ progress: Float)
|
||||
|
||||
public var progress: Float {
|
||||
switch self {
|
||||
case .syncing(let blockProgress):
|
||||
return blockProgress.progress
|
||||
case .enhance(let enhancementProgress):
|
||||
return enhancementProgress.progress
|
||||
default:
|
||||
return 0
|
||||
case .fetch(let fetchingProgress):
|
||||
return fetchingProgress
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public var progressHeight: BlockHeight? {
|
||||
switch self {
|
||||
case .syncing(let blockProgress):
|
||||
|
@ -38,15 +38,15 @@ public enum CompactBlockProgress {
|
|||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public var blockDate: Date? {
|
||||
if case .enhance(let enhancementProgress) = self, let time = enhancementProgress.lastFoundTransaction?.blockTime {
|
||||
return Date(timeIntervalSince1970: time)
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
public var targetHeight: BlockHeight? {
|
||||
switch self {
|
||||
case .syncing(let blockProgress):
|
||||
|
@ -682,7 +682,9 @@ actor CompactBlockProcessor {
|
|||
anyActionExecuted = true
|
||||
logger.debug("Fetching UTXO with range: \(range.lowerBound)...\(range.upperBound)")
|
||||
await updateState(.fetching)
|
||||
let result = try await utxoFetcher.fetch(at: range)
|
||||
let result = try await utxoFetcher.fetch(at: range) { [weak self] progress in
|
||||
await self?.notifyProgress(.fetch(progress))
|
||||
}
|
||||
await send(event: .storedUTXOs(result))
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ struct UTXOFetcherConfig {
|
|||
}
|
||||
|
||||
protocol UTXOFetcher {
|
||||
func fetch(at range: CompactBlockRange) async throws -> (inserted: [UnspentTransactionOutputEntity], skipped: [UnspentTransactionOutputEntity])
|
||||
func fetch(at range: CompactBlockRange, didFetch: (Float) async -> ()) async throws -> (inserted: [UnspentTransactionOutputEntity], skipped: [UnspentTransactionOutputEntity])
|
||||
}
|
||||
|
||||
struct UTXOFetcherImpl {
|
||||
|
@ -31,7 +31,7 @@ struct UTXOFetcherImpl {
|
|||
}
|
||||
|
||||
extension UTXOFetcherImpl: UTXOFetcher {
|
||||
func fetch(at range: CompactBlockRange) async throws -> (inserted: [UnspentTransactionOutputEntity], skipped: [UnspentTransactionOutputEntity]) {
|
||||
func fetch(at range: CompactBlockRange, didFetch: (Float) async -> ()) async throws -> (inserted: [UnspentTransactionOutputEntity], skipped: [UnspentTransactionOutputEntity]) {
|
||||
try Task.checkCancellation()
|
||||
|
||||
let accounts = try accountRepository.getAll()
|
||||
|
@ -60,6 +60,8 @@ extension UTXOFetcherImpl: UTXOFetcher {
|
|||
var skipped: [UnspentTransactionOutputEntity] = []
|
||||
|
||||
let startTime = Date()
|
||||
let all = Float(utxos.count)
|
||||
var counter = Float(0)
|
||||
for utxo in utxos {
|
||||
do {
|
||||
try await rustBackend.putUnspentTransparentOutput(
|
||||
|
@ -72,6 +74,8 @@ extension UTXOFetcherImpl: UTXOFetcher {
|
|||
|
||||
refreshed.append(utxo)
|
||||
|
||||
counter += 1
|
||||
await didFetch(counter / all)
|
||||
await internalSyncProgress.set(utxo.height, .latestUTXOFetchedHeight)
|
||||
} catch {
|
||||
logger.error("failed to put utxo - error: \(error)")
|
||||
|
|
|
@ -502,6 +502,9 @@ public enum ZcashError: Equatable, Error {
|
|||
/// Rewind failed, unknown archor height
|
||||
/// ZSYNCO0005
|
||||
case synchronizerRewindUnknownArchorHeight
|
||||
/// Indicates that this Synchronizer is disconnected from its lightwalletd server.
|
||||
/// ZSYNCO0006
|
||||
case synchronizerDisconnected
|
||||
|
||||
public var message: String {
|
||||
switch self {
|
||||
|
@ -650,6 +653,7 @@ public enum ZcashError: Equatable, Error {
|
|||
case .synchronizerShieldFundsInsuficientTransparentFunds: return "There is not enough transparent funds to cover fee for the shielding."
|
||||
case .synchronizerLatestUTXOsInvalidTAddress: return "LatestUTXOs for the address failed, invalid t-address."
|
||||
case .synchronizerRewindUnknownArchorHeight: return "Rewind failed, unknown archor height"
|
||||
case .synchronizerDisconnected: return "Indicates that this Synchronizer is disconnected from its lightwalletd server."
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -800,6 +804,7 @@ public enum ZcashError: Equatable, Error {
|
|||
case .synchronizerShieldFundsInsuficientTransparentFunds: return .synchronizerShieldFundsInsuficientTransparentFunds
|
||||
case .synchronizerLatestUTXOsInvalidTAddress: return .synchronizerLatestUTXOsInvalidTAddress
|
||||
case .synchronizerRewindUnknownArchorHeight: return .synchronizerRewindUnknownArchorHeight
|
||||
case .synchronizerDisconnected: return .synchronizerDisconnected
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -299,4 +299,6 @@ public enum ZcashErrorCode: String {
|
|||
case synchronizerLatestUTXOsInvalidTAddress = "ZSYNCO0004"
|
||||
/// Rewind failed, unknown archor height
|
||||
case synchronizerRewindUnknownArchorHeight = "ZSYNCO0005"
|
||||
/// Indicates that this Synchronizer is disconnected from its lightwalletd server.
|
||||
case synchronizerDisconnected = "ZSYNCO0006"
|
||||
}
|
||||
|
|
|
@ -584,4 +584,7 @@ enum ZcashErrorDefinition {
|
|||
/// Rewind failed, unknown archor height
|
||||
// sourcery: code="ZSYNCO0005"
|
||||
case synchronizerRewindUnknownArchorHeight
|
||||
/// Indicates that this Synchronizer is disconnected from its lightwalletd server.
|
||||
// sourcery: code="ZSYNCO0006"
|
||||
case synchronizerDisconnected
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ protocol LatestBlocksDataProvider {
|
|||
actor LatestBlocksDataProviderImpl: LatestBlocksDataProvider {
|
||||
let service: LightWalletService
|
||||
let transactionRepository: TransactionRepository
|
||||
|
||||
|
||||
// Valid values are stored here after Synchronizer's `prepare` is called.
|
||||
private(set) var latestScannedHeight: BlockHeight = .zero
|
||||
private(set) var latestScannedTime: TimeInterval = 0.0
|
||||
|
|
|
@ -26,6 +26,7 @@ public enum ConnectionState {
|
|||
/// the connection has been closed
|
||||
case shutdown
|
||||
}
|
||||
|
||||
/// Reports the state of a synchronizer.
|
||||
public struct SynchronizerState: Equatable {
|
||||
/// Unique Identifier for the current sync attempt
|
||||
|
@ -39,6 +40,7 @@ public struct SynchronizerState: Equatable {
|
|||
/// transparent balance known to this synchronizer given the data that has processed locally
|
||||
public var transparentBalance: WalletBalance
|
||||
/// status of the whole sync process
|
||||
var internalSyncStatus: InternalSyncStatus
|
||||
public var syncStatus: SyncStatus
|
||||
/// height of the latest scanned block known to this synchronizer.
|
||||
public var latestScannedHeight: BlockHeight
|
||||
|
@ -54,12 +56,31 @@ public struct SynchronizerState: Equatable {
|
|||
syncSessionID: .nullID,
|
||||
shieldedBalance: .zero,
|
||||
transparentBalance: .zero,
|
||||
syncStatus: .unprepared,
|
||||
internalSyncStatus: .unprepared,
|
||||
latestScannedHeight: .zero,
|
||||
latestBlockHeight: .zero,
|
||||
latestScannedTime: 0
|
||||
)
|
||||
}
|
||||
|
||||
init(
|
||||
syncSessionID: UUID,
|
||||
shieldedBalance: WalletBalance,
|
||||
transparentBalance: WalletBalance,
|
||||
internalSyncStatus: InternalSyncStatus,
|
||||
latestScannedHeight: BlockHeight,
|
||||
latestBlockHeight: BlockHeight,
|
||||
latestScannedTime: TimeInterval
|
||||
) {
|
||||
self.syncSessionID = syncSessionID
|
||||
self.shieldedBalance = shieldedBalance
|
||||
self.transparentBalance = transparentBalance
|
||||
self.internalSyncStatus = internalSyncStatus
|
||||
self.latestScannedHeight = latestScannedHeight
|
||||
self.latestBlockHeight = latestBlockHeight
|
||||
self.latestScannedTime = latestScannedTime
|
||||
self.syncStatus = internalSyncStatus.mapToSyncStatus()
|
||||
}
|
||||
}
|
||||
|
||||
public enum SynchronizerEvent {
|
||||
|
@ -86,9 +107,9 @@ public protocol Synchronizer: AnyObject {
|
|||
var connectionState: ConnectionState { get }
|
||||
|
||||
/// This stream is backed by `CurrentValueSubject`. This is primary source of information about what is the SDK doing. New values are emitted when
|
||||
/// `SyncStatus` is changed inside the SDK.
|
||||
/// `InternalSyncStatus` is changed inside the SDK.
|
||||
///
|
||||
/// Synchronization progress is part of the `SyncStatus` so this stream emits lot of values. `throttle` can be used to control amout of values
|
||||
/// Synchronization progress is part of the `InternalSyncStatus` so this stream emits lot of values. `throttle` can be used to control amout of values
|
||||
/// delivered. Values are delivered on random background thread.
|
||||
var stateStream: AnyPublisher<SynchronizerState, Never> { get }
|
||||
|
||||
|
@ -290,6 +311,55 @@ public protocol Synchronizer: AnyObject {
|
|||
}
|
||||
|
||||
public enum SyncStatus: Equatable {
|
||||
public static func == (lhs: SyncStatus, rhs: SyncStatus) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.unprepared, .unprepared): return true
|
||||
case let (.syncing(lhsProgress), .syncing(rhsProgress)): return lhsProgress == rhsProgress
|
||||
case (.upToDate, .upToDate): return true
|
||||
case (.error, .error): return true
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates that this Synchronizer is actively preparing to start,
|
||||
/// which usually involves setting up database tables, migrations or
|
||||
/// taking other maintenance steps that need to occur after an upgrade.
|
||||
case unprepared
|
||||
|
||||
case syncing(_ progress: Float)
|
||||
|
||||
/// 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.
|
||||
case upToDate
|
||||
|
||||
case error(_ error: Error)
|
||||
|
||||
public var isSyncing: Bool {
|
||||
guard case .syncing = self else { return true }
|
||||
return false
|
||||
}
|
||||
|
||||
public var isSynced: Bool {
|
||||
guard case .upToDate = self else { return true }
|
||||
return false
|
||||
}
|
||||
|
||||
public var isPrepared: Bool {
|
||||
guard case .unprepared = self else { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
public var briefDebugDescription: String {
|
||||
switch self {
|
||||
case .unprepared: return "unprepared"
|
||||
case .syncing: return "syncing"
|
||||
case .upToDate: return "up to date"
|
||||
case .error: return "error"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum InternalSyncStatus: Equatable {
|
||||
/// Indicates that this Synchronizer is actively preparing to start,
|
||||
/// which usually involves setting up database tables, migrations or
|
||||
/// taking other maintenance steps that need to occur after an upgrade.
|
||||
|
@ -302,7 +372,7 @@ public enum SyncStatus: Equatable {
|
|||
case enhancing(_ progress: EnhancementProgress)
|
||||
|
||||
/// fetches the transparent balance and stores it locally
|
||||
case fetching
|
||||
case fetching(_ progress: Float)
|
||||
|
||||
/// 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.
|
||||
|
@ -373,8 +443,8 @@ public enum RewindPolicy {
|
|||
case quick
|
||||
}
|
||||
|
||||
extension SyncStatus {
|
||||
public static func == (lhs: SyncStatus, rhs: SyncStatus) -> Bool {
|
||||
extension InternalSyncStatus {
|
||||
public static func == (lhs: InternalSyncStatus, rhs: InternalSyncStatus) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.unprepared, .unprepared): return true
|
||||
case let (.syncing(lhsProgress), .syncing(rhsProgress)): return lhsProgress == rhsProgress
|
||||
|
@ -389,15 +459,38 @@ extension SyncStatus {
|
|||
}
|
||||
}
|
||||
|
||||
extension SyncStatus {
|
||||
extension InternalSyncStatus {
|
||||
init(_ blockProcessorProgress: CompactBlockProgress) {
|
||||
switch blockProcessorProgress {
|
||||
case .syncing(let progressReport):
|
||||
self = .syncing(progressReport)
|
||||
case .enhance(let enhancingReport):
|
||||
self = .enhancing(enhancingReport)
|
||||
case .fetch:
|
||||
self = .fetching
|
||||
case .fetch(let fetchingProgress):
|
||||
self = .fetching(fetchingProgress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension InternalSyncStatus {
|
||||
func mapToSyncStatus() -> SyncStatus {
|
||||
switch self {
|
||||
case .unprepared:
|
||||
return .unprepared
|
||||
case .syncing(let progress):
|
||||
return .syncing(0.9 * progress.progress)
|
||||
case .enhancing(let progress):
|
||||
return .syncing(0.9 + 0.08 * progress.progress)
|
||||
case .fetching(let progress):
|
||||
return .syncing(0.98 + 0.02 * progress)
|
||||
case .synced:
|
||||
return .upToDate
|
||||
case .stopped:
|
||||
return .upToDate
|
||||
case .disconnected:
|
||||
return .error(ZcashError.synchronizerDisconnected)
|
||||
case .error(let error):
|
||||
return .error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ public class SDKSynchronizer: Synchronizer {
|
|||
public let logger: Logger
|
||||
|
||||
// Don't read this variable directly. Use `status` instead. And don't update this variable directly use `updateStatus()` methods instead.
|
||||
private var underlyingStatus: GenericActor<SyncStatus>
|
||||
var status: SyncStatus {
|
||||
private var underlyingStatus: GenericActor<InternalSyncStatus>
|
||||
var status: InternalSyncStatus {
|
||||
get async { await underlyingStatus.value }
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ public class SDKSynchronizer: Synchronizer {
|
|||
}
|
||||
|
||||
init(
|
||||
status: SyncStatus,
|
||||
status: InternalSyncStatus,
|
||||
initializer: Initializer,
|
||||
transactionEncoder: TransactionEncoder,
|
||||
transactionRepository: TransactionRepository,
|
||||
|
@ -102,13 +102,13 @@ public class SDKSynchronizer: Synchronizer {
|
|||
}
|
||||
}
|
||||
|
||||
func updateStatus(_ newValue: SyncStatus) async {
|
||||
func updateStatus(_ newValue: InternalSyncStatus) async {
|
||||
let oldValue = await underlyingStatus.update(newValue)
|
||||
await notify(oldStatus: oldValue, newStatus: newValue)
|
||||
}
|
||||
|
||||
func throwIfUnprepared() throws {
|
||||
if !latestState.syncStatus.isPrepared {
|
||||
if !latestState.internalSyncStatus.isPrepared {
|
||||
throw ZcashError.synchronizerNotPrepared
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ public class SDKSynchronizer: Synchronizer {
|
|||
await self?.updateStatus(.enhancing(.zero))
|
||||
|
||||
case .startedFetching:
|
||||
await self?.updateStatus(.fetching)
|
||||
await self?.updateStatus(.fetching(0))
|
||||
|
||||
case .startedSyncing:
|
||||
await self?.updateStatus(.syncing(.nullProgress))
|
||||
|
@ -260,7 +260,7 @@ public class SDKSynchronizer: Synchronizer {
|
|||
}
|
||||
|
||||
private func progressUpdated(progress: CompactBlockProgress) async {
|
||||
let newStatus = SyncStatus(progress)
|
||||
let newStatus = InternalSyncStatus(progress)
|
||||
await updateStatus(newStatus)
|
||||
}
|
||||
|
||||
|
@ -461,7 +461,7 @@ public class SDKSynchronizer: Synchronizer {
|
|||
public func rewind(_ policy: RewindPolicy) -> AnyPublisher<Void, Error> {
|
||||
let subject = PassthroughSubject<Void, Error>()
|
||||
Task(priority: .high) {
|
||||
if !latestState.syncStatus.isPrepared {
|
||||
if !latestState.internalSyncStatus.isPrepared {
|
||||
subject.send(completion: .failure(ZcashError.synchronizerNotPrepared))
|
||||
return
|
||||
}
|
||||
|
@ -537,7 +537,7 @@ public class SDKSynchronizer: Synchronizer {
|
|||
|
||||
// MARK: notify state
|
||||
|
||||
private func snapshotState(status: SyncStatus) async -> SynchronizerState {
|
||||
private func snapshotState(status: InternalSyncStatus) async -> SynchronizerState {
|
||||
return await SynchronizerState(
|
||||
syncSessionID: syncSession.value,
|
||||
shieldedBalance: WalletBalance(
|
||||
|
@ -545,14 +545,14 @@ public class SDKSynchronizer: Synchronizer {
|
|||
total: (try? await getShieldedBalance()) ?? .zero
|
||||
),
|
||||
transparentBalance: (try? await blockProcessor.getTransparentBalance(accountIndex: 0)) ?? .zero,
|
||||
syncStatus: status,
|
||||
internalSyncStatus: status,
|
||||
latestScannedHeight: latestBlocksDataProvider.latestScannedHeight,
|
||||
latestBlockHeight: latestBlocksDataProvider.latestBlockHeight,
|
||||
latestScannedTime: latestBlocksDataProvider.latestScannedTime
|
||||
)
|
||||
}
|
||||
|
||||
private func notify(oldStatus: SyncStatus, newStatus: SyncStatus) async {
|
||||
private func notify(oldStatus: InternalSyncStatus, newStatus: InternalSyncStatus) async {
|
||||
guard oldStatus != newStatus else { return }
|
||||
|
||||
let newState: SynchronizerState
|
||||
|
@ -617,8 +617,8 @@ extension SDKSynchronizer {
|
|||
}
|
||||
}
|
||||
|
||||
extension SyncStatus {
|
||||
func isDifferent(from otherStatus: SyncStatus) -> Bool {
|
||||
extension InternalSyncStatus {
|
||||
func isDifferent(from otherStatus: InternalSyncStatus) -> Bool {
|
||||
switch (self, otherStatus) {
|
||||
case (.unprepared, .unprepared): return false
|
||||
case (.syncing, .syncing): return false
|
||||
|
@ -636,7 +636,7 @@ extension SyncStatus {
|
|||
struct SessionTicker {
|
||||
/// Helper function to determine whether we are in front of a SyncSession change for a given syncStatus
|
||||
/// transition we consider that every sync attempt is a new sync session and should have it's unique UUID reported.
|
||||
var isNewSyncSession: (SyncStatus, SyncStatus) -> Bool
|
||||
var isNewSyncSession: (InternalSyncStatus, InternalSyncStatus) -> Bool
|
||||
}
|
||||
|
||||
extension SessionTicker {
|
||||
|
|
|
@ -22,7 +22,7 @@ final class InternalStateConsistencyTests: ZcashTestCase {
|
|||
let branchID = "2bb40e60"
|
||||
let chainName = "main"
|
||||
let network = DarksideWalletDNetwork()
|
||||
var sdkSynchronizerSyncStatusHandler: SDKSynchronizerSyncStatusHandler! = SDKSynchronizerSyncStatusHandler()
|
||||
var sdkSynchronizerInternalSyncStatusHandler: SDKSynchronizerInternalSyncStatusHandler! = SDKSynchronizerInternalSyncStatusHandler()
|
||||
|
||||
override func setUp() async throws {
|
||||
try await super.setUp()
|
||||
|
@ -41,7 +41,7 @@ final class InternalStateConsistencyTests: ZcashTestCase {
|
|||
try await super.tearDown()
|
||||
let coordinator = self.coordinator!
|
||||
self.coordinator = nil
|
||||
sdkSynchronizerSyncStatusHandler = nil
|
||||
sdkSynchronizerInternalSyncStatusHandler = nil
|
||||
|
||||
try await coordinator.stop()
|
||||
try? FileManager.default.removeItem(at: coordinator.databases.fsCacheDbRoot)
|
||||
|
@ -49,7 +49,7 @@ final class InternalStateConsistencyTests: ZcashTestCase {
|
|||
}
|
||||
|
||||
func testInternalStateIsConsistentWhenMigrating() async throws {
|
||||
sdkSynchronizerSyncStatusHandler.subscribe(
|
||||
sdkSynchronizerInternalSyncStatusHandler.subscribe(
|
||||
to: coordinator.synchronizer.stateStream,
|
||||
expectations: [.stopped: firstSyncExpectation]
|
||||
)
|
||||
|
|
|
@ -186,7 +186,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: .nullID,
|
||||
shieldedBalance: .zero,
|
||||
transparentBalance: .zero,
|
||||
syncStatus: .disconnected,
|
||||
internalSyncStatus: .disconnected,
|
||||
latestScannedHeight: 663150,
|
||||
latestBlockHeight: 0,
|
||||
latestScannedTime: 1576821833
|
||||
|
@ -195,7 +195,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: .zero,
|
||||
transparentBalance: .zero,
|
||||
syncStatus: .syncing(BlockProgress(startHeight: 0, targetHeight: 0, progressHeight: 0)),
|
||||
internalSyncStatus: .syncing(BlockProgress(startHeight: 0, targetHeight: 0, progressHeight: 0)),
|
||||
latestScannedHeight: 663150,
|
||||
latestBlockHeight: 0,
|
||||
latestScannedTime: 1576821833
|
||||
|
@ -204,7 +204,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: .zero,
|
||||
syncStatus: .syncing(BlockProgress(startHeight: 663150, targetHeight: 663189, progressHeight: 663189)),
|
||||
internalSyncStatus: .syncing(BlockProgress(startHeight: 663150, targetHeight: 663189, progressHeight: 663189)),
|
||||
latestScannedHeight: 663189,
|
||||
latestBlockHeight: 663189,
|
||||
latestScannedTime: 1
|
||||
|
@ -213,7 +213,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: .zero,
|
||||
syncStatus: .enhancing(EnhancementProgress(totalTransactions: 0, enhancedTransactions: 0, lastFoundTransaction: nil, range: 0...0)),
|
||||
internalSyncStatus: .enhancing(EnhancementProgress(totalTransactions: 0, enhancedTransactions: 0, lastFoundTransaction: nil, range: 0...0)),
|
||||
latestScannedHeight: 663189,
|
||||
latestBlockHeight: 663189,
|
||||
latestScannedTime: 1
|
||||
|
@ -222,7 +222,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: .zero,
|
||||
syncStatus: .enhancing(
|
||||
internalSyncStatus: .enhancing(
|
||||
EnhancementProgress(
|
||||
totalTransactions: 2,
|
||||
enhancedTransactions: 1,
|
||||
|
@ -254,7 +254,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: .zero,
|
||||
syncStatus: .enhancing(
|
||||
internalSyncStatus: .enhancing(
|
||||
EnhancementProgress(
|
||||
totalTransactions: 2,
|
||||
enhancedTransactions: 2,
|
||||
|
@ -286,7 +286,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: .zero,
|
||||
syncStatus: .fetching,
|
||||
internalSyncStatus: .fetching(0),
|
||||
latestScannedHeight: 663189,
|
||||
latestBlockHeight: 663189,
|
||||
latestScannedTime: 1
|
||||
|
@ -295,7 +295,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: .zero,
|
||||
syncStatus: .synced,
|
||||
internalSyncStatus: .synced,
|
||||
latestScannedHeight: 663189,
|
||||
latestBlockHeight: 663189,
|
||||
latestScannedTime: 1
|
||||
|
@ -346,7 +346,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: .nullID,
|
||||
shieldedBalance: .zero,
|
||||
transparentBalance: .zero,
|
||||
syncStatus: .disconnected,
|
||||
internalSyncStatus: .disconnected,
|
||||
latestScannedHeight: 663150,
|
||||
latestBlockHeight: 0,
|
||||
latestScannedTime: 1576821833.0
|
||||
|
@ -355,7 +355,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: .zero,
|
||||
transparentBalance: .zero,
|
||||
syncStatus: .syncing(BlockProgress(startHeight: 0, targetHeight: 0, progressHeight: 0)),
|
||||
internalSyncStatus: .syncing(BlockProgress(startHeight: 0, targetHeight: 0, progressHeight: 0)),
|
||||
latestScannedHeight: 663150,
|
||||
latestBlockHeight: 0,
|
||||
latestScannedTime: 1576821833.0
|
||||
|
@ -364,7 +364,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: .zero,
|
||||
syncStatus: .syncing(BlockProgress(startHeight: 663150, targetHeight: 663189, progressHeight: 663189)),
|
||||
internalSyncStatus: .syncing(BlockProgress(startHeight: 663150, targetHeight: 663189, progressHeight: 663189)),
|
||||
latestScannedHeight: 663189,
|
||||
latestBlockHeight: 663189,
|
||||
latestScannedTime: 1
|
||||
|
@ -373,7 +373,9 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: WalletBalance(verified: Zatoshi(0), total: Zatoshi(0)),
|
||||
syncStatus: .enhancing(EnhancementProgress(totalTransactions: 0, enhancedTransactions: 0, lastFoundTransaction: nil, range: 0...0)),
|
||||
internalSyncStatus: .enhancing(
|
||||
EnhancementProgress(totalTransactions: 0, enhancedTransactions: 0, lastFoundTransaction: nil, range: 0...0)
|
||||
),
|
||||
latestScannedHeight: 663189,
|
||||
latestBlockHeight: 663189,
|
||||
latestScannedTime: 1
|
||||
|
@ -382,7 +384,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: WalletBalance(verified: Zatoshi(0), total: Zatoshi(0)),
|
||||
syncStatus: .enhancing(
|
||||
internalSyncStatus: .enhancing(
|
||||
EnhancementProgress(
|
||||
totalTransactions: 2,
|
||||
enhancedTransactions: 1,
|
||||
|
@ -414,7 +416,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: WalletBalance(verified: Zatoshi(0), total: Zatoshi(0)),
|
||||
syncStatus: .enhancing(
|
||||
internalSyncStatus: .enhancing(
|
||||
EnhancementProgress(
|
||||
totalTransactions: 2,
|
||||
enhancedTransactions: 2,
|
||||
|
@ -446,7 +448,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: WalletBalance(verified: Zatoshi(0), total: Zatoshi(0)),
|
||||
syncStatus: .fetching,
|
||||
internalSyncStatus: .fetching(0),
|
||||
latestScannedHeight: 663189,
|
||||
latestBlockHeight: 663189,
|
||||
latestScannedTime: 1
|
||||
|
@ -455,7 +457,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[0],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: WalletBalance(verified: Zatoshi(0), total: Zatoshi(0)),
|
||||
syncStatus: .synced,
|
||||
internalSyncStatus: .synced,
|
||||
latestScannedHeight: 663189,
|
||||
latestBlockHeight: 663189,
|
||||
latestScannedTime: 1
|
||||
|
@ -491,7 +493,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[1],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100000), total: Zatoshi(200000)),
|
||||
transparentBalance: WalletBalance(verified: Zatoshi(0), total: Zatoshi(0)),
|
||||
syncStatus: .syncing(BlockProgress(startHeight: 0, targetHeight: 0, progressHeight: 0)),
|
||||
internalSyncStatus: .syncing(BlockProgress(startHeight: 0, targetHeight: 0, progressHeight: 0)),
|
||||
latestScannedHeight: 663189,
|
||||
latestBlockHeight: 663189,
|
||||
latestScannedTime: 1.0
|
||||
|
@ -500,7 +502,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[1],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(200000), total: Zatoshi(200000)),
|
||||
transparentBalance: WalletBalance(verified: Zatoshi(0), total: Zatoshi(0)),
|
||||
syncStatus: .syncing(BlockProgress(startHeight: 663190, targetHeight: 663200, progressHeight: 663200)),
|
||||
internalSyncStatus: .syncing(BlockProgress(startHeight: 663190, targetHeight: 663200, progressHeight: 663200)),
|
||||
latestScannedHeight: 663200,
|
||||
latestBlockHeight: 663200,
|
||||
latestScannedTime: 1
|
||||
|
@ -509,7 +511,9 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[1],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(200000), total: Zatoshi(200000)),
|
||||
transparentBalance: WalletBalance(verified: Zatoshi(0), total: Zatoshi(0)),
|
||||
syncStatus: .enhancing(EnhancementProgress(totalTransactions: 0, enhancedTransactions: 0, lastFoundTransaction: nil, range: 0...0)),
|
||||
internalSyncStatus: .enhancing(
|
||||
EnhancementProgress(totalTransactions: 0, enhancedTransactions: 0, lastFoundTransaction: nil, range: 0...0)
|
||||
),
|
||||
latestScannedHeight: 663200,
|
||||
latestBlockHeight: 663200,
|
||||
latestScannedTime: 1
|
||||
|
@ -518,7 +522,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[1],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(200000), total: Zatoshi(200000)),
|
||||
transparentBalance: WalletBalance(verified: Zatoshi(0), total: Zatoshi(0)),
|
||||
syncStatus: .fetching,
|
||||
internalSyncStatus: .fetching(0),
|
||||
latestScannedHeight: 663200,
|
||||
latestBlockHeight: 663200,
|
||||
latestScannedTime: 1
|
||||
|
@ -527,7 +531,7 @@ class SynchronizerDarksideTests: ZcashTestCase {
|
|||
syncSessionID: uuids[1],
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(200000), total: Zatoshi(200000)),
|
||||
transparentBalance: WalletBalance(verified: Zatoshi(0), total: Zatoshi(0)),
|
||||
syncStatus: .synced,
|
||||
internalSyncStatus: .synced,
|
||||
latestScannedHeight: 663200,
|
||||
latestBlockHeight: 663200,
|
||||
latestScannedTime: 1
|
||||
|
|
|
@ -22,7 +22,7 @@ final class SynchronizerTests: ZcashTestCase {
|
|||
let chainName = "main"
|
||||
let network = DarksideWalletDNetwork()
|
||||
var cancellables: [AnyCancellable] = []
|
||||
var sdkSynchronizerSyncStatusHandler: SDKSynchronizerSyncStatusHandler! = SDKSynchronizerSyncStatusHandler()
|
||||
var sdkSynchronizerInternalSyncStatusHandler: SDKSynchronizerInternalSyncStatusHandler! = SDKSynchronizerInternalSyncStatusHandler()
|
||||
|
||||
override func setUp() async throws {
|
||||
try await super.setUp()
|
||||
|
@ -49,7 +49,7 @@ final class SynchronizerTests: ZcashTestCase {
|
|||
try await super.tearDown()
|
||||
let coordinator = self.coordinator!
|
||||
self.coordinator = nil
|
||||
sdkSynchronizerSyncStatusHandler = nil
|
||||
sdkSynchronizerInternalSyncStatusHandler = nil
|
||||
cancellables = []
|
||||
|
||||
try await coordinator.stop()
|
||||
|
@ -79,7 +79,7 @@ final class SynchronizerTests: ZcashTestCase {
|
|||
sleep(10)
|
||||
|
||||
let syncStoppedExpectation = XCTestExpectation(description: "SynchronizerStopped Expectation")
|
||||
sdkSynchronizerSyncStatusHandler.subscribe(
|
||||
sdkSynchronizerInternalSyncStatusHandler.subscribe(
|
||||
to: coordinator.synchronizer.stateStream,
|
||||
expectations: [.stopped: syncStoppedExpectation]
|
||||
)
|
||||
|
|
|
@ -376,7 +376,7 @@ class SynchronizerOfflineTests: ZcashTestCase {
|
|||
|
||||
func testIsNotNewSessionOnUnpreparedToInvalidOrUnexpectedTransitions() {
|
||||
XCTAssertFalse(SessionTicker.live.isNewSyncSession(.unprepared, .synced))
|
||||
XCTAssertFalse(SessionTicker.live.isNewSyncSession(.unprepared, .fetching))
|
||||
XCTAssertFalse(SessionTicker.live.isNewSyncSession(.unprepared, .fetching(0)))
|
||||
XCTAssertFalse(SessionTicker.live.isNewSyncSession(.unprepared, .enhancing(.zero)))
|
||||
}
|
||||
|
||||
|
@ -426,12 +426,135 @@ class SynchronizerOfflineTests: ZcashTestCase {
|
|||
)
|
||||
}
|
||||
|
||||
func testSyncStatusesDontDifferWhenOuterStatusIsTheSame() {
|
||||
XCTAssertFalse(SyncStatus.disconnected.isDifferent(from: .disconnected))
|
||||
XCTAssertFalse(SyncStatus.fetching.isDifferent(from: .fetching))
|
||||
XCTAssertFalse(SyncStatus.stopped.isDifferent(from: .stopped))
|
||||
XCTAssertFalse(SyncStatus.synced.isDifferent(from: .synced))
|
||||
XCTAssertFalse(SyncStatus.syncing(.nullProgress).isDifferent(from: .syncing(.nullProgress)))
|
||||
XCTAssertFalse(SyncStatus.unprepared.isDifferent(from: .unprepared))
|
||||
func testInternalSyncStatusesDontDifferWhenOuterStatusIsTheSame() {
|
||||
XCTAssertFalse(InternalSyncStatus.disconnected.isDifferent(from: .disconnected))
|
||||
XCTAssertFalse(InternalSyncStatus.fetching(0).isDifferent(from: .fetching(0)))
|
||||
XCTAssertFalse(InternalSyncStatus.stopped.isDifferent(from: .stopped))
|
||||
XCTAssertFalse(InternalSyncStatus.synced.isDifferent(from: .synced))
|
||||
XCTAssertFalse(InternalSyncStatus.syncing(.nullProgress).isDifferent(from: .syncing(.nullProgress)))
|
||||
XCTAssertFalse(InternalSyncStatus.unprepared.isDifferent(from: .unprepared))
|
||||
}
|
||||
|
||||
func testInternalSyncStatusMap_SyncingLowerBound() {
|
||||
let synchronizerState = synchronizerState(
|
||||
for:
|
||||
InternalSyncStatus.syncing(BlockProgress(startHeight: 0, targetHeight: 100, progressHeight: 0))
|
||||
)
|
||||
|
||||
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(0.0, data) {
|
||||
XCTFail("Syncing is expected to be 0% (0.0) but received \(data).")
|
||||
}
|
||||
}
|
||||
|
||||
func testInternalSyncStatusMap_SyncingInTheMiddle() {
|
||||
let synchronizerState = synchronizerState(
|
||||
for:
|
||||
InternalSyncStatus.syncing(BlockProgress(startHeight: 0, targetHeight: 100, progressHeight: 50))
|
||||
)
|
||||
|
||||
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(0.45, data) {
|
||||
XCTFail("Syncing is expected to be 45% (0.45) but received \(data).")
|
||||
}
|
||||
}
|
||||
|
||||
func testInternalSyncStatusMap_SyncingUpperBound() {
|
||||
let synchronizerState = synchronizerState(
|
||||
for:
|
||||
InternalSyncStatus.syncing(BlockProgress(startHeight: 0, targetHeight: 100, progressHeight: 100))
|
||||
)
|
||||
|
||||
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(0.9, data) {
|
||||
XCTFail("Syncing is expected to be 90% (0.9) but received \(data).")
|
||||
}
|
||||
}
|
||||
|
||||
func testInternalSyncStatusMap_EnhancingLowerBound() {
|
||||
let synchronizerState = synchronizerState(
|
||||
for:
|
||||
InternalSyncStatus.enhancing(
|
||||
EnhancementProgress(
|
||||
totalTransactions: 100,
|
||||
enhancedTransactions: 0,
|
||||
lastFoundTransaction: nil,
|
||||
range: CompactBlockRange(uncheckedBounds: (0, 100))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(0.9, data) {
|
||||
XCTFail("Syncing is expected to be 90% (0.9) but received \(data).")
|
||||
}
|
||||
}
|
||||
|
||||
func testInternalSyncStatusMap_EnhancingInTheMiddle() {
|
||||
let synchronizerState = synchronizerState(
|
||||
for:
|
||||
InternalSyncStatus.enhancing(
|
||||
EnhancementProgress(
|
||||
totalTransactions: 100,
|
||||
enhancedTransactions: 50,
|
||||
lastFoundTransaction: nil,
|
||||
range: CompactBlockRange(uncheckedBounds: (0, 100))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(0.94, data) {
|
||||
XCTFail("Syncing is expected to be 94% (0.94) but received \(data).")
|
||||
}
|
||||
}
|
||||
|
||||
func testInternalSyncStatusMap_EnhancingUpperBound() {
|
||||
let synchronizerState = synchronizerState(
|
||||
for:
|
||||
InternalSyncStatus.enhancing(
|
||||
EnhancementProgress(
|
||||
totalTransactions: 100,
|
||||
enhancedTransactions: 100,
|
||||
lastFoundTransaction: nil,
|
||||
range: CompactBlockRange(uncheckedBounds: (0, 100))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(0.98, data) {
|
||||
XCTFail("Syncing is expected to be 98% (0.98) but received \(data).")
|
||||
}
|
||||
}
|
||||
|
||||
func testInternalSyncStatusMap_FetchingLowerBound() {
|
||||
let synchronizerState = synchronizerState(for: InternalSyncStatus.fetching(0))
|
||||
|
||||
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(0.98, data) {
|
||||
XCTFail("Syncing is expected to be 98% (0.98) but received \(data).")
|
||||
}
|
||||
}
|
||||
|
||||
func testInternalSyncStatusMap_FetchingInTheMiddle() {
|
||||
let synchronizerState = synchronizerState(for: InternalSyncStatus.fetching(0.5))
|
||||
|
||||
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(0.99, data) {
|
||||
XCTFail("Syncing is expected to be 99% (0.99) but received \(data).")
|
||||
}
|
||||
}
|
||||
|
||||
func testInternalSyncStatusMap_FetchingUpperBound() {
|
||||
let synchronizerState = synchronizerState(for: InternalSyncStatus.fetching(1))
|
||||
|
||||
if case let .syncing(data) = synchronizerState.syncStatus, data != nextafter(1.0, data) {
|
||||
XCTFail("Syncing is expected to be 100% (1.0) but received \(data).")
|
||||
}
|
||||
}
|
||||
|
||||
func synchronizerState(for internalSyncStatus: InternalSyncStatus) -> SynchronizerState {
|
||||
SynchronizerState(
|
||||
syncSessionID: .nullID,
|
||||
shieldedBalance: .zero,
|
||||
transparentBalance: .zero,
|
||||
internalSyncStatus: internalSyncStatus,
|
||||
latestScannedHeight: .zero,
|
||||
latestBlockHeight: .zero,
|
||||
latestScannedTime: 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class SynchronizerTests: XCTestCase {
|
|||
|
||||
var coordinator: TestCoordinator!
|
||||
var cancellables: [AnyCancellable] = []
|
||||
var sdkSynchronizerSyncStatusHandler: SDKSynchronizerSyncStatusHandler! = SDKSynchronizerSyncStatusHandler()
|
||||
var sdkSynchronizerInternalSyncStatusHandler: SDKSynchronizerInternalSyncStatusHandler! = SDKSynchronizerInternalSyncStatusHandler()
|
||||
var rustBackend: ZcashRustBackendWelding!
|
||||
var testTempDirectory: URL!
|
||||
|
||||
|
@ -45,7 +45,7 @@ class SynchronizerTests: XCTestCase {
|
|||
super.tearDown()
|
||||
coordinator = nil
|
||||
cancellables = []
|
||||
sdkSynchronizerSyncStatusHandler = nil
|
||||
sdkSynchronizerInternalSyncStatusHandler = nil
|
||||
rustBackend = nil
|
||||
testTempDirectory = nil
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ class SynchronizerTests: XCTestCase {
|
|||
_ = try await synchronizer.prepare(with: seedBytes, viewingKeys: [ufvk], walletBirthday: birthday)
|
||||
|
||||
let syncSyncedExpectation = XCTestExpectation(description: "synchronizerSynced Expectation")
|
||||
sdkSynchronizerSyncStatusHandler.subscribe(to: synchronizer.stateStream, expectations: [.synced: syncSyncedExpectation])
|
||||
sdkSynchronizerInternalSyncStatusHandler.subscribe(to: synchronizer.stateStream, expectations: [.synced: syncSyncedExpectation])
|
||||
|
||||
let internalSyncProgress = InternalSyncProgress(
|
||||
alias: .default,
|
||||
|
|
|
@ -10,7 +10,7 @@ import Foundation
|
|||
import XCTest
|
||||
@testable import ZcashLightClientKit
|
||||
|
||||
class SDKSynchronizerSyncStatusHandler {
|
||||
class SDKSynchronizerInternalSyncStatusHandler {
|
||||
enum StatusIdentifier: String {
|
||||
case unprepared
|
||||
case syncing
|
||||
|
@ -22,20 +22,20 @@ class SDKSynchronizerSyncStatusHandler {
|
|||
case error
|
||||
}
|
||||
|
||||
private let queue = DispatchQueue(label: "SDKSynchronizerSyncStatusHandler")
|
||||
private let queue = DispatchQueue(label: "SDKSynchronizerInternalSyncStatusHandler")
|
||||
private var cancellables: [AnyCancellable] = []
|
||||
|
||||
func subscribe(to stateStream: AnyPublisher<SynchronizerState, Never>, expectations: [StatusIdentifier: XCTestExpectation]) {
|
||||
stateStream
|
||||
.receive(on: queue)
|
||||
.map { $0.syncStatus }
|
||||
.map { $0.internalSyncStatus }
|
||||
.sink { status in expectations[status.identifier]?.fulfill() }
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
}
|
||||
|
||||
extension SyncStatus {
|
||||
var identifier: SDKSynchronizerSyncStatusHandler.StatusIdentifier {
|
||||
extension InternalSyncStatus {
|
||||
var identifier: SDKSynchronizerInternalSyncStatusHandler.StatusIdentifier {
|
||||
switch self {
|
||||
case .unprepared: return .unprepared
|
||||
case .syncing: return .syncing
|
||||
|
|
|
@ -209,7 +209,7 @@ extension SynchronizerState {
|
|||
syncSessionID: .nullID,
|
||||
shieldedBalance: WalletBalance(verified: Zatoshi(100), total: Zatoshi(200)),
|
||||
transparentBalance: WalletBalance(verified: Zatoshi(200), total: Zatoshi(300)),
|
||||
syncStatus: .fetching,
|
||||
internalSyncStatus: .fetching(0),
|
||||
latestScannedHeight: 111111,
|
||||
latestBlockHeight: 222222,
|
||||
latestScannedTime: 12345678
|
||||
|
|
|
@ -147,7 +147,7 @@ class TestCoordinator {
|
|||
synchronizer.stateStream
|
||||
.sink(
|
||||
receiveValue: { [weak self] state in
|
||||
switch state.syncStatus {
|
||||
switch state.internalSyncStatus {
|
||||
case let .error(error):
|
||||
self?.synchronizerFailed(error: error)
|
||||
case .synced:
|
||||
|
@ -167,7 +167,7 @@ class TestCoordinator {
|
|||
}
|
||||
|
||||
func synchronizerSynced() throws {
|
||||
if case .stopped = self.synchronizer.latestState.syncStatus {
|
||||
if case .stopped = self.synchronizer.latestState.internalSyncStatus {
|
||||
LoggerProxy.debug("WARNING: notification received after synchronizer was stopped")
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue