Skip to content

Commit

Permalink
[#1230] Remove linear sync from the SDK
Browse files Browse the repository at this point in the history
- concept of linear syncing fully removed from the SDK, it's fully replaced with Spend-before-Sync
- BlockDAO - table blocks is no longer used, removed from the SDK and all it's associated getLastBlocks/ScannedHeights as with it
- concept of pending transactions removed from the SDK
- unit tests refactored
  • Loading branch information
LukasKorba committed Sep 8, 2023
1 parent 18141e6 commit d956e99
Show file tree
Hide file tree
Showing 39 changed files with 57 additions and 1,186 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ system itself won't remove these data.
of syncing the amount of data provided is reduced so it's consistent. Spend before Sync is done in non-linear order
so both Height and Time don't make sense anymore.

### [#1230] Remove linear sync from the SDK
`latestScannedHeight` and `latestScannedTime` removed from the SynchronizerState. Concept of pending transaction changed, `func allPendingTransactions()` is no longer available. Use `public func allTransactions()` instead.

# 0.22.0-beta

## Checkpoints
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
spendParamsURL: try! spendParamsURLHelper(),
outputParamsURL: try! outputParamsURLHelper(),
saplingParamsSourceURL: SaplingParamsSourceURL.default,
syncAlgorithm: .spendBeforeSync,
enableBackendTracing: true
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import ZcashLightClientKit

class TransactionsDataSource: NSObject {
enum TransactionType {
case pending
case sent
case received
case cleared
Expand All @@ -32,17 +31,9 @@ class TransactionsDataSource: NSObject {
self.synchronizer = synchronizer
}

// swiftlint:disable:next cyclomatic_complexity
func load() async throws {
transactions = []
switch status {
case .pending:
let rawTransactions = await synchronizer.pendingTransactions
for pendingTransaction in rawTransactions {
let memos = try await synchronizer.getMemos(for: pendingTransaction)
transactions.append(TransactionDetailModel(pendingTransaction: pendingTransaction, memos: memos))
}

case .cleared:
let rawTransactions = await synchronizer.transactions
for transaction in rawTransactions {
Expand All @@ -62,12 +53,6 @@ class TransactionsDataSource: NSObject {
transactions.append(TransactionDetailModel(sendTransaction: transaction, memos: memos))
}
case .all:
let rawPendingTransactions = await synchronizer.pendingTransactions
for pendingTransaction in rawPendingTransactions {
let memos = try await synchronizer.getMemos(for: pendingTransaction)
transactions.append(TransactionDetailModel(pendingTransaction: pendingTransaction, memos: memos))
}

let rawClearedTransactions = await synchronizer.transactions
for transaction in rawClearedTransactions {
let memos = try await synchronizer.getMemos(for: transaction)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,7 @@ class MainTableViewController: UITableViewController {

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? TransactionsTableViewController {
if let id = segue.identifier, id == "Pending" {
destination.datasource = TransactionsDataSource(
status: .pending,
synchronizer: AppDelegate.shared.sharedSynchronizer
)
destination.title = "Pending Transactions"
} else if let id = segue.identifier, id == "Sent" {
if let id = segue.identifier, id == "Sent" {
destination.datasource = TransactionsDataSource(
status: .sent,
synchronizer: AppDelegate.shared.sharedSynchronizer
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ We don't like reinventing the wheel, so we gently borrowed swift lint rules from
## `Spend before Sync` synchronization algorithm

The CompactBlockProcessor is responsible for downloading and processing blocks from the lightwalletd. Since the inception of the SDK the blocks were processed in a linear order up to the chain tip. Latests SDK has introduced brand new algorithm for syncing of the blocks. It's called `Spend before Sync` and processes blocks in non-linear order so the spendable funds are discovered as soon as possible - allowing users to create a transaction while still syncing.

By default the syncing algorithm is set to `.linear` so users of the SDK are not affected by this new feature. To switch to the `Spend before Sync` synchronization, set `syncAlgorithm: .spendBeforeSync` in the Initializer's init.

# Versioning

Expand Down
10 changes: 1 addition & 9 deletions Sources/ZcashLightClientKit/Block/Actions/Action.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ protocol ActionContext {
var state: CBPState { get async }
var prevState: CBPState? { get async }
var syncControlData: SyncControlData { get async }
var preferredSyncAlgorithm: SyncAlgorithm { get }
var supportedSyncAlgorithm: SyncAlgorithm? { get async }
var requestedRewindHeight: BlockHeight? { get async }
var totalProgressRange: CompactBlockRange { get async }
var processedHeight: BlockHeight { get async }
Expand All @@ -28,16 +26,13 @@ protocol ActionContext {
func update(lastScannedHeight: BlockHeight) async
func update(lastDownloadedHeight: BlockHeight) async
func update(lastEnhancedHeight: BlockHeight?) async
func update(supportedSyncAlgorithm: SyncAlgorithm) async
func update(requestedRewindHeight: BlockHeight) async
}

actor ActionContextImpl: ActionContext {
var state: CBPState
var prevState: CBPState?
var syncControlData: SyncControlData
let preferredSyncAlgorithm: SyncAlgorithm
var supportedSyncAlgorithm: SyncAlgorithm?
var requestedRewindHeight: BlockHeight?
/// Represents the overall range of blocks that will be synced, `SyncAlgorithm` doesn't matter.
var totalProgressRange: CompactBlockRange = 0...0
Expand All @@ -49,9 +44,8 @@ actor ActionContextImpl: ActionContext {
var lastDownloadedHeight: BlockHeight?
var lastEnhancedHeight: BlockHeight?

init(state: CBPState, preferredSyncAlgorithm: SyncAlgorithm = .linear) {
init(state: CBPState) {
self.state = state
self.preferredSyncAlgorithm = preferredSyncAlgorithm
syncControlData = SyncControlData.empty
}

Expand All @@ -69,7 +63,6 @@ actor ActionContextImpl: ActionContext {
func update(lastScannedHeight: BlockHeight) async { self.lastScannedHeight = lastScannedHeight }
func update(lastDownloadedHeight: BlockHeight) async { self.lastDownloadedHeight = lastDownloadedHeight }
func update(lastEnhancedHeight: BlockHeight?) async { self.lastEnhancedHeight = lastEnhancedHeight }
func update(supportedSyncAlgorithm: SyncAlgorithm) async { self.supportedSyncAlgorithm = supportedSyncAlgorithm }
func update(requestedRewindHeight: BlockHeight) async { self.requestedRewindHeight = requestedRewindHeight }
}

Expand All @@ -81,7 +74,6 @@ enum CBPState: CaseIterable {
case updateChainTip
case processSuggestedScanRanges
case rewind
case computeSyncControlData
case download
case scan
case clearAlreadyScannedBlocks
Expand Down
14 changes: 1 addition & 13 deletions Sources/ZcashLightClientKit/Block/Actions/ClearCacheAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,7 @@ extension ClearCacheAction: Action {
if await context.prevState == .idle {
await context.update(state: .migrateLegacyCacheDB)
} else {
if context.preferredSyncAlgorithm == .linear {
await context.update(state: .finished)
} else {
if let supportedSyncAlgorithm = await context.supportedSyncAlgorithm {
if supportedSyncAlgorithm == .linear {
await context.update(state: .finished)
} else {
await context.update(state: .processSuggestedScanRanges)
}
} else {
throw ZcashError.compactBlockProcessorSupportedSyncAlgorithm
}
}
await context.update(state: .processSuggestedScanRanges)
}

return context
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,8 @@ extension SaplingParamsAction: Action {
logger.debug("Fetching sapling parameters")
try await saplingParametersHandler.handleIfNeeded()

if context.preferredSyncAlgorithm == .spendBeforeSync {
await context.update(state: .updateSubtreeRoots)
} else {
await context.update(state: .computeSyncControlData)
}
await context.update(state: .updateSubtreeRoots)

return context
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,36 +33,23 @@ extension UpdateSubtreeRootsAction: Action {
let stream = service.getSubtreeRoots(request)

var roots: [SubtreeRoot] = []
var err: Error?

do {
for try await subtreeRoot in stream {
roots.append(subtreeRoot)
}
} catch ZcashError.serviceSubtreeRootsStreamFailed(LightWalletServiceError.timeOut) {
throw ZcashError.serviceSubtreeRootsStreamFailed(LightWalletServiceError.timeOut)
} catch {
logger.debug("getSubtreeRoots failed with error \(error.localizedDescription)")
err = error
}

// In case of error, the lightwalletd doesn't support Spend before Sync -> switching to linear sync.
// Likewise, no subtree roots results in switching to linear sync.
if err != nil || roots.isEmpty {
logger.info("Spend before Sync is not possible, switching to linear sync.")
await context.update(supportedSyncAlgorithm: .linear)
await context.update(state: .computeSyncControlData)
} else {
await context.update(supportedSyncAlgorithm: .spendBeforeSync)
logger.info("Sapling tree has \(roots.count) subtrees")
do {
try await rustBackend.putSaplingSubtreeRoots(startIndex: UInt64(request.startIndex), roots: roots)

await context.update(state: .updateChainTip)
} catch {
logger.debug("putSaplingSubtreeRoots failed with error \(error.localizedDescription)")
throw ZcashError.compactBlockProcessorPutSaplingSubtreeRoots(error)
}
logger.info("Sapling tree has \(roots.count) subtrees")
do {
try await rustBackend.putSaplingSubtreeRoots(startIndex: UInt64(request.startIndex), roots: roots)

await context.update(state: .updateChainTip)
} catch {
logger.debug("putSaplingSubtreeRoots failed with error \(error.localizedDescription)")
throw ZcashError.compactBlockProcessorPutSaplingSubtreeRoots(error)
}

return context
Expand Down
Loading

0 comments on commit d956e99

Please sign in to comment.